11. 空間関係関数¶
ここまで、計測空間関数 (ST_Area, ST_Length)、ジオメトリのシリアライズ (ST_GeomFromText)、デシリアライズ (ST_AsGML) を使ってきました。これらの関数は共通することは、一度に一つのジオメトリでのみ動作することです。
空間データベースが強力なのは、ジオメトリを格納するだけでなく、「ジオメトリ間の関係」の比較をする能力も持っているからです。
「公園から最も近い自転車ラックはどれですか?」や「地下鉄とストリートとはどこで交差しますか?」のような質問に対しては、自転車ラック、ストリート、地下鉄を表現するジオメトリを比較することで答が得られます。
OGC標準は、ジオメトリ比較の手法のメソッドを次の通り定義しています。
11.1. ST_Equals¶
ST_Equals(geometry A, geometry B) 二つのジオメトリが空間的に同じであるかどうかをテストします。
ST_Equals は、二つのジオメトリが同じタイプで、同一の X値、Y値 を持っている場合には TRUE を返します。つまり、2番目の形状が1番目の形状と等しい場合に TRUE を返します。
まず、nyc_subway_stations
テーブルからポイントの表現を取得します。'Broad St' のエントリだけを取ります。
SELECT name, geom
FROM nyc_subway_stations
WHERE name = 'Broad St';
name | geom
----------+---------------------------------------------------
Broad St | 0101000020266900000EEBD4CF27CF2141BC17D69516315141
そうして、ジオメトリ表現を ST_Equals テストに入れなおします。
SELECT name
FROM nyc_subway_stations
WHERE ST_Equals(
geom,
'0101000020266900000EEBD4CF27CF2141BC17D69516315141');
Broad St
注釈
ポイントの表現は人が判読できるものではありません (0101000020266900000EEBD4CF27CF2141BC17D69516315141
) が、正確な座標値の表現です。等価性テストでは正確な座標の使用が必要です。
11.2. ST_Intersects, ST_Disjoint, ST_Crosses, ST_Overlaps¶
ST_Intersects, ST_Crosses, ST_Overlaps は、ジオメトリの内部でインタセクトしているかをテストします。
ST_Intersects(geometry A, geometry B) は、二つの形状に共通の領域を持つ場合、つまり、境界又は内部がインタセクトする場合に t (TRUE) を返します。
ST_Intersects の反対は ST_Disjoint(geometry A , geometry B) です。二つのジオメトリが接続されていない場合にはインタセクトしませんし、その逆も成り立ちます。インタセクトのテストは空間インデックスが利用可能なのに対して、接続しないテストは利用できないため、実際に「インタセクトしない」のテストが「接続しない」のテストより効果的になることがしばしばあります。
マルチポイント/ポリゴン、マルチポイント/ラインストリング、ラインストリング/ラインストリング、リアンストリング/ポリゴン、ラインストリング/マルチポリゴンの比較では ST_Crosses(geometry A, geometry B) は、インタセクトの結果が二つの引数ジオメトリの図形次元の最大値より 1 小さい次元であり、インタセクションの集合が両方の引数ジオメトリ内部にある場合に t (TRUE) を返します。
ST_Overlaps(geometry A, geometry B) は、同じ図形次元の二つのジオメトリを比較して、インタセクトした領域が二つのジオメトリのいずれとも異なり、かつ同じ図形次元である場合に TRUE を返します。
地下鉄 Broad Street 駅を取り上げて、ST_Intersects 関数を使って地区を決定します:
SELECT name, ST_AsText(geom)
FROM nyc_subway_stations
WHERE name = 'Broad St';
POINT(583571 4506714)
SELECT name, boroname
FROM nyc_neighborhoods
WHERE ST_Intersects(geom, ST_GeomFromText('POINT(583571 4506714)',26918));
name | boroname
--------------------+-----------
Financial District | Manhattan
11.3. ST_Touches¶
ST_Touches は、二つのジオメトリが境界で接触していて、かつ内部でインタセクトしていないかをテストします
ST_Touches(geometry A, geometry B) は、ジオメトリの境界同士がインタセクトするか、一方のジオメトリの内部の一つだけと、もう一つのジオメトリの境界とインタセクトする場合に TRUE を返します。
11.4. ST_Within と ST_Contains¶
ST_Within と ST_Contains は、一方のジオメトリが完全にもう一方の中に入っているかどうかをテストします。
ST_Within(geometry A , geometry B) は、一つ目のジオメトリが完全に二つ目のジオメトリの内側にある場合に TRUE を返します。ST_Within は ST_Contains の正反対のテストをします。
ST_Contains(geometry A, geometry B) は、二つ目のジオメトリが完全に一つ目のジオメトリに含まれる場合に TRUE を返します。ST_Within は ST_Contains の正反対のテストをします。
11.5. ST_Distance と ST_DWithin¶
非常に一般的な GIS の質問に「あるものから距離 X 以内にあるものを全て見つける」というものがあります。
ST_Distance(geometry A, geometry B) は、二つのジオメトリの「最短」距離を計算し、浮動小数点数として返します。オブジェクト間の距離を実際に報告する場合に使います。
SELECT ST_Distance(
ST_GeometryFromText('POINT(0 5)'),
ST_GeometryFromText('LINESTRING(-2 2, 2 2)'));
3
ST_DWithin 関数は、二つのジオメトリの一方がもう一方を含むかどうかをテストするために、インデックスで速度向上した真偽テストを行います。これは「道路から 500m 以内にある樹木数は?」といった質問に使えます。実際のバッファを計算する必要はなく (訳注: GIS では、距離計測の代わりにバッファを作成してインタセクトするかテストする場合があります)、距離関係のテストを行う必要があるだけです。
再び地下鉄 Broad Street 駅を使って、地下鉄駅に近い (10メートル以内) ストリートを見つけることができます:
SELECT name
FROM nyc_streets
WHERE ST_DWithin(
geom,
ST_GeomFromText('POINT(583571 4506714)',26918),
10
);
name
--------------
Wall St
Broad St
Nassau St
そして地図上で解答の確認ができます。Broad St 駅は実際に Wall Street, Broad Street, Nassau Street の交差点にあります。
11.6. 関数リスト¶
ST_Contains(geometry A, geometry B): Bの点がAの外部に全く存在せず、Bの内部の少なくとも一つの点がAの内部に存在する場合にのみ TRUE を返します。
ST_Crosses(geometry A, geometry B): 与え得られたジオメトリについて内側の一部で共有部分があり、かつ全てが共有部分になっていない場合には TRUE を返します。
ST_Disjoint(geometry A , geometry B): ジオメトリが「空間的にインタセクト」していない、つまり共通部分を持たない場合には TRUE を返します。
ST_Distance(geometry A, geometry B): 二つのジオメトリの間の2次元デカルト距離の最短距離 (空間参照系に基づく) を投影座標系の単位で返します。
ST_DWithin(geometry A, geometry B, radius): ジオメトリと他のジオメトリとの距離が指定した距離以内である場合に TRUE を返します。
ST_Equals(geometry A, geometry B): 与えられたジオメトリが同じジオメトリを表現している場合には TRUE を返します。進行方向は無視されます。
ST_Intersects(geometry_a, geometry_b): ジオメトリ/ジオグラフィが「空間的にインタセクトする」 - (空間の任意部分を共有する)場合にはTRUEを返し、そうでない(接続されていない、Disjoint)場合にはFALSEを返します。
ST_Overlaps(geometry A, geometry B): ジオメトリが空間を共有し、同じ図形次元で、かつ、完全に一方に包含するようにはなっていない場合には TRUE を返します。
ST_Touches(geometry A, geometry B): ジオメトリが少なくとも一つのポイントを共有し、かつ、内部でインタセクトしていない場合には TRUE を返します。
ST_Within(geometry A , geometry B): ジオメトリ A が完全にジオメトリ B の内部にあるばあいには TRUE を返します