added printability report when generating texture
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user