ncollide3d/query/time_of_impact/
time_of_impact_ball_ball.rs1use na::{RealField, Unit};
2
3use crate::math::{Point, Vector};
4use crate::query::{self, Ray, TOIStatus, TOI};
5use crate::shape::Ball;
6
7#[inline]
9pub fn time_of_impact_ball_ball<N: RealField + Copy>(
10 center1: &Point<N>,
11 vel1: &Vector<N>,
12 b1: &Ball<N>,
13 center2: &Point<N>,
14 vel2: &Vector<N>,
15 b2: &Ball<N>,
16 max_toi: N,
17 target_distance: N,
18) -> Option<TOI<N>> {
19 let vel = *vel1 - *vel2;
20 let rsum = b1.radius + b2.radius;
21 let radius = rsum + target_distance;
22 let center = *center1 + (-center2.coords);
23 let ray = Ray::new(Point::origin(), -vel);
24
25 if let (inside, Some(toi)) = query::ray_toi_with_ball(¢er, radius, &ray, true) {
26 if toi > max_toi {
27 return None;
28 }
29
30 let dpt = ray.point_at(toi) - center;
31 let normal1;
32 let normal2;
33 let witness1;
34 let witness2;
35
36 if radius.is_zero() {
37 normal1 = Vector::x_axis();
38 normal2 = Vector::x_axis();
39 witness1 = Point::origin();
40 witness2 = Point::origin();
41 } else {
42 normal1 = Unit::new_unchecked(dpt / radius);
43 normal2 = -normal1;
44 witness1 = Point::from(*normal1 * b1.radius);
45 witness2 = Point::from(*normal2 * b2.radius);
46 }
47
48 let status = if inside && center.coords.norm_squared() < rsum * rsum {
49 TOIStatus::Penetrating
50 } else {
51 TOIStatus::Converged
52 };
53
54 Some(TOI {
55 toi,
56 normal1,
57 normal2,
58 witness1,
59 witness2,
60 status,
61 })
62 } else {
63 None
64 }
65}