Wie berechne ich die Manhattan-Entfernung mit PostGIS?

9

Ich verwende die ST_Distance-Funktion, um den Abstand zwischen zwei Geometrien (einem Bahnhof und einem Gebäude) zu berechnen. Da ich weiß, dass sich alle Gebäude und alle Bahnhöfe in Chicago befinden, das über ein ausgezeichnetes / vollständiges Straßenraster verfügt, möchte ich Manhattan verwenden (oder Taxi) Entfernung .

Die generische Formel hierfür ist die Differenz in X plus die Differenz in Y, also Abs (X1-X2) + Abs (Y1-Y2).

Mit welcher PostgreSQL-Abfrage würde dies funktionieren?

stevevance
quelle
1
Ein kurzer Gedanke hier: Ihr Gitter 'x' und 'y' müssen nicht unbedingt mit den 'x' und 'y' des Koordinatensystems ausgerichtet sein. Daher müssen Sie möglicherweise den Vektor drehen, bevor Sie die Komponenten extrahieren und berechnen können.
Craig Ringer
@CraigRinger Ich transformiere die Koordinaten in die lokal vorherrschende Projektion EPSG 3435, Illinois StatePlane East Feet. Dies wird von der Stadt Chicago für alle ihre GIS-Arbeiten verwendet. Ich habe meine eigene Frage mit einer Validierung mithilfe der Berechnung der Gehentfernung von Google Maps beantwortet.
Stevevance
1
Haben Sie auch darüber nachgedacht, Ihre PostGIS-Daten mit dem pgRouting- Modul zu erweitern und die integrierten Funktionen zu verwenden? Anscheinend verwendet die A * -Methode etwas Ähnliches .
RyanKDalton
@RyanDalton Ich habe überlegt, pgRouting für ein anderes Projekt von mir zu verwenden, aber der Aufwand, eines für dieses Projekt einzurichten , ist die genaueren Ergebnisse oder die Ressourcenkosten bei der Berechnung der Route nicht wert.
Stevevance

Antworten:

6

Ich beantworte meine eigene Frage mit einer vorgeschlagenen Anfrage.

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

Dies führt zu Folgendem, wobei einige Spalten herausgeschnitten wurden:

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

Die erste nummerierte Spalte ist die Entfernung (in Fuß, da ich EPSG 3435 verwende), die von der ST_Distance PostGIS-Funktion berechnet wurde, und die zweite nummerierte Spalte ist das Ergebnis der Manhattan-Entfernungsformel.

Ich habe das zweite Ergebnis vor Ort überprüft und den Fußweg von Google Maps zwischen der CTA-Station Addison Blue Line und dem Gebäude in der Belle Plaine Ave 3226 W (in der Abfrage als "100533644" angegeben) ermittelt. Google Maps gab eine Wanderroute von 1,1 Meilen aus, während das Postgres-Ergebnis 5,790 Fuß = 1,09 Meilen betrug. Der Unterschied ist für meine Zwecke akzeptabel.

stevevance
quelle
1
Das ist großartig - Sie haben möglicherweise ein Problem gelöst, das ansonsten in der PGRouting-Funktion "Fahrstrecke" behandelt wird ... Ich werde dies auf einige Probleme testen, die wir bei DPS haben ...!
DPSSpatial
@mapBaker Danke! pgRouting ist zu komplex für meine einfache Mathematik.
Stevevance
3

Ich denke, ich habe auch eine etwas elegantere Lösung gefunden, die Trigonometrie und die eingebaute ST_AzimuthFunktion verwendet und sie in eine schöne Funktion eingekapselt hat:

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
quelle