forked from 1b-agent/opencadstudio-upstream
fix(scene): normalize inverted AABBs in spatial index and add warm cache timers
This commit is contained in:
1 parent
2a2d9b55d9
commit
237d3afd2f
2 files changed
+72
-1
No files matched your search
@@ -9948,8 +9948,25 @@ impl Scene {
|
|||||||
|
|
||||||
/// Prepare hover indexes after derived geometry is installed during open.
|
/// Prepare hover indexes after derived geometry is installed during open.
|
||||||
pub(crate) fn warm_interaction_caches(&self) {
|
pub(crate) fn warm_interaction_caches(&self) {
|
||||||
|
let perf = crate::perf::enabled();
|
||||||
|
let t_start = perf.then(iced::time::Instant::now);
|
||||||
|
let t_ei = perf.then(iced::time::Instant::now);
|
||||||
let _ = self.entity_index();
|
let _ = self.entity_index();
|
||||||
|
let ei_ms = crate::perf::elapsed_ms(t_ei);
|
||||||
|
|
||||||
|
let t_ihi = perf.then(iced::time::Instant::now);
|
||||||
let _ = self.interaction_handle_index();
|
let _ = self.interaction_handle_index();
|
||||||
|
let ihi_ms = crate::perf::elapsed_ms(t_ihi);
|
||||||
|
let total_ms = crate::perf::elapsed_ms(t_start);
|
||||||
|
|
||||||
|
if perf {
|
||||||
|
crate::perf_record!(
|
||||||
|
"[perf] warm_interaction_caches total={:.1}ms entity_index={:.1}ms interaction_handle_index={:.1}ms",
|
||||||
|
total_ms,
|
||||||
|
ei_ms,
|
||||||
|
ihi_ms,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn interaction_handle_index(
|
fn interaction_handle_index(
|
||||||
@@ -12221,6 +12238,8 @@ vis_index={:.1} visible_probe={:.1}",
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let perf = crate::perf::enabled();
|
||||||
|
let t_aabbs_start = perf.then(iced::time::Instant::now);
|
||||||
let mut items: Vec<(Handle, [f64; 4])> = Vec::new();
|
let mut items: Vec<(Handle, [f64; 4])> = Vec::new();
|
||||||
let mut unbounded: Vec<Handle> = Vec::new();
|
let mut unbounded: Vec<Handle> = Vec::new();
|
||||||
let mut union: Option<[f64; 4]> = None;
|
let mut union: Option<[f64; 4]> = None;
|
||||||
@@ -12244,6 +12263,7 @@ vis_index={:.1} visible_probe={:.1}",
|
|||||||
None => unbounded.push(e.common().handle),
|
None => unbounded.push(e.common().handle),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let aabbs_ms = crate::perf::elapsed_ms(t_aabbs_start);
|
||||||
let root = match union {
|
let root = match union {
|
||||||
Some(u) => {
|
Some(u) => {
|
||||||
let w = (u[2] - u[0]).max(1.0);
|
let w = (u[2] - u[0]).max(1.0);
|
||||||
@@ -12254,10 +12274,22 @@ vis_index={:.1} visible_probe={:.1}",
|
|||||||
}
|
}
|
||||||
None => [-1.0, -1.0, 1.0, 1.0],
|
None => [-1.0, -1.0, 1.0, 1.0],
|
||||||
};
|
};
|
||||||
|
let t_tree_start = perf.then(iced::time::Instant::now);
|
||||||
let mut tree = pick::quadtree::QuadTree::new(root);
|
let mut tree = pick::quadtree::QuadTree::new(root);
|
||||||
for (h, ab) in items {
|
for (h, ab) in items {
|
||||||
tree.insert(h, ab);
|
tree.insert(h, ab);
|
||||||
}
|
}
|
||||||
|
let tree_ms = crate::perf::elapsed_ms(t_tree_start);
|
||||||
|
|
||||||
|
if perf {
|
||||||
|
crate::perf_record!(
|
||||||
|
"[perf] entity_index-rebuild aabbs={:.1}ms tree={:.1}ms entities={} root={:?}",
|
||||||
|
aabbs_ms,
|
||||||
|
tree_ms,
|
||||||
|
tree.len(),
|
||||||
|
root,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
*self.entity_index_cache.borrow_mut() = Some((
|
*self.entity_index_cache.borrow_mut() = Some((
|
||||||
self.geometry_epoch,
|
self.geometry_epoch,
|
||||||
|
|||||||
@@ -97,7 +97,8 @@ impl QuadTree {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(&mut self, handle: Handle, aabb: Aabb) {
|
pub fn insert(&mut self, handle: Handle, aabb: Aabb) {
|
||||||
if !aabb_contained(self.nodes[0].bounds, aabb) {
|
let aabb = normalize_aabb(aabb);
|
||||||
|
if !aabb.iter().all(|x| x.is_finite()) || !aabb_contained(self.nodes[0].bounds, aabb) {
|
||||||
self.overflow.push(Item { handle, aabb });
|
self.overflow.push(Item { handle, aabb });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -256,6 +257,16 @@ impl QuadTree {
|
|||||||
|
|
||||||
// ── AABB helpers ────────────────────────────────────────────────────
|
// ── AABB helpers ────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
pub fn normalize_aabb(mut aabb: Aabb) -> Aabb {
|
||||||
|
if aabb[0] > aabb[2] {
|
||||||
|
aabb.swap(0, 2);
|
||||||
|
}
|
||||||
|
if aabb[1] > aabb[3] {
|
||||||
|
aabb.swap(1, 3);
|
||||||
|
}
|
||||||
|
aabb
|
||||||
|
}
|
||||||
|
|
||||||
fn aabb_contained(outer: Aabb, inner: Aabb) -> bool {
|
fn aabb_contained(outer: Aabb, inner: Aabb) -> bool {
|
||||||
inner[0] >= outer[0]
|
inner[0] >= outer[0]
|
||||||
&& inner[1] >= outer[1]
|
&& inner[1] >= outer[1]
|
||||||
@@ -391,4 +402,32 @@ mod tests {
|
|||||||
let se_hits = t.query_rect([50.0, 0.0, 100.0, 50.0]);
|
let se_hits = t.query_rect([50.0, 0.0, 100.0, 50.0]);
|
||||||
assert!(se_hits.contains(&h(1)));
|
assert!(se_hits.contains(&h(1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn insert_handles_nan_and_infinite_bounds_safely() {
|
||||||
|
let root = [0.0, 0.0, 100.0, 100.0];
|
||||||
|
let mut tree = QuadTree::new(root);
|
||||||
|
tree.insert(h(1), [10.0, 10.0, 20.0, 20.0]);
|
||||||
|
tree.insert(h(2), [f64::NAN, 10.0, 20.0, 20.0]);
|
||||||
|
tree.insert(h(3), [10.0, f64::INFINITY, 20.0, 20.0]);
|
||||||
|
tree.insert(h(4), [20.0, 20.0, 10.0, 10.0]); // inverted bounds: normalized
|
||||||
|
|
||||||
|
assert_eq!(tree.len(), 4);
|
||||||
|
// Handles 2 & 3 have non-finite coords so they land in overflow
|
||||||
|
// Handle 4 has inverted coords which normalize and fit inside root
|
||||||
|
assert_eq!(tree.overflow.len(), 2);
|
||||||
|
|
||||||
|
let normal_hits = tree.query_rect([5.0, 5.0, 25.0, 25.0]);
|
||||||
|
assert!(normal_hits.contains(&h(1)));
|
||||||
|
assert!(normal_hits.contains(&h(4))); // normalized [10.0, 10.0, 20.0, 20.0]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn normalize_aabb_flips_inverted_extents() {
|
||||||
|
let inverted = [50.0, 60.0, 10.0, 20.0];
|
||||||
|
let normalized = normalize_aabb(inverted);
|
||||||
|
assert_eq!(normalized, [10.0, 20.0, 50.0, 60.0]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Reference in new issue
Block a user