Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ S101_PC ?= $(HOME)/Projects/s101-portrayal-catalogue/PortrayalCatalog
S101_FC ?= $(HOME)/Projects/s101-feature-catalogue/S-101FC/FeatureCatalogue.xml
S101_CACHE ?= $(CACHE)/s101

.PHONY: build xbuild test vet fmt fmt-check tidy clean clear-cache serve docs docs-shots bake-ienc bake-noaa serve-widget demo demo-chart1 serve-demo preslib-chart1 s64-pages
.PHONY: build xbuild test vet fmt fmt-check tidy clean clear-cache serve docs docs-shots bake-ienc bake-noaa serve-widget demo demo-chart1 docs-harness serve-demo preslib-chart1 s64-pages

# Prebaked prod test set (US Inland ENC bundle + the NOAA world archive).
# NB: keep these as bare values with NO inline `#` comments — Make folds any
Expand Down Expand Up @@ -210,6 +210,31 @@ demo-chart1: build ## Bake the S-52 ECDIS Chart 1 sheet to tiles for the docs (i
$(BIN) bake "$(PRESLIB_CACHE)/cells" -o "$(DEMO_CHART1_OUT)/chart1.pmtiles" --bands --max-zoom $(CHART1_MAXZOOM) --manifest "$(DEMO_CHART1_OUT)/charts-index.json"
@echo " chart1 tiles ready: $(DEMO_CHART1_OUT)/ — served beside the demo bundle as /chart1/"

# ---- assets for the docs "Test harness" page (Chart 1 + S-64 review viewer) ----
# Bakes BOTH suites into one merged manifest the page's <chart-plotter> points
# catalog= at, emits the shared widget frontend into /demo/, and crops the IHO
# reference plots the page shows beside our render. All gitignored (large + derived
# from copyrighted PDFs/zips); the page degrades to a build-it hint when absent.
HARNESS_OUT ?= docs/static/harness
HARNESS_ASSETS ?= docs/static/demo
S64_ZIP ?= testdata/S-64_ENC_Unencrypted_TDS.zip

docs-harness: build ## Bake Chart 1 + S-64 tiles + widget assets + reference crops for the docs Test-harness page
# Widget frontend assets (shared with /demo/; additive — won't disturb a full demo bundle).
@mkdir -p "$(HARNESS_ASSETS)"
$(BIN) emit-assets "$(HARNESS_ASSETS)" $(if $(wildcard $(S101_PC)),--s101 "$(S101_PC)")
@cp -R web/src web/vendor web/glyphs web/basemap "$(HARNESS_ASSETS)/"
@cp web/catalog.json "$(HARNESS_ASSETS)/" 2>/dev/null || true
# Chart 1 + S-64 tiles → one merged manifest.
PRESLIB_CACHE="$(PRESLIB_CACHE)" scripts/fetch-preslib-cells.sh
@mkdir -p "$(HARNESS_OUT)"
$(BIN) bake "$(PRESLIB_CACHE)/cells" -o "$(HARNESS_OUT)/chart1.pmtiles" --bands --max-zoom $(CHART1_MAXZOOM) --manifest "$(HARNESS_OUT)/chart1.index.json"
$(BIN) bake "$(S64_ZIP)" -o "$(HARNESS_OUT)/s64.pmtiles" --bands --manifest "$(HARNESS_OUT)/s64.index.json"
node docs/scripts/merge-manifests.mjs "$(HARNESS_OUT)/charts-index.json" "$(HARNESS_OUT)/chart1.index.json" "$(HARNESS_OUT)/s64.index.json"
# Reference-plot crops (needs pdftoppm + the source PDFs; a missing PDF is a warning).
node docs/scripts/extract-refs.mjs
@echo " docs harness ready — run: make docs"

# LOCAL PREVIEW ONLY. The bundle is pure static files — deploy it to ANY
# range-capable static host (GitHub Pages, S3/CloudFront, nginx, `npx serve`); it
# needs no backend. PMTiles are read with HTTP Range, which python's http.server
Expand Down
8 changes: 4 additions & 4 deletions docs/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
# (the read-only widget app + baked Annapolis .pmtiles), never committed.
/static/demo/

