bsp_pathfinding/tree/
node.rs

1use glam::Vec2;
2use rpds::Vector;
3use smallvec::{smallvec, SmallVec};
4
5use crate::{
6    util::{face_intersect, face_intersect_dir, Intersect},
7    ClippedFace, Face, Side, TOLERANCE,
8};
9
10use super::{NodeIndex, Nodes};
11
12#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
13#[derive(Debug)]
14/// Represents  a single node in the binary tree.
15/// The node constitutes of a splitting plane and children behind and in front
16/// of the plane.
17///
18/// A node can be double planar, which means that the partitioning plane
19/// contains two faces with opposite facing normals.
20pub struct BSPNode {
21    origin: Vec2,
22    normal: Vec2,
23
24    front: Option<NodeIndex>,
25    back: Option<NodeIndex>,
26
27    faces: SmallVec<[Face; 2]>,
28
29    depth: usize,
30}
31
32impl BSPNode {
33    /// Creates a new BSPNode and inserts it into nodes.
34    /// Returns None if there were not faces to create a node from
35    pub fn from_faces(nodes: &mut Nodes, faces: &[Face], depth: usize) -> Option<NodeIndex> {
36        let (current, faces) = faces.split_first()?;
37        // let dir = (current.vertices[1] - current.vertices[0]).normalize();
38        let p = current.vertices[0];
39
40        let mut front = Vec::new();
41        let mut back = Vec::new();
42
43        let mut coplanar = smallvec![*current];
44
45        let normal = current.normal;
46
47        for face in faces {
48            let side = face.side_of(current.vertices[0], current.normal);
49            match side {
50                Side::Front => front.push(*face),
51                Side::Back => back.push(*face),
52                Side::Coplanar => {
53                    coplanar.push(*face);
54                }
55                Side::Intersecting => {
56                    // Split the line in two and repeat the process
57                    let intersect = face_intersect(face.into_tuple(), p, normal);
58
59                    let [a, b] = face.split(intersect.point, normal);
60
61                    assert_eq!(a.side_of(p, normal), Side::Front);
62                    assert_eq!(b.side_of(p, normal), Side::Back);
63
64                    assert!(a.normal.dot(face.normal) > 0.0);
65                    assert!(b.normal.dot(face.normal) > 0.0);
66
67                    front.push(a);
68                    back.push(b)
69                }
70            }
71        }
72
73        let front = Self::from_faces(nodes, &front, depth + 1);
74        let back = Self::from_faces(nodes, &back, depth + 1);
75
76        assert!(current.normal.is_normalized());
77
78        let node = Self {
79            // Any point will do
80            origin: current.midpoint(),
81            faces: coplanar,
82            normal: current.normal,
83            front,
84            back,
85            depth,
86        };
87
88        Some(nodes.insert(node))
89    }
90
91    pub fn get_side(&self, point: Vec2) -> Side {
92        let dot = (point - self.origin).dot(self.normal());
93
94        if dot.abs() < TOLERANCE {
95            Side::Coplanar
96        } else if dot <= 0.0 {
97            Side::Back
98        } else {
99            Side::Front
100        }
101    }
102
103    /// Get the bspnode's front.
104    pub fn front(&self) -> Option<NodeIndex> {
105        self.front
106    }
107
108    /// Get the bspnode's back.
109    pub fn back(&self) -> Option<NodeIndex> {
110        self.back
111    }
112
113    /// Get the bspnode's normal.
114    #[inline]
115    pub fn normal(&self) -> Vec2 {
116        self.normal
117    }
118
119    /// Get the bspnode's origin.
120    #[inline]
121    pub fn origin(&self) -> Vec2 {
122        self.origin
123    }
124
125    pub fn descendants(index: NodeIndex, nodes: &Nodes) -> Descendants {
126        Descendants {
127            nodes,
128            stack: vec![index],
129        }
130    }
131
132    /// Get the bspnode's depth.
133    pub fn depth(&self) -> usize {
134        self.depth
135    }
136
137    fn get_adjacent_side(&self, p: Vec2, other: Vec2) -> Option<Side> {
138        self.faces
139            .iter()
140            .filter_map(|f| {
141                if f.contains_point(p) {
142                    Some(if (other - f.vertices[0]).dot(f.normal()) > 0.0 {
143                        Side::Front
144                    } else {
145                        Side::Back
146                    })
147                } else {
148                    None
149                }
150            })
151            .reduce(|acc, val| acc.min_side(val))
152    }
153
154    /// Clips a face by the BSP faces and returns several smaller faces
155    pub fn clip(
156        index: NodeIndex,
157        nodes: &Nodes,
158        mut portal: ClippedFace,
159        root_side: Side,
160    ) -> Vec<ClippedFace> {
161        let node = &nodes[index];
162
163        let side = portal.side_of(node.origin, node.normal);
164        // Allow back faces to override front
165        let a = (portal.vertices[0] - node.origin).dot(node.normal);
166        let b = (portal.vertices[1] - node.origin).dot(node.normal);
167
168        // a is touching the plane
169        if a.abs() < TOLERANCE {
170            if let Some(ad) = node.get_adjacent_side(portal.vertices[0], portal.vertices[1]) {
171                portal.adjacent[0] = true;
172                portal.sides[0] = ad;
173            }
174        }
175        // b is touching the plane
176        if b.abs() < TOLERANCE {
177            if let Some(ad) = node.get_adjacent_side(portal.vertices[1], portal.vertices[0]) {
178                portal.adjacent[1] = true;
179                portal.sides[1] = ad;
180            }
181        }
182
183        Self::clip_new(index, nodes, portal, side, root_side)
184    }
185
186    fn clip_new(
187        index: NodeIndex,
188        nodes: &Nodes,
189        mut portal: ClippedFace,
190        side: Side,
191        root_side: Side,
192    ) -> Vec<ClippedFace> {
193        let node = &nodes[index];
194        // The face is entirely in front of the node
195        match (side, node.front, node.back) {
196            (Side::Coplanar, Some(front), Some(back)) => {
197                // portal.src = NodeIndex::null();
198                Self::clip(front, nodes, portal, Side::Front)
199                    .into_iter()
200                    .map(|val| Self::clip(back, nodes, val, Side::Back))
201                    .flatten()
202                    .collect()
203            }
204            (Side::Coplanar, Some(front), _) => Self::clip(front, nodes, portal, Side::Front),
205            (Side::Coplanar, _, Some(back)) => Self::clip(back, nodes, portal, Side::Back),
206            (Side::Front, Some(front), _) => Self::clip(front, nodes, portal, root_side),
207            (Side::Back, _, Some(back)) => Self::clip(back, nodes, portal, root_side),
208            (Side::Intersecting, _, _) => {
209                let [front, back] = portal.split(node.origin, node.normal);
210
211                assert!(front.normal.dot(portal.normal) > 0.0);
212                assert!(back.normal.dot(portal.normal) > 0.0);
213
214                let mut result = Self::clip(index, nodes, front, root_side);
215
216                result.append(&mut Self::clip(index, nodes, back, root_side));
217                result
218            }
219            _ => {
220                if root_side == Side::Back {
221                    portal.dst = index;
222                } else {
223                    portal.src = index;
224                }
225                vec![portal]
226            }
227        }
228    }
229
230    pub fn generate_portals(
231        index: NodeIndex,
232        nodes: &Nodes,
233        clipping_planes: &Vector<Face>,
234        result: &mut impl Extend<ClippedFace>,
235    ) {
236        let node = &nodes[index];
237        let dir = Vec2::new(node.normal.y, -node.normal.x);
238        let mut min = Intersect::new(Vec2::ZERO, f32::MAX);
239        let mut adjacent = [false, false];
240        let mut max = Intersect::new(Vec2::ZERO, f32::MAX);
241
242        clipping_planes.iter().for_each(|val| {
243            let intersect = face_intersect_dir(node.origin, dir, val.vertices[0], val.normal());
244            if !intersect.distance.is_finite() {
245                return;
246            }
247
248            let ad = val.contains_point(intersect.point);
249
250            if intersect.distance > 0.0 && intersect.distance < max.distance {
251                max = intersect;
252                adjacent[0] = ad;
253            }
254            if intersect.distance < 0.0 && intersect.distance.abs() < min.distance.abs() {
255                min = intersect;
256                adjacent[1] = ad;
257            }
258        });
259
260        let portal = ClippedFace::new(
261            [max.point, min.point],
262            [Side::Front, Side::Front],
263            adjacent,
264            index,
265            index,
266        );
267
268        result.extend(
269            Self::clip(index, nodes, portal, Side::Front)
270                .into_iter()
271                .filter(|val| {
272                    val.src != val.dst
273                        && val.sides == [Side::Front; 2]
274                        && !node.faces.iter().any(|face| face.overlaps(val))
275                }),
276        );
277
278        // Add the current nodes clip plane before recursing
279        // result.push(portal);
280        let clipping_planes = node
281            .faces
282            .iter()
283            .fold(clipping_planes.clone(), |acc, val| acc.push_back(*val));
284
285        // Clone the clipping faces since the descendants of the children will
286        // also be added to the clipping planes,
287        // and we want to keep the clipping planes separated for subtrees.
288        if let Some(child) = node.front {
289            Self::generate_portals(child, nodes, &clipping_planes, result);
290        }
291
292        if let Some(child) = node.back {
293            Self::generate_portals(child, nodes, &clipping_planes, result);
294        }
295    }
296
297    pub fn is_leaf(&self) -> bool {
298        self.front.is_none() && self.back.is_none()
299    }
300
301    /// Get a reference to the bspnode's faces.
302    pub fn faces(&self) -> &[Face] {
303        &self.faces
304    }
305}
306
307pub struct Descendants<'a> {
308    nodes: &'a Nodes,
309
310    stack: Vec<NodeIndex>,
311}
312
313impl<'a> Iterator for Descendants<'a> {
314    type Item = (NodeIndex, &'a BSPNode);
315
316    fn next(&mut self) -> Option<Self::Item> {
317        let index = self.stack.pop()?;
318
319        let node = &self.nodes[index];
320        if let Some(front) = node.front {
321            self.stack.push(front)
322        }
323        if let Some(back) = node.back {
324            self.stack.push(back)
325        }
326
327        Some((index, node))
328    }
329}