我如何告诉 SQL 服务器正确处理大多边形?

How can I tell SQL Server to treat large polygons properly?

我想在 SQL 服务器数据库中将大正方形表示为多边形。这个多边形几乎横跨整个地图。

这里是边界坐标(经纬度)

North-East Corner: { 83.4871233224387, 63.5599894667969 }
South-West Corner: { -3.62943382709019, 86.0599894667969 }

这是它在地图上的样子(这些是缩小的 google 地图的地图边界)

这是 SQL 服务器在我尝试绘制多边形时的想法:

 declare @p5 sys.geography;
 set @p5 = geography::STGeomFromText('POLYGON((86.0599894667969 -3.62943382709019, 63.5599894667969 -3.62943382709019, 63.5599894667969 83.4871233224387, 86.0599894667969 83.4871233224387, 86.0599894667969 -3.62943382709019))', 4326);

 select @p5

它认为我没有正确遵循左手法则,但我是,我只想要一个绝对大的多边形。

如果我使用 reorientobject,我会得到相反的结果,这也不是我想要的:

将这两点绘制在地图上以供参考:

我该如何解决这个问题?

我无法以优雅的方式解释这里发生的事情,但我能够破解出一个与您正在寻找的内容非常接近的多边形:

declare @p1 geography = geography::STGeomFromText('
    POLYGON((
        63 83,
        0  83,
        0  -3,
        63 -3,
        63 83
    ))', 4326)
,@p2 geography = geography::STGeomFromText('
    POLYGON((
        86 83,
        86 -3,
        180  -3,
        180  83,
        86 83
    ))', 4326)
,@p3 geography = geography::STGeomFromText('
    POLYGON((
        180 83,
        180 -3,
        -90 -3,
        -90 83,
        180 83
    ))', 4326)
,@p4 geography = geography::STGeomFromText('
    POLYGON((
        -90 83,
        -90 -3,
        0   -3,
        0   83,
        -90 83
    ))', 4326);

select @p1.STUnion(@p2).STUnion(@p3).STUnion(@p4).STAsText();

编辑:我确实有一些时间研究它并想出了一个合理的行为解释而不是 SQL 中的错误。对于任意四个这样的点(即盒子的角),它们定义了四种不同的形状。我将根据我们在这里处理的具体案例来描述它们,但我认为它具有概括性。

这四种形状是:OP 在原始多边形上调用 ReorientObject 时获得的小框、它的补码(又名原始多边形)、所需形状和 补充。

此外,请注意,在环中指定点的顺序并不重要。这正是我们在这里描述的内容(即环)。地理多边形不一定是,坦率地说,在一般情况下可能不是正方形。

一旦你接受了后者,那么很容易只获得四种形状中的两种,这并不是一个飞跃。还请注意,在这四个点定义的四个多边形中,其中三个非常大。所以,我猜测 SQL 有一种启发式方法,能够找出其中最小的,因为坦率地说,这更可能在现实世界的应用程序中定义。然后,根据定义点的顺序,您可以得到该多边形(即四个多边形中最小的一个)或其补码。

和本一样,我无法解释发生了什么。我对坐标顺序进行了两倍、三倍甚至四倍的检查,但找不到任何东西来确定它为什么会创建带孔的地球(本质上)。您的订单是 SW -> SE -> NE -> NW -> WS - 完全符合我的要求,我怀疑这可能是 SQL 方面的错误。

然而,有一件事立即提醒我,这些坐标不适用于 google 地图上的那个视图 - 相信我 - 我已经与他们合作太久了。估计你的坐标应该更近一些:

西南:经度 78,纬度 7 NE:长 44 纬度 83。

显示标记的 google 地图显示了为什么您的 ReorientObject() 调用实际上产生了正确的结果(即使您不需要重新定向任何东西)。

尽管如此,这里有一个更好的创建边界框的方法:

-- Define NE
declare @ne geography = geography::Point(83.4871233224387, 63.5599894667969, 4326);
- Define SW
declare @sw geography = geography::Point(-3.62943382709019, 86.0599894667969, 4326);

-- Define BOX
declare @box geography = geography::STGeomFromWKB(geometry::STGeomFromWKB(@ne.STUnion(@sw).STAsBinary(), 4326).STEnvelope().STAsBinary(), 4326);

select @box -- shows polygon
select @box.ToString -- shows WKT

有趣的是,坐标顺序被定义为好像地理是一个洞 - 它是 SE -> SW -> NW -> NE -> SE,保持内部在右边。这对 GEOMETRY 是正确的,但对 GEOGRAPHY 不正确,但它会产生正确的答案。这就是为什么我认为它可能是一个错误? - 或者我遗漏了什么。

最后,解释创建框:

  • 取两个点的并集(创建一个 MULTIPOINT 类型的几何体)
  • 将 MULTIPOINT 转换为几何类型
  • 使用几何类型的 STEnvelope() 方法创建包含四肢的边界框
  • 转换为 BOX (POLYGON) 返回地理类型

希望对您(以及其他任何人)有所帮助。