# Live "ECDIS Chart 1" tiles — generated by
# `make demo-chart1 DEMO_CHART1_OUT=docs/static/chart1` in CI (the baked S-52
# PresLib reference sheet the symbol-compliance page embeds), never committed.
/static/chart1/
# Test-harness assets — generated by `make docs-harness` (Chart 1 + S-64 baked
# tiles + merged manifest + IHO reference-plot crops the Test-harness page shows).
# Large + derived from copyrighted PDFs/zips, never committed.
/static/harness/

# Misc
.DS_Store
Expand Down
56 changes: 0 additions & 56 deletions docs/docs/chart1.mdx

This file was deleted.

6 changes: 3 additions & 3 deletions docs/docs/intro.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ static binary for any platform with just `GOOS`/`GOARCH`.
over TCP and it draws your own ship and basic AIS targets on the chart; a
`simulate` command generates traffic for testing.
- **Draws the whole symbol set.** It renders the complete S-52 Presentation
Library **[ECDIS Chart 1](./chart1.mdx)** reference sheet — every symbol, line
style, area fill, and colour — drawn by the same pipeline that bakes real NOAA
charts and diffed against the spec's own plots.
Library **[ECDIS Chart 1](./test-harness.mdx)** reference sheet (plus the S-64 ENC
display tests) — every symbol, line style, area fill, and colour — diffed against the
spec's own plots.

## Beyond the chart

Expand Down
55 changes: 55 additions & 0 deletions docs/docs/test-harness.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
id: test-harness
title: Test harness (symbol compliance)
sidebar_position: 5
---

import TestHarness from '@site/src/components/TestHarness';

# ENC symbology review harness

Pick a scenario and see our **live render** — drawn by our S-101 portrayal engine,
scaled to the cell's compilation scale — **beside the official IHO reference plot**. The
per-scenario mariner display settings are shown above our render, so it's an
apples-to-apples diff against the spec's own figures.

<TestHarness />

:::tip
**⤢ Fullscreen** gives you the full three-pane view for serious side-by-side
comparison. **◀ / ▶** (or **↑ / ↓**, or click a row) step through scenarios — both our
render and the reference plot advance together.
:::

## What's in it

Two suites, both rendered chrome-free in the read-only `spec` widget:

- **Chart 1** — the IHO S-52 Presentation Library's reference symbol sheet (ECDIS
"Chart 1"), a single synthetic ENC that exercises **every symbol, line style, area
fill, and text instruction** the portrayal catalogue can produce, laid out in
labelled panels. Each panel maps to a reference plot in the Presentation Library
(Part I §16, doc pages 238–253). The colour-test panels come in **Day** and **Dusk** —
the same tiles, restyled instantly, because colours are stored as S-101 colour
*names*, not fixed RGB.
- **S-64** — the IHO ENC test dataset's cells that have a comparable reference screen
plot: the §3.1 Base / Standard / Other display-category sheets (every object class)
and the §3.2 invalid-object display. The dataset's behavioural/procedural tests
(power-up, overlap, scale-minimum, settings, non-official data) have nothing to diff a
render against, and the §5/6/7 *detection* cases are out of scope — so they're omitted.

## Reproducing it

The harness is the interactive face of a repeatable, headless test. The same scenario
manifest drives the spec-diff PNGs (`make preslib-chart1`, `make s64-pages`). To build
the tiles + reference crops this page needs — with the S-52 PresLib digital-files zip
and the S-64 ENC test-dataset zip in `testdata/` — run:

```bash
make docs-harness # builds Chart 1 + S-64 tiles + widget assets + ref-plot crops into docs/static/
make docs # build / serve the Docusaurus site
```

