From 5383c64d5dfce211f4bd806a6ab2884b38159a72 Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Tue, 21 Jul 2026 22:24:20 +0300 Subject: [PATCH] fix(edit): STRETCH moves dimension definition points (#372) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The STRETCH apply loop had no Dimension arm, so dimensions fell into the generic skip — points never moved, and a reopened file's stale baked *D block made the result snap back visually. Move every definition point inside the window (grip-equivalent set plus pinned text, sparing the zero auto-placement sentinel), refresh the stored measurement, and drop the stale *D block so the stretch survives render and save. Co-Authored-By: Claude Fable 5 --- src/app/command_driver.rs | 81 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/src/app/command_driver.rs b/src/app/command_driver.rs index 605f7081d..b8f6c501c 100644 --- a/src/app/command_driver.rs +++ b/src/app/command_driver.rs @@ -1423,6 +1423,9 @@ impl OpenCADStudio { let dy = delta.y as f64; // drawing plane is world XY let dz = delta.z as f64; + // Dimensions whose points moved — their baked *D block is + // stale afterwards and must be dropped (see #398 / #372). + let mut stretched_dims: Vec = Vec::new(); for handle in &handles { let Some(entity) = self.tabs[i].scene.document.get_entity_mut(*handle) else { continue; @@ -1520,6 +1523,75 @@ impl OpenCADStudio { stretched = true; } } + acadrust::EntityType::Dimension(dim) => { + use acadrust::entities::Dimension; + // Move every definition point that falls inside the + // window — the same points the grips expose — then + // refresh the stored measurement so the value tracks + // the stretched geometry. + let mut mv = |p: &mut acadrust::types::Vector3| { + if in_win(p.x, p.y) { + p.x += dx; + p.y += dy; + p.z += dz; + true + } else { + false + } + }; + match dim { + Dimension::Linear(d) => { + stretched |= mv(&mut d.first_point); + stretched |= mv(&mut d.second_point); + stretched |= mv(&mut d.definition_point); + } + Dimension::Aligned(d) => { + stretched |= mv(&mut d.first_point); + stretched |= mv(&mut d.second_point); + stretched |= mv(&mut d.definition_point); + } + Dimension::Radius(d) => { + stretched |= mv(&mut d.angle_vertex); + stretched |= mv(&mut d.definition_point); + } + Dimension::Diameter(d) => { + stretched |= mv(&mut d.angle_vertex); + stretched |= mv(&mut d.definition_point); + } + Dimension::Angular2Ln(d) => { + stretched |= mv(&mut d.angle_vertex); + stretched |= mv(&mut d.first_point); + stretched |= mv(&mut d.second_point); + stretched |= mv(&mut d.definition_point); + } + Dimension::Angular3Pt(d) => { + stretched |= mv(&mut d.angle_vertex); + stretched |= mv(&mut d.first_point); + stretched |= mv(&mut d.second_point); + stretched |= mv(&mut d.definition_point); + } + Dimension::Ordinate(d) => { + stretched |= mv(&mut d.definition_point); + stretched |= mv(&mut d.feature_location); + stretched |= mv(&mut d.leader_endpoint); + } + } + // Pinned text follows too; the zero sentinel means + // "auto placement" and must not be captured by a + // window that happens to cover the origin. + let t = dim.base().text_middle_point; + if t.x * t.x + t.y * t.y + t.z * t.z > 1e-16 { + let mut t = t; + if mv(&mut t) { + dim.base_mut().text_middle_point = t; + stretched = true; + } + } + if stretched { + dim.base_mut().actual_measurement = dim.measurement(); + stretched_dims.push(*handle); + } + } _ => { // Generic: move entire entity (treat as block-level) stretched = false; // skip generic types @@ -1530,6 +1602,15 @@ impl OpenCADStudio { count += 1; } } + // A stretched dimension renders through its baked *D block when + // one exists (file roundtrip) — drop it so tessellation falls + // back to the live points and the next save re-bakes. (#372) + for h in stretched_dims { + crate::modules::draw::modify::explode::invalidate_dim_block( + &mut self.tabs[i].scene.document, + h, + ); + } // Geometry was edited in place via get_entity_mut, which the // scene's tessellation cache doesn't observe. Re-tessellate the