fix(dimension): bake↔live consistency, edits, baseline/continue, grips

Batch 1-3 of the dimension audit (19 issues). The dominant class was the
baked *D block diverging from the live render: a reloaded dimension renders
from that block, so on save+reopen it silently changed.

Bake now matches the live render:
- text value/format via the shared style-resolved path (DIMDEC/DIMLFAC/
  DIMPOST/units/<>), correct height + rotation ladder, suppression
- angular dims bake their swept arc (no longer collapse to a V)
- diameter draws edge-to-edge through the centre (live + bake), centre mark
- radius/linear/aligned bake arrowheads
- group-10 (base.definition_point) synced from the edited geometry so an
  edited dim no longer shifts on reload

Editing / properties:
- aligned no longer corrupts ext_line_rotation when a coordinate is edited
- DIMTEDIT pins the moved text (text_user_positioned)
- angle properties shown/edited in degrees
- non-linear text respects the user-positioned gate

Commands / geometry:
- DIMBASELINE stacks outward (not toward the points) and its preview no
  longer tilts over non-level points
- DIMCONTINUE/DIMBASELINE inherit the base dim's text rotation (UCS chains)
- angular extension lines reach the arc (no gap)
- text grip sits on the text for auto-placed dims instead of the origin

Refs #181. (acadrust DXF round-trip + QDIM/DIMBREAK/DIMJOGLINE/DIMSPACE/
DIMEDIT to follow.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hakan SevenandClaude Opus 4.8 committed 2026-06-27 17:47:50 +03:00
1 parent b691854e7a
commit 3c5aa4453a
7 files changed
+591 -131

No files matched your search

+31 -6
View File
@@ -34,6 +34,9 @@ pub struct DimBaselineCommand {
base_p1: Vec3,
/// Direction along the measurement direction (0.0 = horizontal, PI/2 = vertical).
rotation: f64,
/// Text reading rotation inherited from the base dim (keeps a UCS-aligned
/// chain's text consistent with the originating DIMLINEAR). 0 = natural.
text_rotation: f64,
/// Unit vector perpendicular to the dimension axis, pointing toward the dim line side.
perp: Vec3,
/// Perpendicular distance of the NEXT dimension line from the extension-line axis.
@@ -50,6 +53,7 @@ impl DimBaselineCommand {
Self {
base_p1: Vec3::ZERO,
rotation: 0.0,
text_rotation: 0.0,
perp: Vec3::Y,
next_offset: DEFAULT_DIMDLI,
dimdli: DEFAULT_DIMDLI,
@@ -69,6 +73,7 @@ impl DimBaselineCommand {
_p2: Vec3,
definition_point: Vec3,
rotation: f64,
text_rotation: f64,
dimdli: f32,
) -> Self {
// Measurement axis = the base dim's rotation angle (any angle, incl. a
@@ -79,13 +84,19 @@ impl DimBaselineCommand {
let dimdli = if dimdli.abs() < 1e-6 {
DEFAULT_DIMDLI
} else {
dimdli
dimdli.abs()
};
// Next baseline dim goes one DIMDLI further from the baseline.
// Stack each baseline outward — in the SIGN direction of the base dim's
// own offset. When the base dim sits on the -perp side (below / left of
// the points) a positive increment would march the stack back toward and
// across the points; the signed increment keeps it moving away. (#181)
let dir = if base_offset >= 0.0 { 1.0 } else { -1.0 };
let dimdli = dimdli * dir;
let next_offset = base_offset + dimdli;
Self {
base_p1: p1,
rotation,
text_rotation,
perp,
next_offset,
dimdli,
@@ -94,6 +105,19 @@ impl DimBaselineCommand {
}
}
impl DimBaselineCommand {
/// The two dimension-line endpoints for the new baseline at `p2`: the fixed
/// base origin and `p2` each projected INDEPENDENTLY onto the dim line (at
/// the current stacking offset). Projecting both keeps the line straight
/// even when the two origins aren't level — a shared offset tilts it. (#181)
fn dim_line_pts(&self, p2: Vec3) -> (Vec3, Vec3) {
let target = self.base_p1.dot(self.perp) + self.next_offset;
let d1 = self.base_p1 + self.perp * (target - self.base_p1.dot(self.perp));
let d2 = p2 + self.perp * (target - p2.dot(self.perp));
(d1, d2)
}
}
impl CadCommand for DimBaselineCommand {
fn name(&self) -> &'static str {
"DIMBASELINE"
@@ -117,9 +141,11 @@ impl CadCommand for DimBaselineCommand {
// Build a new linear dimension.
let mut dim = DimensionLinear::new(v3(p1), v3(p2));
dim.rotation = self.rotation;
if self.text_rotation.abs() > 1e-9 {
dim.base.text_rotation = self.text_rotation;
}
let dim_line_pt = p1 + self.perp * self.next_offset;
let dim_line_pt2 = p2 + self.perp * self.next_offset;
let (dim_line_pt, dim_line_pt2) = self.dim_line_pts(p2);
dim.definition_point = v3(dim_line_pt);
dim.base.definition_point = v3(dim_line_pt);
dim.base.text_middle_point = v3((dim_line_pt + dim_line_pt2) * 0.5);
@@ -141,8 +167,7 @@ impl CadCommand for DimBaselineCommand {
return None;
}
let p1 = self.base_p1;
let dim_line_pt = p1 + self.perp * self.next_offset;
let dim_line_pt2 = pt + self.perp * self.next_offset;
let (dim_line_pt, dim_line_pt2) = self.dim_line_pts(pt);
Some(WireModel {
name: "dimbase_preview".into(),
points: vec![