fix: honor drawing units in annotation and viewport scales
This commit is contained in:
parent
622da9095e
commit
cc7894cd92
4 changed files with 125 additions and 42 deletions
|
|
@ -876,6 +876,28 @@ impl OpenCADStudio {
|
|||
}
|
||||
reframed += 1;
|
||||
}
|
||||
|
||||
// Keep the active model-space annotation scale in sync as well.
|
||||
// annotation_scale is drawing/paper, while CANNOSCALEVALUE stores
|
||||
// the reciprocal paper/drawing factor.
|
||||
if self.tabs[i].scene.annotation_scale.abs() > 1.0e-12 {
|
||||
self.tabs[i].scene.annotation_scale *= factor as f32;
|
||||
}
|
||||
|
||||
if self.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.header
|
||||
.annotation_scale_value
|
||||
.abs()
|
||||
> 1.0e-12
|
||||
{
|
||||
self.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.header
|
||||
.annotation_scale_value /= factor;
|
||||
}
|
||||
// Sizes the drawing keeps as settings rather than as geometry: dash
|
||||
// lengths, default heights and widths, the radii the fillet and chamfer
|
||||
// commands start from. They are all lengths in the unit that just
|
||||
|
|
|
|||
|
|
@ -1720,12 +1720,29 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
|||
Task::none()
|
||||
}
|
||||
|
||||
pub(super) fn on_prop_geom_choice_changed(&mut self, field: &'static str, value: String) -> Task<Message> {
|
||||
let i = self.active_tab;
|
||||
let handles = self.property_target_handles(i);
|
||||
if !handles.is_empty() {
|
||||
self.push_undo_snapshot(i, "CHPROP");
|
||||
if field == "vp_ucs_name" {
|
||||
pub(super) fn on_prop_geom_choice_changed(
|
||||
&mut self,
|
||||
field: &'static str,
|
||||
value: String,
|
||||
) -> Task<Message> {
|
||||
let i = self.active_tab;
|
||||
let handles = self.property_target_handles(i);
|
||||
|
||||
if !handles.is_empty() {
|
||||
self.push_undo_snapshot(i, "CHPROP");
|
||||
|
||||
if field == "vscale_std" {
|
||||
for &handle in &handles {
|
||||
if matches!(
|
||||
self.tabs[i].scene.document.get_entity(handle),
|
||||
Some(acadrust::EntityType::Viewport(_))
|
||||
) {
|
||||
let _ = self.tabs[i]
|
||||
.scene
|
||||
.set_viewport_scale_named_for(handle, &value);
|
||||
}
|
||||
}
|
||||
} else if field == "vp_ucs_name" {
|
||||
// Resolve UCS name → cloned data, then mutate viewports.
|
||||
let ucs_data = self.tabs[i]
|
||||
.scene
|
||||
|
|
|
|||
|
|
@ -24,19 +24,6 @@ const STANDARD_SCALES: &[(&str, f64)] = &[
|
|||
("10:1", 10.0),
|
||||
];
|
||||
|
||||
/// Parse a scale ratio name to its paper/drawing factor: "1:50" -> 0.02,
|
||||
/// "2:1" -> 2.0. Also accepts a plain decimal ("0.02").
|
||||
fn parse_scale_ratio(label: &str) -> Option<f64> {
|
||||
if let Some((a, b)) = label.split_once(':') {
|
||||
let n: f64 = a.trim().parse().ok()?;
|
||||
let d: f64 = b.trim().parse().ok()?;
|
||||
if d.abs() > 1e-12 {
|
||||
return Some(n / d);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
label.trim().parse::<f64>().ok()
|
||||
}
|
||||
|
||||
fn scale_label(scale: f64) -> String {
|
||||
for (label, val) in STANDARD_SCALES {
|
||||
|
|
@ -248,19 +235,6 @@ fn apply_geom_prop(vp: &mut Viewport, field: &str, value: &str) {
|
|||
_ => {}
|
||||
}
|
||||
|
||||
// Scale picker. The label is a ratio name from the drawing's scale list
|
||||
// ("1:50", "2:1"); parse it to the paper/drawing factor so any named
|
||||
// scale resolves, not just the built-in set.
|
||||
if field == "vscale_std" {
|
||||
if let Some(scale) = parse_scale_ratio(value) {
|
||||
vp.custom_scale = scale;
|
||||
if scale > 1e-9 {
|
||||
vp.view_height = vp.height / scale;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Render mode picker.
|
||||
if field == "vp_render" {
|
||||
if let Some(&(_, mode)) = RENDER_MODES.iter().find(|(label, _)| *label == value) {
|
||||
|
|
|
|||
|
|
@ -3584,6 +3584,26 @@ impl Scene {
|
|||
Self::DEFAULT_METRIC_SCALES
|
||||
}
|
||||
}
|
||||
/// Conversion from one drawing unit to the paper unit used by the
|
||||
/// standard annotation-scale family: millimetres for metric drawings
|
||||
/// and inches for imperial drawings.
|
||||
///
|
||||
/// The built-in scale factors are defined assuming model and paper use
|
||||
/// the same base unit. A drawing in metres therefore needs an extra
|
||||
/// factor of 1000 when its paper side is measured in millimetres.
|
||||
fn annotation_scale_unit_factor(&self) -> f64 {
|
||||
let paper_unit = if self.prefers_imperial_scales() == Some(true) {
|
||||
1 // Inches
|
||||
} else {
|
||||
4 // Millimeters
|
||||
};
|
||||
|
||||
crate::modules::draw::units::conversion_factor(
|
||||
self.document.header.insertion_units,
|
||||
paper_unit,
|
||||
)
|
||||
.unwrap_or(1.0)
|
||||
}
|
||||
|
||||
fn is_architectural_scale_name(name: &str) -> bool {
|
||||
name.contains('=') && name.contains('"') && name.contains('\'')
|
||||
|
|
@ -3642,6 +3662,7 @@ impl Scene {
|
|||
}
|
||||
|
||||
pub fn scale_list(&self) -> Vec<(String, f32, f64)> {
|
||||
let unit_factor = self.annotation_scale_unit_factor();
|
||||
let mut list: Vec<(String, f32, f64)> = self
|
||||
.document
|
||||
.objects
|
||||
|
|
@ -3656,7 +3677,11 @@ impl Scene {
|
|||
&& !s.name.contains('|')
|
||||
&& !s.name.to_ascii_uppercase().ends_with("_XREF") =>
|
||||
{
|
||||
Some((s.name.clone(), s.inverse_factor() as f32, s.factor()))
|
||||
Some((
|
||||
s.name.clone(),
|
||||
(s.inverse_factor() / unit_factor) as f32,
|
||||
s.factor() * unit_factor,
|
||||
))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
|
|
@ -3668,10 +3693,14 @@ impl Scene {
|
|||
// annotation / viewport scale picker would be empty and so appear
|
||||
// broken. Substitute the standard ratio set — file scales still
|
||||
// win whenever the drawing actually defines any. (#154)
|
||||
|
||||
list = self
|
||||
.default_scales()
|
||||
.iter()
|
||||
.map(|&(label, vp)| (label.to_string(), (1.0 / vp) as f32, vp))
|
||||
.map(|&(label, base_vp)| {
|
||||
let vp = base_vp * unit_factor;
|
||||
(label.to_string(), (1.0 / vp) as f32, vp)
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
list
|
||||
|
|
@ -3709,10 +3738,15 @@ impl Scene {
|
|||
}
|
||||
});
|
||||
if !has_matching_family {
|
||||
let unit_factor = self.annotation_scale_unit_factor();
|
||||
|
||||
visible.extend(
|
||||
self.default_scales()
|
||||
.iter()
|
||||
.map(|&(label, vp)| (label.to_string(), (1.0 / vp) as f32, vp)),
|
||||
.map(|&(label, base_vp)| {
|
||||
let vp = base_vp * unit_factor;
|
||||
(label.to_string(), (1.0 / vp) as f32, vp)
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -4005,6 +4039,7 @@ impl Scene {
|
|||
return Some(h);
|
||||
}
|
||||
}
|
||||
|
||||
let fallback = self
|
||||
.default_scales()
|
||||
.iter()
|
||||
|
|
@ -4454,9 +4489,13 @@ impl Scene {
|
|||
}
|
||||
|
||||
fn viewport_annotation_multiplier(&self, viewport: Handle) -> f32 {
|
||||
let unit_factor = self.annotation_scale_unit_factor();
|
||||
|
||||
self.viewport_scale_handle(viewport)
|
||||
.and_then(|handle| match self.document.objects.get(&handle) {
|
||||
Some(ObjectType::Scale(scale)) => Some(scale.inverse_factor() as f32),
|
||||
Some(ObjectType::Scale(scale)) => {
|
||||
Some((scale.inverse_factor() / unit_factor) as f32)
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.unwrap_or(self.annotation_scale)
|
||||
|
|
@ -4483,27 +4522,45 @@ impl Scene {
|
|||
}
|
||||
|
||||
pub fn set_viewport_scale_named(&mut self, name: &str) -> Option<Handle> {
|
||||
let viewport = self.explicit_viewport_handle()?;
|
||||
self.set_viewport_scale_named_for(viewport, name)
|
||||
}
|
||||
|
||||
pub fn set_viewport_scale_named_for(
|
||||
&mut self,
|
||||
viewport: Handle,
|
||||
name: &str,
|
||||
) -> Option<Handle> {
|
||||
let scale_handle = self.scale_handle_ensuring(name)?;
|
||||
let unit_factor = self.annotation_scale_unit_factor();
|
||||
|
||||
let factor = match self.document.objects.get(&scale_handle) {
|
||||
Some(ObjectType::Scale(scale)) => scale.factor(),
|
||||
Some(ObjectType::Scale(scale)) => scale.factor() * unit_factor,
|
||||
_ => return None,
|
||||
};
|
||||
let viewport = self.explicit_viewport_handle()?;
|
||||
|
||||
let locked = matches!(
|
||||
self.document.get_entity(viewport),
|
||||
Some(EntityType::Viewport(vp)) if vp.status.locked
|
||||
);
|
||||
|
||||
if locked || factor <= 1.0e-9 {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Some(EntityType::Viewport(vp)) = self.document.get_entity_mut(viewport) {
|
||||
vp.custom_scale = factor;
|
||||
vp.view_height = vp.height / factor;
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.document
|
||||
.set_viewport_annotation_scale(viewport, scale_handle);
|
||||
|
||||
self.resident_wire_sets.borrow_mut().clear();
|
||||
self.bump_geometry();
|
||||
|
||||
Some(scale_handle)
|
||||
}
|
||||
|
||||
|
|
@ -4512,14 +4569,25 @@ impl Scene {
|
|||
let EntityType::Viewport(vp) = self.document.get_entity(viewport)? else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let scale = self.viewport_scale_handle(viewport)?;
|
||||
let ObjectType::Scale(scale) = self.document.objects.get(&scale)? else {
|
||||
return None;
|
||||
};
|
||||
let effective = vp_effective_scale(vp.custom_scale, vp.view_height, vp.height);
|
||||
Some((effective - scale.factor()).abs() <= 1.0e-6 * scale.factor().max(1.0))
|
||||
}
|
||||
|
||||
let effective = vp_effective_scale(
|
||||
vp.custom_scale,
|
||||
vp.view_height,
|
||||
vp.height,
|
||||
);
|
||||
|
||||
let expected = scale.factor() * self.annotation_scale_unit_factor();
|
||||
|
||||
Some(
|
||||
(effective - expected).abs()
|
||||
<= 1.0e-6 * expected.max(1.0),
|
||||
)
|
||||
}
|
||||
pub fn sync_viewport_annotation_scale(&mut self) -> bool {
|
||||
let Some(viewport) = self.explicit_viewport_handle() else {
|
||||
return false;
|
||||
|
|
@ -4527,8 +4595,10 @@ impl Scene {
|
|||
let Some(scale_handle) = self.viewport_scale_handle(viewport) else {
|
||||
return false;
|
||||
};
|
||||
let unit_factor = self.annotation_scale_unit_factor();
|
||||
|
||||
let factor = match self.document.objects.get(&scale_handle) {
|
||||
Some(ObjectType::Scale(scale)) => scale.factor(),
|
||||
Some(ObjectType::Scale(scale)) => scale.factor() * unit_factor,
|
||||
_ => return false,
|
||||
};
|
||||
let Some(EntityType::Viewport(vp)) = self.document.get_entity_mut(viewport) else {
|
||||
|
|
|
|||
Loading…
Reference in a new issue