1use std::cmp::{Eq, Ordering};
26
27use crate::*;
28
29#[derive(Debug, PartialEq, PartialOrd, Clone, Hash, Default)]
32pub struct Box2D {
34 pub center: Point2D,
35 pub size_x: Positive,
36 pub size_y: Positive,
37}
38
39impl Box2D {
40 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 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 pub fn sizes(&self) -> [Positive; 2] {
56 [self.size_x, self.size_y]
57 }
58}
59
60impl 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() }
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}