PostGIS में एक रेखा को निकालना


19

मैं लाइन पर एक बिंदु खोजने के लिए एक लाइन खंड से एक्सट्रपलेशन करने की कोशिश कर रहा हूं, लेकिन रास्ते का एक 3 'वापस', यानी बिंदु 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);

EDIT: नेवलग्रेशन का कार्य नियत किया ताकि यह 1/3 के बजाय 1 1/3 लंबाई हो, और आरेख को मिलान करने के लिए A & B को चारों ओर घुमाया।


हमें विजेता मिल गया! बहुत अधिक समझ में आता है।
EoghanM

यह बहुत अच्छा है
नाथन डब्ल्यू

धन्यवाद। मुझे मूल रूप से कुछ काम से यह स्निपेट मिला था, जो मैं समोच्च लाइनों के बीच मैन्युअल रूप से प्रक्षेपित कर रहा था - यह पता चला कि यह समय की बर्बादी थी जो मैं आकृति के साथ करने की कोशिश कर रहा था, लेकिन खुशी है कि इस स्निपेट ने किसी और की मदद की! :)
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 Gist पर कोड (यदि आप यहां तक ​​बढ़ाएंगे तो मैं वहां भी एक स्टार की सराहना करूंगा)

मापदंडों का विवरण (यदि आप sql फ़ंक्शन की टिप्पणी में उनसे चूक गए हैं):

  • पहले सेगमेंट की लंबाई ओरिजनल_लिफ्ट * हेड_रेट + हेड_ कॉन्स्टेंट होगी।
  • यदि आप चाहते हैं कि यह दोगुना हो जाए तो सिर की दर 2 है, स्थिर 0 है।
  • हम भूख में सामान्य रूप से ईओवी प्रक्षेपण का उपयोग करते हैं जो मीटर आधारित है। इसलिए अगर मैं लाइन के अंत में 2 मीटर जोड़ना चाहता हूं, तो मैं पूंछ को निर्धारित करता हूं: 1 को दर और 2 को tail_constant।

यह बहुत अच्छा काम करता है। क्या आप head_rate, head_constant, tail_rate, और tail_constant के बारे में कुछ जानकारी जोड़ सकते हैं? उन्हें यहाँ या आपके GitHub पर नहीं समझाया गया है। मैं मान रहा हूं कि समापन बिंदु के बाद लाइन विस्तार के लिए हेड रेट = स्केल फैक्टर और स्टार्टप से पहले लाइन एक्सटेंशन के लिए स्केल रेट = स्केल फैक्टर। स्थिरांक कैसे काम करते हैं? उनका क्या प्रभाव है?
jbalk

टिप्पणी में इसकी। प्रथम खंड की लंबाई हो जाएगा original_length * head_rate + head_constant। यदि आप चाहते हैं कि यह दोगुना हो जाए तो सिर की दर 2 है, स्थिर है 0. हम भूख में सामान्य रूप से ईओवी प्रक्षेपण का उपयोग करते हैं जो मीटर आधारित है। इसलिए अगर मैं लाइन के अंत में 2 मीटर जोड़ना चाहता हूं, तो मैं पूंछ सेट करता हूं: 1 को दर और 2 को tail_constant
SzieberthAdam

धन्यवाद! और इस फंक्शन को शेयर करने के लिए धन्यवाद। यह पूरी तरह से काम करता है और यह जल्दी से चलता है।
jbalk
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.