From d15de754069bac149f2fe199310299752ebbcd0f Mon Sep 17 00:00:00 2001 From: Books Date: Fri, 30 Oct 2026 12:31:22 +1100 Subject: [PATCH] Dimensions: report the measurement as soon as one is created (#2421) (#2438) * Dimensions: fill in the measurement when one is created (#2421) A dimension made in the session kept measurement 0.0 until it was saved and reopened. add_dim now sets it with the geometry call the DXF/DWG writer uses for group 42. Block names are still assigned at save time. Test: a_new_dimension_reports_its_measurement. * Parity checklist: regenerated after merging main * Dimensions: a jogged radius dimension stores its radius as the measurement (#2421) draw_jogged_radius set the text but not DimGeometry.measurement, so DIMJOGGED dimensions kept measurement 0 (and the DXF/DWG group 42 was 0). It now sets the radius. Test: jogged_radius asserts the stored measurement. * Parity checklist: regenerated after merging main * Dimensions: fill in a new dimension's text position when it is created (#2421) A dimension made in the session kept text_mid (0,0) until it was saved and reopened. add_dim now sets it from the same dimension_geometry result as the measurement, the position the writer puts in group 11, unless the user placed the text. Test: a_new_dimension_reports_its_text_position. --------- Co-authored-by: Brandon Thomas --- crates/engine/src/cmd/annotate/common.rs | 13 ++++++++++++ crates/engine/tests/it/dim_commands.rs | 27 ++++++++++++++++++++++++ crates/render/src/dim/variants.rs | 1 + docs/parity-checklist.md | 1 + 4 files changed, 42 insertions(+) diff --git a/crates/engine/src/cmd/annotate/common.rs b/crates/engine/src/cmd/annotate/common.rs index 2267f16bf..419723288 100644 --- a/crates/engine/src/cmd/annotate/common.rs +++ b/crates/engine/src/cmd/annotate/common.rs @@ -48,6 +48,19 @@ pub(super) fn add_dim(s: &mut Session, k: EntityKind) -> Result { { dm.assoc = crate::assoc::reassociate(s.doc()?, &s.space(), dm); } + // The measurement is what the DXF/DWG writer computes from the geometry (group 42); filling it + // in now means queries show it before the drawing is saved and reopened (#2421). + if let EntityKind::Dimension(dm) = &mut k + && let Ok(d) = s.doc() + { + let style = d.dim_style(&dm.style).cloned().unwrap_or_default(); + let g = cadcraft_render::dimension_geometry(dm, &style, d.header.f64("DIMSCALE", 1.0)); + dm.measurement = g.measurement; + // The text position the writer puts in group 11 when the user has not placed the text. + if !dm.user_text_pos { + dm.text_mid = g.text_pos.to3(0.0); + } + } let h = s.add_entity(k)?; s.last_dim = Some(h); Ok(h) diff --git a/crates/engine/tests/it/dim_commands.rs b/crates/engine/tests/it/dim_commands.rs index 8e67b1039..3c5b5c90a 100644 --- a/crates/engine/tests/it/dim_commands.rs +++ b/crates/engine/tests/it/dim_commands.rs @@ -99,6 +99,7 @@ fn jogged_radius() { let (dm, g) = dim_of(&s, &h); let j = dm.marks.jogged.clone().unwrap(); assert_eq!(g.value, "R50.0000", "the true radius"); + assert!((dm.measurement - 50.0).abs() < 1e-9, "the stored measurement is the radius, got {} (#2421)", dm.measurement); assert!(j.center.xy().dist(Vec2::new(20.0, -10.0)) < 1e-9); // The line runs from the arrowhead on the circle to the override, with a 45° jog (DIMJOGANG). let tip = Vec2::new(1.0, 1.0).normalized() * 50.0; @@ -257,3 +258,29 @@ fn marks_follow_move_and_rotate_and_hostile_values_do_not_panic() { .unwrap(); let _ = dim_of(&s, &h); } + +/// A dimension made in the session reports its measurement at once, not 0.0 until it is saved +/// and reopened (#2421). +#[test] +fn a_new_dimension_reports_its_measurement() { + let mut s = Session::new(); + let measurement = |s: &Session, h: &str| dim_of(s, h).0.measurement; + let horizontal = handle(&s.execute("dimlinear", &json!({ "p1": [0, 0], "p2": [100, 0], "at": [50, 20] })).unwrap()); + assert!((measurement(&s, &horizontal) - 100.0).abs() < 1e-9, "{}", measurement(&s, &horizontal)); + let vertical = handle(&s.execute("dimlinear", &json!({ "p1": [0, 0], "p2": [0, 37.5], "at": [-10, 20] })).unwrap()); + assert!((measurement(&s, &vertical) - 37.5).abs() < 1e-9, "{}", measurement(&s, &vertical)); +} + +/// A new dimension's text position is known at once, as it is after save and reopen (#2421). +#[test] +fn a_new_dimension_reports_its_text_position() { + let mut s = Session::new(); + let horizontal = handle(&s.execute("dimlinear", &json!({ "p1": [0, 0], "p2": [100, 0], "at": [50, 20] })).unwrap()); + let vertical = handle(&s.execute("dimlinear", &json!({ "p1": [0, 0], "p2": [0, 37.5], "at": [-20, 18] })).unwrap()); + for h in [&horizontal, &vertical] { + let (dm, g) = dim_of(&s, h); + assert!(dm.text_mid.xy().dist(g.text_pos) < 1e-9, "stored {:?}, drawn at {:?}", dm.text_mid, g.text_pos); + assert!(dm.text_mid.xy().dist(Vec2::ZERO) > 1.0, "still at the origin: {:?}", dm.text_mid); + } + assert!((dim_of(&s, &horizontal).0.text_mid.x - 50.0).abs() < 1e-9); +} diff --git a/crates/render/src/dim/variants.rs b/crates/render/src/dim/variants.rs index 240b5e88d..948483a54 100644 --- a/crates/render/src/dim/variants.rs +++ b/crates/render/src/dim/variants.rs @@ -27,6 +27,7 @@ pub(super) fn draw_jogged_radius(config: &DimConfig<'_>, g: &mut DimGeometry, te if !r.is_finite() { break 'jogged; } + g.measurement = r; let (tw, _) = measure(&g.mtext); let u = (tip - center).normalized(); let u = if u == Vec2::ZERO || !u.is_finite() { Vec2::X } else { u }; diff --git a/docs/parity-checklist.md b/docs/parity-checklist.md index ee0358f9e..d0bd6f967 100644 --- a/docs/parity-checklist.md +++ b/docs/parity-checklist.md @@ -1,5 +1,6 @@ # Parity checklist +> **Generated:** 2026-10-29 by `cargo xtask parity`. Do not edit by hand. > **Generated:** 2026-10-28 by `cargo xtask parity`. Do not edit by hand. Menu-breadth parity: a reference menu item counts as covered when a CADCraft command is registered under the same menu label. It measures breadth, not depth; see [target-app-parity.md](target-app-parity.md) for the weighted assessment.