Stylen einer bestimmten Ebene mithilfe einer Polygonmaske in QGIS?

10

Ich habe eine Linienebene und eine Polygonebene in QGIS:

Vor der Maske

Ich möchte den Teil der Linienebene außerhalb des Polygons mit einem Stil und den Teil innerhalb mit einem anderen Stil formatieren:

Nach der Maske

Ich möchte keinen abgeleiteten Datensatz erstellen, z. Clip die Linienebene und gestalte die beiden Teile.

Dies ist ein einfacher Fall, aber in meinem QGIS-Projekt habe ich +30 Ebenen, sodass ich denke, dass jede Ebenenüberblendung die zugrunde liegenden Ebenen stören würde.

Ist es möglich so etwas zu tun?

Ich möchte die Polygonebene nicht anzeigen, sondern nur, um zu visualisieren, was ich tun möchte.

Chau
quelle
1
Schöne Methode! Ich denke, das sollte als Antwort anstatt als Bearbeitung der Frage gepostet werden :)
Joseph
@ Joseph, es ist geschafft!
Chau

Antworten:

11

Keine perfekte Lösung, aber Sie können den Geometrie-Generator verwenden, der eine visualisierte Linie zur Darstellung des Schnittpunkts hinzufügt. Sie können dies dann so einstellen, dass es die ursprüngliche Linienfunktion überlappt.

Fügen Sie eine neue Symbolebene hinzu, indem Sie auf das Pluszeichen klicken und den Geometry generatorTyp als Symbolebene auswählen . Stellen Sie den Geoemtry-Typ auf ein LineString / MultiLineStringund verwenden Sie den folgenden Ausdruck:

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

Sie müssten Details zu Ihrem spezifischen Polygon hinzufügen, wobei:

  • polygonLayer ist der Name Ihrer Polygonebene
  • fieldName ist der Name des Feldes
  • value ist der Merkmalswert Ihres spezifischen Polygons

Stileigenschaften

Beachten Sie, dass Sie die visuelle Linie möglicherweise über die Eigenschaft " Effekte zeichnen" ausmalen müssen, um sie einzufärben :

Eigenschaften von Zeichnungseffekten

Dies war das Ergebnis (beachten Sie, dass die visuelle Linie die ursprüngliche Linie nicht vollständig überlappte, sodass ich den Versatz geringfügig geändert habe):

Ergebnis

Und ohne das Polygon:

Ergebnis ohne Polygon



Bearbeiten:

Wenn Sie möchten, dass dies für jedes Linien-Feature angewendet wird, das ein Polygon-Feature schneidet, rufen Sie den Funktionseditor auf und verwenden Sie die folgende Funktion (ändern Sie den Namen von polygon example_2, um ihn an den Namen Ihrer Polygon-Ebene anzupassen):

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

Funktionseditor

Klicken Sie auf Laden, wechseln Sie zur Registerkarte Ausdruck und geben Sie ein func(). Hoffentlich sollte das Ergebnis wie folgt aussehen (unter Verwendung der oben genannten Stileigenschaften):

Endergebnis

Joseph
quelle
Ich habe mir das tatsächlich angesehen, aber aufgehört, als ich herausfand, dass dies get_featureFeldname und Wert erfordert. Ich habe nur eine Polygonebene und möchte alle Funktionen auf dieser Ebene zum Ausblenden verwenden. Ist das möglich?
Chau
@Chau - Bearbeiteter Beitrag, um eine mögliche Methode
Joseph
1
Eine andere Möglichkeit wäre, die Polygonebene aufzulösen.
csk
1
@Joseph - Wird bei Verwendung von a Geometry Generatordie Methode funcfür jedes Feature auf der Ebene aufgerufen, auf der es für das Styling verwendet wird? Wenn meine Linienebene drei Features hat, wird sie dann funcdreimal aufgerufen und dreimal das gleiche Ergebnis gezeichnet?
Chau
1
@Chau - Ich denke, Sie hatten Recht, der Code durchlief jede Funktion mehrmals. Der Beitrag wurde so bearbeitet, dass er funcjetzt nur für jedes Zeilen-Feature aufgerufen werden sollte und das Ergebnis nur einmal gezeichnet wird (was anscheinend der Fall ist, wie durch die Scheitelpunktmarkierungen in den Polygonen gezeigt, bevor dies verborgen war, unter dem ich es verpasst habe). Vielen Dank für den Hinweis :)
Joseph
3

Ausgehend von Josephs Antwort habe ich mir diese Funktion ausgedacht. Es berücksichtigt unterschiedliche Koordinatensysteme und ich musste in zwei Maskierungsebenen nachschlagen, daher behandelt es auch das. Außerdem wollte ich in der Lage sein, entweder die Linien innerhalb der Polygone oder die Linien außerhalb der Polygone zu maskieren.

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

Diese Übung hat mir gezeigt, dass QGIS nicht besonders gern mit großen Datenmengen arbeitet und dieser Algorithmus mit QGIS zu oft auf meinem Weg abstürzt. Ich vermute, dass der QGIS-Renderer keine zeitaufwändigen Geometriegeneratoren rendern möchte.

Chau
quelle