Jak obliczyć odległość na Manhattanie za pomocą PostGIS?

9

Używam funkcji ST_Distance obliczyć odległość między dwoma geometrii (a dworzec kolejowy i budynek), ponieważ wiem, że wszystkie budynki i wszystkie stacje kolejowe znajdują się w Chicago, który ma doskonałą / pełna ulicy siatkę, chciałbym użyć Manhattan (lub taksówka) odległość .

Ogólny wzór na to jest różnica w X plus różnica w Y, więc Abs (X1-X2) + Abs (Y1-Y2).

Jakie zapytanie PostgreSQL by działało?

stevevance
źródło
1
Krótka myśl tutaj: Twoja siatka „x” i „y” niekoniecznie są wyrównane z „x” i „y” układu współrzędnych. Może więc być konieczne obrócenie wektora przed wyodrębnieniem składników i obliczeniem.
Craig Ringer
@CraigRinger Przekształcam współrzędne do lokalnie dominującej projekcji, EPSG 3435, Illinois StatePlane East Feet. Jest to wykorzystywane przez miasto Chicago do wszystkich swoich prac związanych z GIS. Odpowiedziałem na moje pytanie z pewną poprawnością, korzystając z obliczeń odległości w Mapach Google.
stevevance
1
Czy rozważałeś także rozszerzenie swoich danych PostGIS o moduł pgRouting i korzystanie z jego wbudowanych funkcji? Najwyraźniej metoda A * używa czegoś podobnego .
RyanKDalton
@RyanDalton ja uważane za pomocą pgRouting na inny projekt kopalni , ale kłopotów ustawienie jednego się do tego projektu nie jest warte dokładniejsze wyniki lub koszt zasobu w obliczaniu trasy.
stevevance

Odpowiedzi:

6

Odpowiadam na moje pytanie proponowanym zapytaniem.

select *, ABS(x_permit-x_station)+ABS(y_permit-y_station) as manhattan FROM (SELECT
longname AS NAME,
lines AS metadata,
T .slug,
ST_Distance (
    T .geom,
    ST_Transform (P .geometry, 3435)
) AS distance, 
ST_X(ST_Transform(p.geometry, 3435)) as x_permit,
ST_Y(ST_Transform(p.geometry, 3435)) as y_permit,
ST_X(t.geom) as x_station,
ST_Y(t.geom) as y_station
FROM
permits P,
stations_cta T
WHERE
P .permit_ = '100533644'
ORDER BY
distance
LIMIT 2) as foo

Powoduje to, że niektóre kolumny zostały wycięte:

Kedzie-Ravenswood   Brown Line  3738.52830193659    3796.29623843171
Addison-O'Hare  Blue Line   4105.37381385087    5790.20002649655

Pierwsza ponumerowana kolumna to odległość (w stopach, ponieważ używam EPSG 3435) obliczona przez funkcję ST_Distance PostGIS, a druga ponumerowana kolumna jest wynikiem formuły odległości na Manhattanie.

Sprawdziłem punktowo drugi wynik, uzyskując odległość od Map Google między stacją CTA Addison Blue Line a budynkiem przy 3226 W Belle Plaine Ave (w zapytaniu oznaczonym jako „100533644”). Mapy Google wygenerowały trasę pieszą o długości 1,1 mili, podczas gdy wynik Postgres wynoszący 5790 stóp = 1,09 mili. Różnica jest do zaakceptowania dla moich celów.

stevevance
źródło
1
to jest świetne - być może rozwiązałeś problem, który w innym przypadku zostałby rozwiązany w funkcji PGRouting „odległość jazdy” ... Przetestuję to pod kątem niektórych problemów, które mamy w DPS ...!
DPSSpatial
@mapBaker Thanks! pgRouting jest zbyt skomplikowany dla mojej prostej potrzeby matematycznej.
stevevance
3

Myślę, że znalazłem również nieco bardziej eleganckie rozwiązanie, które wykorzystuje trygonometrię i wbudowaną ST_Azimuthfunkcję i zamknęło ją w ładną funkcję:

CREATE OR REPLACE FUNCTION JZ_TaxiCab(p1 geometry, p2 geometry)
RETURNS REAL AS $$
DECLARE 
    az REAL;
    h REAL;
BEGIN
    az := ST_Azimuth(p1, p2);
    /* Cast to geography to get result in meters */
    h := ST_Distance(p1::geography, p2::geography);
    /*   Note: we have to take abs() because the values returned by
         can be positive or negative. We really don't necessarily care
         about the reference point since it's going to be a right triangle.
    */
    RETURN h * abs(sin(az)) + h * abs(cos(az));
END;
$$  LANGUAGE plpgsql
jzarob
źródło