scirs2_spatial/collision/
continuous.rs1use super::shapes::{Box3D, Circle, Sphere, Triangle3D};
7
8#[allow(dead_code)]
23pub fn continuous_sphere_sphere_collision(
24 sphere1: &Sphere,
25 velocity1: &[f64; 3],
26 sphere2: &Sphere,
27 velocity2: &[f64; 3],
28 time_step: f64,
29) -> Option<(f64, [f64; 3], [f64; 3])> {
30 let relative_position = [
32 sphere1.center[0] - sphere2.center[0],
33 sphere1.center[1] - sphere2.center[1],
34 sphere1.center[2] - sphere2.center[2],
35 ];
36
37 let relative_velocity = [
38 velocity1[0] - velocity2[0],
39 velocity1[1] - velocity2[1],
40 velocity1[2] - velocity2[2],
41 ];
42
43 let a = relative_velocity[0] * relative_velocity[0]
48 + relative_velocity[1] * relative_velocity[1]
49 + relative_velocity[2] * relative_velocity[2];
50
51 if a < 1e-10 {
53 let distance_squared = relative_position[0] * relative_position[0]
55 + relative_position[1] * relative_position[1]
56 + relative_position[2] * relative_position[2];
57 let sum_of_radii = sphere1.radius + sphere2.radius;
58
59 if distance_squared <= sum_of_radii * sum_of_radii {
60 return Some((0.0, sphere1.center, sphere2.center));
61 } else {
62 return None;
63 }
64 }
65
66 let b = 2.0
68 * (relative_velocity[0] * relative_position[0]
69 + relative_velocity[1] * relative_position[1]
70 + relative_velocity[2] * relative_position[2]);
71
72 let c = relative_position[0] * relative_position[0]
74 + relative_position[1] * relative_position[1]
75 + relative_position[2] * relative_position[2]
76 - (sphere1.radius + sphere2.radius) * (sphere1.radius + sphere2.radius);
77
78 if c <= 0.0 {
80 return Some((0.0, sphere1.center, sphere2.center));
81 }
82
83 let discriminant = b * b - 4.0 * a * c;
85
86 if discriminant < 0.0 {
87 return None;
89 }
90
91 let t = (-b - discriminant.sqrt()) / (2.0 * a);
93
94 if t >= 0.0 && t <= time_step {
96 Some((
97 t,
98 [
99 sphere1.center[0] + velocity1[0] * t,
100 sphere1.center[1] + velocity1[1] * t,
101 sphere1.center[2] + velocity1[2] * t,
102 ],
103 [
104 sphere2.center[0] + velocity2[0] * t,
105 sphere2.center[1] + velocity2[1] * t,
106 sphere2.center[2] + velocity2[2] * t,
107 ],
108 ))
109 } else {
110 None
111 }
112}
113
114#[allow(dead_code)]
127pub fn continuous_circle_circle_collision(
128 circle1: &Circle,
129 velocity1: &[f64; 2],
130 circle2: &Circle,
131 time_step: f64,
132) -> Option<f64> {
133 let relative_position = [
135 circle1.center[0] - circle2.center[0],
136 circle1.center[1] - circle2.center[1],
137 ];
138
139 let relative_velocity = velocity1;
140
141 let a =
143 relative_velocity[0] * relative_velocity[0] + relative_velocity[1] * relative_velocity[1];
144
145 if a < 1e-10 {
147 let distance_squared = relative_position[0] * relative_position[0]
149 + relative_position[1] * relative_position[1];
150 let sum_of_radii = circle1.radius + circle2.radius;
151
152 if distance_squared <= sum_of_radii * sum_of_radii {
153 return Some(0.0);
154 } else {
155 return None;
156 }
157 }
158
159 let b = 2.0
160 * (relative_velocity[0] * relative_position[0]
161 + relative_velocity[1] * relative_position[1]);
162
163 let c = relative_position[0] * relative_position[0]
164 + relative_position[1] * relative_position[1]
165 - (circle1.radius + circle2.radius) * (circle1.radius + circle2.radius);
166
167 if c <= 0.0 {
169 return Some(0.0);
170 }
171
172 let discriminant = b * b - 4.0 * a * c;
173
174 if discriminant < 0.0 {
175 return None;
177 }
178
179 let t = (-b - discriminant.sqrt()) / (2.0 * a);
181
182 if t >= 0.0 && t <= time_step {
184 Some(t)
185 } else {
186 None
187 }
188}
189
190#[allow(dead_code)]
203pub fn continuous_point_triangle3d_collision(
204 point: &[f64; 3],
205 velocity: &[f64; 3],
206 triangle: &Triangle3D,
207 time_step: f64,
208) -> Option<f64> {
209 let speed =
214 (velocity[0] * velocity[0] + velocity[1] * velocity[1] + velocity[2] * velocity[2]).sqrt();
215
216 if speed < 1e-10 {
218 return None;
219 }
220
221 let ray_direction = [
222 velocity[0] / speed,
223 velocity[1] / speed,
224 velocity[2] / speed,
225 ];
226
227 let intersection =
229 super::narrowphase::ray_triangle3d_collision(point, &ray_direction, triangle);
230
231 match intersection {
233 Some((t, hit_point, barycentric)) => {
234 let actual_t = t / speed; if actual_t >= 0.0 && actual_t <= time_step {
236 Some(actual_t)
237 } else {
238 None
239 }
240 }
241 None => None,
242 }
243}
244
245#[allow(dead_code)]
258pub fn continuous_box3d_box3d_collision(
259 box1: &Box3D,
260 velocity1: &[f64; 3],
261 box2: &Box3D,
262 time_step: f64,
263) -> Option<f64> {
264 if super::narrowphase::box3d_box3d_collision(box1, box2) {
266 return Some(0.0);
267 }
268
269 let mut t_entry = [f64::NEG_INFINITY; 3];
271 let mut t_exit = [f64::INFINITY; 3];
272
273 for i in 0..3 {
274 if velocity1[i] > 0.0 {
275 t_entry[i] = (box2.min[i] - box1.max[i]) / velocity1[i];
276 t_exit[i] = (box2.max[i] - box1.min[i]) / velocity1[i];
277 } else if velocity1[i] < 0.0 {
278 t_entry[i] = (box2.max[i] - box1.min[i]) / velocity1[i];
279 t_exit[i] = (box2.min[i] - box1.max[i]) / velocity1[i];
280 }
281 }
284
285 let t_in = t_entry[0].max(t_entry[1]).max(t_entry[2]);
287 let t_out = t_exit[0].min(t_exit[1]).min(t_exit[2]);
288
289 if t_in > t_out || t_in > time_step || t_out < 0.0 {
292 return None;
293 }
294
295 if t_in >= 0.0 {
297 Some(t_in)
298 } else {
299 Some(0.0)
300 }
301}
302
303#[allow(dead_code)]
316pub fn continuous_triangle3d_sphere_collision(
317 triangle: &Triangle3D,
318 velocity: &[f64; 3],
319 sphere: &Sphere,
320 time_step: f64,
321) -> Option<f64> {
322 let inverse_velocity = [-velocity[0], -velocity[1], -velocity[2]];
325
326 let sphere_adjusted = Sphere {
328 center: sphere.center,
329 radius: sphere.radius,
330 };
331
332 if super::narrowphase::sphere_triangle3d_collision(&sphere_adjusted, triangle) {
334 return Some(0.0);
335 }
336
337 let vertices = [triangle.v1, triangle.v2, triangle.v3];
342 let mut earliest_time = f64::INFINITY;
343 let mut collision_found = false;
344
345 for vertex in &vertices {
346 let point = *vertex;
348
349 let dx = point[0] - sphere.center[0];
351 let dy = point[1] - sphere.center[1];
352 let dz = point[2] - sphere.center[2];
353 let dist_squared = dx * dx + dy * dy + dz * dz;
354
355 if dist_squared <= sphere.radius * sphere.radius {
357 return Some(0.0);
358 }
359
360 let a = inverse_velocity[0] * inverse_velocity[0]
362 + inverse_velocity[1] * inverse_velocity[1]
363 + inverse_velocity[2] * inverse_velocity[2];
364
365 if a < 1e-10 {
366 continue; }
368
369 let b =
370 2.0 * (dx * inverse_velocity[0] + dy * inverse_velocity[1] + dz * inverse_velocity[2]);
371
372 let c = dist_squared - sphere.radius * sphere.radius;
373
374 let discriminant = b * b - 4.0 * a * c;
375
376 if discriminant >= 0.0 {
377 let t = (-b - discriminant.sqrt()) / (2.0 * a);
378
379 if t >= 0.0 && t <= time_step && t < earliest_time {
380 earliest_time = t;
381 collision_found = true;
382 }
383 }
384 }
385
386 let edges = [
388 (triangle.v1, triangle.v2),
389 (triangle.v2, triangle.v3),
390 (triangle.v3, triangle.v1),
391 ];
392
393 for &(start, end) in &edges {
394 let edge_vector = [end[0] - start[0], end[1] - start[1], end[2] - start[2]];
396
397 let edge_length_squared = edge_vector[0] * edge_vector[0]
398 + edge_vector[1] * edge_vector[1]
399 + edge_vector[2] * edge_vector[2];
400
401 let t0 = {
403 let v = [
404 sphere.center[0] - start[0],
405 sphere.center[1] - start[1],
406 sphere.center[2] - start[2],
407 ];
408
409 let dot = v[0] * edge_vector[0] + v[1] * edge_vector[1] + v[2] * edge_vector[2];
410
411 dot / edge_length_squared
412 };
413
414 let t0_clamped = t0.clamp(0.0, 1.0);
416
417 let closest_point = [
419 start[0] + t0_clamped * edge_vector[0],
420 start[1] + t0_clamped * edge_vector[1],
421 start[2] + t0_clamped * edge_vector[2],
422 ];
423
424 let dx = closest_point[0] - sphere.center[0];
426 let dy = closest_point[1] - sphere.center[1];
427 let dz = closest_point[2] - sphere.center[2];
428 let dist_squared = dx * dx + dy * dy + dz * dz;
429
430 if dist_squared <= sphere.radius * sphere.radius {
432 return Some(0.0);
433 }
434
435 let a = inverse_velocity[0] * inverse_velocity[0]
440 + inverse_velocity[1] * inverse_velocity[1]
441 + inverse_velocity[2] * inverse_velocity[2];
442
443 if a < 1e-10 {
444 continue; }
446
447 let b =
448 2.0 * (dx * inverse_velocity[0] + dy * inverse_velocity[1] + dz * inverse_velocity[2]);
449
450 let c = dist_squared - sphere.radius * sphere.radius;
451
452 let discriminant = b * b - 4.0 * a * c;
453
454 if discriminant >= 0.0 {
455 let t = (-b - discriminant.sqrt()) / (2.0 * a);
456
457 if t >= 0.0 && t <= time_step && t < earliest_time {
458 earliest_time = t;
459 collision_found = true;
460 }
461 }
462 }
463
464 let normal = {
470 let edge1 = [
471 triangle.v2[0] - triangle.v1[0],
472 triangle.v2[1] - triangle.v1[1],
473 triangle.v2[2] - triangle.v1[2],
474 ];
475
476 let edge2 = [
477 triangle.v3[0] - triangle.v1[0],
478 triangle.v3[1] - triangle.v1[1],
479 triangle.v3[2] - triangle.v1[2],
480 ];
481
482 let cross = [
484 edge1[1] * edge2[2] - edge1[2] * edge2[1],
485 edge1[2] * edge2[0] - edge1[0] * edge2[2],
486 edge1[0] * edge2[1] - edge1[1] * edge2[0],
487 ];
488
489 let length = (cross[0] * cross[0] + cross[1] * cross[1] + cross[2] * cross[2]).sqrt();
491 if length < 1e-10 {
492 [0.0, 0.0, 0.0] } else {
494 [cross[0] / length, cross[1] / length, cross[2] / length]
495 }
496 };
497
498 if normal[0] == 0.0 && normal[1] == 0.0 && normal[2] == 0.0 {
499 if collision_found {
501 return Some(earliest_time);
502 }
503 return None;
504 }
505
506 let plane_dist = (sphere.center[0] - triangle.v1[0]) * normal[0]
508 + (sphere.center[1] - triangle.v1[1]) * normal[1]
509 + (sphere.center[2] - triangle.v1[2]) * normal[2];
510
511 let approach_speed = -(inverse_velocity[0] * normal[0]
513 + inverse_velocity[1] * normal[1]
514 + inverse_velocity[2] * normal[2]);
515
516 if approach_speed.abs() > 1e-10 {
517 let t_plane = (plane_dist.abs() - sphere.radius) / approach_speed;
519
520 if t_plane >= 0.0 && t_plane <= time_step && t_plane < earliest_time {
521 let projected_center = [
525 sphere.center[0] + inverse_velocity[0] * t_plane
526 - normal[0] * sphere.radius * plane_dist.signum(),
527 sphere.center[1] + inverse_velocity[1] * t_plane
528 - normal[1] * sphere.radius * plane_dist.signum(),
529 sphere.center[2] + inverse_velocity[2] * t_plane
530 - normal[2] * sphere.radius * plane_dist.signum(),
531 ];
532
533 if super::narrowphase::point_triangle3d_collision(&projected_center, triangle) {
534 earliest_time = t_plane;
535 collision_found = true;
536 }
537 }
538 }
539
540 if collision_found {
541 Some(earliest_time)
542 } else {
543 None
544 }
545}
546
547#[allow(dead_code)]
560pub fn continuous_sphere_triangle3d_collision(
561 sphere: &Sphere,
562 velocity: &[f64; 3],
563 triangle: &Triangle3D,
564 time_step: f64,
565) -> Option<f64> {
566 let inverse_velocity = [-velocity[0], -velocity[1], -velocity[2]];
569 continuous_triangle3d_sphere_collision(triangle, &inverse_velocity, sphere, time_step)
570}