2.6 KiB
grid/analyse/analyse.ts — colour groups, islands, and shape stats
(no submodules)
Purpose
This module owns analyseGrid, the diagnostic phase of the conversion
pipeline. It walks an RGBA grid once, buckets opaque pixels by colour, runs
a 4-connected flood-fill on each bucket to recover the islands, and
computes per-colour density (pixels / bbox area) and fragmentation
(islands / pixels). The result feeds the layer-ordering heuristics and
the per-island cover strategy in the solver pipeline.
Features
- Single linear pass over the grid to populate
opaquePixelsand the colour buckets. - 4-connected BFS flood-fill — diagonals are treated as separate islands, matching the upstream reference and the convention used by every pixel-art tool.
- Density and fragmentation are pure functions of the bucket and its
bounding box; the solver uses both to score the
island-awareordering. - Output is structurally shared with the rest of the package via
GridAnalysis— solver kernels consumecolourGroups/colourAnalysisdirectly.
Usage: Basic
import { analyseGrid } from "@suaveplan/emblem-solver";
const { colourGroups, colourAnalysis } = analyseGrid(pixels, w, h);
console.log("colours:", colourGroups.size);
Usage: Advanced
import { analyseGrid } from "@suaveplan/emblem-solver";
function pickBackgroundColour(pixels, w, h) {
const a = analyseGrid(pixels, w, h);
let best = "";
let bestScore = -Infinity;
for (const [key, info] of a.colourAnalysis) {
const score = info.totalPixels * info.density;
if (score > bestScore) {
best = key;
bestScore = score;
}
}
return best;
}
API Reference
| Symbol | Kind | Description |
|---|---|---|
analyseGrid(pixels, w, h) |
fn | Returns GridAnalysis |
Implementation Notes
The flood-fill uses an explicit stack (pop()) rather than recursion to
avoid blowing the call stack on large emblems. We add to visited
before enqueueing the neighbour, which guarantees each pixel is touched
at most twice (once when discovered, once when its packed index is popped).
The neighbour set is computed as a small inline array of -1-sentinel
checks for the four cardinal directions; benchmarks against a for (const [dx,dy] …) form showed the inline form measurably faster in V8 and Bun.
The Map<string, Set<number>> colour-group layout is intentional: the
string key is the canonical colour identity, while the packed-index Set
gives O(1) has/add/delete for the cover strategies.