1use crate::scalar::*;
71use crate::vector::*;
72use num_traits::{One, Zero};
73
74#[repr(C)]
76#[derive(Debug, Clone, Copy, Default)]
77pub struct Dimension<T: Scalar> {
78 pub width: T,
80 pub height: T,
82}
83
84impl<T: Scalar> Dimension<T> {
85 pub fn new(width: T, height: T) -> Self {
87 Self { width, height }
88 }
89}
90
91#[repr(C)]
95#[derive(Debug, Clone, Copy, Default)]
96pub struct Rect<T: Scalar> {
97 pub x: T,
99 pub y: T,
101 pub width: T,
103 pub height: T,
105}
106
107impl<T: Scalar> Rect<T> {
108 pub fn new(x: T, y: T, width: T, height: T) -> Self {
110 Self {
111 x,
112 y,
113 width,
114 height,
115 }
116 }
117 pub fn from(min_vec: &Vector2<T>, max_vec: &Vector2<T>) -> Self {
121 let min_x = T::min(min_vec.x, max_vec.x);
122 let min_y = T::min(min_vec.y, max_vec.y);
123 let max_x = T::max(min_vec.x, max_vec.x);
124 let max_y = T::max(min_vec.y, max_vec.y);
125 Self {
126 x: min_x,
127 y: min_y,
128 width: max_x - min_x,
129 height: max_y - min_y,
130 }
131 }
132
133 pub fn min(&self) -> Vector2<T> {
135 Vector2::new(self.x, self.y)
136 }
137 pub fn max(&self) -> Vector2<T> {
139 Vector2::new(self.x + self.width, self.y + self.height)
140 }
141 pub fn intersect(&self, other: &Self) -> Option<Self> {
145 let smx = self.max();
146 let smn = self.min();
147 let omx = other.max();
148 let omn = other.min();
149
150 if smx.x < omn.x || smx.y < omn.y || smn.x > omx.x || smn.y > omx.y {
151 return None;
152 }
153
154 let min_vec = Vector2::max(&self.min(), &other.min());
155 let max_vec = Vector2::min(&self.max(), &other.max());
156 Some(Self::from(&min_vec, &max_vec))
157 }
158
159 pub fn contains(&self, p: &Vector2<T>) -> bool {
161 p.x >= self.x && p.y >= self.y && p.x <= self.x + self.width && p.y <= self.y + self.height
162 }
163}
164
165#[repr(C)]
169#[derive(Debug, Clone, Copy, Default)]
170pub struct Box3<T: Scalar> {
171 pub min: Vector3<T>,
173 pub max: Vector3<T>,
175}
176
177impl<T: Scalar> Box3<T> {
178 pub fn new(v0: &Vector3<T>, v1: &Vector3<T>) -> Self {
182 Self {
183 min: Vector3::min(v0, v1),
184 max: Vector3::max(v0, v1),
185 }
186 }
187 pub fn overlap(&self, other: &Self) -> bool {
189 if self.max.x < other.min.x {
190 return false;
191 }
192 if self.max.y < other.min.y {
193 return false;
194 }
195 if self.max.z < other.min.z {
196 return false;
197 }
198
199 if self.min.x > other.max.x {
200 return false;
201 }
202 if self.min.y > other.max.y {
203 return false;
204 }
205 if self.min.z > other.max.z {
206 return false;
207 }
208 true
209 }
210
211 pub fn add(&self, p: &Vector3<T>) -> Self {
213 Self {
214 min: Vector3::min(p, &self.min),
215 max: Vector3::max(p, &self.max),
216 }
217 }
218}
219
220impl<T: FloatScalar> Box3<T> {
221 pub fn center(&self) -> Vector3<T> {
223 (self.max + self.min) * T::half()
224 }
225 pub fn extent(&self) -> Vector3<T> {
227 self.max - self.center()
228 }
229
230 pub fn subdivide(&self) -> [Self; 8] {
234 let cube_table: [Vector3<i32>; 8] = [
235 Vector3::new(0, 1, 0),
236 Vector3::new(1, 1, 0),
237 Vector3::new(1, 1, 1),
238 Vector3::new(0, 1, 1),
239 Vector3::new(0, 0, 0),
240 Vector3::new(1, 0, 0),
241 Vector3::new(1, 0, 1),
242 Vector3::new(0, 0, 1),
243 ];
244
245 let ps: [Vector3<T>; 2] = [self.min, self.max];
246 let mut vs = [Vector3::zero(); 8];
247 for i in 0..8 {
248 vs[i] = Vector3::new(
249 ps[cube_table[i].x as usize].x,
250 ps[cube_table[i].y as usize].y,
251 ps[cube_table[i].z as usize].z,
252 );
253 }
254
255 let c = self.center();
256 let mut out = [Box3 {
257 min: Vector3::zero(),
258 max: Vector3::zero(),
259 }; 8];
260 for i in 0..8 {
261 out[i] = Self::new(&Vector3::min(&c, &vs[i]), &Vector3::max(&c, &vs[i]));
262 }
263 out
264 }
265}
266
267#[repr(C)]
271#[derive(Debug, Clone, Copy, Default)]
272pub struct Line<T: Scalar, V: Vector<T>> {
273 pub p: V,
275 pub d: V,
277 t: core::marker::PhantomData<T>,
278}
279
280impl<T: FloatScalar, V: FloatVector<T>> Line<T, V> {
281 pub fn new(p: &V, d: &V, epsilon: T) -> Option<Self> {
285 let d_ss = V::dot(d, d);
286 if d_ss <= epsilon * epsilon {
287 return None;
288 }
289 Some(Self {
290 p: *p,
291 d: *d,
292 t: core::marker::PhantomData,
293 })
294 }
295 pub fn from_start_end(s: &V, e: &V, epsilon: T) -> Option<Self> {
301 let dir = *e - *s;
302 Self::new(s, &dir, epsilon)
303 }
304 pub fn closest_point_on_line(&self, p: &V, epsilon: T) -> Option<(T, V)> {
312 let p_dir = *p - self.p;
313
314 let d_sp = V::dot(&self.d, &p_dir);
315 let d_ss = V::dot(&self.d, &self.d);
316
317 if d_ss <= epsilon * epsilon {
318 return None;
319 }
320
321 let t = d_sp / d_ss;
322
323 Some((t, self.p + self.d * t))
324 }
325
326 pub fn normalize(&self, epsilon: T) -> Option<Self> {
330 let d_ss = V::dot(&self.d, &self.d);
331 if d_ss <= epsilon * epsilon {
332 return None;
333 }
334 let inv_len = <T as One>::one() / d_ss.tsqrt();
335 Some(Self {
336 p: self.p,
337 d: self.d * inv_len,
338 t: core::marker::PhantomData,
339 })
340 }
341}
342
343pub fn shortest_segment3d_between_lines3d<T: FloatScalar>(
347 line0: &Line<T, Vector3<T>>,
348 line1: &Line<T, Vector3<T>>,
349 epsilon: T,
350) -> Option<Segment<T, Vector3<T>>> {
351 let s0 = line0.p;
352 let s1 = line1.p;
353
354 let d1 = line1.d;
355 let d0 = line0.d;
356
357 let eps_sq = epsilon * epsilon;
358 let d0_len_sq = Vector3::dot(&d0, &d0);
359 let d1_len_sq = Vector3::dot(&d1, &d1);
360 if d0_len_sq <= eps_sq || d1_len_sq <= eps_sq {
361 return None;
362 }
363
364 let cross = Vector3::cross(&d1, &d0);
365 let cross_len_sq = Vector3::dot(&cross, &cross);
366 if cross_len_sq <= eps_sq {
367 return None;
368 }
369
370 let normal = Vector3::normalize(&cross);
371 let n0 = Vector3::normalize(&Vector3::cross(&normal, &d0));
372 let n1 = Vector3::normalize(&Vector3::cross(&normal, &d1));
373
374 let plane0 = Plane::try_new(&n0, &s0, epsilon)?;
375 let plane1 = Plane::try_new(&n1, &s1, epsilon)?;
376
377 let p1 = plane0.intersect_line(line1, epsilon);
378 let p0 = plane1.intersect_line(line0, epsilon);
379
380 match (p0, p1) {
381 (Some((_, s)), Some((_, e))) => Some(Segment::new(&s, &e)),
382 _ => None,
383 }
384}
385
386#[repr(C)]
388#[derive(Clone, Copy, Default)]
389pub struct Segment<T: Scalar, V: Vector<T>> {
390 pub s: V,
392 pub e: V,
394 t: core::marker::PhantomData<T>,
395}
396
397impl<T: Scalar, V: Vector<T>> Segment<T, V> {
398 pub fn new(s: &V, e: &V) -> Self {
400 Self {
401 s: *s,
402 e: *e,
403 t: core::marker::PhantomData,
404 }
405 }
406}
407
408impl<T: FloatScalar, V: FloatVector<T>> Segment<T, V> {
409 pub fn closest_point_on_segment(&self, p: &V, epsilon: T) -> Option<(T, V)> {
417 let dir = self.e - self.s;
418 let p_dir = *p - self.s;
419
420 let d_sp = V::dot(&dir, &p_dir);
421 let d_ss = V::dot(&dir, &dir);
422
423 if d_ss <= epsilon * epsilon {
424 return None;
425 }
426
427 if d_sp < <T as Zero>::zero() {
428 return Some((<T as Zero>::zero(), self.s));
429 } else if d_sp > d_ss {
430 return Some((<T as One>::one(), self.e));
431 }
432
433 let t = d_sp / d_ss;
434
435 Some((t, self.s + dir * t))
436 }
437 pub fn distance(&self, p: &V, epsilon: T) -> Option<T> {
441 self.closest_point_on_segment(p, epsilon)
442 .map(|(_, p_on_seg)| V::length(&(p_on_seg - *p)))
443 }
444}
445
446#[repr(C)]
450#[derive(Clone, Copy, Default)]
451pub struct Ray<T: Scalar, V: Vector<T>> {
452 pub start: V,
454 pub direction: V,
456 t: core::marker::PhantomData<T>,
457}
458
459impl<T: FloatScalar, V: FloatVector<T>> Ray<T, V> {
460 pub fn new(start: &V, direction: &V, epsilon: T) -> Option<Self> {
464 let d_ss = V::dot(direction, direction);
465 if d_ss <= epsilon * epsilon {
466 return None;
467 }
468 let inv_len = <T as One>::one() / d_ss.tsqrt();
469 Some(Self {
470 start: *start,
471 direction: *direction * inv_len,
472 t: core::marker::PhantomData,
473 })
474 }
475}
476
477impl<T: FloatScalar> Ray<T, Vector3<T>> {
478 pub fn intersect_plane(&self, p: &Plane<T>, epsilon: T) -> Option<Vector3<T>> {
485 let n = p.normal();
486 let denom = Vector3::dot(&n, &self.direction);
487 if denom.tabs() <= epsilon {
488 return None;
489 }
490 let t: T = -(p.d + Vector3::dot(&n, &self.start)) / denom;
491 if t < <T as Zero>::zero() {
492 None
493 } else {
494 Some(self.direction * t + self.start)
495 }
496 }
497}
498
499#[repr(C)]
503#[derive(Clone, Copy, Default)]
504pub struct Sphere3<T: FloatScalar> {
505 pub center: Vector3<T>,
507 pub radius: T,
509}
510
511impl<T: FloatScalar> Sphere3<T> {
512 pub fn new(center: Vector3<T>, radius: T) -> Self {
517 Self {
518 center,
519 radius: radius.tabs(),
520 }
521 }
522}
523
524#[repr(C)]
528#[derive(Clone, Copy, Default)]
529pub struct Tri3<T: FloatScalar> {
530 vertices: [Vector3<T>; 3],
531}
532
533impl<T: FloatScalar> Tri3<T> {
534 pub fn new(vertices: [Vector3<T>; 3]) -> Self {
536 Self { vertices }
537 }
538 pub fn vertices(&self) -> &[Vector3<T>; 3] {
540 &self.vertices
541 }
542
543 pub fn barycentric_coordinates(&self, pt: &Vector3<T>) -> Vector3<T> {
549 let v0 = self.vertices[0];
550 let v1 = self.vertices[1];
551 let v2 = self.vertices[2];
552 let e0 = v1 - v0;
553 let e1 = v2 - v0;
554 let vp = *pt - v0;
555
556 let d00 = Vector3::dot(&e0, &e0);
557 let d01 = Vector3::dot(&e0, &e1);
558 let d11 = Vector3::dot(&e1, &e1);
559 let d20 = Vector3::dot(&vp, &e0);
560 let d21 = Vector3::dot(&vp, &e1);
561 let denom = d00 * d11 - d01 * d01;
562 let v = (d11 * d20 - d01 * d21) / denom;
563 let w = (d00 * d21 - d01 * d20) / denom;
564 let u = <T as One>::one() - v - w;
565 Vector3::new(u, v, w)
566 }
567}
568
569#[repr(C)]
573#[derive(Clone, Copy, Default)]
574pub struct Plane<T: Scalar> {
575 a: T,
576 b: T,
577 c: T,
578 d: T,
579}
580
581impl<T: Scalar> Plane<T> {
582 pub fn normal(&self) -> Vector3<T> {
584 Vector3::new(self.a, self.b, self.c)
585 }
586 pub fn constant(&self) -> T {
588 self.d
589 }
590}
591
592impl<T: FloatScalar> Plane<T> {
593 pub fn new(n: &Vector3<T>, p: &Vector3<T>) -> Self {
599 Self::try_new(n, p, T::epsilon()).expect("plane normal must be non-zero")
600 }
601
602 pub fn try_new(n: &Vector3<T>, p: &Vector3<T>, epsilon: T) -> Option<Self> {
606 let norm = n.try_normalize(epsilon)?;
607 let d = Vector3::dot(&norm, p);
608 Some(Self {
609 a: norm.x,
610 b: norm.y,
611 c: norm.z,
612 d: -d,
613 })
614 }
615
616 pub fn from_tri(v0: &Vector3<T>, v1: &Vector3<T>, v2: &Vector3<T>) -> Self {
622 Self::try_from_tri(v0, v1, v2, T::epsilon()).expect("triangle must define a plane")
623 }
624
625 pub fn try_from_tri(
629 v0: &Vector3<T>,
630 v1: &Vector3<T>,
631 v2: &Vector3<T>,
632 epsilon: T,
633 ) -> Option<Self> {
634 let n = try_tri_normal(v0, v1, v2, epsilon)?;
635 Self::try_new(&n, v0, epsilon)
636 }
637 pub fn from_quad(v0: &Vector3<T>, v1: &Vector3<T>, v2: &Vector3<T>, v3: &Vector3<T>) -> Self {
647 Self::try_from_quad(v0, v1, v2, v3, T::epsilon()).expect("quad must define a plane")
648 }
649
650 pub fn try_from_quad(
659 v0: &Vector3<T>,
660 v1: &Vector3<T>,
661 v2: &Vector3<T>,
662 v3: &Vector3<T>,
663 epsilon: T,
664 ) -> Option<Self> {
665 let n = try_quad_normal(v0, v1, v2, v3, epsilon)?;
666 let c = (*v0 + *v1 + *v2 + *v3) * T::quarter();
667 Self::try_new(&n, &c, epsilon)
668 }
669
670 pub fn intersect_ray(&self, r: &Ray<T, Vector3<T>>, epsilon: T) -> Option<Vector3<T>> {
672 r.intersect_plane(self, epsilon)
673 }
674
675 pub fn intersect_line(
679 &self,
680 line: &Line<T, Vector3<T>>,
681 epsilon: T,
682 ) -> Option<(T, Vector3<T>)> {
683 let s = line.p;
684 let dir = line.d;
685 let n = self.normal();
686
687 let denom = Vector3::dot(&n, &dir);
688 if denom.tabs() < epsilon {
689 None
690 } else {
691 let t = -(self.constant() + Vector3::dot(&n, &s)) / denom;
692 Some((t, dir * t + s))
693 }
694 }
695}
696
697#[repr(C)]
701#[derive(Clone, Copy, Default)]
702pub struct ParametricPlane<T: Scalar> {
703 pub center: Vector3<T>,
705 pub x_axis: Vector3<T>,
707 pub y_axis: Vector3<T>,
709}
710
711impl<T: FloatScalar> ParametricPlane<T> {
712 pub fn new(center: &Vector3<T>, x_axis: &Vector3<T>, y_axis: &Vector3<T>) -> Self {
714 Self {
715 center: *center,
716 x_axis: *x_axis,
717 y_axis: *y_axis,
718 }
719 }
720
721 pub fn plane(&self) -> Plane<T> {
723 self.try_plane(T::epsilon())
724 .expect("parametric plane axes must span a plane")
725 }
726
727 pub fn try_plane(&self, epsilon: T) -> Option<Plane<T>> {
731 let normal = self.try_normal(epsilon)?;
732 Plane::try_new(&normal, &self.center, epsilon)
733 }
734
735 pub fn normal(&self) -> Vector3<T> {
737 self.try_normal(T::epsilon())
738 .expect("parametric plane axes must span a plane")
739 }
740
741 pub fn try_normal(&self, epsilon: T) -> Option<Vector3<T>> {
745 Vector3::cross(&self.x_axis, &self.y_axis).try_normalize(epsilon)
746 }
747
748 pub fn intersect_ray(&self, r: &Ray<T, Vector3<T>>, epsilon: T) -> Option<Vector3<T>> {
750 let plane = self.try_plane(epsilon)?;
751 r.intersect_plane(&plane, epsilon)
752 }
753
754 pub fn intersect_line(
756 &self,
757 line: &Line<T, Vector3<T>>,
758 epsilon: T,
759 ) -> Option<(T, Vector3<T>)> {
760 let plane = self.try_plane(epsilon)?;
761 plane.intersect_line(line, epsilon)
762 }
763
764 pub fn project(&self, v: &Vector3<T>) -> Vector2<T> {
771 let p = *v - self.center;
772 let g00 = Vector3::dot(&self.x_axis, &self.x_axis);
773 let g01 = Vector3::dot(&self.x_axis, &self.y_axis);
774 let g11 = Vector3::dot(&self.y_axis, &self.y_axis);
775 let rhs0 = Vector3::dot(&p, &self.x_axis);
776 let rhs1 = Vector3::dot(&p, &self.y_axis);
777 let det = g00 * g11 - g01 * g01;
778
779 let x_coord = (rhs0 * g11 - rhs1 * g01) / det;
780 let y_coord = (rhs1 * g00 - rhs0 * g01) / det;
781 Vector2::new(x_coord, y_coord)
782 }
783}
784
785pub fn tri_normal<T: FloatScalar>(v0: &Vector3<T>, v1: &Vector3<T>, v2: &Vector3<T>) -> Vector3<T> {
789 try_tri_normal(v0, v1, v2, T::epsilon()).expect("triangle must be non-degenerate")
790}
791
792pub fn try_tri_normal<T: FloatScalar>(
796 v0: &Vector3<T>,
797 v1: &Vector3<T>,
798 v2: &Vector3<T>,
799 epsilon: T,
800) -> Option<Vector3<T>> {
801 let v10 = *v1 - *v0;
802 let v20 = *v2 - *v0;
803 Vector3::cross(&v10, &v20).try_normalize(epsilon)
804}
805
806pub fn quad_normal<T: FloatScalar>(
813 v0: &Vector3<T>,
814 v1: &Vector3<T>,
815 v2: &Vector3<T>,
816 v3: &Vector3<T>,
817) -> Vector3<T> {
818 try_quad_normal(v0, v1, v2, v3, T::epsilon()).expect("quad must be non-degenerate")
819}
820
821pub fn try_quad_normal<T: FloatScalar>(
825 v0: &Vector3<T>,
826 v1: &Vector3<T>,
827 v2: &Vector3<T>,
828 v3: &Vector3<T>,
829 epsilon: T,
830) -> Option<Vector3<T>> {
831 let v20 = *v2 - *v0;
832 let v31 = *v3 - *v1;
833 Vector3::cross(&v20, &v31).try_normalize(epsilon)
834}
835
836#[cfg(test)]
837mod tests {
838 use super::*;
839 #[test]
840 pub fn test_barycentric() {
841 let v0 = Vector3::new(0.0, 0.0, 0.0);
842 let v1 = Vector3::new(0.0, 1.0, 0.0);
843 let v2 = Vector3::new(0.0, 0.0, 1.0);
844
845 let tri = Tri3::new([v0, v1, v2]);
846 let pp0 = tri.barycentric_coordinates(&v0);
847 assert!(f32::abs(pp0.x - 1.0) < 0.01);
848 assert!(f32::abs(pp0.y) < 0.01);
849 assert!(f32::abs(pp0.z) < 0.01);
850
851 let pp1 = tri.barycentric_coordinates(&v1);
852 assert!(f32::abs(pp1.x) < 0.01);
853 assert!(f32::abs(pp1.y - 1.0) < 0.01);
854 assert!(f32::abs(pp1.z) < 0.01);
855
856 let pp2 = tri.barycentric_coordinates(&v2);
857 assert!(f32::abs(pp2.x) < 0.01);
858 assert!(f32::abs(pp2.y) < 0.01);
859 assert!(f32::abs(pp2.z - 1.0) < 0.01);
860 }
861
862 #[test]
863 pub fn test_barycentric_translated() {
864 let v0 = Vector3::new(1.0, 2.0, 3.0);
866 let v1 = Vector3::new(4.0, 2.0, 3.0);
867 let v2 = Vector3::new(1.0, 5.0, 3.0);
868
869 let tri = Tri3::new([v0, v1, v2]);
870
871 let pp0 = tri.barycentric_coordinates(&v0);
873 assert!(f32::abs(pp0.x - 1.0) < 0.001);
874 assert!(f32::abs(pp0.y) < 0.001);
875 assert!(f32::abs(pp0.z) < 0.001);
876
877 let pp1 = tri.barycentric_coordinates(&v1);
878 assert!(f32::abs(pp1.x) < 0.001);
879 assert!(f32::abs(pp1.y - 1.0) < 0.001);
880 assert!(f32::abs(pp1.z) < 0.001);
881
882 let pp2 = tri.barycentric_coordinates(&v2);
883 assert!(f32::abs(pp2.x) < 0.001);
884 assert!(f32::abs(pp2.y) < 0.001);
885 assert!(f32::abs(pp2.z - 1.0) < 0.001);
886
887 let center = (v0 + v1 + v2) / 3.0;
889 let pp_center = tri.barycentric_coordinates(¢er);
890 assert!(f32::abs(pp_center.x - 1.0 / 3.0) < 0.001);
891 assert!(f32::abs(pp_center.y - 1.0 / 3.0) < 0.001);
892 assert!(f32::abs(pp_center.z - 1.0 / 3.0) < 0.001);
893
894 assert!(f32::abs((pp_center.x + pp_center.y + pp_center.z) - 1.0) < 0.001);
896 }
897
898 #[test]
899 pub fn test_barycentric_edge_midpoints() {
900 let v0 = Vector3::new(0.0, 0.0, 0.0);
901 let v1 = Vector3::new(2.0, 0.0, 0.0);
902 let v2 = Vector3::new(0.0, 2.0, 0.0);
903
904 let tri = Tri3::new([v0, v1, v2]);
905
906 let mid01 = (v0 + v1) / 2.0;
908 let pp_mid01 = tri.barycentric_coordinates(&mid01);
909 assert!(f32::abs(pp_mid01.x - 0.5) < 0.001);
910 assert!(f32::abs(pp_mid01.y - 0.5) < 0.001);
911 assert!(f32::abs(pp_mid01.z) < 0.001);
912
913 let mid02 = (v0 + v2) / 2.0;
915 let pp_mid02 = tri.barycentric_coordinates(&mid02);
916 assert!(f32::abs(pp_mid02.x - 0.5) < 0.001);
917 assert!(f32::abs(pp_mid02.y) < 0.001);
918 assert!(f32::abs(pp_mid02.z - 0.5) < 0.001);
919
920 let mid12 = (v1 + v2) / 2.0;
922 let pp_mid12 = tri.barycentric_coordinates(&mid12);
923 assert!(f32::abs(pp_mid12.x) < 0.001);
924 assert!(f32::abs(pp_mid12.y - 0.5) < 0.001);
925 assert!(f32::abs(pp_mid12.z - 0.5) < 0.001);
926 }
927
928 #[test]
929 pub fn test_barycentric_degenerate_triangle() {
930 let v0 = Vector3::new(0.0f32, 0.0, 0.0);
931 let v1 = Vector3::new(1.0f32, 0.0, 0.0);
932 let v2 = Vector3::new(2.0f32, 0.0, 0.0);
933
934 let tri = Tri3::new([v0, v1, v2]);
935 let test_point = Vector3::new(0.5f32, 0.0, 0.0);
936 let bary = tri.barycentric_coordinates(&test_point);
937 assert!(!bary.x.is_finite());
938 assert!(!bary.y.is_finite());
939 assert!(!bary.z.is_finite());
940 }
941
942 #[test]
943 pub fn test_barycentric_interpolation() {
944 let v0 = Vector3::new(1.0, 0.0, 0.0);
946 let v1 = Vector3::new(0.0, 1.0, 0.0);
947 let v2 = Vector3::new(0.0, 0.0, 1.0);
948
949 let tri = Tri3::new([v0, v1, v2]);
950
951 let test_point = Vector3::new(0.2, 0.3, 0.5);
953 let bary = tri.barycentric_coordinates(&test_point);
954
955 let reconstructed = v0 * bary.x + v1 * bary.y + v2 * bary.z;
957
958 assert!(f32::abs(reconstructed.x - test_point.x) < 0.001);
959 assert!(f32::abs(reconstructed.y - test_point.y) < 0.001);
960 assert!(f32::abs(reconstructed.z - test_point.z) < 0.001);
961 }
962
963 #[test]
964 pub fn test_box3_overlap() {
965 let a = Box3::new(&Vector3::new(0.0, 0.0, 0.0), &Vector3::new(1.0, 1.0, 1.0));
966 let b = Box3::new(&Vector3::new(0.5, 0.5, 0.5), &Vector3::new(1.5, 1.5, 1.5));
967 assert!(a.overlap(&b));
968
969 let c = Box3::new(&Vector3::new(2.0, 0.0, 0.0), &Vector3::new(3.0, 1.0, 1.0));
970 assert!(!a.overlap(&c));
971
972 let d = Box3::new(&Vector3::new(0.0, 2.0, 0.0), &Vector3::new(1.0, 3.0, 1.0));
973 assert!(!a.overlap(&d));
974
975 let e = Box3::new(&Vector3::new(0.0, 0.0, 2.0), &Vector3::new(1.0, 1.0, 3.0));
976 assert!(!a.overlap(&e));
977
978 let f = Box3::new(&Vector3::new(1.0, 0.0, 0.0), &Vector3::new(2.0, 1.0, 1.0));
979 assert!(a.overlap(&f));
980 }
981
982 #[test]
983 fn test_line_new_zero_direction() {
984 let p = Vector3::new(0.0f32, 0.0, 0.0);
985 let d = Vector3::new(0.0f32, 0.0, 0.0);
986 assert!(Line::new(&p, &d, EPS_F32).is_none());
987 }
988
989 #[test]
990 fn test_line_from_start_end_zero_direction() {
991 let p = Vector3::new(1.0f32, 2.0, 3.0);
992 assert!(Line::from_start_end(&p, &p, EPS_F32).is_none());
993 }
994
995 #[test]
996 fn test_line_closest_point_valid() {
997 let p = Vector3::new(0.0f32, 0.0, 0.0);
998 let d = Vector3::new(1.0f32, 0.0, 0.0);
999 let line = Line::new(&p, &d, EPS_F32).expect("line should be valid");
1000 let target = Vector3::new(2.0f32, 1.0, 0.0);
1001 let (t, closest) = line
1002 .closest_point_on_line(&target, EPS_F32)
1003 .expect("closest point should exist");
1004 assert!((t - 2.0).abs() < 0.001);
1005 assert!((closest.x - 2.0).abs() < 0.001);
1006 assert!(closest.y.abs() < 0.001);
1007 assert!(closest.z.abs() < 0.001);
1008 }
1009
1010 #[test]
1011 fn test_line_normalize_zero_direction() {
1012 let line = Line {
1013 p: Vector3::new(0.0f32, 0.0, 0.0),
1014 d: Vector3::new(0.0f32, 0.0, 0.0),
1015 t: core::marker::PhantomData,
1016 };
1017 assert!(line.normalize(EPS_F32).is_none());
1018 }
1019
1020 #[test]
1021 fn test_line_normalize_valid_direction() {
1022 let p = Vector3::new(0.0f32, 0.0, 0.0);
1023 let d = Vector3::new(2.0f32, 0.0, 0.0);
1024 let line = Line::new(&p, &d, EPS_F32).expect("line should be valid");
1025 let norm = line.normalize(EPS_F32).expect("normalize should succeed");
1026 assert!((norm.d.length() - 1.0).abs() < 0.001);
1027 }
1028
1029 #[test]
1030 fn test_segment_distance_zero_length() {
1031 let p = Vector3::new(0.0f32, 0.0, 0.0);
1032 let seg = Segment::new(&p, &p);
1033 let target = Vector3::new(1.0f32, 0.0, 0.0);
1034 assert!(seg.distance(&target, EPS_F32).is_none());
1035 assert!(seg.closest_point_on_segment(&target, EPS_F32).is_none());
1036 }
1037
1038 #[test]
1039 fn test_ray_new_zero_direction() {
1040 let p = Vector3::new(0.0f32, 0.0, 0.0);
1041 let d = Vector3::new(0.0f32, 0.0, 0.0);
1042 assert!(Ray::new(&p, &d, EPS_F32).is_none());
1043 }
1044
1045 #[test]
1046 fn test_sphere_new_abs_radius() {
1047 let sphere = Sphere3::new(Vector3::new(0.0f32, 0.0, 0.0), -2.5);
1048 assert!((sphere.radius - 2.5).abs() < 0.001);
1049 }
1050
1051 #[test]
1052 fn test_shortest_segment_parallel_lines() {
1053 let p0 = Vector3::new(0.0f32, 0.0, 0.0);
1054 let p1 = Vector3::new(0.0f32, 1.0, 0.0);
1055 let d = Vector3::new(1.0f32, 0.0, 0.0);
1056 let l0 = Line::new(&p0, &d, EPS_F32).expect("line should be valid");
1057 let l1 = Line::new(&p1, &d, EPS_F32).expect("line should be valid");
1058 assert!(shortest_segment3d_between_lines3d(&l0, &l1, EPS_F32).is_none());
1059 }
1060
1061 #[test]
1062 fn test_ray_intersect_plane_parallel() {
1063 let ray = Ray::new(
1064 &Vector3::new(0.0f32, 0.0, 0.0),
1065 &Vector3::new(1.0, 0.0, 0.0),
1066 EPS_F32,
1067 )
1068 .expect("ray should be valid");
1069 let plane = Plane::new(
1070 &Vector3::new(0.0f32, 1.0, 0.0),
1071 &Vector3::new(0.0, 0.0, 0.0),
1072 );
1073 assert!(ray.intersect_plane(&plane, EPS_F32).is_none());
1074 assert!(plane.intersect_ray(&ray, EPS_F32).is_none());
1075 }
1076
1077 #[test]
1078 fn test_ray_intersect_plane_hit() {
1079 let ray = Ray::new(
1080 &Vector3::new(0.0f32, -1.0, 0.0),
1081 &Vector3::new(0.0, 1.0, 0.0),
1082 EPS_F32,
1083 )
1084 .expect("ray should be valid");
1085 let plane = Plane::new(
1086 &Vector3::new(0.0f32, 1.0, 0.0),
1087 &Vector3::new(0.0, 0.0, 0.0),
1088 );
1089 let hit = ray.intersect_plane(&plane, EPS_F32).expect("should hit");
1090 assert!(hit.y.abs() < 0.001);
1091 }
1092
1093 #[test]
1094 fn test_plane_try_new_zero_normal_none() {
1095 let plane = Plane::try_new(
1096 &Vector3::new(0.0f32, 0.0, 0.0),
1097 &Vector3::new(0.0, 0.0, 0.0),
1098 EPS_F32,
1099 );
1100 assert!(plane.is_none());
1101 }
1102
1103 #[test]
1104 fn test_box3_center_extent_subdivide() {
1105 let b = Box3::new(
1106 &Vector3::new(0.0f32, 0.0, 0.0),
1107 &Vector3::new(2.0, 2.0, 2.0),
1108 );
1109 let center = b.center();
1110 let extent = b.extent();
1111 assert!((center.x - 1.0).abs() < 0.001);
1112 assert!((center.y - 1.0).abs() < 0.001);
1113 assert!((center.z - 1.0).abs() < 0.001);
1114 assert!((extent.x - 1.0).abs() < 0.001);
1115 assert!((extent.y - 1.0).abs() < 0.001);
1116 assert!((extent.z - 1.0).abs() < 0.001);
1117
1118 let subs = b.subdivide();
1119 assert_eq!(subs.len(), 8);
1120 for sub in subs.iter() {
1121 assert!(sub.min.x >= 0.0 && sub.min.y >= 0.0 && sub.min.z >= 0.0);
1122 assert!(sub.max.x <= 2.0 && sub.max.y <= 2.0 && sub.max.z <= 2.0);
1123 }
1124 }
1125
1126 #[test]
1127 fn test_parametric_plane_project() {
1128 let plane = ParametricPlane::new(
1129 &Vector3::new(1.0f32, 2.0, 3.0),
1130 &Vector3::new(1.0, 0.0, 0.0),
1131 &Vector3::new(0.0, 1.0, 0.0),
1132 );
1133 let point = Vector3::new(3.0f32, 6.0, 3.0);
1134 let uv = plane.project(&point);
1135 assert!((uv.x - 2.0).abs() < 0.001);
1136 assert!((uv.y - 4.0).abs() < 0.001);
1137 }
1138
1139 #[test]
1140 fn test_parametric_plane_project_non_orthogonal_axes() {
1141 let plane = ParametricPlane::new(
1142 &Vector3::new(0.0f32, 0.0, 0.0),
1143 &Vector3::new(1.0, 0.0, 0.0),
1144 &Vector3::new(1.0, 1.0, 0.0),
1145 );
1146 let point = Vector3::new(2.0f32, 1.0, 0.0);
1147 let uv = plane.project(&point);
1148 assert!((uv.x - 1.0).abs() < 0.001);
1149 assert!((uv.y - 1.0).abs() < 0.001);
1150 }
1151
1152 #[test]
1153 fn test_parametric_plane_try_normal_parallel_axes_none() {
1154 let plane = ParametricPlane::new(
1155 &Vector3::new(0.0f32, 0.0, 0.0),
1156 &Vector3::new(1.0, 0.0, 0.0),
1157 &Vector3::new(2.0, 0.0, 0.0),
1158 );
1159 assert!(plane.try_normal(EPS_F32).is_none());
1160 assert!(plane.try_plane(EPS_F32).is_none());
1161 }
1162}