Стилізація певного шару за допомогою багатокутної маски в QGIS?


10

У мене в QGIS є лінійний та багатокутний шар:

Перед маскою

Я б хотів стилізувати частину шару лінії поза полігоном, використовуючи один стиль, а частину всередині, використовуючи інший стиль:

Після маски

Я не хочу створювати похідний набір даних, напр. обріжте шар лінії та накресліть дві частини.

Це простий випадок, але в моєму проекті QGIS у мене є +30 шарів, тому я думаю, що будь-яке змішування шарів може порушити основні шари.

Чи можна зробити щось подібне?

Я не хочу показувати багатокутний шар, він просто тут, щоб візуалізувати, що я хотів би зробити.


1
Гарний метод! Я думаю, що це слід розмістити як відповідь замість редагування на питання :)
Джозеф

@ Джозеф, це зроблено!
Чау

Відповіді:


11

Не ідеальне рішення, але ви можете скористатися Генератором геометрії, який додає візуалізовану лінію для зображення перетину. Потім ви можете встановити це для перекриття оригінальної функції рядка.

Додайте новий шар символу, натиснувши знак плюс і виберіть Geometry generatorтип шару символу. Встановіть тип геоелектрики LineString / MultiLineStringта використовуйте такий вираз:

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

Вам потрібно буде додати деталі щодо вашого конкретного багатокутника, де:

  • polygonLayer - назва шару вашого багатокутника
  • fieldName - це назва поля
  • value - це значення функції вашого конкретного багатокутника

Властивості стилю

Зауважте, що для фарбування візуальної лінії вам може знадобитися це зробити із властивості Draw ефекти :

Властивості малювання ефектів

Це було результатом (зауважте, що візуальна лінія повністю не перекривала початкову лінію, тому я трохи змінив зміщення):

Результат

І без полігону:

Результат без багатокутника



Редагувати:

Якщо ви хочете, щоб це застосовувалося до кожної функції рядка, що перетинає функцію багатокутника, перейдіть до редактора функцій та скористайтеся наступною функцією (змініть ім'я 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 - Відредагований пост, щоб включити можливий метод :)
Йосип

1
Іншим варіантом було б розчинення багатокутного шару.
csk

1
@Joseph - Коли використовується a, Geometry Generatorвикликається метод funcдля кожної функції на шарі, де він використовується для стилізації? Отже, якщо мій рядок має 3 функції, то funcвін називається 3 рази і малює той же результат 3 рази?
Чау

1
@Chau - Я думаю, ти мав рацію, код повторювався через кожну функцію кілька разів. Відредагував публікацію так, що funcтепер слід викликати лише кожну функцію рядка і отримає результат лише один раз (що, здається, так, як показано маркерами вершин всередині багатокутників, до того, як це було приховано під яким я пропустив). Дякуємо, що вказали на це :)
Жозеф

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 не любить виводити Геометричні генератори, які забирають багато часу.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.