Disegnare uno strato specifico usando la maschera poligonale in QGIS?


10

Ho un livello linea e un livello poligono in QGIS:

Prima della maschera

Vorrei modellare la parte del livello di linea all'esterno del poligono utilizzando uno stile e la parte interna utilizzando uno stile diverso:

Dopo la maschera

Non voglio creare un set di dati derivati, ad es. tagliare il livello della linea e modellare le due parti.

Questo è un caso semplice ma nel mio progetto QGIS ho +30 livelli, quindi penso che qualsiasi fusione dei livelli disturberebbe i livelli sottostanti.

È possibile fare qualcosa del genere?

Non voglio mostrare il livello poligonale, è solo qui per visualizzare ciò che vorrei fare.


1
Bel metodo! Penso che dovrebbe essere pubblicato come risposta anziché come modifica alla domanda :)
Joseph,

@Joseph, è fatto!
Chau,

Risposte:


11

Non è una soluzione perfetta, ma è possibile utilizzare il generatore di geometria che aggiunge una linea visualizzata per rappresentare l'intersezione. È quindi possibile impostare questo per sovrapporre la funzione di linea originale.

Aggiungi un nuovo livello simbolo facendo clic sul segno più e seleziona Geometry generatorcome tipo di livello simbolo. Impostare il tipo di geoemtry su LineString / MultiLineStringe utilizzare la seguente espressione:

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

Dovresti aggiungere dettagli sul tuo poligono specifico dove:

  • polygonLayer è il nome del tuo livello poligonale
  • fieldName è il nome del campo
  • value è il valore della funzione del tuo poligono specifico

Proprietà di stile

Si noti che per colorare la linea visiva, potrebbe essere necessario farlo dalla proprietà Effetti disegno :

Disegna le proprietà degli effetti

Questo è stato il risultato (nota che la linea visiva non si sovrappone completamente alla linea originale, quindi ho modificato leggermente l'offset):

Risultato

E senza il poligono:

Risultato senza poligono



Modificare:

Se vuoi che questo sia applicato per ogni feature di linea che interseca una feature poligonale, vai all'editor delle funzioni e usa la seguente funzione (cambia il nome polygon example_2in modo che corrisponda al nome del tuo layer poligonale):

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 di funzioni

Fai clic su Carica quindi vai alla scheda Espressione e digita func(). Speriamo che il risultato sia simile al seguente (usando le stesse proprietà di stile sopra menzionate):

Risultato finale


In realtà l'ho guardato ma mi sono fermato quando l'ho scoperto, che get_featurerichiede nome e valore del campo. Ho solo un livello poligonale e vorrei usare tutte le funzionalità su quel livello per mascherare. È possibile?
Chau,

@Chau - Post modificato per includere un possibile metodo :)
Joseph

1
Un'altra opzione sarebbe quella di dissolvere il livello poligonale.
csk

1
@Joseph - Quando si utilizza a Geometry Generatorviene funcchiamato il metodo per ogni funzione sul livello in cui viene utilizzata per lo styling? Quindi se il mio livello di linea ha 3 caratteristiche, funcviene chiamato 3 volte e disegna lo stesso risultato 3 volte?
Chau,

1
@Chau - Penso che tu avessi ragione, il codice ha ripetuto più volte ogni funzione. Ho modificato il post in modo che funcora dovrebbe essere chiamato solo per ogni linea e trarrà il risultato solo una volta (che sembra essere il caso mostrato dai marcatori di vertici all'interno dei poligoni, prima che questo fosse nascosto sotto il quale mi mancava). Grazie per averlo segnalato :)
Joseph

3

Estendendo la risposta di Joseph , ho escogitato questa funzione. Rappresenta diversi sistemi di coordinate e ho dovuto cercare due livelli di mascheramento, quindi gestisce anche quello. Inoltre volevo essere in grado di mascherare le linee all'interno dei poligoni o le linee all'esterno dei poligoni.

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

Questo esercizio mi ha dimostrato che QGIS non ama troppo lavorare con grandi set di dati e questo algoritmo con QGIS si blocca troppo spesso sulla mia strada. Sospetto che al renderer di QGIS non piaccia renderizzare generatori di geometrie che richiedono tempo.

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.