Desenhando linhas onduladas e onduladas no QGIS?

21

Existe uma função QGIS ou plugin para desenhar uma linha ondulada?

Eu usei a Spline Tool para desenhar manualmente algumas ondas, mas isso consome tempo. Se possível, eu gostaria de desenhar algo como:

insira a descrição da imagem aqui

Inkscape Function Plotter ( sin(x)curva).

Kazuhito
fonte
Pergunta realmente interessante! Você está pensando em uma ferramenta para desenhar instantaneamente as linhas (ou seja, quando você desenha um recurso de linha simples usando o mouse), ou talvez uma maneira de obter esse resultado começando das coordenadas como entrada (eventualmente de pontos, linhas ou polígonos)?
Mgri 26/05/19
1
Obrigado pelo seu comentário. Espero usar essa linha para marcar um limite com algumas incertezas (como uma linha de costa flutuante), de modo que a idéia principal foi converter uma polilinha (através de coordenadas predefinidas) em manobras. Mas a ideia de desenhar instantaneamente esse tipo de linha também parece atraente.
Kazuhito 26/05
Por favor, veja se minha solução ajuda. Não testei amplamente, por isso, deixe-me saber se algo der errado (não posso fazer isso agora, mas provavelmente editarei minha resposta com mais informações).
Mgri 26/05

Respostas:

18

Proponho uma solução usando PyQGIS. Deve funcionar para as camadas Linestring e MultiLineString.

Esta solução é baseada na criação de anéis semicirculares, então você precisa definir um valor para o diâmetro (ou seja, a stepvariável no código abaixo). A etapa escolhida não será a real usada, pois é ajustada com base no comprimento da linha (mas seria muito semelhante ao valor definido inicialmente). Você precisa fazer algumas tentativas antes de encontrar o melhor valor para a stepvariável.

O código também requer um segundo parâmetro (opcional) (chamado crv_angle), que ajuda a diminuir ou aumentar a curvatura dos anéis (realizei alguns testes para isso, então sugiro deixar 45 graus como ângulo padrão, pois isso levaria a uma circular real argolas).

Você só precisa executar este código no Python Console:

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 criará uma nova camada de memória de linha com o resultado esperado:

insira a descrição da imagem aqui

mgri
fonte
Uau! Não consigo parar de brincar com isso, tão lindo. Além disso, a saída em si pode ser usada para operações adicionais, como buffer. Obrigado @mgri. Uma última coisa, às vezes vejo pequenos círculos aparecerem nos vértices ou próximos a eles. Isso é evitável? Eu posso removê-los apagando o nó central desse círculo pela Node Tool (para que não seja grande coisa).
Kazuhito 27/05
1
@ Kazuhito, por favor, veja meu código editado. Parece que havia algo errado com a discretização e espero que já esteja consertado. Realizei vários testes e parece estar funcionando bem (o código também é mais legível).
Mgri 27/05
1
Muito obrigado @mgri. Existem círculos muito menores, pelos quais lamento não poder explicar claramente como eles aparecem. A maioria dos vértices agora está "sem círculo". A única distinção que notei foi que esse nó (com círculo) havia mostrado um "valor-r" menor na Tabela de Ferramentas do Nó do Vertex Editor. Isso é facilmente gerenciável e muito melhor do que eu havia previsto. Mais uma vez obrigado. Deixe-me aceitar sua resposta como solução.
Kazuhito 27/05
1
Obrigado, @Kazuhito. Sinto muito por não ter criado uma solução perfeita. No entanto, espero que você goste (caso contrário, você também pode me enviar um exemplo de shapefile e tentarei corrigir o problema). Se eu encontrar uma maneira mais eficiente, eu a publicarei!
Mgri 27/05
1
Muito obrigado @mgri. Se encontrar algum padrão distinto na aparência dos círculos, atualizarei você com um exemplo reproduzível. Isso é muito agradável (e sua produção é linda)!
Kazuhito 28/05
20

Resposta curta: você pode obtê-lo usando um SVG personalizado. Veja a parte inferior deste post para um.

Resposta longa:

Eu acredito que é melhor representá-lo do que modificar a geometria da linha. Se você deseja mover uma aresta ou executar outras ações na geometria, seria um pesadelo gerenciar se as manobras são parte da geometria, em vez de apenas uma representação de uma linha reta.

Você pode jogar com a linha de marcador de estilo. Existe uma maneira de se aproximar facilmente do que você precisa e, com um pouco mais de esforço, é provável que seja possível obtê-lo exatamente. insira a descrição da imagem aqui

Para conseguir isso, você estilizaria a linha com duas linhas de marcador. Cada linha do marcador é composta de um marcador simples, o semicírculo. O primeiro é girado em 180. Ambos estão definidos como transparentes.

Na linha Marcador, você instrui um deles a ser deslocado para que os dois símbolos não sejam desenhados um frente ao outro, mas lado a lado. Se você usar o tamanho do intervalo offest = 1/2 *, a saída será uma curva sinusoidal. Eu sugiro que você brinque com o tamanho do intervalo, deslocamento e tamanho dos símbolos.

A principal limitação dessa abordagem é a linha de diâmetro dos semicírculos, que soma à linha original. Se o fundo for branco (ou qualquer cor lisa), você poderá adicionar uma terceira linha simples usando a cor de fundo.

insira a descrição da imagem aqui

insira a descrição da imagem aqui

insira a descrição da imagem aqui

insira a descrição da imagem aqui

** EDIT **

Outra opção para se livrar da linha central é criar um novo símbolo SVG. Modifiquei a meia curva, vivendo apenas a parte arredondada. Funciona, embora uma elipse de 1/2 possa ser mais atraente. A captura de tela foi feita usando o tamanho do símbolo 10, intervalo 4, deslocamento 2.

insira a descrição da imagem aqui

salve o código abaixo em um arquivo half_circle_line.svg e verifique se o caminho para o svg está definido em 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
fonte
Boa ideia. Atualmente lutando com persistente "linha de centro" ...: \
Kazuhito 26/05
+1 de mim também. Enquanto isso, estou tentando pensar em uma solução PyQGIS. @ Kazuhito, por favor, deixe-me saber se isso seria suficiente para você ou se você prefere uma solução física .
Mgri 26/05/19
@gri Com esta resposta eu tenho uma "corrente" e não "onda" agora (tentando modificá-lo). Realmente gostaria de ter uma solução física.
Kazuhito 26/05
JGH Você tem alguma idéia de remover a "linha central", além de mascará-la com uma linha branca (ou seja, sua figura inferior)? Parece que está fragmentado.
Kazuhito 26/05
@Kazuhito - Você pode mudar o Pen styleque nenhuma pena :)
Joseph