5 votos

¿Coincidir varios nodos de un polígono con los nodos de una línea?

Trabajo con polígonos vectoriales derivados de zonas dibujadas a mano de cuando la cartografía se realizaba con papel de calco sobre mapas de papel. Por lo tanto, muchos de los polígonos no coinciden exactamente con los límites del terreno.

Otro conjunto de datos de líneas vectoriales que tengo es preciso, por lo que he estado ajustando manualmente los nodos de los polígonos a los nodos de las líneas. Pero es un proceso largo.

Aquí tienes una captura de pantalla...

enter image description here

La línea verde es el conjunto de datos exactos. Se puede ver cómo los límites de los polígonos (naranja) son aproximadamente correctos. Abajo a la izquierda he empezado a editar los nodos, con las opciones de ajuste configuradas, y esto funciona para mover manualmente los nodos de los polígonos para que se ajusten a los nodos de la línea. (Sí, podría haber activado la edición topográfica para mover los límites de los polígonos juntos, y así lo hago).

¿Existe algún método para ajustar múltiples nodos del polígono a los nodos de las líneas, o hay quizás un método mejor para hacerlo? ¿Utilizando Python quizás? Estoy buscando algo parecido a la función 'Enable tracing' (que es genial) pero para mover los límites del polígono.

Soy consciente de que esto puede ser en algunos lugares un duplicado, ya que hay muchas preguntas similares, pero no he encontrado nada que responda a mi situación particular? En concreto he mirado en...

QGIS cómo alinear bordes de polígonos existentes

¿Cómo encajar polígonos en líneas?

¿Cómo ajustar líneas al punto más cercano?

https://gis.stackexchange.com/search?q=how+para+encajar+muchos+polígonos+en+líneas

5voto

Geoffrey Puntos 228

Preámbulo

Propongo una solución utilizando PyQGIS. Este es un tema complejo y estoy seguro de que hay (muchos) casos específicos que no consideré en mi enfoque (así, tome esta respuesta como un punto de partida y no como una solución completa ).

No he probado a fondo el código ya que no estaba seguro sobre el problema específico (ver mi comentario sin respuesta donde pedí algunas explicaciones), así que por favor haga algunas pruebas para validarlo: si va a utilizar el primer código adjunto, cree una copia de seguridad de sus capas, ya que las ediciones se registran inmediatamente en la geometría; en cambio, si desea hacer alguna prueba sin afectar a la capa original, intente utilizar el último código adjunto (ambos códigos son iguales, la única diferencia es que el primero registra las ediciones en la propia capa, mientras que el segundo las registra en una nueva capa de memoria).

Por último, supongamos que partimos de esta situación, en la que la línea roja es la directriz y los dos polígonos son dos capas separadas (cada una con una característica):

enter image description here


Explicación del flujo de trabajo

La solución requiere una capa de líneas como directriz y un conjunto de capas de polígonos que deben ser snapped . Mi enfoque itera sobre los nodos de cada característica poligonal e intenta hacer una collage con la geometría de la línea eliminando los vértices innecesarios y añadiendo otros nuevos.

Este planteamiento es bastante sencillo de entender, pero hay que tener en cuenta algunas cosas:

  • Mientras que los vértices de los polígonos se ordenan automáticamente en el sentido de las agujas del reloj al digitalizar (es decir, sólo hay una dirección posible), una capa de líneas puede digitalizarse en dos direcciones diferentes según el lado desde el que se empiece (la dirección final es obviamente única, pero no se sabe si sigue el mismo orden de los vértices del polígono);
  • Como consecuencia del punto anterior, es muy fácil crear características que son geométricamente erróneas y depende básicamente de cómo de las diferentes situaciones que pueden producirse (esta es la parte en la que mi solución no tiene sentido). (esta es la parte en la que hay que mejorar mi solución).

Dicho esto, mi flujo de trabajo podría resumirse así:

  1. leer la geometría de la característica de línea actual como una secuencia de coordenadas (se devuelven en una lista);
  2. leer la geometría actual del polígono como una secuencia de coordenadas (se devuelven en una lista);
  3. de la característica actual del polígono, encuentra el vértice más cercano tanto al inicio como al final de la línea;
  4. edita la lista desde el punto 2 asignando las coordenadas dentro de la lista desde el punto 1 en la posición adecuada.

Como puede comprender, los principales problemas se encuentran en el último paso, ya que no parecía demasiado fácil enumerar todos los casos posibles (sería más fácil si proporcionara un conjunto de datos de muestra).


Solución con ediciones aplicadas a la capa original

Puede ejecutar el siguiente código como un nuevo script desde la Caja de herramientas de procesamiento:

##input_guideline=vector line
##input_polygons=multiple vector

from qgis.core import *
from qgis.utils import iface

polygons = input_polygons.split(';')
line = QgsVectorLayer(input_guideline, input_guideline, 'ogr')

