Bagaimana cara menghitung jarak Manhattan dengan PostGIS?

9

Saya menggunakan fungsi ST_Distance untuk menghitung jarak antara dua geometri (stasiun kereta api dan gedung) Karena saya tahu bahwa semua bangunan dan semua stasiun kereta api berada di Chicago, yang memiliki jaringan jalan yang sangat baik / lengkap, saya ingin menggunakan Manhattan (atau taksi) jarak .

Rumus generik untuk ini adalah perbedaan dalam X ditambah perbedaan dalam Y, jadi Abs (X1-X2) + Abs (Y1-Y2).

Query PostgreSQL apa yang membuat ini bekerja?

stevevance
sumber
1
Sebuah pemikiran cepat di sini: Kotak Anda 'x' dan 'y' tidak selalu selaras dengan 'x' dan 'y' sistem koordinat. Jadi, Anda mungkin perlu memutar vektor sebelum mengekstraksi komponen dan menghitung.
Craig Ringer
@CraigRinger I mengubah koordinat ke proyeksi yang berlaku secara lokal, EPSG 3435, Illinois StatePlane East Feet. Ini digunakan oleh Kota Chicago untuk semua pekerjaan GIS-nya. Saya telah menjawab pertanyaan saya sendiri dengan beberapa validasi menggunakan perhitungan Google Maps walking distance.
stevevance
1
Sudahkah Anda mempertimbangkan untuk memperpanjang data PostGIS Anda dengan modul pgRouting dan menggunakan fungsi bawaannya ? Rupanya metode A * menggunakan sesuatu yang serupa .
RyanKDalton
@RyanDalton Saya telah mempertimbangkan menggunakan pgRouting untuk proyek saya yang lain, tetapi kesulitan untuk mengaturnya untuk proyek ini tidak sebanding dengan hasil yang lebih akurat atau biaya sumber daya dalam menghitung rute.
stevevance

Jawaban:

6

Saya menjawab pertanyaan saya sendiri dengan permintaan yang diajukan.

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

Ini menghasilkan yang berikut dengan beberapa kolom terpotong:

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

Kolom bernomor pertama adalah jarak (dalam kaki, karena saya menggunakan EPSG 3435) yang dihitung oleh fungsi ST_Distance PostGIS, dan kolom bernomor kedua adalah hasil dari rumus jarak Manhattan.

Saya memeriksa hasil kedua, mendapatkan jarak berjalan kaki dari Google Maps antara stasiun CTA Addison Blue Line dan gedung di 3226 W Belle Plaine Ave (dicatat sebagai '100533644' dalam kueri). Google Maps menghasilkan rute 1,1 mil berjalan kaki sementara Postgres menghasilkan 5.790 kaki = 1.09 mil. Perbedaannya dapat diterima untuk tujuan saya.

stevevance
sumber
1
ini hebat - Anda mungkin telah memecahkan masalah yang jika tidak ditangani dalam fungsi 'jarak mengemudi' PGRouting ... Saya akan menguji ini untuk beberapa masalah yang kami miliki di DPS ...!
DPSSpatial
@mapBaker Terima kasih! pgRouting terlalu kompleks untuk kebutuhan matematika sederhana saya.
stevevance
3

Saya pikir saya juga menemukan solusi yang sedikit lebih elegan yang menggunakan trigonometri dan ST_Azimuthfungsi bawaan dan merangkumnya menjadi fungsi yang bagus:

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
sumber