first commit
This commit is contained in:
72
docs/media/image/emblem-solver/src/solver/greedy/greedy.md
Normal file
72
docs/media/image/emblem-solver/src/solver/greedy/greedy.md
Normal file
@@ -0,0 +1,72 @@
|
||||
# `solver/greedy/greedy.ts` — deterministic greedy set-cover
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
This module provides the greedy selector that drives the primary covering
|
||||
strategy. `enhancedGreedyCover` picks rectangles from a candidate pool
|
||||
using a deterministic three-key score (covered count, efficiency, centroid
|
||||
proximity). `perIslandCover` runs the same selector independently on each
|
||||
4-connected island so the algorithm never wastes budget on rectangles that
|
||||
span the transparent gap between two disjoint islands.
|
||||
|
||||
## Features
|
||||
|
||||
- Three-key score: `covered * 1000 + efficiency * 100 + proximity * 10`.
|
||||
The factors are deliberately spaced so a more-covering rect always beats
|
||||
a more-efficient one, and ties are broken by centroid proximity.
|
||||
- Falls back to emitting `1×1` rectangles for any residual uncovered
|
||||
pixels — guarantees the cover is complete even when no candidate
|
||||
intersects the residual.
|
||||
- `perIslandCover` filters the candidate pool per island so the selector
|
||||
never considers a spanning rect; this halves selection work on
|
||||
multi-island colours.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import {
|
||||
dualAxisMaximalRects,
|
||||
enhancedGreedyCover,
|
||||
} from "@suaveplan/emblem-solver/solver";
|
||||
|
||||
const candidates = dualAxisMaximalRects(available, rows, cols);
|
||||
const cover = enhancedGreedyCover(candidates, required, cols, rows);
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import {
|
||||
analyseGrid,
|
||||
perIslandCover,
|
||||
dualAxisMaximalRects,
|
||||
} from "@suaveplan/emblem-solver";
|
||||
|
||||
const a = analyseGrid(pixels, w, h);
|
||||
const info = a.colourAnalysis.get("255,0,0")!;
|
||||
const candidates = dualAxisMaximalRects(available, h, w);
|
||||
const cover = perIslandCover(info.islands, candidates, w, h);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
| Symbol | Kind | Description |
|
||||
|---|---|---|
|
||||
| `enhancedGreedyCover(candidates, required, w, h)` | fn | Greedy cover with three-key score |
|
||||
| `perIslandCover(islands, candidates, w, h)` | fn | Independent cover per island |
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The centroid term is computed against the running set of *uncovered*
|
||||
required pixels, not the original set — this keeps selections clustered
|
||||
even as the residual shrinks. We use a precomputed `maxDist =
|
||||
sqrt(w² + h²)` so the proximity term is normalised to `[0, 1]`; without
|
||||
this, the third tiebreaker could dominate the second on large grids.
|
||||
`perIslandCover` materialises a fresh `boolean[][]` per island; this is
|
||||
acceptable because the typical island count is small (≤ 10 on the
|
||||
upstream fixtures) and the allocation cost is dominated by the cover work
|
||||
inside.
|
||||
Reference in New Issue
Block a user