Czy istnieje sposób na wybranie atrybutu z warstwy wielokąta i wstawienie wartości do wirtualnego pola warstwy punktowej za pomocą „wewnątrz” w kalkulatorze pola?
CASE
WHEN within($geometry, geometry_polygon) THEN attribute_polygon
END
Czy istnieje sposób na wybranie atrybutu z warstwy wielokąta i wstawienie wartości do wirtualnego pola warstwy punktowej za pomocą „wewnątrz” w kalkulatorze pola?
CASE
WHEN within($geometry, geometry_polygon) THEN attribute_polygon
END
Odpowiedzi:
Po wyjęciu z pudełka kalkulator pola nie obsługuje połączeń przestrzennych między warstwami elementów. Ale jeśli spojrzysz na post NathanW w edytorze funkcji dla wyrażeń qgis , będziesz w stanie zrozumieć, że możemy napisać skrypt na temat naszej interakcji z danymi.
Poniższy skrypt pozwoli Ci wyrazić to, czego szukasz. Działa poprzez iterację przez wszystkie operacje na warstwie wielokąta, a jeśli istnieje połączenie przestrzenne, odwołaj się do danych tabelarycznych z określonej kolumny:
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
Poniżej znajduje się przykład warstwy wieloboku, którą możesz mieć. Stworzyłem również odpowiednią warstwę punktową, którą zobaczysz na ostatecznym obrazie.
Uwaga: jeśli chcesz użyć osobnej kolumny, musisz zmienić drugi argument, aby pasował do nazwy kolumny w zestawie danych wielokąta. Przykład: możesz użyć kolumny „Numer_numeru”, ale musisz dopasować typ kolumny w ustawieniach kalkulatora pola.
Możesz zobaczyć, że domyślna wartość kolumny została zastosowana tam, gdzie nie ma łączenia przestrzennego, a pozostałe dopasowały prawidłowe dane. Uwaga: skrypt, który podałem, dołączy tylko przy pierwszym meczu. Musisz stworzyć inną logikę biznesową, jeśli twoje wielokąty się nakładają.
Można to zrobić w kalkulatorze polowym z funkcją aggregate()
. W warstwie punktowej utwórz nowe pole z wyrażeniem kalkulatora pola, takim jak to:
aggregate(
layer:= 'polygon_layer_name',
aggregate:='concatenate',
expression:=joining_field_name,
concatenator:=', ',
filter:=intersects($geometry, geometry(@parent))
)
Gdzie layer
nazwa warstwy wieloboku jest zapisywana jak ciąg znaków, aggreagate
czy funkcja agregująca (może być używana także suma itp.), Czy expression
pole z wartości zostanie wzięte, concatenator
łączy ciąg znaków (musi być ustawiony, nawet w tym przypadku) i filter
opiera się na funkcjach filtrowania po wyrażeniu (w tym przypadku przecina geometrię warstwy z geometrią warstwy macierzystej).
Aby uzyskać więcej informacji, sprawdź dokumentację agregującą QGIS .
Do automatycznych aktualizacji można użyć pól wirtualnych lub można ustawić wyrażenie jako wartość domyślną w ustawieniach formularza atrybutów we właściwościach warstwy ( dokumentacja ustawień formularza atrybutu ).
geometry(@parent)
) są obsługiwane tylko od QGIS 3 i późniejszych. Na wypadek, gdyby ktoś czytający to nadal korzystał z wersji 2.18 ...