Sketch links: body-based references (edges, faces, silhouettes, sections, iso curves) are cached by model identity, so editing a sketch with projections no longer re-projects (30x faster per edit on a 20k-triangle model)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
This commit is contained in:
bherbruckandClaude Opus 5.5 committed 2026-10-08 04:11:07 +00:00
1 parent 7ca6e9278b
commit df64a373b0
1 file changed
+56
+56
View File
@@ -31,8 +31,64 @@ pub struct Resolved {
pub moved: bool,
}
/// Resolutions of body-based references, keyed by the reference, the sketch plane and the
/// identity of every body's display mesh: re-resolving an unchanged model (every sketch edit
/// does) is free.
static CACHE: std::sync::Mutex<Vec<(String, Resolved)>> = std::sync::Mutex::new(Vec::new());
const CACHE_SIZE: usize = 64;
fn cache_key(st: &ModelState, plane: &Plane, kind: LinkKind, src: &LinkSource) -> Option<String> {
let body_based = matches!(
src,
LinkSource::Edge { .. }
| LinkSource::Face { .. }
| LinkSource::Body { .. }
| LinkSource::Vertex { .. }
| LinkSource::Intersection { .. }
| LinkSource::Iso { .. }
| LinkSource::Spun { .. }
);
if !body_based {
return None;
}
let bodies: Vec<String> = st
.bodies
.iter()
.map(|b| {
let m = b.mesh();
format!("{}@{:p}/{}/{:?}", b.name, std::sync::Arc::as_ptr(&m), m.triangles.len(), m.bounds())
})
.collect();
Some(format!("{kind:?}|{src:?}|{plane:?}|{}", bodies.join(";")))
}
/// Resolve a link source against the model state before the sketch.
pub fn resolve(doc: &Document, vals: &BTreeMap<String, Value>, st: &ModelState, plane: &Plane, kind: LinkKind, src: &LinkSource) -> Result<Resolved> {
let key = cache_key(st, plane, kind, src);
if let Some(k) = &key
&& let Ok(c) = CACHE.lock()
&& let Some((_, r)) = c.iter().find(|(x, _)| x == k)
{
return Ok(r.clone());
}
let r = resolve_uncached(doc, vals, st, plane, kind, src)?;
if let Some(k) = key
&& let Ok(mut c) = CACHE.lock()
{
c.insert(0, (k, r.clone()));
c.truncate(CACHE_SIZE);
}
Ok(r)
}
fn resolve_uncached(
doc: &Document,
vals: &BTreeMap<String, Value>,
st: &ModelState,
plane: &Plane,
kind: LinkKind,
src: &LinkSource,
) -> Result<Resolved> {
let lost = |what: &str| DocError::Invalid(format!("{what} no longer exists"));
let mut moved = false;
let mut source = src.clone();