बहुभुज के साथ "लालची" कतरन लाइनें


9

मैं बहुभुज की बाहरी सीमा तक पॉलीलाइन (नीचे की छवि में काली रेखाएं) का एक सेट क्लिप करना चाहता हूं। बहुभुज के भीतर किसी भी voids को नजरअंदाज किया जाना चाहिए। मेरी आदर्श आउटपुट धराशायी पीली लाइनें हैं। शुरुआती लाइनें सीधी हो सकती हैं या नहीं भी। छवि एक सरलीकृत उदाहरण है, वास्तव में बहुभुज बहुत अधिक जटिल है और सैकड़ों लाइनें हैं। मुझे नहीं लगता कि एक उत्तल पतवार काम करेगा (लेकिन मैं गलत हो सकता हूं)। मैं arcgis, qgis, arcpy, सुडौल आदि के समाधान के लिए खुला हूं। यदि आवश्यक हो तो अन्य विकल्पों के लिए खुला होने के कारण कोडिंग अधिमानतः अजगर में होगी। मेरे सहकर्मियों के लिए टूल साझा करना आसान बनाने के लिए आर्गिक भी बेहतर होगा, लेकिन आवश्यकता नहीं है।

सबसे अच्छा मैं अभी सोच सकता हूँ कि सभी बाउंड्री चौराहों पर बिंदुओं का एक सेट बनाने के साथ बहुभुज के साथ एक व्यक्तिगत रेखा को काटना है। लाइन की शुरुआत के लिए दूरी से अंक सॉर्ट करें। सबसे दूर और निकटतम (एफएसी) अंक बहुभुज की बाहरी सीमा होगी। फिर मूल पंक्ति से उचित कोने का चयन करने के लिए FAC बिंदुओं का उपयोग करें और उचित बिंदुओं से पीले धराशायी रेखा बनाएं। यह काम करना चाहिए लेकिन आवश्यकता से अधिक जटिल लगता है।

कुछ अतिरिक्त विचार:

  • लाइनें रैखिक "पर्याप्त" हैं कि अंकों के बीच एक साधारण दूरी की गणना काम करना चाहिए, रैखिक संदर्भ आवश्यक नहीं होना चाहिए।
  • यह आर्कपी में आसान होगा यदि एक बिंदु पर एक लाइन को विभाजित करने के लिए एक उपकरण था, लेकिन मुझे एक नहीं मिल सकता है।

विचार किसी को?

उदाहरण


+1, दिलचस्प समस्या! मैं यह देखने के लिए उत्सुक हूं कि क्या उपाय उपलब्ध हैं =)
जोसफ

केवल आपकी मध्य रेखा को प्राप्त करना कठिन है - ऊपर और नीचे किसी भी voids को भरने के बाद एक क्लिप से आता है। नतीजतन, मुझे लगता है कि आपको अपने प्रश्न पर ध्यान केंद्रित करना चाहिए और इसके दायरे को सीमित करना चाहिए यदि वह आपका पसंदीदा उपकरण है। आप हमेशा किसी अन्य टूल के बारे में पूछ सकते हैं, अगर वह समाधान नहीं देता है।
19 अगस्त को पॉलीगियो

लाइनों कई बहुभुज पार करते हैं?
एमिल ब्रूंडेज

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

आपका लाइसेंस स्तर क्या है?
एमिल ब्रुंडेज

जवाबों:


4

मैं अपने pyQGIS समाधान में फेंकना चाहता हूं, और कुछ नहीं।

from PyQt4.QtCore import QVariant
from qgis.analysis import QgsGeometryAnalyzer

# get layers
lines = QgsMapLayerRegistry.instance().mapLayersByName('lines')[0]
clipper = QgsMapLayerRegistry.instance().mapLayersByName('clipper')[0]

# prepare result layer
clipped = QgsVectorLayer('LineString?crs=epsg:4326', 'clipped', 'memory')
clipped.startEditing()
clipped.addAttribute(QgsField('fid', QVariant.Int))
fni = clipped.fieldNameIndex('fid')
clipped.commitChanges()

prov = clipped.dataProvider()
fields = prov.fields()

for line in lines.getFeatures():
    # to increase performance filter possible clippers 
    clippers = clipper.getFeatures(QgsFeatureRequest().setFilterRect(line.geometry().boundingBox()))
    for clip in clippers:
            # split the line
            line1 = line.geometry().splitGeometry(clip.geometry().asPolygon()[0], True)
            feats = []
            # get the split points
            vertices = [QgsPoint(vert[0], vert[1]) for vert in line1[2]]
            for part in line1[1]:
                # for each split part check, if first AND last vertex equal to split points
                if part.vertexAt(0) in vertices and part.vertexAt(len(part.asPolyline())-1) in vertices:
                    # if so create feature and set fid to original line's id
                    feat = QgsFeature(fields)
                    feat.setAttributes([line.id()])
                    feat.setGeometry(part)
                    feats.append(feat)

            prov.addFeatures(feats)

