rect/
lib.rs

1#![deny(missing_docs)]
2
3//! Helper methods for computing simple rectangle layout.
4
5extern crate float;
6
7use float::Float;
8
9/// Helper methods for computing simple rectangle layout.
10pub trait Rect: Sized {
11    /// The internal scalar type.
12    type Scalar: Float;
13    /// Creates new rectangle from x, y, w, h.
14    fn from_x_y_w_h(Self::Scalar, Self::Scalar, Self::Scalar, Self::Scalar)
15        -> Self;
16    /// Converts from u32 rectangle.
17    #[inline(always)]
18    fn from_u32(rect: [u32; 4]) -> Self {
19        use float::FromPrimitive;
20
21        Rect::from_x_y_w_h(
22            FromPrimitive::from_u32(rect[0]),
23            FromPrimitive::from_u32(rect[1]),
24            FromPrimitive::from_u32(rect[2]),
25            FromPrimitive::from_u32(rect[3])
26        )
27    }
28    /// Converts from i32 rectangle.
29    #[inline(always)]
30    fn from_i32(rect: [i32; 4]) -> Self {
31        use float::FromPrimitive;
32
33        Rect::from_x_y_w_h(
34            FromPrimitive::from_i32(rect[0]),
35            FromPrimitive::from_i32(rect[1]),
36            FromPrimitive::from_i32(rect[2]),
37            FromPrimitive::from_i32(rect[3])
38        )
39    }
40    /// Gets x.
41    fn x(&self) -> Self::Scalar;
42    /// Gets y.
43    fn y(&self) -> Self::Scalar;
44    /// Gets w.
45    fn w(&self) -> Self::Scalar;
46    /// Gets h.
47    fn h(&self) -> Self::Scalar;
48    /// Sets x.
49    fn set_x(&mut self, val: Self::Scalar);
50    /// Sets y.
51    fn set_y(&mut self, val: Self::Scalar);
52    /// Sets w.
53    fn set_w(&mut self, val: Self::Scalar);
54    /// Sets h.
55    fn set_h(&mut self, val: Self::Scalar);
56    /// Returns x and y.
57    #[inline(always)]
58    fn xy(&self) -> (Self::Scalar, Self::Scalar) { (self.x(), self.y()) }
59    /// Returns w and h.
60    #[inline(always)]
61    fn wh(&self) -> (Self::Scalar, Self::Scalar) { (self.w(), self.h()) }
62    /// Return x and w.
63    #[inline(always)]
64    fn xw(&self) -> (Self::Scalar, Self::Scalar) { (self.x(), self.w()) }
65    /// Returns y and h.
66    #[inline(always)]
67    fn yh(&self) -> (Self::Scalar, Self::Scalar) { (self.y(), self.h()) }
68    /// Returns left and right.
69    #[inline(always)]
70    fn x1x2(&self) -> (Self::Scalar, Self::Scalar) { (self.x(), self.x() + self.w()) }
71    /// Returns top and bottom.
72    #[inline(always)]
73    fn y1y2(&self) -> (Self::Scalar, Self::Scalar) { (self.y(), self.y() + self.h()) }
74    /// Returns upper left and lower right corner.
75    #[inline(always)]
76    fn p1p2(&self) -> ([Self::Scalar; 2], [Self::Scalar; 2]) {
77        ([self.x(), self.y()], [self.x() + self.w(), self.y() + self.h()])
78    }
79    /// Returns x, y, w, h.
80    #[inline(always)]
81    fn xywh(&self) -> (Self::Scalar, Self::Scalar, Self::Scalar, Self::Scalar) {
82        (self.x(), self.y(), self.w(), self.h())
83    }
84    /// Returns the center of the rectangle.
85    #[inline(always)]
86    fn center(&self) -> [Self::Scalar; 2] {
87        use float::FromPrimitive;
88
89        let _05: Self::Scalar = FromPrimitive::from_f64(0.5);
90        [self.x() + _05 * self.h(), self.y() + _05 * self.h()]
91    }
92    /// Returns true if the rectangle is empty.
93    #[inline(always)]
94    fn is_empty(&self) -> bool {
95        use float::Zero;
96
97        self.w() * self.h() == Zero::zero()
98    }
99    /// Computes a margin rectangle.
100    /// If the margin is too large, an empty rectangle in the middle is returned.
101    fn margin(&self, val: Self::Scalar) -> Self {
102        use float::{ FromPrimitive, Zero };
103
104        let x: Self::Scalar;
105        let y: Self::Scalar;
106        let w: Self::Scalar;
107        let h: Self::Scalar;
108        let _2: Self::Scalar = FromPrimitive::from_f64(2.0);
109        let _05: Self::Scalar = FromPrimitive::from_f64(0.5);
110        let _0: Self::Scalar = Zero::zero();
111        if self.w() < _2 * val {
112            x = self.x() + _05 * self.w();
113            w = _0;
114        } else {
115            x = self.x() + val;
116            w = self.w() - _2 * val;
117        }
118        if self.h() < _2 * val {
119            y = self.y() + _05 * self.h();
120            h = _0;
121        } else {
122            y = self.y() + val;
123            h = self.h() - _2 * val;
124        }
125        <Self as Rect>::from_x_y_w_h(x, y, w, h)
126    }
127    /// Splits from the left side of rectangle up to a factor.
128    fn split_left(&self, val: Self::Scalar, factor: Self::Scalar)
129    -> (Self, Self) {
130        use float::One;
131
132        let (x, y, w, h) = self.xywh();
133        if val > w * factor {
134            let _1: Self::Scalar = One::one();
135            (Rect::from_x_y_w_h(x, y, w * factor, h),
136             Rect::from_x_y_w_h(x + w * factor, y, w * (_1 - factor), h))
137        } else {
138            (Rect::from_x_y_w_h(x, y, val, h),
139             Rect::from_x_y_w_h(x + val, y, w - val, h))
140         }
141    }
142    /// Splits from the right side of rectangle.
143    #[inline(always)]
144    fn split_right(&self, val: Self::Scalar, factor: Self::Scalar)
145    -> (Self, Self) {
146        use float::One;
147
148        let (x, y, w, h) = self.xywh();
149        if val > w * factor {
150            let _1: Self::Scalar = One::one();
151            (Rect::from_x_y_w_h(x, y, w * (_1 - factor), h),
152             Rect::from_x_y_w_h(x + w * (_1 - factor), y, w * factor, h))
153        } else {
154            (Rect::from_x_y_w_h(x, y, w - val, h),
155             Rect::from_x_y_w_h(x + w - val, y, val, h))
156         }
157    }
158    /// Splits from the top side of rectangle.
159    fn split_top(&self, val: Self::Scalar, factor: Self::Scalar)
160    -> (Self, Self) {
161        use float::One;
162
163        let (x, y, w, h) = self.xywh();
164        if val > h * factor {
165            let _1: Self::Scalar = One::one();
166            (Rect::from_x_y_w_h(x, y, w, h * factor),
167             Rect::from_x_y_w_h(x, y + h * factor, w, h * (_1 - factor)))
168        } else {
169            (Rect::from_x_y_w_h(x, y, w, val),
170             Rect::from_x_y_w_h(x, y + val, w, h - val))
171         }
172    }
173    /// Splits from the bottom side of the rectangle.
174    #[inline(always)]
175    fn split_bottom(&self, val: Self::Scalar, factor: Self::Scalar)
176    -> (Self, Self) {
177        use float::One;
178
179        let (x, y, w, h) = self.xywh();
180        if val > h * factor {
181            let _1: Self::Scalar = One::one();
182            (Rect::from_x_y_w_h(x, y, w, h * (_1 - factor)),
183             Rect::from_x_y_w_h(x, y + h * (_1 - factor), w, h * factor))
184        } else {
185            (Rect::from_x_y_w_h(x, y, w, h - val),
186             Rect::from_x_y_w_h(x, y + h - val, w, val))
187         }
188    }
189}
190
191impl Rect for [f64; 4] {
192    type Scalar = f64;
193    fn from_x_y_w_h(x: f64, y: f64, w: f64, h: f64) -> [f64; 4] {
194        [x, y, w, h]
195    }
196    fn x(&self) -> f64 { self[0] }
197    fn y(&self) -> f64 { self[1] }
198    fn w(&self) -> f64 { self[2] }
199    fn h(&self) -> f64 { self[3] }
200    fn set_x(&mut self, val: f64) { self[0] = val }
201    fn set_y(&mut self, val: f64) { self[1] = val }
202    fn set_w(&mut self, val: f64) { self[2] = val }
203    fn set_h(&mut self, val: f64) { self[3] = val }
204}
205
206
207impl Rect for [f32; 4] {
208    type Scalar = f32;
209    fn from_x_y_w_h(x: f32, y: f32, w: f32, h: f32) -> [f32; 4] {
210        [x, y, w, h]
211    }
212    fn x(&self) -> f32 { self[0] }
213    fn y(&self) -> f32 { self[1] }
214    fn w(&self) -> f32 { self[2] }
215    fn h(&self) -> f32 { self[3] }
216    fn set_x(&mut self, val: f32) { self[0] = val }
217    fn set_y(&mut self, val: f32) { self[1] = val }
218    fn set_w(&mut self, val: f32) { self[2] = val }
219    fn set_h(&mut self, val: f32) { self[3] = val }
220}
221
222#[cfg(test)]
223mod tests {
224    use super::*;
225
226    #[test]
227    fn is_empty() {
228        assert!([0.0, 0.0, 0.0, 0.0].is_empty());
229        assert!([0.0, 0.0, 1.0, 0.0].is_empty());
230        assert!([0.0, 0.0, 0.0, 1.0].is_empty());
231        assert!(![0.0, 0.0, 1.0, 1.0].is_empty());
232    }
233
234    #[test]
235    fn margin() {
236        assert_eq!([0.0, 0.0, 0.0, 0.0].margin(2.0), [0.0, 0.0, 0.0, 0.0]);
237        assert_eq!([0.0, 0.0, 1.0, 1.0].margin(2.0), [0.5, 0.5, 0.0, 0.0]);
238        assert_eq!([0.0, 0.0, 100.0, 100.0].margin(2.0), [2.0, 2.0, 96.0, 96.0]);
239        assert_eq!([0.0, 0.0, 100.0, 200.0].margin(2.0), [2.0, 2.0, 96.0, 196.0]);
240    }
241
242    #[test]
243    fn xywh() {
244        let rect = [0.0, 1.0, 2.0, 3.0];
245        assert_eq!(rect.x(), 0.0);
246        assert_eq!(rect.y(), 1.0);
247        assert_eq!(rect.w(), 2.0);
248        assert_eq!(rect.h(), 3.0);
249    }
250
251    #[test]
252    fn split_left() {
253        assert_eq!([0.0, 0.0, 0.0, 10.0].split_left(30.0, 0.5),
254            ([0.0, 0.0, 0.0, 10.0], [0.0, 0.0, 0.0, 10.0]));
255        assert_eq!([0.0, 0.0, 10.0, 10.0].split_left(15.0, 0.5),
256            ([0.0, 0.0, 5.0, 10.0], [5.0, 0.0, 5.0, 10.0]));
257        assert_eq!([0.0, 0.0, 100.0, 10.0].split_left(30.0, 0.5),
258            ([0.0, 0.0, 30.0, 10.0], [30.0, 0.0, 70.0, 10.0]));
259    }
260
261    #[test]
262    fn split_top() {
263        assert_eq!([0.0, 0.0, 10.0, 0.0].split_top(30.0, 0.5),
264            ([0.0, 0.0, 10.0, 0.0], [0.0, 0.0, 10.0, 0.0]));
265        assert_eq!([0.0, 0.0, 10.0, 10.0].split_top(15.0, 0.5),
266            ([0.0, 0.0, 10.0, 5.0], [0.0, 5.0, 10.0, 5.0]));
267        assert_eq!([0.0, 0.0, 10.0, 100.0].split_top(30.0, 0.5),
268            ([0.0, 0.0, 10.0, 30.0], [0.0, 30.0, 10.0, 70.0]));
269    }
270}