Skip to main content

math_utils/types/
frame.rs

1//! Affine coordinate frames
2
3#[cfg(feature = "derive_serdes")]
4use serde::{Deserialize, Serialize};
5
6use crate::geometry;
7use super::*;
8
9type LinearBasis2 <S> = NonZero2 <S>;
10
11#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
12#[derive(Clone, Copy, Debug, Eq, PartialEq)]
13pub struct PlanarBasis2 <S> (Matrix2 <S>);
14
15type LinearBasis3 <S> = NonZero3 <S>;
16
17#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
18#[derive(Clone, Copy, Debug, Eq, PartialEq)]
19pub struct PlanarBasis3 <S> ([NonZero3 <S>; 2]);
20
21#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
22#[derive(Clone, Copy, Debug, Eq, PartialEq)]
23pub struct EntireBasis3 <S> (Matrix3 <S>);
24
25/// Coordinate frame for a 2D linear affine subspace
26#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
27#[derive(Clone, Copy, Debug, Eq, PartialEq)]
28pub struct Line2 <S> {
29  pub origin : Point2 <S>,
30  pub basis  : LinearBasis2 <S>
31}
32
33/// Coordinate frame for a 2D planar affine subspace
34#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
35#[derive(Clone, Copy, Debug, Eq, PartialEq)]
36pub struct Plane2 <S> {
37  pub origin : Point2 <S>,
38  pub basis  : PlanarBasis2 <S>
39}
40
41/// Coordinate frame for a 3D linear affine subspace
42#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
43#[derive(Clone, Copy, Debug, Eq, PartialEq)]
44pub struct Line3 <S> {
45  pub origin : Point3 <S>,
46  pub basis  : LinearBasis3 <S>
47}
48
49/// Coordinate frame for a 3D planar affine subspace
50#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
51#[derive(Clone, Copy, Debug, Eq, PartialEq)]
52pub struct Plane3 <S> {
53  pub origin : Point3 <S>,
54  pub basis  : PlanarBasis3 <S>
55}
56
57/// Coordinate frame for a 3D entire affine subspace
58#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
59#[derive(Clone, Copy, Debug, Eq, PartialEq)]
60pub struct Space3 <S> {
61  pub origin : Point3 <S>,
62  pub basis  : EntireBasis3 <S>
63}
64
65impl <S : Ring> Line2 <S> {
66  pub fn point (&self, coordinate : S) -> Point2 <S> {
67    self.origin + *self.basis * coordinate
68  }
69}
70impl <S : OrderedRing> From <geometry::Line2 <S>> for Line2 <S> {
71  fn from (line : geometry::Line2 <S>) -> Self {
72    line.affine_line()
73  }
74}
75impl <S : OrderedRing> From <geometry::Ray2 <S>> for Line2 <S> {
76  fn from (ray : geometry::Ray2 <S>) -> Self {
77    ray.affine_line()
78  }
79}
80impl <S : OrderedRing> From <geometry::Segment2 <S>> for Line2 <S> {
81  fn from (segment : geometry::Segment2 <S>) -> Self {
82    segment.affine_line()
83  }
84}
85
86impl <S : Ring> Plane2 <S> {
87  pub fn point (&self, coordinates : Vector2 <S>) -> Point2 <S> {
88    self.origin + *self.basis * coordinates
89  }
90}
91impl <S : OrderedField> From <geometry::Triangle2 <S>> for Plane2 <S> {
92  fn from (triangle : geometry::Triangle2 <S>) -> Self {
93    triangle.affine_plane()
94  }
95}
96
97impl <S : Ring> Line3 <S> {
98  pub fn point (&self, coordinate : S) -> Point3 <S> {
99    self.origin + *self.basis * coordinate
100  }
101}
102impl <S : OrderedRing> From <geometry::Line3 <S>> for Line3 <S> {
103  fn from (line : geometry::Line3 <S>) -> Self {
104    line.affine_line()
105  }
106}
107impl <S : OrderedRing> From <geometry::Ray3 <S>> for Line3 <S> {
108  fn from (ray : geometry::Ray3 <S>) -> Self {
109    ray.affine_line()
110  }
111}
112impl <S : OrderedRing> From <geometry::Segment3 <S>> for Line3 <S> {
113  fn from (segment : geometry::Segment3 <S>) -> Self {
114    segment.affine_line()
115  }
116}
117
118impl <S : Ring> Plane3 <S> {
119  pub fn point (&self, coordinates : Vector2 <S>) -> Point3 <S> {
120    self.origin + *self.basis[0] * coordinates.x + *self.basis[1] * coordinates.y
121  }
122}
123impl <S : OrderedField> From <geometry::Triangle3 <S>> for Plane3 <S> {
124  fn from (triangle : geometry::Triangle3 <S>) -> Self {
125    triangle.affine_plane()
126  }
127}
128
129impl <S> Space3 <S> {
130  pub fn point (&self, coordinates : Vector3 <S>) -> Point3 <S> where S : Ring {
131    self.origin + *self.basis * coordinates
132  }
133}
134
135impl <S : Field> PlanarBasis2 <S> {
136  /// Returns `None` if basis vectors are not linearly independent
137  pub fn new (basis : Matrix2 <S>) -> Option <Self> {
138    if LinearIso::is_invertible (basis) {
139      Some (PlanarBasis2 (basis))
140    } else {
141      None
142    }
143  }
144}
145impl <S> std::ops::Deref for PlanarBasis2 <S> {
146  type Target = Matrix2 <S>;
147  fn deref (&self) -> &Self::Target {
148    &self.0
149  }
150}
151
152impl <S : OrderedRing> PlanarBasis3 <S> {
153  /// Returns `None` if basis vectors are not linearly independent:
154  ///
155  /// ```
156  /// # use math_utils::*;
157  /// # use math_utils::frame::*;
158  /// let basis = [
159  ///   NonZero3::noisy (vector![1.0, 1.0, 1.0]),
160  ///   NonZero3::noisy (vector![11.0, 11.0, 11.0])
161  /// ];
162  /// assert!(PlanarBasis3::new (basis).is_none());
163  /// ```
164  pub fn new (basis : [NonZero3 <S>; 2]) -> Option <Self> {
165    if *basis[0].cross (*basis[1]).self_dot() != S::zero() {
166      Some (PlanarBasis3 (basis))
167    } else {
168      None
169    }
170  }
171}
172impl <S> std::ops::Deref for PlanarBasis3 <S> {
173  type Target = [NonZero3 <S>; 2];
174  fn deref (&self) -> &Self::Target {
175    &self.0
176  }
177}
178
179impl <S : Field> EntireBasis3 <S> {
180  /// Returns `None` if basis vectors are not linearly independent
181  pub fn new (basis : Matrix3 <S>) -> Option <Self> {
182    if LinearIso::is_invertible (basis) {
183      Some (EntireBasis3 (basis))
184    } else {
185      None
186    }
187  }
188}
189impl <S> std::ops::Deref for EntireBasis3 <S> {
190  type Target = Matrix3 <S>;
191  fn deref (&self) -> &Self::Target {
192    &self.0
193  }
194}