Symbole de ligne en zigzag dans QGIS


18

Je recherche un symbole de ligne en zigzag dans QGIS. Existe-t-il peut-être un moyen facile de le faire qui me manque? J'ai essayé de créer une ligne de marqueur à l'aide d'un simple marqueur triangulaire (^) et d'ajuster la taille du marqueur et l'intervalle de placement du marqueur jusqu'à ce que les traîneaux se touchent et semblent faire une belle ligne en zigzag. Cela fonctionne pour les lignes droites mais autour des courbes, il y a des espaces entre les triangles car les triangles ne sont pas réellement connectés. Existe-t-il peut-être un moyen de réunir les marqueurs? Ou une autre façon de procéder? Je serais très reconnaissant pour toutes suggestions! (en utilisant QGIS 2.4.0) Ma tentative de ligne en zigzag

Réponses:


11

Il semble qu'il n'y ait aucun moyen de simplement symboliser la ligne en zigzag: malheureusement, vous devrez modifier les données sous-jacentes.

Vous pouvez obtenir une ligne en zigzag raisonnablement bonne en divisant d'abord la ligne d'origine en plusieurs segments de ligne équidistants, puis en compensant tous les autres points d'une quantité fixe.

Voici un script Python qui fait cela, prenant la réponse de NathanW à Comment puis-je créer des points aléatoires le long d'une polyligne dans QGIS? comme point de départ. Enregistrez le bloc de code dans un fichier appelé zigzag.pydans votre ~/.qgis/pythonrépertoire (ou {User Directory}\.qgis\python\sous Windows), puis importez-le dans la console QGIS Python en tapant import zigzag. Ensuite, vous pouvez sélectionner une ou plusieurs lignes que vous souhaitez zigzagifier et saisir zigzag.createZigzag(<wavelength>, <amplitude>)dans la console QGIS Python, où <wavelength>et <amplitude>sont la "longueur" et la "largeur" ​​des segments en zigzag, en unités de carte.

Voici un exemple:

Comme vous pouvez le voir, les zigzags ne sont pas très agréables près des coins de la ligne d'origine, mais au moins la ligne en zigzag n'a pas de coupures.

Si vous utilisez la suggestion de James Conkling de lisser d'abord la ligne en utilisant l'algorithme de Chaiken, le résultat devient beaucoup plus agréable:


Voici le script:

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)

Solution exceptionnelle! Ma seule question qui reste est de savoir si cet algorithme peut être appliqué sur des polylignes.
Gabor Farkas

1
@GaborFarkas: l'exemple utilise une polyligne. Voulez-vous dire peut-être une couche contenant plusieurs polylignes disjointes (une polyligne multiple)? Ça marche aussi.
Jake

3

J'ai déjà essayé de le faire et je n'ai pas eu beaucoup de chance.

qGIS place des symboles répétés sur une ligne basée sur un point de référence (par défaut, le centre, bien que vous puissiez le définir en haut / milieu / bas x gauche / centre / droite) et fait pivoter ce symbole en fonction de la pente de la ligne à ce point. Sur une ligne droite, où la pente ne change pas d'un emplacement de symbole à l'autre, chaque symbole s'alignera parfaitement avec le précédent. Sur une courbe, cependant, aucun point sur un symbole ne correspondra parfaitement au point correspondant sur le symbole suivant.

symbole de marqueur répété dans qGIS

Donc, si la ligne rouge est la ligne elle-même, la répétition d'un symbole le long de cette ligne entraîne des écarts entre les symboles le long de l'extérieur d'une courbe et se chevauche à l'intérieur d'une courbe.

Pour éliminer complètement les lacunes et les chevauchements, chaque carré de symbole devrait être remodelé comme un losange de taille variable - semblable à la façon dont les pierres sur une arche sont biseautées pour correspondre à la courbe. Pour autant que je sache, il n'est pas possible de simuler quelque chose comme ça. Mais, vous pouvez diminuer la distorsion en densifiant et en lissant la géométrie de votre ligne afin que le changement d'angle soit moins extrême. Le plugin généralisateur peut vous aider (essayez de l'utiliser avec l'algorithme de Chaiken).

symbole de marqueur répétiteur lissé dans qGIS

En outre, il serait utile de diviser votre symbole en segments plus petits et de les placer successivement, afin de réduire à nouveau l'angle entre chaque marqueur suivant. Par exemple, divisez votre Vsymbole en a \et a /, chargez à la fois sur la ligne de marqueur et pour chacun, définissez un décalage x égal à la moitié de leur largeur, positif pour l'un et négatif pour l'autre.

Enfin, un trait de symbole légèrement plus épais avec des extrémités arrondies aiderait à masquer la légère distorsion.

C'est encore un peu un hack - j'aimerais savoir si quelqu'un d'autre a une approche plus fiable.

Éditer:

une autre pensée: le désalignement d'un symbole à un autre causé par la rotation du symbole le long de la courbe est plus important en haut / en bas du symbole, mais moins prononcé au milieu. Ainsi, un motif qui commence et se termine au centre du symbole aura des espaces plus petits qu'un motif qui commence / se termine en haut / en bas. Par exemple

zigzag

... toujours un hack - toujours pas infaillible


1

Je ne pense pas que ce soit une fonctionnalité de QGIS. Cependant, j'essaierais de le faire de cette façon:

  1. faire deux copies du calque en utilisant le plugin outil Affine. Une des couches avec une échelle légèrement plus grande et une avec une échelle légèrement plus petite.

  2. Densifiez la géométrie des couches. Cela signifie ajouter plus de nœuds.

  3. Accédez à la table attributaire et nommez chaque nœud d'entité en conséquence 1,2,3, ... dans une couche et 1b, 2b, 3b, ... dans la deuxième couche.

  4. fusionnez les deux calques et triez le calque d'attribut -> cela devrait vous donner une ligne en zigzag.

Peut-être que cela fonctionne.


1
Merci d'avoir répondu! Cependant, je ne pense pas que cela fonctionnera, sauf dans des cas très spécifiques comme un arc circulaire avec des sommets équidistants, sinon vous vous retrouverez avec une ligne de zigzag inégale (en raison de la mise à l'échelle et de la densification).
Jake
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.