1#![allow(dead_code)]
7
8#[allow(dead_code)]
10#[derive(Debug, Clone, Copy)]
11pub struct BspLine {
12 pub a: f32,
13 pub b: f32,
14 pub c: f32,
15}
16
17#[allow(dead_code)]
20pub fn bsp_line_side(line: &BspLine, p: [f32; 2]) -> f32 {
21 line.a * p[0] + line.b * p[1] + line.c
22}
23
24#[allow(dead_code)]
26#[derive(Debug, Clone)]
27pub struct BspPolygon {
28 pub vertices: Vec<[f32; 2]>,
29 pub label: String,
30}
31
32#[allow(dead_code)]
34#[derive(Debug, Clone)]
35pub enum BspNode {
36 Leaf(Vec<BspPolygon>),
37 Branch {
38 splitter: BspLine,
39 front: Box<BspNode>,
40 back: Box<BspNode>,
41 },
42}
43
44#[allow(dead_code)]
46#[derive(Debug, Clone, Default)]
47pub struct BspTree2D {
48 root: Option<Box<BspNode>>,
49}
50
51#[allow(dead_code)]
53pub fn new_bsp_tree() -> BspTree2D {
54 BspTree2D::default()
55}
56
57#[allow(dead_code)]
60pub fn bsp_split_polygon(poly: &[[f32; 2]], line: &BspLine) -> (Vec<[f32; 2]>, Vec<[f32; 2]>) {
61 let mut front = Vec::new();
62 let mut back = Vec::new();
63 let n = poly.len();
64 if n == 0 {
65 return (front, back);
66 }
67 for i in 0..n {
68 let curr = poly[i];
69 let next = poly[(i + 1) % n];
70 let d_curr = bsp_line_side(line, curr);
71 let d_next = bsp_line_side(line, next);
72 if d_curr >= 0.0 {
73 front.push(curr);
74 } else {
75 back.push(curr);
76 }
77 if (d_curr > 0.0 && d_next < 0.0) || (d_curr < 0.0 && d_next > 0.0) {
79 let t = d_curr / (d_curr - d_next);
80 let ix = curr[0] + t * (next[0] - curr[0]);
81 let iy = curr[1] + t * (next[1] - curr[1]);
82 front.push([ix, iy]);
83 back.push([ix, iy]);
84 }
85 }
86 (front, back)
87}
88
89#[allow(dead_code)]
91pub fn bsp_build(polygons: Vec<BspPolygon>) -> BspNode {
92 if polygons.is_empty() {
93 return BspNode::Leaf(Vec::new());
94 }
95 if polygons.len() == 1 {
96 return BspNode::Leaf(polygons);
97 }
98 let splitter = {
100 let verts = &polygons[0].vertices;
101 if verts.len() < 2 {
102 return BspNode::Leaf(polygons);
103 }
104 let a = verts[0];
105 let b = verts[1];
106 let dx = b[0] - a[0];
107 let dy = b[1] - a[1];
108 let len = (dx * dx + dy * dy).sqrt().max(1e-10);
109 BspLine {
110 a: -dy / len,
111 b: dx / len,
112 c: (dy * a[0] - dx * a[1]) / len,
113 }
114 };
115
116 let mut front_polys = Vec::new();
117 let mut back_polys = Vec::new();
118 let input_count = polygons.len();
119
120 for poly in polygons {
121 let (f, b) = bsp_split_polygon(&poly.vertices, &splitter);
122 let f_ok = f.len() >= 3;
123 let b_ok = b.len() >= 3;
124 if f_ok {
125 front_polys.push(BspPolygon {
126 vertices: f,
127 label: poly.label.clone(),
128 });
129 }
130 if b_ok {
131 back_polys.push(BspPolygon {
132 vertices: b,
133 label: poly.label.clone(),
134 });
135 }
136 if !f_ok && !b_ok {
137 front_polys.push(poly);
138 }
139 }
140
141 if front_polys.len() == input_count && back_polys.is_empty() {
144 return BspNode::Leaf(front_polys);
145 }
146 if back_polys.len() == input_count && front_polys.is_empty() {
147 return BspNode::Leaf(back_polys);
148 }
149
150 BspNode::Branch {
151 splitter,
152 front: Box::new(bsp_build(front_polys)),
153 back: Box::new(bsp_build(back_polys)),
154 }
155}
156
157#[allow(dead_code)]
159pub fn bsp_polygon_count(node: &BspNode) -> usize {
160 match node {
161 BspNode::Leaf(polys) => polys.len(),
162 BspNode::Branch { front, back, .. } => bsp_polygon_count(front) + bsp_polygon_count(back),
163 }
164}
165
166#[allow(dead_code)]
168pub fn bsp_depth(node: &BspNode) -> usize {
169 match node {
170 BspNode::Leaf(_) => 0,
171 BspNode::Branch { front, back, .. } => 1 + bsp_depth(front).max(bsp_depth(back)),
172 }
173}
174
175#[allow(dead_code)]
177pub fn bsp_collect_polygons(node: &BspNode) -> Vec<&BspPolygon> {
178 let mut result = Vec::new();
179 bsp_collect_recursive(node, &mut result);
180 result
181}
182
183fn bsp_collect_recursive<'a>(node: &'a BspNode, out: &mut Vec<&'a BspPolygon>) {
184 match node {
185 BspNode::Leaf(polys) => {
186 for p in polys {
187 out.push(p);
188 }
189 }
190 BspNode::Branch { front, back, .. } => {
191 bsp_collect_recursive(front, out);
192 bsp_collect_recursive(back, out);
193 }
194 }
195}
196
197#[allow(dead_code)]
199pub fn bsp_is_leaf(node: &BspNode) -> bool {
200 matches!(node, BspNode::Leaf(_))
201}
202
203#[allow(dead_code)]
205pub fn bsp_set_root(tree: &mut BspTree2D, node: BspNode) {
206 tree.root = Some(Box::new(node));
207}
208
209#[allow(dead_code)]
211pub fn bsp_get_root(tree: &BspTree2D) -> Option<&BspNode> {
212 tree.root.as_deref()
213}
214
215#[cfg(test)]
216mod tests {
217 use super::*;
218
219 fn make_quad(x: f32, y: f32, w: f32, h: f32, label: &str) -> BspPolygon {
220 BspPolygon {
221 vertices: vec![[x, y], [x + w, y], [x + w, y + h], [x, y + h]],
222 label: label.to_string(),
223 }
224 }
225
226 #[test]
227 fn test_new_tree_empty() {
228 let tree = new_bsp_tree();
229 assert!(bsp_get_root(&tree).is_none());
230 }
231
232 #[test]
233 fn test_build_single_polygon() {
234 let poly = make_quad(0.0, 0.0, 1.0, 1.0, "a");
235 let node = bsp_build(vec![poly]);
236 assert!(bsp_is_leaf(&node));
237 }
238
239 #[test]
240 fn test_build_two_polygons() {
241 let p1 = make_quad(-1.0, -1.0, 2.0, 2.0, "a");
242 let p2 = make_quad(-1.0, 1.0, 2.0, 2.0, "b");
243 let node = bsp_build(vec![p1, p2]);
244 let count = bsp_polygon_count(&node);
246 assert!(count >= 1);
247 }
248
249 #[test]
250 fn test_bsp_line_side() {
251 let line = BspLine {
252 a: 1.0,
253 b: 0.0,
254 c: 0.0,
255 };
256 assert!(bsp_line_side(&line, [1.0, 0.0]) > 0.0);
257 assert!(bsp_line_side(&line, [-1.0, 0.0]) < 0.0);
258 }
259
260 #[test]
261 fn test_split_polygon_horizontal() {
262 let line = BspLine {
263 a: 0.0,
264 b: 1.0,
265 c: -0.5,
266 };
267 let poly = vec![[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]];
268 let (f, b) = bsp_split_polygon(&poly, &line);
269 assert!(!f.is_empty());
270 assert!(!b.is_empty());
271 }
272
273 #[test]
274 fn test_collect_polygons() {
275 let p1 = make_quad(0.0, 0.0, 1.0, 1.0, "a");
276 let p2 = make_quad(2.0, 0.0, 1.0, 1.0, "b");
277 let node = bsp_build(vec![p1, p2]);
278 let collected = bsp_collect_polygons(&node);
279 assert!(!collected.is_empty());
280 }
281
282 #[test]
283 fn test_bsp_depth_single() {
284 let poly = make_quad(0.0, 0.0, 1.0, 1.0, "a");
285 let node = bsp_build(vec![poly]);
286 assert_eq!(bsp_depth(&node), 0);
287 }
288
289 #[test]
290 fn test_bsp_set_and_get_root() {
291 let mut tree = new_bsp_tree();
292 let poly = make_quad(0.0, 0.0, 1.0, 1.0, "a");
293 let node = bsp_build(vec![poly]);
294 bsp_set_root(&mut tree, node);
295 assert!(bsp_get_root(&tree).is_some());
296 }
297
298 #[test]
299 fn test_empty_build() {
300 let node = bsp_build(vec![]);
301 assert!(bsp_is_leaf(&node));
302 assert_eq!(bsp_polygon_count(&node), 0);
303 }
304}