1use fixed::traits::{Fixed, ToFixed};
2use fixed::types::extra::*;
3
4use crate::num_traits as num;
5use crate::traits::*;
6use crate::types::*;
7use crate::types::coordinate::*;
8
9macro_rules! impl_dimension {
10  (
11    $point:ident, $vector:ident, $matrix:ident, $position:ident, $displacement:ident,
12    $transform:ident, $fixed_point:ident, $fixed_vector:ident, $fixed_matrix:ident,
13    $dimension:expr, $mat_dims:expr, [$($component:ident),+]
14  ) => {
15    #[doc = "Convert to fixed precision"]
16    #[doc = $dimension]
17    #[doc = "vector"]
18    pub trait $fixed_vector <S> {
19      fn from_num <N : ToFixed> (num : $vector <N>) -> Self;
20      fn wrapping_from_num <N : ToFixed> (num : $vector <N>) -> Self;
21    }
22    impl <S> $fixed_vector <S> for $vector <S> where S : Fixed {
23      fn from_num <N : ToFixed> (num : $vector <N>) -> Self {
24        $vector::new ($(num.$component.to_fixed()),+)
25      }
26      fn wrapping_from_num <N : ToFixed> (num : $vector <N>) -> Self {
27        $vector::new ($(num.$component.wrapping_to_fixed()),+)
28      }
29    }
30    impl <S, U> $fixed_vector <S> for $displacement <S, U> where S : Fixed {
31      fn from_num <N : ToFixed> (num : $vector <N>) -> Self {
32        $vector::from_num (num).into()
33      }
34      fn wrapping_from_num <N : ToFixed> (num : $vector <N>) -> Self {
35        $vector::wrapping_from_num (num).into()
36      }
37    }
38
39    #[doc = "Convert to fixed precision"]
40    #[doc = $dimension]
41    #[doc = "point"]
42    pub trait $fixed_point <S> {
43      fn from_num <N : ToFixed> (num : $point <N>) -> Self;
44      fn wrapping_from_num <N : ToFixed> (num : $point <N>) -> Self;
45    }
46    impl <S> $fixed_point <S> for $point <S> where S : Fixed {
47      fn from_num <N : ToFixed> (num : $point <N>) -> Self {
48        $vector::from_num (num.0).into()
49      }
50      fn wrapping_from_num <N : ToFixed> (num : $point <N>) -> Self {
51        $vector::wrapping_from_num (num.0).into()
52      }
53    }
54    impl <S, U> $fixed_point <S> for $position <S, U> where S : Fixed {
55      fn from_num <N : ToFixed> (num : $point <N>) -> Self {
56        $point::from_num (num).into()
57      }
58      fn wrapping_from_num <N : ToFixed> (num : $point <N>) -> Self {
59        $point::wrapping_from_num (num).into()
60      }
61    }
62
63    #[doc = "Convert to fixed precision"]
64    #[doc = $mat_dims]
65    #[doc = "matrix"]
66    pub trait $fixed_matrix <S> {
67      fn from_num <N : ToFixed> (num : $matrix <N>) -> Self;
68      fn wrapping_from_num <N : ToFixed> (num : $matrix <N>) -> Self;
69    }
70    impl <S> $fixed_matrix <S> for $matrix <S> where S : Fixed {
71      fn from_num <N : ToFixed> (num : $matrix <N>) -> Self {
72        $matrix {
73          cols: [
74            $($vector::from_num (num.cols.$component)),+
75          ].into()
76        }
77      }
78      fn wrapping_from_num <N : ToFixed> (num : $matrix <N>) -> Self {
79        $matrix {
80          cols: [
81            $($vector::wrapping_from_num (num.cols.$component)),+
82          ].into()
83        }
84      }
85    }
86    impl <S, U, V> $fixed_matrix <S> for $transform <S, U, V> where
87      S : Fixed + num::Zero + num::One
88    {
89      fn from_num <N : ToFixed> (num : $matrix <N>) -> Self {
90        $matrix::from_num (num).into()
91      }
92      fn wrapping_from_num <N : ToFixed> (num : $matrix <N>) -> Self {
93        $matrix::wrapping_from_num (num).into()
94      }
95    }
96  }
97}
98
99impl_dimension!(
100  Point2, Vector2, Matrix2,
101  Position2, Displacement2, Transform2,
102  FixedPoint2, FixedVector2, FixedMatrix2, "2D",
103  "2x2", [x, y]);
104impl_dimension!(
105  Point3, Vector3, Matrix3,
106  Position3, Displacement3, Transform3,
107  FixedPoint3, FixedVector3, FixedMatrix3, "3D",
108  "3x3", [x, y, z]);
109impl_dimension!(
110  Point4, Vector4, Matrix4,
111  Position4, Displacement4, Transform4,
112  FixedPoint4, FixedVector4, FixedMatrix4, "4D",
113  "4x4", [x, y, z, w]);
114
115macro impl_real_fixed ($fixed:ident,
116  $cordic_bound_1:ident, $cordic_bound_2:ident, $cordic_bound_3:ident,
117  $fixed_sqrt_bound:path
118) {
119  impl <U> VectorSpace <Self> for fixed::$fixed <U> where
120    U : Unsigned +
121      IsLessOrEqual<$cordic_bound_2, Output = True> +
122      IsLessOrEqual<$cordic_bound_1, Output = True> +
123      $fixed_sqrt_bound
124  {
125    fn map <F> (self, mut f : F) -> Self where F : FnMut (Self) -> Self {
126      f (self)
127    }
128  }
129  impl <U> Module <Self> for fixed::$fixed <U> where
130    U : Unsigned +
131      IsLessOrEqual<$cordic_bound_2, Output = True> +
132      IsLessOrEqual<$cordic_bound_1, Output = True> +
133      $fixed_sqrt_bound
134  {
135    type LinearEndo = Self;
136  }
137  impl <U> LinearMap <Self, Self, Self> for fixed::$fixed <U> where
138    U : Unsigned +
139      IsLessOrEqual<$cordic_bound_2, Output = True> +
140      IsLessOrEqual<$cordic_bound_1, Output = True> +
141      $fixed_sqrt_bound
142  {
143    fn determinant (self) -> Self {
144      self
145    }
146    fn transpose (self) -> Self {
147      self
148    }
149  }
150  impl <U> Real for fixed::$fixed <U> where
151    U : Unsigned +
152      IsLessOrEqual<$cordic_bound_2, Output = True> +
153      IsLessOrEqual<$cordic_bound_1, Output = True> +
154      $fixed_sqrt_bound
155  {
156    fn pi() -> Self {
157      Self::from_num (fixed::consts::PI)
158    }
159    fn frac_pi_3() -> Self {
160      Self::from_num (fixed::consts::FRAC_PI_3)
161    }
162    fn sqrt_3() -> Self {
163      Self::from_num (fixed::consts::SQRT_3)
164    }
165    fn frac_1_sqrt_3() -> Self {
166      Self::from_num (fixed::consts::FRAC_1_SQRT_3)
167    }
168    fn floor (self) -> Self {
169      self.floor()
170    }
171    fn ceil (self) -> Self {
172      self.ceil()
173    }
174    fn trunc (self) -> Self {
175      self.int()
176    }
177    fn fract (self) -> Self {
178      self.frac()
179    }
180  }
181  impl <U> Field                for fixed::$fixed <U> where
182    U : Unsigned + IsLessOrEqual<$cordic_bound_2, Output = True> + $fixed_sqrt_bound
183  { }
184  impl <U> Ring                 for fixed::$fixed <U> where
185    U : Unsigned + IsLessOrEqual<$cordic_bound_2, Output = True> + $fixed_sqrt_bound
186  { }
187  impl <U> MultiplicativeGroup  for fixed::$fixed <U> where
188    U : Unsigned + IsLessOrEqual<$cordic_bound_2, Output = True> + $fixed_sqrt_bound
189  { }
190  impl <U> MultiplicativeMonoid for fixed::$fixed <U> where
191    U : Unsigned + IsLessOrEqual<$cordic_bound_2, Output = True> + $fixed_sqrt_bound
192  { }
193  impl <U> AdditiveGroup        for fixed::$fixed <U> where
194    U : Unsigned + $fixed_sqrt_bound
195  { }
196  impl <U> AdditiveMonoid       for fixed::$fixed <U> where
197    U : Unsigned + $fixed_sqrt_bound
198  { }
199  impl <U> SignedExt            for fixed::$fixed <U> where
200    U : Unsigned + $fixed_sqrt_bound + IsLessOrEqual<$cordic_bound_2, Output = True>
201  { }
202  impl <U> MinMax               for fixed::$fixed <U> where
203    U : Unsigned + $fixed_sqrt_bound
204  {
205    fn min (self, other : Self) -> Self {
206      Ord::min (self, other)
207    }
208    fn max (self, other : Self) -> Self {
209      Ord::max (self, other)
210    }
211    fn clamp (self, min : Self, max : Self) -> Self {
212      Ord::clamp (self, min, max)
213    }
214  }
215  impl <U> Sqrt for fixed::$fixed <U> where U : $fixed_sqrt_bound {
216    fn sqrt (self) -> Self {
217      fixed_sqrt::FastSqrt::fast_sqrt (self)
218    }
219  }
220  impl <U> Exp for fixed::$fixed <U> where
221    U : 'static + Unsigned + IsLessOrEqual<$cordic_bound_3, Output = True> +
222      IsLessOrEqual<$cordic_bound_2, Output = True> +
223      IsLessOrEqual<$cordic_bound_1, Output = True>
224  {
225    fn exp (self) -> Self {
226      cordic::exp (self)
227    }
228  }
229  impl <U> Powi for fixed::$fixed <U> where
230    U : Unsigned + IsLessOrEqual<$cordic_bound_2, Output = True> + $fixed_sqrt_bound
231  {
232    fn powi (self, _n : i32) -> Self {
233      unimplemented!("TODO: fixed integer powers")
234    }
235  }
236  impl <U> Powf for fixed::$fixed <U> where
237    U : Unsigned + IsLessOrEqual<$cordic_bound_2, Output = True> + $fixed_sqrt_bound
238  {
239    fn powf (self, _n : Self) -> Self {
240      unimplemented!("TODO: fixed fractional powers")
241    }
242  }
243
244  impl <U> Trig for fixed::$fixed <U> where
245    U : 'static + Unsigned + IsLessOrEqual<$cordic_bound_3, Output = True> +
246      IsLessOrEqual<$cordic_bound_2, Output = True> +
247      IsLessOrEqual<$cordic_bound_1, Output = True>
248  {
249    fn sin (self) -> Self {
250      cordic::sin (self)
251    }
252    fn sin_cos (self) -> (Self, Self) {
253      cordic::sin_cos (self)
254    }
255    fn cos (self) -> Self {
256      cordic::cos (self)
257    }
258    fn tan (self) -> Self {
259      cordic::tan (self)
260    }
261    fn asin (self) -> Self {
262      cordic::asin (self)
263    }
264    fn acos (self) -> Self {
265      cordic::acos (self)
266    }
267    fn atan (self) -> Self {
268      cordic::atan (self)
269    }
270    fn atan2 (self, other : Self) -> Self {
271      cordic::atan2 (self, other)
272    }
273  }
274}
275
276impl_real_fixed!(FixedI8, U5, U6, U8, fixed_sqrt::traits::LtU8);
277impl_real_fixed!(FixedI16, U13, U14, U16, fixed_sqrt::traits::LtU16);
278impl_real_fixed!(FixedI32, U29, U30, U32, fixed_sqrt::traits::LtU32);
279impl_real_fixed!(FixedI64, U61, U62, U64, fixed_sqrt::traits::LtU64);