1use crate::{collision, component, constraint, object};
2use crate::geometry::shape;
3use crate::math::*;
4
5mod gjk;
6
7#[cfg(test)]
8mod bench;
9
10#[derive(Clone, Copy, Debug, Eq, PartialEq)]
16pub enum Relation {
17 Disjoint,
18 Contact,
19 Intersect
20}
21
22#[derive(Clone, Debug, PartialEq)]
28pub struct Proximity {
29 pub distance : f64,
34 pub half_axis : Vector3 <f64>,
47 pub midpoint : Point3 <f64>,
49 pub normal : Unit3 <f64>
51}
52
53impl Proximity {
54 pub fn nearest_a (&self) -> Point3 <f64> {
55 self.midpoint - self.half_axis
56 }
57
58 pub fn nearest_b (&self) -> Point3 <f64> {
59 self.midpoint + self.half_axis
60 }
61
62 pub fn relation (&self) -> Relation {
63 if self.distance < 0.0 {
64 Relation::Intersect
65 } else if self.distance <= collision::CONTACT_DISTANCE {
66 Relation::Contact
67 } else {
68 debug_assert!(self.distance > collision::CONTACT_DISTANCE);
69 Relation::Disjoint
70 }
71 }
72
73 #[inline]
74 pub const fn constraint_planar (&self) -> constraint::Planar {
75 constraint::Planar::new (self.midpoint, self.normal)
76 }
77
78 pub fn flip (mut self) -> Self {
80 self.half_axis = -self.half_axis;
81 self.normal = -self.normal;
82 self
83 }
84
85 pub fn query <A, B> (object_a : &A, object_b : &B) -> Self where
125 A : object::Bounded, B : object::Bounded
126 {
127 let component::Position (position_a) = object_a.position();
128 let component::Position (position_b) = object_b.position();
129 let component::Bound (shape_a) = object_a.bound();
130 let component::Bound (shape_b) = object_b.bound();
131
132 match (shape_a, shape_b) {
133 ( shape::Variant::Bounded (shape::Bounded::Sphere (sphere_a)),
137 shape::Variant::Bounded (shape::Bounded::Sphere (sphere_b))
138 ) => Self::query_sphere_sphere (position_a, sphere_a, position_b, sphere_b),
139 ( shape::Variant::Bounded (shape::Bounded::Capsule (capsule_a)),
143 shape::Variant::Bounded (shape::Bounded::Capsule (capsule_b))
144 ) => Self::query_capsule_capsule (position_a, capsule_a, position_b, capsule_b),
145 ( shape::Variant::Bounded (shape::Bounded::Cuboid (cuboid_a)),
149 shape::Variant::Bounded (shape::Bounded::Cuboid (cuboid_b))
150 ) => Self::query_cuboid_cuboid (position_a, cuboid_a, position_b, cuboid_b),
151 ( shape::Variant::Bounded (shape::Bounded::Sphere (sphere_a)),
155 shape::Variant::Bounded (shape::Bounded::Capsule (capsule_b))
156 ) => Self::query_sphere_capsule (position_a, sphere_a, position_b, capsule_b),
157 ( shape::Variant::Bounded (shape::Bounded::Capsule (capsule_a)),
158 shape::Variant::Bounded (shape::Bounded::Sphere (sphere_b))
159 ) => Self::query_sphere_capsule (position_b, sphere_b, position_a, capsule_a)
160 .flip(),
161 ( shape::Variant::Bounded (shape::Bounded::Sphere (sphere_a)),
165 shape::Variant::Bounded (shape::Bounded::Cuboid (cuboid_b))
166 ) => Self::query_sphere_cuboid (
167 position_a, sphere_a, position_b, cuboid_b),
168 ( shape::Variant::Bounded (shape::Bounded::Cuboid (cuboid_a)),
169 shape::Variant::Bounded (shape::Bounded::Sphere (sphere_b))
170 ) => Self::query_sphere_cuboid (position_b, sphere_b, position_a, cuboid_a).flip(),
171 ( shape::Variant::Bounded (shape::Bounded::Sphere (sphere_a)),
175 shape::Variant::Unbounded (shape::Unbounded::Orthant (orthant_b))
176 ) => Self::query_sphere_orthant (position_a, sphere_a, position_b, orthant_b),
177 ( shape::Variant::Unbounded (shape::Unbounded::Orthant (orthant_a)),
178 shape::Variant::Bounded (shape::Bounded::Sphere (sphere_b))
179 ) => Self::query_sphere_orthant (position_b, sphere_b, position_a, orthant_a)
180 .flip(),
181 ( shape::Variant::Bounded (shape::Bounded::Capsule (capsule_a)),
185 shape::Variant::Bounded (shape::Bounded::Cuboid (cuboid_b))
186 ) => Self::query_capsule_cuboid (position_a, capsule_a, position_b, cuboid_b),
187 ( shape::Variant::Bounded (shape::Bounded::Cuboid (cuboid_a)),
188 shape::Variant::Bounded (shape::Bounded::Capsule (capsule_b))
189 ) => Self::query_capsule_cuboid (position_b, capsule_b, position_a, cuboid_a)
190 .flip(),
191 ( shape::Variant::Bounded (shape::Bounded::Capsule (capsule_a)),
195 shape::Variant::Unbounded (shape::Unbounded::Orthant (orthant_b))
196 ) => Self::query_capsule_orthant (position_a, capsule_a, position_b, orthant_b),
197 ( shape::Variant::Unbounded (shape::Unbounded::Orthant (orthant_a)),
198 shape::Variant::Bounded (shape::Bounded::Capsule (capsule_b))
199 ) => Self::query_capsule_orthant (position_b, capsule_b, position_a, orthant_a)
200 .flip(),
201 ( shape::Variant::Bounded (shape::Bounded::Cuboid (cuboid_a)),
205 shape::Variant::Unbounded (shape::Unbounded::Orthant (orthant_b))
206 ) => Self::query_cuboid_orthant (position_a, cuboid_a, position_b, orthant_b),
207 ( shape::Variant::Unbounded (shape::Unbounded::Orthant (orthant_a)),
208 shape::Variant::Bounded (shape::Bounded::Cuboid (cuboid_b))
209 ) => Self::query_cuboid_orthant (position_b, cuboid_b, position_a, orthant_a)
210 .flip(),
211 (shape::Variant::Bounded (shape::Bounded::Hull (_)), _) =>
215 Self::query_gjk (object_a, object_b),
216 (_, shape::Variant::Bounded (shape::Bounded::Hull (_))) =>
217 Self::query_gjk (object_b, object_a).flip(),
218 _ => unimplemented!("proximity query not implemented for (A, B): {:?}",
219 (shape_a, shape_b))
220 }
221 }
222
223 pub fn query_sphere_sphere (
224 position_a : &Point3 <f64>, sphere_a : &shape::Sphere <f64>,
225 position_b : &Point3 <f64>, sphere_b : &shape::Sphere <f64>
226 ) -> Self {
227 use num::Zero;
228 let (radius_a, radius_b) = (*sphere_a.radius, *sphere_b.radius);
229 let distance_normal_half_axis = |axis : &Vector3 <f64>| {
230 let axis_distance = axis.magnitude();
231 let distance = axis_distance - radius_a - radius_b;
232 let normal = if axis.is_zero() {
233 Unit3::axis_x()
234 } else {
235 Unit3::unchecked_approx (-(axis / axis_distance))
236 };
237 let half_axis = -0.5 * distance * *normal;
238 (distance, normal, half_axis)
239 };
240 let axis = position_b - position_a;
241 let (distance, normal, half_axis) = distance_normal_half_axis (&axis);
242 let midpoint = position_a - radius_a * *normal + half_axis;
243 Proximity { distance, half_axis, midpoint, normal }
244 }
245
246 pub fn query_capsule_capsule (
247 position_a : &Point3 <f64>, capsule_a : &shape::Capsule <f64>,
248 position_b : &Point3 <f64>, capsule_b : &shape::Capsule <f64>
249 ) -> Self {
250 use num::Zero;
251 let (half_height_a, half_height_b) =
252 (*capsule_a.half_height, *capsule_b.half_height);
253 let (radius_a, radius_b) = (*capsule_a.radius, *capsule_b.radius);
254 let shaft_max_a = position_a + vector3 (0.0, 0.0, half_height_a);
255 let shaft_min_a = position_a - vector3 (0.0, 0.0, half_height_a);
256 let shaft_max_b = position_b + vector3 (0.0, 0.0, half_height_b);
257 let shaft_min_b = position_b - vector3 (0.0, 0.0, half_height_b);
258 let distance_normal_half_axis = |axis : &Vector3 <f64>| {
259 let axis_distance = axis.magnitude();
260 let distance = axis_distance - radius_a - radius_b;
261 let normal = if axis.is_zero() {
262 Unit3::axis_x()
263 } else {
264 Unit3::unchecked_approx (-(axis / axis_distance))
265 };
266 let half_axis = -0.5 * distance * *normal;
267 (distance, normal, half_axis)
268 };
269 if shaft_max_a.0.z <= shaft_min_b.0.z {
270 let axis = shaft_min_b - shaft_max_a;
272 let (distance, normal, half_axis) = distance_normal_half_axis (&axis);
273 let midpoint = shaft_max_a - radius_a * *normal + half_axis;
274 Proximity { distance, half_axis, midpoint, normal }
275 } else if shaft_max_b.0.z <= shaft_min_a.0.z {
276 let axis = shaft_max_b.0 - shaft_min_a.0;
278 let (distance, normal, half_axis) = distance_normal_half_axis (&axis);
279 let midpoint = shaft_min_a - radius_a * *normal + half_axis;
280 Proximity { distance, half_axis, midpoint, normal }
281 } else {
282 let axis =
284 Point3::from ([position_b.0.x, position_b.0.y, 0.0]) -
285 Point3::from ([position_a.0.x, position_a.0.y, 0.0]);
286 let (distance, normal, half_axis) = distance_normal_half_axis (&axis);
287 let midpoint = {
288 let max_z = f64::min (shaft_max_a.0.z, shaft_max_b.0.z);
289 let min_z = f64::max (shaft_min_a.0.z, shaft_min_b.0.z);
290 let mid_z = 0.5 * (max_z + min_z);
291 let mid_a = position_a - radius_a * *normal + half_axis;
292 [mid_a.0.x, mid_a.0.y, mid_z].into()
293 };
294 Proximity { distance, half_axis, midpoint, normal }
295 }
296 }
297
298 pub fn query_cuboid_cuboid (
299 position_a : &Point3 <f64>, cuboid_a : &shape::Cuboid <f64>,
300 position_b : &Point3 <f64>, cuboid_b : &shape::Cuboid <f64>
301 ) -> Self {
302 use VectorSpace;
303 use num::Zero;
304 fn nearest_ab_to_distance (
305 nearest_a : &Point3 <f64>,
306 nearest_b : &Point3 <f64>,
307 default_normal : &Unit3 <f64>
308 ) -> Proximity {
309 let axis = nearest_b - nearest_a;
310 let distance = axis.magnitude();
311 let half_axis = 0.5 * (nearest_b - nearest_a);
312 let midpoint = nearest_a + half_axis;
313 let normal = if axis.is_zero() {
314 *default_normal
315 } else {
316 Unit3::unchecked_approx (-axis / distance)
317 };
318 Proximity { distance, half_axis, midpoint, normal }
319 }
320
321 let max_a = position_a + cuboid_a.max().0;
322 let min_a = position_a + cuboid_a.min().0;
323 let max_b = position_b + cuboid_b.max().0;
324 let min_b = position_b + cuboid_b.min().0;
325 let overlap_x = min_b.0.x < max_a.0.x && min_a.0.x < max_b.0.x;
326 let overlap_y = min_b.0.y < max_a.0.y && min_a.0.y < max_b.0.y;
327 let overlap_z = min_b.0.z < max_a.0.z && min_a.0.z < max_b.0.z;
328 match (overlap_x, overlap_y, overlap_z) {
329 (false, false, false) => {
330 let a_to_b = position_b - position_a;
332 debug_assert!(!a_to_b.x.is_zero());
333 debug_assert!(!a_to_b.y.is_zero());
334 debug_assert!(!a_to_b.z.is_zero());
335 let a_to_b_sigvec = a_to_b.map (f64::signum);
336 let nearest_a = position_a + cuboid_a.max().0 * a_to_b_sigvec;
337 let nearest_b = position_b + cuboid_b.max().0 * (-a_to_b_sigvec);
338 nearest_ab_to_distance (&nearest_a, &nearest_b,
339 &Unit3::normalize (-a_to_b_sigvec))
340 }
341 (true, false, false) => {
342 let max_x = f64::min (max_a.0.x, max_b.0.x);
344 let min_x = f64::max (min_a.0.x, min_b.0.x);
345 debug_assert_ne!(min_x, max_x);
346 let mid_x = 0.5 * (min_x + max_x);
347 let a_to_b = position_b - position_a;
348 let a_to_b_yz = vector3 (0.0, a_to_b.y, a_to_b.z);
349 let a_to_b_yz_sigvec = Vector3::sigvec (a_to_b_yz);
350 debug_assert!(a_to_b_yz_sigvec.x.is_zero());
351 debug_assert!(!a_to_b_yz_sigvec.y.is_zero());
352 debug_assert!(!a_to_b_yz_sigvec.z.is_zero());
353 let nearest_a = {
354 let y = *cuboid_a.extents.y * a_to_b_yz_sigvec.y;
355 let z = *cuboid_a.extents.z * a_to_b_yz_sigvec.z;
356 [mid_x, position_a.0.y + y, position_a.0.z + z].into()
357 };
358 let nearest_b = {
359 let y = -*cuboid_b.extents.y * a_to_b_yz_sigvec.y;
360 let z = -*cuboid_b.extents.z * a_to_b_yz_sigvec.z;
361 [mid_x, position_b.0.y + y, position_b.0.z + z].into()
362 };
363 nearest_ab_to_distance (&nearest_a, &nearest_b,
364 &Unit3::normalize (-a_to_b_yz_sigvec))
365 }
366 (false, true, false) => {
367 let max_y = f64::min (max_a.0.y, max_b.0.y);
369 let min_y = f64::max (min_a.0.y, min_b.0.y);
370 debug_assert_ne!(min_y, max_y);
371 let mid_y = 0.5 * (min_y + max_y);
372 let a_to_b = position_b - position_a;
373 let a_to_b_xz = vector3 (a_to_b.x, 0.0, a_to_b.z);
374 let a_to_b_xz_sigvec = Vector3::sigvec (a_to_b_xz);
375 debug_assert!(!a_to_b_xz_sigvec.x.is_zero());
376 debug_assert!(a_to_b_xz_sigvec.y.is_zero());
377 debug_assert!(!a_to_b_xz_sigvec.z.is_zero());
378 let nearest_a = {
379 let x = *cuboid_a.extents.x * a_to_b_xz_sigvec.x;
380 let z = *cuboid_a.extents.z * a_to_b_xz_sigvec.z;
381 [position_a.0.x + x, mid_y, position_a.0.z + z].into()
382 };
383 let nearest_b = {
384 let x = -*cuboid_b.extents.x * a_to_b_xz_sigvec.x;
385 let z = -*cuboid_b.extents.z * a_to_b_xz_sigvec.z;
386 [position_b.0.x + x, mid_y, position_b.0.z + z].into()
387 };
388 nearest_ab_to_distance (&nearest_a, &nearest_b,
389 &Unit3::normalize (-a_to_b_xz_sigvec))
390 }
391 (false, false, true) => {
392 let max_z = f64::min (max_a.0.z, max_b.0.z);
394 let min_z = f64::max (min_a.0.z, min_b.0.z);
395 debug_assert_ne!(min_z, max_z);
396 let mid_z = 0.5 * (min_z + max_z);
397 let a_to_b = position_b - position_a;
398 let a_to_b_xy = vector3 (a_to_b.x, a_to_b.y, 0.0);
399 let a_to_b_xy_sigvec = Vector3::sigvec (a_to_b_xy);
400 debug_assert!(!a_to_b_xy_sigvec.x.is_zero());
401 debug_assert!(!a_to_b_xy_sigvec.y.is_zero());
402 debug_assert!(a_to_b_xy_sigvec.z.is_zero());
403 let nearest_a = {
404 let x = *cuboid_a.extents.x * a_to_b_xy_sigvec.x;
405 let y = *cuboid_a.extents.y * a_to_b_xy_sigvec.y;
406 [position_a.0.x + x, position_a.0.y + y, mid_z].into()
407 };
408 let nearest_b = {
409 let x = -*cuboid_b.extents.x * a_to_b_xy_sigvec.x;
410 let y = -*cuboid_b.extents.y * a_to_b_xy_sigvec.y;
411 [position_b.0.x + x, position_b.0.y + y, mid_z].into()
412 };
413 nearest_ab_to_distance (&nearest_a, &nearest_b,
414 &Unit3::normalize (-a_to_b_xy_sigvec))
415 }
416 (true, true, false) => {
417 let max_x = f64::min (max_a.0.x, max_b.0.x);
419 let min_x = f64::max (min_a.0.x, min_b.0.x);
420 let mid_x = 0.5 * (min_x + max_x);
421 let max_y = f64::min (max_a.0.y, max_b.0.y);
422 let min_y = f64::max (min_a.0.y, min_b.0.y);
423 let mid_y = 0.5 * (min_y + max_y);
424 let a_to_b_z = position_b.0.z - position_a.0.z;
425 let a_to_b_signum_z = a_to_b_z.signum();
426 debug_assert_ne!(a_to_b_signum_z, 0.0);
427 let nearest_a = point3 (
428 mid_x, mid_y,
429 a_to_b_signum_z.mul_add (*cuboid_a.extents.z, position_a.0.z)
431 );
432 let nearest_b = point3 (
433 mid_x, mid_y,
434 a_to_b_signum_z.mul_add (-*cuboid_b.extents.z, position_b.0.z)
436 );
437 let nearest_a_to_b_z = nearest_b.0.z - nearest_a.0.z;
438 let distance = nearest_a_to_b_z.abs();
439 let half_axis = [0.0, 0.0, 0.5 * nearest_a_to_b_z].into();
440 let normal = Unit3::unchecked ([0.0, 0.0, -a_to_b_signum_z].into());
441 let midpoint = nearest_a + half_axis;
442 Proximity { distance, half_axis, midpoint, normal }
443 }
444 (true, false, true) => {
445 let max_x = f64::min (max_a.0.x, max_b.0.x);
447 let min_x = f64::max (min_a.0.x, min_b.0.x);
448 let mid_x = 0.5 * (min_x + max_x);
449 let max_z = f64::min (max_a.0.z, max_b.0.z);
450 let min_z = f64::max (min_a.0.z, min_b.0.z);
451 let mid_z = 0.5 * (min_z + max_z);
452 let a_to_b_y = position_b.0.y - position_a.0.y;
453 let a_to_b_signum_y = a_to_b_y.signum();
454 debug_assert_ne!(a_to_b_signum_y, 0.0);
455 let nearest_a = point3 (
456 mid_x,
457 a_to_b_signum_y.mul_add (*cuboid_a.extents.y, position_a.0.y),
459 mid_z
460 );
461 let nearest_b = point3 (
462 mid_x,
463 a_to_b_signum_y.mul_add (-*cuboid_b.extents.y, position_b.0.y),
465 mid_z
466 );
467 let nearest_a_to_b_y = nearest_b.0.y - nearest_a.0.y;
468 let distance = nearest_a_to_b_y.abs();
469 let half_axis = [0.0, 0.5 * nearest_a_to_b_y, 0.0].into();
470 let normal = Unit3::unchecked ([0.0, -a_to_b_signum_y, 0.0].into());
471 let midpoint = nearest_a + half_axis;
472 Proximity { distance, half_axis, midpoint, normal }
473 }
474 (false, true, true) => {
475 let max_y = f64::min (max_a.0.y, max_b.0.y);
477 let min_y = f64::max (min_a.0.y, min_b.0.y);
478 let mid_y = 0.5 * (min_y + max_y);
479 let max_z = f64::min (max_a.0.z, max_b.0.z);
480 let min_z = f64::max (min_a.0.z, min_b.0.z);
481 let mid_z = 0.5 * (min_z + max_z);
482 let a_to_b_x = position_b.0.x - position_a.0.x;
483 let a_to_b_signum_x = a_to_b_x.signum();
484 debug_assert_ne!(a_to_b_signum_x, 0.0);
485 let nearest_a = point3 (
486 a_to_b_signum_x.mul_add (*cuboid_a.extents.x, position_a.0.x),
488 mid_y,
489 mid_z
490 );
491 let nearest_b = point3 (
492 a_to_b_signum_x.mul_add (-*cuboid_b.extents.x, position_b.0.x),
494 mid_y,
495 mid_z
496 );
497 let nearest_a_to_b_x = nearest_b.0.x - nearest_a.0.x;
498 let distance = nearest_a_to_b_x.abs();
499 let half_axis = [0.5 * nearest_a_to_b_x, 0.0, 0.0].into();
500 let normal = Unit3::unchecked ([-a_to_b_signum_x, 0.0, 0.0].into());
501 let midpoint = nearest_a + half_axis;
502 Proximity { distance, half_axis, midpoint, normal }
503 }
504 (true, true, true) => {
505 let max_x = f64::min (max_a.0.x, max_b.0.x);
507 let min_x = f64::max (min_a.0.x, min_b.0.x);
508 let mid_x = 0.5 * (min_x + max_x);
509 let max_y = f64::min (max_a.0.y, max_b.0.y);
510 let min_y = f64::max (min_a.0.y, min_b.0.y);
511 let mid_y = 0.5 * (min_y + max_y);
512 let max_z = f64::min (max_a.0.z, max_b.0.z);
513 let min_z = f64::max (min_a.0.z, min_b.0.z);
514 let mid_z = 0.5 * (min_z + max_z);
515 let midpoint = [mid_x, mid_y, mid_z].into();
516 let resolve_x = if position_a.0.x < position_b.0.x {
517 min_b.0.x - max_a.0.x
518 } else {
519 debug_assert!(position_a.0.x >= position_b.0.x);
520 max_b.0.x - min_a.0.x
521 };
522 let resolve_y = if position_a.0.y < position_b.0.y {
523 min_b.0.y - max_a.0.y
524 } else {
525 debug_assert!(position_a.0.y >= position_b.0.y);
526 max_b.0.y - min_a.0.y
527 };
528 let resolve_z = if position_a.0.z < position_b.0.z {
529 min_b.0.z - max_a.0.z
530 } else {
531 debug_assert!(position_a.0.z >= position_b.0.z);
532 max_b.0.z - min_a.0.z
533 };
534 let resolve_x_abs = resolve_x.abs();
535 let resolve_y_abs = resolve_y.abs();
536 let resolve_z_abs = resolve_z.abs();
537 let (distance, half_axis, normal) : (
538 f64, Vector3 <f64>, Unit3 <f64>
539 ) = if resolve_x_abs <= resolve_y_abs && resolve_x_abs <= resolve_z_abs {
540 ( -resolve_x_abs,
541 0.5 * vector3 (resolve_x, 0.0, 0.0),
542 Unit3::unchecked ([resolve_x.signum(), 0.0, 0.0].into())
543 )
544 } else if resolve_y_abs <= resolve_x_abs && resolve_y_abs <= resolve_z_abs {
545 ( -resolve_y_abs,
546 0.5 * vector3 (0.0, resolve_y, 0.0),
547 Unit3::unchecked ([0.0, resolve_y.signum(), 0.0].into())
548 )
549 } else {
550 debug_assert!(resolve_z_abs <= resolve_x_abs);
551 debug_assert!(resolve_z_abs <= resolve_y_abs);
552 ( -resolve_z_abs,
553 0.5 * vector3 (0.0, 0.0, resolve_z),
554 Unit3::unchecked ([0.0, 0.0, resolve_z.signum()].into())
555 )
556 };
557 debug_assert!(!half_axis.is_zero());
558 Proximity { distance, half_axis, midpoint, normal }
559 }
560 }
561 }
562
563 pub fn query_sphere_capsule (
969 position_a : &Point3 <f64>, sphere_a : &shape::Sphere <f64>,
970 position_b : &Point3 <f64>, capsule_b : &shape::Capsule <f64>
971 ) -> Self {
972 use num::Zero;
973 let half_height_b = *capsule_b.half_height;
974 let (radius_a, radius_b) = (*sphere_a.radius, *capsule_b.radius);
975 let shaft_max_b = position_b + vector3 (0.0, 0.0, half_height_b);
976 let shaft_min_b = position_b - vector3 (0.0, 0.0, half_height_b);
977 let distance_normal_half_axis = |axis : &Vector3 <f64>| {
978 let axis_distance = axis.magnitude();
979 let distance = axis_distance - radius_a - radius_b;
980 let normal = if axis.is_zero() {
981 Unit3::axis_x()
982 } else {
983 Unit3::unchecked_approx (-(axis / axis_distance))
984 };
985 let half_axis = -0.5 * distance * *normal;
986 (distance, normal, half_axis)
987 };
988 if position_a.0.z <= shaft_min_b.0.z {
989 let axis = shaft_min_b - position_a;
991 let (distance, normal, half_axis) = distance_normal_half_axis (&axis);
992 let midpoint = position_a - radius_a * *normal + half_axis;
993 Proximity { distance, half_axis, midpoint, normal }
994 } else if shaft_max_b.0.z <= position_a.0.z {
995 let axis = shaft_max_b - position_a;
997 let (distance, normal, half_axis) = distance_normal_half_axis (&axis);
998 let midpoint = position_a - radius_a * *normal + half_axis;
999 Proximity { distance, half_axis, midpoint, normal }
1000 } else {
1001 let axis =
1003 Point3::from ([position_b.0.x, position_b.0.y, 0.0]) -
1004 Point3::from ([position_a.0.x, position_a.0.y, 0.0]);
1005 let (distance, normal, half_axis) = distance_normal_half_axis (&axis);
1006 let midpoint = {
1007 let max_z = f64::min (position_a.0.z, shaft_max_b.0.z);
1008 let min_z = f64::max (position_a.0.z, shaft_min_b.0.z);
1009 let mid_z = 0.5 * (max_z + min_z);
1010 let mid_a = position_a - radius_a * *normal + half_axis;
1011 [mid_a.0.x, mid_a.0.y, mid_z].into()
1012 };
1013 Proximity { distance, half_axis, midpoint, normal }
1014 }
1015 }
1016
1017 pub fn query_sphere_cuboid (
1018 position_a : &Point3 <f64>, sphere_a : &shape::Sphere <f64>,
1019 position_b : &Point3 <f64>, cuboid_b : &shape::Cuboid <f64>
1020 ) -> Self {
1021 use num::Zero;
1022 let cuboid_max_b = position_b + cuboid_b.max().0;
1023 let cuboid_min_b = position_b - cuboid_b.max().0;
1024
1025 let overlap_x = cuboid_min_b.0.x < position_a.0.x &&
1026 position_a.0.x < cuboid_max_b.0.x;
1027 let overlap_y = cuboid_min_b.0.y < position_a.0.y &&
1028 position_a.0.y < cuboid_max_b.0.y;
1029
1030 let sphere_a_radius = *sphere_a.radius;
1031 let cuboid_b_extent_x = *cuboid_b.extents.x;
1032 let cuboid_b_extent_y = *cuboid_b.extents.y;
1033 let cuboid_b_extent_z = *cuboid_b.extents.z;
1034 if position_a.0.z >= cuboid_max_b.0.z {
1035 match (overlap_x, overlap_y) {
1037 (false, false) => {
1038 let b_to_a = position_a - position_b;
1040 debug_assert!(!b_to_a.x.is_zero());
1041 debug_assert!(!b_to_a.y.is_zero());
1042 debug_assert!(!b_to_a.z.is_zero());
1043 let b_to_a_sigvec = b_to_a.map (f64::signum);
1044 let nearest_b = position_b + cuboid_b.max().0 * b_to_a_sigvec;
1045 let a_to_b = nearest_b - position_a;
1046 let nearest_a = position_a + if !a_to_b.is_zero() {
1047 sphere_a_radius * a_to_b.normalized()
1048 } else {
1049 [-b_to_a_sigvec.x * sphere_a_radius, 0.0, 0.0].into()
1050 };
1051 let axis = nearest_b - nearest_a;
1052 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1053 a_to_b.dot (axis).signum()
1054 } else {
1055 -1.0
1056 };
1057 let half_axis = 0.5 * axis;
1058 let normal = if axis.is_zero() {
1059 Unit3::normalize (b_to_a_sigvec)
1060 } else {
1061 Unit3::unchecked_approx (-axis / distance)
1062 };
1063 let midpoint = nearest_a + half_axis;
1064 Proximity { distance, half_axis, midpoint, normal }
1065 }
1066 (true, false) => {
1067 let signum_y = (position_a.0.y - position_b.0.y).signum();
1069 let nearest_b = point3 (
1070 position_a.0.x,
1071 signum_y.mul_add (cuboid_b_extent_y, position_b.0.y),
1073 cuboid_max_b.0.z
1074 );
1075 let a_to_b = nearest_b - position_a;
1076 let nearest_a = position_a + if a_to_b.is_zero() {
1077 -signum_y * vector3 (0.0, sphere_a_radius, 0.0)
1078 } else {
1079 sphere_a_radius * a_to_b.normalized()
1080 };
1081 let axis = nearest_b - nearest_a;
1082 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1083 a_to_b.dot (axis).signum()
1084 } else {
1085 -1.0
1086 };
1087 let half_axis = 0.5 * axis;
1088 let normal = if axis.is_zero() {
1089 Unit3::normalize (vector3 (0.0, signum_y, 1.0))
1090 } else {
1091 Unit3::unchecked_approx (-axis / distance)
1092 };
1093 let midpoint = nearest_a + half_axis;
1094 Proximity { distance, half_axis, midpoint, normal }
1095 }
1096 (false, true) => {
1097 let signum_x = (position_a.0.x - position_b.0.x).signum();
1099 let nearest_b = point3 (
1100 signum_x.mul_add (cuboid_b_extent_x, position_b.0.x),
1102 position_a.0.y,
1103 cuboid_max_b.0.z
1104 );
1105 let a_to_b = nearest_b - position_a;
1106 let nearest_a = position_a + if a_to_b.is_zero() {
1107 -signum_x * vector3 (sphere_a_radius, 0.0, 0.0)
1108 } else {
1109 sphere_a_radius * a_to_b.normalized()
1110 };
1111 let axis = nearest_b - nearest_a;
1112 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1113 a_to_b.dot (axis).signum()
1114 } else {
1115 -1.0
1116 };
1117 let half_axis = 0.5 * axis;
1118 let normal = if axis.is_zero() {
1119 Unit3::normalize (vector3 (signum_x, 0.0, 1.0))
1120 } else {
1121 Unit3::unchecked_approx (-axis / distance)
1122 };
1123 let midpoint = nearest_a + half_axis;
1124 Proximity { distance, half_axis, midpoint, normal }
1125 }
1126 (true, true) => {
1127 let nearest_a : Point3 <f64> =
1129 position_a - vector3 (0.0, 0.0, sphere_a_radius);
1130 let nearest_b : Point3 <f64> =
1131 [position_a.0.x, position_a.0.y, cuboid_max_b.0.z].into();
1132 let axis = nearest_b - nearest_a;
1133 let normal = Unit3::axis_z();
1134 let half_axis = 0.5 * axis;
1135 let distance = nearest_a.0.z - nearest_b.0.z;
1136 let midpoint = nearest_a + half_axis;
1137 Proximity { distance, half_axis, midpoint, normal }
1138 }
1139 }
1140 } else if position_a.0.z <= cuboid_min_b.0.z {
1141 match (overlap_x, overlap_y) {
1143 (false, false) => {
1144 let b_to_a = position_a - position_b;
1146 debug_assert!(!b_to_a.x.is_zero());
1147 debug_assert!(!b_to_a.y.is_zero());
1148 debug_assert!(!b_to_a.z.is_zero());
1149 let b_to_a_sigvec = b_to_a.map (f64::signum);
1150 let nearest_b = position_b + cuboid_b.max().0 * b_to_a_sigvec;
1151 let a_to_b = nearest_b - position_a;
1152 let nearest_a = position_a + if !a_to_b.is_zero() {
1153 sphere_a_radius * a_to_b.normalized()
1154 } else {
1155 [-b_to_a_sigvec.x * sphere_a_radius, 0.0, 0.0].into()
1156 };
1157 let axis = nearest_b - nearest_a;
1158 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1159 a_to_b.dot (axis).signum()
1160 } else {
1161 -1.0
1162 };
1163 let half_axis = 0.5 * axis;
1164 let normal = if axis.is_zero() {
1165 Unit3::normalize (b_to_a_sigvec)
1166 } else {
1167 Unit3::unchecked_approx (-axis / distance)
1168 };
1169 let midpoint = nearest_a + half_axis;
1170 Proximity { distance, half_axis, midpoint, normal }
1171 }
1172 (true, false) => {
1173 let signum_y = (position_a.0.y - position_b.0.y).signum();
1175 let nearest_b = point3 (
1176 position_a.0.x,
1177 signum_y.mul_add (cuboid_b_extent_y, position_b.0.y),
1179 cuboid_min_b.0.z
1180 );
1181 let a_to_b = nearest_b - position_a;
1182 let nearest_a = position_a + if a_to_b.is_zero() {
1183 -signum_y * vector3 (0.0, sphere_a_radius, 0.0)
1184 } else {
1185 sphere_a_radius * a_to_b.normalized()
1186 };
1187 let axis = nearest_b - nearest_a;
1188 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1189 a_to_b.dot (axis).signum()
1190 } else {
1191 -1.0
1192 };
1193 let half_axis = 0.5 * axis;
1194 let normal = if axis.is_zero() {
1195 Unit3::normalize (vector3 (0.0, signum_y, -1.0))
1196 } else {
1197 Unit3::unchecked_approx (-axis / distance)
1198 };
1199 let midpoint = nearest_a + half_axis;
1200 Proximity { distance, half_axis, midpoint, normal }
1201 }
1202 (false, true) => {
1203 let signum_x = (position_a.0.x - position_b.0.x).signum();
1205 let nearest_b = point3 (
1206 signum_x.mul_add (cuboid_b_extent_x, position_b.0.x),
1208 position_a.0.y,
1209 cuboid_min_b.0.z
1210 );
1211 let a_to_b = nearest_b - position_a;
1212 let nearest_a = position_a + if a_to_b.is_zero() {
1213 -signum_x * vector3 (sphere_a_radius, 0.0, 0.0)
1214 } else {
1215 sphere_a_radius * a_to_b.normalized()
1216 };
1217 let axis = nearest_b - nearest_a;
1218 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1219 a_to_b.dot (axis).signum()
1220 } else {
1221 -1.0
1222 };
1223 let half_axis = 0.5 * axis;
1224 let normal = if axis.is_zero() {
1225 Unit3::normalize (vector3 (signum_x, 0.0, -1.0))
1226 } else {
1227 Unit3::unchecked_approx (-axis / distance)
1228 };
1229 let midpoint = nearest_a + half_axis;
1230 Proximity { distance, half_axis, midpoint, normal }
1231 }
1232 (true, true) => {
1233 let nearest_a : Point3 <f64> =
1235 position_a + vector3 (0.0, 0.0, sphere_a_radius);
1236 let nearest_b : Point3 <f64> =
1237 [position_a.0.x, position_a.0.y, cuboid_min_b.0.z].into();
1238 let axis = nearest_b - nearest_a;
1239 let normal = Unit3::axis_z().invert();
1240 let half_axis = 0.5 * axis;
1241 let distance = nearest_b.0.z - nearest_a.0.z;
1242 let midpoint = nearest_a + half_axis;
1243 Proximity { distance, half_axis, midpoint, normal }
1244 }
1245 }
1246 } else {
1247 match (overlap_x, overlap_y) {
1249 (false, false) => {
1250 let b_to_a_signum_x = (position_a.0.x - position_b.0.x).signum();
1252 let b_to_a_signum_y = (position_a.0.y - position_b.0.y).signum();
1253 let b_to_a_unit_sigvec = vector3 (b_to_a_signum_x, b_to_a_signum_y, 0.0)
1254 .normalized();
1255 let nearest_b = Point3::from ([
1256 b_to_a_signum_x.mul_add (cuboid_b_extent_x, position_b.0.x),
1258 b_to_a_signum_y.mul_add (cuboid_b_extent_y, position_b.0.y),
1260 position_a.0.z
1261 ]);
1262 let a_to_b = vector3 (
1263 nearest_b.0.x - position_a.0.x,
1264 nearest_b.0.y - position_a.0.y,
1265 0.0
1266 );
1267 let nearest_a = point3 (position_a.0.x, position_a.0.y, position_a.0.z)
1268 + sphere_a_radius * if !a_to_b.is_zero() {
1269 a_to_b.normalized()
1270 } else {
1271 -b_to_a_unit_sigvec
1272 };
1273 let axis = nearest_b - nearest_a;
1274 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1275 a_to_b.dot (axis).signum()
1276 } else {
1277 -1.0
1278 };
1279 let half_axis = 0.5 * axis;
1280 let normal = Unit3::unchecked_approx (if axis.is_zero() {
1281 b_to_a_unit_sigvec
1282 } else {
1283 -axis / distance
1284 });
1285 let midpoint = nearest_a + half_axis;
1286 Proximity { distance, half_axis, midpoint, normal }
1287 }
1288 (true, false) => {
1289 let b_to_a_signum_y = (position_a.0.y - position_b.0.y).signum();
1291 let b_to_a_unit_sigvec = vector3 (0.0, b_to_a_signum_y, 0.0);
1292 let nearest_b = Point3::from ([
1293 position_a.0.x,
1294 b_to_a_signum_y.mul_add (cuboid_b_extent_y, position_b.0.y),
1296 position_a.0.z
1297 ]);
1298 let a_to_b = vector3 (0.0, nearest_b.0.y - position_a.0.y, 0.0);
1299 let nearest_a =
1300 point3 (position_a.0.x, position_a.0.y, position_a.0.z) +
1301 vector3 (0.0, -b_to_a_signum_y * sphere_a_radius, 0.0);
1302 let axis = nearest_b - nearest_a;
1303 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1304 a_to_b.dot (axis).signum()
1305 } else {
1306 -1.0
1307 };
1308 let half_axis = 0.5 * axis;
1309 let normal = Unit3::unchecked_approx (if axis.is_zero() {
1310 b_to_a_unit_sigvec
1311 } else {
1312 -axis / distance
1313 });
1314 let midpoint = nearest_a + half_axis;
1315 Proximity { distance, half_axis, midpoint, normal }
1316 }
1317 (false, true) => {
1318 let b_to_a_signum_x = (position_a.0.x - position_b.0.x).signum();
1320 let b_to_a_unit_sigvec = vector3 (b_to_a_signum_x, 0.0, 0.0);
1321 let nearest_b = Point3::from ([
1322 b_to_a_signum_x.mul_add (cuboid_b_extent_x, position_b.0.x),
1324 position_a.0.y,
1325 position_a.0.z
1326 ]);
1327 let a_to_b = vector3 (nearest_b.0.x - position_a.0.x, 0.0, 0.0);
1328 let nearest_a =
1329 point3 (position_a.0.x, position_a.0.y, position_a.0.z) +
1330 vector3 (-b_to_a_signum_x * sphere_a_radius, 0.0, 0.0);
1331 let axis = nearest_b - nearest_a;
1332 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1333 a_to_b.dot (axis).signum()
1334 } else {
1335 -1.0
1336 };
1337 let half_axis = 0.5 * axis;
1338 let normal = Unit3::unchecked_approx (if axis.is_zero() {
1339 b_to_a_unit_sigvec
1340 } else {
1341 -axis / distance
1342 });
1343 let midpoint = nearest_a + half_axis;
1344 Proximity { distance, half_axis, midpoint, normal }
1345 }
1346 (true, true) => {
1347 if position_a == position_b {
1349 let depth_x = cuboid_b_extent_x + sphere_a_radius;
1350 let depth_y = cuboid_b_extent_y + sphere_a_radius;
1351 let depth_z = cuboid_b_extent_z + sphere_a_radius;
1352 if depth_x <= depth_y && depth_x <= depth_z {
1353 let distance = -depth_x;
1354 let half_axis = [0.5 * depth_x, 0.0, 0.0].into();
1355 let normal = Unit3::axis_x();
1356 let midpoint = position_a + half_axis -
1357 vector3 (sphere_a_radius, 0.0, 0.0);
1358 Proximity { distance, half_axis, midpoint, normal }
1359 } else if depth_y <= depth_x && depth_y <= depth_z {
1360 let distance = -depth_y;
1361 let half_axis = [0.0, 0.5 * depth_y, 0.0].into();
1362 let normal = Unit3::axis_y();
1363 let midpoint = position_a + half_axis -
1364 vector3 (0.0, sphere_a_radius, 0.0);
1365 Proximity { distance, half_axis, midpoint, normal }
1366 } else {
1367 debug_assert!(depth_z < depth_x);
1368 debug_assert!(depth_z < depth_y);
1369 let distance = -depth_z;
1370 let half_axis = [0.0, 0.0, 0.5 * depth_z].into();
1371 let normal = Unit3::axis_z();
1372 let midpoint = position_a + half_axis -
1373 vector3 (0.0, 0.0, sphere_a_radius);
1374 Proximity { distance, half_axis, midpoint, normal }
1375 }
1376 } else {
1377 let b_to_a_sigvec = (position_a - position_b).map (f64::signum);
1380 let corner_b = position_b + cuboid_b.max().0 * b_to_a_sigvec;
1381 let depth_x = (corner_b.0.x - position_a.0.x).abs() + sphere_a_radius;
1382 let depth_y = (corner_b.0.y - position_a.0.y).abs() + sphere_a_radius;
1383 let depth_z = (corner_b.0.z - position_a.0.z).abs() + sphere_a_radius
1384 - if position_a.0.z.abs() > corner_b.0.z.abs() {
1385 2.0 * (position_a.0.z.abs() - corner_b.0.z.abs())
1386 } else {
1387 0.0
1388 };
1389
1390 if depth_x <= depth_y && depth_x <= depth_z {
1391 let distance = -depth_x;
1392 let half_axis = [0.5 * b_to_a_sigvec.x * depth_x, 0.0, 0.0].into();
1393 let normal = Unit3::unchecked ([b_to_a_sigvec.x, 0.0, 0.0].into());
1394 let midpoint = position_a + half_axis +
1395 vector3 (-b_to_a_sigvec.x * sphere_a_radius, 0.0, 0.0);
1396 Proximity { distance, half_axis, midpoint, normal }
1397 } else if depth_y <= depth_x && depth_y <= depth_z {
1398 let distance = -depth_y;
1399 let half_axis = [0.0, 0.5 * b_to_a_sigvec.y * depth_y, 0.0].into();
1400 let normal = Unit3::unchecked ([0.0, b_to_a_sigvec.y, 0.0].into());
1401 let midpoint = position_a + half_axis +
1402 vector3 (0.0, -b_to_a_sigvec.y * sphere_a_radius, 0.0);
1403 Proximity { distance, half_axis, midpoint, normal }
1404 } else {
1405 debug_assert!(depth_z < depth_x);
1406 debug_assert!(depth_z < depth_y);
1407 let nearest_a = point3 (
1408 position_a.0.x,
1409 position_a.0.y,
1410 b_to_a_sigvec.z.mul_add (-sphere_a_radius, position_a.0.z)
1412 );
1413 let nearest_b = point3 (
1414 position_a.0.x,
1415 position_a.0.y,
1416 b_to_a_sigvec.z.mul_add (cuboid_b_extent_z, position_b.0.z)
1418 );
1419 let axis = nearest_b - nearest_a;
1420 debug_assert_eq!(axis.x, 0.0);
1421 debug_assert_eq!(axis.y, 0.0);
1422 let distance = -axis.z.abs();
1423 let half_axis = 0.5 * axis;
1424 let normal = Unit3::unchecked ([0.0, 0.0, b_to_a_sigvec.z].into());
1425 let midpoint = nearest_a + half_axis;
1426 Proximity { distance, half_axis, midpoint, normal }
1427 }
1428 }
1429 }
1430 }
1431 }
1432 } pub fn query_sphere_orthant (
1435 position_a : &Point3 <f64>, sphere_a : &shape::Sphere <f64>,
1436 position_b : &Point3 <f64>, orthant_b : &shape::Orthant
1437 ) -> Self {
1438 let radius_a = *sphere_a.radius;
1439 let normal = orthant_b.normal_axis.to_vec::<f64>();
1440 let normal_abs = normal.map (f64::abs);
1441 let surface_sigvec = vector3 (1.0, 1.0, 1.0) - normal_abs;
1442 let nearest_a = position_a - vector3 (radius_a, radius_a, radius_a) * normal;
1443 let nearest_b =
1444 Point3 (position_a.0 * surface_sigvec + position_b.0 * normal_abs);
1445 let axis = nearest_b - nearest_a;
1446 debug_assert_eq!(axis.sum().abs(), axis.magnitude());
1447 let distance = -normal.dot (axis).signum() * axis.sum().abs();
1448 let half_axis = 0.5 * axis;
1449 let midpoint = nearest_a + half_axis;
1450 let normal = Unit3::unchecked (normal);
1451 Proximity { distance, half_axis, midpoint, normal }
1452 } pub fn query_capsule_cuboid (
1455 position_a : &Point3 <f64>, capsule_a : &shape::Capsule <f64>,
1456 position_b : &Point3 <f64>, cuboid_b : &shape::Cuboid <f64>
1457 ) -> Self {
1458 use num::Zero;
1459 let shaft_max_a = position_a + vector3 (0.0, 0.0, *capsule_a.half_height);
1460 let shaft_min_a = position_a - vector3 (0.0, 0.0, *capsule_a.half_height);
1461 let cuboid_max_b = position_b + cuboid_b.max().0;
1462 let cuboid_min_b = position_b - cuboid_b.max().0;
1463
1464 let overlap_x = cuboid_min_b.0.x < position_a.0.x &&
1465 position_a.0.x < cuboid_max_b.0.x;
1466 let overlap_y = cuboid_min_b.0.y < position_a.0.y &&
1467 position_a.0.y < cuboid_max_b.0.y;
1468
1469 let capsule_a_radius = *capsule_a.radius;
1470 let capsule_a_half_height = *capsule_a.half_height;
1471 let cuboid_b_extent_x = *cuboid_b.extents.x;
1472 let cuboid_b_extent_y = *cuboid_b.extents.y;
1473 let cuboid_b_extent_z = *cuboid_b.extents.z;
1474 if shaft_min_a.0.z >= cuboid_max_b.0.z {
1475 match (overlap_x, overlap_y) {
1477 (false, false) => {
1478 let b_to_a = shaft_min_a - position_b;
1480 debug_assert!(!b_to_a.x.is_zero());
1481 debug_assert!(!b_to_a.y.is_zero());
1482 debug_assert!(!b_to_a.z.is_zero());
1483 let b_to_a_sigvec = b_to_a.map (f64::signum);
1484 let nearest_b = position_b + cuboid_b.max().0 * b_to_a_sigvec;
1485 let a_to_b = nearest_b - shaft_min_a;
1486 let nearest_a = shaft_min_a + if !a_to_b.is_zero() {
1487 capsule_a_radius * a_to_b.normalized()
1488 } else {
1489 [-b_to_a_sigvec.x * capsule_a_radius, 0.0, 0.0].into()
1490 };
1491 let axis = nearest_b - nearest_a;
1492 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1493 a_to_b.dot (axis).signum()
1494 } else {
1495 -1.0
1496 };
1497 let half_axis = 0.5 * axis;
1498 let normal = if axis.is_zero() {
1499 Unit3::normalize (b_to_a_sigvec)
1500 } else {
1501 Unit3::unchecked_approx (-axis / distance)
1502 };
1503 let midpoint = nearest_a + half_axis;
1504 Proximity { distance, half_axis, midpoint, normal }
1505 }
1506 (true, false) => {
1507 let signum_y = (shaft_min_a.0.y - position_b.0.y).signum();
1509 let nearest_b = point3 (
1510 shaft_min_a.0.x,
1511 position_b.0.y + signum_y * cuboid_b_extent_y,
1512 cuboid_max_b.0.z
1513 );
1514 let a_to_b = nearest_b - shaft_min_a;
1515 let nearest_a = shaft_min_a + if a_to_b.is_zero() {
1516 -signum_y * vector3 (0.0, capsule_a_radius, 0.0)
1517 } else {
1518 capsule_a_radius * a_to_b.normalized()
1519 };
1520 let axis = nearest_b - nearest_a;
1521 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1522 a_to_b.dot (axis).signum()
1523 } else {
1524 -1.0
1525 };
1526 let half_axis = 0.5 * axis;
1527 let normal = if axis.is_zero() {
1528 Unit3::normalize (vector3 (0.0, signum_y, 1.0))
1529 } else {
1530 Unit3::unchecked_approx (-axis / distance)
1531 };
1532 let midpoint = nearest_a + half_axis;
1533 Proximity { distance, half_axis, midpoint, normal }
1534 }
1535 (false, true) => {
1536 let signum_x = (shaft_min_a.0.x - position_b.0.x).signum();
1538 let nearest_b = point3 (
1539 position_b.0.x + signum_x * cuboid_b_extent_x,
1540 shaft_min_a.0.y,
1541 cuboid_max_b.0.z
1542 );
1543 let a_to_b = nearest_b - shaft_min_a;
1544 let nearest_a = shaft_min_a + if a_to_b.is_zero() {
1545 -signum_x * vector3 (capsule_a_radius, 0.0, 0.0)
1546 } else {
1547 capsule_a_radius * a_to_b.normalized()
1548 };
1549 let axis = nearest_b - nearest_a;
1550 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1551 a_to_b.dot (axis).signum()
1552 } else {
1553 -1.0
1554 };
1555 let half_axis = 0.5 * axis;
1556 let normal = if axis.is_zero() {
1557 Unit3::normalize (vector3 (signum_x, 0.0, 1.0))
1558 } else {
1559 Unit3::unchecked_approx (-axis / distance)
1560 };
1561 let midpoint = nearest_a + half_axis;
1562 Proximity { distance, half_axis, midpoint, normal }
1563 }
1564 (true, true) => {
1565 let nearest_a : Point3 <f64> =
1567 shaft_min_a - vector3 (0.0, 0.0, capsule_a_radius);
1568 let nearest_b : Point3 <f64> =
1569 [position_a.0.x, position_a.0.y, cuboid_max_b.0.z].into();
1570 let axis = nearest_b - nearest_a;
1571 let normal = Unit3::axis_z();
1572 let half_axis = 0.5 * axis;
1573 let distance = nearest_a.0.z - nearest_b.0.z;
1574 let midpoint = nearest_a + half_axis;
1575 Proximity { distance, half_axis, midpoint, normal }
1576 }
1577 }
1578 } else if shaft_max_a.0.z <= cuboid_min_b.0.z {
1579 match (overlap_x, overlap_y) {
1581 (false, false) => {
1582 let b_to_a = shaft_max_a - position_b;
1584 debug_assert!(!b_to_a.x.is_zero());
1585 debug_assert!(!b_to_a.y.is_zero());
1586 debug_assert!(!b_to_a.z.is_zero());
1587 let b_to_a_sigvec = b_to_a.map (f64::signum);
1588 let nearest_b = position_b + cuboid_b.max().0 * b_to_a_sigvec;
1589 let a_to_b = nearest_b - shaft_max_a;
1590 let nearest_a = shaft_max_a + if !a_to_b.is_zero() {
1591 capsule_a_radius * a_to_b.normalized()
1592 } else {
1593 [-b_to_a_sigvec.x * capsule_a_radius, 0.0, 0.0].into()
1594 };
1595 let axis = nearest_b - nearest_a;
1596 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1597 a_to_b.dot (axis).signum()
1598 } else {
1599 -1.0
1600 };
1601 let half_axis = 0.5 * axis;
1602 let normal = if axis.is_zero() {
1603 Unit3::normalize (b_to_a_sigvec)
1604 } else {
1605 Unit3::unchecked_approx (-axis / distance)
1606 };
1607 let midpoint = nearest_a + half_axis;
1608 Proximity { distance, half_axis, midpoint, normal }
1609 }
1610 (true, false) => {
1611 let signum_y = (shaft_max_a.0.y - position_b.0.y).signum();
1613 let nearest_b = point3 (
1614 shaft_max_a.0.x,
1615 position_b.0.y + signum_y * cuboid_b_extent_y,
1616 cuboid_min_b.0.z
1617 );
1618 let a_to_b = nearest_b - shaft_max_a;
1619 let nearest_a = shaft_max_a + if a_to_b.is_zero() {
1620 -signum_y * vector3 (0.0, capsule_a_radius, 0.0)
1621 } else {
1622 capsule_a_radius * a_to_b.normalized()
1623 };
1624 let axis = nearest_b - nearest_a;
1625 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1626 a_to_b.dot (axis).signum()
1627 } else {
1628 -1.0
1629 };
1630 let half_axis = 0.5 * axis;
1631 let normal = if axis.is_zero() {
1632 Unit3::normalize (vector3 (0.0, signum_y, -1.0))
1633 } else {
1634 Unit3::unchecked_approx (-axis / distance)
1635 };
1636 let midpoint = nearest_a + half_axis;
1637 Proximity { distance, half_axis, midpoint, normal }
1638 }
1639 (false, true) => {
1640 let signum_x = (shaft_max_a.0.x - position_b.0.x).signum();
1642 let nearest_b = point3 (
1643 position_b.0.x + signum_x * cuboid_b_extent_x,
1644 shaft_max_a.0.y,
1645 cuboid_min_b.0.z
1646 );
1647 let a_to_b = nearest_b - shaft_max_a;
1648 let nearest_a = shaft_max_a + if a_to_b.is_zero() {
1649 -signum_x * vector3 (capsule_a_radius, 0.0, 0.0)
1650 } else {
1651 capsule_a_radius * a_to_b.normalized()
1652 };
1653 let axis = nearest_b - nearest_a;
1654 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1655 a_to_b.dot (axis).signum()
1656 } else {
1657 -1.0
1658 };
1659 let half_axis = 0.5 * axis;
1660 let normal = if axis.is_zero() {
1661 Unit3::normalize (vector3 (signum_x, 0.0, -1.0))
1662 } else {
1663 Unit3::unchecked_approx (-axis / distance)
1664 };
1665 let midpoint = nearest_a + half_axis;
1666 Proximity { distance, half_axis, midpoint, normal }
1667 }
1668 (true, true) => {
1669 let nearest_a : Point3 <f64> =
1671 shaft_max_a + vector3 (0.0, 0.0, capsule_a_radius);
1672 let nearest_b : Point3 <f64> =
1673 [position_a.0.x, position_a.0.y, cuboid_min_b.0.z].into();
1674 let axis = nearest_b - nearest_a;
1675 let normal = Unit3::axis_z().invert();
1676 let half_axis = 0.5 * axis;
1677 let distance = nearest_b.0.z - nearest_a.0.z;
1678 let midpoint = nearest_a + half_axis;
1679 Proximity { distance, half_axis, midpoint, normal }
1680 }
1681 }
1682 } else {
1683 let max_z = f64::min (shaft_max_a.0.z, cuboid_max_b.0.z);
1685 let min_z = f64::max (shaft_min_a.0.z, cuboid_min_b.0.z);
1686 debug_assert_ne!(min_z, max_z);
1687 let mid_z = 0.5 * (max_z + min_z);
1688 match (overlap_x, overlap_y) {
1689 (false, false) => {
1690 let b_to_a_signum_x = (position_a.0.x - position_b.0.x).signum();
1692 let b_to_a_signum_y = (position_a.0.y - position_b.0.y).signum();
1693 let b_to_a_unit_sigvec = vector3 (b_to_a_signum_x, b_to_a_signum_y, 0.0)
1694 .normalized();
1695 let nearest_b = Point3::from ([
1696 b_to_a_signum_x.mul_add (cuboid_b_extent_x, position_b.0.x),
1698 b_to_a_signum_y.mul_add (cuboid_b_extent_y, position_b.0.y),
1700 mid_z
1701 ]);
1702 let a_to_b = vector3 (
1703 nearest_b.0.x - position_a.0.x,
1704 nearest_b.0.y - position_a.0.y,
1705 0.0
1706 );
1707 let nearest_a = point3 (position_a.0.x, position_a.0.y, mid_z)
1708 + capsule_a_radius * if !a_to_b.is_zero() {
1709 a_to_b.normalized()
1710 } else {
1711 -b_to_a_unit_sigvec
1712 };
1713 let axis = nearest_b - nearest_a;
1714 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1715 a_to_b.dot (axis).signum()
1716 } else {
1717 -1.0
1718 };
1719 let half_axis = 0.5 * axis;
1720 let normal = Unit3::unchecked_approx (if axis.is_zero() {
1721 b_to_a_unit_sigvec
1722 } else {
1723 -axis / distance
1724 });
1725 let midpoint = nearest_a + half_axis;
1726 Proximity { distance, half_axis, midpoint, normal }
1727 }
1728 (true, false) => {
1729 let b_to_a_signum_y = (position_a.0.y - position_b.0.y).signum();
1731 let b_to_a_unit_sigvec = vector3 (0.0, b_to_a_signum_y, 0.0);
1732 let nearest_b = Point3::from ([
1733 position_a.0.x,
1734 b_to_a_signum_y.mul_add (cuboid_b_extent_y, position_b.0.y),
1736 mid_z
1737 ]);
1738 let a_to_b = vector3 (0.0, nearest_b.0.y - position_a.0.y, 0.0);
1739 let nearest_a = point3 (position_a.0.x, position_a.0.y, mid_z) +
1740 vector3 (0.0, -b_to_a_signum_y * capsule_a_radius, 0.0);
1741 let axis = nearest_b - nearest_a;
1742 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1743 a_to_b.dot (axis).signum()
1744 } else {
1745 -1.0
1746 };
1747 let half_axis = 0.5 * axis;
1748 let normal = Unit3::unchecked_approx (if axis.is_zero() {
1749 b_to_a_unit_sigvec
1750 } else {
1751 -axis / distance
1752 });
1753 let midpoint = nearest_a + half_axis;
1754 Proximity { distance, half_axis, midpoint, normal }
1755 }
1756 (false, true) => {
1757 let b_to_a_signum_x = (position_a.0.x - position_b.0.x).signum();
1759 let b_to_a_unit_sigvec = vector3 (b_to_a_signum_x, 0.0, 0.0);
1760 let nearest_b = Point3::from ([
1761 b_to_a_signum_x.mul_add (cuboid_b_extent_x, position_b.0.x),
1763 position_a.0.y,
1764 mid_z
1765 ]);
1766 let a_to_b = vector3 (nearest_b.0.x - position_a.0.x, 0.0, 0.0);
1767 let nearest_a = point3 (position_a.0.x, position_a.0.y, mid_z) +
1768 vector3 (-b_to_a_signum_x * capsule_a_radius, 0.0, 0.0);
1769 let axis = nearest_b - nearest_a;
1770 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1771 a_to_b.dot (axis).signum()
1772 } else {
1773 -1.0
1774 };
1775 let half_axis = 0.5 * axis;
1776 let normal = Unit3::unchecked_approx (if axis.is_zero() {
1777 b_to_a_unit_sigvec
1778 } else {
1779 -axis / distance
1780 });
1781 let midpoint = nearest_a + half_axis;
1782 Proximity { distance, half_axis, midpoint, normal }
1783 }
1784 (true, true) => {
1785 if position_a == position_b {
1787 let depth_x = cuboid_b_extent_x + capsule_a_radius;
1788 let depth_y = cuboid_b_extent_y + capsule_a_radius;
1789 let depth_z = cuboid_b_extent_z + capsule_a_half_height +
1790 capsule_a_radius;
1791 if depth_x <= depth_y && depth_x <= depth_z {
1792 let distance = -depth_x;
1793 let half_axis = [0.5 * depth_x, 0.0, 0.0].into();
1794 let normal = Unit3::axis_x();
1795 let midpoint = position_a + half_axis -
1796 vector3 (capsule_a_radius, 0.0, 0.0);
1797 Proximity { distance, half_axis, midpoint, normal }
1798 } else if depth_y <= depth_x && depth_y <= depth_z {
1799 let distance = -depth_y;
1800 let half_axis = [0.0, 0.5 * depth_y, 0.0].into();
1801 let normal = Unit3::axis_y();
1802 let midpoint = position_a + half_axis -
1803 vector3 (0.0, capsule_a_radius, 0.0);
1804 Proximity { distance, half_axis, midpoint, normal }
1805 } else {
1806 debug_assert!(depth_z < depth_x);
1807 debug_assert!(depth_z < depth_y);
1808 let distance = -depth_z;
1809 let half_axis = [0.0, 0.0, 0.5 * depth_z].into();
1810 let normal = Unit3::axis_z();
1811 let midpoint = position_a + half_axis -
1812 vector3 (0.0, 0.0, capsule_a_radius + capsule_a_half_height);
1813 Proximity { distance, half_axis, midpoint, normal }
1814 }
1815 } else {
1816 let b_to_a_sigvec = (position_a - position_b).map (f64::signum);
1819 let corner_b = position_b + cuboid_b.max().0 * b_to_a_sigvec;
1820 let depth_x = (corner_b.0.x - position_a.0.x).abs() + capsule_a_radius;
1821 let depth_y = (corner_b.0.y - position_a.0.y).abs() + capsule_a_radius;
1822 let depth_z = (corner_b.0.z - position_a.0.z).abs() +
1823 capsule_a_radius + capsule_a_half_height -
1824 if position_a.0.z.abs() > corner_b.0.z.abs() {
1825 2.0 * (position_a.0.z.abs() - corner_b.0.z.abs())
1826 } else {
1827 0.0
1828 };
1829
1830 if depth_x <= depth_y && depth_x <= depth_z {
1831 let distance = -depth_x;
1832 let half_axis = [0.5 * b_to_a_sigvec.x * depth_x, 0.0, 0.0].into();
1833 let normal = Unit3::unchecked ([b_to_a_sigvec.x, 0.0, 0.0].into());
1834 let midpoint = position_a + half_axis +
1835 vector3 (-b_to_a_sigvec.x * capsule_a_radius, 0.0, 0.0);
1836 Proximity { distance, half_axis, midpoint, normal }
1837 } else if depth_y <= depth_x && depth_y <= depth_z {
1838 let distance = -depth_y;
1839 let half_axis = [0.0, 0.5 * b_to_a_sigvec.y * depth_y, 0.0].into();
1840 let normal = Unit3::unchecked ([0.0, b_to_a_sigvec.y, 0.0].into());
1841 let midpoint = position_a + half_axis +
1842 vector3 (0.0, -b_to_a_sigvec.y * capsule_a_radius, 0.0);
1843 Proximity { distance, half_axis, midpoint, normal }
1844 } else {
1845 debug_assert!(depth_z < depth_x);
1846 debug_assert!(depth_z < depth_y);
1847 let nearest_a = point3 (
1848 position_a.0.x,
1849 position_a.0.y,
1850 b_to_a_sigvec.z
1852 .mul_add (-(capsule_a_radius + capsule_a_half_height), position_a.0.z)
1853 );
1854 let nearest_b = point3 (
1855 position_a.0.x,
1856 position_a.0.y,
1857 b_to_a_sigvec.z.mul_add (cuboid_b_extent_z, position_b.0.z)
1859 );
1860 let axis = nearest_b - nearest_a;
1861 debug_assert_eq!(axis.x, 0.0);
1862 debug_assert_eq!(axis.y, 0.0);
1863 let distance = -axis.z.abs();
1864 let half_axis = 0.5 * axis;
1865 let normal = Unit3::unchecked ([0.0, 0.0, b_to_a_sigvec.z].into());
1866 let midpoint = nearest_a + half_axis;
1867 Proximity { distance, half_axis, midpoint, normal }
1868 }
1869 }
1870 }
1871 }
1872 }
1873 } pub fn query_capsule_orthant (
1876 position_a : &Point3 <f64>, capsule_a : &shape::Capsule <f64>,
1877 position_b : &Point3 <f64>, orthant_b : &shape::Orthant
1878 ) -> Self {
1879 let radius_a = *capsule_a.radius;
1880 let half_height = *capsule_a.half_height;
1881 let normal = orthant_b.normal_axis.to_vec::<f64>();
1882 let normal_abs = normal.map (f64::abs);
1883 let surface_sigvec = vector3 (1.0, 1.0, 1.0) - normal_abs;
1884 let nearest_a = position_a -
1885 vector3 (radius_a, radius_a, radius_a + half_height) * normal;
1886 let nearest_b =
1887 Point3 (position_a.0 * surface_sigvec + position_b.0 * normal_abs);
1888 let axis = nearest_b - nearest_a;
1889 debug_assert_eq!(axis.sum().abs(), axis.magnitude());
1890 let distance = -normal.dot (axis).signum() * axis.sum().abs();
1891 let half_axis = 0.5 * axis;
1892 let midpoint = nearest_a + half_axis;
1893 let normal = Unit3::unchecked (normal);
1894 Proximity { distance, half_axis, midpoint, normal }
1895 } pub fn query_cuboid_orthant (
1898 position_a : &Point3 <f64>, cuboid_a : &shape::Cuboid <f64>,
1899 position_b : &Point3 <f64>, orthant_b : &shape::Orthant
1900 ) -> Self {
1901 let normal = orthant_b.normal_axis.to_vec::<f64>();
1902 let normal_abs = normal.map (f64::abs);
1903 let surface_sigvec = vector3 (1.0, 1.0, 1.0) - normal_abs;
1904 let nearest_a = position_a - cuboid_a.extents.map (|e| *e) * normal;
1905 let nearest_b =
1906 Point3 (position_a.0 * surface_sigvec + position_b.0 * normal_abs);
1907 let axis = nearest_b - nearest_a;
1908 debug_assert_eq!(axis.sum().abs(), axis.magnitude());
1909 let distance = -normal.dot (axis).signum() * axis.sum().abs();
1910 let half_axis = 0.5 * axis;
1911 let midpoint = nearest_a + half_axis;
1912 let normal = Unit3::unchecked (normal);
1913 Proximity { distance, half_axis, midpoint, normal }
1914 } pub fn query_triangle_triangle (
1917 triangle_a : &geometry::Triangle3 <f64>,
1918 triangle_b : &geometry::Triangle3 <f64>
1919 ) -> Self {
1920 fn query_triangle_triangle_recursive (
1921 triangle_a : &geometry::Triangle3 <f64>,
1922 triangle_b : &geometry::Triangle3 <f64>,
1923 is_recurse : bool
1924 ) -> Proximity {
1925 let mut out = None;
1926 let mut min_distance = f64::MAX;
1927 for edge in triangle_a.edges() {
1928 let proximity = Proximity::query_triangle_segment (triangle_b, &edge);
1929 if proximity.distance < -f64::EPSILON * 2.0.powi (12) {
1930 out = None;
1931 break
1932 }
1933 if proximity.distance < min_distance {
1934 min_distance = proximity.distance;
1935 out = Some (proximity.flip());
1937 }
1938 }
1939 if out.is_some() {
1940 for edge in triangle_b.edges() {
1942 let proximity = Proximity::query_triangle_segment (triangle_a, &edge);
1943 if proximity.distance < -f64::EPSILON * 2.0.powi (12) {
1944 out = None;
1945 break
1946 }
1947 if proximity.distance < min_distance {
1948 min_distance = proximity.distance;
1949 out = Some (proximity);
1950 }
1951 }
1952 }
1953 if out.is_none() {
1954 if is_recurse {
1956 log::error!("triangle/triangle proximity query can't recurse more than once");
1957 panic!("triangle/triangle proximity query can't recurse more than once");
1958 }
1959 let points : [Point3 <f64>; 9] = std::array::from_fn (|i|{
1961 let p = triangle_a.points()[i / 3];
1962 let q = triangle_b.points()[i % 3];
1963 Point3 (p.0 - q.0)
1964 });
1965 let get_triangle = |a, b, c|
1969 geometry::Triangle3::new (points[a], points[b], points[c]);
1970 let mut nearest_distance : Option <geometry::Distance3 <f64>> = None;
1971 let tolerance = f64::EPSILON * 2.0.powi (10);
1972 for i in 0..9 {
1973 for j in (i + 1)..9 {
1974 for k in (j + 1)..9 {
1975 if let Some (triangle) = get_triangle (i, j, k) {
1976 let distance =
1977 geometry::Distance3::triangle_point (triangle, Point3::origin());
1978 if distance.distance_squared() < nearest_distance.as_ref().map_or (
1979 NonNegative::unchecked (f64::MAX),
1980 geometry::Distance3::distance_squared)
1981 {
1982 let normal = {
1984 let mut normal = triangle.normal();
1985 if normal.dot (triangle.point_a().0) < 0.0 {
1986 normal = -normal
1987 }
1988 normal
1989 };
1990 let mut exterior = true;
1991 for point in points.iter() {
1992 if normal.dot (point - triangle.point_a()) > tolerance {
1993 exterior = false;
1994 break
1995 }
1996 }
1997 if exterior {
1998 nearest_distance = Some (distance);
1999 }
2000 }
2001 }
2002 }
2003 }
2004 }
2005 let mut nearest = nearest_distance.unwrap();
2006 let distance = -*nearest.distance();
2007 let half_axis = -nearest.nearest_a().0 * 0.5;
2008 let resolved_proximity = {
2009 let translate = |mut triangle : geometry::Triangle3 <f64>, displacement| {
2010 triangle.translate (displacement);
2011 triangle
2012 };
2013 let resolved_a = translate (*triangle_a, half_axis);
2014 let resolved_b = translate (*triangle_b, -half_axis);
2015 query_triangle_triangle_recursive (&resolved_a, &resolved_b, true)
2017 };
2018 out = Some(Proximity { distance, half_axis, .. resolved_proximity });
2019 }
2020 out.unwrap()
2021 }
2022 query_triangle_triangle_recursive (triangle_a, triangle_b, false)
2023 }
2024
2025 pub fn query_triangle_line (
2026 triangle : &geometry::Triangle3 <f64>,
2027 line : &geometry::Segment3 <f64>
2028 ) -> Self {
2029 use approx::{AbsDiffEq, RelativeEq};
2030 let (([s, t], nearest_a), (_, nearest_b)) =
2031 geometry::distance::nearest_triangle3_line3 (*triangle, *line);
2032 if approx::relative_eq!(nearest_a, nearest_b,
2033 max_relative = f64::default_max_relative() * 256.0,
2034 epsilon = f64::default_epsilon() * 256.0)
2035 {
2036 let distance;
2038 let half_axis;
2039 let midpoint;
2040 let normal;
2041 let triangle_normal = triangle.normal();
2042 if approx::abs_diff_eq!(triangle_normal.dot (*line.vector()), 0.0) {
2043 let a_to_b = nearest_b - nearest_a;
2046 distance = a_to_b.magnitude();
2047 half_axis = a_to_b * 0.5;
2048 midpoint = nearest_a + half_axis;
2049 normal = triangle_normal.normalize();
2050 } else {
2051 let y = nearest_a;
2052 let (d0, d1, d2) = triangle_distance_to_edges (*triangle, *s, *t);
2053 let edge0 = triangle.point_c() - triangle.point_b();
2055 let edge1 = triangle.point_b() - triangle.point_a();
2056 let edge2 = triangle.point_c() - triangle.point_a();
2057 let len2_e0 = edge0.magnitude_squared();
2058 let len2_e1 = edge1.magnitude_squared();
2059 let len2_e2 = edge2.magnitude_squared();
2060 let mut e0_is_nearest = false;
2061 let mut e1_is_nearest = false;
2062 let mut e2_is_nearest = false;
2063 let nearest_a = if d0 <= d1 && d0 <= d2 {
2064 e0_is_nearest = true;
2065 let t = (y - triangle.point_b()).dot (edge0) / len2_e0;
2066 triangle.point_b() + edge0 * t
2067 } else if d1 <= d2 {
2068 e1_is_nearest = true;
2069 let t = (y - triangle.point_a()).dot (edge1) / len2_e1;
2070 triangle.point_a() + edge1 * t
2071 } else {
2072 debug_assert!(d2 < d0);
2073 debug_assert!(d2 < d1);
2074 e2_is_nearest = true;
2075 let t = (y - triangle.point_a()).dot (edge2) / len2_e2;
2076 triangle.point_a() + edge2 * t
2077 };
2078 let nearest_b = y;
2079 let a_to_b = nearest_b - nearest_a;
2080 distance = -a_to_b.magnitude();
2081 half_axis = a_to_b * 0.5;
2082 midpoint = nearest_a + half_axis;
2083 normal = if approx::relative_eq!(nearest_a, nearest_b,
2087 max_relative = f64::default_max_relative() * 256.0,
2088 epsilon = f64::default_epsilon() * 256.0)
2089 {
2090 let perp = if e0_is_nearest {
2091 -triangle.perpendicular_bc()
2093 } else if e1_is_nearest {
2094 -triangle.perpendicular_ab()
2096 } else {
2097 debug_assert!(e2_is_nearest);
2098 -triangle.perpendicular_ca()
2100 };
2101 *perp
2102 } else {
2103 -a_to_b
2104 }.normalize();
2105 }
2106 return Proximity { distance, half_axis, midpoint, normal }
2107 }
2108 let a_to_b = nearest_b - nearest_a;
2109 let distance = a_to_b.magnitude();
2110 let half_axis = a_to_b * 0.5;
2111 let midpoint = nearest_a + half_axis;
2112 let normal = Unit3::normalize (-a_to_b);
2113 Proximity { distance, half_axis, midpoint, normal }
2114 }
2115
2116 pub fn query_triangle_segment (
2117 triangle : &geometry::Triangle3 <f64>,
2118 segment : &geometry::Segment3 <f64>
2119 ) -> Self {
2120 use approx::{AbsDiffEq, RelativeEq};
2121 let (([s, t], nearest_a), (_r, nearest_b)) =
2122 geometry::distance::nearest_triangle3_segment3 (*triangle, *segment);
2123 if approx::relative_eq!(nearest_a, nearest_b,
2124 max_relative = f64::default_max_relative() * 2.0.powi (17),
2125 epsilon = f64::default_epsilon() * 2.0.powi (17))
2126 {
2127 if let Some((mut proximity, edge_perp)) = if approx::abs_diff_eq!(*s, 0.0,
2130 epsilon = f64::default_epsilon() * 2.0.powi (23))
2131 {
2132 Some (( Proximity::query_segment_segment (&triangle.edge_ca(), segment),
2134 triangle.perpendicular_ca() ))
2135 } else if approx::abs_diff_eq!(*t, 0.0,
2136 epsilon = f64::default_epsilon() * 2.0.powi (23))
2137 {
2138 Some (( Proximity::query_segment_segment (&triangle.edge_ab(), segment),
2140 triangle.perpendicular_ab() ))
2141 } else if approx::relative_eq!(*s + *t, 1.0,
2142 max_relative = f64::default_max_relative() * 2.0.powi (23),
2143 epsilon = f64::default_epsilon() * 2.0.powi (23))
2144 {
2145 Some (( Proximity::query_segment_segment (&triangle.edge_bc(), segment),
2147 triangle.perpendicular_bc() ))
2148 } else {
2149 None
2150 }
2151 {
2152 if edge_perp.dot (*proximity.normal) > 0.0 {
2153 proximity.normal = -proximity.normal;
2155 }
2156 return proximity
2157 }
2158 let distance;
2162 let half_axis;
2163 let midpoint;
2164 let normal;
2165 let triangle_normal = triangle.normal();
2166 let mut triangle_normal_unit = None;
2167 let segment_vec = segment.vector();
2168 if approx::abs_diff_eq!(triangle_normal.dot (*segment_vec), 0.0) {
2169 distance = 0.0;
2172 half_axis = Vector3::zero();
2173 midpoint = nearest_a;
2174 normal = triangle_normal.normalize();
2175 } else {
2176 let (seg_depth_sq, seg_depth_vec) = if triangle_normal.cross (*segment_vec)
2178 == Vector3::zero()
2179 {
2180 let depth_vec_a = segment.point_a() - nearest_b;
2182 let depth_vec_b = segment.point_b() - nearest_b;
2183 let dsq_a = depth_vec_a.magnitude_squared();
2184 let dsq_b = depth_vec_b.magnitude_squared();
2185 if dsq_a < dsq_b {
2186 (dsq_a, depth_vec_a)
2187 } else {
2188 (dsq_b, depth_vec_b)
2189 }
2190 } else {
2191 let normal_unit = triangle_normal.normalize();
2194 triangle_normal_unit = Some (normal_unit);
2195 let tri0_to_seg0 = segment.point_a() - triangle.point_a();
2196 let tri0_to_seg1 = segment.point_b() - triangle.point_a();
2197 let normal_dot_seg0 = normal_unit.dot (tri0_to_seg0);
2198 let normal_dot_seg1 = normal_unit.dot (tri0_to_seg1);
2199 let proj_seg0 = segment.point_a() - *normal_unit * normal_dot_seg0;
2200 let proj_seg1 = segment.point_b() - *normal_unit * normal_dot_seg1;
2201 let ab = triangle.point_b() - triangle.point_a();
2203 let ac = triangle.point_c() - triangle.point_a();
2204 let ab_mag_sq = ab.magnitude_squared();
2205 let ab_dot_ac = ab.dot (ac);
2206 let ac_mag_sq = ac.magnitude_squared();
2207 let determinant = ab_mag_sq.mul_add (ac_mag_sq, -ab_dot_ac.squared());
2209 let barycentric_to_cartesian = |s, t| triangle.point_a() + ab * s + ac * t;
2211 let barycentric_coords = |p_proj : Point3 <f64>| {
2212 let to_p = p_proj - triangle.point_a();
2213 let to_p_dot_ab = to_p.dot (ab);
2214 let to_p_dot_ac = to_p.dot (ac);
2215 let s = ac_mag_sq.mul_add (to_p_dot_ab, -ab_dot_ac * to_p_dot_ac)
2217 / determinant;
2218 let t = ab_mag_sq.mul_add (to_p_dot_ac, -ab_dot_ac * to_p_dot_ab)
2220 / determinant;
2221 if cfg!(debug_assertions) {
2222 approx::assert_relative_eq!(p_proj, barycentric_to_cartesian (s, t),
2223 epsilon = f64::default_epsilon() * 2.0.powi (40),
2224 max_relative = f64::default_max_relative() * 2.0.powi (40));
2225 }
2226 [s, t]
2227 };
2228 let [s0, t0] = barycentric_coords (proj_seg0);
2229 let [s1, t1] = barycentric_coords (proj_seg1);
2230 let (base_s, base_t) = (s0, t0);
2231 let (vec_s, vec_t) = (s1 - s0, t1 - t0);
2232 let clip_seg_endpoint = |s, t| {
2234 let (mut s, mut t) = (s, t);
2242 let mut u = 0.0;
2243 #[expect(clippy::useless_let_if_seq)]
2244 let mut clipped = false;
2245 if s < 0.0 {
2246 u = -base_s / vec_s;
2248 s = 0.0;
2249 t = base_t + u * vec_t;
2250 clipped = true;
2251 }
2252 if t < 0.0 {
2253 u = -base_t / vec_t;
2255 s = base_s + u * vec_s;
2256 t = 0.0;
2257 clipped = true;
2258 }
2259 if s + t > 1.0 {
2260 u = (1.0 - base_s - base_t) / (vec_s + vec_t);
2262 s = base_s + u * vec_s;
2263 t = base_t + u * vec_t;
2264 if cfg!(debug_assertions) {
2265 approx::assert_relative_eq!(s + t, 1.0,
2266 max_relative = f64::default_max_relative() * 2.0.powi (16),
2267 epsilon = f64::default_epsilon() * 2.0.powi (16));
2268 }
2269 debug_assert!(s >= 0.0);
2270 debug_assert!(t >= 0.0);
2271 clipped = true;
2272 }
2273 if clipped {
2274 Some (([s, t], u))
2275 } else {
2276 None
2277 }
2278 };
2279 let (dsq_a, depth_vec_a) =
2280 if let Some (([s, t], u)) = clip_seg_endpoint (s0, t0) {
2281 let clipped = segment.point_a() + *segment_vec * u;
2282 let proj = barycentric_to_cartesian (s, t);
2283 let depth_vec = clipped - proj;
2284 (depth_vec.magnitude_squared(), depth_vec)
2285 } else {
2286 let depth_vec = segment.point_a() - proj_seg0;
2287 (depth_vec.magnitude_squared(), depth_vec)
2288 };
2289 let (dsq_b, depth_vec_b) =
2290 if let Some (([s, t], u)) = clip_seg_endpoint (s1, t1) {
2291 let clipped = segment.point_a() + *segment_vec * u;
2292 let proj = barycentric_to_cartesian (s, t);
2293 let depth_vec = clipped - proj;
2294 (depth_vec.magnitude_squared(), depth_vec)
2295 } else {
2296 let depth_vec = segment.point_b() - proj_seg1;
2297 (depth_vec.magnitude_squared(), depth_vec)
2298 };
2299 if dsq_a < dsq_b {
2300 (dsq_a, depth_vec_a)
2301 } else {
2302 (dsq_b, depth_vec_b)
2303 }
2304 };
2305 let (d0, d1, d2) = triangle_distance_to_edges (*triangle, *s, *t);
2307 let edge_dist_sq = f64::min (d0 * d0, f64::min (d1 * d1, d2 * d2));
2308 if seg_depth_sq <= edge_dist_sq {
2310 let unit_normal = triangle_normal_unit
2312 .unwrap_or_else (|| triangle_normal.normalize());
2313 if unit_normal.dot (seg_depth_vec) < 0.0 {
2314 normal = -unit_normal;
2315 } else {
2316 normal = unit_normal;
2317 }
2318 distance = -seg_depth_sq.sqrt();
2319 half_axis = *normal * -distance * 0.5;
2320 midpoint = nearest_a + half_axis;
2321 } else {
2322 let edge_dist = edge_dist_sq.sqrt();
2324 distance = -edge_dist;
2325 let edge0 = triangle.point_b() - triangle.point_a();
2327 let edge1 = triangle.point_c() - triangle.point_a();
2328 let edge2 = triangle.point_c() - triangle.point_b();
2329 let len2_e0 = edge0.magnitude_squared();
2330 let len2_e1 = edge1.magnitude_squared();
2331 let len2_e2 = edge2.magnitude_squared();
2332 let (nearest_edge_point, nearest_edge_perp) = if d0 <= d1 && d0 <= d2 {
2333 let t = (nearest_b - triangle.point_b()).dot (edge0) / len2_e0;
2334 (triangle.point_b() + edge0 * t, -triangle.perpendicular_ab())
2335 } else if d1 <= d2 {
2336 let t = (nearest_b - triangle.point_a()).dot (edge1) / len2_e1;
2337 (triangle.point_a() + edge1 * t, -triangle.perpendicular_ca())
2338 } else {
2339 let t = (nearest_b - triangle.point_a()).dot (edge2) / len2_e2;
2340 (triangle.point_a() + edge2 * t, -triangle.perpendicular_bc())
2341 };
2342 half_axis = (nearest_b - nearest_edge_point) * 0.5;
2343 midpoint = nearest_a + half_axis;
2344 normal = nearest_edge_perp.normalize();
2345 }
2346 }
2347 return Proximity { distance, half_axis, midpoint, normal }
2348 }
2349 let a_to_b = nearest_b - nearest_a;
2350 let distance = a_to_b.magnitude();
2351 let half_axis = a_to_b * 0.5;
2352 let midpoint = nearest_a + half_axis;
2353 let normal = -a_to_b.normalize();
2354 Proximity { distance, half_axis, midpoint, normal }
2355 }
2356
2357 pub fn query_triangle_point (
2358 triangle : &geometry::Triangle3 <f64>,
2359 point : &Point3 <f64>
2360 ) -> Self {
2361 let ([s, t], nearest_a) = triangle.nearest_point (*point);
2362 let a_to_b = point - nearest_a;
2363 let distance = a_to_b.magnitude();
2364 let half_axis = a_to_b * 0.5;
2365 let midpoint = nearest_a + half_axis;
2366 let normal = if *point == nearest_a {
2367 let perp = if *t == 0.0 {
2369 -triangle.perpendicular_ab()
2371 } else if *s == 0.0 {
2372 -triangle.perpendicular_ca()
2374 } else if *s + *t == 1.0 {
2375 -triangle.perpendicular_bc()
2377 } else {
2378 triangle.normal()
2380 };
2381 *perp
2382 } else {
2383 -a_to_b
2384 }.normalize();
2385 Proximity { distance, half_axis, midpoint, normal }
2386 }
2387
2388 pub fn query_line_line (
2389 line_a : &geometry::Segment3 <f64>,
2390 line_b : &geometry::Segment3 <f64>
2391 ) -> Self {
2392 use approx::{AbsDiffEq, RelativeEq};
2393 use num::Zero;
2394 let ((_, nearest_a), (_, nearest_b)) =
2395 geometry::distance::nearest_line3_line3 (*line_a, *line_b);
2396 let a_to_b = nearest_b - nearest_a;
2397 let distance = a_to_b.magnitude();
2398 let half_axis = a_to_b * 0.5;
2399 let midpoint = nearest_a + half_axis;
2400 let normal = if approx::relative_eq!(nearest_a, nearest_b,
2401 max_relative = f64::default_max_relative() * 256.0,
2402 epsilon = f64::default_epsilon() * 256.0)
2403 {
2404 let line_a_dir = line_a.vector();
2406 let line_b_dir = line_b.vector();
2407 let mut perp = line_a_dir.cross (*line_b_dir);
2408 if perp.is_zero() {
2409 perp = line_a_dir.orthogonal();
2410 }
2411 perp
2412 } else {
2413 -a_to_b
2414 }.normalize();
2415 Proximity { distance, half_axis, midpoint, normal }
2416 }
2417
2418 pub fn query_line_segment (
2419 line : &geometry::Segment3 <f64>,
2420 segment : &geometry::Segment3 <f64>
2421 ) -> Self {
2422 use approx::{AbsDiffEq, RelativeEq};
2423 let seg_dir = segment.vector();
2424 let line_dir = line.vector();
2425 let ((_, nearest_a), (s1, nearest_b)) =
2426 geometry::distance::nearest_line3_segment3 (*line, *segment);
2427 let a_to_b = nearest_b - nearest_a;
2428 let distance = a_to_b.magnitude();
2429 let half_axis = a_to_b * 0.5;
2430 let midpoint = nearest_a + half_axis;
2431 let normal = if approx::relative_eq!(nearest_a, nearest_b,
2432 max_relative = f64::default_max_relative() * 256.0,
2433 epsilon = f64::default_epsilon() * 256.0)
2434 {
2435 if 0.0 < *s1 && *s1 < 1.0 {
2437 let mut perp = seg_dir.cross (*line_dir);
2439 if perp.is_approx_zero() {
2440 perp = seg_dir.orthogonal();
2442 }
2443 debug_assert!(!perp.is_approx_zero());
2444 perp
2445 } else {
2446 debug_assert!(*s1 == 0.0 || *s1 == 1.0);
2449 let mut perp = seg_dir.cross (*line_dir).cross (*line_dir);
2450 if perp.is_approx_zero() {
2451 perp = seg_dir.orthogonal()
2453 } else if *s1 == 1.0 {
2454 perp = -perp
2455 }
2456 debug_assert!((nearest_a - segment.point_a()).dot (perp) >= 0.0);
2457 debug_assert!((nearest_a - segment.point_b()).dot (perp) >= 0.0);
2458 perp
2459 }
2460 } else {
2461 -a_to_b
2462 }.normalize();
2463 Proximity { distance, half_axis, midpoint, normal }
2464 }
2465
2466 pub fn query_line_point (
2467 line : &geometry::Segment3 <f64>,
2468 point : &Point3 <f64>
2469 ) -> Self {
2470 let (_, nearest_a) = line.nearest_point (*point);
2471 let nearest_b = *point;
2472 let a_to_b = nearest_b - nearest_a;
2473 let distance = a_to_b.magnitude();
2474 let half_axis = a_to_b * 0.5;
2475 let midpoint = nearest_a + half_axis;
2476 let normal = if approx::relative_eq!(nearest_a, nearest_b) {
2477 *line.perpendicular()
2478 } else {
2479 -a_to_b
2480 }.normalize();
2481 Proximity { distance, half_axis, midpoint, normal }
2482 }
2483
2484 pub fn query_segment_segment (
2485 segment_a : &geometry::Segment3 <f64>,
2486 segment_b : &geometry::Segment3 <f64>
2487 ) -> Self {
2488 use approx::{AbsDiffEq, RelativeEq};
2489 let vec_a = segment_a.vector();
2492 let vec_b = segment_b.vector();
2493 let vec_b0a0 = segment_a.point_a() - segment_b.point_a();
2494 let a = Positive::unchecked (*vec_a.self_dot());
2495 let b = vec_a.dot (*vec_b);
2496 let c = Positive::unchecked (*vec_b.self_dot());
2497 let d = vec_a.dot (vec_b0a0);
2498 let e = vec_b.dot (vec_b0a0);
2499 let f00 = d;
2500 let f10 = f00 + *a;
2501 let f01 = f00 - b;
2502 let f11 = f10 - b;
2503 let g00 = -e;
2504 let g10 = g00 - b;
2505 let g01 = g00 + *c;
2506 let g11 = g10 + *c;
2507 let svalue = [
2508 clamped_root (*a, f00, f10),
2509 clamped_root (*a, f01, f11)
2510 ];
2511 let mut classify = [i8::MAX; 2];
2512 for i in 0..2 {
2513 if svalue[i] <= 0.0 {
2514 classify[i] = -1
2515 } else if svalue[i] >= 1.0 {
2516 classify[i] = 1
2517 } else {
2518 classify[i] = 0
2519 }
2520 }
2521 let param_a;
2522 let param_b;
2523 if classify[0] == -1 && classify[1] == -1 {
2524 param_a = 0.0;
2525 param_b = clamped_root (*c, g00, g01);
2526 } else if classify[0] == 1 && classify[1] == 1 {
2527 param_a = 1.0;
2528 param_b = clamped_root (*c, g10, g11);
2529 } else {
2530 let mut edge = [u8::MAX; 2];
2531 let mut end = [[f64::NAN; 2]; 2];
2532 if classify[0] == -1 {
2533 edge[0] = 0;
2534 end[0][0] = 0.0;
2535 end[0][1] = f00 / b;
2536 if end[0][1] < 0.0 || end[0][1] > 1.0 {
2537 end[0][1] = 0.5
2538 }
2539 if classify[1] == 0 {
2540 edge[1] = 3;
2541 end[1][0] = svalue[1];
2542 end[1][1] = 1.0;
2543 } else {
2544 debug_assert_eq!(classify[1], 1);
2545 edge[1] = 1;
2546 end[1][0] = 1.0;
2547 end[1][1] = f10 / b;
2548 if end[1][1] < 0.0 || end[1][1] > 1.0 {
2549 end[1][1] = 0.5
2550 }
2551 }
2552 } else if classify[0] == 0 {
2553 edge[0] = 2;
2554 end[0][0] = svalue[0];
2555 end[0][1] = 0.0;
2556 if classify[1] == -1 {
2557 edge[1] = 0;
2558 end[1][0] = 0.0;
2559 end[1][1] = f00 / b;
2560 if end[1][1] < 0.0 || end[1][1] > 1.0 {
2561 end[1][1] = 0.5
2562 }
2563 } else if classify[1] == 0 {
2564 edge[1] = 3;
2565 end[1][0] = svalue[1];
2566 end[1][1] = 1.0;
2567 } else {
2568 debug_assert_eq!(classify[1], 1);
2569 edge[1] = 1;
2570 end[1][0] = 1.0;
2571 end[1][1] = f10 / b;
2572 if end[1][1] < 0.0 || end[1][1] > 1.0 {
2573 end[1][1] = 0.5
2574 }
2575 }
2576 } else {
2577 debug_assert_eq!(classify[0], 1);
2578 edge[0] = 1;
2579 end[0][0] = 1.0;
2580 end[0][1] = f10 / b;
2581 if end[0][1] < 0.0 || end[0][1] > 1.0 {
2582 end[0][1] = 0.5
2583 }
2584 if classify[1] == 0 {
2585 edge[1] = 3;
2586 end[1][0] = svalue[1];
2587 end[1][1] = 1.0;
2588 } else {
2589 edge[1] = 0;
2590 end[1][0] = 0.0;
2591 end[1][1] = f00 / b;
2592 if end[1][1] < 0.0 || end[1][1] > 1.0 {
2593 end[1][1] = 0.5
2594 }
2595 }
2596 }
2597 let delta = end[1][1] - end[0][1];
2599 let h0 = delta * ((-b).mul_add (end[0][0], c.mul_add (end[0][1], -e)));
2601 if h0 >= 0.0 {
2602 param_a = (end[0][0] + end[1][0]) / 2.0;
2603 param_b = (end[0][1] + end[1][1]) / 2.0;
2604 } else {
2605 let h1 = delta * ((-b).mul_add (end[1][0], c.mul_add (end[1][1], -e)));
2607 if h1 <= 0.0 {
2608 if edge[1] == 0 {
2609 param_a = 0.0;
2610 param_b = clamped_root (*c, g00, g01);
2611 } else if edge[1] == 1 {
2612 param_a = 1.0;
2613 param_b = clamped_root (*c, g10, g11);
2614 } else {
2615 param_a = end[1][0];
2616 param_b = end[1][1];
2617 }
2618 } else {
2619 debug_assert!(h0 < 0.0);
2620 debug_assert!(h1 > 0.0);
2621 let z = (h0 / (h0 - h1)).clamp (0.0, 1.0);
2622 let omz = 1.0 - z;
2623 param_a = omz * end[0][0] + z * end[1][0];
2624 param_b = omz * end[0][1] + z * end[1][1];
2625 }
2626 }
2627 debug_assert_ne!(edge[0], u8::MAX);
2628 debug_assert_ne!(edge[1], u8::MAX);
2629 debug_assert_ne!(end[0][0], f64::NAN);
2630 debug_assert_ne!(end[0][1], f64::NAN);
2631 debug_assert_ne!(end[1][0], f64::NAN);
2632 debug_assert_ne!(end[1][1], f64::NAN);
2633 }
2634 let nearest_a = Point3::from (segment_a.point_a().0 * (1.0 - param_a)
2635 + segment_a.point_b().0 * param_a);
2636 let nearest_b = Point3::from (segment_b.point_a().0 * (1.0 - param_b)
2637 + segment_b.point_b().0 * param_b);
2638 let a_to_b = nearest_b - nearest_a;
2639 let distance = a_to_b.magnitude();
2640 let half_axis = a_to_b * 0.5;
2641 let midpoint = nearest_a + half_axis;
2642 let normal = if approx::relative_eq!(nearest_a, nearest_b,
2643 max_relative = f64::default_max_relative() * 2.0.powi (20),
2644 epsilon = f64::default_epsilon() * 2.0.powi (20))
2645 {
2646 let mut perp = vec_a.cross (*vec_b);
2648 if perp == Vector3::zero() {
2649 perp = vec_a.cross (Vector3::unit_z());
2651 if perp == Vector3::zero() {
2652 perp = vec_a.cross (Vector3::unit_x());
2654 }
2655 }
2656 Unit3::normalize (perp)
2657 } else {
2658 Unit3::normalize (-a_to_b)
2659 };
2660 Proximity { distance, half_axis, midpoint, normal }
2661 }
2662
2663 pub fn query_segment_point (
2664 segment : &geometry::Segment3 <f64>,
2665 point : &Point3 <f64>
2666 ) -> Self {
2667 let (s, nearest_a) = segment.nearest_point (*point);
2668 let nearest_b = *point;
2669 let a_to_b = nearest_b - nearest_a;
2670 let distance = a_to_b.magnitude();
2671 let half_axis = a_to_b * 0.5;
2672 let midpoint = nearest_a + half_axis;
2673 let normal = if approx::relative_eq!(nearest_a, nearest_b) {
2674 let perp = if *s == 0.0 {
2675 debug_assert_eq!(nearest_a, segment.point_a());
2676 -segment.vector()
2677 } else if *s == 1.0 {
2678 segment.vector()
2679 } else {
2680 segment.perpendicular()
2681 };
2682 *perp
2683 } else {
2684 -a_to_b
2685 }.normalize();
2686 Proximity { distance, half_axis, midpoint, normal }
2687 }
2688}
2689
2690fn triangle_distance_to_edges (triangle : geometry::Triangle3 <f64>, s : f64, t : f64)
2693 -> (f64, f64, f64)
2694{
2695 use approx::{AbsDiffEq, RelativeEq};
2696 debug_assert!(s + t <= 1.0);
2697 let b0 = 1.0 - s - t;
2699 let b1 = s;
2700 let b2 = t;
2701 let edge0 = triangle.point_c() - triangle.point_b();
2703 let edge1 = triangle.point_c() - triangle.point_a();
2704 let edge2 = triangle.point_b() - triangle.point_a();
2705 let len_e0_sq = edge0.magnitude_squared();
2706 let len_e1_sq = edge1.magnitude_squared();
2707 let len_e2_sq = edge2.magnitude_squared();
2708 let area_2_sq = triangle.normal().magnitude_squared();
2710 let d0 = b0 * (area_2_sq / len_e0_sq).sqrt();
2712 let d1 = b1 * (area_2_sq / len_e1_sq).sqrt();
2713 let d2 = b2 * (area_2_sq / len_e2_sq).sqrt();
2714 approx::assert_relative_eq!(
2715 triangle.barycentric ([b0, b1, b2].into()),
2716 triangle.trilinear ([d0, d1, d2].into()),
2717 max_relative = f64::default_max_relative() * 32.0,
2718 epsilon = f64::default_epsilon() * 32.0);
2719 (d0, d1, d2)
2720}
2721
2722fn clamped_root (slope : f64, h0 : f64, h1 : f64) -> f64 {
2723 if h0 < 0.0 {
2725 if h1 > 0.0 {
2726 let mut root = -h0 / slope;
2727 if root > 1.0 {
2728 root = 0.5
2729 }
2730 root
2731 } else {
2732 1.0
2733 }
2734 } else {
2735 0.0
2736 }
2737}
2738
2739#[cfg(test)]
2740mod tests {
2741 use approx::AbsDiffEq;
2742 use rand;
2743 use rand_distr;
2744 use rand_xorshift::XorShiftRng;
2745 use std::f64::consts::*;
2746 use super::*;
2747
2748 #[test]
2749 fn segment_point() {
2750 use rand::SeedableRng;
2751 use rand_distr::Distribution;
2752 let segment = geometry::Segment3::noisy (
2754 [-1.0, 0.0, 0.0].into(),
2755 [ 1.0, 0.0, 0.0].into());
2756 let point = point3 (0.0, 1.0, 0.0);
2757 let proximity = Proximity::query_segment_point (&segment, &point);
2758 assert_eq!(proximity.nearest_a(), [0.0, 0.0, 0.0].into());
2759 assert_eq!(proximity.nearest_b(), [0.0, 1.0, 0.0].into());
2760 assert_eq!(proximity.distance, 1.0);
2761 assert_eq!(proximity.half_axis, [0.0, 0.5, 0.0].into());
2762 assert_eq!(proximity.midpoint, [0.0, 0.5, 0.0].into());
2763 assert_eq!(proximity.normal, -Unit3::axis_y());
2764 let segment = geometry::Segment3::noisy (
2766 [-1.0, 0.0, 0.0].into(),
2767 [ 1.0, 0.0, 0.0].into());
2768 let point = point3 (0.0, 0.0, 0.0);
2769 let proximity = Proximity::query_segment_point (&segment, &point);
2770 assert_eq!(proximity.nearest_a(), [0.0, 0.0, 0.0].into());
2771 assert_eq!(proximity.nearest_b(), [0.0, 0.0, 0.0].into());
2772 assert_eq!(proximity.distance, 0.0);
2773 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
2774 assert_eq!(proximity.midpoint, [0.0, 0.0, 0.0].into());
2775 assert_eq!(proximity.normal, Unit3::axis_z());
2776 let segment = geometry::Segment3::noisy (
2778 [-1.0, 0.0, 0.0].into(),
2779 [ 1.0, 0.0, 0.0].into());
2780 let point = point3 (1.0, 0.0, 0.0);
2781 let proximity = Proximity::query_segment_point (&segment, &point);
2782 assert_eq!(proximity.nearest_a(), [1.0, 0.0, 0.0].into());
2783 assert_eq!(proximity.nearest_b(), [1.0, 0.0, 0.0].into());
2784 assert_eq!(proximity.distance, 0.0);
2785 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
2786 assert_eq!(proximity.midpoint, [1.0, 0.0, 0.0].into());
2787 assert_eq!(proximity.normal, segment.vector().normalize());
2788 let segment = geometry::Segment3::noisy (
2790 [-1.0, 0.0, 0.0].into(),
2791 [ 1.0, 0.0, 0.0].into());
2792 let point = point3 (0.0, 0.0, 0.0);
2793 let mut rng = XorShiftRng::seed_from_u64 (0);
2794 let std_normal = rand_distr::StandardNormal;
2795 let randf = |rng : &mut XorShiftRng| {
2797 let x : f64 = std_normal.sample (rng);
2798 let y : f64 = std_normal.sample (rng);
2799 x / y
2800 };
2801 for _ in 0..10000 {
2802 let translation = vector3 (randf (&mut rng), randf (&mut rng), randf (&mut rng));
2803 let mut segment = segment;
2804 segment.translate (translation);
2805 let point = point + translation;
2806 let proximity = Proximity::query_segment_point (&segment, &point);
2807 assert_eq!(proximity.normal, Unit3::axis_z());
2808 }
2809 }
2810
2811 #[test]
2812 fn segment_segment() {
2813 use approx::RelativeEq;
2814 use rand::SeedableRng;
2815 use rand_distr::Distribution;
2816 let segment1 = geometry::Segment3::noisy (
2818 [-2.0, 2.0, 0.0].into(),
2819 [ 2.0, 2.0, 0.0].into());
2820 let segment2 = geometry::Segment3::noisy (
2821 [-1.0, 0.0, 0.0].into(),
2822 [ 0.0, 0.0, 0.0].into());
2823 let proximity = Proximity::query_segment_segment (&segment1, &segment2);
2824 assert_eq!(proximity.nearest_a(), [-0.5, 2.0, 0.0].into());
2825 assert_eq!(proximity.nearest_b(), [-0.5, 0.0, 0.0].into());
2826 assert_eq!(proximity.distance, 2.0);
2827 assert_eq!(proximity.half_axis, [0.0, -1.0, 0.0].into());
2828 assert_eq!(proximity.midpoint, [-0.5, 1.0, 0.0].into());
2829 assert_eq!(proximity.normal, Unit3::noisy ([0.0, 1.0, 0.0].into()));
2830 let segment1 = geometry::Segment3::noisy (
2831 [-2.0, 2.0, 0.0].into(),
2832 [ 2.0, 2.0, 0.0].into());
2833 let segment2 = geometry::Segment3::noisy (
2834 [ 0.0, 0.0, 0.0].into(),
2835 [-3.0, 0.0, 0.0].into());
2836 let proximity = Proximity::query_segment_segment (&segment1, &segment2);
2837 assert_eq!(proximity.nearest_a(), [-1.0, 2.0, 0.0].into());
2838 assert_eq!(proximity.nearest_b(), [-1.0, 0.0, 0.0].into());
2839 assert_eq!(proximity.distance, 2.0);
2840 assert_eq!(proximity.half_axis, [0.0, -1.0, 0.0].into());
2841 assert_eq!(proximity.midpoint, [-1.0, 1.0, 0.0].into());
2842 assert_eq!(proximity.normal, Unit3::noisy ([0.0, 1.0, 0.0].into()));
2843 let segment1 = geometry::Segment3::noisy (
2844 [-2.0, 2.0, 0.0].into(),
2845 [ 2.0, 2.0, 0.0].into());
2846 let segment2 = geometry::Segment3::noisy (
2847 [ 0.0, 0.0, 0.0].into(),
2848 [ 3.0, 0.0, 0.0].into());
2849 let proximity = Proximity::query_segment_segment (&segment1, &segment2);
2850 assert_eq!(proximity.nearest_a(), [ 1.0, 2.0, 0.0].into());
2851 assert_eq!(proximity.nearest_b(), [ 1.0, 0.0, 0.0].into());
2852 assert_eq!(proximity.distance, 2.0);
2853 assert_eq!(proximity.half_axis, [0.0, -1.0, 0.0].into());
2854 assert_eq!(proximity.midpoint, [ 1.0, 1.0, 0.0].into());
2855 assert_eq!(proximity.normal, Unit3::noisy ([0.0, 1.0, 0.0].into()));
2856 let segment1 = geometry::Segment3::noisy (
2857 [-2.0, 2.0, 0.0].into(),
2858 [ 2.0, 2.0, 0.0].into());
2859 let segment2 = geometry::Segment3::noisy (
2860 [ 3.0, 0.0, 0.0].into(),
2861 [ 0.0, 0.0, 0.0].into());
2862 let proximity = Proximity::query_segment_segment (&segment1, &segment2);
2863 assert_eq!(proximity.nearest_a(), [ 1.0, 2.0, 0.0].into());
2864 assert_eq!(proximity.nearest_b(), [ 1.0, 0.0, 0.0].into());
2865 assert_eq!(proximity.distance, 2.0);
2866 assert_eq!(proximity.half_axis, [0.0, -1.0, 0.0].into());
2867 assert_eq!(proximity.midpoint, [ 1.0, 1.0, 0.0].into());
2868 assert_eq!(proximity.normal, Unit3::noisy ([0.0, 1.0, 0.0].into()));
2869 let segment1 = geometry::Segment3::noisy (
2870 [-2.0, 2.0, 0.0].into(),
2871 [ 2.0, 2.0, 0.0].into());
2872 let segment2 = geometry::Segment3::noisy (
2873 [-3.0, 0.0, 0.0].into(),
2874 [ 0.0, 0.0, 0.0].into());
2875 let proximity = Proximity::query_segment_segment (&segment1, &segment2);
2876 assert_eq!(proximity.nearest_a(), [0.0, 2.0, 0.0].into());
2877 assert_eq!(proximity.nearest_b(), [0.0, 0.0, 0.0].into());
2878 assert_eq!(proximity.distance, 2.0);
2879 assert_eq!(proximity.half_axis, [0.0, -1.0, 0.0].into());
2880 assert_eq!(proximity.midpoint, [0.0, 1.0, 0.0].into());
2881 assert_eq!(proximity.normal, Unit3::noisy ([0.0, 1.0, 0.0].into()));
2882 let segment1 = geometry::Segment3::noisy (
2883 [-2.0, 2.0, 0.0].into(),
2884 [ 2.0, 2.0, 0.0].into());
2885 let segment2 = geometry::Segment3::noisy (
2886 [ 1.0, -1.0, 0.0].into(),
2887 [ 1.0, 1.0, 0.0].into());
2888 let proximity = Proximity::query_segment_segment (&segment1, &segment2);
2889 assert_eq!(proximity.nearest_a(), [ 1.0, 2.0, 0.0].into());
2890 assert_eq!(proximity.nearest_b(), [ 1.0, 1.0, 0.0].into());
2891 assert_eq!(proximity.distance, 1.0);
2892 assert_eq!(proximity.half_axis, [0.0, -0.5, 0.0].into());
2893 assert_eq!(proximity.midpoint, [ 1.0, 1.5, 0.0].into());
2894 assert_eq!(proximity.normal, Unit3::noisy ([0.0, 1.0, 0.0].into()));
2895 let segment1 = geometry::Segment3::noisy (
2896 [-2.0, 2.0, 0.0].into(),
2897 [ 2.0, 2.0, 0.0].into());
2898 let segment2 = geometry::Segment3::noisy (
2899 [-3.0, 0.0, 0.0].into(),
2900 [-3.0, 3.0, 0.0].into());
2901 let proximity = Proximity::query_segment_segment (&segment1, &segment2);
2902 assert_eq!(proximity.nearest_a(), [-2.0, 2.0, 0.0].into());
2903 assert_eq!(proximity.nearest_b(), [-3.0, 2.0, 0.0].into());
2904 assert_eq!(proximity.distance, 1.0);
2905 assert_eq!(proximity.half_axis, [-0.5, 0.0, 0.0].into());
2906 assert_eq!(proximity.midpoint, [-2.5, 2.0, 0.0].into());
2907 assert_eq!(proximity.normal, Unit3::noisy ([1.0, 0.0, 0.0].into()));
2908 let segment1 = geometry::Segment3::noisy (
2909 [-2.0, 2.0, 0.0].into(),
2910 [ 2.0, 2.0, 0.0].into());
2911 let segment2 = geometry::Segment3::noisy (
2912 [ 3.0, 0.0, 0.0].into(),
2913 [ 3.0, 3.0, 0.0].into());
2914 let proximity = Proximity::query_segment_segment (&segment1, &segment2);
2915 assert_eq!(proximity.nearest_a(), [2.0, 2.0, 0.0].into());
2916 assert_eq!(proximity.nearest_b(), [3.0, 2.0, 0.0].into());
2917 assert_eq!(proximity.distance, 1.0);
2918 assert_eq!(proximity.half_axis, [0.5, 0.0, 0.0].into());
2919 assert_eq!(proximity.midpoint, [2.5, 2.0, 0.0].into());
2920 assert_eq!(proximity.normal, Unit3::noisy ([-1.0, 0.0, 0.0].into()));
2921 let segment1 = geometry::Segment3::noisy (
2923 [ 0.0, 1.0, 0.0].into(),
2924 [ 0.0, -1.0, 0.0].into());
2925 let segment2 = geometry::Segment3::noisy (
2926 [ -0.5, -0.5, -0.5].into(),
2927 [ 0.5, 0.5, 0.5].into());
2928 let proximity1 = Proximity::query_segment_segment (&segment1, &segment2);
2929 let mut rng = XorShiftRng::seed_from_u64 (0);
2930 let std_normal = rand_distr::StandardNormal;
2931 let randf = |rng : &mut XorShiftRng| {
2933 let x : f64 = std_normal.sample (rng);
2934 let y : f64 = std_normal.sample (rng);
2935 x / y
2936 };
2937 for _ in 0..10000 {
2938 let translation = vector3 (randf (&mut rng), randf (&mut rng), randf (&mut rng));
2939 let mut segment1 = segment1;
2940 let mut segment2 = segment2;
2941 segment1.translate (translation);
2942 segment2.translate (translation);
2943 let proximity = Proximity::query_segment_segment (&segment1, &segment2);
2944 approx::assert_relative_eq!(*proximity.normal, *proximity1.normal,
2945 max_relative = f64::default_max_relative() * 2.0.powi (10))
2946 }
2947 }
2948
2949 #[test]
2950 fn line_point() {
2951 use rand::SeedableRng;
2952 use rand_distr::Distribution;
2953 let line = geometry::Segment3::noisy (
2955 [-1.0, 0.0, 0.0].into(),
2956 [ 1.0, 0.0, 0.0].into());
2957 let point = point3 (0.0, 1.0, 0.0);
2958 let proximity = Proximity::query_line_point (&line, &point);
2959 assert_eq!(proximity.nearest_a(), [0.0, 0.0, 0.0].into());
2960 assert_eq!(proximity.nearest_b(), [0.0, 1.0, 0.0].into());
2961 assert_eq!(proximity.distance, 1.0);
2962 assert_eq!(proximity.half_axis, [0.0, 0.5, 0.0].into());
2963 assert_eq!(proximity.midpoint, [0.0, 0.5, 0.0].into());
2964 assert_eq!(proximity.normal, -Unit3::axis_y());
2965 let line = geometry::Segment3::noisy (
2967 [-1.0, 0.0, 0.0].into(),
2968 [ 1.0, 0.0, 0.0].into());
2969 let point = point3 (0.0, 0.0, 0.0);
2970 let proximity = Proximity::query_line_point (&line, &point);
2971 assert_eq!(proximity.nearest_a(), [0.0, 0.0, 0.0].into());
2972 assert_eq!(proximity.nearest_b(), [0.0, 0.0, 0.0].into());
2973 assert_eq!(proximity.distance, 0.0);
2974 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
2975 assert_eq!(proximity.midpoint, [0.0, 0.0, 0.0].into());
2976 assert_eq!(proximity.normal, Unit3::axis_z());
2977 let line = geometry::Segment3::noisy (
2979 [-1.0, 0.0, 0.0].into(),
2980 [ 1.0, 0.0, 0.0].into());
2981 let point = point3 (1.0, 0.0, 0.0);
2982 let proximity = Proximity::query_line_point (&line, &point);
2983 assert_eq!(proximity.nearest_a(), [1.0, 0.0, 0.0].into());
2984 assert_eq!(proximity.nearest_b(), [1.0, 0.0, 0.0].into());
2985 assert_eq!(proximity.distance, 0.0);
2986 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
2987 assert_eq!(proximity.midpoint, [1.0, 0.0, 0.0].into());
2988 assert_eq!(proximity.normal, Unit3::axis_z());
2989 let line = geometry::Segment3::noisy (
2991 [-1.0, 0.0, 0.0].into(),
2992 [ 1.0, 0.0, 0.0].into());
2993 let point = point3 (0.0, 0.0, 0.0);
2994 let mut rng = XorShiftRng::seed_from_u64 (0);
2995 let std_normal = rand_distr::StandardNormal;
2996 let randf = |rng : &mut XorShiftRng| {
2998 let x : f64 = std_normal.sample (rng);
2999 let y : f64 = std_normal.sample (rng);
3000 x / y
3001 };
3002 for _ in 0..10000 {
3003 let translation = vector3 (randf (&mut rng), randf (&mut rng), randf (&mut rng));
3004 let mut line = line;
3005 line.translate (translation);
3006 let point = point + translation;
3007 let proximity = Proximity::query_line_point (&line, &point);
3008 assert_eq!(proximity.normal, Unit3::axis_z());
3009 }
3010 }
3011
3012 #[test]
3013 fn line_segment() {
3014 use approx::RelativeEq;
3015 use rand::SeedableRng;
3016 use rand_distr::Distribution;
3017 let line = geometry::Segment3::noisy (
3019 [-2.0, 0.0, 0.0].into(),
3020 [ 2.0, 0.0, 0.0].into());
3021 let segment = geometry::Segment3::noisy (
3022 [-2.0, 2.0, 0.0].into(),
3023 [ 2.0, 2.0, 0.0].into());
3024 let proximity = Proximity::query_line_segment (&line, &segment);
3025 assert_eq!(proximity.nearest_a(), [-2.0, 0.0, 0.0].into());
3026 assert_eq!(proximity.nearest_b(), [-2.0, 2.0, 0.0].into());
3027 assert_eq!(proximity.distance, 2.0);
3028 assert_eq!(proximity.half_axis, [0.0, 1.0, 0.0].into());
3029 assert_eq!(proximity.midpoint, [-2.0, 1.0, 0.0].into());
3030 assert_eq!(proximity.normal, -Unit3::axis_y());
3031 let line = geometry::Segment3::noisy (
3032 [-5.0, 0.0, 0.0].into(),
3033 [-2.0, 0.0, 0.0].into());
3034 let segment = geometry::Segment3::noisy (
3035 [-2.0, 2.0, 0.0].into(),
3036 [ 2.0, 2.0, 0.0].into());
3037 let proximity = Proximity::query_line_segment (&line, &segment);
3038 assert_eq!(proximity.nearest_a(), [-2.0, 0.0, 0.0].into());
3039 assert_eq!(proximity.nearest_b(), [-2.0, 2.0, 0.0].into());
3040 assert_eq!(proximity.distance, 2.0);
3041 assert_eq!(proximity.half_axis, [0.0, 1.0, 0.0].into());
3042 assert_eq!(proximity.midpoint, [-2.0, 1.0, 0.0].into());
3043 assert_eq!(proximity.normal, -Unit3::axis_y());
3044 let line = geometry::Segment3::noisy (
3046 [0.0, -1.0, 0.0].into(),
3047 [0.0, 1.0, 0.0].into());
3048 let segment = geometry::Segment3::noisy (
3049 [1.0, 1.0, 0.0].into(),
3050 [3.0, 1.0, 0.0].into());
3051 let proximity = Proximity::query_line_segment (&line, &segment);
3052 assert_eq!(proximity.nearest_a(), [0.0, 1.0, 0.0].into());
3053 assert_eq!(proximity.nearest_b(), [1.0, 1.0, 0.0].into());
3054 assert_eq!(proximity.distance, 1.0);
3055 assert_eq!(proximity.half_axis, [0.5, 0.0, 0.0].into());
3056 assert_eq!(proximity.midpoint, [0.5, 1.0, 0.0].into());
3057 assert_eq!(proximity.normal, -Unit3::axis_x());
3058 let line = geometry::Segment3::noisy (
3059 [ 0.0, -1.0, 0.0].into(),
3060 [ 0.0, 1.0, 0.0].into());
3061 let segment = geometry::Segment3::noisy (
3062 [-3.0, 1.0, 0.0].into(),
3063 [-1.0, 1.0, 0.0].into());
3064 let proximity = Proximity::query_line_segment (&line, &segment);
3065 assert_eq!(proximity.nearest_a(), [ 0.0, 1.0, 0.0].into());
3066 assert_eq!(proximity.nearest_b(), [-1.0, 1.0, 0.0].into());
3067 assert_eq!(proximity.distance, 1.0);
3068 assert_eq!(proximity.half_axis, [-0.5, 0.0, 0.0].into());
3069 assert_eq!(proximity.midpoint, [-0.5, 1.0, 0.0].into());
3070 assert_eq!(proximity.normal, Unit3::axis_x());
3071 let line = geometry::Segment3::noisy (
3073 [ 0.0, -1.0, 0.0].into(),
3074 [ 0.0, 1.0, 0.0].into());
3075 let segment = geometry::Segment3::noisy (
3076 [-2.0, 2.0, 1.0].into(),
3077 [ 2.0, 2.0, 1.0].into());
3078 let proximity = Proximity::query_line_segment (&line, &segment);
3079 assert_eq!(proximity.nearest_a(), [ 0.0, 2.0, 0.0].into());
3080 assert_eq!(proximity.nearest_b(), [ 0.0, 2.0, 1.0].into());
3081 assert_eq!(proximity.distance, 1.0);
3082 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.5].into());
3083 assert_eq!(proximity.midpoint, [0.0, 2.0, 0.5].into());
3084 assert_eq!(proximity.normal, -Unit3::axis_z());
3085 let line = geometry::Segment3::noisy (
3087 [ 0.0, -1.0, 0.0].into(),
3088 [ 0.0, 1.0, 0.0].into());
3089 let segment = geometry::Segment3::noisy (
3090 [-2.0, 2.0, 0.0].into(),
3091 [ 2.0, 2.0, 0.0].into());
3092 let proximity = Proximity::query_line_segment (&line, &segment);
3093 assert_eq!(proximity.nearest_a(), [ 0.0, 2.0, 0.0].into());
3094 assert_eq!(proximity.nearest_b(), [ 0.0, 2.0, 0.0].into());
3095 assert_eq!(proximity.distance, 0.0);
3096 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3097 assert_eq!(proximity.midpoint, [0.0, 2.0, 0.0].into());
3098 assert_eq!(proximity.normal, Unit3::axis_z());
3099 let line = geometry::Segment3::noisy (
3101 [-2.0, -1.0, 0.0].into(),
3102 [-2.0, 1.0, 0.0].into());
3103 let segment = geometry::Segment3::noisy (
3104 [-2.0, 2.0, 0.0].into(),
3105 [ 2.0, 2.0, 0.0].into());
3106 let proximity = Proximity::query_line_segment (&line, &segment);
3107 assert_eq!(proximity.nearest_a(), [-2.0, 2.0, 0.0].into());
3108 assert_eq!(proximity.nearest_b(), [-2.0, 2.0, 0.0].into());
3109 assert_eq!(proximity.distance, 0.0);
3110 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3111 assert_eq!(proximity.midpoint, [-2.0, 2.0, 0.0].into());
3112 assert_eq!(proximity.normal, -Unit3::axis_x());
3113 let line = geometry::Segment3::noisy (
3114 [-2.0, -1.0, 0.0].into(),
3115 [-2.0, 1.0, 0.0].into());
3116 let segment = geometry::Segment3::noisy (
3117 [-2.0, 2.0, 0.0].into(),
3118 [ 2.0, -2.0, 0.0].into());
3119 let proximity = Proximity::query_line_segment (&line, &segment);
3120 assert_eq!(proximity.nearest_a(), [-2.0, 2.0, 0.0].into());
3121 assert_eq!(proximity.nearest_b(), [-2.0, 2.0, 0.0].into());
3122 assert_eq!(proximity.distance, 0.0);
3123 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3124 assert_eq!(proximity.midpoint, [-2.0, 2.0, 0.0].into());
3125 assert_eq!(proximity.normal, -Unit3::axis_x());
3126 let line = geometry::Segment3::noisy (
3128 [ 2.0, -1.0, 0.0].into(),
3129 [ 2.0, 1.0, 0.0].into());
3130 let segment = geometry::Segment3::noisy (
3131 [-2.0, 2.0, 0.0].into(),
3132 [ 2.0, 2.0, 0.0].into());
3133 let proximity = Proximity::query_line_segment (&line, &segment);
3134 assert_eq!(proximity.nearest_a(), [2.0, 2.0, 0.0].into());
3135 assert_eq!(proximity.nearest_b(), [2.0, 2.0, 0.0].into());
3136 assert_eq!(proximity.distance, 0.0);
3137 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3138 assert_eq!(proximity.midpoint, [2.0, 2.0, 0.0].into());
3139 assert_eq!(proximity.normal, Unit3::axis_x());
3140 let line = geometry::Segment3::noisy (
3141 [ 2.0, -1.0, 0.0].into(),
3142 [ 2.0, 1.0, 0.0].into());
3143 let segment = geometry::Segment3::noisy (
3144 [-2.0, 2.0, 0.0].into(),
3145 [ 2.0, 0.0, 0.0].into());
3146 let proximity = Proximity::query_line_segment (&line, &segment);
3147 assert_eq!(proximity.nearest_a(), [2.0, 0.0, 0.0].into());
3148 assert_eq!(proximity.nearest_b(), [2.0, 0.0, 0.0].into());
3149 assert_eq!(proximity.distance, 0.0);
3150 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3151 assert_eq!(proximity.midpoint, [2.0, 0.0, 0.0].into());
3152 assert_eq!(proximity.normal, Unit3::axis_x());
3153 let line = geometry::Segment3::noisy (
3155 [-1.0, 2.0, 0.0].into(),
3156 [ 0.0, 2.0, 0.0].into());
3157 let segment = geometry::Segment3::noisy (
3158 [-2.0, 2.0, 0.0].into(),
3159 [ 2.0, 2.0, 0.0].into());
3160 let proximity = Proximity::query_line_segment (&line, &segment);
3161 assert_eq!(proximity.nearest_a(), [-2.0, 2.0, 0.0].into());
3162 assert_eq!(proximity.nearest_b(), [-2.0, 2.0, 0.0].into());
3163 assert_eq!(proximity.distance, 0.0);
3164 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3165 assert_eq!(proximity.midpoint, [-2.0, 2.0, 0.0].into());
3166 assert_eq!(proximity.normal, Unit3::axis_z());
3167 let line = geometry::Segment3::noisy (
3169 [ -0.5, -0.5, -0.5].into(),
3170 [ 0.5, 0.5, 0.5].into());
3171 let segment = geometry::Segment3::noisy (
3172 [ 0.0, 1.0, 0.0].into(),
3173 [ 0.0, -1.0, 0.0].into());
3174 let proximity1 = Proximity::query_line_segment (&line, &segment);
3175 let mut rng = XorShiftRng::seed_from_u64 (0);
3176 let std_normal = rand_distr::StandardNormal;
3177 let randf = |rng : &mut XorShiftRng| {
3179 let x : f64 = std_normal.sample (rng);
3180 let y : f64 = std_normal.sample (rng);
3181 x / y
3182 };
3183 for _ in 0..10000 {
3184 let translation = vector3 (randf (&mut rng), randf (&mut rng), randf (&mut rng));
3185 let mut line = line;
3186 let mut segment = segment;
3187 line.translate (translation);
3188 segment.translate (translation);
3189 let proximity = Proximity::query_line_segment (&line, &segment);
3190 approx::assert_relative_eq!(*proximity.normal, *proximity1.normal,
3191 max_relative = f64::default_max_relative() * 2.0.powi (10))
3192 }
3193 }
3194
3195 #[test]
3196 fn line_line() {
3197 use approx::RelativeEq;
3198 use rand::SeedableRng;
3199 use rand_distr::Distribution;
3200 let line_a = geometry::Segment3::noisy (
3202 [-2.0, 0.0, 0.0].into(),
3203 [ 2.0, 0.0, 0.0].into());
3204 let line_b = geometry::Segment3::noisy (
3205 [-2.0, 2.0, 0.0].into(),
3206 [ 2.0, 2.0, 0.0].into());
3207 let proximity = Proximity::query_line_line (&line_a, &line_b);
3208 assert_eq!(proximity.nearest_a(), [-2.0, 0.0, 0.0].into());
3209 assert_eq!(proximity.nearest_b(), [-2.0, 2.0, 0.0].into());
3210 assert_eq!(proximity.distance, 2.0);
3211 assert_eq!(proximity.half_axis, [0.0, 1.0, 0.0].into());
3212 assert_eq!(proximity.midpoint, [-2.0, 1.0, 0.0].into());
3213 assert_eq!(proximity.normal, -Unit3::axis_y());
3214 let line_a = geometry::Segment3::noisy (
3215 [-5.0, 0.0, 0.0].into(),
3216 [-2.0, 0.0, 0.0].into());
3217 let line_b = geometry::Segment3::noisy (
3218 [-2.0, 2.0, 0.0].into(),
3219 [ 2.0, 2.0, 0.0].into());
3220 let proximity = Proximity::query_line_line (&line_a, &line_b);
3221 assert_eq!(proximity.nearest_a(), [-2.0, 0.0, 0.0].into());
3222 assert_eq!(proximity.nearest_b(), [-2.0, 2.0, 0.0].into());
3223 assert_eq!(proximity.distance, 2.0);
3224 assert_eq!(proximity.half_axis, [0.0, 1.0, 0.0].into());
3225 assert_eq!(proximity.midpoint, [-2.0, 1.0, 0.0].into());
3226 assert_eq!(proximity.normal, -Unit3::axis_y());
3227 let line_a = geometry::Segment3::noisy (
3229 [0.0, -1.0, 0.0].into(),
3230 [0.0, 1.0, 0.0].into());
3231 let line_b = geometry::Segment3::noisy (
3232 [1.0, 1.0, 0.0].into(),
3233 [3.0, 1.0, 0.0].into());
3234 let proximity = Proximity::query_line_line (&line_a, &line_b);
3235 assert_eq!(proximity.nearest_a(), [0.0, 1.0, 0.0].into());
3236 assert_eq!(proximity.nearest_b(), [0.0, 1.0, 0.0].into());
3237 assert_eq!(proximity.distance, 0.0);
3238 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3239 assert_eq!(proximity.midpoint, [0.0, 1.0, 0.0].into());
3240 assert_eq!(proximity.normal, -Unit3::axis_z());
3241 let line_a = geometry::Segment3::noisy (
3242 [ 0.0, -1.0, 0.0].into(),
3243 [ 0.0, 1.0, 0.0].into());
3244 let line_b = geometry::Segment3::noisy (
3245 [-3.0, 1.0, 0.0].into(),
3246 [-1.0, 1.0, 0.0].into());
3247 let proximity = Proximity::query_line_line (&line_a, &line_b);
3248 assert_eq!(proximity.nearest_a(), [0.0, 1.0, 0.0].into());
3249 assert_eq!(proximity.nearest_b(), [0.0, 1.0, 0.0].into());
3250 assert_eq!(proximity.distance, 0.0);
3251 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3252 assert_eq!(proximity.midpoint, [0.0, 1.0, 0.0].into());
3253 assert_eq!(proximity.normal, -Unit3::axis_z());
3254 let line_a = geometry::Segment3::noisy (
3256 [ 0.0, -1.0, 0.0].into(),
3257 [ 0.0, 1.0, 0.0].into());
3258 let line_b = geometry::Segment3::noisy (
3259 [-2.0, 2.0, 1.0].into(),
3260 [ 2.0, 2.0, 1.0].into());
3261 let proximity = Proximity::query_line_line (&line_a, &line_b);
3262 assert_eq!(proximity.nearest_a(), [ 0.0, 2.0, 0.0].into());
3263 assert_eq!(proximity.nearest_b(), [ 0.0, 2.0, 1.0].into());
3264 assert_eq!(proximity.distance, 1.0);
3265 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.5].into());
3266 assert_eq!(proximity.midpoint, [0.0, 2.0, 0.5].into());
3267 assert_eq!(proximity.normal, -Unit3::axis_z());
3268 let line_a = geometry::Segment3::noisy (
3270 [ 0.0, -1.0, 0.0].into(),
3271 [ 0.0, 1.0, 0.0].into());
3272 let line_b = geometry::Segment3::noisy (
3273 [-2.0, 2.0, 0.0].into(),
3274 [ 2.0, 2.0, 0.0].into());
3275 let proximity = Proximity::query_line_line (&line_a, &line_b);
3276 assert_eq!(proximity.nearest_a(), [ 0.0, 2.0, 0.0].into());
3277 assert_eq!(proximity.nearest_b(), [ 0.0, 2.0, 0.0].into());
3278 assert_eq!(proximity.distance, 0.0);
3279 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3280 assert_eq!(proximity.midpoint, [0.0, 2.0, 0.0].into());
3281 assert_eq!(proximity.normal, -Unit3::axis_z());
3282 let line_a = geometry::Segment3::noisy (
3284 [-2.0, -1.0, 0.0].into(),
3285 [-2.0, 1.0, 0.0].into());
3286 let line_b = geometry::Segment3::noisy (
3287 [-2.0, 2.0, 0.0].into(),
3288 [ 2.0, 2.0, 0.0].into());
3289 let proximity = Proximity::query_line_line (&line_a, &line_b);
3290 assert_eq!(proximity.nearest_a(), [-2.0, 2.0, 0.0].into());
3291 assert_eq!(proximity.nearest_b(), [-2.0, 2.0, 0.0].into());
3292 assert_eq!(proximity.distance, 0.0);
3293 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3294 assert_eq!(proximity.midpoint, [-2.0, 2.0, 0.0].into());
3295 assert_eq!(proximity.normal, -Unit3::axis_z());
3296 let line_a = geometry::Segment3::noisy (
3297 [-2.0, -1.0, 0.0].into(),
3298 [-2.0, 1.0, 0.0].into());
3299 let line_b = geometry::Segment3::noisy (
3300 [-2.0, 2.0, 0.0].into(),
3301 [ 2.0, -2.0, 0.0].into());
3302 let proximity = Proximity::query_line_line (&line_a, &line_b);
3303 assert_eq!(proximity.nearest_a(), [-2.0, 2.0, 0.0].into());
3304 assert_eq!(proximity.nearest_b(), [-2.0, 2.0, 0.0].into());
3305 assert_eq!(proximity.distance, 0.0);
3306 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3307 assert_eq!(proximity.midpoint, [-2.0, 2.0, 0.0].into());
3308 assert_eq!(proximity.normal, -Unit3::axis_z());
3309 let line_a = geometry::Segment3::noisy (
3311 [ 2.0, -1.0, 0.0].into(),
3312 [ 2.0, 1.0, 0.0].into());
3313 let line_b = geometry::Segment3::noisy (
3314 [-2.0, 2.0, 0.0].into(),
3315 [ 2.0, 2.0, 0.0].into());
3316 let proximity = Proximity::query_line_line (&line_a, &line_b);
3317 assert_eq!(proximity.nearest_a(), [2.0, 2.0, 0.0].into());
3318 assert_eq!(proximity.nearest_b(), [2.0, 2.0, 0.0].into());
3319 assert_eq!(proximity.distance, 0.0);
3320 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3321 assert_eq!(proximity.midpoint, [2.0, 2.0, 0.0].into());
3322 assert_eq!(proximity.normal, -Unit3::axis_z());
3323 let line_a = geometry::Segment3::noisy (
3324 [ 2.0, -1.0, 0.0].into(),
3325 [ 2.0, 1.0, 0.0].into());
3326 let line_b = geometry::Segment3::noisy (
3327 [-2.0, 2.0, 0.0].into(),
3328 [ 2.0, 0.0, 0.0].into());
3329 let proximity = Proximity::query_line_line (&line_a, &line_b);
3330 assert_eq!(proximity.nearest_a(), [2.0, 0.0, 0.0].into());
3331 assert_eq!(proximity.nearest_b(), [2.0, 0.0, 0.0].into());
3332 assert_eq!(proximity.distance, 0.0);
3333 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3334 assert_eq!(proximity.midpoint, [2.0, 0.0, 0.0].into());
3335 assert_eq!(proximity.normal, -Unit3::axis_z());
3336 let line_a = geometry::Segment3::noisy (
3338 [-1.0, 2.0, 0.0].into(),
3339 [ 0.0, 2.0, 0.0].into());
3340 let line_b = geometry::Segment3::noisy (
3341 [-2.0, 2.0, 0.0].into(),
3342 [ 2.0, 2.0, 0.0].into());
3343 let proximity = Proximity::query_line_line (&line_a, &line_b);
3344 assert_eq!(proximity.nearest_a(), [-2.0, 2.0, 0.0].into());
3345 assert_eq!(proximity.nearest_b(), [-2.0, 2.0, 0.0].into());
3346 assert_eq!(proximity.distance, 0.0);
3347 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3348 assert_eq!(proximity.midpoint, [-2.0, 2.0, 0.0].into());
3349 assert_eq!(proximity.normal, Unit3::axis_z());
3350 let line_a = geometry::Segment3::noisy (
3352 [ -0.5, -0.5, -0.5].into(),
3353 [ 0.5, 0.5, 0.5].into());
3354 let line_b = geometry::Segment3::noisy (
3355 [ 0.0, 1.0, 0.0].into(),
3356 [ 0.0, -1.0, 0.0].into());
3357 let proximity1 = Proximity::query_line_line (&line_a, &line_b);
3358 let mut rng = XorShiftRng::seed_from_u64 (0);
3359 let std_normal = rand_distr::StandardNormal;
3360 let randf = |rng : &mut XorShiftRng| {
3362 let x : f64 = std_normal.sample (rng);
3363 let y : f64 = std_normal.sample (rng);
3364 x / y
3365 };
3366 for _ in 0..10000 {
3367 let translation = vector3 (randf (&mut rng), randf (&mut rng), randf (&mut rng));
3368 let mut line_a = line_a;
3369 let mut line_b = line_b;
3370 line_a.translate (translation);
3371 line_b.translate (translation);
3372 let proximity = Proximity::query_line_line (&line_a, &line_b);
3373 approx::assert_relative_eq!(*proximity.normal, *proximity1.normal,
3374 max_relative = f64::default_max_relative() * 2.0.powi (10))
3375 }
3376 }
3377
3378 #[test]
3379 fn triangle_point() {
3380 use approx::RelativeEq;
3381 use rand::SeedableRng;
3382 use rand_distr::Distribution;
3383 let triangle = geometry::Triangle3::noisy (
3384 [-1.0, -1.0, 0.0].into(),
3385 [ 1.0, -1.0, 0.0].into(),
3386 [ 0.0, 1.0, 0.0].into());
3387 let point = point3 (0.0, 0.0, 0.0);
3388 let proximity = Proximity::query_triangle_point (&triangle, &point);
3389 assert_eq!(proximity.nearest_a(), [0.0, 0.0, 0.0].into());
3390 assert_eq!(proximity.nearest_b(), [0.0, 0.0, 0.0].into());
3391 assert_eq!(proximity.distance, 0.0);
3392 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3393 assert_eq!(proximity.midpoint, [0.0, 0.0, 0.0].into());
3394 assert_eq!(proximity.normal, Unit3::axis_z());
3395 let triangle = geometry::Triangle3::noisy (
3396 [-1.0, -1.0, 0.0].into(),
3397 [ 1.0, -1.0, 0.0].into(),
3398 [ 0.0, 1.0, 0.0].into());
3399 let point = point3 (0.5, 0.0, 0.0);
3400 let proximity = Proximity::query_triangle_point (&triangle, &point);
3401 assert_eq!(proximity.nearest_a(), [0.5, 0.0, 0.0].into());
3402 assert_eq!(proximity.nearest_b(), [0.5, 0.0, 0.0].into());
3403 assert_eq!(proximity.distance, 0.0);
3404 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3405 assert_eq!(proximity.midpoint, [0.5, 0.0, 0.0].into());
3406 assert_eq!(proximity.normal, Unit3::normalize ([-2.0, -1.0, 0.0].into()));
3407 let triangle = geometry::Triangle3::noisy (
3408 [ 0.0, -2.0, 3.5].into(),
3409 [ 2.0, 2.0, 3.5].into(),
3410 [-2.0, 2.0, 3.5].into());
3411 let point = point3 (0.0, 0.0, 2.0);
3412 let proximity = Proximity::query_triangle_point (&triangle, &point);
3413 assert_eq!(proximity.distance, 1.5);
3414 assert_eq!(proximity.half_axis, [0.0, 0.0, -0.75].into());
3415 assert_eq!(proximity.midpoint, [0.0, 0.0, 2.75].into());
3416 assert_eq!(proximity.normal, Unit3::axis_z());
3417 assert_eq!(proximity.nearest_a(), [0.0, 0.0, 3.5].into());
3418 assert_eq!(proximity.nearest_b(), [0.0, 0.0, 2.0].into());
3419 let triangle = geometry::Triangle3::noisy (
3421 [-1.0, -1.0, 0.0].into(),
3422 [ 1.0, -1.0, 0.0].into(),
3423 [ 0.0, 1.0, 0.0].into());
3424 let point = point3 (1.0, 0.0, 0.0);
3425 let proximity1 = Proximity::query_triangle_point (&triangle, &point);
3426 let mut rng = XorShiftRng::seed_from_u64 (0);
3427 let std_normal = rand_distr::StandardNormal;
3428 let randf = |rng : &mut XorShiftRng| {
3430 let x : f64 = std_normal.sample (rng);
3431 let y : f64 = std_normal.sample (rng);
3432 x / y
3433 };
3434 for _ in 0..10000 {
3435 let translation = vector3 (randf (&mut rng), randf (&mut rng), randf (&mut rng));
3436 let mut triangle = triangle;
3437 triangle.translate (translation);
3438 let point = point + translation;
3439 let proximity = Proximity::query_triangle_point (&triangle, &point);
3440 approx::assert_relative_eq!(*proximity.normal, *proximity1.normal,
3441 max_relative = f64::default_max_relative() * 2.0.powi (12));
3442 }
3443 }
3444
3445 #[test]
3446 fn triangle_segment() {
3447 use approx::RelativeEq;
3448 use rand::SeedableRng;
3449 use rand_distr::Distribution;
3450 let mut triangle = geometry::Triangle3::noisy (
3451 [-1.0, -1.0, 0.0].into(),
3452 [ 1.0, -1.0, 0.0].into(),
3453 [ 0.0, 1.0, 0.0].into());
3454 let mut segment = geometry::Segment3::noisy (
3455 [-2.0, -2.0, -0.01].into(),
3456 [ 2.0, 2.0, 0.01].into());
3457 let proximity = Proximity::query_triangle_segment (&triangle, &segment);
3458 triangle.translate (proximity.half_axis);
3459 segment.translate (-proximity.half_axis);
3460 let proximity = Proximity::query_triangle_segment (&triangle, &segment);
3461 approx::assert_abs_diff_eq!(proximity.distance, 0.0,
3462 epsilon = f64::default_epsilon() * 2.0);
3463 let mut triangle = geometry::Triangle3::noisy (
3464 [-1.0, -1.0, 0.0].into(),
3465 [ 1.0, -1.0, 0.0].into(),
3466 [ 0.0, 1.0, 0.0].into());
3467 let mut segment = geometry::Segment3::noisy (
3468 [-2.0, 2.0, -10.0].into(),
3469 [ 2.0, -2.0, 10.0].into());
3470 let proximity = Proximity::query_triangle_segment (&triangle, &segment);
3471 triangle.translate (proximity.half_axis);
3472 segment.translate (-proximity.half_axis);
3473 let proximity = Proximity::query_triangle_segment (&triangle, &segment);
3474 approx::assert_abs_diff_eq!(proximity.distance, 0.0,
3475 epsilon = f64::default_epsilon() * 2.0);
3476 let triangle = geometry::Triangle3::noisy (
3478 [-1.0, -1.0, 0.0].into(),
3479 [ 1.0, -1.0, 0.0].into(),
3480 [ 0.0, 1.0, 0.0].into());
3481 let segment = geometry::Segment3::noisy (
3482 [-1.5, 0.0, -2.0].into(),
3483 [ 2.0, 0.0, 2.0].into());
3484 let proximity1 = Proximity::query_triangle_segment (&triangle, &segment);
3485 println!("normal: {}", *proximity1.normal);
3486 let mut rng = XorShiftRng::seed_from_u64 (0);
3487 let std_normal = rand_distr::StandardNormal;
3488 let randf = |rng : &mut XorShiftRng| {
3490 let x : f64 = std_normal.sample (rng);
3491 let y : f64 = std_normal.sample (rng);
3492 x / y
3493 };
3494 for _ in 0..10000 {
3495 let translation = vector3 (randf (&mut rng), randf (&mut rng), randf (&mut rng));
3496 let mut triangle = triangle;
3497 let mut segment = segment;
3498 triangle.translate (translation);
3499 segment.translate (translation);
3500 let proximity = Proximity::query_triangle_segment (&triangle, &segment);
3501 approx::assert_relative_eq!(*proximity.normal, *proximity1.normal,
3502 max_relative = f64::default_max_relative() * 2.0.powi (10))
3503 }
3504 }
3505
3506 #[test]
3507 fn triangle_line() {
3508 use approx::RelativeEq;
3509 use rand::SeedableRng;
3510 use rand_distr::Distribution;
3511 let triangle = geometry::Triangle3::noisy (
3512 [-1.0, -1.0, 0.0].into(),
3513 [ 1.0, -1.0, 0.0].into(),
3514 [ 0.0, 1.0, 0.0].into()
3515 );
3516 let line = geometry::Segment3::noisy (
3517 [-2.0, 2.0, 0.0].into(),
3518 [ 2.0, 2.0, 0.0].into());
3519 let proximity = Proximity::query_triangle_line (&triangle, &line);
3520 assert_eq!(proximity.nearest_a(), [0.0, 1.0, 0.0].into());
3521 assert_eq!(proximity.nearest_b(), [0.0, 2.0, 0.0].into());
3522 assert_eq!(proximity.distance, 1.0);
3523 assert_eq!(proximity.half_axis, [0.0, 0.5, 0.0].into());
3524 assert_eq!(proximity.midpoint, [0.0, 1.5, 0.0].into());
3525 assert_eq!(proximity.normal, -Unit3::axis_y());
3526 let triangle = geometry::Triangle3::noisy (
3528 [-1.0, -1.0, 0.0].into(),
3529 [ 1.0, -1.0, 0.0].into(),
3530 [ 0.0, 1.0, 0.0].into());
3531 let line = geometry::Segment3::noisy (
3532 [-2.0, 0.0, 0.0].into(),
3533 [ 2.0, 0.0, 0.0].into());
3534 let proximity1 = Proximity::query_triangle_line (&triangle, &line);
3535 let mut rng = XorShiftRng::seed_from_u64 (0);
3536 let std_normal = rand_distr::StandardNormal;
3537 let randf = |rng : &mut XorShiftRng| {
3539 let x : f64 = std_normal.sample (rng);
3540 let y : f64 = std_normal.sample (rng);
3541 x / y
3542 };
3543 for _ in 0..10000 {
3544 let translation = vector3 (randf (&mut rng), randf (&mut rng), randf (&mut rng));
3545 let mut triangle = triangle;
3546 let mut line = line;
3547 triangle.translate (translation);
3548 line.translate (translation);
3549 let proximity = Proximity::query_triangle_line (&triangle, &line);
3550 approx::assert_relative_eq!(*proximity.normal, *proximity1.normal,
3551 max_relative = f64::default_max_relative() * 2.0.powi (10))
3552 }
3553 }
3554
3555 #[test]
3556 #[expect(clippy::unreadable_literal)]
3557 fn triangle_triangle() {
3558 use approx::RelativeEq;
3559 use rand::SeedableRng;
3560 use rand_distr::Distribution;
3561 let triangle_a = geometry::Triangle3::noisy (
3562 [-3.0, 0.0, 0.0].into(),
3563 [-1.0, 0.0, 0.0].into(),
3564 [-2.0, 2.0, 0.0].into());
3565 let triangle_b = geometry::Triangle3::noisy (
3566 [ 3.0, 0.0, 0.0].into(),
3567 [ 1.0, 0.0, 0.0].into(),
3568 [ 2.0, 2.0, 0.0].into());
3569 let proximity = Proximity::query_triangle_triangle (&triangle_a, &triangle_b);
3570 assert_eq!(proximity, Proximity {
3571 distance: 2.0,
3572 half_axis: [1.0, 0.0, 0.0].into(),
3573 midpoint: [0.0, 0.0, 0.0].into(),
3574 normal: -Unit3::axis_x()
3575 });
3576 let triangle_a = geometry::Triangle3::noisy (
3577 [-2.0, -2.0, 0.0].into(),
3578 [ 2.0, -2.0, 0.0].into(),
3579 [ 0.0, 2.0, 0.0].into());
3580 let triangle_b = geometry::Triangle3::noisy (
3581 [-0.5, 0.0, -0.1].into(),
3582 [ 0.5, 0.0, -0.1].into(),
3583 [ 0.0, 0.0, 2.0].into());
3584 let proximity = Proximity::query_triangle_triangle (&triangle_a, &triangle_b);
3585 assert_eq!(proximity.distance, -0.1);
3586 approx::assert_relative_eq!(proximity.half_axis, [0.0, 0.0, -0.05].into());
3587 let triangle_a = geometry::Triangle3::noisy (
3588 [-2.0, -2.0, 0.0].into(),
3589 [ 2.0, -2.0, 0.0].into(),
3590 [ 0.0, 2.0, 0.0].into());
3591 let triangle_b = geometry::Triangle3::noisy (
3592 [-1.0, 0.0, -0.1].into(),
3593 [ 1.0, 0.0, -0.1].into(),
3594 [ 0.0, 0.0, 2.0].into());
3595 let proximity = Proximity::query_triangle_triangle (&triangle_a, &triangle_b);
3596 assert_eq!(proximity.distance, -0.1);
3597 assert_eq!(proximity.half_axis, [0.0, 0.0, -0.05].into());
3598 let mut triangle_a = geometry::Triangle3::noisy (
3599 [-2.0, -2.0, 0.0].into(),
3600 [ 2.0, -2.0, 0.0].into(),
3601 [ 0.0, 2.0, 0.0].into());
3602 let mut triangle_b = geometry::Triangle3::noisy (
3603 [ 0.0, 0.0, -2.0].into(),
3604 [-1.0, 0.0, 2.0].into(),
3605 [ 1.0, 0.0, 2.0].into());
3606 let proximity = Proximity::query_triangle_triangle (&triangle_a, &triangle_b);
3607 assert_eq!(proximity, Proximity {
3608 distance: -1.3093073414159542,
3609 half_axis: [0.5714285714285714, -0.2857142857142857, -0.1428571428571429].into(),
3610 midpoint: [-0.14285714285714285, 0.28571428571428564, -0.1428571428571429].into(),
3611 normal: Unit3::noisy (
3612 [0.8728715609439696, -0.4364357804719848, -0.2182178902359924].into())
3613 });
3614 triangle_a.translate (proximity.half_axis * 0.5);
3616 triangle_b.translate (-proximity.half_axis * 0.5);
3617 let proximity1 = Proximity::query_triangle_triangle (&triangle_a, &triangle_b);
3618 approx::assert_relative_eq!(proximity1.distance * 2.0, proximity.distance,
3619 max_relative = f64::default_max_relative() * 2.0);
3620 approx::assert_relative_eq!(proximity1.half_axis * 2.0, proximity.half_axis,
3621 max_relative = f64::default_max_relative() * 16.0);
3622 approx::assert_relative_eq!(proximity1.midpoint, proximity.midpoint,
3623 max_relative = f64::default_max_relative() * 8.0);
3624 approx::assert_relative_eq!(*proximity1.normal, *proximity.normal);
3625 let mut rng = XorShiftRng::seed_from_u64 (0);
3627 let std_normal = rand_distr::StandardNormal;
3628 let randf = |rng : &mut XorShiftRng| {
3630 let x : f64 = std_normal.sample (rng);
3631 let y : f64 = std_normal.sample (rng);
3632 x / y
3633 };
3634 for _i in 0..5000 {
3635 let translation = vector3 (randf (&mut rng), randf (&mut rng), randf (&mut rng));
3636 let mut triangle_a = triangle_a;
3637 let mut triangle_b = triangle_b;
3638 triangle_a.translate (translation);
3639 triangle_b.translate (translation);
3640 let proximity = Proximity::query_triangle_triangle (&triangle_a, &triangle_b);
3641 approx::assert_relative_eq!(*proximity.normal, *proximity1.normal,
3642 max_relative = f64::default_max_relative() * 2.0.powi (10))
3643 }
3644 }
3645
3646 #[test]
3647 #[expect(clippy::suboptimal_flops)]
3648 fn distance_query() {
3649 use rand::{RngExt, SeedableRng};
3650 use approx::{assert_relative_eq, assert_ulps_eq};
3651
3652 let a = object::Static {
3659 position: component::Position ([0.0, 0.0, 0.0].into()),
3660 bound: component::Bound::from (shape::Capsule::noisy (2.0, 3.0)),
3661 material: component::MATERIAL_STONE,
3662 collidable: true
3663 };
3664 let b = object::Static {
3665 position: component::Position ([0.0, 0.0, 0.0].into()),
3666 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
3667 material: component::MATERIAL_STONE,
3668 collidable: true
3669 };
3670 assert_eq!(
3671 Proximity::query (&a, &b),
3672 Proximity {
3673 distance: -3.0,
3674 half_axis: [ 1.5, 0.0, 0.0].into(),
3675 normal: Unit3::axis_x(),
3676 midpoint: [-0.5, 0.0, 0.0].into()
3677 }
3678 );
3679
3680 let a = object::Static {
3683 position: component::Position ([0.0, 0.0, 1.0].into()), .. a
3684 };
3685 let b = object::Static {
3686 position: component::Position ([0.0, 0.0, -1.0].into()), .. b
3687 };
3688 assert_eq!(
3689 Proximity::query (&a, &b),
3690 Proximity {
3691 distance: -3.0,
3692 half_axis: [ 1.5, 0.0, 0.0].into(),
3693 normal: Unit3::axis_x(),
3694 midpoint: [-0.5, 0.0, -0.5].into()
3695 }
3696 );
3697
3698 let a = object::Static {
3701 position: component::Position ([0.0, 0.0, -3.0].into()), .. a
3702 };
3703 let b = object::Static {
3704 position: component::Position ([0.0, 0.0, 2.0].into()), .. b
3705 };
3706 assert_eq!(
3707 Proximity::query (&a, &b),
3708 Proximity {
3709 distance: -3.0,
3710 half_axis: [ 1.5, 0.0, 0.0].into(),
3711 normal: Unit3::axis_x(),
3712 midpoint: [-0.5, 0.0, 0.0].into()
3713 }
3714 );
3715
3716 let a = object::Static {
3718 position: component::Position ([0.0, 0.0, 3.0].into()), .. a
3719 };
3720 let b = object::Static {
3721 position: component::Position ([0.0, 0.0, -2.0].into()), .. b
3722 };
3723 assert_eq!(
3724 Proximity::query (&a, &b),
3725 Proximity {
3726 distance: -3.0,
3727 half_axis: [ 1.5, 0.0, 0.0].into(),
3728 normal: Unit3::axis_x(),
3729 midpoint: [-0.5, 0.0, 0.0].into()
3730 }
3731 );
3732
3733 let a = object::Static {
3735 position: component::Position ([-1.0, 0.0, 1.0].into()), .. a
3736 };
3737 let b = object::Static {
3738 position: component::Position ([0.0, 0.0, -1.0].into()), .. b
3739 };
3740 assert_eq!(
3741 Proximity::query (&a, &b),
3742 Proximity {
3743 distance: -2.0,
3744 half_axis: [-1.0, 0.0, 0.0].into(),
3745 normal: Unit3::axis_x().invert(),
3746 midpoint: [ 0.0, 0.0, -0.5].into()
3747 }
3748 );
3749
3750 let a = object::Static {
3752 position: component::Position ([0.0, 0.0, -3.0].into()), .. a
3753 };
3754 let b = object::Static {
3755 position: component::Position ([0.0, 0.0, 3.0].into()), .. b
3756 };
3757 assert_eq!(
3758 Proximity::query (&a, &b),
3759 Proximity {
3760 distance: -2.0,
3761 half_axis: [ 0.0, 0.0, -1.0].into(),
3762 normal: Unit3::axis_z().invert(),
3763 midpoint: [ 0.0, 0.0, 1.0].into()
3764 }
3765 );
3766
3767 let a = object::Static {
3769 position: component::Position ([0.0, 0.0, 3.0].into()), .. a
3770 };
3771 let b = object::Static {
3772 position: component::Position ([0.0, 0.0, -3.0].into()), .. b
3773 };
3774 assert_eq!(
3775 Proximity::query (&a, &b),
3776 Proximity {
3777 distance: -2.0,
3778 half_axis: [ 0.0, 0.0, 1.0].into(),
3779 normal: Unit3::axis_z(),
3780 midpoint: [ 0.0, 0.0, -1.0].into()
3781 }
3782 );
3783
3784 let a = object::Static {
3786 position: component::Position ([ 1.0, 0.0, 0.0].into()), .. a
3787 };
3788 let b = object::Static {
3789 position: component::Position ([-1.0, 0.0, 0.0].into()), .. b
3790 };
3791 assert_eq!(
3792 Proximity::query (&a, &b),
3793 Proximity {
3794 distance: -1.0,
3795 half_axis: [ 0.5, 0.0, 0.0].into(),
3796 normal: Unit3::axis_x(),
3797 midpoint: [-0.5, 0.0, 0.0].into()
3798 }
3799 );
3800
3801 let a = object::Static {
3803 position: component::Position ([ 2.0, 0.0, 5.0].into()), .. a
3804 };
3805 let b = object::Static {
3806 position: component::Position ([-1.0, 0.0, -3.0].into()), .. b
3807 };
3808
3809 let proximity = Proximity::query (&a, &b);
3810 let distance_manual = {
3811 let distance = vector3 (3.0, 0.0, 3.0).magnitude() - 3.0;
3812 let half_axis : Vector3 <_> =
3813 0.5 * distance * vector3 (-1.0, 0.0, -1.0).normalized();
3814 let normal = Unit3::normalize ([1.0, 0.0, 1.0].into());
3815 let midpoint = Point3::from ([-1.0, 0.0, -1.0]) + *normal - half_axis;
3816 Proximity { distance, half_axis, midpoint, normal }
3817 };
3818 assert_eq!(proximity.distance, distance_manual.distance);
3819 assert_relative_eq!(proximity.half_axis, distance_manual.half_axis);
3820 assert_relative_eq!(*proximity.normal, *distance_manual.normal);
3821 assert_relative_eq!(proximity.midpoint, distance_manual.midpoint,
3822 epsilon = 2.0 * f64::EPSILON);
3823
3824 let a = object::Static {
3826 position: component::Position ([ 3.0, 0.0, 3.0].into()), .. a
3827 };
3828 let b = object::Static {
3829 position: component::Position ([-1.0, 0.0, 0.0].into()), .. b
3830 };
3831 assert_eq!(
3832 Proximity::query (&a, &b),
3833 Proximity {
3834 distance: 1.0,
3835 half_axis: [-0.5, 0.0, 0.0].into(),
3836 normal: Unit3::axis_x(),
3837 midpoint: [ 0.5, 0.0, 1.0].into()
3838 }
3839 );
3840
3841 let a = object::Static {
3847 position: component::Position ([-5.0, -5.0, -5.0].into()),
3848 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 2.0, 3.0])),
3849 .. a
3850 };
3851 let b = object::Static {
3852 position: component::Position ([5.0, 5.0, 5.0].into()),
3853 bound: component::Bound::from (shape::Cuboid::noisy ([3.0, 1.0, 2.0])),
3854 .. b
3855 };
3856 let proximity = Proximity::query (&a, &b);
3857 assert_eq!(proximity.distance, f64::sqrt (110.0));
3858 assert_eq!(proximity.half_axis, [3.0, 3.5, 2.5].into());
3859 assert_ulps_eq!(*proximity.normal, -vector3 (3.0, 3.5, 2.5).normalized());
3860 assert_eq!(proximity.midpoint, [-1.0, 0.5, 0.5].into());
3861
3862 let a = object::Static {
3864 position: component::Position ([-5.0, 0.0, -5.0].into()), .. a
3865 };
3866 let b = object::Static {
3867 position: component::Position ([5.0, 0.0, 5.0].into()), .. b
3868 };
3869 let proximity = Proximity::query (&a, &b);
3870 assert_eq!(proximity.distance, f64::sqrt (61.0));
3871 assert_eq!(proximity.half_axis, [3.0, 0.0, 2.5].into());
3872 assert_ulps_eq!(*proximity.normal, -vector3 (3.0, 0.0, 2.5).normalized());
3873 assert_eq!(proximity.midpoint, [-1.0, 0.0, 0.5].into());
3874
3875 let a = object::Static {
3881 position: component::Position ([5.0, 5.0, 3.0].into()),
3882 bound: component::Bound::from (shape::Capsule::noisy (SQRT_2, 2.0)),
3883 .. a
3884 };
3885 let b = object::Static {
3886 position: component::Position ([0.0, 0.0, 0.0].into()),
3887 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 1.0, 1.0])),
3888 .. b
3889 };
3890 let proximity = Proximity::query (&a, &b);
3891 assert_ulps_eq!(proximity.distance, 3.0 * SQRT_2);
3892 assert_eq!(proximity.half_axis, [-1.5, -1.5, 0.0].into());
3893 assert_ulps_eq!(*proximity.normal, vector3 (1.0, 1.0, 0.0).normalized());
3894 assert_eq!(proximity.midpoint, [ 2.5, 2.5, 1.0].into());
3895
3896 let a = object::Static {
3898 position: component::Position ([-5.0, -5.0, -3.0].into()),
3899 bound: component::Bound::from (shape::Capsule::noisy (SQRT_2, 2.0)),
3900 .. a
3901 };
3902 let b = object::Static {
3903 position: component::Position ([0.0, 0.0, 0.0].into()),
3904 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 1.0, 1.0])),
3905 .. b
3906 };
3907 let proximity = Proximity::query (&a, &b);
3908 assert_ulps_eq!(proximity.distance, 3.0 * SQRT_2);
3909 assert_eq!(proximity.half_axis, [ 1.5, 1.5, 0.0].into());
3910 assert_ulps_eq!(*proximity.normal, vector3 (-1.0, -1.0, 0.0).normalized());
3911 assert_eq!(proximity.midpoint, [-2.5,-2.5,-1.0].into());
3912
3913 let a = object::Static {
3915 position: component::Position ([4.0, 0.5, 4.0].into()),
3916 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
3917 .. a
3918 };
3919 let b = object::Static {
3920 position: component::Position ([0.0, 0.0, 0.0].into()),
3921 bound: component::Bound::from (shape::Cuboid::noisy ([2.0, 2.0, 2.0])),
3922 .. b
3923 };
3924 assert_eq!(
3925 Proximity::query (&a, &b),
3926 Proximity {
3927 distance: 1.0,
3928 half_axis: [-0.5, 0.0, 0.0].into(),
3929 normal: Unit3::axis_x(),
3930 midpoint: [ 2.5, 0.5, 2.0].into()
3931 }
3932 );
3933
3934 let a = object::Static {
3936 position: component::Position ([4.0, 0.5, -4.0].into()), .. a
3937 };
3938 let b = object::Static {
3939 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
3940 };
3941 assert_eq!(
3942 Proximity::query (&a, &b),
3943 Proximity {
3944 distance: 1.0,
3945 half_axis: [-0.5, 0.0, 0.0].into(),
3946 normal: Unit3::axis_x(),
3947 midpoint: [ 2.5, 0.5, -2.0].into()
3948 }
3949 );
3950
3951 let a = object::Static {
3953 position: component::Position ([0.5, 4.0, 4.0].into()), .. a
3954 };
3955 let b = object::Static {
3956 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
3957 };
3958 assert_eq!(
3959 Proximity::query (&a, &b),
3960 Proximity {
3961 distance: 1.0,
3962 half_axis: [ 0.0, -0.5, 0.0].into(),
3963 normal: Unit3::axis_y(),
3964 midpoint: [ 0.5, 2.5, 2.0].into()
3965 }
3966 );
3967
3968 let a = object::Static {
3970 position: component::Position ([0.5, 4.0, -4.0].into()), .. a
3971 };
3972 let b = object::Static {
3973 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
3974 };
3975 assert_eq!(
3976 Proximity::query (&a, &b),
3977 Proximity {
3978 distance: 1.0,
3979 half_axis: [ 0.0, -0.5, 0.0].into(),
3980 normal: Unit3::axis_y(),
3981 midpoint: [ 0.5, 2.5, -2.0].into()
3982 }
3983 );
3984
3985 let a = object::Static {
3987 position: component::Position ([0.5, 0.5, 6.0].into()), .. a
3988 };
3989 let b = object::Static {
3990 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
3991 };
3992 assert_eq!(
3993 Proximity::query (&a, &b),
3994 Proximity {
3995 distance: 1.0,
3996 half_axis: [ 0.0, 0.0, -0.5].into(),
3997 normal: Unit3::axis_z(),
3998 midpoint: [ 0.5, 0.5, 2.5].into()
3999 }
4000 );
4001
4002 let a = object::Static {
4004 position: component::Position ([0.5, 0.5, -6.0].into()), .. a
4005 };
4006 let b = object::Static {
4007 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4008 };
4009 assert_eq!(
4010 Proximity::query (&a, &b),
4011 Proximity {
4012 distance: 1.0,
4013 half_axis: [ 0.0, 0.0, 0.5].into(),
4014 normal: Unit3::axis_z().invert(),
4015 midpoint: [ 0.5, 0.5, -2.5].into()
4016 }
4017 );
4018
4019 let a = object::Static {
4021 position: component::Position ([3.0, 3.0, 2.0].into()), .. a
4022 };
4023 let b = object::Static {
4024 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4025 };
4026 let proximity = Proximity::query (&a, &b);
4027 assert_eq!(proximity.distance, SQRT_2 - 1.0);
4028 assert_eq!(proximity.half_axis, [
4029 -0.5 * f64::sqrt (0.5 * (SQRT_2 - 1.0).powi (2)),
4030 -0.5 * f64::sqrt (0.5 * (SQRT_2 - 1.0).powi (2)),
4031 0.0
4032 ].into());
4033 assert_ulps_eq!(*proximity.normal,
4034 [FRAC_1_SQRT_2, FRAC_1_SQRT_2, 0.0].into());
4035 assert_eq!(proximity.midpoint, [
4036 2.0 + 0.5 * f64::sqrt (0.5 * (SQRT_2 - 1.0).powi (2)),
4037 2.0 + 0.5 * f64::sqrt (0.5 * (SQRT_2 - 1.0).powi (2)),
4038 1.0
4039 ].into());
4040
4041 let a = object::Static {
4043 position: component::Position ([-3.0, -3.0, -2.0].into()), .. a
4044 };
4045 let b = object::Static {
4046 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4047 };
4048 let proximity = Proximity::query (&a, &b);
4049 assert_eq!(proximity.distance, SQRT_2 - 1.0);
4050 assert_eq!(proximity.half_axis, [
4051 0.5 * f64::sqrt (0.5 * (SQRT_2 - 1.0).powi (2)),
4052 0.5 * f64::sqrt (0.5 * (SQRT_2 - 1.0).powi (2)),
4053 0.0
4054 ].into());
4055 assert_ulps_eq!(*proximity.normal, [-FRAC_1_SQRT_2, -FRAC_1_SQRT_2, 0.0].into());
4056 assert_eq!(proximity.midpoint, [
4057 -2.0 - 0.5 * f64::sqrt (0.5 * (SQRT_2 - 1.0).powi (2)),
4058 -2.0 - 0.5 * f64::sqrt (0.5 * (SQRT_2 - 1.0).powi (2)),
4059 -1.0
4060 ].into());
4061
4062 let a = object::Static {
4064 position: component::Position ([1.0, 4.0, 2.0].into()), .. a
4065 };
4066 let b = object::Static {
4067 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4068 };
4069 assert_eq!(
4070 Proximity::query (&a, &b),
4071 Proximity {
4072 distance: 1.0,
4073 half_axis: [ 0.0, -0.5, 0.0].into(),
4074 normal: Unit3::axis_y(),
4075 midpoint: [ 1.0, 2.5, 1.0].into()
4076 }
4077 );
4078
4079 let a = object::Static {
4081 position: component::Position ([-1.0, -4.0, -2.0].into()), .. a
4082 };
4083 let b = object::Static {
4084 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4085 };
4086 assert_eq!(
4087 Proximity::query (&a, &b),
4088 Proximity {
4089 distance: 1.0,
4090 half_axis: [ 0.0, 0.5, 0.0].into(),
4091 normal: Unit3::axis_y().invert(),
4092 midpoint: [-1.0, -2.5, -1.0].into()
4093 }
4094 );
4095
4096 let a = object::Static {
4098 position: component::Position ([4.0, 1.0, 2.0].into()), .. a
4099 };
4100 let b = object::Static {
4101 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4102 };
4103 assert_eq!(
4104 Proximity::query (&a, &b),
4105 Proximity {
4106 distance: 1.0,
4107 half_axis: [-0.5, 0.0, 0.0].into(),
4108 normal: Unit3::axis_x(),
4109 midpoint: [ 2.5, 1.0, 1.0].into()
4110 }
4111 );
4112
4113 let a = object::Static {
4115 position: component::Position ([-4.0, -1.0, -2.0].into()), .. a
4116 };
4117 let b = object::Static {
4118 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4119 };
4120 assert_eq!(
4121 Proximity::query (&a, &b),
4122 Proximity {
4123 distance: 1.0,
4124 half_axis: [ 0.5, 0.0, 0.0].into(),
4125 normal: Unit3::axis_x().invert(),
4126 midpoint: [-2.5, -1.0, -1.0].into()
4127 }
4128 );
4129
4130 let a = object::Static {
4132 position: component::Position ([2.0, 2.0, 4.0].into()),
4133 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4134 .. a
4135 };
4136 let b = object::Static {
4137 position: component::Position ([0.0, 0.0, 0.0].into()),
4138 bound: component::Bound::from (shape::Cuboid::noisy ([2.0, 2.0, 2.0])),
4139 .. b
4140 };
4141 assert_eq!(
4142 Proximity::query (&a, &b),
4143 Proximity {
4144 distance: -1.0,
4145 half_axis: [ 0.5, 0.0, 0.0].into(),
4146 normal: Unit3::axis_x(),
4147 midpoint: [ 1.5, 2.0, 2.0].into()
4148 }
4149 );
4150
4151 let a = object::Static {
4153 position: component::Position ([-2.0, -2.0, -4.0].into()), .. a
4154 };
4155 let b = object::Static {
4156 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4157 };
4158 assert_eq!(
4159 Proximity::query (&a, &b),
4160 Proximity {
4161 distance: -1.0,
4162 half_axis: [-0.5, 0.0, 0.0].into(),
4163 normal: Unit3::axis_x().invert(),
4164 midpoint: [-1.5, -2.0,-2.0].into()
4165 }
4166 );
4167
4168 let a = object::Static {
4170 position: component::Position ([2.0, 1.0, 4.0].into()), .. a
4171 };
4172 let b = object::Static {
4173 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4174 };
4175 assert_eq!(
4176 Proximity::query (&a, &b),
4177 Proximity {
4178 distance: -1.0,
4179 half_axis: [ 0.5, 0.0, 0.0].into(),
4180 normal: Unit3::axis_x(),
4181 midpoint: [ 1.5, 1.0, 2.0].into()
4182 }
4183 );
4184
4185 let a = object::Static {
4187 position: component::Position ([-2.0, 1.0, -4.0].into()), .. a
4188 };
4189 let b = object::Static {
4190 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4191 };
4192 assert_eq!(
4193 Proximity::query (&a, &b),
4194 Proximity {
4195 distance: -1.0,
4196 half_axis: [-0.5, 0.0, 0.0].into(),
4197 normal: Unit3::axis_x().invert(),
4198 midpoint: [-1.5, 1.0, -2.0].into()
4199 }
4200 );
4201
4202 let a = object::Static {
4204 position: component::Position ([1.0, 2.0, 4.0].into()), .. a
4205 };
4206 let b = object::Static {
4207 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4208 };
4209 assert_eq!(
4210 Proximity::query (&a, &b),
4211 Proximity {
4212 distance: -1.0,
4213 half_axis: [ 0.0, 0.5, 0.0].into(),
4214 normal: Unit3::axis_y(),
4215 midpoint: [ 1.0, 1.5, 2.0].into()
4216 }
4217 );
4218
4219 let a = object::Static {
4221 position: component::Position ([ 1.0, -2.0, -4.0].into()), .. a
4222 };
4223 let b = object::Static {
4224 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4225 };
4226 assert_eq!(
4227 Proximity::query (&a, &b),
4228 Proximity {
4229 distance: -1.0,
4230 half_axis: [0.0, -0.5, 0.0].into(),
4231 normal: Unit3::axis_y().invert(),
4232 midpoint: [1.0, -1.5, -2.0].into()
4233 }
4234 );
4235
4236 let a = object::Static {
4238 position: component::Position ([1.0, 1.0, 4.0].into()), .. a
4239 };
4240 let b = object::Static {
4241 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4242 };
4243 assert_eq!(
4244 Proximity::query (&a, &b),
4245 Proximity {
4246 distance: -1.0,
4247 half_axis: [ 0.0, 0.0, 0.5].into(),
4248 normal: Unit3::axis_z(),
4249 midpoint: [ 1.0, 1.0, 1.5].into()
4250 }
4251 );
4252
4253 let a = object::Static {
4255 position: component::Position ([-1.0, -1.0, -4.0].into()), .. a
4256 };
4257 let b = object::Static {
4258 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4259 };
4260 assert_eq!(
4261 Proximity::query (&a, &b),
4262 Proximity {
4263 distance: -1.0,
4264 half_axis: [ 0.0, 0.0, -0.5].into(),
4265 normal: Unit3::axis_z().invert(),
4266 midpoint: [-1.0, -1.0, -1.5].into()
4267 }
4268 );
4269
4270 let a = object::Static {
4272 position: component::Position ([0.0, 0.0, 0.0].into()), .. a
4273 };
4274 let b = object::Static {
4275 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4276 };
4277 assert_eq!(
4278 Proximity::query (&a, &b),
4279 Proximity {
4280 distance: -3.0,
4281 half_axis: [ 1.5, 0.0, 0.0].into(),
4282 normal: Unit3::axis_x(),
4283 midpoint: [ 0.5, 0.0, 0.0].into()
4284 }
4285 );
4286
4287 let a = object::Static {
4289 position: component::Position ([1.0, 0.0, 0.0].into()), .. a
4290 };
4291 let b = object::Static {
4292 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4293 };
4294 assert_eq!(
4295 Proximity::query (&a, &b),
4296 Proximity {
4297 distance: -2.0,
4298 half_axis: [ 1.0, 0.0, 0.0].into(),
4299 normal: Unit3::axis_x(),
4300 midpoint: [ 1.0, 0.0, 0.0].into()
4301 }
4302 );
4303
4304 let a = object::Static {
4306 position: component::Position ([-1.0, 0.0, 0.0].into()), .. a
4307 };
4308 let b = object::Static {
4309 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4310 };
4311 assert_eq!(
4312 Proximity::query (&a, &b),
4313 Proximity {
4314 distance: -2.0,
4315 half_axis: [-1.0, 0.0, 0.0].into(),
4316 normal: Unit3::axis_x().invert(),
4317 midpoint: [-1.0, 0.0, 0.0].into()
4318 }
4319 );
4320
4321 let a = object::Static {
4323 position: component::Position ([0.0, 1.0, 0.0].into()), .. a
4324 };
4325 let b = object::Static {
4326 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4327 };
4328 assert_eq!(
4329 Proximity::query (&a, &b),
4330 Proximity {
4331 distance: -2.0,
4332 half_axis: [0.0, 1.0, 0.0].into(),
4333 normal: Unit3::axis_y(),
4334 midpoint: [0.0, 1.0, 0.0].into()
4335 }
4336 );
4337
4338 let a = object::Static {
4340 position: component::Position ([0.0, -1.0, 0.0].into()), .. a
4341 };
4342 let b = object::Static {
4343 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4344 };
4345 assert_eq!(
4346 Proximity::query (&a, &b),
4347 Proximity {
4348 distance: -2.0,
4349 half_axis: [0.0, -1.0, 0.0].into(),
4350 normal: Unit3::axis_y().invert(),
4351 midpoint: [0.0, -1.0, 0.0].into()
4352 }
4353 );
4354
4355 let a = object::Static {
4357 position: component::Position ([0.0, 0.0, 3.0].into()),
4358 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4359 .. a
4360 };
4361 let b = object::Static {
4362 position: component::Position ([0.0, 0.0, 0.0].into()),
4363 bound: component::Bound::from (shape::Cuboid::noisy ([4.0, 4.0, 2.0])),
4364 .. b
4365 };
4366 assert_eq!(
4367 Proximity::query (&a, &b),
4368 Proximity {
4369 distance: -2.0,
4370 half_axis: [0.0, 0.0, 1.0].into(),
4371 normal: Unit3::axis_z(),
4372 midpoint: [0.0, 0.0, 1.0].into()
4373 }
4374 );
4375
4376 let a = object::Static {
4378 position: component::Position ([0.0, 0.0, 1.0].into()),
4379 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4380 .. a
4381 };
4382 let b = object::Static {
4383 position: component::Position ([0.0, 0.0, 0.0].into()),
4384 bound: component::Bound::from (shape::Cuboid::noisy ([4.0, 4.0, 2.0])),
4385 .. b
4386 };
4387 assert_eq!(
4388 Proximity::query (&a, &b),
4389 Proximity {
4390 distance: -4.0,
4391 half_axis: [0.0, 0.0, 2.0].into(),
4392 normal: Unit3::axis_z(),
4393 midpoint: [0.0, 0.0, 0.0].into()
4394 }
4395 );
4396
4397 let a = object::Static {
4399 position: component::Position ([0.0, 0.0, -3.0].into()),
4400 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4401 .. a
4402 };
4403 let b = object::Static {
4404 position: component::Position ([0.0, 0.0, 0.0].into()),
4405 bound: component::Bound::from (shape::Cuboid::noisy ([4.0, 4.0, 2.0])),
4406 .. b
4407 };
4408 assert_eq!(
4409 Proximity::query (&a, &b),
4410 Proximity {
4411 distance: -2.0,
4412 half_axis: [0.0, 0.0, -1.0].into(),
4413 normal: Unit3::axis_z().invert(),
4414 midpoint: [0.0, 0.0, -1.0].into()
4415 }
4416 );
4417
4418 let a = object::Static {
4420 position: component::Position ([0.0, 0.0, -1.0].into()),
4421 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4422 .. a
4423 };
4424 let b = object::Static {
4425 position: component::Position ([0.0, 0.0, 0.0].into()),
4426 bound: component::Bound::from (shape::Cuboid::noisy ([4.0, 4.0, 2.0])),
4427 .. b
4428 };
4429 assert_eq!(
4430 Proximity::query (&a, &b),
4431 Proximity {
4432 distance: -4.0,
4433 half_axis: [0.0, 0.0, -2.0].into(),
4434 normal: Unit3::axis_z().invert(),
4435 midpoint: [0.0, 0.0, 0.0].into()
4436 }
4437 );
4438
4439 let mut rng = XorShiftRng::seed_from_u64 (0);
4441 let a = object::Static {
4442 position: component::Position ([0.0, 0.0, 0.0].into()),
4443 bound: component::Bound::from (shape::Capsule::noisy (1.5, 1.5)),
4444 .. a
4445 };
4446 for _ in 0..100 {
4447 let position = component::Position ([
4448 rng.random_range (-40.0..40.0),
4449 rng.random_range (-40.0..40.0),
4450 rng.random_range (-40.0..40.0)
4451 ].into());
4452 let bound = shape::Cuboid::noisy ([
4453 rng.random_range (0.5..5.0),
4454 rng.random_range (0.5..5.0),
4455 rng.random_range (0.5..5.0)
4456 ]).into();
4457 let b = object::Static {
4458 position, bound, material: component::MATERIAL_STONE, collidable: true
4459 };
4460 let _ = Proximity::query (&a, &b);
4461 }
4462
4463 use SignedAxis3;
4467
4468 let a = object::Static {
4470 position: component::Position ([0.0, 0.0, 4.0].into()),
4471 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4472 .. a
4473 };
4474 let b = object::Static {
4475 position: component::Position ([0.0, 0.0, 0.0].into()),
4476 bound: shape::Orthant { normal_axis: SignedAxis3::PosZ }.into(),
4477 .. b
4478 };
4479 assert_eq!(
4480 Proximity::query (&a, &b),
4481 Proximity {
4482 distance: 1.0,
4483 half_axis: [0.0, 0.0, -0.5].into(),
4484 normal: Unit3::axis_z(),
4485 midpoint: [0.0, 0.0, 0.5].into()
4486 }
4487 );
4488
4489 let a = object::Static {
4491 position: component::Position ([0.0, 0.0, -4.0].into()),
4492 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4493 .. a
4494 };
4495 let b = object::Static {
4496 position: component::Position ([0.0, 0.0, 0.0].into()),
4497 bound: shape::Orthant { normal_axis: SignedAxis3::NegZ }.into(),
4498 .. b
4499 };
4500 assert_eq!(
4501 Proximity::query (&a, &b),
4502 Proximity {
4503 distance: 1.0,
4504 half_axis: [0.0, 0.0, 0.5].into(),
4505 normal: Unit3::axis_z().invert(),
4506 midpoint: [0.0, 0.0, -0.5].into()
4507 }
4508 );
4509
4510 let a = object::Static {
4512 position: component::Position ([0.0, 2.0, 0.0].into()),
4513 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4514 .. a
4515 };
4516 let b = object::Static {
4517 position: component::Position ([0.0, 0.0, 0.0].into()),
4518 bound: shape::Orthant { normal_axis: SignedAxis3::PosY }.into(),
4519 .. b
4520 };
4521 assert_eq!(
4522 Proximity::query (&a, &b),
4523 Proximity {
4524 distance: 1.0,
4525 half_axis: [0.0, -0.5, 0.0].into(),
4526 normal: Unit3::axis_y(),
4527 midpoint: [0.0, 0.5, 0.0].into()
4528 }
4529 );
4530
4531 let a = object::Static {
4533 position: component::Position ([0.0, -2.0, 0.0].into()),
4534 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4535 .. a
4536 };
4537 let b = object::Static {
4538 position: component::Position ([0.0, 0.0, 0.0].into()),
4539 bound: shape::Orthant { normal_axis: SignedAxis3::NegY }.into(),
4540 .. b
4541 };
4542 assert_eq!(
4543 Proximity::query (&a, &b),
4544 Proximity {
4545 distance: 1.0,
4546 half_axis: [0.0, 0.5, 0.0].into(),
4547 normal: Unit3::axis_y().invert(),
4548 midpoint: [0.0, -0.5, 0.0].into()
4549 }
4550 );
4551
4552 let a = object::Static {
4554 position: component::Position ([2.0, 0.0, 0.0].into()),
4555 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4556 .. a
4557 };
4558 let b = object::Static {
4559 position: component::Position ([0.0, 0.0, 0.0].into()),
4560 bound: shape::Orthant { normal_axis: SignedAxis3::PosX }.into(),
4561 .. b
4562 };
4563 assert_eq!(
4564 Proximity::query (&a, &b),
4565 Proximity {
4566 distance: 1.0,
4567 half_axis: [-0.5, 0.0, 0.0].into(),
4568 normal: Unit3::axis_x(),
4569 midpoint: [ 0.5, 0.0, 0.0].into()
4570 }
4571 );
4572
4573 let a = object::Static {
4575 position: component::Position ([-2.0, 0.0, 0.0].into()),
4576 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4577 .. a
4578 };
4579 let b = object::Static {
4580 position: component::Position ([0.0, 0.0, 0.0].into()),
4581 bound: shape::Orthant { normal_axis: SignedAxis3::NegX }.into(),
4582 .. b
4583 };
4584 assert_eq!(
4585 Proximity::query (&a, &b),
4586 Proximity {
4587 distance: 1.0,
4588 half_axis: [ 0.5, 0.0, 0.0].into(),
4589 normal: Unit3::axis_x().invert(),
4590 midpoint: [-0.5, 0.0, 0.0].into()
4591 }
4592 );
4593
4594 let a = object::Static {
4596 position: component::Position ([0.0, 0.0, 0.0].into()),
4597 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4598 .. a
4599 };
4600 let b = object::Static {
4601 position: component::Position ([0.0, 0.0, 0.0].into()),
4602 bound: shape::Orthant { normal_axis: SignedAxis3::PosZ }.into(),
4603 .. b
4604 };
4605 assert_eq!(
4606 Proximity::query (&a, &b),
4607 Proximity {
4608 distance: -3.0,
4609 half_axis: [0.0, 0.0, 1.5].into(),
4610 normal: Unit3::axis_z(),
4611 midpoint: [0.0, 0.0, -1.5].into()
4612 }
4613 );
4614
4615 let a = object::Static {
4617 position: component::Position ([0.0, 0.0, 0.0].into()),
4618 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4619 .. a
4620 };
4621 let b = object::Static {
4622 position: component::Position ([0.0, 0.0, 0.0].into()),
4623 bound: shape::Orthant { normal_axis: SignedAxis3::NegZ }.into(),
4624 .. b
4625 };
4626 assert_eq!(
4627 Proximity::query (&a, &b),
4628 Proximity {
4629 distance: -3.0,
4630 half_axis: [0.0, 0.0, -1.5].into(),
4631 normal: Unit3::axis_z().invert(),
4632 midpoint: [0.0, 0.0, 1.5].into()
4633 }
4634 );
4635
4636 let a = object::Static {
4638 position: component::Position ([0.0, 0.0, 0.0].into()),
4639 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4640 .. a
4641 };
4642 let b = object::Static {
4643 position: component::Position ([0.0, 0.0, 0.0].into()),
4644 bound: shape::Orthant { normal_axis: SignedAxis3::PosY }.into(),
4645 .. b
4646 };
4647 assert_eq!(
4648 Proximity::query (&a, &b),
4649 Proximity {
4650 distance: -1.0,
4651 half_axis: [0.0, 0.5, 0.0].into(),
4652 normal: Unit3::axis_y(),
4653 midpoint: [0.0, -0.5, 0.0].into()
4654 }
4655 );
4656
4657 let a = object::Static {
4659 position: component::Position ([0.0, 0.0, 0.0].into()),
4660 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4661 .. a
4662 };
4663 let b = object::Static {
4664 position: component::Position ([0.0, 0.0, 0.0].into()),
4665 bound: shape::Orthant { normal_axis: SignedAxis3::NegY }.into(),
4666 .. b
4667 };
4668 assert_eq!(
4669 Proximity::query (&a, &b),
4670 Proximity {
4671 distance: -1.0,
4672 half_axis: [0.0, -0.5, 0.0].into(),
4673 normal: Unit3::axis_y().invert(),
4674 midpoint: [0.0, 0.5, 0.0].into()
4675 }
4676 );
4677
4678 let a = object::Static {
4680 position: component::Position ([0.0, 0.0, 0.0].into()),
4681 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4682 .. a
4683 };
4684 let b = object::Static {
4685 position: component::Position ([0.0, 0.0, 0.0].into()),
4686 bound: shape::Orthant { normal_axis: SignedAxis3::PosX }.into(),
4687 .. b
4688 };
4689 assert_eq!(
4690 Proximity::query (&a, &b),
4691 Proximity {
4692 distance: -1.0,
4693 half_axis: [ 0.5, 0.0, 0.0].into(),
4694 normal: Unit3::axis_x(),
4695 midpoint: [-0.5, 0.0, 0.0].into()
4696 }
4697 );
4698
4699 let a = object::Static {
4701 position: component::Position ([0.0, 0.0, 0.0].into()),
4702 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4703 .. a
4704 };
4705 let b = object::Static {
4706 position: component::Position ([0.0, 0.0, 0.0].into()),
4707 bound: shape::Orthant { normal_axis: SignedAxis3::NegX }.into(),
4708 .. b
4709 };
4710 assert_eq!(
4711 Proximity::query (&a, &b),
4712 Proximity {
4713 distance: -1.0,
4714 half_axis: [-0.5, 0.0, 0.0].into(),
4715 normal: Unit3::axis_x().invert(),
4716 midpoint: [ 0.5, 0.0, 0.0].into()
4717 }
4718 );
4719
4720 let a = object::Static {
4726 position: component::Position ([0.0, 0.0, 4.0].into()),
4727 bound: component::Bound::from (shape::Sphere::noisy (1.0)),
4728 .. a
4729 };
4730 let b = object::Static {
4731 position: component::Position ([0.0, 0.0, 0.0].into()),
4732 bound: shape::Orthant { normal_axis: SignedAxis3::PosZ }.into(),
4733 .. b
4734 };
4735 assert_eq!(
4736 Proximity::query (&a, &b),
4737 Proximity {
4738 distance: 3.0,
4739 half_axis: [0.0, 0.0, -1.5].into(),
4740 normal: Unit3::axis_z(),
4741 midpoint: [0.0, 0.0, 1.5].into()
4742 }
4743 );
4744
4745 let a = object::Static {
4747 position: component::Position ([0.0, 0.0, -4.0].into()),
4748 bound: component::Bound::from (shape::Sphere::noisy (1.0)),
4749 .. a
4750 };
4751 let b = object::Static {
4752 position: component::Position ([0.0, 0.0, 0.0].into()),
4753 bound: shape::Orthant { normal_axis: SignedAxis3::NegZ }.into(),
4754 .. b
4755 };
4756 assert_eq!(
4757 Proximity::query (&a, &b),
4758 Proximity {
4759 distance: 3.0,
4760 half_axis: [0.0, 0.0, 1.5].into(),
4761 normal: Unit3::axis_z().invert(),
4762 midpoint: [0.0, 0.0, -1.5].into()
4763 }
4764 );
4765
4766 let a = object::Static {
4768 position: component::Position ([0.0, 2.0, 0.0].into()),
4769 bound: component::Bound::from (shape::Sphere::noisy (1.0)),
4770 .. a
4771 };
4772 let b = object::Static {
4773 position: component::Position ([0.0, 0.0, 0.0].into()),
4774 bound: shape::Orthant { normal_axis: SignedAxis3::PosY }.into(),
4775 .. b
4776 };
4777 assert_eq!(
4778 Proximity::query (&a, &b),
4779 Proximity {
4780 distance: 1.0,
4781 half_axis: [0.0, -0.5, 0.0].into(),
4782 normal: Unit3::axis_y(),
4783 midpoint: [0.0, 0.5, 0.0].into()
4784 }
4785 );
4786
4787 let a = object::Static {
4789 position: component::Position ([0.0, -2.0, 0.0].into()),
4790 bound: component::Bound::from (shape::Sphere::noisy (1.0)),
4791 .. a
4792 };
4793 let b = object::Static {
4794 position: component::Position ([0.0, 0.0, 0.0].into()),
4795 bound: shape::Orthant { normal_axis: SignedAxis3::NegY }.into(),
4796 .. b
4797 };
4798 assert_eq!(
4799 Proximity::query (&a, &b),
4800 Proximity {
4801 distance: 1.0,
4802 half_axis: [0.0, 0.5, 0.0].into(),
4803 normal: Unit3::axis_y().invert(),
4804 midpoint: [0.0, -0.5, 0.0].into()
4805 }
4806 );
4807
4808 let a = object::Static {
4810 position: component::Position ([2.0, 0.0, 0.0].into()),
4811 bound: component::Bound::from (shape::Sphere::noisy (1.0)),
4812 .. a
4813 };
4814 let b = object::Static {
4815 position: component::Position ([0.0, 0.0, 0.0].into()),
4816 bound: shape::Orthant { normal_axis: SignedAxis3::PosX }.into(),
4817 .. b
4818 };
4819 assert_eq!(
4820 Proximity::query (&a, &b),
4821 Proximity {
4822 distance: 1.0,
4823 half_axis: [-0.5, 0.0, 0.0].into(),
4824 normal: Unit3::axis_x(),
4825 midpoint: [ 0.5, 0.0, 0.0].into()
4826 }
4827 );
4828
4829 let a = object::Static {
4831 position: component::Position ([-2.0, 0.0, 0.0].into()),
4832 bound: component::Bound::from (shape::Sphere::noisy (1.0)),
4833 .. a
4834 };
4835 let b = object::Static {
4836 position: component::Position ([0.0, 0.0, 0.0].into()),
4837 bound: shape::Orthant { normal_axis: SignedAxis3::NegX }.into(),
4838 .. b
4839 };
4840 assert_eq!(
4841 Proximity::query (&a, &b),
4842 Proximity {
4843 distance: 1.0,
4844 half_axis: [ 0.5, 0.0, 0.0].into(),
4845 normal: Unit3::axis_x().invert(),
4846 midpoint: [-0.5, 0.0, 0.0].into()
4847 }
4848 );
4849
4850 let a = object::Static {
4852 position: component::Position ([0.0, 0.0, 0.0].into()),
4853 bound: component::Bound::from (shape::Sphere::noisy (1.0)),
4854 .. a
4855 };
4856 let b = object::Static {
4857 position: component::Position ([0.0, 0.0, 0.0].into()),
4858 bound: shape::Orthant { normal_axis: SignedAxis3::PosZ }.into(),
4859 .. b
4860 };
4861 assert_eq!(
4862 Proximity::query (&a, &b),
4863 Proximity {
4864 distance: -1.0,
4865 half_axis: [0.0, 0.0, 0.5].into(),
4866 normal: Unit3::axis_z(),
4867 midpoint: [0.0, 0.0, -0.5].into()
4868 }
4869 );
4870
4871 let a = object::Static {
4873 position: component::Position ([0.0, 0.0, 0.0].into()),
4874 bound: component::Bound::from (shape::Sphere::noisy (1.0)),
4875 .. a
4876 };
4877 let b = object::Static {
4878 position: component::Position ([0.0, 0.0, 0.0].into()),
4879 bound: shape::Orthant { normal_axis: SignedAxis3::NegZ }.into(),
4880 .. b
4881 };
4882 assert_eq!(
4883 Proximity::query (&a, &b),
4884 Proximity {
4885 distance: -1.0,
4886 half_axis: [0.0, 0.0, -0.5].into(),
4887 normal: Unit3::axis_z().invert(),
4888 midpoint: [0.0, 0.0, 0.5].into()
4889 }
4890 );
4891
4892 let a = object::Static {
4894 position: component::Position ([0.0, 0.0, 0.0].into()),
4895 bound: component::Bound::from (shape::Sphere::noisy (1.0)),
4896 .. a
4897 };
4898 let b = object::Static {
4899 position: component::Position ([0.0, 0.0, 0.0].into()),
4900 bound: shape::Orthant { normal_axis: SignedAxis3::PosY }.into(),
4901 .. b
4902 };
4903 assert_eq!(
4904 Proximity::query (&a, &b),
4905 Proximity {
4906 distance: -1.0,
4907 half_axis: [0.0, 0.5, 0.0].into(),
4908 normal: Unit3::axis_y(),
4909 midpoint: [0.0, -0.5, 0.0].into()
4910 }
4911 );
4912
4913 let a = object::Static {
4915 position: component::Position ([0.0, 0.0, 0.0].into()),
4916 bound: component::Bound::from (shape::Sphere::noisy (1.0)),
4917 .. a
4918 };
4919 let b = object::Static {
4920 position: component::Position ([0.0, 0.0, 0.0].into()),
4921 bound: shape::Orthant { normal_axis: SignedAxis3::NegY }.into(),
4922 .. b
4923 };
4924 assert_eq!(
4925 Proximity::query (&a, &b),
4926 Proximity {
4927 distance: -1.0,
4928 half_axis: [0.0, -0.5, 0.0].into(),
4929 normal: Unit3::axis_y().invert(),
4930 midpoint: [0.0, 0.5, 0.0].into()
4931 }
4932 );
4933
4934 let a = object::Static {
4936 position: component::Position ([0.0, 0.0, 0.0].into()),
4937 bound: component::Bound::from (shape::Sphere::noisy (1.0)),
4938 .. a
4939 };
4940 let b = object::Static {
4941 position: component::Position ([0.0, 0.0, 0.0].into()),
4942 bound: shape::Orthant { normal_axis: SignedAxis3::PosX }.into(),
4943 .. b
4944 };
4945 assert_eq!(
4946 Proximity::query (&a, &b),
4947 Proximity {
4948 distance: -1.0,
4949 half_axis: [ 0.5, 0.0, 0.0].into(),
4950 normal: Unit3::axis_x(),
4951 midpoint: [-0.5, 0.0, 0.0].into()
4952 }
4953 );
4954
4955 let a = object::Static {
4957 position: component::Position ([0.0, 0.0, 0.0].into()),
4958 bound: component::Bound::from (shape::Sphere::noisy (1.0)),
4959 .. a
4960 };
4961 let b = object::Static {
4962 position: component::Position ([0.0, 0.0, 0.0].into()),
4963 bound: shape::Orthant { normal_axis: SignedAxis3::NegX }.into(),
4964 .. b
4965 };
4966 assert_eq!(
4967 Proximity::query (&a, &b),
4968 Proximity {
4969 distance: -1.0,
4970 half_axis: [-0.5, 0.0, 0.0].into(),
4971 normal: Unit3::axis_x().invert(),
4972 midpoint: [ 0.5, 0.0, 0.0].into()
4973 }
4974 );
4975
4976 let a = object::Static {
4982 position: component::Position ([0.0, 0.0, 4.0].into()),
4983 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 1.0, 1.0])),
4984 .. a
4985 };
4986 let b = object::Static {
4987 position: component::Position ([0.0, 0.0, 0.0].into()),
4988 bound: shape::Orthant { normal_axis: SignedAxis3::PosZ }.into(),
4989 .. b
4990 };
4991 assert_eq!(
4992 Proximity::query (&a, &b),
4993 Proximity {
4994 distance: 3.0,
4995 half_axis: [0.0, 0.0, -1.5].into(),
4996 normal: Unit3::axis_z(),
4997 midpoint: [0.0, 0.0, 1.5].into()
4998 }
4999 );
5000
5001 let a = object::Static {
5003 position: component::Position ([0.0, 0.0, -4.0].into()),
5004 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 1.0, 1.0])),
5005 .. a
5006 };
5007 let b = object::Static {
5008 position: component::Position ([0.0, 0.0, 0.0].into()),
5009 bound: shape::Orthant { normal_axis: SignedAxis3::NegZ }.into(),
5010 .. b
5011 };
5012 assert_eq!(
5013 Proximity::query (&a, &b),
5014 Proximity {
5015 distance: 3.0,
5016 half_axis: [0.0, 0.0, 1.5].into(),
5017 normal: Unit3::axis_z().invert(),
5018 midpoint: [0.0, 0.0, -1.5].into()
5019 }
5020 );
5021
5022 let a = object::Static {
5024 position: component::Position ([0.0, 2.0, 0.0].into()),
5025 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 1.0, 1.0])),
5026 .. a
5027 };
5028 let b = object::Static {
5029 position: component::Position ([0.0, 0.0, 0.0].into()),
5030 bound: shape::Orthant { normal_axis: SignedAxis3::PosY }.into(),
5031 .. b
5032 };
5033 assert_eq!(
5034 Proximity::query (&a, &b),
5035 Proximity {
5036 distance: 1.0,
5037 half_axis: [0.0, -0.5, 0.0].into(),
5038 normal: Unit3::axis_y(),
5039 midpoint: [0.0, 0.5, 0.0].into()
5040 }
5041 );
5042
5043 let a = object::Static {
5045 position: component::Position ([0.0, -2.0, 0.0].into()),
5046 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 1.0, 1.0])),
5047 .. a
5048 };
5049 let b = object::Static {
5050 position: component::Position ([0.0, 0.0, 0.0].into()),
5051 bound: shape::Orthant { normal_axis: SignedAxis3::NegY }.into(),
5052 .. b
5053 };
5054 assert_eq!(
5055 Proximity::query (&a, &b),
5056 Proximity {
5057 distance: 1.0,
5058 half_axis: [0.0, 0.5, 0.0].into(),
5059 normal: Unit3::axis_y().invert(),
5060 midpoint: [0.0, -0.5, 0.0].into()
5061 }
5062 );
5063
5064 let a = object::Static {
5066 position: component::Position ([2.0, 0.0, 0.0].into()),
5067 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 1.0, 1.0])),
5068 .. a
5069 };
5070 let b = object::Static {
5071 position: component::Position ([0.0, 0.0, 0.0].into()),
5072 bound: shape::Orthant { normal_axis: SignedAxis3::PosX }.into(),
5073 .. b
5074 };
5075 assert_eq!(
5076 Proximity::query (&a, &b),
5077 Proximity {
5078 distance: 1.0,
5079 half_axis: [-0.5, 0.0, 0.0].into(),
5080 normal: Unit3::axis_x(),
5081 midpoint: [ 0.5, 0.0, 0.0].into()
5082 }
5083 );
5084
5085 let a = object::Static {
5087 position: component::Position ([-2.0, 0.0, 0.0].into()),
5088 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 1.0, 1.0])),
5089 .. a
5090 };
5091 let b = object::Static {
5092 position: component::Position ([0.0, 0.0, 0.0].into()),
5093 bound: shape::Orthant { normal_axis: SignedAxis3::NegX }.into(),
5094 .. b
5095 };
5096 assert_eq!(
5097 Proximity::query (&a, &b),
5098 Proximity {
5099 distance: 1.0,
5100 half_axis: [ 0.5, 0.0, 0.0].into(),
5101 normal: Unit3::axis_x().invert(),
5102 midpoint: [-0.5, 0.0, 0.0].into()
5103 }
5104 );
5105
5106 let a = object::Static {
5108 position: component::Position ([0.0, 0.0, 0.0].into()),
5109 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 1.0, 1.0])),
5110 .. a
5111 };
5112 let b = object::Static {
5113 position: component::Position ([0.0, 0.0, 0.0].into()),
5114 bound: shape::Orthant { normal_axis: SignedAxis3::PosZ }.into(),
5115 .. b
5116 };
5117 assert_eq!(
5118 Proximity::query (&a, &b),
5119 Proximity {
5120 distance: -1.0,
5121 half_axis: [0.0, 0.0, 0.5].into(),
5122 normal: Unit3::axis_z(),
5123 midpoint: [0.0, 0.0, -0.5].into()
5124 }
5125 );
5126
5127 let a = object::Static {
5129 position: component::Position ([0.0, 0.0, 0.0].into()),
5130 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 1.0, 1.0])),
5131 .. a
5132 };
5133 let b = object::Static {
5134 position: component::Position ([0.0, 0.0, 0.0].into()),
5135 bound: shape::Orthant { normal_axis: SignedAxis3::NegZ }.into(),
5136 .. b
5137 };
5138 assert_eq!(
5139 Proximity::query (&a, &b),
5140 Proximity {
5141 distance: -1.0,
5142 half_axis: [0.0, 0.0, -0.5].into(),
5143 normal: Unit3::axis_z().invert(),
5144 midpoint: [0.0, 0.0, 0.5].into()
5145 }
5146 );
5147
5148 let a = object::Static {
5150 position: component::Position ([0.0, 0.0, 0.0].into()),
5151 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 1.0, 1.0])),
5152 .. a
5153 };
5154 let b = object::Static {
5155 position: component::Position ([0.0, 0.0, 0.0].into()),
5156 bound: shape::Orthant { normal_axis: SignedAxis3::PosY }.into(),
5157 .. b
5158 };
5159 assert_eq!(
5160 Proximity::query (&a, &b),
5161 Proximity {
5162 distance: -1.0,
5163 half_axis: [0.0, 0.5, 0.0].into(),
5164 normal: Unit3::axis_y(),
5165 midpoint: [0.0, -0.5, 0.0].into()
5166 }
5167 );
5168
5169 let a = object::Static {
5171 position: component::Position ([0.0, 0.0, 0.0].into()),
5172 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 1.0, 1.0])),
5173 .. a
5174 };
5175 let b = object::Static {
5176 position: component::Position ([0.0, 0.0, 0.0].into()),
5177 bound: shape::Orthant { normal_axis: SignedAxis3::NegY }.into(),
5178 .. b
5179 };
5180 assert_eq!(
5181 Proximity::query (&a, &b),
5182 Proximity {
5183 distance: -1.0,
5184 half_axis: [0.0, -0.5, 0.0].into(),
5185 normal: Unit3::axis_y().invert(),
5186 midpoint: [0.0, 0.5, 0.0].into()
5187 }
5188 );
5189
5190 let a = object::Static {
5192 position: component::Position ([0.0, 0.0, 0.0].into()),
5193 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 1.0, 1.0])),
5194 .. a
5195 };
5196 let b = object::Static {
5197 position: component::Position ([0.0, 0.0, 0.0].into()),
5198 bound: shape::Orthant { normal_axis: SignedAxis3::PosX }.into(),
5199 .. b
5200 };
5201 assert_eq!(
5202 Proximity::query (&a, &b),
5203 Proximity {
5204 distance: -1.0,
5205 half_axis: [ 0.5, 0.0, 0.0].into(),
5206 normal: Unit3::axis_x(),
5207 midpoint: [-0.5, 0.0, 0.0].into()
5208 }
5209 );
5210
5211 let a = object::Static {
5213 position: component::Position ([0.0, 0.0, 0.0].into()),
5214 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 1.0, 1.0])),
5215 .. a
5216 };
5217 let b = object::Static {
5218 position: component::Position ([0.0, 0.0, 0.0].into()),
5219 bound: shape::Orthant { normal_axis: SignedAxis3::NegX }.into(),
5220 .. b
5221 };
5222 assert_eq!(
5223 Proximity::query (&a, &b),
5224 Proximity {
5225 distance: -1.0,
5226 half_axis: [-0.5, 0.0, 0.0].into(),
5227 normal: Unit3::axis_x().invert(),
5228 midpoint: [ 0.5, 0.0, 0.0].into()
5229 }
5230 );
5231
5232 } #[test]
5235 #[expect(clippy::approx_constant)]
5236 fn query_hull() {
5237 let object_a = (
5239 component::Position ([0.0, 1.0, 1.6].into()),
5240 component::Bound::from (shape::Cuboid::noisy ([2.2, 2.2, 0.2]))
5241 );
5242 let object_b = {
5243 let hull = {
5244 let points = [
5245 [0.7333798838354574, 0.07387687099658402, -0.4254516842354885],
5246 [0.28934048979234384, -0.41943067939022566, 0.20302532977593885],
5247 [0.006562630606422983, 0.7345982182090985, 0.6784706255126608],
5248 [-0.16787537854609894, -0.7656664645854194, 0.004114727975213302],
5249 [-0.6400977561459589, -0.062079241531162725, -0.33763483879239625],
5250 [-0.3844054415702367, 0.6216012595122049, -0.04739397447380115]
5251 ].map (Point3::from);
5252 geometry::Hull3::from_points (&points).unwrap()
5253 };
5254 ( component::Position (
5255 [-0.021233076872148704, 1.4862487906056179, 2.2279516842354887].into()),
5256 component::Bound::from (hull)
5257 )
5258 };
5259 let proximity = Proximity::query (&object_a, &object_b);
5260 assert_eq!(proximity.distance, 0.0025000000000001688);
5261
5262 let object_a = {
5263 let hull = {
5264 let points = [
5265 [-1.6970562748477143, -2.2, 1.4142135623730951],
5266 [-1.4142135623730954, -2.2, 1.697056274847714],
5267 [-1.6970562748477143, 2.2, 1.4142135623730951],
5268 [-1.4142135623730954, 2.2, 1.697056274847714],
5269 [ 1.4142135623730954, -2.2, -1.697056274847714],
5270 [ 1.6970562748477143, -2.2, -1.4142135623730951],
5271 [ 1.4142135623730954, 2.2, -1.697056274847714],
5272 [ 1.6970562748477143, 2.2, -1.4142135623730951]
5273 ].map (Point3::from);
5274 geometry::Hull3::from_points (&points).unwrap()
5275 };
5276 ( component::Position ([-3.9, 1.0, 11.2125].into()),
5277 component::Bound::from (hull)
5278 )
5279 };
5280 let object_b = (
5281 component::Position (
5282 [-4.004858348343004, -1.2161640324940572, 11.869089780656527].into()),
5283 component::Bound::from (shape::Sphere::noisy (0.5))
5284 );
5285 let proximity = Proximity::query (&object_a, &object_b);
5286 assert_eq!(proximity.distance, -0.3091811079468084);
5287
5288 let object_a = {
5289 let hull = {
5290 let points = [
5291 [-2.2, -1.4142135623730954, -1.697056274847714],
5292 [-2.2, -1.6970562748477143, -1.4142135623730951],
5293 [-2.2, 1.6970562748477143, 1.4142135623730951],
5294 [-2.2, 1.4142135623730954, 1.697056274847714],
5295 [ 2.2, -1.4142135623730954, -1.697056274847714],
5296 [ 2.2, -1.6970562748477143, -1.4142135623730951],
5297 [ 2.2, 1.6970562748477143, 1.4142135623730951],
5298 [ 2.2, 1.4142135623730954, 1.69705627484771]
5299 ].map (Point3::from);
5300 geometry::Hull3::from_points (&points).unwrap()
5301 };
5302 ( component::Position ([0.0, 4.9, 11.2125].into()),
5303 component::Bound::from (hull)
5304 )
5305 };
5306 let object_b = (
5307 component::Position (
5308 [1.3113904930865399, 3.1609676773871804, 9.819471286970987].into()),
5309 component::Bound::from (shape::Sphere::noisy (0.5))
5310 );
5311 let proximity = Proximity::query (&object_a, &object_b);
5312 assert_eq!(proximity.distance, -0.4529809974587258);
5313
5314 let object_a = {
5315 let hull = {
5316 let points = [
5317 [-2.2, -1.6970562748477138, 1.4142135623730956],
5318 [-2.2, -1.414213562373095, 1.6970562748477145],
5319 [-2.2, 1.414213562373095, -1.6970562748477145],
5320 [-2.2, 1.6970562748477138, -1.4142135623730956],
5321 [ 2.2, -1.6970562748477138, 1.4142135623730956],
5322 [ 2.2, -1.414213562373095, 1.6970562748477145],
5323 [ 2.2, 1.414213562373095, -1.6970562748477145],
5324 [ 2.2, 1.6970562748477138, -1.4142135623730956]
5325 ].map (Point3::from);
5326 geometry::Hull3::from_points (&points).unwrap()
5327 };
5328 ( component::Position ([0.0, -2.9, 11.2125].into()),
5329 component::Bound::from (hull)
5330 )
5331 };
5332 let object_b = (
5333 component::Position (
5334 [2.256458188002921, -0.9674933916701636, 10.065811222437437].into()),
5335 component::Bound::from (shape::Sphere::noisy (0.5))
5336 );
5337 let proximity = Proximity::query (&object_a, &object_b);
5338 assert_eq!(proximity.distance, -0.13988958350691275);
5339
5340 let object_a = {
5341 let hull = {
5342 let points = [
5343 [-1.8000000000000003, -1.4142135623730954, -1.697056274847714 ],
5344 [-1.8000000000000003, -1.6970562748477143, -1.4142135623730951],
5345 [-1.8000000000000003, 1.6970562748477143, 1.4142135623730951],
5346 [-1.8000000000000003, 1.4142135623730954, 1.697056274847714 ],
5347 [ 1.8000000000000003, -1.4142135623730954, -1.697056274847714 ],
5348 [ 1.8000000000000003, -1.6970562748477143, -1.4142135623730951],
5349 [ 1.8000000000000003, 1.6970562748477143, 1.4142135623730951],
5350 [ 1.8000000000000003, 1.4142135623730954, 1.697056274847714 ]
5351 ].map (Point3::from);
5352 geometry::Hull3::from_points (&points).unwrap()
5353 };
5354 ( component::Position ([0.0, 4.5, 11.2125].into()),
5355 component::Bound::from (hull)
5356 )
5357 };
5358 let object_b = (
5359 component::Position (
5360 [-1.8483359321030037, 3.6499052772728637, 11.360649949330503].into()),
5361 component::Bound::from (shape::Sphere::noisy (0.5))
5362 );
5363 let proximity = Proximity::query (&object_a, &object_b);
5364 assert_eq!(proximity.distance, 0.008169602403322415);
5365 }
5366
5367 #[test]
5368 fn distance_to_triangle_edges() {
5369 let triangle = geometry::Triangle3::noisy (
5370 [-2.0, -1.0, 0.0].into(),
5371 [ 1.0, -1.0, 0.0].into(),
5372 [ 1.0, 5.0, 0.0].into()
5373 );
5374 let s = 0.5;
5376 let t = 1.0 / 6.0;
5377 let (d0, d1, d2) = triangle_distance_to_edges (triangle, s, t);
5378 approx::assert_relative_eq!(d0, 1.0);
5379 assert_eq!(d1, 3.0 / 5.0.sqrt());
5380 assert_eq!(d2, 1.0);
5381 }
5382
5383}