parry3d_f64/partitioning/qbvh/
update.rs1use crate::bounding_volume::{Aabb, BoundingVolume, SimdAabb};
2#[cfg(feature = "dim3")]
3use crate::math::Vector;
4use crate::math::{Point, Real};
5use crate::partitioning::{CenterDataSplitter, QbvhProxy};
6use crate::simd::{SimdReal, SIMD_WIDTH};
7use alloc::{vec, vec::Vec};
8use simba::simd::{SimdBool, SimdValue};
9
10use super::{IndexedData, NodeIndex, Qbvh, QbvhNode, QbvhNodeFlags};
11
12#[cfg(test)]
13mod tests;
14
15#[derive(Clone, Default)]
16pub struct QbvhUpdateWorkspace {
21 stack: Vec<(u32, u8)>,
22 dirty_parent_nodes: Vec<u32>,
23 to_sort: Vec<usize>,
25 orig_ids: Vec<u32>,
26 is_leaf: Vec<bool>,
27 aabbs: Vec<Aabb>,
28}
29
30impl QbvhUpdateWorkspace {
31 fn clear(&mut self) {
32 self.stack.clear();
33 self.dirty_parent_nodes.clear();
34 self.to_sort.clear();
35 self.orig_ids.clear();
36 self.is_leaf.clear();
37 self.aabbs.clear();
38 }
39}
40
41impl<LeafData: IndexedData> Qbvh<LeafData> {
42 pub fn remove(&mut self, data: LeafData) -> Option<LeafData> {
44 let id = data.index();
45 let proxy = self.proxies.get_mut(id)?;
46 let node = self.nodes.get_mut(proxy.node.index as usize)?;
47 node.children[proxy.node.lane as usize] = u32::MAX;
48
49 if !node.is_dirty() {
50 node.set_dirty(true);
51 self.dirty_nodes.push(proxy.node.index);
52 }
53
54 *proxy = QbvhProxy::invalid();
55
56 Some(data)
57 }
58
59 pub fn pre_update_or_insert(&mut self, data: LeafData) {
63 if self.nodes.is_empty() {
64 let mut root = QbvhNode::empty();
65 root.children = [1, u32::MAX, u32::MAX, u32::MAX];
66 self.nodes
67 .extend_from_slice(&[root, QbvhNode::empty_leaf_with_parent(NodeIndex::new(0, 0))]);
68 }
69
70 let proxy_id = data.index();
71
72 if self.proxies.len() <= proxy_id {
73 self.proxies.resize(proxy_id + 1, QbvhProxy::invalid());
74 }
75
76 let proxy = &mut self.proxies[proxy_id];
77 proxy.data = data;
78
79 if proxy.is_detached() {
80 for ii in 0..SIMD_WIDTH {
82 let mut child = self.nodes[0].children[ii];
83
84 if child == u32::MAX {
85 child = self.nodes.len() as u32;
87 self.nodes
88 .push(QbvhNode::empty_leaf_with_parent(NodeIndex::new(
89 0, ii as u8,
90 )));
91 self.nodes[0].children[ii] = child;
92 }
93
94 let child_node = &mut self.nodes[child as usize];
95 if !child_node.is_leaf() {
97 continue;
98 }
99
100 for kk in 0..SIMD_WIDTH {
102 if child_node.children[kk] == u32::MAX {
103 child_node.children[kk] = proxy_id as u32;
104 proxy.node = NodeIndex::new(child, kk as u8);
105
106 if !child_node.is_dirty() {
107 self.dirty_nodes.push(child);
108 child_node.set_dirty(true);
109 }
110
111 return;
112 }
113 }
114 }
115
116 let mut old_root = self.nodes[0];
119 old_root.parent = NodeIndex::new(0, 0);
120
121 for child_id in old_root.children {
122 let parent_index = self.nodes.len() as u32;
123
124 if let Some(child_node) = self.nodes.get_mut(child_id as usize) {
125 child_node.parent.index = parent_index;
126 }
127 }
128
129 let new_leaf_node_id = self.nodes.len() as u32 + 1;
130 let mut new_leaf_node = QbvhNode::empty_leaf_with_parent(NodeIndex::new(0, 1));
131 new_leaf_node.children[0] = proxy_id as u32;
132 self.dirty_nodes.push(new_leaf_node_id);
135 new_leaf_node.set_dirty(true);
136 proxy.node = NodeIndex::new(new_leaf_node_id, 0);
137
138 let new_root_children = [
139 self.nodes.len() as u32,
140 new_leaf_node_id,
141 u32::MAX,
142 u32::MAX,
143 ];
144
145 self.nodes.extend_from_slice(&[old_root, new_leaf_node]);
146 self.nodes[0].children = new_root_children;
147 } else {
148 let node = &mut self.nodes[proxy.node.index as usize];
149 if !node.is_dirty() {
150 node.set_dirty(true);
151 self.dirty_nodes.push(proxy.node.index);
152 }
153 }
154 }
155
156 #[allow(dead_code)] pub(crate) fn clear_changed_flag(&mut self, workspace: &mut QbvhUpdateWorkspace) {
158 if self.nodes.is_empty() {
159 return;
160 }
161
162 workspace.clear();
163 workspace.stack.push((0, 0));
164
165 while let Some((id, _)) = workspace.stack.pop() {
166 let node = &mut self.nodes[id as usize];
167
168 if node.is_changed() {
169 node.set_changed(false);
170
171 for child in node.children {
172 if child < self.nodes.len() as u32 {
173 workspace.stack.push((child, 0));
174 }
175 }
176 }
177 }
178 }
179
180 #[doc(hidden)]
181 pub fn check_topology(&self, check_aabbs: bool, aabb_builder: impl Fn(&LeafData) -> Aabb) {
182 if self.nodes.is_empty() {
183 return;
184 }
185
186 let mut stack = vec![];
187 stack.push(0);
188
189 let mut node_id_found = vec![false; self.nodes.len()];
190 let mut proxy_id_found = vec![false; self.proxies.len()];
191
192 while let Some(id) = stack.pop() {
193 let node = &self.nodes[id as usize];
194
195 assert!(!node_id_found[id as usize]);
197 node_id_found[id as usize] = true;
198
199 if id != 0 {
200 let parent = &self.nodes[node.parent.index as usize];
201
202 assert!(!parent.is_leaf());
204 assert_eq!(parent.children[node.parent.lane as usize], id);
205
206 if check_aabbs {
207 assert!(
209 parent
210 .simd_aabb
211 .extract(node.parent.lane as usize)
212 .contains(&node.simd_aabb.to_merged_aabb()),
213 "failed for {id}"
214 );
215 }
216
217 if node.is_changed() {
219 assert!(parent.is_changed());
220 }
221 }
222
223 if node.is_leaf() {
224 for ii in 0..SIMD_WIDTH {
225 let proxy_id = node.children[ii];
226 if proxy_id != u32::MAX {
227 assert!(!proxy_id_found[proxy_id as usize]);
229 proxy_id_found[proxy_id as usize] = true;
230
231 if check_aabbs {
232 let aabb = node.simd_aabb.extract(ii);
234 assert!(
235 aabb.contains(&aabb_builder(&self.proxies[proxy_id as usize].data))
236 );
237 }
238
239 assert_eq!(
241 self.proxies[proxy_id as usize].node,
242 NodeIndex::new(id, ii as u8),
243 "Failed {proxy_id}"
244 );
245 }
246 }
247 } else {
248 for child in node.children {
249 if child != u32::MAX {
250 stack.push(child);
251 }
252 }
253 }
254 }
255
256 assert_eq!(
258 proxy_id_found.iter().filter(|found| **found).count(),
259 self.proxies.iter().filter(|p| !p.is_detached()).count()
260 );
261 }
262
263 pub fn refit<F>(
268 &mut self,
269 margin: Real,
270 workspace: &mut QbvhUpdateWorkspace,
271 aabb_builder: F,
272 ) -> usize
273 where
274 F: Fn(&LeafData) -> Aabb,
275 {
276 workspace.clear();
278 let margin = SimdReal::splat(margin);
279 let mut first_iter = true;
280 let mut num_changed = 0;
281
282 while !self.dirty_nodes.is_empty() {
283 while let Some(id) = self.dirty_nodes.pop() {
284 if let Some(node) = self.nodes.get(id as usize) {
286 let mut new_aabbs = [Aabb::new_invalid(); SIMD_WIDTH];
288 for (child_id, new_aabb) in node.children.iter().zip(new_aabbs.iter_mut()) {
289 if node.is_leaf() {
290 if let Some(proxy) = self.proxies.get(*child_id as usize) {
292 *new_aabb = aabb_builder(&proxy.data);
293 }
294 } else {
295 if let Some(node) = self.nodes.get(*child_id as usize) {
297 *new_aabb = node.simd_aabb.to_merged_aabb();
298 }
299 }
300 }
301
302 let node = &mut self.nodes[id as usize];
303 let new_simd_aabb = SimdAabb::from(new_aabbs);
304 node.set_dirty(false);
305
306 if !first_iter || !node.simd_aabb.contains(&new_simd_aabb).all() {
307 node.set_changed(true);
308 node.simd_aabb = new_simd_aabb;
309 node.simd_aabb.loosen(margin);
310 let parent_id = node.parent.index;
311 num_changed += 1;
312
313 if let Some(parent) = self.nodes.get_mut(parent_id as usize) {
314 if !parent.is_dirty() {
315 workspace.dirty_parent_nodes.push(parent_id);
316 parent.set_dirty(true);
317 }
318 }
319 }
320 }
321 }
322
323 first_iter = false;
324 core::mem::swap(&mut self.dirty_nodes, &mut workspace.dirty_parent_nodes);
325 }
326
327 num_changed
328 }
329
330 pub fn rebalance(&mut self, margin: Real, workspace: &mut QbvhUpdateWorkspace) {
335 if self.nodes.is_empty() {
336 return;
337 }
338
339 workspace.clear();
340
341 const MIN_CHANGED_DEPTH: u8 = 5; const FULL_REBUILD_DEPTH: u8 = 15;
350
351 for root_child in self.nodes[0].children {
352 if root_child < self.nodes.len() as u32 {
353 workspace.stack.push((root_child, 1));
354 }
355 }
356
357 let mut force_full_rebuild = false;
359 while let Some((id, depth)) = workspace.stack.pop() {
360 if depth > FULL_REBUILD_DEPTH {
361 force_full_rebuild = true;
362 break;
363 }
364
365 let node = &mut self.nodes[id as usize];
366
367 if node.is_leaf() {
368 self.free_list.push(id);
369 for ii in 0..SIMD_WIDTH {
370 let proxy_id = node.children[ii];
371 if proxy_id < self.proxies.len() as u32 {
372 workspace.orig_ids.push(proxy_id);
373 workspace.aabbs.push(node.simd_aabb.extract(ii));
374 workspace.is_leaf.push(true);
375 }
376 }
377 } else if node.is_changed() || depth < MIN_CHANGED_DEPTH {
378 self.free_list.push(id);
379
380 for child in node.children {
381 if child < self.nodes.len() as u32 {
382 workspace.stack.push((child, depth + 1));
383 }
384 }
385 } else {
386 workspace.orig_ids.push(id);
387 workspace.aabbs.push(node.simd_aabb.to_merged_aabb());
388 workspace.is_leaf.push(false);
389 }
390 }
391
392 if force_full_rebuild {
393 workspace.clear();
394 let all_leaves: Vec<_> = self
395 .proxies
396 .iter()
397 .filter_map(|proxy| self.node_aabb(proxy.node).map(|aabb| (proxy.data, aabb)))
398 .collect();
399
400 self.clear_and_rebuild(all_leaves.into_iter(), 0.0);
401 return;
402 }
403
404 workspace.to_sort.extend(0..workspace.orig_ids.len());
405 let root_id = NodeIndex::new(0, 0);
406
407 let mut indices = core::mem::take(&mut workspace.to_sort);
408 let (id, aabb) = self.do_recurse_rebalance(&mut indices, workspace, root_id, margin);
409 workspace.to_sort = indices;
410
411 self.root_aabb = aabb;
412
413 self.nodes[0] = QbvhNode {
414 simd_aabb: SimdAabb::from([
415 aabb,
416 Aabb::new_invalid(),
417 Aabb::new_invalid(),
418 Aabb::new_invalid(),
419 ]),
420 children: [id, u32::MAX, u32::MAX, u32::MAX],
421 parent: NodeIndex::invalid(),
422 flags: QbvhNodeFlags::default(),
423 };
424 }
425
426 fn do_recurse_rebalance(
427 &mut self,
428 indices: &mut [usize],
429 workspace: &QbvhUpdateWorkspace,
430 parent: NodeIndex,
431 margin: Real,
432 ) -> (u32, Aabb) {
433 if indices.len() <= 4 {
434 let mut has_leaf = false;
436 let mut has_internal = false;
437
438 for id in &*indices {
439 has_leaf |= workspace.is_leaf[*id];
440 has_internal |= !workspace.is_leaf[*id];
441 }
442
443 let my_internal_id = if has_internal {
444 self.free_list.pop().unwrap_or_else(|| {
445 self.nodes.push(QbvhNode::empty());
446 self.nodes.len() as u32 - 1
447 })
448 } else {
449 u32::MAX
450 };
451
452 let my_leaf_id = if has_leaf {
453 self.free_list.pop().unwrap_or_else(|| {
454 self.nodes.push(QbvhNode::empty());
455 self.nodes.len() as u32 - 1
456 })
457 } else {
458 u32::MAX
459 };
460
461 let mut my_leaf_aabb = Aabb::new_invalid();
462 let mut my_internal_aabb = Aabb::new_invalid();
463
464 let mut leaf_aabbs = [Aabb::new_invalid(); 4];
465 let mut internal_aabbs = [Aabb::new_invalid(); 4];
466
467 let mut proxy_ids = [u32::MAX; 4];
468 let mut internal_ids = [u32::MAX; 4];
469 let mut new_internal_lane_containing_leaf = usize::MAX;
470
471 for (k, id) in indices.iter().enumerate() {
472 let orig_id = workspace.orig_ids[*id];
473 if workspace.is_leaf[*id] {
474 new_internal_lane_containing_leaf = k;
475 my_leaf_aabb.merge(&workspace.aabbs[*id]);
476 leaf_aabbs[k] = workspace.aabbs[*id];
477 proxy_ids[k] = orig_id;
478 self.proxies[orig_id as usize].node = NodeIndex::new(my_leaf_id, k as u8);
479 } else {
480 my_internal_aabb.merge(&workspace.aabbs[*id]);
481 internal_aabbs[k] = workspace.aabbs[*id];
482 internal_ids[k] = orig_id;
483 self.nodes[orig_id as usize].parent = NodeIndex::new(my_internal_id, k as u8);
484 }
485 }
486
487 if has_internal {
488 if has_leaf {
489 internal_ids[new_internal_lane_containing_leaf] = my_leaf_id;
490 internal_aabbs[new_internal_lane_containing_leaf] = my_leaf_aabb;
491 my_internal_aabb.merge(&my_leaf_aabb);
493 }
494
495 let internal_node = QbvhNode {
496 simd_aabb: SimdAabb::from(internal_aabbs),
497 children: internal_ids,
498 parent,
499 flags: QbvhNodeFlags::default(),
500 };
501 self.nodes[my_internal_id as usize] = internal_node;
504 }
505
506 if has_leaf {
507 let leaf_node = QbvhNode {
508 simd_aabb: SimdAabb::from(leaf_aabbs),
509 children: proxy_ids,
510 parent: if has_internal {
511 NodeIndex::new(my_internal_id, new_internal_lane_containing_leaf as u8)
512 } else {
513 parent
514 },
515 flags: QbvhNodeFlags::LEAF,
516 };
517 self.nodes[my_leaf_id as usize] = leaf_node;
520 }
521
522 if has_internal {
523 return (my_internal_id, my_internal_aabb);
524 } else {
525 return (my_leaf_id, my_leaf_aabb);
526 }
527 }
528
529 let mut center = Point::origin();
534 #[cfg(feature = "dim3")]
535 let mut variance = Vector::zeros();
536
537 let center_denom = 1.0 / (indices.len() as Real);
538
539 for i in &*indices {
540 let coords = workspace.aabbs[*i].center().coords;
541 center += coords * center_denom;
542 }
543
544 #[cfg(feature = "dim3")]
545 {
546 let variance_denom = 1.0 / ((indices.len() - 1) as Real);
547 for i in &*indices {
548 let dir_to_center = workspace.aabbs[*i].center() - center;
549 variance += dir_to_center.component_mul(&dir_to_center) * variance_denom;
550 }
551 }
552
553 #[allow(unused_mut)] let mut subdiv_dims = [0, 1];
557 #[cfg(feature = "dim3")]
558 {
559 let min = variance.imin();
560 subdiv_dims[0] = (min + 1) % 3;
561 subdiv_dims[1] = (min + 2) % 3;
562 }
563
564 let node = QbvhNode {
565 simd_aabb: SimdAabb::new_invalid(),
566 children: [0; 4], parent,
568 flags: QbvhNodeFlags::default(),
569 };
570
571 let nid = if let Some(nid) = self.free_list.pop() {
572 self.nodes[nid as usize] = node;
573 nid
574 } else {
575 let nid = self.nodes.len();
576 self.nodes.push(node);
577 nid as u32
578 };
579
580 let splitter = CenterDataSplitter::default();
582 let splits =
583 splitter.split_dataset_wo_workspace(subdiv_dims, center, indices, &workspace.aabbs);
584 let n = [
585 NodeIndex::new(nid, 0),
586 NodeIndex::new(nid, 1),
587 NodeIndex::new(nid, 2),
588 NodeIndex::new(nid, 3),
589 ];
590
591 let children = [
592 self.do_recurse_rebalance(splits[0], workspace, n[0], margin),
593 self.do_recurse_rebalance(splits[1], workspace, n[1], margin),
594 self.do_recurse_rebalance(splits[2], workspace, n[2], margin),
595 self.do_recurse_rebalance(splits[3], workspace, n[3], margin),
596 ];
597
598 self.nodes[nid as usize].children =
600 [children[0].0, children[1].0, children[2].0, children[3].0];
601 self.nodes[nid as usize].simd_aabb =
602 SimdAabb::from([children[0].1, children[1].1, children[2].1, children[3].1]);
603 self.nodes[nid as usize]
604 .simd_aabb
605 .loosen(SimdReal::splat(margin));
606
607 let my_aabb = self.nodes[nid as usize].simd_aabb.to_merged_aabb();
608 (nid, my_aabb)
609 }
610}