Skip to content

feat: units and geometry - #2

Open
ledif wants to merge 1 commit into
mainfrom
slop/stack-01-units-geometry
Open

feat: units and geometry#2
ledif wants to merge 1 commit into
mainfrom
slop/stack-01-units-geometry

Conversation

@ledif

@ledif ledif commented Aug 27, 2026

Copy link
Copy Markdown
Member

Stack created with GitHub Stacks CLIGive Feedback 💬

@ledif
ledif force-pushed the slop/stack-01-units-geometry branch from c70d20e to 9870661 Compare August 27, 2026 18:52
@ledif
ledif force-pushed the slop/stack-01-units-geometry branch from 9870661 to 6612bb8 Compare August 27, 2026 19:04
Base automatically changed from slop/stack-00-scaffold to main August 27, 2026 19:29
…of a corner

Layer 1 of RFC-005's stack, carrying refactors R1, R2 and R5's half. Two small
modules with no OpenCV dependency, so this layer runs anywhere -- the imaging
half starts at layer 2.

R2 -- the measured constants get one home, and it fixes a live inconsistency.
Three modules each carried their own copy of the card geometry and two of them
disagreed: `detect.CardSpec.aspect` defaulted to 0.5843, which has no provenance
in any document, while `project.DEFAULT_ASPECT` used the calipered 0.583 and
`cli._settings` separately hardcoded 70.0 x 120.0. The consequence was live --
`deckle detect` outside a project gated against a different card than the same
command inside one. `units.py` already owned DEFAULT_DPI on exactly this
reasoning, so DEFAULT_CARD_MM and DEFAULT_ASPECT join it and the copies are
removed as layers 4, 7 and 10 introduce the modules that held them.

Measured on the three padded scans before choosing: cards report aspect 0.5838,
which is 0.0008 from 0.583 and 0.0005 from 0.5843, against a tolerance of 0.010.
Both pass with more than ten times the margin, all three scans detect 4/4 under
either, and the reported geometry is byte-identical -- aspect feeds the gate, not
the fit. So this is a provenance fix, not a behaviour change, and it is worth
saying which it is.

R5 -- DEFAULT_STRATEGY moves here too, which cuts the edge that ran the wrong way
in the import graph: `project.py` imported it from `edges.py` purely so `Config`
could default it, making the state-file module depend on the edge fitter. The
STRATEGIES tuple comes along, because which strategy a scan needs is a fact about
how the scan was taken -- with the foam pad the true edge is a hard 150-248 luma
step, without it there is a shadow ramp in the clearance gap -- and that is rig
description, not fitter internals. Keeping the pair together also makes
"the default is one that exists" testable here rather than at layer 3.

R1 -- `geometry.corners_from_lines()`. `jig._corners_from_walls` and the inline
block in `detect.detect_card` built the identical TL/TR/BR/BL intersection of four
fitted lines. RFC-001 defines a corner as that intersection, because a real corner
is rounded and there is nothing there to observe, so one place should say so. The
winding is documented as a contract rather than an implementation detail: `rectify`
maps the quad onto the output rectangle in that order.

Tests: the corner primitive against a clean rectangle, against the 1.2deg of skew
hand placement produces, and against edge stubs that stop well short of the
corners -- that last one is the property the primitive exists for. Plus the
constants against the calipers, and a check that 0.5789, the deck spec default,
is not what we use.

`just test` 31 passed, `just lint` clean, standalone at this layer.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ledif
ledif force-pushed the slop/stack-01-units-geometry branch from 6612bb8 to 0a1636e Compare August 27, 2026 19:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant