Skip to main content

box2d_rust/dynamic_tree/
rebuild.rs

1// Tree rebuild with the median-split heuristic from dynamic_tree.c.
2// The SAH heuristic (B2_TREE_HEURISTIC == 1) is compiled out upstream and is
3// not ported.
4// SPDX-FileCopyrightText: 2023 Erin Catto
5// SPDX-License-Identifier: MIT
6
7use super::{DynamicTree, ENLARGED_NODE, TREE_STACK_SIZE};
8use crate::core::NULL_INDEX;
9use crate::math_functions::{aabb_center, aabb_union, max, min, sub, Vec2};
10
11fn max_u16(a: u16, b: u16) -> u16 {
12    if a > b {
13        a
14    } else {
15        b
16    }
17}
18
19/// Median split heuristic. (static b2PartitionMid)
20fn partition_mid(indices: &mut [i32], centers: &mut [Vec2]) -> i32 {
21    let count = indices.len();
22
23    // Handle trivial case
24    if count <= 2 {
25        return (count / 2) as i32;
26    }
27
28    let mut lower_bound = centers[0];
29    let mut upper_bound = centers[0];
30
31    for center in centers.iter().skip(1) {
32        lower_bound = min(lower_bound, *center);
33        upper_bound = max(upper_bound, *center);
34    }
35
36    let d = sub(upper_bound, lower_bound);
37    let c = Vec2 {
38        x: 0.5 * (lower_bound.x + upper_bound.x),
39        y: 0.5 * (lower_bound.y + upper_bound.y),
40    };
41
42    // Partition longest axis using the Hoare partition scheme
43    // https://en.wikipedia.org/wiki/Quicksort
44    // https://nicholasvadivelu.com/2021/01/11/array-partition/
45    let (mut i1, mut i2) = (0usize, count);
46    if d.x > d.y {
47        let pivot = c.x;
48
49        while i1 < i2 {
50            while i1 < i2 && centers[i1].x < pivot {
51                i1 += 1;
52            }
53
54            while i1 < i2 && centers[i2 - 1].x >= pivot {
55                i2 -= 1;
56            }
57
58            if i1 < i2 {
59                indices.swap(i1, i2 - 1);
60                centers.swap(i1, i2 - 1);
61
62                i1 += 1;
63                i2 -= 1;
64            }
65        }
66    } else {
67        let pivot = c.y;
68
69        while i1 < i2 {
70            while i1 < i2 && centers[i1].y < pivot {
71                i1 += 1;
72            }
73
74            while i1 < i2 && centers[i2 - 1].y >= pivot {
75                i2 -= 1;
76            }
77
78            if i1 < i2 {
79                indices.swap(i1, i2 - 1);
80                centers.swap(i1, i2 - 1);
81
82                i1 += 1;
83                i2 -= 1;
84            }
85        }
86    }
87    debug_assert!(i1 == i2);
88
89    if i1 > 0 && i1 < count {
90        i1 as i32
91    } else {
92        (count / 2) as i32
93    }
94}
95
96/// Temporary data used to track the rebuild of a tree node.
97/// (struct b2RebuildItem)
98#[derive(Clone, Copy, Default)]
99struct RebuildItem {
100    node_index: i32,
101    child_count: i32,
102    // Leaf indices
103    start_index: i32,
104    split_index: i32,
105    end_index: i32,
106}
107
108impl DynamicTree {
109    /// Returns the root node index. (static b2BuildTree)
110    fn build_tree(&mut self, leaf_count: i32) -> i32 {
111        if leaf_count == 1 {
112            let leaf = self.leaf_indices[0];
113            self.nodes[leaf as usize].parent = NULL_INDEX;
114            return leaf;
115        }
116
117        let mut stack = vec![RebuildItem::default(); TREE_STACK_SIZE];
118        let mut top = 0usize;
119
120        stack[0].node_index = self.allocate_node();
121        stack[0].child_count = -1;
122        stack[0].start_index = 0;
123        stack[0].end_index = leaf_count;
124        stack[0].split_index = {
125            // Split borrows: partition operates on the rebuild scratch arrays.
126            let (indices, centers) = (&mut self.leaf_indices, &mut self.leaf_centers);
127            partition_mid(
128                &mut indices[..leaf_count as usize],
129                &mut centers[..leaf_count as usize],
130            )
131        };
132
133        loop {
134            stack[top].child_count += 1;
135            let item = stack[top];
136
137            if item.child_count == 2 {
138                // This internal node has both children established
139
140                if top == 0 {
141                    // all done
142                    break;
143                }
144
145                let parent_item = stack[top - 1];
146
147                if parent_item.child_count == 0 {
148                    debug_assert!(self.nodes[parent_item.node_index as usize].child1 == NULL_INDEX);
149                    self.nodes[parent_item.node_index as usize].child1 = item.node_index;
150                } else {
151                    debug_assert!(parent_item.child_count == 1);
152                    debug_assert!(self.nodes[parent_item.node_index as usize].child2 == NULL_INDEX);
153                    self.nodes[parent_item.node_index as usize].child2 = item.node_index;
154                }
155
156                let node_index = item.node_index as usize;
157                debug_assert!(self.nodes[node_index].parent == NULL_INDEX);
158                self.nodes[node_index].parent = parent_item.node_index;
159
160                debug_assert!(self.nodes[node_index].child1 != NULL_INDEX);
161                debug_assert!(self.nodes[node_index].child2 != NULL_INDEX);
162                let c1 = self.nodes[node_index].child1 as usize;
163                let c2 = self.nodes[node_index].child2 as usize;
164
165                self.nodes[node_index].aabb = aabb_union(self.nodes[c1].aabb, self.nodes[c2].aabb);
166                self.nodes[node_index].height =
167                    1 + max_u16(self.nodes[c1].height, self.nodes[c2].height);
168                self.nodes[node_index].category_bits =
169                    self.nodes[c1].category_bits | self.nodes[c2].category_bits;
170
171                // Pop stack
172                top -= 1;
173            } else {
174                let (start_index, end_index) = if item.child_count == 0 {
175                    (item.start_index, item.split_index)
176                } else {
177                    debug_assert!(item.child_count == 1);
178                    (item.split_index, item.end_index)
179                };
180
181                let count = end_index - start_index;
182
183                if count == 1 {
184                    let child_index = self.leaf_indices[start_index as usize];
185                    let node_index = item.node_index as usize;
186
187                    if item.child_count == 0 {
188                        debug_assert!(self.nodes[node_index].child1 == NULL_INDEX);
189                        self.nodes[node_index].child1 = child_index;
190                    } else {
191                        debug_assert!(item.child_count == 1);
192                        debug_assert!(self.nodes[node_index].child2 == NULL_INDEX);
193                        self.nodes[node_index].child2 = child_index;
194                    }
195
196                    debug_assert!(self.nodes[child_index as usize].parent == NULL_INDEX);
197                    self.nodes[child_index as usize].parent = item.node_index;
198                } else {
199                    debug_assert!(count > 0);
200                    debug_assert!(top < TREE_STACK_SIZE);
201
202                    top += 1;
203                    let node_index = self.allocate_node();
204                    let split_index = {
205                        let (s, e) = (start_index as usize, end_index as usize);
206                        let (indices, centers) = (&mut self.leaf_indices, &mut self.leaf_centers);
207                        partition_mid(&mut indices[s..e], &mut centers[s..e])
208                    };
209                    let new_item = &mut stack[top];
210                    new_item.node_index = node_index;
211                    new_item.child_count = -1;
212                    new_item.start_index = start_index;
213                    new_item.end_index = end_index;
214                    new_item.split_index = split_index + start_index;
215                }
216            }
217        }
218
219        let root_index = stack[0].node_index as usize;
220        debug_assert!(self.nodes[root_index].parent == NULL_INDEX);
221        debug_assert!(self.nodes[root_index].child1 != NULL_INDEX);
222        debug_assert!(self.nodes[root_index].child2 != NULL_INDEX);
223
224        let c1 = self.nodes[root_index].child1 as usize;
225        let c2 = self.nodes[root_index].child2 as usize;
226
227        self.nodes[root_index].aabb = aabb_union(self.nodes[c1].aabb, self.nodes[c2].aabb);
228        self.nodes[root_index].height = 1 + max_u16(self.nodes[c1].height, self.nodes[c2].height);
229        self.nodes[root_index].category_bits =
230            self.nodes[c1].category_bits | self.nodes[c2].category_bits;
231
232        stack[0].node_index
233    }
234
235    /// Rebuild the tree while retaining subtrees that haven't changed.
236    /// Returns the number of boxes sorted. (b2DynamicTree_Rebuild)
237    pub fn rebuild(&mut self, full_build: bool) -> i32 {
238        let proxy_count = self.proxy_count;
239        if proxy_count == 0 {
240            return 0;
241        }
242
243        // Ensure capacity for rebuild space
244        if proxy_count > self.rebuild_capacity {
245            let new_capacity = proxy_count + proxy_count / 2;
246
247            self.leaf_indices = vec![0; new_capacity as usize];
248            self.leaf_centers = vec![Vec2::default(); new_capacity as usize];
249            self.rebuild_capacity = new_capacity;
250        }
251
252        let mut leaf_count = 0usize;
253        let mut stack = [0i32; TREE_STACK_SIZE];
254        let mut stack_count = 0usize;
255
256        let mut node_index = self.root;
257
258        // Gather all proxy nodes that have grown and all internal nodes that
259        // haven't grown. Both are considered leaves in the tree rebuild.
260        // Free all internal nodes that have grown.
261        loop {
262            let node = self.nodes[node_index as usize];
263            if node.height == 0 || (node.flags & ENLARGED_NODE == 0 && !full_build) {
264                self.leaf_indices[leaf_count] = node_index;
265                self.leaf_centers[leaf_count] = aabb_center(node.aabb);
266                leaf_count += 1;
267
268                // Detach
269                self.nodes[node_index as usize].parent = NULL_INDEX;
270            } else {
271                let doomed_node_index = node_index;
272
273                // Handle children
274                node_index = node.child1;
275
276                if stack_count < TREE_STACK_SIZE {
277                    stack[stack_count] = node.child2;
278                    stack_count += 1;
279                } else {
280                    debug_assert!(stack_count < TREE_STACK_SIZE);
281                }
282
283                // Remove doomed node
284                self.free_node(doomed_node_index);
285
286                continue;
287            }
288
289            if stack_count == 0 {
290                break;
291            }
292
293            stack_count -= 1;
294            node_index = stack[stack_count];
295        }
296
297        debug_assert!(leaf_count <= proxy_count as usize);
298
299        self.root = self.build_tree(leaf_count as i32);
300
301        self.validate();
302
303        leaf_count as i32
304    }
305}