当前位置: 首页 > 面试题库 >

在SQL Server 2008中沿路径移动点

伊锦
2023-03-14
问题内容

我的数据库中存储了一个地理位置字段,其中包含一个线串路径。

我想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();

问题答案:

这有点棘手,但是肯定是可能的。

让我们开始计算从一个点到另一个点的方位。给定起点,方位角和距离,以下函数将返回目标点:

CREATE FUNCTION [dbo].[func_MoveTowardsPoint](@start_point geography,
                                              @end_point   geography,  
                                              @distance    int)  /* Meters */   
RETURNS geography
AS
BEGIN
    DECLARE @ang_dist float = @distance / 6371000.0;  /* Earth's radius */
    DECLARE @bearing  decimal(18,15);
    DECLARE @lat_1    decimal(18,15) = Radians(@start_point.Lat);
    DECLARE @lon_1    decimal(18,15) = Radians(@start_point.Long);
    DECLARE @lat_2    decimal(18,15) = Radians(@end_point.Lat);
    DECLARE @lon_diff decimal(18,15) = Radians(@end_point.Long - @start_point.Long);
    DECLARE @new_lat  decimal(18,15);
    DECLARE @new_lon  decimal(18,15);
    DECLARE @result   geography;

    /* First calculate the bearing */

    SET @bearing = ATN2(sin(@lon_diff) * cos(@lat_2),
                        (cos(@lat_1) * sin(@lat_2)) - 
                        (sin(@lat_1) * cos(@lat_2) * 
                        cos(@lon_diff)));

    /* Then use the bearing and the start point to find the destination */

    SET @new_lat = asin(sin(@lat_1) * cos(@ang_dist) + 
                        cos(@lat_1) * sin(@ang_dist) * cos(@bearing));

    SET @new_lon = @lon_1 + atn2( sin(@bearing) * sin(@ang_dist) * cos(@lat_1), 
                                  cos(@ang_dist) - sin(@lat_1) * sin(@lat_2));

    /* Convert from Radians to Decimal */

    SET @new_lat = Degrees(@new_lat);
    SET @new_lon = Degrees(@new_lon);

    /* Return the geography result */

    SET @result = 
        geography::STPointFromText('POINT(' + CONVERT(varchar(64), @new_lon) + ' ' + 
                                              CONVERT(varchar(64), @new_lat) + ')', 
                                   4326);

    RETURN @result;
END

我了解您需要一个以线串作为输入,而不仅仅是起点和终点的函数。该点必须沿着连接的线段的路径移动,并且必须继续沿路径的“角”移动。起初这似乎很复杂,但我认为可以解决以下问题:

  1. STPointN()从x = 1到x =遍历线串的每个点STNumPoints()
  2. 找到STDistance()迭代中当前点到下一个点之间的距离:@linestring.STPointN(x).STDistance(@linestring.STPointN(x+1))
  3. 如果上述距离>您的输入距离’n’:

…然后,目的地点在此点和下一个点之间。只需将 func_MoveTowardsPoint传递点x用作起点,将点x +
1用作终点,并应用距离n。返回结果并中断迭代。

别的:

…目标点在迭代中距下一个点更远的路径中。从距离’n’中减去点x和点x + 1之间的距离。以修改后的距离继续进行迭代。

您可能已经注意到,我们可以轻松地以递归方式(而不是迭代地)实现上述功能。

我们开始做吧:

CREATE FUNCTION [dbo].[func_MoveAlongPath](@path geography, 
                                           @distance int, 
                                           @index int = 1)   
