forked from 1b-agent/opencadstudio-upstream
AutoCAD stores a layout's sheet as the plotter driver's canonical media name (`ISO_A4_(210.00_x_297.00_MM)`, `ANSI_full_bleed_B_(11.00_x_17.00_Inches)`), so a drawing saved here has to carry the same spelling for AutoCAD to find the sheet in its DWG To PDF list, and a name that arrives from AutoCAD must resolve to its dimensions and go back out untouched. - New `io::paper_catalog` replaces the eight-entry `paper_sizes`: ISO A/B, ANSI, ARCH (incl. E1) and JIS series with full-bleed / expand variants, Letter / Legal / Tabloid, millimetre and inch units, a parser that reconstructs any well-formed AutoCAD name (custom or driver-specific) from its embedded dimensions, driver / legacy-config aliases (`A4`, `Letter`, `Ledger`), and dimension matching that prefers the plain sheet. - The Plot dialog stores the canonical name and shows the sheet as `ISO A4 (210 × 297 mm)`; a sheet that only exists in the drawing is listed first so it stays selectable. - A sheet the user did not change keeps the drawing's own media name (`paper_name_for_settings`), so a Windows printer's `A4` is not rewritten to `ISO_A4_(…)` just by passing through the dialog. - Drops the unused `PlotFormat` / `PlotOrientation` messages, `paper_label_from_dims`, and three duplicated `match "A4" | …` tables. Tests: catalogue spelling, parser round-trip, aliases, dimension matching, display formatting, plus dialog ↔ layout round-trips for driver-named, catalogue and unknown sheets. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
78 lines
2.6 KiB
Rust
78 lines
2.6 KiB
Rust
//! Small pure helpers split out of `update.rs`.
|
|
|
|
use crate::scene::Scene;
|
|
|
|
/// Parse a scale string like "1:50" or "2:1" into (numerator, denominator).
|
|
/// Returns (1.0, 1.0) for "Fit" or unknown formats.
|
|
/// Sync the model-space annotation scale into its named drawing variable and
|
|
/// numeric header mirror before a save.
|
|
pub(super) fn sync_annotation_scale_header(scene: &mut Scene) {
|
|
let anno = scene.annotation_scale;
|
|
let value = if anno.abs() > 1e-9 {
|
|
1.0 / anno as f64
|
|
} else {
|
|
1.0
|
|
};
|
|
let current = scene.document.header.current_annotation_scale.clone();
|
|
let current_matches = scene.scale_list().into_iter().any(|(name, factor, _)| {
|
|
name.eq_ignore_ascii_case(¤t)
|
|
&& (factor - anno).abs() < 0.001 * anno.max(0.001)
|
|
});
|
|
let name = if current_matches {
|
|
current
|
|
} else {
|
|
scene
|
|
.scale_list()
|
|
.into_iter()
|
|
.find(|(_, factor, _)| (factor - anno).abs() < 0.001 * anno.max(0.001))
|
|
.map(|(name, _, _)| name)
|
|
.unwrap_or_else(|| format_annotation_scale_name(anno))
|
|
};
|
|
let hdr = &mut scene.document.header;
|
|
hdr.current_annotation_scale = name.clone();
|
|
hdr.annotation_scale_value = value;
|
|
crate::io::set_drawing_variable(&mut scene.document, "CANNOSCALE", &name);
|
|
}
|
|
|
|
/// Format an annotation-scale multiplier as a ratio name: 50.0 -> "1:50",
|
|
/// 0.5 -> "2:1", 1.0 -> "1:1".
|
|
fn format_annotation_scale_name(anno: f32) -> String {
|
|
if anno >= 1.0 {
|
|
format!("1:{}", anno.round() as i64)
|
|
} else if anno > 0.0 {
|
|
format!("{}:1", (1.0 / anno).round() as i64)
|
|
} else {
|
|
"1:1".to_string()
|
|
}
|
|
}
|
|
|
|
/// `<none>` / `<previous>` are pseudo-entries, not real page setups.
|
|
pub(super) fn is_special_entry(s: &str) -> bool {
|
|
s == crate::ui::window::plot::SETUP_NONE || s == crate::ui::window::plot::SETUP_PREV
|
|
}
|
|
|
|
/// A page-setup list entry wrapped in `*…*` is a layout (its embedded page
|
|
/// setup), not a standalone named page setup.
|
|
pub(super) fn is_layout_entry(s: &str) -> bool {
|
|
s.len() >= 2 && s.starts_with('*') && s.ends_with('*')
|
|
}
|
|
|
|
/// The layout name inside a `*name*` list entry.
|
|
pub(super) fn layout_entry_name(s: &str) -> &str {
|
|
s.trim_start_matches('*').trim_end_matches('*')
|
|
}
|
|
|
|
pub(super) fn parse_plot_scale(s: &str) -> (f64, f64) {
|
|
if s == "Fit" {
|
|
return (1.0, 1.0);
|
|
}
|
|
if let Some((a, b)) = s.split_once(':') {
|
|
let num: f64 = a.trim().parse().unwrap_or(1.0);
|
|
let den: f64 = b.trim().parse().unwrap_or(1.0);
|
|
if den > 0.0 {
|
|
return (num, den);
|
|
}
|
|
}
|
|
(1.0, 1.0)
|
|
}
|