ฉันจะคำนวณระยะทางแมนฮัตตันด้วย PostGIS ได้อย่างไร


9

ฉันใช้ฟังก์ชัน ST_Distance เพื่อคำนวณระยะทางระหว่างรูปทรงเรขาคณิตสองแห่ง (สถานีรถไฟและอาคาร) เนื่องจากฉันรู้ว่าอาคารทุกหลังและสถานีรถไฟทั้งหมดอยู่ในชิคาโกซึ่งมีตารางถนนที่ยอดเยี่ยม / สมบูรณ์ฉันต้องการใช้แมนฮัตตัน (หรือรถแท็กซี่) ระยะทาง

สูตรทั่วไปสำหรับสิ่งนี้คือความแตกต่างใน X บวกความแตกต่างใน Y ดังนั้น Abs (X1-X2) + Abs (Y1-Y2)

แบบสอบถามใดของ PostgreSQL ที่จะใช้งานได้


1
ความคิดอย่างรวดเร็วที่นี่: กริด 'x' และ 'y' ของคุณไม่จำเป็นต้องสอดคล้องกับระบบพิกัด 'x' และ 'y' ดังนั้นคุณอาจต้องหมุนเวกเตอร์ก่อนที่จะแยกส่วนประกอบและคำนวณ
Craig Ringer

@ CraigRinger ฉันเปลี่ยนพิกัดเป็นการฉายภาพในท้องถิ่น, EPSG 3435, Illinois StatePlane East Feet สิ่งนี้ถูกใช้โดยเมืองชิคาโกสำหรับงาน GIS ทั้งหมด ฉันตอบคำถามของฉันเองด้วยการตรวจสอบความถูกต้องโดยใช้การคำนวณระยะทางเดินของ Google Maps
stevevance

1
คุณได้พิจารณาขยายข้อมูล PostGIS ของคุณด้วยโมดูลpgRoutingและใช้ฟังก์ชั่นในตัวหรือไม่? เห็นได้ชัดว่าA * วิธีการใช้สิ่งที่คล้ายกัน
RyanKDalton

@RyanDalton ฉันได้พิจารณาใช้ pgRouting สำหรับโครงการอื่นของฉันแต่ความยุ่งยากในการตั้งค่าหนึ่งสำหรับโครงการนี้ไม่คุ้มค่ากับผลลัพธ์ที่แม่นยำยิ่งขึ้นหรือต้นทุนทรัพยากรในการคำนวณเส้นทาง
stevevance

คำตอบ:


6

ฉันกำลังตอบคำถามของตัวเองด้วยคำถามที่เสนอ

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

ซึ่งจะส่งผลต่อไปนี้โดยบางคอลัมน์ถูกตัดออก:

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

คอลัมน์หมายเลขแรกคือระยะทาง (เป็นฟุตเพราะฉันใช้ EPSG 3435) คำนวณโดยฟังก์ชัน ST_Distance PostGIS และคอลัมน์ลำดับที่สองเป็นผลลัพธ์ของสูตรระยะทางแมนฮัตตัน

ฉันตรวจสอบผลลัพธ์ที่สองโดยรับระยะทางเดินจาก Google Maps ระหว่างสถานี CTA ของ Addison Blue Line และอาคารที่ 3226 W Belle Plaine Ave (บันทึกไว้เป็น '100533644' ในข้อความค้นหา) Google Maps แสดงเส้นทางเดินเป็นระยะทาง 1.1 ไมล์ในขณะที่ผลลัพธ์ของ Postgres 5,790 ฟุต = 1.09 ไมล์ ความแตกต่างเป็นที่ยอมรับได้สำหรับวัตถุประสงค์ของฉัน


1
นี่เป็นสิ่งที่ดีมาก - คุณอาจแก้ไขปัญหาที่เกิดขึ้นในฟังก์ชั่น PGRouting 'Driving distance' ... ฉันจะทดสอบปัญหานี้ที่ DPS ... !
DPSSpatial

@mapBaker ขอบคุณ! pgRouting ซับซ้อนเกินไปสำหรับความต้องการทางคณิตศาสตร์อย่างง่ายของฉัน
stevevance

3

ฉันคิดว่าฉันพบโซลูชันที่สง่างามกว่าเล็กน้อยซึ่งใช้ตรีโกณมิติและST_Azimuthฟังก์ชันในตัวและห่อหุ้มมันเป็นฟังก์ชันที่ดี:

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.