Estilo de camada específica usando máscara de polígono no QGIS?

10

Eu tenho uma camada de linha e uma camada de polígono no QGIS:

Antes da máscara

Gostaria de estilizar a parte da camada de linha fora do polígono usando um estilo e a parte interna usando um estilo diferente:

Depois da máscara

Não quero criar um conjunto de dados derivativos, ex. recorte a camada de linha e estilize as duas partes.

Este é um caso simples, mas no meu projeto QGIS eu tenho +30 camadas, então acho que qualquer mistura de camadas poderia perturbar as camadas subjacentes.

É possível fazer algo assim?

Eu não quero mostrar a camada de polígonos, é só aqui para visualizar o que eu gostaria de fazer.

Chau
fonte
1
Bom método! Eu acho que deve ser postado como uma resposta em vez de uma edição para a questão :)
Joseph
@ Joseph, está feito!
Chau

Respostas:

11

Não é uma solução perfeita, mas você pode usar o Geometry Generator, que adiciona uma linha visualizada para representar a interseção. Você pode definir isso para sobrepor o recurso de linha original.

Adicione uma nova camada de símbolo clicando no sinal de mais e selecione o Geometry generatortipo de camada como símbolo. Defina o tipo de região geográfica LineString / MultiLineStringe use a seguinte expressão:

intersection($geometry, geometry(get_feature( 'polygonLayer','fieldName','value'))) 

Você precisaria adicionar detalhes sobre seu polígono específico onde:

  • polygonLayer é o nome da sua camada de polígono
  • fieldName é o nome do campo
  • value é o valor do recurso de seu polígono específico

Propriedades de estilo

Observe que para colorir a linha visual, você pode precisar fazer isso na propriedade Efeitos do desenho :

Propriedades dos efeitos de desenho

Este foi o resultado (observe que a linha visual não se sobrepôs completamente à linha original, por isso modifiquei ligeiramente o deslocamento):

Resultado

E sem o polígono:

Resultado sem polígono



Editar:

Se você deseja que isso seja aplicado a cada recurso de linha que cruza um recurso de polígono, vá para o Editor de Funções e use a seguinte função (altere o nome de polygon example_2para corresponder ao nome da camada de polígono):

from qgis.core import *
from qgis.gui import *

@qgsfunction(args='auto', group='Custom')
def func(feature, parent):
    polygon_layer = QgsMapLayerRegistry.instance().mapLayersByName( "polygon example_2" )[0]
    feat_list = []
    geoms = QgsGeometry.fromWkt('GEOMETRYCOLLECTION()')
    for polygon_feat in polygon_layer.getFeatures():
        if feature.geometry().intersects(polygon_feat.geometry()):
            intersection = feature.geometry().intersection(polygon_feat.geometry())
            feat_list.append(intersection)
    for x in feat_list:
        geoms = geoms.combine(x)
    return geoms

Editor de funções

Clique em Carregar , vá para a guia Expressão e digite func(). Esperamos que o resultado seja o seguinte (usando as mesmas propriedades de estilo mencionadas acima):

Resultado final

Joseph
fonte
Na verdade, eu olhei para isso, mas parei quando descobri, que get_featurerequer nome e valor do campo. Eu só tenho uma camada de polígono e gostaria de usar todos os recursos dessa camada para mascarar. Isso é possível?
Chau
@Chau - Editado post para incluir um método possível :)
Joseph
1
Outra opção seria dissolver a camada de polígono.
CSK
1
@ Joseph - Ao usar a, Geometry Generatoro método é funcchamado para todos os recursos da camada em que é usado para estilizar? Então, se a minha camada de linha tem 3 recursos, então funcé chamada 3 vezes e obtém o mesmo resultado 3 vezes?
Chau
1
@ Chau - Eu acho que você estava certo, o código iterou através de cada recurso várias vezes. Editei a postagem para que funcagora seja chamada apenas por cada recurso de linha e desenhe o resultado apenas uma vez (o que parece ser o caso, conforme mostrado pelos marcadores de vértices dentro dos polígonos, antes que isso estivesse oculto embaixo do que eu perdi). Obrigado por apontar isso :)
Joseph
3

Estendendo a resposta de Joseph , criei essa função. Ele é responsável por diferentes sistemas de coordenadas e eu precisava pesquisar em duas camadas de máscara, assim também lida com isso. Mais ainda, eu queria poder mascarar as linhas dentro dos polígonos ou as linhas fora dos polígonos.

from qgis.core import *
from qgis.gui import *
from qgis.utils import iface

@qgsfunction(args='auto', group='Custom')
def mask_line_with_polygon(mask_type, line_layer_name, polygon_layer_name_1, polygon_layer_name_2, feature, parent):
    line_layer = QgsMapLayerRegistry.instance().mapLayersByName( line_layer_name )[0]

    # This is the geometry outside the polygon mask.
    outside = QgsGeometry(feature.geometry())

    polygon_layer_names = [polygon_layer_name_1, polygon_layer_name_2]
    line_feature_extent = outside.boundingBox()

    geoms = QgsGeometry.fromWkt('MultiLineString()')

    for polygon_layer_name in polygon_layer_names:
        if polygon_layer_name is None or len(polygon_layer_name) == 0:
            continue

        # If the line and the polygon layers have different projections, handle them here.
        polygon_layer = QgsMapLayerRegistry.instance().mapLayersByName(polygon_layer_name)[0]
        trs = QgsCoordinateTransform(line_layer.crs(), polygon_layer.crs())
        polygon_extent = trs.transform(line_feature_extent)
        trs = QgsCoordinateTransform(polygon_layer.crs(), line_layer.crs())

        # Go through the features in the polygon layer, but only those within the line feature bounding box.
        for feature in polygon_layer.getFeatures(QgsFeatureRequest().setFilterRect(polygon_extent)):
            polygon_geometry = QgsGeometry(feature.geometry())

            # Transform the polygon to line space.
            polygon_geometry.transform(trs)

            if outside.intersects(polygon_geometry):
                if mask_type.lower() == 'outside':
                    inside = outside.intersection(polygon_geometry)

                    if inside.isMultipart():
                        for x in inside.asMultiPolyline():
                            geoms.addPart(x)
                    else:
                        geoms.addPart(inside.asPolyline())

                outside = outside.difference(polygon_geometry)

    if mask_type.lower() == 'inside':
        if outside.isMultipart():
            for x in outside.asMultiPolyline():
                geoms.addPart(x)
        else:
            geoms.addPart(outside.asPolyline())

    return geoms

Este exercício me mostrou que o QGIS não gosta muito de trabalhar com grandes conjuntos de dados e esse algoritmo com o QGIS travando no meu caminho com muita frequência. Suspeito que o renderizador QGIS não gere renderizadores de geometria que consomem tempo.

Chau
fonte