通过在QGIS中使用多边形蒙版来对特定图层进行样式设置?


10

我在QGIS中有一个线层和一个多边形层:

面膜前

我想使用一种样式来设置多边形外部的线层部分,并使用另一种样式来设置内部的部分线型:

面膜后

我不想创建衍生数据集,例如。剪辑线层并设置两个部分的样式。

这是一个简单的情况,但是在我的QGIS项目中,我有+30层,因此我认为任何层混合都会干扰底层。

可以做这样的事情吗?

我不想显示多边形层,它只是在这里可视化我想做的事情。


1
好方法!我认为应该将其发布为答案,而不是对问题进行编辑:)
约瑟夫(Joseph)

@Joseph,完成了!

Answers:


11

这不是一个完美的解决方案,但您可以使用“ 几何图形生成器”,该几何图形生成器添加了一条可视化的线来表示相交。然后,您可以将其设置为与原始线要素重叠。

通过单击加号添加新的符号层,然后选择Geometry generator作为符号层类型。将geoemtry类型设置为LineString / MultiLineString并使用以下表达式:

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

您需要在以下位置添加有关特定多边形的详细信息:

  • polygonLayer 是多边形图层的名称
  • fieldName 是字段的名称
  • value 是您特定多边形的要素值

样式属性

请注意,要为视线着色,您可能需要在Draw Effects属性中完成:

绘图效果属性

这是结果(请注意,可视线未与原始线完全重叠,因此我稍微修改了偏移量):

结果

并且没有多边形:

没有多边形的结果



编辑:

如果要将其应用于与多边形要素相交的每个线要素,请转到函数编辑器并使用以下函数(更改名称polygon example_2以匹配多边形层的名称):

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

功能编辑器

单击“ 加载”,然后转到“ 表达式”选项卡并键入func()。希望结果应如下所示(使用上述相同的样式属性):

最后结果


我实际上看了一下,但是发现时停了下来,这get_feature需要字段名称和值。我只有一个多边形图层,想使用该图层上的所有要素进行遮罩。那可能吗?

@Chau-编辑过的帖子,包括了一种可能的方法:)
Joseph

1
另一种选择是溶解多边形层。
csk

1
@Joseph-使用a时,Geometry Generatorfunc为图层上用于样式设置的每个要素调用该方法吗?因此,如果我的线层具有3个要素,那么func被称为3次并绘制相同结果3次?

1
@Chau-我认为您是对的,该代码多次遍历每个功能。编辑了帖子,使其func现在仅应按每个线要素调用,并且只会绘制一次结果(似乎是这种情况,如多边形内部的顶点标记所示,然后隐藏在我错过的下方)。感谢您指出:)
约瑟夫(Joseph)

3

扩展约瑟夫的答案,我想出了这个功能。它考虑了不同的坐标系,我需要查找两个遮罩层,因此它也可以处理。此外,我希望能够掩盖多边形内的线或多边形外的线。

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

这项练习向我展示了QGIS不太喜欢使用大型数据集,并且这种带有QGIS的算法经常崩溃。我怀疑QGIS渲染器不喜欢渲染费时的Geometry Generators。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.