//! Model-only browser queries, reused while navigating. Resolving a placement walks the //! definition's bodies; doing that for every offscreen row and folder made large imports //! quadratic on every frame. Keep the document and evaluated state alive with the index so //! neither a new document nor a later allocation can accidentally reuse its answers. use std::collections::{BTreeMap, HashMap}; use std::sync::Arc; use solidcraft_engine::Session; use solidcraft_engine::doc::{Document, FeatureKind, Mat, ModelState}; use solidcraft_engine::occurrences::OccurrencePlacement; pub(super) struct Model { doc: Arc, state: Arc, pending_moves: BTreeMap, pub bodies: HashMap>, pub sketches: HashMap>, pub planes: HashMap>, pub children: HashMap>, placements: HashMap, Option>>, } impl Model { pub fn new(session: &Session) -> Self { let state = session.model.state(); let mut bodies: HashMap> = HashMap::new(); for (i, body) in state.bodies.iter().enumerate() { bodies.entry(session.doc.model_body_component(body)).or_default().push(i); } let mut sketches: HashMap> = HashMap::new(); let mut planes: HashMap> = HashMap::new(); for (i, feature) in session.doc.features.iter().enumerate() { let index = match feature.kind { FeatureKind::Sketch { .. } => &mut sketches, FeatureKind::ConstructionPlane { .. } => &mut planes, _ => continue, }; index.entry(feature.component).or_default().push(i); } let mut children: HashMap> = HashMap::new(); for occurrence in &session.doc.occurrences { children.entry(occurrence.parent).or_default().push(occurrence.id); } Self { doc: session.doc.clone(), state, pending_moves: session.pending_moves.clone(), bodies, sketches, planes, children, placements: HashMap::new(), } } pub fn matches(&self, session: &Session) -> bool { Arc::ptr_eq(&self.doc, &session.doc) && Arc::ptr_eq(&self.state, &session.model.state()) && self.pending_moves == session.pending_moves } pub fn placement(&mut self, session: &Session, path: &[u64]) -> Option> { self.placements.entry(path.to_vec()).or_insert_with(|| session.occurrence_placement(path).ok().map(Arc::new)).clone() } }