# expose layer
clipped.updateExtents()
QgsMapLayerRegistry.instance().addMapLayers([clipped])

# now dissolve lines having the same value in field fni: here original line's id
diss = QgsGeometryAnalyzer()
diss.dissolve(clipped, 'E:\\clipped.shp', uniqueIdField=fni)

मेरा परीक्षण मामला - कतरन से पहले: क्लिप से पहले

कतरन के बाद:

उपरांत

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


बहुत संक्षिप्त जवाब। QGIS स्क्रीन शॉट्स हमेशा QGIS की तरह कैसे दिखते हैं?
माइक बैनिस्टर

3

यह आर्कपी में आसान होगा यदि एक बिंदु पर एक लाइन को विभाजित करने के लिए एक उपकरण था, लेकिन मुझे एक नहीं मिल सकता है।

यदि आप इनपुट के रूप में बहुभुज और रेखाओं के साथ एकीकृत करते हैं, तो यह प्रत्येक को एक शीर्ष जोड़ देगा जहां वे अंतर करते हैं। (सावधान, क्योंकि एकीकृत नए आउटपुट के बजाय इनपुट को एकीकृत करता है।)

एक बार जब आप यह सुनिश्चित कर लेते हैं कि संयोग वर्धमान हैं, तो आप पंक्ति के सिरों पर पुनरावृत्ति कर सकते हैं और यह देखने के लिए परीक्षण कर सकते हैं कि क्या प्रत्येक अन्य सुविधा को स्पर्श करता है। स्पर्श करने वाले वर्टिकल की क्रमबद्ध सूची से, सेट से न्यूनतम और अधिकतम लेते हैं। फिर, प्रत्येक सुविधा से दो पंक्तियाँ बनाएं: ए (शुरू, ..., मिनट) और बी: (अधिकतम, ..., अंत)।

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


3

इस मामले में लड़ने के लिए तीन मुद्दे हैं:

  • छेद
  • बहुभुज के बीच की रेखाएँ
  • अंतिम पंक्तियाँ

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

छेद

चूंकि छेद के भीतर कोई भी रेखा बनी रहेगी, इसलिए बहुभुजों से छेद हटा दें। नीचे की स्क्रिप्ट में मैं ऐसा श्राप देने वालों और ज्यामिति के इस्तेमाल से करता हूं।

बहुभुज के बीच की रेखाएँ

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

अंतिम पंक्तियाँ

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

परिणाम

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

मान्यताओं

  • इनपुट फ़ाइल जियोडेटाबेस फीचर क्लासेस हैं
  • ArcGIS उन्नत लाइसेंस उपलब्ध है ( erasea और a के कारण feature vertices to points)
  • निरंतर, कनेक्टेड लाइनें एक एकल विशेषता है
  • बहुभुज कोई ओवरलैप नहीं करते हैं
  • मल्टीपार्ट पॉलीगन नहीं हैं

लिपि

नीचे दी गई स्क्रिप्ट आपकी लाइन फीचर क्लास प्लस के _GreedyClipरूप में एक फीचर क्लास को आपके लाइन फीचर क्लास प्लस के नाम से आउटपुट करती है । एक कार्यक्षेत्र स्थान भी आवश्यक है।

#input polygon feature class
polyFc = r"C:\Users\e1b8\Desktop\E1B8\Workspace\Workspace.gdb\testPolygon2"
#input line feature class
lineFc = r"C:\Users\e1b8\Desktop\E1B8\Workspace\Workspace.gdb\testLine"
#workspace
workspace = r"in_memory"

print "importing"
import arcpy
import os

#generate a unique ArcGIS file name
def UniqueFileName(location = "in_memory", name = "file", extension = ""):
    if extension:
        outName = os.path.join (location, name + "." + extension)
    else:
        outName = os.path.join (location, name)
    i = 0
    while arcpy.Exists (outName):
        i += 1
        if extension:
            outName = os.path.join (location, "{0}_{1}.{2}".format (name, i, extension))
        else:
            outName = os.path.join (location, "{0}_{1}".format (name, i))
    return outName

