diff --git a/src/modules/annotate/dim_continue.rs b/src/modules/annotate/dim_continue.rs index 7ae3ec92f..bf4f22046 100644 --- a/src/modules/annotate/dim_continue.rs +++ b/src/modules/annotate/dim_continue.rs @@ -31,9 +31,12 @@ pub struct DimContinueCommand { chain_p1: Vec3, /// Direction along the dimension axis (0.0 = horizontal, PI/2 = vertical). rotation: f64, - /// Perpendicular distance from the extension-line axis to the dimension line. - /// Preserved from the base dimension. - dim_offset: f32, + /// Absolute perpendicular coordinate (dot with `perp`) of the base + /// dimension line. Each continued dim line is projected onto this exact + /// coordinate so the whole chain stays collinear — even when the extension + /// origins sit at different perpendicular positions (extension lines of + /// different lengths). (#151) + dim_line_perp: f32, /// Direction of "up" perpendicular to the dim axis (points toward the dim line). perp: Vec3, /// True once we have a base dimension loaded. @@ -46,7 +49,7 @@ impl DimContinueCommand { Self { chain_p1: Vec3::ZERO, rotation: 0.0, - dim_offset: 0.0, + dim_line_perp: 0.0, perp: Vec3::Y, ready: false, } @@ -54,20 +57,24 @@ impl DimContinueCommand { /// Build from the last placed dimension. /// - /// `p1` / `p2` — extension line origins of the base dim. - /// `definition_point` — where the dim line was placed (defines perpendicular offset). + /// `p2` — second extension line origin of the base dim (the chain starts + /// here). `p1` is unused — the dim line position comes from + /// `definition_point` alone — but kept for signature parity with the + /// shared `find_last_linear_dim` tuple (DIMBASELINE uses p1). + /// `definition_point` — where the dim line was placed; its perpendicular + /// coordinate is the line the whole chain stays collinear with. /// `rotation` — 0.0 = horizontal dim, PI/2 = vertical dim. - pub fn from_base(p1: Vec3, p2: Vec3, definition_point: Vec3, rotation: f64) -> Self { + pub fn from_base(_p1: Vec3, p2: Vec3, definition_point: Vec3, rotation: f64) -> Self { // Axis unit vector along the measurement direction — the base dim's // rotation angle (any angle, incl. a UCS-aligned one), not a world H/V. let axis = Vec3::new(rotation.cos() as f32, rotation.sin() as f32, 0.0); // Perpendicular unit vector toward the dim line. let perp = Vec3::new(-axis.y, axis.x, 0.0); - let dim_offset = (definition_point - p1).dot(perp); + let dim_line_perp = definition_point.dot(perp); Self { chain_p1: p2, rotation, - dim_offset, + dim_line_perp, perp, ready: true, } @@ -98,11 +105,15 @@ impl CadCommand for DimContinueCommand { let mut dim = DimensionLinear::new(v3(p1), v3(p2)); dim.rotation = self.rotation; - // Dim-line position: same perpendicular distance as base. - let dim_line_pt = p1 + self.perp * self.dim_offset; - dim.definition_point = v3(dim_line_pt); - dim.base.definition_point = v3(dim_line_pt); - dim.base.text_middle_point = v3((dim_line_pt + (p2 + self.perp * self.dim_offset)) * 0.5); + // Dim line stays collinear with the base: project both extension + // origins onto the base dim line's absolute perpendicular coordinate. + // (A fixed offset from p1 drifts off the base line whenever p1 and p2 + // sit at different perpendicular positions.) (#151) + let d1 = p1 + self.perp * (self.dim_line_perp - p1.dot(self.perp)); + let d2 = p2 + self.perp * (self.dim_line_perp - p2.dot(self.perp)); + dim.definition_point = v3(d1); + dim.base.definition_point = v3(d1); + dim.base.text_middle_point = v3((d1 + d2) * 0.5); dim.base.insertion_point = dim.base.text_middle_point; dim.base.actual_measurement = dim.measurement(); @@ -121,8 +132,8 @@ impl CadCommand for DimContinueCommand { return None; } let p1 = self.chain_p1; - let dim_line_pt = p1 + self.perp * self.dim_offset; - let dim_line_pt2 = pt + self.perp * self.dim_offset; + let dim_line_pt = p1 + self.perp * (self.dim_line_perp - p1.dot(self.perp)); + let dim_line_pt2 = pt + self.perp * (self.dim_line_perp - pt.dot(self.perp)); Some(WireModel { name: "dimcont_preview".into(), points: vec![