added printability report when generating texture

This commit is contained in:
ykcheungab
2026-09-20 12:14:51 +08:00
parent 71c2a29ccb
commit 39caecbfda
9 changed files with 1939 additions and 6 deletions
+90
View File
@@ -209,6 +209,96 @@ default 3280×3200 grid matches the in-app script and is deliberately slow
(pure-Python rasterization) — use smaller `--width/--height/--nx/--ny` for quick
check runs, and the full default grid for the textures you actually ship.
## Inspect printability (advisory)
`orisys-design inspect` measures an **already generated** texture and reports
whether it can be produced. It reads the vector SVG, never runs Blender, and
never gates: a failed constraint is reported but the command still exits 0.
```powershell
orisys-design inspect sensors/finger-xynova/r01
# writes build/textures/<sensor>/<revision>/texture_report.json
```
Millimetres come from the SVG's own declared page (`width`/`height` in mm) and
its `viewBox`, so the numbers describe the artifact that exists. When that page
disagrees with `design.yaml`, the report fills `page_mismatch` with both sizes and
a reason — a texture generated before a page change is not silently accepted.
`design.yaml` carries the thresholds; CLI flags override them:
```yaml
printability:
printer_dpi: 600 # dot pitch = 25.4 / dpi = 0.0423 mm
min_dots: 2 # printer dots across the smallest feature
min_feature_mm: 0.10
min_edge_mm: 0.05
max_sliver_ratio: 4.0
min_patch_area_mm2: 1.0e-4
```
### Report fields
The report (`orisys-sensor-design/texture-report-v2`) keeps only what drives a
decision. Top level: `schema`, `generated_at`, `revision` (repo-relative),
`settings`, `overall`, and `maps[]`. Each map carries:
| Field | Meaning |
|---|---|
| `uv_map`, `file` | which map, and the SVG inspected (`name`, `relative_path`, `sha256`) |
| `page_mm`, `mm_per_px`, `uniform_scale` | physical page and its scale onto the viewBox |
| `raster_dpi` | effective raster resolution; informational, never gates |
| `nominal_cell` | grid cell size in mm and across its shortest side in printer dots |
| `patches` | `total`, `material`, `debris`, `below_dot`, `degenerate`, `nonconvex` |
| `min_width_mm`, `min_edge_mm` | `min`, `p5`, `p50` in mm (`min_width_mm.method` notes the caliper basis) |
| `max_sliver_ratio` | worst longest-edge ÷ minimum-width ratio |
| `coverage` | `patch_area_fraction` of the mesh, and `mesh_polygons` |
| `colours` | `distinct` fills and the closest `min_rgb_distance` between two of them |
| `reference_cross` | arm `thickness_mm` and whether it is `printable` at the configured dots |
| `page_mismatch` | `null`, or `{artifact_mm, declared_mm, reason}` when stale |
| `notes` | situational explanations only |
| `checks`, `verdict` | one entry per constraint: `name`, `required`, `actual`, `passed` |
| `offenders` | worst material patches, then debris examples, each with a locator |
### Locating a reported patch
A patch id is an **emission-order ordinal**, not a stable name: it renumbers
whenever the texture is regenerated, and on its own it says nothing about where
the patch is. `file.sha256` therefore identifies the exact SVG a report
describes, and every offender carries a locator:
```json
{ "kind": "material", "id": "patch-33927", "fill": "#56faa1",
"centroid_px": [2483.924, 1255.508], "centroid_mm": [12.419618, 6.277541],
"min_width_mm": 0.000417, "sliver_ratio": 1208.131, "area_mm2": 0.000105 }
```
Use the id to find the `<polygon>` in the SVG, `centroid_px` to locate it in the
viewBox, `centroid_mm` to place it on the printed page, and `fill` to recognise
it on screen. `--csv` writes the reported offenders; `--csv-all` writes every
material patch with the same columns, which is the practical way to triage
thousands of patches in a spreadsheet or CorelDRAW.
Only the SVG is read, so `file` names the SVG even though the PDF remains the
print master and the PNG the raster preview.
### Reading the checks
Measured feature statistics use **material** patches, those at or above
`min_patch_area_mm2`. Cell clipping emits a long tail of numerically degenerate
slivers (~1% of polygons below one output pixel on the Xynova revision); counting
those as features would make every revision fail. They are not hidden:
`patches.debris`, `patches.below_dot` and the debris entries in `offenders`
report them, and `notes` says how many were excluded.
Checks are **per polygon**. Abutting polygons sharing one fill merge into a single
printed feature, so a cell split by triangle or seam boundaries prints whole even
though each fragment is smaller. Compare `nominal_cell.dots` against
`min_dots` to judge that; per-polygon minima matter for processes that resolve
every object separately, such as cutting or weeding. A failing `min_feature_mm`
alongside a passing `nominal_cell.dots` means the artwork is fragmented, not that
the pattern itself is unprintable.
Collection check:
```powershell