From 845194e05b7733348daa27b0fa90ff1bc13670b6 Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Sun, 5 Jul 2026 02:10:56 +0300 Subject: [PATCH] refactor(render): reuse block_has_hatch in synced_hatch_models MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hatch-free-block skip added in the previous commit duplicated the existing `block_has_hatch` helper (already used by `insert_hatches_for_click`). Drop the parallel `block_contains_hatch` and call the shared, memoised helper instead — same result, one implementation. Co-Authored-By: Claude Opus 4.8 --- src/scene/entity.rs | 70 +++++---------------------------------------- 1 file changed, 7 insertions(+), 63 deletions(-) diff --git a/src/scene/entity.rs b/src/scene/entity.rs index 74645d884..ab1fc8ae4 100644 --- a/src/scene/entity.rs +++ b/src/scene/entity.rs @@ -409,55 +409,6 @@ impl Scene { self.bump_geometry(); } - /// Whether a block definition holds at least one HATCH, directly or through - /// a nested INSERT. Memoized by block-record handle — `None` marks a block - /// currently being visited so a cyclic block reference resolves to `false` - /// instead of recursing forever. Lets `synced_hatch_models` skip the costly - /// explode of hatch-free blocks (a read-only type scan, no entity clones). - fn block_contains_hatch( - &self, - block_handle: Handle, - memo: &mut HashMap>, - ) -> bool { - if let Some(v) = memo.get(&block_handle) { - return v.unwrap_or(false); - } - memo.insert(block_handle, None); - let mut has = false; - if let Some(br) = self - .document - .block_records - .iter() - .find(|b| b.handle == block_handle) - { - for &h in &br.entity_handles { - match self.document.get_entity(h) { - Some(EntityType::Hatch(_)) => { - has = true; - break; - } - Some(EntityType::Insert(nins)) => { - let nbh = self - .document - .block_records - .iter() - .find(|b| b.name.eq_ignore_ascii_case(&nins.block_name)) - .map(|b| b.handle); - if let Some(nbh) = nbh { - if self.block_contains_hatch(nbh, memo) { - has = true; - break; - } - } - } - _ => {} - } - } - } - memo.insert(block_handle, Some(has)); - has - } - pub(super) fn synced_hatch_models(&self) -> Vec { let layout_block = self.current_layout_block_handle(); @@ -549,10 +500,11 @@ impl Scene { // to scan the result for hatch fills. On xref-heavy drawings whose // blocks hold thousands of solids and NO hatches, that cloned ~all block // content on every open for nothing (~20 s on a 5-xref BIM aggregate). - // Pre-scan each block's entity types (no clone) and skip the explode for - // blocks that contain no hatch, transitively. Blocks that DO contain a - // hatch still explode exactly as before, so the output is unchanged. - let mut hatch_block_memo: HashMap> = HashMap::default(); + // Skip the explode for blocks with no hatch (transitively) via the same + // memoised `block_has_hatch` scan the pick path uses. Blocks that DO + // contain a hatch still explode exactly as before, so output is unchanged. + let mut hatch_block_memo: std::collections::HashMap = + std::collections::HashMap::new(); for entity in self.document.entities() { let EntityType::Insert(ins) = entity else { continue; @@ -567,16 +519,8 @@ impl Scene { ) { continue; } - if let Some(bh) = self - .document - .block_records - .iter() - .find(|b| b.name.eq_ignore_ascii_case(&ins.block_name)) - .map(|b| b.handle) - { - if !self.block_contains_hatch(bh, &mut hatch_block_memo) { - continue; - } + if !self.block_has_hatch(&ins.block_name, &mut hatch_block_memo) { + continue; } let selected = self.selected.contains(&ins.common.handle); // XCLIP: clip this insert's exploded hatch fills to the boundary,