fix(3d): place and move ACIS solids and tilted-normal blocks correctly
Bump acadrust to pick up real ACIS body transforms (so moving/copying/ rotating a 3D solid relocates its geometry) and OCS-aware INSERT placement. - body_transform: read the SAT transform record from its first 13 float tokens instead of by raw index, which skipped the matrix because the record leads with a book-keeping pointer — so the body placement was silently ignored and solids never honored their stored transform. - Insert grips: the grip lives in world space but insert_point is stored in the block's OCS, so grip display and grip-drag now round-trip through the OCS. A block whose extrusion normal isn't +Z no longer shows its grip in the wrong place or drags along the wrong axes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
fd15dd0aac
commit
31ed911714
3 changed files with 27 additions and 20 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -70,7 +70,7 @@ checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "acadrust"
|
name = "acadrust"
|
||||||
version = "0.3.4"
|
version = "0.3.4"
|
||||||
source = "git+https://github.com/HakanSeven12/acadrust?branch=main#67db8eeeb63e429d301f7708ee8a4629ed3eb780"
|
source = "git+https://github.com/HakanSeven12/acadrust?branch=main#33cb8b72dbf9f3dc585619a31848b42c5acf8c81"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use acadrust::entities::Insert;
|
use acadrust::entities::Insert;
|
||||||
use acadrust::types::{Transform, Vector3};
|
use acadrust::types::{Matrix3, Transform, Vector3};
|
||||||
use acadrust::{EntityType, Handle};
|
use acadrust::{EntityType, Handle};
|
||||||
use glam::Vec3;
|
use glam::Vec3;
|
||||||
|
|
||||||
|
|
@ -13,8 +13,10 @@ use crate::scene::convert::tessellate;
|
||||||
use crate::scene::view::render;
|
use crate::scene::view::render;
|
||||||
|
|
||||||
fn grips(ins: &Insert) -> Vec<GripDef> {
|
fn grips(ins: &Insert) -> Vec<GripDef> {
|
||||||
let p = glam::DVec3::new(ins.insert_point.x, ins.insert_point.y, ins.insert_point.z);
|
// `insert_point` is in the OCS defined by `normal`; the grip must sit at
|
||||||
vec![square_grip(0, p)]
|
// the world placement, so map it through the OCS. Identity for +Z.
|
||||||
|
let w = Matrix3::arbitrary_axis(ins.normal) * ins.insert_point;
|
||||||
|
vec![square_grip(0, glam::DVec3::new(w.x, w.y, w.z))]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn properties(ins: &Insert) -> PropSection {
|
fn properties(ins: &Insert) -> PropSection {
|
||||||
|
|
@ -50,18 +52,18 @@ fn apply_geom_prop(ins: &mut Insert, field: &str, value: &str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_grip(ins: &mut Insert, _grip_id: usize, apply: GripApply) {
|
fn apply_grip(ins: &mut Insert, _grip_id: usize, apply: GripApply) {
|
||||||
match apply {
|
// The grip works in world space, but `insert_point` is stored in the OCS
|
||||||
GripApply::Absolute(p) => {
|
// defined by `normal`. Round-trip through the OCS so dragging a block
|
||||||
ins.insert_point.x = p.x as f64;
|
// whose extrusion direction isn't +Z moves along world axes. Identity OCS
|
||||||
ins.insert_point.y = p.y as f64;
|
// for a +Z normal, so this matches the old direct assignment there.
|
||||||
ins.insert_point.z = p.z as f64;
|
let ocs = Matrix3::arbitrary_axis(ins.normal);
|
||||||
}
|
let world = match apply {
|
||||||
|
GripApply::Absolute(p) => Vector3::new(p.x as f64, p.y as f64, p.z as f64),
|
||||||
GripApply::Translate(d) => {
|
GripApply::Translate(d) => {
|
||||||
ins.insert_point.x += d.x as f64;
|
ocs * ins.insert_point + Vector3::new(d.x as f64, d.y as f64, d.z as f64)
|
||||||
ins.insert_point.y += d.y as f64;
|
|
||||||
ins.insert_point.z += d.z as f64;
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
ins.insert_point = ocs.transpose() * world;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_transform(ins: &mut Insert, t: &EntityTransform) {
|
fn apply_transform(ins: &mut Insert, t: &EntityTransform) {
|
||||||
|
|
|
||||||
|
|
@ -191,13 +191,18 @@ fn tessellate_sat_lods(
|
||||||
/// document has no transform (treated as identity).
|
/// document has no transform (treated as identity).
|
||||||
pub(crate) fn body_transform(sat: &SatDocument) -> Option<([f64; 9], [f64; 3], f64)> {
|
pub(crate) fn body_transform(sat: &SatDocument) -> Option<([f64; 9], [f64; 3], f64)> {
|
||||||
let t = sat.records.iter().find(|r| r.entity_type == "transform")?;
|
let t = sat.records.iter().find(|r| r.entity_type == "transform")?;
|
||||||
let mut m = [0.0f64; 9];
|
// The transform record's numeric payload is its first 13 float-valued
|
||||||
for (i, slot) in m.iter_mut().enumerate() {
|
// tokens: 3×3 matrix, translation, scale. A leading book-keeping pointer
|
||||||
*slot = t.token_float(i)?;
|
// (`$-1`) and the trailing rotate/reflect/shear flags aren't floats, so
|
||||||
|
// collecting float tokens skips them — reading by raw token index would
|
||||||
|
// be thrown off by the leading pointer.
|
||||||
|
let v: Vec<f64> = t.tokens.iter().filter_map(|tok| tok.as_float()).take(13).collect();
|
||||||
|
if v.len() < 13 {
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
let tr = [t.token_float(9)?, t.token_float(10)?, t.token_float(11)?];
|
let m = [v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8]];
|
||||||
let scale = t.token_float(12).unwrap_or(1.0);
|
let tr = [v[9], v[10], v[11]];
|
||||||
Some((m, tr, scale))
|
Some((m, tr, v[12]))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply a body placement transform to a mesh. ACIS treats points as row
|
/// Apply a body placement transform to a mesh. ACIS treats points as row
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue