Disegnare linee ondulate e ondulate in QGIS?


21

Esiste una funzione o un plugin QGIS per tracciare una linea ondulata?

Ho usato lo strumento Spline per disegnare manualmente alcune onde, ma richiede tempo. Se possibile, vorrei disegnare qualcosa del tipo:

inserisci qui la descrizione dell'immagine

Inkscape Function Plotter ( sin(x)curva).


Domanda davvero interessante! Stai pensando a uno strumento per disegnare istantaneamente le linee (cioè come quando disegni una linea semplice usando il mouse), o forse un modo per ottenere questo risultato partendo da coordinate come input (eventualmente da punti, linee o poligoni)?
mgri,

1
@mgri Grazie per il tuo commento. Mi aspetto di usare questa linea per segnare un limite con alcune incertezze (come una linea costiera fluttuante), quindi l'idea principale era quella di convertire una polilinea (attraverso coordinate predefinite) in oscillazioni. Ma l'idea di disegnare istantaneamente questo tipo di linea suona anche attraente.
Kazuhito,

Per favore, vedi se la mia soluzione aiuta. Non l'ho testato ampiamente, quindi per favore fatemi sapere se qualcosa va storto (non posso farlo ora, ma probabilmente modificherò la mia risposta con ulteriori informazioni).
mgri,

Risposte:


18

Propongo una soluzione usando PyQGIS. Dovrebbe funzionare sia per i livelli Linestring che MultiLineString.

Questa soluzione si basa sulla creazione di anelli semicircolari, quindi è necessario impostare un valore per il diametro (ovvero la stepvariabile nel codice seguente). Il passo che scegli non sarà il vero passo usato perché è regolato sulla base della lunghezza della linea (ma sarebbe molto simile al valore inizialmente impostato). Devi fare alcuni tentativi prima di trovare il valore migliore per la stepvariabile.

Il codice richiede anche un secondo parametro (opzionale) (chiamato crv_angle), che aiuta a ridurre o aumentare la curvatura degli anelli (ho eseguito alcuni test per questo, quindi suggerisco di lasciare 45 gradi come angolo predefinito poiché porterebbe a una vera circolare anelli).

Devi solo eseguire questo codice dalla console di 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)

e creerà un nuovo livello di memoria di linea con il risultato atteso:

inserisci qui la descrizione dell'immagine


Wow! Non riesco a smettere di giocare con questo, così meraviglioso. Inoltre, l'output stesso può essere utilizzato per ulteriori operazioni come il buffer. Grazie @mgri. Un'ultima cosa, a volte vedo apparire piccoli cerchi vicino o vicino ai vertici. È evitabile? Posso rimuoverli cancellando il nodo centrale di tale cerchio da Node Tool (quindi non è un grosso problema).
Kazuhito,

1
@Kazuhito, per favore, vedi il mio codice modificato. Sembra che ci sia stato qualcosa di sbagliato nella discretizzazione e spero che sia stato risolto ormai. Ho eseguito diversi test e sembra funzionare bene (il codice è anche più leggibile).
mgri,

1
Grazie mille @mgri. Ci sono circoli molto minori, per i quali mi dispiace non poter spiegare chiaramente come questi appaiono. La maggior parte dei vertici ora sono "senza cerchio". L'unica differenza che ho notato era che tale nodo (con cerchio) aveva mostrato un "valore r" più piccolo nella Tabella degli strumenti di nodo dell'editor dei vertici. Questo è facilmente gestibile e molto meglio di quanto mi aspettassi. Grazie ancora. Fammi accettare la tua risposta come soluzione.
Kazuhito,

1
Grazie, @Kazuhito. Mi dispiace di non aver creato una soluzione perfetta. Tuttavia, spero che ti piacerà (altrimenti, potresti anche inviarmi un file di esempio e proverò a risolvere il problema). Se trovo un modo più efficiente, lo posterò!
mgri,

1
Mille grazie @mgri. Se trovo qualche motivo distintivo nell'aspetto dei cerchi, ti aggiornerò con un esempio riproducibile. Questo è molto divertente (e il suo output è bellissimo)!
Kazuhito,

20

Risposta breve: puoi ottenerlo utilizzando un SVG personalizzato. Vedi in fondo a questo post per uno.

Risposta lunga:

Credo che sia meglio rappresentarlo piuttosto che modificare la geometria della linea. Se si desidera spostare un bordo o eseguire altre azioni sulla geometria, sarebbe un incubo gestire se le oscillazioni fanno parte della geometria anziché solo una rappresentazione di una linea retta.

Puoi giocare con la linea dell'indicatore di stile. C'è un modo per avvicinarsi facilmente a ciò di cui hai bisogno e con un po 'più di sforzo è probabile che sia possibile ottenerlo esattamente. inserisci qui la descrizione dell'immagine

Per ottenere ciò, modelleresti la linea con due linee Marker. Ogni linea di marker è composta da un marker semplice, il semicerchio. Il primo è ruotato di 180. Entrambi sono impostati su trasparente.

Sulla linea Marker, si ordina a uno di essi di essere sfalsato in modo che i due simboli non siano disegnati uno di fronte all'altro, ma fianco a fianco. Se si utilizza offest = 1/2 * intervallo, l'uscita sarà una curva sinusoidale. Ti suggerisco di giocare con le dimensioni dell'intervallo, offset e dimensioni del simbolo.

La principale limitazione con questo approccio è la linea del diametro dei semicerchi, che si somma alla linea originale. Se lo sfondo è bianco (o qualsiasi colore normale), è possibile aggiungere una terza linea semplice utilizzando il colore di sfondo.

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

** MODIFICA **

Un'altra opzione per sbarazzarsi della linea centrale è quella di creare un nuovo simbolo SVG. Ho modificato la mezza curva, vivendo solo la parte arrotondata. Funziona, anche se un'ellisse 1/2 potrebbe essere più attraente. Lo screenshot è stato realizzato utilizzando la dimensione del simbolo 10, intervallo 4, offset 2.

inserisci qui la descrizione dell'immagine

salva il codice qui sotto in un file half_circle_line.svg e assicurati che il percorso per svg sia impostato in 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>

Bella idea Attualmente alle prese con la "linea centrale" persistente ...: \
Kazuhito,

+1 anche da me. Nel frattempo, sto cercando di pensare a una soluzione PyQGIS. @Kazuhito, per favore fatemi sapere se questo sarebbe abbastanza per voi o se preferite una soluzione fisica .
mgri,

@mgri Con questa risposta ho una "catena" non "onda" ora (cercando di modificarla). Gradirei davvero avere una soluzione fisica.
Kazuhito,

JGH Hai potenzialmente un'idea per rimuovere la "linea centrale", oltre a mascherarla con una linea bianca (cioè la tua figura in basso)? Sembra frammentato.
Kazuhito,

@Kazuhito - È possibile modificare l' Pen stylea No Pen :)
Joseph
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.