Criando polígonos conectando pontos finais de várias linhas usando o ArcPy?

10

Estou tentando descobrir como criar um polígono que conecta todos os pontos finais de um shapefile contendo um conjunto de polilnes com python no ArcGIS. Estou tendo problemas para fazer isso, pois a ordem dos nós no polígono é importante. Eu quero alcançar o polígono cinza na imagem a partir das linhas verdes

Quero conectar os pontos finais das linhas verdes para criar o polígono cinza sem ter que fazê-lo manualmente

Amanda
fonte
suas linhas têm algum atributo para dar a ordem?
Ian Turton
em primeiro lugar, você precisa a ordenação definida como @iant perguntou, então você precisa a regra se conectar endpoint para o próximo ponto inicial ou fazê-lo de outra maneira
Matej
3
falhando que talvez algum tipo de casco alfa nos pontos finais?
Ian Turton
Até certo ponto, a linha possui atributos para lhes dar ordem. Eles têm um número de identificação, mas para o exemplo acima, o rightbranch têm ID 1-7, o deixou 15- 21 e depois que eles estiverem conectados os IDs são 22-27
Amanda
11
Você pode se aproximar muito: a) criando o TIN, usando linhas, b) convertendo o TIN em triângulos c) selecionando os triângulos que compartilham um limite com as linhas. Você terá apenas 1 polígono para apagar no topo
FelixIP

Respostas:

11

PASSOS:

Calcular pontos centrais das seções: insira a descrição da imagem aqui

Construiu sua árvore de abrangência mínima euclidiana, dissolve-a e calcula o buffer, distância igual à metade do menor comprimento de seção: insira a descrição da imagem aqui

Crie pontos finais de seção e calcule sua cadeia (distância ao longo da linha) no limite do buffer (versão polilinha fechada do buffer): insira a descrição da imagem aqui

Classifique os pontos finais em ordem crescente usando o campo de cadeia. Pontos abaixo rotulados pelo FID:

insira a descrição da imagem aqui

Crie polígono a partir de um conjunto ordenado de pontos: insira a descrição da imagem aqui

Roteiro:

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

Eu sei que é uma bicicleta, mas é minha e eu gosto

FelixIP
fonte
2

Publico aqui esta solução para o QGIS porque é um software livre e fácil de implementar. Eu considerei apenas o "ramo" certo da camada vetorial da polilinha; como pode ser observado na próxima imagem (12 recursos na tabela de atributos):

insira a descrição da imagem aqui

O código (algoritmo em uma compreensão de lista python de uma linha), para execução no Python Console do 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()

Depois de executar o código:

insira a descrição da imagem aqui

foi produzida uma camada de memória poligonal (com 11 recursos em sua tabela de atributos). Funciona bem.

xunilk
fonte
1

Você pode selecionar os pontos de extremidade que participarão de um polígono, criar um NIF apenas a partir desses pontos. Converta o TIN em polígonos, dissolva os polígonos. O truque para automatizar esse processo é decidir quais pontos contribuir para cada polígono. Se você possui linhas com direções válidas e todas elas compartilham algum atributo comum, você pode escrever uma consulta para exportar, digamos os vértices finais, usando vértices de linhas para pontos, e selecione por atributo aqueles pontos que possuem o valor de atributo comum.
Melhor seria extrair / selecionar os pontos, ler os valores x, y usando um cursor, usar os valores x, y para escrever um novo polígono. Não consigo ver uma imagem anexada em sua postagem, mas se a ordem dos pontos for importante, depois que você tiver os valores x, y armazenados em uma lista Python, classifique-os. http://resources.arcgis.com/EN/HELP/MAIN/10.1/index.html#//002z0000001v000000

GBG
fonte
1

Expandindo o comentário @iant, a geometria mais próxima do seu instantâneo é a forma alfa (casco alfa) dos pontos finais. Felizmente, muitos tópicos bem recebidos já foram respondidos no GIS SE. Por exemplo:

Para resolver seu problema, primeiro use o recurso para apontar para extrair os pontos finais. Em seguida, use a ferramenta python deste link para calcular o casco côncavo.

Farid Cheraghi
fonte
Seu primeiro link parece estar quebrado.
PolyGeo