diff --git a/src/scene/boundary.rs b/src/scene/boundary.rs index 01d398e00..6db167936 100644 --- a/src/scene/boundary.rs +++ b/src/scene/boundary.rs @@ -729,6 +729,41 @@ impl Scene { self.refresh_fill_model(handle); } + /// A copied associative hatch must follow the copied boundary, not the + /// source one — otherwise editing the source regenerates the copy onto the + /// source's outline and the copy seems to vanish. A path whose boundary + /// was not copied along loses its association. (#1370) + pub(crate) fn copy_hatch_associations( + &mut self, + handle_map: &rustc_hash::FxHashMap, + ) { + let mut touched = false; + for © in handle_map.values() { + let Some(EntityType::Hatch(hatch)) = self.document.get_entity_mut(copy) else { + continue; + }; + if !hatch.is_associative { + continue; + } + for path in &mut hatch.paths { + if path.boundary_handles.iter().all(|source| handle_map.contains_key(source)) { + for source in &mut path.boundary_handles { + *source = handle_map[source]; + } + } else { + path.boundary_handles.clear(); + path.flags.set_external(false); + } + } + hatch.is_associative = + hatch.paths.iter().any(|path| !path.boundary_handles.is_empty()); + touched = true; + } + if touched { + self.associative_hatch_source_cache.borrow_mut().take(); + } + } + pub(crate) fn edit_hatch_boundary_handles( &mut self, hatch_handle: Handle, diff --git a/src/scene/modify.rs b/src/scene/modify.rs index 7de123e14..0384d6c3c 100644 --- a/src/scene/modify.rs +++ b/src/scene/modify.rs @@ -810,6 +810,7 @@ impl Scene { // entry as targeted object deltas inside copy_complete_groups. self.copy_complete_groups(&handle_map); self.copy_dimension_associations(&handle_map); + self.copy_hatch_associations(&handle_map); // The copies are new handles (natural memo misses, tessellated fresh) // and reference only already-cached blocks — no block defn changes. // Report them as additions so derived caches patch in exactly the copies.