1use crate::matrix::*;
56use crate::scalar::*;
57use crate::vector::*;
58use num_traits::{Zero, One};
59
60#[repr(C)]
62#[derive(Debug, Clone, Copy, Default)]
63pub struct Dimension<T: Scalar> {
64 pub width: T,
66 pub height: T,
68}
69
70impl<T: Scalar> Dimension<T> {
71 pub fn new(width: T, height: T) -> Self {
73 Self { width, height }
74 }
75}
76
77#[repr(C)]
81#[derive(Debug, Clone, Copy, Default)]
82pub struct Rect<T: Scalar> {
83 pub x: T,
85 pub y: T,
87 pub width: T,
89 pub height: T,
91}
92
93impl<T: Scalar> Rect<T> {
94 pub fn new(x: T, y: T, width: T, height: T) -> Self {
96 Self {
97 x,
98 y,
99 width,
100 height,
101 }
102 }
103 pub fn from(min_vec: &Vector2<T>, max_vec: &Vector2<T>) -> Self {
107 let min_x = T::min(min_vec.x, max_vec.x);
108 let min_y = T::min(min_vec.y, max_vec.y);
109 let max_x = T::max(min_vec.x, max_vec.x);
110 let max_y = T::max(min_vec.y, max_vec.y);
111 Self {
112 x: min_x,
113 y: min_y,
114 width: max_x - min_x,
115 height: max_y - min_y,
116 }
117 }
118
119 pub fn min(&self) -> Vector2<T> {
121 Vector2::new(self.x, self.y)
122 }
123 pub fn max(&self) -> Vector2<T> {
125 Vector2::new(self.x + self.width, self.y + self.height)
126 }
127 pub fn intersect(&self, other: &Self) -> Option<Self> {
131 let smx = self.max();
132 let smn = self.min();
133 let omx = other.max();
134 let omn = other.min();
135
136 if smx.x < omn.x || smx.y < omn.y || smn.x > omx.x || smn.y > omx.y {
137 return None;
138 }
139
140 let min_vec = Vector2::max(&self.min(), &other.min());
141 let max_vec = Vector2::min(&self.max(), &other.max());
142 Some(Self::from(&min_vec, &max_vec))
143 }
144
145 pub fn contains(&self, p: &Vector2<T>) -> bool {
147 p.x >= self.x && p.y >= self.y && p.x <= self.x + self.width && p.y <= self.y + self.height
148 }
149}
150
151#[repr(C)]
155#[derive(Debug, Clone, Copy, Default)]
156pub struct Box3<T: Scalar> {
157 pub min: Vector3<T>,
159 pub max: Vector3<T>,
161}
162
163impl<T: Scalar> Box3<T> {
164 pub fn new(v0: &Vector3<T>, v1: &Vector3<T>) -> Self {
168 Self {
169 min: Vector3::min(v0, v1),
170 max: Vector3::max(v0, v1),
171 }
172 }
173 pub fn overlap(&self, other: &Self) -> bool {
175 if self.max.x < other.min.x {
176 return false;
177 }
178 if self.max.y < other.min.y {
179 return false;
180 }
181 if self.max.z < other.min.z {
182 return false;
183 }
184
185 if self.min.x > other.max.x {
186 return false;
187 }
188 if self.min.y > other.max.y {
189 return false;
190 }
191 if self.min.z > other.max.z {
192 return false;
193 }
194 return true;
195 }
196
197 pub fn add(&self, p: &Vector3<T>) -> Self {
199 Self {
200 min: Vector3::min(&p, &self.min),
201 max: Vector3::max(&p, &self.max),
202 }
203 }
204}
205
206impl<T: FloatScalar> Box3<T> {
207 pub fn center(&self) -> Vector3<T> {
209 (self.max + self.min) * T::half()
210 }
211 pub fn extent(&self) -> Vector3<T> {
213 self.max - self.center()
214 }
215
216 pub fn subdivide(&self) -> [Self; 8] {
220 let cube_table: [Vector3<i32>; 8] = [
221 Vector3::new(0, 1, 0),
222 Vector3::new(1, 1, 0),
223 Vector3::new(1, 1, 1),
224 Vector3::new(0, 1, 1),
225 Vector3::new(0, 0, 0),
226 Vector3::new(1, 0, 0),
227 Vector3::new(1, 0, 1),
228 Vector3::new(0, 0, 1),
229 ];
230
231 let ps: [Vector3<T>; 2] = [self.min, self.max];
232 let mut vs = [Vector3::zero(); 8];
233 for i in 0..8 {
234 vs[i] = Vector3::new(
235 ps[cube_table[i].x as usize].x,
236 ps[cube_table[i].y as usize].y,
237 ps[cube_table[i].z as usize].z,
238 );
239 }
240
241 let c = self.center();
242 let mut out = [Box3 {
243 min: Vector3::zero(),
244 max: Vector3::zero(),
245 }; 8];
246 for i in 0..8 {
247 out[i] = Self::new(&Vector3::min(&c, &vs[i]), &Vector3::max(&c, &vs[i]));
248 }
249 out
250 }
251}
252
253#[repr(C)]
257#[derive(Debug, Clone, Copy, Default)]
258pub struct Line<T: Scalar, V: Vector<T>> {
259 pub p: V,
261 pub d: V,
263 t: core::marker::PhantomData<T>,
264}
265
266impl<T: Scalar, V: Vector<T>> Line<T, V> {
267 pub fn new(p: &V, d: &V, epsilon: T) -> Option<Self> {
271 let d_ss = V::dot(d, d);
272 if d_ss <= epsilon * epsilon {
273 return None;
274 }
275 Some(Self {
276 p: *p,
277 d: *d,
278 t: core::marker::PhantomData,
279 })
280 }
281 pub fn from_start_end(s: &V, e: &V, epsilon: T) -> Option<Self> {
287 let dir = *e - *s;
288 Self::new(s, &dir, epsilon)
289 }
290 pub fn closest_point_on_line(&self, p: &V, epsilon: T) -> Option<(T, V)> {
298 let p_dir = *p - self.p;
299
300 let d_sp = V::dot(&self.d, &p_dir);
301 let d_ss = V::dot(&self.d, &self.d);
302
303 if d_ss <= epsilon * epsilon {
304 return None;
305 }
306
307 let t = d_sp / d_ss;
308
309 Some((t, self.p + self.d * t))
310 }
311}
312
313impl<T: FloatScalar, V: FloatVector<T>> Line<T, V> {
314 pub fn normalize(&self, epsilon: T) -> Option<Self> {
318 let d_ss = V::dot(&self.d, &self.d);
319 if d_ss <= epsilon * epsilon {
320 return None;
321 }
322 let inv_len = <T as One>::one() / d_ss.tsqrt();
323 Some(Self {
324 p: self.p,
325 d: self.d * inv_len,
326 t: core::marker::PhantomData,
327 })
328 }
329}
330
331pub fn shortest_segment3d_between_lines3d<T: FloatScalar>(
335 line0: &Line<T, Vector3<T>>,
336 line1: &Line<T, Vector3<T>>,
337 epsilon: T,
338) -> Option<Segment<T, Vector3<T>>> {
339 let s0 = line0.p;
340 let s1 = line1.p;
341
342 let d1 = line1.d;
343 let d0 = line0.d;
344
345 let eps_sq = epsilon * epsilon;
346 let d0_len_sq = Vector3::dot(&d0, &d0);
347 let d1_len_sq = Vector3::dot(&d1, &d1);
348 if d0_len_sq <= eps_sq || d1_len_sq <= eps_sq {
349 return None;
350 }
351
352 let cross = Vector3::cross(&d1, &d0);
353 let cross_len_sq = Vector3::dot(&cross, &cross);
354 if cross_len_sq <= eps_sq {
355 return None;
356 }
357
358 let normal = Vector3::normalize(&cross);
359 let n0 = Vector3::normalize(&Vector3::cross(&normal, &d0));
360 let n1 = Vector3::normalize(&Vector3::cross(&normal, &d1));
361
362 let plane0 = Plane::new(&n0, &s0);
363 let plane1 = Plane::new(&n1, &s1);
364
365 let p1 = plane0.intersect_line(line1, epsilon);
366 let p0 = plane1.intersect_line(line0, epsilon);
367
368 match (p0, p1) {
369 (Some((_, s)), Some((_, e))) => Some(Segment::new(&s, &e)),
370 _ => None,
371 }
372}
373
374#[repr(C)]
376#[derive(Clone, Copy, Default)]
377pub struct Segment<T: Scalar, V: Vector<T>> {
378 pub s: V,
380 pub e: V,
382 t: core::marker::PhantomData<T>,
383}
384
385impl<T: Scalar, V: Vector<T>> Segment<T, V> {
386 pub fn new(s: &V, e: &V) -> Self {
388 Self {
389 s: *s,
390 e: *e,
391 t: core::marker::PhantomData,
392 }
393 }
394 pub fn closest_point_on_segment(&self, p: &V, epsilon: T) -> Option<(T, V)> {
402 let dir = self.e - self.s;
403 let p_dir = *p - self.s;
404
405 let d_sp = V::dot(&dir, &p_dir);
406 let d_ss = V::dot(&dir, &dir);
407
408 if d_ss <= epsilon * epsilon {
409 return None;
410 }
411
412 if d_sp < <T as Zero>::zero() {
413 return Some((<T as Zero>::zero(), self.s));
414 } else if d_sp > d_ss {
415 return Some((<T as One>::one(), self.e));
416 }
417
418 let t = d_sp / d_ss;
419
420 Some((t, self.s + dir * t))
421 }
422}
423
424impl<T: FloatScalar, V: FloatVector<T>> Segment<T, V> {
425 pub fn distance(&self, p: &V, epsilon: T) -> Option<T> {
429 self.closest_point_on_segment(p, epsilon)
430 .map(|(_, p_on_seg)| V::length(&(p_on_seg - *p)))
431 }
432}
433
434#[repr(C)]
438#[derive(Clone, Copy, Default)]
439pub struct Ray<T: Scalar, V: Vector<T>> {
440 pub start: V,
442 pub direction: V,
444 t: core::marker::PhantomData<T>,
445}
446
447impl<T: FloatScalar, V: FloatVector<T>> Ray<T, V> {
448 pub fn new(start: &V, direction: &V, epsilon: T) -> Option<Self> {
452 let d_ss = V::dot(direction, direction);
453 if d_ss <= epsilon * epsilon {
454 return None;
455 }
456 let inv_len = <T as One>::one() / d_ss.tsqrt();
457 Some(Self {
458 start: *start,
459 direction: *direction * inv_len,
460 t: core::marker::PhantomData,
461 })
462 }
463}
464
465impl<T: Scalar> Ray<T, Vector3<T>> {
466 pub fn intersect_plane(&self, p: &Plane<T>, epsilon: T) -> Option<Vector3<T>> {
473 let n = p.normal();
474 let denom = Vector3::dot(&n, &self.direction);
475 if denom.tabs() <= epsilon {
476 return None;
477 }
478 let t: T = -(p.d + Vector3::dot(&n, &self.start)) / denom;
479 if t < <T as Zero>::zero() {
480 None
481 } else {
482 Some(self.direction * t + self.start)
483 }
484 }
485}
486
487#[repr(C)]
491#[derive(Clone, Copy, Default)]
492pub struct Sphere3<T: FloatScalar> {
493 pub center: Vector3<T>,
495 pub radius: T,
497}
498
499impl<T: FloatScalar> Sphere3<T> {
500 pub fn new(center: Vector3<T>, radius: T) -> Self {
502 Self {
503 center: center,
504 radius: radius,
505 }
506 }
507}
508
509#[repr(C)]
513#[derive(Clone, Copy, Default)]
514pub struct Tri3<T: FloatScalar> {
515 vertices: [Vector3<T>; 3],
516}
517
518impl<T: FloatScalar> Tri3<T> {
519 pub fn new(vertices: [Vector3<T>; 3]) -> Self {
521 Self { vertices: vertices }
522 }
523 pub fn vertices(&self) -> &[Vector3<T>; 3] {
525 &self.vertices
526 }
527
528 pub fn barycentric_coordinates(&self, pt: &Vector3<T>) -> Vector3<T> {
530 let v0 = self.vertices[0];
531 let v1 = self.vertices[1];
532 let v2 = self.vertices[2];
533 let e0 = v1 - v0;
534 let e1 = v2 - v0;
535 let vp = *pt - v0;
536
537 let d00 = Vector3::dot(&e0, &e0);
538 let d01 = Vector3::dot(&e0, &e1);
539 let d11 = Vector3::dot(&e1, &e1);
540 let d20 = Vector3::dot(&vp, &e0);
541 let d21 = Vector3::dot(&vp, &e1);
542 let denom = d00 * d11 - d01 * d01;
543 let v = (d11 * d20 - d01 * d21) / denom;
544 let w = (d00 * d21 - d01 * d20) / denom;
545 let u = <T as One>::one() - v - w;
546 Vector3::new(u, v, w)
547 }
548}
549
550#[repr(C)]
554#[derive(Clone, Copy, Default)]
555pub struct Plane<T: Scalar> {
556 a: T,
557 b: T,
558 c: T,
559 d: T,
560}
561
562impl<T: Scalar> Plane<T> {
563 pub fn normal(&self) -> Vector3<T> {
565 Vector3::new(self.a, self.b, self.c)
566 }
567 pub fn constant(&self) -> T {
569 self.d
570 }
571
572 pub fn intersect_ray(&self, r: &Ray<T, Vector3<T>>, epsilon: T) -> Option<Vector3<T>> {
574 r.intersect_plane(self, epsilon)
575 }
576
577 pub fn intersect_line(
581 &self,
582 line: &Line<T, Vector3<T>>,
583 epsilon: T,
584 ) -> Option<(T, Vector3<T>)> {
585 let s = line.p;
586 let dir = line.d;
587 let n = self.normal();
588
589 let denom = Vector3::dot(&n, &dir);
590 if denom.tabs() < epsilon {
591 None
592 } else {
593 let t = -(self.constant() + Vector3::dot(&n, &s)) / denom;
594 Some((t, dir * t + s))
595 }
596 }
597}
598
599impl<T: FloatScalar> Plane<T> {
600 pub fn new(n: &Vector3<T>, p: &Vector3<T>) -> Self {
602 let norm = Vector3::normalize(n);
603 let d = Vector3::dot(&norm, p);
604 Self {
605 a: norm.x,
606 b: norm.y,
607 c: norm.z,
608 d: -d,
609 }
610 }
611
612 pub fn from_tri(v0: &Vector3<T>, v1: &Vector3<T>, v2: &Vector3<T>) -> Self {
614 let n = tri_normal(v0, v1, v2);
615 Self::new(&n, v0)
616 }
617 pub fn from_quad(v0: &Vector3<T>, v1: &Vector3<T>, v2: &Vector3<T>, v3: &Vector3<T>) -> Self {
619 let n = quad_normal(v0, v1, v2, v3);
620 let c = (*v0 + *v1 + *v2 + *v3) * T::quarter();
621 Self::new(&n, &c)
622 }
623}
624
625#[repr(C)]
629#[derive(Clone, Copy, Default)]
630pub struct ParametricPlane<T: Scalar> {
631 pub center: Vector3<T>,
633 pub x_axis: Vector3<T>,
635 pub y_axis: Vector3<T>,
637}
638
639impl<T: FloatScalar> ParametricPlane<T> {
640 pub fn new(center: &Vector3<T>, x_axis: &Vector3<T>, y_axis: &Vector3<T>) -> Self {
642 Self {
643 center: *center,
644 x_axis: *x_axis,
645 y_axis: *y_axis,
646 }
647 }
648
649 pub fn plane(&self) -> Plane<T> {
651 Plane::new(&self.normal(), &self.center)
652 }
653
654 pub fn normal(&self) -> Vector3<T> {
656 Vector3::cross(&self.x_axis, &self.y_axis).normalize()
657 }
658
659 pub fn intersect_ray(&self, r: &Ray<T, Vector3<T>>, epsilon: T) -> Option<Vector3<T>> {
661 r.intersect_plane(&self.plane(), epsilon)
662 }
663
664 pub fn intersect_line(
666 &self,
667 line: &Line<T, Vector3<T>>,
668 epsilon: T,
669 ) -> Option<(T, Vector3<T>)> {
670 self.plane().intersect_line(line, epsilon)
671 }
672
673 pub fn project(&self, v: &Vector3<T>) -> Vector2<T> {
675 let p = *v - self.center;
676 let x_coord = Vector3::dot(&p, &self.x_axis) / Vector3::dot(&self.x_axis, &self.x_axis);
677 let y_coord = Vector3::dot(&p, &self.y_axis) / Vector3::dot(&self.y_axis, &self.y_axis);
678 Vector2::new(x_coord, y_coord)
679 }
680}
681
682pub fn tri_normal<T: FloatScalar>(v0: &Vector3<T>, v1: &Vector3<T>, v2: &Vector3<T>) -> Vector3<T> {
686 let v10 = *v1 - *v0;
687 let v20 = *v2 - *v0;
688 Vector3::normalize(&Vector3::cross(&v10, &v20))
689}
690
691pub fn quad_normal<T: FloatScalar>(
695 v0: &Vector3<T>,
696 v1: &Vector3<T>,
697 v2: &Vector3<T>,
698 v3: &Vector3<T>,
699) -> Vector3<T> {
700 let v20 = *v2 - *v0;
701 let v31 = *v3 - *v1;
702 Vector3::normalize(&Vector3::cross(&v20, &v31))
703}
704
705#[cfg(test)]
706mod tests {
707 use super::*;
708 #[test]
709 pub fn test_barycentric() {
710 let v0 = Vector3::new(0.0, 0.0, 0.0);
711 let v1 = Vector3::new(0.0, 1.0, 0.0);
712 let v2 = Vector3::new(0.0, 0.0, 1.0);
713
714 let tri = Tri3::new([v0, v1, v2]);
715 let pp0 = tri.barycentric_coordinates(&v0);
716 assert!(f32::abs(pp0.x - 1.0) < 0.01);
717 assert!(f32::abs(pp0.y) < 0.01);
718 assert!(f32::abs(pp0.z) < 0.01);
719
720 let pp1 = tri.barycentric_coordinates(&v1);
721 assert!(f32::abs(pp1.x) < 0.01);
722 assert!(f32::abs(pp1.y - 1.0) < 0.01);
723 assert!(f32::abs(pp1.z) < 0.01);
724
725 let pp2 = tri.barycentric_coordinates(&v2);
726 assert!(f32::abs(pp2.x) < 0.01);
727 assert!(f32::abs(pp2.y) < 0.01);
728 assert!(f32::abs(pp2.z - 1.0) < 0.01);
729 }
730
731 #[test]
732 pub fn test_barycentric_translated() {
733 let v0 = Vector3::new(1.0, 2.0, 3.0);
735 let v1 = Vector3::new(4.0, 2.0, 3.0);
736 let v2 = Vector3::new(1.0, 5.0, 3.0);
737
738 let tri = Tri3::new([v0, v1, v2]);
739
740 let pp0 = tri.barycentric_coordinates(&v0);
742 assert!(f32::abs(pp0.x - 1.0) < 0.001);
743 assert!(f32::abs(pp0.y) < 0.001);
744 assert!(f32::abs(pp0.z) < 0.001);
745
746 let pp1 = tri.barycentric_coordinates(&v1);
747 assert!(f32::abs(pp1.x) < 0.001);
748 assert!(f32::abs(pp1.y - 1.0) < 0.001);
749 assert!(f32::abs(pp1.z) < 0.001);
750
751 let pp2 = tri.barycentric_coordinates(&v2);
752 assert!(f32::abs(pp2.x) < 0.001);
753 assert!(f32::abs(pp2.y) < 0.001);
754 assert!(f32::abs(pp2.z - 1.0) < 0.001);
755
756 let center = (v0 + v1 + v2) / 3.0;
758 let pp_center = tri.barycentric_coordinates(¢er);
759 assert!(f32::abs(pp_center.x - 1.0/3.0) < 0.001);
760 assert!(f32::abs(pp_center.y - 1.0/3.0) < 0.001);
761 assert!(f32::abs(pp_center.z - 1.0/3.0) < 0.001);
762
763 assert!(f32::abs((pp_center.x + pp_center.y + pp_center.z) - 1.0) < 0.001);
765 }
766
767 #[test]
768 pub fn test_barycentric_edge_midpoints() {
769 let v0 = Vector3::new(0.0, 0.0, 0.0);
770 let v1 = Vector3::new(2.0, 0.0, 0.0);
771 let v2 = Vector3::new(0.0, 2.0, 0.0);
772
773 let tri = Tri3::new([v0, v1, v2]);
774
775 let mid01 = (v0 + v1) / 2.0;
777 let pp_mid01 = tri.barycentric_coordinates(&mid01);
778 assert!(f32::abs(pp_mid01.x - 0.5) < 0.001);
779 assert!(f32::abs(pp_mid01.y - 0.5) < 0.001);
780 assert!(f32::abs(pp_mid01.z) < 0.001);
781
782 let mid02 = (v0 + v2) / 2.0;
784 let pp_mid02 = tri.barycentric_coordinates(&mid02);
785 assert!(f32::abs(pp_mid02.x - 0.5) < 0.001);
786 assert!(f32::abs(pp_mid02.y) < 0.001);
787 assert!(f32::abs(pp_mid02.z - 0.5) < 0.001);
788
789 let mid12 = (v1 + v2) / 2.0;
791 let pp_mid12 = tri.barycentric_coordinates(&mid12);
792 assert!(f32::abs(pp_mid12.x) < 0.001);
793 assert!(f32::abs(pp_mid12.y - 0.5) < 0.001);
794 assert!(f32::abs(pp_mid12.z - 0.5) < 0.001);
795 }
796
797 #[test]
798 pub fn test_barycentric_degenerate_triangle() {
799 let v0 = Vector3::new(0.0f32, 0.0, 0.0);
800 let v1 = Vector3::new(1.0f32, 0.0, 0.0);
801 let v2 = Vector3::new(2.0f32, 0.0, 0.0);
802
803 let tri = Tri3::new([v0, v1, v2]);
804 let test_point = Vector3::new(0.5f32, 0.0, 0.0);
805 let bary = tri.barycentric_coordinates(&test_point);
806 assert!(!bary.x.is_finite());
807 assert!(!bary.y.is_finite());
808 assert!(!bary.z.is_finite());
809 }
810
811 #[test]
812 pub fn test_barycentric_interpolation() {
813 let v0 = Vector3::new(1.0, 0.0, 0.0);
815 let v1 = Vector3::new(0.0, 1.0, 0.0);
816 let v2 = Vector3::new(0.0, 0.0, 1.0);
817
818 let tri = Tri3::new([v0, v1, v2]);
819
820 let test_point = Vector3::new(0.2, 0.3, 0.5);
822 let bary = tri.barycentric_coordinates(&test_point);
823
824 let reconstructed = v0 * bary.x + v1 * bary.y + v2 * bary.z;
826
827 assert!(f32::abs(reconstructed.x - test_point.x) < 0.001);
828 assert!(f32::abs(reconstructed.y - test_point.y) < 0.001);
829 assert!(f32::abs(reconstructed.z - test_point.z) < 0.001);
830 }
831
832 #[test]
833 pub fn test_box3_overlap() {
834 let a = Box3::new(
835 &Vector3::new(0.0, 0.0, 0.0),
836 &Vector3::new(1.0, 1.0, 1.0),
837 );
838 let b = Box3::new(
839 &Vector3::new(0.5, 0.5, 0.5),
840 &Vector3::new(1.5, 1.5, 1.5),
841 );
842 assert!(a.overlap(&b));
843
844 let c = Box3::new(
845 &Vector3::new(2.0, 0.0, 0.0),
846 &Vector3::new(3.0, 1.0, 1.0),
847 );
848 assert!(!a.overlap(&c));
849
850 let d = Box3::new(
851 &Vector3::new(0.0, 2.0, 0.0),
852 &Vector3::new(1.0, 3.0, 1.0),
853 );
854 assert!(!a.overlap(&d));
855
856 let e = Box3::new(
857 &Vector3::new(0.0, 0.0, 2.0),
858 &Vector3::new(1.0, 1.0, 3.0),
859 );
860 assert!(!a.overlap(&e));
861
862 let f = Box3::new(
863 &Vector3::new(1.0, 0.0, 0.0),
864 &Vector3::new(2.0, 1.0, 1.0),
865 );
866 assert!(a.overlap(&f));
867 }
868
869 #[test]
870 fn test_line_new_zero_direction() {
871 let p = Vector3::new(0.0f32, 0.0, 0.0);
872 let d = Vector3::new(0.0f32, 0.0, 0.0);
873 assert!(Line::new(&p, &d, EPS_F32).is_none());
874 }
875
876 #[test]
877 fn test_line_from_start_end_zero_direction() {
878 let p = Vector3::new(1.0f32, 2.0, 3.0);
879 assert!(Line::from_start_end(&p, &p, EPS_F32).is_none());
880 }
881
882 #[test]
883 fn test_line_closest_point_valid() {
884 let p = Vector3::new(0.0f32, 0.0, 0.0);
885 let d = Vector3::new(1.0f32, 0.0, 0.0);
886 let line = Line::new(&p, &d, EPS_F32).expect("line should be valid");
887 let target = Vector3::new(2.0f32, 1.0, 0.0);
888 let (t, closest) = line
889 .closest_point_on_line(&target, EPS_F32)
890 .expect("closest point should exist");
891 assert!((t - 2.0).abs() < 0.001);
892 assert!((closest.x - 2.0).abs() < 0.001);
893 assert!(closest.y.abs() < 0.001);
894 assert!(closest.z.abs() < 0.001);
895 }
896
897 #[test]
898 fn test_line_normalize_zero_direction() {
899 let line = Line {
900 p: Vector3::new(0.0f32, 0.0, 0.0),
901 d: Vector3::new(0.0f32, 0.0, 0.0),
902 t: core::marker::PhantomData,
903 };
904 assert!(line.normalize(EPS_F32).is_none());
905 }
906
907 #[test]
908 fn test_line_normalize_valid_direction() {
909 let p = Vector3::new(0.0f32, 0.0, 0.0);
910 let d = Vector3::new(2.0f32, 0.0, 0.0);
911 let line = Line::new(&p, &d, EPS_F32).expect("line should be valid");
912 let norm = line.normalize(EPS_F32).expect("normalize should succeed");
913 assert!((norm.d.length() - 1.0).abs() < 0.001);
914 }
915
916 #[test]
917 fn test_segment_distance_zero_length() {
918 let p = Vector3::new(0.0f32, 0.0, 0.0);
919 let seg = Segment::new(&p, &p);
920 let target = Vector3::new(1.0f32, 0.0, 0.0);
921 assert!(seg.distance(&target, EPS_F32).is_none());
922 assert!(seg.closest_point_on_segment(&target, EPS_F32).is_none());
923 }
924
925 #[test]
926 fn test_ray_new_zero_direction() {
927 let p = Vector3::new(0.0f32, 0.0, 0.0);
928 let d = Vector3::new(0.0f32, 0.0, 0.0);
929 assert!(Ray::new(&p, &d, EPS_F32).is_none());
930 }
931
932 #[test]
933 fn test_shortest_segment_parallel_lines() {
934 let p0 = Vector3::new(0.0f32, 0.0, 0.0);
935 let p1 = Vector3::new(0.0f32, 1.0, 0.0);
936 let d = Vector3::new(1.0f32, 0.0, 0.0);
937 let l0 = Line::new(&p0, &d, EPS_F32).expect("line should be valid");
938 let l1 = Line::new(&p1, &d, EPS_F32).expect("line should be valid");
939 assert!(shortest_segment3d_between_lines3d(&l0, &l1, EPS_F32).is_none());
940 }
941
942 #[test]
943 fn test_ray_intersect_plane_parallel() {
944 let ray = Ray::new(
945 &Vector3::new(0.0f32, 0.0, 0.0),
946 &Vector3::new(1.0, 0.0, 0.0),
947 EPS_F32,
948 )
949 .expect("ray should be valid");
950 let plane = Plane::new(
951 &Vector3::new(0.0f32, 1.0, 0.0),
952 &Vector3::new(0.0, 0.0, 0.0),
953 );
954 assert!(ray.intersect_plane(&plane, EPS_F32).is_none());
955 assert!(plane.intersect_ray(&ray, EPS_F32).is_none());
956 }
957
958 #[test]
959 fn test_ray_intersect_plane_hit() {
960 let ray = Ray::new(
961 &Vector3::new(0.0f32, -1.0, 0.0),
962 &Vector3::new(0.0, 1.0, 0.0),
963 EPS_F32,
964 )
965 .expect("ray should be valid");
966 let plane = Plane::new(
967 &Vector3::new(0.0f32, 1.0, 0.0),
968 &Vector3::new(0.0, 0.0, 0.0),
969 );
970 let hit = ray.intersect_plane(&plane, EPS_F32).expect("should hit");
971 assert!(hit.y.abs() < 0.001);
972 }
973
974 #[test]
975 fn test_box3_center_extent_subdivide() {
976 let b = Box3::new(
977 &Vector3::new(0.0f32, 0.0, 0.0),
978 &Vector3::new(2.0, 2.0, 2.0),
979 );
980 let center = b.center();
981 let extent = b.extent();
982 assert!((center.x - 1.0).abs() < 0.001);
983 assert!((center.y - 1.0).abs() < 0.001);
984 assert!((center.z - 1.0).abs() < 0.001);
985 assert!((extent.x - 1.0).abs() < 0.001);
986 assert!((extent.y - 1.0).abs() < 0.001);
987 assert!((extent.z - 1.0).abs() < 0.001);
988
989 let subs = b.subdivide();
990 assert_eq!(subs.len(), 8);
991 for sub in subs.iter() {
992 assert!(sub.min.x >= 0.0 && sub.min.y >= 0.0 && sub.min.z >= 0.0);
993 assert!(sub.max.x <= 2.0 && sub.max.y <= 2.0 && sub.max.z <= 2.0);
994 }
995 }
996
997 #[test]
998 fn test_parametric_plane_project() {
999 let plane = ParametricPlane::new(
1000 &Vector3::new(1.0f32, 2.0, 3.0),
1001 &Vector3::new(1.0, 0.0, 0.0),
1002 &Vector3::new(0.0, 1.0, 0.0),
1003 );
1004 let point = Vector3::new(3.0f32, 6.0, 3.0);
1005 let uv = plane.project(&point);
1006 assert!((uv.x - 2.0).abs() < 0.001);
1007 assert!((uv.y - 4.0).abs() < 0.001);
1008 }
1009}