Symbol linii zygzakowej w QGIS

18

Szukam symbolu linii zygzakowej w QGIS. Czy jest jakiś prosty sposób, aby to zrobić, którego mi brakuje? Próbowałem utworzyć linię znacznika za pomocą prostego znacznika trójkąta (^) i dopasować rozmiar znacznika oraz interwał umieszczania znacznika, dopóki trablele nie zetkną się ze sobą i nie utworzą ładnej zygzakowatej linii. Działa to dla linii prostych, ale wokół krzywych występują odstępy między trójkątami, ponieważ trójkąty nie są w rzeczywistości połączone. Czy jest jakiś sposób na połączenie markerów? A może inaczej? Byłbym bardzo wdzięczny za wszelkie sugestie! (przy użyciu QGIS 2.4.0) Moja próba zygzakowatej linii

Joanna McMillan
źródło

Odpowiedzi:

11

Wygląda na to, że nie ma sposobu, aby po prostu symbolizować linię jako zygzak: niestety będziesz musiał zmienić podstawowe dane.

Można uzyskać dość dobrą linię zygzakowatą, najpierw dzieląc linię oryginalną na wiele odcinków linii w jednakowej odległości, a następnie przesuwając co drugi punkt o ustaloną wartość.

Oto skrypt Pythona, który to robi, biorąc odpowiedź NathanW na: Jak mogę tworzyć losowe punkty wzdłuż polilinii w QGIS? jako punkt wyjścia. Zapisz fragment kodu w pliku o nazwie zigzag.pyw ~/.qgis/pythonkatalogu (lub {User Directory}\.qgis\python\w systemie Windows), a następnie zaimportuj go w konsoli QGIS Python, wpisując import zigzag. Następnie możesz wybrać jedną lub więcej linii, które chcesz zygzakować, i wpisać zigzag.createZigzag(<wavelength>, <amplitude>)w konsoli QGIS Python, gdzie <wavelength>i gdzie <amplitude>są „długość” i „szerokość” zygzakowatych segmentów, w jednostkach mapy.

Oto przykład:

Jak widać, zygzaki nie są zbyt ładne w pobliżu narożników oryginalnej linii, ale przynajmniej linia zygzakowata nie ma żadnych przerw.

Jeśli skorzystasz z sugestii Jamesa Conklinga, aby najpierw wygładzić linię za pomocą Algorytmu Chaikena, wynik staje się znacznie przyjemniejszy:


Oto skrypt:

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
źródło
Znakomite rozwiązanie! Pozostaje mi tylko pytanie, czy ten algorytm można zastosować do polilinii.
Gabor Farkas
1
@GaborFarkas: W przykładzie użyto polilinii. Czy masz na myśli warstwę zawierającą kilka rozłącznych polilinii (wielolilinię)? To też działa.
Jake,
3

Próbowałem to zrobić wcześniej i nie miałem szczęścia.

qGIS umieszcza powtarzające się symbole na linii w oparciu o jeden punkt odniesienia (domyślnie środek, chociaż można ustawić go na górny / środkowy / dolny x lewy / środkowy / prawy) i obraca ten symbol na podstawie nachylenia linii w ten punkt. Na linii prostej, gdzie nachylenie nie zmienia się od jednego położenia symbolu do następnego, każdy symbol idealnie zrówna się z poprzednim. Jednak na krzywej żaden punkt na jednym symbolu nie będzie idealnie pasował do odpowiedniego punktu na następnym symbolu.

powtórzony symbol znacznika w qGIS

Tak więc, jeśli czerwona linia jest samą linią, powtarzanie symbolu wzdłuż tej linii powoduje przerwy między symbolami na zewnątrz krzywej i nakłada się na wnętrze krzywej.

Aby całkowicie wyeliminować luki i nakładki, każdy kwadrat symbolu musiałby zostać przekształcony w romb o różnej wielkości - podobnie jak fazowane kamienie na łuku, aby pasowały do ​​krzywej. O ile mi wiadomo, nie można symulować czegoś takiego. Możesz jednak zmniejszyć zniekształcenie, zagęszczając i wygładzając geometrię linii, aby zmiana kąta była mniej ekstremalna. Wtyczki generalizer może w tym pomóc (spróbuj go z algorytmem Chaiken za).

wygładzony symbol znacznika repeatera w qGIS

Pomogłoby również podzielenie symbolu na mniejsze segmenty i umieszczanie każdego z nich kolejno, aby ponownie zmniejszyć kąt między każdym kolejnym znacznikiem. Np. Podziel swój Vsymbol na a \i a /, załaduj zarówno na linię znacznika, jak i dla każdego, ustaw przesunięcie x równe połowie ich szerokości, dodatnie dla jednego i ujemne dla drugiego.

Wreszcie nieco grubszy obrys symbolu z zaokrąglonymi końcami pomógłby maskować niewielkie zniekształcenie.

To wciąż trochę hack - chciałbym usłyszeć, jeśli ktoś ma bardziej niezawodne podejście.

Edytować:

inna myśl: niewspółosiowość jednego symbolu do drugiego spowodowana obrotem symbolu wzdłuż krzywej jest największa na górze / na dole symbolu, ale mniej wyraźna na środku. Tak więc wzorzec, który zaczyna się i kończy w środku symbolu, będzie miał mniejsze przerwy niż wzorzec, który zaczyna się / kończy na górze / na dole. Na przykład

zygzak

... wciąż hack - wciąż niezawodny

James Conkling
źródło
1

Nie sądzę, że jest to funkcja QGIS. Chciałbym jednak zrobić to w ten sposób:

  1. wykonaj dwie kopie warstwy za pomocą wtyczki narzędzia Affine. Jedna z warstw o ​​nieco większej skali i jedna o nieco mniejszej skali.

  2. Zagęścić geometrię warstw. Oznacza to, że dodaj więcej węzłów.

  3. Przejdź do tabeli atrybutów i nazwij każdy węzeł funkcji odpowiednio 1,2,3, ... w jednej warstwie i 1b, 2b, 3b, ... w drugiej warstwie.

  4. połącz obie warstwy i posortuj warstwę atrybutu -> powinno to dać linię zygzakowatą.

Może to działa.

Buzdygan
źródło
1
Dziękuję za odpowiedź! Jednak nie sądzę, że to zadziała, z wyjątkiem bardzo specyficznych przypadków, takich jak łuk kołowy z jednakowo odległymi wierzchołkami, w przeciwnym razie skończy się nierówna linia zygzakowa (z powodu skalowania i zagęszczenia).
Jake