DbGeography相交方法不起作用

System.Data.Spatial.DbGeography.Intersects方法似乎总是为我返回true。 我不确定为什么会这样。 我在下面创建了一个简单的命令行代码段,导致下面的控制台输出

Intersects Intersects 

这一点显然不在界限附近,因此不应该相交。

 DbGeography bounds = DbGeography.PolygonFromText("POLYGON ((146 -20,148 -20,148 -22,146 -22,146 -20))", 4326); DbGeography point = DbGeography.PointFromText("POINT (0 0)", 4326); if (point.Intersects(bounds) == true) Console.WriteLine("Intersects"); else Console.WriteLine("Does NOT intersect"); if (bounds.Intersects(point) == true) Console.WriteLine("Intersects"); else Console.WriteLine("Does NOT intersect"); 

这一点显然不在界限附近,因此不应该相交。

有一条规则:只要你说“清楚”,就要准备好做错。 🙂

开玩笑,你有一个环定向问题。 也就是说,指定点的顺序很重要。 当您指定角落时,您已经定义了一个整个地球的区域,其中有一个非常小的洞。 请尝试使用此代码:

 POLYGON ((146 -20,146 -22,148 -22,148 -20,146 -20)) 

那么,你怎么知道你有一个方向问题呢? 我喜欢使用的一种启发式方法是,如果对象的包络角很大(90度=一个半球),那么您已经错误地指定了排序。 在数据库引擎中的Geography数据类型上有一个EnvelopeAngle方法(但它看起来不像在C#中的DbGeography类中)来确定这一点。 还有一种方便的方法(再次肯定在数据库中而不是在C#中)来重新调整所调用的环,这并不奇怪是ReorientObject

如前所述,这是一个环定向误差。 对于那些使用SQL Server – 它使用左手方向,这意味着如果你沿着多边形的周边行走,你的左手应该在多边形的内侧而右手应该在外面(逆时针)或逆时针)。 我甚至从政府数据中得到了“环形方向”错误,因为多边形是在相反方向(顺时针或右手)绘制的,这意味着SQL Server正在处理地球的整个表面除了我的多边形作为区域多边形

这是一种自动修复此问题的方法:

 public bool IsInside(DbGeography polygon, double longitude, double latitude) { DbGeography point = DbGeography.FromText(string.Format("POINT({1} {0})", latitude.ToString().Replace(',', '.'), longitude.ToString().Replace(',', '.')), DbGeography.DefaultCoordinateSystemId); var wellKnownText = polygon.AsText(); var sqlGeography = SqlGeography.STGeomFromText(new SqlChars(wellKnownText), DbGeography.DefaultCoordinateSystemId) .MakeValid(); //Now get the inversion of the above area var invertedSqlGeography = sqlGeography.ReorientObject(); //Whichever of these is smaller is the enclosed polygon, so we use that one. if (sqlGeography.STArea() > invertedSqlGeography.STArea()) { sqlGeography = invertedSqlGeography; } polygon = DbSpatialServices.Default.GeographyFromProviderValue(sqlGeography); return point.Intersects(polygon); } 

对于那些使用Entity Framework 5的人<:

我使用此扩展方法检查每个PolygonMultipolygon然后将它们保存到数据库。

 public static DbGeography MakePolygonValid(this DbGeography geom) { var wellKnownText = geom.AsText(); //First, get the area defined by the well-known text using left-hand rule var sqlGeography = SqlGeography.STGeomFromText(new SqlChars(wellKnownText), DbGeography.DefaultCoordinateSystemId) .MakeValid(); //Now get the inversion of the above area var invertedSqlGeography = sqlGeography.ReorientObject(); //Whichever of these is smaller is the enclosed polygon, so we use that one. if (sqlGeography.STArea() > invertedSqlGeography.STArea()) { sqlGeography = invertedSqlGeography; } return DbSpatialServices.Default.GeographyFromProviderValue(sqlGeography); } 

然后我可以使用这样的方法来检查数据库级别的Intersects

 public static class GeoHelper { public const int SridGoogleMaps = 4326; public const int SridCustomMap = 3857; public static DbGeography PointFromLatLng(double lat, double lng) { return DbGeography.PointFromText( "POINT(" + lng.ToString(CultureInfo.InvariantCulture) + " " + lat.ToString(CultureInfo.InvariantCulture) + ")", SridGoogleMaps); } } public County GetCurrentCounty(double latitude, double longitude) { var point = GeoHelper.PointFromLatLng(latitude, longitude); var county = db.Counties.FirstOrDefault(x => x.Area.Intersects(point)); return county; } 

entity framework生成的T-SQL:

 SELECT TOP (1) [Extent1].[Id] AS [Id], [Extent1].[Name] AS [Name], [Extent1].[Code] AS [Code], [Extent1].[Area] AS [Area] FROM [Election].[County] AS [Extent1] WHERE ([Extent1].[Area].STIntersects(@p__linq__0)) = 1 -- p__linq__0: 'POINT (10.0000000 32.0000000)' (Type = Object) 

可以像这样手动测试:

 declare @p__linq__0 varchar(max) set @p__linq__0 = 'POINT (10.0000000 32.0000000)' SELECT TOP (1) [Extent1].[Id] AS [Id], [Extent1].[Name] AS [Name], [Extent1].[Code] AS [Code], [Extent1].[Area] AS [Area] FROM [Election].[County] AS [Extent1] WHERE ([Extent1].[Area].STIntersects(@p__linq__0)) = 1 

更多信息可以在这里找到:

https://docs.microsoft.com/en-us/sql/t-sql/spatial-geometry/stintersects-geometry-data-type

来自这个post的来源:

检查dbgeometry dbgeometry / dbgeography点是否在多边形内