Ngoại suy một dòng trong PostGIS


19

Tôi đang cố gắng ngoại suy từ một đoạn thẳng để tìm một điểm trên đường nhưng cách thứ 3 'trở lại', tức là cố gắng tìm điểm new, cho điểm ABbên dưới:

nhập mô tả hình ảnh ở đây

Đưa ra một dòng, tôi có thể nội suy nó để có được một vị trí ở bất kỳ tỷ lệ phần trăm cụ thể nào dọc theo nó:

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

Tôi đã thử nhập một số âm để tìm một điểm dọc theo đường ngược lại, nhưng điều đó không thành công vì đối số nội suy phải nằm trong phạm vi [0, 1]

Tôi đã nghĩ về việc mở rộng dòng đầu tiên, nhưng điều đó không sử dụng trung tâm của dòng làm gốc, vì vậy nó vô dụng cho mục đích của tôi.

Câu trả lời:


21

Một cách khác tôi đã giải quyết một vấn đề tương tự trước đây là chia nó thành các bước sau.

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

EDIT: đã sửa lỗi gán newlength sao cho nó dài bằng 1 1/3, thay vì 1/3 và chuyển A & B xung quanh để khớp với sơ đồ.


Chúng ta có một người chiến thắng! Dễ hiểu hơn nhiều.
EoghanM

Điều này khá tuyệt
Nathan W

Cảm ơn. Ban đầu tôi có đoạn trích này từ một số công việc tôi đang thực hiện nội suy thủ công giữa các đường đồng mức - hóa ra thật lãng phí thời gian những gì tôi đang cố gắng thực hiện với các đường viền, nhưng rất vui vì đoạn trích này đã giúp người khác thoát ra! :)
Jayden

6

Đã giải quyết nó với:

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

Giải trình:

(2-d) Chia tỷ lệ điểm bắt đầu theo hệ số 1,3333, lấy điểm giữa của đoạn đường làm gốc cho tỷ lệ.

Lấy giấy ra đồ thị!

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


2

Tôi đã viết một chức năng cho việc này:

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;

Sử dụng:

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

Lưu ý rằng điều này mang lại linestring dài hơn nhưng không phải là điểm cuối.

Mã trên GitHub Gist (nếu bạn upvote ở đây tôi cũng sẽ đánh giá cao một ngôi sao ở đó)

Mô tả các tham số (trong trường hợp bạn bỏ lỡ chúng trong nhận xét của hàm sql):

  • Độ dài đoạn đầu tiên sẽ là gốc_length * head_rate + head_constant.
  • Nếu bạn muốn nó được nhân đôi thì tỷ lệ đầu là 2, hằng số là 0.
  • Chúng tôi trong hungary thường sử dụng phép chiếu EOV dựa trên mét. Vì vậy, nếu tôi muốn thêm 2 mét vào cuối dòng, tôi đặt đuôi: tỷ lệ thành 1 và tail_constant thành 2.

Điều này hoạt động rất tốt. Bạn có thể thêm một số thông tin về head_rate, head_constant, tail_rate và tail_constant không? Họ không giải thích ở đây hoặc trên GitHub của bạn. Tôi giả định rằng tỷ lệ đầu = hệ số tỷ lệ cho mở rộng dòng sau điểm cuối và tỷ lệ đuôi = hệ số tỷ lệ cho mở rộng dòng trước điểm bắt đầu. Làm thế nào để hằng số làm việc? Họ có ảnh hưởng gì?
jbalk

Nó trong bình luận. Chiều dài phân khúc đầu tiên sẽ được original_length * head_rate + head_constant. Nếu bạn muốn nó tăng gấp đôi thì tỷ lệ đầu là 2, hằng số là 0. Chúng ta thường sử dụng phép chiếu EOV dựa trên mét. Vì vậy, nếu tôi muốn thêm 2 mét vào cuối dòng, tôi đặt đuôi: tỷ lệ thành 1 và đuôi_constant thành 2.
SzieberthAdam

Cảm ơn bạn! Và cảm ơn bạn đã chia sẻ chức năng này. Nó hoạt động hoàn hảo và nó chạy nhanh.
jbalk
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.