Кажется, что просто невозможно обозначить линию зигзагообразно: к сожалению, вам придется изменить базовые данные.
Вы можете получить достаточно хорошую зигзагообразную линию, сначала разбив исходную линию на множество равноотстоящих отрезков, а затем сместив каждую другую точку на фиксированную величину.
Вот скрипт 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)
Я пытался сделать это раньше, и мне не повезло.
QGIS места повторен символов на линии на основе одной опорной точки (по умолчанию, в центре, но вы можете установить его в верхний / средний / нижний х левый / центральный / правый) и вращает этот символ на основе наклона линии на этот момент. На прямой линии, где наклон не меняется от размещения одного символа к другому, каждый символ будет идеально совпадать с предыдущим. На кривой, однако, ни одна точка на одном символе не будет идеально соответствовать соответствующей точке на следующем символе.
Таким образом, если красная линия является самой линией, повторение символа вдоль этой линии приводит к появлению промежутков между символами вдоль внешней стороны кривой и наложению на внутреннюю часть кривой.
Чтобы полностью устранить пробелы и перекрытия, каждый квадрат символа должен быть изменен как ромб различного размера - подобно тому, как камни на арке скошены, чтобы соответствовать кривой. Насколько я знаю, невозможно что-то симулировать. Но вы можете уменьшить искажение, уплотнив и сгладив геометрию линии, чтобы изменение угла было менее значительным. В этом может помочь плагин обобщителя (попробуйте использовать его с алгоритмом Чайкена).
Кроме того, поможет разбить ваш символ на более мелкие сегменты и расположить их последовательно, чтобы снова уменьшить угол между каждым последующим маркером. Например, разбить ваш
V
символ на a\
и a/
, загрузить как на линию маркера, так и для каждого, установить смещение по оси x, равное половине их ширины, положительное для одного и отрицательное для другого.Наконец, немного более толстый символ с закругленными концами поможет замаскировать небольшое искажение.
Это все еще немного хак - хотелось бы услышать, если у кого-то есть более надежный подход.
Редактировать:
другая мысль: смещение от одного символа к другому, вызванное вращением символа вдоль кривой, является наибольшим в верхней / нижней части символа, но менее выраженным в середине. Таким образом, шаблон, который начинается и заканчивается в центре символа, будет иметь меньшие промежутки, чем шаблон, который начинается / заканчивается сверху / снизу. Например
... все еще взломать - все еще не надежный
источник
Я не думаю, что это особенность в QGIS. Однако я бы попробовал сделать это так:
сделайте две копии слоя, используя плагин Affine tool. Один из слоев с немного большим масштабом и один с немного меньшим масштабом.
Увеличьте геометрию слоев. Это значит добавить больше узлов.
Перейдите к таблице атрибутов и назовите каждый узел объекта последовательно 1, 2, 3, ... на одном уровне и 1b, 2b, 3b, ... на втором уровне.
объединить оба слоя и отсортировать слой атрибута -> это должно дать вам зигзагообразную линию.
Может быть, это работает.
источник