From 0d9e62bc9aa55356f65310417fd80602f2b4db7e Mon Sep 17 00:00:00 2001 From: NetterSilver <133535268+Silvertree2010@users.noreply.github.com> Date: Fri, 30 Oct 2026 02:31:13 +0100 Subject: [PATCH] Stop DIMTMOVE 2 text taking the DIMTAD 1 clearance twice (#2302) Fixes #2222 Co-authored-by: Claude Opus 5.5 Co-authored-by: Brandon Thomas --- crates/render/src/dim/linear.rs | 16 ++++++++++------ crates/render/src/dim/tests.rs | 23 +++++++++++++++++++++++ 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/crates/render/src/dim/linear.rs b/crates/render/src/dim/linear.rs index 40b684832..8127aef8f 100644 --- a/crates/render/src/dim/linear.rs +++ b/crates/render/src/dim/linear.rs @@ -150,11 +150,13 @@ fn position_linear_text(config: &DimConfig<'_>, state: &mut LinearDimState) { }; state.side_out = if (config.dimension.defpt.xy() - state.p1).dot(state.n) >= 0.0 { state.n } else { -state.n }; state.text_axis = Vec2::from_angle(state.angle); - let off_along = |axis: Vec2| { - let glyph_extent = state.text_width * state.text_axis.dot(axis).abs() / 2.0 - + state.text_height * state.text_axis.perp().dot(axis).abs() * if st.text_above == 1 { 0.6 } else { 0.5 }; - config.gap + glyph_extent + let clearance = |axis: Vec2, across: f64| { + config.gap + + state.text_width * state.text_axis.dot(axis).abs() / 2.0 + + state.text_height * state.text_axis.perp().dot(axis).abs() * across }; + // Empirical #2004 match: 0.595× height with SHX and 0.601× with TrueType. + let off_along = |axis: Vec2| clearance(axis, if st.text_above == 1 { 0.6 } else { 0.5 }); let above = if state.angle.abs() < 1e-12 && state.n.y.abs() > 1e-9 { if state.n.y > 0.0 { state.n } else { -state.n } } else if state.angle.abs() < 1e-12 { @@ -181,11 +183,13 @@ fn position_linear_text(config: &DimConfig<'_>, state: &mut LinearDimState) { + outward * (config.gap + state.text_height / 2.0); } else if state.moved { let mid = state.f1.mid(state.f2); - let lift = off_along(state.side_out) + 2.0 * config.arrow_size.max(config.tick_size); + // Half the text height either way, whatever DIMTAD says (#2222). + let clear = clearance(state.side_out, 0.5); + let lift = clear + 2.0 * config.arrow_size.max(config.tick_size); state.text_mid = if st.text_move == 1 { mid + state.side_out * lift + state.u * state.half_extent } else { - mid + state.side_out * (lift + off_along(state.side_out)) + mid + state.side_out * (lift + clear) }; } else if !config.dimension.user_text_pos { state.text_mid = state.along_center + state.offset; diff --git a/crates/render/src/dim/tests.rs b/crates/render/src/dim/tests.rs index fd439097c..fe3b3c74e 100644 --- a/crates/render/src/dim/tests.rs +++ b/crates/render/src/dim/tests.rs @@ -233,6 +233,29 @@ fn text_that_does_not_fit_follows_dimtmove_2() { assert!(g.lines_of(LineRole::Dim).flatten().all(|p| p.x <= 0.5 + 1e-9 && p.y >= 5.0 - 1e-9), "no leader, no line out to the text"); } +#[test] +fn dimtmove_2_text_clearance_matches_autocad() { + // #2222: the 0.10 dimension of #1998 in the #2004 1:50 style. AutoCAD 2026 recomputes the + // moved text at about 0.358 from the dimension line (0.658214, 0.05). + let st = st_with(|s| { + s.scale = 50.0; + s.text_height = 0.0025; + s.text_gap = 0.0008; + s.arrow_size = 0.0015; + s.text_above = 1; + s.text_inside_horizontal = false; + s.text_outside_horizontal = false; + s.decimals = 2; + s.text_move = 2; + }); + let d = lin((0.0, 0.0), (0.0, 0.10), (0.30, 0.0), std::f64::consts::FRAC_PI_2); + let g = dimension_geometry(&d, &st, 50.0); + assert!(g.text_pos.dist(Vec2::new(0.658214, 0.05)) < 0.005, "vertical: {:?}", g.text_pos); + let d = lin((0.0, 0.0), (0.10, 0.0), (0.0, -0.30), 0.0); + let g = dimension_geometry(&d, &st, 50.0); + assert!(g.text_pos.dist(Vec2::new(0.05, -0.658214)) < 0.005, "horizontal: {:?}", g.text_pos); +} + #[test] fn text_that_does_not_fit_follows_dimtmove_1() { // Moved off the line with a leader from the middle of the dimension line.