高校数学ではもちろん、大学の数学や物理でもよく言うところの「自明」であるのか、こういう用途に使えることを教えてはくれない。ここでは外積を使用することでふたつの線分がどの位置関係にあるのか判定できることを解説する。

2次元空間における外積はベクトル があるときに、その外積は で求められる。これをPythonで書けば次のようになる。

from typing import Self
 
class Vec2D:
    def __init__(self, x: float, y: float) -> None:
        self.x = x
        self.y = y
 
    def cross(self, other: Self) -> float:
        return self.x * other.y - self.y * other.x
 
class Point2D:
    def __init__(self, x: float, y: float) -> None:
        self.x = x
        self.y = y
 
    def __sub__(self, other: Self) -> Vec2D:
        return Vec2D(self.x - other.x, self.y - other.y)

また、ここで考える点は次のような位置関係にあるとする。

同じ傾きであれば外積は0

ここで は0になる。逆ベクトルとの外積 も0である。また、 の半分の長さの , があったとしても、 の結果は同様に0になる。つまり、符号を無視して同じ傾きを持っていれば(平行であれば)、長さに関係なく外積は0になる。

a = Point2D(8, 7) - Point2D(2, 3)
b = Point2D(8, 7) - Point2D(2, 3)
print(a.cross(b))    # 0
 
a = Point2D(8, 7) - Point2D(2, 3)
b = Point2D(2, 3) - Point2D(8, 7)
print(a.cross(b))    # 0
 
a = Point2D(8, 7) - Point2D(2, 3)
b = Point2D(5, 5) - Point2D(2, 3)
print(a.cross(b))    # 0

始点が同じ場合の位置関係

次に について考えてみる。 に対して反時計回りの方向にある の外積は となり、時計回りの方向にある との外積は となる。

a = Point2D(8, 7) - Point2D(2, 3)
b = Point2D(3, 9) - Point2D(2, 3)
print(a.cross(b))    # 32
 
a = Point2D(8, 7) - Point2D(2, 3)
b = Point2D(7, 4) - Point2D(2, 3)
print(a.cross(b))    # -14

線分ABとCDの交差判定

の間に があり、 の間に があることを確認すればよい。これを計算すると次のようになる。

  • から見て交差する
  • から見て交差する
  • 噛み砕くと…
    • に対して反時計回り方向に交差するだけの十分な長さがある
    • に対して反時計回り方向に交差するだけの十分な長さがある
    • に対して時計回り方向に交差するだけの十分な長さがある
    • に対して時計回り方向に交差するだけの十分な長さがある

さらに、, はそれぞれ入れ替えても同様なので、

かつ

であれば線分 は交差する。

多角形の凸包判定

任意の凹んでいない 角形 () のことを凸包と言うが、反時計回りに一周するように頂点同士の外積を計算し、結果がすべて正であれば凸包となる。

ポリゴンの頂点を設定する際に、砂時計の形のようにねじれた形に配置することもできるが、その場合でも正しく判定できる。

多角形と点Pの内包判定

多角形の点のうち、最大の 座標を としたときに、線分 がいずれかの辺とちょうど1回交差すれば多角形内に点Pが含まれている。線分Pと交差判定を行う辺が平行関係にあると外積は0になるので、辺上の点も内包扱いにする場合には追加の考慮が必要となる。