fix(3d): move and paste ACIS solids to the right place
Solids were missing from the entity transform dispatch, so move / rotate / scale / mirror were silently no-ops on a 3D solid (only its wires shifted) and a pasted solid stayed at its original location. Add a Transformable impl for Solid3D/Region/Body/Surface (delegating to acadrust, which now composes the move into the ACIS body placement) and register them in the dispatcher. Also make cross-drawing paste land at the cursor: the clipboard centroid is measured in the source drawing's offset-relative frame, so correct the paste translation by the source/target world_offset difference (zero within one drawing). Bumps acadrust for the solid-geometry transform fixes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
e45064f8a8
commit
de1f1c0e24
6 changed files with 49 additions and 4 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#33cb8b72dbf9f3dc585619a31848b42c5acf8c81"
|
source = "git+https://github.com/HakanSeven12/acadrust?branch=main#07006d104150006332d2873413afba9620cf0aa3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
|
|
||||||
|
|
@ -594,7 +594,19 @@ impl OpenCADStudio {
|
||||||
if self.clipboard.is_empty() {
|
if self.clipboard.is_empty() {
|
||||||
self.command_line.push_error("Clipboard is empty.");
|
self.command_line.push_error("Clipboard is empty.");
|
||||||
} else {
|
} else {
|
||||||
let delta = base_pt - self.clipboard_centroid;
|
// The centroid was measured in the source drawing's
|
||||||
|
// offset-relative frame and `base_pt` is in this drawing's;
|
||||||
|
// correct by the world_offset difference so a cross-drawing
|
||||||
|
// paste lands at the cursor instead of drifting by the
|
||||||
|
// offset gap. Zero for a same-drawing paste. (#135)
|
||||||
|
let src_wo = self.clipboard_world_offset;
|
||||||
|
let tgt_wo = self.tabs[i].scene.world_offset;
|
||||||
|
let wo_corr = glam::Vec3::new(
|
||||||
|
(tgt_wo[0] - src_wo[0]) as f32,
|
||||||
|
(tgt_wo[1] - src_wo[1]) as f32,
|
||||||
|
(tgt_wo[2] - src_wo[2]) as f32,
|
||||||
|
);
|
||||||
|
let delta = base_pt - self.clipboard_centroid + wo_corr;
|
||||||
let translate = crate::command::EntityTransform::Translate(delta);
|
let translate = crate::command::EntityTransform::Translate(delta);
|
||||||
self.push_undo_snapshot(i, "PASTECLIP");
|
self.push_undo_snapshot(i, "PASTECLIP");
|
||||||
// Recreate any layer / linetype / style the copied entities
|
// Recreate any layer / linetype / style the copied entities
|
||||||
|
|
|
||||||
|
|
@ -540,6 +540,7 @@ impl OpenCADStudio {
|
||||||
self.clipboard_centroid = super::helpers::entities_centroid(
|
self.clipboard_centroid = super::helpers::entities_centroid(
|
||||||
&self.tabs[i].scene.wire_models_for(&handles),
|
&self.tabs[i].scene.wire_models_for(&handles),
|
||||||
);
|
);
|
||||||
|
self.clipboard_world_offset = self.tabs[i].scene.world_offset;
|
||||||
self.clipboard = entities;
|
self.clipboard = entities;
|
||||||
self.clipboard_deps = super::ClipboardDeps::capture(
|
self.clipboard_deps = super::ClipboardDeps::capture(
|
||||||
&self.tabs[i].scene.document,
|
&self.tabs[i].scene.document,
|
||||||
|
|
@ -572,6 +573,7 @@ impl OpenCADStudio {
|
||||||
self.clipboard_centroid = super::helpers::entities_centroid(
|
self.clipboard_centroid = super::helpers::entities_centroid(
|
||||||
&self.tabs[i].scene.wire_models_for(&handles),
|
&self.tabs[i].scene.wire_models_for(&handles),
|
||||||
);
|
);
|
||||||
|
self.clipboard_world_offset = self.tabs[i].scene.world_offset;
|
||||||
let count = entities.len();
|
let count = entities.len();
|
||||||
self.clipboard = entities;
|
self.clipboard = entities;
|
||||||
self.clipboard_deps = super::ClipboardDeps::capture(
|
self.clipboard_deps = super::ClipboardDeps::capture(
|
||||||
|
|
|
||||||
|
|
@ -369,6 +369,12 @@ pub(super) struct OpenCADStudio {
|
||||||
clipboard: Vec<acadrust::EntityType>,
|
clipboard: Vec<acadrust::EntityType>,
|
||||||
/// Centroid of the clipboard entities (world XY plane).
|
/// Centroid of the clipboard entities (world XY plane).
|
||||||
clipboard_centroid: glam::Vec3,
|
clipboard_centroid: glam::Vec3,
|
||||||
|
/// The source drawing's `world_offset` at copy time. The centroid above is
|
||||||
|
/// measured in that drawing's offset-relative frame; pasting into a drawing
|
||||||
|
/// with a different offset (e.g. a large-coordinate file → a fresh one)
|
||||||
|
/// must correct the paste translation by the offset difference, else the
|
||||||
|
/// objects land `source_offset − target_offset` away from the cursor.
|
||||||
|
clipboard_world_offset: [f64; 3],
|
||||||
/// Table records (layer / linetype / text + dim style) the clipboard
|
/// Table records (layer / linetype / text + dim style) the clipboard
|
||||||
/// entities reference, captured from the source drawing at copy time so a
|
/// entities reference, captured from the source drawing at copy time so a
|
||||||
/// paste into a *different* drawing can recreate any that are missing —
|
/// paste into a *different* drawing can recreate any that are missing —
|
||||||
|
|
@ -1721,6 +1727,7 @@ impl OpenCADStudio {
|
||||||
update_notice_body: None,
|
update_notice_body: None,
|
||||||
clipboard: Vec::new(),
|
clipboard: Vec::new(),
|
||||||
clipboard_centroid: glam::Vec3::ZERO,
|
clipboard_centroid: glam::Vec3::ZERO,
|
||||||
|
clipboard_world_offset: [0.0; 3],
|
||||||
clipboard_deps: ClipboardDeps::default(),
|
clipboard_deps: ClipboardDeps::default(),
|
||||||
shift_down: false,
|
shift_down: false,
|
||||||
mtext_editor: None,
|
mtext_editor: None,
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,36 @@
|
||||||
// fallback stays in sync; the caller (scene/mod.rs apply_grip) translates
|
// fallback stays in sync; the caller (scene/mod.rs apply_grip) translates
|
||||||
// the MeshModel vertices to match.
|
// the MeshModel vertices to match.
|
||||||
|
|
||||||
use acadrust::entities::{Body, Region, Solid3D};
|
use acadrust::entities::{Body, Region, Solid3D, Surface};
|
||||||
use glam::Vec3;
|
use glam::Vec3;
|
||||||
|
|
||||||
|
use crate::command::EntityTransform;
|
||||||
use crate::entities::common::{center_grip, ro_prop as ro};
|
use crate::entities::common::{center_grip, ro_prop as ro};
|
||||||
use crate::entities::traits::{Grippable, PropertyEditable};
|
use crate::entities::traits::{Grippable, PropertyEditable, Transformable};
|
||||||
use crate::scene::model::object::{GripApply, GripDef, PropSection};
|
use crate::scene::model::object::{GripApply, GripDef, PropSection};
|
||||||
|
|
||||||
|
/// Shared transform for the ACIS volume entities. Translate / rotate / scale
|
||||||
|
/// delegate to acadrust (which composes the move into the solid's ACIS
|
||||||
|
/// placement), and mirror delegates via a reflection transform. Without this
|
||||||
|
/// the entity dispatcher treated solids as non-transformable, so a moved or
|
||||||
|
/// pasted solid stayed at its original ACIS placement.
|
||||||
|
macro_rules! impl_acis_transformable {
|
||||||
|
($ty:ty) => {
|
||||||
|
impl Transformable for $ty {
|
||||||
|
fn apply_transform(&mut self, t: &EntityTransform) {
|
||||||
|
crate::scene::view::transform::apply_standard_entity_transform(self, t, |e, p1, p2| {
|
||||||
|
let m = crate::scene::view::transform::reflection_about_xy_line(p1, p2);
|
||||||
|
acadrust::Entity::apply_transform(e, &m);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
impl_acis_transformable!(Solid3D);
|
||||||
|
impl_acis_transformable!(Region);
|
||||||
|
impl_acis_transformable!(Body);
|
||||||
|
impl_acis_transformable!(Surface);
|
||||||
|
|
||||||
// ── shared helpers ────────────────────────────────────────────────────────────
|
// ── shared helpers ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
fn dvec3(v: &acadrust::types::Vector3) -> glam::DVec3 {
|
fn dvec3(v: &acadrust::types::Vector3) -> glam::DVec3 {
|
||||||
|
|
|
||||||
|
|
@ -422,6 +422,7 @@ impl EntityTypeOps for EntityType {
|
||||||
Tolerance, Solid, Face3D, PolygonMesh, PolyfaceMesh, Mesh,
|
Tolerance, Solid, Face3D, PolygonMesh, PolyfaceMesh, Mesh,
|
||||||
Table, MText, Point, Spline, Text, Viewport, Dimension,
|
Table, MText, Point, Spline, Text, Viewport, Dimension,
|
||||||
Leader, MultiLeader, Underlay, Shape, Ole2Frame,
|
Leader, MultiLeader, Underlay, Shape, Ole2Frame,
|
||||||
|
Solid3D, Region, Body, Surface,
|
||||||
],
|
],
|
||||||
_ => {},
|
_ => {},
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue