Sql server TSQL-获取线串上距离点最近的坐标

Sql server TSQL-获取线串上距离点最近的坐标,sql-server,tsql,gis,Sql Server,Tsql,Gis,考虑一个过于简单的例子:点(0)和线串(1-10,110) 直线上距离该点最近的点为1,0 在TSQL中如何确定这一点?我简单但不完全准确的方法是制作一个线串(点-点),并延伸出一个坐标的X坐标,直到两个线串相交 因此: 线串(0,0.25 0)(不相交) 线串(0,0.50)(不相交) 线串(0,0.75 0)(不相交) 线串(0,1 0)(交点-因此1 0是距离点最近的点 这种准方法奏效了,但似乎不是实现这一点的最佳/更有效的方法 例如,一个低效之处是我将其移动一个方向(正增量),如果没有匹

考虑一个过于简单的例子:点(0)和线串(1-10,110)

直线上距离该点最近的点为1,0

在TSQL中如何确定这一点?我简单但不完全准确的方法是制作一个线串(点-点),并延伸出一个坐标的X坐标,直到两个线串相交

因此:

  • 线串(0,0.25 0)(不相交)
  • 线串(0,0.50)(不相交)
  • 线串(0,0.75 0)(不相交)
  • 线串(0,1 0)(交点-因此1 0是距离点最近的点
  • 这种准方法奏效了,但似乎不是实现这一点的最佳/更有效的方法

    例如,一个低效之处是我将其移动一个方向(正增量),如果没有匹配(在尝试x次之后),则我将重新开始,但增量为负

    为了优化,我尝试以更大的步幅移动,然后当相交时(可能超过点),我后退1个增量,从那里开始以较小的增量。我做了几次,而不是以微小的增量移动,以免过多

    基于我的处理,一个可接受的假设是,该点将位于线字符串的(左/右)旁边


    另一个可接受的假设是,线串将相当“垂直”于点。

    我认为您可以通过数学方法而不是使用蛮力迭代算法来实现这一点

    有一篇文章描述了这种方法

    我将此方法转换为SQL,它返回正确的值(1,0)。您的“平凡”示例实际上有点边缘情况(具有无限斜率的垂直线),因此它看起来很健壮

    我还用这个例子测试了源代码:使用(-1,2)(3,0)行的输入和(2,2)处的一个点得到了正确的答案(1.4,0.8)

    SQL代码(也在SQL FIDLE at中)


    谢谢-我想有更优雅的方式来做这件事。我把小提琴转换成了现实世界中的拉特/拉隆——我一定是在转换过程中弄错了什么(漫漫长夜,需要(很多)更多的咖啡:)。这些值似乎不在线段上。(SQLFiddle只输出1行,但在MgmtStudio中有7行)@meisen99I可能无法在接下来的几个小时内看到这一点;不确定为什么SQLFIDLE只输出一行,我注意到昨晚执行多个SELECT语句时也是如此。就点而言,该算法假设直线是无限的,并且提供的点只是该直线上的两个点。可能需要进行测试,以查看最近的点是否为直线的两个端点之一。你能检查返回的点是否在由你的坐标定义的(无限)线上吗?我用它来表示我的字符串
    declare@LineString GEOMETRY=GEOMETRY::stgeomefromtext('LineString(-74.7 21.8,-75.7 22.1,-77.8 22.6,-79.4 23.3,-80.4 24.5,-81.5 28,-84 33,-87 36)”,4326)
    my将线字符串分成两对(所以-74.7 21.8,-75.7 22.1;然后-75.7 22.1,-77.8 22.6;等等)在你的SQL Fiddler中修复了它。你的深夜和咖啡意味着你在计算“atp_dot_atb”的行中使用了两次“@lat”:set@atp_dot_atb=(@lat-@x1)*(@x2-@x1)+(@lat-@y1)*(@y2-@y1)更新,结果看起来更合理。。。
    DECLARE @x int, @y int, @x1 int, @y1 int, @x2 int, @y2 int 
    DECLARE @atb2 float, @atp_dot_atb float
    DECLARE @t float
    
    --SELECT @x=0, @y=0 
    --SELECT @x1=1, @y1=10, @x2=1, @y2=-10  
    SELECT @x=2, @y=2
    SELECT @x1=-1, @y1=2, @x2=3, @y2=0
    
    SELECT @atb2 = SQUARE(@x2-@x1)  + SQUARE(@y2-@y1)  -- Basically finding the squared magnitude   of a_to_b
    SELECT  @atp_dot_atb = (@x-@x1)*(@x2-@x1) + (@y-@y1)*(@y2-@y1) -- The dot product of a_to_p and a_to_b
    SELECT @t = @atp_dot_atb / @atb2              --  The normalized "distance" from a to  your closest point
    
    SELECT @x1 + (@x2-@x1)*@t, @y1 + (@y2-@y1)*@t  --Add the distance to A, moving towards B