MySQL Pluginの機能を使って、MySQLにSpatial(GIS;地理空間情報)データを扱う関数を爆増させる試みをしています。
(MySQL Spatial Functions Plugin を公開しました(α版) - sakaikの日々雑感~(T)編)
検証しながら関数を紹介していくエントリー、6個目の関数は IsRing です。
ST_IsRing()
引数で与えられた LINESTRINGが「閉じているか」を検証して True/False( 1/0 ) を返す関数です。MySQL標準には似た関数として ST_IsClosed() というのがありますが、こちらは始点と終点が同じであればTrueと判定されるのに対し、本関数は線のクロスや重なりを許さない(閉じているとは見做さない)点が異なります。
あくまでも LINESTRING専用の関数であることに注意してください。POINTはもちろん、POLYGONを与えてもエラーになります。
動作紹介
- 基本動作。1辺10の四角形(に見えるようなLINESTRING)は「閉じている」と判定されます
mysql> SELECT STX_IsRing(ST_GeomFromText('LINESTRING(0 0, 10 0, 10 10, 0 10, 0 0)')) ir;
+------+
| ir |
+------+
| 1 |
+------+
1 row in set (0.000 sec)
- 始点まで戻りきれずに手前で止まっている(0 1)線は、もちろん「閉じていない」です
mysql> SELECT STX_IsRing(ST_GeomFromText('LINESTRING(0 0, 10 0, 10 10, 0 10, 0 1)')) ir;
+------+
| ir |
+------+
| 0 |
+------+
1 row in set (0.000 sec)
- 線で囲まれるエリアが P の字のように始点を通り過ぎて下に延びている場合、塗りつぶし的には閉じているのですが、当関数の判定では「閉じていない」です。あくまでも始点と終点が同じであることが条件
mysql> SELECT STX_IsRing(ST_GeomFromText('LINESTRING(0 0, 10 0, 10 10, 0 10, 1 -1)')) ir;
+------+
| ir |
+------+
| 0 |
+------+
1 row in set (0.000 sec)
- 一部に△のように頂点としても閉じた部分を持つ線(ここではσをひっくりかえしたような形)も「閉じていない」です。飽くまでも始点と終点が(以下略)
mysql> SELECT STX_IsRing(ST_GeomFromText('LINESTRING(0 0, 10 0, 10 10, 0 10, 10 0)')) ir;
+------+
| ir |
+------+
| 0 |
+------+
1 row in set (0.000 sec)
- 先ほどのσをひっくりかえした形(_△)で、もう1線追加して始点に戻るようにしても、線が被っているのは「閉じていない」と判定されます。ここが IsRingの厳密なところ
mysql> SELECT STX_IsRing(ST_GeomFromText('LINESTRING(0 0, 10 0, 10 10, 0 10, 10 0, 0 0)')) ir;
+------+
| ir |
+------+
| 0 |
+------+
1 row in set (0.000 sec)
- 同じ図形を標準関数の ST_IsRing() で判定すると、(始点と終点が一致しているので)「閉じている」と判定されます。面になり得るか面としてはおかしな状態かの判断基準の違いが、この2つの関数にはあります
mysql> SELECT ST_IsClosed(ST_GeomFromText('LINESTRING(0 0, 10 0, 10 10, 0 10, 10 0, 0 0)')) ir;
+------+
| ir |
+------+
| 1 |
+------+
1 row in set (0.000 sec)
- 蝶蝶(またはキティさんのリボン)のような形を描く線は、線が交叉してしまうところが「囲まれた空間」とは言えないので、「閉じていない」と判定されます
mysql> SELECT STX_IsRing(ST_GeomFromText('LINESTRING(0 0, 10 0, 10 10, 5 -3, 0 0)')) ir;
+------+
| ir |
+------+
| 0 |
+------+
1 row in set (0.000 sec)
- もうお分かりですね。ST_IsClose()なら蝶蝶ラインも「閉じている」と判定されます。
mysql> SELECT ST_IsClosed(ST_GeomFromText('LINESTRING(0 0, 10 0, 10 10, 5 -3, 0 0)')) ir;
+------+
| ir |
+------+
| 1 |
+------+
1 row in set (0.000 sec)
- POINT型だとエラー(LINESTRING専用の関数です)
mysql> SELECT STX_IsRing(ST_GeomFromText('POINT(2 3)')) ir;
ERROR 3516 (22S01): LINESTRING value is a geometry of unexpected type POINT in stx_isring.
- POLYGONでもエラー(LINESTRING専用関数です)
mysql> SELECT STX_IsRing(ST_GeomFromText('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))')) ir;
ERROR 3516 (22S01): LINESTRING value is a geometry of unexpected type POLYGON in stx_isring.
- 標準関数 ST_IsClosed() に POLYGONを与えた時はNULLになるようです。PostGISのマニュアルに「SQL-MMではST_IsRing(NULL)の結果は0と定義されていますが、PostGISではNULLを返します」と書かれているのと同じ動作です
mysql> SELECT ST_IsClosed(ST_GeomFromText('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))')) ir;
+------+
| ir |
+------+
| NULL |
+------+
1 row in set (0.000 sec)
- JGD2011の地理座標系を指定しても、もちろん正しく判定されます。これは「閉じている」例
mysql> SELECT STX_IsRing(ST_GeomFromText('LINESTRING(35 135, 35 135.5, 35.5 135.5, 35.5 135, 35 135)',6668)) ir;
+------+
| ir |
+------+
| 1 |
+------+
1 row in set (0.000 sec)
- 同じく、線がもとの場所に戻りきれなかった「閉じていない」例です
mysql> SELECT STX_IsRing(ST_GeomFromText('LINESTRING(35 135, 35 135.5, 35.5 135.5, 35.5 135, 35.1 135)',6668)) ir;
+------+
| ir |
+------+
| 0 |
+------+
1 row in set (0.000 sec)
追加情報
実装する関数をAIと相談している時に出てきたこの関数。「たしかクローズ判定する関数は既にあったよな」と調べて、というかそれすらAIとお話して情報を得るのですが(もちろんその後でマニュアルをちゃんと参照します)、そこで本エントリで紹介したような違いを理解しました。
線分を集めてPOLYGON化する過程で、この関数を使って「POLYGONになりうるか」を判定するのに使います。
