diff --git a/GLOSSARY.md b/GLOSSARY.md index fdfe082..8ad7766 100644 --- a/GLOSSARY.md +++ b/GLOSSARY.md @@ -5,7 +5,7 @@ Seed terms for the plane-projection domain. Refine and expand via `/domain-model ## Terms - **Matrix (`M`)** — the 3D input array of voxels. Dimensions `sx, sy, sz` each satisfy `1 <= s < 2^10`. Stored as `.nrrd` files; values are unsigned 8-, 16-, or 32-bit integers. -- **Voxel (`v`)** — a single element of `M`, i.e. `v = M[x][y][z]`, always an unsigned integer. +- **Voxel (`v`)** — a single element of `M`, i.e. `v = M[x][y][z]`, an integer value: unsigned 8-, 16-, or 32-bit per the brief's contract; signed integer types (e.g. the corpus's `int16` MRHead) are tolerated input per SRS FR-4. - **Plane (`p`)** — a flat geometric target defined by 3 or 4 coordinates. A 3-point plane satisfies `|dist(a,b) - dist(a,c)| < 0.001`; a 4-point plane satisfies the three validity rules in `AGENTS.md`. An invalid plane raises an exception. - **Plane set** — 1+ planes from a `.csv` input file, combined for one output video. - **Projection** — the mapping of `M`'s voxel values onto a plane `p`; the per-plane result is a 2D frame of voxel values. @@ -13,7 +13,7 @@ Seed terms for the plane-projection domain. Refine and expand via `/domain-model - **Closest voxel** — the selection rule: when computing a projection, choose the nearest voxel rather than a more complex sampling solution. - **Frame** — one rendered plane projection; frames are combined into an output video (`.mp4`). - **Error frame** — a black video frame with a red banner in a fixed corner giving the CSV row index and the specific reason a plane could not produce a frame (failed validity rule or degenerate geometry). The video continues with the remaining planes; the same line is logged to the CLI. -- **Canonical space** — voxel-index space: all plane coordinates and lookups live in `M[x][y][z]` array coordinates. World-space header fields (`space origin`, `space directions`) are deliberately unused; see ADR 0002 (to be written). +- **Canonical space** — voxel-index space: all plane coordinates and lookups live in `M[x][y][z]` array coordinates. World-space header fields (`space origin`, `space directions`) are deliberately unused; see [ADR 0002](docs/adr/0002-canonical-voxel-index-space.md). - **Frame** *(refined)* — a 2D image one sample per voxel-length unit: height = leg length in index units (rounded), width = base length (rounded). Apex `a` at top-center, legs running downward to b/c, rows centered on the canvas; no mirroring. - **Canvas** — the fixed video frame size: the maximum frame width and height across all planes in one CSV, all frames padded top-left with black to fit, since one video requires one fixed frame size. - **Sample rule** — closest voxel by half-to-even rounding of the sample point's index coordinates. diff --git a/bench.py b/bench.py index 0ad4a5a..b638236 100644 --- a/bench.py +++ b/bench.py @@ -33,6 +33,7 @@ import numpy import Ex0 +from plane_validation import parse_planes Clock = Callable[[], float] @@ -85,7 +86,7 @@ def timed_pipeline( start = clock() volume = Ex0.load_volume(volume_path) after_load = clock() - records = Ex0.parse_planes(plane_list_path) + records = parse_planes(plane_list_path) rendered = Ex0.render_frames(volume, records) canvas = Ex0.canvas_size(rendered) after_render = clock() diff --git a/docs/images/example-run/croissant-row1.png b/docs/images/example-run/croissant-row1.png new file mode 100644 index 0000000..8f1a3cf Binary files /dev/null and b/docs/images/example-run/croissant-row1.png differ diff --git a/docs/testing-strategy.md b/docs/testing-strategy.md index 87db15f..c7a6d80 100644 --- a/docs/testing-strategy.md +++ b/docs/testing-strategy.md @@ -129,7 +129,7 @@ change to the sampled values shows up immediately, byte-for-byte. - **Real timing.** `tests/test_bench.py` injects a scripted clock. FPS, hardware, drift and the NFR-1 verdict belong to `bench.py` and - [`benchmarks/results-2026-11-06.md`](../benchmarks/results-2026-11-06.md); + [`benchmarks/results-2026-11-07.md`](../benchmarks/results-2026-11-07.md); asserting wall time in the suite would only make it flaky. - **Encoder-exact pixels.** mp4v is lossy, so video tests assert decoded properties (frame count, size, fps, presence/absence of content, black diff --git a/site/index.html b/site/index.html index 35d95b9..26d19cb 100644 --- a/site/index.html +++ b/site/index.html @@ -60,13 +60,15 @@
Reads 8-, 16- and 32-bit unsigned volumes up to 1024³ per axis
- (v = M[x][y][z]), with the geometry cached for fast repeat runs.
v = M[x][y][z]), rendered with a fully vectorized
+ numpy path.
3-point planes must be equidistant from a common origin; 4-point planes must form a - proper rectangle. Invalid specs raise and produce a visible error frame.
+3-point planes must be isosceles (legs equal from the first point); + 4-point planes must be an isosceles trapezoid. Invalid specs raise + and produce a visible error frame.
Min-of-repeats wall time via time.perf_counter(); throughput =
rendered frames ÷ (load + render); encoding reported separately. Full methodology and all
- 31 runs in benchmarks/results-2026-11-06.md.
- Machine: Intel i7-4650U (4 cores), Python 3.12.
| Input (volume × planes) | Frames | Load s | Render s | FPS (load+render) |
|---|---|---|---|---|
| croissant.nrrd × croissant.csv (canonical, 500³ uint8) | 100 | 1.016 | 1.276 | 43.6 ✓ NFR-1 hard bar |
| onion.nrrd × head.csv | 280 | 0.061 | 0.672 | 382.0 |
| MRHead_1.nrrd × head.csv | 280 | 0.086 | 0.649 | 381.3 |
| biscuit_cake.nrrd × biscuit_cake.csv | 120 | 0.095 | 0.336 | 278.3 |
| swiss_roll.nrrd × biscuit_cake.csv | 120 | 0.245 | 0.381 | 191.8 |
| croissant.nrrd × croissant.csv (canonical, 500³ uint8) | 100 | 0.878 | 1.116 | 50.1 ✓ NFR-1 hard bar |
| onion.nrrd × head.csv | 280 | 0.050 | 0.596 | 433.5 |
| MRHead_1.nrrd × head.csv | 280 | 0.087 | 0.650 | 380.2 |
| biscuit_cake.nrrd × biscuit_cake.csv | 120 | 0.091 | 0.339 | 278.6 |
| swiss_roll.nrrd × biscuit_cake.csv | 120 | 0.180 | 0.343 | 229.3 |