Files
OneCAD-Draft/src/modules/draw/modify/entity_index.rs
T

100 lines
3.1 KiB
Rust

//! Shared broad phase for interactive modify commands.
//!
//! The scene already narrows the cursor pick. Commands still need fast access
//! to the picked analytic entity and, for intersection-heavy operations such
//! as TRIM, to nearby boundary entities. Keeping this compact command-local
//! index avoids cloning/scanning the complete drawing on every mouse move.
use acadrust::{EntityType, Handle};
use rustc_hash::{FxHashMap, FxHashSet};
use crate::scene::convert::tess::entity_world_aabb_f64;
use crate::scene::pick::quadtree::QuadTree;
pub(super) struct ModifyEntityIndex {
by_handle: FxHashMap<Handle, usize>,
tree: Option<QuadTree>,
unbounded: Vec<Handle>,
}
impl ModifyEntityIndex {
pub(super) fn build(entities: &[EntityType]) -> Self {
let mut by_handle = FxHashMap::default();
let mut bounded = Vec::new();
let mut unbounded = Vec::new();
let mut world = [
f64::INFINITY,
f64::INFINITY,
f64::NEG_INFINITY,
f64::NEG_INFINITY,
];
for (index, entity) in entities.iter().enumerate() {
let handle = entity.common().handle;
by_handle.insert(handle, index);
if let Some(aabb) = entity_world_aabb_f64(entity) {
world[0] = world[0].min(aabb[0]);
world[1] = world[1].min(aabb[1]);
world[2] = world[2].max(aabb[2]);
world[3] = world[3].max(aabb[3]);
bounded.push((handle, aabb));
} else {
unbounded.push(handle);
}
}
let tree = if bounded.is_empty() {
None
} else {
let span = (world[2] - world[0]).max(world[3] - world[1]).max(1.0);
let pad = span * 1.0e-9 + 1.0e-6;
let mut tree = QuadTree::new([
world[0] - pad,
world[1] - pad,
world[2] + pad,
world[3] + pad,
]);
for (handle, aabb) in bounded {
tree.insert(handle, aabb);
}
Some(tree)
};
Self {
by_handle,
tree,
unbounded,
}
}
#[inline]
pub(super) fn get<'a>(
&self,
entities: &'a [EntityType],
handle: Handle,
) -> Option<&'a EntityType> {
self.by_handle
.get(&handle)
.and_then(|index| entities.get(*index))
}
pub(super) fn nearby_handles(
&self,
entities: &[EntityType],
handle: Handle,
) -> Option<FxHashSet<Handle>> {
let entity = self.get(entities, handle)?;
let aabb = entity_world_aabb_f64(entity)?;
let span = (aabb[2] - aabb[0]).max(aabb[3] - aabb[1]).max(1.0);
let pad = span * 1.0e-10 + 1.0e-7;
let query = [aabb[0] - pad, aabb[1] - pad, aabb[2] + pad, aabb[3] + pad];
let mut handles: FxHashSet<Handle> = self
.tree
.as_ref()
.map(|tree| tree.query_rect(query).into_iter().collect())
.unwrap_or_default();
handles.extend(self.unbounded.iter().copied());
Some(handles)
}
}