postgresql - 使用带有 EF Core 和 postgis 的 NetTopologySuite 计算两点之间的地理距离
问题描述
我正在使用kartoza docker映像来运行带有 postgis 的 postgres 服务器。我有一个使用 ASP.NET Core 应用程序和 Enity Framework Core 使用的数据库。该数据库包含一个名为 Park 的表,由以下实体表示:
[Table("Park")]
public class Park
{
[Key]
public int Id { get; set; }
[Column(TypeName = "geography (point)")]
public Point Location { get; set; }
}
我正在创建文档指定的 DbContext:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasPostgresExtension("postgis");
modelBuilder.Entity<Park>()
.Property(p => p.Location)
.HasColumnType("geography (point)");
}
我使用以下代码为数据库播种:
if (!Parks.Any())
{
var park = new Park
{
Location = new Point(48.8566, 2.3522)
{
SRID = 4326
}
};
Parks.Add(park);
this.SaveChanges();
}
现在为了测试我的代码,我计算了这个公园和某个点之间的距离:
结果对应于笛卡尔坐标系中两点之间的几何距离,而不是地理距离。是否有可能获得以下查询的等价物:
解决方案
正如这里提到的,为了计算地理距离,需要坐标系的投影。ProjNet4GeoAPI 用于使用 extetion 方法执行投影:
static class GeometryExtensions
{
static readonly IGeometryServices _geometryServices = NtsGeometryServices.Instance;
static readonly ICoordinateSystemServices _coordinateSystemServices
= new CoordinateSystemServices(
new CoordinateSystemFactory(),
new CoordinateTransformationFactory(),
new Dictionary<int, string>
{
// Coordinate systems:
// (3857 and 4326 included automatically)
// This coordinate system covers the area of our data.
// Different data requires a different coordinate system.
[2855] =
@"
PROJCS[""NAD83(HARN) / Washington North"",
GEOGCS[""NAD83(HARN)"",
DATUM[""NAD83_High_Accuracy_Regional_Network"",
SPHEROID[""GRS 1980"",6378137,298.257222101,
AUTHORITY[""EPSG"",""7019""]],
AUTHORITY[""EPSG"",""6152""]],
PRIMEM[""Greenwich"",0,
AUTHORITY[""EPSG"",""8901""]],
UNIT[""degree"",0.01745329251994328,
AUTHORITY[""EPSG"",""9122""]],
AUTHORITY[""EPSG"",""4152""]],
PROJECTION[""Lambert_Conformal_Conic_2SP""],
PARAMETER[""standard_parallel_1"",48.73333333333333],
PARAMETER[""standard_parallel_2"",47.5],
PARAMETER[""latitude_of_origin"",47],
PARAMETER[""central_meridian"",-120.8333333333333],
PARAMETER[""false_easting"",500000],
PARAMETER[""false_northing"",0],
UNIT[""metre"",1,
AUTHORITY[""EPSG"",""9001""]],
AUTHORITY[""EPSG"",""2855""]]
"
});
public static IGeometry ProjectTo(this IGeometry geometry, int srid)
{
var geometryFactory = _geometryServices.CreateGeometryFactory(srid);
var transformation = _coordinateSystemServices.CreateTransformation(geometry.SRID, srid);
return GeometryTransform.TransformGeometry(
geometryFactory,
geometry,
transformation.MathTransform);
}
}
现在结果似乎更正确:
PS:除了ProjNet4GeoAPI nugget包外,扩展方法还需要NetTopologySuite。
推荐阅读
- java - 如何实例化非静态内部类?
- iframe - CKEditor 总是在 iframe 周围包裹 p 标签
- jquery - 在从 Ajax 请求返回的 jquery 中存储和使用标记
- mysql - 计算每个用户登录之间的时间
- mysql - 如何读取和更改 mysql 5 字段
- c# - 是否有一个事件处理程序在标签更新时通知用户?
- powershell - 用于格式化输入链接字段的 powershell 脚本
- python - 从列表中写入一个 json 文件
- javascript - 在 Angular 模板中循环遍历带有子项的 Javascript 对象
- python - 如何让我的怪物在我的游戏中随机移动