microcad_core/geo3d/
bounds.rs1use cgmath::ElementWise;
5use derive_more::Deref;
6
7use crate::*;
8
9pub type Bounds3D = Bounds<Vec3>;
11
12pub struct Bounds3DCorners {
14 bounds: Bounds3D,
15 index: u8, }
17
18impl Iterator for Bounds3DCorners {
19 type Item = Vec3;
20
21 fn next(&mut self) -> Option<Self::Item> {
22 if self.index >= 8 {
23 return None;
24 }
25
26 let i = self.index;
27 self.index += 1;
28
29 let x = if i & 1 == 0 {
30 self.bounds.min.x
31 } else {
32 self.bounds.max.x
33 };
34 let y = if i & 2 == 0 {
35 self.bounds.min.y
36 } else {
37 self.bounds.max.y
38 };
39 let z = if i & 4 == 0 {
40 self.bounds.min.z
41 } else {
42 self.bounds.max.z
43 };
44
45 Some(Vec3 { x, y, z })
46 }
47}
48
49impl Bounds3D {
50 pub fn min_max(&self) -> (Vec3, Vec3) {
52 (self.min, self.max)
53 }
54
55 pub fn extend(self, other: Bounds3D) -> Self {
57 match (self.is_valid(), other.is_valid()) {
58 (false, false) => Self::default(),
59 (false, true) => other,
60 (true, false) => self,
61 (true, true) => Self::new(
62 Vec3::new(
63 self.min.x.min(other.min.x),
64 self.min.y.min(other.min.y),
65 self.min.z.min(other.min.z),
66 ),
67 Vec3::new(
68 self.max.x.max(other.max.x),
69 self.max.y.max(other.max.y),
70 self.max.z.max(other.max.z),
71 ),
72 ),
73 }
74 }
75
76 pub fn is_valid(&self) -> bool {
78 self.min.x <= self.max.x && self.min.y <= self.max.y && self.min.z <= self.max.z
79 }
80
81 pub fn extend_by_point(&mut self, p: Vec3) {
83 self.min.x = p.x.min(self.min.x);
84 self.min.y = p.y.min(self.min.y);
85 self.min.z = p.z.min(self.min.z);
86 self.max.x = p.x.max(self.max.x);
87 self.max.y = p.y.max(self.max.y);
88 self.max.z = p.z.max(self.max.z);
89 }
90
91 pub fn corners(&self) -> Bounds3DCorners {
93 Bounds3DCorners {
94 bounds: self.clone(),
95 index: 0,
96 }
97 }
98
99 pub fn map_vec3(&self, v: Vec3) -> Vec3 {
103 (v - self.min).div_element_wise(self.max - self.min)
104 }
105}
106
107impl Default for Bounds3D {
108 fn default() -> Self {
109 let min = Scalar::MAX;
111 let max = Scalar::MIN;
112 Self::new(Vec3::new(min, min, min), Vec3::new(max, max, max))
113 }
114}
115
116impl FromIterator<Vec3> for Bounds3D {
117 fn from_iter<I: IntoIterator<Item = Vec3>>(iter: I) -> Self {
118 let mut iter = iter.into_iter();
119 let first_point = match iter.next() {
120 Some(point) => point,
121 None => return Bounds3D::default(),
122 };
123
124 let mut min = first_point;
125 let mut max = first_point;
126
127 iter.for_each(|p| {
128 min.x = min.x.min(p.x);
129 min.y = min.y.min(p.y);
130 min.z = min.z.min(p.z);
131
132 max.x = max.x.max(p.x);
133 max.y = max.y.max(p.y);
134 max.z = max.z.max(p.z);
135 });
136
137 Bounds3D::new(min, max)
138 }
139}
140
141impl Transformed3D for Bounds3D {
142 fn transformed_3d(&self, mat: &Mat4) -> Self {
143 let mut bounds = Bounds3D::default();
144 self.corners()
145 .for_each(|corner| bounds.extend_by_point((mat * corner.extend(1.0)).truncate()));
146
147 bounds
148 }
149}
150
151pub trait CalcBounds3D {
153 fn calc_bounds_3d(&self) -> Bounds3D;
155}
156
157pub trait Transformed3D<T = Self> {
159 fn transformed_3d(&self, mat: &Mat4) -> T;
161}
162
163#[derive(Clone, Default, Debug, Deref)]
165pub struct WithBounds3D<T: CalcBounds3D + Transformed3D> {
166 pub bounds: Bounds3D,
168 #[deref]
170 pub inner: T,
171}
172
173impl<T: CalcBounds3D + Transformed3D> WithBounds3D<T> {
174 pub fn new(inner: T, bounds: Bounds3D) -> Self {
176 Self { bounds, inner }
177 }
178
179 pub fn update_bounds(&mut self) {
181 self.bounds = self.inner.calc_bounds_3d()
182 }
183}
184
185impl<T: CalcBounds3D + Transformed3D> Transformed3D for WithBounds3D<T> {
186 fn transformed_3d(&self, mat: &Mat4) -> Self {
187 let inner = self.inner.transformed_3d(mat);
188 let bounds = inner.calc_bounds_3d();
189 Self { inner, bounds }
190 }
191}
192
193impl From<Geometry3D> for WithBounds3D<Geometry3D> {
194 fn from(geo: Geometry3D) -> Self {
195 let bounds = geo.calc_bounds_3d();
196 Self::new(geo, bounds)
197 }
198}