PostGIS में विशिष्ट दूरी पर बिंदुओं के बीच रेखा खींचना?


9

मेरे पास सड़कों के साथ बिंदुओं का एक डेटा है, मैं उन डॉट्स को साधारण रंगीन लाइनों में बदलना चाहूंगा। कोई भी संकेत इस समस्या को क्या कहा जा सकता है या कोई एल्गोरिदम जो मुझे इसे हल करने में मदद कर सकता है? सड़क के किनारे के पॉइंट्स जिन्हें मैं लाइनों में बदलना चाहता हूँ।

मैं ऐसा करने के लिए PostGISफ़ंक्शंस का उपयोग करने की उम्मीद कर रहा था, लेकिन मैं सुझावों के लिए खुला हूं, यह एक .shpफ़ाइल का डेटा है ।

Edit1: इस समस्या के आदर्श समाधान को प्रदर्शित करने के लिए चित्र को अपडेट किया गया।

रेखा खींचना विशुद्ध रूप से उन बिंदुओं के बीच की दूरी पर आधारित होगा, और कुछ नहीं है जिसका उपयोग मैं उनके द्वारा समूह बनाने के लिए कर सकता हूं। आदर्श रूप में यह अनुमानित रेखा के साथ अधिकतम निर्दिष्ट दूरी पर बिंदु होंगे? और अनुमानित रेखा से मेरा मतलब है कि 1 बिंदु को खोजें, उसके बाद अगला निकटतम, फिर एक रेखा को प्रोजेक्ट करें और जांचें कि क्या इस रेखा पर कोई बिंदु हैं जो कि लाइन पर पहले से ही किसी भी व्यक्ति के लिए अधिकतम दूरी पर हैं।


1
आप किस सॉफ्टवेयर का उपयोग करने की योजना बना रहे हैं?
अरोमाएर

क्या आप इन्हें फुटपाथ में बदलने की कोशिश कर रहे हैं?
DPSSpatial

मैं ऐसा करने के लिए PostGIS फ़ंक्शन का उपयोग करने की उम्मीद कर रहा था, लेकिन मैं सुझावों के लिए खुला हूं, यह एक .shp फ़ाइल का एक डेटा है।
महाकाल

1
क्या आप वास्तव में दिखा सकते हैं कि आप अपनी ड्राइंग या किसी अन्य ड्राइंग पर किस बिंदु से जुड़ना चाहते हैं? क्या यह एक समय में केवल दो अंक है? या तीन? क्या उन बिंदुओं के बीच की दूरी जो हमेशा एक ही से जुड़ी होनी चाहिए या यह एक निश्चित सीमा से नीचे "बस" है?
पीटर हॉर्स्बल मोलर

1
@Dbaston और MarHoff दोनों के लिए बड़ा धन्यवाद, मेरे पास अप्रैल के अंत तक आपके विचारों का परीक्षण करने का समय नहीं होगा, मैं चाहता हूं कि मैं बीच में फूट डाल सकता हूं, लेकिन मुझे आपको यह पुरस्कार देना होगा और dbaston ने मुझे कुछ प्रश्न दिए हैं इसलिए मैं उनकी प्रतिक्रिया स्वीकार करूंगा। हर कोई जो जवाब देने के लिए समय लेता था! :-) का हिस्सा बनने के लिए महा समुदाय
महाकाल

जवाबों:


8

आप प्रत्येक बिंदु के निकटतम पड़ोसी का पता लगाने के लिए एक पुनरावर्ती क्वेरी का उपयोग कर सकते हैं जो आपके द्वारा बनाई गई लाइनों के प्रत्येक ज्ञात छोर से शुरू होती है।

पूर्वापेक्षाएँ : अपने बिंदुओं के साथ एक पोस्टगिस लेयर तैयार करें और दूसरा आपके सड़क पर एक एकल मल्टी-लिनस्ट्रिंग ऑब्जेक्ट के साथ। दो परतें एक ही CRS पर होनी चाहिए। यहाँ मेरे द्वारा बनाए गए परीक्षण डेटा-सेट के लिए कोड है, कृपया इसे आवश्यकतानुसार संशोधित करें। (पोस्ट 9.2 और पोस्टगिस 2.1 पर परीक्षण किया गया)

WITH RECURSIVE
points as (SELECT id, st_transform((st_dump(wkb_geometry)).geom,2154) as geom, my_comment as com FROM mypoints),
roads as (SELECT st_transform(ST_union(wkb_geometry),2154) as geom from highway),

यहां छवि विवरण दर्ज करें

