Wyrównanie wielu punktów do linii w QGIS?

11

Chciałbym wyrównać wiele punktów do linii lub linii w warstwie, używając określonej tolerancji lub bufora wokół obiektów linii. Proszę odnieść się do załączonego przykładowego szkicu.

Na potrzeby tego przykładu punkty najbliższe linii na obrazie PRZED znajdują się w odległości 5 jednostek mapy od linii, podczas gdy najbardziej oddalone punkty znajdują się w odległości ponad 10 jednostek mapy. Chciałbym przyciągnąć najbliższe punkty do najbliższej linii, stosując tolerancję 5 jednostek mapy, aby osiągnąć wynik na zdjęciu PO.

wprowadź opis zdjęcia tutaj

Ed Camden
źródło
Punkt musi więc wynosić 0 jednostek mapy z boku linii, ale czy obchodzi cię, gdzie punkt kończy się wzdłuż linii względem pierwotnej lokalizacji punktu?
Joe
Idealnym scenariuszem byłoby przesunięcie punktów prostopadłą ścieżką do linii. Jednak intencją jest stosowanie dość małych tolerancji. Jeśli punkty zostaną przesunięte wzdłuż lub wzdłuż, w kierunku linii, nie spowoduje to tak dużego przesunięcia punktów w stosunku do preferowanej pozycji prostopadłej.
Ed Camden,
Nie jestem pewien, czy jest to najlepszy sposób, ale jednym ze sposobów, o którym mogę myśleć, jest napisanie kodu w języku Python w celu przeanalizowania dwóch zestawów danych i wygenerowania współrzędnych punktowych. Jeśli tego właśnie chcesz, daj mi znać, a ja mogę udzielić odpowiedzi. Np. Dla każdego punktu, jeśli wartość bezwzględna lat dist od linii <= 5 jednostek, to odległość boczna = 0. Trzeba będzie zaimportować bibliotekę gdal, aby przekonwertować wartości x, y na współrzędne. Zobacz komentarze w: gis.stackexchange.com/questions/185445/…
Joe
Dzięki PyQGIS można utworzyć warstwę pamięci, w której punkty są przyciągane zgodnie z wcześniej rozważaną tolerancją 5 jednostek mapy i prostopadłą ścieżką do linii. Zobacz moją odpowiedź.
xunilk

Odpowiedzi:

15

W (nie wydanej) wersji QGIS 3.0 jest wbudowane narzędzie do tego. Możesz uzyskać nocną migawkę ze strony internetowej QGIS, aby wcześniej to przetestować.

Aby to zrobić:

  1. Uruchom algorytm przetwarzania „Przyciągaj geometrie do warstw”
  2. Wybierz warstwę punktów jako „warstwę wejściową”
  3. Wybierz warstwę liniową jako „warstwę odniesienia”
  4. Wprowadź odpowiednią tolerancję (maksymalna odległość do przesunięcia punktów podczas przyciągania)
  5. Zmień zachowanie na „Preferuj najbliższy punkt”

wprowadź opis zdjęcia tutaj

Oto wynik, pokazując oryginalne punkty jako „x”, a punkty przyciągania jako zielone kropki. Użyłem tutaj tolerancji, aby przyciągać tylko niektóre punkty wejściowe.

wprowadź opis zdjęcia tutaj

ndawson
źródło
Właśnie tego potrzebuję. Niestety mój pracodawca instaluje tylko wersje QGIS LTR i wszyscy jesteśmy ograniczeni w pobieraniu i instalowaniu wersji testowych. (westchnienie) Myślę, że to kwestia oczekiwania. Czy jest to funkcja standardowa / wbudowana czy wtyczka?
Ed Camden,
Standardowa funkcjonalność polegająca na zmianach w klasach c ++ - nie ma możliwości ręcznego skopiowania tego do starszej wersji. Możesz potencjalnie spróbować zainstalować OSGEO4W na innym komputerze, a następnie skopiować folder osgeo4w na pamięć USB, aby uruchomić go na stacji roboczej. W przeszłości miałem szczęście z takim podejściem.
ndawson,
1
W przypadku starej wersji zapoznaj się z tą wtyczką. docs.qgis.org/2.14/en/docs/user_manual/plugins/…
iRfAn 27.04.17
wygląda na to, że wtyczka nie obsługuje warstw punktów.
Mykola Kozyr
7

Można to zapewnić dzięki PyQGIS . Do następnej sytuacji:

wprowadź opis zdjęcia tutaj

następujący kod, z uwzględnieniem tolerancji 5 jednostek mapy, został uruchomiony w konsoli Pythona w QGIS:

from math import sqrt

registry = QgsMapLayerRegistry.instance()

points = registry.mapLayersByName('points')
line = registry.mapLayersByName('line')

feat_points = [ feat for feat in points[0].getFeatures() ]
feat_line = line[0].getFeatures().next()

new_points = []

for feat in feat_points:
    pt = feat.geometry().asPoint()
    sqrdist, point, vertex = feat_line.geometry().closestSegmentWithContext(pt)
    if sqrt(sqrdist) <= 5:
        new_points.append(point)
    else:
        new_points.append(pt)

epsg = points[0].crs().postgisSrid()

uri = "Point?crs=epsg:" + str(epsg) + "&field=id:integer""&index=yes"

mem_layer = QgsVectorLayer(uri,
                           'new_points',
                           'memory')

prov = mem_layer.dataProvider()

feats = [ QgsFeature() for i in range(len(new_points)) ]

for i, feat in enumerate(feats):
    feat.setAttributes([i])
    feat.setGeometry(QgsGeometry.fromPoint(new_points[i]))

prov.addFeatures(feats)

QgsMapLayerRegistry.instance().addMapLayer(mem_layer)

Stworzono warstwę pamięci, w której punkty były przyciągane zgodnie z wcześniej rozważaną tolerancją 5 jednostek mapy i prostopadłą ścieżką do linii.

wprowadź opis zdjęcia tutaj

Xunilk
źródło
2

Możesz to również zrobić w kalkulatorze polowym za pomocą wtyczki refFunctions. Za pomocą kalkulatora pola można zaktualizować geometrię warstwy, a także pola. refFunctions daje ci funkcję „geomdistance”, aby znaleźć najbliższą linię w danej odległości (lub „geomnearest”, jeśli nie chcesz progu) i zwróci atrybut lub geometrię, a funkcja „closest_point” znajdzie najbliższą punkt na danej geometrii. Połącz je tak, aby obliczyć nowe geometrie dla swojej warstwy punktowej:

closest_point(geom_from_wkt(geomdistance('snap_lines','$geometry',10)) , $geometry)

Zamiast bezpośrednio aktualizować geometrię, możesz obliczyć pole za pomocą przyciąganej geometrii. Przechowuję wiele geometrii do przyciągania punktów przepustu do różnych warstw strumienia i mogę łatwo zaktualizować geometrię punktu w Kalkulatorze pola w zależności od tego, których linii strumienia muszę użyć.

Istnieją pewne ograniczenia, obie warstwy muszą być tym samym CRS, a funkcja geomdistance wyświetli błąd, jeśli masz więcej niż 100 000 punktów, ale możesz zmienić ten limit, jeśli edytujesz plik wtyczki refFunctions.

amcaninch
źródło