【问题标题】:Draw perpendicular line between two line strings in SQL Server在 SQL Server 中的两个线串之间绘制垂直线
【发布时间】:2021-10-22 19:14:55
【问题描述】:

我在 SQL Server 中有 2 行字符串。

declare @s geometry  = geometry::STGeomFromText
    (
        'LINESTRING('
        +     convert(varchar(max),35.688889,128) +' '+ convert(varchar(max),51.314722,128) -- 
        +', '+convert(varchar(max),32.750833,128) +' '+ convert(varchar(max),51.862778,128)+')',0 -- 
    );

declare @d geometry  = geometry::STGeomFromText
    (
        'LINESTRING('
        +     convert(varchar(max),34.761111,128) +' '+ convert(varchar(max),52.144444,128)
        +', '+convert(varchar(max),33.56,128) +' '+ convert(varchar(max),53.4475,128)+')',0
    );

如何从@s 的中间用90-degree angle@d 在它们之间画一条线?

我有这个代码:

DECLARE @result geometry = @s.STEnvelope().STCentroid().ShortestLineTo(@d).ToString();

但是这段代码只是找到不垂直的最短线!

【问题讨论】:

  • i.stack.imgur.com/KILjO.png,p垂直于d;你想让 p 垂直于 s 吗?
  • @RazvanSocol ,只有当 d 的长度足以与 s 相交时,p 才垂直于 d。如果 D 很短,那么您可能会得到一条不垂直于 d 的线,因为ShortestLineTo 找到与 d 和 s 相交的较短线......这是一个非常有趣的问题,乍一看我假设一些数学会需要,我们将无法仅依靠内置方法。
  • @RonenAriely:你是对的,它并不总是垂直的。
  • 我更改了行的输入,以明确使用 ShortestLineTo 方法不能解决这种情况,我已经找到了解决方案,但现在需要时间将其上传为博客。这是以前效果不佳的解决方案的图像和我的解决方案。 ibb.co/qsXfy9B

标签: sql sql-server tsql spatial


【解决方案1】:

画一条延伸的垂直线(到@s),它从@s的中点穿过并在可能的情况下穿过@d(延伸的线覆盖两条线@s&@的所有点的minX,maxX平面d [or minY, maxY if @s 是水平的])

declare @s geometry = geometry::STGeomFromText ( 'LINESTRING(' + convert(varchar(max),35.688889,128) +' '+ convert(varchar(max),51.314722,128) +', '+convert(varchar(max),32.750833,128) +' '+ convert(varchar(max),51.862778,128)+')',0)

declare @d geometry = geometry::STGeomFromText ( 'LINESTRING(' + convert(varchar(max),34.761111,128) +' '+ convert(varchar(max),52.144444,128) +', '+convert(varchar(max),33.56,128) +' '+ convert(varchar(max),53.4475,128)+')',0 )

--horizontal @s
--select @s = geometry::STGeomFromText ( 'LINESTRING(' + convert(varchar(max),35.688889,128) +' '+ convert(varchar(max),51.314722,128) +', '+convert(varchar(max),32.750833,128) +' '+ convert(varchar(max),51.314722,128)+')',0)
 
declare @extperpendicular geometry;

select @extperpendicular = geometry::STGeomFromText 
(
    concat('LINESTRING(',
    --start point of extended perpendicular to @s
    convert(varchar(100), case when pm is null then smidX else minX end, 2), ' ', convert(varchar(100), case when pm is null then minY else pm*minX + pc end, 2), 
    ',', 
    --end point of extended perpendicular to @s
    convert(varchar(100), case when pm is null then smidX else maxX end, 2), ' ', convert(varchar(100), case when pm is null then maxY else pm*maxX + pc end, 2), 
    ')')
, 0)

from
(
select
   p.*, 
   --middle point of @s is on perpendicular to @s --> smidY=pm*smidX+pc
   smidY-(pm*smidX) as pc,
   gbx.*,
   gby.*
from
(
    select *, -(sX2-sX1)/nullif(sY2-sY1, 0) as pm --slope of perpendicular to @s
    from
    (
    select  
      --mid point of @s
      @s.STEnvelope().STCentroid().STX as smidX, @s.STEnvelope().STCentroid().STY as smidY,
      --start point of @s
      @s.STStartPoint().STX as sX1, @s.STStartPoint().STY as sY1, 
      --end point of @s
      @s.STEndPoint().STX as sX2, @s.STEndPoint().STY as sY2
    ) as s
) as p
--boundaries of plane
--X
cross apply
(
    select min(h.x) as minX, max(h.x) as maxX
    from (values(@s.STStartPoint().STX),(@s.STEndPoint().STX),(@d.STStartPoint().STX),(@d.STEndPoint().STX)) as h(x)
) as gbx 
--Y. when @s is horizontal
cross apply
(
    select min(v.y) as minY, max(v.y) as maxY
    from (values(@s.STStartPoint().STY),(@s.STEndPoint().STY),(@d.STStartPoint().STY),(@d.STEndPoint().STY)) as v(y)
) as gby 
) as allpoints;

select * from (values(@s),(@d),(@extperpendicular)) as thelines(line);

--line between @s & @d
select @extperpendicular.STIntersection(@s).ToString() as startpoint, @extperpendicular.STIntersection(@d).ToString() as endpoint;

【讨论】: