1use geometry::shape;
2
3use crate::{collision, component, constraint, geometry, math, object};
4
5#[derive(Clone, Copy, Debug, Eq, PartialEq)]
11pub enum Relation {
12 Disjoint,
13 Contact,
14 Intersect
15}
16
17#[derive(Clone, Debug, PartialEq)]
23pub struct Proximity {
24 pub distance : f64,
30 pub half_axis : math::Vector3 <f64>,
44 pub midpoint : math::Point3 <f64>,
46 pub normal : math::Unit3 <f64>
49}
50
51impl Proximity {
52 pub fn query <A, B> (object_a : &A, object_b : &B) -> Self where
94 A : object::Bounded, B : object::Bounded
95 {
96 let component::Position (position_a) = object_a.position();
97 let component::Position (position_b) = object_b.position();
98 let component::Bound (shape_a) = object_a.bound();
99 let component::Bound (shape_b) = object_b.bound();
100
101 match (shape_a, shape_b) {
102 ( shape::Variant::Bounded (shape::Bounded::Sphere (sphere_a)),
106 shape::Variant::Bounded (shape::Bounded::Sphere (sphere_b))
107 ) => Self::query_sphere_sphere (
108 position_a, sphere_a, position_b, sphere_b),
109 ( shape::Variant::Bounded (shape::Bounded::Capsule (capsule_a)),
113 shape::Variant::Bounded (shape::Bounded::Capsule (capsule_b))
114 ) => Self::query_capsule_capsule (
115 position_a, capsule_a, position_b, capsule_b),
116 ( shape::Variant::Bounded (shape::Bounded::Cuboid (cuboid_a)),
120 shape::Variant::Bounded (shape::Bounded::Cuboid (cuboid_b))
121 ) => Self::query_cuboid_cuboid (
122 position_a, cuboid_a, position_b, cuboid_b),
123 ( shape::Variant::Bounded (shape::Bounded::Sphere (sphere_a)),
127 shape::Variant::Bounded (shape::Bounded::Capsule (capsule_b))
128 ) => Self::query_sphere_capsule (
129 position_a, sphere_a, position_b, capsule_b),
130 ( shape::Variant::Bounded (shape::Bounded::Capsule (capsule_a)),
131 shape::Variant::Bounded (shape::Bounded::Sphere (sphere_b))
132 ) => {
133 let mut proximity = Self::query_sphere_capsule (
134 position_b, sphere_b, position_a, capsule_a);
135 proximity.half_axis *= -1.0;
136 proximity.normal = proximity.normal.invert();
137 proximity
138 }
139 ( shape::Variant::Bounded (shape::Bounded::Sphere (sphere_a)),
143 shape::Variant::Bounded (shape::Bounded::Cuboid (cuboid_b))
144 ) => Self::query_sphere_cuboid (
145 position_a, sphere_a, position_b, cuboid_b),
146 ( shape::Variant::Bounded (shape::Bounded::Cuboid (cuboid_a)),
147 shape::Variant::Bounded (shape::Bounded::Sphere (sphere_b))
148 ) => {
149 let mut proximity = Self::query_sphere_cuboid (
150 position_b, sphere_b, position_a, cuboid_a);
151 proximity.half_axis *= -1.0;
152 proximity.normal = proximity.normal.invert();
153 proximity
154 }
155 ( shape::Variant::Bounded (shape::Bounded::Sphere (sphere_a)),
159 shape::Variant::Unbounded (shape::Unbounded::Orthant (orthant_b))
160 ) => Self::query_sphere_orthant (
161 position_a, sphere_a, position_b, orthant_b),
162 ( shape::Variant::Unbounded (shape::Unbounded::Orthant (orthant_a)),
163 shape::Variant::Bounded (shape::Bounded::Sphere (sphere_b))
164 ) => {
165 let mut proximity = Self::query_sphere_orthant (
166 position_b, sphere_b, position_a, orthant_a);
167 proximity.half_axis *= -1.0;
168 proximity.normal = proximity.normal.invert();
169 proximity
170 }
171 ( shape::Variant::Bounded (shape::Bounded::Capsule (capsule_a)),
175 shape::Variant::Bounded (shape::Bounded::Cuboid (cuboid_b))
176 ) => Self::query_capsule_cuboid (
177 position_a, capsule_a, position_b, cuboid_b),
178 ( shape::Variant::Bounded (shape::Bounded::Cuboid (cuboid_a)),
179 shape::Variant::Bounded (shape::Bounded::Capsule (capsule_b))
180 ) => {
181 let mut proximity = Self::query_capsule_cuboid (
182 position_b, capsule_b, position_a, cuboid_a);
183 proximity.half_axis *= -1.0;
184 proximity.normal = proximity.normal.invert();
185 proximity
186 }
187 ( shape::Variant::Bounded (shape::Bounded::Capsule (capsule_a)),
191 shape::Variant::Unbounded (shape::Unbounded::Orthant (orthant_b))
192 ) => Self::query_capsule_orthant (
193 position_a, capsule_a, position_b, orthant_b),
194 ( shape::Variant::Unbounded (shape::Unbounded::Orthant (orthant_a)),
195 shape::Variant::Bounded (shape::Bounded::Capsule (capsule_b))
196 ) => {
197 let mut proximity = Self::query_capsule_orthant (
198 position_b, capsule_b, position_a, orthant_a);
199 proximity.half_axis *= -1.0;
200 proximity.normal = proximity.normal.invert();
201 proximity
202 }
203 ( shape::Variant::Bounded (shape::Bounded::Cuboid (cuboid_a)),
207 shape::Variant::Unbounded (shape::Unbounded::Orthant (orthant_b))
208 ) => Self::query_cuboid_orthant (
209 position_a, cuboid_a, position_b, orthant_b),
210 ( shape::Variant::Unbounded (shape::Unbounded::Orthant (orthant_a)),
211 shape::Variant::Bounded (shape::Bounded::Cuboid (cuboid_b))
212 ) => {
213 let mut proximity = Self::query_cuboid_orthant (
214 position_b, cuboid_b, position_a, orthant_a);
215 proximity.half_axis *= -1.0;
216 proximity.normal = proximity.normal.invert();
217 proximity
218 }
219 _ => unimplemented!("proximity query not implemented for (A, B): {:?}",
220 (shape_a, shape_b))
221 }
222 }
223
224 pub fn relation (&self) -> Relation {
225 if self.distance < 0.0 {
226 Relation::Intersect
227 } else if self.distance <= collision::CONTACT_DISTANCE {
228 Relation::Contact
229 } else {
230 debug_assert!(self.distance > collision::CONTACT_DISTANCE);
231 Relation::Disjoint
232 }
233 }
234
235 #[inline]
236 pub fn constraint_planar (&self) -> constraint::Planar {
237 constraint::Planar::new (self.midpoint, self.normal)
238 }
239
240 pub fn query_sphere_sphere (
241 position_a : &math::Point3 <f64>, sphere_a : &shape::Sphere <f64>,
242 position_b : &math::Point3 <f64>, sphere_b : &shape::Sphere <f64>
243 ) -> Self {
244 use math::num_traits::Zero;
245 let (radius_a, radius_b) = (*sphere_a.radius, *sphere_b.radius);
246 let distance_normal_half_axis = |axis : &math::Vector3 <f64>| {
247 let axis_distance = axis.magnitude();
248 let distance = axis_distance - radius_a - radius_b;
249 let normal = if axis.is_zero() {
250 math::Unit3::axis_x()
251 } else {
252 math::Unit3::unchecked_approx (-(axis / axis_distance))
253 };
254 let half_axis = -0.5 * distance * *normal;
255 (distance, normal, half_axis)
256 };
257 let axis = position_b - position_a;
258 let (distance, normal, half_axis) = distance_normal_half_axis (&axis);
259 let midpoint = position_a - radius_a * *normal + half_axis;
260 Proximity { distance, half_axis, midpoint, normal }
261 }
262
263 pub fn query_capsule_capsule (
264 position_a : &math::Point3 <f64>, capsule_a : &shape::Capsule <f64>,
265 position_b : &math::Point3 <f64>, capsule_b : &shape::Capsule <f64>
266 ) -> Self {
267 use math::num_traits::Zero;
268 let (half_height_a, half_height_b) =
269 (*capsule_a.half_height, *capsule_b.half_height);
270 let (radius_a, radius_b) = (*capsule_a.radius, *capsule_b.radius);
271 let shaft_max_a = position_a + math::Vector3::new (0.0, 0.0, half_height_a);
272 let shaft_min_a = position_a - math::Vector3::new (0.0, 0.0, half_height_a);
273 let shaft_max_b = position_b + math::Vector3::new (0.0, 0.0, half_height_b);
274 let shaft_min_b = position_b - math::Vector3::new (0.0, 0.0, half_height_b);
275 let distance_normal_half_axis = |axis : &math::Vector3 <f64>| {
276 let axis_distance = axis.magnitude();
277 let distance = axis_distance - radius_a - radius_b;
278 let normal = if axis.is_zero() {
279 math::Unit3::axis_x()
280 } else {
281 math::Unit3::unchecked_approx (-(axis / axis_distance))
282 };
283 let half_axis = -0.5 * distance * *normal;
284 (distance, normal, half_axis)
285 };
286 if shaft_max_a.0.z <= shaft_min_b.0.z {
287 let axis = shaft_min_b - shaft_max_a;
289 let (distance, normal, half_axis) = distance_normal_half_axis (&axis);
290 let midpoint = shaft_max_a - radius_a * *normal + half_axis;
291 Proximity { distance, half_axis, midpoint, normal }
292 } else if shaft_max_b.0.z <= shaft_min_a.0.z {
293 let axis = shaft_max_b.0 - shaft_min_a.0;
295 let (distance, normal, half_axis) = distance_normal_half_axis (&axis);
296 let midpoint = shaft_min_a - radius_a * *normal + half_axis;
297 Proximity { distance, half_axis, midpoint, normal }
298 } else {
299 let axis =
301 math::Point3::from ([position_b.0.x, position_b.0.y, 0.0]) -
302 math::Point3::from ([position_a.0.x, position_a.0.y, 0.0]);
303 let (distance, normal, half_axis) = distance_normal_half_axis (&axis);
304 let midpoint = {
305 let max_z = f64::min (shaft_max_a.0.z, shaft_max_b.0.z);
306 let min_z = f64::max (shaft_min_a.0.z, shaft_min_b.0.z);
307 let mid_z = 0.5 * (max_z + min_z);
308 let mid_a = position_a - radius_a * *normal + half_axis;
309 [mid_a.0.x, mid_a.0.y, mid_z].into()
310 };
311 Proximity { distance, half_axis, midpoint, normal }
312 }
313 }
314
315 pub fn query_cuboid_cuboid (
316 position_a : &math::Point3 <f64>, cuboid_a : &shape::Cuboid <f64>,
317 position_b : &math::Point3 <f64>, cuboid_b : &shape::Cuboid <f64>
318 ) -> Self {
319 use math::VectorSpace;
320 use math::num_traits::Zero;
321 fn nearest_ab_to_distance (
322 nearest_a : &math::Point3 <f64>,
323 nearest_b : &math::Point3 <f64>,
324 default_normal : &math::Unit3 <f64>
325 ) -> Proximity {
326 let axis = nearest_b - nearest_a;
327 let distance = axis.magnitude();
328 let half_axis = 0.5 * (nearest_b - nearest_a);
329 let midpoint = nearest_a + half_axis;
330 let normal = if axis.is_zero() {
331 *default_normal
332 } else {
333 math::Unit3::unchecked_approx (-axis / distance)
334 };
335 Proximity { distance, half_axis, midpoint, normal }
336 }
337
338 let max_a = position_a + cuboid_a.max().0;
339 let min_a = position_a + cuboid_a.min().0;
340 let max_b = position_b + cuboid_b.max().0;
341 let min_b = position_b + cuboid_b.min().0;
342 let overlap_x = min_b.0.x < max_a.0.x && min_a.0.x < max_b.0.x;
343 let overlap_y = min_b.0.y < max_a.0.y && min_a.0.y < max_b.0.y;
344 let overlap_z = min_b.0.z < max_a.0.z && min_a.0.z < max_b.0.z;
345 match (overlap_x, overlap_y, overlap_z) {
346 (false, false, false) => {
347 let a_to_b = position_b - position_a;
349 debug_assert!(!a_to_b.x.is_zero());
350 debug_assert!(!a_to_b.y.is_zero());
351 debug_assert!(!a_to_b.z.is_zero());
352 let a_to_b_sigvec = a_to_b.map (f64::signum);
353 let nearest_a = position_a + cuboid_a.max().0 * a_to_b_sigvec;
354 let nearest_b = position_b + cuboid_b.max().0 * (-a_to_b_sigvec);
355 nearest_ab_to_distance (&nearest_a, &nearest_b,
356 &math::Unit3::normalize (-a_to_b_sigvec))
357 }
358 (true, false, false) => {
359 let max_x = f64::min (max_a.0.x, max_b.0.x);
361 let min_x = f64::max (min_a.0.x, min_b.0.x);
362 debug_assert_ne!(min_x, max_x);
363 let mid_x = 0.5 * (min_x + max_x);
364 let a_to_b = position_b - position_a;
365 let a_to_b_yz = math::Vector3::new (0.0, a_to_b.y, a_to_b.z);
366 let a_to_b_yz_sigvec = math::Vector3::sigvec (a_to_b_yz);
367 debug_assert!(a_to_b_yz_sigvec.x.is_zero());
368 debug_assert!(!a_to_b_yz_sigvec.y.is_zero());
369 debug_assert!(!a_to_b_yz_sigvec.z.is_zero());
370 let nearest_a = {
371 let y = *cuboid_a.half_extent_y * a_to_b_yz_sigvec.y;
372 let z = *cuboid_a.half_extent_z * a_to_b_yz_sigvec.z;
373 [mid_x, position_a.0.y + y, position_a.0.z + z].into()
374 };
375 let nearest_b = {
376 let y = -*cuboid_b.half_extent_y * a_to_b_yz_sigvec.y;
377 let z = -*cuboid_b.half_extent_z * a_to_b_yz_sigvec.z;
378 [mid_x, position_b.0.y + y, position_b.0.z + z].into()
379 };
380 nearest_ab_to_distance (&nearest_a, &nearest_b,
381 &math::Unit3::normalize (-a_to_b_yz_sigvec))
382 }
383 (false, true, false) => {
384 let max_y = f64::min (max_a.0.y, max_b.0.y);
386 let min_y = f64::max (min_a.0.y, min_b.0.y);
387 debug_assert_ne!(min_y, max_y);
388 let mid_y = 0.5 * (min_y + max_y);
389 let a_to_b = position_b - position_a;
390 let a_to_b_xz = math::Vector3::new (a_to_b.x, 0.0, a_to_b.z);
391 let a_to_b_xz_sigvec = math::Vector3::sigvec (a_to_b_xz);
392 debug_assert!(!a_to_b_xz_sigvec.x.is_zero());
393 debug_assert!(a_to_b_xz_sigvec.y.is_zero());
394 debug_assert!(!a_to_b_xz_sigvec.z.is_zero());
395 let nearest_a = {
396 let x = *cuboid_a.half_extent_x * a_to_b_xz_sigvec.x;
397 let z = *cuboid_a.half_extent_z * a_to_b_xz_sigvec.z;
398 [position_a.0.x + x, mid_y, position_a.0.z + z].into()
399 };
400 let nearest_b = {
401 let x = -*cuboid_b.half_extent_x * a_to_b_xz_sigvec.x;
402 let z = -*cuboid_b.half_extent_z * a_to_b_xz_sigvec.z;
403 [position_b.0.x + x, mid_y, position_b.0.z + z].into()
404 };
405 nearest_ab_to_distance (&nearest_a, &nearest_b,
406 &math::Unit3::normalize (-a_to_b_xz_sigvec))
407 }
408 (false, false, true) => {
409 let max_z = f64::min (max_a.0.z, max_b.0.z);
411 let min_z = f64::max (min_a.0.z, min_b.0.z);
412 debug_assert_ne!(min_z, max_z);
413 let mid_z = 0.5 * (min_z + max_z);
414 let a_to_b = position_b - position_a;
415 let a_to_b_xy = math::Vector3::new (a_to_b.x, a_to_b.y, 0.0);
416 let a_to_b_xy_sigvec = math::Vector3::sigvec (a_to_b_xy);
417 debug_assert!(!a_to_b_xy_sigvec.x.is_zero());
418 debug_assert!(!a_to_b_xy_sigvec.y.is_zero());
419 debug_assert!(a_to_b_xy_sigvec.z.is_zero());
420 let nearest_a = {
421 let x = *cuboid_a.half_extent_x * a_to_b_xy_sigvec.x;
422 let y = *cuboid_a.half_extent_y * a_to_b_xy_sigvec.y;
423 [position_a.0.x + x, position_a.0.y + y, mid_z].into()
424 };
425 let nearest_b = {
426 let x = -*cuboid_b.half_extent_x * a_to_b_xy_sigvec.x;
427 let y = -*cuboid_b.half_extent_y * a_to_b_xy_sigvec.y;
428 [position_b.0.x + x, position_b.0.y + y, mid_z].into()
429 };
430 nearest_ab_to_distance (&nearest_a, &nearest_b,
431 &math::Unit3::normalize (-a_to_b_xy_sigvec))
432 }
433 (true, true, false) => {
434 let max_x = f64::min (max_a.0.x, max_b.0.x);
436 let min_x = f64::max (min_a.0.x, min_b.0.x);
437 let mid_x = 0.5 * (min_x + max_x);
438 let max_y = f64::min (max_a.0.y, max_b.0.y);
439 let min_y = f64::max (min_a.0.y, min_b.0.y);
440 let mid_y = 0.5 * (min_y + max_y);
441 let a_to_b_z = position_b.0.z - position_a.0.z;
442 let a_to_b_signum_z = a_to_b_z.signum();
443 debug_assert_ne!(a_to_b_signum_z, 0.0);
444 let nearest_a = math::Point3::new (
445 mid_x, mid_y,
446 position_a.0.z + a_to_b_signum_z * *cuboid_a.half_extent_z
447 );
448 let nearest_b = math::Point3::new (
449 mid_x, mid_y,
450 position_b.0.z - a_to_b_signum_z * *cuboid_b.half_extent_z
451 );
452 let nearest_a_to_b_z = nearest_b.0.z - nearest_a.0.z;
453 let distance = nearest_a_to_b_z.abs();
454 let half_axis = [0.0, 0.0, 0.5 * nearest_a_to_b_z].into();
455 let normal = math::Unit3::unchecked (
456 [0.0, 0.0, -a_to_b_signum_z].into());
457 let midpoint = nearest_a + half_axis;
458 Proximity { distance, half_axis, midpoint, normal }
459 }
460 (true, false, true) => {
461 let max_x = f64::min (max_a.0.x, max_b.0.x);
463 let min_x = f64::max (min_a.0.x, min_b.0.x);
464 let mid_x = 0.5 * (min_x + max_x);
465 let max_z = f64::min (max_a.0.z, max_b.0.z);
466 let min_z = f64::max (min_a.0.z, min_b.0.z);
467 let mid_z = 0.5 * (min_z + max_z);
468 let a_to_b_y = position_b.0.y - position_a.0.y;
469 let a_to_b_signum_y = a_to_b_y.signum();
470 debug_assert_ne!(a_to_b_signum_y, 0.0);
471 let nearest_a = math::Point3::new (
472 mid_x,
473 position_a.0.y + a_to_b_signum_y * *cuboid_a.half_extent_y,
474 mid_z
475 );
476 let nearest_b = math::Point3::new (
477 mid_x,
478 position_b.0.y - a_to_b_signum_y * *cuboid_b.half_extent_y,
479 mid_z
480 );
481 let nearest_a_to_b_y = nearest_b.0.y - nearest_a.0.y;
482 let distance = nearest_a_to_b_y.abs();
483 let half_axis = [0.0, 0.5 * nearest_a_to_b_y, 0.0].into();
484 let normal = math::Unit3::unchecked (
485 [0.0, -a_to_b_signum_y, 0.0].into());
486 let midpoint = nearest_a + half_axis;
487 Proximity { distance, half_axis, midpoint, normal }
488 }
489 (false, true, true) => {
490 let max_y = f64::min (max_a.0.y, max_b.0.y);
492 let min_y = f64::max (min_a.0.y, min_b.0.y);
493 let mid_y = 0.5 * (min_y + max_y);
494 let max_z = f64::min (max_a.0.z, max_b.0.z);
495 let min_z = f64::max (min_a.0.z, min_b.0.z);
496 let mid_z = 0.5 * (min_z + max_z);
497 let a_to_b_x = position_b.0.x - position_a.0.x;
498 let a_to_b_signum_x = a_to_b_x.signum();
499 debug_assert_ne!(a_to_b_signum_x, 0.0);
500 let nearest_a = math::Point3::new (
501 position_a.0.x + a_to_b_signum_x * *cuboid_a.half_extent_x,
502 mid_y,
503 mid_z
504 );
505 let nearest_b = math::Point3::new (
506 position_b.0.x - a_to_b_signum_x * *cuboid_b.half_extent_x,
507 mid_y,
508 mid_z
509 );
510 let nearest_a_to_b_x = nearest_b.0.x - nearest_a.0.x;
511 let distance = nearest_a_to_b_x.abs();
512 let half_axis = [0.5 * nearest_a_to_b_x, 0.0, 0.0].into();
513 let normal = math::Unit3::unchecked (
514 [-a_to_b_signum_x, 0.0, 0.0].into());
515 let midpoint = nearest_a + half_axis;
516 Proximity { distance, half_axis, midpoint, normal }
517 }
518 (true, true, true) => {
519 let max_x = f64::min (max_a.0.x, max_b.0.x);
521 let min_x = f64::max (min_a.0.x, min_b.0.x);
522 let mid_x = 0.5 * (min_x + max_x);
523 let max_y = f64::min (max_a.0.y, max_b.0.y);
524 let min_y = f64::max (min_a.0.y, min_b.0.y);
525 let mid_y = 0.5 * (min_y + max_y);
526 let max_z = f64::min (max_a.0.z, max_b.0.z);
527 let min_z = f64::max (min_a.0.z, min_b.0.z);
528 let mid_z = 0.5 * (min_z + max_z);
529 let midpoint = [mid_x, mid_y, mid_z].into();
530 let resolve_x = if position_a.0.x < position_b.0.x {
531 min_b.0.x - max_a.0.x
532 } else {
533 debug_assert!(position_a.0.x >= position_b.0.x);
534 max_b.0.x - min_a.0.x
535 };
536 let resolve_y = if position_a.0.y < position_b.0.y {
537 min_b.0.y - max_a.0.y
538 } else {
539 debug_assert!(position_a.0.y >= position_b.0.y);
540 max_b.0.y - min_a.0.y
541 };
542 let resolve_z = if position_a.0.z < position_b.0.z {
543 min_b.0.z - max_a.0.z
544 } else {
545 debug_assert!(position_a.0.z >= position_b.0.z);
546 max_b.0.z - min_a.0.z
547 };
548 let resolve_x_abs = resolve_x.abs();
549 let resolve_y_abs = resolve_y.abs();
550 let resolve_z_abs = resolve_z.abs();
551 let (distance, half_axis, normal) : (
552 f64, math::Vector3 <f64>, math::Unit3 <f64>
553 ) = if resolve_x_abs <= resolve_y_abs && resolve_x_abs <= resolve_z_abs {
554 ( -resolve_x_abs,
555 0.5 * math::Vector3::new (resolve_x, 0.0, 0.0),
556 math::Unit3::unchecked ([resolve_x.signum(), 0.0, 0.0].into())
557 )
558 } else if
559 resolve_y_abs <= resolve_x_abs && resolve_y_abs <= resolve_z_abs
560 {
561 ( -resolve_y_abs,
562 0.5 * math::Vector3::new (0.0, resolve_y, 0.0),
563 math::Unit3::unchecked ([0.0, resolve_y.signum(), 0.0].into())
564 )
565 } else {
566 debug_assert!(resolve_z_abs <= resolve_x_abs);
567 debug_assert!(resolve_z_abs <= resolve_y_abs);
568 ( -resolve_z_abs,
569 0.5 * math::Vector3::new (0.0, 0.0, resolve_z),
570 math::Unit3::unchecked ([0.0, 0.0, resolve_z.signum()].into())
571 )
572 };
573 debug_assert!(!half_axis.is_zero());
574 Proximity { distance, half_axis, midpoint, normal }
575 }
576 }
577 }
578
579 pub fn query_sphere_capsule (
985 position_a : &math::Point3 <f64>, sphere_a : &shape::Sphere <f64>,
986 position_b : &math::Point3 <f64>, capsule_b : &shape::Capsule <f64>
987 ) -> Self {
988 use math::num_traits::Zero;
989 let half_height_b = *capsule_b.half_height;
990 let (radius_a, radius_b) = (*sphere_a.radius, *capsule_b.radius);
991 let shaft_max_b = position_b + math::Vector3::new (0.0, 0.0, half_height_b);
992 let shaft_min_b = position_b - math::Vector3::new (0.0, 0.0, half_height_b);
993 let distance_normal_half_axis = |axis : &math::Vector3 <f64>| {
994 let axis_distance = axis.magnitude();
995 let distance = axis_distance - radius_a - radius_b;
996 let normal = if axis.is_zero() {
997 math::Unit3::axis_x()
998 } else {
999 math::Unit3::unchecked_approx (-(axis / axis_distance))
1000 };
1001 let half_axis = -0.5 * distance * *normal;
1002 (distance, normal, half_axis)
1003 };
1004 if position_a.0.z <= shaft_min_b.0.z {
1005 let axis = shaft_min_b - position_a;
1007 let (distance, normal, half_axis) = distance_normal_half_axis (&axis);
1008 let midpoint = position_a - radius_a * *normal + half_axis;
1009 Proximity { distance, half_axis, midpoint, normal }
1010 } else if shaft_max_b.0.z <= position_a.0.z {
1011 let axis = shaft_max_b - position_a;
1013 let (distance, normal, half_axis) = distance_normal_half_axis (&axis);
1014 let midpoint = position_a - radius_a * *normal + half_axis;
1015 Proximity { distance, half_axis, midpoint, normal }
1016 } else {
1017 let axis =
1019 math::Point3::from ([position_b.0.x, position_b.0.y, 0.0]) -
1020 math::Point3::from ([position_a.0.x, position_a.0.y, 0.0]);
1021 let (distance, normal, half_axis) = distance_normal_half_axis (&axis);
1022 let midpoint = {
1023 let max_z = f64::min (position_a.0.z, shaft_max_b.0.z);
1024 let min_z = f64::max (position_a.0.z, shaft_min_b.0.z);
1025 let mid_z = 0.5 * (max_z + min_z);
1026 let mid_a = position_a - radius_a * *normal + half_axis;
1027 [mid_a.0.x, mid_a.0.y, mid_z].into()
1028 };
1029 Proximity { distance, half_axis, midpoint, normal }
1030 }
1031 }
1032
1033 pub fn query_sphere_cuboid (
1034 position_a : &math::Point3 <f64>, sphere_a : &shape::Sphere <f64>,
1035 position_b : &math::Point3 <f64>, cuboid_b : &shape::Cuboid <f64>
1036 ) -> Self {
1037 use math::num_traits::Zero;
1038 let cuboid_max_b = position_b + cuboid_b.max().0;
1039 let cuboid_min_b = position_b - cuboid_b.max().0;
1040
1041 let overlap_x = cuboid_min_b.0.x < position_a.0.x &&
1042 position_a.0.x < cuboid_max_b.0.x;
1043 let overlap_y = cuboid_min_b.0.y < position_a.0.y &&
1044 position_a.0.y < cuboid_max_b.0.y;
1045
1046 let sphere_a_radius = *sphere_a.radius;
1047 let cuboid_b_half_extent_x = *cuboid_b.half_extent_x;
1048 let cuboid_b_half_extent_y = *cuboid_b.half_extent_y;
1049 let cuboid_b_half_extent_z = *cuboid_b.half_extent_z;
1050 if position_a.0.z >= cuboid_max_b.0.z {
1051 match (overlap_x, overlap_y) {
1053 (false, false) => {
1054 let b_to_a = position_a - position_b;
1056 debug_assert!(!b_to_a.x.is_zero());
1057 debug_assert!(!b_to_a.y.is_zero());
1058 debug_assert!(!b_to_a.z.is_zero());
1059 let b_to_a_sigvec = b_to_a.map (f64::signum);
1060 let nearest_b = position_b + cuboid_b.max().0 * b_to_a_sigvec;
1061 let a_to_b = nearest_b - position_a;
1062 let nearest_a = position_a + if !a_to_b.is_zero() {
1063 sphere_a_radius * a_to_b.normalized()
1064 } else {
1065 [-b_to_a_sigvec.x * sphere_a_radius, 0.0, 0.0].into()
1066 };
1067 let axis = nearest_b - nearest_a;
1068 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1069 a_to_b.dot (axis).signum()
1070 } else {
1071 -1.0
1072 };
1073 let half_axis = 0.5 * axis;
1074 let normal = if axis.is_zero() {
1075 math::Unit3::normalize (b_to_a_sigvec)
1076 } else {
1077 math::Unit3::unchecked_approx (-axis / distance)
1078 };
1079 let midpoint = nearest_a + half_axis;
1080 Proximity { distance, half_axis, midpoint, normal }
1081 }
1082 (true, false) => {
1083 let signum_y = (position_a.0.y - position_b.0.y).signum();
1085 let nearest_b = math::Point3::new (
1086 position_a.0.x,
1087 position_b.0.y + signum_y * cuboid_b_half_extent_y,
1088 cuboid_max_b.0.z
1089 );
1090 let a_to_b = nearest_b - position_a;
1091 let nearest_a = position_a + if a_to_b.is_zero() {
1092 -signum_y * math::Vector3::new (0.0, sphere_a_radius, 0.0)
1093 } else {
1094 sphere_a_radius * a_to_b.normalized()
1095 };
1096 let axis = nearest_b - nearest_a;
1097 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1098 a_to_b.dot (axis).signum()
1099 } else {
1100 -1.0
1101 };
1102 let half_axis = 0.5 * axis;
1103 let normal = if axis.is_zero() {
1104 math::Unit3::normalize (math::Vector3::new (0.0, signum_y, 1.0))
1105 } else {
1106 math::Unit3::unchecked_approx (-axis / distance)
1107 };
1108 let midpoint = nearest_a + half_axis;
1109 Proximity { distance, half_axis, midpoint, normal }
1110 }
1111 (false, true) => {
1112 let signum_x = (position_a.0.x - position_b.0.x).signum();
1114 let nearest_b = math::Point3::new (
1115 position_b.0.x + signum_x * cuboid_b_half_extent_x,
1116 position_a.0.y,
1117 cuboid_max_b.0.z
1118 );
1119 let a_to_b = nearest_b - position_a;
1120 let nearest_a = position_a + if a_to_b.is_zero() {
1121 -signum_x * math::Vector3::new (sphere_a_radius, 0.0, 0.0)
1122 } else {
1123 sphere_a_radius * a_to_b.normalized()
1124 };
1125 let axis = nearest_b - nearest_a;
1126 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1127 a_to_b.dot (axis).signum()
1128 } else {
1129 -1.0
1130 };
1131 let half_axis = 0.5 * axis;
1132 let normal = if axis.is_zero() {
1133 math::Unit3::normalize (math::Vector3::new (signum_x, 0.0, 1.0))
1134 } else {
1135 math::Unit3::unchecked_approx (-axis / distance)
1136 };
1137 let midpoint = nearest_a + half_axis;
1138 Proximity { distance, half_axis, midpoint, normal }
1139 }
1140 (true, true) => {
1141 let nearest_a : math::Point3 <f64> =
1143 position_a - math::Vector3::new (0.0, 0.0, sphere_a_radius);
1144 let nearest_b : math::Point3 <f64> =
1145 [position_a.0.x, position_a.0.y, cuboid_max_b.0.z].into();
1146 let axis = nearest_b - nearest_a;
1147 let normal = math::Unit3::axis_z();
1148 let half_axis = 0.5 * axis;
1149 let distance = nearest_a.0.z - nearest_b.0.z;
1150 let midpoint = nearest_a + half_axis;
1151 Proximity { distance, half_axis, midpoint, normal }
1152 }
1153 }
1154 } else if position_a.0.z <= cuboid_min_b.0.z {
1155 match (overlap_x, overlap_y) {
1157 (false, false) => {
1158 let b_to_a = position_a - position_b;
1160 debug_assert!(!b_to_a.x.is_zero());
1161 debug_assert!(!b_to_a.y.is_zero());
1162 debug_assert!(!b_to_a.z.is_zero());
1163 let b_to_a_sigvec = b_to_a.map (f64::signum);
1164 let nearest_b = position_b + cuboid_b.max().0 * b_to_a_sigvec;
1165 let a_to_b = nearest_b - position_a;
1166 let nearest_a = position_a + if !a_to_b.is_zero() {
1167 sphere_a_radius * a_to_b.normalized()
1168 } else {
1169 [-b_to_a_sigvec.x * sphere_a_radius, 0.0, 0.0].into()
1170 };
1171 let axis = nearest_b - nearest_a;
1172 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1173 a_to_b.dot (axis).signum()
1174 } else {
1175 -1.0
1176 };
1177 let half_axis = 0.5 * axis;
1178 let normal = if axis.is_zero() {
1179 math::Unit3::normalize (b_to_a_sigvec)
1180 } else {
1181 math::Unit3::unchecked_approx (-axis / distance)
1182 };
1183 let midpoint = nearest_a + half_axis;
1184 Proximity { distance, half_axis, midpoint, normal }
1185 }
1186 (true, false) => {
1187 let signum_y = (position_a.0.y - position_b.0.y).signum();
1189 let nearest_b = math::Point3::new (
1190 position_a.0.x,
1191 position_b.0.y + signum_y * cuboid_b_half_extent_y,
1192 cuboid_min_b.0.z
1193 );
1194 let a_to_b = nearest_b - position_a;
1195 let nearest_a = position_a + if a_to_b.is_zero() {
1196 -signum_y * math::Vector3::new (0.0, sphere_a_radius, 0.0)
1197 } else {
1198 sphere_a_radius * a_to_b.normalized()
1199 };
1200 let axis = nearest_b - nearest_a;
1201 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1202 a_to_b.dot (axis).signum()
1203 } else {
1204 -1.0
1205 };
1206 let half_axis = 0.5 * axis;
1207 let normal = if axis.is_zero() {
1208 math::Unit3::normalize (math::Vector3::new (0.0, signum_y, -1.0))
1209 } else {
1210 math::Unit3::unchecked_approx (-axis / distance)
1211 };
1212 let midpoint = nearest_a + half_axis;
1213 Proximity { distance, half_axis, midpoint, normal }
1214 }
1215 (false, true) => {
1216 let signum_x = (position_a.0.x - position_b.0.x).signum();
1218 let nearest_b = math::Point3::new (
1219 position_b.0.x + signum_x * cuboid_b_half_extent_x,
1220 position_a.0.y,
1221 cuboid_min_b.0.z
1222 );
1223 let a_to_b = nearest_b - position_a;
1224 let nearest_a = position_a + if a_to_b.is_zero() {
1225 -signum_x * math::Vector3::new (sphere_a_radius, 0.0, 0.0)
1226 } else {
1227 sphere_a_radius * a_to_b.normalized()
1228 };
1229 let axis = nearest_b - nearest_a;
1230 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1231 a_to_b.dot (axis).signum()
1232 } else {
1233 -1.0
1234 };
1235 let half_axis = 0.5 * axis;
1236 let normal = if axis.is_zero() {
1237 math::Unit3::normalize (math::Vector3::new (signum_x, 0.0, -1.0))
1238 } else {
1239 math::Unit3::unchecked_approx (-axis / distance)
1240 };
1241 let midpoint = nearest_a + half_axis;
1242 Proximity { distance, half_axis, midpoint, normal }
1243 }
1244 (true, true) => {
1245 let nearest_a : math::Point3 <f64> =
1247 position_a + math::Vector3::new (0.0, 0.0, sphere_a_radius);
1248 let nearest_b : math::Point3 <f64> =
1249 [position_a.0.x, position_a.0.y, cuboid_min_b.0.z].into();
1250 let axis = nearest_b - nearest_a;
1251 let normal = math::Unit3::axis_z().invert();
1252 let half_axis = 0.5 * axis;
1253 let distance = nearest_b.0.z - nearest_a.0.z;
1254 let midpoint = nearest_a + half_axis;
1255 Proximity { distance, half_axis, midpoint, normal }
1256 }
1257 }
1258 } else {
1259 match (overlap_x, overlap_y) {
1261 (false, false) => {
1262 let b_to_a_signum_x = (position_a.0.x - position_b.0.x).signum();
1264 let b_to_a_signum_y = (position_a.0.y - position_b.0.y).signum();
1265 let b_to_a_unit_sigvec =
1266 math::Vector3::new (b_to_a_signum_x, b_to_a_signum_y, 0.0)
1267 .normalized();
1268 let nearest_b = math::Point3::from ([
1269 position_b.0.x + b_to_a_signum_x * cuboid_b_half_extent_x,
1270 position_b.0.y + b_to_a_signum_y * cuboid_b_half_extent_y,
1271 position_a.0.z
1272 ]);
1273 let a_to_b = math::Vector3::new (
1274 nearest_b.0.x - position_a.0.x,
1275 nearest_b.0.y - position_a.0.y,
1276 0.0
1277 );
1278 let nearest_a = math::Point3::new (
1279 position_a.0.x, position_a.0.y, position_a.0.z
1280 ) + sphere_a_radius * if !a_to_b.is_zero() {
1281 a_to_b.normalized()
1282 } else {
1283 -b_to_a_unit_sigvec
1284 };
1285 let axis = nearest_b - nearest_a;
1286 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1287 a_to_b.dot (axis).signum()
1288 } else {
1289 -1.0
1290 };
1291 let half_axis = 0.5 * axis;
1292 let normal = math::Unit3::unchecked_approx (if axis.is_zero() {
1293 b_to_a_unit_sigvec
1294 } else {
1295 -axis / distance
1296 });
1297 let midpoint = nearest_a + half_axis;
1298 Proximity { distance, half_axis, midpoint, normal }
1299 }
1300 (true, false) => {
1301 let b_to_a_signum_y = (position_a.0.y - position_b.0.y).signum();
1303 let b_to_a_unit_sigvec =
1304 math::Vector3::new (0.0, b_to_a_signum_y, 0.0);
1305 let nearest_b = math::Point3::from ([
1306 position_a.0.x,
1307 position_b.0.y + b_to_a_signum_y * cuboid_b_half_extent_y,
1308 position_a.0.z
1309 ]);
1310 let a_to_b =
1311 math::Vector3::new (0.0, nearest_b.0.y - position_a.0.y, 0.0);
1312 let nearest_a = math::Point3::new (
1313 position_a.0.x, position_a.0.y, position_a.0.z
1314 ) + math::Vector3::new (0.0, -b_to_a_signum_y * sphere_a_radius, 0.0);
1315 let axis = nearest_b - nearest_a;
1316 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1317 a_to_b.dot (axis).signum()
1318 } else {
1319 -1.0
1320 };
1321 let half_axis = 0.5 * axis;
1322 let normal = math::Unit3::unchecked_approx (if axis.is_zero() {
1323 b_to_a_unit_sigvec
1324 } else {
1325 -axis / distance
1326 });
1327 let midpoint = nearest_a + half_axis;
1328 Proximity { distance, half_axis, midpoint, normal }
1329 }
1330 (false, true) => {
1331 let b_to_a_signum_x = (position_a.0.x - position_b.0.x).signum();
1333 let b_to_a_unit_sigvec =
1334 math::Vector3::new (b_to_a_signum_x, 0.0, 0.0);
1335 let nearest_b = math::Point3::from ([
1336 position_b.0.x + b_to_a_signum_x * cuboid_b_half_extent_x,
1337 position_a.0.y,
1338 position_a.0.z
1339 ]);
1340 let a_to_b =
1341 math::Vector3::new (nearest_b.0.x - position_a.0.x, 0.0, 0.0);
1342 let nearest_a = math::Point3::new (
1343 position_a.0.x, position_a.0.y, position_a.0.z
1344 ) + math::Vector3::new (-b_to_a_signum_x * sphere_a_radius, 0.0, 0.0);
1345 let axis = nearest_b - nearest_a;
1346 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1347 a_to_b.dot (axis).signum()
1348 } else {
1349 -1.0
1350 };
1351 let half_axis = 0.5 * axis;
1352 let normal = math::Unit3::unchecked_approx (if axis.is_zero() {
1353 b_to_a_unit_sigvec
1354 } else {
1355 -axis / distance
1356 });
1357 let midpoint = nearest_a + half_axis;
1358 Proximity { distance, half_axis, midpoint, normal }
1359 }
1360 (true, true) => {
1361 if position_a == position_b {
1363 let depth_x = cuboid_b_half_extent_x + sphere_a_radius;
1364 let depth_y = cuboid_b_half_extent_y + sphere_a_radius;
1365 let depth_z = cuboid_b_half_extent_z + sphere_a_radius;
1366 if depth_x <= depth_y && depth_x <= depth_z {
1367 let distance = -depth_x;
1368 let half_axis = [0.5 * depth_x, 0.0, 0.0].into();
1369 let normal = math::Unit3::axis_x();
1370 let midpoint = position_a + half_axis -
1371 math::Vector3::new (sphere_a_radius, 0.0, 0.0);
1372 Proximity { distance, half_axis, midpoint, normal }
1373 } else if depth_y <= depth_x && depth_y <= depth_z {
1374 let distance = -depth_y;
1375 let half_axis = [0.0, 0.5 * depth_y, 0.0].into();
1376 let normal = math::Unit3::axis_y();
1377 let midpoint = position_a + half_axis -
1378 math::Vector3::new (0.0, sphere_a_radius, 0.0);
1379 Proximity { distance, half_axis, midpoint, normal }
1380 } else {
1381 debug_assert!(depth_z < depth_x);
1382 debug_assert!(depth_z < depth_y);
1383 let distance = -depth_z;
1384 let half_axis = [0.0, 0.0, 0.5 * depth_z].into();
1385 let normal = math::Unit3::axis_z();
1386 let midpoint = position_a + half_axis -
1387 math::Vector3::new (0.0, 0.0, sphere_a_radius);
1388 Proximity { distance, half_axis, midpoint, normal }
1389 }
1390 } else {
1391 let b_to_a_sigvec = (position_a - position_b).map (f64::signum);
1394 let corner_b = position_b + cuboid_b.max().0 * b_to_a_sigvec;
1395 let depth_x = (corner_b.0.x - position_a.0.x).abs() +
1396 sphere_a_radius;
1397 let depth_y = (corner_b.0.y - position_a.0.y).abs() +
1398 sphere_a_radius;
1399 let depth_z = (corner_b.0.z - position_a.0.z).abs() +
1400 sphere_a_radius -
1401 if position_a.0.z.abs() > corner_b.0.z.abs() {
1402 2.0 * (position_a.0.z.abs() - corner_b.0.z.abs())
1403 } else {
1404 0.0
1405 };
1406
1407 if depth_x <= depth_y && depth_x <= depth_z {
1408 let distance = -depth_x;
1409 let half_axis = [0.5 * b_to_a_sigvec.x * depth_x, 0.0, 0.0].into();
1410 let normal = math::Unit3::unchecked (
1411 [b_to_a_sigvec.x, 0.0, 0.0].into());
1412 let midpoint = position_a + half_axis +
1413 math::Vector3::new (
1414 -b_to_a_sigvec.x * sphere_a_radius, 0.0, 0.0);
1415 Proximity { distance, half_axis, midpoint, normal }
1416 } else if depth_y <= depth_x && depth_y <= depth_z {
1417 let distance = -depth_y;
1418 let half_axis = [0.0, 0.5 * b_to_a_sigvec.y * depth_y, 0.0].into();
1419 let normal = math::Unit3::unchecked (
1420 [0.0, b_to_a_sigvec.y, 0.0].into());
1421 let midpoint = position_a + half_axis +
1422 math::Vector3::new (
1423 0.0, -b_to_a_sigvec.y * sphere_a_radius, 0.0);
1424 Proximity { distance, half_axis, midpoint, normal }
1425 } else {
1426 debug_assert!(depth_z < depth_x);
1427 debug_assert!(depth_z < depth_y);
1428 let nearest_a = math::Point3::new (
1429 position_a.0.x,
1430 position_a.0.y,
1431 position_a.0.z - b_to_a_sigvec.z * sphere_a_radius
1432 );
1433 let nearest_b = math::Point3::new (
1434 position_a.0.x,
1435 position_a.0.y,
1436 position_b.0.z + b_to_a_sigvec.z * cuboid_b_half_extent_z
1437 );
1438 let axis = nearest_b - nearest_a;
1439 debug_assert_eq!(axis.x, 0.0);
1440 debug_assert_eq!(axis.y, 0.0);
1441 let distance = -axis.z.abs();
1442 let half_axis = 0.5 * axis;
1443 let normal = math::Unit3::unchecked (
1444 [0.0, 0.0, b_to_a_sigvec.z].into());
1445 let midpoint = nearest_a + half_axis;
1446 Proximity { distance, half_axis, midpoint, normal }
1447 }
1448 }
1449 }
1450 }
1451 }
1452 } pub fn query_sphere_orthant (
1455 position_a : &math::Point3 <f64>, sphere_a : &shape::Sphere <f64>,
1456 position_b : &math::Point3 <f64>, orthant_b : &shape::Orthant
1457 ) -> Self {
1458 let radius_a = *sphere_a.radius;
1459 let normal = orthant_b.normal_axis.to_vec::<f64>();
1460 let normal_abs = normal.map (f64::abs);
1461 let surface_sigvec = math::Vector3::new (1.0, 1.0, 1.0) - normal_abs;
1462 let nearest_a = position_a -
1463 math::Vector3::new (radius_a, radius_a, radius_a) * normal;
1464 let nearest_b =
1465 math::Point3 (position_a.0 * surface_sigvec + position_b.0 * normal_abs);
1466 let axis = nearest_b - nearest_a;
1467 debug_assert_eq!(axis.sum().abs(), axis.magnitude());
1468 let distance = -normal.dot (axis).signum() * axis.sum().abs();
1469 let half_axis = 0.5 * axis;
1470 let midpoint = nearest_a + half_axis;
1471 let normal = math::Unit3::unchecked (normal);
1472 Proximity { distance, half_axis, midpoint, normal }
1473 } pub fn query_capsule_cuboid (
1476 position_a : &math::Point3 <f64>, capsule_a : &shape::Capsule <f64>,
1477 position_b : &math::Point3 <f64>, cuboid_b : &shape::Cuboid <f64>
1478 ) -> Self {
1479 use math::num_traits::Zero;
1480 let shaft_max_a = position_a +
1481 math::Vector3::new (0.0, 0.0, *capsule_a.half_height);
1482 let shaft_min_a = position_a -
1483 math::Vector3::new (0.0, 0.0, *capsule_a.half_height);
1484 let cuboid_max_b = position_b + cuboid_b.max().0;
1485 let cuboid_min_b = position_b - cuboid_b.max().0;
1486
1487 let overlap_x = cuboid_min_b.0.x < position_a.0.x &&
1488 position_a.0.x < cuboid_max_b.0.x;
1489 let overlap_y = cuboid_min_b.0.y < position_a.0.y &&
1490 position_a.0.y < cuboid_max_b.0.y;
1491
1492 let capsule_a_radius = *capsule_a.radius;
1493 let capsule_a_half_height = *capsule_a.half_height;
1494 let cuboid_b_half_extent_x = *cuboid_b.half_extent_x;
1495 let cuboid_b_half_extent_y = *cuboid_b.half_extent_y;
1496 let cuboid_b_half_extent_z = *cuboid_b.half_extent_z;
1497 if shaft_min_a.0.z >= cuboid_max_b.0.z {
1498 match (overlap_x, overlap_y) {
1500 (false, false) => {
1501 let b_to_a = shaft_min_a - position_b;
1503 debug_assert!(!b_to_a.x.is_zero());
1504 debug_assert!(!b_to_a.y.is_zero());
1505 debug_assert!(!b_to_a.z.is_zero());
1506 let b_to_a_sigvec = b_to_a.map (f64::signum);
1507 let nearest_b = position_b + cuboid_b.max().0 * b_to_a_sigvec;
1508 let a_to_b = nearest_b - shaft_min_a;
1509 let nearest_a = shaft_min_a + if !a_to_b.is_zero() {
1510 capsule_a_radius * a_to_b.normalized()
1511 } else {
1512 [-b_to_a_sigvec.x * capsule_a_radius, 0.0, 0.0].into()
1513 };
1514 let axis = nearest_b - nearest_a;
1515 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1516 a_to_b.dot (axis).signum()
1517 } else {
1518 -1.0
1519 };
1520 let half_axis = 0.5 * axis;
1521 let normal = if axis.is_zero() {
1522 math::Unit3::normalize (b_to_a_sigvec)
1523 } else {
1524 math::Unit3::unchecked_approx (-axis / distance)
1525 };
1526 let midpoint = nearest_a + half_axis;
1527 Proximity { distance, half_axis, midpoint, normal }
1528 }
1529 (true, false) => {
1530 let signum_y = (shaft_min_a.0.y - position_b.0.y).signum();
1532 let nearest_b = math::Point3::new (
1533 shaft_min_a.0.x,
1534 position_b.0.y + signum_y * cuboid_b_half_extent_y,
1535 cuboid_max_b.0.z
1536 );
1537 let a_to_b = nearest_b - shaft_min_a;
1538 let nearest_a = shaft_min_a + if a_to_b.is_zero() {
1539 -signum_y * math::Vector3::new (0.0, capsule_a_radius, 0.0)
1540 } else {
1541 capsule_a_radius * a_to_b.normalized()
1542 };
1543 let axis = nearest_b - nearest_a;
1544 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1545 a_to_b.dot (axis).signum()
1546 } else {
1547 -1.0
1548 };
1549 let half_axis = 0.5 * axis;
1550 let normal = if axis.is_zero() {
1551 math::Unit3::normalize (math::Vector3::new (0.0, signum_y, 1.0))
1552 } else {
1553 math::Unit3::unchecked_approx (-axis / distance)
1554 };
1555 let midpoint = nearest_a + half_axis;
1556 Proximity { distance, half_axis, midpoint, normal }
1557 }
1558 (false, true) => {
1559 let signum_x = (shaft_min_a.0.x - position_b.0.x).signum();
1561 let nearest_b = math::Point3::new (
1562 position_b.0.x + signum_x * cuboid_b_half_extent_x,
1563 shaft_min_a.0.y,
1564 cuboid_max_b.0.z
1565 );
1566 let a_to_b = nearest_b - shaft_min_a;
1567 let nearest_a = shaft_min_a + if a_to_b.is_zero() {
1568 -signum_x * math::Vector3::new (capsule_a_radius, 0.0, 0.0)
1569 } else {
1570 capsule_a_radius * a_to_b.normalized()
1571 };
1572 let axis = nearest_b - nearest_a;
1573 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1574 a_to_b.dot (axis).signum()
1575 } else {
1576 -1.0
1577 };
1578 let half_axis = 0.5 * axis;
1579 let normal = if axis.is_zero() {
1580 math::Unit3::normalize (math::Vector3::new (signum_x, 0.0, 1.0))
1581 } else {
1582 math::Unit3::unchecked_approx (-axis / distance)
1583 };
1584 let midpoint = nearest_a + half_axis;
1585 Proximity { distance, half_axis, midpoint, normal }
1586 }
1587 (true, true) => {
1588 let nearest_a : math::Point3 <f64> =
1590 shaft_min_a - math::Vector3::new (0.0, 0.0, capsule_a_radius);
1591 let nearest_b : math::Point3 <f64> =
1592 [position_a.0.x, position_a.0.y, cuboid_max_b.0.z].into();
1593 let axis = nearest_b - nearest_a;
1594 let normal = math::Unit3::axis_z();
1595 let half_axis = 0.5 * axis;
1596 let distance = nearest_a.0.z - nearest_b.0.z;
1597 let midpoint = nearest_a + half_axis;
1598 Proximity { distance, half_axis, midpoint, normal }
1599 }
1600 }
1601 } else if shaft_max_a.0.z <= cuboid_min_b.0.z {
1602 match (overlap_x, overlap_y) {
1604 (false, false) => {
1605 let b_to_a = shaft_max_a - position_b;
1607 debug_assert!(!b_to_a.x.is_zero());
1608 debug_assert!(!b_to_a.y.is_zero());
1609 debug_assert!(!b_to_a.z.is_zero());
1610 let b_to_a_sigvec = b_to_a.map (f64::signum);
1611 let nearest_b = position_b + cuboid_b.max().0 * b_to_a_sigvec;
1612 let a_to_b = nearest_b - shaft_max_a;
1613 let nearest_a = shaft_max_a + if !a_to_b.is_zero() {
1614 capsule_a_radius * a_to_b.normalized()
1615 } else {
1616 [-b_to_a_sigvec.x * capsule_a_radius, 0.0, 0.0].into()
1617 };
1618 let axis = nearest_b - nearest_a;
1619 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1620 a_to_b.dot (axis).signum()
1621 } else {
1622 -1.0
1623 };
1624 let half_axis = 0.5 * axis;
1625 let normal = if axis.is_zero() {
1626 math::Unit3::normalize (b_to_a_sigvec)
1627 } else {
1628 math::Unit3::unchecked_approx (-axis / distance)
1629 };
1630 let midpoint = nearest_a + half_axis;
1631 Proximity { distance, half_axis, midpoint, normal }
1632 }
1633 (true, false) => {
1634 let signum_y = (shaft_max_a.0.y - position_b.0.y).signum();
1636 let nearest_b = math::Point3::new (
1637 shaft_max_a.0.x,
1638 position_b.0.y + signum_y * cuboid_b_half_extent_y,
1639 cuboid_min_b.0.z
1640 );
1641 let a_to_b = nearest_b - shaft_max_a;
1642 let nearest_a = shaft_max_a + if a_to_b.is_zero() {
1643 -signum_y * math::Vector3::new (0.0, capsule_a_radius, 0.0)
1644 } else {
1645 capsule_a_radius * a_to_b.normalized()
1646 };
1647 let axis = nearest_b - nearest_a;
1648 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1649 a_to_b.dot (axis).signum()
1650 } else {
1651 -1.0
1652 };
1653 let half_axis = 0.5 * axis;
1654 let normal = if axis.is_zero() {
1655 math::Unit3::normalize (math::Vector3::new (0.0, signum_y, -1.0))
1656 } else {
1657 math::Unit3::unchecked_approx (-axis / distance)
1658 };
1659 let midpoint = nearest_a + half_axis;
1660 Proximity { distance, half_axis, midpoint, normal }
1661 }
1662 (false, true) => {
1663 let signum_x = (shaft_max_a.0.x - position_b.0.x).signum();
1665 let nearest_b = math::Point3::new (
1666 position_b.0.x + signum_x * cuboid_b_half_extent_x,
1667 shaft_max_a.0.y,
1668 cuboid_min_b.0.z
1669 );
1670 let a_to_b = nearest_b - shaft_max_a;
1671 let nearest_a = shaft_max_a + if a_to_b.is_zero() {
1672 -signum_x * math::Vector3::new (capsule_a_radius, 0.0, 0.0)
1673 } else {
1674 capsule_a_radius * a_to_b.normalized()
1675 };
1676 let axis = nearest_b - nearest_a;
1677 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1678 a_to_b.dot (axis).signum()
1679 } else {
1680 -1.0
1681 };
1682 let half_axis = 0.5 * axis;
1683 let normal = if axis.is_zero() {
1684 math::Unit3::normalize (math::Vector3::new (signum_x, 0.0, -1.0))
1685 } else {
1686 math::Unit3::unchecked_approx (-axis / distance)
1687 };
1688 let midpoint = nearest_a + half_axis;
1689 Proximity { distance, half_axis, midpoint, normal }
1690 }
1691 (true, true) => {
1692 let nearest_a : math::Point3 <f64> =
1694 shaft_max_a + math::Vector3::new (0.0, 0.0, capsule_a_radius);
1695 let nearest_b : math::Point3 <f64> =
1696 [position_a.0.x, position_a.0.y, cuboid_min_b.0.z].into();
1697 let axis = nearest_b - nearest_a;
1698 let normal = math::Unit3::axis_z().invert();
1699 let half_axis = 0.5 * axis;
1700 let distance = nearest_b.0.z - nearest_a.0.z;
1701 let midpoint = nearest_a + half_axis;
1702 Proximity { distance, half_axis, midpoint, normal }
1703 }
1704 }
1705 } else {
1706 let max_z = f64::min (shaft_max_a.0.z, cuboid_max_b.0.z);
1708 let min_z = f64::max (shaft_min_a.0.z, cuboid_min_b.0.z);
1709 debug_assert_ne!(min_z, max_z);
1710 let mid_z = 0.5 * (max_z + min_z);
1711 match (overlap_x, overlap_y) {
1712 (false, false) => {
1713 let b_to_a_signum_x = (position_a.0.x - position_b.0.x).signum();
1715 let b_to_a_signum_y = (position_a.0.y - position_b.0.y).signum();
1716 let b_to_a_unit_sigvec =
1717 math::Vector3::new (b_to_a_signum_x, b_to_a_signum_y, 0.0)
1718 .normalized();
1719 let nearest_b = math::Point3::from ([
1720 position_b.0.x + b_to_a_signum_x * cuboid_b_half_extent_x,
1721 position_b.0.y + b_to_a_signum_y * cuboid_b_half_extent_y,
1722 mid_z
1723 ]);
1724 let a_to_b = math::Vector3::new (
1725 nearest_b.0.x - position_a.0.x,
1726 nearest_b.0.y - position_a.0.y,
1727 0.0
1728 );
1729 let nearest_a = math::Point3::new (
1730 position_a.0.x, position_a.0.y, mid_z
1731 ) + capsule_a_radius * if !a_to_b.is_zero() {
1732 a_to_b.normalized()
1733 } else {
1734 -b_to_a_unit_sigvec
1735 };
1736 let axis = nearest_b - nearest_a;
1737 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1738 a_to_b.dot (axis).signum()
1739 } else {
1740 -1.0
1741 };
1742 let half_axis = 0.5 * axis;
1743 let normal = math::Unit3::unchecked_approx (if axis.is_zero() {
1744 b_to_a_unit_sigvec
1745 } else {
1746 -axis / distance
1747 });
1748 let midpoint = nearest_a + half_axis;
1749 Proximity { distance, half_axis, midpoint, normal }
1750 }
1751 (true, false) => {
1752 let b_to_a_signum_y = (position_a.0.y - position_b.0.y).signum();
1754 let b_to_a_unit_sigvec =
1755 math::Vector3::new (0.0, b_to_a_signum_y, 0.0);
1756 let nearest_b = math::Point3::from ([
1757 position_a.0.x,
1758 position_b.0.y + b_to_a_signum_y * cuboid_b_half_extent_y,
1759 mid_z
1760 ]);
1761 let a_to_b =
1762 math::Vector3::new (0.0, nearest_b.0.y - position_a.0.y, 0.0);
1763 let nearest_a = math::Point3::new (
1764 position_a.0.x, position_a.0.y, mid_z
1765 ) + math::Vector3::new (0.0, -b_to_a_signum_y * capsule_a_radius, 0.0);
1766 let axis = nearest_b - nearest_a;
1767 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1768 a_to_b.dot (axis).signum()
1769 } else {
1770 -1.0
1771 };
1772 let half_axis = 0.5 * axis;
1773 let normal = math::Unit3::unchecked_approx (if axis.is_zero() {
1774 b_to_a_unit_sigvec
1775 } else {
1776 -axis / distance
1777 });
1778 let midpoint = nearest_a + half_axis;
1779 Proximity { distance, half_axis, midpoint, normal }
1780 }
1781 (false, true) => {
1782 let b_to_a_signum_x = (position_a.0.x - position_b.0.x).signum();
1784 let b_to_a_unit_sigvec =
1785 math::Vector3::new (b_to_a_signum_x, 0.0, 0.0);
1786 let nearest_b = math::Point3::from ([
1787 position_b.0.x + b_to_a_signum_x * cuboid_b_half_extent_x,
1788 position_a.0.y,
1789 mid_z
1790 ]);
1791 let a_to_b =
1792 math::Vector3::new (nearest_b.0.x - position_a.0.x, 0.0, 0.0);
1793 let nearest_a = math::Point3::new (
1794 position_a.0.x, position_a.0.y, mid_z
1795 ) + math::Vector3::new (-b_to_a_signum_x * capsule_a_radius, 0.0, 0.0);
1796 let axis = nearest_b - nearest_a;
1797 let distance = axis.magnitude() * if !a_to_b.is_zero() {
1798 a_to_b.dot (axis).signum()
1799 } else {
1800 -1.0
1801 };
1802 let half_axis = 0.5 * axis;
1803 let normal = math::Unit3::unchecked_approx (if axis.is_zero() {
1804 b_to_a_unit_sigvec
1805 } else {
1806 -axis / distance
1807 });
1808 let midpoint = nearest_a + half_axis;
1809 Proximity { distance, half_axis, midpoint, normal }
1810 }
1811 (true, true) => {
1812 if position_a == position_b {
1814 let depth_x = cuboid_b_half_extent_x + capsule_a_radius;
1815 let depth_y = cuboid_b_half_extent_y + capsule_a_radius;
1816 let depth_z = cuboid_b_half_extent_z + capsule_a_half_height +
1817 capsule_a_radius;
1818 if depth_x <= depth_y && depth_x <= depth_z {
1819 let distance = -depth_x;
1820 let half_axis = [0.5 * depth_x, 0.0, 0.0].into();
1821 let normal = math::Unit3::axis_x();
1822 let midpoint = position_a + half_axis -
1823 math::Vector3::new (capsule_a_radius, 0.0, 0.0);
1824 Proximity { distance, half_axis, midpoint, normal }
1825 } else if depth_y <= depth_x && depth_y <= depth_z {
1826 let distance = -depth_y;
1827 let half_axis = [0.0, 0.5 * depth_y, 0.0].into();
1828 let normal = math::Unit3::axis_y();
1829 let midpoint = position_a + half_axis -
1830 math::Vector3::new (0.0, capsule_a_radius, 0.0);
1831 Proximity { distance, half_axis, midpoint, normal }
1832 } else {
1833 debug_assert!(depth_z < depth_x);
1834 debug_assert!(depth_z < depth_y);
1835 let distance = -depth_z;
1836 let half_axis = [0.0, 0.0, 0.5 * depth_z].into();
1837 let normal = math::Unit3::axis_z();
1838 let midpoint = position_a + half_axis - math::Vector3::new (
1839 0.0, 0.0, capsule_a_radius + capsule_a_half_height);
1840 Proximity { distance, half_axis, midpoint, normal }
1841 }
1842 } else {
1843 let b_to_a_sigvec = (position_a - position_b).map (f64::signum);
1846 let corner_b = position_b + cuboid_b.max().0 * b_to_a_sigvec;
1847 let depth_x = (corner_b.0.x - position_a.0.x).abs() +
1848 capsule_a_radius;
1849 let depth_y = (corner_b.0.y - position_a.0.y).abs() +
1850 capsule_a_radius;
1851 let depth_z = (corner_b.0.z - position_a.0.z).abs() +
1852 capsule_a_radius + capsule_a_half_height -
1853 if position_a.0.z.abs() > corner_b.0.z.abs() {
1854 2.0 * (position_a.0.z.abs() - corner_b.0.z.abs())
1855 } else {
1856 0.0
1857 };
1858
1859 if depth_x <= depth_y && depth_x <= depth_z {
1860 let distance = -depth_x;
1861 let half_axis = [0.5 * b_to_a_sigvec.x * depth_x, 0.0, 0.0].into();
1862 let normal = math::Unit3::unchecked (
1863 [b_to_a_sigvec.x, 0.0, 0.0].into());
1864 let midpoint = position_a + half_axis +
1865 math::Vector3::new (
1866 -b_to_a_sigvec.x * capsule_a_radius, 0.0, 0.0);
1867 Proximity { distance, half_axis, midpoint, normal }
1868 } else if depth_y <= depth_x && depth_y <= depth_z {
1869 let distance = -depth_y;
1870 let half_axis = [0.0, 0.5 * b_to_a_sigvec.y * depth_y, 0.0].into();
1871 let normal = math::Unit3::unchecked (
1872 [0.0, b_to_a_sigvec.y, 0.0].into());
1873 let midpoint = position_a + half_axis +
1874 math::Vector3::new (
1875 0.0, -b_to_a_sigvec.y * capsule_a_radius, 0.0);
1876 Proximity { distance, half_axis, midpoint, normal }
1877 } else {
1878 debug_assert!(depth_z < depth_x);
1879 debug_assert!(depth_z < depth_y);
1880 let nearest_a = math::Point3::new (
1881 position_a.0.x,
1882 position_a.0.y,
1883 position_a.0.z - b_to_a_sigvec.z *
1884 (capsule_a_radius + capsule_a_half_height)
1885 );
1886 let nearest_b = math::Point3::new (
1887 position_a.0.x,
1888 position_a.0.y,
1889 position_b.0.z + b_to_a_sigvec.z * cuboid_b_half_extent_z
1890 );
1891 let axis = nearest_b - nearest_a;
1892 debug_assert_eq!(axis.x, 0.0);
1893 debug_assert_eq!(axis.y, 0.0);
1894 let distance = -axis.z.abs();
1895 let half_axis = 0.5 * axis;
1896 let normal = math::Unit3::unchecked (
1897 [0.0, 0.0, b_to_a_sigvec.z].into());
1898 let midpoint = nearest_a + half_axis;
1899 Proximity { distance, half_axis, midpoint, normal }
1900 }
1901 }
1902 }
1903 }
1904 }
1905 } pub fn query_capsule_orthant (
1908 position_a : &math::Point3 <f64>, capsule_a : &shape::Capsule <f64>,
1909 position_b : &math::Point3 <f64>, orthant_b : &shape::Orthant
1910 ) -> Self {
1911 let radius_a = *capsule_a.radius;
1912 let half_height = *capsule_a.half_height;
1913 let normal = orthant_b.normal_axis.to_vec::<f64>();
1914 let normal_abs = normal.map (f64::abs);
1915 let surface_sigvec = math::Vector3::new (1.0, 1.0, 1.0) - normal_abs;
1916 let nearest_a = position_a -
1917 math::Vector3::new (radius_a, radius_a, radius_a + half_height) * normal;
1918 let nearest_b =
1919 math::Point3 (position_a.0 * surface_sigvec + position_b.0 * normal_abs);
1920 let axis = nearest_b - nearest_a;
1921 debug_assert_eq!(axis.sum().abs(), axis.magnitude());
1922 let distance = -normal.dot (axis).signum() * axis.sum().abs();
1923 let half_axis = 0.5 * axis;
1924 let midpoint = nearest_a + half_axis;
1925 let normal = math::Unit3::unchecked (normal);
1926 Proximity { distance, half_axis, midpoint, normal }
1927 } pub fn query_cuboid_orthant (
1930 position_a : &math::Point3 <f64>, cuboid_a : &shape::Cuboid <f64>,
1931 position_b : &math::Point3 <f64>, orthant_b : &shape::Orthant
1932 ) -> Self {
1933 let normal = orthant_b.normal_axis.to_vec::<f64>();
1934 let normal_abs = normal.map (f64::abs);
1935 let surface_sigvec = math::Vector3::new (1.0, 1.0, 1.0) - normal_abs;
1936 let nearest_a = position_a - cuboid_a.half_extents_vec() * normal;
1937 let nearest_b =
1938 math::Point3 (position_a.0 * surface_sigvec + position_b.0 * normal_abs);
1939 let axis = nearest_b - nearest_a;
1940 debug_assert_eq!(axis.sum().abs(), axis.magnitude());
1941 let distance = -normal.dot (axis).signum() * axis.sum().abs();
1942 let half_axis = 0.5 * axis;
1943 let midpoint = nearest_a + half_axis;
1944 let normal = math::Unit3::unchecked (normal);
1945 Proximity { distance, half_axis, midpoint, normal }
1946 } } #[cfg(test)]
1951mod tests {
1952 extern crate test;
1953 use {std, rand};
1954 use rand_xorshift::XorShiftRng;
1955 use std::f64::consts::*;
1956 use super::*;
1957 #[test]
1961 fn test_distance_query() {
1962 use rand::{Rng, SeedableRng};
1963 use geometry::shape;
1964 use math::approx::{assert_relative_eq, assert_ulps_eq};
1965
1966 let a = object::Static {
1973 position: component::Position ([0.0, 0.0, 0.0].into()),
1974 bound: component::Bound (shape::Bounded::from (
1975 shape::Capsule::noisy (2.0, 3.0)).into()),
1976 material: component::MATERIAL_STONE,
1977 collidable: true
1978 };
1979 let b = object::Static {
1980 position: component::Position ([0.0, 0.0, 0.0].into()),
1981 bound: component::Bound (shape::Bounded::from (
1982 shape::Capsule::noisy (1.0, 2.0)).into()),
1983 material: component::MATERIAL_STONE,
1984 collidable: true
1985 };
1986 assert_eq!(
1987 Proximity::query (&a, &b),
1988 Proximity {
1989 distance: -3.0,
1990 half_axis: [ 1.5, 0.0, 0.0].into(),
1991 normal: math::Unit3::axis_x(),
1992 midpoint: [-0.5, 0.0, 0.0].into()
1993 }
1994 );
1995
1996 let a = object::Static {
1999 position: component::Position ([0.0, 0.0, 1.0].into()), .. a
2000 };
2001 let b = object::Static {
2002 position: component::Position ([0.0, 0.0, -1.0].into()), .. b
2003 };
2004 assert_eq!(
2005 Proximity::query (&a, &b),
2006 Proximity {
2007 distance: -3.0,
2008 half_axis: [ 1.5, 0.0, 0.0].into(),
2009 normal: math::Unit3::axis_x(),
2010 midpoint: [-0.5, 0.0, -0.5].into()
2011 }
2012 );
2013
2014 let a = object::Static {
2017 position: component::Position ([0.0, 0.0, -3.0].into()), .. a
2018 };
2019 let b = object::Static {
2020 position: component::Position ([0.0, 0.0, 2.0].into()), .. b
2021 };
2022 assert_eq!(
2023 Proximity::query (&a, &b),
2024 Proximity {
2025 distance: -3.0,
2026 half_axis: [ 1.5, 0.0, 0.0].into(),
2027 normal: math::Unit3::axis_x(),
2028 midpoint: [-0.5, 0.0, 0.0].into()
2029 }
2030 );
2031
2032 let a = object::Static {
2034 position: component::Position ([0.0, 0.0, 3.0].into()), .. a
2035 };
2036 let b = object::Static {
2037 position: component::Position ([0.0, 0.0, -2.0].into()), .. b
2038 };
2039 assert_eq!(
2040 Proximity::query (&a, &b),
2041 Proximity {
2042 distance: -3.0,
2043 half_axis: [ 1.5, 0.0, 0.0].into(),
2044 normal: math::Unit3::axis_x(),
2045 midpoint: [-0.5, 0.0, 0.0].into()
2046 }
2047 );
2048
2049 let a = object::Static {
2051 position: component::Position ([-1.0, 0.0, 1.0].into()), .. a
2052 };
2053 let b = object::Static {
2054 position: component::Position ([0.0, 0.0, -1.0].into()), .. b
2055 };
2056 assert_eq!(
2057 Proximity::query (&a, &b),
2058 Proximity {
2059 distance: -2.0,
2060 half_axis: [-1.0, 0.0, 0.0].into(),
2061 normal: math::Unit3::axis_x().invert(),
2062 midpoint: [ 0.0, 0.0, -0.5].into()
2063 }
2064 );
2065
2066 let a = object::Static {
2068 position: component::Position ([0.0, 0.0, -3.0].into()), .. a
2069 };
2070 let b = object::Static {
2071 position: component::Position ([0.0, 0.0, 3.0].into()), .. b
2072 };
2073 assert_eq!(
2074 Proximity::query (&a, &b),
2075 Proximity {
2076 distance: -2.0,
2077 half_axis: [ 0.0, 0.0, -1.0].into(),
2078 normal: math::Unit3::axis_z().invert(),
2079 midpoint: [ 0.0, 0.0, 1.0].into()
2080 }
2081 );
2082
2083 let a = object::Static {
2085 position: component::Position ([0.0, 0.0, 3.0].into()), .. a
2086 };
2087 let b = object::Static {
2088 position: component::Position ([0.0, 0.0, -3.0].into()), .. b
2089 };
2090 assert_eq!(
2091 Proximity::query (&a, &b),
2092 Proximity {
2093 distance: -2.0,
2094 half_axis: [ 0.0, 0.0, 1.0].into(),
2095 normal: math::Unit3::axis_z(),
2096 midpoint: [ 0.0, 0.0, -1.0].into()
2097 }
2098 );
2099
2100 let a = object::Static {
2102 position: component::Position ([ 1.0, 0.0, 0.0].into()), .. a
2103 };
2104 let b = object::Static {
2105 position: component::Position ([-1.0, 0.0, 0.0].into()), .. b
2106 };
2107 assert_eq!(
2108 Proximity::query (&a, &b),
2109 Proximity {
2110 distance: -1.0,
2111 half_axis: [ 0.5, 0.0, 0.0].into(),
2112 normal: math::Unit3::axis_x(),
2113 midpoint: [-0.5, 0.0, 0.0].into()
2114 }
2115 );
2116
2117 let a = object::Static {
2119 position: component::Position ([ 2.0, 0.0, 5.0].into()), .. a
2120 };
2121 let b = object::Static {
2122 position: component::Position ([-1.0, 0.0, -3.0].into()), .. b
2123 };
2124
2125 let proximity = Proximity::query (&a, &b);
2126 let distance_manual = {
2127 let distance = math::Vector3::new (3.0, 0.0, 3.0).magnitude() - 3.0;
2128 let half_axis : math::Vector3 <_> =
2129 0.5 * distance * math::Vector3::new (-1.0, 0.0, -1.0).normalized();
2130 let normal = math::Unit3::normalize ([1.0, 0.0, 1.0].into());
2131 let midpoint = math::Point3::from ([-1.0, 0.0, -1.0]) +
2132 *normal - half_axis;
2133 Proximity { distance, half_axis, midpoint, normal }
2134 };
2135 assert_eq!(proximity.distance, distance_manual.distance);
2136 assert_relative_eq!(proximity.half_axis, distance_manual.half_axis);
2137 assert_relative_eq!(*proximity.normal, *distance_manual.normal);
2138 assert_relative_eq!(proximity.midpoint, distance_manual.midpoint,
2139 epsilon = 2.0 * std::f64::EPSILON);
2140
2141 let a = object::Static {
2143 position: component::Position ([ 3.0, 0.0, 3.0].into()), .. a
2144 };
2145 let b = object::Static {
2146 position: component::Position ([-1.0, 0.0, 0.0].into()), .. b
2147 };
2148 assert_eq!(
2149 Proximity::query (&a, &b),
2150 Proximity {
2151 distance: 1.0,
2152 half_axis: [-0.5, 0.0, 0.0].into(),
2153 normal: math::Unit3::axis_x(),
2154 midpoint: [ 0.5, 0.0, 1.0].into()
2155 }
2156 );
2157
2158 let a = object::Static {
2164 position: component::Position ([-5.0, -5.0, -5.0].into()),
2165 bound: component::Bound (shape::Bounded::from (
2166 shape::Cuboid::noisy ([1.0, 2.0, 3.0])).into()),
2167 .. a
2168 };
2169 let b = object::Static {
2170 position: component::Position ([5.0, 5.0, 5.0].into()),
2171 bound: component::Bound (shape::Bounded::from (
2172 shape::Cuboid::noisy ([3.0, 1.0, 2.0])).into()),
2173 .. b
2174 };
2175 let proximity = Proximity::query (&a, &b);
2176 assert_eq!(proximity.distance, f64::sqrt (110.0));
2177 assert_eq!(proximity.half_axis, [3.0, 3.5, 2.5].into());
2178 assert_ulps_eq!(*proximity.normal,
2179 -math::Vector3::new (3.0, 3.5, 2.5).normalized());
2180 assert_eq!(proximity.midpoint, [-1.0, 0.5, 0.5].into());
2181
2182 let a = object::Static {
2184 position: component::Position ([-5.0, 0.0, -5.0].into()), .. a
2185 };
2186 let b = object::Static {
2187 position: component::Position ([5.0, 0.0, 5.0].into()), .. b
2188 };
2189 let proximity = Proximity::query (&a, &b);
2190 assert_eq!(proximity.distance, f64::sqrt (61.0));
2191 assert_eq!(proximity.half_axis, [3.0, 0.0, 2.5].into());
2192 assert_ulps_eq!(*proximity.normal,
2193 -math::Vector3::new (3.0, 0.0, 2.5).normalized());
2194 assert_eq!(proximity.midpoint, [-1.0, 0.0, 0.5].into());
2195
2196 let a = object::Static {
2202 position: component::Position ([5.0, 5.0, 3.0].into()),
2203 bound: component::Bound (shape::Bounded::from (
2204 shape::Capsule::noisy (SQRT_2, 2.0)).into()),
2205 .. a
2206 };
2207 let b = object::Static {
2208 position: component::Position ([0.0, 0.0, 0.0].into()),
2209 bound: component::Bound (shape::Bounded::from (
2210 shape::Cuboid::noisy ([1.0, 1.0, 1.0])).into()),
2211 .. b
2212 };
2213 let proximity = Proximity::query (&a, &b);
2214 assert_ulps_eq!(proximity.distance, 3.0 * SQRT_2);
2215 assert_eq!(proximity.half_axis, [-1.5, -1.5, 0.0].into());
2216 assert_ulps_eq!(*proximity.normal,
2217 math::Vector3::new (1.0, 1.0, 0.0).normalized());
2218 assert_eq!(proximity.midpoint, [ 2.5, 2.5, 1.0].into());
2219
2220 let a = object::Static {
2222 position: component::Position ([-5.0, -5.0, -3.0].into()),
2223 bound: component::Bound (shape::Bounded::from (
2224 shape::Capsule::noisy (SQRT_2, 2.0)).into()),
2225 .. a
2226 };
2227 let b = object::Static {
2228 position: component::Position ([0.0, 0.0, 0.0].into()),
2229 bound: component::Bound (shape::Bounded::from (
2230 shape::Cuboid::noisy ([1.0, 1.0, 1.0])).into()),
2231 .. b
2232 };
2233 let proximity = Proximity::query (&a, &b);
2234 assert_ulps_eq!(proximity.distance, 3.0 * SQRT_2);
2235 assert_eq!(proximity.half_axis, [ 1.5, 1.5, 0.0].into());
2236 assert_ulps_eq!(*proximity.normal,
2237 math::Vector3::new (-1.0, -1.0, 0.0).normalized());
2238 assert_eq!(proximity.midpoint, [-2.5,-2.5,-1.0].into());
2239
2240 let a = object::Static {
2242 position: component::Position ([4.0, 0.5, 4.0].into()),
2243 bound: component::Bound (shape::Bounded::from (
2244 shape::Capsule::noisy (1.0, 2.0)).into()),
2245 .. a
2246 };
2247 let b = object::Static {
2248 position: component::Position ([0.0, 0.0, 0.0].into()),
2249 bound: component::Bound (shape::Bounded::from (
2250 shape::Cuboid::noisy ([2.0, 2.0, 2.0])).into()),
2251 .. b
2252 };
2253 assert_eq!(
2254 Proximity::query (&a, &b),
2255 Proximity {
2256 distance: 1.0,
2257 half_axis: [-0.5, 0.0, 0.0].into(),
2258 normal: math::Unit3::axis_x(),
2259 midpoint: [ 2.5, 0.5, 2.0].into()
2260 }
2261 );
2262
2263 let a = object::Static {
2265 position: component::Position ([4.0, 0.5, -4.0].into()), .. a
2266 };
2267 let b = object::Static {
2268 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
2269 };
2270 assert_eq!(
2271 Proximity::query (&a, &b),
2272 Proximity {
2273 distance: 1.0,
2274 half_axis: [-0.5, 0.0, 0.0].into(),
2275 normal: math::Unit3::axis_x(),
2276 midpoint: [ 2.5, 0.5, -2.0].into()
2277 }
2278 );
2279
2280 let a = object::Static {
2282 position: component::Position ([0.5, 4.0, 4.0].into()), .. a
2283 };
2284 let b = object::Static {
2285 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
2286 };
2287 assert_eq!(
2288 Proximity::query (&a, &b),
2289 Proximity {
2290 distance: 1.0,
2291 half_axis: [ 0.0, -0.5, 0.0].into(),
2292 normal: math::Unit3::axis_y(),
2293 midpoint: [ 0.5, 2.5, 2.0].into()
2294 }
2295 );
2296
2297 let a = object::Static {
2299 position: component::Position ([0.5, 4.0, -4.0].into()), .. a
2300 };
2301 let b = object::Static {
2302 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
2303 };
2304 assert_eq!(
2305 Proximity::query (&a, &b),
2306 Proximity {
2307 distance: 1.0,
2308 half_axis: [ 0.0, -0.5, 0.0].into(),
2309 normal: math::Unit3::axis_y(),
2310 midpoint: [ 0.5, 2.5, -2.0].into()
2311 }
2312 );
2313
2314 let a = object::Static {
2316 position: component::Position ([0.5, 0.5, 6.0].into()), .. a
2317 };
2318 let b = object::Static {
2319 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
2320 };
2321 assert_eq!(
2322 Proximity::query (&a, &b),
2323 Proximity {
2324 distance: 1.0,
2325 half_axis: [ 0.0, 0.0, -0.5].into(),
2326 normal: math::Unit3::axis_z(),
2327 midpoint: [ 0.5, 0.5, 2.5].into()
2328 }
2329 );
2330
2331 let a = object::Static {
2333 position: component::Position ([0.5, 0.5, -6.0].into()), .. a
2334 };
2335 let b = object::Static {
2336 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
2337 };
2338 assert_eq!(
2339 Proximity::query (&a, &b),
2340 Proximity {
2341 distance: 1.0,
2342 half_axis: [ 0.0, 0.0, 0.5].into(),
2343 normal: math::Unit3::axis_z().invert(),
2344 midpoint: [ 0.5, 0.5, -2.5].into()
2345 }
2346 );
2347
2348 let a = object::Static {
2350 position: component::Position ([3.0, 3.0, 2.0].into()), .. a
2351 };
2352 let b = object::Static {
2353 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
2354 };
2355 let proximity = Proximity::query (&a, &b);
2356 assert_eq!(proximity.distance, SQRT_2 - 1.0);
2357 assert_eq!(proximity.half_axis, [
2358 -0.5 * f64::sqrt (0.5 * (SQRT_2 - 1.0).powf (2.0)),
2359 -0.5 * f64::sqrt (0.5 * (SQRT_2 - 1.0).powf (2.0)),
2360 0.0
2361 ].into());
2362 assert_ulps_eq!(*proximity.normal,
2363 [FRAC_1_SQRT_2, FRAC_1_SQRT_2, 0.0].into());
2364 assert_eq!(proximity.midpoint, [
2365 2.0 + 0.5 * f64::sqrt (0.5 * (SQRT_2 - 1.0).powf (2.0)),
2366 2.0 + 0.5 * f64::sqrt (0.5 * (SQRT_2 - 1.0).powf (2.0)),
2367 1.0
2368 ].into());
2369
2370 let a = object::Static {
2372 position: component::Position ([-3.0, -3.0, -2.0].into()), .. a
2373 };
2374 let b = object::Static {
2375 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
2376 };
2377 let proximity = Proximity::query (&a, &b);
2378 assert_eq!(proximity.distance, SQRT_2 - 1.0);
2379 assert_eq!(proximity.half_axis, [
2380 0.5 * f64::sqrt (0.5 * (SQRT_2 - 1.0).powf (2.0)),
2381 0.5 * f64::sqrt (0.5 * (SQRT_2 - 1.0).powf (2.0)),
2382 0.0
2383 ].into());
2384 assert_ulps_eq!(*proximity.normal,
2385 [-FRAC_1_SQRT_2, -FRAC_1_SQRT_2, 0.0].into());
2386 assert_eq!(proximity.midpoint, [
2387 -2.0 - 0.5 * f64::sqrt (0.5 * (SQRT_2 - 1.0).powf (2.0)),
2388 -2.0 - 0.5 * f64::sqrt (0.5 * (SQRT_2 - 1.0).powf (2.0)),
2389 -1.0
2390 ].into());
2391
2392 let a = object::Static {
2394 position: component::Position ([1.0, 4.0, 2.0].into()), .. a
2395 };
2396 let b = object::Static {
2397 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
2398 };
2399 assert_eq!(
2400 Proximity::query (&a, &b),
2401 Proximity {
2402 distance: 1.0,
2403 half_axis: [ 0.0, -0.5, 0.0].into(),
2404 normal: math::Unit3::axis_y(),
2405 midpoint: [ 1.0, 2.5, 1.0].into()
2406 }
2407 );
2408
2409 let a = object::Static {
2411 position: component::Position ([-1.0, -4.0, -2.0].into()), .. a
2412 };
2413 let b = object::Static {
2414 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
2415 };
2416 assert_eq!(
2417 Proximity::query (&a, &b),
2418 Proximity {
2419 distance: 1.0,
2420 half_axis: [ 0.0, 0.5, 0.0].into(),
2421 normal: math::Unit3::axis_y().invert(),
2422 midpoint: [-1.0, -2.5, -1.0].into()
2423 }
2424 );
2425
2426 let a = object::Static {
2428 position: component::Position ([4.0, 1.0, 2.0].into()), .. a
2429 };
2430 let b = object::Static {
2431 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
2432 };
2433 assert_eq!(
2434 Proximity::query (&a, &b),
2435 Proximity {
2436 distance: 1.0,
2437 half_axis: [-0.5, 0.0, 0.0].into(),
2438 normal: math::Unit3::axis_x(),
2439 midpoint: [ 2.5, 1.0, 1.0].into()
2440 }
2441 );
2442
2443 let a = object::Static {
2445 position: component::Position ([-4.0, -1.0, -2.0].into()), .. a
2446 };
2447 let b = object::Static {
2448 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
2449 };
2450 assert_eq!(
2451 Proximity::query (&a, &b),
2452 Proximity {
2453 distance: 1.0,
2454 half_axis: [ 0.5, 0.0, 0.0].into(),
2455 normal: math::Unit3::axis_x().invert(),
2456 midpoint: [-2.5, -1.0, -1.0].into()
2457 }
2458 );
2459
2460 let a = object::Static {
2462 position: component::Position ([2.0, 2.0, 4.0].into()),
2463 bound: component::Bound (shape::Bounded::from (
2464 shape::Capsule::noisy (1.0, 2.0)).into()),
2465 .. a
2466 };
2467 let b = object::Static {
2468 position: component::Position ([0.0, 0.0, 0.0].into()),
2469 bound: component::Bound (shape::Bounded::from (
2470 shape::Cuboid::noisy ([2.0, 2.0, 2.0])).into()),
2471 .. b
2472 };
2473 assert_eq!(
2474 Proximity::query (&a, &b),
2475 Proximity {
2476 distance: -1.0,
2477 half_axis: [ 0.5, 0.0, 0.0].into(),
2478 normal: math::Unit3::axis_x(),
2479 midpoint: [ 1.5, 2.0, 2.0].into()
2480 }
2481 );
2482
2483 let a = object::Static {
2485 position: component::Position ([-2.0, -2.0, -4.0].into()), .. a
2486 };
2487 let b = object::Static {
2488 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
2489 };
2490 assert_eq!(
2491 Proximity::query (&a, &b),
2492 Proximity {
2493 distance: -1.0,
2494 half_axis: [-0.5, 0.0, 0.0].into(),
2495 normal: math::Unit3::axis_x().invert(),
2496 midpoint: [-1.5, -2.0,-2.0].into()
2497 }
2498 );
2499
2500 let a = object::Static {
2502 position: component::Position ([2.0, 1.0, 4.0].into()), .. a
2503 };
2504 let b = object::Static {
2505 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
2506 };
2507 assert_eq!(
2508 Proximity::query (&a, &b),
2509 Proximity {
2510 distance: -1.0,
2511 half_axis: [ 0.5, 0.0, 0.0].into(),
2512 normal: math::Unit3::axis_x(),
2513 midpoint: [ 1.5, 1.0, 2.0].into()
2514 }
2515 );
2516
2517 let a = object::Static {
2519 position: component::Position ([-2.0, 1.0, -4.0].into()), .. a
2520 };
2521 let b = object::Static {
2522 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
2523 };
2524 assert_eq!(
2525 Proximity::query (&a, &b),
2526 Proximity {
2527 distance: -1.0,
2528 half_axis: [-0.5, 0.0, 0.0].into(),
2529 normal: math::Unit3::axis_x().invert(),
2530 midpoint: [-1.5, 1.0, -2.0].into()
2531 }
2532 );
2533
2534 let a = object::Static {
2536 position: component::Position ([1.0, 2.0, 4.0].into()), .. a
2537 };
2538 let b = object::Static {
2539 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
2540 };
2541 assert_eq!(
2542 Proximity::query (&a, &b),
2543 Proximity {
2544 distance: -1.0,
2545 half_axis: [ 0.0, 0.5, 0.0].into(),
2546 normal: math::Unit3::axis_y(),
2547 midpoint: [ 1.0, 1.5, 2.0].into()
2548 }
2549 );
2550
2551 let a = object::Static {
2553 position: component::Position ([ 1.0, -2.0, -4.0].into()), .. a
2554 };
2555 let b = object::Static {
2556 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
2557 };
2558 assert_eq!(
2559 Proximity::query (&a, &b),
2560 Proximity {
2561 distance: -1.0,
2562 half_axis: [0.0, -0.5, 0.0].into(),
2563 normal: math::Unit3::axis_y().invert(),
2564 midpoint: [1.0, -1.5, -2.0].into()
2565 }
2566 );
2567
2568 let a = object::Static {
2570 position: component::Position ([1.0, 1.0, 4.0].into()), .. a
2571 };
2572 let b = object::Static {
2573 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
2574 };
2575 assert_eq!(
2576 Proximity::query (&a, &b),
2577 Proximity {
2578 distance: -1.0,
2579 half_axis: [ 0.0, 0.0, 0.5].into(),
2580 normal: math::Unit3::axis_z(),
2581 midpoint: [ 1.0, 1.0, 1.5].into()
2582 }
2583 );
2584
2585 let a = object::Static {
2587 position: component::Position ([-1.0, -1.0, -4.0].into()), .. a
2588 };
2589 let b = object::Static {
2590 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
2591 };
2592 assert_eq!(
2593 Proximity::query (&a, &b),
2594 Proximity {
2595 distance: -1.0,
2596 half_axis: [ 0.0, 0.0, -0.5].into(),
2597 normal: math::Unit3::axis_z().invert(),
2598 midpoint: [-1.0, -1.0, -1.5].into()
2599 }
2600 );
2601
2602 let a = object::Static {
2604 position: component::Position ([0.0, 0.0, 0.0].into()), .. a
2605 };
2606 let b = object::Static {
2607 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
2608 };
2609 assert_eq!(
2610 Proximity::query (&a, &b),
2611 Proximity {
2612 distance: -3.0,
2613 half_axis: [ 1.5, 0.0, 0.0].into(),
2614 normal: math::Unit3::axis_x(),
2615 midpoint: [ 0.5, 0.0, 0.0].into()
2616 }
2617 );
2618
2619 let a = object::Static {
2621 position: component::Position ([1.0, 0.0, 0.0].into()), .. a
2622 };
2623 let b = object::Static {
2624 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
2625 };
2626 assert_eq!(
2627 Proximity::query (&a, &b),
2628 Proximity {
2629 distance: -2.0,
2630 half_axis: [ 1.0, 0.0, 0.0].into(),
2631 normal: math::Unit3::axis_x(),
2632 midpoint: [ 1.0, 0.0, 0.0].into()
2633 }
2634 );
2635
2636 let a = object::Static {
2638 position: component::Position ([-1.0, 0.0, 0.0].into()), .. a
2639 };
2640 let b = object::Static {
2641 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
2642 };
2643 assert_eq!(
2644 Proximity::query (&a, &b),
2645 Proximity {
2646 distance: -2.0,
2647 half_axis: [-1.0, 0.0, 0.0].into(),
2648 normal: math::Unit3::axis_x().invert(),
2649 midpoint: [-1.0, 0.0, 0.0].into()
2650 }
2651 );
2652
2653 let a = object::Static {
2655 position: component::Position ([0.0, 1.0, 0.0].into()), .. a
2656 };
2657 let b = object::Static {
2658 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
2659 };
2660 assert_eq!(
2661 Proximity::query (&a, &b),
2662 Proximity {
2663 distance: -2.0,
2664 half_axis: [0.0, 1.0, 0.0].into(),
2665 normal: math::Unit3::axis_y(),
2666 midpoint: [0.0, 1.0, 0.0].into()
2667 }
2668 );
2669
2670 let a = object::Static {
2672 position: component::Position ([0.0, -1.0, 0.0].into()), .. a
2673 };
2674 let b = object::Static {
2675 position: component::Position ([0.0, 0.0, 0.0].into()), .. b
2676 };
2677 assert_eq!(
2678 Proximity::query (&a, &b),
2679 Proximity {
2680 distance: -2.0,
2681 half_axis: [0.0, -1.0, 0.0].into(),
2682 normal: math::Unit3::axis_y().invert(),
2683 midpoint: [0.0, -1.0, 0.0].into()
2684 }
2685 );
2686
2687 let a = object::Static {
2689 position: component::Position ([0.0, 0.0, 3.0].into()),
2690 bound: component::Bound (shape::Bounded::from (
2691 shape::Capsule::noisy (1.0, 2.0)).into()),
2692 .. a
2693 };
2694 let b = object::Static {
2695 position: component::Position ([0.0, 0.0, 0.0].into()),
2696 bound: component::Bound (shape::Bounded::from (
2697 shape::Cuboid::noisy ([4.0, 4.0, 2.0])).into()),
2698 .. b
2699 };
2700 assert_eq!(
2701 Proximity::query (&a, &b),
2702 Proximity {
2703 distance: -2.0,
2704 half_axis: [0.0, 0.0, 1.0].into(),
2705 normal: math::Unit3::axis_z(),
2706 midpoint: [0.0, 0.0, 1.0].into()
2707 }
2708 );
2709
2710 let a = object::Static {
2712 position: component::Position ([0.0, 0.0, 1.0].into()),
2713 bound: component::Bound (shape::Bounded::from (
2714 shape::Capsule::noisy (1.0, 2.0)).into()),
2715 .. a
2716 };
2717 let b = object::Static {
2718 position: component::Position ([0.0, 0.0, 0.0].into()),
2719 bound: component::Bound (shape::Bounded::from (
2720 shape::Cuboid::noisy ([4.0, 4.0, 2.0])).into()),
2721 .. b
2722 };
2723 assert_eq!(
2724 Proximity::query (&a, &b),
2725 Proximity {
2726 distance: -4.0,
2727 half_axis: [0.0, 0.0, 2.0].into(),
2728 normal: math::Unit3::axis_z(),
2729 midpoint: [0.0, 0.0, 0.0].into()
2730 }
2731 );
2732
2733 let a = object::Static {
2735 position: component::Position ([0.0, 0.0, -3.0].into()),
2736 bound: component::Bound (shape::Bounded::from (
2737 shape::Capsule::noisy (1.0, 2.0)).into()),
2738 .. a
2739 };
2740 let b = object::Static {
2741 position: component::Position ([0.0, 0.0, 0.0].into()),
2742 bound: component::Bound (shape::Bounded::from (
2743 shape::Cuboid::noisy ([4.0, 4.0, 2.0])).into()),
2744 .. b
2745 };
2746 assert_eq!(
2747 Proximity::query (&a, &b),
2748 Proximity {
2749 distance: -2.0,
2750 half_axis: [0.0, 0.0, -1.0].into(),
2751 normal: math::Unit3::axis_z().invert(),
2752 midpoint: [0.0, 0.0, -1.0].into()
2753 }
2754 );
2755
2756 let a = object::Static {
2758 position: component::Position ([0.0, 0.0, -1.0].into()),
2759 bound: component::Bound (shape::Bounded::from (
2760 shape::Capsule::noisy (1.0, 2.0)).into()),
2761 .. a
2762 };
2763 let b = object::Static {
2764 position: component::Position ([0.0, 0.0, 0.0].into()),
2765 bound: component::Bound (shape::Bounded::from (
2766 shape::Cuboid::noisy ([4.0, 4.0, 2.0])).into()),
2767 .. b
2768 };
2769 assert_eq!(
2770 Proximity::query (&a, &b),
2771 Proximity {
2772 distance: -4.0,
2773 half_axis: [0.0, 0.0, -2.0].into(),
2774 normal: math::Unit3::axis_z().invert(),
2775 midpoint: [0.0, 0.0, 0.0].into()
2776 }
2777 );
2778
2779 let mut rng = XorShiftRng::seed_from_u64 (0);
2781 let a = object::Static {
2782 position: component::Position ([0.0, 0.0, 0.0].into()),
2783 bound: component::Bound (shape::Bounded::from (
2784 shape::Capsule::noisy (1.5, 1.5)).into()),
2785 .. a
2786 };
2787 for _ in 0..100 {
2788 let position = component::Position ([
2789 rng.random_range (-40.0..40.0),
2790 rng.random_range (-40.0..40.0),
2791 rng.random_range (-40.0..40.0)
2792 ].into());
2793 let bound = component::Bound (shape::Bounded::from (
2794 shape::Cuboid::noisy ([
2795 rng.random_range (0.5..5.0),
2796 rng.random_range (0.5..5.0),
2797 rng.random_range (0.5..5.0)
2798 ])
2799 ).into());
2800 let b = object::Static {
2801 position, bound, material: component::MATERIAL_STONE, collidable: true
2802 };
2803 let _ = Proximity::query (&a, &b);
2804 }
2805
2806 use math::SignedAxis3;
2810
2811 let a = object::Static {
2813 position: component::Position ([0.0, 0.0, 4.0].into()),
2814 bound: component::Bound (shape::Bounded::from (
2815 shape::Capsule::noisy (1.0, 2.0)).into()),
2816 .. a
2817 };
2818 let b = object::Static {
2819 position: component::Position ([0.0, 0.0, 0.0].into()),
2820 bound: component::Bound (shape::Unbounded::from (
2821 shape::Orthant { normal_axis: SignedAxis3::PosZ }).into()),
2822 .. b
2823 };
2824 assert_eq!(
2825 Proximity::query (&a, &b),
2826 Proximity {
2827 distance: 1.0,
2828 half_axis: [0.0, 0.0, -0.5].into(),
2829 normal: math::Unit3::axis_z(),
2830 midpoint: [0.0, 0.0, 0.5].into()
2831 }
2832 );
2833
2834 let a = object::Static {
2836 position: component::Position ([0.0, 0.0, -4.0].into()),
2837 bound: component::Bound (shape::Bounded::from (
2838 shape::Capsule::noisy (1.0, 2.0)).into()),
2839 .. a
2840 };
2841 let b = object::Static {
2842 position: component::Position ([0.0, 0.0, 0.0].into()),
2843 bound: component::Bound (shape::Unbounded::from (
2844 shape::Orthant { normal_axis: SignedAxis3::NegZ }).into()),
2845 .. b
2846 };
2847 assert_eq!(
2848 Proximity::query (&a, &b),
2849 Proximity {
2850 distance: 1.0,
2851 half_axis: [0.0, 0.0, 0.5].into(),
2852 normal: math::Unit3::axis_z().invert(),
2853 midpoint: [0.0, 0.0, -0.5].into()
2854 }
2855 );
2856
2857 let a = object::Static {
2859 position: component::Position ([0.0, 2.0, 0.0].into()),
2860 bound: component::Bound (shape::Bounded::from (
2861 shape::Capsule::noisy (1.0, 2.0)).into()),
2862 .. a
2863 };
2864 let b = object::Static {
2865 position: component::Position ([0.0, 0.0, 0.0].into()),
2866 bound: component::Bound (shape::Unbounded::from (
2867 shape::Orthant { normal_axis: SignedAxis3::PosY }).into()),
2868 .. b
2869 };
2870 assert_eq!(
2871 Proximity::query (&a, &b),
2872 Proximity {
2873 distance: 1.0,
2874 half_axis: [0.0, -0.5, 0.0].into(),
2875 normal: math::Unit3::axis_y(),
2876 midpoint: [0.0, 0.5, 0.0].into()
2877 }
2878 );
2879
2880 let a = object::Static {
2882 position: component::Position ([0.0, -2.0, 0.0].into()),
2883 bound: component::Bound (shape::Bounded::from (
2884 shape::Capsule::noisy (1.0, 2.0)).into()),
2885 .. a
2886 };
2887 let b = object::Static {
2888 position: component::Position ([0.0, 0.0, 0.0].into()),
2889 bound: component::Bound (shape::Unbounded::from (
2890 shape::Orthant { normal_axis: SignedAxis3::NegY }).into()),
2891 .. b
2892 };
2893 assert_eq!(
2894 Proximity::query (&a, &b),
2895 Proximity {
2896 distance: 1.0,
2897 half_axis: [0.0, 0.5, 0.0].into(),
2898 normal: math::Unit3::axis_y().invert(),
2899 midpoint: [0.0, -0.5, 0.0].into()
2900 }
2901 );
2902
2903 let a = object::Static {
2905 position: component::Position ([2.0, 0.0, 0.0].into()),
2906 bound: component::Bound (shape::Bounded::from (
2907 shape::Capsule::noisy (1.0, 2.0)).into()),
2908 .. a
2909 };
2910 let b = object::Static {
2911 position: component::Position ([0.0, 0.0, 0.0].into()),
2912 bound: component::Bound (shape::Unbounded::from (
2913 shape::Orthant { normal_axis: SignedAxis3::PosX }).into()),
2914 .. b
2915 };
2916 assert_eq!(
2917 Proximity::query (&a, &b),
2918 Proximity {
2919 distance: 1.0,
2920 half_axis: [-0.5, 0.0, 0.0].into(),
2921 normal: math::Unit3::axis_x(),
2922 midpoint: [ 0.5, 0.0, 0.0].into()
2923 }
2924 );
2925
2926 let a = object::Static {
2928 position: component::Position ([-2.0, 0.0, 0.0].into()),
2929 bound: component::Bound (shape::Bounded::from (
2930 shape::Capsule::noisy (1.0, 2.0)).into()),
2931 .. a
2932 };
2933 let b = object::Static {
2934 position: component::Position ([0.0, 0.0, 0.0].into()),
2935 bound: component::Bound (shape::Unbounded::from (
2936 shape::Orthant { normal_axis: SignedAxis3::NegX }).into()),
2937 .. b
2938 };
2939 assert_eq!(
2940 Proximity::query (&a, &b),
2941 Proximity {
2942 distance: 1.0,
2943 half_axis: [ 0.5, 0.0, 0.0].into(),
2944 normal: math::Unit3::axis_x().invert(),
2945 midpoint: [-0.5, 0.0, 0.0].into()
2946 }
2947 );
2948
2949 let a = object::Static {
2951 position: component::Position ([0.0, 0.0, 0.0].into()),
2952 bound: component::Bound (shape::Bounded::from (
2953 shape::Capsule::noisy (1.0, 2.0)).into()),
2954 .. a
2955 };
2956 let b = object::Static {
2957 position: component::Position ([0.0, 0.0, 0.0].into()),
2958 bound: component::Bound (shape::Unbounded::from (
2959 shape::Orthant { normal_axis: SignedAxis3::PosZ }).into()),
2960 .. b
2961 };
2962 assert_eq!(
2963 Proximity::query (&a, &b),
2964 Proximity {
2965 distance: -3.0,
2966 half_axis: [0.0, 0.0, 1.5].into(),
2967 normal: math::Unit3::axis_z(),
2968 midpoint: [0.0, 0.0, -1.5].into()
2969 }
2970 );
2971
2972 let a = object::Static {
2974 position: component::Position ([0.0, 0.0, 0.0].into()),
2975 bound: component::Bound (shape::Bounded::from (
2976 shape::Capsule::noisy (1.0, 2.0)).into()),
2977 .. a
2978 };
2979 let b = object::Static {
2980 position: component::Position ([0.0, 0.0, 0.0].into()),
2981 bound: component::Bound (shape::Unbounded::from (
2982 shape::Orthant { normal_axis: SignedAxis3::NegZ }).into()),
2983 .. b
2984 };
2985 assert_eq!(
2986 Proximity::query (&a, &b),
2987 Proximity {
2988 distance: -3.0,
2989 half_axis: [0.0, 0.0, -1.5].into(),
2990 normal: math::Unit3::axis_z().invert(),
2991 midpoint: [0.0, 0.0, 1.5].into()
2992 }
2993 );
2994
2995 let a = object::Static {
2997 position: component::Position ([0.0, 0.0, 0.0].into()),
2998 bound: component::Bound (shape::Bounded::from (
2999 shape::Capsule::noisy (1.0, 2.0)).into()),
3000 .. a
3001 };
3002 let b = object::Static {
3003 position: component::Position ([0.0, 0.0, 0.0].into()),
3004 bound: component::Bound (shape::Unbounded::from (
3005 shape::Orthant { normal_axis: SignedAxis3::PosY }).into()),
3006 .. b
3007 };
3008 assert_eq!(
3009 Proximity::query (&a, &b),
3010 Proximity {
3011 distance: -1.0,
3012 half_axis: [0.0, 0.5, 0.0].into(),
3013 normal: math::Unit3::axis_y(),
3014 midpoint: [0.0, -0.5, 0.0].into()
3015 }
3016 );
3017
3018 let a = object::Static {
3020 position: component::Position ([0.0, 0.0, 0.0].into()),
3021 bound: component::Bound (shape::Bounded::from (
3022 shape::Capsule::noisy (1.0, 2.0)).into()),
3023 .. a
3024 };
3025 let b = object::Static {
3026 position: component::Position ([0.0, 0.0, 0.0].into()),
3027 bound: component::Bound (shape::Unbounded::from (
3028 shape::Orthant { normal_axis: SignedAxis3::NegY }).into()),
3029 .. b
3030 };
3031 assert_eq!(
3032 Proximity::query (&a, &b),
3033 Proximity {
3034 distance: -1.0,
3035 half_axis: [0.0, -0.5, 0.0].into(),
3036 normal: math::Unit3::axis_y().invert(),
3037 midpoint: [0.0, 0.5, 0.0].into()
3038 }
3039 );
3040
3041 let a = object::Static {
3043 position: component::Position ([0.0, 0.0, 0.0].into()),
3044 bound: component::Bound (shape::Bounded::from (
3045 shape::Capsule::noisy (1.0, 2.0)).into()),
3046 .. a
3047 };
3048 let b = object::Static {
3049 position: component::Position ([0.0, 0.0, 0.0].into()),
3050 bound: component::Bound (shape::Unbounded::from (
3051 shape::Orthant { normal_axis: SignedAxis3::PosX }).into()),
3052 .. b
3053 };
3054 assert_eq!(
3055 Proximity::query (&a, &b),
3056 Proximity {
3057 distance: -1.0,
3058 half_axis: [ 0.5, 0.0, 0.0].into(),
3059 normal: math::Unit3::axis_x(),
3060 midpoint: [-0.5, 0.0, 0.0].into()
3061 }
3062 );
3063
3064 let a = object::Static {
3066 position: component::Position ([0.0, 0.0, 0.0].into()),
3067 bound: component::Bound (shape::Bounded::from (
3068 shape::Capsule::noisy (1.0, 2.0)).into()),
3069 .. a
3070 };
3071 let b = object::Static {
3072 position: component::Position ([0.0, 0.0, 0.0].into()),
3073 bound: component::Bound (shape::Unbounded::from (
3074 shape::Orthant { normal_axis: SignedAxis3::NegX }).into()),
3075 .. b
3076 };
3077 assert_eq!(
3078 Proximity::query (&a, &b),
3079 Proximity {
3080 distance: -1.0,
3081 half_axis: [-0.5, 0.0, 0.0].into(),
3082 normal: math::Unit3::axis_x().invert(),
3083 midpoint: [ 0.5, 0.0, 0.0].into()
3084 }
3085 );
3086
3087 let a = object::Static {
3093 position: component::Position ([0.0, 0.0, 4.0].into()),
3094 bound: component::Bound (shape::Bounded::from (
3095 shape::Sphere::noisy (1.0)).into()),
3096 .. a
3097 };
3098 let b = object::Static {
3099 position: component::Position ([0.0, 0.0, 0.0].into()),
3100 bound: component::Bound (shape::Unbounded::from (
3101 shape::Orthant { normal_axis: SignedAxis3::PosZ }).into()),
3102 .. b
3103 };
3104 assert_eq!(
3105 Proximity::query (&a, &b),
3106 Proximity {
3107 distance: 3.0,
3108 half_axis: [0.0, 0.0, -1.5].into(),
3109 normal: math::Unit3::axis_z(),
3110 midpoint: [0.0, 0.0, 1.5].into()
3111 }
3112 );
3113
3114 let a = object::Static {
3116 position: component::Position ([0.0, 0.0, -4.0].into()),
3117 bound: component::Bound (shape::Bounded::from (
3118 shape::Sphere::noisy (1.0)).into()),
3119 .. a
3120 };
3121 let b = object::Static {
3122 position: component::Position ([0.0, 0.0, 0.0].into()),
3123 bound: component::Bound (shape::Unbounded::from (
3124 shape::Orthant { normal_axis: SignedAxis3::NegZ }).into()),
3125 .. b
3126 };
3127 assert_eq!(
3128 Proximity::query (&a, &b),
3129 Proximity {
3130 distance: 3.0,
3131 half_axis: [0.0, 0.0, 1.5].into(),
3132 normal: math::Unit3::axis_z().invert(),
3133 midpoint: [0.0, 0.0, -1.5].into()
3134 }
3135 );
3136
3137 let a = object::Static {
3139 position: component::Position ([0.0, 2.0, 0.0].into()),
3140 bound: component::Bound (shape::Bounded::from (
3141 shape::Sphere::noisy (1.0)).into()),
3142 .. a
3143 };
3144 let b = object::Static {
3145 position: component::Position ([0.0, 0.0, 0.0].into()),
3146 bound: component::Bound (shape::Unbounded::from (
3147 shape::Orthant { normal_axis: SignedAxis3::PosY }).into()),
3148 .. b
3149 };
3150 assert_eq!(
3151 Proximity::query (&a, &b),
3152 Proximity {
3153 distance: 1.0,
3154 half_axis: [0.0, -0.5, 0.0].into(),
3155 normal: math::Unit3::axis_y(),
3156 midpoint: [0.0, 0.5, 0.0].into()
3157 }
3158 );
3159
3160 let a = object::Static {
3162 position: component::Position ([0.0, -2.0, 0.0].into()),
3163 bound: component::Bound (shape::Bounded::from (
3164 shape::Sphere::noisy (1.0)).into()),
3165 .. a
3166 };
3167 let b = object::Static {
3168 position: component::Position ([0.0, 0.0, 0.0].into()),
3169 bound: component::Bound (shape::Unbounded::from (
3170 shape::Orthant { normal_axis: SignedAxis3::NegY }).into()),
3171 .. b
3172 };
3173 assert_eq!(
3174 Proximity::query (&a, &b),
3175 Proximity {
3176 distance: 1.0,
3177 half_axis: [0.0, 0.5, 0.0].into(),
3178 normal: math::Unit3::axis_y().invert(),
3179 midpoint: [0.0, -0.5, 0.0].into()
3180 }
3181 );
3182
3183 let a = object::Static {
3185 position: component::Position ([2.0, 0.0, 0.0].into()),
3186 bound: component::Bound (shape::Bounded::from (
3187 shape::Sphere::noisy (1.0)).into()),
3188 .. a
3189 };
3190 let b = object::Static {
3191 position: component::Position ([0.0, 0.0, 0.0].into()),
3192 bound: component::Bound (shape::Unbounded::from (
3193 shape::Orthant { normal_axis: SignedAxis3::PosX }).into()),
3194 .. b
3195 };
3196 assert_eq!(
3197 Proximity::query (&a, &b),
3198 Proximity {
3199 distance: 1.0,
3200 half_axis: [-0.5, 0.0, 0.0].into(),
3201 normal: math::Unit3::axis_x(),
3202 midpoint: [ 0.5, 0.0, 0.0].into()
3203 }
3204 );
3205
3206 let a = object::Static {
3208 position: component::Position ([-2.0, 0.0, 0.0].into()),
3209 bound: component::Bound (shape::Bounded::from (
3210 shape::Sphere::noisy (1.0)).into()),
3211 .. a
3212 };
3213 let b = object::Static {
3214 position: component::Position ([0.0, 0.0, 0.0].into()),
3215 bound: component::Bound (shape::Unbounded::from (
3216 shape::Orthant { normal_axis: SignedAxis3::NegX }).into()),
3217 .. b
3218 };
3219 assert_eq!(
3220 Proximity::query (&a, &b),
3221 Proximity {
3222 distance: 1.0,
3223 half_axis: [ 0.5, 0.0, 0.0].into(),
3224 normal: math::Unit3::axis_x().invert(),
3225 midpoint: [-0.5, 0.0, 0.0].into()
3226 }
3227 );
3228
3229 let a = object::Static {
3231 position: component::Position ([0.0, 0.0, 0.0].into()),
3232 bound: component::Bound (shape::Bounded::from (
3233 shape::Sphere::noisy (1.0)).into()),
3234 .. a
3235 };
3236 let b = object::Static {
3237 position: component::Position ([0.0, 0.0, 0.0].into()),
3238 bound: component::Bound (shape::Unbounded::from (
3239 shape::Orthant { normal_axis: SignedAxis3::PosZ }).into()),
3240 .. b
3241 };
3242 assert_eq!(
3243 Proximity::query (&a, &b),
3244 Proximity {
3245 distance: -1.0,
3246 half_axis: [0.0, 0.0, 0.5].into(),
3247 normal: math::Unit3::axis_z(),
3248 midpoint: [0.0, 0.0, -0.5].into()
3249 }
3250 );
3251
3252 let a = object::Static {
3254 position: component::Position ([0.0, 0.0, 0.0].into()),
3255 bound: component::Bound (shape::Bounded::from (
3256 shape::Sphere::noisy (1.0)).into()),
3257 .. a
3258 };
3259 let b = object::Static {
3260 position: component::Position ([0.0, 0.0, 0.0].into()),
3261 bound: component::Bound (shape::Unbounded::from (
3262 shape::Orthant { normal_axis: SignedAxis3::NegZ }).into()),
3263 .. b
3264 };
3265 assert_eq!(
3266 Proximity::query (&a, &b),
3267 Proximity {
3268 distance: -1.0,
3269 half_axis: [0.0, 0.0, -0.5].into(),
3270 normal: math::Unit3::axis_z().invert(),
3271 midpoint: [0.0, 0.0, 0.5].into()
3272 }
3273 );
3274
3275 let a = object::Static {
3277 position: component::Position ([0.0, 0.0, 0.0].into()),
3278 bound: component::Bound (shape::Bounded::from (
3279 shape::Sphere::noisy (1.0)).into()),
3280 .. a
3281 };
3282 let b = object::Static {
3283 position: component::Position ([0.0, 0.0, 0.0].into()),
3284 bound: component::Bound (shape::Unbounded::from (
3285 shape::Orthant { normal_axis: SignedAxis3::PosY }).into()),
3286 .. b
3287 };
3288 assert_eq!(
3289 Proximity::query (&a, &b),
3290 Proximity {
3291 distance: -1.0,
3292 half_axis: [0.0, 0.5, 0.0].into(),
3293 normal: math::Unit3::axis_y(),
3294 midpoint: [0.0, -0.5, 0.0].into()
3295 }
3296 );
3297
3298 let a = object::Static {
3300 position: component::Position ([0.0, 0.0, 0.0].into()),
3301 bound: component::Bound (shape::Bounded::from (
3302 shape::Sphere::noisy (1.0)).into()),
3303 .. a
3304 };
3305 let b = object::Static {
3306 position: component::Position ([0.0, 0.0, 0.0].into()),
3307 bound: component::Bound (shape::Unbounded::from (
3308 shape::Orthant { normal_axis: SignedAxis3::NegY }).into()),
3309 .. b
3310 };
3311 assert_eq!(
3312 Proximity::query (&a, &b),
3313 Proximity {
3314 distance: -1.0,
3315 half_axis: [0.0, -0.5, 0.0].into(),
3316 normal: math::Unit3::axis_y().invert(),
3317 midpoint: [0.0, 0.5, 0.0].into()
3318 }
3319 );
3320
3321 let a = object::Static {
3323 position: component::Position ([0.0, 0.0, 0.0].into()),
3324 bound: component::Bound (shape::Bounded::from (
3325 shape::Sphere::noisy (1.0)).into()),
3326 .. a
3327 };
3328 let b = object::Static {
3329 position: component::Position ([0.0, 0.0, 0.0].into()),
3330 bound: component::Bound (shape::Unbounded::from (
3331 shape::Orthant { normal_axis: SignedAxis3::PosX }).into()),
3332 .. b
3333 };
3334 assert_eq!(
3335 Proximity::query (&a, &b),
3336 Proximity {
3337 distance: -1.0,
3338 half_axis: [ 0.5, 0.0, 0.0].into(),
3339 normal: math::Unit3::axis_x(),
3340 midpoint: [-0.5, 0.0, 0.0].into()
3341 }
3342 );
3343
3344 let a = object::Static {
3346 position: component::Position ([0.0, 0.0, 0.0].into()),
3347 bound: component::Bound (shape::Bounded::from (
3348 shape::Sphere::noisy (1.0)).into()),
3349 .. a
3350 };
3351 let b = object::Static {
3352 position: component::Position ([0.0, 0.0, 0.0].into()),
3353 bound: component::Bound (shape::Unbounded::from (
3354 shape::Orthant { normal_axis: SignedAxis3::NegX }).into()),
3355 .. b
3356 };
3357 assert_eq!(
3358 Proximity::query (&a, &b),
3359 Proximity {
3360 distance: -1.0,
3361 half_axis: [-0.5, 0.0, 0.0].into(),
3362 normal: math::Unit3::axis_x().invert(),
3363 midpoint: [ 0.5, 0.0, 0.0].into()
3364 }
3365 );
3366
3367 let a = object::Static {
3373 position: component::Position ([0.0, 0.0, 4.0].into()),
3374 bound: component::Bound (shape::Bounded::from (
3375 shape::Cuboid::noisy ([1.0, 1.0, 1.0])).into()),
3376 .. a
3377 };
3378 let b = object::Static {
3379 position: component::Position ([0.0, 0.0, 0.0].into()),
3380 bound: component::Bound (shape::Unbounded::from (
3381 shape::Orthant { normal_axis: SignedAxis3::PosZ }).into()),
3382 .. b
3383 };
3384 assert_eq!(
3385 Proximity::query (&a, &b),
3386 Proximity {
3387 distance: 3.0,
3388 half_axis: [0.0, 0.0, -1.5].into(),
3389 normal: math::Unit3::axis_z(),
3390 midpoint: [0.0, 0.0, 1.5].into()
3391 }
3392 );
3393
3394 let a = object::Static {
3396 position: component::Position ([0.0, 0.0, -4.0].into()),
3397 bound: component::Bound (shape::Bounded::from (
3398 shape::Cuboid::noisy ([1.0, 1.0, 1.0])).into()),
3399 .. a
3400 };
3401 let b = object::Static {
3402 position: component::Position ([0.0, 0.0, 0.0].into()),
3403 bound: component::Bound (shape::Unbounded::from (
3404 shape::Orthant { normal_axis: SignedAxis3::NegZ }).into()),
3405 .. b
3406 };
3407 assert_eq!(
3408 Proximity::query (&a, &b),
3409 Proximity {
3410 distance: 3.0,
3411 half_axis: [0.0, 0.0, 1.5].into(),
3412 normal: math::Unit3::axis_z().invert(),
3413 midpoint: [0.0, 0.0, -1.5].into()
3414 }
3415 );
3416
3417 let a = object::Static {
3419 position: component::Position ([0.0, 2.0, 0.0].into()),
3420 bound: component::Bound (shape::Bounded::from (
3421 shape::Cuboid::noisy ([1.0, 1.0, 1.0])).into()),
3422 .. a
3423 };
3424 let b = object::Static {
3425 position: component::Position ([0.0, 0.0, 0.0].into()),
3426 bound: component::Bound (shape::Unbounded::from (
3427 shape::Orthant { normal_axis: SignedAxis3::PosY }).into()),
3428 .. b
3429 };
3430 assert_eq!(
3431 Proximity::query (&a, &b),
3432 Proximity {
3433 distance: 1.0,
3434 half_axis: [0.0, -0.5, 0.0].into(),
3435 normal: math::Unit3::axis_y(),
3436 midpoint: [0.0, 0.5, 0.0].into()
3437 }
3438 );
3439
3440 let a = object::Static {
3442 position: component::Position ([0.0, -2.0, 0.0].into()),
3443 bound: component::Bound (shape::Bounded::from (
3444 shape::Cuboid::noisy ([1.0, 1.0, 1.0])).into()),
3445 .. a
3446 };
3447 let b = object::Static {
3448 position: component::Position ([0.0, 0.0, 0.0].into()),
3449 bound: component::Bound (shape::Unbounded::from (
3450 shape::Orthant { normal_axis: SignedAxis3::NegY }).into()),
3451 .. b
3452 };
3453 assert_eq!(
3454 Proximity::query (&a, &b),
3455 Proximity {
3456 distance: 1.0,
3457 half_axis: [0.0, 0.5, 0.0].into(),
3458 normal: math::Unit3::axis_y().invert(),
3459 midpoint: [0.0, -0.5, 0.0].into()
3460 }
3461 );
3462
3463 let a = object::Static {
3465 position: component::Position ([2.0, 0.0, 0.0].into()),
3466 bound: component::Bound (shape::Bounded::from (
3467 shape::Cuboid::noisy ([1.0, 1.0, 1.0])).into()),
3468 .. a
3469 };
3470 let b = object::Static {
3471 position: component::Position ([0.0, 0.0, 0.0].into()),
3472 bound: component::Bound (shape::Unbounded::from (
3473 shape::Orthant { normal_axis: SignedAxis3::PosX }).into()),
3474 .. b
3475 };
3476 assert_eq!(
3477 Proximity::query (&a, &b),
3478 Proximity {
3479 distance: 1.0,
3480 half_axis: [-0.5, 0.0, 0.0].into(),
3481 normal: math::Unit3::axis_x(),
3482 midpoint: [ 0.5, 0.0, 0.0].into()
3483 }
3484 );
3485
3486 let a = object::Static {
3488 position: component::Position ([-2.0, 0.0, 0.0].into()),
3489 bound: component::Bound (shape::Bounded::from (
3490 shape::Cuboid::noisy ([1.0, 1.0, 1.0])).into()),
3491 .. a
3492 };
3493 let b = object::Static {
3494 position: component::Position ([0.0, 0.0, 0.0].into()),
3495 bound: component::Bound (shape::Unbounded::from (
3496 shape::Orthant { normal_axis: SignedAxis3::NegX }).into()),
3497 .. b
3498 };
3499 assert_eq!(
3500 Proximity::query (&a, &b),
3501 Proximity {
3502 distance: 1.0,
3503 half_axis: [ 0.5, 0.0, 0.0].into(),
3504 normal: math::Unit3::axis_x().invert(),
3505 midpoint: [-0.5, 0.0, 0.0].into()
3506 }
3507 );
3508
3509 let a = object::Static {
3511 position: component::Position ([0.0, 0.0, 0.0].into()),
3512 bound: component::Bound (shape::Bounded::from (
3513 shape::Cuboid::noisy ([1.0, 1.0, 1.0])).into()),
3514 .. a
3515 };
3516 let b = object::Static {
3517 position: component::Position ([0.0, 0.0, 0.0].into()),
3518 bound: component::Bound (shape::Unbounded::from (
3519 shape::Orthant { normal_axis: SignedAxis3::PosZ }).into()),
3520 .. b
3521 };
3522 assert_eq!(
3523 Proximity::query (&a, &b),
3524 Proximity {
3525 distance: -1.0,
3526 half_axis: [0.0, 0.0, 0.5].into(),
3527 normal: math::Unit3::axis_z(),
3528 midpoint: [0.0, 0.0, -0.5].into()
3529 }
3530 );
3531
3532 let a = object::Static {
3534 position: component::Position ([0.0, 0.0, 0.0].into()),
3535 bound: component::Bound (shape::Bounded::from (
3536 shape::Cuboid::noisy ([1.0, 1.0, 1.0])).into()),
3537 .. a
3538 };
3539 let b = object::Static {
3540 position: component::Position ([0.0, 0.0, 0.0].into()),
3541 bound: component::Bound (shape::Unbounded::from (
3542 shape::Orthant { normal_axis: SignedAxis3::NegZ }).into()),
3543 .. b
3544 };
3545 assert_eq!(
3546 Proximity::query (&a, &b),
3547 Proximity {
3548 distance: -1.0,
3549 half_axis: [0.0, 0.0, -0.5].into(),
3550 normal: math::Unit3::axis_z().invert(),
3551 midpoint: [0.0, 0.0, 0.5].into()
3552 }
3553 );
3554
3555 let a = object::Static {
3557 position: component::Position ([0.0, 0.0, 0.0].into()),
3558 bound: component::Bound (shape::Bounded::from (
3559 shape::Cuboid::noisy ([1.0, 1.0, 1.0])).into()),
3560 .. a
3561 };
3562 let b = object::Static {
3563 position: component::Position ([0.0, 0.0, 0.0].into()),
3564 bound: component::Bound (shape::Unbounded::from (
3565 shape::Orthant { normal_axis: SignedAxis3::PosY }).into()),
3566 .. b
3567 };
3568 assert_eq!(
3569 Proximity::query (&a, &b),
3570 Proximity {
3571 distance: -1.0,
3572 half_axis: [0.0, 0.5, 0.0].into(),
3573 normal: math::Unit3::axis_y(),
3574 midpoint: [0.0, -0.5, 0.0].into()
3575 }
3576 );
3577
3578 let a = object::Static {
3580 position: component::Position ([0.0, 0.0, 0.0].into()),
3581 bound: component::Bound (shape::Bounded::from (
3582 shape::Cuboid::noisy ([1.0, 1.0, 1.0])).into()),
3583 .. a
3584 };
3585 let b = object::Static {
3586 position: component::Position ([0.0, 0.0, 0.0].into()),
3587 bound: component::Bound (shape::Unbounded::from (
3588 shape::Orthant { normal_axis: SignedAxis3::NegY }).into()),
3589 .. b
3590 };
3591 assert_eq!(
3592 Proximity::query (&a, &b),
3593 Proximity {
3594 distance: -1.0,
3595 half_axis: [0.0, -0.5, 0.0].into(),
3596 normal: math::Unit3::axis_y().invert(),
3597 midpoint: [0.0, 0.5, 0.0].into()
3598 }
3599 );
3600
3601 let a = object::Static {
3603 position: component::Position ([0.0, 0.0, 0.0].into()),
3604 bound: component::Bound (shape::Bounded::from (
3605 shape::Cuboid::noisy ([1.0, 1.0, 1.0])).into()),
3606 .. a
3607 };
3608 let b = object::Static {
3609 position: component::Position ([0.0, 0.0, 0.0].into()),
3610 bound: component::Bound (shape::Unbounded::from (
3611 shape::Orthant { normal_axis: SignedAxis3::PosX }).into()),
3612 .. b
3613 };
3614 assert_eq!(
3615 Proximity::query (&a, &b),
3616 Proximity {
3617 distance: -1.0,
3618 half_axis: [ 0.5, 0.0, 0.0].into(),
3619 normal: math::Unit3::axis_x(),
3620 midpoint: [-0.5, 0.0, 0.0].into()
3621 }
3622 );
3623
3624 let a = object::Static {
3626 position: component::Position ([0.0, 0.0, 0.0].into()),
3627 bound: component::Bound (shape::Bounded::from (
3628 shape::Cuboid::noisy ([1.0, 1.0, 1.0])).into()),
3629 .. a
3630 };
3631 let b = object::Static {
3632 position: component::Position ([0.0, 0.0, 0.0].into()),
3633 bound: component::Bound (shape::Unbounded::from (
3634 shape::Orthant { normal_axis: SignedAxis3::NegX }).into()),
3635 .. b
3636 };
3637 assert_eq!(
3638 Proximity::query (&a, &b),
3639 Proximity {
3640 distance: -1.0,
3641 half_axis: [-0.5, 0.0, 0.0].into(),
3642 normal: math::Unit3::axis_x().invert(),
3643 midpoint: [ 0.5, 0.0, 0.0].into()
3644 }
3645 );
3646
3647 } #[bench]
3650 fn bench_distance_query_cuboid_edges_normalize (b : &mut test::Bencher) {
3652 use rand::SeedableRng;
3653 let mut rng = XorShiftRng::seed_from_u64 (0);
3654 b.iter (||{
3655 let (position_a, cuboid_a, position_b, cuboid_b) =
3656 distance_query_cuboid_edge_case (&mut rng);
3657 let proximity = Proximity::query_cuboid_cuboid (
3658 &position_a, &cuboid_a, &position_b, &cuboid_b);
3659 assert!(proximity.distance > 0.0);
3660 });
3661 }
3662
3663 fn distance_query_cuboid_edge_case <RNG : rand::Rng> (rng : &mut RNG) -> (
3693 math::Point3 <f64>, shape::Cuboid <f64>,
3694 math::Point3 <f64>, shape::Cuboid <f64>
3695 ) {
3696 let base_min_a : f64 = rng.random_range (-10.0..10.0);
3698 let base_max_a : f64 = rng.random_range (base_min_a + 0.01..10.01);
3699 let base_min_b : f64 = rng.random_range (-10.01..base_max_a);
3700 let base_max_b : f64 = if base_min_b < base_min_a {
3701 rng.random_range (base_min_a + 0.01..10.02)
3702 } else {
3703 rng.random_range (base_min_b + 0.01..10.02)
3704 };
3705 debug_assert!(base_min_a < base_max_b);
3706 debug_assert!(base_min_b < base_max_a);
3707 let base_pos_a = 0.5 * (base_min_a + base_max_a);
3708 let base_half_extent_a = base_max_a - base_pos_a;
3709 let base_pos_b = 0.5 * (base_min_b + base_max_b);
3710 let base_half_extent_b = base_max_b - base_pos_b;
3711 debug_assert!(base_half_extent_a > 0.0);
3712 debug_assert!(base_half_extent_b > 0.0);
3713 let other1_min_a = rng.random_range (-10.0..10.0);
3715 let other1_max_a = rng.random_range (other1_min_a + 0.01..10.01);
3716 let (other1_min_b, other1_max_b) = if rng.random_bool (0.5) {
3717 let other1_min_b = rng.random_range (other1_max_a + 0.01..10.02);
3719 let other1_max_b = rng.random_range (other1_min_b + 0.01..10.03);
3720 debug_assert!(other1_max_a < other1_min_b);
3721 (other1_min_b, other1_max_b)
3722 } else {
3723 let other1_min_b = rng.random_range (-10.03..other1_min_a - 0.03);
3725 let other1_max_b = rng.random_range (other1_min_b + 0.01..other1_min_a - 0.01);
3726 debug_assert!(other1_max_b < other1_min_a);
3727 (other1_min_b, other1_max_b)
3728 };
3729 let other1_pos_a = 0.5 * (other1_min_a + other1_max_a);
3730 let other1_half_extent_a = other1_max_a - other1_pos_a;
3731 let other1_pos_b = 0.5 * (other1_min_b + other1_max_b);
3732 let other1_half_extent_b = other1_max_b - other1_pos_b;
3733 debug_assert!(other1_half_extent_a > 0.0);
3734 debug_assert!(other1_half_extent_b > 0.0);
3735
3736 let other2_min_a = rng.random_range (-10.0..10.0);
3737 let other2_max_a = rng.random_range (other2_min_a + 0.01..10.01);
3738 let (other2_min_b, other2_max_b) = if rng.random_bool (0.5) {
3739 let other2_min_b = rng.random_range (other2_max_a + 0.01..10.02);
3741 let other2_max_b = rng.random_range (other2_min_b + 0.01..10.03);
3742 debug_assert!(other2_max_a < other2_min_b);
3743 (other2_min_b, other2_max_b)
3744 } else {
3745 let other2_min_b = rng.random_range (-10.03..other2_min_a - 0.03);
3747 let other2_max_b = rng.random_range (other2_min_b + 0.01..other2_min_a - 0.01);
3748 debug_assert!(other2_max_b < other2_min_a);
3749 (other2_min_b, other2_max_b)
3750 };
3751 let other2_pos_a = 0.5 * (other2_min_a + other2_max_a);
3752 let other2_half_extent_a = other2_max_a - other2_pos_a;
3753 let other2_pos_b = 0.5 * (other2_min_b + other2_max_b);
3754 let other2_half_extent_b = other2_max_b - other2_pos_b;
3755 debug_assert!(other2_half_extent_a > 0.0);
3756 debug_assert!(other2_half_extent_b > 0.0);
3757
3758 let axis : usize = rng.random_range (0..3);
3759
3760 if axis == 0 {
3761 (
3763 [base_pos_a, other1_pos_a, other2_pos_a].into(),
3764 shape::Cuboid::noisy ([
3765 base_half_extent_a, other1_half_extent_a, other2_half_extent_a]),
3766 [base_pos_b, other1_pos_b, other2_pos_b].into(),
3767 shape::Cuboid::noisy ([
3768 base_half_extent_b, other1_half_extent_b, other2_half_extent_b])
3769 )
3770 } else if axis == 1 {
3771 (
3773 [other1_pos_a, base_pos_a, other2_pos_a].into(),
3774 shape::Cuboid::noisy ([
3775 other1_half_extent_a, base_half_extent_a, other2_half_extent_a]),
3776 [other1_pos_b, base_pos_b, other2_pos_b].into(),
3777 shape::Cuboid::noisy ([
3778 other1_half_extent_b, base_half_extent_b, other2_half_extent_b])
3779 )
3780 } else {
3781 debug_assert_eq!(axis, 2);
3783 (
3784 [other1_pos_a, other2_pos_a, base_pos_a].into(),
3785 shape::Cuboid::noisy ([
3786 other1_half_extent_a, other2_half_extent_a, base_half_extent_a]),
3787 [other1_pos_b, other2_pos_b, base_pos_b].into(),
3788 shape::Cuboid::noisy ([
3789 other1_half_extent_b, other2_half_extent_b, base_half_extent_b])
3790 )
3791 }
3792 }
3793
3794}