Until those assets exist, the page shows a short build-it hint in place of the live
widget. The generated tiles and PDF-derived reference crops are git-ignored (large, and
derived from copyrighted source material).
58 changes: 58 additions & 0 deletions docs/scripts/extract-refs.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Extract the official reference-plot pages from the IHO PDFs into per-page JPEGs the
// docs test-harness page (TestHarness.js) shows beside the live render.
//
// node docs/scripts/extract-refs.mjs (run from the repo root)
//
// For every scenario we render a WINDOW of pages around its (best-guess) refPage, so
// the page's ◀/▶ nudge can slide to the exact plot without re-running this. Output →
// docs/static/harness/refs/<pdf>/p<page>.jpg (gitignored, cached: existing pages
// skipped). Needs pdftoppm (poppler). A missing source PDF is a warning, not a failure
// — the chart1 PDF lives in the sibling ../chartplotter-specs repo.
import { execFileSync } from "node:child_process";
import { existsSync, mkdirSync } from "node:fs";
import { SCENARIOS, REF_PDFS } from "../src/components/testharness/scenarios.js";

const OUT = "docs/static/harness/refs";
const WINDOW = 12; // pages on each side of refPage (covers printed-vs-PDF page offsets)
const DPI = 110;

function havePdftoppm() {
try { execFileSync("pdftoppm", ["-v"], { stdio: "ignore" }); return true; }
catch { return false; }
}
if (!havePdftoppm()) {
console.error("extract-refs: pdftoppm (poppler) not found — install it to generate reference crops.");
process.exit(1);
}

const pagesByPdf = new Map();
for (const s of SCENARIOS) {
if (!s.refPage) continue;
const set = pagesByPdf.get(s.pdf) || new Set();
for (let p = Math.max(1, s.refPage - WINDOW); p <= s.refPage + WINDOW; p++) set.add(p);
pagesByPdf.set(s.pdf, set);
}

let wrote = 0, skipped = 0, missing = 0;
for (const [pdf, pages] of pagesByPdf) {
const src = REF_PDFS[pdf];
if (!src || !existsSync(src)) {
console.warn(`extract-refs: ${pdf} PDF not found (${src}) — skipping ${pages.size} page(s).`);
missing += pages.size;
continue;
}
const dir = `${OUT}/${pdf}`;
mkdirSync(dir, { recursive: true });
for (const p of [...pages].sort((a, b) => a - b)) {
const stem = `${dir}/p${p}`;
if (existsSync(`${stem}.jpg`)) { skipped++; continue; }
try {
execFileSync("pdftoppm", ["-jpeg", "-r", String(DPI), "-f", String(p), "-l", String(p), "-singlefile", src, stem], { stdio: "ignore" });
wrote++;
} catch (e) {
console.warn(`extract-refs: failed page ${p} of ${pdf}: ${e.message}`);
}
}
console.log(`extract-refs: ${pdf} → ${dir} (${pages.size} page(s) in window)`);
}
console.log(`extract-refs: wrote ${wrote}, cached ${skipped}, missing-pdf ${missing}.`);
22 changes: 22 additions & 0 deletions docs/scripts/merge-manifests.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Merge several `bake --manifest` charts-index files into one, by concatenating
// their `districts` arrays, so a single <chart-plotter> on the docs test-harness page
// holds both the Chart 1 and S-64 pre-baked band archives at once.
//
// node docs/scripts/merge-manifests.mjs <out.json> <in1.json> <in2.json> …
import { readFileSync, writeFileSync } from "node:fs";

const [out, ...ins] = process.argv.slice(2);
if (!out || !ins.length) {
console.error("usage: merge-manifests.mjs <out.json> <in...>");
process.exit(1);
}
const districts = [];
let aux = "";
for (const f of ins) {
const m = JSON.parse(readFileSync(f, "utf8"));
for (const d of m.districts || []) districts.push(d);
if (m.aux && !aux) aux = m.aux;
}
const merged = aux ? { districts, aux } : { districts };
writeFileSync(out, JSON.stringify(merged, null, 2));
console.log(`merge-manifests: ${districts.length} archive(s) → ${out}`);
2 changes: 1 addition & 1 deletion docs/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const sidebars = {
'intro',
'installation',
'getting-started',
'chart1',
'test-harness',
'widget',
'cli',
'architecture',
Expand Down
Loading