Símbolo de línea en zigzag en QGIS

18

Estoy buscando un símbolo de línea en zigzag en QGIS. ¿Hay quizás una manera fácil de hacer esto que me estoy perdiendo? He intentado crear una línea de marcador usando un marcador de triángulo simple (^) y ajustando el tamaño del marcador y el intervalo de colocación del marcador hasta que los traingles se tocaron entre sí y parecieron formar una bonita línea en zigzag. Esto funciona para líneas rectas, pero alrededor de las curvas hay espacios entre los triángulos porque los triángulos no están realmente conectados. ¿Hay alguna forma de unir los marcadores? ¿O otra forma de hacerlo? Estaría muy agradecido por cualquier sugerencia! (usando QGIS 2.4.0) Mi intento de una línea en zigzag

Joanna McMillan
fuente

Respuestas:

11

Parece que no hay forma de simbolizar la línea como un zigzag: desafortunadamente, tendrá que alterar los datos subyacentes.

Puede obtener una línea en zigzag razonablemente buena dividiendo primero la línea original en muchos segmentos de línea equidistantes y luego compensando cualquier otro punto en una cantidad fija.

Aquí hay un script de Python que hace esto, tomando la respuesta de NathanW a ¿Cómo puedo crear puntos aleatorios a lo largo de una polilínea en QGIS? como punto de partida Guarde el fragmento de código en un archivo llamado zigzag.pyen su ~/.qgis/pythondirectorio (o {User Directory}\.qgis\python\en Windows) y luego impórtelo en la consola QGIS Python escribiendo import zigzag. Luego, puede seleccionar una o más líneas que desea zigzagificar y escribir zigzag.createZigzag(<wavelength>, <amplitude>)la consola QGIS Python, donde <wavelength>y <amplitude>son la "longitud" y el "ancho" de los segmentos en zigzag, en unidades de mapa.

Aquí hay un ejemplo:

Como puede ver, los zigzags no son muy agradables cerca de las esquinas de la línea original, pero al menos la línea en zigzag no tiene ningún salto.

Si usa la sugerencia de James Conkling de suavizar la línea primero usando el algoritmo de Chaiken, el resultado se vuelve mucho más agradable:


Aquí está el guión:

from qgis.utils import iface
from qgis.core import *
import numpy as np
from cmath import rect, phase


# Function for calculating the mean of two angles.
# Based on http://rosettacode.org/wiki/Averages/Mean_angle#Python
def meanAngle(a1, a2):
    return phase((rect(1, a1) + rect(1, a2)) / 2.0)


def createZigzag(wavelength, amplitude):
    # Create a new memory layer to store the zigzag line.
    vl = QgsVectorLayer("LineString", "Zigzag", "memory")
    pr = vl.dataProvider()

    # For each selected object in the current layer
    layer = iface.mapCanvas().currentLayer()
    for feature in layer.selectedFeatures():
        geom = feature.geometry()

        # Number of zigzag segments
        length = geom.length()
        segments = np.round(length / wavelength)

        # Find equally spaced points that approximate the line
        points = [geom.interpolate(distance).asPoint() for
            distance in np.linspace(0, length, segments)]

        # Calculate the azimuths of the approximating line segments
        azimuths = np.radians(
            [points[i].azimuth(points[i + 1]) for i in range(len(points) - 1)])

        # Average consecutive azimuths and rotate 90 deg counterclockwise
        zigzagazimuths = [azimuths[0] - np.pi / 2]
        zigzagazimuths.extend([meanAngle(azimuths[i],
            azimuths[i - 1]) - np.pi / 2 for i in range(len(points) - 1)]
        )
        zigzagazimuths.append(azimuths[-1] - np.pi / 2)

        # Offset the points along the zigzagazimuths
        zigzagpoints = []
        for i in range(len(points)):
            # Alternate the sign
            dst = amplitude * (1 - 2 * np.mod(i, 2))
            zigzagpoints.append(
                QgsPoint(points[i][0] + np.sin(zigzagazimuths[i]) * dst,
                    points[i][1] + np.cos(zigzagazimuths[i]) * dst
                )
            )

        # Create new feature from the list of zigzag points
        fet = QgsFeature()
        fet.setGeometry(QgsGeometry.fromPolyline(zigzagpoints))

        pr.addFeatures([fet])
        vl.updateExtents()

    QgsMapLayerRegistry.instance().addMapLayer(vl)
