1use crate::*;
2pub struct BspNode<T: Number> {
3 plane: Option<Plane<T, 3>>,
4 front: Option<Box<BspNode<T>>>,
5 back: Option<Box<BspNode<T>>>,
6 polygons: Vec<Polygon<T, 3>>,
7}
8
9impl<T: Number> Default for BspNode<T> {
10 fn default() -> Self {
11 Self {
12 plane: None,
13 front: None,
14 back: None,
15 polygons: Vec::new(),
16 }
17 }
18}
19
20impl<T: Number> BspNode<T> {
21 fn pick_splitting_plane(polygons: &[Polygon<T, 3>]) -> (usize, Vec<PolygonClassification>) {
22 let len = polygons.len();
23 if len <= 1 {
24 let classes = polygons
25 .iter()
26 .map(|_| PolygonClassification::Coplanar)
27 .collect();
28 return (0, classes);
29 }
30
31 let num_candidates = if len <= 48 {
37 len
38 } else {
39 ((len as f64).sqrt().ceil() as usize).clamp(16, 64)
40 };
41 let cand_step = if num_candidates >= len {
42 1
43 } else {
44 len / num_candidates
45 };
46
47 let mut best_idx = 0;
48 let mut best_score = i64::MAX;
49 let mut classes = Vec::with_capacity(len);
51 let mut best_classes = Vec::with_capacity(len);
52
53 for c in 0..num_candidates {
54 let idx = c * cand_step;
55 let plane = polygons[idx].plane();
56 let mut front = 0i64;
57 let mut back = 0i64;
58 let mut spanning = 0i64;
59 let mut coplanar = 0i64;
60
61 classes.clear();
62 classes.extend(polygons.iter().map(|p| {
63 let cl = plane.classify_polygon(p);
64 match cl {
65 PolygonClassification::Front => front += 1,
66 PolygonClassification::Back => back += 1,
67 PolygonClassification::Spanning => spanning += 1,
68 PolygonClassification::Coplanar => coplanar += 1,
69 }
70 cl
71 }));
72
73 let imbalance = if front > back {
78 front - back
79 } else {
80 back - front
81 };
82 let score = spanning * 16 + imbalance - coplanar * 2;
83
84 if score < best_score {
85 best_score = score;
86 best_idx = idx;
87 core::mem::swap(&mut classes, &mut best_classes);
88 }
89 }
90
91 (best_idx, best_classes)
92 }
93
94 pub fn build(polygons: Vec<Polygon<T, 3>>) -> Self {
95 if polygons.is_empty() {
96 return Self::default();
97 }
98
99 let (split_idx, classes) = Self::pick_splitting_plane(&polygons);
100 let plane = polygons[split_idx].plane();
101
102 let mut node = Self {
103 plane: Some(plane),
104 front: None,
105 back: None,
106 polygons: Vec::new(),
107 };
108
109 let mut front_polygons = Vec::new();
110 let mut back_polygons = Vec::new();
111
112 for (polygon, class) in polygons.into_iter().zip(classes) {
113 match class {
114 PolygonClassification::Coplanar => node.polygons.push(polygon),
115 PolygonClassification::Front => front_polygons.push(polygon),
116 PolygonClassification::Back => back_polygons.push(polygon),
117 PolygonClassification::Spanning => {
118 let (front, back) = plane.split_polygon(polygon);
119 front_polygons.push(front);
120 back_polygons.push(back);
121 }
122 }
123 }
124
125 if !front_polygons.is_empty() {
126 node.front = Some(Box::new(Self::build(front_polygons)));
127 }
128 if !back_polygons.is_empty() {
129 node.back = Some(Box::new(Self::build(back_polygons)));
130 }
131
132 node
133 }
134
135 pub fn clip_polygons(&self, polygons: Vec<Polygon<T, 3>>) -> Vec<Polygon<T, 3>> {
136 let mut out = Vec::new();
137 self.clip_polygons_into(polygons, &mut out);
138 out
139 }
140
141 fn clip_polygons_into(&self, polygons: Vec<Polygon<T, 3>>, out: &mut Vec<Polygon<T, 3>>) {
142 let Some(plane) = self.plane else {
143 out.extend(polygons);
144 return;
145 };
146
147 let mut front = Vec::new();
148 let mut back = Vec::new();
149
150 for polygon in polygons {
151 match plane.classify_polygon(&polygon) {
152 PolygonClassification::Front => front.push(polygon),
153 PolygonClassification::Back => back.push(polygon),
154 PolygonClassification::Coplanar => {
155 let dot = plane.normal().dot(&polygon.plane().normal());
156 if dot > T::zero() {
157 front.push(polygon);
158 } else {
159 back.push(polygon);
160 }
161 }
162 PolygonClassification::Spanning => {
163 let (f, b) = plane.split_polygon(polygon);
164 front.push(f);
165 back.push(b);
166 }
167 }
168 }
169
170 match &self.front {
171 Some(f) => f.clip_polygons_into(front, out),
172 None => out.extend(front),
173 };
174
175 if let Some(b) = &self.back {
176 b.clip_polygons_into(back, out);
177 }
178 }
180
181 pub fn clip_to(&mut self, other: &BspNode<T>) {
182 let taken = core::mem::take(&mut self.polygons);
183 self.polygons = other.clip_polygons(taken);
184 if let Some(ref mut front) = self.front {
185 front.clip_to(other);
186 }
187 if let Some(ref mut back) = self.back {
188 back.clip_to(other);
189 }
190 }
191
192 pub fn invert(&mut self) {
193 for polygon in &mut self.polygons {
194 polygon.flip_in_place();
195 }
196 if let Some(ref mut plane) = self.plane {
197 *plane = plane.flip();
198 }
199 core::mem::swap(&mut self.front, &mut self.back);
200 if let Some(ref mut front) = self.front {
201 front.invert();
202 }
203 if let Some(ref mut back) = self.back {
204 back.invert();
205 }
206 }
207
208 pub fn polygons(&self) -> Vec<Polygon<T, 3>> {
209 let mut result = Vec::new();
210 self.collect_polygons_into(&mut result);
211 result
212 }
213
214 fn collect_polygons_into(&self, out: &mut Vec<Polygon<T, 3>>) {
215 out.extend(self.polygons.iter().cloned());
216 if let Some(ref front) = self.front {
217 front.collect_polygons_into(out);
218 }
219 if let Some(ref back) = self.back {
220 back.collect_polygons_into(out);
221 }
222 }
223
224 pub fn build_into(&mut self, polygons: Vec<Polygon<T, 3>>) {
225 let mut front_polygons = Vec::new();
226 let mut back_polygons = Vec::new();
227
228 for polygon in polygons {
229 let Some(plane) = self.plane else {
230 self.plane = Some(polygon.plane());
231 self.polygons.push(polygon);
232 continue;
233 };
234 match plane.classify_polygon(&polygon) {
235 PolygonClassification::Coplanar => self.polygons.push(polygon),
236 PolygonClassification::Front => front_polygons.push(polygon),
237 PolygonClassification::Back => back_polygons.push(polygon),
238 PolygonClassification::Spanning => {
239 let (front, back) = plane.split_polygon(polygon);
240 front_polygons.push(front);
241 back_polygons.push(back);
242 }
243 }
244 }
245
246 if !front_polygons.is_empty() {
247 match &mut self.front {
248 Some(f) => f.build_into(front_polygons),
249 None => self.front = Some(Box::new(Self::build(front_polygons))),
250 }
251 }
252 if !back_polygons.is_empty() {
253 match &mut self.back {
254 Some(b) => b.build_into(back_polygons),
255 None => self.back = Some(Box::new(Self::build(back_polygons))),
256 }
257 }
258 }
259}