首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >DbGeography相交方法无效

DbGeography相交方法无效
EN

Stack Overflow用户
提问于 2015-10-01 03:26:41
回答 2查看 2.2K关注 0票数 4

对于我来说,System.Data.Spatial.DbGeography.Intersects方法似乎总是返回true。我不知道为什么会这样。我在下面创建了一个简单的命令行代码片段,结果是下面的控制台输出

代码语言:javascript
复制
Intersects
Intersects

这一点显然远未达到界限,因此不应相交。

代码语言:javascript
复制
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");
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-10-01 05:41:38

这一点显然远未达到界限,因此不应相交。

有一条规则:一旦你说“清楚”,就准备错了。:)

别开玩笑了,你有戒指定位的问题。也就是说,您指定点数的顺序很重要。当你指定角落的时候,你定义了一个区域,整个地球上都有一个很小的洞。试着用这个代替:

代码语言:javascript
复制
POLYGON ((146 -20,146 -22,148 -22,148 -20,146 -20))

那么,你如何从本质上知道你有一个定向问题呢?我喜欢使用的一种启发式方法是,如果物体的包络角很大(90度=一个半球),那么你就不正确地指定了顺序。在DB引擎中的地理数据类型上有一个EnvelopeAngle方法(但看起来不是在C#中的DbGeography类中)来确定这一点。还有一种方便的方法(同样在DB中是肯定的,但在C#中没有),用于重新定位名为ReorientObject的环。

票数 5
EN

Stack Overflow用户

发布于 2018-03-23 16:18:55

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

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

代码语言:javascript
复制
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<:的用户

在将每个PolygonMultipolygon保存到数据库之前,我使用这种扩展方法检查它们。

代码语言:javascript
复制
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

代码语言:javascript
复制
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;
}

实体框架生成的T:

代码语言:javascript
复制
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)

可以像这样手动测试:

代码语言:javascript
复制
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://learn.microsoft.com/en-us/sql/t-sql/spatial-geometry/stintersects-geometry-data-type

来自此线程的消息来源:

Check if dbgeometry dbgeometry/dbgeography point is within a polygon

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32878951

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档