शालीनता से उपयोग करते हुए पॉइंट के पास निकटतम रेखा खंड ढूँढना?


17

पृष्ठभूमि

एक ज्ञात बिंदु से, मुझे मल्टीलाइन स्ट्रेस की तालिका के खिलाफ निकटतम "दृश्य परिधि" स्थापित करने की आवश्यकता है, जैसा कि आरेख पर दिखाया गया है।

मैंने इस साइट को कई शब्दों (जैसे न्यूनतम बढ़त, न्यूनतम परिधि, निकटतम पड़ोसी, क्लिप, बहुभुज, दृश्यता, स्नैप, कट नोड्स, रे-ट्रेस, बाढ़ भरण, आंतरिक सीमा, मार्ग, अवतल पतवार) के साथ खोजा है लेकिन कोई भी पिछला प्रश्न नहीं मिल सकता है जो इस परिदृश्य से मेल खाता हो।

आरेख

  • हरा वृत्त ज्ञात बिंदु है।
  • काली रेखाएँ मल्टीलाइन स्ट्रीम्स हैं।
  • ग्रे लाइनें ज्ञात बिंदु से एक रेडियल स्वीप का संकेत हैं।
  • रेड पॉइंट रेडियल स्वीप और मल्टीलाइनस्ट्रेस के निकटतम चौराहे हैं।

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

पैरामीटर

  • प्वाइंट कभी मल्टीलाइनस्ट्रेस को इंटरसेक्ट नहीं करेगा।
  • प्वाइंट हमेशा मल्टीलाइनस्ट्रीम के भीतर नाममात्र केंद्रित होगा।
  • मल्टीलाइनस्ट्रेस कभी भी पॉइंट को पूरी तरह से नहीं घेरता है, इसलिए परिधि एक मल्टीलाइनरिंग होगी।
  • इसमें लगभग 1,000 मल्टीलाइनस्ट्रेस (आमतौर पर लगभग 100 बिंदुओं की एक पंक्ति वाली) वाली तालिका होगी।

कार्यप्रणाली पर विचार किया

  • ज्ञात बिंदु से लाइनों की एक श्रृंखला का निर्माण करके एक रेडियल स्वीप को अंडरटेक करें (पर, कहते हैं, 1 डिग्री वेतन वृद्धि)।
  • मल्टीलाइन स्ट्रिंग्स के साथ प्रत्येक रेडियल स्वीप लाइन के निकटतम चौराहे बिंदु को स्थापित करें।
  • जब रेडियल स्वीप लाइनों में से कोई भी मल्टीलाइनस्ट्रेस के साथ इंटरसेक्ट नहीं होता है, तो यह परिधि में एक अंतर को दर्शाता है जिसे परिधि मल्टीलाइन स्ट्रेन निर्माण में समायोजित किया जाएगा।

सारांश

जब भी यह तकनीक निकटतम चौराहों को खोजेगी, यह आवश्यक रूप से रेडियल स्वीप के संकल्प पर निर्भर सभी निकटतम परिधि नोड बिंदुओं को नहीं पाएगा। क्या सभी परिधि बिंदुओं को स्थापित करने के लिए कोई वैकल्पिक विधि सुझा सकता है या किसी प्रकार की बफरिंग, सेक्टरिंग या ऑफसेटिंग के साथ रेडियल स्वीप तकनीक को पूरक कर सकता है?

सॉफ्टवेयर

मेरी प्राथमिकता समाधान के लिए स्पैटियालाइट और / या शेपली का उपयोग करना है लेकिन किसी भी सुझाव का स्वागत करना होगा जिसे ओपन सोर्स सॉफ़्टवेयर का उपयोग करके लागू किया जा सकता है।

संपादित करें: वर्किंग सॉल्यूशन (@gene द्वारा उत्तर पर आधारित)

from shapely.geometry import Point, LineString, mapping, shape
from shapely.ops import cascaded_union
from shapely import affinity
import fiona

sweep_res = 10  # sweep resolution (degrees)
focal_pt = Point(0, 0)  # radial sweep centre point
sweep_radius = 100.0  # sweep radius

# create the radial sweep lines
line = LineString([(focal_pt.x,focal_pt.y), \
                   (focal_pt.x, focal_pt.y + sweep_radius)])

sweep_lines = [affinity.rotate(line, i, (focal_pt.x, focal_pt.y)) \
               for i in range(0, 360, sweep_res)]

radial_sweep = cascaded_union(sweep_lines)

# load the input lines and combine them into one geometry
input_lines = fiona.open("input_lines.shp")
input_shapes = [shape(f['geometry']) for f in input_lines]
all_input_lines = cascaded_union(input_shapes)

perimeter = []
# traverse each radial sweep line and check for intersection with input lines
for radial_line in radial_sweep:
    inter = radial_line.intersection(all_input_lines)

    if inter.type == "MultiPoint":
       # radial line intersects at multiple points
       inter_dict = {}
       for inter_pt in inter:
           inter_dict[focal_pt.distance(inter_pt)] = inter_pt
       # save the nearest intersected point to the sweep centre point
       perimeter.append(inter_dict[min(inter_dict.keys())])

    if inter.type == "Point":
       # radial line intersects at one point only
       perimeter.append(inter)

    if inter.type == "GeometryCollection":
       # radial line doesn't intersect, so skip
       pass