RETURNS geography
AS
BEGIN
    DECLARE @result       geography = null;
    DECLARE @num_points   int = @path.STNumPoints();
    DECLARE @dist_to_next float;

    IF @index < @num_points
    BEGIN
        /* There is still at least one point further from the point @index
           in the linestring. Find the distance to the next point. */

        SET @dist_to_next = @path.STPointN(@index).STDistance(@path.STPointN(@index + 1));

        IF @distance <= @dist_to_next 
        BEGIN
            /* @dist_to_next is within this point and the next. Return
              the destination point with func_MoveTowardsPoint(). */

            SET @result = [dbo].[func_MoveTowardsPoint](@path.STPointN(@index),
                                                        @path.STPointN(@index + 1),
                                                        @distance);
        END
        ELSE
        BEGIN
            /* The destination is further from the next point. Subtract
               @dist_to_next from @distance and continue recursively. */

            SET @result = [dbo].[func_MoveAlongPath](@path, 
                                                     @distance - @dist_to_next,
                                                     @index + 1);
        END
    END
    ELSE
    BEGIN
        /* There is no further point. Our distance exceeds the length 
           of the linestring. Return the last point of the linestring.
           You may prefer to return NULL instead. */

        SET @result = @path.STPointN(@index);
    END

    RETURN @result;
END

有了适当的设置,是时候进行一些测试了。让我们使用问题中提供的原始线串,然后在350m,3500m和7000m处请求目标点:

DECLARE @g geography;
SET @g = geography::STGeomFromText('LINESTRING(-122.360 47.656, 
                                               -122.343 47.656, 
                                               -122.310 47.690)', 4326);

SELECT [dbo].[func_MoveAlongPath](@g, 350, DEFAULT).ToString();
SELECT [dbo].[func_MoveAlongPath](@g, 3500, DEFAULT).ToString();
SELECT [dbo].[func_MoveAlongPath](@g, 7000, DEFAULT).ToString();

我们的测试返回以下结果:

POINT (-122.3553270591861 47.6560002502638)
POINT (-122.32676470116748 47.672728464582583)
POINT (-122.31 47.69)

请注意,我们要求的最后距离(7000m)超出了线串的长度,因此我们返回了最后一点。在这种情况下,您可以根据需要轻松地修改该函数以返回NULL。



 类似资料:
  • 我想在HTML5画布/或SVG上执行以下操作: 有一个背景路径,将光标移过去并绘制(填充)背景路径 用户完成绘图后有回调函数 我的问题是,我不知道如何检查抽屉线是否遵循路径。 有人能给我解释一下如何做到这一点,或者给我一些建议吗? http://jsbin.com/reguyuxawo/edit?html,js,控制台,输出

  • 我有一个postgis数据库(postgres 8.4.11,postgis 1.5.2),其中包含gps观测,我想计算一些旅行距离。 一小时后,我使用从gpspoint p1、gpspoint p2选择observedid、ST_distance(p1.shape_utm、p2.shape_utm)计算从一个点到另一个点的行驶距离,其中p2.datetime=p1.datetime间隔“1小时”

  • 本文向大家介绍在弯曲的路径中移动HTML div,包括了在弯曲的路径中移动HTML div的使用技巧和注意事项,需要的朋友参考一下 要在弯曲的路径中移动HTML div,请使用以下任一方法:  CSS过渡  JavaScript(jQuery)  HTML5画布 尝试使用JavaScript,使其在所有浏览器中都能正常工作。 使用方法。该方法对一组CSS属性执行自定义动画。 以下是语法: 这是此方

  • 我在。工作。在表单(一个GUI应用程序)中的Netbeans Java项目上,我希望将移动到循环路径中。有什么可以告诉或帮助如何做到这一点吗?

  • 我想知道使用xpath是否可以实现以下目标 鉴于: 要求: 我想使用单个xpath表达式查找select元素,如下所示,bcs ID是动态的,并且在属性“for”中始终可用。 //label[text()=“Select Country”]/@for//*[@id=@for] 我们是否可以在xpath中传递属性值(此处为标签的属性),沿着路径进一步查找元素。 请不要建议使用兄弟姐妹、子级、id或s

  • 大家早上好。我有以下代码: 问题是,uri变量被分配给RestTemplate构造函数为,也就是说,它从代码变量中删除初始的。