microcad_core/geo2d/
bounds.rs1use derive_more::Deref;
7use geo::coord;
8
9use crate::*;
10
11pub type Bounds2D = Bounds<Vec2>;
13
14impl Bounds2D {
15 pub fn is_valid(&self) -> bool {
17 self.min.x <= self.max.x && self.min.y <= self.max.y
18 }
19
20 pub fn width(&self) -> Scalar {
22 (self.max.x - self.min.x).max(0.0)
23 }
24
25 pub fn height(&self) -> Scalar {
27 (self.max.y - self.min.y).max(0.0)
28 }
29
30 pub fn max_extent(&self) -> Scalar {
32 self.width().max(self.height())
33 }
34
35 pub fn center(&self) -> Vec2 {
37 (self.min + self.max) * 0.5
38 }
39
40 pub fn rect(&self) -> Option<Rect> {
42 if self.is_valid() {
43 Some(Rect::new(
44 coord! {x: self.min.x, y: self.min.y },
45 coord! {x: self.max.x, y: self.max.y },
46 ))
47 } else {
48 None
49 }
50 }
51
52 pub fn enlarge(&self, factor: Scalar) -> Self {
54 match self.rect() {
55 Some(rect) => {
56 let c = rect.center();
57 let s: geo::Coord = (rect.width(), rect.height()).into();
58 let s = s * 0.5 * (1.0 + factor);
59 Rect::new(c - s, c + s).into()
60 }
61 None => Bounds2D::default(),
62 }
63 }
64
65 pub fn extend(mut self, other: Bounds2D) -> Self {
67 self.extend_by_point(other.min);
68 self.extend_by_point(other.max);
69 self
70 }
71
72 pub fn extend_by_point(&mut self, p: Vec2) {
74 self.min.x = p.x.min(self.min.x);
75 self.min.y = p.y.min(self.min.y);
76 self.max.x = p.x.max(self.max.x);
77 self.max.y = p.y.max(self.max.y);
78 }
79
80 pub fn radius(&self) -> Scalar {
82 use cgmath::InnerSpace;
83 (self.max - self.min).magnitude() * 0.5
84 }
85
86 pub fn distance_center_to_boundary(&self, dir: Vec2) -> Length {
88 let center = self.center();
89
90 let tx = if dir.x > 0.0 {
92 (self.max.x - center.x) / dir.x
93 } else if dir.x < 0.0 {
94 (self.min.x - center.x) / dir.x
95 } else {
96 f64::INFINITY
97 };
98
99 let ty = if dir.y > 0.0 {
101 (self.max.y - center.y) / dir.y
102 } else if dir.y < 0.0 {
103 (self.min.y - center.y) / dir.y
104 } else {
105 f64::INFINITY
106 };
107
108 Length::mm(tx.min(ty))
110 }
111}
112
113impl Default for Bounds2D {
114 fn default() -> Self {
115 let min = Scalar::MAX;
117 let max = Scalar::MIN;
118 Self::new((min, min).into(), (max, max).into())
119 }
120}
121
122impl From<Rect> for Bounds2D {
123 fn from(rect: Rect) -> Self {
124 Self::new(rect.min().x_y().into(), rect.max().x_y().into())
125 }
126}
127
128impl From<Option<Rect>> for Bounds2D {
129 fn from(rect: Option<Rect>) -> Self {
130 match rect {
131 Some(rect) => rect.into(),
132 None => Bounds2D::default(),
133 }
134 }
135}
136
137impl From<Size2> for Bounds2D {
138 fn from(value: Size2) -> Self {
139 Self::new(Vec2::new(0.0, 0.0), Vec2::new(value.width, value.height))
140 }
141}
142
143impl std::fmt::Display for Bounds2D {
144 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145 match self.rect() {
146 Some(rect) => write!(
147 f,
148 "[{min:?}, {max:?}]",
149 min = rect.min().x_y(),
150 max = rect.max().x_y()
151 ),
152 None => write!(f, "[no bounds]"),
153 }
154 }
155}
156
157pub trait CalcBounds2D {
159 fn calc_bounds_2d(&self) -> Bounds2D;
161}
162
163#[derive(Clone, Default, Debug, Deref)]
165pub struct WithBounds2D<T: CalcBounds2D + Transformed2D> {
166 pub bounds: Bounds2D,
168 #[deref]
170 pub inner: T,
171}
172
173impl<T: CalcBounds2D + Transformed2D> WithBounds2D<T> {
174 pub fn new(inner: T) -> Self {
176 Self {
177 bounds: inner.calc_bounds_2d(),
178 inner,
179 }
180 }
181
182 pub fn update_bounds(&mut self) {
184 self.bounds = self.inner.calc_bounds_2d()
185 }
186}
187
188impl<T: CalcBounds2D + Transformed2D> Transformed2D for WithBounds2D<T> {
189 fn transformed_2d(&self, mat: &Mat3) -> Self {
190 let inner = self.inner.transformed_2d(mat);
191 let bounds = inner.calc_bounds_2d();
192 Self { inner, bounds }
193 }
194}
195
196impl From<Geometry2D> for WithBounds2D<Geometry2D> {
197 fn from(geo: Geometry2D) -> Self {
198 Self::new(geo)
199 }
200}
201
202#[test]
203fn bounds_2d_test() {
204 let bounds1 = Bounds2D::new(Vec2::new(0.0, 1.0), Vec2::new(2.0, 3.0));
205 let bounds2 = Bounds2D::new(Vec2::new(4.0, 5.0), Vec2::new(6.0, 7.0));
206
207 let bounds1 = bounds1.extend(bounds2);
208
209 assert_eq!(bounds1.min, Vec2::new(0.0, 1.0));
210 assert_eq!(bounds1.max, Vec2::new(6.0, 7.0));
211}