¿Dibujando líneas onduladas y onduladas en QGIS?

21

¿Existe una función o complemento QGIS para dibujar una línea ondulada?

He usado Spline Tool para dibujar manualmente algunas ondas, pero lleva mucho tiempo. Si es posible, me gustaría dibujar algo como:

ingrese la descripción de la imagen aquí

Inkscape Function Plotter ( sin(x)curva).

Kazuhito
fuente
Pregunta realmente interesante! ¿Está pensando en una herramienta para dibujar instantáneamente las líneas (es decir, cuando dibuja una entidad de línea simple con el mouse), o tal vez una forma de obtener este resultado a partir de coordenadas como entrada (eventualmente de puntos, líneas o polígonos)?
mgri
1
@mgri Gracias por tu comentario. Espero usar esta línea para marcar un límite con algunas incertidumbres (como una línea de costa fluctuante), por lo que la idea principal era convertir una polilínea (a través de coordenadas predefinidas) en meneos. Pero la idea de dibujar instantáneamente este tipo de línea también suena atractiva.
Kazuhito
Por favor, vea si mi solución ayuda. No lo probé ampliamente, así que avíseme si algo sale mal (no puedo hacerlo ahora, pero probablemente edite mi respuesta con más información).
mgri

Respuestas:

18

Propongo una solución usando PyQGIS. Debería funcionar tanto para las capas Linestring como MultiLineString.

Esta solución se basa en la creación de anillos semicirculares, por lo que debe establecer un valor para el diámetro (es decir, la stepvariable en el código a continuación). El paso que elija no será el paso real utilizado porque se ajusta en función de la longitud de la línea (pero sería muy similar al valor establecido inicialmente). Debe hacer algunos intentos antes de encontrar el mejor valor para la stepvariable.

El código también requiere un segundo parámetro (opcional) (llamado crv_angle), que ayuda a disminuir o aumentar la curvatura de los anillos (realicé algunas pruebas para ello, por lo que sugiero dejar 45 grados como ángulo predeterminado ya que conduciría a una circular real anillos).

Solo necesita ejecutar este código desde la consola de 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)

y creará una nueva capa de memoria de línea con el resultado esperado:

ingrese la descripción de la imagen aquí

mgri
fuente
¡Guauu! No puedo dejar de jugar con esto, tan hermosa. Además, la salida en sí se puede utilizar para otras operaciones como el búfer. Gracias @mgri. Una última cosa, a veces veo pequeños círculos que aparecen en los vértices o cerca de ellos. ¿Es esto evitable? Puedo eliminarlos borrando el nodo central de dicho círculo con Node Tool (por lo que no es gran cosa).
Kazuhito
1
@Kazuhito por favor, mira mi código editado. Parece que hubo algo mal con la discretización y espero que ya esté solucionado. Realicé varias pruebas y parece funcionar bien (el código también es más legible).
mgri
1
Muchas gracias @mgri. Hay círculos muy pequeños, por lo que lamento no poder explicar claramente cómo aparecen. La mayoría de los vértices ahora están "sin círculo". La única distinción que noté fue que dicho nodo (con círculo) había mostrado un "valor r" más pequeño en la herramienta de tabla de nodos de Vertex Editor. Esto es fácilmente manejable y mucho mejor de lo que había previsto. Gracias de nuevo. Déjame aceptar tu respuesta como solución.
Kazuhito
1
Gracias @Kazuhito. Lamento no haber creado una solución perfecta. Sin embargo, espero que lo disfrute (de lo contrario, también puede enviarme un archivo de forma de muestra e intentaré solucionar el problema). Si encuentro una manera más eficiente, ¡lo publicaré!
mgri
1
Muchas gracias @mgri. Si encuentro algún patrón distintivo en la apariencia de los círculos, lo actualizaré con un ejemplo reproducible. ¡Esto es muy agradable (y su salida es hermosa)!
Kazuhito
20

Respuesta corta: puede obtenerlo usando un SVG personalizado. Ver al final de esta publicación para uno.

Respuesta larga:

Creo que es mejor representarlo que modificar la geometría de la línea. Si desea mover una arista o realizar otras acciones en la geometría, sería una pesadilla administrar si las oscilaciones son parte de la geometría en lugar de solo una representación de una línea recta.

Puedes jugar con la línea de marcador de estilo. Hay una manera de acercarse fácilmente a lo que necesita, y con un poco más de esfuerzo es posible obtenerlo exactamente. ingrese la descripción de la imagen aquí

Para obtener esto, debe diseñar la línea con dos líneas de marcador. Cada línea de marcador está hecha de un marcador simple, el semicírculo. El primero se gira 180. Ambos están configurados en transparente.

En la línea de Marcador, le indica a uno de ellos que se desplace para que los dos símbolos no se dibujen uno frente al otro, sino uno al lado del otro. Si usa offest = 1/2 * tamaño de intervalo, la salida será una curva sinusoidal. Te sugiero que juegues con el tamaño del intervalo, el desplazamiento y los tamaños de los símbolos.

La principal limitación con este enfoque es la línea de diámetro de los semicírculos, que se suma a la línea original. Si su fondo es blanco (o cualquier color normal), puede agregar una tercera línea simple usando el color de fondo.

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

** EDITAR **

Otra opción para deshacerse de la línea central es crear un nuevo símbolo SVG. Modifiqué la media curva, solo viviendo la parte redondeada. Funciona, aunque una 1/2 elipse podría ser más atractiva. La captura de pantalla se realizó con el tamaño de símbolo 10, intervalo 4, desplazamiento 2.

ingrese la descripción de la imagen aquí

guarde el código a continuación en un archivo half_circle_line.svg y asegúrese de que la ruta al svg esté establecida en 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
fuente
Buena idea. Actualmente luchando con persistente "línea central" ...: \
Kazuhito
+1 de mi parte también. Mientras tanto, estoy tratando de pensar en una solución PyQGIS. @Kazuhito, avíseme si esto sería suficiente para usted o si prefiere una solución física .
mgri
@mgri Con esta respuesta, ahora tengo una "cadena", no "ola" (tratando de modificarla). Realmente agradecería tener una solución física.
Kazuhito
JGH ¿Tiene una idea potencial para eliminar la "línea central", aparte de enmascararla con una línea blanca (es decir, su figura inferior)? Parece que está fragmentado.
Kazuhito
@Kazuhito - Puedes cambiar Pen stylea No Pen :)
Joseph