Skip to main content

math_utils/
fixed.rs

1use fixed::traits::{Fixed, ToFixed};
2use fixed::types::extra::*;
3
4use crate::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    type NonZero = NonZero <fixed::$fixed <U>>;
126    fn map <F> (self, mut f : F) -> Self where F : FnMut (Self) -> Self {
127      f (self)
128    }
129  }
130  impl <U> Module <Self> for fixed::$fixed <U> where
131    U : Unsigned +
132      IsLessOrEqual<$cordic_bound_2, Output = True> +
133      IsLessOrEqual<$cordic_bound_1, Output = True> +
134      $fixed_sqrt_bound
135  {
136    type LinearEndo = Self;
137  }
138  impl <U> LinearMap <Self, Self, Self> for fixed::$fixed <U> where
139    U : Unsigned +
140      IsLessOrEqual<$cordic_bound_2, Output = True> +
141      IsLessOrEqual<$cordic_bound_1, Output = True> +
142      $fixed_sqrt_bound
143  {
144    fn determinant (self) -> Self {
145      self
146    }
147    fn transpose (self) -> Self {
148      self
149    }
150  }
151  impl <U> Real for fixed::$fixed <U> where
152    U : Unsigned +
153      IsLessOrEqual<$cordic_bound_2, Output = True> +
154      IsLessOrEqual<$cordic_bound_1, Output = True> +
155      $fixed_sqrt_bound
156  {
157    fn pi() -> Self {
158      Self::from_num (fixed::consts::PI)
159    }
160    fn frac_pi_3() -> Self {
161      Self::from_num (fixed::consts::FRAC_PI_3)
162    }
163    fn sqrt_3() -> Self {
164      Self::from_num (fixed::consts::SQRT_3)
165    }
166    fn frac_1_sqrt_3() -> Self {
167      Self::from_num (fixed::consts::FRAC_1_SQRT_3)
168    }
169  }
170  impl <U> Rational for fixed::$fixed <U> where U : Unsigned + $fixed_sqrt_bound {
171    fn floor (self) -> Self {
172      self.floor()
173    }
174    fn ceil (self) -> Self {
175      self.ceil()
176    }
177    fn trunc (self) -> Self {
178      self.int()
179    }
180    fn fract (self) -> Self {
181      self.frac()
182    }
183  }
184  impl <U> MinMax       for fixed::$fixed <U> where U : Unsigned + $fixed_sqrt_bound {
185    fn min (self, other : Self) -> Self {
186      Ord::min (self, other)
187    }
188    fn max (self, other : Self) -> Self {
189      Ord::max (self, other)
190    }
191    fn clamp (self, min : Self, max : Self) -> Self {
192      Ord::clamp (self, min, max)
193    }
194  }
195  impl <U> Sqrt for fixed::$fixed <U> where U : $fixed_sqrt_bound {
196    fn sqrt (self) -> Self {
197      fixed_sqrt::FastSqrt::fast_sqrt (self)
198    }
199  }
200  impl <U> Exp for fixed::$fixed <U> where
201    U : 'static + Unsigned + IsLessOrEqual<$cordic_bound_3, Output = True> +
202      IsLessOrEqual<$cordic_bound_2, Output = True> +
203      IsLessOrEqual<$cordic_bound_1, Output = True>
204  {
205    fn exp (self) -> Self {
206      cordic::exp (self)
207    }
208  }
209  impl <U> Powi for fixed::$fixed <U> where
210    U : Unsigned + IsLessOrEqual<$cordic_bound_2, Output = True> + $fixed_sqrt_bound
211  {
212    fn powi (self, _n : i32) -> Self {
213      unimplemented!("TODO: fixed integer powers")
214    }
215  }
216  impl <U> Powf for fixed::$fixed <U> where
217    U : Unsigned + IsLessOrEqual<$cordic_bound_2, Output = True> + $fixed_sqrt_bound
218  {
219    fn powf (self, _n : Self) -> Self {
220      unimplemented!("TODO: fixed fractional powers")
221    }
222  }
223
224  impl <U> Trig for fixed::$fixed <U> where
225    U : 'static + Unsigned + IsLessOrEqual<$cordic_bound_3, Output = True> +
226      IsLessOrEqual<$cordic_bound_2, Output = True> +
227      IsLessOrEqual<$cordic_bound_1, Output = True>
228  {
229    fn sin (self) -> Self {
230      cordic::sin (self)
231    }
232    fn sin_cos (self) -> (Self, Self) {
233      cordic::sin_cos (self)
234    }
235    fn cos (self) -> Self {
236      cordic::cos (self)
237    }
238    fn tan (self) -> Self {
239      cordic::tan (self)
240    }
241    fn asin (self) -> Self {
242      cordic::asin (self)
243    }
244    fn acos (self) -> Self {
245      cordic::acos (self)
246    }
247    fn atan (self) -> Self {
248      cordic::atan (self)
249    }
250    fn atan2 (self, other : Self) -> Self {
251      cordic::atan2 (self, other)
252    }
253  }
254}
255
256impl_real_fixed!(FixedI8, U5, U6, U8, fixed_sqrt::traits::LtU8);
257impl_real_fixed!(FixedI16, U13, U14, U16, fixed_sqrt::traits::LtU16);
258impl_real_fixed!(FixedI32, U29, U30, U32, fixed_sqrt::traits::LtU32);
259impl_real_fixed!(FixedI64, U61, U62, U64, fixed_sqrt::traits::LtU64);