¿Crear polígonos que conectan puntos finales de varias líneas usando ArcPy?

10

Estoy tratando de descubrir cómo crear un polígono que conecte todos los puntos finales de un shapefile que contiene un conjunto de polilíneas con pythonscript en ArcGIS, estoy teniendo problemas para hacerlo, ya que el orden de los nodos en el polígono es importante. Quiero lograr el polígono gris en la imagen desde las líneas verdes

Quiero conectar los puntos finales de las líneas verdes para crear el polígono gris sin tener que hacerlo manualmente

Amanda
fuente
¿Sus líneas tienen algún atributo para dar el orden?
Ian Turton
primero, necesita el orden definido como @iant, luego necesita la regla de si conectar el punto final al siguiente punto de inicio o hacerlo de otra manera
Matej
3
en su defecto, ¿tal vez algún tipo de casco alfa en los puntos finales?
Ian Turton
La línea tiene en cierta medida atributos para darles orden. Tienen un número de identificación, pero para el ejemplo anterior, la rama derecha tiene ID 1-7, la izquierda 15-21 y después de que se conectan las ID son 22-27
Amanda
1
Puede acercarse mucho a) creando TIN, usando líneas, b) convirtiendo TIN en triángulos c) seleccionando triángulos que comparten un límite con las líneas. Solo tendrá 1 polígono para eliminar en la parte superior
FelixIP

Respuestas:

11

PASOS:

Calcular puntos centrales de secciones: ingrese la descripción de la imagen aquí

Construyó su árbol de expansión mínimo euclidiano, disuélvalo y calcule el búfer, la distancia es igual a la mitad de la longitud de sección más corta ingrese la descripción de la imagen aquí

Cree puntos finales de sección y calcule su cadena (distancia a lo largo de la línea) en el límite del búfer (versión de polilínea cerrada del búfer): ingrese la descripción de la imagen aquí

Ordenar los puntos finales en orden ascendente utilizando el campo de PK. Puntos a continuación etiquetados por su FID:

ingrese la descripción de la imagen aquí

Crear polígono a partir de un conjunto ordenado de puntos: ingrese la descripción de la imagen aquí

Guión:

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()

Sé que es una bicicleta, pero es mía y me gusta.

FelixIP
fuente
2

Publico esta solución para QGIS aquí porque es un software gratuito y fácil de implementar. Solo consideré la "rama" correcta de la capa vectorial de polilínea; como se puede observar en la siguiente imagen (12 características en la tabla de atributos):

ingrese la descripción de la imagen aquí

El código (algoritmo en una comprensión de la lista de Python de una línea), para ejecutarse en la Consola Python de QGIS, es:

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()

Después de ejecutar el código:

ingrese la descripción de la imagen aquí

se produjo una capa de memoria poligonal (con 11 características en su tabla de atributos). Funciona muy bien

xunilk
fuente
1

Puede seleccionar los puntos finales que participarán en un polígono, crear un TIN solo a partir de esos puntos. Convierta el TIN en polígonos, disuelva los polígonos. El truco para automatizar este proceso es decidir qué puntos contribuir a cada polígono. Si tiene líneas con direcciones válidas, y todas esas líneas comparten algún atributo común, podría escribir una consulta para exportar, digamos los vértices finales usando vértices de línea a puntos, luego seleccione por atributo aquellos puntos que tienen el valor de atributo común.
Mejor sería extraer / seleccionar los puntos, leer los valores x, y usando un cursor, usar los valores x, y para escribir un nuevo polígono. No puedo ver una imagen adjunta en su publicación, pero si el orden de puntos es importante, una vez que tenga los valores x, y almacenados en una lista de Python, ordénelos. http://resources.arcgis.com/EN/HELP/MAIN/10.1/index.html#//002z0000001v000000

GBG
fuente
1

Ampliando el comentario @iant, la geometría más cercana a su instantánea es la forma alfa (casco alfa) de los puntos finales. Afortunadamente, muchos hilos bien recibidos ya han sido respondidos en GIS SE. Por ejemplo:

Para resolver su problema, primero use Feature To Point para extraer los puntos finales. Luego use la herramienta Python de este enlace para calcular el casco cóncavo.

Farid Cheraghi
fuente
Tu primer enlace parece estar roto.
PolyGeo