1use crate::CoordinateType;
10
11use crate::matrix2d::*;
12use crate::point::Point;
13use crate::traits::{Mirror, RotateOrtho, Scale, Translate, TryCastCoord};
14use crate::types::Angle;
15use crate::vector::Vector;
16
17use crate::matrix3d::Matrix3d;
18use crate::types::FloatType;
19use num_traits::{Float, NumCast, One, Zero};
20use std::ops::Mul;
21
22pub trait Transformation {
24 type SourceCoord;
26 type DestinationCoord;
28
29 fn transform_point(&self, p: Point<Self::SourceCoord>) -> Point<Self::DestinationCoord>;
31}
32
33pub trait AffineTransform: Transformation {
36 fn eigen_vectors(&self) -> (Vector<Self::SourceCoord>, Vector<Self::SourceCoord>);
39
40 }
42
43pub trait SimilarityTransform: AffineTransform {
46 fn transform_distance(&self, distance: Self::SourceCoord) -> Self::DestinationCoord;
48}
49
50pub trait SimilarityTransform90:
53 SimilarityTransform<SourceCoord = Self::Coord, DestinationCoord = Self::Coord>
54{
55 type Coord;
57 }
59
60pub trait IsometricTransform: SimilarityTransform {
62 }
64
65pub trait IsometricTransform90: IsometricTransform + SimilarityTransform90 {
68 fn rotation(&self) -> Angle;
72}
73
74pub trait DisplacementTransform: IsometricTransform90 {
76 fn displacement(&self) -> Vector<Self::SourceCoord>;
78}
79
80#[derive(Clone, Hash, PartialEq, Eq, Debug)]
101#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
102pub struct Matrix2dTransform<T: CoordinateType> {
103 matrix: Matrix2d<T>,
104}
105
106impl<T: CoordinateType> Matrix2dTransform<T> {
107 pub fn new(matrix: Matrix2d<T>) -> Self {
109 Matrix2dTransform { matrix }
110 }
111
112 pub fn new_rotation90(angle: Angle) -> Self {
114 let zero = T::zero();
115 let one = T::one();
116 let minus_one = zero - one;
117
118 let matrix = match angle {
119 Angle::R0 => Matrix2d::new(one, zero, zero, one),
120 Angle::R90 => Matrix2d::new(zero, minus_one, one, zero),
121 Angle::R180 => Matrix2d::new(minus_one, zero, zero, minus_one),
122 Angle::R270 => Matrix2d::new(zero, one, minus_one, zero),
123 };
124
125 Matrix2dTransform::new(matrix)
126 }
127
128 pub fn new_scaling(factor: T) -> Self {
130 let zero = T::zero();
131 Matrix2dTransform::new(Matrix2d::new(factor, zero, zero, factor))
132 }
133
134 pub fn new_mirror_x() -> Self {
136 let zero = T::zero();
137 let one = T::one();
138 let minus_one = zero - one;
139 Matrix2dTransform::new(Matrix2d::new(minus_one, zero, zero, one))
140 }
141
142 pub fn new_mirror_y() -> Self {
144 let zero = T::zero();
145 let one = T::one();
146 let minus_one = zero - one;
147 Matrix2dTransform::new(Matrix2d::new(one, zero, zero, minus_one))
148 }
149
150 pub fn transform_point(&self, p: Point<T>) -> Point<T> {
157 self.matrix.mul_column_vector(p.into()).into()
158 }
159
160 pub fn to_matrix2d(&self) -> Matrix2d<T> {
162 self.matrix.clone()
163 }
164
165 pub fn try_invert(&self) -> Option<Self> {
167 self.matrix.try_inverse().map(|inv| Self { matrix: inv })
168 }
169}
170
171#[test]
172fn test_matrix_transform_rotations() {
173 let p = Point::new(1, 0);
174
175 assert_eq!(
176 Matrix2dTransform::new_rotation90(Angle::R0).transform_point(p),
177 p
178 );
179 assert_eq!(
180 Matrix2dTransform::new_rotation90(Angle::R90).transform_point(p),
181 Point::new(0, 1)
182 );
183 assert_eq!(
184 Matrix2dTransform::new_rotation90(Angle::R180).transform_point(p),
185 Point::new(-1, 0)
186 );
187 assert_eq!(
188 Matrix2dTransform::new_rotation90(Angle::R270).transform_point(p),
189 Point::new(0, -1)
190 );
191}
192
193#[derive(Clone, Hash, PartialEq, Eq, Debug)]
196#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
197pub struct Rot90Transform {
198 angle: Angle,
199}
200
201impl Rot90Transform {
202 pub fn new(angle: Angle) -> Self {
204 Rot90Transform { angle }
205 }
206 pub fn is_unitary(&self) -> bool {
208 true
209 }
210 pub fn transform_point<T: CoordinateType>(&self, p: Point<T>) -> Point<T> {
212 p.rotate_ortho(self.angle)
213 }
214
215 pub fn magnification<T: CoordinateType>(&self) -> T {
217 T::one()
218 }
219
220 pub fn try_magnification<T: CoordinateType>(&self) -> Option<T> {
222 Some(self.magnification())
223 }
224}
225
226#[derive(Copy, Clone, PartialEq, Eq, Debug)]
230#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
231pub struct SimpleTransform<T> {
232 pub mirror: bool,
234 pub rotation: Angle,
236 pub magnification: T,
238 pub displacement: Vector<T>,
240}
241
242impl<T: CoordinateType> Default for SimpleTransform<T> {
243 fn default() -> Self {
244 SimpleTransform::identity()
245 }
246}
247
248impl<T> SimpleTransform<T> {
249 pub fn new(mirror: bool, rotation: Angle, magnification: T, displacement: Vector<T>) -> Self {
251 SimpleTransform {
252 mirror,
253 rotation,
254 magnification,
255 displacement,
256 }
257 }
258}
259
260impl<T: Zero + One> SimpleTransform<T> {
261 pub fn identity() -> Self {
263 Self::translate(Vector::zero())
264 }
265
266 pub fn translate<V: Into<Vector<T>>>(v: V) -> Self {
268 let t = v.into();
269 Self::new(false, Angle::R0, T::one(), t)
270 }
271
272 pub fn rotate90(angle: Angle) -> Self {
275 Self::new(false, angle, T::one(), Vector::zero())
276 }
277
278 pub fn rotate_ccw90() -> Self {
280 Self::rotate90(Angle::R90)
281 }
282
283 pub fn rotate_cw90() -> Self {
285 Self::rotate90(Angle::R270)
286 }
287
288 pub fn mirror_x() -> Self {
290 Self::new(true, Angle::R0, T::one(), Vector::zero())
291 }
292
293 pub fn mirror_y() -> Self {
295 Self::new(true, Angle::R180, T::one(), Vector::zero())
296 }
297
298 pub fn scale(factor: T) -> Self {
300 Self::new(false, Angle::R0, factor, Vector::zero())
301 }
302}
303
304impl<T> SimpleTransform<T>
305where
306 T: Copy + Mul<Output = T>,
307{
308 pub fn transform_distance(&self, d: T) -> T {
310 d * self.magnification
311 }
312}
313
314impl<T: CoordinateType> SimpleTransform<T> {
315 pub fn rotate90_around(angle: Angle, rotation_center: Point<T>) -> Self {
317 Self::translate(Point::zero() - rotation_center)
318 .then(&Self::rotate90(angle))
319 .then(&Self::translate(rotation_center))
320 }
321
322 pub fn transform_point(&self, p: Point<T>) -> Point<T> {
324 if self.mirror { p.mirror_x() } else { p }
325 .rotate_ortho(self.rotation)
326 .scale(self.magnification)
327 .translate(self.displacement)
328 }
329
330 pub fn inverse_transform_point(&self, p: Point<T>) -> Point<T> {
332 let p = p
333 .translate(Vector::zero() - self.displacement)
334 .scale(T::one() / self.magnification)
335 .rotate_ortho(-self.rotation);
336
337 if self.mirror {
338 p.mirror_x()
339 } else {
340 p
341 }
342 }
343
344 pub fn to_matrix_transform(&self) -> Matrix3dTransform<T> {
346 if self.mirror {
347 Matrix3dTransform::mirror_x()
348 } else {
349 Matrix3dTransform::identity()
350 }
351 .then_rotate90(self.rotation)
352 .then_scale(self.magnification)
353 .then_translate(self.displacement)
354 }
355
356 pub fn then(&self, t: &Self) -> Self {
359 let d = t.transform_point(self.displacement.into());
360 let r = if t.mirror {
361 -self.rotation
362 } else {
363 self.rotation
364 };
365 Self {
366 mirror: self.mirror ^ t.mirror,
367 rotation: r + t.rotation,
368 magnification: self.magnification * t.magnification,
369 displacement: d.v(),
370 }
371 }
372}
373
374#[test]
375fn test_simple_transform_combine() {
376 let t1 = SimpleTransform::new(false, Angle::R90, 1, (1, 2).into());
377 let t2 = SimpleTransform::new(true, Angle::R90, 1, (3, 4).into());
378
379 let p = Point::new(10, 11);
380 assert_eq!(
381 t2.transform_point(t1.transform_point(p)),
382 t1.then(&t2).transform_point(p)
383 );
384 assert_eq!(
385 t1.transform_point(t2.transform_point(p)),
386 t2.then(&t1).transform_point(p)
387 );
388}
389
390#[derive(Clone, PartialEq, Debug)]
394#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
395pub struct ComplexTransform<T: CoordinateType> {
396 mirror: bool,
398 rotation: FloatType,
400 magnification: FloatType,
402 displacement: Vector<T>,
404}
405
406#[derive(Clone, Hash, PartialEq, Eq, Debug)]
413#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
414pub struct Matrix3dTransform<T: CoordinateType> {
415 pub m11: T,
417 pub m12: T,
419 pub m21: T,
421 pub m22: T,
423 pub m31: T,
425 pub m32: T,
427}
428
429impl<T: CoordinateType> Matrix3dTransform<T> {
430 pub fn new(m11: T, m12: T, m21: T, m22: T, m31: T, m32: T) -> Self {
432 Matrix3dTransform {
433 m11,
434 m12,
435 m21,
436 m22,
437 m31,
438 m32,
439 }
440 }
441
442 pub fn identity() -> Self {
444 Self::translate(Vector::zero())
445 }
446
447 pub fn translate<V: Into<Vector<T>>>(v: V) -> Self {
449 let t = v.into();
450 Self::new(T::one(), T::zero(), T::zero(), T::one(), t.x, t.y)
451 }
452
453 pub fn rotate90(angle: Angle) -> Self {
455 let zero = T::zero();
456 let one = T::one();
457 let minus_one = zero - one;
458
459 let (a, b, c, d) = match angle {
460 Angle::R0 => (one, zero, zero, one),
461 Angle::R90 => (zero, one, minus_one, zero),
462 Angle::R180 => (minus_one, zero, zero, minus_one),
463 Angle::R270 => (zero, minus_one, one, zero),
464 };
465
466 Self::new(a, b, c, d, T::zero(), T::zero())
467 }
468
469 pub fn scale(factor: T) -> Self {
471 let zero = T::zero();
472 Self::new(factor, zero, zero, factor, zero, zero)
473 }
474
475 pub fn mirror_x() -> Self {
477 let zero = T::zero();
478 let one = T::one();
479 let minus_one = zero - one;
480 Self::new(minus_one, zero, zero, one, zero, zero)
481 }
482
483 pub fn mirror_y() -> Self {
485 let zero = T::zero();
486 let one = T::one();
487 let minus_one = zero - one;
488 Self::new(one, zero, zero, minus_one, zero, zero)
489 }
490
491 pub fn transform_point(&self, p: Point<T>) -> Point<T> {
493 Point::new(
494 p.x * self.m11 + p.y * self.m21 + self.m31,
495 p.x * self.m12 + p.y * self.m22 + self.m32,
496 )
497 }
498
499 pub fn to_matrix3d(&self) -> Matrix3d<T> {
501 Matrix3d::new([
502 [self.m11, self.m12, T::zero()],
503 [self.m21, self.m22, T::zero()],
504 [self.m31, self.m32, T::zero()],
505 ])
506 }
507
508 pub fn to_matrix2d(&self) -> Matrix2d<T> {
511 Matrix2d::new(self.m11, self.m12, self.m21, self.m22)
512 }
513
514 pub fn determinant(&self) -> T {
516 self.m11 * self.m22 - self.m12 * self.m21
527 }
528
529 pub fn try_invert(&self) -> Option<Self> {
531 let a = self;
548
549 let det = a.determinant();
551 if !det.is_zero() {
552 Some(Self::new(
553 a.m22 / det,
554 T::zero() - a.m12 / det,
555 T::zero() - a.m21 / det,
556 a.m11 / det,
557 (a.m21 * a.m32 - a.m22 * a.m31) / det,
558 (a.m12 * a.m31 - a.m11 * a.m32) / det,
559 ))
560 } else {
561 None
562 }
563 }
564
565 pub fn then(&self, t: &Self) -> Self {
568 Self::new(
569 self.m11 * t.m11 + self.m12 * t.m21,
570 self.m11 * t.m12 + self.m12 * t.m22,
571 self.m21 * t.m11 + self.m22 * t.m21,
572 self.m21 * t.m12 + self.m22 * t.m22,
573 self.m31 * t.m11 + self.m32 * t.m21 + t.m31,
574 self.m31 * t.m12 + self.m32 * t.m22 + t.m32,
575 )
576 }
577
578 pub fn then_scale(&self, factor: T) -> Self {
580 self.then(&Self::scale(factor))
581 }
582
583 pub fn then_translate<V: Into<Vector<T>>>(&self, v: V) -> Self {
585 self.then(&Self::translate(v))
586 }
587
588 pub fn then_rotate90(&self, angle: Angle) -> Self {
590 self.then(&Self::rotate90(angle))
591 }
592
593 pub fn then_mirror_x(&self) -> Self {
595 self.then(&Self::mirror_x())
596 }
597
598 pub fn then_mirror_y(&self) -> Self {
600 self.then(&Self::mirror_y())
601 }
602
603 pub fn get_translation(&self) -> Vector<T> {
605 Vector::new(self.m31, self.m32)
606 }
607}
608
609impl<T: CoordinateType> Mul for Matrix3dTransform<T> {
610 type Output = Matrix3dTransform<T>;
611
612 fn mul(self, rhs: Self) -> Self::Output {
614 self.then(&rhs)
615 }
616}
617
618#[test]
619fn test_identity() {
620 let p = Point::new(1, 2);
621 let tf = Matrix3dTransform::identity();
622 assert_eq!(tf.transform_point(p), p);
623}
624
625#[test]
626fn test_translate() {
627 let p = Point::new(1, 2);
628 let tf = Matrix3dTransform::translate(Vector::new(10, 100));
629 assert_eq!(tf.transform_point(p), Point::new(11, 102));
630 assert_eq!(tf.get_translation(), Vector::new(10, 100));
631}
632
633#[test]
634fn test_rotate90() {
635 let p = Point::new(1, 2);
636 let tf = Matrix3dTransform::rotate90(Angle::R0);
637 assert_eq!(tf.transform_point(p), Point::new(1, 2));
638 let tf = Matrix3dTransform::rotate90(Angle::R90);
639 assert_eq!(tf.transform_point(p), Point::new(-2, 1));
640 let tf = Matrix3dTransform::rotate90(Angle::R180);
641 assert_eq!(tf.transform_point(p), Point::new(-1, -2));
642 let tf = Matrix3dTransform::rotate90(Angle::R270);
643 assert_eq!(tf.transform_point(p), Point::new(2, -1));
644}
645
646#[test]
647fn test_scale() {
648 let p = Point::new(1, 2);
649 let tf = Matrix3dTransform::scale(2);
650 assert_eq!(tf.transform_point(p), Point::new(2, 4));
651}
652
653impl<T: CoordinateType + Float> Matrix3dTransform<T> {
654 pub fn rotation(phi: T) -> Self {
656 let zero = T::zero();
657 let cos = phi.cos();
658 let sin = phi.sin();
659 Self::new(cos, sin, zero - sin, cos, T::zero(), T::zero())
660 }
661
662 pub fn then_rotate(&self, phi: T) -> Self {
664 self.then(&Self::rotation(phi))
665 }
666}
667
668#[test]
669fn test_rotate() {
670 let p = Point::new(1.0, 0.0);
671 let pi = std::f64::consts::PI;
672 let tf = Matrix3dTransform::rotation(pi);
673 assert!((tf.transform_point(p) - Point::new(-1.0, 0.0)).norm2_squared() < 1e-6);
674 let tf = Matrix3dTransform::rotation(pi * 0.5);
675 assert!((tf.transform_point(p) - Point::new(0.0, 1.0)).norm2_squared() < 1e-6);
676}
677
678#[test]
679fn test_then() {
680 let tf1 = Matrix3dTransform::translate((1, 2));
681 let id: Matrix3dTransform<i32> = Matrix3dTransform::identity();
682 assert_eq!(tf1.then(&id), tf1);
683
684 let tf1_tf1 = Matrix3dTransform::translate((2, 4));
685 assert_eq!(tf1.then(&tf1), tf1_tf1);
686
687 let tf3 = Matrix3dTransform::rotate90(Angle::R90);
688 assert_eq!(tf3.then(&tf3).then(&tf3).then(&tf3), id);
689}
690
691#[test]
692fn test_invert() {
693 let id: Matrix3dTransform<i32> = Matrix3dTransform::identity();
694 assert_eq!(id.try_invert(), Some(id));
695
696 let tf1 = Matrix3dTransform::translate((1, 2));
697 let tf1_inv = tf1.try_invert().unwrap();
698 assert_eq!(tf1.then(&tf1_inv), Matrix3dTransform::identity());
699
700 let tf2 = Matrix3dTransform::translate((1, 2))
701 .then_rotate90(Angle::R90)
702 .then_mirror_x();
703 assert!(tf2.to_matrix2d().is_unitary());
704
705 let tf2_inv = tf2.try_invert().unwrap();
706 assert_eq!(tf2.then(&tf2_inv), Matrix3dTransform::identity());
707
708 assert_eq!(tf2.try_invert().unwrap().try_invert(), Some(tf2));
709}
710
711#[test]
712fn test_invert_float() {
713 let tf = Matrix3dTransform::rotation(1.234)
714 .then_scale(12345.6)
715 .then_translate((1.2, 34.5));
716 let tf_inv = tf.try_invert().unwrap();
717 let p = Point::new(42.42, -1.0);
718 let p2 = tf_inv.transform_point(tf.transform_point(p));
719 assert!((p - p2).norm2_squared() < 1e-6); }
721
722impl<T: CoordinateType + NumCast, Dst: CoordinateType + NumCast> TryCastCoord<T, Dst>
723 for SimpleTransform<T>
724{
725 type Output = SimpleTransform<Dst>;
726
727 fn try_cast(&self) -> Option<Self::Output> {
728 match (self.displacement.try_cast(), Dst::from(self.magnification)) {
729 (Some(displacement), Some(magnification)) => Some(Self::Output {
730 mirror: self.mirror,
731 displacement,
732 magnification,
733 rotation: self.rotation,
734 }),
735 _ => None,
736 }
737 }
738}