简体   繁体   English

通过 EF Core 和 NetTopologySuite 使用半径按区域搜索

[英]Searching by area using radius with EF Core and NetTopologySuite

I'm building an application that I need to be able to search for businesses, based on their 'delivery area'我正在构建一个应用程序,我需要能够根据他们的“交付区域”搜索企业

For example, London Business provides services up to 10000 meters from a lat/lon Southampton Business provides services 1000 meters from a lat/lon例如, London Business提供距纬度/经度最远 10000 米的服务Southampton Business提供距纬度/经度 1000 米的服务

I'm part of the way there, using EF Core and NetTopologySuite.我是其中的一部分,使用 EF Core 和 NetTopologySuite。

I'm using the following simplified code:我正在使用以下简化代码:

var geometryFactory = NtsGeometryServices.Instance.CreateGeometryFactory(srid: 4326);

var londonBusiness = new Business
{
    Name = "London Business",
    Area = geometryFactory.CreatePoint(new Coordinate(-0.127758, 51.507351)),
    AreaRadius = 10000
};

var southamptonBusiness = new Business
{
    Name = "Southampton Business",
    Area = geometryFactory.CreatePoint(new Coordinate(1.4044, 50.9097)),
    AreaRadius = 1000
};

await _dbContext.Businesses.AddAsync(londonBusiness);
await _dbContext.Businesses.AddAsync(southamptonBusiness);
await _dbContext.SaveChangesAsync();


// QUERY

// this is very clsoe to the londonBusiness (a couple of km)
var searchLocation = _geometryFactory.CreatePoint(new Coordinate(-0.142500, 51.539188));

var query = _dbContext
    .Businesses
    .Where(x => x.AreaLocation.Distance(searchLocation) <= x.AreaRadius)
    .ToList()

    // this projection is for debug purposes
    .Select(x => new
    {
        Distance = x.AreaLocation.Distance(searchLocation),
        radius = x.AreaRadius
    });

This is returning the following results:这将返回以下结果:

{ Name = "London Business", Distance = 0.035084485645370242, Radius = 10000 }
{ Name = "Southampton Business", Distance = 1.6700762713552944, Radius = 1000 }

So, I think my issue lies somewhere with the distance(s) I'm clearly misunderstanding what the distances are / relate to.所以,我认为我的问题与距离有关,我显然误解了距离是什么/与之相关。 They're relatively correct - the London Business distance is much much smaller than the Southampton Business他们是相对正确的——伦敦商业距离远小于南安普敦商业距离

Is there a way to query by meters?有没有办法按米查询?

Demo with the use of ProjNet4GeoAPI package to map points of filtered values to projected coordinated system and use them to calculate distance in meters.演示使用ProjNet4GeoAPI包将过滤值的点映射到投影坐标系,并使用它们计算以米为单位的距离。

using GeoAPI.CoordinateSystems.Transformations;
using Microsoft.EntityFrameworkCore;
using NetTopologySuite.Geometries;
using ProjNet.CoordinateSystems;
using ProjNet.CoordinateSystems.Transformations;
using System.Diagnostics;
using System.Linq;

namespace ConsoleApp7
{
    public class Location
    {
        public int Id { get; set; }
        public Point Point { get; set; }
    }
    public class Business
    {
        public int Id { get; set; }
        public Point Point { get; set; }
        public double Distance { get; set; }
    }
    public class MyDbContext : DbContext
    {
        public DbSet<Location> Locations { get; set; }
        public DbSet<Business> Businesses { get; set; }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer("Server=DESKTOP-5PVJ0I5;Database=geog;Integrated Security=true;", 
                options => options.UseNetTopologySuite());

            base.OnConfiguring(optionsBuilder);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            CoordinateTransformationFactory ctfac = new CoordinateTransformationFactory();

            var from = GeographicCoordinateSystem.WGS84;
            var to = ProjectedCoordinateSystem.WGS84_UTM(30, true);

            // convert points from one coordinate system to another
            ICoordinateTransformation trans = ctfac.CreateFromCoordinateSystems(from, to);

            var businessCoordinate = new GeoAPI.Geometries.Coordinate(-0.127758, 51.507351);
            var searchLocationCoordinate = new GeoAPI.Geometries.Coordinate(-0.142500, 51.539188);

            var mathTransform = trans.MathTransform;
            var businessLocation = mathTransform.Transform(businessCoordinate);
            var searchLocation = mathTransform.Transform(searchLocationCoordinate);

            // calculate distance in meters
            var dist = businessLocation.Distance(searchLocation); // 3687m


            // arrange db
            var dbContext = new MyDbContext();
            dbContext.Database.Migrate();

