math_utils/geometry/primitive/
simplex.rs

1pub use self::simplex2::Simplex2;
2pub use self::simplex3::Simplex3;
3
4/// 2D simplex types
5pub mod simplex2 {
6  #[cfg(feature = "derive_serdes")]
7  use serde::{Deserialize, Serialize};
8
9  use crate::*;
10  use crate::geometry::*;
11
12  /// A $n<3$-simplex in 2-dimensional space.
13  ///
14  /// Individual simplex variants should fail to construct in debug builds when
15  /// points are degenerate.
16  #[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
17  #[derive(Clone, Copy, Debug, PartialEq)]
18  pub enum Simplex2 <S> {
19    Segment  (Segment  <S>),
20    Triangle (Triangle <S>)
21  }
22
23  /// A 1-simplex or line segment in 2D space.
24  ///
25  /// Creation methods should fail with a debug assertion if the points are
26  /// identical.
27  #[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
28  #[derive(Clone, Copy, Debug, PartialEq)]
29  pub struct Segment <S> {
30    a : Point2 <S>,
31    b : Point2 <S>
32  }
33
34  /// A 2-simplex or triangle in 2D space
35  ///
36  /// Creation methods should fail with a debug assertion if the points are
37  /// colinear.
38  #[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
39  #[derive(Clone, Copy, Debug, PartialEq)]
40  pub struct Triangle <S> {
41    a : Point2 <S>,
42    b : Point2 <S>,
43    c : Point2 <S>
44  }
45
46  impl <S : Ring> Segment <S> {
47    /// Panics if the points are identical:
48    ///
49    /// ```should_panic
50    /// # use math_utils::geometry::simplex2::Segment;
51    /// let s = Segment::new ([0.0, 0.0].into(), [0.0, 0.0].into());
52    /// ```
53    pub fn new (
54      a : Point2 <S>,
55      b : Point2 <S>
56    ) -> Self where S : std::fmt::Debug {
57      assert_ne!(a, b);
58      Segment { a, b }
59    }
60    /// Debug panic if the points are identical:
61    ///
62    /// ```should_panic
63    /// # use math_utils::geometry::simplex2::Segment;
64    /// let s = Segment::unchecked ([0.0, 0.0].into(), [0.0, 0.0].into());
65    /// ```
66    pub fn unchecked (
67      a : Point2 <S>,
68      b : Point2 <S>
69    ) -> Self where S : std::fmt::Debug {
70      debug_assert_ne!(a, b);
71      Segment { a, b }
72    }
73    #[inline]
74    pub fn numcast <T> (self) -> Option <Segment <T>> where
75      S : num_traits::NumCast,
76      T : num_traits::NumCast
77    {
78      Some (Segment {
79        a: self.a.numcast()?,
80        b: self.b.numcast()?
81      })
82    }
83    #[inline]
84    pub fn point_a (&self) -> &Point2 <S> {
85      &self.a
86    }
87    #[inline]
88    pub fn point_b (&self) -> &Point2 <S> {
89      &self.b
90    }
91    #[inline]
92    pub fn length (&self) -> S where S : Field + Sqrt {
93      self.vector().norm()
94    }
95    #[inline]
96    pub fn length2 (&self) -> S {
97      self.vector().self_dot()
98    }
99    /// Returns `point_b() - point_a()`
100    #[inline]
101    pub fn vector (&self) -> Vector2 <S> {
102      self.b - self.a
103    }
104    #[inline]
105    pub fn aabb2 (&self) -> Aabb2 <S> where S : std::fmt::Debug {
106      Aabb2::from_points (self.a, self.b)
107    }
108    #[inline]
109    pub fn line2 (&self) -> Line2 <S> where S : Real {
110      Line2::new (self.a, Unit2::normalize (self.vector()))
111    }
112    #[inline]
113    pub fn intersect_aabb (&self, aabb : &Aabb2 <S>)
114      -> Option <((S, Point2 <S>), (S, Point2 <S>))>
115    where
116      S : Real + std::fmt::Debug
117    {
118      intersect::continuous_segment2_aabb2 (self, aabb)
119    }
120    #[inline]
121    pub fn intersect_sphere (&self, sphere : &Sphere2 <S>)
122      -> Option <((S, Point2 <S>), (S, Point2 <S>))>
123    where
124      S : Real + std::fmt::Debug
125    {
126      intersect::continuous_segment2_sphere2 (self, sphere)
127    }
128  }
129  impl <S : Field> Default for Segment <S> {
130    /// A default simplex is arbitrarily chosen to be the simplex from -1.0 to 1.0
131    /// lying on the X axis:
132    ///
133    /// ```
134    /// # use math_utils::geometry::simplex2::Segment;
135    /// assert_eq!(
136    ///   Segment::default(),
137    ///   Segment::new ([-1.0, 0.0].into(), [1.0, 0.0].into())
138    /// );
139    /// ```
140    fn default() -> Self {
141      Segment {
142        a: [-S::one(), S::zero()].into(),
143        b: [ S::one(), S::zero()].into()
144      }
145    }
146  }
147
148  impl <S : Field> Triangle <S> {
149    /// Panics if the points are colinear:
150    ///
151    /// ```should_panic
152    /// # use math_utils::geometry::simplex2::Triangle;
153    /// let s = Triangle::new (
154    ///   [-1.0, -1.0].into(),
155    ///   [ 0.0,  0.0].into(),
156    ///   [ 1.0,  1.0].into());
157    /// ```
158    pub fn new (
159      a : Point2 <S>,
160      b : Point2 <S>,
161      c : Point2 <S>
162    ) -> Self where S : approx::RelativeEq + std::fmt::Debug {
163      debug_assert_ne!(a, b);
164      debug_assert_ne!(a, c);
165      debug_assert_ne!(b, c);
166      assert!(!colinear_2d (&a, &b, &c));
167      Triangle { a, b, c }
168    }
169    /// Debug panic if the points are colinear:
170    ///
171    /// ```should_panic
172    /// # use math_utils::geometry::simplex2::Triangle;
173    /// let s = Triangle::unchecked (
174    ///   [-1.0, -1.0].into(),
175    ///   [ 0.0,  0.0].into(),
176    ///   [ 1.0,  1.0].into());
177    /// ```
178    pub fn unchecked (
179      a : Point2 <S>,
180      b : Point2 <S>,
181      c : Point2 <S>
182    ) -> Self where S : approx::RelativeEq + std::fmt::Debug {
183      debug_assert_ne!(a, b);
184      debug_assert_ne!(a, c);
185      debug_assert_ne!(b, c);
186      debug_assert!(!colinear_2d (&a, &b, &c));
187      Triangle { a, b, c }
188    }
189    #[inline]
190    pub fn point_a (&self) -> &Point2 <S> {
191      &self.a
192    }
193    #[inline]
194    pub fn point_b (&self) -> &Point2 <S> {
195      &self.b
196    }
197    #[inline]
198    pub fn point_c (&self) -> &Point2 <S> {
199      &self.c
200    }
201  }
202  impl <S : Field + Sqrt> Default for Triangle <S> {
203    /// A default triangle is arbitrarily chosen to be the equilateral triangle
204    /// with point at 1.0 on the Y axis:
205    ///
206    /// ```
207    /// # use math_utils::approx;
208    /// # use math_utils::geometry::simplex2::Triangle;
209    /// use std::f64::consts::FRAC_1_SQRT_2;
210    /// let s = Triangle::default();
211    /// let t = Triangle::new (
212    ///   [           0.0,            1.0].into(),
213    ///   [-FRAC_1_SQRT_2, -FRAC_1_SQRT_2].into(),
214    ///   [ FRAC_1_SQRT_2, -FRAC_1_SQRT_2].into()
215    /// );
216    /// approx::assert_relative_eq!(s.point_a(), t.point_a());
217    /// approx::assert_relative_eq!(s.point_b(), t.point_b());
218    /// approx::assert_relative_eq!(s.point_c(), t.point_c());
219    /// ```
220    fn default() -> Self {
221      let frac_1_sqrt_2 = S::one() / (S::one() + S::one()).sqrt();
222      Triangle {
223        a: [     S::zero(),       S::one()].into(),
224        b: [-frac_1_sqrt_2, -frac_1_sqrt_2].into(),
225        c: [ frac_1_sqrt_2, -frac_1_sqrt_2].into()
226      }
227    }
228  }
229}
230
231/// 3D simplex types
232pub mod simplex3 {
233  #[cfg(feature = "derive_serdes")]
234  use serde::{Deserialize, Serialize};
235
236  use crate::*;
237  use crate::geometry::*;
238  /// A $n<4$-simplex in 3-dimensional space.
239  ///
240  /// Individual simplex variants should fail to construct in debug builds when
241  /// points are degenerate.
242  #[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
243  #[derive(Clone, Copy, Debug, PartialEq)]
244  pub enum Simplex3 <S> {
245    Segment     (Segment     <S>),
246    Triangle    (Triangle    <S>),
247    Tetrahedron (Tetrahedron <S>)
248  }
249
250  /// A 1-simplex or line segment in 3D space.
251  ///
252  /// Creation methods should fail with a debug assertion if the points are
253  /// identical.
254  #[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
255  #[derive(Clone, Copy, Debug, PartialEq)]
256  pub struct Segment <S> {
257    a : Point3 <S>,
258    b : Point3 <S>
259  }
260
261  /// A 2-simplex or triangle in 3D space
262  ///
263  /// Creation methods should fail with a debug assertion if the points are
264  /// colinear.
265  #[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
266  #[derive(Clone, Copy, Debug, PartialEq)]
267  pub struct Triangle <S> {
268    a : Point3 <S>,
269    b : Point3 <S>,
270    c : Point3 <S>
271  }
272
273  /// A 3-simplex or tetrahedron in 3D space
274  ///
275  /// Creation methods will fail with a debug assertion if the points are
276  /// coplanar.
277  #[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
278  #[derive(Clone, Copy, Debug, PartialEq)]
279  pub struct Tetrahedron <S> {
280    a : Point3 <S>,
281    b : Point3 <S>,
282    c : Point3 <S>,
283    d : Point3 <S>
284  }
285
286  impl <S : Ring> Segment <S> {
287    /// Panics if the points are identical:
288    ///
289    /// ```should_panic
290    /// # use math_utils::geometry::simplex3::Segment;
291    /// let s = Segment::new ([0.0, 0.0, 1.0].into(), [0.0, 0.0, 1.0].into());
292    /// ```
293    pub fn new (
294      a : Point3 <S>,
295      b : Point3 <S>
296    ) -> Self where S : std::fmt::Debug {
297      assert_ne!(a, b);
298      Segment { a, b }
299    }
300    /// Debug panic if the points are identical:
301    ///
302    /// ```should_panic
303    /// # use math_utils::geometry::simplex3::Segment;
304    /// let s = Segment::unchecked ([0.0, 0.0, 1.0].into(), [0.0, 0.0, 1.0].into());
305    /// ```
306    pub fn unchecked (
307      a : Point3 <S>,
308      b : Point3 <S>
309    ) -> Self where S : std::fmt::Debug {
310      debug_assert_ne!(a, b);
311      Segment { a, b }
312    }
313    #[inline]
314    pub fn numcast <T> (self) -> Option <Segment <T>> where
315      S : num_traits::NumCast,
316      T : num_traits::NumCast
317    {
318      Some (Segment {
319        a: self.a.numcast()?,
320        b: self.b.numcast()?
321      })
322    }
323    #[inline]
324    pub fn point_a (&self) -> &Point3 <S> {
325      &self.a
326    }
327    #[inline]
328    pub fn point_b (&self) -> &Point3 <S> {
329      &self.b
330    }
331    #[inline]
332    pub fn length (&self) -> S where S : Field + Sqrt {
333      self.vector().norm()
334    }
335    #[inline]
336    pub fn length2 (&self) -> S {
337      self.vector().self_dot()
338    }
339    /// Returns `point_b() - point_a()`
340    #[inline]
341    pub fn vector (&self) -> Vector3 <S> {
342      self.b - self.a
343    }
344    #[inline]
345    pub fn aabb3 (&self) -> Aabb3 <S> where S : std::fmt::Debug {
346      Aabb3::from_points (self.a, self.b)
347    }
348    #[inline]
349    pub fn line3 (&self) -> Line3 <S> where S : Real {
350      Line3::new (self.a, Unit3::normalize (self.vector()))
351    }
352    #[inline]
353    pub fn intersect_aabb (&self, aabb : &Aabb3 <S>)
354      -> Option <((S, Point3 <S>), (S, Point3 <S>))>
355    where
356      S : Real + num_traits::Float + approx::RelativeEq <Epsilon=S> +
357        std::fmt::Debug
358    {
359      intersect::continuous_segment3_aabb3 (self, aabb)
360    }
361    #[inline]
362    pub fn intersect_sphere (&self, sphere : &Sphere3 <S>)
363      -> Option <((S, Point3 <S>), (S, Point3 <S>))>
364    where
365      S : Field + Sqrt
366    {
367      intersect::continuous_segment3_sphere3 (self, sphere)
368    }
369    #[inline]
370    pub fn intersect_cylinder (&self, sphere : &Cylinder3 <S>)
371      -> Option <((S, Point3 <S>), (S, Point3 <S>))>
372    where
373      S : Real + std::fmt::Debug
374    {
375      intersect::continuous_segment3_cylinder3 (self, sphere)
376    }
377    #[inline]
378    pub fn intersect_capsule (&self, capsule : &Capsule3 <S>)
379      -> Option <((S, Point3 <S>), (S, Point3 <S>))>
380    where
381      S : Real + std::fmt::Debug
382    {
383      intersect::continuous_segment3_capsule3 (self, capsule)
384    }
385  }
386  impl <S : Field> Default for Segment <S> {
387    /// A default simplex is arbitrarily chosen to be the simplex from -1.0 to 1.0
388    /// lying on the X axis:
389    ///
390    /// ```
391    /// # use math_utils::geometry::simplex3::Segment;
392    /// assert_eq!(
393    ///   Segment::default(),
394    ///   Segment::new ([-1.0, 0.0, 0.0].into(), [1.0, 0.0, 0.0].into())
395    /// );
396    /// ```
397    fn default() -> Self {
398      Segment {
399        a: [-S::one(), S::zero(), S::zero()].into(),
400        b: [ S::one(), S::zero(), S::zero()].into()
401      }
402    }
403  }
404
405  impl <S : Ring> Triangle <S> {
406    /// Panics if the points are colinear:
407    ///
408    /// ```should_panic
409    /// # use math_utils::geometry::simplex3::Triangle;
410    /// let s = Triangle::new (
411    ///   [-1.0, -1.0, -1.0].into(),
412    ///   [ 0.0,  0.0,  0.0].into(),
413    ///   [ 1.0,  1.0,  1.0].into());
414    /// ```
415    pub fn new (
416      a : Point3 <S>,
417      b : Point3 <S>,
418      c : Point3 <S>
419    ) -> Self where
420      S : Field + Sqrt + approx::RelativeEq + std::fmt::Debug
421    {
422      debug_assert_ne!(a, b);
423      debug_assert_ne!(a, c);
424      debug_assert_ne!(b, c);
425      assert!(!colinear_3d (&a, &b, &c));
426      Triangle { a, b, c }
427    }
428    /// Debug panic if the points are colinear:
429    ///
430    /// ```should_panic
431    /// # use math_utils::geometry::simplex3::Triangle;
432    /// let s = Triangle::unchecked (
433    ///   [-1.0, -1.0, -1.0].into(),
434    ///   [ 0.0,  0.0,  0.0].into(),
435    ///   [ 1.0,  1.0,  1.0].into());
436    /// ```
437    pub fn unchecked (
438      a : Point3 <S>,
439      b : Point3 <S>,
440      c : Point3 <S>
441    ) -> Self where
442      S : Field + Sqrt + approx::RelativeEq + std::fmt::Debug
443    {
444      debug_assert_ne!(a, b);
445      debug_assert_ne!(a, c);
446      debug_assert_ne!(b, c);
447      debug_assert!(!colinear_3d (&a, &b, &c));
448      Triangle { a, b, c }
449    }
450    #[inline]
451    pub fn point_a (&self) -> &Point3 <S> {
452      &self.a
453    }
454    #[inline]
455    pub fn point_b (&self) -> &Point3 <S> {
456      &self.b
457    }
458    #[inline]
459    pub fn point_c (&self) -> &Point3 <S> {
460      &self.c
461    }
462  }
463  impl <S : Field + Sqrt> Default for Triangle <S> {
464    /// A default simplex is arbitrarily chosen to be the simplex on the XY plane
465    /// formed by an equilateral triangle with point at 1.0 on the Y axis:
466    ///
467    /// ```
468    /// # use math_utils::approx;
469    /// # use math_utils::geometry::simplex3::Triangle;
470    /// # use math_utils::*;
471    /// use std::f64::consts::FRAC_1_SQRT_2;
472    /// let s = Triangle::default();
473    /// let t = Triangle::new (
474    ///   [           0.0,            1.0, 0.0].into(),
475    ///   [-FRAC_1_SQRT_2, -FRAC_1_SQRT_2, 0.0].into(),
476    ///   [ FRAC_1_SQRT_2, -FRAC_1_SQRT_2, 0.0].into()
477    /// );
478    /// approx::assert_relative_eq!(
479    ///   Matrix3::from_col_arrays ([
480    ///     s.point_a().0.into_array(),
481    ///     s.point_b().0.into_array(),
482    ///     s.point_c().0.into_array()
483    ///   ]),
484    ///   Matrix3::from_col_arrays ([
485    ///     t.point_a().0.into_array(),
486    ///     t.point_b().0.into_array(),
487    ///     t.point_c().0.into_array()
488    ///   ]));
489    /// ```
490    fn default() -> Self {
491      let frac_1_sqrt_2 = S::one() / (S::one() + S::one()).sqrt();
492      Triangle {
493        a: [     S::zero(),       S::one(), S::zero()].into(),
494        b: [-frac_1_sqrt_2, -frac_1_sqrt_2, S::zero()].into(),
495        c: [ frac_1_sqrt_2, -frac_1_sqrt_2, S::zero()].into()
496      }
497    }
498  }
499
500  impl <S : Ring> Tetrahedron <S> {
501    /// Panics if the points are coplanar:
502    ///
503    /// ```should_panic
504    /// # use math_utils::geometry::simplex3::Tetrahedron;
505    /// let s = Tetrahedron::new (
506    ///   [-1.0, -1.0, -1.0].into(),
507    ///   [ 1.0,  1.0,  1.0].into(),
508    ///   [-1.0,  1.0,  0.0].into(),
509    ///   [ 1.0, -1.0,  0.0].into());
510    /// ```
511    pub fn new (
512      a : Point3 <S>,
513      b : Point3 <S>,
514      c : Point3 <S>,
515      d : Point3 <S>
516    ) -> Self where
517      S : approx::RelativeEq
518    {
519      assert!(!coplanar_3d (&a, &b, &c, &d));
520      Tetrahedron { a, b, c, d }
521    }
522    /// Debug panic if the points are coplanar:
523    ///
524    /// ```should_panic
525    /// # use math_utils::geometry::simplex3::Tetrahedron;
526    /// let s = Tetrahedron::unchecked (
527    ///   [-1.0, -1.0, -1.0].into(),
528    ///   [ 1.0,  1.0,  1.0].into(),
529    ///   [-1.0,  1.0,  0.0].into(),
530    ///   [ 1.0, -1.0,  0.0].into());
531    /// ```
532    pub fn unchecked (
533      a : Point3 <S>,
534      b : Point3 <S>,
535      c : Point3 <S>,
536      d : Point3 <S>
537    ) -> Self where
538      S : approx::RelativeEq
539    {
540      debug_assert!(!coplanar_3d (&a, &b, &c, &d));
541      Tetrahedron { a, b, c, d }
542    }
543    #[inline]
544    pub fn point_a (&self) -> &Point3 <S> {
545      &self.a
546    }
547    #[inline]
548    pub fn point_b (&self) -> &Point3 <S> {
549      &self.b
550    }
551    #[inline]
552    pub fn point_c (&self) -> &Point3 <S> {
553      &self.c
554    }
555    #[inline]
556    pub fn point_d (&self) -> &Point3 <S> {
557      &self.d
558    }
559  }
560  impl <S : Field + Sqrt> Default for Tetrahedron <S> {
561    /// A default simplex is arbitrarily chosen to be the simplex with vertices at
562    /// unit distance from the origin with A at `[0.0, 0.0, 1.0]` and B at
563    /// `[0.0, sqrt(8.0/9.0), -1.0/3.0]`, and points C and D at
564    /// `[ sqrt(2.0/3.0), -sqrt(2.0/9.0), -1.0/3.0]` and
565    /// `[-sqrt(2.0/3.0), -sqrt(2.0/9.0), -1.0/3.0]`.
566    ///
567    /// ```
568    /// # use math_utils::approx;
569    /// # use math_utils::geometry::simplex3::Tetrahedron;
570    /// # use math_utils::*;
571    /// let s = Tetrahedron::default();
572    /// let t = Tetrahedron::new (
573    ///   [                0.0,                 0.0,      1.0].into(),
574    ///   [                0.0,  f64::sqrt(8.0/9.0), -1.0/3.0].into(),
575    ///   [ f64::sqrt(2.0/3.0), -f64::sqrt(2.0/9.0), -1.0/3.0].into(),
576    ///   [-f64::sqrt(2.0/3.0), -f64::sqrt(2.0/9.0), -1.0/3.0].into());
577    /// approx::assert_relative_eq!(
578    ///   Matrix4::from_col_arrays ([
579    ///     s.point_a().0.with_w (0.0).into_array(),
580    ///     s.point_b().0.with_w (0.0).into_array(),
581    ///     s.point_c().0.with_w (0.0).into_array(),
582    ///     s.point_d().0.with_w (0.0).into_array()
583    ///   ]),
584    ///   Matrix4::from_col_arrays ([
585    ///     t.point_a().0.with_w (0.0).into_array(),
586    ///     t.point_b().0.with_w (0.0).into_array(),
587    ///     t.point_c().0.with_w (0.0).into_array(),
588    ///     t.point_d().0.with_w (0.0).into_array()
589    ///   ]));
590    /// ```
591    fn default() -> Self {
592      let frac_1_3 = S::one()    / S::three();
593      let sqrt_2_3 = (S::two()   / S::three()).sqrt();
594      let sqrt_8_9 = (S::eight() / S::nine()).sqrt();
595      let sqrt_2_9 = (S::two()   / S::nine()).sqrt();
596      Tetrahedron {
597        a: [S::zero(), S::zero(),  S::one()].into(),
598        b: [S::zero(),  sqrt_8_9, -frac_1_3].into(),
599        c: [ sqrt_2_3, -sqrt_2_9, -frac_1_3].into(),
600        d: [-sqrt_2_3, -sqrt_2_9, -frac_1_3].into()
601      }
602    }
603  }
604}