Browse / github.com/storytold/cadcraft / patch
Size the generated sheet viewport by the layout's plot scale
Generated sheet viewport is sized in mm, ignoring the page setup's plot scale Split out of #1463 (see https://github.com/storytold/cadcraft/issues/1463#issuecomment-6384594279), as @ffishman suggested. ## What happens When a layout has no paper-space viewport (id 1), `paper_views()` makes the save add one, and `paper_view()` in `crates/io/src/dxf_write.rs` sizes it with `cadcraft_render::paper::sheet(d, &l.name)`: the page size divided by `page_unit_mm` (1 mm per unit when the page setup says mm, else the drawing's MEASUREMENT). The layout's own plot scale (`PageSetup::scale`, written as groups 142/143 and 147) is not applied. Measured on a ZWCAD 2025 drawing (privat
- Status
- open
- Score
- 0.00
- Adopters
- 0 other operators
- Author
- Silvertree2010 (imported from pull request #2131, open)
- Base
e86d895ba1086a7efc2a83048348f89098282d08- Size
- +37 −0 in 2 files
- Review
- pending
- Shared
- 2026-10-28
- Id
83e92fa34e1d71b4c53c48a9
How it went
No other operator has reported using it yet.
Diff
raw · crates/io/src/dxf_write.rs crates/io/tests/it/dwg_roundtrip_losses.rs
@@ -1701,6 +1701,10 @@ fn sheet_first(l: &Layout) -> Vec<&Entity> { fn paper_view(w: &mut W, d: &Drawing, e: &Entity, owner: &str, cx: &Ctx) { let Some(l) = cx.paper_views.get(&e.handle).and_then(|i| d.layouts.get(*i)) else { return }; let size = cadcraft_render::paper::sheet(d, &l.name).map(|s| s.size).unwrap_or(Vec2::new(12.0, 9.0));+ // A custom plot scale (142/143 paper units per drawing unit) shrinks the sheet in paper+ // space; the same guard as the written scale (#2108).+ let scale = if !l.page.scale_to_fit && l.page.scale.is_finite() && l.page.scale > 0.0 { l.page.scale } else { 1.0 };+ let size = size / scale; let center = size * 0.5; let h = w.h(); w.s(0, "VIEWPORT");@@ -139,6 +139,39 @@ fn viewport_ids_survive_dwg_and_the_paper_viewport_stays_implicit() { assert_eq!(viewport_ids(&cadcraft_io::read_dxf(text.as_bytes()).unwrap().layouts[0]), [1, 2]); } +/// The paper-space viewport the writer adds covers the sheet in paper-space units, so a custom+/// plot scale (142/143, 147) divides the page size; a hostile scale falls back to 1:1 (#2108).+#[test]+fn the_generated_paper_viewport_follows_the_plot_scale() {+ let sheet_of = |scale: f64| {+ let mut d = Drawing::new_metric();+ let page = &mut d.layouts[0].page;+ page.width_mm = 297.0;+ page.height_mm = 420.0;+ page.landscape = true;+ page.paper_mm = true;+ page.scale = scale;+ page.scale_to_fit = false;+ let first = Space::Paper(d.layouts[0].name.clone());+ d.add(&first, Common::default(), viewport(2)).unwrap();+ let text = cadcraft_io::write_dxf(&d);+ let vps = records(&text, "VIEWPORT");+ let sheet = vps.iter().find(|v| group(v, "1000") == Some("PAPERVIEW")).unwrap();+ let f = |c: &str| group(sheet, c).and_then(|v| v.parse::<f64>().ok()).unwrap();+ (f("40"), f("41"), f("10"), f("20"), f("12"), f("22"))+ };+ let close = |a: f64, b: f64| (a - b).abs() < 1e-6;+ let (w, h, cx, cy, vx, vy) = sheet_of(49.6);+ assert!(close(w, 420.0 / 49.6) && close(h, 297.0 / 49.6), "width {w} height {h}");+ assert!(close(cx, w / 2.0) && close(cy, h / 2.0) && close(vx, w / 2.0) && close(vy, h / 2.0));+ let (w, h, ..) = sheet_of(1.0);+ assert!(close(w, 420.0) && close(h, 297.0), "width {w} height {h}");+ for hostile in [f64::NAN, 0.0, -2.0, f64::INFINITY] {+ let (w, h, ..) = sheet_of(hostile);+ assert!(close(w, 420.0) && close(h, 297.0), "scale {hostile}: width {w} height {h}");+ }+}+ /// The paper-space viewport (id 1) of a drawing from another program can come after a model /// viewport in the layout, e.g. when the draw order (SORTENTS) put it behind. DWG numbers in /// order, so the writer puts it first: otherwise the model viewport became the sheet on reopen.