1use approx;
4
5use crate::*;
6use super::*;
7
8pub mod integer;
9
10#[inline]
22pub fn discrete_interval <S : Ring> (a : &Interval <S>, b : &Interval <S>)
23 -> bool
24{
25 let (min_a, max_a) = (a.min(), a.max());
26 let (min_b, max_b) = (b.min(), b.max());
27 max_a > min_b && min_a < max_b
29}
30
31#[inline]
43pub fn continuous_interval <S> (a : &Interval <S>, b : &Interval <S>)
44 -> Option <Interval <S>>
45where
46 S : Ring + std::fmt::Debug
47{
48 if discrete_interval (a, b) {
49 Some (Interval::with_minmax (
50 S::max (a.min(), b.min()),
51 S::min (a.max(), b.max())
52 ))
53 } else {
54 None
55 }
56}
57
58#[inline]
70pub fn discrete_aabb2_aabb2 <S : Ring> (a : &Aabb2 <S>, b : &Aabb2 <S>)
71 -> bool
72{
73 let (min_a, max_a) = (a.min(), a.max());
74 let (min_b, max_b) = (b.min(), b.max());
75 max_a.0.x > min_b.0.x && min_a.0.x < max_b.0.x &&
77 max_a.0.y > min_b.0.y && min_a.0.y < max_b.0.y
78}
79
80#[inline]
92pub fn continuous_aabb2_aabb2 <S> (a : &Aabb2 <S>, b : &Aabb2 <S>)
93 -> Option <Aabb2 <S>>
94where
95 S : Ring + std::fmt::Debug
96{
97 if discrete_aabb2_aabb2 (a, b) {
98 Some (Aabb2::with_minmax (
99 point2_max (a.min(), b.min()),
100 point2_min (a.max(), b.max())
101 ))
102 } else {
103 None
104 }
105}
106
107#[inline]
119pub fn discrete_aabb3_aabb3 <S : Ring> (a : &Aabb3 <S>, b : &Aabb3 <S>)
120 -> bool
121{
122 let (min_a, max_a) = (a.min(), a.max());
123 let (min_b, max_b) = (b.min(), b.max());
124 max_a.0.x > min_b.0.x && min_a.0.x < max_b.0.x &&
126 max_a.0.y > min_b.0.y && min_a.0.y < max_b.0.y &&
127 max_a.0.z > min_b.0.z && min_a.0.z < max_b.0.z
128}
129
130#[inline]
142pub fn continuous_aabb3_aabb3 <S> (a : &Aabb3 <S>, b : &Aabb3 <S>)
143 -> Option <Aabb3 <S>>
144where
145 S : Ring + std::fmt::Debug
146{
147 if discrete_aabb3_aabb3 (a, b) {
148 Some (Aabb3::with_minmax (
149 point3_max (a.min(), b.min()),
150 point3_min (a.max(), b.max())
151 ))
152 } else {
153 None
154 }
155}
156
157#[allow(clippy::type_complexity)]
187pub fn continuous_line2_aabb2 <S> (line : &Line2 <S>, aabb : &Aabb2 <S>)
188 -> Option <((S, Point2 <S>), (S, Point2 <S>))>
189where
190 S : Real + std::fmt::Debug
191{
192 let aabb_min = aabb.min();
193 let aabb_max = aabb.max();
194 if line.direction.x == S::zero() {
195 if aabb_min.0.x < line.base.0.x && line.base.0.x < aabb_max.0.x {
197 let out = if line.direction.y > S::zero() {
198 let (t0, t1) = (aabb_min.0.y - line.base.0.y, aabb_max.0.y - line.base.0.y);
199 ( (t0, [line.base.0.x, aabb_min.0.y].into()),
200 (t1, [line.base.0.x, aabb_max.0.y].into())
201 )
202 } else {
203 let (t0, t1) = (line.base.0.y - aabb_max.0.y, line.base.0.y - aabb_min.0.y);
204 ( (t0, [line.base.0.x, aabb_max.0.y].into()),
205 (t1, [line.base.0.x, aabb_min.0.y].into())
206 )
207 };
208 Some (out)
209 } else {
210 None
211 }
212 } else if line.direction.y == S::zero() {
213 if aabb_min.0.y < line.base.0.y && line.base.0.y < aabb_max.0.y {
215 let out = if line.direction.x > S::zero() {
216 let (t0, t1) = (aabb_min.0.x - line.base.0.x, aabb_max.0.x - line.base.0.x);
217 ( (t0, [aabb_min.0.x, line.base.0.y].into()),
218 (t1, [aabb_max.0.x, line.base.0.y].into())
219 )
220 } else {
221 let (t0, t1) = (line.base.0.x - aabb_max.0.x, line.base.0.x - aabb_min.0.x);
222 ( (t0, [aabb_max.0.x, line.base.0.y].into()),
223 (t1, [aabb_min.0.x, line.base.0.y].into())
224 )
225 };
226 Some (out)
227 } else {
228 None
229 }
230 } else {
231 let dir_reciprocal = line.direction.map (|s| S::one() / s);
232 let (t0_x, t1_x) = {
233 let (near_x, far_x) = if line.direction.x.is_positive() {
234 (aabb_min.0.x, aabb_max.0.x)
235 } else {
236 (aabb_max.0.x, aabb_min.0.x)
237 };
238 ( (near_x - line.base.0.x) * dir_reciprocal.x,
239 (far_x - line.base.0.x) * dir_reciprocal.x
240 )
241 };
242 let (t0_y, t1_y) = {
243 let (near_y, far_y) = if line.direction.y.is_positive() {
244 (aabb_min.0.y, aabb_max.0.y)
245 } else {
246 (aabb_max.0.y, aabb_min.0.y)
247 };
248 ( (near_y - line.base.0.y) * dir_reciprocal.y,
249 (far_y - line.base.0.y) * dir_reciprocal.y
250 )
251 };
252 let interval_x = Interval::with_minmax (t0_x, t1_x);
253 let interval_y = Interval::with_minmax (t0_y, t1_y);
254 continuous_interval (&interval_x, &interval_y).map (|interval|{
255 let start = line.point (interval.min());
256 let end = line.point (interval.max());
257 ( (interval.min(), start), (interval.max(), end) )
258 })
259 }
260}
261
262#[allow(clippy::type_complexity)]
292pub fn continuous_line2_sphere2 <S : Real> (line : &Line2 <S>, sphere : &Sphere2 <S>)
293 -> Option <((S, Point2 <S>), (S, Point2 <S>))>
294{
295 let two = S::two();
297 let four = S::four();
298 let p1 = line.base;
306 let _p2 = line.base + *line.direction;
307 let p3 = sphere.center;
308 let r = *sphere.radius;
309 let p1p2 = &line.direction;
310 let p3p1 = p1 - p3;
311 let a = S::one();
312 let b = two * p1p2.dot (p3p1);
313 let c = p3p1.norm_squared() - r * r;
314 let discriminant = b * b - four * a * c;
318 if discriminant <= S::zero() {
319 None
320 } else {
321 let discriminant_sqrt = discriminant.sqrt();
322 let frac_2a = S::one() / (two * a);
323 let t1 = (-b - discriminant_sqrt) * frac_2a;
324 let t2 = (-b + discriminant_sqrt) * frac_2a;
325 let first = p1 + (**p1p2) * t1;
326 let second = p1 + (**p1p2) * t2;
327 Some (((t1, first), (t2, second)))
328 }
329}
330
331pub fn continuous_line3_plane3 <S> (line : &Line3 <S>, plane : &Plane3 <S>)
345 -> Option <(S, Point3 <S>)>
346where
347 S : Real + approx::RelativeEq
348{
349 let normal_dot_direction = plane.normal.dot (*line.direction);
350 if approx::relative_eq!(normal_dot_direction, S::zero()) {
351 None
352 } else {
353 let plane_to_line = line.base - plane.base;
354 let t = -plane.normal.dot (plane_to_line) / normal_dot_direction;
355 let point = line.point (t);
356 Some ((t, point))
357 }
358}
359
360#[allow(clippy::type_complexity)]
392pub fn continuous_line3_aabb3 <S> (line : &Line3 <S>, aabb : &Aabb3 <S>)
393 -> Option <((S, Point3 <S>), (S, Point3 <S>))>
394where
395 S : Real + num_traits::Float + approx::RelativeEq <Epsilon=S> + std::fmt::Debug
396{
397 let aabb_min = aabb.min();
398 let aabb_max = aabb.max();
399 if line.direction.x == S::zero() {
400 if aabb_min.0.x < line.base.0.x && line.base.0.x < aabb_max.0.x {
401 let line2 = Line2::new ([line.base.0.y, line.base.0.z].into(),
402 Unit2::unchecked_approx ([line.direction.y, line.direction.z].into()));
403 let aabb2 = Aabb2::with_minmax (
404 [aabb_min.0.y, aabb_min.0.z].into(),
405 [aabb_max.0.y, aabb_max.0.z].into());
406 continuous_line2_aabb2 (&line2, &aabb2).map (|((t0, p0), (t1, p1))|
407 ( (t0, [line.base.0.x, p0.0.x, p0.0.y].into()),
408 (t1, [line.base.0.x, p1.0.x, p1.0.y].into())
409 )
410 )
411 } else {
412 None
413 }
414 } else if line.direction.y == S::zero() {
415 if aabb_min.0.y < line.base.0.y && line.base.0.y < aabb_max.0.y {
416 let line2 = Line2::new ([line.base.0.x, line.base.0.z].into(),
417 Unit2::unchecked_approx ([line.direction.x, line.direction.z].into()));
418 let aabb2 = Aabb2::with_minmax (
419 [aabb_min.0.x, aabb_min.0.z].into(),
420 [aabb_max.0.x, aabb_max.0.z].into());
421 continuous_line2_aabb2 (&line2, &aabb2).map (|((t0, p0), (t1, p1))|
422 ( (t0, [p0.0.x, line.base.0.y, p0.0.y].into()),
423 (t1, [p1.0.x, line.base.0.y, p1.0.y].into())
424 )
425 )
426 } else {
427 None
428 }
429 } else if line.direction.z == S::zero() {
430 if aabb_min.0.z < line.base.0.z && line.base.0.z < aabb_max.0.z {
431 let line2 = Line2::new ([line.base.0.x, line.base.0.y].into(),
432 Unit2::unchecked_approx ([line.direction.x, line.direction.y].into()));
433 let aabb2 = Aabb2::with_minmax (
434 [aabb_min.0.x, aabb_min.0.y].into(),
435 [aabb_max.0.x, aabb_max.0.y].into());
436 continuous_line2_aabb2 (&line2, &aabb2).map (|((t0, p0), (t1, p1))|
437 ( (t0, [p0.0.x, p0.0.y, line.base.0.z].into()),
438 (t1, [p1.0.x, p1.0.y, line.base.0.z].into())
439 )
440 )
441 } else {
442 None
443 }
444 } else {
445 let dir_reciprocal = line.direction.map (|s| S::one() / s);
446 let (t0_x, t1_x) = {
447 let (near_x, far_x) = if line.direction.x.is_positive() {
448 (aabb_min.0.x, aabb_max.0.x)
449 } else {
450 (aabb_max.0.x, aabb_min.0.x)
451 };
452 ( (near_x - line.base.0.x) * dir_reciprocal.x,
453 (far_x - line.base.0.x) * dir_reciprocal.x
454 )
455 };
456 let (t0_y, t1_y) = {
457 let (near_y, far_y) = if line.direction.y.is_positive() {
458 (aabb_min.0.y, aabb_max.0.y)
459 } else {
460 (aabb_max.0.y, aabb_min.0.y)
461 };
462 ( (near_y - line.base.0.y) * dir_reciprocal.y,
463 (far_y - line.base.0.y) * dir_reciprocal.y
464 )
465 };
466 let (t0_z, t1_z) = {
467 let (near_z, far_z) = if line.direction.z.is_positive() {
468 (aabb_min.0.z, aabb_max.0.z)
469 } else {
470 (aabb_max.0.z, aabb_min.0.z)
471 };
472 ( (near_z - line.base.0.z) * dir_reciprocal.z,
473 (far_z - line.base.0.z) * dir_reciprocal.z
474 )
475 };
476 let interval_x = Interval::with_minmax (t0_x, t1_x);
477 let interval_y = Interval::with_minmax (t0_y, t1_y);
478 continuous_interval (&interval_x, &interval_y).and_then (|interval| {
479 let interval_z = Interval::with_minmax (t0_z, t1_z);
480 continuous_interval (&interval, &interval_z).map (|interval|{
481 let start = line.point (interval.min());
482 let end = line.point (interval.max());
483 ( (interval.min(), start), (interval.max(), end) )
484 })
485 })
486 }
487}
488
489#[allow(clippy::type_complexity)]
519pub fn continuous_line3_sphere3 <S : Real> (line : &Line3 <S>, sphere : &Sphere3 <S>)
520 -> Option <((S, Point3 <S>), (S, Point3 <S>))>
521{
522 let two = S::two();
523 let four = S::four();
524 let p1 = line.base;
532 let _p2 = line.base + *line.direction;
533 let p3 = sphere.center;
534 let r = *sphere.radius;
535 let p1p2 = &line.direction;
536 let p3p1 = p1 - p3;
537 let a = S::one();
538 let b = two * p1p2.dot (p3p1);
539 let c = p3p1.norm_squared() - r * r;
540 let discriminant = b * b - four * a * c;
544 if discriminant <= S::zero() {
545 None
546 } else {
547 let discriminant_sqrt = discriminant.sqrt();
548 let frac_2a = S::one() / (two * a);
549 let t1 = (-b - discriminant_sqrt) * frac_2a;
550 let t2 = (-b + discriminant_sqrt) * frac_2a;
551 let first = p1 + (**p1p2) * t1;
552 let second = p1 + (**p1p2) * t2;
553 Some (((t1, first), (t2, second)))
554 }
555}
556
557#[allow(clippy::type_complexity)]
565pub fn continuous_segment2_aabb2 <S> (segment : &Segment2 <S>, aabb : &Aabb2 <S>)
566 -> Option <((S, Point2 <S>), (S, Point2 <S>))>
567where S : Real + std::fmt::Debug {
568 let vector = *segment.point_b() - segment.point_a();
569 let length = vector.norm();
570 let line = Line2::new (
571 *segment.point_a(), Unit2::unchecked (vector / length));
572 if let Some (((t0, _p0), (t1, _p1))) = continuous_line2_aabb2 (&line, aabb) {
573 let interval = Interval::with_minmax (S::zero(), length);
574 continuous_interval (&interval, &Interval::with_minmax (t0, t1)).map (
575 |interval|
576 ( (interval.min() / length, line.point (interval.min())),
577 (interval.max() / length, line.point (interval.max()))
578 )
579 )
580 } else {
581 None
582 }
583}
584
585#[allow(clippy::type_complexity)]
594pub fn continuous_segment2_sphere2 <S> (segment : &Segment2 <S>, sphere : &Sphere2 <S>)
595 -> Option <((S, Point2 <S>), (S, Point2<S>))>
596where S : Real + std::fmt::Debug {
597 let vector = *segment.point_b() - segment.point_a();
598 let length = vector.norm();
599 let line = Line2::new (
600 *segment.point_a(), Unit2::unchecked (vector / length));
601 if let Some (((t0, _p0), (t1, _p1))) = continuous_line2_sphere2 (&line, sphere) {
602 let interval = Interval::with_minmax (S::zero(), length);
603 continuous_interval (&interval, &Interval::with_minmax (t0, t1)).map (
604 |interval|
605 ( (interval.min() / length, line.point (interval.min())),
606 (interval.max() / length, line.point (interval.max()))
607 )
608 )
609 } else {
610 None
611 }
612}
613
614#[allow(clippy::type_complexity)]
621pub fn continuous_segment3_aabb3 <S> (segment : &Segment3 <S>, aabb : &Aabb3 <S>)
622 -> Option <((S, Point3 <S>), (S, Point3<S>))>
623where S : Real + num_traits::Float + approx::RelativeEq <Epsilon=S> + std::fmt::Debug {
624 let vector = *segment.point_b() - segment.point_a();
625 let length = vector.norm();
626 let line = Line3::new (
627 *segment.point_a(), Unit3::unchecked_approx (vector / length));
628 if let Some (((t0, _p0), (t1, _p1))) = continuous_line3_aabb3 (&line, aabb) {
629 let interval = Interval::with_minmax (S::zero(), length);
630 continuous_interval (&interval, &Interval::with_minmax (t0, t1)).map (
631 |interval|
632 ( (interval.min() / length, line.point (interval.min())),
633 (interval.max() / length, line.point (interval.max()))
634 )
635 )
636 } else {
637 None
638 }
639}
640
641#[allow(clippy::type_complexity)]
649pub fn continuous_segment3_sphere3 <S> (segment : &Segment3 <S>, sphere : &Sphere3 <S>)
650 -> Option <((S, Point3 <S>), (S, Point3<S>))>
651where S : Field + Sqrt {
652 let two = S::two();
653 let four = S::four();
654 let p1 = segment.point_a();
662 let p2 = segment.point_b();
663 let p3 = sphere.center;
664 let r = *sphere.radius;
665 let p1p2 = *p2-p1;
666 let p3p1 = *p1-p3;
667 let a = p1p2.norm_squared();
668 let b = two * p1p2.dot (p3p1);
669 let c = p3p1.norm_squared() - r * r;
670 let discriminant = b * b - four * a * c;
674 if discriminant <= S::zero() {
675 None
676 } else {
677 let discriminant_sqrt = discriminant.sqrt();
678 let frac_2a = S::one() / (two * a);
679 let t1 = S::max (
680 (-b - discriminant_sqrt) * frac_2a,
681 S::zero());
682 let t2 = S::min (
683 (-b + discriminant_sqrt) * frac_2a,
684 S::one());
685 if t2 <= S::zero() || S::one() <= t1 {
686 None
687 } else {
688 let first = *p1 + p1p2 * t1;
689 let second = *p1 + p1p2 * t2;
690 Some (((t1, first), (t2, second)))
691 }
692 }
693}
694
695#[allow(clippy::type_complexity)]
704pub fn continuous_segment3_cylinder3 <S> (
705 segment : &Segment3 <S>, cylinder : &Cylinder3 <S>
706) -> Option <((S, Point3 <S>), (S, Point3<S>))> where
707 S : Real + std::fmt::Debug
708{
709 let segment_aabb = segment.aabb3();
710 let cylinder_aabb = cylinder.aabb3();
711 if !discrete_aabb3_aabb3 (&segment_aabb, &cylinder_aabb) {
712 None
713 } else {
714 let p1 = segment.point_a();
715 let p2 = segment.point_b();
716 let p3 = cylinder.center;
717 let r = *cylinder.radius;
718 let r2 = r * r;
719 let p1p2 = *p2 - p1;
720 let p1_xy = Point2::from ([p1.0.x, p1.0.y]);
721 let p2_xy = Point2::from ([p2.0.x, p2.0.y]);
722 let p3_xy = Point2::from ([p3.0.x, p3.0.y]);
723 let p3_z_max = cylinder_aabb.max().0.z;
724 let p3_z_min = cylinder_aabb.min().0.z;
725 if p1_xy == p2_xy { let d2 = (p1_xy - p3_xy).norm_squared();
727 if d2 >= r2 {
728 None
729 } else {
730 let (t1, begin_z) = if p1.0.z >= p3_z_max {
731 ((p3_z_max - p1.0.z) / p1p2.z, p3_z_max)
732 } else if p1.0.z <= p3_z_min {
733 ((p3_z_min - p1.0.z) / p1p2.z, p3_z_min)
734 } else {
735 (S::zero(), p1.0.z)
736 };
737 let (t2, end_z) = if p2.0.z >= p3_z_max {
738 ((p3_z_max - p1.0.z) / p1p2.z, p3_z_max)
739 } else if p2.0.z <= p3_z_min {
740 ((p3_z_min - p1.0.z) / p1p2.z, p3_z_min)
741 } else {
742 (S::one(), p2.0.z)
743 };
744 let begin = [p1_xy.0.x, p1_xy.0.y, begin_z].into();
745 let end = [p1_xy.0.x, p1_xy.0.y, end_z ].into();
746 Some (((t1, begin), (t2, end)))
747 }
748 } else { let two = S::two();
751 let four = S::four();
752 let p1p2_xy = p1p2.xy();
753 let p3p1_xy = p1_xy - p3_xy;
754 let a = p1p2_xy.norm_squared();
755 let b = two * p1p2_xy.dot (p3p1_xy);
756 let c = p3p1_xy.norm_squared() - r * r;
757 let discriminant = b * b - four * a * c;
761 if discriminant <= S::zero() {
762 None
763 } else {
764 let discriminant_sqrt = discriminant.sqrt();
765 let frac_2a = S::one() / (two * a);
766 let t1_xy = S::max (
767 (-b - discriminant_sqrt) * frac_2a,
768 S::zero());
769 let t2_xy = S::min (
770 (-b + discriminant_sqrt) * frac_2a,
771 S::one());
772 if t2_xy <= S::zero() || S::one() <= t1_xy {
773 None
774 } else if let Some ((t1, t2)) = if p1.0.z == p2.0.z { Some ((t1_xy, t2_xy))
776 } else { let p1p3_z_max = p3_z_max - p1.0.z;
779 let p1p3_z_min = p3_z_min - p1.0.z;
780 let t_z_max = S::max (
781 S::min (p1p3_z_max / p1p2.z, S::one()),
782 S::zero());
783 let t_z_min = S::max (
784 S::min (p1p3_z_min / p1p2.z, S::one()),
785 S::zero());
786 let t1_z = S::min (t_z_max, t_z_min);
787 let t2_z = S::max (t_z_max, t_z_min);
788 let aabb_xy = Interval::with_minmax (t1_xy, t2_xy);
789 let aabb_z = Interval::with_minmax ( t1_z, t2_z);
790 if !aabb_xy.intersects (&aabb_z) {
791 None
792 } else {
793 Some ((S::max (t1_xy, t1_z), S::min (t2_xy, t2_z)))
794 }
795 } {
796 debug_assert!(t1 < t2);
797 debug_assert!(t1 >= S::zero());
798 debug_assert!(t1 < S::one());
799 debug_assert!(t2 > S::zero());
800 debug_assert!(t2 <= S::one());
801 let first = *p1 + p1p2 * t1;
802 let second = *p1 + p1p2 * t2;
803 Some (((t1, first), (t2, second)))
804 } else {
805 None
806 }
807 }
808 }
809 }
810}
811
812#[allow(clippy::type_complexity)]
821pub fn continuous_segment3_capsule3 <S> (
822 segment : &Segment3 <S>, capsule : &Capsule3 <S>
823) -> Option <((S, Point3 <S>), (S, Point3 <S>))> where
824 S : Real + std::fmt::Debug
825{
826 let segment_aabb = segment.aabb3();
827 let capsule_aabb = capsule.aabb3();
828 if !discrete_aabb3_aabb3 (&segment_aabb, &capsule_aabb) {
829 None
830 } else {
831 let (upper_sphere, cylinder, lower_sphere) = capsule.decompose();
833 let cylinder_result = cylinder.and_then (
834 |cylinder| segment.intersect_cylinder (&cylinder));
835 let upper_result = segment.intersect_sphere (&upper_sphere);
836 let lower_result = segment.intersect_sphere (&lower_sphere);
837 match (upper_result, cylinder_result, lower_result) {
838 (None, None, None) => None,
839 (one, None, None) |
840 (None, one, None) |
841 (None, None, one) => one,
842 (Some (((t1,p1), (t2,p2))), Some (((u1,q1), (u2,q2))), None) |
843 (Some (((t1,p1), (t2,p2))), None, Some (((u1,q1), (u2,q2)))) |
844 (None, Some (((t1,p1), (t2,p2))), Some (((u1,q1), (u2,q2)))) => {
845 let first = if t1 < u1 {
846 (t1,p1)
847 } else {
848 (u1,q1)
849 };
850 let second = if t2 > u2 {
851 (t2,p2)
852 } else {
853 (u2,q2)
854 };
855 Some ((first, second))
856 }
857 ( Some (((t1,p1), (t2,p2))),
858 Some (((u1,q1), (u2,q2))),
859 Some (((v1,r1), (v2,r2)))
860 ) => {
861 let min1 = S::min (S::min (t1, u1), v1);
862 let max2 = S::max (S::max (t2, u2), v2);
863 let first = if min1 == t1 {
864 (t1,p1)
865 } else if min1 == u1 {
866 (u1,q1)
867 } else {
868 debug_assert_eq!(min1, v1);
869 (v1,r1)
870 };
871 let second = if max2 == t2 {
872 (t2,p2)
873 } else if max2 == u2 {
874 (u2,q2)
875 } else {
876 debug_assert_eq!(max2, v2);
877 (v2,r2)
878 };
879 Some ((first, second))
880 }
881 }
882 }
883}
884
885#[inline]
900pub fn discrete_sphere2_sphere2 <S : Ring> (
901 a : &Sphere2 <S>, b : &Sphere2 <S>
902) -> bool {
903 let r_ab = *(a.radius + b.radius);
904 (b.center - a.center).self_dot() < r_ab * r_ab
905}
906
907#[inline]
922pub fn discrete_sphere3_sphere3 <S : Ring> (
923 a : &Sphere3 <S>, b : &Sphere3 <S>
924) -> bool {
925 let r_ab = *(a.radius + b.radius);
926 (b.center - a.center).self_dot() < r_ab * r_ab
927}
928
929#[cfg(test)]
930mod tests {
931 use super::*;
932
933 #[test]
934 fn test_line2_aabb2() {
935 use std::f64::consts::SQRT_2;
936 let aabb = Aabb2::with_minmax ([-1.0, -1.0].into(), [1.0, 1.0].into());
937 let line = Line2::new ([ 0.0, 0.0].into(), Unit2::axis_y());
938 assert_eq!(
939 continuous_line2_aabb2 (&line, &aabb).unwrap(),
940 ((-1.0, [ 0.0, -1.0].into()), (1.0, [ 0.0, 1.0].into())));
941 let line = Line2::new ([ 0.0, 0.0].into(), Unit2::axis_x());
942 assert_eq!(
943 continuous_line2_aabb2 (&line, &aabb).unwrap(),
944 ((-1.0, [-1.0, 0.0].into()), (1.0, [ 1.0, 0.0].into())));
945 let line = Line2::new ([ 0.0, 0.0].into(),
946 Unit2::normalize ([1.0, 1.0].into()));
947 assert_eq!(
948 continuous_line2_aabb2 (&line, &aabb).unwrap(),
949 ((-SQRT_2, [-1.0, -1.0].into()), (SQRT_2, [ 1.0, 1.0].into())));
950 let line = Line2::new ([ 0.0, 0.0].into(),
951 Unit2::normalize ([-1.0, -1.0].into()));
952 assert_eq!(
953 continuous_line2_aabb2 (&line, &aabb).unwrap(),
954 ((-SQRT_2, [ 1.0, 1.0].into()), (SQRT_2, [-1.0, -1.0].into())));
955 let line = Line2::new ([ 0.0, 3.0].into(),
956 Unit2::normalize ([-1.0, -1.0].into()));
957 assert!(continuous_line2_aabb2 (&line, &aabb).is_none());
958 let line = Line2::new ([ 0.0, -3.0].into(),
959 Unit2::normalize ([ 1.0, 1.0].into()));
960 assert!(continuous_line2_aabb2 (&line, &aabb).is_none());
961 }
962
963 #[test]
964 fn test_line3_aabb3() {
965 use approx::assert_ulps_eq;
966 let aabb = Aabb3::with_minmax (
967 [-1.0, -1.0, -1.0].into(), [1.0, 1.0, 1.0].into());
968 let line = Line3::new ([ 0.0, 0.0, 0.0].into(), Unit3::axis_z());
969 assert_eq!(
970 continuous_line3_aabb3 (&line, &aabb).unwrap(),
971 ((-1.0, [ 0.0, 0.0, -1.0].into()), (1.0, [ 0.0, 0.0, 1.0].into())));
972 let line = Line3::new ([ 0.0, 0.0, 0.0].into(), Unit3::axis_y());
973 assert_eq!(
974 continuous_line3_aabb3 (&line, &aabb).unwrap(),
975 ((-1.0, [0.0, -1.0, 0.0].into()), (1.0, [ 0.0, 1.0, 0.0].into())));
976 {
977 let line = Line3::new ([ 0.0, 0.0, 0.0].into(),
978 Unit3::normalize ([1.0, 1.0, 1.0].into()));
979 let result = continuous_line3_aabb3 (&line, &aabb).unwrap();
980 assert_ulps_eq!((result.0).0, -f64::sqrt_3());
981 assert_ulps_eq!((result.1).0, f64::sqrt_3());
982 assert_eq!((result.0).1, [-1.0, -1.0, -1.0].into());
983 assert_eq!((result.1).1, [ 1.0, 1.0, 1.0].into());
984 }
985 {
986 let line = Line3::new ([ 0.0, 0.0, 0.0].into(),
987 Unit3::normalize ([-1.0, -1.0, -1.0].into()));
988 let result = continuous_line3_aabb3 (&line, &aabb).unwrap();
989 assert_ulps_eq!((result.0).0, -f64::sqrt_3());
990 assert_ulps_eq!((result.1).0, f64::sqrt_3());
991 assert_eq!((result.0).1, [ 1.0, 1.0, 1.0].into());
992 assert_eq!((result.1).1, [-1.0, -1.0, -1.0].into());
993 }
994 let line = Line3::new ([ 0.0, 0.0, 3.0].into(),
995 Unit3::normalize ([-1.0, -1.0, -1.0].into()));
996 assert!(continuous_line3_aabb3 (&line, &aabb).is_none());
997 let line = Line3::new ([0.0, 0.0, -3.0].into(),
998 Unit3::normalize ([1.0, 1.0, 1.0].into()));
999 assert!(continuous_line3_aabb3 (&line, &aabb).is_none());
1000 }
1001
1002 #[test]
1003 fn test_segment3_sphere3() {
1004 let sphere = shape::Sphere::unit().sphere3 (Point3::origin());
1005 let segment = Segment3::new (
1006 [-2.0, 0.0, 0.0].into(), [ 2.0, 0.0, 0.0].into());
1007 assert_eq!(
1008 continuous_segment3_sphere3 (&segment, &sphere).unwrap(),
1009 ((0.25, [-1.0, 0.0, 0.0].into()), (0.75, [ 1.0, 0.0, 0.0].into())));
1010 let segment = Segment3::new (
1011 [ 2.0, 0.0, 0.0].into(), [-2.0, 0.0, 0.0].into());
1012 assert_eq!(
1013 continuous_segment3_sphere3 (&segment, &sphere).unwrap(),
1014 ((0.25, [ 1.0, 0.0, 0.0].into()), (0.75, [-1.0, 0.0, 0.0].into())));
1015 let segment = Segment3::new (
1016 [ 0.0, 0.0, 0.0].into(), [ 0.0, 0.0, 2.0].into());
1017 assert_eq!(
1018 continuous_segment3_sphere3 (&segment, &sphere).unwrap(),
1019 ((0.0, [ 0.0, 0.0, 0.0].into()), (0.5, [ 0.0, 0.0, 1.0].into())));
1020 let segment = Segment3::new (
1021 [ 0.0, 0.0, -2.0].into(), [ 0.0, 0.0, 0.0].into());
1022 assert_eq!(
1023 continuous_segment3_sphere3 (&segment, &sphere).unwrap(),
1024 ((0.5, [ 0.0, 0.0, -1.0].into()), (1.0, [ 0.0, 0.0, 0.0].into())));
1025 }
1026
1027 #[test]
1028 fn test_segment3_cylinder3() {
1029 let cylinder = shape::Cylinder::unit().cylinder3 (Point3::origin());
1030 let segment = Segment3::new (
1031 [-2.0, 0.0, 0.0].into(), [ 2.0, 0.0, 0.0].into());
1032 assert_eq!(
1033 continuous_segment3_cylinder3 (&segment, &cylinder).unwrap(),
1034 ((0.25, [-1.0, 0.0, 0.0].into()), (0.75, [ 1.0, 0.0, 0.0].into())));
1035 let segment = Segment3::new (
1036 [ 2.0, 0.0, 0.0].into(), [-2.0, 0.0, 0.0].into());
1037 assert_eq!(
1038 continuous_segment3_cylinder3 (&segment, &cylinder).unwrap(),
1039 ((0.25, [ 1.0, 0.0, 0.0].into()), (0.75, [-1.0, 0.0, 0.0].into())));
1040 let segment = Segment3::new (
1041 [ 0.0, 0.0, 0.0].into(), [ 0.0, 0.0, 2.0].into());
1042 assert_eq!(
1043 continuous_segment3_cylinder3 (&segment, &cylinder).unwrap(),
1044 ((0.0, [ 0.0, 0.0, 0.0].into()), (0.5, [ 0.0, 0.0, 1.0].into())));
1045 let segment = Segment3::new (
1046 [ 0.0, 0.0, -2.0].into(), [ 0.0, 0.0, 0.0].into());
1047 assert_eq!(
1048 continuous_segment3_cylinder3 (&segment, &cylinder).unwrap(),
1049 ((0.5, [ 0.0, 0.0, -1.0].into()), (1.0, [ 0.0, 0.0, 0.0].into())));
1050 }
1051
1052 #[test]
1053 fn test_segment3_capsule3() {
1054 let capsule = shape::Capsule::noisy (1.0, 1.0)
1055 .capsule3 (Point3::origin());
1056 let segment = Segment3::new (
1057 [-2.0, 0.0, 0.0].into(), [ 2.0, 0.0, 0.0].into());
1058 assert_eq!(
1059 continuous_segment3_capsule3 (&segment, &capsule).unwrap(),
1060 ((0.25, [-1.0, 0.0, 0.0].into()), (0.75, [ 1.0, 0.0, 0.0].into())));
1061 let segment = Segment3::new (
1062 [ 2.0, 0.0, 0.0].into(), [-2.0, 0.0, 0.0].into());
1063 assert_eq!(
1064 continuous_segment3_capsule3 (&segment, &capsule).unwrap(),
1065 ((0.25, [ 1.0, 0.0, 0.0].into()), (0.75, [-1.0, 0.0, 0.0].into())));
1066 let segment = Segment3::new (
1067 [ 0.0, 0.0, 0.0].into(), [ 0.0, 0.0, 4.0].into());
1068 assert_eq!(
1069 continuous_segment3_capsule3 (&segment, &capsule).unwrap(),
1070 ((0.0, [ 0.0, 0.0, 0.0].into()), (0.5, [ 0.0, 0.0, 2.0].into())));
1071 let segment = Segment3::new (
1072 [ 0.0, 0.0, -4.0].into(), [ 0.0, 0.0, 0.0].into());
1073 assert_eq!(
1074 continuous_segment3_capsule3 (&segment, &capsule).unwrap(),
1075 ((0.5, [ 0.0, 0.0, -2.0].into()), (1.0, [ 0.0, 0.0, 0.0].into())));
1076 }
1077
1078 #[test]
1079 fn test_segment3_aabb3() {
1080 let aabb = Aabb3::with_minmax (
1081 [1.0, -0.5, 0.0].into(), [2.0, 0.5, 1.0].into()
1082 );
1083 let segment = Segment3::new (
1084 [-1.0, 0.0, 0.5].into(), [ 2.0, 0.0, 0.5].into());
1085 assert_eq!(
1086 continuous_segment3_aabb3 (&segment, &aabb).unwrap(),
1087 ((2.0/3.0, [1.0, 0.0, 0.5].into()), (1.0, [ 2.0, 0.0, 0.5].into())));
1088 }
1089
1090}