Как рассчитать манхэттенское расстояние с PostGIS?

9

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

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

Какой запрос PostgreSQL сделает эту работу?

stevevance
источник
1
Кратко подумайте: ваша сетка 'x' и 'y' не обязательно выровнена с 'x' и 'y' системы координат. Таким образом, вам может потребоваться повернуть вектор перед тем, как извлечь компоненты и вычислить.
Крейг Рингер
@CraigRinger Я преобразую координаты в местную проекцию EPSG 3435, штат Иллинойс, штат Восточный Фет. Это используется городом Чикаго для всей своей работы по ГИС. Я ответил на свой вопрос с некоторой проверкой с использованием 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), рассчитанное функцией PostGIS ST_Distance, а второй пронумерованный столбец - результат формулы расстояния Манхэттена.

Я проверил второй результат, получив расстояние пешком от Google Maps между станцией CTA Addison Blue Line и зданием по адресу: Belle Plaine Ave, 3226 W (в запросе отмечен как «100533644»). Карты Google вывели пешеходный маршрут протяженностью 1,1 мили, а результат Postgres - 5790 футов = 1,09 мили. Разница приемлема для моих целей.

stevevance
источник
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
jzarob
источник