49
23

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

2線分の交差判定手法 (2次元)

Last updated at Posted at 2019-11-18

AtCoderで遊んでいたところ「このような問題」に出くわした。
そこで同一平面上に存在する2線分の交差判定手法について調査した。

#線分が交差する条件
線分 $AB$ と線分 $CD$ について考える。

(1) 点 $A$ 点 $B$ を含む直線 $AB$ を境界線として平面を分割するとき、点 $C$ 点 $D$ がそれぞれ別の領域に存在
(2) 点 $C$ 点 $D$ を含む直線 $CD$ を境界線として平面を分割するとき、点 $A$ 点 $B$ がそれぞれ別の領域に存在

(1), (2)の条件を共に満たすとき線分 $AB$ と線分 $CD$ は交差する。

#点の存在する領域
点 $P$ が平面を分割する直線に対してどちらの領域に存在するかは、直線の方程式に点 $P$ の座標を代入した値の正負で判定ができる。

例えば、直線 $x - y = 0$ に対する点 $C$ $(4, -2)$ の存在する領域を調べる場合
$x - y$ に $(x, y) = (4, -2)$ を代入すると $x - y = 6$ $(> 0)$

一方、直線 $x - y = 0$ に対する点 $D$ $(-4, 2)$ の存在する領域を調べる場合
$x - y$ に $(x, y) = (-4, 2)$ を代入すると $x - y = -6$ $(< 0)$

点 $C, D$ で得られる値の正負が異なるため、点 $C, D$ は別の領域に存在することがわかる。
graph1.png

つまりこの判定を

  • 直線 $AB$ に対する点 $C, D$
  • 直線 $CD$ に対する点 $A, B$

で行えば線分の交差判定ができる。
(線分の端点が別の線分上に存在する場合に注意)

#線分の交差判定を行うアルゴリズム
まず点 $A$ $(x_A, y_A),$ 点 $B$ $(x_B, y_B)$ を含む直線 $AB$ の方程式を求める。

直線 $AB$ の傾きは $\frac{y_A - y_B}{x_A - x_B}$

直線 $AB$ は点 $A$ を含むため、直線 $AB$ の方程式は $y - y_A = \frac{y_A - y_B}{x_A - x_B} (x - x_A)$

式を変形すると $(x_A - x_B)(y - y_A) - (y_A - y_B)(x - x_A) = 0$

したがって点 $C$ $(x_C, y_C),$ 点 $D$ $(x_D, y_D)$ の領域判定を行う場合

$s = (x_A - x_B)(y_C - y_A) - (y_A - y_B)(x_C - x_A)$
$t = (x_A - x_B)(y_D - y_A) - (y_A - y_B)(x_D - x_A)$

とおくと $st<0$ の時、点 $C, D$ は直線 $AB$ に対して別の領域に存在するといえる。

上記のアルゴリズムをC++で記述した例を以下に示す。


typedef struct Point_Coordinates {
	double x, y;
} point;

// 線分ab, cdが交差する場合True
// 端点が他方の線分上にある場合もTrue
// 端点が他方の線分の延長線上にある場合もTrueを返すので注意
int Judge(point &a, point &b, point &c, point &d) {
	double s, t;
	s = (a.x - b.x) * (c.y - a.y) - (a.y - b.y) * (c.x - a.x);
	t = (a.x - b.x) * (d.y - a.y) - (a.y - b.y) * (d.x - a.x);
	if (s * t > 0)
		return false;

	s = (c.x - d.x) * (a.y - c.y) - (c.y - d.y) * (a.x - c.x);
	t = (c.x - d.x) * (b.y - c.y) - (c.y - d.y) * (b.x - c.x);
	if (s * t > 0)
		return false;
	return true;
}

#外積を用いる方法
ここまで直線の方程式を用いて領域判定を行ってきたが、外積を用いると簡単に判定を行うことができる。
image1.jpeg

2次元平面においてベクトル $\vec{a}, \vec{b}$ の外積 $\vec{a} \times \vec{b}$ は $\vec{a}$ から $\vec{b}$ への右ねじの方向を符号に持つスカラー値となる。
したがって線分 $AB, CD$ の交差判定を行う場合

$s = \vec{AB} \times \vec{AC} = (x_B - x_A)(y_C - y_A) - (x_C - x_A)(y_B - y_A)$
$t = \vec{AB} \times \vec{AD} = (x_B - x_A)(y_D - y_A) - (x_D - x_A)(y_B - y_A)$

とおくと $st<0$ の時、点 $C, D$ は直線 $AB$ に対して別の領域に存在するといえる。
またこの $st$ の値は 線分の交差判定を行うアルゴリズム と同じ値を取ることがわかる

#まとめ
一見異なる求め方でも同じ式が導かれるの面白い

49
23
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
49
23

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?