rs_measures/inner/
linear_map_2d.rs

1#[macro_export]
2macro_rules! inner_define_linear_map_2d {
3    {} => {
4        pub struct LinearMap2d<Number: ArithmeticOps> {
5            c: [[Number; 2]; 2],
6        }
7
8        impl<Number: ArithmeticOps> LinearMap2d<Number> {
9            pub const fn new(coefficients: [[Number; 2]; 2]) -> Self {
10                Self { c: coefficients }
11            }
12
13            // No translations
14
15            //// Rotations
16
17            // Rotation by an angle measure.
18            pub fn rotation<AngleUnit: AngleMeasurementUnit<Property = Angle>>(
19                angle: Measure<AngleUnit, Number>,
20            ) -> Self {
21                Self::rotation_by_radians(angle.convert::<Radian>().value)
22            }
23
24            pub fn rotation_at_right() -> Self {
25                Self {
26                    c: [[Number::ZERO, Number::ONE], [-Number::ONE, Number::ZERO]],
27                }
28            }
29
30            pub fn rotation_at_left() -> Self {
31                Self {
32                    c: [[Number::ZERO, -Number::ONE], [Number::ONE, Number::ZERO]],
33                }
34            }
35
36            //// Projections
37
38            // Projection onto a line identified by a measure point angle.
39            pub fn projection_by_point_angle<Unit: AngleMeasurementUnit<Property = Angle>>(
40                angle: MeasurePoint<Unit, Number>,
41            ) -> Self {
42                Self::projection_by_radians(angle.convert::<Radian>().value)
43            }
44
45            // Projection onto a line identified by a signed direction.
46            pub fn projection_by_signed_direction<Unit: AngleMeasurementUnit<Property = Angle>>(
47                direction: SignedDirection<Unit, Number>,
48            ) -> Self {
49                Self::projection_by_radians(direction.convert::<Radian>().value)
50            }
51
52            // Projection onto a line identified by an unsigned direction.
53            pub fn projection_by_unsigned_direction<Unit: AngleMeasurementUnit<Property = Angle>>(
54                angle: UnsignedDirection<Unit, Number>,
55            ) -> Self {
56                Self::projection_by_radians(angle.convert::<Radian>().value)
57            }
58
59            // Projection onto a line identified by a unit plane vector.
60            // Precondition: unit_v.squared_norm().value == 1
61            pub fn projection_by_unit_vector<Unit: MeasurementUnit>(v: Measure2d<Unit, Number>) -> Self {
62                Self::projection_by_cos_sin(v.x, v.y)
63            }
64
65            //// Reflections
66
67            // Reflection over a line identified by a point angle.
68            pub fn reflection_by_point_angle<AngleUnit: AngleMeasurementUnit<Property = Angle>>(
69                angle: MeasurePoint<AngleUnit, Number>,
70            ) -> Self {
71                Self::reflection_by_radians(angle.convert::<Radian>().value)
72            }
73
74            // Reflection over a line identified by a signed direction.
75            pub fn reflection_by_signed_direction<AngleUnit: AngleMeasurementUnit<Property = Angle>>(
76                direction: SignedDirection<AngleUnit, Number>,
77            ) -> Self {
78                Self::reflection_by_radians(direction.convert::<Radian>().value)
79            }
80
81            // Reflection over a line identified by an unsigned direction.
82            pub fn reflection_by_unsigned_direction<AngleUnit: AngleMeasurementUnit<Property = Angle>>(
83                direction: UnsignedDirection<AngleUnit, Number>,
84            ) -> Self {
85                Self::reflection_by_radians(direction.convert::<Radian>().value)
86            }
87
88            // Reflection over a line identified by a unit plane vector.
89            // Precondition: v.squared_norm() == 1
90            pub fn reflection_by_unit_vector<Unit: MeasurementUnit>(v: Measure2d<Unit, Number>) -> Self {
91                Self::reflection_by_cos_sin(v.x, v.y)
92            }
93
94            //// Scaling by two factors.
95
96            pub fn scaling(kx: Number, ky: Number) -> Self {
97                Self {
98                    c: [[kx, Number::ZERO], [Number::ZERO, ky]],
99                }
100            }
101
102            //// Inversion
103
104            pub fn inverted(&self) -> Self {
105                let inv_determinant =
106                    Number::ONE / (self.c[0][0] * self.c[1][1] - self.c[0][1] * self.c[1][0]);
107                Self {
108                    c: [
109                        [
110                            self.c[1][1] * inv_determinant,
111                            self.c[0][1] * -inv_determinant,
112                        ],
113                        [
114                            self.c[1][0] * -inv_determinant,
115                            self.c[0][0] * inv_determinant,
116                        ],
117                    ],
118                }
119            }
120
121            // Composition of two plane linear transformations.
122            // Applying the resulting transformation is equivalent to apply first
123            // `other` and then `self`.
124            pub fn combined_with(&self, other: &LinearMap2d<Number>) -> Self {
125                Self {
126                    c: [
127                        [
128                            other.c[0][0] * self.c[0][0] + other.c[0][1] * self.c[1][0],
129                            other.c[0][0] * self.c[0][1] + other.c[0][1] * self.c[1][1],
130                        ],
131                        [
132                            other.c[1][0] * self.c[0][0] + other.c[1][1] * self.c[1][0],
133                            other.c[1][0] * self.c[0][1] + other.c[1][1] * self.c[1][1],
134                        ],
135                    ],
136                }
137            }
138
139            pub fn apply_to<Unit: MeasurementUnit>(
140                &self,
141                m: Measure2d<Unit, Number>,
142            ) -> Measure2d<Unit, Number>
143            where
144                Unit::Property: VectorProperty,
145            {
146                Measure2d::<Unit, Number>::new(
147                    self.c[0][0] * m.x + self.c[0][1] * m.y,
148                    self.c[1][0] * m.x + self.c[1][1] * m.y,
149                )
150            }
151
152            fn rotation_by_radians(a: Number) -> Self {
153                let (sin_a, cos_a) = a.sin_cos();
154                Self {
155                    c: [[cos_a, -sin_a], [sin_a, cos_a]],
156                }
157            }
158
159            fn projection_by_cos_sin(cos_a: Number, sin_a: Number) -> Self {
160                Self {
161                    c: [
162                        [cos_a * cos_a, cos_a * sin_a],
163                        [sin_a * cos_a, sin_a * sin_a],
164                    ],
165                }
166            }
167
168            fn projection_by_radians(a: Number) -> Self {
169                let (sin_a, cos_a) = a.sin_cos();
170                Self::projection_by_cos_sin(cos_a, sin_a)
171            }
172
173            fn reflection_by_cos_sin(cos_a: Number, sin_a: Number) -> Self {
174                let one = Number::ONE;
175                let two = Number::ONE + Number::ONE;
176                Self {
177                    c: [
178                        [two * cos_a * cos_a - one, two * cos_a * sin_a],
179                        [two * cos_a * sin_a, two * sin_a * sin_a - one],
180                    ],
181                }
182            }
183
184            fn reflection_by_radians(radians: Number) -> Self {
185                let (sin_a, cos_a) = radians.sin_cos();
186                Self::reflection_by_cos_sin(cos_a, sin_a)
187            }
188        }
189
190        impl<Number> Default for LinearMap2d<Number>
191        where
192            Number: ArithmeticOps,
193        {
194            // It returns the identity transformation.
195            fn default() -> Self {
196                Self::new([[Number::ONE, Number::ZERO], [Number::ZERO, Number::ONE]])
197            }
198        }
199
200        // format!("{}", LinearMap2d)
201        impl<Number: ArithmeticOps> fmt::Display for LinearMap2d<Number> {
202            fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
203                write!(
204                    formatter,
205                    "{}",
206                    rs_measures::matrix_utils::format_matrix::<2, 2, Number>(&self.c, "")
207                )
208            }
209        }
210
211        // format!("{:?}", LinearMap2d)
212        impl<Number: ArithmeticOps> fmt::Debug for LinearMap2d<Number> {
213            fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
214                write!(
215                    formatter,
216                    "{}",
217                    rs_measures::matrix_utils::format_matrix::<2, 2, Number>(&self.c, "")
218                )
219            }
220        }
221    };
222}