measures/inner/exact/
affine_map_2d.rs

1#[macro_export] // Don't add nor remove the first three lines and the last two lines.
2macro_rules! inner_define_affine_map_2d {
3    {} => {
4        /// Affine transformation of `MeasurePoint2d` objects.
5        pub struct AffineMap2d<Unit, Number = f64>
6        where
7            Unit: MeasurementUnit<Property: VectorProperty>,
8            Number: ArithmeticOps,
9        {
10            pub c: [[Number; 3]; 2],
11            phantom: core::marker::PhantomData<Unit>,
12        }
13
14        impl<Unit, Number> AffineMap2d<Unit, Number>
15        where
16            Unit: MeasurementUnit<Property: VectorProperty>,
17            Number: ArithmeticOps,
18        {
19            /// Create an AffineMap2d from its 6 coefficients.
20            pub const fn new(coefficients: [[Number; 3]; 2]) -> Self {
21                Self {
22                    c: coefficients,
23                    phantom: PhantomData,
24                }
25            }
26
27            // Unit conversion.
28            pub fn convert<DestUnit>(&self) -> AffineMap2d<DestUnit, Number>
29            where
30                DestUnit: MeasurementUnit<Property = Unit::Property>,
31            {
32                let factor = Number::from_f64(Unit::RATIO / DestUnit::RATIO);
33                AffineMap2d::<DestUnit, Number>::new([
34                    [self.c[0][0], self.c[0][1], self.c[0][2] * factor],
35                    [self.c[1][0], self.c[1][1], self.c[1][2] * factor],
36                ])
37            }
38
39            // Translation.
40            pub const fn translation(v: Measure2d<Unit, Number>) -> Self {
41                Self::new([
42                    [Number::ONE, Number::ZERO, v.values[0]],
43                    [Number::ZERO, Number::ONE, v.values[1]],
44                ])
45            }
46
47            // Rotation about a point by an angle measure.
48            pub fn rotation<AngleUnit>(
49                fixed_point: MeasurePoint2d<Unit, Number>,
50                angle: Measure<AngleUnit, Number>,
51            ) -> Self
52            where
53                AngleUnit: AngleMeasurementUnit,
54            {
55                Self::rotation_by_radians(fixed_point.values, angle.convert::<Radian>().value)
56            }
57
58            /// Create a rotation to the right.
59            pub fn right_rotation(fixed_point: MeasurePoint2d<Unit, Number>) -> Self {
60                Self::right_rotation_by_sin(fixed_point.values, -Number::ONE)
61            }
62
63            /// Create a rotation to the left.
64            pub fn left_rotation(fixed_point: MeasurePoint2d<Unit, Number>) -> Self {
65                Self::right_rotation_by_sin(fixed_point.values, Number::ONE)
66            }
67
68            // Projections
69
70            // Projection onto a line identified by a fixed point
71            // and a value which can be converted into a point angle.
72            pub fn projection_by_angle<AngleUnit>(
73                fixed_point: MeasurePoint2d<Unit, Number>,
74                angle: impl Into<MeasurePoint<AngleUnit, Number>>,
75            ) -> Self
76            where
77                AngleUnit: AngleMeasurementUnit,
78            {
79                let (sin_a, cos_a) = angle.into().convert::<Radian>().value.sin_cos();
80                Self::projection_by_cos_sin(fixed_point.values, cos_a, sin_a)
81            }
82
83            // Projection onto a line identified by a fixed point
84            // and a unit plane vector.
85            // Precondition: v.squared_norm().value == 1
86            pub fn projection_by_unit_vector(
87                fixed_point: MeasurePoint2d<Unit, Number>,
88                uv: Measure2d<Unit, Number>,
89            ) -> Self {
90                Self::projection_by_cos_sin(fixed_point.values, uv.values[0], uv.values[1])
91            }
92
93            // Reflections
94
95            // Reflection over a line identified by a fixed point
96            // and a value which can be converted into a point angle.
97            pub fn reflection_by_angle<AngleUnit>(
98                fixed_point: MeasurePoint2d<Unit, Number>,
99                angle: impl Into<MeasurePoint<AngleUnit, Number>>,
100            ) -> Self
101            where
102                AngleUnit: AngleMeasurementUnit,
103            {
104                let (sin_a, cos_a) = angle.into().convert::<Radian>().value.sin_cos();
105                Self::reflection_by_cos_sin(fixed_point.values, cos_a, sin_a)
106            }
107
108            // Reflection over a line identified by a fixed point
109            // and a unit plane vector.
110            // Precondition: v.squared_norm().value == 1
111            pub fn reflection_by_unit_vector(
112                fixed_point: MeasurePoint2d<Unit, Number>,
113                uv: Measure2d<Unit, Number>,
114            ) -> Self {
115                Self::reflection_by_cos_sin(fixed_point.values, uv.values[0], uv.values[1])
116            }
117
118            // Scaling by two factors from a fixed point.
119            pub fn scaling(fixed_point: MeasurePoint2d<Unit, Number>, factors: [Number; 2]) -> Self {
120                Self::new([
121                    [
122                        factors[0],
123                        Number::ZERO,
124                        fixed_point.values[0] * (Number::ONE - factors[0]),
125                    ],
126                    [
127                        Number::ZERO,
128                        factors[1],
129                        fixed_point.values[1] * (Number::ONE - factors[1]),
130                    ],
131                ])
132            }
133
134            pub fn inverted(&self) -> Self {
135                let inv_determinant =
136                    Number::ONE / (self.c[0][0] * self.c[1][1] - self.c[0][1] * self.c[1][0]);
137                Self::new([
138                    [
139                        self.c[1][1] * inv_determinant,
140                        self.c[0][1] * -inv_determinant,
141                        (self.c[0][1] * self.c[1][2] - self.c[0][2] * self.c[1][1]) * inv_determinant,
142                    ],
143                    [
144                        self.c[1][0] * -inv_determinant,
145                        self.c[0][0] * inv_determinant,
146                        (self.c[0][2] * self.c[1][0] - self.c[0][0] * self.c[1][2]) * inv_determinant,
147                    ],
148                ])
149            }
150
151            // Composition of two plane affine transformations.
152            // Applying the resulting transformation is equivalent to apply first
153            // `other` and then `self`.
154            pub fn combined_with(&self, other: &AffineMap2d<Unit, Number>) -> Self {
155                Self::new([
156                    [
157                        other.c[0][0] * self.c[0][0] + other.c[0][1] * self.c[1][0],
158                        other.c[0][0] * self.c[0][1] + other.c[0][1] * self.c[1][1],
159                        other.c[0][0] * self.c[0][2] + other.c[0][1] * self.c[1][2] + other.c[0][2],
160                    ],
161                    [
162                        other.c[1][0] * self.c[0][0] + other.c[1][1] * self.c[1][0],
163                        other.c[1][0] * self.c[0][1] + other.c[1][1] * self.c[1][1],
164                        other.c[1][0] * self.c[0][2] + other.c[1][1] * self.c[1][2] + other.c[1][2],
165                    ],
166                ])
167            }
168
169            pub fn apply_to(&self, m: MeasurePoint2d<Unit, Number>) -> MeasurePoint2d<Unit, Number> {
170                MeasurePoint2d::<Unit, Number>::new([
171                    self.c[0][0] * m.values[0] + self.c[0][1] * m.values[1] + self.c[0][2],
172                    self.c[1][0] * m.values[0] + self.c[1][1] * m.values[1] + self.c[1][2],
173                ])
174            }
175
176            fn rotation_by_radians(fp: [Number; 2], radians: Number) -> Self {
177                let (sin_a, cos_a) = radians.sin_cos();
178                Self::new([
179                    [cos_a, -sin_a, fp[0] - cos_a * fp[0] + sin_a * fp[1]],
180                    [sin_a, cos_a, fp[1] - sin_a * fp[0] - cos_a * fp[1]],
181                ])
182            }
183
184            fn right_rotation_by_sin(fp: [Number; 2], sine: Number) -> Self {
185                Self::new([
186                    [Number::ZERO, -sine, fp[0] + sine * fp[1]],
187                    [sine, Number::ZERO, fp[1] - sine * fp[0]],
188                ])
189            }
190
191            fn projection_by_cos_sin(fp: [Number; 2], cos_a: Number, sin_a: Number) -> Self {
192                let cc = cos_a * cos_a;
193                let cs = cos_a * sin_a;
194                let ss = sin_a * sin_a;
195                let sxmcy = sin_a * fp[0] - cos_a * fp[1];
196                Self::new([[cc, cs, sin_a * sxmcy], [cs, ss, -cos_a * sxmcy]])
197            }
198
199            fn reflection_by_cos_sin(fp: [Number; 2], cos_a: Number, sin_a: Number) -> Self {
200                let c2ms2 = cos_a * cos_a - sin_a * sin_a;
201                let two = Number::ONE + Number::ONE;
202                let cs_bis = two * cos_a * sin_a;
203                let sxmcy_bis = two * (sin_a * fp[0] - cos_a * fp[1]);
204                Self::new([
205                    [c2ms2, cs_bis, sin_a * sxmcy_bis],
206                    [cs_bis, -c2ms2, -cos_a * sxmcy_bis],
207                ])
208            }
209        }
210
211        impl<Unit, Number> Default for AffineMap2d<Unit, Number>
212        where
213            Unit: MeasurementUnit<Property: VectorProperty>,
214            Number: ArithmeticOps,
215        {
216            /// AffineMap2d::default() -> AffineMap2d
217            /// It returns the identity transformation.
218            fn default() -> Self {
219                Self::new([
220                    [Number::ONE, Number::ZERO, Number::ZERO],
221                    [Number::ZERO, Number::ONE, Number::ZERO],
222                ])
223            }
224        }
225
226        // AffineMap2d == AffineMap2d -> bool
227        impl<Unit, Number> PartialEq<AffineMap2d<Unit, Number>> for AffineMap2d<Unit, Number>
228        where
229            Unit: MeasurementUnit<Property: VectorProperty>,
230            Number: ArithmeticOps,
231        {
232            fn eq(&self, other: &AffineMap2d<Unit, Number>) -> bool {
233                self.c == other.c
234            }
235        }
236
237        // AffineMap2d.clone() -> AffineMap2d
238        impl<Unit, Number> Clone for AffineMap2d<Unit, Number>
239        where
240            Unit: MeasurementUnit<Property: VectorProperty>,
241            Number: ArithmeticOps,
242        {
243            fn clone(&self) -> Self {
244                Self::new(self.c.clone())
245            }
246        }
247
248        impl<Unit> From<AffineMap2d<Unit, f32>> for AffineMap2d<Unit, f64>
249        where
250            Unit: MeasurementUnit<Property: VectorProperty>,
251        {
252            fn from(m: AffineMap2d<Unit, f32>) -> Self {
253                Self::new([
254                    [m.c[0][0] as f64, m.c[0][1] as f64, m.c[0][2] as f64],
255                    [m.c[1][0] as f64, m.c[1][1] as f64, m.c[1][2] as f64],
256                ])
257            }
258        }
259
260        /// format!("{}", AffineMap2d) -> String
261        /// AffineMap2d.to_string() -> String
262        impl<Unit, Number> fmt::Display for AffineMap2d<Unit, Number>
263        where
264            Unit: MeasurementUnit<Property: VectorProperty>,
265            Number: ArithmeticOps,
266        {
267            fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
268                write!(
269                    formatter,
270                    "{}",
271                    measures::matrix_utils::format_matrix::<2, 3, Number>(&self.c, Unit::SUFFIX, 1)
272                )
273            }
274        }
275
276        // format!("{:?}", AffineMap2d)
277        impl<Unit, Number> fmt::Debug for AffineMap2d<Unit, Number>
278        where
279            Unit: MeasurementUnit<Property: VectorProperty>,
280            Number: ArithmeticOps,
281        {
282            fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
283                write!(
284                    formatter,
285                    "{}",
286                    measures::matrix_utils::format_matrix::<2, 3, Number>(&self.c, Unit::SUFFIX, 1)
287                )
288            }
289        }
290    };
291}