Làm cách nào để tính khoảng cách Manhattan với PostGIS?


9

Tôi đang sử dụng hàm ST_Distance để tính khoảng cách giữa hai hình học (nhà ga và tòa nhà) Vì tôi biết rằng tất cả các tòa nhà và tất cả các nhà ga đều ở Chicago, nơi có mạng lưới đường phố tuyệt vời / hoàn chỉnh, tôi muốn sử dụng Manhattan (hoặc taxi) khoảng cách .

Công thức chung cho điều này là sự khác biệt về X cộng với sự khác biệt về Y, do đó, abs (X1 - X2) + abs (Y1 - Y2).

Điều gì truy vấn PostgreSQL sẽ làm cho công việc này?


1
Một suy nghĩ nhanh ở đây: Lưới của bạn 'x' và 'y' không nhất thiết phải được liên kết với hệ thống phối hợp 'x' và 'y'. Vì vậy, bạn có thể cần phải xoay vector trước khi giải nén các thành phần và tính toán.
Craig Ringer

@CraigRinger Tôi chuyển đổi tọa độ sang hình chiếu phổ biến tại địa phương, EPSG 3435, Illinois StatePlane East feet. Điều này được Thành phố Chicago sử dụng cho tất cả các công việc về GIS của mình. Tôi đã trả lời câu hỏi của riêng mình bằng một số xác thực bằng tính toán khoảng cách đi bộ của Google Maps.
stevevance

1
Bạn cũng đã xem xét việc mở rộng dữ liệu PostGIS của mình với mô-đun pgRouting và sử dụng các chức năng tích hợp của nó chưa? Rõ ràng phương pháp A * sử dụng một cái gì đó tương tự .
RyanKDalton

@RyanDalton Tôi đã cân nhắc sử dụng pgRouting cho một dự án khác của tôi nhưng rắc rối khi thiết lập một dự án này không xứng đáng với kết quả chính xác hơn hoặc chi phí tài nguyên khi tính toán tuyến đường.
stevevance

Câu trả lời:


6

Tôi đang trả lời câu hỏi của riêng tôi với một truy vấn được đề xuất.

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

Điều này dẫn đến kết quả sau với một số cột bị bắn ra:

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

Cột được đánh số đầu tiên là khoảng cách (tính bằng feet, vì tôi đang sử dụng EPSG 3435) được tính bởi hàm ST_Distance PostGIS và cột được đánh số thứ hai là kết quả của công thức khoảng cách Manhattan.

Tôi đã kiểm tra kết quả thứ hai, nhận được khoảng cách đi bộ từ Google Maps giữa trạm CTA Addison Blue Line và tòa nhà tại 3226 W Belle Plaine Ave (ghi chú là '100533644' trong truy vấn). Google Maps outputted một 1,1 dặm đường đi bộ trong khi Postgres kết quả của 5790 chân = 1,09 dặm. Sự khác biệt là chấp nhận được cho mục đích của tôi.


1
điều này thật tuyệt - bạn có thể đã giải quyết một vấn đề khác được giải quyết trong chức năng 'khoảng cách lái xe' PGRouting ... Tôi sẽ kiểm tra vấn đề này cho một số vấn đề chúng tôi gặp phải ở DPS ...!
DPSSpatial

@mapBaker Cảm ơn! pgRouting quá phức tạp đối với nhu cầu toán học đơn giản của tôi.
stevevance

3

Tôi nghĩ rằng tôi cũng đã tìm thấy một giải pháp thanh lịch hơn một chút sử dụng lượng giác và hàm tích hợp ST_Azimuthvà đóng gói nó thành một hàm đẹp:

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.