PostGISでマンハッタン距離を計算するにはどうすればよいですか?


9

ST_Distance関数を使用して、2つのジオメトリ(駅と建物)間の距離を計算しています。すべての建物とすべての駅がシカゴにあり、優れた完全なストリートグリッドがあるため、マンハッタンを使用したいと思います。(またはタクシー)距離

これの一般的な式は、Xの違いとYの違いを足したものです。したがって、Abs(X1-X2)+ Abs(Y1-Y2)になります。

これを機能させるPostgreSQLクエリは何ですか?


1
ここで簡単に考えます。グリッドの「x」と「y」は、必ずしも座標系の「x」と「y」と整列しているとは限りません。したがって、コンポーネントを抽出して計算する前に、ベクトルを回転させる必要がある場合があります。
クレイグリンガー

@CraigRinger座標をローカルで一般的な投影法であるEPSG 3435、イリノイ州プレーンイーストフィートに変換します。これは、シカゴ市がすべてのGIS作業に使用しています。私は、Googleマップの歩行距離計算を使用した検証で自分の質問に回答しました。
stevevance 2014

1
また、pgRoutingモジュールを使用してPostGISデータを拡張し、その組み込み関数を使用することを検討しましたか?どうやらA *メソッドは似ようなものを使用しています。
RyanKDalton 2014

@RyanDalton私は別のプロジェクトで pgRoutingを使用することを検討しましたが、このプロジェクト用に設定する手間は、ルートを計算する際のより正確な結果やリソースコストに値しません。
stevevance 2014

回答:


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を使用しているため)であり、2番目の番号付きの列はマンハッタン距離式の結果です。

2番目の結果をスポットチェックして、GoogleマップからアディソンブルーラインCTA駅と3226 W Belle Plaine Aveにある建物(クエリでは「100533644」と表記)の間の徒歩距離を取得しました。Googleマップは1.1マイルのウォーキングルートを出力しましたが、Postgresの結果は5,790フィート= 1.09マイルです。違いは私の目的には受け入れられます。


1
これはすばらしいことです。そうでなければPGRoutingの「走行距離」機能で対処される問題を解決した可能性があります... DPSで発生したいくつかの問題についてこれをテストします...!
DPSSpatial 2014

@mapBakerありがとうございます!pgRoutingは、単純な数学のニーズには複雑すぎます。
stevevance 2014

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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.