空間情報を解析するとき,しばしば地球上の2つ以上の地物の関係を理解したくなる.例えば,a と b はどれだけ離れているのか?x と y との間の経路に z はあるのか?p と q は共通の境界を共有しているのか?本章では,これらの疑問に答えるためのメソッドを紹介し,空間データの2つのアイテム間の関係の異なる点から比較しよう.これらのメソッドのすべての構文は,比較のなされるインスタンスがパラメータとしてメソッドに提供され,最初のインスタンス上で次のように動作する.
Instance1.Method(Instance2)
geometry 型および geography 型の両者が実装しているメソッドのコアセットは空間関係を比較するのに使われ,STEquals(), STIntersects(), STDistance() を含んでいる一方,geometry 型は特異的な関係を検査するのに使うもっと拡張した範囲のメソッドを実装しており,STOverlaps(), STCrosses(), および STContains() のようなものである.本章で紹介する各メソッドについて,どちらのデータ型で使われるか示そう.注意すべき点として,geometry 型および geography 型両者に実装されていても,異なるデータ型のインスタンスをそのメソッドで比較することはできないことである.例えば,STDistance() メソッドは2つの geography 型インスタンス間または2つの geometry 型インスタンス間の距離を計算することはできるが,geometry 型インスタンスと geography 型インスタンス間の距離を決定するのに使うことはできない.
2つのジオメトリの同一性を検査する
STEquals() メソッドは2つの空間インスタンスが同一であるか否かを検査する.つまり,それらが正確に同じ点の集合を含むということである.同一であるとみなされるために,そのジオメトリは同じ種類のジオメトリである必要はないことを銘記されたい.例えば,3つの点を結んだ一つの LineString ジオメトリである LINESTIRNG(0 0, 2 2, 5 2) は MULTILINESTRING((0 0, 2 2), (2 2, 5 2)) に等しい.同じ点の集合を表現しているからである.
サポートされるデータ型
STEquals() メソッドは次のデータ型のインスタンス上で使われる.
- geometry 型
- geography 型
使用法
STEquals() メソッドは次のように使われ,geography 型や geometry 型の2つのインスタンスが同一であるか検査する.
Instance1.STEquals(Instance2)
このメソッドの結果はビット値である.値 1 は真を表現し,そのインスタンスが同じ点の集合を含むことを示唆しており,値 0 は偽を表現し,そのインスタンスが同じ点の集合を含んでいないことを示唆している.
例
STEquals() メソッドの例を示すため,次の例は3つの geography 型インスタンスを生成し,それぞれは北緯 40.689235°, 西経 74.044480° に位置する一つの Point を表現している.これはニューヨーク市にある自由の女神の位置の近似である.各インスタンスはそれぞれ異なる静的メソッドを使って生成されるが,それらは皆,同じ SRID を使って定義された同じ座標を元に Point を生成する.次に STEquals() メソッドを使って各メソッドによって生成されたそれらのインスタンスが同じであるか検査する.
DECALRE @a geography DECLARE @b geography DECLARE @c geography SET @a = geography::STPointFromText('POINT(-74.044480 40.689235)', 4326) SET @b = geography::STPointFromWKB(0x0101000000DE54A4C2D88252C018213CDA38584440, 4326) SET @c = geography::GeomFromGML( '<Point xmlns="http://www.opengis.net/gml"> <pos>40.689235 -74.044480</pos> </Point>', 4326) SELECT @a.STEquals(@b) AS 'a = b', @b.STEquals(@c) AS 'b = c'
結果は次の通り.
a = b b = c 1 1
これの確認するところは,このシンプルなケースでは,WKT, WKB および GML 表現により生成された3つの Point インスタンスは皆同一であるということである.しかし,STEquals() メソッドを使う時には注意を払うべきである.というのは,時々”同一”に見えるインスタンスが,期待したようには同一でないことがあるからである.例えば第12章を思い出してほしいのだが,2つのジオメトリの STIntersection() メソッドを使った結果得られる,Point と Polygon の交差はその Point 自身と同じであった.これを考慮して,次のコードを考えてみよう.
DECLARE @Point geometry SET @Point = geometry::Point(1.1, 50, 0) DECLARE @Polygon geometry SET @Polygon = geometry::STPolyFromText('POLYGON((0 0, 100 0, 100 100, 0 100, 0 0))', 0) DECLARE @Intersection geometry SET @Intersection = @Point.STIntersection(@Polygon) SELECT @Point.STEquals(@Intersection)
@Intersection, @Point と @Polygon の交差から生成されたジオメトリは @Point に等しいと期待しているかもしれない.ゆえにSTEquals() メソッドが 1 を返すだろうと.本当だろうか?実際,このクエリを実行すると,代わりに次の結果を受け取ることになる.
0
特にこの場合,@Point の定義された x 座標値は 1.1 であるが,浮動小数点バイナリフォーマットでは正確に表現できない.ゆえに STIntersection() メソッドの結果は返る座標値に分数誤差を紹介する,というのはその値の最も可能性のある近似値を使った計算に基づいているからである(これについては第12章のサイドバー”浮動小数点空間データの不正確さ”で述べた).次の行をコード末に付加することでこのエラーを確認できる.
SELECT @Point.STAsText(), @Intersection.STAsText()
次の結果を見るだろう.
POINT (1.1 50) POINT (1.1000003814697266 50)
x 座標値におけるこの僅かな不一致を銘記されたい.それはこの2つのインスタンスが同一とはみなされないということである.座標値におけるこの僅かな変化が浮動小数点バイナリ算術を含め SQL Server でのいかなる操作においても発生し,それを避けることはできない.いかなるエラーの強さも,データの一つのアイテムの正確性に影響を及ぼすほど大きくはない.しかし,そのようなエラーは,STEquals() メソッドのように正確な比較を行うメソッドの結果には十分なインパクトがある.
2つのジオメトリ間の距離を計算する
STDistance() メソッドは任意の2つのジオメトリの点の間の最短距離を計算するのに使われる.geometry 型のインスタンスで使われるとき,これは2つのインスタンス間に引かれた最短直線の長さである.geography 型にとっては,それらの間の参照楕円体の表面に従う,2つのジオメトリに含まれる2つの点の間に引かれた最短の大圏航路の長さである.Figure 13-1 に様々な種類のジオメトリで STDistance() メソッドを実行したときの結果を図示する(略).
サポートされるデータ型
STDistance() メソッドは次のデータ型のインスタンス上で使われる.
- geometry 型
- geography 型
使用法
STDistance() メソッドは geometry 型や geography 型の2つのインスタンス間の距離を計算する際に次のように適用される.
Instance1.STDistance(Instance2)
結果は浮動小数点数値であり,2つのジオメトリ間の距離を表現する.2つの geography 型インスタンス間の距離の計算に使われたとき,その結果はインスタンスが定義された空間参照系に対応する計測単位で表現される.geometry 型の場合,その結果はその座標値自身と同じ計測単位で表現される.
付記 STDistance() メソッドは geography 型でも geometry 型でも適用できるのに対して,異なる型のインスタンス間では使うことができない.使用法で提供した例では,Instance1 と Instance2 は,同じ SRID を使って定義され,同じデータ型でなくてはならない.
例
空間データの一般的な応用は,所定の位置に最も近い地物を識別することであり,更に一般的な場合,ある位置に最も近い n 個の地物を見つけることである.この種のクエリは一般には最近傍クエリと呼ばれる.SQL Server における最近傍クエリを実行するための STDistance() メソッドの使い方を示すため,マサチューセッツ州における災害対応サービスを運用することを考えてみよう.大火事に気づいたとき,対応単位を送り出すために,その事変に最も近い消防署を識別して接触する必要がある.例えば,まずマサチューセッツ州における消防署の詳細を含むテーブルを作成しよう.
CREATE TABLE MA_Firestations ( Name varchar(255), Address varchar(255), City varchar(255), Location geometry )
このテーブルに移入するため,個別の消防署を表現する数件のレコードを生成する.各消防署の位置はマサチューセッツ州平面座標系を使って定義された Point ジオメトリにより表現され,SRID 26986 により記述された投影座標系である.
INSERT INTO MA_Firestations VALUES ('SANDWICH FIRE DEPARTMENT', '115 Rt. 6A', 'SANDWICH', 0x6A690000010C07095104C54C114113471EC8467D2941), ('BROCKTON FIRE DEPARTMENT', '560 West Street', 'BROCKTON' 0x6A690000010C9DD497310C050D4113471EC8A4852A41), ('SWANSEA FIRE DEPARTMENT', '50 New Gardner Neck Road', 'SWANSEA', 0x6A690000010C4145D53B43770B4113471EC89F5C2941), ('ASHLAND FIRE DEPARTMENT', '70 Cedar Street', 'ASHLAND', 0x6A690000010C22C0E9E9A0090941C18EFF4247252B41)
これら4つの例を見られるにも関わらず,数千から数百万のレコードからレコードを選択するときには,最近傍クエリがどう動作するのか見るのは容易である.MA_Firestations テーブルにもっと多くのレコードを加えたい場合には,本書に付属のコードアーカイブの一部マサチューセッツ州消防署のフルデータセットをダウンロードすることができ,Apress ウェブサイト http://www.apress.com のソースコード・ダウンロードエリアで利用できる.
この例では,消防署の位置と同じ EPSG 26986 を使って,座標 (210000, 890000) で定義される火災の通報を受けたと考えてみよう.これらの座標はボストンの南西 15 マイル付近の地点に関連する.今やセットアップされたテーブルを有しており,火災の位置も知っており,最も近い消防署を識別するにはどうすればよいだろうか?可能性のある3つのメソッドを順番に見てみよう.
最近傍法:基本的アプローチ
最近傍を識別する最も簡便な方法は SELECT ステートメントの ORDER BY 句の中で STDistance() メソッドを使うことである.一度レコードが距離の昇順でソートされれば,次のクエリで示すように SELECT TOP n 構文を用いて最近傍の TOP n 件を返すことができる.
DECLARE @Fire geometry SET @Fire = geometry::STPointFromText('POINT(210000 890000)', 26986) SELECT TOP 1 Name, Address, City, Location.STDistance(@Fire) AS Distance FROM MA_Firestations ORDER BY Location.STDistance(@Fire) ASC
結果は次の通りである.
Name Address City Distance ASHLAND FIRE DEPARTMENT 70 Cedar Street ASHLAND 4916.60186549405
このクエリは火災現場に近い最近傍の n 件の消防署を直接識別し返すだろうが(この例では最近傍の消防署が一件選ばれる),このアプローチはあまり有効ではない.STDistance() は正確なメソッドであるが,計算コストが高い.SQL Server はトップ行を識別して返すために,テーブル内の全行に対して STDistance() メソッドを実行してレコードを順序付けなければならないため,数百万行を含むこのようなテーブルに対して最近傍法を実行すると,結果処理には非常に長い時間がかかる.ゆえにこのアプローチが最も有効なのは最近傍法で検索するには非常に限られたデータしかない場合である(例えば数百行とか,数千行の場合である).
最近傍法:固定検索ゾーン内
この解決法は先述した基本的な最近傍法を二段階アプローチに変更する.最初の段階は最近傍の候補を識別することであり,問題の地物の予め決めた半径以内に位置するレコードのみを選ぶ.これを行うため,STBuffer() メソッドを使って検索範囲を生成する.バッファーの大きさは最近傍の要求される数を確保するのに十分に大きいが,要求される結果数を超える大量のデータ行を含むほど大きくない程度に選ぶ.検索範囲内に位置する地物は,空間インデックスを使用して可能性のある候補のテーブルを生成する,有効な Filter() メソッドを使って選択される.そして STDistance() メソッドを使って,テーブル全体を処理しソートするのではなく,それらの候補レコードのみ関連する距離を計算する.次のリストに示すのはこのアプローチで,STBuffer(25000) を使って火災周囲 25 km の検索範囲内の候補レコードを識別し,最近傍法で検索する.
DECLARE @Fire geometry SET @Fire = geometry::STPointFromText('POINT(210000 890000)', 26986) DECLARE @SearchArea geometry SET @SearchArea = @Fire.STBuffer(25000) DECLARE @Candidates TABLE ( Name varchar(255), Address varchar(255), City varchar(255), Distance float ) INSERT INTO @Candidates SELECT Name, Address, City, Location.STDistance(@Fire) AS DIstance FROM MA_Firestations WHERE Location.FIlter(@SearchArea) = 1 SELECT TOP 1 * FORM @Candidate ORDER BY Distance
先の例で見たように,固定検索ゾーンアプローチはこの場合最も近い消防署を直接次のように識別する.
Name Address City Distance ASHLAND FIRE DEPARTMENT 70 Cedar Street 4916.60186549405
固定検索ゾーン法の利点は,候補結果の集合を地物の近傍以内に位置するもののみに選別することで,先述した基本的な最近傍法と比較して,STDistance() が呼ばれるのに要する多くの時間を減らし,ソートに要するデータセットをさらに小さくし,クエリを著明に高速化することである.しかし,このアプローチの問題は,適切な固定値を STBuffer() メソッドに渡して検索範囲を設定することである.大きすぎる値を設定すると,有力候補が多く返りすぎてフィルターが有効に機能しなくなる.バッファーサイズが小さすぎると,検索範囲内に候補が含まれなくなるリスクがあり,最近傍をひとつも識別できないというクエリが失敗する結果となる.例えば,火災現場から最短距離に位置する消防署は Ashland Fire Department だが,4.9 km 離れている.仮に 4 km の距離以内に位置する候補を検索するために最近傍クエリを狭めると,SET @SearchArea = @Fire.STBuffer(4000)
を使うのだが,そのクエリはいかなる結果も返さないだろう.
固定検索ゾーン法は,最近傍の候補の集合を選択するにあたって,適切なバッファーサイズを確実に設定できる状況でなら最適である.これはデータが既知で一様分布していることに基づいており,例えば,データセット内のアイテムが決して最近傍から 25 km 以上離れていないことを知っている場合である.代わりに,特定の距離の制約以内の最近傍を得たいと思うかもしれない.例えば,”この場所に最も近いガソリンスタンドを3つ見せて,ただし 10 マイル以内なら”というクエリに答えることである.
チップス 最近傍候補を識別するため Filter() メソッドが有効な主要フィルターとして動作するのを確保するため,テーブルに空間インデックスが含まれることを確認されたい.空間インデックスについてさらに詳細な情報は,第14章を参照されたい.
最近傍法:拡張検索ゾーン内
このアプローチは,先述したのと同様,二段階のアプローチを使って最近傍を識別するもので,最近傍の有力候補がまず識別され,ついで有力候補の集合から実際の最近傍が選出される.固定検索ゾーン内に位置する候補を識別するために Filter() メソッドを使うよりも(いかなる最近傍も全く識別しないリスクに直面する),このアプローチは拡張する検索範囲の系列を生成し,最終的には最近傍を発見することが保証されている.
拡張する範囲を生成するため,このアプローチは numbers テーブルを使い(時には集計テーブルと呼ばれる),連続する整数の一列のみを含む.まず,連続する数のリストのみを含むテーブルを生成することは不必要に見えるかもしれないが,numbers テーブルは集合ベースの環境ではある種の問題を解決するときにとても役立つことを証明できる.この例でお見せしよう.numbers テーブルを生成して 0 から 1000 までの整数を移入するため,次のコードを実行する.
CREATE TABLE Numbers ( Number int PRIMARY KEY CLUSTERED ) DECLARE @i int = 0 WHILE @i <= 1000 BEGIN INSERT INTO Numbers VALUES (@i) SET @i = @i + 1 END
Numbers テーブルは MA_Firestations テーブルと結合されて拡張する検索範囲を生成する.最近傍の必須の数を含むのに十分な大きさの検索範囲が見つかるまで,各連続検索の拡張する距離は指数関数的に増加する.この検索範囲の地物はすべて候補として返り,ついで TOP 1 が最近傍として選ばれる.このアプローチを次のコードで示す.
DECLARE @Fire geometry SET @Fire = geometry::STPointFromText('POINT (210000 890000)', 26986) DECLARE @Candidates TABLE ( Name varchar(255), Address varchar(255), City varchar(255), Distance float, Range int ) INSERT INTO @Candidates SELECT TOP 1 WITH TIES Name, Address, City, Location.STDistance(@Fire) AS Distance, 1000*POWER(2, Number) AS Range FROM MA_Firestations INNER JOIN Numbers ON MA_Firestations.Location.STDIstance(@Fire) < 1000*POWER(2, Numbers.Number) ORDER BY Number SELECT TOP 1 * FROM @Candidates ORDER BY Range DESC, Distance ASC
得られる結果は次の通り.
Name Address City Distance Range ASHLAND FIRE DEPARTMENT 70 Cedar Street ASHLAND 4916.60186549405 8000
Numbers テーブルは連続する整数を含み,ゼロで始まることを思い出そう.それで,MA_Firestations.Location.STDistance(@Fire) < 1000*POWER(2, Numbers.Number)
の状態は最近傍法の候補と考えられる地物の最初の基準は,STDistance() の結果がその地物の 1000*2^0 より小さいことを特定するものである.EPSG 26986 空間参照系はメートルで距離を定義するため,これは検索範囲 1 km に等しい.仮に代わりの開始半径を指定したいなら,1000 の値を他の値に変更することである(問題にしているデータの SRID とデータ型に適切な計測単位を使用することを忘れずに).仮に近傍の必須の数が(この場合,我々が探しているのは TOP 1 である)指定した距離内に見つからない場合,次に検索範囲は大きさを増やす.連続検索範囲は 2 から Numbers テーブル内の次の数の指数まで取得される.ゆえに,最初の範囲は火災現場から 1 km の範囲であり,次の範囲は 2 km に拡張し,そして 4 km, 8 km, 16 km と続く.指数関数的成長モデルを採用することで,根底にある地物がどのように分布していても,このメソッドは反復の比較的小さい数のうちに最近傍を発見することが保証される.
いったん検索範囲が最近傍の候補数に必要な最小限を含むまで十分に増加すれば,WITH TIES 引数を伴う SELECT ステートメントをつかうことで,その範囲内にある全ての地物は候補として選択される.最後に,その候補は火災現場からの距離によって昇順にソートされ,TOP 1 レコードが真の最近傍として選ばれる.結果の中に返る Range 列は最近傍を発見するのに拡張した検索範囲を記述している.この場合 8 km である.
これは少し複雑である一方,このアプローチは最近傍クエリを実装するのに最も柔軟な解法を提供する.固定検索ゾーンほど高速ではないが,基本的アプローチより著明に高速であり,固定検索半径を指定しなければならないことに関連する制約に苦しめられることはない.
チップス このクエリのパフォーマンスは MA_Firestations テーブルに空間インデックスを加えることで改善する.
3次元内の地点間の距離を計算する
SQL Server 2008 におけるあらゆる機能性と同様,STDistance() 関数は2次元でのみ動作する.geometry 型の平面上の距離かあるいは geography 型の湾曲した楕円面上の距離を記述するものである.この表面に関連する標高または深度を記述する z 座標値を使ってジオメトリの点を定義するかもしれないが,この z 座標は内蔵のいかなる空間メソッドにも考慮されていない.しかし,ジオメトリにより定義された z 座標を考慮に入れたユーザー定義関数を生成することにより, SQL Server で提供される空間機能を拡張することはできる.
次のコードは,x, y および z 座標を考慮に入れて,任意の2つの geometry 型の Point 間の3次元の距離を計算するユーザー定義関数を生成する方法を示している.
CREATE FUNCTION dbo.DistanceXYZ ( @Point1 geometry, @Point2 geometry ) RETURNS float AS BEGIN RETURN SQRT( SQUARE(@Point2.STX - @point1.STX) + SQUARE(@Point2.STY - @Point1.STY) + SQUARE(COALESCE(@Point2.Z, 0) - COALESCE(@Point1.Z, 0)) ) END GO
この関数を使って2つの geometry 型 Point 間の距離を計算すると,次の通り.
DECALRE @a geometry = geometry::STPointFromText('POINT(3 4 12)', 0) DECLARE @b geometry = geometry::STPointFromText('POINT(0 0 0)', 0) SELECT @a.STDistance(@b) AS STDIstance, dbo.DistanceXYZ(@a, @b) AS DistanceXYZ
STDistance() を使って得られた平面上の (0, 0, 0) および (3, 4, 12) に位置する Point 間の2次元の距離と,新しい DistanceXYZ 関数を使った3次元で計算した Point 間の距離の結果を次に示す.
STDistance DistanceXYZ 5 13
STDistance() はいかなる2つのジオメトリ間の2次元平面の距離でも計算できるが,DistanceXYZ 関数は2つの Point ジオメトリ間の計算しか記述していないことを銘記されたい.
2つのジオメトリがインターセクト交差するか検査する
最低でも一つの点を共有していれば,2つのジオメトリは交差(筆者注:インターセクト)していると言われる.それらの共通の点は関連のあるジオメトリの境界上に位置しているか,それらの内部に含まれている.一つのジオメトリが他の一つとインターセクト交差しているかどうかを見るために検査することは,互いに一般的な空間関係をもつオブジェクトを識別するための最も一般的なメソッドの一つである.例えば,関心のある特定のエリアに関連するすべての地物を識別するなど.
付記 2つのジオメトリがインターセクト交差するかの一般的な場合に検査するためのメソッドに加えて,geometry 型ではインターセクト交差の特殊な種類を検査する付加的な方法を提供する.2つのジオメトリが互いに接するか,クロス交差するか,またはオーバーラップするか,あるいは一つのジオメトリが他のジオメトリを含むか,他のジオメトリに含まれるのか.これらの特殊な種類のインターセクト交差について,本章の後半で述べる.
STIntersects() メソッドは,2つのインスタンスが最低でも一つの点を共通に持つか否かを検査する.Figure 13-2 は異なる種類のジオメトリ間のインターセクト交差の場合の検査に STIntersects() メソッドを使った結果を示す(略).
付記 STIntersects() は2つのジオメトリがインターセクト交差しているか否かを検査するために使われる.2つのジオメトリのインターセクト交差により生成される形状がほしいなら,代わりに STIntersection() メソッドを使うべきである.
サポートされるデータ型
STIntersects() メソッドは次のデータ型のインスタンス上で使われる.
- geometry 型
- geography 型
使用法
STIntersects() メソッドは geometry 型または geography 型の2つのインスタンスがインターセクト交差するか検査するために次のように使われる.
Instance1.STIntersects(Instance2)
それらのインスタンスに一つでも共通の点があればメソッドの結果は 1 であり,そうでないなら 0 である.
例
次の例のコードはシドニーにある有名な3つのランドマークを示す Point ジオメトリ,LineString ジオメトリ,Polygon ジオメトリを含むテーブルを生成する.つまりシドニーオペラハウス,シドニーハーバーブリッジ,および王立植物園である.そして市中心部の関心のある 1 km 四方のエリアを表現する Polygon ジオメトリを定義し,テーブルにあるどのジオメトリがそのエリアとインターセクト交差するか決定する.
DECLARE @SydneyFeatures TABLE ( Name varchar(255), Shape geometry ) INSERT INTO @SydneyFeatures VALUES ('Sydney Opera House', geometry::STPointFromText('POINT(334900 6252300)', 32756)), ('Sydney Harbour Bridge', geometry::STLineFromText('LINESTRING(334300 6252450, 334600 6253000)', 32756)), ('Royal Botanic Garden', geometry::STPolyFromText(' POLYGON((334750 6252030, 334675 6251340, 335230 6251100, 335620 6251700, 335540 6252040, 335280 6251580, 335075 6251650, 335075 6251960, 334860 6252120, 334750 6252030))', 32756)) DECALRE @AreaOfInterest geometry = geometry::STPolyFromText('POLYGON ((334400 6252800, 334400 6251800, 335400 6251800, 335400 6252800, 334400 6252800))', 32756) SELECT Name FROM @SydneyFeatures WHERE Shape.STIntersects(@AreaOfInterest) = 1
これは次の結果をもたらす.
Sydney Opera House Sydney Harbour Bridge Royal Botanic Garden
STIntersecion() メソッドの結果に含まれるような,関心のあるエリア内に完全に含まれている必要はないことを銘記されたい.単にその一部分がインターセクト交差していれば良い(本章で後述する STWithin() メソッドとは対照的である).この例での特定の地物間の関係を視覚化するため,次のコードを先のクエリの直後に付加する.
SELECT Shape FROM @SydneyFeatures UNION ALL SELECT @AreaOfInterest
そのクエリを実行し,空間結果タブをクリックすると,Figure 13-3 に示す結果を見ることになる(略).
巨大な正方形のジオメトリは関心のあるエリアを表現している.シドニーオペラハウスを表現する Point ジオメトリはその正方形に完全に含まれており,大まかにその中心に位置している.シドニーハーバーブリッジを表現する LineString ジオメトリはそのエリアの北西の角とクロス交差している.王立植物園を表現する Polygon ジオメトリは南側とオーバーラップしている.そのエリアとインターセクト交差する3つのジオメトリはすべて,何らかの方法でインターセクト交差しており,ゆえに状態 STIntersects(@AreaOfInterest) = 1
により返る結果に含まれる.
2つのジオメトリ間の交差の迅速検査を実行する
Filter() メソッドは STIntersects() メソッドに似た機能を提供する.2つの geometry 型または geography 型インスタンス間のいかなるインターセクト交差も検査するために使われ,インターセクト交差が起これば値 1 を返し,インターセクト交差が起こらなければ値 0 を返す.しかし,問題の2つのジオメトリが一つでも共通の点を持つか確定させるためにそれらを直接検査する(STIntersects() はそうする)代わりに,Filter() メソッドは空間インデックスを走査して,パラメータオブジェクトとインターセクト交差するインデックスグリッドセルの占めるそれらのオブジェクトを見つけ出す.これは,問題のジオメトリが複雑になるほど,Filter() メソッドを使った2つのジオメトリ間のインターセクト交差の検査は STIntersects() メソッドを使った場合よりも速くなることを意味する.
付記 空間インデックスはセルのグリッドでジオメトリの拡張を一般化したものを蓄積し,各ジオメトリを完全に覆うのに必要なグリッド内のそれらのセルを記録する.これはジオメトリ自身の占める空間のエリアを近似するための主要なフィルターとして使われる.空間インデックスのトピックは次章で完全にカバーする.
Filter() メソッドは STIntersects() より速いのだが,Filter() メソッドには一つ欠点があり,それは偽陽性の結果を返すリスクがあるというものである.つまり,問題にしているジオメトリとインターセクト交差する空間インデックス内のセルがあるような場合に Filter() メソッドが 1 を返しているのに,インスタンス自身はそうではない.Filter() メソッドの最も有効な応用法は,それらのジオメトリについて更に詳細に解析を実行できるような顧客にデータを渡すために,特定のインスタンスとインターセクト交差するすべてのジオメトリを速く実行し,近似を問い合わせたい場合である.
サポートされるデータ型
Filter() メソッドは次のデータ型のインスタンス上で使われる.
- geometry 型
- geography 型
使用法
Filter() メソッドはgeometry 型あるいは geomgraphy 型の2つのインスタンス間でインターセクト交差の迅速検査を実行するために次のように適用される.
Instance1.Filter(Instance2)
STIntersects() メソッドのように,Filter() メソッドはインスタンスがインターセクト交差するなら値 1 を返し,そうでないなら値 0 を返す.しかし,空間インデックス内の各インスタンスの占めるセルのインターセクト交差の近似の検査に基づいた結果であるため,Filter() メソッドはSTIntersects() メソッドと同じ結果を返さないことがあることは覚えておきたい.
付記 空間インデックスを持たない列を使う場合は,Filter() メソッドは STIntersects() メソッドを正確に同じ振る舞いを返すことを失敗する.
例
Filter() メソッドを示すため,次のように空間インデックスを持つテーブルをまず生成する必要がある.
CREATE TABLE #Geometries ( id int IDENTIFY(1, 1) PRIMARY KEY, geom geometry ) CRATE SPATIAL INDEX [idx_Spatial] ON [dbo].[#Geometries] (geom) USING GEOMETRY_GRID WITH ( BOUNDING_BOX = (-180, -90, 180, 90), GRIDS = ( LEVEL_1 = MEDIUM, LEVEL_2 = MEDIUM, LEVEL_3 = MEDIUM, LEVEL_4 = MEIDUM), CELLS_PER_OBJECT = 4)
そして,次のコードを実行してテーブルに2つの Polygon を挿入する.
INSERT INTO #Geometries (geom) VALUES (geometry::STPolyFromText('POLYGON((52.09 -2.14, 51.88 -2.15, 51.89 -1.89, 52.12 -1.99, 52.09 -2.14))', 0)), (geometry::STPolyFromText('POLYGON((52.1 -2, 52.05 -2.01, 51.9 -1.9, 52.11 -2.15, 52.15 -1.9, 52.1 -2))', 0))
#Geometries テーブルに挿入したうちのどちらの Polygon が座標 (52.07, -2) にある Point と交差するか発見してみよう.まず,Filter() メソッドを使おう.
DECLARE @Point geometry = geometry::STGeomFromText('52.07 -2', 0) SELECT id FROM #Geometries WITH(INDEX(idx_Spatial)) WHERE geom.Filter(@Point) = 1
Filter() メソッドの結果は両 Polygon 共にこの Point を含むことを示唆している.
1 2
今度は同じ問いを STIntersects() メソッドを使って問う.
SELECT id FROM #Geometries WITH(INDEX(idx_Spatial)) WHERE geom.STIntersects(@Point) = 1
この場合,STIntersects() の結果は,最初の Polygon だけがその Point を含むことを正確に示す.
1
この例では,なぜ Filter() メソッドと STIntersects() メソッドは違う結果を与えたのだろうか?Point @Point は二番目の Polygon の縁に非常に近いところに位置しているが,内部に含まれてはいない.しかし,インデックスグリッドセルはその Polygon の形にゆるくフィットしているだけであり,ゆえに問題の Point を含んでいるのである.Filter() メソッドは空間インデックス内の各オブジェクトを示すセルに基づいて近似解を得るゆえに,この場合偽陽性を生成したのである.
付記 Filter() メソッドが2つのジオメトリ間で実際にインターセクト交差する結果の精度は,それの使う空間インデックスのプロパティに依存する.
2つのジオメトリが離れているか検査する
STDisjoint() メソッドは2つのインスタンスが離れているか否かを検査する.つまり,共通して持つ点がまったくないことである.STIntersects() と STDisjoint() は相補的なメソッドであり,いかなるジオメトリのペアが与えられても,片方のメソッドの結果が真であれば,他方の結果は必ず偽となる.A.Intersects(B) = 1
と A.Disjoint(B) = 0
は論理的に等価である.
チップス インスタンスがインターセクト交差していれば STIntersects() は 1 を返し,離れていれば 0 を返す.インスタンスが離れていれば STDisjoint() は 1 を返し,インターセクト交差していれば 0 を返す.
Figure 13-4 に様々なジオメトリが離れているか STDisjoint() メソッドで検査した結果を示す(略).
サポートされるデータ型
STDisjoint() メソッドは次のデータ型のインスタンス上で使われる.
- geometry 型
- geography 型
使用法
STDisjoint() メソッドは geometry 型でも geomgraphy 型でも任意の2つのインスタンス上で次のように使われる.
Instance1.STDisjoint(Instance2)
仮に2つのインスタンスが離れていれば(共通の点が一つもなければ),STDisjoint() の結果は 1 である.2つのインスタンスに一つでも共通する点があれば,STDisjoint() メソッドは値 0 を返す.
例
自然環境を保護し保全するため,多くの国は卓越した自然美の特殊なエリアを指定し,例えば国立公園などは,特別な計画制限によって管理され,それらのエリアでは工業開発は制限される.この例では,イングランドの Dorset の田舎の保護区域を表現する Polygon ジオメトリを生成する.このエリア内に開発される新しい道路の提案されたルートを表現する LineString ジオメトリをついで生成する.STDisjoint() メソッドはその道路が田舎の指定区域を回避しているかどうか検査するのに使われる.
DECLARE @Countryside geography SET @Countryside = geography::STPolyFromText( 'POLYGON((-2.66 50.67, -2.47 50.59, -2.39 50.64, -1.97 50.58, -1.94 50.66, -2.05 50.69, -2.02 50.72, -2.14 50.75, -2.66 50.67))', 4326) DECLARE @Road geography SET @Road = geography::STGeomFromText('LINESTRING(-2.44 50.71, -2.46 50.66, -2.45 50.61)', 4326) SELECT @Road.STDisjoint(@Counteryside)
STDisjoint() メソッドの結果は次の通り.
0
これはこの場合,その道路が保護された田舎エリアと離れていないことを示唆しており,その道路計画は見直さなくてはならない.
一つのジオメトリが他とクロス交差するか見つけ出す
STCrosses() メソッドは,一つのジオメトリが他とクロス交差するかというインターセクト交差の特殊例で使われる.空間用語でいうと,次の状態のいずれかにあるとき,ジオメトリ A はジオメトリ B とクロス交差するという.
- ジオメトリ B は Polygon で,ジオメトリ A はその Polygon の内部および外部両者とインターセクト交差する.これはジオメトリ A が MultiPoint, LineString または MultiLineString のときにのみ適用される.仮にジオメトリ A も Polygon だった場合,この状態は Polygon がオーバーラップしているという.
- ジオメトリ A およびジオメトリ B が共に LineString または MultiLineString の場合で,インターセクト交差により生成されるジオメトリが0次元の場合(例として,LineStrings は互いに一点ないしは複数の点でインターセクト交差するが,連続した LineString に沿ったものではない).
付記 Point はいかなるオブジェクトともクロス交差できない.2つの Polygon は互いにクロス交差できないが,オーバーラップすることになる(さらなる情報については,本章後半の STOverlaps() メソッドで述べる).
Figure 13-5 で一つのジオメトリが他とクロス交差する多くのシナリオについて STCrosses() メソッドで検査するように示す(略).
注意 STCrosses() メソッドは対称的ではない.例えば,LineString は Polygon とクロス交差することができるが,Polygon は LineString とクロス交差することはできない.STCrosses() メソッドを使うときは,インスタンスの順番を正しく指定するよう注意すること.
サポートされるデータ型
- geometry 型
使用法
STCrosses() メソッドは geometry 型インスタンスが他とクロス交差するか検査するために次のように使われる.
Instance1.STCrosses(Instance2)
仮に2つのインスタンスが先述した状態を満足し,クロス交差しているとみなされるなら,STCrosses() メソッドは値 1 を返す.そうでないなら,STCrosses() は値 0 を返す.
例
STCrosses() メソッドの使い方について示すため,ロンドンの混雑課金ゾーンに基づく次の例を考えてみよう.市内の交通を緩和するため,2003 年にロンドン市長はロンドン中心部をカバーする混雑ゾーンを導入した.平日 7:00 から 18:00 の間にこのゾーンに入る車はなんであれ課金対象となる.
この例では,課金適用となるゾーンを表現する Polygon を定義しよう.ついで市を横切り,GPS 追跡システムでそれを記録する配達車のルートを表現する LineString を定義しよう.そしてSTCrosses() メソッドを使って配達車の通るルートが渋滞ゾーンを通るか否か,そして課金対象となるか否かを決定しよう.
DECLARE @LondonCongestionZone geometry SET @LondonCongestionZone - geometry::STPolyFromText( 'POLYGON((-0.12367 51.48642, -0.07999 51.49773, -0.07256 51.51593, -0.08115 51.52472, -0.10977 51.53168, -0.17644 51.51512, -0.21495 51.52631, -0.22672 51.51943, -0.18149 51.48174, -0.12367 51.48642))', 4326) DECLARE @FrliveryRoute geometry SET @DeliveryRoute = geometry::STLineFromText( 'LINESTRING( -0.1428 51.5389, -0.1209 51.5190, -0.1171 51.5129, -0.1187 51.5112, -0.1136 51.5047, -0.1059 51.4983, -0.1043 51.4986, -0.1003 51.4946, -0.0935 51.4850, -0.0945 51.4827, -0.0929 51.4713)', 4326) SELECT @DeliveryRoute.STCrosses(@LondonCongestionZone)
STCrosss メソッドの結果は,そのルートが混雑課金ゾーンを通るか確認するものだが,次の通りである.
1
この例で使ったジオメトリを示すため,次のステートメントをクエリの末尾に付加する.
SELECT @LondonCongestionZone UNION ALL SELECT @@DelyveryRoute
空間結果タブに切り替えると,Figure 13-6 に示す結果が得られる(略).配達バンの通る経路を表現する LineString は混雑課金ゾーンを表現する Polygon とクロス交差している.
2つのジオメトリが接しているか見つけ出す
2つのジオメトリが互いに接するためには,それらの間のインターセクト交差は最低一つの点を問題のジオメトリの境界から含まなければならず,内部の点を含んでいてはならない.2つのジオメトリが互いに接しているか検査するには STTouches() メソッドを使う.Figure 13-7 にいくつかの接しているジオメトリの例を示す(略).
サポートされるデータ型
STTouches() メソッドは次のデータ型のインスタンス上で使われる.
- geometry 型
使用法
STTouches() メソッドは2つの geometry 型インスタンスが互いに接するか検査するために次のように使われる.
Instance1.STTouches(Instance2)
仮に Instance1 が Instance2 に接しているなら, STTouches() メソッドは値 1 を返し,そうでないなら値 0 を返す.
付記 STTouches() は対称的なメソッドである.つまり,いかなる2つのインスタンでも,Instance1.STTouches(Instance2) = Instance2.STTouches(Instance1)
である.
例
大都市フランスは 21 の行政区域に分割されている(コルシカ島を除く).この例では,Polygon ジオメトリは Aquitaine および Limousin を表現するために生成される.ついで STTouches() メソッドを使って2つの区域が互いに接しているか検査する.
DECLARE @Aquitaine geometry SET @Aquitaine = geometry::STPolyFromText( 'POLYGON((-1.785 43.357, -0.389 42.809, 0.006 43.371, -0.280 43.603, -0.226 43.947, 0.871 44.162, 0.981 44.580, 1.340 44.780, 1.422 45.037, 1.116 45.580, 0.737 45.624, 0.532 45.649, -0.061 45.113, -1.127 45.512, -1.442 43.661, -1.785 43.357))', 4326) DECLARE @Limousin geometry SET @Limousin = geometry::STPolyFromText( 'POLYGON((0.737 45.624, 1.116 45.580, 1.422 45.037, 1.798 44.937, 2.122 45.003, 2.481 45.396, 2.402 45.855, 2.597 46.020, 2.286 46.390, 1.825 46.437, 0.888 46.297, 0.952 45.966, 0.737 45.624))', 4326) SELECT @Aquitaine.STTouches(@Limousin)
STTouches() メソッドの結果は次の通り.
1
この例で生成したジオメトリは互いに接しており,Figure 13-8 に示したように,フランスの地図のアウトラインに関連して示してある(略).
一つのジオメトリが他とオーバーラップするか検査する
2つのジオメトリ A と B は,次の基準をすべて満たした場合にオーバーラップしていると考えられる.
- A と B は共に同じ種類のジオメトリである.
- A と B はいくつか,しかし全部ではない,内部の点を共通に持つ.
- A と B のインターセクト交差により生成されるジオメトリは,A および B 自身と同じ次元数を占める.
geometry 型の2つのインスタンスがこれらの基準に合致するか否か決定するために STOverlaps() メソッドが Figure 13-9 に示すように使われる(略).
サポートされるデータ型
STOverlaps() メソッドは次のデータ型のインスタンス上で使われる.
- geometry 型
使用法
STOverlaps() メソッドは2つの geometry 型インスタンスがオーバーラップするか検査するために次のように使われる.
Instance1.STOverlaps(Instance2)
仮にインスタンスが実際にオーバーラップしているなら結果は値 1 (真)となり,そうでないなら 0 (偽)となる.
例
合衆国のアリゾナ州,コロラド州,ユタ州およびニューメキシコ州は単一の点で接しており,Four Cournersとして知られている.その Four Corners モニュメントがこの位置に位置しており,巨大な円形のブロンズ製のディスクが4つの州それぞれに一部分ずつ位置している.そのような場所は合衆国では他にない.この例では,各4州を表現する Polygon インスタンスを生成し,さらに円形の Four Corners モニュメントを表現するための Polygon を生成する(Point 周囲半径 1 メートルをバッファー生成して定義する).
DECLARE @Status TABLE( Name varchar(32), Shape geometry ) INSERT INTO @Status(Name, Shape) VALUES ('Arizona', geometry::STPolyFromText('POLYGON((500000 4094872, 54963 4106576, -45243 3610718, 309650 3464577, 500000 3462850, 500000 4094872))', 9999)), ('Colorado', geometry::STPolyFromText('POLYGON((500000 4094872, 1123261 4117851, 1088915 4562422, 500000 4538757, 500000 4094872))', 9999)), ('Utah', geometry::STPolyFromText('POLYGON((500000 4094872, 500000 4538757, 331792 4540684, 334361 4651711, 85856 4661884, 54963 410576, 500000 4094872))', 9999)), ('New Mexico', geometry::STPolyFromText('POLYGON((500000 4094872, 500000 3462850, 576134 346126, 575729 3518546, 736683 3520990, 726722 3542965, 1067189 3556209, 1034127 4111739, 500000 4094872))', 9999)) DECLARE @Monument geometry SET @Monument = geometry::STPointFromText('POINT(500000 4094872)', 9999).STBuffer(1) SELECT Name FROM @Status WHERE @Monument.STOverlaps(Shape)
その結果,そのモニュメントが4つすべての州とオーバーラップすることを確認できる.
Arizona Colorado Utah New Mexico
付記 アリゾナ,コロラド,ユタ,ニューメキシコの複合地域を正確に描写できる投影法を選択するのは容易ではない.それらは同じ UTM に位置しておらず,各州それぞれが独自の平面投影系を持っているからである.歪曲を最小にして4州を描写するために,この例の座標は UTM 系で使われる横メルカトル図法に基づいているが,西経 109° を中心にしており,それは Four Corners 自身の位置する経線である.この投影法は UTM ゾーン 12N および 13N の間に位置しており,EPSG 空間参照系で認識されない.関連する空間参照識別子が存在しないため,代わりに SRID 9999 を使っている.
一つのジオメトリが他の内部に含まれるか検査する
ジオメトリ A の内部が完全にジオメトリ B に含まれるなら,ジオメトリ A はジオメトリ B の内部にあるという.特に,2つのジオメトリは次の基準に合致しなくてはならない.
- 両ジオメトリの内部はインターセクト交差しなければならない.
- ジオメトリ A の点がジオメトリ B の外側にあってはならない(ジオメトリ A の点が B の境界に位置していても).
一方のジオメトリが他方の内部に含まれるかとうか検査するために STWithin() メソッドは Figure 13-10 の例に示すように使われる(略).
サポートされるデータ型
STWithin() メソッドは次のデータ型のインスタンス上で使われる.
- geometry 型
使用法
STWithin() メソッドは geometry 型インスタンス Instance1 が他のインスタンス Instance2 の内部に含まれるか否か検査するために次のように使われる.
Instance1.STWithin(Instance2)
Instance1 が Instance2 内部に位置するなら 1 が返り,そうでないなら 0 が返る.
例
次の例はベルファストのストーモント政治区を表現する Polygon を生成する.区は北アイルランドの地方政府の地区であり,個別の評議員が選出される.ストーモンド政治区を示す Polygon の点は Irish Grid system (SRID 29901) を使って定義される.その例は STWithin() メソッドが Point @Constituents で示される特定の家の住人がその区の構成要素であるか否か検査するためにどう使われるを示す.
DECLARE @Stormont geometry SET @Stormont = geometry::STPolyFromText('POLYGON((338109 373760, 341057 373912, 341208 375079, 338560 376107, 338109 373760))', 29901) DECLARE @Constituents geometry SET @Constituents = geometry::STPointFromText('POINT(340275 375032)', 29901) SELECT @Contituents.STWithin(@Stormont)
その結果は,その家を表現するその Point は,ストーモント区を表現する Polygon ジオメトリ内部に立地することを示唆している.その家の住人はゆえにその区の有権者である.
1
ジオメトリが他を含むか検査する
STContains() メソッドは一つのジオメトリが他のジオメトリを含むかどうか検査するために使われる.次の基準に合致した場合にジオメトリ A はジオメトリ B を含む.
- 両ジオメトリの内部はインターセクト交差する.
- ジオメトリ A の外部に位置するジオメトリ B の点は存在しない.
STContains() メソッドは STWithin() メソッドと相補的な機能を提供する.ゆえに a.STContains(b)
は b.STWithin(a)
と論理的に等価である.
注意 ジオメトリ A がジオメトリ B を含むためには,ジオメトリ B がジオメトリ A の外側に位置するだけでは十分ではない.十分条件を満たすには,B の内部の最低1点が A の内部になければならない.例えば,Polygon の外部リングを定義する LineString ジオメトリはその Polygon 内部には含まれていない.というのは,その Polygon 内部に LineString が位置する点が存在せず,ただ境界線上に存在するだけだからである.
Figure 13-11 に他のオブジェクトを含む様々な空間オブジェクトの例を示す(略).
サポートされるデータ型
STContains() メソッドは次のデータ型のインスタンス上で使われる.
- geometry 型
使用法
STCountains() メソッドは geometry 型の一つのインスタンス Instance1 が他の Instance2 を含むか否かを検査するのに次のように使われる.
Instance1.STContains(Instance2)
Instance1 が Instance2 を含むなら結果は値 1 であり,そうでないなら値 0 である.
例
次の例ではオックスフォードシャー州教育当局 (LEA) の管轄を示す Polygon ジオメトリを生成する.イングランドのオックスフォードシャー州内での教育と図書館サービス担当の地方当局である.ついで学校を表現する Point ジオメトリを生成し,STContains() メソッドを使って,LEA がその学校の担当であるか否かを決定する.
DECLARE @OxfordshireLEA geometry SET @OxfordshireLEA = geometry::STPolyFromText('POLYGON((478150 178900, 446250 252400, 419900 209050, 428200 180250, 478150 178900))', 27700) DECLARE @School geometry SET @School geometry::STPointFromText('POINT(431400 214500)', 27700) SELECT @OxfordshireLEA.STContains(@School)
STContains() メソッドの結果は,当局が責任を持つそのエリアにその学校が含まれることを確認するものだが,次の通りである.
1
ジオメトリ間のカスタムの関係を検査する
STRelate() メソッドは,次元拡張9交差点モデル (DE-9IM) パターンを使って2つの geometry 型インスタンス間の明示的なインターセクト交差の集合を検査することができる.DE-9IM モデルは2つのジオメトリの内部,境界および外部に位置する点の間で起きうる各インターセクト交差を表現する数学的な行列である.DE-9IM モデルからのパターンは,2つのジオメトリ間で起きうるインターセクト交差が起きるかどうか,もしそうなら,結果のインターセクト交差の次元は何かに基づいて,2つのジオメトリ間の関係を特定する.これらのパターンの一つかそれ以上を使うことにより,自身で定義したカスタムの関係同様,本章で紹介した他のメソッドのいかなる機能をも再生産することが可能となる.
主要な空間アプリケーションにとって,2つの空間データのアイテム間の関係を比較するために必要な機能の全ては,すでに論じた予め定義された SQL Server のメソッドで提供されている.STIntersects(), STContains(), STCrosses() など.しかし,いくつかのアプリケーションは特異的で2つのインスタンス間のカスタムの空間関係を確立することを要求しており,それらは既存のメソッドでは提供されていない.これらの状況の中では,STRelate() メソッドに提供されている DE-9IM パターンで検査すべき関係を明示的に記述することができる.
サポートされるデータ型
STRealte() メソッドは次のデータ型のインスタンス上で使われる.
- geometry 型
使用法
STRealte() メソッドの構文は次の通りである.
Instance1.STRelate(Instance2, Pattern)
Instance1 と Instance2 は geometry 型のインスタンスである.Pattern は DE-9IM モデルからの 9 文字の文字列パターンで,検査したい関係を記述したものである.Pattern 文字列の各文字は2つのジオメトリの内部,境界,外部間のありうるインターセクト交差の9つの許された一つのインターセクト交差の種類を表現している.そのパターンの中で使われる値は次のとおりである.
- T: ジオメトリ間でインターセクト交差が起こらなくてはならない.
- F: インターセクト交差が起きてはならない.
- 0: インターセクト交差の結果0次元のジオメトリを生じなければならない(例 Point や MultiPoint)
- 1: インターセクト交差の結果一次元のジオメトリを生じなければならない(例 LineString や MultiLineString)
- 2: インターセクト交差の結果二次元のジオメトリを生じなければならない(例 Polygon や MultiPolygon)
- *: インターセクト交差が起きても起きなくても構わない
STRelate() メソッドを使うために DE-9IM パターンを構築する方法を示すため,STWithin() メソッドが真を返さなければならない2つのジオメトリ間のインターセクト交差について考えてみよう.
- ジオメトリ 1 の内部はジオメトリ 2 の内部とインターセクト交差する.このインターセクト交差の次元は考慮しなくて良い.
- ジオメトリ 1 の内部も境界もジオメトリ 2 の外部とインターセクト交差することは許されていない.
DE-9IM モデルを使って,この関係を Table 13-1 の行列に示した.
Geometry 2 Interior | Geometry 2 Boundary | Geometry 2 Exterior | |
---|---|---|---|
Geometry 1 Interior | T | * | F |
Geometry 1 Boundary | * | * | F |
Geometry 1 Exterior | * | * | * |
STRelate() メソッドでの組み合わせにおけるこの行列で記述した関係を使うためには,まず行列のセルに含まれる値を9文字の文字列で表現する必要がある.これを行うために,行列の左上のセルから始め,左から右に読み,上から下へ読む.Table 13-1 の行列に示した関係にとって,これは次のパターンで紹介される: T*F**F***.
2つのジオメトリを検査して,STRelate() メソッドにこのパターンを提供することで特定される関係を示すのを次のように見ることができる.
Instance1.STRelate(Instance2, 'T*F**F***')
仮に2つのジオメトリの関係がそのパターンで特定される基準に合致した場合,STRelate() メソッドは 1 を返す.そうでないならそのメソッドは 0 を返す.この例では,パターン T*F**F*** は一つのジオメトリが他方を含んでいなくてはならないことを表現しているため,Instance1.STRelate(Instance2)
は Instance1.STWithin(Instance2)
と等価である.
例
2つのジオメトリ間の特定の種類のインターセクト交差を検査し定義することを考えてみよう.2つのインスタンスは”接続されている”としよう.2つのジオメトリが接続されている状態を次のように定義しよう.
- 2つのジオメトリの境界は一つ以上の点でインターセクト交差していなくてはならないが,共通の辺を有してはいけない.言い換えると,2つの境界のインターセクト交差はゼロ次元でなくてはならない.
- いずれのジオメトリの内部の一部も他とインターセクト交差してはいけない.
この関係を Table 13-2 で DE-9IM 行列で示す.
Geometry 2 Interior | Geometry 2 Boundary | Geometry 2 Exterior | |
---|---|---|---|
Geometry 1 Interior | F | F | * |
Geometry 1 Boundary | F | 0 | * |
Geometry 1 Exterior | * | * | * |
この行列からは,次の DE-9IM パターン FF*F0**** を得られる.このパターンを使って2つのジオメトリが接続しているか否かを検査したいような状況を示すため,次の例ではユタ州のガスパイプラインを表現する2つの LineString ジオメトリを生成し,それは NAD 83 データム (SRID 26912) に基づく UTM Zone 12N 投影法を使っている.DE-9IM パターン FF*F0**** を STRelate() メソッドに提供することで,その例はついで2つのパイプラインが接続しているか否かをチェックしている.
DECLARE @Pipe1 geometry SET @Pipe1 = geometry::STLineFromText('LINSTRING (446683 4441938, 446878 4442269, 447236 4447851, 448057 4448802, 448060 4449019, 447303 4450244, 446746 4450760)', 26912) DECALRE @Pipe2 geometry SET @Pipe2 = geometry::STLineFromText('LINESTRING (437751 4438849, 443022 4438830, 444164 4439588, 445240 4439580, 446683 4441938)', 26912) SELECT @Pipe1.STRelate(@Pipe2, 'FF*F0****')
STRelate() メソッドの結果は次の通り.
1
この結果の確認するところは,この場合,2つのジオメトリはパターン FF*F0**** で指定された状態を満たしていることである.つまり,両ジオメトリの境界が互いにインターセクト交差しており,その結果ゼロ次元ジオメトリ (Point) となり,いずれのジオメトリの内部も境界も,他の内部とはインターセクト交差していない.
要約
本章においては,空間オブジェクト間で可能性のある関係を問い合わせる多くのメソッドを紹介した.それにはインターセクト交差と近接に基づくクエリが含まれる.Table 13-3 に本章で紹介したメソッドの要約を示す.
メソッド | 記述 | geometry型 | geography型 |
---|---|---|---|
STEquals() | 2つのインスタンスが同じ点の集合から構成されるか決定する | ● | ● |
STDistance() | 2つのインスタンス間の最短距離を計算する | ● | ● |
STIntersects() | 2つのインスタンスが交差するか決定する | ● | ● |
Filter() | 2つのインスタンスが空間インデックスに基づいて交差するか検査する | ● | ● |
STDisjoint() | 2つのインスタンスが離れているか検査する | ● | ● |
STTouches() | 2つのインスタンスが接しているか検査する | ● | |
STOverlaps() | 2つのインスタンスがオーバーラップしているか決定する | ● | |
STCrosses() | 一つのインスタンスが他と交差しているか決定する | ● | |
STWithin() | 一つのインスタンスが他の内部に含まれるか決定する | ● | |
STContains() | 一つのインスタンスが他を含んでいるか決定する | ● | |
STRelate() | DE-91Mモデルを使って2つのインスタンスが指定された特定の関係を示すか検査する | ● |
“第13章 空間の関係性を検査する(Begining Spatial with SQL Server 2008)” への1件の返信