การประมาณบรรทัดใน PostGIS


19

ฉันพยายามที่จะคาดการณ์จากส่วนของเส้นเพื่อหาจุดบนบรรทัด แต่หนึ่งในสามของ 'ย้อนกลับ' คือพยายามค้นหาจุดจุดที่newกำหนดAและBด้านล่าง:

ป้อนคำอธิบายรูปภาพที่นี่

รับบรรทัดฉันสามารถแก้ไขเพื่อให้ได้ตำแหน่งที่เปอร์เซ็นต์ใด ๆ ตาม:

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

ฉันพยายามป้อนจำนวนลบเพื่อหาจุดตามเส้นในทิศทางตรงกันข้าม แต่นั่นล้มเหลวเนื่องจากอาร์กิวเมนต์การแก้ไขต้องอยู่ในช่วง [0, 1]

ฉันคิดเกี่ยวกับการปรับขนาดบรรทัดแรก แต่ไม่ได้ใช้จุดศูนย์กลางของเส้นเป็นจุดเริ่มต้นดังนั้นจึงไม่มีประโยชน์สำหรับจุดประสงค์ของฉัน

คำตอบ:


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

แก้ไข: แก้ไขการกำหนดความยาวใหม่เพื่อให้มีความยาว 1 1/3 แทนที่จะเป็น 1/3 และสลับ A & B ไปรอบ ๆ เพื่อจับคู่แผนภาพ


เรามีผู้ชนะ! เข้าใจได้มากกว่า
EoghanM

นี่คือเย็นสวย
นาธาน W

ขอบคุณ ตอนแรกฉันมีตัวอย่างนี้จากงานบางอย่างที่ฉันกำลังทำการแก้ไขด้วยตนเองระหว่างเส้นชั้นความสูง - กลับกลายเป็นว่ามันเสียเวลาสิ่งที่ฉันพยายามทำกับรูปทรง แต่ดีใจที่ตัวอย่างนี้ช่วยคนอื่น! :)
Jayden

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 สรุปสาระสำคัญ (ถ้าคุณ upvote ที่นี่ฉันจะขอบคุณดาวที่นั่นด้วย)

คำอธิบายของพารามิเตอร์ (ในกรณีที่คุณพลาดในความคิดเห็นของฟังก์ชัน sql):

  • ความยาวส่วนแรกจะเป็นแบบดั้งเดิม _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
SzieberthAdam

ขอขอบคุณ! และขอขอบคุณสำหรับการแบ่งปันฟังก์ชั่นนี้ มันทำงานได้อย่างสมบูรณ์และทำงานได้อย่างรวดเร็ว
jbalk
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.