圆线段碰撞检测算法?
我有一条从 A 到 B 的直线和一个位于 C 处、半径为 R 的圆.
I have a line from A to B and a circle positioned at C with the radius R.
用于检查直线是否与圆相交的好算法是什么?它发生在沿圆边缘的哪个坐标处?
What is a good algorithm to use to check whether the line intersects the circle? And at what coordinate along the circles edge it occurred?
采取
- E 是射线的起点,
- L 是射线的终点,
- C 是您要测试的球心
- r 是球体的半径
- E is the starting point of the ray,
- L is the end point of the ray,
- C is the center of sphere you're testing against
- r is the radius of that sphere
计算:
d = L - E(射线的方向向量,从开始到结束)
f = E - C(从中心球体到射线起点的向量)
Compute:
d = L - E ( Direction vector of ray, from start to end )
f = E - C ( Vector from center sphere to ray start )
然后通过..找到交点
堵塞:
P = E + t * d
这是一个参数方程:
Px = Ex + tdx
Py = Ey + tdy
进入
(x - h)2 + (y - k)2 = r2
(h,k) = 圆心.
Then the intersection is found by..
Plugging:
P = E + t * d
This is a parametric equation:
Px = Ex + tdx
Py = Ey + tdy
into
(x - h)2 + (y - k)2 = r2
(h,k) = center of circle.
注意:我们在这里将问题简化为 2D,我们得到的解决方案也适用于 3D
Note: We've simplified the problem to 2D here, the solution we get applies also in 3D
获得:
- 展开x2 - 2xh + h2 + y2 - 2yk + k2 - r2 = 0
-
插头x = ex + tdx
y = ey + tdy
( ex + tdx )2 - 2( ex + tdx )h + h2 +( ey + tdy )2 - 2( ey + tdy )k + k2 - r2 = 0 - 爆炸ex2 + 2extdx + t2dx2 - 2exh - 2tdxh + h2 +ey2 + 2eytdy + t2dy2 - 2eyk - 2tdyk + k2 - r2 = 0
- 群组t2( dx2 + dy2 ) +2t( exdx + eydy - dxh- dyk ) +ex2 + ey2 -2exh - 2eyk + h2 + k2 - r2 = 0
-
最后,t2( d · d ) + 2t( e · d - d · c ) + e · e - 2( e · c ) + c · c - r2 = 0
其中 d 是向量 d,· 是点积. - 然后,t2( d · d ) + 2t( d · ( e -c ) ) + ( e - c ) · ( e - c )- r2 = 0
- Letting f = e - ct2( d · d ) + 2t( d · f ) +f · f - r2 = 0
- Expand x2 - 2xh + h2 + y2 - 2yk + k2 - r2 = 0
-
Plug
x = ex + tdx
y = ey + tdy
( ex + tdx )2 - 2( ex + tdx )h + h2 + ( ey + tdy )2 - 2( ey + tdy )k + k2 - r2 = 0 - Explode ex2 + 2extdx + t2dx2 - 2exh - 2tdxh + h2 + ey2 + 2eytdy + t2dy2 - 2eyk - 2tdyk + k2 - r2 = 0
- Group t2( dx2 + dy2 ) + 2t( exdx + eydy - dxh - dyk ) + ex2 + ey2 - 2exh - 2eyk + h2 + k2 - r2 = 0
-
Finally,
t2( d · d ) + 2t( e · d - d · c ) + e · e - 2( e · c ) + c · c - r2 = 0
Where d is the vector d and · is the dot product. - And then, t2( d · d ) + 2t( d · ( e - c ) ) + ( e - c ) · ( e - c ) - r2 = 0
- Letting f = e - c t2( d · d ) + 2t( d · f ) + f · f - r2 = 0
所以我们得到:
t2 * (d · d) + 2t*( f · d) + ( f · f - r2 ) = 0
So we get:
t2 * (d · d) + 2t*( f · d ) + ( f · f - r2 ) = 0
所以求解二次方程:
float a = d.Dot( d ) ;
float b = 2*f.Dot( d ) ;
float c = f.Dot( f ) - r*r ;
float discriminant = b*b-4*a*c;
if( discriminant < 0 )
{
// no intersection
}
else
{
// ray didn't totally miss sphere,
// so there is a solution to
// the equation.
discriminant = sqrt( discriminant );
// either solution may be on or off the ray so need to test both
// t1 is always the smaller value, because BOTH discriminant and
// a are nonnegative.
float t1 = (-b - discriminant)/(2*a);
float t2 = (-b + discriminant)/(2*a);
// 3x HIT cases:
// -o-> --|--> | | --|->
// Impale(t1 hit,t2 hit), Poke(t1 hit,t2>1), ExitWound(t1<0, t2 hit),
// 3x MISS cases:
// -> o o -> | -> |
// FallShort (t1>1,t2>1), Past (t1<0,t2<0), CompletelyInside(t1<0, t2>1)
if( t1 >= 0 && t1 <= 1 )
{
// t1 is the intersection, and it's closer than t2
// (since t1 uses -b - discriminant)
// Impale, Poke
return true ;
}
// here t1 didn't intersect so we are either started
// inside the sphere or completely past it
if( t2 >= 0 && t2 <= 1 )
{
// ExitWound
return true ;
}
// no intn: FallShort, Past, CompletelyInside
return false ;
}