bracket_geometry/
rectf.rs

1use crate::prelude::PointF;
2use std::convert::TryInto;
3use std::ops;
4
5/// Defines a rectangle with floating-point coordinates.
6#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7#[derive(PartialEq, Copy, Clone, Debug)]
8pub struct RectF {
9    /// The X position of the first point (typically the left)
10    pub x1: f32,
11    /// The X position of the second point (typically the right)
12    pub x2: f32,
13    /// The Y position of the first point (typically the top)
14    pub y1: f32,
15    /// The Y position of the second point (typically the bottom)
16    pub y2: f32,
17}
18
19#[cfg(feature = "specs")]
20impl specs::prelude::Component for RectF {
21    type Storage = specs::prelude::VecStorage<Self>;
22}
23
24impl Default for RectF {
25    fn default() -> RectF {
26        RectF::zero()
27    }
28}
29
30impl RectF {
31    /// Create a new rectangle, specifying X/Y Width/Height
32    pub fn with_size<T>(x: T, y: T, w: T, h: T) -> RectF
33    where
34        T: TryInto<f32>,
35    {
36        let x_f32: f32 = x.try_into().ok().unwrap();
37        let y_f32: f32 = y.try_into().ok().unwrap();
38        RectF {
39            x1: x_f32,
40            y1: y_f32,
41            x2: x_f32 + w.try_into().ok().unwrap(),
42            y2: y_f32 + h.try_into().ok().unwrap(),
43        }
44    }
45
46    /// Create a new rectangle, specifying exact dimensions
47    pub fn with_exact<T>(x1: T, y1: T, x2: T, y2: T) -> RectF
48    where
49        T: TryInto<f32>,
50    {
51        RectF {
52            x1: x1.try_into().ok().unwrap(),
53            y1: y1.try_into().ok().unwrap(),
54            x2: x2.try_into().ok().unwrap(),
55            y2: y2.try_into().ok().unwrap(),
56        }
57    }
58
59    /// Creates a zero rectangle
60    #[must_use]
61    pub fn zero() -> RectF {
62        RectF {
63            x1: 0.0,
64            y1: 0.0,
65            x2: 0.0,
66            y2: 0.0,
67        }
68    }
69
70    /// Returns true if this overlaps with other
71    #[must_use]
72    pub fn intersect(&self, other: &RectF) -> bool {
73        self.x1 <= other.x2 && self.x2 >= other.x1 && self.y1 <= other.y2 && self.y2 >= other.y1
74    }
75
76    /// Returns the center of the rectangle
77    #[must_use]
78    pub fn center(&self) -> PointF {
79        PointF {
80            x: (self.x1 + self.x2) / 2.0,
81            y: (self.y1 + self.y2) / 2.0,
82        }
83    }
84
85    /// Returns true if a point is inside the rectangle
86    #[must_use]
87    pub fn point_in_rect(&self, point: PointF) -> bool {
88        point.x >= self.x1 && point.x < self.x2 && point.y >= self.y1 && point.y < self.y2
89    }
90
91    /// Returns the rectangle's width
92    #[must_use]
93    pub fn width(&self) -> f32 {
94        f32::abs(self.x2 - self.x1)
95    }
96
97    /// Returns the rectangle's height
98    #[must_use]
99    pub fn height(&self) -> f32 {
100        f32::abs(self.y2 - self.y1)
101    }
102}
103
104impl ops::Add<RectF> for RectF {
105    type Output = RectF;
106    fn add(mut self, rhs: RectF) -> RectF {
107        let w = self.width();
108        let h = self.height();
109        self.x1 += rhs.x1;
110        self.x2 = self.x1 + w;
111        self.y1 += rhs.y1;
112        self.y2 = self.y1 + h;
113        self
114    }
115}