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 @@

What it does

INPUT

NRRD volume loader

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.

VALIDATE

Plane validation

-

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.

RENDER @@ -187,19 +189,19 @@

Quickstart

Benchmarks

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.

+ 31 runs in benchmarks/results-2026-11-07.md. + Machine: Intel i7-4650U (4 cores), Python 3.15.

- - - - - + + + + +
Input (volume × planes)FramesLoad sRender sFPS (load+render)
croissant.nrrd × croissant.csv (canonical, 500³ uint8)1001.0161.27643.6 ✓ NFR-1 hard bar
onion.nrrd × head.csv2800.0610.672382.0
MRHead_1.nrrd × head.csv2800.0860.649381.3
biscuit_cake.nrrd × biscuit_cake.csv1200.0950.336278.3
swiss_roll.nrrd × biscuit_cake.csv1200.2450.381191.8
croissant.nrrd × croissant.csv (canonical, 500³ uint8)1000.8781.11650.1 ✓ NFR-1 hard bar
onion.nrrd × head.csv2800.0500.596433.5
MRHead_1.nrrd × head.csv2800.0870.650380.2
biscuit_cake.nrrd × biscuit_cake.csv1200.0910.339278.6
swiss_roll.nrrd × biscuit_cake.csv1200.1800.343229.3