From 23d38fab97020468514dc527f55f0ef22fce7d82 Mon Sep 17 00:00:00 2001 From: bherbruck Date: Thu, 8 Oct 2026 14:22:20 +0000 Subject: [PATCH] STEP export: read the file back only when faces were merged The read-back check (fallback to unmerged pieces) imported every export. Now it runs only when some body actually had faces merged. Oracle 41 (42 faces, nothing merged): export no longer re-imports, which saved 7 s. Pipe flange (merges): 1.1 s for the read-back. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL --- crates/kernel/src/step_out.rs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/crates/kernel/src/step_out.rs b/crates/kernel/src/step_out.rs index beab8d60..73915115 100644 --- a/crates/kernel/src/step_out.rs +++ b/crates/kernel/src/step_out.rs @@ -1199,10 +1199,22 @@ fn brep_exchange(b: &Body, merge: bool) -> Result<(p21::Exchange, HashMap usize { + ex.entities + .values() + .filter(|e| matches!(e.name(), "CLOSED_SHELL" | "OPEN_SHELL")) + .filter_map(|e| e.params().get(1).and_then(Param::as_list)) + .map(<[Param]>::len) + .sum() +} + /// A face's own colour (0..1) and opacity. type FaceLook = ([f32; 3], f32); @@ -1221,11 +1233,13 @@ fn rigid_frame(m: &[[f64; 4]; 4]) -> Result<([f64; 3], [f64; 3], [f64; 3])> { /// STEP text (AP242) for products with bodies and assembly placements; `root` is the top product. pub fn step_export_products(products: &[ExportProduct], root: usize, header: &StepHeader) -> Result { + MERGES.with(|m| m.set(0)); let text = products_text(products, root, header, true)?; // Faces merged per surface must read back as cleanly as the pieces they came from (a merge - // can leave a loop the reader cannot lay out); otherwise the pieces are written. + // can leave a loop the reader cannot lay out); otherwise the pieces are written. Without a + // merge there is nothing to check. let clean = |t: &str| crate::step_in::step_import(t).is_ok_and(|i| i.warnings.is_empty()); - if !clean(&text) { + if MERGES.with(|m| m.get()) > 0 && !clean(&text) { let plain = products_text(products, root, header, false)?; if clean(&plain) { return Ok(plain); @@ -1234,6 +1248,11 @@ pub fn step_export_products(products: &[ExportProduct], root: usize, header: &St Ok(text) } +thread_local! { + /// Faces merged while writing the current export. + static MERGES: std::cell::Cell = const { std::cell::Cell::new(0) }; +} + fn products_text(products: &[ExportProduct], root: usize, header: &StepHeader, merge: bool) -> Result { if products.is_empty() || root >= products.len() { return Err(KernelError::Invalid("nothing to export".into()));