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)]
44pub struct BspTree {
45 root: Option<BspNode>,
46}
47
48impl BspTree {
49 pub fn new() -> Self {
51 Self { root: None }
52 }
53
54 pub fn build<S: PlaneSelector>(polygons: Vec<Polygon>, selector: &S) -> Self {
62 Self {
63 root: build_node(polygons, selector),
64 }
65 }
66
67 pub fn from_polygons(polygons: Vec<Polygon>) -> Self {
69 use super::selector::FirstPolygon;
70 Self::build(polygons, &FirstPolygon)
71 }
72
73 #[inline]
75 pub fn is_empty(&self) -> bool {
76 self.root.is_none()
77 }
78
79 #[inline]
81 pub fn root(&self) -> Option<&BspNode> {
82 self.root.as_ref()
83 }
84
85 #[inline]
89 pub fn root_mut(&mut self) -> Option<&mut BspNode> {
90 self.root.as_mut()
91 }
92
93 pub fn polygon_count(&self) -> usize {
95 self.root.as_ref().map_or(0, |n| n.polygon_count())
96 }
97
98 pub fn depth(&self) -> usize {
100 self.root.as_ref().map_or(0, |n| n.depth())
101 }
102
103 pub fn traverse_front_to_back<V: BspVisitor>(&self, eye: Point3<f32>, visitor: &mut V) {
112 if let Some(ref root) = self.root {
113 traverse_front_to_back_node(root, eye, visitor);
114 }
115 }
116
117 pub fn traverse_back_to_front<V: BspVisitor>(&self, eye: Point3<f32>, visitor: &mut V) {
123 if let Some(ref root) = self.root {
124 traverse_back_to_front_node(root, eye, visitor);
125 }
126 }
127
128 pub fn collect_polygons(&self) -> Vec<Polygon> {
132 let mut result = Vec::with_capacity(self.polygon_count());
133 collect_polygons_recursive(self.root.as_ref(), &mut result);
134 result
135 }
136
137 }
140
141fn build_node<S: PlaneSelector>(mut polygons: Vec<Polygon>, selector: &S) -> Option<BspNode> {
143 if polygons.is_empty() {
144 return None;
145 }
146
147 let splitter_idx = polygons
149 .iter()
150 .position(|p| Some(p) == selector.select(&polygons))?;
151
152 let splitter = polygons.swap_remove(splitter_idx);
153 let plane = splitter.plane();
154
155 let mut coplanar_front = Vec::new();
157 let mut coplanar_back = Vec::new();
158 let mut front_list = Vec::new();
159 let mut back_list = Vec::new();
160
161 if faces_same_direction(&splitter, &plane) {
163 coplanar_front.push(splitter);
164 } else {
165 coplanar_back.push(splitter);
166 }
167
168 for polygon in polygons {
170 match polygon.classify(&plane) {
171 Classification::Front => {
172 front_list.push(polygon);
173 }
174 Classification::Back => {
175 back_list.push(polygon);
176 }
177 Classification::Coplanar => {
178 if faces_same_direction(&polygon, &plane) {
179 coplanar_front.push(polygon);
180 } else {
181 coplanar_back.push(polygon);
182 }
183 }
184 Classification::Spanning => {
185 let (front_part, back_part) = polygon.cut(&plane);
186 if let Some(f) = front_part {
187 front_list.push(f);
188 }
189 if let Some(b) = back_part {
190 back_list.push(b);
191 }
192 }
193 }
194 }
195
196 let mut node = BspNode::with_coplanar(plane, coplanar_front, coplanar_back);
198 node.set_front(build_node(front_list, selector));
199 node.set_back(build_node(back_list, selector));
200
201 Some(node)
202}
203
204fn traverse_front_to_back_node<V: BspVisitor>(node: &BspNode, eye: Point3<f32>, visitor: &mut V) {
206 let side = node.plane().classify_point(eye);
207
208 let coplanar: Vec<Polygon> = node.all_coplanar().cloned().collect();
210
211 match side {
212 crate::PlaneSide::Front | crate::PlaneSide::OnPlane => {
213 if let Some(front) = node.front() {
215 traverse_front_to_back_node(front, eye, visitor);
216 }
217 if !coplanar.is_empty() {
218 visitor.visit(&coplanar);
219 }
220 if let Some(back) = node.back() {
221 traverse_front_to_back_node(back, eye, visitor);
222 }
223 }
224 crate::PlaneSide::Back => {
225 if let Some(back) = node.back() {
227 traverse_front_to_back_node(back, eye, visitor);
228 }
229 if !coplanar.is_empty() {
230 visitor.visit(&coplanar);
231 }
232 if let Some(front) = node.front() {
233 traverse_front_to_back_node(front, eye, visitor);
234 }
235 }
236 }
237}
238
239fn traverse_back_to_front_node<V: BspVisitor>(node: &BspNode, eye: Point3<f32>, visitor: &mut V) {
241 let side = node.plane().classify_point(eye);
242
243 let coplanar: Vec<Polygon> = node.all_coplanar().cloned().collect();
244
245 match side {
246 crate::PlaneSide::Front | crate::PlaneSide::OnPlane => {
247 if let Some(back) = node.back() {
249 traverse_back_to_front_node(back, eye, visitor);
250 }
251 if !coplanar.is_empty() {
252 visitor.visit(&coplanar);
253 }
254 if let Some(front) = node.front() {
255 traverse_back_to_front_node(front, eye, visitor);
256 }
257 }
258 crate::PlaneSide::Back => {
259 if let Some(front) = node.front() {
261 traverse_back_to_front_node(front, eye, visitor);
262 }
263 if !coplanar.is_empty() {
264 visitor.visit(&coplanar);
265 }
266 if let Some(back) = node.back() {
267 traverse_back_to_front_node(back, eye, visitor);
268 }
269 }
270 }
271}
272
273fn collect_polygons_recursive(node: Option<&BspNode>, result: &mut Vec<Polygon>) {
275 if let Some(n) = node {
276 result.extend(n.all_coplanar().cloned());
277 collect_polygons_recursive(n.front(), result);
278 collect_polygons_recursive(n.back(), result);
279 }
280}
281
282#[cfg(test)]
283mod tests {
284 use super::*;
285 use crate::bsp::visitor::CollectingVisitor;
286 use nalgebra::Point3;
287
288 fn make_triangle(a: [f32; 3], b: [f32; 3], c: [f32; 3]) -> Polygon {
289 Polygon::new(vec![
290 Point3::new(a[0], a[1], a[2]),
291 Point3::new(b[0], b[1], b[2]),
292 Point3::new(c[0], c[1], c[2]),
293 ])
294 }
295
296 #[test]
297 fn empty_tree() {
298 let tree = BspTree::new();
299 assert!(tree.is_empty());
300 assert_eq!(tree.polygon_count(), 0);
301 assert_eq!(tree.depth(), 0);
302 }
303
304 #[test]
305 fn build_empty() {
306 let tree = BspTree::from_polygons(vec![]);
307 assert!(tree.is_empty());
308 }
309
310 #[test]
311 fn build_single_polygon() {
312 let poly = make_triangle([0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]);
313 let tree = BspTree::from_polygons(vec![poly]);
314
315 assert!(!tree.is_empty());
316 assert_eq!(tree.polygon_count(), 1);
317 assert_eq!(tree.depth(), 1);
318 }
319
320 #[test]
321 fn build_two_parallel_polygons() {
322 let poly1 = make_triangle([0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]);
324 let poly2 = make_triangle([0.0, 0.0, 1.0], [1.0, 0.0, 1.0], [0.0, 1.0, 1.0]);
325
326 let tree = BspTree::from_polygons(vec![poly1, poly2]);
327
328 assert_eq!(tree.polygon_count(), 2);
329 assert!(tree.depth() >= 1);
331 }
332
333 #[test]
334 fn build_coplanar_same_facing() {
335 let poly1 = make_triangle([0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]);
337 let poly2 = make_triangle([1.0, 0.0, 0.0], [2.0, 0.0, 0.0], [1.0, 1.0, 0.0]);
338
339 let tree = BspTree::from_polygons(vec![poly1, poly2]);
340
341 assert_eq!(tree.polygon_count(), 2);
342 assert_eq!(tree.depth(), 1);
344
345 let root = tree.root().unwrap();
346 assert_eq!(root.coplanar_count(), 2);
347 }
348
349 #[test]
350 fn build_spanning_polygon_gets_split() {
351 let splitter = make_triangle([0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 0.0, 1.0]);
353
354 let spanning = make_triangle([-0.5, -1.0, 0.5], [0.5, 1.0, 0.5], [0.5, -1.0, 0.5]);
356
357 let tree = BspTree::from_polygons(vec![splitter, spanning]);
358
359 assert_eq!(tree.polygon_count(), 3);
362 }
363
364 #[test]
365 fn traverse_front_to_back_single() {
366 let poly = make_triangle([0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]);
367 let tree = BspTree::from_polygons(vec![poly.clone()]);
368
369 let mut visitor = CollectingVisitor::new();
370 tree.traverse_front_to_back(Point3::new(0.0, 0.0, 10.0), &mut visitor);
371
372 assert_eq!(visitor.polygons().len(), 1);
373 }
374
375 #[test]
376 fn traverse_front_to_back_ordering() {
377 let poly_near = make_triangle([0.0, 0.0, 1.0], [1.0, 0.0, 1.0], [0.0, 1.0, 1.0]);
380 let poly_far = make_triangle([0.0, 0.0, -1.0], [1.0, 0.0, -1.0], [0.0, 1.0, -1.0]);
381
382 let tree = BspTree::from_polygons(vec![poly_far.clone(), poly_near.clone()]);
383
384 let mut visitor = CollectingVisitor::new();
386 tree.traverse_front_to_back(Point3::new(0.5, 0.5, 10.0), &mut visitor);
387
388 let collected = visitor.into_polygons();
389 assert_eq!(collected.len(), 2);
390
391 let first_z = collected[0].centroid().z;
394 let second_z = collected[1].centroid().z;
395 assert!(
396 first_z > second_z,
397 "Expected front-to-back order: first_z={} should be > second_z={}",
398 first_z,
399 second_z
400 );
401 }
402
403 #[test]
404 fn traverse_back_to_front_ordering() {
405 let poly_near = make_triangle([0.0, 0.0, 1.0], [1.0, 0.0, 1.0], [0.0, 1.0, 1.0]);
406 let poly_far = make_triangle([0.0, 0.0, -1.0], [1.0, 0.0, -1.0], [0.0, 1.0, -1.0]);
407
408 let tree = BspTree::from_polygons(vec![poly_far.clone(), poly_near.clone()]);
409
410 let mut visitor = CollectingVisitor::new();
411 tree.traverse_back_to_front(Point3::new(0.5, 0.5, 10.0), &mut visitor);
412
413 let collected = visitor.into_polygons();
414 assert_eq!(collected.len(), 2);
415
416 let first_z = collected[0].centroid().z;
418 let second_z = collected[1].centroid().z;
419 assert!(
420 first_z < second_z,
421 "Expected back-to-front order: first_z={} should be < second_z={}",
422 first_z,
423 second_z
424 );
425 }
426
427 #[test]
428 fn collect_polygons() {
429 let poly1 = make_triangle([0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]);
430 let poly2 = make_triangle([0.0, 0.0, 1.0], [1.0, 0.0, 1.0], [0.0, 1.0, 1.0]);
431 let poly3 = make_triangle([0.0, 0.0, 2.0], [1.0, 0.0, 2.0], [0.0, 1.0, 2.0]);
432
433 let tree = BspTree::from_polygons(vec![poly1, poly2, poly3]);
434 let collected = tree.collect_polygons();
435
436 assert_eq!(collected.len(), 3);
437 }
438}