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