            var location = new Location()
            {
                Point = new Point(searchLocationCoordinate.X, searchLocationCoordinate.Y) {  SRID = 4326, }
            };

            // one business has radius to include location point
            var businessWithLocationInRadius = new Business()
            {
                Distance = 4000,
                Point = new Point(businessCoordinate.X, businessCoordinate.Y) { SRID = 4326, }
            };

            // and this one has too low range
            var businessWithLocationNOTInRadius = new Business()
            {
                Distance = 3500,
                Point = new Point(businessCoordinate.X, businessCoordinate.Y) { SRID = 4326, }
            };

            dbContext.Add(location);
            dbContext.Add(businessWithLocationInRadius);
            dbContext.Add(businessWithLocationNOTInRadius);

            dbContext.SaveChanges();

            var query = dbContext
                .Businesses
                .Where(x => x.Point.Distance(location.Point) <= x.Distance)
                .ToList()

                .Select(x => new
                {
                    Distance = searchLocation
                        .Distance(mathTransform.Transform(new GeoAPI.Geometries.Coordinate(x.Point.X, x.Point.Y))), // 3687m
                    Radius = x.Distance
                })
                
                .ToList();

            Debugger.Break();
        }
    }
}

Reference: SRID Ignored during client operations :参考: SRID 在客户端操作期间被忽略

NTS ignores SRID values during operations. NTS 在操作期间忽略 SRID 值。 It assumes a planar coordinate system.它假定一个平面坐标系。 This means that if you specify coordinates in terms of longitude and latitude, some client-evaluated values like distance, length, and area will be in degrees, not meters.这意味着,如果您根据经度和纬度指定坐标,一些客户端评估的值(如距离、长度和面积)将以度为单位,而不是米。 For more meaningful values, you first need to project the coordinates to another coordinate system using a library like ProjNet4GeoAPI before calculating these values.对于更有意义的值,您首先需要使用 ProjNet4GeoAPI 等库将坐标投影到另一个坐标系,然后再计算这些值。

This is because NetTopologySuite is a .NET port of the JTS Topology Suite.这是因为 NetTopologySuite 是 JTS Topology Suite 的 .NET 端口。 Reference: NetTopologySuite :参考: NetTopologySuite

A .NET GIS solution that is fast and reliable for the .NET platform.一种适用于 .NET 平台的快速可靠的 .NET GIS 解决方案。 NetTopologySuite is a direct-port of all the functionalities offered by JTS Topology Suite: NTS expose JTS in a '.NET way', as example using Properties, Indexers etc... NetTopologySuite 是 JTS Topology Suite 提供的所有功能的直接端口:NTS 以“.NET 方式”公开 JTS,例如使用属性、索引器等...

An excerpt from JTS website explains the capabilities of NTS too: "The JTS Topology Suite is an API for modelling and manipulating 2-dimensional linear geometry. It provides numerous geometric predicates and functions. JTS conforms to the Simple Features Specification for SQL published by the Open GIS Consortium." JTS 网站的摘录也解释了 NTS 的功能:“JTS 拓扑套件是一个用于建模和操作二维线性几何的 API。它提供了许多几何谓词和函数。JTS 符合 SQL 发布的简单特征规范。开放 GIS 联盟。”

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用 EF Core 2.2、Npgsql 和 NetTopologySuite 映射几何 - Mapping geometries with EF Core 2.2, Npgsql and NetTopologySuite 使用 ef core 5 将 GeoJson 转换为 FeatureCollection 并保存在 NetTopologySuite.Geometries.Geometry 列中 - Convert GeoJson to FeatureCollection and save in NetTopologySuite.Geometries.Geometry column using ef core 5 使用带有 EF Core 的 PostgreSql 在加密列中搜索 - Searching in encrypted columns using PostgreSql with EF Core dotnet核心数据库首先使用NetTopologySuite - dotnet core database first using NetTopologySuite 使用 NetTopologySuite 保存几何时的 Entity Framework Core IndexOutOfRangeException - Entity Framework Core IndexOutOfRangeException when saving geometry using NetTopologySuite 搜索投影的 EF Core 导航属性 - Searching Against Projected EF Core Navigation Properties 使用 Code First 和 EF.Core 引用表以进行有效搜索的正确方法是什么 - What's the correct way to reference tables using Code First with EF.Core for searching efficiently 使用NetTopologySuite TransformGeometry时出错 - Error when using NetTopologySuite TransformGeometry NetTopologySuite Distance 在 .net Core 3 中返回奇数结果 - NetTopologySuite Distance is returning odd results in .net Core 3 NetTopologySuite.Core 1.15.3 和距离单位 - NetTopologySuite.Core 1.15.3 and distance units
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM