Рисование волнистых, волнистых линий в QGIS?

21

Есть ли функция QGIS или плагин для рисования волнистой линии?

Я использовал Spline Tool для рисования некоторых волн вручную, но это отнимает много времени. Если возможно, я хотел бы нарисовать что-то вроде:

введите описание изображения здесь

Inkscape Function Plotter ( sin(x)кривая).

Казухито
источник
Действительно интересный вопрос! Вы думаете об инструменте для мгновенного рисования линий (например, когда вы рисуете простой линейный объект с помощью мыши), или, возможно, о способе получения этого результата, начиная с координат в качестве входных данных (в конечном итоге с точек, линий или полигонов)?
Мгри
1
@mgri Спасибо за ваш комментарий. Я рассчитываю использовать эту линию для обозначения границы с некоторыми неопределенностями (например, колеблющейся береговой линией), поэтому основной идеей было преобразовать ломаную линию (через предварительно определенные координаты) в покачивания. Но идея мгновенного рисования линий такого типа тоже звучит привлекательно.
Казухито,
Пожалуйста, посмотрите, поможет ли мое решение. Я не проверял это широко, поэтому, пожалуйста, дайте мне знать, если что-то пойдет не так (я не могу сделать это прямо сейчас, но я, вероятно, отредактирую свой ответ с более подробной информацией).
Мгри

Ответы:

18

Я предлагаю решение с использованием PyQGIS. Это должно работать как для слоев Linestring, так и для MultiLineString.

Это решение основано на создании полукруглых колец, поэтому вам необходимо установить значение для диаметра (то есть stepпеременную в коде ниже). Шаг, который вы выберете, не будет реальным используемым шагом, потому что он регулируется на основе длины строки (но он будет действительно похож на первоначально установленное значение). Вам нужно сделать несколько попыток, прежде чем найти лучшее значение для stepпеременной.

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

Вам нужно только запустить этот код из консоли Python:

from math import sin, cos, radians

step = 3 # choose the proper value (e.g. meters or degrees) with reference to the CRS used
crv_angle = 45 # degrees

def segment(polyline):
    for x in range(0, len(polyline) - 1):
        first_point = polyline[x]
        second_point = polyline[x +1]
        seg = QgsGeometry.fromPolyline([first_point, second_point])
        tmp_azim = first_point.azimuth(second_point)
        len_feat = seg.length()
        parts = int(len_feat/step)
        real_step = len_feat/parts # this is the real step applied

        points = []
        current = 0
        up = True

        while current < len_feat:
            if up:
                round_angle = radians(90 - (tmp_azim - crv_angle))
                up = False
            else:
                round_angle = radians(90 - (tmp_azim + crv_angle))
                up = True
            first = seg.interpolate(current)
            coord_x, coord_y = (first.asPoint().x(), first.asPoint().y())
            p1=QgsPointV2(coord_x, coord_y)
            dist_x, dist_y = ((real_step*sin(rad_crv_angle))* cos(round_angle), (real_step*sin(rad_crv_angle)) * sin(round_angle))
            p2 = QgsPointV2(coord_x + dist_x, coord_y + dist_y)
            points.extend([p1, p2])
            current += real_step

        second = seg.interpolate(current + real_step)
        p3=QgsPointV2(second.asPoint().x(), second.asPoint().y())
        points.append(p3)

        circularRing = QgsCircularStringV2()
        circularRing.setPoints(points) # set points for circular rings
        fet = QgsFeature()
        fet.setGeometry(QgsGeometry(circularRing))
        prov.addFeatures([fet])

layer = iface.activeLayer() # load the input layer as you want
crs = layer.crs().toWkt()
rad_crv_angle = radians(crv_angle)

# Create the output layer
outLayer = QgsVectorLayer('Linestring?crs='+ crs, 'wiggly_line' , 'memory')
prov = outLayer.dataProvider()
fields = layer.pendingFields()
prov.addAttributes(fields)
outLayer.updateFields()

for feat in layer.getFeatures():
    geom = feat.geometry()
    polyline = geom.asPolyline()
    segment(polyline)

# Add the layer to the Layers panel
QgsMapLayerRegistry.instance().addMapLayer(outLayer)

и он создаст новый слой памяти строки с ожидаемым результатом:

введите описание изображения здесь

МГРИ
источник
Вот Это Да! Я не могу перестать играть с этим, так великолепно. Кроме того, сам вывод можно использовать для дальнейших операций, таких как буфер. Спасибо @mgri. И последнее, я иногда вижу маленькие круги в вершинах или рядом с ними. Это можно избежать? Я могу удалить их, удалив центральный узел такого круга с помощью Node Tool (так что это не имеет большого значения).
Казухито
1
@ Kazuhito, пожалуйста, смотрите мой отредактированный код. Кажется, что-то было не так с дискретизацией, и я надеюсь, что это уже исправлено. Я выполнил несколько тестов, и это, кажется, работает хорошо (код также более читабелен).
МГРИТЕ
1
Большое спасибо @mgri. Есть очень незначительные круги, для которых я извиняюсь, я не могу ясно объяснить, как они появляются. Большинство вершин теперь "без кругов". Единственное различие, которое я заметил, было то, что такой узел (с кружком) показал меньшее «r-значение» в таблице редактора вершин инструмента Node Tool. Это легко управляемо и намного лучше, чем я ожидал. Еще раз спасибо Позвольте мне принять ваш ответ в качестве решения.
Казухито
1
Спасибо, @Kazuhito. Я извиняюсь за то, что не создал идеальное решение. Тем не менее, я надеюсь, вам понравится (в противном случае вы также можете отправить мне образец шейп-файла, и я постараюсь решить проблему). Если я найду более эффективный способ, я опубликую его!
Мгри
1
Большое спасибо @mgri. Если я найду какой-либо характерный образец во внешности кругов, я обновлю вас воспроизводимым примером. Это очень приятно (и его выход красивый)!
Казухито,
20

Краткий ответ: вы можете получить его, используя пользовательский SVG. Смотрите в нижней части этого поста для одного.

Длинный ответ:

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

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

Чтобы получить это, вы должны стилизовать линию с двумя линиями маркера. Каждая линия маркера состоит из простого маркера, полукруга. 1-й повернут на 180. Оба установлены прозрачными.

На линии маркера вы указываете, что один из них должен быть смещен, чтобы два символа были нарисованы не друг напротив друга, а рядом. Если вы используете offest = 1/2 * размер интервала, на выходе будет синусоидальная кривая. Я предлагаю вам поиграть с размером интервала, смещением и размерами символов.

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

введите описание изображения здесь

введите описание изображения здесь

введите описание изображения здесь

введите описание изображения здесь

** РЕДАКТИРОВАТЬ **

Другой вариант избавиться от центральной линии - создать новый символ SVG. Я изменил полукруг, только живя закругленной частью. Это работает, хотя эллипс 1/2 может быть более привлекательным. Скриншот был сделан с использованием размера символа 10, интервал 4, смещение 2.

введите описание изображения здесь

сохраните приведенный ниже код в файле half_circle_line.svg и убедитесь, что путь к svg указан в QGIS // Settings / Options / System / SVG Paths

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="11.2889mm" height="11.2889mm"
 viewBox="0 0 32 32"
 xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"  version="1.2" baseProfile="tiny">
<title>Qt Svg Document</title>
<desc>Generated with Qt</desc>
<defs>
</defs>
<g fill="none" stroke="black" stroke-width="1" fill-rule="evenodd" stroke-linecap="square" stroke-linejoin="bevel" >

<g fill="#ffffff" fill-opacity="0" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1,0,0,1,0,0)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal" 
>
<path vector-effect="non-scaling-stroke" fill-rule="evenodd" d="M19.1181,16 C19.1181,16 19.1181,14.2779 17.7221,12.8819 16,12.8819 C14.2779,12.8819 12.8819,14.2779 12.8819,16"/>
</g>
</g>
</svg>
JGH
источник
Хорошая идея. В настоящее время борется с постоянной «средней линии» ...: \
Казухито
+1 от меня тоже. В то же время я пытаюсь найти решение PyQGIS. @ Kazuhito, пожалуйста, дайте мне знать, если этого будет достаточно для вас или вы предпочитаете физическое решение.
Мгри
@mgri С этим ответом у меня теперь есть «цепочка», а не «волна» (пытаюсь ее изменить). Был бы очень признателен, чтобы иметь физическое решение.
Казухито,
JGH У вас есть идея удалить «центральную линию», кроме маскировки ее белой линией (т. Е. Нижней фигурой)? Это выглядит так, как будто оно фрагментировано.
Казухито,
@Kazuhito - Вы можете изменить , Pen styleчтобы Нет Pen :)
Иосиф