use super::shapes::{Box3D, Circle, Sphere, Triangle3D};
#[allow(dead_code)]
pub fn continuous_sphere_sphere_collision(
sphere1: &Sphere,
velocity1: &[f64; 3],
sphere2: &Sphere,
velocity2: &[f64; 3],
time_step: f64,
) -> Option<(f64, [f64; 3], [f64; 3])> {
let relative_position = [
sphere1.center[0] - sphere2.center[0],
sphere1.center[1] - sphere2.center[1],
sphere1.center[2] - sphere2.center[2],
];
let relative_velocity = [
velocity1[0] - velocity2[0],
velocity1[1] - velocity2[1],
velocity1[2] - velocity2[2],
];
let a = relative_velocity[0] * relative_velocity[0]
+ relative_velocity[1] * relative_velocity[1]
+ relative_velocity[2] * relative_velocity[2];
if a < 1e-10 {
let distance_squared = relative_position[0] * relative_position[0]
+ relative_position[1] * relative_position[1]
+ relative_position[2] * relative_position[2];
let sum_of_radii = sphere1.radius + sphere2.radius;
if distance_squared <= sum_of_radii * sum_of_radii {
return Some((0.0, sphere1.center, sphere2.center));
} else {
return None;
}
}
let b = 2.0
* (relative_velocity[0] * relative_position[0]
+ relative_velocity[1] * relative_position[1]
+ relative_velocity[2] * relative_position[2]);
let c = relative_position[0] * relative_position[0]
+ relative_position[1] * relative_position[1]
+ relative_position[2] * relative_position[2]
- (sphere1.radius + sphere2.radius) * (sphere1.radius + sphere2.radius);
if c <= 0.0 {
return Some((0.0, sphere1.center, sphere2.center));
}
let discriminant = b * b - 4.0 * a * c;
if discriminant < 0.0 {
return None;
}
let t = (-b - discriminant.sqrt()) / (2.0 * a);
if t >= 0.0 && t <= time_step {
Some((
t,
[
sphere1.center[0] + velocity1[0] * t,
sphere1.center[1] + velocity1[1] * t,
sphere1.center[2] + velocity1[2] * t,
],
[
sphere2.center[0] + velocity2[0] * t,
sphere2.center[1] + velocity2[1] * t,
sphere2.center[2] + velocity2[2] * t,
],
))
} else {
None
}
}
#[allow(dead_code)]
pub fn continuous_circle_circle_collision(
circle1: &Circle,
velocity1: &[f64; 2],
circle2: &Circle,
time_step: f64,
) -> Option<f64> {
let relative_position = [
circle1.center[0] - circle2.center[0],
circle1.center[1] - circle2.center[1],
];
let relative_velocity = velocity1;
let a =
relative_velocity[0] * relative_velocity[0] + relative_velocity[1] * relative_velocity[1];
if a < 1e-10 {
let distance_squared = relative_position[0] * relative_position[0]
+ relative_position[1] * relative_position[1];
let sum_of_radii = circle1.radius + circle2.radius;
if distance_squared <= sum_of_radii * sum_of_radii {
return Some(0.0);
} else {
return None;
}
}
let b = 2.0
* (relative_velocity[0] * relative_position[0]
+ relative_velocity[1] * relative_position[1]);
let c = relative_position[0] * relative_position[0]
+ relative_position[1] * relative_position[1]
- (circle1.radius + circle2.radius) * (circle1.radius + circle2.radius);
if c <= 0.0 {
return Some(0.0);
}
let discriminant = b * b - 4.0 * a * c;
if discriminant < 0.0 {
return None;
}
let t = (-b - discriminant.sqrt()) / (2.0 * a);
if t >= 0.0 && t <= time_step {
Some(t)
} else {
None
}
}
#[allow(dead_code)]
pub fn continuous_point_triangle3d_collision(
point: &[f64; 3],
velocity: &[f64; 3],
triangle: &Triangle3D,
time_step: f64,
) -> Option<f64> {
let speed =
(velocity[0] * velocity[0] + velocity[1] * velocity[1] + velocity[2] * velocity[2]).sqrt();
if speed < 1e-10 {
return None;
}
let ray_direction = [
velocity[0] / speed,
velocity[1] / speed,
velocity[2] / speed,
];
let intersection =
super::narrowphase::ray_triangle3d_collision(point, &ray_direction, triangle);
match intersection {
Some((t, hit_point, barycentric)) => {
let actual_t = t / speed; if actual_t >= 0.0 && actual_t <= time_step {
Some(actual_t)
} else {
None
}
}
None => None,
}
}
#[allow(dead_code)]
pub fn continuous_box3d_box3d_collision(
box1: &Box3D,
velocity1: &[f64; 3],
box2: &Box3D,
time_step: f64,
) -> Option<f64> {
if super::narrowphase::box3d_box3d_collision(box1, box2) {
return Some(0.0);
}
let mut t_entry = [f64::NEG_INFINITY; 3];
let mut t_exit = [f64::INFINITY; 3];
for i in 0..3 {
if velocity1[i] > 0.0 {
t_entry[i] = (box2.min[i] - box1.max[i]) / velocity1[i];
t_exit[i] = (box2.max[i] - box1.min[i]) / velocity1[i];
} else if velocity1[i] < 0.0 {
t_entry[i] = (box2.max[i] - box1.min[i]) / velocity1[i];
t_exit[i] = (box2.min[i] - box1.max[i]) / velocity1[i];
}
}
let t_in = t_entry[0].max(t_entry[1]).max(t_entry[2]);
let t_out = t_exit[0].min(t_exit[1]).min(t_exit[2]);
if t_in > t_out || t_in > time_step || t_out < 0.0 {
return None;
}
if t_in >= 0.0 {
Some(t_in)
} else {
Some(0.0)
}
}
#[allow(dead_code)]
pub fn continuous_triangle3d_sphere_collision(
triangle: &Triangle3D,
velocity: &[f64; 3],
sphere: &Sphere,
time_step: f64,
) -> Option<f64> {
let inverse_velocity = [-velocity[0], -velocity[1], -velocity[2]];
let sphere_adjusted = Sphere {
center: sphere.center,
radius: sphere.radius,
};
if super::narrowphase::sphere_triangle3d_collision(&sphere_adjusted, triangle) {
return Some(0.0);
}
let vertices = [triangle.v1, triangle.v2, triangle.v3];
let mut earliest_time = f64::INFINITY;
let mut collision_found = false;
for vertex in &vertices {
let point = *vertex;
let dx = point[0] - sphere.center[0];
let dy = point[1] - sphere.center[1];
let dz = point[2] - sphere.center[2];
let dist_squared = dx * dx + dy * dy + dz * dz;
if dist_squared <= sphere.radius * sphere.radius {
return Some(0.0);
}
let a = inverse_velocity[0] * inverse_velocity[0]
+ inverse_velocity[1] * inverse_velocity[1]
+ inverse_velocity[2] * inverse_velocity[2];
if a < 1e-10 {
continue; }
let b =
2.0 * (dx * inverse_velocity[0] + dy * inverse_velocity[1] + dz * inverse_velocity[2]);
let c = dist_squared - sphere.radius * sphere.radius;
let discriminant = b * b - 4.0 * a * c;
if discriminant >= 0.0 {
let t = (-b - discriminant.sqrt()) / (2.0 * a);
if t >= 0.0 && t <= time_step && t < earliest_time {
earliest_time = t;
collision_found = true;
}
}
}
let edges = [
(triangle.v1, triangle.v2),
(triangle.v2, triangle.v3),
(triangle.v3, triangle.v1),
];
for &(start, end) in &edges {
let edge_vector = [end[0] - start[0], end[1] - start[1], end[2] - start[2]];
let edge_length_squared = edge_vector[0] * edge_vector[0]
+ edge_vector[1] * edge_vector[1]
+ edge_vector[2] * edge_vector[2];
let t0 = {
let v = [
sphere.center[0] - start[0],
sphere.center[1] - start[1],
sphere.center[2] - start[2],
];
let dot = v[0] * edge_vector[0] + v[1] * edge_vector[1] + v[2] * edge_vector[2];
dot / edge_length_squared
};
let t0_clamped = t0.clamp(0.0, 1.0);
let closest_point = [
start[0] + t0_clamped * edge_vector[0],
start[1] + t0_clamped * edge_vector[1],
start[2] + t0_clamped * edge_vector[2],
];
let dx = closest_point[0] - sphere.center[0];
let dy = closest_point[1] - sphere.center[1];
let dz = closest_point[2] - sphere.center[2];
let dist_squared = dx * dx + dy * dy + dz * dz;
if dist_squared <= sphere.radius * sphere.radius {
return Some(0.0);
}
let a = inverse_velocity[0] * inverse_velocity[0]
+ inverse_velocity[1] * inverse_velocity[1]
+ inverse_velocity[2] * inverse_velocity[2];
if a < 1e-10 {
continue; }
let b =
2.0 * (dx * inverse_velocity[0] + dy * inverse_velocity[1] + dz * inverse_velocity[2]);
let c = dist_squared - sphere.radius * sphere.radius;
let discriminant = b * b - 4.0 * a * c;
if discriminant >= 0.0 {
let t = (-b - discriminant.sqrt()) / (2.0 * a);
if t >= 0.0 && t <= time_step && t < earliest_time {
earliest_time = t;
collision_found = true;
}
}
}
let normal = {
let edge1 = [
triangle.v2[0] - triangle.v1[0],
triangle.v2[1] - triangle.v1[1],
triangle.v2[2] - triangle.v1[2],
];
let edge2 = [
triangle.v3[0] - triangle.v1[0],
triangle.v3[1] - triangle.v1[1],
triangle.v3[2] - triangle.v1[2],
];
let cross = [
edge1[1] * edge2[2] - edge1[2] * edge2[1],
edge1[2] * edge2[0] - edge1[0] * edge2[2],
edge1[0] * edge2[1] - edge1[1] * edge2[0],
];
let length = (cross[0] * cross[0] + cross[1] * cross[1] + cross[2] * cross[2]).sqrt();
if length < 1e-10 {
[0.0, 0.0, 0.0] } else {
[cross[0] / length, cross[1] / length, cross[2] / length]
}
};
if normal[0] == 0.0 && normal[1] == 0.0 && normal[2] == 0.0 {
if collision_found {
return Some(earliest_time);
}
return None;
}
let plane_dist = (sphere.center[0] - triangle.v1[0]) * normal[0]
+ (sphere.center[1] - triangle.v1[1]) * normal[1]
+ (sphere.center[2] - triangle.v1[2]) * normal[2];
let approach_speed = -(inverse_velocity[0] * normal[0]
+ inverse_velocity[1] * normal[1]
+ inverse_velocity[2] * normal[2]);
if approach_speed.abs() > 1e-10 {
let t_plane = (plane_dist.abs() - sphere.radius) / approach_speed;
if t_plane >= 0.0 && t_plane <= time_step && t_plane < earliest_time {
let projected_center = [
sphere.center[0] + inverse_velocity[0] * t_plane
- normal[0] * sphere.radius * plane_dist.signum(),
sphere.center[1] + inverse_velocity[1] * t_plane
- normal[1] * sphere.radius * plane_dist.signum(),
sphere.center[2] + inverse_velocity[2] * t_plane
- normal[2] * sphere.radius * plane_dist.signum(),
];
if super::narrowphase::point_triangle3d_collision(&projected_center, triangle) {
earliest_time = t_plane;
collision_found = true;
}
}
}
if collision_found {
Some(earliest_time)
} else {
None
}
}
#[allow(dead_code)]
pub fn continuous_sphere_triangle3d_collision(
sphere: &Sphere,
velocity: &[f64; 3],
triangle: &Triangle3D,
time_step: f64,
) -> Option<f64> {
let inverse_velocity = [-velocity[0], -velocity[1], -velocity[2]];
continuous_triangle3d_sphere_collision(triangle, &inverse_velocity, sphere, time_step)
}