본문 바로가기

강의자료/수학이야기

직선과 구의 교차여부 테스트.

직선은 시작점 start와 방향벡터 dir로 표현하고
구는 중점 center와 반지름 radius로 표현한다.

직선과 구의 교차여부를 테스트하기 위해서는
구의 중점에서 직선으로 수선(직교하는 선)을 그린 후 수선의 길이와 구의 반지름의 길이를 비교해야 한다.

즉, 수선의 길이를 구하는 것이 핵심인 것이다.
이 수선의 길이를 구하기 위해서 피타고라스의 정리를 이용한다.
우선 수선을 직각삼각형의 높이라고 가정하고,
직각삼각형의 빗변은 직선의 시작점에서 구의 중점을 이은 선분으로 가정한다.
그럼 자연스레 직각삼각형의 밑변은 직선의 시작점에서 수선의 발(직선과 수선이 직교하는 점)까지를 이은 선분이 된다.
바로 빗변과 밑변의 길이를 구함으로써 우리가 구하고자 하는 높이(수선의 길이)를 구할수가 있게 된다.

○ 빗변 구하기
직선의 시작점 start에서 구의 중점 center를 향하는 벡터 q를 구한다.
    q = center - start
벡터 q를 직각삼각형의 빗변 c로 가정하고 그 길이를 구한다.
    c*c = q.x*q.x + q.y*q.y
○ 밑변 구하기
직선의 방향벡터(정규화를 시킨)와 벡터 q를 내적하여 직각삼각형의 밑변의 길이 v를 구한다.
    v = q Ο dir
○ 높이 구하기
직각삼각형의 빗변의 길이 c와 밑변의 길이 v를 구했으므로 높이 d는 피타고라스의 정리에 의해서
    d*d = c*c - v*v
여기서 구한 직각삼각형의 높이와 구의 반지름의 길이를 비교하면 충돌여부를 알 수 있다.

위의 과정을 C++ 코드로 구현해보자.
// 구와의 교차여부 테스트.
// start : 직선의 시작점.
// vdir : 직선의 방향벡터.
// sorgin : 구의 중점.
// sradius : 구의 반지름.
// outdistance : 구와 직선의 직교 거리.
bool getIntersectionWithSphere(Vector3d sorigin, T sradius, f64& outdistance) const
{
	// 직선의 시작점에서 구의 중점을 향하는 벡터 q를 구한다.
	const Vector3d q = sorigin - start;
	// 벡터 q를 직각삼각형의 빗변 c로 가정하고 그 길이를 구한다.
	T c = q.getLength();
	// 직선의 방향벡터(정규화를 시킨)와 벡터 q를 내적하여 직각삼각형의 밑변의 길이 v를 구한다.
	T v = q.dotProduct(vdir.normalize());
	// 직각삼각형의 빗변의 길이 c와 밑변의 길이 v를 구했으므로 높이 d는 피타고라스의 정리에 의해서
	// d*d = c*c - v*v
	// 직각삼각형의 높이와 반지름의 길이를 비교하면 충돌여부를 알 수 있다.
	T d = sradius * sradius - (c*c - v*v);

	if (d < 0.0)
		return false;

	outdistance = v - WhiteSnake::squareroot(d);
	return true;
}