#remove holes from polygons
def RemoveHoles (inFc, workspace):
    outFc = UniqueFileName (workspace)
    array = arcpy.Array ()
    sr = arcpy.Describe (inFc).spatialReference
    outPath, outName = os.path.split (outFc)
    arcpy.CreateFeatureclass_management (outPath, outName, "POLYGON", spatial_reference = sr)
    with arcpy.da.InsertCursor (outFc, "SHAPE@") as iCurs:
        with arcpy.da.SearchCursor (inFc, "SHAPE@") as sCurs:
            for geom, in sCurs:
                try:
                    part = geom.getPart (0)
                except:
                    continue
                for pnt in part:
                    if not pnt:
                        break
                    array.add (pnt)
                polygon = arcpy.Polygon (array)
                array.removeAll ()
                row = (polygon,)
                iCurs.insertRow (row)
    del iCurs
    del sCurs
    return outFc

#split line fc by polygon fc
def SplitLinesByPolygon (lineFc, polygonFc, workspace):
    #clip
    clipFc = UniqueFileName(workspace)
    arcpy.Clip_analysis (lineFc, polygonFc, clipFc)
    #erase
    eraseFc = UniqueFileName(workspace)
    arcpy.Erase_analysis (lineFc, polygonFc, eraseFc)
    #merge
    mergeFc = UniqueFileName(workspace)
    arcpy.Merge_management ([clipFc, eraseFc], mergeFc)
    #multipart to singlepart
    outFc = UniqueFileName(workspace)
    arcpy.MultipartToSinglepart_management (mergeFc, outFc)
    #delete intermediate data
    for trash in [clipFc, eraseFc, mergeFc]:
        arcpy.Delete_management (trash)
    return outFc

#remove lines between two polygons and end lines
def RemoveLines (inFc, polygonFc, workspace):
    #check if "TARGET_FID" is in fields
    flds = [f.name for f in arcpy.ListFields (inFc)]
    if "TARGET_FID" in flds:
        #delete "TARGET_FID" field
        arcpy.DeleteField_management (inFc, "TARGET_FID")
    #spatial join
    sjFc = UniqueFileName(workspace)
    arcpy.SpatialJoin_analysis (inFc, polygonFc, sjFc, "JOIN_ONE_TO_MANY")
    #list of TARGET_FIDs
    targetFids = [fid for fid, in arcpy.da.SearchCursor (sjFc, "TARGET_FID")]
    #target FIDs with multiple occurances
    deleteFids = [dFid for dFid in targetFids if targetFids.count (dFid) > 1]
    if deleteFids:
        #delete rows with update cursor
        with arcpy.da.UpdateCursor (inFc, "OID@") as cursor:
            for oid, in cursor:
                if oid in deleteFids:
                    cursor.deleteRow ()
        del cursor
    #feature vertices to points
    vertFc = UniqueFileName(workspace)
    arcpy.FeatureVerticesToPoints_management (inFc, vertFc, "BOTH_ENDS")
    #select points intersecting polygons
    arcpy.MakeFeatureLayer_management (vertFc, "vertLyr")
    arcpy.SelectLayerByLocation_management ("vertLyr", "", polygonFc, "1 FEET")
    #switch selection
    arcpy.SelectLayerByAttribute_management ("vertLyr", "SWITCH_SELECTION")
    arcpy.MakeFeatureLayer_management (inFc, "lineLyr")
    #check for selection
    if arcpy.Describe ("vertLyr").FIDSet:
        #select lines by selected points
        arcpy.SelectLayerByLocation_management ("lineLyr", "", "vertLyr", "1 FEET")
        #double check selection (should always have selection)
        if arcpy.Describe ("lineLyr").FIDSet:
            #delete selected rows
            arcpy.DeleteFeatures_management ("lineLyr")

    #delete intermediate data
    for trash in [sjFc, "vertLyr", "lineLyr"]:
        arcpy.Delete_management (trash)

#main script
def main (polyFc, lineFc, workspace):

    #remove holes
    print "removing holes"
    holelessPolyFc = RemoveHoles (polyFc, workspace)

    #split line at polygons
    print "splitting lines at polygons"
    splitFc = SplitLinesByPolygon (lineFc, holelessPolyFc, workspace)

    #delete unwanted lines
    print "removing unwanted lines"
    RemoveLines (splitFc, polyFc, workspace)

    #create output feature class
    outFc = lineFc + "_GreedyClip"
    outFcPath, outFcName = os.path.split (outFc)
    outFc = UniqueFileName (outFcPath, outFcName)
    arcpy.CopyFeatures_management (splitFc, outFc)
    print "created:"
    print outFc
    print
    print "cleaning up"
    #delete intermediate data
    for trash in [holelessPolyFc, splitFc]:
        arcpy.Delete_management (trash)

    print "done"                    

if __name__ == "__main__":
    main (polyFc, lineFc, workspace)  

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