for linefeat in line.getFeatures():
    line_geom = linefeat.geometry()
    geom_to_add = line_geom.asPolyline()
    (first_line_point, end_line_point) = (line_geom.interpolate(0), line_geom.interpolate(-1))

    for polygon in polygons:
        poly = QgsVectorLayer(polygon, polygon, 'ogr')
        for feat in poly.getFeatures():
            attrs = feat.attributes()
            geom = feat.geometry()
            coords = geom.asPolygon()[0]

            first_vertex=geom.closestVertex(first_line_point.asPoint())[0]
            last_vertex=geom.closestVertex(end_line_point.asPoint())[0]
            first_indices = [i for i, x in enumerate(coords) if x == first_vertex]
            first_index = first_indices[0]
            second_index = coords.index(last_vertex)
            if first_index < second_index:
                coords[first_index:second_index] = geom_to_add
                new_geom = QgsGeometry.fromPolygon([coords])
                if not new_geom.isGeosValid():
                    first_index = first_indices[-1]
                    if first_index < second_index:
                        coords = geom.asPolygon()[0]
                        coords[second_index:first_index] = (geom_to_add)
                        new_geom = QgsGeometry.fromPolygon([coords])
                    else:
                        coords = geom.asPolygon()[0]
                        coords[second_index:first_index] = reversed(geom_to_add)
                        new_geom = QgsGeometry.fromPolygon([coords])  
            else:
                coords[first_index:second_index] = reversed(geom_to_add)
                new_geom = QgsGeometry.fromPolygon([coords])
                if not new_geom.isGeosValid():
                    first_index = first_indices[-1]
                    coords = geom.asPolygon()[0]
                    coords[second_index:first_index] = reversed(geom_to_add)
                    new_geom = QgsGeometry.fromPolygon([coords])

            poly.dataProvider().changeGeometryValues({feat.id(): new_geom})
iface.mapCanvas().refreshAllLayers()

y obtendrá este resultado:

enter image description here

Si todo funciona, los polígonos editados coincidirán perfectamente con la directriz y tendrán tanto las aristas como los vértices perfectamente alineados con ella.


Solución con ediciones aplicadas a una nueva capa

Esta solución difiere de la anterior porque guarda las ediciones en una nueva capa de memoria en lugar de grabar los cambios en la capa original (podría ser útil para hacer pruebas):

##input_guideline=vector line
##input_polygons=multiple vector

from qgis.core import *

polygons = input_polygons.split(';')
line = QgsVectorLayer(input_guideline, input_guideline, 'ogr')

for linefeat in line.getFeatures():
    line_geom = linefeat.geometry()
    geom_to_add = line_geom.asPolyline()
    (first_line_point, end_line_point) = (line_geom.interpolate(0), line_geom.interpolate(-1))

    for polygon in polygons:
        poly = QgsVectorLayer(polygon, polygon, 'ogr')

        # Create the output layer
        crs = poly.crs().toWkt()
        outLayer = QgsVectorLayer('Polygon?crs='+ crs, 'snapped' , 'memory')
        prov = outLayer.dataProvider()
        fields = poly.pendingFields() # Fields from the input layer
        prov.addAttributes(fields) # Add input layer fields to the outLayer
        outLayer.updateFields()

        for feat in poly.getFeatures():
            attrs = feat.attributes()
            geom = feat.geometry()
            coords = geom.asPolygon()[0]

            first_vertex=geom.closestVertex(first_line_point.asPoint())[0]
            last_vertex=geom.closestVertex(end_line_point.asPoint())[0]
            first_indices = [i for i, x in enumerate(coords) if x == first_vertex]
            first_index = first_indices[0]
            second_index = coords.index(last_vertex)
            if first_index < second_index:
                coords[first_index:second_index] = geom_to_add
                new_geom = QgsGeometry.fromPolygon([coords])
                if not new_geom.isGeosValid():
                    first_index = first_indices[-1]
                    if first_index < second_index:
                        coords = geom.asPolygon()[0]
                        coords[second_index:first_index] = (geom_to_add)
                        new_geom = QgsGeometry.fromPolygon([coords])
                    else:
                        coords = geom.asPolygon()[0]
                        coords[second_index:first_index] = reversed(geom_to_add)
                        new_geom = QgsGeometry.fromPolygon([coords])  
            else:
                coords[first_index:second_index] = reversed(geom_to_add)
                new_geom = QgsGeometry.fromPolygon([coords])
                if not new_geom.isGeosValid():
                    first_index = first_indices[-1]
                    coords = geom.asPolygon()[0]
                    coords[second_index:first_index] = reversed(geom_to_add)
                    new_geom = QgsGeometry.fromPolygon([coords])

            outGeom = QgsFeature()
            outGeom.setAttributes(attrs)
            outGeom.setGeometry(new_geom)
            prov.addFeatures([outGeom])

        # Add the layer to the Layers Panel
        QgsMapLayerRegistry.instance().addMapLayer(outLayer)

1voto

Dirk Bruere Puntos 6634

Además de utilizar el método de csk de dividir polígonos y luego fusionarlos, he descubierto que un método consiste en seleccionar varios nodos y, con las opciones de ajuste configuradas adecuadamente, moverlos todos hacia la línea vectorial.

Esto funciona mejor cuando hay un hueco entre el polígono y la línea, en lugar de un polígono adyacente que pueda dividirse.

enter image description here

Debe mantener pulsada la tecla "Ctrl" al mismo tiempo que selecciona cada nodo.

Puede ser más fácil utilizar el 'Editor de Vértices' para seleccionar múltiples nodos, de nuevo utilizando la tecla 'Ctrl', en lugar de los clics del ratón, ya que un ligero movimiento del ratón al hacer clic los mueve y luego los deselecciona y tienes que empezar todo de nuevo.

Es una solución rápida, pero no perfecta, ya que no suma, ni resta, nodos para que coincidan exactamente con la línea vectorial. Pero con miles de polígonos como este, es relativamente rápido conseguir algo que sirva en la mayoría de los casos para lo que necesito.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X