fix(dim): let the dimension line say which distance is measured

DIMLINEAR chose its measurement axis from the two extension line origins
alone, taking the longer of their x and y differences. Every line tilted
less than 45° therefore came out horizontal and stayed horizontal, no
matter where the dimension line was dragged.

The third pick is what answers the question. A linear dimension reports
the run or the rise; pulling the dimension line clear of the points above
or below asks for the horizontal distance, pulling it out to the side
asks for the vertical one.

"Clear of the points" is measured against their extent, not their
midpoint. A dimension line dragged straight up from near one end of a
long pair is still above them even though it is a long way from the
middle, and a midpoint test would call that sideways. When the location
is inside the pair on both axes it has not said anything yet, so the
longer side still decides.

Nothing else needed changing: the measurement already projects onto the
rotation axis, and the block builder already derives the dimension line
and both extension lines from it.

Closes #669

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Opus 5 committed 2026-08-08 00:34:03 +03:00
1 parent 1a753e821c
commit 8e09a312aa
1 file changed
+26 -3
+26 -3
View File
@@ -8,7 +8,30 @@ use crate::scene::model::wire_model::WireModel;
use glam::DVec3;
use crate::t;
fn measure_axis(first: DVec3, second: DVec3) -> DVec3 {
/// Which axis a linear dimension measures along.
///
/// Not the segment's own direction. A linear dimension reports the run or the
/// rise, and which of the two is wanted is said by where the dimension line is
/// put: pulled clear of the points above or below, the horizontal distance is
/// what is left to show; pulled out to the side, the vertical one. Taking the
/// answer from the two origins alone made every shallow tilt horizontal
/// forever, whatever the cursor did. (#669)
///
/// "Clear of the points" is measured against their extent rather than their
/// midpoint: a dimension line dragged straight up from near one end of a long
/// pair is still above them, though it is a long way from the middle.
fn measure_axis(first: DVec3, second: DVec3, def: DVec3) -> DVec3 {
let outside = |value: f64, a: f64, b: f64| {
let (low, high) = if a <= b { (a, b) } else { (b, a) };
(low - value).max(value - high).max(0.0)
};
let out_x = outside(def.x, first.x, second.x);
let out_y = outside(def.y, first.y, second.y);
if out_x > 0.0 || out_y > 0.0 {
return if out_y >= out_x { DVec3::X } else { DVec3::Y };
}
// Still between the origins on both axes — the location has not said
// anything yet, so fall back to the longer side of the pair.
let delta = second - first;
if delta.x.abs() >= delta.y.abs() {
DVec3::X
@@ -102,7 +125,7 @@ impl CadCommand for LinearDimensionCommand {
let second = self.plane.to_local(second);
let pt = self.plane.to_local(pt);
let mut dim = DimensionLinear::new(v3(first), v3(second));
let axis = measure_axis(first, second);
let axis = measure_axis(first, second, pt);
dim.rotation = axis.y.atan2(axis.x);
dim.definition_point = v3(pt);
dim.base.definition_point = v3(pt);
@@ -197,7 +220,7 @@ impl CadCommand for LinearDimensionCommand {
let first = self.plane.to_local(first);
let second = self.plane.to_local(second);
let pt = self.plane.to_local(pt);
let axis = measure_axis(first, second);
let axis = measure_axis(first, second, pt);
let points = linear_dimension_preview(first, second, pt, axis)
.into_iter()
.map(|point| self.plane.to_world(point))