はじめに
面(POLYGON)のデータは、中をくり抜いた形も表現することができます。今回はその表現方法について解説していきます。
面データのおさらい
前回は千葉県の大まかな形を例に面データの扱い方を紹介しました。今回は打って変わって小さな単位、建物の形を題材にしようと思います。東京都千代田区にある財務省のビルを例にしましょう。
財務省のビルはほぼ正方形のきれいな形をしており、その中がくり抜かれているような形になっています。建物の形、つまり外側の四角形を構成する各点の座標は次のとおりです。POLYGONなので、最初と最後の座標は同じものです(1回りしてもとの点に戻ってきている)。
35.673388, 139.748775
35.672305, 139.748219
35.671872, 139.749524
35.672938, 139.750067
35.673388, 139.748775
この座標を、前回作成した「g3」テーブルへ登録してみましょう。ポリゴンを表すWKTでは括弧を二重にするのでしたね。DBeaverでの確認結果も示します。
INSERT INTO g3 VALUES(2, 'Zaim1',
ST_GeomFromText(
'POLYGON((35.673388 139.748775,
35.672305 139.748219, 35.671872 139.749524,
35.672938 139.750067, 35.673388 139.748775))', 6668));
中をくり抜いてみよう
それでは、今回のテーマである「中のくり抜き」をやってみましょう。財務省の建物には2箇所のくりぬき部分があります。まず、右側(東側)の部分をくり抜いてみましょう。くり抜き部分の頂点座標は次のとおりです。
35.67295088033991, 139.74942701156846
35.672819055789624, 139.74980855578266
35.672101098421436, 139.74941494162985
35.672224208413056, 139.74903138575903
35.67295088033991, 139.74942701156846
中をくり抜くPOLYGONのWKTは次のように表します。
POLYGON( (外側の形のPOLYGON座標群), (くり抜くPOLYGON座標群))
これをINSERT文のST_GeomFromText()関数にに与えたものが、以下のSQLです。数字が多いために複雑に見えますが、上で説明した括弧の構造に着目して眺めてみてください。
INSERT INTO g3 VALUES(3,'Zaim2',
ST_GeomFromText(
'POLYGON(
(35.673388 139.748775, 35.672305 139.748219, 35.671872 139.749524,
35.672938 139.750067, 35.673388 139.748775),
(35.67295088033991 139.74942701156846, 35.672819055789624 139.74980855578266,
35.672101098421436 139.74941494162985, 35.672224208413056 139.74903138575903,
35.67295088033991 139.74942701156846)
)', 6668));
DBeaverで確認すると、くり抜かれたデータとしてこのツールにも認識されていることが分かります(この手のツールはデータが若干おかしい場合でも「気を回して」上手に表示してくれることもあるので手放しで信頼してはいけませんが、本ツールでのこのポリゴンについては私の使用経験上から正しくPolygonデータの形状が表示されていると信頼して良いと考えます)。
いくつもくり抜いてみる
このポリゴンのくり抜きは、1箇所だけではなく何箇所にでも行うことができます。追加で、財務省の左側の部分をくり抜いてみましょう(今回は細かい形の部分は捨象しました)。
先ほどはWKTのPOLYGONの内側に2つ目の括弧としてくり抜く部分を指定しましたが、3つ目の括弧で追加のくりぬき分を与えることができます。
INSERT INTO g3 VALUES(4, 'Zaim3',
ST_GeomFromText(
'POLYGON(
(35.673388 139.748775, 35.672305 139.748219,35.671872 139.749524,
35.672938 139.750067, 35.673388 139.748775),
(35.67295088033991 139.74942701156846, 35.672819055789624 139.74980855578266,
35.672101098421436 139.74941494162985, 35.672224208413056 139.74903138575903,
35.67295088033991 139.74942701156846),
(35.673197097509636 139.74895226058686, 35.67309577814588 139.7492312103111,
35.67223183469117 139.74877925811364,35.672318992082765 139.74849092063482,
35.673197097509636 139.74895226058686)
)', 6668));
このように、ポリゴンでは内側の1つ目の括弧内に全体の形を記述し、2つ目以降の括弧でくり抜く部分をいくつでも指定することができます。 内側の1つ1つの要素もまた閉じた形(最初の点と最後の点が同じ)であり、くり抜く部分は外形の外側へとび出してはいけないという点に注意してください。
POLYGON( (外側の形のPOLYGON座標群), (くり抜くPOLYGON座標群), (くり抜くPOLYGON座標群), (くり抜くPOLYGON座標群)....)
前回は「POLYGONではWKTに二重括弧を使う」と紹介しましたが、これはくり抜く部分(2つめ以降の要素)がないために「(( .... ))」のように単純に二重括弧で囲んだように見えた、ということを今回の説明で理解していただけたでしょうか。
ポリゴンの中をくり抜く場合に「くり抜き部分が外形の外側にはみ出してはいけない」と説明しました。しかし、実はMySQLではそのようなポリゴンでも登録できてしまいます。
ルールに則ったポリゴンの例:INSERT INTO g3 VALUES (5, 'sample',
ST_GeomFromText(
'POLYGON(
(35.5 139.7, 35.5 139.8, 35.6 139.8, 35.6 139.7, 35.5 139.7),
(35.56 139.75, 35.56 139.77, 35.58 139.77, 35.58 139.75, 35.56 139.75)
)', 6668));
内側がはみ出してしまったポリゴンの例:
INSERT INTO g3 VALUES (6, 'sample',
ST_GeomFromText(
'POLYGON(
(35.5 139.7, 35.5 139.8, 35.6 139.8, 35.6 139.7, 35.5 139.7),
(35.56 139.75, 35.56 139.82, 35.58 139.82, 35.58 139.75, 35.56 139.75)
)', 6668));
実際にはみ出した場合でもMySQLではエラーなく登録ができていますし、DBeaverでもそれっぽい表示をしてくれてはいます。しかし、これはルールに則ったポリゴンの形ではないため、このデータを使って様々な処理をしていく際に問題が発生する可能性が高くなります。
このようなデータの確認に便利なのが「ST_IsValid()」関数です。正当な地理情報の値である場合は「1」を、不正な場合は「0」を返します。MySQLは地理情報データの登録に関してはやや甘めに作られているところがあるので、エラーなく登録できたからと安心せず、必要な場合はこの関数を使って確認することをお勧めします。
mysql> SELECT id, ST_IsValid(g) FROM g3 WHERE id IN (5,6);
+------+---------------+
| id | ST_IsValid(g) |
+------+---------------+
| 5 | 1 |
| 6 | 0 |
+------+---------------+