在使用地理数据类型(DbGeography)时查询矩形区域

4

我正在查询SQL Server中的表格以在Google Maps上显示结果,并且在服务器应用程序中使用Entity Framework和DbGeography数据类型。

简单地说,我从Google Maps实例获取地图边界,然后使用类似以下方法构建一个DbGeography实例:

var wkt = string.Format("POLYGON(({0} {1}, {0} {2}, {3} {2}, {3} {1}, {0} {1}))", EastLng, NorthLat, SouthLat, WestLng);
var bounds = DbGeography.FromText(wkt);

然后使用以下内容(作为更大查询的一部分)查询数据库:

dbset.Where(i => bounds.Intersects(l.GeographicLocation));

这个代码一直运行良好,我已经在生产环境中使用了一段时间。今天我注意到有时候地图上的一些结果显示不正确。
经过一番调查,我意识到这是因为地球曲率的缘故;Google Maps使用地球的矩形投影,但当我创建一个矩形多边形时,它的形状就像这样(从正在运行的查询中复制而来):
效果在查看非常大的区域的地图时会更明显(缩小)。但当我放大地图时,地球曲率的影响减小,查询似乎可以正常工作。
我需要做的就是基本上查询所有位于纬度/经度边界内的点。有办法做到这一点吗?
编辑:
这是我用来创建DbGeography实例的完整代码:
public class LatLngBounds
{
    // ...

    public DbGeography ToDbGeography()
    {
        return DbGeographyUtil.CreatePolygon(string.Format("POLYGON(({0} {1}, {0} {2}, {3} {2}, {3} {1}, {0} {1}))", EastLng, NorthLat, SouthLat, WestLng));
    }
}


public static class DbGeographyUtil
{
    public static DbGeography CreatePolygon(string wktString)
    {
        if (string.IsNullOrWhiteSpace(wktString))
            return null;

        var sqlGeography = SqlGeography.STGeomFromText(new SqlChars(wktString), DbGeography.DefaultCoordinateSystemId).MakeValid();

        var invertedSqlGeography = sqlGeography.ReorientObject();
        if (sqlGeography.STArea() > invertedSqlGeography.STArea())
        {
            sqlGeography = invertedSqlGeography;
        }

        return DbSpatialServices.Default.GeographyFromProviderValue(sqlGeography);
    }

}

编辑2:

以上示例中谷歌地图输出的坐标是:

  • 东北:纬度=53.6 经度=92.5
  • 西南:纬度=35.0 经度=21.2

这是我使用SQL Server Profiler捕获到的运行查询的一部分:

declare @p4 sys.geography
set @p4=convert(sys.geography,0xE6100000010405000000463E933FAFD64A40070000006E3F354061E412079A894140070000006E3F354061E412079A894140020000808B245740463E933FAFD64A40020000808B245740463E933FAFD64A40070000006E3F354001000000020000000001000000FFFFFFFF0000000003)

SELECT @p4;

我添加了SELECT以查看它的外观,结果如上图所示。


如果您使用地理数据类型,或者SRID为4326的几何类型,并在地理坐标中定义一个框,则不会有任何问题。我不确定我是否理解了Google Maps部分 - 这是非常简单的投影,y值本质上只是纬度的线性函数,我看不出为什么您会看到您所看到的曲率。在球形墨卡托(Google Maps)中,给定的纬线将映射到相同的y坐标。还有其他投影,这种情况并非如此,例如英国使用的横向墨卡托投影,但在这种情况下不是这样。 - John Powell
@JohnBarça 请看我的编辑。我数据库中的所有类型都是地理信息。我想这些线条之所以弯曲,是因为连接东南点和西南点的最短线不与赤道平行,而我记得“地理信息”类型定义(与几何学相比)就是考虑了这种情况。 - Iravanchi
你能否给出一个示例,展示从谷歌地图中获取的坐标是如何用于生成上面的图片的? - John Powell
@JohnBarça 请查看“EDIT 2” :) - Iravanchi
我仍然不知道你是如何制作出那个曲线矩形的,但我向你保证它与从Google Maps SRID 3857转换为lat/lon(4326)无关。你可能会得到一个梯形,但在3857中的水平线对应于4326中的水平线。经线会弯曲,但是平行线不会。也许如果你提供一个点和一个矩形(在4326中),并且它没有按照你的期望工作,那么这可能会更容易些。 - John Powell
显示剩余3条评论
1个回答

1
我通过使用DbGeometry而不是DbGeography来解决了这个问题。
var boundsAsGeometry = DbGeometry.FromText(bounds.AsText(), bounds.CoordinateSystemId);

dbset.Where(x => boundsAsGeometry.Intersects(DbGeometry.FromText(x.GeographicLocation.AsText(), x.GeographicLocation.CoordinateSystemId)));

请注意,如果您已经使用了地理位置字段的现有数据库索引,则此操作将不会使用该索引。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接