fix(paper): derive paper-space unit from plot scale, not a limits heuristic
The previous limits/paper-size ratio heuristic only recognised millimetre (1.0) and inch (1/25.4) paper spaces. Issue #341's layout uses an arbitrary architectural scale (~11.84 mm per paper-space unit), which the snap-to-inch-or-mm logic missed, so the sheet was drawn 11.8x too large and the drawing shrank into the corner. Derive the mm->paper-space factor from the plot scale instead, matching how the DXF format defines the paper-space/paper relationship: page_unit_mm = 25.4 if plot_paper_units==inch else 1.0 mm_per_unit = (scale_numerator / scale_denominator) * page_unit_mm factor = 1 / mm_per_unit (fallback 1.0 when scale is degenerate) The scale and page unit are a matched pair, so this is correct even when the page unit alone looks wrong (an inch page at 1:25.4 is a millimetre paper space). Uses scale_numerator/denominator (codes 142/143), not the scale_factor field (code 147), whose value is unreliable for Scale-To-Fit. Verified against budweiser2018 (inch + mm layouts) and the #341 AEC Bldg Plan Sample (11.84 mm/unit): every sheet now matches its viewport bbox. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
7d68eb0f10
commit
bda79c5967
1 changed files with 25 additions and 31 deletions
|
|
@ -2160,17 +2160,20 @@ impl Scene {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// PlotSettings store the paper size and plot margins in millimetres, but a
|
/// PlotSettings store the paper size and plot margins in millimetres, but a
|
||||||
/// layout's paper space may be laid out in inches — its viewports, drawing
|
/// layout's paper space is laid out in its own units — its viewports,
|
||||||
/// limits and the sheet the user sees are all in inch units. Return the
|
/// drawing limits and the sheet the user sees can be in inches, millimetres,
|
||||||
/// factor that converts those millimetre plot-settings values into the
|
/// or an arbitrary scaled unit. Return the factor that converts those
|
||||||
/// active layout's paper-space units: `1.0` for a millimetre layout,
|
/// millimetre plot-settings values into the active layout's paper-space
|
||||||
/// `1/25.4` for an inch layout.
|
/// units (`1.0` for a millimetre paper space, `1/25.4` for an inch one, and
|
||||||
|
/// anything else for a scaled layout).
|
||||||
///
|
///
|
||||||
/// The unit is inferred from the layout's drawing limits — the only
|
/// The unit is derived from the plot scale, which maps paper-space units to
|
||||||
/// per-layout tie between paper-space coordinates and the physical sheet.
|
/// the physical page: `mm_per_unit = (scale_num / scale_den) × page_unit_mm`
|
||||||
/// `plot_paper_units` (code 72) records the plot *output* unit and can
|
/// where `page_unit_mm` is 25.4 for an inch page (code 72 == 0) or 1 for a
|
||||||
/// disagree with the paper-space geometry (a layout can carry inch output
|
/// millimetre page. The scale and the page unit are a matched pair, so this
|
||||||
/// units over a millimetre paper space and vice-versa), so it is not used.
|
/// is correct even when the page unit alone looks wrong (an inch page at
|
||||||
|
/// scale 1:25.4 is a millimetre paper space). Falls back to `1.0` when the
|
||||||
|
/// scale is missing or degenerate.
|
||||||
pub fn paper_space_unit_factor(&self) -> f64 {
|
pub fn paper_space_unit_factor(&self) -> f64 {
|
||||||
if self.current_layout == "Model" {
|
if self.current_layout == "Model" {
|
||||||
return 1.0;
|
return 1.0;
|
||||||
|
|
@ -2190,28 +2193,19 @@ impl Scene {
|
||||||
/// Millimetre → paper-space-unit factor for a specific layout (see
|
/// Millimetre → paper-space-unit factor for a specific layout (see
|
||||||
/// [`Scene::paper_space_unit_factor`]).
|
/// [`Scene::paper_space_unit_factor`]).
|
||||||
fn layout_unit_factor(l: &acadrust::objects::Layout) -> f64 {
|
fn layout_unit_factor(l: &acadrust::objects::Layout) -> f64 {
|
||||||
if l.paper_width <= 1e-6 || l.paper_height <= 1e-6 {
|
// Millimetres represented by one plotted page unit: an inch page
|
||||||
return 1.0;
|
// (plot_paper_units == 0) is 25.4 mm, a millimetre page is 1 mm.
|
||||||
}
|
let page_unit_mm = if l.plot_paper_units == 0 { 25.4 } else { 1.0 };
|
||||||
// Match the rotation swap `paper_limits` applies so the span/paper axes
|
let (num, den) = (l.plot_scale_numerator, l.plot_scale_denominator);
|
||||||
// line up.
|
if num > 1e-12 && den > 1e-12 {
|
||||||
let (pw, ph) = if l.plot_rotation == 1 || l.plot_rotation == 3 {
|
// One paper-space unit spans this many millimetres on the page.
|
||||||
(l.paper_height, l.paper_width)
|
let mm_per_unit = (num / den) * page_unit_mm;
|
||||||
} else {
|
if mm_per_unit > 1e-9 {
|
||||||
(l.paper_width, l.paper_height)
|
return 1.0 / mm_per_unit;
|
||||||
};
|
}
|
||||||
let span_w = (l.max_limits.0 - l.min_limits.0).abs();
|
|
||||||
let span_h = (l.max_limits.1 - l.min_limits.1).abs();
|
|
||||||
// The paper-space span ≈ physical_mm × factor. Solve factor = span / mm
|
|
||||||
// on whichever axis carries a usable span, then snap to inch when it
|
|
||||||
// lands near 1/25.4; otherwise treat the layout as millimetre (default).
|
|
||||||
let ratio = [(span_w, pw), (span_h, ph)]
|
|
||||||
.into_iter()
|
|
||||||
.find_map(|(s, p)| (s > 1e-6 && p > 1e-6).then_some(s / p));
|
|
||||||
match ratio {
|
|
||||||
Some(r) if (r - 1.0 / 25.4).abs() < 0.15 / 25.4 => 1.0 / 25.4,
|
|
||||||
_ => 1.0,
|
|
||||||
}
|
}
|
||||||
|
// No usable plot scale — assume the paper space is already millimetres.
|
||||||
|
1.0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn paper_limits(&self) -> Option<((f64, f64), (f64, f64))> {
|
pub fn paper_limits(&self) -> Option<((f64, f64), (f64, f64))> {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue