# How do I calculate Manhattan distance with PostGIS?

I am answering my own question with a proposed query.

select *, ABS(x_permit-x_station)+ABS(y_permit-y_station) as manhattan FROM (SELECT
longname AS NAME,
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


This results in the following with some columns snipped out:

Kedzie-Ravenswood   Brown Line  3738.52830193659    3796.29623843171


The first numbered column is the distance (in feet, because I'm using EPSG 3435) calculated by the ST_Distance PostGIS function, and the second numbered column is the result of the Manhattan distance formula.

I spot-checked the second result, getting the walking distance from Google Maps between the Addison Blue Line CTA station and the building at 3226 W Belle Plaine Ave (noted as '100533644' in the query). Google Maps outputted a 1.1 miles walking route while the Postgres result of 5,790 feet = 1.09 miles. The difference is acceptable for my purposes.

I think I also found a slightly more elegant solution that uses trigonometry and the built in ST_Azimuth function and encapsulated it into a nice function:

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