forked from 1b-agent/opencadstudio-upstream
fix(dimension): rotate and mirror dimensions in working planes off world Z
With a working plane other than world XY, ROTATE and MIRROR handed a non-ordinate dimension to acadrust's Entity::apply_transform, which only translates those dimension types by where the transform sends the origin. The definition points, plane and angles stayed unturned, so the dimension jumped back once its block was baked again. Send both through the existing Affine branch, which ALIGN already uses and which transforms points, normal and stored angles together. The world-Z paths are unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
cba64631b8
commit
23cd448c7f
1 file changed
+86
-12
+86
-12
@@ -882,12 +882,21 @@ fn apply_transform(dim: &mut Dimension, t: &EntityTransform) {
|
||||
d.rotation += *angle_rad;
|
||||
}
|
||||
} else {
|
||||
crate::scene::view::transform::apply_standard_transform(
|
||||
dim,
|
||||
*center,
|
||||
*axis,
|
||||
// acadrust only moves a non-ordinate dimension by where the
|
||||
// origin goes, so turn it through the affine path below.
|
||||
use acadrust::types::Transform;
|
||||
let unit = axis.normalize_or(DVec3::Z);
|
||||
let rotation = Transform::from_translation(Vector3::new(
|
||||
-center.x, -center.y, -center.z,
|
||||
))
|
||||
.then(&Transform::from_rotation(
|
||||
Vector3::new(unit.x, unit.y, unit.z),
|
||||
*angle_rad,
|
||||
);
|
||||
))
|
||||
.then(&Transform::from_translation(Vector3::new(
|
||||
center.x, center.y, center.z,
|
||||
)));
|
||||
apply_transform(dim, &EntityTransform::Affine(rotation));
|
||||
}
|
||||
}
|
||||
EntityTransform::Scale { center, factor } => {
|
||||
@@ -903,14 +912,13 @@ fn apply_transform(dim: &mut Dimension, t: &EntityTransform) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
acadrust::Entity::apply_transform(
|
||||
dim,
|
||||
&crate::scene::view::transform::reflection_about_working_line(
|
||||
*p1,
|
||||
*p2,
|
||||
*working_normal,
|
||||
),
|
||||
// Same as ROTATE: reflect points, plane and angles together.
|
||||
let reflection = crate::scene::view::transform::reflection_about_working_line(
|
||||
*p1,
|
||||
*p2,
|
||||
*working_normal,
|
||||
);
|
||||
apply_transform(dim, &EntityTransform::Affine(reflection));
|
||||
}
|
||||
}
|
||||
EntityTransform::Affine(transform) => {
|
||||
@@ -7743,4 +7751,70 @@ mod linear_transform_tests {
|
||||
assert_eq!(rotation(&dim), 0.0);
|
||||
assert_measures_ten(&dim);
|
||||
}
|
||||
|
||||
/// The point the dimension line passes through.
|
||||
fn definition_point(dim: &Dimension) -> DVec3 {
|
||||
let p = dimension_definition_point(dim);
|
||||
DVec3::new(p.x, p.y, p.z)
|
||||
}
|
||||
|
||||
fn assert_near(actual: DVec3, expected: DVec3, what: &str) {
|
||||
assert!(
|
||||
actual.abs_diff_eq(expected, 1e-9),
|
||||
"{what}: expected {expected:?}, got {actual:?}"
|
||||
);
|
||||
}
|
||||
|
||||
/// ROTATE about an axis off world Z (a working plane other than world XY)
|
||||
/// turns the dimension like the geometry it measures. It used to only move
|
||||
/// by where the origin went, leaving the dimension line and plane unturned.
|
||||
#[test]
|
||||
fn rotate_off_world_z_turns_the_dimension() {
|
||||
let center = DVec3::new(0.0, 10.0, 0.0);
|
||||
let turn = glam::DQuat::from_axis_angle(DVec3::X, FRAC_PI_2);
|
||||
let mut dim = horizontal();
|
||||
apply_transform(
|
||||
&mut dim,
|
||||
&EntityTransform::Rotate {
|
||||
center,
|
||||
axis: DVec3::X,
|
||||
angle_rad: FRAC_PI_2,
|
||||
},
|
||||
);
|
||||
assert_near(
|
||||
definition_point(&dim),
|
||||
turn * (DVec3::new(0.0, 5.0, 0.0) - center) + center,
|
||||
"definition point",
|
||||
);
|
||||
let normal = dim.base().normal;
|
||||
assert_near(
|
||||
DVec3::new(normal.x, normal.y, normal.z),
|
||||
turn * DVec3::Z,
|
||||
"normal",
|
||||
);
|
||||
assert_measures_ten(&dim);
|
||||
}
|
||||
|
||||
/// MIRROR in a working plane off world Z reflects the dimension through
|
||||
/// the mirror plane instead of only moving it.
|
||||
#[test]
|
||||
fn mirror_off_world_z_reflects_the_dimension() {
|
||||
// Working plane YZ; the line runs along Z at y = 2, so the mirror
|
||||
// plane is y = 2.
|
||||
let mut dim = horizontal();
|
||||
apply_transform(
|
||||
&mut dim,
|
||||
&EntityTransform::Mirror {
|
||||
p1: DVec3::new(0.0, 2.0, 0.0),
|
||||
p2: DVec3::new(0.0, 2.0, 1.0),
|
||||
working_normal: DVec3::X,
|
||||
},
|
||||
);
|
||||
assert_near(
|
||||
definition_point(&dim),
|
||||
DVec3::new(0.0, -1.0, 0.0),
|
||||
"definition point",
|
||||
);
|
||||
assert_measures_ten(&dim);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user