first commit
This commit is contained in:
84
docs/media/image/emblem-solver/src/solver/layer/layer.md
Normal file
84
docs/media/image/emblem-solver/src/solver/layer/layer.md
Normal file
@@ -0,0 +1,84 @@
|
||||
# `solver/layer/layer.ts` — multi-strategy per-layer cover
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## 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<number>()
|
||||
);
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { processLayerMultiStrategy } from "@suaveplan/emblem-solver";
|
||||
|
||||
const earlier = new Set<number>();
|
||||
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.
|
||||
Reference in New Issue
Block a user