1use nalgebra::Point3;
4
5use crate::{Classification, Cuttable, Polygon};
6
7use super::node::{faces_same_direction, BspNode};
8use super::selector::PlaneSelector;
9use super::visitor::BspVisitor;
10
11#[derive(Debug, Clone, Default)]
40pub struct BspTree {
41 root: Option<BspNode>,
42}
43
44impl BspTree {
45 pub fn new() -> Self {
47 Self { root: None }
48 }
49
50 pub fn build<S: PlaneSelector>(polygons: Vec<Polygon>, selector: &S) -> Self {
58 Self {
59 root: build_node(polygons, selector),
60 }
61 }
62
63 pub fn from_polygons(polygons: Vec<Polygon>) -> Self {
65 use super::selector::FirstPolygon;
66 Self::build(polygons, &FirstPolygon)
67 }
68
69 #[inline]
71 pub fn is_empty(&self) -> bool {
72 self.root.is_none()
73 }
74
75 #[inline]
77 pub fn root(&self) -> Option<&BspNode> {
78 self.root.as_ref()
79 }
80
81 #[inline]
85 pub fn root_mut(&mut self) -> Option<&mut BspNode> {
86 self.root.as_mut()
87 }
88
89 pub fn polygon_count(&self) -> usize {
91 self.root.as_ref().map_or(0, |n| n.polygon_count())
92 }
93
94 pub fn depth(&self) -> usize {
96 self.root.as_ref().map_or(0, |n| n.depth())
97 }
98
99 pub fn traverse_front_to_back<V: BspVisitor>(&self, eye: Point3<f32>, visitor: &mut V) {
108 if let Some(ref root) = self.root {
109 traverse_front_to_back_node(root, eye, visitor);
110 }
111 }
112
113 pub fn traverse_back_to_front<V: BspVisitor>(&self, eye: Point3<f32>, visitor: &mut V) {
119 if let Some(ref root) = self.root {
120 traverse_back_to_front_node(root, eye, visitor);
121 }
122 }
123
124 pub fn collect_polygons(&self) -> Vec<Polygon> {
128 let mut result = Vec::with_capacity(self.polygon_count());
129 collect_polygons_recursive(self.root.as_ref(), &mut result);
130 result
131 }
132
133 }
136
137fn build_node<S: PlaneSelector>(mut polygons: Vec<Polygon>, selector: &S) -> Option<BspNode> {
139 if polygons.is_empty() {
140 return None;
141 }
142
143 let splitter_idx = polygons
145 .iter()
146 .position(|p| Some(p) == selector.select(&polygons))?;
147
148 let splitter = polygons.swap_remove(splitter_idx);
149 let plane = splitter.plane();
150
151 let mut coplanar_front = Vec::new();
153 let mut coplanar_back = Vec::new();
154 let mut front_list = Vec::new();
155 let mut back_list = Vec::new();
156
157 if faces_same_direction(&splitter, &plane) {
159 coplanar_front.push(splitter);
160 } else {
161 coplanar_back.push(splitter);
162 }
163
164 for polygon in polygons {
166 match polygon.classify(&plane) {
167 Classification::Front => {
168 front_list.push(polygon);
169 }
170 Classification::Back => {
171 back_list.push(polygon);
172 }
173 Classification::Coplanar => {
174 if faces_same_direction(&polygon, &plane) {
175 coplanar_front.push(polygon);
176 } else {
177 coplanar_back.push(polygon);
178 }
179 }
180 Classification::Spanning => {
181 let (front_part, back_part) = polygon.cut(&plane);
182 if let Some(f) = front_part {
183 front_list.push(f);
184 }
185 if let Some(b) = back_part {
186 back_list.push(b);
187 }
188 }
189 }
190 }
191
192 let mut node = BspNode::with_coplanar(plane, coplanar_front, coplanar_back);
194 node.set_front(build_node(front_list, selector));
195 node.set_back(build_node(back_list, selector));
196
197 Some(node)
198}
199
200fn traverse_front_to_back_node<V: BspVisitor>(node: &BspNode, eye: Point3<f32>, visitor: &mut V) {
202 let side = node.plane().classify_point(eye);
203
204 let coplanar: Vec<Polygon> = node.all_coplanar().cloned().collect();
206
207 match side {
208 crate::PlaneSide::Front | crate::PlaneSide::OnPlane => {
209 if let Some(front) = node.front() {
211 traverse_front_to_back_node(front, eye, visitor);
212 }
213 if !coplanar.is_empty() {
214 visitor.visit(&coplanar);
215 }
216 if let Some(back) = node.back() {
217 traverse_front_to_back_node(back, eye, visitor);
218 }
219 }
220 crate::PlaneSide::Back => {
221 if let Some(back) = node.back() {
223 traverse_front_to_back_node(back, eye, visitor);
224 }
225 if !coplanar.is_empty() {
226 visitor.visit(&coplanar);
227 }
228 if let Some(front) = node.front() {
229 traverse_front_to_back_node(front, eye, visitor);
230 }
231 }
232 }
233}
234
235fn traverse_back_to_front_node<V: BspVisitor>(node: &BspNode, eye: Point3<f32>, visitor: &mut V) {
237 let side = node.plane().classify_point(eye);
238
239 let coplanar: Vec<Polygon> = node.all_coplanar().cloned().collect();
240
241 match side {
242 crate::PlaneSide::Front | crate::PlaneSide::OnPlane => {
243 if let Some(back) = node.back() {
245 traverse_back_to_front_node(back, eye, visitor);
246 }
247 if !coplanar.is_empty() {
248 visitor.visit(&coplanar);
249 }
250 if let Some(front) = node.front() {
251 traverse_back_to_front_node(front, eye, visitor);
252 }
253 }
254 crate::PlaneSide::Back => {
255 if let Some(front) = node.front() {
257 traverse_back_to_front_node(front, eye, visitor);
258 }
259 if !coplanar.is_empty() {
260 visitor.visit(&coplanar);
261 }
262 if let Some(back) = node.back() {
263 traverse_back_to_front_node(back, eye, visitor);
264 }
265 }
266 }
267}
268
269fn collect_polygons_recursive(node: Option<&BspNode>, result: &mut Vec<Polygon>) {
271 if let Some(n) = node {
272 result.extend(n.all_coplanar().cloned());
273 collect_polygons_recursive(n.front(), result);
274 collect_polygons_recursive(n.back(), result);
275 }
276}
277
278#[cfg(test)]
279mod tests {
280 use super::*;
281 use crate::bsp::visitor::CollectingVisitor;
282 use nalgebra::Point3;
283
284 fn make_triangle(a: [f32; 3], b: [f32; 3], c: [f32; 3]) -> Polygon {
285 Polygon::new(vec![
286 Point3::new(a[0], a[1], a[2]),
287 Point3::new(b[0], b[1], b[2]),
288 Point3::new(c[0], c[1], c[2]),
289 ])
290 }
291
292 #[test]
293 fn empty_tree() {
294 let tree = BspTree::new();
295 assert!(tree.is_empty());
296 assert_eq!(tree.polygon_count(), 0);
297 assert_eq!(tree.depth(), 0);
298 }
299
300 #[test]
301 fn build_empty() {
302 let tree = BspTree::from_polygons(vec![]);
303 assert!(tree.is_empty());
304 }
305
306 #[test]
307 fn build_single_polygon() {
308 let poly = make_triangle([0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]);
309 let tree = BspTree::from_polygons(vec![poly]);
310
311 assert!(!tree.is_empty());
312 assert_eq!(tree.polygon_count(), 1);
313 assert_eq!(tree.depth(), 1);
314 }
315
316 #[test]
317 fn build_two_parallel_polygons() {
318 let poly1 = make_triangle([0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]);
320 let poly2 = make_triangle([0.0, 0.0, 1.0], [1.0, 0.0, 1.0], [0.0, 1.0, 1.0]);
321
322 let tree = BspTree::from_polygons(vec![poly1, poly2]);
323
324 assert_eq!(tree.polygon_count(), 2);
325 assert!(tree.depth() >= 1);
327 }
328
329 #[test]
330 fn build_coplanar_same_facing() {
331 let poly1 = make_triangle([0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]);
333 let poly2 = make_triangle([1.0, 0.0, 0.0], [2.0, 0.0, 0.0], [1.0, 1.0, 0.0]);
334
335 let tree = BspTree::from_polygons(vec![poly1, poly2]);
336
337 assert_eq!(tree.polygon_count(), 2);
338 assert_eq!(tree.depth(), 1);
340
341 let root = tree.root().unwrap();
342 assert_eq!(root.coplanar_count(), 2);
343 }
344
345 #[test]
346 fn build_spanning_polygon_gets_split() {
347 let splitter = make_triangle([0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 0.0, 1.0]);
349
350 let spanning = make_triangle([-0.5, -1.0, 0.5], [0.5, 1.0, 0.5], [0.5, -1.0, 0.5]);
352
353 let tree = BspTree::from_polygons(vec![splitter, spanning]);
354
355 assert_eq!(tree.polygon_count(), 3);
358 }
359
360 #[test]
361 fn traverse_front_to_back_single() {
362 let poly = make_triangle([0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]);
363 let tree = BspTree::from_polygons(vec![poly.clone()]);
364
365 let mut visitor = CollectingVisitor::new();
366 tree.traverse_front_to_back(Point3::new(0.0, 0.0, 10.0), &mut visitor);
367
368 assert_eq!(visitor.polygons().len(), 1);
369 }
370
371 #[test]
372 fn traverse_front_to_back_ordering() {
373 let poly_near = make_triangle([0.0, 0.0, 1.0], [1.0, 0.0, 1.0], [0.0, 1.0, 1.0]);
376 let poly_far = make_triangle([0.0, 0.0, -1.0], [1.0, 0.0, -1.0], [0.0, 1.0, -1.0]);
377
378 let tree = BspTree::from_polygons(vec![poly_far.clone(), poly_near.clone()]);
379
380 let mut visitor = CollectingVisitor::new();
382 tree.traverse_front_to_back(Point3::new(0.5, 0.5, 10.0), &mut visitor);
383
384 let collected = visitor.into_polygons();
385 assert_eq!(collected.len(), 2);
386
387 let first_z = collected[0].centroid().z;
390 let second_z = collected[1].centroid().z;
391 assert!(
392 first_z > second_z,
393 "Expected front-to-back order: first_z={} should be > second_z={}",
394 first_z,
395 second_z
396 );
397 }
398
399 #[test]
400 fn traverse_back_to_front_ordering() {
401 let poly_near = make_triangle([0.0, 0.0, 1.0], [1.0, 0.0, 1.0], [0.0, 1.0, 1.0]);
402 let poly_far = make_triangle([0.0, 0.0, -1.0], [1.0, 0.0, -1.0], [0.0, 1.0, -1.0]);
403
404 let tree = BspTree::from_polygons(vec![poly_far.clone(), poly_near.clone()]);
405
406 let mut visitor = CollectingVisitor::new();
407 tree.traverse_back_to_front(Point3::new(0.5, 0.5, 10.0), &mut visitor);
408
409 let collected = visitor.into_polygons();
410 assert_eq!(collected.len(), 2);
411
412 let first_z = collected[0].centroid().z;
414 let second_z = collected[1].centroid().z;
415 assert!(
416 first_z < second_z,
417 "Expected back-to-front order: first_z={} should be < second_z={}",
418 first_z,
419 second_z
420 );
421 }
422
423 #[test]
424 fn collect_polygons() {
425 let poly1 = make_triangle([0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]);
426 let poly2 = make_triangle([0.0, 0.0, 1.0], [1.0, 0.0, 1.0], [0.0, 1.0, 1.0]);
427 let poly3 = make_triangle([0.0, 0.0, 2.0], [1.0, 0.0, 2.0], [0.0, 1.0, 2.0]);
428
429 let tree = BspTree::from_polygons(vec![poly1, poly2, poly3]);
430 let collected = tree.collect_polygons();
431
432 assert_eq!(collected.len(), 3);
433 }
434}