Creare poligoni che collegano endpoint di più linee usando ArcPy?


10

Sto cercando di capire come creare un poligono che collega tutti gli endpoint di uno shapefile contenente un set di polyilnes con pythonscript in ArcGIS, sto avendo problemi a farlo poiché l'ordine dei nodi nel poligono è importante. Voglio ottenere il poligono grigio nell'immagine dalle linee verdi

Voglio collegare i punti finali delle linee verdi per creare il poligono grigio senza doverlo fare manualmente


le tue linee hanno qualche attributo da dare all'ordine?
Ian Turton

in primo luogo, è necessario l'ordinamento definito come richiesto da @iant, quindi è necessaria la regola se collegare l'endpoint al punto iniziale successivo o farlo in altro modo
Matej

3
in mancanza che forse una sorta di scafo alfa sui punti finali?
Ian Turton

La linea ha in qualche modo degli attributi per dare loro l'ordine. Hanno un numero ID, ma per l'esempio sopra il braccio destro hanno l'ID 1-7, il 15-21 sinistro e dopo che sono collegati gli ID sono 22-27
Amanda

1
Puoi avvicinarti molto a) creando TIN, usando le linee, b) convertendo TIN in triangoli c) selezionando triangoli che condividono un confine con linee. Avrai solo 1 poligono da eliminare in alto
FelixIP

Risposte:


11

STEPS:

Calcola i punti centrali delle sezioni: inserisci qui la descrizione dell'immagine

Costruito il loro albero spanning minimo euclideo, dissolvendolo e calcolando il buffer, la distanza è uguale alla metà della lunghezza della sezione più corta: inserisci qui la descrizione dell'immagine

Crea i punti finali della sezione e calcola la loro catena (distanza lungo la linea) sul limite del buffer (versione polilinea chiusa del buffer): inserisci qui la descrizione dell'immagine

Ordinare i punti finali in ordine crescente utilizzando il campo della catena. Punti seguenti etichettati dal loro FID:

inserisci qui la descrizione dell'immagine

Crea poligono dal set di punti ordinato: inserisci qui la descrizione dell'immagine

script:

import arcpy, traceback, os, sys,time
from heapq import *
from math import sqrt
import itertools as itt
from collections import defaultdict

try:
    def showPyMessage():
        arcpy.AddMessage(str(time.ctime()) + " - " + message)
    # MST by PRIM's
    def prim( nodes, edges ):
        conn = defaultdict( list )
        for n1,n2,c in edges:
            conn[ n1 ].append( (c, n1, n2) )
            conn[ n2 ].append( (c, n2, n1) )
        mst = []
        used = set( nodes[ 0 ] )
        usable_edges = conn[ nodes[0] ][:]
        heapify( usable_edges )

        while usable_edges:
            cost, n1, n2 = heappop( usable_edges )
            if n2 not in used:
                used.add( n2 )
                mst.append( ( n1, n2, cost ) )

                for e in conn[ n2 ]:
                    if e[ 2 ] not in used:
                        heappush( usable_edges, e )
        return mst        


    mxd = arcpy.mapping.MapDocument("CURRENT")
    SECTIONS=arcpy.mapping.ListLayers(mxd,"SECTION")[0]
    PGONS=arcpy.mapping.ListLayers(mxd,"RESULT")[0]
    d=arcpy.Describe(SECTIONS)
    SR=d.spatialReference

    cPoints,endPoints,lMin=[],[],1000000
    with arcpy.da.SearchCursor(SECTIONS, "Shape@") as cursor:
        # create centre and end points
        for row in cursor:
            feat=row[0]
            l=feat.length
            lMin=min(lMin,feat.length)
            theP=feat.positionAlongLine (l/2).firstPoint
            cPoints.append(theP)
            theP=feat.firstPoint
            endPoints.append(theP)
            theP=feat.lastPoint
            endPoints.append(theP)

        arcpy.AddMessage('Computing minimum spanning tree')
        m=len(cPoints)
        nodes=[str(i) for i in range(m)]
        p=list(itt.combinations(range(m), 2))
        edges=[]
        for f,t in p:
            p1=cPoints[f]
            p2=cPoints[t]
            dX=p2.X-p1.X;dY=p2.Y-p1.Y
            lenV=sqrt(dX*dX+dY*dY)
            edges.append((str(f),str(t),lenV))
        MST=prim(nodes,edges)

        mLine=[]
        for edge in MST:
            p1=cPoints[int(edge[0])]
            p2=cPoints[int(edge[1])]
            mLine.append([p1,p2])
        pLine=arcpy.Polyline(arcpy.Array(mLine),SR)

        # create buffer and compute chainage
        buf=pLine.buffer(lMin/2)
        outLine=buf.boundary()
        chainage=[]
        for p in endPoints:
            measure=outLine.measureOnLine(p)
            chainage.append([measure,p])
        chainage.sort(key=lambda x: x[0])

        # built polygon
        pGon=arcpy.Array()
        for pair in chainage:
            pGon.add(pair[1])
        pGon=arcpy.Polygon(pGon,SR)
        curT = arcpy.da.InsertCursor(PGONS,"SHAPE@")
        curT.insertRow((pGon,))
        del curT
