collective

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

diff --git a/crates/io/src/dxf_write.rs b/crates/io/src/dxf_write.rs--- a/crates/io/src/dxf_write.rs+++ b/crates/io/src/dxf_write.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");diff --git a/crates/io/tests/it/dwg_roundtrip_losses.rs b/crates/io/tests/it/dwg_roundtrip_losses.rs--- a/crates/io/tests/it/dwg_roundtrip_losses.rs+++ b/crates/io/tests/it/dwg_roundtrip_losses.rs@@ -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.