Símbolo de linha em zigue-zague no QGIS


18

Estou procurando um símbolo de linha em zigue-zague no QGIS. Existe talvez uma maneira fácil de fazer isso que estou perdendo? Tentei criar uma linha de marcador usando um marcador de triângulo simples (^) e ajustar o tamanho do marcador e o intervalo de posicionamento do marcador até que as traingles se tocassem e parecessem fazer uma bela linha em zigue-zague. Isso funciona para linhas retas, mas ao redor das curvas há espaços entre os triângulos porque os triângulos não estão realmente conectados. Existe talvez uma maneira de unir os marcadores? Ou outra maneira de fazer isso? Ficaria muito grato por todas as sugestões! (usando o QGIS 2.4.0) Minha tentativa de uma linha em zigue-zague

Respostas:


11

Parece que não há como simbolizar a linha como um zigue-zague: infelizmente, você precisará alterar os dados subjacentes.

Você pode obter uma linha em zigue-zague razoavelmente boa, primeiro dividindo a linha original em muitos segmentos de linha equidistantes e depois compensando todos os outros pontos por um valor fixo.

Aqui está um script Python que faz isso, levando a resposta de NathanW para Como criar pontos aleatórios ao longo de uma polilinha no QGIS? como ponto de partida. Salve o pedaço de código em um arquivo chamado zigzag.pyem seu ~/.qgis/pythondiretório (ou {User Directory}\.qgis\python\no Windows) e importe-o no console do QGIS Python digitando import zigzag. Em seguida, você pode selecionar uma ou mais linhas que deseja ziguezagificar e digitar zigzag.createZigzag(<wavelength>, <amplitude>)no console do QGIS Python, onde <wavelength>e <amplitude>são o "comprimento" e a "largura" dos segmentos em zigue-zague, em unidades de mapa.

Aqui está um exemplo:

Como você pode ver, os ziguezagues não são muito agradáveis ​​perto dos cantos da linha original, mas pelo menos a linha em zigue-zague não tem interrupções.

Se você usar a sugestão de James Conkling de suavizar a linha primeiro usando o algoritmo de Chaiken, o resultado será muito melhor:


Aqui está o script:

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)

Excelente solução! Minha única pergunta que resta é se esse algoritmo pode ser aplicado em polilinhas.
Gabor Farkas

1
@GaborFarkas: O exemplo usa uma polilinha. Você quer dizer uma camada contendo várias polilinhas disjuntas (uma polilinha múltipla)? Isso também funciona.
Jake #

3

Eu tentei fazer isso antes e não tive muita sorte.

qGIS coloca símbolos repetidos em uma linha com base em um ponto de referência (por padrão, o centro, embora você possa defini-lo como superior / médio / inferior x esquerdo / central / direito) e gira esse símbolo com base na inclinação da linha em esse ponto. Em uma linha reta, onde a inclinação não muda de um posicionamento para o próximo, cada símbolo se alinha perfeitamente com o anterior. Em uma curva, porém, nenhum ponto em um símbolo corresponde perfeitamente ao ponto correspondente no próximo símbolo.

símbolo de marcador repetido no qGIS

Portanto, se a linha vermelha for a própria linha, a repetição de um símbolo ao longo dessa linha resultará em intervalos entre os símbolos na parte externa de uma curva e se sobrepor na parte interna de uma curva.

Para eliminar completamente as lacunas e sobreposições, cada quadrado de símbolo precisaria ser remodelado como um losango de tamanho variável - semelhante à forma como as pedras em um arco são chanfradas para coincidir com a curva. Até onde eu sei, não é possível simular algo assim. Porém, você pode diminuir a distorção densificando e suavizando a geometria da linha, para que a mudança no ângulo seja menos extrema. O plugin generalizador pode ajudar com isso (tente usá-lo com o algoritmo de Chaiken).

símbolo de marcador de repetidor suavizado no qGIS

Além disso, dividir seu símbolo em segmentos menores e colocar cada um em sucessão, para que novamente você diminua o ângulo entre cada marcador subsequente, ajudaria. Por exemplo, quebrar o seu Vsímbolo em um \e um /, carregar tanto na linha marcador e para cada um, definir um igual a metade da sua largura, positivo para um e negativo para outra distância x.

Por fim, um toque de símbolo um pouco mais grosso com extremidades arredondadas ajudaria a mascarar a leve distorção.

Isso ainda é um pouco complicado - adoraria saber se alguém tem uma abordagem mais confiável.

Editar:

outro pensamento: o desalinhamento de um símbolo para outro causado pela rotação do símbolo ao longo da curva é maior na parte superior / inferior do símbolo, mas menos pronunciado no meio. Portanto, um padrão que inicia e termina no centro do símbolo terá intervalos menores do que um padrão que inicia / termina na parte superior / inferior. Por exemplo

ziguezague

... ainda um hack - ainda não é infalível


1

Eu não acho que isso seja um recurso do QGIS. No entanto, eu tentaria fazê-lo desta maneira:

  1. faça duas cópias da camada usando o plugin da ferramenta Affine. Uma das camadas com uma escala um pouco maior e outra com uma escala um pouco menor.

  2. Densifique a geometria das camadas. Isso significa adicionar mais nós.

  3. Vá para a tabela de atributos e nomeie cada nó do recurso, consequentemente, 1,2,3, ... em uma camada e 1b, 2b, 3b, ... na segunda camada.

  4. mesclar as duas camadas e classificar a camada de atributo -> isso deve fornecer uma linha em zigue-zague.

Talvez isso funcione.


1
Obrigado pela resposta! No entanto, acho que isso não funcionará, exceto em casos muito específicos, como um arco circular com vértices equidistantes, caso contrário, você terminará com uma linha em zigue-zague irregular (devido ao dimensionamento e à densificação).
Jake
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.