在 SQL Server 2008 中沿路径移动点
我的数据库中存储了一个地理字段,其中包含线串路径。
我想沿着该线串移动一个点 n
米,并返回目的地。
例如,我希望目标点从起点开始沿着线串 500 米。
这是一个示例 - 什么是 YourFunctionHere
?或者,还有其他办法吗?
DECLARE @g geography;
SET @g = geography::STGeomFromText('LINESTRING(-122.360 47.656, -122.343 47.656, -122.310 47.690)', 4326);
SELECT @g.YourFunctionHere(100).ToString();
I have a geography field stored in my database, holding a linestring path.
I want to move a point n
meters along this linestring, and return the destination.
For example, I want the destination point 500 meters along the linestring starting from its beginning.
Here's an example -- what is the YourFunctionHere
? Or, is there another way?
DECLARE @g geography;
SET @g = geography::STGeomFromText('LINESTRING(-122.360 47.656, -122.343 47.656, -122.310 47.690)', 4326);
SELECT @g.YourFunctionHere(100).ToString();
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这有点棘手,但肯定是可能的。
让我们首先计算从一点到另一点的方位角。给定起点、方位和距离,以下函数将返回目标点:
我知道您需要一个将线串作为输入的函数,而不仅仅是起点和终点。该点必须沿着连接线段的路径移动,并且必须继续围绕路径的“角”移动。一开始这可能看起来很复杂,但我认为可以按如下方式解决:
STPointN()
,从 x=1 到 x=STNumPoints()
。STDistance()
查找距离迭代中当前点到下一个点之间:@linestring.STPointN(x).STDistance(@linestring.STPointN(x+1))
如果上述距离 >您的输入距离“n”:
...那么目标点就在这个点和下一个点之间。只需应用
func_MoveTowardsPoint
,传递点x作为起点,点x+1作为终点,距离n。返回结果并中断迭代。其他:
...目标点距离迭代中的下一个点更远。从距离“n”中减去点 x 和点 x+1 之间的距离。继续使用修改后的距离进行迭代。
您可能已经注意到,我们可以轻松地递归实现上述内容,而不是迭代。
让我们开始吧:
准备好之后,就可以进行一些测试了。让我们使用问题中提供的原始线串,我们将请求 350m、3500m 和 7000m 处的目标点:
我们的测试返回以下结果:
请注意,我们请求的最后一个距离 (7000m) 超出了线串,所以我们返回了最后一个点。在这种情况下,如果您愿意,可以轻松修改该函数以返回 NULL。
This is a little bit tricky, but it is certainly possible.
Let's start by calculating the bearing from one point to another. Given a starting point, a bearing, and a distance, the following function will return the destination point:
I understand that you require a function that takes a linestring as input, not just start and end points. The point has to move along a path of concatenated line segments, and must continue moving around the "corners" of the path. This might seem complicated at first, but I think it can be tackled as follows:
STPointN()
, from x=1 to x=STNumPoints()
.STDistance()
between the current point in the iteration to the next point:@linestring.STPointN(x).STDistance(@linestring.STPointN(x+1))
If the above distance > your input distance 'n':
...then the destination point is between this point and the next. Simply apply
func_MoveTowardsPoint
passing point x as start point, point x+1 as end point, and distance n. Return the result and break the iteration.Else:
...the destination point is further in the path from the next point in the iteration. Subtract the distance between point x and point x+1 from your distance 'n'. Continue through the iteration with the modified distance.
You may have noticed that we can easily implement the above recursively, instead of iteratively.
Let's do it:
With that in place, it's time to do some tests. Let's use the original linestring that was provided in the question, and we'll request the destination points at 350m, at 3500m and at 7000m:
Our test returns the following results:
Note that the last distance we requested (7000m) exceeded the length of the linestring, so we were returned the last point. In this case, you can easily modify the function to return NULL, if you prefer.
CodePlex 上的 SQL Spatial Tools 库中还有 LocateAlongGeog 函数
http://sqlspatialtools.codeplex.com/wikipage?title=Current% 20Contents&referringTitle=首页
There is also the function LocateAlongGeog in the SQL Spatial Tools libarary on CodePlex
http://sqlspatialtools.codeplex.com/wikipage?title=Current%20Contents&referringTitle=Home
我使用了上面丹尼尔的答案,但我必须将“func_MoveAlongPath”签名修复为
int 会返回错误的结果,因为它会舍入递归调用中的值。
然后我将其转换为迭代版本,因为递归版本无法处理我拥有的样本数据中的较大距离:
I used Daniel's answer from above, but I had to fix the "func_MoveAlongPath" signature to
The int would returned wrong results, because it would round the values in the recursive calls.
I then converted it into an iterative version, since the recursive one couldn't handle larger distances in the sample data I had: