math_utils/types/
coordinate.rs

1//! Tagged coordinate types
2
3use std::marker::PhantomData;
4
5#[cfg(feature = "derive_serdes")]
6use serde::{Deserialize, Serialize};
7
8use crate::num_traits as num;
9use crate::traits::*;
10use super::*;
11
12macro_rules! impl_dimension {
13  ( $point:ident, $vector:ident, $matrix:ident, $position:ident, $displacement:ident,
14    [$($projective_base:ident, $projective:ident, $translation_column:ident)?],
15    $transform:ident, $cartesian:ident, $ndims:expr, $dimension:expr
16  ) => {
17    #[doc = $dimension]
18    #[doc = "cartesian coordinate space tagged with units"]
19    #[derive(Clone, Copy, Debug)]
20    #[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
21    #[repr(C)]
22    pub struct $cartesian <S, U> (PhantomData <(S, U)>);
23
24    #[doc = $dimension]
25    #[doc = "linear transformation between two coordinate systems tagged with units"]
26    #[derive(Debug, Default, Eq, Display)]
27    #[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
28    #[display("{}", _0)]
29    #[repr(C)]
30    pub struct $transform <S, U, V> (pub $matrix <S>, PhantomData <(U, V)>) where
31      S : num::Zero + num::One;
32
33    #[doc = $dimension]
34    #[doc = "point coordinates tagged with unit"]
35    #[derive(Debug, Default, Eq, Display)]
36    #[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
37    #[display("{}", _0)]
38    #[repr(C)]
39    pub struct $position <S, U> (pub $point <S>, PhantomData <U>);
40
41    #[doc = $dimension]
42    #[doc = "linear displacement vector coordinates tagged with unit"]
43    #[derive(Debug, Default, Eq, Display)]
44    #[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
45    #[display("{}", _0)]
46    #[repr(C)]
47    pub struct $displacement <S, U> (pub $vector <S>, PhantomData <U>);
48
49    ////////////////////////////////////////////////////////////////////////////
50    //  impls
51    ////////////////////////////////////////////////////////////////////////////
52
53    //
54    //  CartesianN
55    //
56    impl <S, U> EuclideanSpace <S> for $cartesian <S, U> where S : Real { }
57    impl <S, U> AffineSpace <S> for $cartesian <S, U> where S : Real {
58      type Point  = $position <S, U>;
59      type Vector = $displacement <S, U>;
60    }
61
62    //
63    //  TransformN
64    //
65    impl <S, U, V> LinearMap <S, $displacement <S, U>, $displacement <S, V>> for
66      $transform <S, U, V>
67    where S : Ring {
68      fn determinant (self) -> S {
69        self.0.determinant()
70      }
71      fn transpose (self) -> Self {
72        $transform (self.0.transpose(), PhantomData::default())
73      }
74    }
75    impl <S, U, V> MultiplicativeMonoid for $transform <S, U, V> where S : Ring { }
76    impl <S, U, V> num::One for $transform <S, U, V> where S : Ring {
77      fn one() -> Self {
78        Self ($matrix::one(), PhantomData::default())
79      }
80    }
81    impl <S, U, V> std::ops::Mul <Self> for $transform <S, U, V> where S : Ring {
82      type Output = Self;
83      fn mul (self, rhs : Self) -> Self {
84        (self.0 * rhs.0).into()
85      }
86    }
87    impl <S, U, V> std::ops::MulAssign <Self> for $transform <S, U, V> where S : Ring {
88      fn mul_assign (&mut self, rhs : Self) {
89        (self.0 *= rhs.0).into()
90      }
91    }
92    impl <S, U, V> std::ops::Mul <$displacement <S, U>> for $transform <S, U, V> where
93      S : Ring
94    {
95      type Output = $displacement <S, V>;
96      fn mul (self, rhs : $displacement <S, U>) -> $displacement <S, V> {
97        (self.0 * rhs.0).into()
98      }
99    }
100    impl <S, U, V> PartialEq for $transform <S, U, V> where
101      S : PartialEq + num::Zero + num::One
102    {
103      fn eq (&self, other : &Self) -> bool {
104        self.0 == other.0
105      }
106    }
107    impl <S, U, V> Copy for $transform <S, U, V> where S : Copy + num::Zero + num::One
108      { }
109    impl <S, U, V> Clone for $transform <S, U, V> where
110      S : Clone + num::Zero + num::One
111    {
112      fn clone (&self) -> Self {
113        self.0.clone().into()
114      }
115    }
116    impl <S, U, V> From <$matrix <S>> for $transform <S, U, V> where
117      S : num::Zero + num::One
118    {
119      fn from (matrix : $matrix <S>) -> Self {
120        $transform (matrix, PhantomData::default())
121      }
122    }
123
124    //
125    //  DisplacementN
126    //
127    impl <S, U> Point <$displacement <S, U>> for $displacement <S, U> where S : Ring {
128      fn to_vector (self) -> $displacement <S, U> {
129        self
130      }
131      fn from_vector (displacement : $displacement <S, U>) -> Self {
132        displacement
133      }
134    }
135    impl <S, U> InnerProductSpace <S> for $displacement <S, U> where
136      $vector <S> : InnerProductSpace <S>,
137      S : Field
138    { }
139    impl <S, U> VectorSpace <S> for $displacement <S, U> where
140      $vector <S> : VectorSpace <S>,
141      S : Field
142    {
143      fn map <F> (self, f : F) -> Self where F : FnMut (S) -> S {
144        self.0.map (f).into()
145      }
146    }
147    impl <S, U> Dot <S> for $displacement <S, U> where
148      $vector <S> : Dot <S>,
149      S : Ring
150    {
151      fn dot (self, other : Self) -> S {
152        self.0.dot (other.0)
153      }
154    }
155    impl <S, U> std::ops::Div <S> for $displacement <S, U> where
156      $vector <S> : std::ops::Div <S, Output=$vector <S>>
157    {
158      type Output = Self;
159      fn div (self, scalar : S) -> Self {
160        (self.0 / scalar).into()
161      }
162    }
163    impl <S, U> Module <S> for $displacement <S, U> where
164      $vector <S> : Module <S>,
165      S : Ring
166    {
167      type LinearEndo = $transform <S, U, U>;
168    }
169    impl <S, U> std::ops::Mul <S> for $displacement <S, U> where
170      $vector <S> : std::ops::Mul <S, Output=$vector <S>>
171    {
172      type Output = Self;
173      fn mul (self, scalar : S) -> Self {
174        (self.0 * scalar).into()
175      }
176    }
177    impl <S, U> GroupAction <$position <S, U>> for $displacement <S, U> where
178      S : AdditiveGroup
179    {
180      fn action (self, position : $position <S, U>) -> $position <S, U> {
181        (position.0 + self.0).into()
182      }
183    }
184    impl <S, U> AdditiveGroup for $displacement <S, U> where
185      $vector <S> : AdditiveGroup,
186      S : Ring
187    { }
188    impl <S, U> AdditiveMonoid for $displacement <S, U> where
189      $vector <S> : AdditiveGroup,
190      S : Ring
191    { }
192    impl <S, U> Group for $displacement <S, U> where S : AdditiveGroup {
193      fn identity() -> Self {
194        use num::Zero;
195        Self::zero()
196      }
197      fn operation (a : Self, b : Self) -> Self {
198        a + b
199      }
200    }
201    impl <S, U> std::ops::Add <Self> for $displacement <S, U> where
202      $vector <S> : std::ops::Add <Output=$vector <S>>
203    {
204      type Output = Self;
205      fn add (self, other : Self) -> Self {
206        (self.0 + other.0).into()
207      }
208    }
209    impl <S, U> std::ops::Add <&Self> for $displacement <S, U> where
210      $vector <S> : std::ops::Add <Output=$vector <S>>,
211      S : Copy
212    {
213      type Output = Self;
214      fn add (self, other : &Self) -> Self {
215        (self.0 + other.0).into()
216      }
217    }
218    impl <S, U> std::ops::Sub <Self> for $displacement <S, U> where
219      $vector <S> : std::ops::Sub <Output=$vector <S>>
220    {
221      type Output = Self;
222      fn sub (self, other : Self) -> Self {
223        (self.0 - other.0).into()
224      }
225    }
226    impl <S, U> std::ops::Sub <&Self> for $displacement <S, U> where
227      $vector <S> : std::ops::Sub <Output=$vector <S>>,
228      S : Copy
229    {
230      type Output = Self;
231      fn sub (self, other : &Self) -> Self {
232        (self.0 - other.0).into()
233      }
234    }
235    impl <S, U> std::ops::AddAssign <Self> for $displacement <S, U> where
236      $vector <S> : std::ops::AddAssign
237    {
238      fn add_assign (&mut self, other : Self) {
239        self.0 += other.0
240      }
241    }
242    impl <S, U> std::ops::SubAssign <Self> for $displacement <S, U> where
243      $vector <S> : std::ops::SubAssign
244    {
245      fn sub_assign (&mut self, other : Self) {
246        self.0 -= other.0
247      }
248    }
249    impl <S, U> std::ops::Neg for $displacement <S, U> where
250      $vector <S> : std::ops::Neg <Output=$vector <S>>
251    {
252      type Output = Self;
253      fn neg (self) -> Self {
254        (-self.0).into()
255      }
256    }
257    impl <S, U> num::Zero for $displacement <S, U> where S : AdditiveGroup {
258      fn zero() -> Self {
259        $vector::zero().into()
260      }
261      fn is_zero (&self) -> bool {
262        self.0 == $vector::zero()
263      }
264    }
265    impl <S, U> PartialEq for $displacement <S, U> where $vector <S> : PartialEq {
266      fn eq (&self, other : &Self) -> bool {
267        self.0 == other.0
268      }
269    }
270    impl <S, U> Copy for $displacement <S, U> where S : Copy { }
271    impl <S, U> Clone for $displacement <S, U> where S : Clone {
272      fn clone (&self) -> Self {
273        self.0.clone().into()
274      }
275    }
276    impl <S, U> From <$vector <S>> for $displacement <S, U> {
277      fn from (vector : $vector <S>) -> Self {
278        $displacement (vector, PhantomData::default())
279      }
280    }
281    impl <S, U> From<[S; $ndims]> for $displacement <S, U> {
282      fn from (array : [S; $ndims]) -> Self {
283        $displacement (array.into(), PhantomData::default())
284      }
285    }
286    // projective completion
287    $(
288      impl <S, U> ProjectiveSpace <S, $displacement <S, U>> for $projective <S, U> where
289        S : Field + std::fmt::Display
290      {
291        fn homography <A> (
292          affinity : Affinity <S, A, A, <A::Vector as Module <S>>::LinearEndo>
293        ) -> Projectivity <
294          S, $displacement <S, U>, $displacement <S, U>, Self, Self, Self::LinearEndo
295        > where
296          A : AffineSpace <S, Vector=$displacement <S, U>>
297        {
298          let mut transform = Self::LinearEndo::from (*affinity.linear_iso);
299          transform.0.cols.$translation_column =
300            $projective_base::from ((affinity.translation.0, S::one()));
301          Projectivity::new (
302            LinearIso::<S, Self, Self, Self::LinearEndo>::new (transform).unwrap())
303        }
304        fn homogeneous <A> (point_or_vector : Either <A::Point, A::Vector>) -> Self where
305          A : AffineSpace <S, Vector=$displacement <S, U>>,
306          $displacement <S, U> : GroupAction <A::Point>
307        {
308          match point_or_vector {
309            Either::Left  (point)  =>
310              $projective_base::from ((point.to_vector().0, S::one())).into(),
311            Either::Right (vector) =>
312              $projective_base::from ((vector.0, S::zero())).into()
313          }
314        }
315      }
316    )?
317
318    //
319    //  PositionN
320    //
321    impl <S, U> Point <$displacement <S, U>> for $position <S, U> where S : Ring {
322      fn to_vector (self) -> $displacement <S, U> {
323        self.0.to_vector().into()
324      }
325      fn from_vector (displacement : $displacement <S, U>) -> Self {
326        $point::from_vector (displacement.0).into()
327      }
328    }
329    impl <S, U> std::ops::Sub <Self> for $position <S, U> where
330      $vector <S> : std::ops::Sub <Output=$vector <S>>,
331      S : AdditiveGroup
332    {
333      type Output = $displacement <S, U>;
334      fn sub (self, other : Self) -> $displacement <S, U> {
335        (self.0 - other.0).into()
336      }
337    }
338    impl <S, U> PartialEq for $position <S, U> where $point <S> : PartialEq {
339      fn eq (&self, other : &Self) -> bool {
340        self.0 == other.0
341      }
342    }
343    impl <S, U> Copy for $position <S, U> where S : Copy { }
344    impl <S, U> Clone for $position <S, U> where S : Clone {
345      fn clone (&self) -> Self {
346        self.0.clone().into()
347      }
348    }
349    impl <S, U> From <$point <S>> for $position <S, U> {
350      fn from (point : $point <S>) -> Self {
351        $position (point, PhantomData::default())
352      }
353    }
354    impl <S, U> From<[S; $ndims]> for $position <S, U> {
355      fn from (array : [S; $ndims]) -> Self {
356        $position (array.into(), PhantomData::default())
357      }
358    }
359  }
360}
361
362impl_dimension!(Point2, Vector2, Matrix2, Position2,
363  Displacement2, [Vector3, Displacement3, z], Transform2, Cartesian2, 2, "2D");
364impl_dimension!(Point3, Vector3, Matrix3, Position3,
365  Displacement3, [Vector4, Displacement4, w], Transform3, Cartesian3, 3, "3D");
366impl_dimension!(Point4, Vector4, Matrix4, Position4,
367  Displacement4, [], Transform4, Cartesian4, 4, "4D");
368
369//
370//  DisplacementN
371//
372impl <S, U> From <Displacement2 <S, U>> for Displacement3 <S, U> where S : Field {
373  fn from (transform : Displacement2 <S, U>) -> Self {
374    Displacement3 (transform.0.into(), PhantomData)
375  }
376}
377impl <S, U> From <Displacement3 <S, U>> for Displacement4 <S, U> where S : Field {
378  fn from (transform : Displacement3 <S, U>) -> Self {
379    Displacement4 (transform.0.into(), PhantomData)
380  }
381}
382
383//
384//  TransformN
385//
386impl <S, U, V> From <Transform2 <S, U, V>> for Transform3 <S, U, V> where S : Field {
387  fn from (transform : Transform2 <S, U, V>) -> Self {
388    Transform3 (transform.0.into(), PhantomData)
389  }
390}
391impl <S, U, V> From <Transform3 <S, U, V>> for Transform4 <S, U, V> where S : Field {
392  fn from (transform : Transform3 <S, U, V>) -> Self {
393    Transform4 (transform.0.into(), PhantomData)
394  }
395}
396
397#[cfg(test)]
398mod tests {
399  use super::*;
400
401  #[derive(Default)]
402  struct Foo;
403  #[derive(Default)]
404  struct Bar;
405
406  #[test]
407  fn defaults() {
408    assert_eq!(Position3::<f32, Foo>::default().0, Point3::origin());
409    assert_eq!(Displacement3::<f32, Foo>::default().0, Vector3::zero());
410    assert_eq!(Transform3::<f32, Foo, Bar>::default().0, Matrix3::identity());
411  }
412}