# `solver/layer/layer.ts` — multi-strategy per-layer cover _(no submodules)_ ## Purpose This module owns `processLayerMultiStrategy`, the function the converter calls once per layer in the current ordering. It runs every covering strategy the package implements (dual-axis histogram + greedy, per-island cover, strip decomposition, adjacent-rect merge) and returns the result with the fewest rectangles. Running every strategy is what makes the upstream algorithm robust — no single strategy wins on every emblem. ## Features - Strategy A (dual-axis histogram → greedy → overlap optimise) is always evaluated; it is the workhorse. - Strategy B (per-island cover) only runs when the colour has more than one island — pure optimisation, since a single-island colour would produce the same answer. - Strategy C (strip decomposition) is only adopted when the strips fully cover the required pixels; the layer pipeline does not stitch in a partial strip cover. - Strategy D (adjacent-rect merge) runs against the best-so-far so we never reject a free merge. - The final winner is the smallest of all four (or three when B is skipped). ## Usage: Basic ```ts import { analyseGrid, processLayerMultiStrategy, } from "@suaveplan/emblem-solver"; const a = analyseGrid(pixels, w, h); const ownPixels = a.colourGroups.get("255,0,0")!; const rects = processLayerMultiStrategy( "255,0,0", ownPixels, a, new Set() ); ``` ## Usage: Advanced ```ts import { processLayerMultiStrategy } from "@suaveplan/emblem-solver"; const earlier = new Set(); for (const key of orderedKeys) { const ownPixels = analysis.colourGroups.get(key)!; const rects = processLayerMultiStrategy( key, ownPixels, analysis, earlier ); layers.push({ key, rects /* ... */ }); for (const p of ownPixels) earlier.add(p); } ``` ## API Reference | Symbol | Kind | Description | |---|---|---| | `processLayerMultiStrategy(key, ownPixels, analysis, earlier)` | fn | Smallest rect cover across all strategies | ## Implementation Notes The strip strategy only contributes when it fully covers the required mask. We compute coverage by intersecting each valid strip with the `required` grid (via `pack`) and comparing the resulting count to a single pre-tallied `totalRequired`. The adjacent-rect merge pass runs *after* the strategies have produced their winners; running it earlier would force a merge on results that would have been pruned anyway. The final reduce uses a strictly-less-than comparison (`a.length <= b.length`) so the first result wins on ties — this preserves deterministic ordering across runs.