如何用NetTopologySuite/ProjNet计算两点间米级距离(2022)
解决方案
错误原因
你提供的EPSG:27700的WKT包含EXTENSION扩展段,而ProjNet的WKT解析器不支持该扩展语法,导致解析报错。
简化方案(无需手动投影)
如果你的目标只是计算两点间的球面距离(单位:米),完全不需要手动转换坐标系,直接使用NetTopologySuite的相关工具即可,和TSQL的STDistance行为一致:
@using NetTopologySuite.Geometries @using NetTopologySuite.Algorithm.Distance @{ // 注意:地理坐标点的顺序是 经度, 纬度,SRID=4326对应WGS84坐标系 var windsorCastle = new Point(-0.604455, 51.483884) { SRID = 4326 }; var buckinghamPalace = new Point(-0.141208, 51.501576) { SRID = 4326 }; // 直接计算球面距离,单位为米 var distanceCalculator = new SphericalDistanceCalculator(); double distanceInMeters = distanceCalculator.Distance(windsorCastle, buckinghamPalace); Console.WriteLine($"两点距离:{distanceInMeters:F2} 米"); }
如需转换到EPSG:27700(英国国家网格)
如果必须转换坐标系,需要去掉WKT中的EXTENSION段(去掉后会忽略OSTN15校正,精度略有损失),修正后的代码如下:
@using NetTopologySuite.Geometries @using ProjNet.CoordinateSystems @using ProjNet.CoordinateSystems.Transformations @{ var windsorCastle = new Point(-0.604455, 51.483884) { SRID = 4326 }; var buckinghamPalace = new Point(-0.141208, 51.501576) { SRID = 4326 }; // 移除EXTENSION段的EPSG:27700 WKT const string epsg27700 = @" PROJCS[""OSGB36 / British National Grid"", GEOGCS[""OSGB36"", DATUM[""Ordnance_Survey_of_Great_Britain_1936"", SPHEROID[""Airy 1830"",6377563.396,299.3249646]], PRIMEM[""Greenwich"",0, AUTHORITY[""EPSG"",""8901""]], UNIT[""degree"",0.0174532925199433, AUTHORITY[""EPSG"",""9122""]], AUTHORITY[""EPSG"",""4277""]], PROJECTION[""Transverse_Mercator""], PARAMETER[""latitude_of_origin"",49], PARAMETER[""central_meridian"",-2], PARAMETER[""scale_factor"",0.9996012717], PARAMETER[""false_easting"",400000], PARAMETER[""false_northing"",-100000], UNIT[""metre"",1, AUTHORITY[""EPSG"",""9001""]], AXIS[""Easting"",EAST], AXIS[""Northing"",NORTH], AUTHORITY[""EPSG"",""27700""]] "; var csWgs84 = GeographicCoordinateSystem.WGS84; var cs27700 = (CoordinateSystem)CoordinateSystemWktReader.Parse(epsg27700); var ctFactory = new CoordinateTransformationFactory(); var transformation = ctFactory.CreateFromCoordinateSystems(csWgs84, cs27700); // 转换坐标点到英国国家网格 var windsorCastleOsgb = new Point(transformation.MathTransform.Transform(windsorCastle.Coordinate)) { SRID = 27700 }; var buckinghamPalaceOsgb = new Point(transformation.MathTransform.Transform(buckinghamPalace.Coordinate)) { SRID = 27700 }; // 计算平面距离,单位为米 double distanceInMeters = windsorCastleOsgb.Distance(buckinghamPalaceOsgb); Console.WriteLine($"两点距离:{distanceInMeters:F2} 米"); }
关键注意事项
- 地理坐标点的顺序是经度在前,纬度在后,和TSQL的
geography::Point(Lat, Lon)相反,不要混淆。 - 用EF Core查询数据库时,直接在LINQ中调用
Distance方法,EF Core会自动转换为SQL的STDistance,返回米单位结果:var nearbyPlaces = db.Places .Where(p => p.Location.Distance(userLocation) < 1000) // 查询1000米以内的地点 .ToList();
内容的提问来源于stack exchange,提问作者EvilDr
相关产品推荐
相关产品推荐

