PostGIS에서 라인 외삽 보간 할 수 있습니다. =# select

선 세그먼트에서 외삽하여 선의 점을 찾으려고하지만 ‘뒤로’의 3 번째 방법, 즉 newAB아래에서 점 을 찾으려고 합니다.

여기에 이미지 설명을 입력하십시오

선이 주어지면 특정 비율에서 위치를 얻도록 보간 할 수 있습니다.

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

반대 방향으로 선을 따라 점을 찾으려면 음수를 입력하려고했지만 보간 인수가 [0, 1] 범위에 있어야하기 때문에 실패합니다.

먼저 선의 크기를 조정하는 것에 대해 생각했지만 선의 중심을 원점으로 사용하지 않으므로 내 목적으로는 쓸모가 없습니다.



답변

이전에 비슷한 문제를 해결 한 다른 방법은 다음 단계로 구분하는 것입니다.

-- 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);

편집 : 길이가 1/3이 아닌 1/3 길이가되도록 newlength 할당을 수정하고 다이어그램과 일치하도록 A & B를 전환했습니다.


답변

그것을 해결했다 :

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


답변

나는 이것을 위해 함수를 썼다 :

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로 설정하십시오.