यहाँ कदम हैं :

  1. प्रत्येक बिंदु के लिए उत्पन्न करें प्रत्येक पड़ोसी की सूची और उनकी दूरी जो तीन मानदंडों को पूरा करती है।

    • दूरी उपयोगकर्ता परिभाषित सीमा से अधिक नहीं होनी चाहिए (यह अलग-अलग बिंदुओं से जुड़ने से बच जाएगी) यहां छवि विवरण दर्ज करें
      graph_full as (
      SELECT a.id, b.id as link_id, a.com, st_makeline(a.geom,b.geom) as geom, st_distance(a.geom,b.geom) as distance
      FROM points a
      LEFT JOIN points b ON a.id<>b.id
      WHERE st_distance(a.geom,b.geom) <= 15
      ),
      
    • सीधे रास्ते पर सड़क पार नहीं करनी चाहिए यहां छवि विवरण दर्ज करें
      graph as (
      SELECt graph_full.*
      FROM graph_full RIGHT JOIN
      roads ON st_intersects(graph_full.geom,roads.geom) = false
      ),
      
    • दूरी निकटतम पड़ोसी से एक उपयोगकर्ता परिभाषित अनुपात से अधिक नहीं होनी चाहिए (यह तय दूरी से अनियमित डिजिटलाइजेशन के लिए बेहतर समायोजित करना चाहिए) यह हिस्सा वास्तव में लागू करने के लिए बहुत कठिन था, निश्चित खोज त्रिज्या से चिपका हुआ

    चलो इस तालिका को "ग्राफ" कहते हैं

  2. ग्राफ़ में शामिल होकर लाइन पॉइंट के अंत का चयन करें और केवल उस बिंदु को रखें, जिसमें ग्राफ़ में एक प्रविष्टि हो। यहां छवि विवरण दर्ज करें

    eol as (
    SELECT points.* FROM
    points  JOIN
    (SELECT id, count(*) FROM graph 
    GROUP BY id
    HAVING count(*)= 1) sel
    ON points.id = sel.id),
    

    आइए इस तालिका को "ईओएल" (लाइन का अंत)
    आसान कहते हैं? यह एक शानदार ग्राफ बनाने के लिए इनाम है, लेकिन अगले कदम पर चीजें पागल हो जाएंगी

  3. एक पुनरावर्ती क्वेरी सेट करें जो प्रत्येक ईओल से शुरू होने वाले पड़ोसियों से पड़ोसियों तक साइकिल चलाएगी यहां छवि विवरण दर्ज करें

    • ईओल तालिका का उपयोग करके पुनरावर्ती क्वेरी की शुरुआत करें और गहराई के लिए एक काउंटर जोड़कर, मार्ग के लिए एक एग्रीगेटर और लाइनों के निर्माण के लिए एक ज्यामिति निर्माता
    • ग्राफ़ का उपयोग करके निकटतम पड़ोसी पर स्विच करके अगले पुनरावृत्ति पर जाएं और जांचें कि आप पथ का उपयोग करके कभी भी पीछे नहीं जाते हैं
    • पुनरावृत्ति समाप्त होने के बाद प्रत्येक प्रारंभिक बिंदु के लिए केवल सबसे लंबा रास्ता रखें (यदि आपके डेटासेट में संभावित लाइनों के बीच संभावित प्रतिच्छेदन शामिल है जो उस हिस्से को अधिक परिस्थितियों की आवश्यकता होगी)
    recurse_eol (id, link_id, depth, path, start_id, geom) AS (--initialisation
    SELECT id, link_id, depth, path, start_id, geom FROM (
        SELECT eol.id, graph.link_id,1 as depth,
        ARRAY[eol.id, graph.link_id] as path,
        eol.id as start_id,
        graph.geom as geom,
        (row_number() OVER (PARTITION BY eol.id ORDER BY distance asc))=1 as test
        FROM eol JOIn graph ON eol.id = graph.id 
        ) foo
    WHERE test = true
    
    UNION ALL ---here start the recursive part
    
    SELECT id, link_id, depth, path, start_id, geom  FROM (
        SELECT graph.id, graph.link_id, r.depth+1 as depth,
        path || graph.link_id as path,
        r.start_id,
        ST_union(r.geom,graph.geom) as geom,
        (row_number() OVER (PARTITION BY r.id ORDER BY distance asc))=1 as test
        FROM recurse_eol r JOIN graph ON r.link_id = graph.id AND NOT graph.link_id = ANY(path)) foo
    WHERE test = true AND depth < 1000), --this last line is a safe guard to stop recurring after 1000 run adapt it as needed
    

    चलो इस तालिका को "recurse_eol" कहते हैं

  4. प्रत्येक प्रारंभ बिंदु के लिए केवल सबसे लंबी लाइन रखें और हर सटीक डुप्लिकेट पथ को हटा दें उदाहरण: पथ 1,2,3,5 और 5,3,2,1 एक ही रेखा है जिसे दो लाइन "लाइन के अंत" द्वारा खोजा गया है।

    result as (SELECT start_id, path, depth, geom FROM
    (SELECT *,
    row_number() OVER (PARTITION BY array(SELECT * FROM unnest(path) ORDER BY 1))=1 as test_duplicate,
    (max(depth) OVER (PARTITION BY start_id))=depth as test_depth
    FROM recurse_eol) foo
    WHERE  test_depth = true AND test_duplicate = true)
    
    SELECT * FROM result
  5. शेष त्रुटियों (अलग-अलग बिंदुओं, अतिव्यापी लाइनों, अजीब आकार की सड़क) को मैन्युअल रूप से जांचता है


