1use std::convert::From;
2use std::ops::Add;
3
4use num_traits::sign::Signed;
5
6use crate::geom::Line;
7use crate::geom::Point;
8use crate::geom::Size;
9use crate::num::Num;
10use crate::num::NumIdentity;
11
12#[derive(Copy, Clone, Debug, PartialEq)]
13pub struct Transform<N: Num = f32> {
14 scale: Size<N>,
15 position: Point<N>,
16 rotation: f32,
17}
18
19impl<N: Num> Transform<N> {
20 #[must_use]
21 pub fn new() -> Self {
22 Self {
23 position: Point::new_zero_value(),
24 scale: Size::new_one_value(),
25 rotation: 0.0,
26 }
27 }
28
29 #[must_use]
30 pub fn set_position(mut self, position: Point<N>) -> Self {
31 self.position = position;
32 self
33 }
34
35 pub fn position(&self) -> Point<N> {
36 self.position
37 }
38
39 #[must_use]
40 pub fn set_rotation(mut self, rotation: f32) -> Self {
41 self.rotation = rotation;
42 self
43 }
44
45 pub fn rotation(&self) -> f32 {
46 self.rotation
47 }
48
49 #[must_use]
50 fn set_scale_width(mut self, scale_width: N) -> Self {
51 self.scale.set_width(scale_width);
52 self
53 }
54
55 #[must_use]
56 fn set_scale_height(mut self, scale_height: N) -> Self {
57 self.scale.set_height(scale_height);
58 self
59 }
60
61 #[must_use]
62 pub fn set_scale(mut self, scale: Size<N>) -> Self {
63 self.scale = scale;
64 self
65 }
66
67 pub fn scale(self) -> Size<N> {
68 self.scale
69 }
70}
71
72impl<N> Transform<N>
73where
74 N: Num + Signed,
75{
76 pub fn set_flip_x_from_dir_num(self, dir: f32) -> Self {
77 self.set_flip_x_from_bool(dir < 0.0)
78 }
79
80 pub fn set_flip_y_from_dir_num(self, dir: f32) -> Self {
81 self.set_flip_y_from_bool(dir < 0.0)
82 }
83
84 pub fn set_flip_x_from_bool(self, is_flipped: bool) -> Self {
85 if is_flipped {
86 self.set_scale_width(-<N as NumIdentity>::one())
87 } else {
88 self.set_scale_width(<N as NumIdentity>::one())
89 }
90 }
91
92 pub fn set_flip_y_from_bool(self, is_flipped: bool) -> Self {
93 if is_flipped {
94 self.set_scale_height(-<N as NumIdentity>::one())
95 } else {
96 self.set_scale_height(<N as NumIdentity>::one())
97 }
98 }
99}
100
101impl<N> Add<Line<N>> for Transform<N>
102where
103 N: Num,
104{
105 type Output = Line<N>;
106
107 fn add(self, line: Self::Output) -> Self::Output {
108 line.rotate_around_zero(self.rotation()) * self.scale() + self.position()
109 }
110}
111
112impl<N> Add<Point<N>> for Transform<N>
113where
114 N: Num,
115{
116 type Output = Point<N>;
117
118 fn add(self, point: Self::Output) -> Self::Output {
119 point.rotate_around_zero(self.rotation()) * self.scale() + self.position()
120 }
121}
122
123impl<N> From<Point<N>> for Transform<N>
124where
125 N: Num,
126{
127 fn from(p: Point<N>) -> Self {
128 Self::new().set_position(p)
129 }
130}
131
132impl<N> From<Size<N>> for Transform<N>
133where
134 N: Num,
135{
136 fn from(s: Size<N>) -> Self {
137 Self::new().set_scale(s)
138 }
139}