第33回 プログラミングについて 『ポリゴンの話3』

『ポリゴンの話3』
「点がポリゴンの中にあるか否か」。これを調べるのもアルゴリズム的には簡単なのですが、実際のプログラムとなると結構厄介な問題なのです。まず下の図を見て下さい。
・ーーーー・ p2
| | x
・ーー・ |
| ・ーーーーー・
| |
・ーー・ |
| p1 ・ーーー・
| x |
| |
・ーーーーーー・
人間はp1がポリゴンの中にあって、p2は外側にあるとすぐに分かります。やはり人間には不思議な能力がありますね。これをプログラムで判定するにはまずp1、p2からX軸に垂直な線を引いてみます。
| |
・ー+ーー・ |p2
| | | x
・ー+・ | |
|| ・ーー+ーー・
|| | |
・ー+・ | |
| |p1 ・+ーー・
| x ||
| | ||
・ー+ーーーー・|
| |
p1から引いた線がポリゴンと交差する点の数は4個あり、p1より上には3個、下には1個です。p2では全部で2個で上には0個下には2個です。これで検討がついたと思いますが、点から上または下に引いた線とポリゴンとの交点の数が奇数のときには内側、偶数のときには外側と判断することができます。
ここまでは簡単な話です。むずかしいのは交点を求める線をどうやって決めるかなのです。下の図を見て下さい。
8 7
・ーーーー・ p2
| 10 | x
9・ーー・ |
| ・ーーーーー・5
| 6 |
p1| |
x ・11 ・ーーー・4
/ |3
/ |
・ーーーーーー・
1 2
p1から垂線を引いたとき、辺1ー2、辺7ー8、辺9ー10、辺11ー1との交点はそれぞれの辺の末端に一致するので交点があるとすると、p1よりも上にある交点の数は偶数、また下にある交点も偶数ですので、p1は外側にあることになります。同じようにp2について見てみると、辺1ー2、辺3ー4、辺5ー6とで交点があります。
p2よりも上にある交点の数は0個、下にあるのは3個で奇数ですから内側か外側かは判定できません。
また、辺の末端に交点があるときにはそれを交点とは認めないとしても、p1に対しては上も下も0個で、p2に対しては上が0個、下が1個とこれも矛盾してしまいます。
一体何が間違っているのでしょうか?
大きな間違いはないのすが、交点を求めるときに単純に直線と直線の交点を求めてしまったことが原因なのです。ここがポリゴン(折れ線のときにも言えますが)を処理する上で重要な性質なのです。
交点を求める際に、交点が辺の端になるとき(端に近いとき)には特別な考慮をしなければならないのです。
p1を通る垂線との交点を求めるときをまず考えてみましょう。
最初に垂線は辺1ー2と交差しますが、このとき頂点1のX座標がp1のX座標と同じですので、交点は辺の端になります。このときには垂線に対する辺11ー1と辺1ー2の関係を考慮しなければならないのです。その関係を抜き出してみましょう。
p1
x ・11
| /
|/
・ーーーーーー・
1 2
(関係1)
このような関係のときには交点を求めないか、交点を求めるか(辺11ー1と辺1ー2に対しそれぞれ1つずつ交点があるのでこの角の部分では交点が2個)のどちらかにします。
次にp1の垂線と辺8ー7も同様に交点が辺の端にありますので、これもその部分を抜き出してみましょう。
8 7
・ーーーー・
|
9・
|
|
|p1
x
(関係2)
このようなときには、関係1と同様に交点を求めないか、交点を求めるか(辺7ー8との交点が1個)のどちらかにします。
このようにして垂線とポリゴンが辺の端で交差するすべてのパターンを考えると、次の図のようになります。
1 |2 3 | 3 |
・ーー・ーー・ 2・ーー・ ・3
| | |
| 1・ 1・ーー・2
| | |
x x x
(パターン1) (パターン2) (パターン3)
| ・1 |
| / 1・ーー・2
|/ /|
2・ーー・3 / |
| 3・ |
x x
(パターン4) (パターン5)
この図で、それぞれのパターンと交点を考えてみましょう。
パターン1 交点を1つ求める。
パターン2 交点を求めない。
パターン3 交点を1つ求める。
パターン4 交点を求めない。
パターン5 交点を求めない。
このようにすればいいことになります。要するに、「垂線とポリゴンの辺の交点が辺の第2ポイントになるときには、その辺の第1ポイントのが垂線より左側にあり、第2ポイントが垂線と同じか右側にあるときに交点を求める。」と言うことができます。
それではこのことを頭に入れておいて次の図を考えてみましょう。
・12
/|
14 13 / |
・ーーーー・ |
| p ・11
| x /
| /
| 10・ーー・9
| |
| 7・ーー・8
| |
| 5 |
| ・ーー・6
| |
| |
| ・ーー・3
| 4 /
| /
・ー・
1 2
点pを通る垂線がポリゴンと交わる部分の交点をリストアップしてみます。
辺 2ー 3 交点が辺の第2ポイントですのでパターン5になります。これは交点
を求めません。
辺 3ー 4 交点が辺の第1ポイントですので交点は求めません。
辺 5ー 6 交点が辺の第2ポイントですのでパターン3になります。これは交点
を求めます。
辺 7ー 8 交点が辺の第1ポイントですので交点は求めません。
辺 9ー10 交点が辺の第2ポイントですのでパターン4になります。これは交点
を求めません。
辺10ー11 交点が辺の第1ポイントですので交点は求めません。
辺12ー13 交点が辺の第2ポイントですのでパターン1になります。これは交点
を求めます。
結果としては、頂点6と頂点13の位置に交点が求まり、点の上には1つ点の下には1つとなり、点はポリゴンの内側にあることになります。
ポリゴンにハッチングをかけたり、塗りつぶしを行なうときにも交点を正確に求めなければなりません。そのときにもここで考えたことを考慮する必要があります。ハッチングは塗りつぶしのときには、求められた交点をXまたはYの座標値でソートし、奇数番から偶数番の交点に線分をひくことで実現することができます。
以前CADシステムを作ったときにこの問題で苦労したことがありました。最初は単純に交点を求めて点の位置を調べたりハッチングをかけていたのです。自分でテストしている限りでは正常に動作したのですが、実際のデータでは全然駄目でバグのオンパレードとなってしまった経験があります。その当時は参考になる書籍もなかったので、苦労の末にこのような法則を見つけたのです。今ではこのようなことは本屋に行けばすぐに解決してしまうことなのでちょっと拍子抜けしてしまいます。
それではまた次回。