जैसा कि वादा किया गया था, मुझे अभी भी यह पता नहीं चल सका है कि कभी-कभी एक ही पंक्ति के विपरीत ईओएल से शुरू करते समय पुनरावर्ती क्वेरी सटीक परिणाम क्यों नहीं देती है, इसलिए कुछ डुप्लिकेट अब परिणाम परत में बने रह सकते हैं।

बेझिझक पूछें मुझे पूरी तरह से लगता है कि इस कोड को अधिक टिप्पणियों की आवश्यकता है। यहाँ पूरी क्वेरी है:

WITH RECURSIVE
points as (SELECT id, st_transform((st_dump(wkb_geometry)).geom,2154) as geom, my_comment as com FROM mypoints),
roads as (SELECT st_transform(ST_union(wkb_geometry),2154) as geom from highway),

graph_full as (
    SELECT a.id, b.id as link_id, a.com, st_makeline(a.geom,b.geom) as geom, st_distance(a.geom,b.geom) as distance
    FROM points a
    LEFT JOIN points b ON a.id<>b.id
    WHERE st_distance(a.geom,b.geom) <= 15
    ),

graph as (
    SELECt graph_full.*
    FROM graph_full RIGHT JOIN
    roads ON st_intersects(graph_full.geom,roads.geom) = false
    ),

eol as (
    SELECT points.* FROM
    points  JOIN
        (SELECT id, count(*) FROM graph 
        GROUP BY id
        HAVING count(*)= 1) sel
    ON points.id = sel.id),


recurse_eol (id, link_id, depth, path, start_id, geom) AS (
    SELECT id, link_id, depth, path, start_id, geom FROM (
        SELECT eol.id, graph.link_id,1 as depth,
        ARRAY[eol.id, graph.link_id] as path,
        eol.id as start_id,
        graph.geom as geom,
        (row_number() OVER (PARTITION BY eol.id ORDER BY distance asc))=1 as test
        FROM eol JOIn graph ON eol.id = graph.id 
        ) foo
    WHERE test = true

UNION ALL
    SELECT id, link_id, depth, path, start_id, geom  FROM (
        SELECT graph.id, graph.link_id, r.depth+1 as depth,
        path || graph.link_id as path,
        r.start_id,
        ST_union(r.geom,graph.geom) as geom,
        (row_number() OVER (PARTITION BY r.id ORDER BY distance asc))=1 as test
        FROM recurse_eol r JOIN graph ON r.link_id = graph.id AND NOT graph.link_id = ANY(path)) foo
    WHERE test = true AND depth < 1000),

result as (SELECT start_id, path, depth, geom FROM
    (SELECT *,
    row_number() OVER (PARTITION BY array(SELECT * FROM unnest(path) ORDER BY 1))=1 as test_duplicate,
    (max(depth) OVER (PARTITION BY start_id))=depth as test_depth
    FROM recurse_eol) foo
WHERE  test_depth = true AND test_duplicate = true)

SELECT * FROM result


हाय @ मर्फोफ़, आपके उत्तर के लिए धन्यवाद, मेरे पास जाने के लिए कुछ है। मैं एक पूर्ण समाधान की उम्मीद नहीं कर रहा था, बस एक बिंदु जहां जवाब देखने के लिए। मैं इसे और समझना चाहता हूं और मैं खुदाई करता रहूंगा और संभवत: बाद में और भी सवाल करूंगा। मुझे आपके एल्गोरिथ्म को समझने की आवश्यकता है और इससे मुझे कुछ समय लगेगा :)
महाकाल

