如何使用PostGIS计算曼哈顿距离?


9

我正在使用ST_Distance函数计算两个几何图形(火车站和建筑物)之间的距离。由于我知道所有建筑物和所有火车站都在芝加哥,街道网格非常好/完整,所以我想使用曼哈顿(或出租车)距离

通用的公式是X的差加Y的差,所以Abs(X1-X2)+ Abs(Y1-Y2)。

什么PostgreSQL查询将使这项工作?


1
在这里快速思考一下:您的网格“ x”和“ y”不一定与坐标系的“ x”和“ y”对齐。因此,在提取分量并进行计算之前,可能需要旋转矢量。
Craig Ringer 2014年

@CraigRinger我将坐标转换为当地流行的投影,伊利诺伊州StatePlane East Feet的EPSG 3435。芝加哥市将其用于所有GIS工作。我已经使用Google Maps步行距离计算进行了一些验证,回答了自己的问题。
stevevance

1
您是否还考虑过使用pgRouting模块并使用其内置功能来扩展PostGIS数据?显然,A *方法使用了类似的东西
RyanKDalton 2014年

@RyanDalton我已经考虑过将pgRouting用于我的另一个项目,但是为该项目设置一个麻烦的工作不值得在计算路线时获得更准确的结果或资源成本。
stevevance

Answers:


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

第一个数字列是由ST_Distance PostGIS函数计算的距离(以英尺为单位,因为我正在使用EPSG 3435),第二个数字列是Manhattan距离公式的结果。

我抽查了第二个结果,获得了Google地图在Addison Blue Line CTA站与3226 W Belle Plaine Ave的建筑物之间的步行距离(在查询中标记为“ 100533644”)。Google Maps输出了一条1.1英里的步行路线,而Postgres的结果是5,790英尺= 1.09英里。就我的目的而言,差异是可以接受的。


1
太好了-您可能已经解决了PGRouting“行驶距离”功能无法解决的问题...我将针对DPS所遇到的一些问题进行测试...!
DPSSpatial 2014年

@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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.