forked from 1b-agent/opencadstudio-upstream
Add UCS FACE and UCS OBJECT
Draw a profile, extrude it, then sketch on a face of the result: the operations were all there, but nothing turned a solid's face into the active drawing plane, so the second half of that loop was unreachable. UCS FACE takes a surface pick, finds the planar face under it and builds the plane from the face normal. X comes from the Arbitrary Axis Algorithm, so the same face always yields the same X axis and a sketch drawn on it does not spin when the UCS is rebuilt. UCS OBJECT adopts a planar entity's own stored axes instead of re-deriving X, so a sketch started from a circle lines up with how that circle is stored. It reuses the profile extraction EXTRUDE already runs, which means anything extrudable can also be sketched on. Bare UCS FACE starts an interactive pick that resolves through the same inline handler, so the clicked and typed paths cannot diverge.
This commit is contained in:
3 files changed
+215
No files matched your search
@@ -247,6 +247,40 @@ pub(super) fn ucs_z_axis(ucs: &Ucs) -> glam::DVec3 {
|
||||
UcsXform::from_ucs(ucs).axes().3
|
||||
}
|
||||
|
||||
/// Build a UCS whose Z axis is `normal`, anchored at `origin`.
|
||||
///
|
||||
/// X and Y come from the Arbitrary Axis Algorithm, the same rule DWG uses to
|
||||
/// turn an extrusion direction into an object coordinate system. Picking the
|
||||
/// world axis that is *least* parallel to the normal keeps the cross product
|
||||
/// well conditioned, and makes the result stable: the same face always yields
|
||||
/// the same X axis, so a sketch drawn on it does not spin when the UCS is
|
||||
/// rebuilt.
|
||||
///
|
||||
/// Returns `None` when `normal` is degenerate and defines no plane.
|
||||
pub(super) fn ucs_from_normal(origin: glam::DVec3, normal: glam::DVec3) -> Option<Ucs> {
|
||||
let z = normal.normalize_or_zero();
|
||||
if z.length_squared() < 1e-12 {
|
||||
return None;
|
||||
}
|
||||
// 1/64 is the threshold the DWG spec names for "close enough to the world
|
||||
// Z axis that using it as the reference would be ill conditioned".
|
||||
let reference = if z.x.abs() < 1.0 / 64.0 && z.y.abs() < 1.0 / 64.0 {
|
||||
glam::DVec3::Y
|
||||
} else {
|
||||
glam::DVec3::Z
|
||||
};
|
||||
let x = reference.cross(z).normalize_or_zero();
|
||||
if x.length_squared() < 1e-12 {
|
||||
return None;
|
||||
}
|
||||
let y = z.cross(x).normalize_or_zero();
|
||||
let mut ucs = Ucs::new("*ACTIVE*");
|
||||
ucs.origin = acadrust::types::Vector3::new(origin.x, origin.y, origin.z);
|
||||
ucs.x_axis = acadrust::types::Vector3::new(x.x, x.y, x.z);
|
||||
ucs.y_axis = acadrust::types::Vector3::new(y.x, y.y, y.z);
|
||||
Some(ucs)
|
||||
}
|
||||
|
||||
/// Build a UCS with `origin` and axes rotated by `angle_z_rad` around the Z axis.
|
||||
pub(super) fn ucs_rotated_z(origin: glam::DVec3, angle_z: f32) -> Ucs {
|
||||
let cos = angle_z.cos() as f64;
|
||||
|
||||
Reference in new issue
Block a user