forked from 1b-agent/opencadstudio-upstream
fix(annotative): MOVE/ROTATE/SCALE carry every scale representation; copies get their own
Only the displayed annotation context followed a transform, so other scales reappeared at the old place, and a copied annotative entity other than a LEADER/MTEXT pair shared the source's context tree. Fixes #700 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
746edaa32b
commit
b66b5100bd
2 files changed
+27
-28
No files matched your search
+19
-5
@@ -1335,6 +1335,21 @@ pub fn translate_annotation_contexts(
|
|||||||
doc: &mut CadDocument,
|
doc: &mut CadDocument,
|
||||||
entity_handle: Handle,
|
entity_handle: Handle,
|
||||||
delta: glam::DVec3,
|
delta: glam::DVec3,
|
||||||
|
) -> bool {
|
||||||
|
transform_annotation_contexts(
|
||||||
|
doc,
|
||||||
|
entity_handle,
|
||||||
|
&crate::command::EntityTransform::Translate(delta),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Carry every annotation-scale representation of an entity through `t`, not
|
||||||
|
/// only the displayed one — otherwise MOVE/ROTATE/SCALE leave the other scales
|
||||||
|
/// where they were and they reappear there on a scale switch. (#700)
|
||||||
|
pub fn transform_annotation_contexts(
|
||||||
|
doc: &mut CadDocument,
|
||||||
|
entity_handle: Handle,
|
||||||
|
t: &crate::command::EntityTransform,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let Some(base_entity) = doc.get_entity(entity_handle).cloned() else {
|
let Some(base_entity) = doc.get_entity(entity_handle).cloned() else {
|
||||||
return false;
|
return false;
|
||||||
@@ -1361,14 +1376,13 @@ pub fn translate_annotation_contexts(
|
|||||||
let mut changed = false;
|
let mut changed = false;
|
||||||
for (_, scale) in leaves {
|
for (_, scale) in leaves {
|
||||||
let mut placed = entity_for_annotation_context(doc, &base_entity, Some(scale)).into_owned();
|
let mut placed = entity_for_annotation_context(doc, &base_entity, Some(scale)).into_owned();
|
||||||
crate::scene::view::dispatch::apply_transform(
|
crate::scene::view::dispatch::apply_transform(&mut placed, t);
|
||||||
&mut placed,
|
|
||||||
&crate::command::EntityTransform::Translate(delta),
|
|
||||||
);
|
|
||||||
|
|
||||||
// The entity translator keeps the compatibility break list in sync,
|
// The entity translator keeps the compatibility break list in sync,
|
||||||
// while the complete per-segment list is a separate persisted field.
|
// while the complete per-segment list is a separate persisted field.
|
||||||
if let EntityType::MultiLeader(mleader) = &mut placed {
|
if let (EntityType::MultiLeader(mleader), crate::command::EntityTransform::Translate(delta)) =
|
||||||
|
(&mut placed, t)
|
||||||
|
{
|
||||||
let offset = Vector3::new(delta.x, delta.y, delta.z);
|
let offset = Vector3::new(delta.x, delta.y, delta.z);
|
||||||
for root in &mut mleader.context.leader_roots {
|
for root in &mut mleader.context.leader_roots {
|
||||||
for line in &mut root.lines {
|
for line in &mut root.lines {
|
||||||
|
|||||||
+8
-23
@@ -342,7 +342,9 @@ impl Scene {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for &h in handles {
|
for &h in handles {
|
||||||
if self.sync_displayed_annotation_context(h) {
|
let others =
|
||||||
|
crate::scene::annotative::transform_annotation_contexts(&mut self.document, h, t);
|
||||||
|
if self.sync_displayed_annotation_context(h) || others {
|
||||||
self.poison_undo_recording();
|
self.poison_undo_recording();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -649,23 +651,6 @@ impl Scene {
|
|||||||
pub fn copy_entities(&mut self, handles: &[Handle], t: &EntityTransform) -> Vec<Handle> {
|
pub fn copy_entities(&mut self, handles: &[Handle], t: &EntityTransform) -> Vec<Handle> {
|
||||||
let copy_handles = self.handles_expanded_for_leader_annotations(handles);
|
let copy_handles = self.handles_expanded_for_leader_annotations(handles);
|
||||||
|
|
||||||
// LEADER + attached MTEXT are a logical pair. Their entity clones must not
|
|
||||||
// retain the source extension dictionary, otherwise both copies share the
|
|
||||||
// same annotation-context objects.
|
|
||||||
let leader_pair_handles: Vec<Handle> = copy_handles
|
|
||||||
.iter()
|
|
||||||
.flat_map(|&handle| {
|
|
||||||
let annotation = match self.document.get_entity(handle) {
|
|
||||||
Some(EntityType::Leader(leader)) if !leader.annotation_handle.is_null() => {
|
|
||||||
Some(leader.annotation_handle)
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
std::iter::once(handle).chain(annotation)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// Objects on a locked layer can be selected but not copied.
|
// Objects on a locked layer can be selected but not copied.
|
||||||
let clones: Vec<(Handle, EntityType, Vec<Handle>)> = copy_handles
|
let clones: Vec<(Handle, EntityType, Vec<Handle>)> = copy_handles
|
||||||
.iter()
|
.iter()
|
||||||
@@ -673,11 +658,11 @@ impl Scene {
|
|||||||
.filter_map(|&h| {
|
.filter_map(|&h| {
|
||||||
let entity = self.document.get_entity(h)?.clone();
|
let entity = self.document.get_entity(h)?.clone();
|
||||||
|
|
||||||
let annotation_scales = if leader_pair_handles.contains(&h) {
|
// Any annotative entity (not only a LEADER/MTEXT pair) needs
|
||||||
crate::scene::annotative::annotation_scale_handles_for_entity(&self.document, h)
|
// its own context tree; a shared one ties the copy to the
|
||||||
} else {
|
// source. (#700)
|
||||||
Vec::new()
|
let annotation_scales =
|
||||||
};
|
crate::scene::annotative::annotation_scale_handles_for_entity(&self.document, h);
|
||||||
|
|
||||||
Some((h, entity, annotation_scales))
|
Some((h, entity, annotation_scales))
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in new issue
Block a user