Jak odnieść się do innej warstwy w kalkulatorze polowym?

26

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

wprowadź opis zdjęcia tutaj

Morze Księżycowe
źródło
1
Dlaczego nie wykorzystać do tego wtyczki „Point Sampling Tool”?
Jakob,
Ponieważ potrzebuję dynamicznych aktualizacji podczas tworzenia nowych punktów lub przenoszenia istniejących punktów.
Lunar Sea
Lepiej byłoby napisać skrypt do tej interakcji niż polegać na gotowych narzędziach.
nagytech
Niestety nie mam doświadczenia ze skryptami.
Lunar Sea
@LunarSea Poniżej napisałem przykład, który możesz naśladować, ale być może będziesz musiał go dostosować, aby pasował do twoich potrzeb.
nagytech

Odpowiedzi:

22

Połączenia przestrzenne są dostępne w kalkulatorze polowym po zainstalowaniu wtyczki refFunctions.

geomwithin(targetLayer,targetField)
Morze Księżycowe
źródło
Wtyczki są znacznie prostsze niż używanie skryptu niestandardowego. Dzięki!
jpmc26
geomwithin („targetLayer”, „targetField”).
Raja
19

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

Przykład warstwy wielokąta

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.

wprowadź opis zdjęcia tutaj

Wykorzystanie wyrażenia

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.

wprowadź opis zdjęcia tutaj

Wynik

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ą.

wprowadź opis zdjęcia tutaj

nagytech
źródło
Wielkie dzięki, twój skrypt działa dobrze, używając „geom” zamiast „geometrii” w pierwszej instrukcji „if”. Łączenie geometrii w ten sposób może być bardzo przydatne np. Do tworzenia wielu etykiet na wielokątach.
Lunar Sea
Przepraszam, nie wiem jak mi tego brakowało. Mam nadzieję, że nie ma problemów z wydajnością - wypróbowałem to tylko z bardzo małym podzbiorem rekordów.
nagytech
Mając tylko ponad 100 punktów, QGIS ma problemy z wydajnością. Dodanie nowej operacji punktowej jest naprawdę uciążliwe, nawet jeśli nie ma żadnej operacji punktowej wyświetlanej w obszarze roboczym. W przeciwnym razie przy powiększaniu QGIS przyspieszy. Próbowałem „CASE WHEN $ scale <10000 THEN spatialJoinLookupI („ Polygons ”,„ AreaName ”,„ None ”, $ geometry) END”, ale nie działa. Czy mogę coś zrobić, aby poprawić wydajność?
Morze Księżycowe
@LunarSea Zaktualizowałem funkcję, aby używać indeksu przestrzennego. Powinno być znacznie szybsze.
nagytech,
Dzięki za pomoc. Łączenie przestrzenne jest teraz znacznie szybsze, ale niestety coś nie działa poprawnie. Otrzymuję różne wyniki dla punktów w tym samym wielokącie.
Morze
8

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 layernazwa warstwy wieloboku jest zapisywana jak ciąg znaków, aggreagateczy funkcja agregująca (może być używana także suma itp.), Czy expressionpole z wartości zostanie wzięte, concatenatorłączy ciąg znaków (musi być ustawiony, nawet w tym przypadku) i filteropiera 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 ).

wprowadź opis zdjęcia tutaj

Oto Kaláb
źródło
3
Należy zauważyć, że funkcje przestrzenne (z 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 ...
she_weeds
Dziękuję Ci. Działa jak marzenie.
przemyślenia przestrzenne