forked from 1b-agent/opencadstudio-upstream
fix(blocks): one base point convention for creation, redefine, insert, explode, XCLIP and REFEDIT
world = insert_point + Rot * Scale * (P - base_point). Attribute placement, EXPLODE, XCLIP storage, REFEDIT's working copy, the UCS reframe of attributes and the dynamic-block visibility grip ignored the base point and were offset by Rot*Scale*base. They now share insert_transform_with_base. Creation stores a ZERO base and redefine resets it; a no-op redefine moves nothing; the Block Definition dialog prefills the base from the definition. XCLIP filters stored by older builds keep their old displacement.
This commit is contained in:
1 parent
a456367b26
commit
5dfa41c032
17 files changed
+1447
-19
No files matched your search
@@ -809,12 +809,19 @@ impl OpenCADStudio {
|
||||
};
|
||||
|
||||
// Build the INSERT's full placement transform (OCS + rotation +
|
||||
// scale, including non-uniform / mirrored) and its inverse, so
|
||||
// edits round-trip back to block-local coordinates on SAVE.
|
||||
// scale, including non-uniform / mirrored, minus the block base
|
||||
// point) and its inverse, so edits round-trip back to
|
||||
// block-local coordinates on SAVE. The base point is part of
|
||||
// the placement: without it the working copy sits Rot*Scale*base
|
||||
// away from the reference the user picked.
|
||||
let sx = insert.x_scale();
|
||||
let sy = insert.y_scale();
|
||||
let sz = insert.z_scale();
|
||||
let forward = insert.get_transform();
|
||||
let base = crate::scene::render_graph::block_base_point(
|
||||
&self.tabs[i].scene.document,
|
||||
&insert.block_name,
|
||||
);
|
||||
let forward = crate::scene::render_graph::insert_transform_with_base(&insert, base);
|
||||
let inverse = {
|
||||
use codec::types::{Matrix3, Matrix4, Transform};
|
||||
let ocs_t =
|
||||
@@ -826,8 +833,11 @@ impl OpenCADStudio {
|
||||
);
|
||||
let r_inv = Matrix4::rotation_z(-insert.rotation);
|
||||
let s_inv = Matrix4::scaling(1.0 / sx, 1.0 / sy, 1.0 / sz);
|
||||
// inverse(OCS·T·R·S) = S⁻¹·R⁻¹·T⁻¹·OCSᵀ
|
||||
Transform::from_matrix(s_inv * r_inv * t_inv * ocs_t)
|
||||
// inverse(T(-base)·OCS·T·R·S) = T(+base)·S⁻¹·R⁻¹·T⁻¹·OCSᵀ
|
||||
Transform::from_matrix(
|
||||
Matrix4::translation(base.x, base.y, base.z)
|
||||
* (s_inv * r_inv * t_inv * ocs_t),
|
||||
)
|
||||
};
|
||||
|
||||
// Find the block record.
|
||||
|
||||
@@ -2269,8 +2269,8 @@ impl OpenCADStudio {
|
||||
let host = self.tabs[i].scene.document.header.insertion_units;
|
||||
let k = crate::app::properties::insert_unit_scale(host, units).unwrap_or(1.0);
|
||||
let mut insert = codec::entities::Insert::new(name.to_string(), at).with_scale(k, k, k);
|
||||
let transform = insert.get_transform();
|
||||
let doc = &self.tabs[i].scene.document;
|
||||
let transform = crate::scene::render_graph::insert_transform(doc, &insert);
|
||||
let attdefs: Vec<codec::entities::AttributeDefinition> = doc
|
||||
.block_records
|
||||
.get(name)
|
||||
|
||||
@@ -6,13 +6,14 @@ use crate::scene::pick::xclip as clip;
|
||||
|
||||
impl OpenCADStudio {
|
||||
/// A block reference's extents in WCS: its block's objects through the
|
||||
/// insert transform.
|
||||
/// insert transform — the base-point-aware one, because that is where the
|
||||
/// renderer puts the contents the user drew the boundary around.
|
||||
fn insert_extents(&self, i: usize, insert: codec::Handle) -> ([f64; 2], [f64; 2]) {
|
||||
let document = &self.tabs[i].scene.document;
|
||||
let Some(codec::EntityType::Insert(ins)) = document.get_entity(insert) else {
|
||||
return ([0.0; 2], [0.0; 2]);
|
||||
};
|
||||
let xform = ins.get_transform();
|
||||
let xform = crate::scene::render_graph::insert_transform(document, ins);
|
||||
let (mut lo, mut hi) = ([f64::MAX; 2], [f64::MIN; 2]);
|
||||
for e in document.entities_in_block(&ins.block_name) {
|
||||
let (a, b) = crate::scene::convert::tess::entity_bounds_in(document, e);
|
||||
@@ -77,7 +78,14 @@ impl OpenCADStudio {
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
let outline = clip::clip_outline_world(doc, filter, &ins.get_transform());
|
||||
// The same base-point-aware transform the spatial filter
|
||||
// was stored with, so the generated polyline lands on the
|
||||
// boundary the user drew (the two cancel exactly).
|
||||
let outline = clip::clip_outline_world(
|
||||
doc,
|
||||
filter,
|
||||
&crate::scene::render_graph::insert_transform(doc, ins),
|
||||
);
|
||||
let mut pl = codec::entities::LwPolyline::from_points(
|
||||
outline
|
||||
.iter()
|
||||
|
||||
Reference in new issue
Block a user