diff --git a/src/app/update/file.rs b/src/app/update/file.rs index 89fd79a98..ca24cba21 100644 --- a/src/app/update/file.rs +++ b/src/app/update/file.rs @@ -1072,8 +1072,7 @@ pub(super) fn on_open_file(&mut self) -> Task { PlotScale::Fit } }; - let (scale, ox, oy) = - window_to_sheet((win_w, win_h), (x0, y0), (sheet_w, sheet_h), scale_sel); + let (scale, ox, oy) = window_to_sheet((win_w, win_h), (sheet_w, sheet_h), scale_sel); let scene = &self.tabs[i].scene; // Cull to the window so a small-area plot doesn't write the whole diff --git a/src/io/paper_sizes.rs b/src/io/paper_sizes.rs index dcc7e8a82..8fcbefde8 100644 --- a/src/io/paper_sizes.rs +++ b/src/io/paper_sizes.rs @@ -63,12 +63,12 @@ pub enum PlotScale { Ratio(f64), } -/// Map a world-space window onto a sheet. Returns (scale, offset_x, offset_y): -/// world (x, y) -> sheet mm ((x - window_min.0) * scale + offset_x, (y - window_min.1) * scale + offset_y). -/// The scaled window is centered on the sheet. +/// Map a world-space window onto a sheet. Returns (scale, offset_x, offset_y), +/// where the scaled window is centered on the sheet and (offset_x, offset_y) is +/// the sheet-mm position of the window's min corner. The caller turns that into +/// its own coordinate offset. pub fn window_to_sheet( window_wh: (f64, f64), - window_min: (f64, f64), sheet_mm: (f64, f64), scale: PlotScale, ) -> (f64, f64, f64) { @@ -86,7 +86,6 @@ pub fn window_to_sheet( let scaled_h = wh * scale; let offset_x = (sheet_mm.0 - scaled_w) / 2.0; let offset_y = (sheet_mm.1 - scaled_h) / 2.0; - let _ = window_min; // offset already places the window min at (offset_x, offset_y) (scale, offset_x, offset_y) } @@ -109,7 +108,7 @@ mod tests { fn fit_centers_and_scales_within_margin() { // 100×100 window onto a 210×297 sheet, Fit. Limiting axis is width: // usable = 210/1.05 = 200; scale = 200/100 = 2.0. - let (s, ox, oy) = window_to_sheet((100.0, 100.0), (0.0, 0.0), (210.0, 297.0), PlotScale::Fit); + let (s, ox, oy) = window_to_sheet((100.0, 100.0), (210.0, 297.0), PlotScale::Fit); assert!((s - 2.0).abs() < 1e-9, "scale {s}"); // Window is 100*2 = 200 wide/tall; centered on 210×297. assert!((ox - (210.0 - 200.0) / 2.0).abs() < 1e-9, "ox {ox}"); @@ -117,12 +116,11 @@ mod tests { } #[test] - fn ratio_applies_exact_scale_and_offsets_window_min() { - // Ratio(0.5): scale is exactly 0.5; a window starting at (10,20) - // maps its min corner to the offset so (10,20) -> (ox,oy). - let (s, ox, oy) = window_to_sheet((100.0, 80.0), (10.0, 20.0), (210.0, 297.0), PlotScale::Ratio(0.5)); + fn ratio_applies_exact_scale_and_centers() { + // Ratio(0.5): scale is exactly 0.5; the scaled window is centered and + // (ox, oy) is the sheet-mm position of its min corner. + let (s, ox, oy) = window_to_sheet((100.0, 80.0), (210.0, 297.0), PlotScale::Ratio(0.5)); assert!((s - 0.5).abs() < 1e-9); - // Centered: sheet_center - scaled_window_center, then min maps to offset. // scaled window = 50×40; centered box origin = ((210-50)/2,(297-40)/2). assert!((ox - (210.0 - 50.0) / 2.0).abs() < 1e-9, "ox {ox}"); assert!((oy - (297.0 - 40.0) / 2.0).abs() < 1e-9, "oy {oy}"); diff --git a/src/io/pdf_export.rs b/src/io/pdf_export.rs index 9fc7def9b..a2df67a39 100644 --- a/src/io/pdf_export.rs +++ b/src/io/pdf_export.rs @@ -283,10 +283,9 @@ fn build_pdf( } // Line weight: CTB override (in pt) or screen px → points. Divided by - // `scale` in both branches so pen widths stay absolute under the - // scaled CTM above (AutoCAD keeps lineweights independent of plot - // scale) — without this a Fit plot of a large window renders - // near-invisible hairlines. + // `scale` in both branches so pen widths stay absolute under the scaled + // CTM above — lineweights are independent of plot scale, so without this + // a Fit plot of a large window renders near-invisible hairlines. let lw_pt = lw_override .unwrap_or_else(|| (wire.line_weight_px * LW_PX_TO_PT).max(0.1) / scale.max(1e-6)); if last_lw.map(|l| (l - lw_pt).abs() > 0.01).unwrap_or(true) { diff --git a/src/scene/camera_ops.rs b/src/scene/camera_ops.rs index c2d24a8b5..9628c8258 100644 --- a/src/scene/camera_ops.rs +++ b/src/scene/camera_ops.rs @@ -642,9 +642,9 @@ impl Scene { // both rejects below: its centroid sits at the base point (inside // the consensus cluster), and in a fresh drawing `local_extent_max` // is still the 1e9 default, so the far points pass the `lim` filter - // too (issue #284). Exclude them up front — matching AutoCAD, where - // infinite lines never contribute to ZOOM Extents — and fall back - // to their base points if the drawing holds nothing else. + // too (issue #284). Exclude them up front — an infinite construction + // line should never contribute to ZOOM Extents — and fall back to their + // base points if the drawing holds nothing else. let mut infinite_base_pts: Vec = Vec::new(); wires.retain(|w| { let is_infinite = Self::handle_from_wire_name(&w.name)