Jak uzyskać najbliższy punkt na linii do danego punktu?

28

Od dłuższego czasu korzystam z PostGIS, ale nigdy nie musiałem używać LINESTRINGgeometrii ...! :)

Oto, co chciałbym zrobić: mam tabelę linii (reprezentujących ulice danego miasta, SRID 3395) i chciałbym znaleźć najbliższe linie do danego punktu (pozycja GPS, SRID 4326).

Rozwiązaniem, które znalazłem, jest wybranie wszystkich linii wewnątrz mojego punktu za pomocą expand()metody i określenie odległości między każdym linią i moim punktem za pomocą ST_Distance()metody.

Oto SQL:

SELECT myLineId, myLineName, ST_Distance(ST_Transform(GeomFromText('POINT(LON LAT)',4326),3395),myLineGeom) AS myLineDistance
FROM myLines
WHERE myLineGeom && expand(ST_Transform(GeomFromText('POINT(LON LAT)',4326),3395), 100)
ORDER BY myLineDistance;

Wyniki wyglądają OK, ale mam wrażenie, że coś jest nie tak z moją implementacją.

1) Czy uważasz, że expand()można uzyskać wszystkie niepokojące linie?

2) Czy uważają Państwo, że ST_Distance()jest to właściwa metoda? Myślę, że robię to źle, ponieważ odległość, którą chciałbym uzyskać, jest najmniejszą odległością między punktem a moją linią, a nie odległością między punktem a jednym z punktów linii.

Ilustracja:

alternatywny tekst

Vivi
źródło

Odpowiedzi:

11

ad 1) Patrząc na dokumentację używanych funkcji, powiedziałbym: „Tak, wszystkie odnośne linie zostaną znalezione”.

rozwiń (geometria, liczba zmiennoprzecinkowa)

Ta funkcja zwraca obwiednię rozszerzoną we wszystkich kierunkach z obwiedni geometrii wejściowej o wartość określoną w drugim argumencie. Bardzo przydatne w zapytaniach o odległość (), aby dodać filtr zapytania do zapytania.

A i&B

Operator „&&” jest operatorem „nakładającym się”. Jeśli obwiednia A nachodzi na obwiednię B, operator zwraca wartość true.

ad 2) Powinieneś być w stanie osiągnąć to, co chcesz:

line_interpolate_point(linestring, line_locate_point(LineString, Point))

line_interpolate_point (oznaczenie linii, lokalizacja)

Interpoluje punkt wzdłuż linii. Pierwszym argumentem musi być LINESTRING. Drugi argument to liczba zmiennoprzecinkowa 8 między 0 a 1, reprezentująca ułamek całkowitej długości 2d, w której punkt musi być zlokalizowany.

line_locate_point (LineString, Point)

Zwraca liczbę zmiennoprzecinkową między 0 a 1, reprezentującą lokalizację najbliższego punktu na LineString do danego punktu, jako ułamek całkowitej długości linii 2d. Możesz użyć zwróconej lokalizacji, aby wyodrębnić punkt (point_interpolate_point)

Źródło: http://main.merlin.com.ua/doc/postgis/docs/ch06.html

podmrok
źródło
W przypadku punktu 2) zastanawiałem się tylko, czy ST_Distance między geometrią POINT a geometrią LINESTRING daje najmniejszą możliwą odległość między tezami (czyli długość linii prostopadłej między POINT a LINGESTRING); Chcę odległość od każdej geometrii LINESTRING :)
Vivi
I chyba nie szukam odległości, ponieważ „funkcja line_locate_point daje wartość od 0 do 1 reprezentującą lokalizację najbliższego punktu na LineString do danego punktu”: /
Vivi
Obawiam się, że straciłeś mnie w swoim ostatnim komentarzu. Teraz nie jestem już pewien, czego chcesz;)
podmrok
1
Przepraszam :) Chciałbym to: podając geometrię LINESTRING (reprezentującą ścieżkę) i geometrię POINT, chcę mieć najbliższą geometrię POINT, która znajduje się na ścieżce (która może nie być punktem definicji geometrii LINESTRING). Czy to jest jasne? Może powinienem zaktualizować swój post rysunkiem: D
Vivi
Nie mogę zaktualizować mojego postu, więc oto link do rysunku tego, co chciałbym uzyskać: i.imgur.com/UwPxo.jpg
Vivi
7

Halo

Najpierw pytanie o to, co zwraca ST_Distance. ST_Distance zwraca najkrótszą odległość między linią a punktem (lub jakie typy geometrii są wprowadzone) Oznacza to, że ST_Distance między punktem (1 3) a linestring (0 0,0 10) zwróci 1. Odległość nie będzie mierzona między punkt i (0 0) lub punkt i (0 10), ale od punktu (1 3) do (0 3).

Z tego, co rozumiem, ST_Distance daje odpowiedź, której potrzebujesz.

Jeśli chcesz znaleźć punkt (0 3) w powyższym przykładzie, możesz użyć ST_Closestpoint, jeśli masz PostGIS 1.5. W moim przykładzie używasz go w następujący sposób: ST_Closestpoint ('LINESTRING (0 0,0 10)' :: geometria, ' PUNKT (1 3) ':: geometria), powinieneś otrzymać w zamian punkt (0 3), punkt na linii najbliżej twojego punktu.

HTH Nicklas

Nicklas Avén
źródło
5

Znalazłem to :) (No chyba: P)

Za pomocą ST_Line_Locate_Point()i ST_Line_Interpolate_point()udało mi się uzyskać punkt, który NIE JEST częścią definicji LINESTRING, ale JEST na tej linii :) Wszystko, co muszę zrobić, to uzyskać odległość od mojego punktu do tego punktu i gotowe.

SELECT AsText(ST_Line_Interpolate_Point(myLineGeom,ST_Line_Locate_Point(myLineGeom,ST_Transform(GeomFromText('POINT(LON LAT)',4326),3395))))
FROM myLines
WHERE myGeom && expand(ST_Transform(GeomFromText('POINT(LON LAT)',4326),3395), 100)

ST_Line_Locate_Point()Sposób znaleźć lokalizację najbliższego punktu na linii do danej kwestii, ST_Line_Interpolate_Pointmetoda włączyć tę lokalizację do punktu.

Vivi
źródło
1
Odległość między punktem a linią daje tę samą odpowiedź. Jak myślisz, dlaczego musisz to zrobić w ten sposób?
Nicklas Avén
1
Myślę, że ST_Distance może być używany z dowolnym rodzajem geometrii. postgis.refractions.net/docs/ST_Distance.html :ST_Distance(geometry g1, geometry g2)
Magno C
2

Ten wątek archiwalny Postgis może Ci odpowiedzieć http://postgis.refractions.net/pipermail/postgis-users/2007-June/016045.html

ThomasG77
źródło
refractions.net nie działa dla mnie: „refractions.net wygasł 14.09.2010 i oczekuje na odnowienie lub usunięcie”.
podmroku
@underdark to działa dla mnie
dassouki
@dassouki: to dziwne: |
podmroku
@underdark refractions.net znów działa
ThomasG77