トポロジに手を染めてみる
PostGIS 2.0 の新機能のひとつにトポロジがあります。…いやどうも 1.5 でもあったけれども文書を書いてなかったらしい。それはともかく、トポロジの扱い方が分からないので、自分で手を動かして確認しているところです。
トポロジサポートの導入
% psql topo -f /.../postgis.sql % psql topo -f /.../spatial_ref_sys.sql % psql topo -f /.../topology.sql
spatial_ref_sys.sql は、空間参照系を使わない (SRID = 0 または -1 にする) 場合には不要です。
スキーマに注意
トポロジサポートのインストール先のスキーマは topology です。
スキーマのデフォルトは public ですので、トポロジ関数を扱うなら topology.CreateTopology 等と、スキーマ名を指定します。
また、作成するトポロジデータも、スキーマ単位で管理します。
トポロジの作成
トポロジを作成して、TopologySummary と pg_tables で確認してみましょう。
topo=# SELECT topology.CreateTopology('topo1',0); ... (なんかいっぱい出力される) ... createtopology
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
孤立ノードを追加して三角形の頂点を作る
(0,0) (100,0) (200,0) を頂点とする三角形を作ります。
まずは、頂点の追加です。
topo=# SELECT topology.ST_AddIsoNode('topo1', 0, 'POINT(0 0)'); st_addisonode
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
ST_AddIsoNode の返り値は、ノードのID です。
孤立ノードを繋いでエッジを作りノードも作る
繋げていきましょう。この際、単純にノードIDだけでなく GEOMETRY (LINESTRING) も必要です。始点と終点は開始ノードと終了ノードに一致しないといけません。
topo=# SELECT ST_AddEdgeModFace('topo1', 1, 2, 'LINESTRING(0 0, 100 0)'); st_addedgemodface
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
三つ目のクエリで自動的にフェイスができあがりました。あと、警告が出ましたが、無視しときます。
現状を確認しておきましょう。
topo=# SELECT topology.TopologySummary('topo1'); topologysummary
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
ノードが3つ、エッジが3つ、フェイスが1つ、となっていますね。
TopoGeometryレイヤを作る
TopoGeometryレイヤは、トポロジとジオメトリとの間に入るものです。とりあえずテーブルを作って、TopoGeometryカラムを追加してみましょう。なお、これは Typmod になっていません。
topo=# CREATE TABLE topo1.area ( id SERIAL PRIMARY KEY ); ... topo=# SELECT topology.AddTopoGeometryColumn('topo1', 'topo1', 'area', 'topogeom', 'POLYGON'); addtopogeometrycolumn
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
AddTopoGeometryColumn の返り値は、レイヤIDです。
登録状況を確認してみましょう。
topo=# SELECT * FROM topology.layer; topology_id | layer_id | schema_name | table_name | feature_column | feature_type | level | child_id
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
TopoGeometryを作る
topo=# INSERT INTO topo1.area (topogeom) SELECT CreateTopoGeom('topo1', 3, 1, '{{1,3}}'); INSERT 0 1
インサートされたものを見てみましょう。
topo=# SELECT * FROM topo1.area; id | topogeom
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
topogeomカラムのプロパティは、順に トポロジID, レイヤID, TopoGeometry ID, レイヤタイプ です。
TopoGeometryはGEOMETRYに変換できます。
topo=# SELECT ST_AsText(topogeom::GEOMETRY) FROM topo1.area; st_astext
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
三角形を横に切る
ここまで (0,0) (100,0) (0,200) の三頂点からなる三角形を作ってきました。
Y=50 の直線でぶった切ってみましょう。辺との交点はとりあえず自前で出して、そこでエッジを分割して、あらためて繋ぎます。交点は、エッジ3番とは(0,50)、 エッジ2番とは(75,50) です。
topo=# SELECT ST_ModEdgeSplit('topo1',2,'POINT(75 50)'); st_modedgesplit
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
さきほどと同じようにノード番号4番と5番をつなげてみます。
topo=# SELECT ST_AddEdgeModFace('topo1', 4, 5, 'LINESTRING(75 50, 0 50)'); WARNING: Not updating next_{left,right}_face fields of face boundary edges CONTEXT: SQL statement "SELECT topology.AddFace(atopology, rec.geom, true)" PL/pgSQL function "st_addedgemodface" line 614 at SQL statement st_addedgemodface
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
ST_AddEdgeModFace の返り値は新たに追加されたエッジのIDです。生成されるフェイスのIDではありません。
フェイスのIDが分からないので、とりあえずテーブルを見てみましょう。
topo=# SELECT * FROM topo1.face; face_id | mbd
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
たぶん2番ですね。
なお、これだと見えにくいのですが、ST_AddEdgeModFace でフェイスの1番を分割した場合、フェイスの1番は分割の片一方として残留し、もう一方が新規登録されます。
フェイスを編集しても TopoGeometry まで更新されない
フェイスの2番をTopoGeometryにします。
topo=# INSERT INTO topo1.area (topogeom) SELECT CreateTopoGeom('topo1', 3, 1, '{{2,3}}'); INSERT 0 1 topo=# SELECT id, ST_AsText(topogeom::GEOMETRY) FROM topo1.area; id | st_astext
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
えーっと、id=1 の行がちょっと不思議か。…ていうか順を追っていくと、(100 0) (0 0) (0 200) を頂点とする三角形に分割ノード (0 50) と (75 50) がくっついているだじゃないか。
じゃあ改めてフェイスの1番をTopoGeometryにしてやる。
topo=# INSERT INTO topo1.area (topogeom) SELECT CreateTopoGeom('topo1', 3, 1, '{{1,3}}'); INSERT 0 1 topo=# SELECT id, ST_AsText(topogeom::GEOMETRY) FROM topo1.area; id | st_astext
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
id=3 の行が追加されました。id=1は消えません。