Ruby/SDLで計算幾何(3) 線分交差判定のディテール
intersectの謎の分析をしようと思いましたが、ccwの分析ができてればそう悩むこともなくてですね。
再掲。
module GeoUtil module_function # 線分p0p1を基準にして、線分p0p2が # 反時計回りの向きにあれば+1 # 時計回りの向きにあれば-1 def ccw(p0, p1, p2) dx1 = p1.x - p0.x; dy1 = p1.y - p0.y dx2 = p2.x - p0.x; dy2 = p2.y - p0.y return +1 if dx1*dy2 > dy1*dx2 return -1 if dx1*dy2 < dy1*dx2 return -1 if (dx1*dx2 < 0) || (dy1*dy2 < 0) #(1) return +1 if dx1*dx1+dy1*dy1 < dx2*dx2+dy2*dy2 #(2) return 0 #(3) end # 2線分が交差しているかを判定する def intersect(l1, l2) return ((ccw(l1.p1, l1.p2, l2.p1) * ccw(l1.p1, l1.p2, l2.p2)) <= 0 ) && ((ccw(l2.p1, l2.p2, l1.p1) * ccw(l2.p1, l2.p2, l1.p2)) <= 0 ) end end
「一方の線分から見て、他方の線分の両端が左右に分かれている」&&「他方から見ても同様」なら、交差しているとみなすのがintersectメソッド。
そして、他方の端点が一方の線分上にある場合は、これは交差しているとみなされます。
線分が同一直線上にある場合、端点位置のパターンとしては上図の3つしかないのですが、その場合の交差・非交差の状況は上の通り。
うん、直感には反してないと思います。
ただ、「一方の線分の端点が同一(線分が一点)の場合」は、個人的には直感に反する結果が出てきます。
class GeoBaseTest < GeoBase def start puts GeoUtil.intersect(l(30,30,30,30), l(20,20,40,40)) end def self.start geo = self.new geo.start end end GeoBaseTest.start #=> false