From 446430d2b3c495768c45223dcd1102febf4657fe Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Thu, 18 Jun 2026 14:45:06 +0300 Subject: [PATCH] fix: regenerate inline sub-entity handles when copying entities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `document.add_entity` only assigns the top-level handle, leaving inline sub-entities that carry their own — INSERT attributes and 3D-polyline vertices — with the source's handles. Copying such an entity therefore produced duplicate handles in the document, which corrupts the saved DWG so other CAD apps (QCAD, DWG TrueView) refuse to open it. Add `Scene::add_entity_clone` / `reset_clone_subhandles`, which allocate fresh handles for the entity and every inline sub-entity, and route all duplication paths through it: COPY/ARRAY/MIRROR-copy (via copy_entities) and clipboard paste. (#129) Co-Authored-By: Claude Opus 4.8 --- src/app/cmd_result.rs | 3 +-- src/scene/mod.rs | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/app/cmd_result.rs b/src/app/cmd_result.rs index b883031f6..60573c8a9 100644 --- a/src/app/cmd_result.rs +++ b/src/app/cmd_result.rs @@ -557,8 +557,7 @@ impl OpenCADStudio { .into_iter() .map(|mut entity| { crate::scene::view::dispatch::apply_transform(&mut entity, &translate); - entity.common_mut().handle = acadrust::Handle::NULL; - self.tabs[i].scene.add_entity(entity) + self.tabs[i].scene.add_entity_clone(entity) }) .filter(|h| !h.is_null()) .collect(); diff --git a/src/scene/mod.rs b/src/scene/mod.rs index 1b3e39c7f..0ed2ac9b7 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -5018,6 +5018,38 @@ impl Scene { self.bump_geometry_no_blocks(); } + /// Give a freshly-cloned entity brand-new handles for every *inline* + /// sub-entity that stores one (INSERT attributes, 3D-polyline vertices). + /// `document.add_entity` only assigns the top-level handle, so without this + /// a copy keeps its source's sub-handles — duplicate handles that corrupt + /// the saved DWG (file won't reopen in other CAD apps). Vertices that don't + /// store a handle (LwPolyline / heavy 2D polyline) get one from the writer, + /// so they need no fix-up here. (#129) + fn reset_clone_subhandles(doc: &mut acadrust::CadDocument, entity: &mut EntityType) { + match entity { + EntityType::Insert(ins) => { + for att in ins.attributes.iter_mut() { + att.common.handle = doc.allocate_handle(); + } + } + EntityType::Polyline3D(p) => { + for v in p.vertices.iter_mut() { + v.handle = doc.allocate_handle(); + } + } + _ => {} + } + } + + /// Add a freshly-cloned entity, allocating a new handle for it *and* every + /// inline sub-entity so the copy never shares a handle with its source. + /// Use this (not `add_entity`) whenever inserting a duplicate. (#129) + pub fn add_entity_clone(&mut self, mut entity: EntityType) -> Handle { + Self::reset_clone_subhandles(&mut self.document, &mut entity); + entity.common_mut().handle = Handle::NULL; + self.add_entity(entity) + } + pub fn copy_entities(&mut self, handles: &[Handle], t: &EntityTransform) -> Vec { let hatch_offset = if self.current_layout == "Model" { self.world_offset @@ -5031,6 +5063,7 @@ impl Scene { let mut new_handles = Vec::with_capacity(clones.len()); for mut entity in clones { view::dispatch::apply_transform(&mut entity, t); + Self::reset_clone_subhandles(&mut self.document, &mut entity); entity.common_mut().handle = Handle::NULL; let h = self.document.add_entity(entity).unwrap_or(Handle::NULL); if !h.is_null() {