[英]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.