rust_3d/
box_2d.rs

1/*
2Copyright 2017 Martin Buck
3
4Permission is hereby granted, free of charge, to any person obtaining a copy
5of this software and associated documentation files (the "Software"),
6to deal in the Software without restriction, including without limitation the
7rights to use, copy, modify, merge, publish, distribute, sublicense,
8and/or sell copies of the Software, and to permit persons to whom the Software
9is furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice shall
12be included all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
20OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21*/
22
23//! Box2D, a box in 2D space
24
25use std::cmp::{Eq, Ordering};
26
27use crate::*;
28
29//------------------------------------------------------------------------------
30
31#[derive(Debug, PartialEq, PartialOrd, Clone, Hash, Default)]
32/// Box2D, a box in 2D space
33pub struct Box2D {
34    pub center: Point2D,
35    pub size_x: Positive,
36    pub size_y: Positive,
37}
38
39impl Box2D {
40    /// Returns the minimum position of the box
41    pub fn min_p(&self) -> Point2D {
42        Point2D::new(
43            self.center.x() - 0.5 * self.size_x.get(),
44            self.center.y() - 0.5 * self.size_y.get(),
45        )
46    }
47    /// Returns the maximum position of the box
48    pub fn max_p(&self) -> Point2D {
49        Point2D::new(
50            self.center.x() + 0.5 * self.size_x.get(),
51            self.center.y() + 0.5 * self.size_y.get(),
52        )
53    }
54    /// Returns the sizes of the bounding box
55    pub fn sizes(&self) -> [Positive; 2] {
56        [self.size_x, self.size_y]
57    }
58}
59
60//------------------------------------------------------------------------------
61
62impl Eq for Box2D {}
63
64impl Ord for Box2D {
65    fn cmp(&self, other: &Self) -> Ordering {
66        let origin = Point2D::default();
67        match sqr_dist_2d(&origin, &self.center).partial_cmp(&sqr_dist_2d(&origin, &other.center)) {
68            Some(x) => x,
69            None => match self.size_x.partial_cmp(&other.size_x) {
70                Some(x) => x,
71                None => self
72                    .size_y
73                    .partial_cmp(&other.size_y)
74                    .unwrap_or(Ordering::Equal),
75            },
76        }
77    }
78}
79
80impl IsND for Box2D {
81    fn n_dimensions() -> usize {
82        Point2D::n_dimensions()
83    }
84
85    fn position_nd(&self, dimension: usize) -> Result<f64> {
86        self.center.position_nd(dimension)
87    }
88}
89
90impl Is2D for Box2D {
91    #[inline(always)]
92    fn x(&self) -> f64 {
93        self.center.x()
94    }
95
96    #[inline(always)]
97    fn y(&self) -> f64 {
98        self.center.y()
99    }
100}
101
102impl IsBuildableND for Box2D {
103    #[inline(always)]
104    fn new_nd(coords: &[f64]) -> Result<Self> {
105        Ok(Box2D {
106            center: Point2D::new_nd(coords)?,
107            size_x: Positive::one(),
108            size_y: Positive::one(),
109        })
110    }
111
112    #[inline(always)]
113    fn from_nd<P>(&mut self, other: P) -> Result<()>
114    where
115        P: IsBuildableND,
116    {
117        self.center.from_nd(other)
118    }
119}
120
121impl IsBuildable2D for Box2D {
122    #[inline(always)]
123    fn new(x: f64, y: f64) -> Self {
124        Box2D {
125            center: Point2D { x, y },
126            size_x: Positive::one(),
127            size_y: Positive::one(),
128        }
129    }
130
131    #[inline(always)]
132    fn from<P>(&mut self, other: &P)
133    where
134        P: Is2D,
135    {
136        self.center.from(other)
137    }
138}
139
140impl IsEditableND for Box2D {
141    fn set_position(&mut self, dimension: usize, val: f64) -> Result<()> {
142        self.center.set_position(dimension, val)
143    }
144}
145
146impl IsEditable2D for Box2D {
147    #[inline(always)]
148    fn set_x(&mut self, val: f64) {
149        self.center.set_x(val);
150    }
151
152    #[inline(always)]
153    fn set_y(&mut self, val: f64) {
154        self.center.set_y(val);
155    }
156}
157
158impl HasBoundingBox2D for Box2D {
159    fn bounding_box(&self) -> BoundingBox2D {
160        let p_min = Point2D {
161            x: self.center.x() - self.size_x.get() / 2.0,
162            y: self.center.y() - self.size_y.get() / 2.0,
163        };
164        let p_max = Point2D {
165            x: self.center.x() + self.size_x.get() / 2.0,
166            y: self.center.y() + self.size_y.get() / 2.0,
167        };
168        BoundingBox2D::new(&p_min, &p_max).unwrap() // safe
169    }
170}
171
172impl HasBoundingBox2DMaybe for Box2D {
173    fn bounding_box_maybe(&self) -> Result<BoundingBox2D> {
174        Ok(self.bounding_box())
175    }
176}
177
178impl IsScalable for Box2D {
179    fn scale(&mut self, factor: Positive) {
180        self.size_x *= factor;
181        self.size_y *= factor;
182    }
183}
184
185impl IsMovable2D for Box2D {
186    fn move_by(&mut self, x: f64, y: f64) {
187        self.center.move_by(x, y)
188    }
189}
190
191impl From<BoundingBox2D> for Box2D {
192    fn from(x: BoundingBox2D) -> Self {
193        Box2D {
194            center: x.center_bb(),
195            size_x: x.size_x(),
196            size_y: x.size_y(),
197        }
198    }
199}