वर्किंग स्क्रिप्ट मिली, प्रीव्यू यहाँ qgiscloud.com/MarHoff/test_qgiscloud_bis डी-डुप्लीकेशन के लिए एक छोटा सा कैविएट बना रहे ... कोई और अधिक इनाम, कोई और अधिक दबाव मुझे नहीं लगता, इसलिए मैं जब भी रिलीज करूंगा। यह पहेली हालांकि मज़ेदार थी
मारफॉफ़

धन्यवाद @MarHoff, अगर मैं कर सकता तो मैं इस इनाम को विभाजित कर सकता था मैं यह नहीं देख सकता कि मैं आपको किसी भी अंक के साथ कैसे पुरस्कार दे सकता हूं, लेकिन इस और आपके प्रमाण को देखने के लिए बड़ा धन्यवाद। वास्तविक लगता है :)
महाकाल

किया हुआ। पहेली के लिए धन्यवाद, और शेख़ी के लिए खेद है। यदि अन्य उत्तर ने आपके लिए किया है तो यह पूरी तरह से ठीक है कुछ समय सबसे अच्छा है ... मेरा उत्तर शायद थोड़ा सा इसे उखाड़ फेंकने वाला था। हालांकि CTE + पुनरावर्ती क्वेरी + Windows फ़ंक्शन + एक ही क्वेरी पर
पोस्टगिस

8

जैसा कि @FelixIP बताता है, पहला चरण उन बिंदुओं को खोजना है जो प्रत्येक पंक्ति को बनाएंगे। आप इसे अपनी अधिकतम पृथक्करण दूरी के साथ ST_ClusterWithin पर कॉल करके कर सकते हैं :

SELECT
  row_number() OVER () AS cid, 
  (ST_Dump(geom)).geom 
FROM (
  SELECT unnest(st_clusterwithin(geom, 0.05)) AS geom 
  FROM inputs) sq

फिर, आपको प्रत्येक क्लस्टर में सभी बिंदुओं के माध्यम से एक लाइन बनाने के लिए कुछ अनुमानी का उपयोग करने की आवश्यकता होगी। उदाहरण के लिए, यदि आप वांछित लाइनों को वाई-मोनोटोन मान सकते हैं, तो आप प्रत्येक क्लस्टर में अंक सॉर्ट कर सकते हैं और उन्हें ST_MakeLine में फीड कर सकते हैं । सभी को एक साथ मिलाकर देखना इस तरह होगा:

SELECT 
  ST_MakeLine(geom ORDER BY ST_Y(geom)) AS geom
FROM (
  SELECT row_number() OVER () AS cid, 
  (ST_Dump(geom)).geom FROM (
    SELECT unnest(st_clusterwithin(geom, 0.05)) AS geom 
    FROM inputs) sq) ssq 
GROUP BY cid

जाने के लिए रास्ता लेकिन Y- मोनोटोन (या यहां तक ​​कि एक्स / वाई-मोनोटोन के बीच भी स्विच) दृष्टिकोण न तो अच्छी तरह से काम करेगा अगर डेटा-सेट में घुमावदार सड़क होती है। क्या यह मामला है? आदेश एल्गोरिथ्म इस सवाल का सबसे कठिन हिस्सा है IMHO।
मार्फॉ

@ मार्फ: हाँ घुमावदार सड़कें एक मुद्दा होगी, लेकिन मैं कोशिश कर रहा हूं कि अधिकांश डेटा स्वचालित रूप से रूपांतरित हो जाएं और बाकी को मैन्युअल रूप से करने की आवश्यकता होगी। या मैं समाधान निकालने के लिए और अधिक विषय में खुदाई करता रहूंगा लेकिन शेष डेटा को ठीक करने में किसी को प्राप्त करने में अधिक समय लग सकता है। मुझे निर्णय लेने में सक्षम होने के लिए परिणामों का मूल्यांकन करने की आवश्यकता होगी। यह इंगित करने के लिए Thx!
महाकाल Ma

स्टैच्यूड ने सोचा कि मुझे सिर्फ एक ट्रिक के बारे में सोचा गया है ...
MarHoff

क्या ऐसा करने का कोई मजबूत तरीका है, जिसमें अंकों के सभी संभावित क्रमों की कोशिश करना शामिल नहीं है, और यह पता लगाना कि सबसे कम लंबाई कौन देता है?
dbaston

यदि अंकों के ये सेट हमेशा सड़कों का अनुसरण करते हैं, तो आप सड़क खंड (ST_Line_Locate_Point) पर बिंदु की स्थिति को प्रोजेक्ट करते हैं, फिर परिणाम द्वारा अंक का आदेश दें।
ट्रैविस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.