C# 检查dbgeometry dbgeometry/dbgeography点是否在多边形内
我有个问题,希望你们能帮我解决 我得到了一个DbGeometry点(或者DbGeometry,我可以两者都使用),我想检查它是否在DbGeometry多边形(或者DbGeometry)内 我目前正在这样做:C# 检查dbgeometry dbgeometry/dbgeography点是否在多边形内,c#,sql-server,polygon,point-in-polygon,C#,Sql Server,Polygon,Point In Polygon,我有个问题,希望你们能帮我解决 我得到了一个DbGeometry点(或者DbGeometry,我可以两者都使用),我想检查它是否在DbGeometry多边形(或者DbGeometry)内 我目前正在这样做: var dbZones = new List<WasteManager.Database.Zone>(); foreach(var zone in zones) { var res = from z in DatabaseContext.Z
var dbZones = new List<WasteManager.Database.Zone>();
foreach(var zone in zones)
{
var res = from z in DatabaseContext.Zones
let boundary =
!z.BoundaryGeometry.IsValid
? SqlSpatialFunctions.MakeValid(z.BoundaryGeometry)
: z.BoundaryGeometry
where z.ID == zone.ID && point.Within(boundary)
select z;
if(res.FirstOrDefault() != null) dbZones.Add(res.FirstOrDefault());
}
var dbZones=newlist();
foreach(区域中的var区域)
{
var res=从DatabaseContext.Zones中的z开始
让边界=
!z.BoundaryGeometry.IsValid
?SqlSpatialFunctions.MakeValid(z.BoundaryGeometry)
:z.边界几何体
其中z.ID==zone.ID&&point.in(边界)
选择z;
如果(res.FirstOrDefault()!=null)dbZones.Add(res.FirstOrDefault());
}
所以我遍历区域(我的db的EF实体)并检查我的这个点是否在这个边界内
问题是它不会返回任何结果,但我知道该点位于该边界内,因为我手动创建了边界,并且该点位于该边界内
有人能告诉我我做的是不是错了,有没有其他方法可以做到这一点或其他什么
非常感谢
曼纽尔实际上很容易
bool isInside(DbGeometry polygon, double longitude, double latitude) //or DbGeography in your case
{
DbGeometry point = DbGeometry.FromText(string.Format("POINT({0} {1})",longitude, latitude), 4326);
return polygon.Contains(point);
}
我想对尼克·斯特鲁帕特补充一点意见 你应该小心环的方向。 SQL Server使用左手方向,这意味着如果沿着多边形的周长行走,左手应该在多边形的内侧,右手应该在外侧(逆时针或逆时针)。我得到了“环方向”错误,因为我以相反的方向(顺时针或右手)绘制多边形,这意味着SQL Server将整个地球表面(多边形除外)视为多边形的面积 要检查点是否在多边形中,应始终使用
点。相交(多边形)
,而不是!点.相交(多边形)
有一个解决方案可以通过检查区域的大小来检查多边形是否正常,
有关更多信息,请访问:
以下是我根据博客解释编写的代码:
private 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);
// If the polygon area is larger than an earth hemisphere (510 Trillion m2 / 2), we know it needs to be fixed
if (polygon.Area.HasValue && polygon.Area.Value > 255000000000000L)
{
// Convert our DbGeography polygon into a SqlGeography object for the ReorientObject() call
SqlGeography sqlPolygon = SqlGeography.STGeomFromWKB(new System.Data.SqlTypes.SqlBytes(polygon.AsBinary()), DbGeography.DefaultCoordinateSystemId);
// ReorientObject will flip the polygon so the outside becomes the inside
sqlPolygon = sqlPolygon.ReorientObject();
// Convert the SqlGeography object back into DbGeography
polygon = DbGeography.FromBinary(sqlPolygon.STAsBinary().Value);
}
return point.Intersects(polygon);
}
我还想对@BenoitGlaizette添加一条评论 代码
polygon.Area.HasValue
可能会为某些多多边形
抛出以下错误
ArgumentException:24144:无法完成此操作,因为
实例无效。使用MakeValid将实例转换为
有效实例。请注意,MakeValid可能会导致几何图形的点
实例稍微移动
但是,如果直接转换为SqlGeography
,则不会发生这种情况
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);
}
对于那些使用实体框架5的人,让我们看看你的边界,以及边界和点的一些实际值。你如何定义点?我经常犯切换lon和lat的错误(因为sql将其定义为(lon,lat),而不是更自然的发音(lat,lon)@tgolisch,这实际上是一个非常好的观点。我100%确定我在为我的区域创建边界时犯了一个错误。我将它们输入为“经度”,而不是“经度”.该死!我还没有保存insert语句,因此,我必须在地图上重新找到坐标并重新插入它们:(因为它们存储为二进制数据,无法检索它们,或者是真的吗?如果找到我的答案,您应该能够执行SQL查询,将边界选择为GML.btw)有用,我很感激一两个点。向上箭头plz&Thank.DbGeography没有
Contains()
成员DbGeography
的等价物似乎是!point.Intersects(polygon)
@NickStrupat这是非常有用的注释,特别是考虑到这有多么违反直觉:)
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);
}
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;
}
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