Символ зигзагообразной линии в QGIS

18

Я ищу символ зигзагообразной линии в QGIS. Есть ли простой способ сделать это, что я скучаю? Я попытался создать линию маркера с помощью простого треугольного маркера (^) и отрегулировать размер маркера и интервал размещения маркера до тех пор, пока тралинги не соприкоснулись друг с другом и не образовали красивую зигзагообразную линию. Это работает для прямых линий, но вокруг кривых есть промежутки между треугольниками, потому что треугольники фактически не связаны. Есть ли способ объединить маркеры вместе? Или другой способ сделать это? Буду очень признателен за любые предложения! (используя QGIS 2.4.0) Моя попытка зигзагообразной линии

Джоанна Макмиллан
источник

Ответы:

11

Кажется, что просто невозможно обозначить линию зигзагообразно: к сожалению, вам придется изменить базовые данные.

Вы можете получить достаточно хорошую зигзагообразную линию, сначала разбив исходную линию на множество равноотстоящих отрезков, а затем сместив каждую другую точку на фиксированную величину.

Вот скрипт Python, который делает это, взяв ответ NathanW на Как я могу создать случайные точки вдоль полилинии в QGIS? в качестве отправной точки. Сохраните фрагмент кода в файл, который называется zigzag.pyв вашем ~/.qgis/pythonкаталоге (или {User Directory}\.qgis\python\в Windows), а затем импортируйте его в консоль QGIS Python, введя команду import zigzag. Затем вы можете выбрать одну или несколько линий, которые хотите зигзагировать, и ввести zigzag.createZigzag(<wavelength>, <amplitude>)в консоли QGIS Python, где <wavelength>и <amplitude>«длина» и «ширина» сегментов зигзага, в единицах карты.

Вот пример:

Как вы можете видеть, зигзаги не очень хороши вблизи углов исходной линии, но, по крайней мере, линия зигзага не имеет разрывов.

Если вы используете предложенное Джеймсом Конклингом сглаживание линии сначала с помощью алгоритма Чайкена, результат становится намного лучше:


Вот сценарий:

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)
Джейк
источник
Отличное решение! У меня остается только один вопрос: можно ли применить этот алгоритм к полилиниям?
Габор Фаркас,
1
@GaborFarkas: в примере используется ломаная линия. Возможно, вы имеете в виду слой, содержащий несколько непересекающихся полилиний (мультиполилинии)? Это также работает.
Джейк
3

Я пытался сделать это раньше, и мне не повезло.

QGIS места повторен символов на линии на основе одной опорной точки (по умолчанию, в центре, но вы можете установить его в верхний / средний / нижний х левый / центральный / правый) и вращает этот символ на основе наклона линии на этот момент. На прямой линии, где наклон не меняется от размещения одного символа к другому, каждый символ будет идеально совпадать с предыдущим. На кривой, однако, ни одна точка на одном символе не будет идеально соответствовать соответствующей точке на следующем символе.

повторный символ маркера в qGIS

Таким образом, если красная линия является самой линией, повторение символа вдоль этой линии приводит к появлению промежутков между символами вдоль внешней стороны кривой и наложению на внутреннюю часть кривой.

Чтобы полностью устранить пробелы и перекрытия, каждый квадрат символа должен быть изменен как ромб различного размера - подобно тому, как камни на арке скошены, чтобы соответствовать кривой. Насколько я знаю, невозможно что-то симулировать. Но вы можете уменьшить искажение, уплотнив и сгладив геометрию линии, чтобы изменение угла было менее значительным. В этом может помочь плагин обобщителя (попробуйте использовать его с алгоритмом Чайкена).

сглаженный символ маркера повторителя в qGIS

Кроме того, поможет разбить ваш символ на более мелкие сегменты и расположить их последовательно, чтобы снова уменьшить угол между каждым последующим маркером. Например, разбить ваш Vсимвол на a \и a /, загрузить как на линию маркера, так и для каждого, установить смещение по оси x, равное половине их ширины, положительное для одного и отрицательное для другого.

Наконец, немного более толстый символ с закругленными концами поможет замаскировать небольшое искажение.

Это все еще немного хак - хотелось бы услышать, если у кого-то есть более надежный подход.

Редактировать:

другая мысль: смещение от одного символа к другому, вызванное вращением символа вдоль кривой, является наибольшим в верхней / нижней части символа, но менее выраженным в середине. Таким образом, шаблон, который начинается и заканчивается в центре символа, будет иметь меньшие промежутки, чем шаблон, который начинается / заканчивается сверху / снизу. Например

зигзаг

... все еще взломать - все еще не надежный

Джеймс Конклинг
источник
1

Я не думаю, что это особенность в QGIS. Однако я бы попробовал сделать это так:

  1. сделайте две копии слоя, используя плагин Affine tool. Один из слоев с немного большим масштабом и один с немного меньшим масштабом.

  2. Увеличьте геометрию слоев. Это значит добавить больше узлов.

  3. Перейдите к таблице атрибутов и назовите каждый узел объекта последовательно 1, 2, 3, ... на одном уровне и 1b, 2b, 3b, ... на втором уровне.

  4. объединить оба слоя и отсортировать слой атрибута -> это должно дать вам зигзагообразную линию.

Может быть, это работает.

булава
источник
1
Спасибо за ответ! Однако я не думаю, что это будет работать, за исключением очень специфических случаев, таких как круговая дуга с равноотстоящими вершинами, в противном случае вы получите неровную зигзагообразную линию (из-за масштабирования и из-за уплотнения).
Джейк