except:
    message = "\n*** PYTHON ERRORS *** "; showPyMessage()
    message = "Python Traceback Info: " + traceback.format_tb(sys.exc_info()[2])[0]; showPyMessage()
    message = "Python Error Info: " +  str(sys.exc_type)+ ": " + str(sys.exc_value) + "\n"; showPyMessage()

So che è una bicicletta, ma è la mia e mi piace


2

Pubblico questa soluzione per QGIS qui perché è un software gratuito e facile da implementare. Ho considerato solo il "ramo" giusto del livello vettoriale della polilinea; come si può vedere nell'immagine successiva (12 caratteristiche nella tabella degli attributi):

inserisci qui la descrizione dell'immagine

Il codice (algoritmo in una comprensione dell'elenco python di una riga), per l'esecuzione nella console Python di QGIS, è:

layer = iface.activeLayer()

features = layer.getFeatures()

features = [feature for feature in features]

n = len(features)

geom = [feature.geometry().asPolyline() for feature in features ]

#multi lines as closed shapes
multi_lines = [[geom[i][0], geom[i][1], geom[i+1][1], geom[i+1][0], geom[i][0]]
               for i in range(n-1)]

#multi polygons
mult_pol = [[] for i in range(n-1)]

for i in range(n-1):
    mult_pol[i].append(multi_lines[i])

#creating a memory layer for multi polygon
crs = layer.crs()
epsg = crs.postgisSrid()

uri = "Polygon?crs=epsg:" + str(epsg) + "&field=id:integer""&index=yes"

mem_layer = QgsVectorLayer(uri,
                           "polygon",
                           "memory")

QgsMapLayerRegistry.instance().addMapLayer(mem_layer)

mem_layer.startEditing()

#Set features
feature = [QgsFeature() for i in range(n-1)]

for i in range(n-1):
    #set geometry
    feature[i].setGeometry(QgsGeometry.fromPolygon(mult_pol[i]))
    #set attributes values
    feature[i].setAttributes([i])
    mem_layer.addFeature(feature[i], True)

#stop editing and save changes
mem_layer.commitChanges()

Dopo aver eseguito il codice:

inserisci qui la descrizione dell'immagine

è stato prodotto un livello di memoria poligonale (con 11 caratteristiche nella sua tabella degli attributi). Funziona bene.


1

È possibile selezionare gli endpoint che parteciperanno a un poligono, creare una TIN solo da quei punti. Converti la TIN in poligoni, sciogli i poligoni. Il trucco per automatizzare questo processo è decidere quali punti contribuire a ciascun poligono. Se hai linee con direzioni valide e tutte quelle linee condividono alcuni attributi comuni, puoi scrivere una query per esportare dire i vertici finali usando i vertici delle linee ai punti, quindi selezionare per attributo quei punti che hanno il valore dell'attributo comune.
Meglio sarebbe estrarre / selezionare i punti, leggere i valori x, y usando un cursore, usare i valori x, y per scrivere un nuovo poligono. Non riesco a vedere un'immagine allegata nel tuo post, ma se l'ordine dei punti è importante, una volta che hai i valori x, y memorizzati in un elenco Python, ordinali. http://resources.arcgis.com/EN/HELP/MAIN/10.1/index.html#//002z0000001v000000


1

Espandendo sul commento @iant, la geometria più vicina all'istantanea è la forma alfa (scafo alfa) degli endpoint. Fortunatamente, molti thread ben accolti hanno già ricevuto risposta su GIS SE. Per esempio:

Per risolvere il problema, utilizzare innanzitutto Feature To Point per estrarre i punti finali. Quindi utilizzare lo strumento Python da questo collegamento per calcolare lo scafo concavo.


Il tuo primo link sembra essere rotto.
PolyGeo
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.