Come posso calcolare la distanza di Manhattan con PostGIS?


9

Sto usando la funzione ST_Distance per calcolare la distanza tra due geometrie (una stazione ferroviaria e un edificio) Poiché so che tutti gli edifici e tutte le stazioni ferroviarie si trovano a Chicago, che ha una griglia stradale eccellente / completa, vorrei usare Manhattan (o taxi) distanza .

La formula generica per questo è la differenza in X più la differenza in Y, quindi Abs (X1-X2) + Abs (Y1-Y2).

Quale query PostgreSQL farebbe funzionare questo?


1
Un rapido pensiero qui: la tua griglia 'x' e 'y' non sono necessariamente allineate con 'x' e 'y' del sistema di coordinate. Quindi potrebbe essere necessario ruotare il vettore prima di estrarre i componenti e il calcolo.
Craig Ringer,

@CraigRinger Trasformo le coordinate nella proiezione prevalente a livello locale, EPSG 3435, Illinois StatePlane East Feet. Questo è usato dalla City di Chicago per tutto il suo lavoro GIS. Ho risposto alla mia domanda con qualche convalida utilizzando il calcolo della distanza a piedi di Google Maps.
stevevance,

1
Hai anche considerato di estendere i tuoi dati PostGIS con il modulo pgRouting e di utilizzarne le funzioni integrate? Apparentemente il metodo A * usa qualcosa di simile .
RyanKDalton,

@RyanDalton Ho preso in considerazione l'utilizzo di pgRouting per un altro mio progetto, ma la seccatura di crearne uno per questo progetto non vale i risultati più accurati o il costo delle risorse nel calcolo del percorso.
stevevance,

Risposte:


6

Sto rispondendo alla mia domanda con una domanda proposta.

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

Ciò comporta quanto segue con alcune colonne ritagliate:

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

La prima colonna numerata è la distanza (in piedi, perché sto usando EPSG 3435) calcolata dalla funzione Post_GIS ST_Distance e la seconda colonna numerata è il risultato della formula della distanza di Manhattan.

Ho controllato il secondo risultato, ottenendo la distanza a piedi da Google Maps tra la stazione CTA Addison Blue Line e l'edificio al 3226 W Belle Plaine Ave (indicato come "100533644" nella query). Google Maps ha prodotto un percorso a piedi di 1,1 miglia mentre il risultato di Postgres di 5.790 piedi = 1,09 miglia. La differenza è accettabile per i miei scopi.


1
questo è fantastico - potresti aver risolto un problema che altrimenti verrebbe risolto nella funzione "distanza di guida" di PGRouting ... Lo testerò per alcuni problemi che abbiamo al DPS ...!
DPSSpatial

@mapBaker Grazie! pgRouting è troppo complesso per le mie semplici esigenze matematiche.
stevevance,

3

Penso di aver anche trovato una soluzione leggermente più elegante che utilizza la trigonometria e la ST_Azimuthfunzione integrata e la incapsula in una bella funzione:

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.