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