bracket_geometry/
point.rs

1use std::convert::{From, TryInto};
2use std::ops;
3use ultraviolet::Vec2;
4
5/// A 2D floating-point position.
6pub type PointF = Vec2;
7
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9#[derive(Eq, PartialEq, Copy, Clone, Debug, Hash)]
10/// Helper struct defining a 2D point in space.
11pub struct Point {
12    /// The point's X location
13    pub x: i32,
14    /// The point's Y location
15    pub y: i32,
16}
17
18#[cfg(feature = "specs")]
19impl specs::prelude::Component for Point {
20    type Storage = specs::prelude::VecStorage<Self>;
21}
22
23#[cfg(feature = "bevy")]
24impl bevy::ecs::component::Component for Point {
25    type Storage = bevy::ecs::component::TableStorage;
26}
27
28impl Point {
29    /// Create a new point from an x/y coordinate.
30    #[inline]
31    #[must_use]
32    pub fn new<T>(x: T, y: T) -> Point
33    where
34        T: TryInto<i32>,
35    {
36        Point {
37            x: x.try_into().ok().unwrap_or(0),
38            y: y.try_into().ok().unwrap_or(0),
39        }
40    }
41
42    /// Create a new point from i32, this can be constant
43    #[must_use]
44    pub const fn constant(x: i32, y: i32) -> Self {
45        Point { x, y }
46    }
47
48    /// Create a zero point
49    #[inline]
50    pub fn zero() -> Self {
51        Point { x: 0, y: 0 }
52    }
53
54    #[inline]
55    /// Create a point from a tuple of two i32s
56    pub fn from_tuple<T>(t: (T, T)) -> Self
57    where
58        T: TryInto<i32>,
59    {
60        Point::new(t.0, t.1)
61    }
62
63    #[inline]
64    /// Helper for map index conversion
65    #[must_use]
66    pub fn to_index<T>(self, width: T) -> usize
67    where
68        T: TryInto<usize>,
69    {
70        let x: usize = self.x.try_into().ok().unwrap();
71        let y: usize = self.y.try_into().ok().unwrap();
72        let w: usize = width.try_into().ok().unwrap();
73        (y * w) + x
74    }
75
76    /// Converts the point to an i32 tuple
77    #[must_use]
78    pub fn to_tuple(self) -> (i32, i32) {
79        (self.x, self.y)
80    }
81
82    /// Converts the point to a usize tuple
83    /// 
84    /// # Panics
85    /// 
86    /// This can panic if X or Y are not convertible to a `usize`.
87    #[must_use]
88    pub fn to_unsigned_tuple(self) -> (usize, usize) {
89        (
90            self.x.try_into().ok().unwrap(),
91            self.y.try_into().ok().unwrap(),
92        )
93    }
94
95    /// Converts the point to an UltraViolet vec2
96    #[must_use]
97    pub fn to_vec2(self) -> Vec2 {
98        Vec2::new(self.x as f32, self.y as f32)
99    }
100
101    /*
102    // This doesn't seem to exist anymore?
103    /// Converts the point to an UltraViolet vec2i
104    pub fn to_vec2i(self) -> Vec2i {
105        Vec2i::new(self.x, self.y)
106    }
107    */
108
109    /// Creates a point from an `UltraViolet` vec2
110    pub fn from_vec2(v: Vec2) -> Self {
111        Self::new(v.x as i32, v.y as i32)
112    }
113
114    /*
115    /// Creates a point from an `UltraViolet` vec2i
116    pub fn from_vec2i(v: Vec2i) -> Self {
117        Self::new(v.x, v.y)
118    }
119    */
120}
121
122impl From<(i32, i32)> for Point {
123    fn from(item: (i32, i32)) -> Self {
124        Self {
125            x: item.0,
126            y: item.1,
127        }
128    }
129}
130
131impl From<(f32, f32)> for Point {
132    fn from(item: (f32, f32)) -> Self {
133        Self {
134            x: item.0 as i32,
135            y: item.1 as i32,
136        }
137    }
138}
139
140impl From<Vec2> for Point {
141    fn from(item: Vec2) -> Self {
142        Self {
143            x: item.x as i32,
144            y: item.y as i32,
145        }
146    }
147}
148
149/*
150impl From<Vec2i> for Point {
151    fn from(item: Vec2i) -> Self {
152        Self {
153            x: item.x,
154            y: item.y,
155        }
156    }
157}
158*/
159
160///////////////////////////////////////////////////////////////////////////////////////
161/// Overloads: We support basic point math
162
163/// Support adding a point to a point
164impl ops::Add<Point> for Point {
165    type Output = Point;
166    fn add(mut self, rhs: Point) -> Point {
167        self.x += rhs.x;
168        self.y += rhs.y;
169        self
170    }
171}
172
173/// Support adding an int to a point
174impl ops::Add<i32> for Point {
175    type Output = Point;
176    fn add(mut self, rhs: i32) -> Point {
177        self.x += rhs;
178        self.y += rhs;
179        self
180    }
181}
182
183/// Support subtracting a point from a point
184impl ops::Sub<Point> for Point {
185    type Output = Point;
186    fn sub(mut self, rhs: Point) -> Point {
187        self.x -= rhs.x;
188        self.y -= rhs.y;
189        self
190    }
191}
192
193/// Support subtracting an int from a point
194impl ops::Sub<i32> for Point {
195    type Output = Point;
196    fn sub(mut self, rhs: i32) -> Point {
197        self.x -= rhs;
198        self.y -= rhs;
199        self
200    }
201}
202
203/// Support multiplying a point by a point
204impl ops::Mul<Point> for Point {
205    type Output = Point;
206    fn mul(mut self, rhs: Point) -> Point {
207        self.x *= rhs.x;
208        self.y *= rhs.y;
209        self
210    }
211}
212
213/// Support multiplying a point by an int
214impl ops::Mul<i32> for Point {
215    type Output = Point;
216    fn mul(mut self, rhs: i32) -> Point {
217        self.x *= rhs;
218        self.y *= rhs;
219        self
220    }
221}
222
223/// Support multiplying a point by an f32
224impl ops::Mul<f32> for Point {
225    type Output = Point;
226    fn mul(mut self, rhs: f32) -> Point {
227        self.x = (self.x as f32 * rhs) as i32;
228        self.y = (self.y as f32 * rhs) as i32;
229        self
230    }
231}
232
233/// Support dividing a point by a point
234impl ops::Div<Point> for Point {
235    type Output = Point;
236    fn div(mut self, rhs: Point) -> Point {
237        self.x /= rhs.x;
238        self.y /= rhs.y;
239        self
240    }
241}
242
243/// Support dividing a point by an int
244impl ops::Div<i32> for Point {
245    type Output = Point;
246    fn div(mut self, rhs: i32) -> Point {
247        self.x /= rhs;
248        self.y /= rhs;
249        self
250    }
251}
252
253/// Support dividing a point by an f32
254impl ops::Div<f32> for Point {
255    type Output = Point;
256    fn div(mut self, rhs: f32) -> Point {
257        self.x = (self.x as f32 / rhs) as i32;
258        self.y = (self.y as f32 / rhs) as i32;
259        self
260    }
261}
262
263impl ops::AddAssign for Point {
264    fn add_assign(&mut self, other: Self) {
265        *self = Self {
266            x: self.x + other.x,
267            y: self.y + other.y,
268        };
269    }
270}
271
272impl ops::SubAssign for Point {
273    fn sub_assign(&mut self, other: Self) {
274        *self = Self {
275            x: self.x - other.x,
276            y: self.y - other.y,
277        };
278    }
279}
280
281impl ops::MulAssign for Point {
282    fn mul_assign(&mut self, other: Self) {
283        *self = Self {
284            x: self.x * other.x,
285            y: self.y * other.y,
286        };
287    }
288}
289
290impl ops::DivAssign for Point {
291    fn div_assign(&mut self, other: Self) {
292        *self = Self {
293            x: self.x / other.x,
294            y: self.y / other.y,
295        };
296    }
297}
298
299// Unit tests
300#[cfg(test)]
301mod tests {
302    use super::Point;
303
304    #[test]
305    fn new_point() {
306        let pt = Point::new(1, 2);
307        assert_eq!(pt.x, 1);
308        assert_eq!(pt.y, 2);
309    }
310
311    #[test]
312    fn add_point_to_point() {
313        let pt = Point::new(0, 0);
314        let p2 = pt + Point::new(1, 2);
315        assert_eq!(p2.x, 1);
316        assert_eq!(p2.y, 2);
317    }
318
319    #[test]
320    fn add_assign_point_to_point() {
321        let mut pt = Point::new(0, 0);
322        pt += Point::new(1, 2);
323        assert_eq!(pt.x, 1);
324        assert_eq!(pt.y, 2);
325    }
326
327    #[test]
328    fn add_point_to_int() {
329        let pt = Point::new(0, 0);
330        let p2 = pt + 2;
331        assert_eq!(p2.x, 2);
332        assert_eq!(p2.y, 2);
333    }
334
335    #[test]
336    fn sub_point_to_point() {
337        let pt = Point::new(0, 0);
338        let p2 = pt - Point::new(1, 2);
339        assert_eq!(p2.x, -1);
340        assert_eq!(p2.y, -2);
341    }
342
343    #[test]
344    fn sub_assign_point_to_point() {
345        let mut pt = Point::new(0, 0);
346        pt -= Point::new(1, 2);
347        assert_eq!(pt.x, -1);
348        assert_eq!(pt.y, -2);
349    }
350
351    #[test]
352    fn sub_point_to_int() {
353        let pt = Point::new(0, 0);
354        let p2 = pt - 2;
355        assert_eq!(p2.x, -2);
356        assert_eq!(p2.y, -2);
357    }
358
359    #[test]
360    fn mul_point_to_point() {
361        let pt = Point::new(1, 1);
362        let p2 = pt * Point::new(1, 2);
363        assert_eq!(p2.x, 1);
364        assert_eq!(p2.y, 2);
365    }
366
367    #[test]
368    fn mul_assign_point_to_point() {
369        let mut pt = Point::new(1, 1);
370        pt *= Point::new(1, 2);
371        assert_eq!(pt.x, 1);
372        assert_eq!(pt.y, 2);
373    }
374
375    #[test]
376    fn mul_point_to_int() {
377        let pt = Point::new(1, 1);
378        let p2 = pt * 2;
379        assert_eq!(p2.x, 2);
380        assert_eq!(p2.y, 2);
381    }
382
383    #[test]
384    fn mul_point_to_float() {
385        let pt = Point::new(1, 1);
386        let p2 = pt * 4.0;
387        assert_eq!(p2.x, 4);
388        assert_eq!(p2.y, 4);
389    }
390
391    #[test]
392    fn div_point_to_point() {
393        let pt = Point::new(4, 4);
394        let p2 = pt / Point::new(2, 4);
395        assert_eq!(p2.x, 2);
396        assert_eq!(p2.y, 1);
397    }
398
399    #[test]
400    fn div_assign_point_to_point() {
401        let mut pt = Point::new(4, 4);
402        pt /= Point::new(2, 4);
403        assert_eq!(pt.x, 2);
404        assert_eq!(pt.y, 1);
405    }
406
407    #[test]
408    fn div_point_to_int() {
409        let pt = Point::new(4, 4);
410        let p2 = pt / 2;
411        assert_eq!(p2.x, 2);
412        assert_eq!(p2.y, 2);
413    }
414
415    #[test]
416    fn div_point_to_float() {
417        let pt = Point::new(4, 4);
418        let p2 = pt / 2.0;
419        assert_eq!(p2.x, 2);
420        assert_eq!(p2.y, 2);
421    }
422}