Як обчислити відстань на Манхеттені за допомогою PostGIS?


9

Я використовую функцію ST_Distance, щоб обчислити відстань між двома геометріями (залізнична станція та будівля). Оскільки я знаю, що всі будівлі та всі залізничні станції знаходяться в Чикаго, який має чудову / повну сітку вулиць, я хотів би використовувати Манхеттен (або такси) відстань .

Загальною формулою для цього є різниця в X плюс різниця в Y, тому Abs (X1-X2) + Abs (Y1-Y2).

Який запит PostgreSQL зробив би цю роботу?


1
Швидка думка тут: Ваші сітки 'x' та 'y' не обов'язково узгоджуються із системами 'x' та 'y' системи координат. Тому вам може знадобитися обертати вектор перед вилученням компонентів та обчисленням.
Крейг Рінгер

@CraigRinger Я перетворюю координати на локальну проекцію, EPSG 3435, штат Іллінойс, штат Плайн Схід. Це використовує місто Чикаго для всієї своєї роботи в галузі ГІС. Я відповів на власне запитання з деякою валідацією, використовуючи розрахунок пішохідної відстані Карт Google.
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 між станцією CTA Addison Blue Line та будівлею на 3226 Вт Belle Plaine Ave (зазначено як "100533644" у запиті). Карти Google вивели пішохідний шлях на відстані 1,1 милі, а результат Postgres - 5 790 футів = 1,09 милі. Різниця прийнятна для моїх цілей.


1
це чудово - можливо, ви вирішили проблему, яку в іншому випадку вирішують у функції PGRouting "відстань проїзду" ... Я перевірю це на наявність деяких проблем, які виникають у 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.