我正在允许用户通过单击来绘制Silverlight中的多边形。然后我循环遍历这些点,将它们转换为经度和纬度,然后保存到 SQL 中 (geography
列)。
问题在于,由于地球是圆的,所以只有当用户顺时针绘制时才能正常工作。否则它会尝试使多边形绕着世界转一圈并失败。
因此,我应该如何正确地做到这一点?我必须确定他们绘制的方向吗?如果是这样,我该如何确定方向?
我正在允许用户通过单击来绘制Silverlight中的多边形。然后我循环遍历这些点,将它们转换为经度和纬度,然后保存到 SQL 中 (geography
列)。
问题在于,由于地球是圆的,所以只有当用户顺时针绘制时才能正常工作。否则它会尝试使多边形绕着世界转一圈并失败。
因此,我应该如何正确地做到这一点?我必须确定他们绘制的方向吗?如果是这样,我该如何确定方向?
如果地理图形的EnvelopeAngle()
方法返回180,则可以使用ReorientObject()
函数进行纠正。
以下是示例:
--A CW polygon
DECLARE @G3 GEOGRAPHY = 'POLYGON ((45 45, 44 45, 44 46, 45 46, 45 45))';
SELECT @G3.EnvelopeAngle(); --180
SELECT @G3.ReorientObject().STAsText(); --POLYGON ((44 46, 44 45, 45 45, 45 46, 44 46))
编辑 根据评论中的说明,您可以使用一个简单的更新命令来纠正当前的几何形状(在您确定它们不正确的情况下):
UPDATE foo_table SET bar_column = bar_column.ReorientObject()
WHERE bar_column.EnvelopeAngle() > 90
DECLARE @geom GEOMETRY = 'POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))';
DECLARE @geog GEOGRAPHY = @geom.MakeValid().STUnion(@geom.STStartPoint()).STAsText()
STUnion()
方法。由于这是基于OGC的方法,可以在给定要素的整个几何体上工作,它会强制将多边形放置到所需的方法方向上 - 这恰好是用于地理类型
的方向[...]。这种方法非常高效,可以保持开销较小[...]。MakeValid()
了吗? - Michaelpolygon
是一个字符串还是一个 geometry
对象?如果是后者,您可以尝试使用 CAST(foo_column.MakeValid().StUnion(foo_column.STStartPoint()).STAsText() AS GEOGRAPHY)
进行转换。其次,如果您使用的 SQL Server 版本高于 2008,则可以在 我的 GIS.SE 问题 中使用 链接 中的 ReorientObject()
。最后,如果可能的话,请在保存之前进行重新定向,而不是在读取时进行。 - Michael如果您使用的是SqlServer 2008的RTM版本,您可以随时使用codeplex上的sqlspatial工具,该工具可自由分发,并且从该库中只需使用makevalid方法即可。
如果您有时间尝试SqlServer Denali的CTP1版本,您可以选择新的空间类型,这些类型可以接受大于半球体积的对象,并且具有ReorientObject方法,以便在需要时重新定位对象 :)
左手定则控制着这个问题...当你“走”多边形的周长时,你的左手必须始终在内部...所以事物应该“看起来”是逆时针数字化的。对于带孔的甜甜圈和多边形也是如此。
如果你把左手放在感兴趣的多边形区域内,它们将以顺时针方式数字化。
确定哪一个是正确的简单方法是始终选择面积较小的那个...在我能想到的任何工作流程中,没有多边形会被数字化为大于世界一半的大小...
工作流程如下:让用户创建他们的多边形,创建另一个具有相反方向的多边形(在SQL Server中使用ReorientObject()),然后比较它们的面积...逻辑上,最小的是正确的。
这只是解决这个问题的另一种方法。
这是地理空间数据类型中的一个常见概念,多边形由许多顶点和连接这些顶点的边所定义。然而,你必须能够区分多边形内部和外部的内容。这是通过系统假设边的一侧将始终定义内部来完成的(不同的标准使用左侧或右侧)。
在一个方向上,你画了一个小圆圈,在另一个方向上,你画了一个包围整个世界的球体,除了一个小圆圈。后者往往会打破地理限制并引发异常。
如果你考虑尝试画一个甜甜圈,你有两个多边形,并且必须按顺时针/逆时针的方式放置点,以定义中心的“孔”。
UPDATE foo_table SET bar_column = bar_column.ReorientObject() WHERE bar_column.EnvelopeAngle() > 90
。 - jhhwilliams