96 lines
5.5 KiB
Markdown
96 lines
5.5 KiB
Markdown
# Shop Packet Plan
|
||
|
||
A living plan for turning the BOM into a **shop-packet generator**. Adjust as we go.
|
||
|
||
**Status:** Phases 0–4 implemented (cutplan.py model; multi-strategy auto-layout;
|
||
deterministic instructions + AI polish; rule-based jig suggestions; constrained
|
||
drag-edit layout). Logic is unit-tested; the drag/print GUI needs a real display to
|
||
verify interactively.
|
||
|
||
Review fixes applied: one active CutPlan rendered by every tab; unplaced parts
|
||
surfaced in Shopping; process-stable shuffle (hashlib); kerf-gap validation; drop
|
||
stock-type compatibility; waste/score recompute after manual edits; rotation legality
|
||
(settings/grain); position-aware jig grouping.
|
||
|
||
**Phase 1 now complete:** bounded branch-and-bound exact lumber packing
|
||
(`_min_bins`/`_pack_lumber_exact`, ≤12 pieces, FFD-seeded with a count bound),
|
||
guillotine free-rectangle plywood packing (`_pack_plywood_guillotine`, best-area-fit +
|
||
rotation), a real "Best of 100" control in the Cut Layout tab, and richer scoring that
|
||
prefers more & longer reusable offcuts (`reusable_in` tie-break). Lock-aware
|
||
re-optimization also landed (locked pieces preserved through "Find better layout"/"Best of N").
|
||
|
||
Remaining follow-ups: grain-direction in auto-layout, on-hand offcut inventory,
|
||
opt-in jig material in the BOM.
|
||
|
||
## Guiding principle
|
||
The **math layer is deterministic and inspectable**; AI is used **only for narrative**
|
||
(instruction wording, jig explanations). Cut lengths, kerf, counts, layouts, jig
|
||
dimensions, validation, and warnings all come from code — the AI never invents a number.
|
||
|
||
UI language: say **"Optimize" / "Find better layout"**, never "optimal" (woodworking
|
||
wants explainable good layouts, not slow provably-perfect ones).
|
||
|
||
## Data flow
|
||
```
|
||
Scene → CutItems → StockInventory → CutPlan → ShopPacket(view)
|
||
```
|
||
|
||
## The keystone: `CutPlan` (cutplan.py)
|
||
Dataclasses, JSON-friendly, **stable IDs everywhere** (`CutItem.id`, `StockPiece.id`,
|
||
`Placement.id`) — never rely on list position. Serializable from day one
|
||
(`to_dict`/`from_dict`) so we can save manual layouts, compare strategies, export, debug.
|
||
|
||
- `ShopSettings` — kerf, stick/sheet sizes, offcut-usable thresholds, plywood rotation
|
||
allowed, grain direction (future), tolerances (mortise/tenon clearance, sanding
|
||
allowance, reveal). Defaults present from day one even before they're in the UI.
|
||
- `CutItem` — a required piece (part id, stock, length, width, is_sheet, note e.g. "incl. tenon").
|
||
- `StockPiece` — a physical stick/sheet with its `placements` and `waste` regions.
|
||
- `Placement` — a cut item on a stock piece: position (x[,y]), rotated?, locked?.
|
||
- `WasteRegion` — leftover, with a `reusable` flag (≥ threshold).
|
||
- `CutPlan` — settings, items, stock_pieces, unplaced, strategy, **score**, warnings.
|
||
- `score = {stock_count, waste_area, reusable_offcuts, warnings, strategy_name}` —
|
||
detailed, so the UI can explain *why* one layout beats another.
|
||
- `build_cut_plan(scene, settings=None, strategy="decreasing") -> CutPlan`.
|
||
- `validate_cut_plan(plan) -> [problems]` — no piece outside stock, no overlaps, kerf
|
||
respected, every item placed-or-warned, stock dims respected, rotations legal.
|
||
|
||
`ShopPacket` stays thin (a view/composition over cut rows + shopping rows + cut plan +
|
||
warnings) until `CutPlan` is solid.
|
||
|
||
## Phases (commit after each)
|
||
|
||
**Phase 0 — CutPlan + ShopSettings (keystone).**
|
||
New `cutplan.py` with the model + `build_cut_plan` + `validate_cut_plan`. Port the current
|
||
FFD (lumber) / shelf (plywood) packers behind it. **Keep old APIs** (`layout.nest_lumber/
|
||
nest_plywood/stock_counts/waste_summary`, `cutlist.shopping/waste_summary`) as thin wrappers
|
||
over `build_cut_plan` so existing tests/UI keep working. BOM window renders from `CutPlan`.
|
||
Tests: lumber, plywood, kerf, tenon extra length, unplaced/oversize warnings, JSON roundtrip.
|
||
|
||
**Phase 1 — smart auto-layout.** Strategies behind the buttons: FFD, BFD, bounded exact
|
||
(small jobs, capped), random restarts / best-of-N for big jobs; objective "minimize stock,
|
||
then maximize useful offcuts (bonus for common 12/24/36″)". Plywood: per-panel rotation;
|
||
shelf/guillotine/maxrects; score by sheet count, waste area, reusable-offcut size. Buttons:
|
||
**Optimize · Try Alternative · Best of N**; surface warnings.
|
||
|
||
**Phase 2 — structured instructions.** Deterministic ordered steps from CutPlan + scene
|
||
(buy → cut per plan → mark joinery → repeated cuts/jigs → cut/drill features → dry-fit →
|
||
assemble → finish); **then** AI polishes wording (numbers stay from code). Instructions tab.
|
||
|
||
**Phase 3 — jig suggestions (rule-based → AI explanation).** Detect patterns (identical
|
||
crosscuts, repeated end-offsets, repeated mortises/holes, mirrored L/R, repeated angles,
|
||
repeated panel widths) → candidates with **computed dims** (stop block, spacer, drill
|
||
template, story stick, mortise template, angle sled). AI explains build/use. Jigs are
|
||
**shop aids** kept separate from project parts — optional, opt-in before any jig material
|
||
enters the BOM. Jigs tab.
|
||
|
||
**Phase 4 — constrained manual layout editing.** Drag in the layout view as a *constrained
|
||
planner*: snap to stock edges / kerf / neighbors; invalid = red; move pieces between
|
||
sticks/sheets; rotate plywood (if grain allows); **lock** a piece so re-optimization works
|
||
around it; live "valid / invalid / saves a stick / wastes more" feedback. Builds on
|
||
`CutPlan.locked` + `validate_cut_plan`.
|
||
|
||
## Deterministic vs AI
|
||
| Code (deterministic) | AI (narrative only) |
|
||
|---|---|
|
||
| lengths, kerf, counts, layouts, scores, jig dims, validation, warnings | instruction wording, jig build/use explanations, summaries |
|