chore: post-merge cleanup for #287/#289

- Reword the two new explanatory comments to describe the behaviour on its
  own instead of citing another product.
- window_to_sheet: drop the unused window_min parameter (the caller already
  derives its coordinate offset from the returned min-corner position) and fix
  the doc comment to match what the function returns.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hakan Seven 2026-07-06 01:22:10 +03:00
commit b50921923f
4 changed files with 16 additions and 20 deletions

View file

@ -1072,8 +1072,7 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
PlotScale::Fit PlotScale::Fit
} }
}; };
let (scale, ox, oy) = let (scale, ox, oy) = window_to_sheet((win_w, win_h), (sheet_w, sheet_h), scale_sel);
window_to_sheet((win_w, win_h), (x0, y0), (sheet_w, sheet_h), scale_sel);
let scene = &self.tabs[i].scene; let scene = &self.tabs[i].scene;
// Cull to the window so a small-area plot doesn't write the whole // Cull to the window so a small-area plot doesn't write the whole

View file

@ -63,12 +63,12 @@ pub enum PlotScale {
Ratio(f64), Ratio(f64),
} }
/// Map a world-space window onto a sheet. Returns (scale, offset_x, offset_y): /// 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). /// where the scaled window is centered on the sheet and (offset_x, offset_y) is
/// The scaled window is centered on the sheet. /// the sheet-mm position of the window's min corner. The caller turns that into
/// its own coordinate offset.
pub fn window_to_sheet( pub fn window_to_sheet(
window_wh: (f64, f64), window_wh: (f64, f64),
window_min: (f64, f64),
sheet_mm: (f64, f64), sheet_mm: (f64, f64),
scale: PlotScale, scale: PlotScale,
) -> (f64, f64, f64) { ) -> (f64, f64, f64) {
@ -86,7 +86,6 @@ pub fn window_to_sheet(
let scaled_h = wh * scale; let scaled_h = wh * scale;
let offset_x = (sheet_mm.0 - scaled_w) / 2.0; let offset_x = (sheet_mm.0 - scaled_w) / 2.0;
let offset_y = (sheet_mm.1 - scaled_h) / 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) (scale, offset_x, offset_y)
} }
@ -109,7 +108,7 @@ mod tests {
fn fit_centers_and_scales_within_margin() { fn fit_centers_and_scales_within_margin() {
// 100×100 window onto a 210×297 sheet, Fit. Limiting axis is width: // 100×100 window onto a 210×297 sheet, Fit. Limiting axis is width:
// usable = 210/1.05 = 200; scale = 200/100 = 2.0. // 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}"); assert!((s - 2.0).abs() < 1e-9, "scale {s}");
// Window is 100*2 = 200 wide/tall; centered on 210×297. // Window is 100*2 = 200 wide/tall; centered on 210×297.
assert!((ox - (210.0 - 200.0) / 2.0).abs() < 1e-9, "ox {ox}"); assert!((ox - (210.0 - 200.0) / 2.0).abs() < 1e-9, "ox {ox}");
@ -117,12 +116,11 @@ mod tests {
} }
#[test] #[test]
fn ratio_applies_exact_scale_and_offsets_window_min() { fn ratio_applies_exact_scale_and_centers() {
// Ratio(0.5): scale is exactly 0.5; a window starting at (10,20) // Ratio(0.5): scale is exactly 0.5; the scaled window is centered and
// maps its min corner to the offset so (10,20) -> (ox,oy). // (ox, oy) is the sheet-mm position of its min corner.
let (s, ox, oy) = window_to_sheet((100.0, 80.0), (10.0, 20.0), (210.0, 297.0), PlotScale::Ratio(0.5)); 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); 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). // 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!((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}"); assert!((oy - (297.0 - 40.0) / 2.0).abs() < 1e-9, "oy {oy}");

View file

@ -283,10 +283,9 @@ fn build_pdf(
} }
// Line weight: CTB override (in pt) or screen px → points. Divided by // Line weight: CTB override (in pt) or screen px → points. Divided by
// `scale` in both branches so pen widths stay absolute under the // `scale` in both branches so pen widths stay absolute under the scaled
// scaled CTM above (AutoCAD keeps lineweights independent of plot // CTM above — lineweights are independent of plot scale, so without this
// scale) — without this a Fit plot of a large window renders // a Fit plot of a large window renders near-invisible hairlines.
// near-invisible hairlines.
let lw_pt = lw_override let lw_pt = lw_override
.unwrap_or_else(|| (wire.line_weight_px * LW_PX_TO_PT).max(0.1) / scale.max(1e-6)); .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) { if last_lw.map(|l| (l - lw_pt).abs() > 0.01).unwrap_or(true) {

View file

@ -642,9 +642,9 @@ impl Scene {
// both rejects below: its centroid sits at the base point (inside // both rejects below: its centroid sits at the base point (inside
// the consensus cluster), and in a fresh drawing `local_extent_max` // the consensus cluster), and in a fresh drawing `local_extent_max`
// is still the 1e9 default, so the far points pass the `lim` filter // is still the 1e9 default, so the far points pass the `lim` filter
// too (issue #284). Exclude them up front — matching AutoCAD, where // too (issue #284). Exclude them up front — an infinite construction
// infinite lines never contribute to ZOOM Extents — and fall back // line should never contribute to ZOOM Extents — and fall back to their
// to their base points if the drawing holds nothing else. // base points if the drawing holds nothing else.
let mut infinite_base_pts: Vec<glam::Vec3> = Vec::new(); let mut infinite_base_pts: Vec<glam::Vec3> = Vec::new();
wires.retain(|w| { wires.retain(|w| {
let is_infinite = Self::handle_from_wire_name(&w.name) let is_infinite = Self::handle_from_wire_name(&w.name)