1use crate::{collision, component, 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 plane (&self) -> geometry::Plane3 <f64> {
75 geometry::Plane3::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 use geometry::Primitive;
1926 let mut out = None;
1927 let mut min_distance = f64::MAX;
1928 for edge in triangle_a.edges() {
1929 let proximity = Proximity::query_triangle_segment (triangle_b, &edge);
1930 if proximity.distance < -f64::EPSILON * 2.0.powi (12) {
1931 out = None;
1932 break
1933 }
1934 if proximity.distance < min_distance {
1935 min_distance = proximity.distance;
1936 out = Some (proximity.flip());
1938 }
1939 }
1940 if out.is_some() {
1941 for edge in triangle_b.edges() {
1943 let proximity = Proximity::query_triangle_segment (triangle_a, &edge);
1944 if proximity.distance < -f64::EPSILON * 2.0.powi (12) {
1945 out = None;
1946 break
1947 }
1948 if proximity.distance < min_distance {
1949 min_distance = proximity.distance;
1950 out = Some (proximity);
1951 }
1952 }
1953 }
1954 if out.is_none() {
1955 if is_recurse {
1957 log::error!("triangle/triangle proximity query can't recurse more than once");
1958 panic!("triangle/triangle proximity query can't recurse more than once");
1959 }
1960 let points : [Point3 <f64>; 9] = std::array::from_fn (|i|{
1962 let p = triangle_a.points()[i / 3];
1963 let q = triangle_b.points()[i % 3];
1964 Point3 (p.0 - q.0)
1965 });
1966 let get_triangle = |a, b, c|
1970 geometry::Triangle3::new (points[a], points[b], points[c]);
1971 let mut nearest_distance : Option <geometry::Distance3 <f64>> = None;
1972 let tolerance = f64::EPSILON * 2.0.powi (10);
1973 for i in 0..9 {
1974 for j in (i + 1)..9 {
1975 for k in (j + 1)..9 {
1976 if let Some (triangle) = get_triangle (i, j, k) {
1977 let distance =
1978 geometry::Distance3::triangle_point (triangle, Point3::origin());
1979 if distance.distance_squared() < nearest_distance.as_ref().map_or (
1980 NonNegative::unchecked (f64::MAX),
1981 geometry::Distance3::distance_squared)
1982 {
1983 let normal = {
1985 let mut normal = triangle.normal();
1986 if normal.dot (triangle.point_a().0) < 0.0 {
1987 normal = -normal
1988 }
1989 normal
1990 };
1991 let mut exterior = true;
1992 for point in points.iter() {
1993 if normal.dot (point - triangle.point_a()) > tolerance {
1994 exterior = false;
1995 break
1996 }
1997 }
1998 if exterior {
1999 nearest_distance = Some (distance);
2000 }
2001 }
2002 }
2003 }
2004 }
2005 }
2006 let mut nearest = nearest_distance.unwrap();
2007 let distance = -*nearest.distance();
2008 let half_axis = -nearest.nearest_a().0 * 0.5;
2009 let resolved_proximity = {
2010 let translate = |mut triangle : geometry::Triangle3 <f64>, displacement| {
2011 triangle.translate (displacement);
2012 triangle
2013 };
2014 let resolved_a = translate (*triangle_a, half_axis);
2015 let resolved_b = translate (*triangle_b, -half_axis);
2016 query_triangle_triangle_recursive (&resolved_a, &resolved_b, true)
2018 };
2019 out = Some(Proximity { distance, half_axis, .. resolved_proximity });
2020 }
2021 out.unwrap()
2022 }
2023 query_triangle_triangle_recursive (triangle_a, triangle_b, false)
2024 }
2025
2026 pub fn query_triangle_line (
2027 triangle : &geometry::Triangle3 <f64>,
2028 line : &geometry::Segment3 <f64>
2029 ) -> Self {
2030 use approx::{AbsDiffEq, RelativeEq};
2031 let (([s, t], nearest_a), (_, nearest_b)) =
2032 geometry::distance::nearest_triangle3_line3 (*triangle, *line);
2033 if approx::relative_eq!(nearest_a, nearest_b,
2034 max_relative = f64::default_max_relative() * 256.0,
2035 epsilon = f64::default_epsilon() * 256.0)
2036 {
2037 let distance;
2039 let half_axis;
2040 let triangle_normal = triangle.normal();
2041 let (midpoint, normal) = if approx::abs_diff_eq!(triangle_normal.dot (*line.vector()), 0.0) {
2042 let a_to_b = nearest_b - nearest_a;
2045 distance = a_to_b.magnitude();
2046 half_axis = a_to_b * 0.5;
2047 let midpoint = nearest_a + half_axis;
2048 let normal = triangle_normal.normalize();
2049 (midpoint, normal)
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 let midpoint = nearest_a + half_axis;
2083 let 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 (midpoint, normal)
2106 };
2107 return Proximity { distance, half_axis, midpoint, normal }
2108 }
2109 let a_to_b = nearest_b - nearest_a;
2110 let distance = a_to_b.magnitude();
2111 let half_axis = a_to_b * 0.5;
2112 let midpoint = nearest_a + half_axis;
2113 let normal = Unit3::normalize (-a_to_b);
2114 Proximity { distance, half_axis, midpoint, normal }
2115 }
2116
2117 pub fn query_triangle_segment (
2118 triangle : &geometry::Triangle3 <f64>,
2119 segment : &geometry::Segment3 <f64>
2120 ) -> Self {
2121 use approx::{AbsDiffEq, RelativeEq};
2122 let (([s, t], nearest_a), (_r, nearest_b)) =
2123 geometry::distance::nearest_triangle3_segment3 (*triangle, *segment);
2124 if approx::relative_eq!(nearest_a, nearest_b,
2125 max_relative = f64::default_max_relative() * 2.0.powi (17),
2126 epsilon = f64::default_epsilon() * 2.0.powi (17))
2127 {
2128 if let Some((mut proximity, edge_perp)) = if approx::abs_diff_eq!(*s, 0.0,
2131 epsilon = f64::default_epsilon() * 2.0.powi (23))
2132 {
2133 Some (( Proximity::query_segment_segment (&triangle.edge_ca(), segment),
2135 triangle.perpendicular_ca() ))
2136 } else if approx::abs_diff_eq!(*t, 0.0,
2137 epsilon = f64::default_epsilon() * 2.0.powi (23))
2138 {
2139 Some (( Proximity::query_segment_segment (&triangle.edge_ab(), segment),
2141 triangle.perpendicular_ab() ))
2142 } else if approx::relative_eq!(*s + *t, 1.0,
2143 max_relative = f64::default_max_relative() * 2.0.powi (23),
2144 epsilon = f64::default_epsilon() * 2.0.powi (23))
2145 {
2146 Some (( Proximity::query_segment_segment (&triangle.edge_bc(), segment),
2148 triangle.perpendicular_bc() ))
2149 } else {
2150 None
2151 }
2152 {
2153 if edge_perp.dot (*proximity.normal) > 0.0 {
2154 proximity.normal = -proximity.normal;
2156 }
2157 return proximity
2158 }
2159 let distance;
2163 let half_axis;
2164 let midpoint;
2165 let normal;
2166 let triangle_normal = triangle.normal();
2167 let mut triangle_normal_unit = None;
2168 let segment_vec = segment.vector();
2169 if approx::abs_diff_eq!(triangle_normal.dot (*segment_vec), 0.0) {
2170 distance = 0.0;
2173 half_axis = Vector3::zero();
2174 midpoint = nearest_a;
2175 normal = triangle_normal.normalize();
2176 } else {
2177 let (seg_depth_sq, seg_depth_vec) = if triangle_normal.cross (*segment_vec)
2179 == Vector3::zero()
2180 {
2181 let depth_vec_a = segment.point_a() - nearest_b;
2183 let depth_vec_b = segment.point_b() - nearest_b;
2184 let dsq_a = depth_vec_a.magnitude_squared();
2185 let dsq_b = depth_vec_b.magnitude_squared();
2186 if dsq_a < dsq_b {
2187 (dsq_a, depth_vec_a)
2188 } else {
2189 (dsq_b, depth_vec_b)
2190 }
2191 } else {
2192 let normal_unit = triangle_normal.normalize();
2195 triangle_normal_unit = Some (normal_unit);
2196 let tri0_to_seg0 = segment.point_a() - triangle.point_a();
2197 let tri0_to_seg1 = segment.point_b() - triangle.point_a();
2198 let normal_dot_seg0 = normal_unit.dot (tri0_to_seg0);
2199 let normal_dot_seg1 = normal_unit.dot (tri0_to_seg1);
2200 let proj_seg0 = segment.point_a() - *normal_unit * normal_dot_seg0;
2201 let proj_seg1 = segment.point_b() - *normal_unit * normal_dot_seg1;
2202 let ab = triangle.point_b() - triangle.point_a();
2204 let ac = triangle.point_c() - triangle.point_a();
2205 let ab_mag_sq = ab.magnitude_squared();
2206 let ab_dot_ac = ab.dot (ac);
2207 let ac_mag_sq = ac.magnitude_squared();
2208 let determinant = ab_mag_sq.mul_add (ac_mag_sq, -ab_dot_ac.squared());
2210 let barycentric_to_cartesian = |s, t| triangle.point_a() + ab * s + ac * t;
2212 let barycentric_coords = |p_proj : Point3 <f64>| {
2213 let to_p = p_proj - triangle.point_a();
2214 let to_p_dot_ab = to_p.dot (ab);
2215 let to_p_dot_ac = to_p.dot (ac);
2216 let s = ac_mag_sq.mul_add (to_p_dot_ab, -ab_dot_ac * to_p_dot_ac)
2218 / determinant;
2219 let t = ab_mag_sq.mul_add (to_p_dot_ac, -ab_dot_ac * to_p_dot_ab)
2221 / determinant;
2222 if cfg!(debug_assertions) {
2223 approx::assert_relative_eq!(p_proj, barycentric_to_cartesian (s, t),
2224 epsilon = f64::default_epsilon() * 2.0.powi (40),
2225 max_relative = f64::default_max_relative() * 2.0.powi (40));
2226 }
2227 [s, t]
2228 };
2229 let [s0, t0] = barycentric_coords (proj_seg0);
2230 let [s1, t1] = barycentric_coords (proj_seg1);
2231 let (base_s, base_t) = (s0, t0);
2232 let (vec_s, vec_t) = (s1 - s0, t1 - t0);
2233 let clip_seg_endpoint = |s, t| {
2235 let (mut s, mut t) = (s, t);
2243 let mut u = 0.0;
2244 #[expect(clippy::useless_let_if_seq)]
2245 let mut clipped = false;
2246 if s < 0.0 {
2247 u = -base_s / vec_s;
2249 s = 0.0;
2250 t = base_t + u * vec_t;
2251 clipped = true;
2252 }
2253 if t < 0.0 {
2254 u = -base_t / vec_t;
2256 s = base_s + u * vec_s;
2257 t = 0.0;
2258 clipped = true;
2259 }
2260 if s + t > 1.0 {
2261 u = (1.0 - base_s - base_t) / (vec_s + vec_t);
2263 s = base_s + u * vec_s;
2264 t = base_t + u * vec_t;
2265 if cfg!(debug_assertions) {
2266 approx::assert_relative_eq!(s + t, 1.0,
2267 max_relative = f64::default_max_relative() * 2.0.powi (16),
2268 epsilon = f64::default_epsilon() * 2.0.powi (16));
2269 }
2270 debug_assert!(s >= 0.0);
2271 debug_assert!(t >= 0.0);
2272 clipped = true;
2273 }
2274 if clipped {
2275 Some (([s, t], u))
2276 } else {
2277 None
2278 }
2279 };
2280 let (dsq_a, depth_vec_a) =
2281 if let Some (([s, t], u)) = clip_seg_endpoint (s0, t0) {
2282 let clipped = segment.point_a() + *segment_vec * u;
2283 let proj = barycentric_to_cartesian (s, t);
2284 let depth_vec = clipped - proj;
2285 (depth_vec.magnitude_squared(), depth_vec)
2286 } else {
2287 let depth_vec = segment.point_a() - proj_seg0;
2288 (depth_vec.magnitude_squared(), depth_vec)
2289 };
2290 let (dsq_b, depth_vec_b) =
2291 if let Some (([s, t], u)) = clip_seg_endpoint (s1, t1) {
2292 let clipped = segment.point_a() + *segment_vec * u;
2293 let proj = barycentric_to_cartesian (s, t);
2294 let depth_vec = clipped - proj;
2295 (depth_vec.magnitude_squared(), depth_vec)
2296 } else {
2297 let depth_vec = segment.point_b() - proj_seg1;
2298 (depth_vec.magnitude_squared(), depth_vec)
2299 };
2300 if dsq_a < dsq_b {
2301 (dsq_a, depth_vec_a)
2302 } else {
2303 (dsq_b, depth_vec_b)
2304 }
2305 };
2306 let (d0, d1, d2) = triangle_distance_to_edges (*triangle, *s, *t);
2308 let edge_dist_sq = f64::min (d0 * d0, f64::min (d1 * d1, d2 * d2));
2309 if seg_depth_sq <= edge_dist_sq {
2311 let unit_normal = triangle_normal_unit
2313 .unwrap_or_else (|| triangle_normal.normalize());
2314 if unit_normal.dot (seg_depth_vec) < 0.0 {
2315 normal = -unit_normal;
2316 } else {
2317 normal = unit_normal;
2318 }
2319 distance = -seg_depth_sq.sqrt();
2320 half_axis = *normal * -distance * 0.5;
2321 midpoint = nearest_a + half_axis;
2322 } else {
2323 let edge_dist = edge_dist_sq.sqrt();
2325 distance = -edge_dist;
2326 let edge0 = triangle.point_b() - triangle.point_a();
2328 let edge1 = triangle.point_c() - triangle.point_a();
2329 let edge2 = triangle.point_c() - triangle.point_b();
2330 let len2_e0 = edge0.magnitude_squared();
2331 let len2_e1 = edge1.magnitude_squared();
2332 let len2_e2 = edge2.magnitude_squared();
2333 let (nearest_edge_point, nearest_edge_perp) = if d0 <= d1 && d0 <= d2 {
2334 let t = (nearest_b - triangle.point_b()).dot (edge0) / len2_e0;
2335 (triangle.point_b() + edge0 * t, -triangle.perpendicular_ab())
2336 } else if d1 <= d2 {
2337 let t = (nearest_b - triangle.point_a()).dot (edge1) / len2_e1;
2338 (triangle.point_a() + edge1 * t, -triangle.perpendicular_ca())
2339 } else {
2340 let t = (nearest_b - triangle.point_a()).dot (edge2) / len2_e2;
2341 (triangle.point_a() + edge2 * t, -triangle.perpendicular_bc())
2342 };
2343 half_axis = (nearest_b - nearest_edge_point) * 0.5;
2344 midpoint = nearest_a + half_axis;
2345 normal = nearest_edge_perp.normalize();
2346 }
2347 }
2348 return Proximity { distance, half_axis, midpoint, normal }
2349 }
2350 let a_to_b = nearest_b - nearest_a;
2351 let distance = a_to_b.magnitude();
2352 let half_axis = a_to_b * 0.5;
2353 let midpoint = nearest_a + half_axis;
2354 let normal = -a_to_b.normalize();
2355 Proximity { distance, half_axis, midpoint, normal }
2356 }
2357
2358 pub fn query_triangle_point (
2359 triangle : &geometry::Triangle3 <f64>,
2360 point : &Point3 <f64>
2361 ) -> Self {
2362 let ([s, t], nearest_a) = triangle.nearest_point (*point);
2363 let a_to_b = point - nearest_a;
2364 let distance = a_to_b.magnitude();
2365 let half_axis = a_to_b * 0.5;
2366 let midpoint = nearest_a + half_axis;
2367 let normal = if *point == nearest_a {
2368 let perp = if *t == 0.0 {
2370 -triangle.perpendicular_ab()
2372 } else if *s == 0.0 {
2373 -triangle.perpendicular_ca()
2375 } else if *s + *t == 1.0 {
2376 -triangle.perpendicular_bc()
2378 } else {
2379 triangle.normal()
2381 };
2382 *perp
2383 } else {
2384 -a_to_b
2385 }.normalize();
2386 Proximity { distance, half_axis, midpoint, normal }
2387 }
2388
2389 pub fn query_line_line (
2390 line_a : &geometry::Segment3 <f64>,
2391 line_b : &geometry::Segment3 <f64>
2392 ) -> Self {
2393 use approx::{AbsDiffEq, RelativeEq};
2394 use num::Zero;
2395 let ((_, nearest_a), (_, nearest_b)) =
2396 geometry::distance::nearest_line3_line3 (*line_a, *line_b);
2397 let a_to_b = nearest_b - nearest_a;
2398 let distance = a_to_b.magnitude();
2399 let half_axis = a_to_b * 0.5;
2400 let midpoint = nearest_a + half_axis;
2401 let normal = if approx::relative_eq!(nearest_a, nearest_b,
2402 max_relative = f64::default_max_relative() * 256.0,
2403 epsilon = f64::default_epsilon() * 256.0)
2404 {
2405 let line_a_dir = line_a.vector();
2407 let line_b_dir = line_b.vector();
2408 let mut perp = line_a_dir.cross (*line_b_dir);
2409 if perp.is_zero() {
2410 perp = line_a_dir.orthogonal();
2411 }
2412 perp
2413 } else {
2414 -a_to_b
2415 }.normalize();
2416 Proximity { distance, half_axis, midpoint, normal }
2417 }
2418
2419 pub fn query_line_segment (
2420 line : &geometry::Segment3 <f64>,
2421 segment : &geometry::Segment3 <f64>
2422 ) -> Self {
2423 use approx::{AbsDiffEq, RelativeEq};
2424 let seg_dir = segment.vector();
2425 let line_dir = line.vector();
2426 let ((_, nearest_a), (s1, nearest_b)) =
2427 geometry::distance::nearest_line3_segment3 (*line, *segment);
2428 let a_to_b = nearest_b - nearest_a;
2429 let distance = a_to_b.magnitude();
2430 let half_axis = a_to_b * 0.5;
2431 let midpoint = nearest_a + half_axis;
2432 let normal = if approx::relative_eq!(nearest_a, nearest_b,
2433 max_relative = f64::default_max_relative() * 256.0,
2434 epsilon = f64::default_epsilon() * 256.0)
2435 {
2436 if 0.0 < *s1 && *s1 < 1.0 {
2438 let mut perp = seg_dir.cross (*line_dir);
2440 if perp.is_approx_zero() {
2441 perp = seg_dir.orthogonal();
2443 }
2444 debug_assert!(!perp.is_approx_zero());
2445 perp
2446 } else {
2447 debug_assert!(*s1 == 0.0 || *s1 == 1.0);
2450 let mut perp = seg_dir.cross (*line_dir).cross (*line_dir);
2451 if perp.is_approx_zero() {
2452 perp = seg_dir.orthogonal()
2454 } else if *s1 == 1.0 {
2455 perp = -perp
2456 }
2457 debug_assert!((nearest_a - segment.point_a()).dot (perp) >= 0.0);
2458 debug_assert!((nearest_a - segment.point_b()).dot (perp) >= 0.0);
2459 perp
2460 }
2461 } else {
2462 -a_to_b
2463 }.normalize();
2464 Proximity { distance, half_axis, midpoint, normal }
2465 }
2466
2467 pub fn query_line_point (
2468 line : &geometry::Segment3 <f64>,
2469 point : &Point3 <f64>
2470 ) -> Self {
2471 let (_, nearest_a) = line.nearest_point (*point);
2472 let nearest_b = *point;
2473 let a_to_b = nearest_b - nearest_a;
2474 let distance = a_to_b.magnitude();
2475 let half_axis = a_to_b * 0.5;
2476 let midpoint = nearest_a + half_axis;
2477 let normal = if approx::relative_eq!(nearest_a, nearest_b) {
2478 *line.perpendicular()
2479 } else {
2480 -a_to_b
2481 }.normalize();
2482 Proximity { distance, half_axis, midpoint, normal }
2483 }
2484
2485 pub fn query_segment_segment (
2486 segment_a : &geometry::Segment3 <f64>,
2487 segment_b : &geometry::Segment3 <f64>
2488 ) -> Self {
2489 use approx::{AbsDiffEq, RelativeEq};
2490 let vec_a = segment_a.vector();
2493 let vec_b = segment_b.vector();
2494 let vec_b0a0 = segment_a.point_a() - segment_b.point_a();
2495 let a = Positive::unchecked (*vec_a.self_dot());
2496 let b = vec_a.dot (*vec_b);
2497 let c = Positive::unchecked (*vec_b.self_dot());
2498 let d = vec_a.dot (vec_b0a0);
2499 let e = vec_b.dot (vec_b0a0);
2500 let f00 = d;
2501 let f10 = f00 + *a;
2502 let f01 = f00 - b;
2503 let f11 = f10 - b;
2504 let g00 = -e;
2505 let g10 = g00 - b;
2506 let g01 = g00 + *c;
2507 let g11 = g10 + *c;
2508 let svalue = [
2509 clamped_root (*a, f00, f10),
2510 clamped_root (*a, f01, f11)
2511 ];
2512 let mut classify = [i8::MAX; 2];
2513 for i in 0..2 {
2514 if svalue[i] <= 0.0 {
2515 classify[i] = -1
2516 } else if svalue[i] >= 1.0 {
2517 classify[i] = 1
2518 } else {
2519 classify[i] = 0
2520 }
2521 }
2522 let param_a;
2523 let param_b;
2524 if classify[0] == -1 && classify[1] == -1 {
2525 param_a = 0.0;
2526 param_b = clamped_root (*c, g00, g01);
2527 } else if classify[0] == 1 && classify[1] == 1 {
2528 param_a = 1.0;
2529 param_b = clamped_root (*c, g10, g11);
2530 } else {
2531 let mut edge = [u8::MAX; 2];
2532 let mut end = [[f64::NAN; 2]; 2];
2533 if classify[0] == -1 {
2534 edge[0] = 0;
2535 end[0][0] = 0.0;
2536 end[0][1] = f00 / b;
2537 if end[0][1] < 0.0 || end[0][1] > 1.0 {
2538 end[0][1] = 0.5
2539 }
2540 if classify[1] == 0 {
2541 edge[1] = 3;
2542 end[1][0] = svalue[1];
2543 end[1][1] = 1.0;
2544 } else {
2545 debug_assert_eq!(classify[1], 1);
2546 edge[1] = 1;
2547 end[1][0] = 1.0;
2548 end[1][1] = f10 / b;
2549 if end[1][1] < 0.0 || end[1][1] > 1.0 {
2550 end[1][1] = 0.5
2551 }
2552 }
2553 } else if classify[0] == 0 {
2554 edge[0] = 2;
2555 end[0][0] = svalue[0];
2556 end[0][1] = 0.0;
2557 if classify[1] == -1 {
2558 edge[1] = 0;
2559 end[1][0] = 0.0;
2560 end[1][1] = f00 / b;
2561 if end[1][1] < 0.0 || end[1][1] > 1.0 {
2562 end[1][1] = 0.5
2563 }
2564 } else if classify[1] == 0 {
2565 edge[1] = 3;
2566 end[1][0] = svalue[1];
2567 end[1][1] = 1.0;
2568 } else {
2569 debug_assert_eq!(classify[1], 1);
2570 edge[1] = 1;
2571 end[1][0] = 1.0;
2572 end[1][1] = f10 / b;
2573 if end[1][1] < 0.0 || end[1][1] > 1.0 {
2574 end[1][1] = 0.5
2575 }
2576 }
2577 } else {
2578 debug_assert_eq!(classify[0], 1);
2579 edge[0] = 1;
2580 end[0][0] = 1.0;
2581 end[0][1] = f10 / b;
2582 if end[0][1] < 0.0 || end[0][1] > 1.0 {
2583 end[0][1] = 0.5
2584 }
2585 if classify[1] == 0 {
2586 edge[1] = 3;
2587 end[1][0] = svalue[1];
2588 end[1][1] = 1.0;
2589 } else {
2590 edge[1] = 0;
2591 end[1][0] = 0.0;
2592 end[1][1] = f00 / b;
2593 if end[1][1] < 0.0 || end[1][1] > 1.0 {
2594 end[1][1] = 0.5
2595 }
2596 }
2597 }
2598 let delta = end[1][1] - end[0][1];
2600 let h0 = delta * ((-b).mul_add (end[0][0], c.mul_add (end[0][1], -e)));
2602 if h0 >= 0.0 {
2603 param_a = (end[0][0] + end[1][0]) / 2.0;
2604 param_b = (end[0][1] + end[1][1]) / 2.0;
2605 } else {
2606 let h1 = delta * ((-b).mul_add (end[1][0], c.mul_add (end[1][1], -e)));
2608 if h1 <= 0.0 {
2609 if edge[1] == 0 {
2610 param_a = 0.0;
2611 param_b = clamped_root (*c, g00, g01);
2612 } else if edge[1] == 1 {
2613 param_a = 1.0;
2614 param_b = clamped_root (*c, g10, g11);
2615 } else {
2616 param_a = end[1][0];
2617 param_b = end[1][1];
2618 }
2619 } else {
2620 debug_assert!(h0 < 0.0);
2621 debug_assert!(h1 > 0.0);
2622 let z = (h0 / (h0 - h1)).clamp (0.0, 1.0);
2623 let omz = 1.0 - z;
2624 param_a = omz * end[0][0] + z * end[1][0];
2625 param_b = omz * end[0][1] + z * end[1][1];
2626 }
2627 }
2628 debug_assert_ne!(edge[0], u8::MAX);
2629 debug_assert_ne!(edge[1], u8::MAX);
2630 debug_assert_ne!(end[0][0], f64::NAN);
2631 debug_assert_ne!(end[0][1], f64::NAN);
2632 debug_assert_ne!(end[1][0], f64::NAN);
2633 debug_assert_ne!(end[1][1], f64::NAN);
2634 }
2635 let nearest_a = Point3::from (segment_a.point_a().0 * (1.0 - param_a)
2636 + segment_a.point_b().0 * param_a);
2637 let nearest_b = Point3::from (segment_b.point_a().0 * (1.0 - param_b)
2638 + segment_b.point_b().0 * param_b);
2639 let a_to_b = nearest_b - nearest_a;
2640 let distance = a_to_b.magnitude();
2641 let half_axis = a_to_b * 0.5;
2642 let midpoint = nearest_a + half_axis;
2643 let normal = if approx::relative_eq!(nearest_a, nearest_b,
2644 max_relative = f64::default_max_relative() * 2.0.powi (20),
2645 epsilon = f64::default_epsilon() * 2.0.powi (20))
2646 {
2647 let mut perp = vec_a.cross (*vec_b);
2649 if perp == Vector3::zero() {
2650 perp = vec_a.cross (Vector3::unit_z());
2652 if perp == Vector3::zero() {
2653 perp = vec_a.cross (Vector3::unit_x());
2655 }
2656 }
2657 Unit3::normalize (perp)
2658 } else {
2659 Unit3::normalize (-a_to_b)
2660 };
2661 Proximity { distance, half_axis, midpoint, normal }
2662 }
2663
2664 pub fn query_segment_point (
2665 segment : &geometry::Segment3 <f64>,
2666 point : &Point3 <f64>
2667 ) -> Self {
2668 let (s, nearest_a) = segment.nearest_point (*point);
2669 let nearest_b = *point;
2670 let a_to_b = nearest_b - nearest_a;
2671 let distance = a_to_b.magnitude();
2672 let half_axis = a_to_b * 0.5;
2673 let midpoint = nearest_a + half_axis;
2674 let normal = if approx::relative_eq!(nearest_a, nearest_b) {
2675 let perp = if *s == 0.0 {
2676 debug_assert_eq!(nearest_a, segment.point_a());
2677 -segment.vector()
2678 } else if *s == 1.0 {
2679 segment.vector()
2680 } else {
2681 segment.perpendicular()
2682 };
2683 *perp
2684 } else {
2685 -a_to_b
2686 }.normalize();
2687 Proximity { distance, half_axis, midpoint, normal }
2688 }
2689}
2690
2691fn triangle_distance_to_edges (triangle : geometry::Triangle3 <f64>, s : f64, t : f64)
2694 -> (f64, f64, f64)
2695{
2696 use approx::{AbsDiffEq, RelativeEq};
2697 debug_assert!(s + t <= 1.0);
2698 let b0 = 1.0 - s - t;
2700 let b1 = s;
2701 let b2 = t;
2702 let edge0 = triangle.point_c() - triangle.point_b();
2704 let edge1 = triangle.point_c() - triangle.point_a();
2705 let edge2 = triangle.point_b() - triangle.point_a();
2706 let len_e0_sq = edge0.magnitude_squared();
2707 let len_e1_sq = edge1.magnitude_squared();
2708 let len_e2_sq = edge2.magnitude_squared();
2709 let area_2_sq = triangle.normal().magnitude_squared();
2711 let d0 = b0 * (area_2_sq / len_e0_sq).sqrt();
2713 let d1 = b1 * (area_2_sq / len_e1_sq).sqrt();
2714 let d2 = b2 * (area_2_sq / len_e2_sq).sqrt();
2715 approx::assert_relative_eq!(
2716 triangle.barycentric ([b0, b1, b2].into()),
2717 triangle.trilinear ([d0, d1, d2].into()),
2718 max_relative = f64::default_max_relative() * 32.0,
2719 epsilon = f64::default_epsilon() * 32.0);
2720 (d0, d1, d2)
2721}
2722
2723fn clamped_root (slope : f64, h0 : f64, h1 : f64) -> f64 {
2724 if h0 < 0.0 {
2726 if h1 > 0.0 {
2727 let mut root = -h0 / slope;
2728 if root > 1.0 {
2729 root = 0.5
2730 }
2731 root
2732 } else {
2733 1.0
2734 }
2735 } else {
2736 0.0
2737 }
2738}
2739
2740#[cfg(test)]
2741mod tests {
2742 use approx::AbsDiffEq;
2743 use rand;
2744 use rand_distr;
2745 use rand_xorshift::XorShiftRng;
2746 use std::f64::consts::*;
2747 use super::*;
2748
2749 #[test]
2750 fn segment_point() {
2751 use geometry::Primitive;
2752 use rand::SeedableRng;
2753 use rand_distr::Distribution;
2754 let segment = geometry::Segment3::noisy (
2756 [-1.0, 0.0, 0.0].into(),
2757 [ 1.0, 0.0, 0.0].into());
2758 let point = point3 (0.0, 1.0, 0.0);
2759 let proximity = Proximity::query_segment_point (&segment, &point);
2760 assert_eq!(proximity.nearest_a(), [0.0, 0.0, 0.0].into());
2761 assert_eq!(proximity.nearest_b(), [0.0, 1.0, 0.0].into());
2762 assert_eq!(proximity.distance, 1.0);
2763 assert_eq!(proximity.half_axis, [0.0, 0.5, 0.0].into());
2764 assert_eq!(proximity.midpoint, [0.0, 0.5, 0.0].into());
2765 assert_eq!(proximity.normal, -Unit3::axis_y());
2766 let segment = geometry::Segment3::noisy (
2768 [-1.0, 0.0, 0.0].into(),
2769 [ 1.0, 0.0, 0.0].into());
2770 let point = point3 (0.0, 0.0, 0.0);
2771 let proximity = Proximity::query_segment_point (&segment, &point);
2772 assert_eq!(proximity.nearest_a(), [0.0, 0.0, 0.0].into());
2773 assert_eq!(proximity.nearest_b(), [0.0, 0.0, 0.0].into());
2774 assert_eq!(proximity.distance, 0.0);
2775 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
2776 assert_eq!(proximity.midpoint, [0.0, 0.0, 0.0].into());
2777 assert_eq!(proximity.normal, Unit3::axis_z());
2778 let segment = geometry::Segment3::noisy (
2780 [-1.0, 0.0, 0.0].into(),
2781 [ 1.0, 0.0, 0.0].into());
2782 let point = point3 (1.0, 0.0, 0.0);
2783 let proximity = Proximity::query_segment_point (&segment, &point);
2784 assert_eq!(proximity.nearest_a(), [1.0, 0.0, 0.0].into());
2785 assert_eq!(proximity.nearest_b(), [1.0, 0.0, 0.0].into());
2786 assert_eq!(proximity.distance, 0.0);
2787 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
2788 assert_eq!(proximity.midpoint, [1.0, 0.0, 0.0].into());
2789 assert_eq!(proximity.normal, segment.vector().normalize());
2790 let segment = geometry::Segment3::noisy (
2792 [-1.0, 0.0, 0.0].into(),
2793 [ 1.0, 0.0, 0.0].into());
2794 let point = point3 (0.0, 0.0, 0.0);
2795 let mut rng = XorShiftRng::seed_from_u64 (0);
2796 let std_normal = rand_distr::StandardNormal;
2797 let randf = |rng : &mut XorShiftRng| {
2799 let x : f64 = std_normal.sample (rng);
2800 let y : f64 = std_normal.sample (rng);
2801 x / y
2802 };
2803 for _ in 0..10000 {
2804 let translation = vector3 (randf (&mut rng), randf (&mut rng), randf (&mut rng));
2805 let mut segment = segment;
2806 segment.translate (translation);
2807 let point = point + translation;
2808 let proximity = Proximity::query_segment_point (&segment, &point);
2809 assert_eq!(proximity.normal, Unit3::axis_z());
2810 }
2811 }
2812
2813 #[test]
2814 fn segment_segment() {
2815 use approx::RelativeEq;
2816 use geometry::Primitive;
2817 use rand::SeedableRng;
2818 use rand_distr::Distribution;
2819 let segment1 = geometry::Segment3::noisy (
2821 [-2.0, 2.0, 0.0].into(),
2822 [ 2.0, 2.0, 0.0].into());
2823 let segment2 = geometry::Segment3::noisy (
2824 [-1.0, 0.0, 0.0].into(),
2825 [ 0.0, 0.0, 0.0].into());
2826 let proximity = Proximity::query_segment_segment (&segment1, &segment2);
2827 assert_eq!(proximity.nearest_a(), [-0.5, 2.0, 0.0].into());
2828 assert_eq!(proximity.nearest_b(), [-0.5, 0.0, 0.0].into());
2829 assert_eq!(proximity.distance, 2.0);
2830 assert_eq!(proximity.half_axis, [0.0, -1.0, 0.0].into());
2831 assert_eq!(proximity.midpoint, [-0.5, 1.0, 0.0].into());
2832 assert_eq!(proximity.normal, Unit3::noisy ([0.0, 1.0, 0.0].into()));
2833 let segment1 = geometry::Segment3::noisy (
2834 [-2.0, 2.0, 0.0].into(),
2835 [ 2.0, 2.0, 0.0].into());
2836 let segment2 = geometry::Segment3::noisy (
2837 [ 0.0, 0.0, 0.0].into(),
2838 [-3.0, 0.0, 0.0].into());
2839 let proximity = Proximity::query_segment_segment (&segment1, &segment2);
2840 assert_eq!(proximity.nearest_a(), [-1.0, 2.0, 0.0].into());
2841 assert_eq!(proximity.nearest_b(), [-1.0, 0.0, 0.0].into());
2842 assert_eq!(proximity.distance, 2.0);
2843 assert_eq!(proximity.half_axis, [0.0, -1.0, 0.0].into());
2844 assert_eq!(proximity.midpoint, [-1.0, 1.0, 0.0].into());
2845 assert_eq!(proximity.normal, Unit3::noisy ([0.0, 1.0, 0.0].into()));
2846 let segment1 = geometry::Segment3::noisy (
2847 [-2.0, 2.0, 0.0].into(),
2848 [ 2.0, 2.0, 0.0].into());
2849 let segment2 = geometry::Segment3::noisy (
2850 [ 0.0, 0.0, 0.0].into(),
2851 [ 3.0, 0.0, 0.0].into());
2852 let proximity = Proximity::query_segment_segment (&segment1, &segment2);
2853 assert_eq!(proximity.nearest_a(), [ 1.0, 2.0, 0.0].into());
2854 assert_eq!(proximity.nearest_b(), [ 1.0, 0.0, 0.0].into());
2855 assert_eq!(proximity.distance, 2.0);
2856 assert_eq!(proximity.half_axis, [0.0, -1.0, 0.0].into());
2857 assert_eq!(proximity.midpoint, [ 1.0, 1.0, 0.0].into());
2858 assert_eq!(proximity.normal, Unit3::noisy ([0.0, 1.0, 0.0].into()));
2859 let segment1 = geometry::Segment3::noisy (
2860 [-2.0, 2.0, 0.0].into(),
2861 [ 2.0, 2.0, 0.0].into());
2862 let segment2 = geometry::Segment3::noisy (
2863 [ 3.0, 0.0, 0.0].into(),
2864 [ 0.0, 0.0, 0.0].into());
2865 let proximity = Proximity::query_segment_segment (&segment1, &segment2);
2866 assert_eq!(proximity.nearest_a(), [ 1.0, 2.0, 0.0].into());
2867 assert_eq!(proximity.nearest_b(), [ 1.0, 0.0, 0.0].into());
2868 assert_eq!(proximity.distance, 2.0);
2869 assert_eq!(proximity.half_axis, [0.0, -1.0, 0.0].into());
2870 assert_eq!(proximity.midpoint, [ 1.0, 1.0, 0.0].into());
2871 assert_eq!(proximity.normal, Unit3::noisy ([0.0, 1.0, 0.0].into()));
2872 let segment1 = geometry::Segment3::noisy (
2873 [-2.0, 2.0, 0.0].into(),
2874 [ 2.0, 2.0, 0.0].into());
2875 let segment2 = geometry::Segment3::noisy (
2876 [-3.0, 0.0, 0.0].into(),
2877 [ 0.0, 0.0, 0.0].into());
2878 let proximity = Proximity::query_segment_segment (&segment1, &segment2);
2879 assert_eq!(proximity.nearest_a(), [0.0, 2.0, 0.0].into());
2880 assert_eq!(proximity.nearest_b(), [0.0, 0.0, 0.0].into());
2881 assert_eq!(proximity.distance, 2.0);
2882 assert_eq!(proximity.half_axis, [0.0, -1.0, 0.0].into());
2883 assert_eq!(proximity.midpoint, [0.0, 1.0, 0.0].into());
2884 assert_eq!(proximity.normal, Unit3::noisy ([0.0, 1.0, 0.0].into()));
2885 let segment1 = geometry::Segment3::noisy (
2886 [-2.0, 2.0, 0.0].into(),
2887 [ 2.0, 2.0, 0.0].into());
2888 let segment2 = geometry::Segment3::noisy (
2889 [ 1.0, -1.0, 0.0].into(),
2890 [ 1.0, 1.0, 0.0].into());
2891 let proximity = Proximity::query_segment_segment (&segment1, &segment2);
2892 assert_eq!(proximity.nearest_a(), [ 1.0, 2.0, 0.0].into());
2893 assert_eq!(proximity.nearest_b(), [ 1.0, 1.0, 0.0].into());
2894 assert_eq!(proximity.distance, 1.0);
2895 assert_eq!(proximity.half_axis, [0.0, -0.5, 0.0].into());
2896 assert_eq!(proximity.midpoint, [ 1.0, 1.5, 0.0].into());
2897 assert_eq!(proximity.normal, Unit3::noisy ([0.0, 1.0, 0.0].into()));
2898 let segment1 = geometry::Segment3::noisy (
2899 [-2.0, 2.0, 0.0].into(),
2900 [ 2.0, 2.0, 0.0].into());
2901 let segment2 = geometry::Segment3::noisy (
2902 [-3.0, 0.0, 0.0].into(),
2903 [-3.0, 3.0, 0.0].into());
2904 let proximity = Proximity::query_segment_segment (&segment1, &segment2);
2905 assert_eq!(proximity.nearest_a(), [-2.0, 2.0, 0.0].into());
2906 assert_eq!(proximity.nearest_b(), [-3.0, 2.0, 0.0].into());
2907 assert_eq!(proximity.distance, 1.0);
2908 assert_eq!(proximity.half_axis, [-0.5, 0.0, 0.0].into());
2909 assert_eq!(proximity.midpoint, [-2.5, 2.0, 0.0].into());
2910 assert_eq!(proximity.normal, Unit3::noisy ([1.0, 0.0, 0.0].into()));
2911 let segment1 = geometry::Segment3::noisy (
2912 [-2.0, 2.0, 0.0].into(),
2913 [ 2.0, 2.0, 0.0].into());
2914 let segment2 = geometry::Segment3::noisy (
2915 [ 3.0, 0.0, 0.0].into(),
2916 [ 3.0, 3.0, 0.0].into());
2917 let proximity = Proximity::query_segment_segment (&segment1, &segment2);
2918 assert_eq!(proximity.nearest_a(), [2.0, 2.0, 0.0].into());
2919 assert_eq!(proximity.nearest_b(), [3.0, 2.0, 0.0].into());
2920 assert_eq!(proximity.distance, 1.0);
2921 assert_eq!(proximity.half_axis, [0.5, 0.0, 0.0].into());
2922 assert_eq!(proximity.midpoint, [2.5, 2.0, 0.0].into());
2923 assert_eq!(proximity.normal, Unit3::noisy ([-1.0, 0.0, 0.0].into()));
2924 let segment1 = geometry::Segment3::noisy (
2926 [ 0.0, 1.0, 0.0].into(),
2927 [ 0.0, -1.0, 0.0].into());
2928 let segment2 = geometry::Segment3::noisy (
2929 [ -0.5, -0.5, -0.5].into(),
2930 [ 0.5, 0.5, 0.5].into());
2931 let proximity1 = Proximity::query_segment_segment (&segment1, &segment2);
2932 let mut rng = XorShiftRng::seed_from_u64 (0);
2933 let std_normal = rand_distr::StandardNormal;
2934 let randf = |rng : &mut XorShiftRng| {
2936 let x : f64 = std_normal.sample (rng);
2937 let y : f64 = std_normal.sample (rng);
2938 x / y
2939 };
2940 for _ in 0..10000 {
2941 let translation = vector3 (randf (&mut rng), randf (&mut rng), randf (&mut rng));
2942 let mut segment1 = segment1;
2943 let mut segment2 = segment2;
2944 segment1.translate (translation);
2945 segment2.translate (translation);
2946 let proximity = Proximity::query_segment_segment (&segment1, &segment2);
2947 approx::assert_relative_eq!(*proximity.normal, *proximity1.normal,
2948 max_relative = f64::default_max_relative() * 2.0.powi (10))
2949 }
2950 }
2951
2952 #[test]
2953 fn line_point() {
2954 use geometry::Primitive;
2955 use rand::SeedableRng;
2956 use rand_distr::Distribution;
2957 let line = geometry::Segment3::noisy (
2959 [-1.0, 0.0, 0.0].into(),
2960 [ 1.0, 0.0, 0.0].into());
2961 let point = point3 (0.0, 1.0, 0.0);
2962 let proximity = Proximity::query_line_point (&line, &point);
2963 assert_eq!(proximity.nearest_a(), [0.0, 0.0, 0.0].into());
2964 assert_eq!(proximity.nearest_b(), [0.0, 1.0, 0.0].into());
2965 assert_eq!(proximity.distance, 1.0);
2966 assert_eq!(proximity.half_axis, [0.0, 0.5, 0.0].into());
2967 assert_eq!(proximity.midpoint, [0.0, 0.5, 0.0].into());
2968 assert_eq!(proximity.normal, -Unit3::axis_y());
2969 let line = geometry::Segment3::noisy (
2971 [-1.0, 0.0, 0.0].into(),
2972 [ 1.0, 0.0, 0.0].into());
2973 let point = point3 (0.0, 0.0, 0.0);
2974 let proximity = Proximity::query_line_point (&line, &point);
2975 assert_eq!(proximity.nearest_a(), [0.0, 0.0, 0.0].into());
2976 assert_eq!(proximity.nearest_b(), [0.0, 0.0, 0.0].into());
2977 assert_eq!(proximity.distance, 0.0);
2978 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
2979 assert_eq!(proximity.midpoint, [0.0, 0.0, 0.0].into());
2980 assert_eq!(proximity.normal, Unit3::axis_z());
2981 let line = geometry::Segment3::noisy (
2983 [-1.0, 0.0, 0.0].into(),
2984 [ 1.0, 0.0, 0.0].into());
2985 let point = point3 (1.0, 0.0, 0.0);
2986 let proximity = Proximity::query_line_point (&line, &point);
2987 assert_eq!(proximity.nearest_a(), [1.0, 0.0, 0.0].into());
2988 assert_eq!(proximity.nearest_b(), [1.0, 0.0, 0.0].into());
2989 assert_eq!(proximity.distance, 0.0);
2990 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
2991 assert_eq!(proximity.midpoint, [1.0, 0.0, 0.0].into());
2992 assert_eq!(proximity.normal, Unit3::axis_z());
2993 let line = geometry::Segment3::noisy (
2995 [-1.0, 0.0, 0.0].into(),
2996 [ 1.0, 0.0, 0.0].into());
2997 let point = point3 (0.0, 0.0, 0.0);
2998 let mut rng = XorShiftRng::seed_from_u64 (0);
2999 let std_normal = rand_distr::StandardNormal;
3000 let randf = |rng : &mut XorShiftRng| {
3002 let x : f64 = std_normal.sample (rng);
3003 let y : f64 = std_normal.sample (rng);
3004 x / y
3005 };
3006 for _ in 0..10000 {
3007 let translation = vector3 (randf (&mut rng), randf (&mut rng), randf (&mut rng));
3008 let mut line = line;
3009 line.translate (translation);
3010 let point = point + translation;
3011 let proximity = Proximity::query_line_point (&line, &point);
3012 assert_eq!(proximity.normal, Unit3::axis_z());
3013 }
3014 }
3015
3016 #[test]
3017 fn line_segment() {
3018 use approx::RelativeEq;
3019 use geometry::Primitive;
3020 use rand::SeedableRng;
3021 use rand_distr::Distribution;
3022 let line = geometry::Segment3::noisy (
3024 [-2.0, 0.0, 0.0].into(),
3025 [ 2.0, 0.0, 0.0].into());
3026 let segment = geometry::Segment3::noisy (
3027 [-2.0, 2.0, 0.0].into(),
3028 [ 2.0, 2.0, 0.0].into());
3029 let proximity = Proximity::query_line_segment (&line, &segment);
3030 assert_eq!(proximity.nearest_a(), [-2.0, 0.0, 0.0].into());
3031 assert_eq!(proximity.nearest_b(), [-2.0, 2.0, 0.0].into());
3032 assert_eq!(proximity.distance, 2.0);
3033 assert_eq!(proximity.half_axis, [0.0, 1.0, 0.0].into());
3034 assert_eq!(proximity.midpoint, [-2.0, 1.0, 0.0].into());
3035 assert_eq!(proximity.normal, -Unit3::axis_y());
3036 let line = geometry::Segment3::noisy (
3037 [-5.0, 0.0, 0.0].into(),
3038 [-2.0, 0.0, 0.0].into());
3039 let segment = geometry::Segment3::noisy (
3040 [-2.0, 2.0, 0.0].into(),
3041 [ 2.0, 2.0, 0.0].into());
3042 let proximity = Proximity::query_line_segment (&line, &segment);
3043 assert_eq!(proximity.nearest_a(), [-2.0, 0.0, 0.0].into());
3044 assert_eq!(proximity.nearest_b(), [-2.0, 2.0, 0.0].into());
3045 assert_eq!(proximity.distance, 2.0);
3046 assert_eq!(proximity.half_axis, [0.0, 1.0, 0.0].into());
3047 assert_eq!(proximity.midpoint, [-2.0, 1.0, 0.0].into());
3048 assert_eq!(proximity.normal, -Unit3::axis_y());
3049 let line = geometry::Segment3::noisy (
3051 [0.0, -1.0, 0.0].into(),
3052 [0.0, 1.0, 0.0].into());
3053 let segment = geometry::Segment3::noisy (
3054 [1.0, 1.0, 0.0].into(),
3055 [3.0, 1.0, 0.0].into());
3056 let proximity = Proximity::query_line_segment (&line, &segment);
3057 assert_eq!(proximity.nearest_a(), [0.0, 1.0, 0.0].into());
3058 assert_eq!(proximity.nearest_b(), [1.0, 1.0, 0.0].into());
3059 assert_eq!(proximity.distance, 1.0);
3060 assert_eq!(proximity.half_axis, [0.5, 0.0, 0.0].into());
3061 assert_eq!(proximity.midpoint, [0.5, 1.0, 0.0].into());
3062 assert_eq!(proximity.normal, -Unit3::axis_x());
3063 let line = geometry::Segment3::noisy (
3064 [ 0.0, -1.0, 0.0].into(),
3065 [ 0.0, 1.0, 0.0].into());
3066 let segment = geometry::Segment3::noisy (
3067 [-3.0, 1.0, 0.0].into(),
3068 [-1.0, 1.0, 0.0].into());
3069 let proximity = Proximity::query_line_segment (&line, &segment);
3070 assert_eq!(proximity.nearest_a(), [ 0.0, 1.0, 0.0].into());
3071 assert_eq!(proximity.nearest_b(), [-1.0, 1.0, 0.0].into());
3072 assert_eq!(proximity.distance, 1.0);
3073 assert_eq!(proximity.half_axis, [-0.5, 0.0, 0.0].into());
3074 assert_eq!(proximity.midpoint, [-0.5, 1.0, 0.0].into());
3075 assert_eq!(proximity.normal, Unit3::axis_x());
3076 let line = geometry::Segment3::noisy (
3078 [ 0.0, -1.0, 0.0].into(),
3079 [ 0.0, 1.0, 0.0].into());
3080 let segment = geometry::Segment3::noisy (
3081 [-2.0, 2.0, 1.0].into(),
3082 [ 2.0, 2.0, 1.0].into());
3083 let proximity = Proximity::query_line_segment (&line, &segment);
3084 assert_eq!(proximity.nearest_a(), [ 0.0, 2.0, 0.0].into());
3085 assert_eq!(proximity.nearest_b(), [ 0.0, 2.0, 1.0].into());
3086 assert_eq!(proximity.distance, 1.0);
3087 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.5].into());
3088 assert_eq!(proximity.midpoint, [0.0, 2.0, 0.5].into());
3089 assert_eq!(proximity.normal, -Unit3::axis_z());
3090 let line = geometry::Segment3::noisy (
3092 [ 0.0, -1.0, 0.0].into(),
3093 [ 0.0, 1.0, 0.0].into());
3094 let segment = geometry::Segment3::noisy (
3095 [-2.0, 2.0, 0.0].into(),
3096 [ 2.0, 2.0, 0.0].into());
3097 let proximity = Proximity::query_line_segment (&line, &segment);
3098 assert_eq!(proximity.nearest_a(), [ 0.0, 2.0, 0.0].into());
3099 assert_eq!(proximity.nearest_b(), [ 0.0, 2.0, 0.0].into());
3100 assert_eq!(proximity.distance, 0.0);
3101 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3102 assert_eq!(proximity.midpoint, [0.0, 2.0, 0.0].into());
3103 assert_eq!(proximity.normal, Unit3::axis_z());
3104 let line = geometry::Segment3::noisy (
3106 [-2.0, -1.0, 0.0].into(),
3107 [-2.0, 1.0, 0.0].into());
3108 let segment = geometry::Segment3::noisy (
3109 [-2.0, 2.0, 0.0].into(),
3110 [ 2.0, 2.0, 0.0].into());
3111 let proximity = Proximity::query_line_segment (&line, &segment);
3112 assert_eq!(proximity.nearest_a(), [-2.0, 2.0, 0.0].into());
3113 assert_eq!(proximity.nearest_b(), [-2.0, 2.0, 0.0].into());
3114 assert_eq!(proximity.distance, 0.0);
3115 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3116 assert_eq!(proximity.midpoint, [-2.0, 2.0, 0.0].into());
3117 assert_eq!(proximity.normal, -Unit3::axis_x());
3118 let line = geometry::Segment3::noisy (
3119 [-2.0, -1.0, 0.0].into(),
3120 [-2.0, 1.0, 0.0].into());
3121 let segment = geometry::Segment3::noisy (
3122 [-2.0, 2.0, 0.0].into(),
3123 [ 2.0, -2.0, 0.0].into());
3124 let proximity = Proximity::query_line_segment (&line, &segment);
3125 assert_eq!(proximity.nearest_a(), [-2.0, 2.0, 0.0].into());
3126 assert_eq!(proximity.nearest_b(), [-2.0, 2.0, 0.0].into());
3127 assert_eq!(proximity.distance, 0.0);
3128 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3129 assert_eq!(proximity.midpoint, [-2.0, 2.0, 0.0].into());
3130 assert_eq!(proximity.normal, -Unit3::axis_x());
3131 let line = geometry::Segment3::noisy (
3133 [ 2.0, -1.0, 0.0].into(),
3134 [ 2.0, 1.0, 0.0].into());
3135 let segment = geometry::Segment3::noisy (
3136 [-2.0, 2.0, 0.0].into(),
3137 [ 2.0, 2.0, 0.0].into());
3138 let proximity = Proximity::query_line_segment (&line, &segment);
3139 assert_eq!(proximity.nearest_a(), [2.0, 2.0, 0.0].into());
3140 assert_eq!(proximity.nearest_b(), [2.0, 2.0, 0.0].into());
3141 assert_eq!(proximity.distance, 0.0);
3142 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3143 assert_eq!(proximity.midpoint, [2.0, 2.0, 0.0].into());
3144 assert_eq!(proximity.normal, Unit3::axis_x());
3145 let line = geometry::Segment3::noisy (
3146 [ 2.0, -1.0, 0.0].into(),
3147 [ 2.0, 1.0, 0.0].into());
3148 let segment = geometry::Segment3::noisy (
3149 [-2.0, 2.0, 0.0].into(),
3150 [ 2.0, 0.0, 0.0].into());
3151 let proximity = Proximity::query_line_segment (&line, &segment);
3152 assert_eq!(proximity.nearest_a(), [2.0, 0.0, 0.0].into());
3153 assert_eq!(proximity.nearest_b(), [2.0, 0.0, 0.0].into());
3154 assert_eq!(proximity.distance, 0.0);
3155 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3156 assert_eq!(proximity.midpoint, [2.0, 0.0, 0.0].into());
3157 assert_eq!(proximity.normal, Unit3::axis_x());
3158 let line = geometry::Segment3::noisy (
3160 [-1.0, 2.0, 0.0].into(),
3161 [ 0.0, 2.0, 0.0].into());
3162 let segment = geometry::Segment3::noisy (
3163 [-2.0, 2.0, 0.0].into(),
3164 [ 2.0, 2.0, 0.0].into());
3165 let proximity = Proximity::query_line_segment (&line, &segment);
3166 assert_eq!(proximity.nearest_a(), [-2.0, 2.0, 0.0].into());
3167 assert_eq!(proximity.nearest_b(), [-2.0, 2.0, 0.0].into());
3168 assert_eq!(proximity.distance, 0.0);
3169 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3170 assert_eq!(proximity.midpoint, [-2.0, 2.0, 0.0].into());
3171 assert_eq!(proximity.normal, Unit3::axis_z());
3172 let line = geometry::Segment3::noisy (
3174 [ -0.5, -0.5, -0.5].into(),
3175 [ 0.5, 0.5, 0.5].into());
3176 let segment = geometry::Segment3::noisy (
3177 [ 0.0, 1.0, 0.0].into(),
3178 [ 0.0, -1.0, 0.0].into());
3179 let proximity1 = Proximity::query_line_segment (&line, &segment);
3180 let mut rng = XorShiftRng::seed_from_u64 (0);
3181 let std_normal = rand_distr::StandardNormal;
3182 let randf = |rng : &mut XorShiftRng| {
3184 let x : f64 = std_normal.sample (rng);
3185 let y : f64 = std_normal.sample (rng);
3186 x / y
3187 };
3188 for _ in 0..10000 {
3189 let translation = vector3 (randf (&mut rng), randf (&mut rng), randf (&mut rng));
3190 let mut line = line;
3191 let mut segment = segment;
3192 line.translate (translation);
3193 segment.translate (translation);
3194 let proximity = Proximity::query_line_segment (&line, &segment);
3195 approx::assert_relative_eq!(*proximity.normal, *proximity1.normal,
3196 max_relative = f64::default_max_relative() * 2.0.powi (10))
3197 }
3198 }
3199
3200 #[test]
3201 fn line_line() {
3202 use approx::RelativeEq;
3203 use geometry::Primitive;
3204 use rand::SeedableRng;
3205 use rand_distr::Distribution;
3206 let line_a = geometry::Segment3::noisy (
3208 [-2.0, 0.0, 0.0].into(),
3209 [ 2.0, 0.0, 0.0].into());
3210 let line_b = geometry::Segment3::noisy (
3211 [-2.0, 2.0, 0.0].into(),
3212 [ 2.0, 2.0, 0.0].into());
3213 let proximity = Proximity::query_line_line (&line_a, &line_b);
3214 assert_eq!(proximity.nearest_a(), [-2.0, 0.0, 0.0].into());
3215 assert_eq!(proximity.nearest_b(), [-2.0, 2.0, 0.0].into());
3216 assert_eq!(proximity.distance, 2.0);
3217 assert_eq!(proximity.half_axis, [0.0, 1.0, 0.0].into());
3218 assert_eq!(proximity.midpoint, [-2.0, 1.0, 0.0].into());
3219 assert_eq!(proximity.normal, -Unit3::axis_y());
3220 let line_a = geometry::Segment3::noisy (
3221 [-5.0, 0.0, 0.0].into(),
3222 [-2.0, 0.0, 0.0].into());
3223 let line_b = geometry::Segment3::noisy (
3224 [-2.0, 2.0, 0.0].into(),
3225 [ 2.0, 2.0, 0.0].into());
3226 let proximity = Proximity::query_line_line (&line_a, &line_b);
3227 assert_eq!(proximity.nearest_a(), [-2.0, 0.0, 0.0].into());
3228 assert_eq!(proximity.nearest_b(), [-2.0, 2.0, 0.0].into());
3229 assert_eq!(proximity.distance, 2.0);
3230 assert_eq!(proximity.half_axis, [0.0, 1.0, 0.0].into());
3231 assert_eq!(proximity.midpoint, [-2.0, 1.0, 0.0].into());
3232 assert_eq!(proximity.normal, -Unit3::axis_y());
3233 let line_a = geometry::Segment3::noisy (
3235 [0.0, -1.0, 0.0].into(),
3236 [0.0, 1.0, 0.0].into());
3237 let line_b = geometry::Segment3::noisy (
3238 [1.0, 1.0, 0.0].into(),
3239 [3.0, 1.0, 0.0].into());
3240 let proximity = Proximity::query_line_line (&line_a, &line_b);
3241 assert_eq!(proximity.nearest_a(), [0.0, 1.0, 0.0].into());
3242 assert_eq!(proximity.nearest_b(), [0.0, 1.0, 0.0].into());
3243 assert_eq!(proximity.distance, 0.0);
3244 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3245 assert_eq!(proximity.midpoint, [0.0, 1.0, 0.0].into());
3246 assert_eq!(proximity.normal, -Unit3::axis_z());
3247 let line_a = geometry::Segment3::noisy (
3248 [ 0.0, -1.0, 0.0].into(),
3249 [ 0.0, 1.0, 0.0].into());
3250 let line_b = geometry::Segment3::noisy (
3251 [-3.0, 1.0, 0.0].into(),
3252 [-1.0, 1.0, 0.0].into());
3253 let proximity = Proximity::query_line_line (&line_a, &line_b);
3254 assert_eq!(proximity.nearest_a(), [0.0, 1.0, 0.0].into());
3255 assert_eq!(proximity.nearest_b(), [0.0, 1.0, 0.0].into());
3256 assert_eq!(proximity.distance, 0.0);
3257 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3258 assert_eq!(proximity.midpoint, [0.0, 1.0, 0.0].into());
3259 assert_eq!(proximity.normal, -Unit3::axis_z());
3260 let line_a = geometry::Segment3::noisy (
3262 [ 0.0, -1.0, 0.0].into(),
3263 [ 0.0, 1.0, 0.0].into());
3264 let line_b = geometry::Segment3::noisy (
3265 [-2.0, 2.0, 1.0].into(),
3266 [ 2.0, 2.0, 1.0].into());
3267 let proximity = Proximity::query_line_line (&line_a, &line_b);
3268 assert_eq!(proximity.nearest_a(), [ 0.0, 2.0, 0.0].into());
3269 assert_eq!(proximity.nearest_b(), [ 0.0, 2.0, 1.0].into());
3270 assert_eq!(proximity.distance, 1.0);
3271 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.5].into());
3272 assert_eq!(proximity.midpoint, [0.0, 2.0, 0.5].into());
3273 assert_eq!(proximity.normal, -Unit3::axis_z());
3274 let line_a = geometry::Segment3::noisy (
3276 [ 0.0, -1.0, 0.0].into(),
3277 [ 0.0, 1.0, 0.0].into());
3278 let line_b = geometry::Segment3::noisy (
3279 [-2.0, 2.0, 0.0].into(),
3280 [ 2.0, 2.0, 0.0].into());
3281 let proximity = Proximity::query_line_line (&line_a, &line_b);
3282 assert_eq!(proximity.nearest_a(), [ 0.0, 2.0, 0.0].into());
3283 assert_eq!(proximity.nearest_b(), [ 0.0, 2.0, 0.0].into());
3284 assert_eq!(proximity.distance, 0.0);
3285 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3286 assert_eq!(proximity.midpoint, [0.0, 2.0, 0.0].into());
3287 assert_eq!(proximity.normal, -Unit3::axis_z());
3288 let line_a = geometry::Segment3::noisy (
3290 [-2.0, -1.0, 0.0].into(),
3291 [-2.0, 1.0, 0.0].into());
3292 let line_b = geometry::Segment3::noisy (
3293 [-2.0, 2.0, 0.0].into(),
3294 [ 2.0, 2.0, 0.0].into());
3295 let proximity = Proximity::query_line_line (&line_a, &line_b);
3296 assert_eq!(proximity.nearest_a(), [-2.0, 2.0, 0.0].into());
3297 assert_eq!(proximity.nearest_b(), [-2.0, 2.0, 0.0].into());
3298 assert_eq!(proximity.distance, 0.0);
3299 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3300 assert_eq!(proximity.midpoint, [-2.0, 2.0, 0.0].into());
3301 assert_eq!(proximity.normal, -Unit3::axis_z());
3302 let line_a = geometry::Segment3::noisy (
3303 [-2.0, -1.0, 0.0].into(),
3304 [-2.0, 1.0, 0.0].into());
3305 let line_b = geometry::Segment3::noisy (
3306 [-2.0, 2.0, 0.0].into(),
3307 [ 2.0, -2.0, 0.0].into());
3308 let proximity = Proximity::query_line_line (&line_a, &line_b);
3309 assert_eq!(proximity.nearest_a(), [-2.0, 2.0, 0.0].into());
3310 assert_eq!(proximity.nearest_b(), [-2.0, 2.0, 0.0].into());
3311 assert_eq!(proximity.distance, 0.0);
3312 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3313 assert_eq!(proximity.midpoint, [-2.0, 2.0, 0.0].into());
3314 assert_eq!(proximity.normal, -Unit3::axis_z());
3315 let line_a = geometry::Segment3::noisy (
3317 [ 2.0, -1.0, 0.0].into(),
3318 [ 2.0, 1.0, 0.0].into());
3319 let line_b = geometry::Segment3::noisy (
3320 [-2.0, 2.0, 0.0].into(),
3321 [ 2.0, 2.0, 0.0].into());
3322 let proximity = Proximity::query_line_line (&line_a, &line_b);
3323 assert_eq!(proximity.nearest_a(), [2.0, 2.0, 0.0].into());
3324 assert_eq!(proximity.nearest_b(), [2.0, 2.0, 0.0].into());
3325 assert_eq!(proximity.distance, 0.0);
3326 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3327 assert_eq!(proximity.midpoint, [2.0, 2.0, 0.0].into());
3328 assert_eq!(proximity.normal, -Unit3::axis_z());
3329 let line_a = geometry::Segment3::noisy (
3330 [ 2.0, -1.0, 0.0].into(),
3331 [ 2.0, 1.0, 0.0].into());
3332 let line_b = geometry::Segment3::noisy (
3333 [-2.0, 2.0, 0.0].into(),
3334 [ 2.0, 0.0, 0.0].into());
3335 let proximity = Proximity::query_line_line (&line_a, &line_b);
3336 assert_eq!(proximity.nearest_a(), [2.0, 0.0, 0.0].into());
3337 assert_eq!(proximity.nearest_b(), [2.0, 0.0, 0.0].into());
3338 assert_eq!(proximity.distance, 0.0);
3339 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3340 assert_eq!(proximity.midpoint, [2.0, 0.0, 0.0].into());
3341 assert_eq!(proximity.normal, -Unit3::axis_z());
3342 let line_a = geometry::Segment3::noisy (
3344 [-1.0, 2.0, 0.0].into(),
3345 [ 0.0, 2.0, 0.0].into());
3346 let line_b = geometry::Segment3::noisy (
3347 [-2.0, 2.0, 0.0].into(),
3348 [ 2.0, 2.0, 0.0].into());
3349 let proximity = Proximity::query_line_line (&line_a, &line_b);
3350 assert_eq!(proximity.nearest_a(), [-2.0, 2.0, 0.0].into());
3351 assert_eq!(proximity.nearest_b(), [-2.0, 2.0, 0.0].into());
3352 assert_eq!(proximity.distance, 0.0);
3353 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3354 assert_eq!(proximity.midpoint, [-2.0, 2.0, 0.0].into());
3355 assert_eq!(proximity.normal, Unit3::axis_z());
3356 let line_a = geometry::Segment3::noisy (
3358 [ -0.5, -0.5, -0.5].into(),
3359 [ 0.5, 0.5, 0.5].into());
3360 let line_b = geometry::Segment3::noisy (
3361 [ 0.0, 1.0, 0.0].into(),
3362 [ 0.0, -1.0, 0.0].into());
3363 let proximity1 = Proximity::query_line_line (&line_a, &line_b);
3364 let mut rng = XorShiftRng::seed_from_u64 (0);
3365 let std_normal = rand_distr::StandardNormal;
3366 let randf = |rng : &mut XorShiftRng| {
3368 let x : f64 = std_normal.sample (rng);
3369 let y : f64 = std_normal.sample (rng);
3370 x / y
3371 };
3372 for _ in 0..10000 {
3373 let translation = vector3 (randf (&mut rng), randf (&mut rng), randf (&mut rng));
3374 let mut line_a = line_a;
3375 let mut line_b = line_b;
3376 line_a.translate (translation);
3377 line_b.translate (translation);
3378 let proximity = Proximity::query_line_line (&line_a, &line_b);
3379 approx::assert_relative_eq!(*proximity.normal, *proximity1.normal,
3380 max_relative = f64::default_max_relative() * 2.0.powi (10))
3381 }
3382 }
3383
3384 #[test]
3385 fn triangle_point() {
3386 use approx::RelativeEq;
3387 use geometry::Primitive;
3388 use rand::SeedableRng;
3389 use rand_distr::Distribution;
3390 let triangle = geometry::Triangle3::noisy (
3391 [-1.0, -1.0, 0.0].into(),
3392 [ 1.0, -1.0, 0.0].into(),
3393 [ 0.0, 1.0, 0.0].into());
3394 let point = point3 (0.0, 0.0, 0.0);
3395 let proximity = Proximity::query_triangle_point (&triangle, &point);
3396 assert_eq!(proximity.nearest_a(), [0.0, 0.0, 0.0].into());
3397 assert_eq!(proximity.nearest_b(), [0.0, 0.0, 0.0].into());
3398 assert_eq!(proximity.distance, 0.0);
3399 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3400 assert_eq!(proximity.midpoint, [0.0, 0.0, 0.0].into());
3401 assert_eq!(proximity.normal, Unit3::axis_z());
3402 let triangle = geometry::Triangle3::noisy (
3403 [-1.0, -1.0, 0.0].into(),
3404 [ 1.0, -1.0, 0.0].into(),
3405 [ 0.0, 1.0, 0.0].into());
3406 let point = point3 (0.5, 0.0, 0.0);
3407 let proximity = Proximity::query_triangle_point (&triangle, &point);
3408 assert_eq!(proximity.nearest_a(), [0.5, 0.0, 0.0].into());
3409 assert_eq!(proximity.nearest_b(), [0.5, 0.0, 0.0].into());
3410 assert_eq!(proximity.distance, 0.0);
3411 assert_eq!(proximity.half_axis, [0.0, 0.0, 0.0].into());
3412 assert_eq!(proximity.midpoint, [0.5, 0.0, 0.0].into());
3413 assert_eq!(proximity.normal, Unit3::normalize ([-2.0, -1.0, 0.0].into()));
3414 let triangle = geometry::Triangle3::noisy (
3415 [ 0.0, -2.0, 3.5].into(),
3416 [ 2.0, 2.0, 3.5].into(),
3417 [-2.0, 2.0, 3.5].into());
3418 let point = point3 (0.0, 0.0, 2.0);
3419 let proximity = Proximity::query_triangle_point (&triangle, &point);
3420 assert_eq!(proximity.distance, 1.5);
3421 assert_eq!(proximity.half_axis, [0.0, 0.0, -0.75].into());
3422 assert_eq!(proximity.midpoint, [0.0, 0.0, 2.75].into());
3423 assert_eq!(proximity.normal, Unit3::axis_z());
3424 assert_eq!(proximity.nearest_a(), [0.0, 0.0, 3.5].into());
3425 assert_eq!(proximity.nearest_b(), [0.0, 0.0, 2.0].into());
3426 let triangle = geometry::Triangle3::noisy (
3428 [-1.0, -1.0, 0.0].into(),
3429 [ 1.0, -1.0, 0.0].into(),
3430 [ 0.0, 1.0, 0.0].into());
3431 let point = point3 (1.0, 0.0, 0.0);
3432 let proximity1 = Proximity::query_triangle_point (&triangle, &point);
3433 let mut rng = XorShiftRng::seed_from_u64 (0);
3434 let std_normal = rand_distr::StandardNormal;
3435 let randf = |rng : &mut XorShiftRng| {
3437 let x : f64 = std_normal.sample (rng);
3438 let y : f64 = std_normal.sample (rng);
3439 x / y
3440 };
3441 for _ in 0..10000 {
3442 let translation = vector3 (randf (&mut rng), randf (&mut rng), randf (&mut rng));
3443 let mut triangle = triangle;
3444 triangle.translate (translation);
3445 let point = point + translation;
3446 let proximity = Proximity::query_triangle_point (&triangle, &point);
3447 approx::assert_relative_eq!(*proximity.normal, *proximity1.normal,
3448 max_relative = f64::default_max_relative() * 2.0.powi (12));
3449 }
3450 }
3451
3452 #[test]
3453 fn triangle_segment() {
3454 use approx::RelativeEq;
3455 use geometry::Primitive;
3456 use rand::SeedableRng;
3457 use rand_distr::Distribution;
3458 let mut triangle = geometry::Triangle3::noisy (
3459 [-1.0, -1.0, 0.0].into(),
3460 [ 1.0, -1.0, 0.0].into(),
3461 [ 0.0, 1.0, 0.0].into());
3462 let mut segment = geometry::Segment3::noisy (
3463 [-2.0, -2.0, -0.01].into(),
3464 [ 2.0, 2.0, 0.01].into());
3465 let proximity = Proximity::query_triangle_segment (&triangle, &segment);
3466 triangle.translate (proximity.half_axis);
3467 segment.translate (-proximity.half_axis);
3468 let proximity = Proximity::query_triangle_segment (&triangle, &segment);
3469 approx::assert_abs_diff_eq!(proximity.distance, 0.0,
3470 epsilon = f64::default_epsilon() * 2.0);
3471 let mut triangle = geometry::Triangle3::noisy (
3472 [-1.0, -1.0, 0.0].into(),
3473 [ 1.0, -1.0, 0.0].into(),
3474 [ 0.0, 1.0, 0.0].into());
3475 let mut segment = geometry::Segment3::noisy (
3476 [-2.0, 2.0, -10.0].into(),
3477 [ 2.0, -2.0, 10.0].into());
3478 let proximity = Proximity::query_triangle_segment (&triangle, &segment);
3479 triangle.translate (proximity.half_axis);
3480 segment.translate (-proximity.half_axis);
3481 let proximity = Proximity::query_triangle_segment (&triangle, &segment);
3482 approx::assert_abs_diff_eq!(proximity.distance, 0.0,
3483 epsilon = f64::default_epsilon() * 2.0);
3484 let triangle = geometry::Triangle3::noisy (
3486 [-1.0, -1.0, 0.0].into(),
3487 [ 1.0, -1.0, 0.0].into(),
3488 [ 0.0, 1.0, 0.0].into());
3489 let segment = geometry::Segment3::noisy (
3490 [-1.5, 0.0, -2.0].into(),
3491 [ 2.0, 0.0, 2.0].into());
3492 let proximity1 = Proximity::query_triangle_segment (&triangle, &segment);
3493 println!("normal: {}", *proximity1.normal);
3494 let mut rng = XorShiftRng::seed_from_u64 (0);
3495 let std_normal = rand_distr::StandardNormal;
3496 let randf = |rng : &mut XorShiftRng| {
3498 let x : f64 = std_normal.sample (rng);
3499 let y : f64 = std_normal.sample (rng);
3500 x / y
3501 };
3502 for _ in 0..10000 {
3503 let translation = vector3 (randf (&mut rng), randf (&mut rng), randf (&mut rng));
3504 let mut triangle = triangle;
3505 let mut segment = segment;
3506 triangle.translate (translation);
3507 segment.translate (translation);
3508 let proximity = Proximity::query_triangle_segment (&triangle, &segment);
3509 approx::assert_relative_eq!(*proximity.normal, *proximity1.normal,
3510 max_relative = f64::default_max_relative() * 2.0.powi (10))
3511 }
3512 }
3513
3514 #[test]
3515 fn triangle_line() {
3516 use approx::RelativeEq;
3517 use geometry::Primitive;
3518 use rand::SeedableRng;
3519 use rand_distr::Distribution;
3520 let triangle = geometry::Triangle3::noisy (
3521 [-1.0, -1.0, 0.0].into(),
3522 [ 1.0, -1.0, 0.0].into(),
3523 [ 0.0, 1.0, 0.0].into()
3524 );
3525 let line = geometry::Segment3::noisy (
3526 [-2.0, 2.0, 0.0].into(),
3527 [ 2.0, 2.0, 0.0].into());
3528 let proximity = Proximity::query_triangle_line (&triangle, &line);
3529 assert_eq!(proximity.nearest_a(), [0.0, 1.0, 0.0].into());
3530 assert_eq!(proximity.nearest_b(), [0.0, 2.0, 0.0].into());
3531 assert_eq!(proximity.distance, 1.0);
3532 assert_eq!(proximity.half_axis, [0.0, 0.5, 0.0].into());
3533 assert_eq!(proximity.midpoint, [0.0, 1.5, 0.0].into());
3534 assert_eq!(proximity.normal, -Unit3::axis_y());
3535 let triangle = geometry::Triangle3::noisy (
3537 [-1.0, -1.0, 0.0].into(),
3538 [ 1.0, -1.0, 0.0].into(),
3539 [ 0.0, 1.0, 0.0].into());
3540 let line = geometry::Segment3::noisy (
3541 [-2.0, 0.0, 0.0].into(),
3542 [ 2.0, 0.0, 0.0].into());
3543 let proximity1 = Proximity::query_triangle_line (&triangle, &line);
3544 let mut rng = XorShiftRng::seed_from_u64 (0);
3545 let std_normal = rand_distr::StandardNormal;
3546 let randf = |rng : &mut XorShiftRng| {
3548 let x : f64 = std_normal.sample (rng);
3549 let y : f64 = std_normal.sample (rng);
3550 x / y
3551 };
3552 for _ in 0..10000 {
3553 let translation = vector3 (randf (&mut rng), randf (&mut rng), randf (&mut rng));
3554 let mut triangle = triangle;
3555 let mut line = line;
3556 triangle.translate (translation);
3557 line.translate (translation);
3558 let proximity = Proximity::query_triangle_line (&triangle, &line);
3559 approx::assert_relative_eq!(*proximity.normal, *proximity1.normal,
3560 max_relative = f64::default_max_relative() * 2.0.powi (10))
3561 }
3562 }
3563
3564 #[test]
3565 #[expect(clippy::unreadable_literal)]
3566 fn triangle_triangle() {
3567 use approx::RelativeEq;
3568 use geometry::Primitive;
3569 use rand::SeedableRng;
3570 use rand_distr::Distribution;
3571 let triangle_a = geometry::Triangle3::noisy (
3572 [-3.0, 0.0, 0.0].into(),
3573 [-1.0, 0.0, 0.0].into(),
3574 [-2.0, 2.0, 0.0].into());
3575 let triangle_b = geometry::Triangle3::noisy (
3576 [ 3.0, 0.0, 0.0].into(),
3577 [ 1.0, 0.0, 0.0].into(),
3578 [ 2.0, 2.0, 0.0].into());
3579 let proximity = Proximity::query_triangle_triangle (&triangle_a, &triangle_b);
3580 assert_eq!(proximity, Proximity {
3581 distance: 2.0,
3582 half_axis: [1.0, 0.0, 0.0].into(),
3583 midpoint: [0.0, 0.0, 0.0].into(),
3584 normal: -Unit3::axis_x()
3585 });
3586 let triangle_a = geometry::Triangle3::noisy (
3587 [-2.0, -2.0, 0.0].into(),
3588 [ 2.0, -2.0, 0.0].into(),
3589 [ 0.0, 2.0, 0.0].into());
3590 let triangle_b = geometry::Triangle3::noisy (
3591 [-0.5, 0.0, -0.1].into(),
3592 [ 0.5, 0.0, -0.1].into(),
3593 [ 0.0, 0.0, 2.0].into());
3594 let proximity = Proximity::query_triangle_triangle (&triangle_a, &triangle_b);
3595 assert_eq!(proximity.distance, -0.1);
3596 approx::assert_relative_eq!(proximity.half_axis, [0.0, 0.0, -0.05].into());
3597 let triangle_a = geometry::Triangle3::noisy (
3598 [-2.0, -2.0, 0.0].into(),
3599 [ 2.0, -2.0, 0.0].into(),
3600 [ 0.0, 2.0, 0.0].into());
3601 let triangle_b = geometry::Triangle3::noisy (
3602 [-1.0, 0.0, -0.1].into(),
3603 [ 1.0, 0.0, -0.1].into(),
3604 [ 0.0, 0.0, 2.0].into());
3605 let proximity = Proximity::query_triangle_triangle (&triangle_a, &triangle_b);
3606 assert_eq!(proximity.distance, -0.1);
3607 assert_eq!(proximity.half_axis, [0.0, 0.0, -0.05].into());
3608 let mut triangle_a = geometry::Triangle3::noisy (
3609 [-2.0, -2.0, 0.0].into(),
3610 [ 2.0, -2.0, 0.0].into(),
3611 [ 0.0, 2.0, 0.0].into());
3612 let mut triangle_b = geometry::Triangle3::noisy (
3613 [ 0.0, 0.0, -2.0].into(),
3614 [-1.0, 0.0, 2.0].into(),
3615 [ 1.0, 0.0, 2.0].into());
3616 let proximity = Proximity::query_triangle_triangle (&triangle_a, &triangle_b);
3617 assert_eq!(proximity, Proximity {
3618 distance: -1.3093073414159542,
3619 half_axis: [0.5714285714285714, -0.2857142857142857, -0.1428571428571429].into(),
3620 midpoint: [-0.14285714285714285, 0.28571428571428564, -0.1428571428571429].into(),
3621 normal: Unit3::noisy (
3622 [0.8728715609439696, -0.4364357804719848, -0.2182178902359924].into())
3623 });
3624 triangle_a.translate (proximity.half_axis * 0.5);
3626 triangle_b.translate (-proximity.half_axis * 0.5);
3627 let proximity1 = Proximity::query_triangle_triangle (&triangle_a, &triangle_b);
3628 approx::assert_relative_eq!(proximity1.distance * 2.0, proximity.distance,
3629 max_relative = f64::default_max_relative() * 2.0);
3630 approx::assert_relative_eq!(proximity1.half_axis * 2.0, proximity.half_axis,
3631 max_relative = f64::default_max_relative() * 16.0);
3632 approx::assert_relative_eq!(proximity1.midpoint, proximity.midpoint,
3633 max_relative = f64::default_max_relative() * 8.0);
3634 approx::assert_relative_eq!(*proximity1.normal, *proximity.normal);
3635 let mut rng = XorShiftRng::seed_from_u64 (0);
3637 let std_normal = rand_distr::StandardNormal;
3638 let randf = |rng : &mut XorShiftRng| {
3640 let x : f64 = std_normal.sample (rng);
3641 let y : f64 = std_normal.sample (rng);
3642 x / y
3643 };
3644 for _i in 0..5000 {
3645 let translation = vector3 (randf (&mut rng), randf (&mut rng), randf (&mut rng));
3646 let mut triangle_a = triangle_a;
3647 let mut triangle_b = triangle_b;
3648 triangle_a.translate (translation);
3649 triangle_b.translate (translation);
3650 let proximity = Proximity::query_triangle_triangle (&triangle_a, &triangle_b);
3651 approx::assert_relative_eq!(*proximity.normal, *proximity1.normal,
3652 max_relative = f64::default_max_relative() * 2.0.powi (10))
3653 }
3654 }
3655
3656 #[test]
3657 #[expect(clippy::suboptimal_flops)]
3658 fn distance_query() {
3659 use rand::{RngExt, SeedableRng};
3660 use approx::{assert_relative_eq, assert_ulps_eq};
3661
3662 let a = object::Static {
3669 position: component::Position ([0.0, 0.0, 0.0].into()),
3670 bound: component::Bound::from (shape::Capsule::noisy (2.0, 3.0)),
3671 material: component::MATERIAL_STONE,
3672 collidable: true
3673 };
3674 let b = object::Static {
3675 position: component::Position ([0.0, 0.0, 0.0].into()),
3676 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
3677 material: component::MATERIAL_STONE,
3678 collidable: true
3679 };
3680 assert_eq!(
3681 Proximity::query (&a, &b),
3682 Proximity {
3683 distance: -3.0,
3684 half_axis: [ 1.5, 0.0, 0.0].into(),
3685 normal: Unit3::axis_x(),
3686 midpoint: [-0.5, 0.0, 0.0].into()
3687 }
3688 );
3689
3690 let a = object::Static {
3693 position: component::Position ([0.0, 0.0, 1.0].into()), .. a
3694 };
3695 let b = object::Static {
3696 position: component::Position ([0.0, 0.0, -1.0].into()), .. b
3697 };
3698 assert_eq!(
3699 Proximity::query (&a, &b),
3700 Proximity {
3701 distance: -3.0,
3702 half_axis: [ 1.5, 0.0, 0.0].into(),
3703 normal: Unit3::axis_x(),
3704 midpoint: [-0.5, 0.0, -0.5].into()
3705 }
3706 );
3707
3708 let a = object::Static {
3711 position: component::Position ([0.0, 0.0, -3.0].into()), .. a
3712 };
3713 let b = object::Static {
3714 position: component::Position ([0.0, 0.0, 2.0].into()), .. b
3715 };
3716 assert_eq!(
3717 Proximity::query (&a, &b),
3718 Proximity {
3719 distance: -3.0,
3720 half_axis: [ 1.5, 0.0, 0.0].into(),
3721 normal: Unit3::axis_x(),
3722 midpoint: [-0.5, 0.0, 0.0].into()
3723 }
3724 );
3725
3726 let a = object::Static {
3728 position: component::Position ([0.0, 0.0, 3.0].into()), .. a
3729 };
3730 let b = object::Static {
3731 position: component::Position ([0.0, 0.0, -2.0].into()), .. b
3732 };
3733 assert_eq!(
3734 Proximity::query (&a, &b),
3735 Proximity {
3736 distance: -3.0,
3737 half_axis: [ 1.5, 0.0, 0.0].into(),
3738 normal: Unit3::axis_x(),
3739 midpoint: [-0.5, 0.0, 0.0].into()
3740 }
3741 );
3742
3743 let a = object::Static {
3745 position: component::Position ([-1.0, 0.0, 1.0].into()), .. a
3746 };
3747 let b = object::Static {
3748 position: component::Position ([0.0, 0.0, -1.0].into()), .. b
3749 };
3750 assert_eq!(
3751 Proximity::query (&a, &b),
3752 Proximity {
3753 distance: -2.0,
3754 half_axis: [-1.0, 0.0, 0.0].into(),
3755 normal: Unit3::axis_x().invert(),
3756 midpoint: [ 0.0, 0.0, -0.5].into()
3757 }
3758 );
3759
3760 let a = object::Static {
3762 position: component::Position ([0.0, 0.0, -3.0].into()), .. a
3763 };
3764 let b = object::Static {
3765 position: component::Position ([0.0, 0.0, 3.0].into()), .. b
3766 };
3767 assert_eq!(
3768 Proximity::query (&a, &b),
3769 Proximity {
3770 distance: -2.0,
3771 half_axis: [ 0.0, 0.0, -1.0].into(),
3772 normal: Unit3::axis_z().invert(),
3773 midpoint: [ 0.0, 0.0, 1.0].into()
3774 }
3775 );
3776
3777 let a = object::Static {
3779 position: component::Position ([0.0, 0.0, 3.0].into()), .. a
3780 };
3781 let b = object::Static {
3782 position: component::Position ([0.0, 0.0, -3.0].into()), .. b
3783 };
3784 assert_eq!(
3785 Proximity::query (&a, &b),
3786 Proximity {
3787 distance: -2.0,
3788 half_axis: [ 0.0, 0.0, 1.0].into(),
3789 normal: Unit3::axis_z(),
3790 midpoint: [ 0.0, 0.0, -1.0].into()
3791 }
3792 );
3793
3794 let a = object::Static {
3796 position: component::Position ([ 1.0, 0.0, 0.0].into()), .. a
3797 };
3798 let b = object::Static {
3799 position: component::Position ([-1.0, 0.0, 0.0].into()), .. b
3800 };
3801 assert_eq!(
3802 Proximity::query (&a, &b),
3803 Proximity {
3804 distance: -1.0,
3805 half_axis: [ 0.5, 0.0, 0.0].into(),
3806 normal: Unit3::axis_x(),
3807 midpoint: [-0.5, 0.0, 0.0].into()
3808 }
3809 );
3810
3811 let a = object::Static {
3813 position: component::Position ([ 2.0, 0.0, 5.0].into()), .. a
3814 };
3815 let b = object::Static {
3816 position: component::Position ([-1.0, 0.0, -3.0].into()), .. b
3817 };
3818
3819 let proximity = Proximity::query (&a, &b);
3820 let distance_manual = {
3821 let distance = vector3 (3.0, 0.0, 3.0).magnitude() - 3.0;
3822 let half_axis : Vector3 <_> =
3823 0.5 * distance * vector3 (-1.0, 0.0, -1.0).normalized();
3824 let normal = Unit3::normalize ([1.0, 0.0, 1.0].into());
3825 let midpoint = Point3::from ([-1.0, 0.0, -1.0]) + *normal - half_axis;
3826 Proximity { distance, half_axis, midpoint, normal }
3827 };
3828 assert_eq!(proximity.distance, distance_manual.distance);
3829 assert_relative_eq!(proximity.half_axis, distance_manual.half_axis);
3830 assert_relative_eq!(*proximity.normal, *distance_manual.normal);
3831 assert_relative_eq!(proximity.midpoint, distance_manual.midpoint,
3832 epsilon = 2.0 * f64::EPSILON);
3833
3834 let a = object::Static {
3836 position: component::Position ([ 3.0, 0.0, 3.0].into()), .. a
3837 };
3838 let b = object::Static {
3839 position: component::Position ([-1.0, 0.0, 0.0].into()), .. b
3840 };
3841 assert_eq!(
3842 Proximity::query (&a, &b),
3843 Proximity {
3844 distance: 1.0,
3845 half_axis: [-0.5, 0.0, 0.0].into(),
3846 normal: Unit3::axis_x(),
3847 midpoint: [ 0.5, 0.0, 1.0].into()
3848 }
3849 );
3850
3851 let a = object::Static {
3857 position: component::Position ([-5.0, -5.0, -5.0].into()),
3858 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 2.0, 3.0])),
3859 .. a
3860 };
3861 let b = object::Static {
3862 position: component::Position ([5.0, 5.0, 5.0].into()),
3863 bound: component::Bound::from (shape::Cuboid::noisy ([3.0, 1.0, 2.0])),
3864 .. b
3865 };
3866 let proximity = Proximity::query (&a, &b);
3867 assert_eq!(proximity.distance, f64::sqrt (110.0));
3868 assert_eq!(proximity.half_axis, [3.0, 3.5, 2.5].into());
3869 assert_ulps_eq!(*proximity.normal, -vector3 (3.0, 3.5, 2.5).normalized());
3870 assert_eq!(proximity.midpoint, [-1.0, 0.5, 0.5].into());
3871
3872 let a = object::Static {
3874 position: component::Position ([-5.0, 0.0, -5.0].into()), .. a
3875 };
3876 let b = object::Static {
3877 position: component::Position ([5.0, 0.0, 5.0].into()), .. b
3878 };
3879 let proximity = Proximity::query (&a, &b);
3880 assert_eq!(proximity.distance, f64::sqrt (61.0));
3881 assert_eq!(proximity.half_axis, [3.0, 0.0, 2.5].into());
3882 assert_ulps_eq!(*proximity.normal, -vector3 (3.0, 0.0, 2.5).normalized());
3883 assert_eq!(proximity.midpoint, [-1.0, 0.0, 0.5].into());
3884
3885 let a = object::Static {
3891 position: component::Position ([5.0, 5.0, 3.0].into()),
3892 bound: component::Bound::from (shape::Capsule::noisy (SQRT_2, 2.0)),
3893 .. a
3894 };
3895 let b = object::Static {
3896 position: component::Position ([0.0, 0.0, 0.0].into()),
3897 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 1.0, 1.0])),
3898 .. b
3899 };
3900 let proximity = Proximity::query (&a, &b);
3901 assert_ulps_eq!(proximity.distance, 3.0 * SQRT_2);
3902 assert_eq!(proximity.half_axis, [-1.5, -1.5, 0.0].into());
3903 assert_ulps_eq!(*proximity.normal, vector3 (1.0, 1.0, 0.0).normalized());
3904 assert_eq!(proximity.midpoint, [ 2.5, 2.5, 1.0].into());
3905
3906 let a = object::Static {
3908 position: component::Position ([-5.0, -5.0, -3.0].into()),
3909 bound: component::Bound::from (shape::Capsule::noisy (SQRT_2, 2.0)),
3910 .. a
3911 };
3912 let b = object::Static {
3913 position: component::Position ([0.0, 0.0, 0.0].into()),
3914 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 1.0, 1.0])),
3915 .. b
3916 };
3917 let proximity = Proximity::query (&a, &b);
3918 assert_ulps_eq!(proximity.distance, 3.0 * SQRT_2);
3919 assert_eq!(proximity.half_axis, [ 1.5, 1.5, 0.0].into());
3920 assert_ulps_eq!(*proximity.normal, vector3 (-1.0, -1.0, 0.0).normalized());
3921 assert_eq!(proximity.midpoint, [-2.5,-2.5,-1.0].into());
3922
3923 let a = object::Static {
3925 position: component::Position ([4.0, 0.5, 4.0].into()),
3926 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
3927 .. a
3928 };
3929 let b = object::Static {
3930 position: component::Position ([0.0, 0.0, 0.0].into()),
3931 bound: component::Bound::from (shape::Cuboid::noisy ([2.0, 2.0, 2.0])),
3932 .. b
3933 };
3934 assert_eq!(
3935 Proximity::query (&a, &b),
3936 Proximity {
3937 distance: 1.0,
3938 half_axis: [-0.5, 0.0, 0.0].into(),
3939 normal: Unit3::axis_x(),
3940 midpoint: [ 2.5, 0.5, 2.0].into()
3941 }
3942 );
3943
3944 let a = object::Static {
3946 position: component::Position ([4.0, 0.5, -4.0].into()), .. a
3947 };
3948 let b = object::Static {
3949 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
3950 };
3951 assert_eq!(
3952 Proximity::query (&a, &b),
3953 Proximity {
3954 distance: 1.0,
3955 half_axis: [-0.5, 0.0, 0.0].into(),
3956 normal: Unit3::axis_x(),
3957 midpoint: [ 2.5, 0.5, -2.0].into()
3958 }
3959 );
3960
3961 let a = object::Static {
3963 position: component::Position ([0.5, 4.0, 4.0].into()), .. a
3964 };
3965 let b = object::Static {
3966 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
3967 };
3968 assert_eq!(
3969 Proximity::query (&a, &b),
3970 Proximity {
3971 distance: 1.0,
3972 half_axis: [ 0.0, -0.5, 0.0].into(),
3973 normal: Unit3::axis_y(),
3974 midpoint: [ 0.5, 2.5, 2.0].into()
3975 }
3976 );
3977
3978 let a = object::Static {
3980 position: component::Position ([0.5, 4.0, -4.0].into()), .. a
3981 };
3982 let b = object::Static {
3983 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
3984 };
3985 assert_eq!(
3986 Proximity::query (&a, &b),
3987 Proximity {
3988 distance: 1.0,
3989 half_axis: [ 0.0, -0.5, 0.0].into(),
3990 normal: Unit3::axis_y(),
3991 midpoint: [ 0.5, 2.5, -2.0].into()
3992 }
3993 );
3994
3995 let a = object::Static {
3997 position: component::Position ([0.5, 0.5, 6.0].into()), .. a
3998 };
3999 let b = object::Static {
4000 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4001 };
4002 assert_eq!(
4003 Proximity::query (&a, &b),
4004 Proximity {
4005 distance: 1.0,
4006 half_axis: [ 0.0, 0.0, -0.5].into(),
4007 normal: Unit3::axis_z(),
4008 midpoint: [ 0.5, 0.5, 2.5].into()
4009 }
4010 );
4011
4012 let a = object::Static {
4014 position: component::Position ([0.5, 0.5, -6.0].into()), .. a
4015 };
4016 let b = object::Static {
4017 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4018 };
4019 assert_eq!(
4020 Proximity::query (&a, &b),
4021 Proximity {
4022 distance: 1.0,
4023 half_axis: [ 0.0, 0.0, 0.5].into(),
4024 normal: Unit3::axis_z().invert(),
4025 midpoint: [ 0.5, 0.5, -2.5].into()
4026 }
4027 );
4028
4029 let a = object::Static {
4031 position: component::Position ([3.0, 3.0, 2.0].into()), .. a
4032 };
4033 let b = object::Static {
4034 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4035 };
4036 let proximity = Proximity::query (&a, &b);
4037 assert_eq!(proximity.distance, SQRT_2 - 1.0);
4038 assert_eq!(proximity.half_axis, [
4039 -0.5 * f64::sqrt (0.5 * (SQRT_2 - 1.0).powi (2)),
4040 -0.5 * f64::sqrt (0.5 * (SQRT_2 - 1.0).powi (2)),
4041 0.0
4042 ].into());
4043 assert_ulps_eq!(*proximity.normal,
4044 [FRAC_1_SQRT_2, FRAC_1_SQRT_2, 0.0].into());
4045 assert_eq!(proximity.midpoint, [
4046 2.0 + 0.5 * f64::sqrt (0.5 * (SQRT_2 - 1.0).powi (2)),
4047 2.0 + 0.5 * f64::sqrt (0.5 * (SQRT_2 - 1.0).powi (2)),
4048 1.0
4049 ].into());
4050
4051 let a = object::Static {
4053 position: component::Position ([-3.0, -3.0, -2.0].into()), .. a
4054 };
4055 let b = object::Static {
4056 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4057 };
4058 let proximity = Proximity::query (&a, &b);
4059 assert_eq!(proximity.distance, SQRT_2 - 1.0);
4060 assert_eq!(proximity.half_axis, [
4061 0.5 * f64::sqrt (0.5 * (SQRT_2 - 1.0).powi (2)),
4062 0.5 * f64::sqrt (0.5 * (SQRT_2 - 1.0).powi (2)),
4063 0.0
4064 ].into());
4065 assert_ulps_eq!(*proximity.normal, [-FRAC_1_SQRT_2, -FRAC_1_SQRT_2, 0.0].into());
4066 assert_eq!(proximity.midpoint, [
4067 -2.0 - 0.5 * f64::sqrt (0.5 * (SQRT_2 - 1.0).powi (2)),
4068 -2.0 - 0.5 * f64::sqrt (0.5 * (SQRT_2 - 1.0).powi (2)),
4069 -1.0
4070 ].into());
4071
4072 let a = object::Static {
4074 position: component::Position ([1.0, 4.0, 2.0].into()), .. a
4075 };
4076 let b = object::Static {
4077 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4078 };
4079 assert_eq!(
4080 Proximity::query (&a, &b),
4081 Proximity {
4082 distance: 1.0,
4083 half_axis: [ 0.0, -0.5, 0.0].into(),
4084 normal: Unit3::axis_y(),
4085 midpoint: [ 1.0, 2.5, 1.0].into()
4086 }
4087 );
4088
4089 let a = object::Static {
4091 position: component::Position ([-1.0, -4.0, -2.0].into()), .. a
4092 };
4093 let b = object::Static {
4094 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4095 };
4096 assert_eq!(
4097 Proximity::query (&a, &b),
4098 Proximity {
4099 distance: 1.0,
4100 half_axis: [ 0.0, 0.5, 0.0].into(),
4101 normal: Unit3::axis_y().invert(),
4102 midpoint: [-1.0, -2.5, -1.0].into()
4103 }
4104 );
4105
4106 let a = object::Static {
4108 position: component::Position ([4.0, 1.0, 2.0].into()), .. a
4109 };
4110 let b = object::Static {
4111 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4112 };
4113 assert_eq!(
4114 Proximity::query (&a, &b),
4115 Proximity {
4116 distance: 1.0,
4117 half_axis: [-0.5, 0.0, 0.0].into(),
4118 normal: Unit3::axis_x(),
4119 midpoint: [ 2.5, 1.0, 1.0].into()
4120 }
4121 );
4122
4123 let a = object::Static {
4125 position: component::Position ([-4.0, -1.0, -2.0].into()), .. a
4126 };
4127 let b = object::Static {
4128 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4129 };
4130 assert_eq!(
4131 Proximity::query (&a, &b),
4132 Proximity {
4133 distance: 1.0,
4134 half_axis: [ 0.5, 0.0, 0.0].into(),
4135 normal: Unit3::axis_x().invert(),
4136 midpoint: [-2.5, -1.0, -1.0].into()
4137 }
4138 );
4139
4140 let a = object::Static {
4142 position: component::Position ([2.0, 2.0, 4.0].into()),
4143 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4144 .. a
4145 };
4146 let b = object::Static {
4147 position: component::Position ([0.0, 0.0, 0.0].into()),
4148 bound: component::Bound::from (shape::Cuboid::noisy ([2.0, 2.0, 2.0])),
4149 .. b
4150 };
4151 assert_eq!(
4152 Proximity::query (&a, &b),
4153 Proximity {
4154 distance: -1.0,
4155 half_axis: [ 0.5, 0.0, 0.0].into(),
4156 normal: Unit3::axis_x(),
4157 midpoint: [ 1.5, 2.0, 2.0].into()
4158 }
4159 );
4160
4161 let a = object::Static {
4163 position: component::Position ([-2.0, -2.0, -4.0].into()), .. a
4164 };
4165 let b = object::Static {
4166 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4167 };
4168 assert_eq!(
4169 Proximity::query (&a, &b),
4170 Proximity {
4171 distance: -1.0,
4172 half_axis: [-0.5, 0.0, 0.0].into(),
4173 normal: Unit3::axis_x().invert(),
4174 midpoint: [-1.5, -2.0,-2.0].into()
4175 }
4176 );
4177
4178 let a = object::Static {
4180 position: component::Position ([2.0, 1.0, 4.0].into()), .. a
4181 };
4182 let b = object::Static {
4183 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4184 };
4185 assert_eq!(
4186 Proximity::query (&a, &b),
4187 Proximity {
4188 distance: -1.0,
4189 half_axis: [ 0.5, 0.0, 0.0].into(),
4190 normal: Unit3::axis_x(),
4191 midpoint: [ 1.5, 1.0, 2.0].into()
4192 }
4193 );
4194
4195 let a = object::Static {
4197 position: component::Position ([-2.0, 1.0, -4.0].into()), .. a
4198 };
4199 let b = object::Static {
4200 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4201 };
4202 assert_eq!(
4203 Proximity::query (&a, &b),
4204 Proximity {
4205 distance: -1.0,
4206 half_axis: [-0.5, 0.0, 0.0].into(),
4207 normal: Unit3::axis_x().invert(),
4208 midpoint: [-1.5, 1.0, -2.0].into()
4209 }
4210 );
4211
4212 let a = object::Static {
4214 position: component::Position ([1.0, 2.0, 4.0].into()), .. a
4215 };
4216 let b = object::Static {
4217 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4218 };
4219 assert_eq!(
4220 Proximity::query (&a, &b),
4221 Proximity {
4222 distance: -1.0,
4223 half_axis: [ 0.0, 0.5, 0.0].into(),
4224 normal: Unit3::axis_y(),
4225 midpoint: [ 1.0, 1.5, 2.0].into()
4226 }
4227 );
4228
4229 let a = object::Static {
4231 position: component::Position ([ 1.0, -2.0, -4.0].into()), .. a
4232 };
4233 let b = object::Static {
4234 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4235 };
4236 assert_eq!(
4237 Proximity::query (&a, &b),
4238 Proximity {
4239 distance: -1.0,
4240 half_axis: [0.0, -0.5, 0.0].into(),
4241 normal: Unit3::axis_y().invert(),
4242 midpoint: [1.0, -1.5, -2.0].into()
4243 }
4244 );
4245
4246 let a = object::Static {
4248 position: component::Position ([1.0, 1.0, 4.0].into()), .. a
4249 };
4250 let b = object::Static {
4251 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4252 };
4253 assert_eq!(
4254 Proximity::query (&a, &b),
4255 Proximity {
4256 distance: -1.0,
4257 half_axis: [ 0.0, 0.0, 0.5].into(),
4258 normal: Unit3::axis_z(),
4259 midpoint: [ 1.0, 1.0, 1.5].into()
4260 }
4261 );
4262
4263 let a = object::Static {
4265 position: component::Position ([-1.0, -1.0, -4.0].into()), .. a
4266 };
4267 let b = object::Static {
4268 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4269 };
4270 assert_eq!(
4271 Proximity::query (&a, &b),
4272 Proximity {
4273 distance: -1.0,
4274 half_axis: [ 0.0, 0.0, -0.5].into(),
4275 normal: Unit3::axis_z().invert(),
4276 midpoint: [-1.0, -1.0, -1.5].into()
4277 }
4278 );
4279
4280 let a = object::Static {
4282 position: component::Position ([0.0, 0.0, 0.0].into()), .. a
4283 };
4284 let b = object::Static {
4285 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4286 };
4287 assert_eq!(
4288 Proximity::query (&a, &b),
4289 Proximity {
4290 distance: -3.0,
4291 half_axis: [ 1.5, 0.0, 0.0].into(),
4292 normal: Unit3::axis_x(),
4293 midpoint: [ 0.5, 0.0, 0.0].into()
4294 }
4295 );
4296
4297 let a = object::Static {
4299 position: component::Position ([1.0, 0.0, 0.0].into()), .. a
4300 };
4301 let b = object::Static {
4302 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4303 };
4304 assert_eq!(
4305 Proximity::query (&a, &b),
4306 Proximity {
4307 distance: -2.0,
4308 half_axis: [ 1.0, 0.0, 0.0].into(),
4309 normal: Unit3::axis_x(),
4310 midpoint: [ 1.0, 0.0, 0.0].into()
4311 }
4312 );
4313
4314 let a = object::Static {
4316 position: component::Position ([-1.0, 0.0, 0.0].into()), .. a
4317 };
4318 let b = object::Static {
4319 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4320 };
4321 assert_eq!(
4322 Proximity::query (&a, &b),
4323 Proximity {
4324 distance: -2.0,
4325 half_axis: [-1.0, 0.0, 0.0].into(),
4326 normal: Unit3::axis_x().invert(),
4327 midpoint: [-1.0, 0.0, 0.0].into()
4328 }
4329 );
4330
4331 let a = object::Static {
4333 position: component::Position ([0.0, 1.0, 0.0].into()), .. a
4334 };
4335 let b = object::Static {
4336 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4337 };
4338 assert_eq!(
4339 Proximity::query (&a, &b),
4340 Proximity {
4341 distance: -2.0,
4342 half_axis: [0.0, 1.0, 0.0].into(),
4343 normal: Unit3::axis_y(),
4344 midpoint: [0.0, 1.0, 0.0].into()
4345 }
4346 );
4347
4348 let a = object::Static {
4350 position: component::Position ([0.0, -1.0, 0.0].into()), .. a
4351 };
4352 let b = object::Static {
4353 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
4354 };
4355 assert_eq!(
4356 Proximity::query (&a, &b),
4357 Proximity {
4358 distance: -2.0,
4359 half_axis: [0.0, -1.0, 0.0].into(),
4360 normal: Unit3::axis_y().invert(),
4361 midpoint: [0.0, -1.0, 0.0].into()
4362 }
4363 );
4364
4365 let a = object::Static {
4367 position: component::Position ([0.0, 0.0, 3.0].into()),
4368 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4369 .. a
4370 };
4371 let b = object::Static {
4372 position: component::Position ([0.0, 0.0, 0.0].into()),
4373 bound: component::Bound::from (shape::Cuboid::noisy ([4.0, 4.0, 2.0])),
4374 .. b
4375 };
4376 assert_eq!(
4377 Proximity::query (&a, &b),
4378 Proximity {
4379 distance: -2.0,
4380 half_axis: [0.0, 0.0, 1.0].into(),
4381 normal: Unit3::axis_z(),
4382 midpoint: [0.0, 0.0, 1.0].into()
4383 }
4384 );
4385
4386 let a = object::Static {
4388 position: component::Position ([0.0, 0.0, 1.0].into()),
4389 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4390 .. a
4391 };
4392 let b = object::Static {
4393 position: component::Position ([0.0, 0.0, 0.0].into()),
4394 bound: component::Bound::from (shape::Cuboid::noisy ([4.0, 4.0, 2.0])),
4395 .. b
4396 };
4397 assert_eq!(
4398 Proximity::query (&a, &b),
4399 Proximity {
4400 distance: -4.0,
4401 half_axis: [0.0, 0.0, 2.0].into(),
4402 normal: Unit3::axis_z(),
4403 midpoint: [0.0, 0.0, 0.0].into()
4404 }
4405 );
4406
4407 let a = object::Static {
4409 position: component::Position ([0.0, 0.0, -3.0].into()),
4410 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4411 .. a
4412 };
4413 let b = object::Static {
4414 position: component::Position ([0.0, 0.0, 0.0].into()),
4415 bound: component::Bound::from (shape::Cuboid::noisy ([4.0, 4.0, 2.0])),
4416 .. b
4417 };
4418 assert_eq!(
4419 Proximity::query (&a, &b),
4420 Proximity {
4421 distance: -2.0,
4422 half_axis: [0.0, 0.0, -1.0].into(),
4423 normal: Unit3::axis_z().invert(),
4424 midpoint: [0.0, 0.0, -1.0].into()
4425 }
4426 );
4427
4428 let a = object::Static {
4430 position: component::Position ([0.0, 0.0, -1.0].into()),
4431 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4432 .. a
4433 };
4434 let b = object::Static {
4435 position: component::Position ([0.0, 0.0, 0.0].into()),
4436 bound: component::Bound::from (shape::Cuboid::noisy ([4.0, 4.0, 2.0])),
4437 .. b
4438 };
4439 assert_eq!(
4440 Proximity::query (&a, &b),
4441 Proximity {
4442 distance: -4.0,
4443 half_axis: [0.0, 0.0, -2.0].into(),
4444 normal: Unit3::axis_z().invert(),
4445 midpoint: [0.0, 0.0, 0.0].into()
4446 }
4447 );
4448
4449 let mut rng = XorShiftRng::seed_from_u64 (0);
4451 let a = object::Static {
4452 position: component::Position ([0.0, 0.0, 0.0].into()),
4453 bound: component::Bound::from (shape::Capsule::noisy (1.5, 1.5)),
4454 .. a
4455 };
4456 for _ in 0..100 {
4457 let position = component::Position ([
4458 rng.random_range (-40.0..40.0),
4459 rng.random_range (-40.0..40.0),
4460 rng.random_range (-40.0..40.0)
4461 ].into());
4462 let bound = shape::Cuboid::noisy ([
4463 rng.random_range (0.5..5.0),
4464 rng.random_range (0.5..5.0),
4465 rng.random_range (0.5..5.0)
4466 ]).into();
4467 let b = object::Static {
4468 position, bound, material: component::MATERIAL_STONE, collidable: true
4469 };
4470 let _ = Proximity::query (&a, &b);
4471 }
4472
4473 use SignedAxis3;
4477
4478 let a = object::Static {
4480 position: component::Position ([0.0, 0.0, 4.0].into()),
4481 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4482 .. a
4483 };
4484 let b = object::Static {
4485 position: component::Position ([0.0, 0.0, 0.0].into()),
4486 bound: shape::Orthant { normal_axis: SignedAxis3::PosZ }.into(),
4487 .. b
4488 };
4489 assert_eq!(
4490 Proximity::query (&a, &b),
4491 Proximity {
4492 distance: 1.0,
4493 half_axis: [0.0, 0.0, -0.5].into(),
4494 normal: Unit3::axis_z(),
4495 midpoint: [0.0, 0.0, 0.5].into()
4496 }
4497 );
4498
4499 let a = object::Static {
4501 position: component::Position ([0.0, 0.0, -4.0].into()),
4502 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4503 .. a
4504 };
4505 let b = object::Static {
4506 position: component::Position ([0.0, 0.0, 0.0].into()),
4507 bound: shape::Orthant { normal_axis: SignedAxis3::NegZ }.into(),
4508 .. b
4509 };
4510 assert_eq!(
4511 Proximity::query (&a, &b),
4512 Proximity {
4513 distance: 1.0,
4514 half_axis: [0.0, 0.0, 0.5].into(),
4515 normal: Unit3::axis_z().invert(),
4516 midpoint: [0.0, 0.0, -0.5].into()
4517 }
4518 );
4519
4520 let a = object::Static {
4522 position: component::Position ([0.0, 2.0, 0.0].into()),
4523 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4524 .. a
4525 };
4526 let b = object::Static {
4527 position: component::Position ([0.0, 0.0, 0.0].into()),
4528 bound: shape::Orthant { normal_axis: SignedAxis3::PosY }.into(),
4529 .. b
4530 };
4531 assert_eq!(
4532 Proximity::query (&a, &b),
4533 Proximity {
4534 distance: 1.0,
4535 half_axis: [0.0, -0.5, 0.0].into(),
4536 normal: Unit3::axis_y(),
4537 midpoint: [0.0, 0.5, 0.0].into()
4538 }
4539 );
4540
4541 let a = object::Static {
4543 position: component::Position ([0.0, -2.0, 0.0].into()),
4544 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4545 .. a
4546 };
4547 let b = object::Static {
4548 position: component::Position ([0.0, 0.0, 0.0].into()),
4549 bound: shape::Orthant { normal_axis: SignedAxis3::NegY }.into(),
4550 .. b
4551 };
4552 assert_eq!(
4553 Proximity::query (&a, &b),
4554 Proximity {
4555 distance: 1.0,
4556 half_axis: [0.0, 0.5, 0.0].into(),
4557 normal: Unit3::axis_y().invert(),
4558 midpoint: [0.0, -0.5, 0.0].into()
4559 }
4560 );
4561
4562 let a = object::Static {
4564 position: component::Position ([2.0, 0.0, 0.0].into()),
4565 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4566 .. a
4567 };
4568 let b = object::Static {
4569 position: component::Position ([0.0, 0.0, 0.0].into()),
4570 bound: shape::Orthant { normal_axis: SignedAxis3::PosX }.into(),
4571 .. b
4572 };
4573 assert_eq!(
4574 Proximity::query (&a, &b),
4575 Proximity {
4576 distance: 1.0,
4577 half_axis: [-0.5, 0.0, 0.0].into(),
4578 normal: Unit3::axis_x(),
4579 midpoint: [ 0.5, 0.0, 0.0].into()
4580 }
4581 );
4582
4583 let a = object::Static {
4585 position: component::Position ([-2.0, 0.0, 0.0].into()),
4586 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4587 .. a
4588 };
4589 let b = object::Static {
4590 position: component::Position ([0.0, 0.0, 0.0].into()),
4591 bound: shape::Orthant { normal_axis: SignedAxis3::NegX }.into(),
4592 .. b
4593 };
4594 assert_eq!(
4595 Proximity::query (&a, &b),
4596 Proximity {
4597 distance: 1.0,
4598 half_axis: [ 0.5, 0.0, 0.0].into(),
4599 normal: Unit3::axis_x().invert(),
4600 midpoint: [-0.5, 0.0, 0.0].into()
4601 }
4602 );
4603
4604 let a = object::Static {
4606 position: component::Position ([0.0, 0.0, 0.0].into()),
4607 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4608 .. a
4609 };
4610 let b = object::Static {
4611 position: component::Position ([0.0, 0.0, 0.0].into()),
4612 bound: shape::Orthant { normal_axis: SignedAxis3::PosZ }.into(),
4613 .. b
4614 };
4615 assert_eq!(
4616 Proximity::query (&a, &b),
4617 Proximity {
4618 distance: -3.0,
4619 half_axis: [0.0, 0.0, 1.5].into(),
4620 normal: Unit3::axis_z(),
4621 midpoint: [0.0, 0.0, -1.5].into()
4622 }
4623 );
4624
4625 let a = object::Static {
4627 position: component::Position ([0.0, 0.0, 0.0].into()),
4628 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4629 .. a
4630 };
4631 let b = object::Static {
4632 position: component::Position ([0.0, 0.0, 0.0].into()),
4633 bound: shape::Orthant { normal_axis: SignedAxis3::NegZ }.into(),
4634 .. b
4635 };
4636 assert_eq!(
4637 Proximity::query (&a, &b),
4638 Proximity {
4639 distance: -3.0,
4640 half_axis: [0.0, 0.0, -1.5].into(),
4641 normal: Unit3::axis_z().invert(),
4642 midpoint: [0.0, 0.0, 1.5].into()
4643 }
4644 );
4645
4646 let a = object::Static {
4648 position: component::Position ([0.0, 0.0, 0.0].into()),
4649 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4650 .. a
4651 };
4652 let b = object::Static {
4653 position: component::Position ([0.0, 0.0, 0.0].into()),
4654 bound: shape::Orthant { normal_axis: SignedAxis3::PosY }.into(),
4655 .. b
4656 };
4657 assert_eq!(
4658 Proximity::query (&a, &b),
4659 Proximity {
4660 distance: -1.0,
4661 half_axis: [0.0, 0.5, 0.0].into(),
4662 normal: Unit3::axis_y(),
4663 midpoint: [0.0, -0.5, 0.0].into()
4664 }
4665 );
4666
4667 let a = object::Static {
4669 position: component::Position ([0.0, 0.0, 0.0].into()),
4670 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4671 .. a
4672 };
4673 let b = object::Static {
4674 position: component::Position ([0.0, 0.0, 0.0].into()),
4675 bound: shape::Orthant { normal_axis: SignedAxis3::NegY }.into(),
4676 .. b
4677 };
4678 assert_eq!(
4679 Proximity::query (&a, &b),
4680 Proximity {
4681 distance: -1.0,
4682 half_axis: [0.0, -0.5, 0.0].into(),
4683 normal: Unit3::axis_y().invert(),
4684 midpoint: [0.0, 0.5, 0.0].into()
4685 }
4686 );
4687
4688 let a = object::Static {
4690 position: component::Position ([0.0, 0.0, 0.0].into()),
4691 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4692 .. a
4693 };
4694 let b = object::Static {
4695 position: component::Position ([0.0, 0.0, 0.0].into()),
4696 bound: shape::Orthant { normal_axis: SignedAxis3::PosX }.into(),
4697 .. b
4698 };
4699 assert_eq!(
4700 Proximity::query (&a, &b),
4701 Proximity {
4702 distance: -1.0,
4703 half_axis: [ 0.5, 0.0, 0.0].into(),
4704 normal: Unit3::axis_x(),
4705 midpoint: [-0.5, 0.0, 0.0].into()
4706 }
4707 );
4708
4709 let a = object::Static {
4711 position: component::Position ([0.0, 0.0, 0.0].into()),
4712 bound: component::Bound::from (shape::Capsule::noisy (1.0, 2.0)),
4713 .. a
4714 };
4715 let b = object::Static {
4716 position: component::Position ([0.0, 0.0, 0.0].into()),
4717 bound: shape::Orthant { normal_axis: SignedAxis3::NegX }.into(),
4718 .. b
4719 };
4720 assert_eq!(
4721 Proximity::query (&a, &b),
4722 Proximity {
4723 distance: -1.0,
4724 half_axis: [-0.5, 0.0, 0.0].into(),
4725 normal: Unit3::axis_x().invert(),
4726 midpoint: [ 0.5, 0.0, 0.0].into()
4727 }
4728 );
4729
4730 let a = object::Static {
4736 position: component::Position ([0.0, 0.0, 4.0].into()),
4737 bound: component::Bound::from (shape::Sphere::noisy (1.0)),
4738 .. a
4739 };
4740 let b = object::Static {
4741 position: component::Position ([0.0, 0.0, 0.0].into()),
4742 bound: shape::Orthant { normal_axis: SignedAxis3::PosZ }.into(),
4743 .. b
4744 };
4745 assert_eq!(
4746 Proximity::query (&a, &b),
4747 Proximity {
4748 distance: 3.0,
4749 half_axis: [0.0, 0.0, -1.5].into(),
4750 normal: Unit3::axis_z(),
4751 midpoint: [0.0, 0.0, 1.5].into()
4752 }
4753 );
4754
4755 let a = object::Static {
4757 position: component::Position ([0.0, 0.0, -4.0].into()),
4758 bound: component::Bound::from (shape::Sphere::noisy (1.0)),
4759 .. a
4760 };
4761 let b = object::Static {
4762 position: component::Position ([0.0, 0.0, 0.0].into()),
4763 bound: shape::Orthant { normal_axis: SignedAxis3::NegZ }.into(),
4764 .. b
4765 };
4766 assert_eq!(
4767 Proximity::query (&a, &b),
4768 Proximity {
4769 distance: 3.0,
4770 half_axis: [0.0, 0.0, 1.5].into(),
4771 normal: Unit3::axis_z().invert(),
4772 midpoint: [0.0, 0.0, -1.5].into()
4773 }
4774 );
4775
4776 let a = object::Static {
4778 position: component::Position ([0.0, 2.0, 0.0].into()),
4779 bound: component::Bound::from (shape::Sphere::noisy (1.0)),
4780 .. a
4781 };
4782 let b = object::Static {
4783 position: component::Position ([0.0, 0.0, 0.0].into()),
4784 bound: shape::Orthant { normal_axis: SignedAxis3::PosY }.into(),
4785 .. b
4786 };
4787 assert_eq!(
4788 Proximity::query (&a, &b),
4789 Proximity {
4790 distance: 1.0,
4791 half_axis: [0.0, -0.5, 0.0].into(),
4792 normal: Unit3::axis_y(),
4793 midpoint: [0.0, 0.5, 0.0].into()
4794 }
4795 );
4796
4797 let a = object::Static {
4799 position: component::Position ([0.0, -2.0, 0.0].into()),
4800 bound: component::Bound::from (shape::Sphere::noisy (1.0)),
4801 .. a
4802 };
4803 let b = object::Static {
4804 position: component::Position ([0.0, 0.0, 0.0].into()),
4805 bound: shape::Orthant { normal_axis: SignedAxis3::NegY }.into(),
4806 .. b
4807 };
4808 assert_eq!(
4809 Proximity::query (&a, &b),
4810 Proximity {
4811 distance: 1.0,
4812 half_axis: [0.0, 0.5, 0.0].into(),
4813 normal: Unit3::axis_y().invert(),
4814 midpoint: [0.0, -0.5, 0.0].into()
4815 }
4816 );
4817
4818 let a = object::Static {
4820 position: component::Position ([2.0, 0.0, 0.0].into()),
4821 bound: component::Bound::from (shape::Sphere::noisy (1.0)),
4822 .. a
4823 };
4824 let b = object::Static {
4825 position: component::Position ([0.0, 0.0, 0.0].into()),
4826 bound: shape::Orthant { normal_axis: SignedAxis3::PosX }.into(),
4827 .. b
4828 };
4829 assert_eq!(
4830 Proximity::query (&a, &b),
4831 Proximity {
4832 distance: 1.0,
4833 half_axis: [-0.5, 0.0, 0.0].into(),
4834 normal: Unit3::axis_x(),
4835 midpoint: [ 0.5, 0.0, 0.0].into()
4836 }
4837 );
4838
4839 let a = object::Static {
4841 position: component::Position ([-2.0, 0.0, 0.0].into()),
4842 bound: component::Bound::from (shape::Sphere::noisy (1.0)),
4843 .. a
4844 };
4845 let b = object::Static {
4846 position: component::Position ([0.0, 0.0, 0.0].into()),
4847 bound: shape::Orthant { normal_axis: SignedAxis3::NegX }.into(),
4848 .. b
4849 };
4850 assert_eq!(
4851 Proximity::query (&a, &b),
4852 Proximity {
4853 distance: 1.0,
4854 half_axis: [ 0.5, 0.0, 0.0].into(),
4855 normal: Unit3::axis_x().invert(),
4856 midpoint: [-0.5, 0.0, 0.0].into()
4857 }
4858 );
4859
4860 let a = object::Static {
4862 position: component::Position ([0.0, 0.0, 0.0].into()),
4863 bound: component::Bound::from (shape::Sphere::noisy (1.0)),
4864 .. a
4865 };
4866 let b = object::Static {
4867 position: component::Position ([0.0, 0.0, 0.0].into()),
4868 bound: shape::Orthant { normal_axis: SignedAxis3::PosZ }.into(),
4869 .. b
4870 };
4871 assert_eq!(
4872 Proximity::query (&a, &b),
4873 Proximity {
4874 distance: -1.0,
4875 half_axis: [0.0, 0.0, 0.5].into(),
4876 normal: Unit3::axis_z(),
4877 midpoint: [0.0, 0.0, -0.5].into()
4878 }
4879 );
4880
4881 let a = object::Static {
4883 position: component::Position ([0.0, 0.0, 0.0].into()),
4884 bound: component::Bound::from (shape::Sphere::noisy (1.0)),
4885 .. a
4886 };
4887 let b = object::Static {
4888 position: component::Position ([0.0, 0.0, 0.0].into()),
4889 bound: shape::Orthant { normal_axis: SignedAxis3::NegZ }.into(),
4890 .. b
4891 };
4892 assert_eq!(
4893 Proximity::query (&a, &b),
4894 Proximity {
4895 distance: -1.0,
4896 half_axis: [0.0, 0.0, -0.5].into(),
4897 normal: Unit3::axis_z().invert(),
4898 midpoint: [0.0, 0.0, 0.5].into()
4899 }
4900 );
4901
4902 let a = object::Static {
4904 position: component::Position ([0.0, 0.0, 0.0].into()),
4905 bound: component::Bound::from (shape::Sphere::noisy (1.0)),
4906 .. a
4907 };
4908 let b = object::Static {
4909 position: component::Position ([0.0, 0.0, 0.0].into()),
4910 bound: shape::Orthant { normal_axis: SignedAxis3::PosY }.into(),
4911 .. b
4912 };
4913 assert_eq!(
4914 Proximity::query (&a, &b),
4915 Proximity {
4916 distance: -1.0,
4917 half_axis: [0.0, 0.5, 0.0].into(),
4918 normal: Unit3::axis_y(),
4919 midpoint: [0.0, -0.5, 0.0].into()
4920 }
4921 );
4922
4923 let a = object::Static {
4925 position: component::Position ([0.0, 0.0, 0.0].into()),
4926 bound: component::Bound::from (shape::Sphere::noisy (1.0)),
4927 .. a
4928 };
4929 let b = object::Static {
4930 position: component::Position ([0.0, 0.0, 0.0].into()),
4931 bound: shape::Orthant { normal_axis: SignedAxis3::NegY }.into(),
4932 .. b
4933 };
4934 assert_eq!(
4935 Proximity::query (&a, &b),
4936 Proximity {
4937 distance: -1.0,
4938 half_axis: [0.0, -0.5, 0.0].into(),
4939 normal: Unit3::axis_y().invert(),
4940 midpoint: [0.0, 0.5, 0.0].into()
4941 }
4942 );
4943
4944 let a = object::Static {
4946 position: component::Position ([0.0, 0.0, 0.0].into()),
4947 bound: component::Bound::from (shape::Sphere::noisy (1.0)),
4948 .. a
4949 };
4950 let b = object::Static {
4951 position: component::Position ([0.0, 0.0, 0.0].into()),
4952 bound: shape::Orthant { normal_axis: SignedAxis3::PosX }.into(),
4953 .. b
4954 };
4955 assert_eq!(
4956 Proximity::query (&a, &b),
4957 Proximity {
4958 distance: -1.0,
4959 half_axis: [ 0.5, 0.0, 0.0].into(),
4960 normal: Unit3::axis_x(),
4961 midpoint: [-0.5, 0.0, 0.0].into()
4962 }
4963 );
4964
4965 let a = object::Static {
4967 position: component::Position ([0.0, 0.0, 0.0].into()),
4968 bound: component::Bound::from (shape::Sphere::noisy (1.0)),
4969 .. a
4970 };
4971 let b = object::Static {
4972 position: component::Position ([0.0, 0.0, 0.0].into()),
4973 bound: shape::Orthant { normal_axis: SignedAxis3::NegX }.into(),
4974 .. b
4975 };
4976 assert_eq!(
4977 Proximity::query (&a, &b),
4978 Proximity {
4979 distance: -1.0,
4980 half_axis: [-0.5, 0.0, 0.0].into(),
4981 normal: Unit3::axis_x().invert(),
4982 midpoint: [ 0.5, 0.0, 0.0].into()
4983 }
4984 );
4985
4986 let a = object::Static {
4992 position: component::Position ([0.0, 0.0, 4.0].into()),
4993 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 1.0, 1.0])),
4994 .. a
4995 };
4996 let b = object::Static {
4997 position: component::Position ([0.0, 0.0, 0.0].into()),
4998 bound: shape::Orthant { normal_axis: SignedAxis3::PosZ }.into(),
4999 .. b
5000 };
5001 assert_eq!(
5002 Proximity::query (&a, &b),
5003 Proximity {
5004 distance: 3.0,
5005 half_axis: [0.0, 0.0, -1.5].into(),
5006 normal: Unit3::axis_z(),
5007 midpoint: [0.0, 0.0, 1.5].into()
5008 }
5009 );
5010
5011 let a = object::Static {
5013 position: component::Position ([0.0, 0.0, -4.0].into()),
5014 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 1.0, 1.0])),
5015 .. a
5016 };
5017 let b = object::Static {
5018 position: component::Position ([0.0, 0.0, 0.0].into()),
5019 bound: shape::Orthant { normal_axis: SignedAxis3::NegZ }.into(),
5020 .. b
5021 };
5022 assert_eq!(
5023 Proximity::query (&a, &b),
5024 Proximity {
5025 distance: 3.0,
5026 half_axis: [0.0, 0.0, 1.5].into(),
5027 normal: Unit3::axis_z().invert(),
5028 midpoint: [0.0, 0.0, -1.5].into()
5029 }
5030 );
5031
5032 let a = object::Static {
5034 position: component::Position ([0.0, 2.0, 0.0].into()),
5035 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 1.0, 1.0])),
5036 .. a
5037 };
5038 let b = object::Static {
5039 position: component::Position ([0.0, 0.0, 0.0].into()),
5040 bound: shape::Orthant { normal_axis: SignedAxis3::PosY }.into(),
5041 .. b
5042 };
5043 assert_eq!(
5044 Proximity::query (&a, &b),
5045 Proximity {
5046 distance: 1.0,
5047 half_axis: [0.0, -0.5, 0.0].into(),
5048 normal: Unit3::axis_y(),
5049 midpoint: [0.0, 0.5, 0.0].into()
5050 }
5051 );
5052
5053 let a = object::Static {
5055 position: component::Position ([0.0, -2.0, 0.0].into()),
5056 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 1.0, 1.0])),
5057 .. a
5058 };
5059 let b = object::Static {
5060 position: component::Position ([0.0, 0.0, 0.0].into()),
5061 bound: shape::Orthant { normal_axis: SignedAxis3::NegY }.into(),
5062 .. b
5063 };
5064 assert_eq!(
5065 Proximity::query (&a, &b),
5066 Proximity {
5067 distance: 1.0,
5068 half_axis: [0.0, 0.5, 0.0].into(),
5069 normal: Unit3::axis_y().invert(),
5070 midpoint: [0.0, -0.5, 0.0].into()
5071 }
5072 );
5073
5074 let a = object::Static {
5076 position: component::Position ([2.0, 0.0, 0.0].into()),
5077 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 1.0, 1.0])),
5078 .. a
5079 };
5080 let b = object::Static {
5081 position: component::Position ([0.0, 0.0, 0.0].into()),
5082 bound: shape::Orthant { normal_axis: SignedAxis3::PosX }.into(),
5083 .. b
5084 };
5085 assert_eq!(
5086 Proximity::query (&a, &b),
5087 Proximity {
5088 distance: 1.0,
5089 half_axis: [-0.5, 0.0, 0.0].into(),
5090 normal: Unit3::axis_x(),
5091 midpoint: [ 0.5, 0.0, 0.0].into()
5092 }
5093 );
5094
5095 let a = object::Static {
5097 position: component::Position ([-2.0, 0.0, 0.0].into()),
5098 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 1.0, 1.0])),
5099 .. a
5100 };
5101 let b = object::Static {
5102 position: component::Position ([0.0, 0.0, 0.0].into()),
5103 bound: shape::Orthant { normal_axis: SignedAxis3::NegX }.into(),
5104 .. b
5105 };
5106 assert_eq!(
5107 Proximity::query (&a, &b),
5108 Proximity {
5109 distance: 1.0,
5110 half_axis: [ 0.5, 0.0, 0.0].into(),
5111 normal: Unit3::axis_x().invert(),
5112 midpoint: [-0.5, 0.0, 0.0].into()
5113 }
5114 );
5115
5116 let a = object::Static {
5118 position: component::Position ([0.0, 0.0, 0.0].into()),
5119 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 1.0, 1.0])),
5120 .. a
5121 };
5122 let b = object::Static {
5123 position: component::Position ([0.0, 0.0, 0.0].into()),
5124 bound: shape::Orthant { normal_axis: SignedAxis3::PosZ }.into(),
5125 .. b
5126 };
5127 assert_eq!(
5128 Proximity::query (&a, &b),
5129 Proximity {
5130 distance: -1.0,
5131 half_axis: [0.0, 0.0, 0.5].into(),
5132 normal: Unit3::axis_z(),
5133 midpoint: [0.0, 0.0, -0.5].into()
5134 }
5135 );
5136
5137 let a = object::Static {
5139 position: component::Position ([0.0, 0.0, 0.0].into()),
5140 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 1.0, 1.0])),
5141 .. a
5142 };
5143 let b = object::Static {
5144 position: component::Position ([0.0, 0.0, 0.0].into()),
5145 bound: shape::Orthant { normal_axis: SignedAxis3::NegZ }.into(),
5146 .. b
5147 };
5148 assert_eq!(
5149 Proximity::query (&a, &b),
5150 Proximity {
5151 distance: -1.0,
5152 half_axis: [0.0, 0.0, -0.5].into(),
5153 normal: Unit3::axis_z().invert(),
5154 midpoint: [0.0, 0.0, 0.5].into()
5155 }
5156 );
5157
5158 let a = object::Static {
5160 position: component::Position ([0.0, 0.0, 0.0].into()),
5161 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 1.0, 1.0])),
5162 .. a
5163 };
5164 let b = object::Static {
5165 position: component::Position ([0.0, 0.0, 0.0].into()),
5166 bound: shape::Orthant { normal_axis: SignedAxis3::PosY }.into(),
5167 .. b
5168 };
5169 assert_eq!(
5170 Proximity::query (&a, &b),
5171 Proximity {
5172 distance: -1.0,
5173 half_axis: [0.0, 0.5, 0.0].into(),
5174 normal: Unit3::axis_y(),
5175 midpoint: [0.0, -0.5, 0.0].into()
5176 }
5177 );
5178
5179 let a = object::Static {
5181 position: component::Position ([0.0, 0.0, 0.0].into()),
5182 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 1.0, 1.0])),
5183 .. a
5184 };
5185 let b = object::Static {
5186 position: component::Position ([0.0, 0.0, 0.0].into()),
5187 bound: shape::Orthant { normal_axis: SignedAxis3::NegY }.into(),
5188 .. b
5189 };
5190 assert_eq!(
5191 Proximity::query (&a, &b),
5192 Proximity {
5193 distance: -1.0,
5194 half_axis: [0.0, -0.5, 0.0].into(),
5195 normal: Unit3::axis_y().invert(),
5196 midpoint: [0.0, 0.5, 0.0].into()
5197 }
5198 );
5199
5200 let a = object::Static {
5202 position: component::Position ([0.0, 0.0, 0.0].into()),
5203 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 1.0, 1.0])),
5204 .. a
5205 };
5206 let b = object::Static {
5207 position: component::Position ([0.0, 0.0, 0.0].into()),
5208 bound: shape::Orthant { normal_axis: SignedAxis3::PosX }.into(),
5209 .. b
5210 };
5211 assert_eq!(
5212 Proximity::query (&a, &b),
5213 Proximity {
5214 distance: -1.0,
5215 half_axis: [ 0.5, 0.0, 0.0].into(),
5216 normal: Unit3::axis_x(),
5217 midpoint: [-0.5, 0.0, 0.0].into()
5218 }
5219 );
5220
5221 let a = object::Static {
5223 position: component::Position ([0.0, 0.0, 0.0].into()),
5224 bound: component::Bound::from (shape::Cuboid::noisy ([1.0, 1.0, 1.0])),
5225 .. a
5226 };
5227 let b = object::Static {
5228 position: component::Position ([0.0, 0.0, 0.0].into()),
5229 bound: shape::Orthant { normal_axis: SignedAxis3::NegX }.into(),
5230 .. b
5231 };
5232 assert_eq!(
5233 Proximity::query (&a, &b),
5234 Proximity {
5235 distance: -1.0,
5236 half_axis: [-0.5, 0.0, 0.0].into(),
5237 normal: Unit3::axis_x().invert(),
5238 midpoint: [ 0.5, 0.0, 0.0].into()
5239 }
5240 );
5241
5242 } #[test]
5245 #[expect(clippy::approx_constant)]
5246 fn query_hull() {
5247 let object_a = (
5249 component::Position ([0.0, 1.0, 1.6].into()),
5250 component::Bound::from (shape::Cuboid::noisy ([2.2, 2.2, 0.2]))
5251 );
5252 let object_b = {
5253 let hull = {
5254 let points = [
5255 [0.7333798838354574, 0.07387687099658402, -0.4254516842354885],
5256 [0.28934048979234384, -0.41943067939022566, 0.20302532977593885],
5257 [0.006562630606422983, 0.7345982182090985, 0.6784706255126608],
5258 [-0.16787537854609894, -0.7656664645854194, 0.004114727975213302],
5259 [-0.6400977561459589, -0.062079241531162725, -0.33763483879239625],
5260 [-0.3844054415702367, 0.6216012595122049, -0.04739397447380115]
5261 ].map (Point3::from);
5262 geometry::Hull3::from_points_with_mesh (&points).unwrap()
5263 };
5264 ( component::Position (
5265 [-0.021233076872148704, 1.4862487906056179, 2.2279516842354887].into()),
5266 component::Bound::from (hull)
5267 )
5268 };
5269 let proximity = Proximity::query (&object_a, &object_b);
5270 assert_eq!(proximity.distance, 0.0025000000000001688);
5271
5272 let object_a = {
5273 let hull = {
5274 let points = [
5275 [-1.6970562748477143, -2.2, 1.4142135623730951],
5276 [-1.4142135623730954, -2.2, 1.697056274847714],
5277 [-1.6970562748477143, 2.2, 1.4142135623730951],
5278 [-1.4142135623730954, 2.2, 1.697056274847714],
5279 [ 1.4142135623730954, -2.2, -1.697056274847714],
5280 [ 1.6970562748477143, -2.2, -1.4142135623730951],
5281 [ 1.4142135623730954, 2.2, -1.697056274847714],
5282 [ 1.6970562748477143, 2.2, -1.4142135623730951]
5283 ].map (Point3::from);
5284 geometry::Hull3::from_points_with_mesh (&points).unwrap()
5285 };
5286 ( component::Position ([-3.9, 1.0, 11.2125].into()),
5287 component::Bound::from (hull)
5288 )
5289 };
5290 let object_b = (
5291 component::Position (
5292 [-4.004858348343004, -1.2161640324940572, 11.869089780656527].into()),
5293 component::Bound::from (shape::Sphere::noisy (0.5))
5294 );
5295 let proximity = Proximity::query (&object_a, &object_b);
5296 assert_eq!(proximity.distance, -0.3091811079468084);
5297
5298 let object_a = {
5299 let hull = {
5300 let points = [
5301 [-2.2, -1.4142135623730954, -1.697056274847714],
5302 [-2.2, -1.6970562748477143, -1.4142135623730951],
5303 [-2.2, 1.6970562748477143, 1.4142135623730951],
5304 [-2.2, 1.4142135623730954, 1.697056274847714],
5305 [ 2.2, -1.4142135623730954, -1.697056274847714],
5306 [ 2.2, -1.6970562748477143, -1.4142135623730951],
5307 [ 2.2, 1.6970562748477143, 1.4142135623730951],
5308 [ 2.2, 1.4142135623730954, 1.69705627484771]
5309 ].map (Point3::from);
5310 geometry::Hull3::from_points_with_mesh (&points).unwrap()
5311 };
5312 ( component::Position ([0.0, 4.9, 11.2125].into()),
5313 component::Bound::from (hull)
5314 )
5315 };
5316 let object_b = (
5317 component::Position (
5318 [1.3113904930865399, 3.1609676773871804, 9.819471286970987].into()),
5319 component::Bound::from (shape::Sphere::noisy (0.5))
5320 );
5321 let proximity = Proximity::query (&object_a, &object_b);
5322 assert_eq!(proximity.distance, -0.4529809974587258);
5323
5324 let object_a = {
5325 let hull = {
5326 let points = [
5327 [-2.2, -1.6970562748477138, 1.4142135623730956],
5328 [-2.2, -1.414213562373095, 1.6970562748477145],
5329 [-2.2, 1.414213562373095, -1.6970562748477145],
5330 [-2.2, 1.6970562748477138, -1.4142135623730956],
5331 [ 2.2, -1.6970562748477138, 1.4142135623730956],
5332 [ 2.2, -1.414213562373095, 1.6970562748477145],
5333 [ 2.2, 1.414213562373095, -1.6970562748477145],
5334 [ 2.2, 1.6970562748477138, -1.4142135623730956]
5335 ].map (Point3::from);
5336 geometry::Hull3::from_points_with_mesh (&points).unwrap()
5337 };
5338 ( component::Position ([0.0, -2.9, 11.2125].into()),
5339 component::Bound::from (hull)
5340 )
5341 };
5342 let object_b = (
5343 component::Position (
5344 [2.256458188002921, -0.9674933916701636, 10.065811222437437].into()),
5345 component::Bound::from (shape::Sphere::noisy (0.5))
5346 );
5347 let proximity = Proximity::query (&object_a, &object_b);
5348 assert_eq!(proximity.distance, -0.13988958350691275);
5349
5350 let object_a = {
5351 let hull = {
5352 let points = [
5353 [-1.8000000000000003, -1.4142135623730954, -1.697056274847714 ],
5354 [-1.8000000000000003, -1.6970562748477143, -1.4142135623730951],
5355 [-1.8000000000000003, 1.6970562748477143, 1.4142135623730951],
5356 [-1.8000000000000003, 1.4142135623730954, 1.697056274847714 ],
5357 [ 1.8000000000000003, -1.4142135623730954, -1.697056274847714 ],
5358 [ 1.8000000000000003, -1.6970562748477143, -1.4142135623730951],
5359 [ 1.8000000000000003, 1.6970562748477143, 1.4142135623730951],
5360 [ 1.8000000000000003, 1.4142135623730954, 1.697056274847714 ]
5361 ].map (Point3::from);
5362 geometry::Hull3::from_points_with_mesh (&points).unwrap()
5363 };
5364 ( component::Position ([0.0, 4.5, 11.2125].into()),
5365 component::Bound::from (hull)
5366 )
5367 };
5368 let object_b = (
5369 component::Position (
5370 [-1.8483359321030037, 3.6499052772728637, 11.360649949330503].into()),
5371 component::Bound::from (shape::Sphere::noisy (0.5))
5372 );
5373 let proximity = Proximity::query (&object_a, &object_b);
5374 assert_eq!(proximity.distance, 0.008169602403322415);
5375 }
5376
5377 #[test]
5378 fn distance_to_triangle_edges() {
5379 let triangle = geometry::Triangle3::noisy (
5380 [-2.0, -1.0, 0.0].into(),
5381 [ 1.0, -1.0, 0.0].into(),
5382 [ 1.0, 5.0, 0.0].into()
5383 );
5384 let s = 0.5;
5386 let t = 1.0 / 6.0;
5387 let (d0, d1, d2) = triangle_distance_to_edges (triangle, s, t);
5388 approx::assert_relative_eq!(d0, 1.0);
5389 assert_eq!(d1, 3.0 / 5.0.sqrt());
5390 assert_eq!(d2, 1.0);
5391 }
5392
5393}