在PostGIS中外推直线


19

我正在尝试从线段中推断出线上的一个点,但是是“返回”方式的第三点new,即试图找到point ,给定的点AB下面的点:

在此处输入图片说明

给定一条线,我可以对其进行插值以获得沿其任何特定百分比的头寸:

=# select st_line_interpolate_point(
   st_makeline('0101000020E6100000300DC347C49418C03EE8D9ACFAA44A40', 
               '0101000020E6100000FB743C66A03218C0CDCCCCCCCC7C4A40'), 
   0.333);
0101000020E6100000ED45B41D537718C069C6A2E9EC984A40

我尝试输入一个负数沿线的相反方向找到一个点,但这失败了,因为插值参数必须在[0,1]范围内

我考虑过先缩放线条,但那并不使用线条的中心作为原点,因此对我而言毫无用处。

Answers:


21

我以前解决过类似问题的另一种方法是将其分解为以下步骤。

-- get the points A and B given a line L
A := ST_STARTPOINT(L);
B := ST_ENDPOINT(L);

-- get the bearing from point B --> A
azimuth := ST_AZIMUTH(B,A);

-- get the length of the line A --> B
length := ST_DISTANCE(A,B);
newlength := length + (length * (1/3));   -- increase the line length by 1/3

-- create a new point 1/3 as far away from A as B is from A
newpoint := ST_TRANSLATE(A, sin(azimuth) * newlength, cos(azimuth) * newlength);

编辑:固定newlength的分配,使其为长度的1 1/3,而不是1/3,并在A和B周围切换以匹配图。


我们有赢家!更容易理解。
EoghanM 2012年

这非常酷
Nathan W

谢谢。我最初是通过手动在轮廓线之间进行插补的一些工作获得此片段的-事实证明,我试图对轮廓进行操作很浪费时间,但是很高兴这个片段帮助了其他人!:)
杰登(Jayden)2012年

6

用以下方法解决了它:

F = 1.3333
st_affine(A, F, 0, 
             0, F, 
            (F-1)*-st_x(st_line_interpolate_point(st_makeline(A, B), 0.5)), 
            (F-1)*-st_y(st_line_interpolate_point(st_makeline(A, B), 0.5))
          )

说明:

(2-d)以线段的中点作为缩放起点,将起点缩放1.3333。

拿出方格纸!

http://en.wikipedia.org/wiki/Affine_transformation


2

我为此编写了一个函数:

CREATE OR REPLACE FUNCTION st_extend (
    geom geometry,
    head_rate double precision,
    head_constant double precision,
    tail_rate double precision,
    tail_constant double precision)
  RETURNS geometry AS
$BODY$
-- Extends a linestring.
-- First segment get extended by length * head_rate + head_constant.
-- Last segment get extended by length * tail_rate + tail_constant.
--
-- References:
-- http://blog.cleverelephant.ca/2015/02/breaking-linestring-into-segments.html
-- /gis//a/104451/44921
-- /gis//a/16701/44921
WITH segment_parts AS (
SELECT
(pt).path[1]-1 as segment_num
,
CASE
WHEN
  (nth_value((pt).path, 2) OVER ()) = (pt).path
AND
  (last_value((pt).path) OVER ()) = (pt).path
THEN
  3
WHEN
  (nth_value((pt).path, 2) OVER ()) = (pt).path
THEN
  1
WHEN
  (last_value((pt).path) OVER ()) = (pt).path
THEN
  2
ELSE
  0
END AS segment_flag
,
(pt).geom AS a
,
lag((pt).geom, 1, NULL) OVER () AS b
FROM ST_DumpPoints($1) pt
)
,
extended_segment_parts
AS
(
SELECT
  *
  ,
  ST_Azimuth(a,b) AS az1
  ,
  ST_Azimuth(b,a) AS az2
  ,
  ST_Distance(a,b) AS len
FROM
segment_parts
where b IS NOT NULL
)
,
expanded_segment_parts
AS
(
SELECT
  segment_num
  ,
  CASE
  WHEN
    bool(segment_flag & 2)
  THEN
    ST_Translate(b, sin(az2) * (len*tail_rate+tail_constant), cos(az2) * (len*tail_rate+tail_constant))
  ELSE
    a
  END
  AS a
  ,
  CASE
  WHEN
    bool(segment_flag & 1)
  THEN
    ST_Translate(a, sin(az1) * (len*head_rate+head_constant), cos(az1) * (len*head_rate+head_constant))
  ELSE
    b
  END
  AS b
FROM extended_segment_parts
)
,
expanded_segment_lines
AS
(
SELECT
  segment_num
  ,
  ST_MakeLine(a, b) as geom
FROM
expanded_segment_parts
)
SELECT
  ST_LineMerge(ST_Collect(geom ORDER BY segment_num)) AS geom
FROM expanded_segment_lines
;
$BODY$
LANGUAGE sql;

用法:

SELECT st_extend(
st_makeline(
  '0101000020E6100000300DC347C49418C03EE8D9ACFAA44A40', 
  '0101000020E6100000FB743C66A03218C0CDCCCCCCCC7C4A40'
),
1.333::double precision,
0::double precision,
1::double precision,
0::double precision
);

请注意,这会产生更长的线串,但不会产生端点。

GitHub Gist上的代码(如果您在这里投票,我也很感谢在那里的一颗星)

参数说明(如果您在sql函数的注释中错过了它们):

  • 第一段长度将为original_length * head_rate + head_constant。
  • 如果您希望它加倍,那么人头率是2,常数是0。
  • 在匈牙利,我们通常使用基于米的EOV投影。因此,如果要在行尾添加2米,我将tail:rate设置为1,将tail_constant设置为2。

这很好。您可以添加一些有关head_rate,head_constant,tail_rate和tail_constant的信息吗?在这里或您的GitHub上都没有说明。我假设头率=端点之后的线扩展比例因子,尾角=起点之前的线扩展比例因子。常数如何工作?它们有什么作用?
jbalk

它在评论中。第一段的长度为original_length * head_rate + head_constant。如果您希望它翻倍,则人头率是2,常数是0。在匈牙利,我们通常使用基于米的EOV投影。因此,如果我想在行尾添加2米,我将tail:rate设置为1,将tail_constant设置为
2。– SzieberthAdam19

谢谢!并感谢您分享此功能。它运行完美,运行迅速。
jbalk
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.