fix(task-17): an inch sheet's fit reports paper units per drawing unit, not the mm ratio times 25.4

`_paper_frame` computed `paper_per_unit = mm_per_unit * unit` where `unit`
is millimetres per paper unit, so an extents+fit plot on an inch sheet
reported `effective_scale: "607.06:1"` for a fit that is `1:1.06276` (off
by 25.4 squared). The render was right (`units_per_mm` is unit-free); only
the label was wrong, and it flowed into `drawing_export_pdf(layout=...)`.
The mm sheet could not see it because there `unit` is 1.

`test_extents_plot_fits_the_printable_area_and_centres` is parametrized
over ISO A3 (mm, width-bound) and ANSI B (inches, height-bound); the ink
position is derived from the centred frame so both cases check the same
invariant. The inch case fails without the fix.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd
This commit is contained in:
Umut CAN
2026-09-21 16:55:05 +03:00
co-authored by Claude Opus 5
parent aeb27c252b
commit 54bbf72312
2 changed files with 52 additions and 13 deletions
+6 -1
View File
@@ -2524,7 +2524,12 @@ class EzdxfBackend(AutoCADBackend):
usable = [r for r in ratios if r is not None]
mm_per_unit = min(usable) if usable else 1.0
units_per_mm = 1.0 / mm_per_unit
paper_per_unit = mm_per_unit * unit
# ``unit`` is millimetres per paper unit (25.4 under inches),
# so paper units per drawing unit *divides* by it. Multiplying
# reported a 1:1.06 inch fit as ``607.06:1`` (off by 25.4^2)
# while the render itself was right, ``units_per_mm`` being
# unit-free; the mm sheet hid it because there ``unit`` is 1.
paper_per_unit = mm_per_unit / unit
effective = (
scale_label(paper_per_unit, 1.0)
if paper_per_unit >= 1.0
+46 -12
View File
@@ -454,29 +454,63 @@ async def test_fit_on_a_layout_plot_is_one_to_one(backend):
assert frame["xlim"][1] - frame["xlim"][0] == pytest.approx(420.0)
async def test_extents_plot_fits_the_printable_area_and_centres(backend, tmp_path):
@pytest.mark.parametrize(
("paper", "paper_units", "sheet_mm", "frame_units"),
[
pytest.param("ISO_A3", "mm", (420.0, 297.0), (800.0, 500.0), id="mm"),
pytest.param("ANSI_B", "inches", (432.0, 279.0), (16.0, 10.0), id="inches"),
],
)
async def test_extents_plot_fits_the_printable_area_and_centres(
backend, tmp_path, paper, paper_units, sheet_mm, frame_units
):
"""extents + fit: the paper-space extents (not the main viewport, which
ezdxf's bbox would count) scale to the printable area and sit centred."""
ezdxf's bbox would count) scale to the printable area and sit centred.
The inch sheet is the label's regression: ``effective_scale`` is paper
units per drawing unit, and 25.4 mm per paper unit *divides* the mm ratio.
Measured before the fix: the ANSI B fit reported ``607.06:1`` for a fit
that is ``1:1.06276`` (off by 25.4 squared) while the ink landed right,
and the mm sheet could not see it because there the unit is 1.
"""
await _sheet(backend)
await backend.page_setup_apply(
SHEET, resolve_page_setup("ISO_A3", scale="fit", plot_area="extents", center=True)
SHEET,
resolve_page_setup(
paper,
"landscape",
scale="fit",
plot_area="extents",
center=True,
paper_units=paper_units,
),
)
lay = backend._doc.layouts.get(SHEET)
lay.add_lwpolyline([(0, 0), (800, 0), (800, 500), (0, 500)], close=True)
top, bottom, left_mm, right_mm = (await backend.page_setup_list(SHEET))[0]["margins_mm"]
printable_w, printable_h = 420.0 - left_mm - right_mm, 297.0 - top - bottom
mm_per_unit = min(printable_w / 800.0, printable_h / 500.0)
sheet_w, sheet_h = sheet_mm
frame_w, frame_h = frame_units
lay.add_lwpolyline([(0, 0), (frame_w, 0), (frame_w, frame_h), (0, frame_h)], close=True)
row = (await backend.page_setup_list(SHEET))[0]
assert row["paper_units"] == paper_units and row["size_mm"] == list(sheet_mm)
top, bottom, left_mm, right_mm = row["margins_mm"]
printable_w, printable_h = sheet_w - left_mm - right_mm, sheet_h - top - bottom
mm_per_unit = min(printable_w / frame_w, printable_h / frame_h)
mm_per_paper_unit = 25.4 if paper_units == "inches" else 1.0
frame = backend._paper_frame(lay)
assert frame["plot_area"] == "extents" and frame["plot_area_applied"] is True
assert frame["scale"] == "fit"
assert frame["xlim"][1] - frame["xlim"][0] == pytest.approx(420.0 / mm_per_unit)
# The axes window is unit-free: the sheet in drawing units.
assert frame["xlim"][1] - frame["xlim"][0] == pytest.approx(sheet_w / mm_per_unit)
result, (first, last, width) = await _export_png(backend, tmp_path, SHEET, "extents")
assert result["effective_scale"] == scale_label(1.0, 1.0 / mm_per_unit)
# The frame is the wider of the two: it spans the printable width exactly.
assert abs(first - int(width * left_mm / 420.0)) <= 3, (first, last, width)
assert abs(last - int(width * (420.0 - right_mm) / 420.0)) <= 3, (first, last, width)
# Paper units per drawing unit, not millimetres per drawing unit.
assert result["effective_scale"] == scale_label(1.0, mm_per_paper_unit / mm_per_unit)
# The frame sits centred in the printable area; the mm case is width-bound
# (it spans the printable width exactly), the inch case is height-bound.
frame_mm = frame_w * mm_per_unit
ink_left_mm = left_mm + (printable_w - frame_mm) / 2.0
assert abs(first - int(width * ink_left_mm / sheet_w)) <= 3, (first, last, width)
assert abs(last - int(width * (ink_left_mm + frame_mm) / sheet_w)) <= 3, (first, last, width)
async def test_extents_plot_at_a_fixed_scale_starts_at_the_plot_origin(backend):