From 99b7ab11764cb8c74ceb343be331f6106b09b7b9 Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Fri, 5 Jun 2026 16:16:44 +0300 Subject: [PATCH] perf(scene): incremental tessellation for MOVE / COPY / ERASE Extends the Phase 2.2 per-entity memo to the common modify commands, which still did a full bump_geometry (whole-model re-tess + block rebuild): - transform_entities (MOVE / ROTATE / SCALE / MIRROR) marks each transformed handle dirty, then bump_geometry_no_blocks; - erase_entities drops the deleted handles from the memo and bump_geometry_no_blocks; - copy_entities' new handles are natural memo misses, so just bump_geometry_no_blocks. All three are top-level operations (including on inserts) that can't change a block definition, so keeping the block cache is sound. Each now re-tessellates only the touched entities and reuses the memoized wires for the rest, matching the grip / line-commit path. Co-Authored-By: Claude Opus 4.8 --- ROADMAP.md | 10 +++++++--- src/scene/mod.rs | 17 ++++++++++++++--- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 4367eb10e..622e694bc 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -127,9 +127,13 @@ keyed by a guard hash of the tessellation parameters (tol / view / anno / offset / bg / entered viewport); a mismatch (zoom, layout) clears it. `bump_geometry` clears it (structural change); incremental edits drop just the changed handle via `mark_entity_dirty` and bump with `bump_geometry_no_blocks`. -So a single-entity edit (line commit, grip commit/cancel) re-tessellates only -that entity and reuses every other — the per-entity geometry math is skipped -for the unchanged set. The hit-test (`view_aabb == None`), paper and +So a single-entity edit (line commit, grip commit/cancel, MOVE / ROTATE / +SCALE / MIRROR, COPY, ERASE) re-tessellates only the touched entities and +reuses every other — the per-entity geometry math is skipped for the +unchanged set. `transform_entities` marks the moved handles dirty, +`erase_entities` drops the deleted ones, and `copy_entities`' new handles are +natural memo misses; all use `bump_geometry_no_blocks` so the block cache is +kept too. The hit-test (`view_aabb == None`), paper and per-viewport paths bypass the memo so their cull params don't thrash it. Remaining: the assembly still concatenates into one `Vec` and rebuilds the diff --git a/src/scene/mod.rs b/src/scene/mod.rs index 27da924e8..50c20c2d2 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -4711,6 +4711,7 @@ impl Scene { self.hatches.remove(&h); self.meshes.remove(&h); self.model_solids.remove(&h); + self.mark_entity_dirty(h); } // Remove erased handles from all groups; delete groups that become empty. let group_dict_handle = self.document.header.acad_group_dict_handle; @@ -4738,7 +4739,9 @@ impl Scene { } self.document.objects.remove(gh); } - self.bump_geometry(); + // Deleting top-level entities/inserts leaves block definitions intact; + // the erased handles were already dropped from the memo above. + self.bump_geometry_no_blocks(); } // ── Group helpers ────────────────────────────────────────────────────── @@ -4908,7 +4911,13 @@ impl Scene { } } } - self.bump_geometry(); + // Only the transformed entities changed (a top-level move/rotate/scale/ + // mirror never edits a block definition) — re-tessellate just those and + // keep the block cache + every other entity's memoized wires. + for &h in handles { + self.mark_entity_dirty(h); + } + self.bump_geometry_no_blocks(); } pub fn copy_entities(&mut self, handles: &[Handle], t: &EntityTransform) -> Vec { @@ -4939,7 +4948,9 @@ impl Scene { } new_handles.push(h); } - self.bump_geometry(); + // The copies are new handles (natural memo misses, tessellated fresh) + // and reference only already-cached blocks — no block defn changes. + self.bump_geometry_no_blocks(); new_handles }