Есть ли способ выбрать атрибут из слоя многоугольника и вставить значение в виртуальное поле точечного слоя, используя «в» в калькуляторе полей?
CASE
WHEN within($geometry, geometry_polygon) THEN attribute_polygon
END
Есть ли способ выбрать атрибут из слоя многоугольника и вставить значение в виртуальное поле точечного слоя, используя «в» в калькуляторе полей?
CASE
WHEN within($geometry, geometry_polygon) THEN attribute_polygon
END
Ответы:
Встроенный калькулятор поля не поддерживает пространственные объединения между слоями объектов. Но, если вы посмотрите на пост Натана в редакторе функций для выражений qgis, вы сможете понять, что мы можем написать сценарий нашего взаимодействия с данными.
Следующий скрипт позволит вам выразить то, что вы после. Он работает путем перебора всех объектов на слое многоугольника и, если есть пространственное соединение, то ссылается на табличные данные из указанного столбца:
from qgis.core import *
from qgis.gui import *
from qgis.utils import iface
allfeatures = None
index = QgsSpatialIndex()
indexMade = 0
refLayer = None
@qgsfunction(args="auto", group='Custom')
def spatialJoinLookup(layerName, refColumn, defaultValue, geom, feature, parent):
if geom is None:
return defaultValue
# globals so we don't create the index, refLayer more than once
global allfeatures
global index
global indexMade
global refLayer
# Get the reference layer
if refLayer is None:
for layer in iface.mapCanvas().layers():
if layerName == layer.name():
refLayer = layer
break
if refLayer is None:
raise Exception("Layer [" + layerName + "] not found")
# Create the index if not exists
if indexMade == 0:
index = QgsSpatialIndex()
allAttrs = layer.pendingAllAttributesList()
layer.select(allAttrs)
allfeatures = {feature.id(): feature for (feature) in refLayer.getFeatures()}
for f in allfeatures.values():
index.insertFeature(f)
indexMade = 1
# Use spatail index to find intersect
fid = None
ids = index.intersects(geom.boundingBox())
for id in ids:
fid = id
break # Only get the first match.
if fid is not None:
return allfeatures[fid].attribute(refColumn)
# Default
return defaultValue
Ниже приведен пример слоя многоугольника, который у вас может быть. Я также создал соответствующий точечный слой, который вы увидите на последнем изображении.
Обратите внимание: если вы хотите использовать отдельный столбец, вы должны изменить второй аргумент, чтобы он соответствовал имени столбца в наборе данных многоугольника. Например, вы можете использовать столбец «AreaNumber», но он должен соответствовать типу столбца в настройках калькулятора поля.
Вы можете видеть, что значение столбца по умолчанию было применено там, где нет пространственного соединения, а другие сопоставили правильные данные. Обратите внимание, что сценарий, который я дал, будет включен только в первом матче. Вам нужно будет создать какую-то другую бизнес-логику, если ваши полигоны перекрываются.
Это можно сделать в полевом калькуляторе с функцией aggregate()
. В точечном слое создайте новое поле с выражением калькулятора поля следующим образом:
aggregate(
layer:= 'polygon_layer_name',
aggregate:='concatenate',
expression:=joining_field_name,
concatenator:=', ',
filter:=intersects($geometry, geometry(@parent))
)
Где layer
имя слоя многоугольника написано как строка, aggreagate
это агрегатная функция (может использоваться также сумма и т. Д.), expression
Это поле из значений будет взято, concatenator
это соединение символьной строки (должно быть установлено, даже в этом случае) и filter
основанная на функциях фильтрации по выражению (в этом случае геометрия слоя пересекается с геометрией родительского слоя).
Для получения дополнительной информации проверьте документацию Агрегатов QGIS .
Для автоматического обновления могут использоваться виртуальные поля или вы можете установить выражение в качестве значения по умолчанию в настройках формы атрибутов в свойствах слоя ( документация по настройке формы атрибута ).
geometry(@parent)
) поддерживаются только начиная с QGIS 3 и далее. На всякий случай, если кто-то читает это, все еще использует 2.18 ...