任意の点から無限遠方に半直線を延ばした場合、
点がパスの内部なら奇数回、パスの外部なら偶数回パスと交差することを
利用。パスの時計回り・反時計回りは影響しない。
かなり古いコードなので、今ならもっと整理できるところがありそう。#module cross
#deffunc setline int p1, int p2, int p3, int p4
x1 = p1 : y1 = p2
x2 = p3 : y2 = p4
type1 = x1 != x2
if type1 {
// 傾きあり
a1 = double(y2 - y1)/(x2 - x1)
b1 = double(x2 * y1 - x1 * y2)/(x2 - x1)
}
return
#deffunc serchline int x3, int y3, int x4, int y4
result = 0
type2 = x3 != x4
if type2 {
a2 = double(y4 - y3)/(x4 - x3)
b2 = double(x4 * y3 - x3 * y4)/(x4 - x3)
}
if (type1 == 0)&(type2 == 0) {
// 共にY軸に並行
result = 0
}
if (type1 == 0)&(type2 == 1){
// OK
CrossX = int(x1)
CrossY = int(a2 * x1 + b2)
result = ((CrossY - y1)*(CrossY - y2)<=0) & ((CrossX - x3)*(CrossX - x4)<=0) & ((CrossY - y3)*(CrossY - y4)<=0)
}
if (type1 == 1)&(type2 == 0) {
CrossX = int(x3)
CrossY = int(a4 * x3 + b4)
result = ((CrossX - x1)*(CrossX - x2)<=0) & ((CrossY - y1)*(CrossY - y2)<=0) & ((CrossX - x3)*(CrossX - x4)<=0)
}
if (type1 == 1)&(type2 == 1){
if a1 == a2 {
result = 0
} else {
CrossX = -int((b1 - b2)/(a1 - a2))
CrossY = int((a1 * b2 - a2 * b1)/(a1 - a2))
result = ((CrossX - x1)*(CrossX - x2)<=0) & ((CrossY - y1)*(CrossY - y2)<=0) & ((CrossX - x3)*(CrossX - x4)<=0) & ((CrossY - y3)*(CrossY - y4)<=0)
}
}
return result
#defcfunc GetCrossX
return CrossX
#defcfunc GetCrossY
return CrossY
#global
#module path
#deffunc renew
index = 0
return
#deffunc addpoint int p1, int p2
x(index) = p1 : y(index) = p2
if index >= 2 {
// すでにあるパスと交差していないか?
setline x(index - 1), y(index - 1), x(index), y(index)
l = -1
repeat index - 2
serchline x(cnt), y(cnt), x(cnt + 1), y(cnt + 1)
if stat : l = cnt : break
loop
if l>=0 {
// 交点を新たなパスにする
x(index) = GetCrossX() // int(NewX)
y(index) = GetCrossY() // int(NewY)
// No.0~lまでを削除(l+1個点が消えることになる)
index -= l
repeat index
x(cnt) = x(cnt + l + 1)
y(cnt) = y(cnt + l + 1)
loop
return 1 // パスが完結しました!
}
}
index++
return 0
#deffunc drawpoint int p1
repeat index
circle x(cnt)-p1, y(cnt)-p1, x(cnt)+p1, y(cnt)+p1
loop
return
#define global drawedge(%1=-1, %2=0, %3=0) _drawedge %1, %2, %3
#deffunc _drawedge int p1, int p2, int p3
if index < 2 : return
pos x(0), y(0)
repeat index - 1, 1
line x(cnt), y(cnt)
loop
if p3{
if p1 >= 0 : line p1, p2
} else {
line x(0), y(0)
}
return
#defcfunc inner int p1, int p2
; 点と同じYだと異常動作
if index <= 2 : return 0
i = 0
repeat index ; 右に伸ばす
EdgeBack = cnt // ひとつ前の点
EdgeStart = (cnt + 1) \ index // この点は含む
EdgeEnd = (cnt + 2) \ index // この点は含まない
if (x(EdgeStart)<p1)&(x(EdgeEnd)<=p1) : continue
if (y(EdgeStart)<p2)&(y(EdgeEnd)<=p2) : continue
if (y(EdgeStart)>p2)&(y(EdgeEnd)>=p2) : continue
if y(EdgeStart) == y(EdgeEnd) {
if x(EdgeStart) > p1 : i++
}else{
if (x(EdgeEnd) + (x(EdgeStart) - x(EdgeEnd))*(p2 - y(EdgeEnd))/(y(EdgeStart) - y(EdgeEnd))) >= p1 {
i++
if (y(EdgeStart) == p2)&(y(EdgeStart) - y(EdgeEnd))*(y(EdgeStart) - y(EdgeBack)) > 0 : i++
}
}
loop
return i \ 2
#defcfunc lastx
if index : return x(index-1)
return 0
#defcfunc lasty
if index : return y(index-1)
return 0
#global
screen 0, 384, 288
renew
*main
wait 4
getkey MouseLeft, 1
if MouseLeft & Click {
R = sqrt((mousex-lastx())*(mousex-lastx()) + (mousey-lasty())*(mousey-lasty()))
if R > 15 : addpoint mousex, mousey
if stat == 1 : Click = 0 // パス完結
} else {
Click = 0
}
stick Key
if Key & 256 {
Click = 1
renew
addpoint mousex, mousey
}
redraw 0
color 255, 255, 255 : boxf
color 0, 64, 128 : drawedge mousex, mousey, Click
repeat ginfo_winx/48
x = cnt*48 + 24
repeat ginfo_winy/48
y = cnt*48 + 24
color 0, 0, 255
if inner(x, y) : color 255, 128, 0
circle x-3, y-3, x+3, y+3
loop
loop
redraw 1
if inner(mousex, mousey) {
title "マウスカーソルはパスの内部にあります"
} else {
title "マウスカーソルはパスの外部にあります"
}
goto *main
2007年5月8日火曜日
点がパスの内部にあるか判定
登録:
コメントの投稿 (Atom)
0 件のコメント:
コメントを投稿