Jake
fuente
¡Solución excepcional! Mi única pregunta es si este algoritmo se puede aplicar en polilíneas.
Gabor Farkas
1
@GaborFarkas: el ejemplo utiliza una polilínea. ¿Quizás te refieres a una capa que contiene varias polilíneas disjuntas (una multi-polilínea)? Eso también funciona.
Jake
3

He intentado hacer esto antes y no he tenido mucha suerte.

qGIS coloca símbolos repetidos en una línea basada en un punto de referencia (de forma predeterminada, el centro, aunque puede establecerlo en superior / medio / inferior x izquierda / centro / derecha), y gira ese símbolo en función de la pendiente de la línea en ese punto. En una línea recta, donde la pendiente no cambia de una ubicación de símbolo a la siguiente, cada símbolo se alineará perfectamente con el anterior. Sin embargo, en una curva, ningún punto en un símbolo coincidirá perfectamente con el punto correspondiente en el siguiente símbolo.

símbolo de marcador repetido en qGIS

Entonces, si la línea roja es la línea misma, repetir un símbolo a lo largo de esa línea da como resultado espacios entre símbolos a lo largo del exterior de una curva, y se superpone en el interior de una curva.

Para eliminar por completo los huecos y las superposiciones, cada cuadrado de símbolo necesitaría ser reformado como un rombo de tamaño variable, similar a cómo se biselan las piedras en un arco para que coincida con la curva. Que yo sepa, no es posible simular algo así. Pero puede disminuir la distorsión densificando y suavizando la geometría de la línea para que el cambio de ángulo sea menos extremo. El complemento generalizador puede ayudar con eso (intente usarlo con el algoritmo de Chaiken).

símbolo de marcador de repetidor suavizado en qGIS

Además, sería útil dividir su símbolo en segmentos más pequeños y colocar cada uno en sucesión, de modo que nuevamente disminuya el ángulo entre cada marcador posterior. Por ejemplo, romper su Vsímbolo en un \y una /, cargar tanto en la línea de marcador y para cada uno, establecer un desplazamiento x igual a la mitad de su anchura, positiva para uno y negativo para el otro.

Por último, un trazo de símbolo ligeramente más grueso con extremos redondeados ayudaría a enmascarar la ligera distorsión.

Esto sigue siendo un truco: me encantaría saber si alguien más tiene un enfoque más confiable.

Editar:

otro pensamiento: la desalineación de un símbolo a otro causada por la rotación del símbolo a lo largo de la curva es mayor en la parte superior / inferior del símbolo, pero menos pronunciada en el medio. Por lo tanto, un patrón que comienza y termina en el centro del símbolo tendrá espacios más pequeños que un patrón que comienza / termina en la parte superior / inferior. P.ej

zigzag

... sigue siendo un truco - todavía no es infalible

James Conkling
fuente
1

No creo que esta sea una característica de QGIS. Sin embargo, trataría de hacerlo de esta manera:

  1. haga dos copias de la capa usando el complemento de la herramienta Affine. Una de las capas con una escala un poco más grande y otra con una escala un poco más pequeña.

  2. Densificar la geometría de las capas. Eso significa agregar más nodos.

  3. Vaya a la tabla de atributos y nombre cada nodo de entidad en consecuencia 1,2,3, ... en una capa y 1b, 2b, 3b, ... en la segunda capa.

  4. fusiona ambas capas y ordena la capa de atributo -> esto debería darte una línea en zigzag.

Quizás esto funcione.

Mazo
fuente
1
¡Gracias por la respuesta! Sin embargo, no creo que esto funcione, excepto en casos muy específicos como un arco circular con vértices equidistantes, de lo contrario, terminará con una línea de zigzag desigual (debido a la escala y debido a la densificación).
Jake