fix(mleader): improve behavior and persistence

Keep annotation contexts, grip placement, and style dictionary entries consistent across editing and file saves.

Refs #779
This commit is contained in:
Hakan Seven committed 2026-08-25 08:34:25 +03:00
commit 20c7a2df58
29 files changed
+858 -195

No files matched your search

+130 -49
View File
@@ -693,29 +693,9 @@ pub fn effective_annotation_scale_for(
return fallback;
}
// Unlike MTEXT / DIMENSION contexts, an MLEADER context carries its
// already-scaled text height and overall scale factor. Keep the text
// height as stored; make `ml.scale_factor * anno_scale` resolve to the
// active context's scale factor for arrows, doglegs, and fallback text.
if let EntityType::MultiLeader(mleader) = entity {
let Some(active) =
active_object_context_for_scale(doc, entity.common().handle, scale_handle)
else {
return fallback;
};
let ObjectContextKind::MLeader(context) = &active.kind else {
return fallback;
};
let base = mleader.scale_factor;
if base.abs() <= 1.0e-12 {
return fallback;
}
let relative = context.scale_factor / base;
return if relative.is_finite() && relative > 0.0 {
relative as f32
} else {
fallback
};
// MLEADER resolves the active-to-stored context ratio while tessellating.
if matches!(entity, EntityType::MultiLeader(_)) {
return fallback;
}
let Some(coll_h) = annotation_scales_dict(doc, entity.common().handle) else {
@@ -1586,47 +1566,149 @@ pub fn apply_mleader_style(
}
}
}
fn apply_mleader_style_at_display_scale(
entity: &mut acadrust::entities::MultiLeader,
style: &acadrust::objects::MultiLeaderStyle,
display_scale: f64,
) {
apply_mleader_style(entity, style);
let scale = if display_scale.is_finite()
&& display_scale > 1.0e-12
{
display_scale
} else {
1.0
};
// Context sizes are stored at their display scale.
entity.context.scale_factor = scale;
entity.context.text_height =
style.text_height * scale;
entity.context.arrowhead_size =
style.arrowhead_size * scale;
entity.context.landing_gap =
style.landing_gap * scale;
for root in &mut entity.context.leader_roots {
root.landing_distance =
style.landing_distance * scale;
root.text_attachment_direction =
entity.text_attachment_direction;
}
}
pub fn apply_mleader_style_to_object(
doc: &mut CadDocument,
handle: Handle,
style: &acadrust::objects::MultiLeaderStyle,
) -> bool {
let Some(EntityType::MultiLeader(original)) = doc.get_entity(handle).cloned() else {
let Some(EntityType::MultiLeader(original)) =
doc.get_entity(handle).cloned()
else {
return false;
};
let base_display_scale = if style.is_annotative {
let scale = original.context.scale_factor;
if scale.is_finite() && scale > 1.0e-12 {
scale
} else {
1.0
}
} else {
let scale = style.scale_factor;
if scale.is_finite() && scale > 1.0e-12 {
scale
} else {
1.0
}
};
let mut styled = original.clone();
apply_mleader_style(&mut styled, style);
if let Some(EntityType::MultiLeader(entity)) = doc.get_entity_mut(handle) {
apply_mleader_style_at_display_scale(
&mut styled,
style,
base_display_scale,
);
if let Some(EntityType::MultiLeader(entity)) =
doc.get_entity_mut(handle)
{
*entity = styled;
}
let leaf_handles: Vec<_> = annotation_scales_dict(doc, handle)
.and_then(|collection| as_dict(doc, collection))
.map(|collection| collection.entries.iter().map(|(_, leaf)| *leaf).collect())
.unwrap_or_default();
let leaf_handles: Vec<_> =
annotation_scales_dict(doc, handle)
.and_then(|collection| as_dict(doc, collection))
.map(|collection| {
collection
.entries
.iter()
.map(|(_, leaf)| *leaf)
.collect()
})
.unwrap_or_default();
for leaf_handle in leaf_handles {
let Some(ObjectType::ObjectContextData(leaf)) = doc.objects.get_mut(&leaf_handle) else {
continue;
};
let ObjectContextKind::MLeader(context) = &mut leaf.kind else {
continue;
};
let context_scale = context.scale_factor;
let text_height_ratio = if original.text_height.abs() > 1.0e-12 {
context.text_height / original.text_height
} else {
1.0
};
let context_before =
match doc.objects.get(&leaf_handle) {
Some(
ObjectType::ObjectContextData(leaf)
) => {
let ObjectContextKind::MLeader(context) =
&leaf.kind
else {
continue;
};
context.clone()
}
_ => continue,
};
let context_scale =
if context_before.scale_factor.is_finite()
&& context_before.scale_factor > 1.0e-12
{
context_before.scale_factor
} else {
base_display_scale
};
let mut per_scale = original.clone();
per_scale.context.clone_from(context);
apply_mleader_style(&mut per_scale, style);
per_scale.context.scale_factor = context_scale;
if style.text_height > 0.0 && text_height_ratio.is_finite() {
per_scale.context.text_height = style.text_height * text_height_ratio;
per_scale.context =
context_before;
apply_mleader_style_at_display_scale(
&mut per_scale,
style,
context_scale,
);
if let Some(
ObjectType::ObjectContextData(leaf)
) = doc.objects.get_mut(&leaf_handle)
{
if let ObjectContextKind::MLeader(context) =
&mut leaf.kind
{
context.clone_from(
&per_scale.context,
);
}
}
context.clone_from(&per_scale.context);
}
true
}
@@ -1773,4 +1855,3 @@ pub fn is_annotative(doc: &CadDocument, entity: &EntityType) -> bool {
}
}