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 <echelon@gmail.com>
This commit is contained in:
Books
2026-10-29 21:31:22 -04:00
committed by GitHub
co-authored by Brandon Thomas
parent dcbcb6ab32
commit d15de75406
4 changed files with 42 additions and 0 deletions
+13
View File
@@ -48,6 +48,19 @@ pub(super) fn add_dim(s: &mut Session, k: EntityKind) -> Result<Handle> {
{
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)
+27
View File
@@ -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);
}
+1
View File
@@ -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 };
+1
View File
@@ -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.