swf/types/
point.rs

1use crate::Twips;
2use std::fmt;
3use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
4
5pub trait Coordinate:
6    Copy
7    + Add<Output = Self>
8    + AddAssign
9    + Sub<Output = Self>
10    + SubAssign
11    + Mul<i32, Output = Self>
12    + MulAssign<i32>
13    + Div<i32, Output = Self>
14    + DivAssign<i32>
15    + Neg<Output = Self>
16    + fmt::Display
17{
18    const ZERO: Self;
19}
20
21impl Coordinate for i32 {
22    const ZERO: Self = 0;
23}
24
25impl Coordinate for Twips {
26    const ZERO: Self = Self::ZERO;
27}
28
29/// A 2D position defined by x and y coordinates.
30#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
31pub struct Point<T: Coordinate> {
32    pub x: T,
33    pub y: T,
34}
35
36impl<T: Coordinate> Point<T> {
37    /// The `Point` object with a value of `(0, 0)`.
38    ///
39    /// # Examples
40    ///
41    /// ```rust
42    /// assert_eq!(swf::Point::<swf::Twips>::ZERO.x, swf::Twips::ZERO);
43    /// assert_eq!(swf::Point::<swf::Twips>::ZERO.y, swf::Twips::ZERO);
44    /// ```
45    pub const ZERO: Self = Self {
46        x: T::ZERO,
47        y: T::ZERO,
48    };
49
50    pub const fn new(x: T, y: T) -> Self {
51        Self { x, y }
52    }
53}
54
55impl Point<Twips> {
56    /// Converts the given number of `pixels` into twips.
57    ///
58    /// This may be a lossy conversion; any precision more than a twip (1/20 pixels) is truncated.
59    ///
60    /// # Examples
61    ///
62    /// ```rust
63    /// // 40 pixels is equivalent to 800 twips.
64    /// let point = swf::Point::from_pixels(40.0, 20.0);
65    /// assert_eq!(point.x.get(), 800);
66    /// assert_eq!(point.y.get(), 400);
67    ///
68    /// // Output is truncated if more precise than a twip (1/20 pixels).
69    /// let point = swf::Point::from_pixels(40.018, 20.0);
70    /// assert_eq!(point.x.get(), 800);
71    /// assert_eq!(point.y.get(), 400);
72    /// ```
73    #[inline]
74    pub fn from_pixels(x: f64, y: f64) -> Self {
75        Self {
76            x: Twips::from_pixels(x),
77            y: Twips::from_pixels(y),
78        }
79    }
80}
81
82// point + delta
83impl<T: Coordinate> Add<PointDelta<T>> for Point<T> {
84    type Output = Self;
85
86    #[inline]
87    fn add(self, other: PointDelta<T>) -> Self {
88        Self {
89            x: self.x + other.dx,
90            y: self.y + other.dy,
91        }
92    }
93}
94
95// point += delta
96impl<T: Coordinate> AddAssign<PointDelta<T>> for Point<T> {
97    #[inline]
98    fn add_assign(&mut self, other: PointDelta<T>) {
99        self.x += other.dx;
100        self.y += other.dy;
101    }
102}
103
104// point - delta
105impl<T: Coordinate> Sub<PointDelta<T>> for Point<T> {
106    type Output = Self;
107
108    #[inline]
109    fn sub(self, other: PointDelta<T>) -> Self {
110        Self {
111            x: self.x - other.dx,
112            y: self.y - other.dy,
113        }
114    }
115}
116
117// point -= delta
118impl<T: Coordinate> SubAssign<PointDelta<T>> for Point<T> {
119    #[inline]
120    fn sub_assign(&mut self, other: PointDelta<T>) {
121        self.x -= other.dx;
122        self.y -= other.dy;
123    }
124}
125
126// point - point
127impl<T: Coordinate> Sub for Point<T> {
128    type Output = PointDelta<T>;
129
130    #[inline]
131    fn sub(self, other: Self) -> PointDelta<T> {
132        PointDelta {
133            dx: self.x - other.x,
134            dy: self.y - other.y,
135        }
136    }
137}
138
139impl<T: Coordinate> fmt::Display for Point<T> {
140    #[inline]
141    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
142        write!(f, "({}, {})", self.x, self.y)
143    }
144}
145
146/// A difference between two 2D points.
147#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
148pub struct PointDelta<T: Coordinate> {
149    pub dx: T,
150    pub dy: T,
151}
152
153impl<T: Coordinate> PointDelta<T> {
154    /// The `PointDelta` object with a value of `(0, 0)`.
155    ///
156    /// # Examples
157    ///
158    /// ```rust
159    /// assert_eq!(swf::PointDelta::<swf::Twips>::ZERO.dx, swf::Twips::ZERO);
160    /// assert_eq!(swf::PointDelta::<swf::Twips>::ZERO.dy, swf::Twips::ZERO);
161    /// ```
162    pub const ZERO: Self = Self {
163        dx: T::ZERO,
164        dy: T::ZERO,
165    };
166
167    pub const fn new(dx: T, dy: T) -> Self {
168        Self { dx, dy }
169    }
170}
171
172impl PointDelta<Twips> {
173    /// Converts the given number of `pixels` into twips.
174    ///
175    /// This may be a lossy conversion; any precision more than a twip (1/20 pixels) is truncated.
176    ///
177    /// # Examples
178    ///
179    /// ```rust
180    /// // 40 pixels is equivalent to 800 twips.
181    /// let point = swf::PointDelta::from_pixels(40.0, 20.0);
182    /// assert_eq!(point.dx.get(), 800);
183    /// assert_eq!(point.dy.get(), 400);
184    ///
185    /// // Output is truncated if more precise than a twip (1/20 pixels).
186    /// let point = swf::PointDelta::from_pixels(40.018, 20.0);
187    /// assert_eq!(point.dx.get(), 800);
188    /// assert_eq!(point.dy.get(), 400);
189    /// ```
190    #[inline]
191    pub fn from_pixels(dx: f64, dy: f64) -> Self {
192        Self {
193            dx: Twips::from_pixels(dx),
194            dy: Twips::from_pixels(dy),
195        }
196    }
197}
198
199// delta * i32
200impl<T: Coordinate> Mul<i32> for PointDelta<T> {
201    type Output = Self;
202
203    #[inline]
204    fn mul(self, other: i32) -> Self {
205        Self {
206            dx: self.dx * other,
207            dy: self.dy * other,
208        }
209    }
210}
211
212// delta *= i32
213impl<T: Coordinate> MulAssign<i32> for PointDelta<T> {
214    #[inline]
215    fn mul_assign(&mut self, other: i32) {
216        self.dx *= other;
217        self.dy *= other;
218    }
219}
220
221// delta / i32
222impl<T: Coordinate> Div<i32> for PointDelta<T> {
223    type Output = Self;
224
225    #[inline]
226    fn div(self, other: i32) -> Self {
227        Self {
228            dx: self.dx / other,
229            dy: self.dy / other,
230        }
231    }
232}
233
234// delta /= i32
235impl<T: Coordinate> DivAssign<i32> for PointDelta<T> {
236    #[inline]
237    fn div_assign(&mut self, other: i32) {
238        self.dx /= other;
239        self.dy /= other;
240    }
241}
242
243// -delta
244impl<T: Coordinate> Neg for PointDelta<T> {
245    type Output = Self;
246
247    #[inline]
248    fn neg(self) -> Self {
249        Self {
250            dx: -self.dx,
251            dy: -self.dy,
252        }
253    }
254}