# combine the nearest perimeter points into one geometry
solution = cascaded_union(perimeter)

# save the perimeter geometry
schema = {'geometry': 'MultiPoint', 'properties': {'test': 'int'}}
with fiona.open('perimeter.shp', 'w', 'ESRI Shapefile', schema) as e:
     e.write({'geometry':mapping(solution), 'properties':{'test':1}})

आम तौर पर एक रेडियल स्वीप का कोई सार्थक "संकल्प" नहीं होता है: यह एक "घटना" से अगले क्रम में स्कैन करता है, जहां घटनाओं में पॉलीइन्स के मूल नोड्स और उनके आपसी चौराहों (जो गतिशील रूप से मूल के आसपास स्वीप करते हुए पाए जा सकते हैं) से मिलकर बनते हैं नोड्स)। इसका आउटपुट पूरी तरह से सटीक होगा।
whuber

जवाबों:


17

मैंने आपके उदाहरण को आकृतिफाइल्स के साथ पुन: पेश किया है।

आप अपनी समस्या को हल करने के लिए Shapely और Fiona का उपयोग कर सकते हैं ।

1) आपकी समस्या (एक सुडौल के साथ Point):

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

2) एक मनमाना लाइन (पर्याप्त लंबाई के साथ) के साथ शुरू:

from shapely.geometry import Point, LineString
line = LineString([(point.x,point.y),(final_pt.x,final_pt.y)])

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

3) का उपयोग कर shapely.affinity.rotate (बिंदु से लाइन घूर्णन त्रिज्या बनाने के लिए, यह भी देखने के लिए माइक Toews के पर जवाब अजगर, सुडौल पुस्तकालय: यह आकार बहुभुज पर एक affine आपरेशन करने के लिए संभव है? ):

from shapely import affinity
# Rotate i degrees CCW from origin at point (step 10°)
radii= [affinity.rotate(line, i, (point.x,point.y)) for i in range(0,360,10)]

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

4) अब, सुडौल का उपयोग कर : एक मल्टीलाइनरिंग प्राप्त करने के लिए cascaded_union (या सुडौल: unary_union ):

from shapely.ops import cascaded_union
mergedradii = cascaded_union(radii)
print mergedradii.type
MultiLineString

5) मूल लाइनों के साथ एक ही (आकृति)

import fiona
from shapely.geometry import shape
orlines = fiona.open("orlines.shp")
shapes = [shape(f['geometry']) for f in orlines]
mergedlines = cascaded_union(shapes)
print mergedlines.type
MultiLineString

6) दो मल्टीजियोमेट्रीज़ के बीच के अंतर को गणना की जाती है और परिणाम एक आकृति के लिए सहेजा जाता है:

 points =  mergedlines.intersection(mergedradii)
 print points.type
 MultiPoint
 from shapely.geometry import mapping
 schema = {'geometry': 'MultiPoint','properties': {'test': 'int'}}
 with fiona.open('intersect.shp','w','ESRI Shapefile', schema) as e:
      e.write({'geometry':mapping(points), 'properties':{'test':1}})

परिणाम:

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

7) लेकिन, समस्या है, यदि आप एक लंबे समय तक त्रिज्या का उपयोग करते हैं, तो परिणाम अलग है:

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

8) और यदि आप अपना परिणाम प्राप्त करना चाहते हैं, तो आपको केवल त्रिज्या के मूल बिंदु से सबसे कम दूरी वाले बिंदु का चयन करना होगा:

points_ok = []
for line in mergeradii:
   if line.intersects(mergedlines):
       if line.intersection(mergedlines).type == "MultiPoint":
          # multiple points: select the point with the minimum distance
          a = {}
          for pt in line.intersection(merged):
              a[point.distance(pt)] = pt
          points_ok.append(a[min(a.keys())])
       if line.intersection(mergedlines).type == "Point":
          # ok, only one intersection
          points_ok.append(line.intersection(mergedlines))
solution = cascaded_union(points_ok)
schema = {'geometry': 'MultiPoint','properties': {'test': 'int'}}
with fiona.open('intersect3.shp','w','ESRI Shapefile', schema) as e:
     e.write({'geometry':mapping(solution), 'properties':{'test':1}})

अंतिम परिणाम:

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

मुझे उम्मीद है कि आप यही चाहते हैं।


1
उत्कृष्ट उत्तर - आकृति विज्ञान के माध्यम से इनपुट / आउटपुट के लिए फियोना के उपयोग के संबंध में विशेष रूप से जानकारीपूर्ण। मैंने अपने प्रश्न में कुछ कोड जोड़ा है जो आपके उत्तर का उपयोग करता है और intersectionआवश्यक गणना की मात्रा को कम करने के लिए इसे संशोधित करता है - धन्यवाद।
जंग लगी मागू
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.