digital-boardgame-framework 0.8.2 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/geo.d.ts +150 -0
- package/dist/core/geo.d.ts.map +1 -0
- package/dist/core/geo.js +419 -0
- package/dist/core/geo.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
export interface Point {
|
|
2
|
+
x: number;
|
|
3
|
+
y: number;
|
|
4
|
+
}
|
|
5
|
+
/** A simple closed ring. First point need not repeat the last. */
|
|
6
|
+
export type Polygon = Point[];
|
|
7
|
+
export interface BBox {
|
|
8
|
+
minX: number;
|
|
9
|
+
minY: number;
|
|
10
|
+
maxX: number;
|
|
11
|
+
maxY: number;
|
|
12
|
+
}
|
|
13
|
+
export declare function boundingBox(polygon: Polygon): BBox;
|
|
14
|
+
/** Signed area (shoelace). Positive for counter-clockwise rings. */
|
|
15
|
+
export declare function signedArea(polygon: Polygon): number;
|
|
16
|
+
export declare function area(polygon: Polygon): number;
|
|
17
|
+
/** Area-weighted polygon centroid. NOTE: for a concave shape this can fall
|
|
18
|
+
* outside the polygon — do not use it to anchor tokens. Use
|
|
19
|
+
* poleOfInaccessibility instead. Kept for comparison / degenerate fallback. */
|
|
20
|
+
export declare function centroid(polygon: Polygon): Point;
|
|
21
|
+
export declare function pointInPolygon(point: Point, polygon: Polygon): boolean;
|
|
22
|
+
/** Signed distance from a point to the polygon boundary: positive inside,
|
|
23
|
+
* negative outside, magnitude = distance to the nearest edge. */
|
|
24
|
+
export declare function signedDistanceToPolygon(point: Point, polygon: Polygon): number;
|
|
25
|
+
export interface PoleResult {
|
|
26
|
+
/** The anchor point. */
|
|
27
|
+
point: Point;
|
|
28
|
+
/** Radius of the largest circle centred at `point` that fits inside the
|
|
29
|
+
* polygon — the natural size budget for a token stack before it bleeds. */
|
|
30
|
+
clearance: number;
|
|
31
|
+
}
|
|
32
|
+
/** The interior point farthest from any edge — the "visual centre" used for map
|
|
33
|
+
* labels — together with its clearance (the largest inscribed-circle radius at
|
|
34
|
+
* that point). Always inside the polygon (for a valid simple polygon) and in
|
|
35
|
+
* its thickest part. This is the correct anchor for a token cluster.
|
|
36
|
+
*
|
|
37
|
+
* `precision` is in COORDINATE UNITS: smaller = more accurate, slower. The
|
|
38
|
+
* default 1.0 assumes pixel-scale coordinates (≈ one pixel). For normalized
|
|
39
|
+
* 0..1 polygons, 1.0 is larger than the whole shape and the search won't
|
|
40
|
+
* subdivide — pass ~1e-3 instead. */
|
|
41
|
+
export declare function poleOfInaccessibilityWithClearance(polygon: Polygon, precision?: number): PoleResult;
|
|
42
|
+
/** The anchor point only. See poleOfInaccessibilityWithClearance for the
|
|
43
|
+
* clearance radius (and the `precision` note — for normalized 0..1 coordinates
|
|
44
|
+
* pass ~1e-3, not the pixel-scale default of 1.0). */
|
|
45
|
+
export declare function poleOfInaccessibility(polygon: Polygon, precision?: number): Point;
|
|
46
|
+
export interface LayoutOptions {
|
|
47
|
+
/** Radius of one token, in coordinate units. */
|
|
48
|
+
tokenRadius: number;
|
|
49
|
+
/** Extra spacing between adjacent tokens (default tokenRadius * 0.3). */
|
|
50
|
+
gap?: number;
|
|
51
|
+
/** Smallest scale to shrink the cluster to before collapsing to a stack
|
|
52
|
+
* (default 0.4). */
|
|
53
|
+
minScale?: number;
|
|
54
|
+
/** Precision passed to poleOfInaccessibility (default 1.0). For normalized
|
|
55
|
+
* 0..1 coordinates pass ~1e-3, not the pixel-scale default. */
|
|
56
|
+
precision?: number;
|
|
57
|
+
/** Precomputed anchor — skip the pole-of-inaccessibility pass. Board geometry
|
|
58
|
+
* is static, so a renderer can compute the anchor once per region and pass it
|
|
59
|
+
* on every re-layout instead of recomputing it each frame. */
|
|
60
|
+
anchor?: Point;
|
|
61
|
+
}
|
|
62
|
+
export interface TokenLayout {
|
|
63
|
+
/** The polygon's visual centre — the cluster anchor / stack location. */
|
|
64
|
+
anchor: Point;
|
|
65
|
+
/** One point per token, all inside the polygon. When `stacked` is true this
|
|
66
|
+
* holds a single point (the anchor) and the renderer should draw a pile. */
|
|
67
|
+
points: Point[];
|
|
68
|
+
/** Scale applied to fit the cluster (1 = full size, smaller = shrunk). */
|
|
69
|
+
scale: number;
|
|
70
|
+
/** True when the cluster couldn't fit even at minScale — render a single
|
|
71
|
+
* anchored pile with a count badge instead of N separate tokens. */
|
|
72
|
+
stacked: boolean;
|
|
73
|
+
}
|
|
74
|
+
/** Lay out `count` tokens inside `polygon`, clustered at its visual centre and
|
|
75
|
+
* kept within the boundary. Shrinks the cluster to fit; if even the shrunk
|
|
76
|
+
* cluster won't fit, returns a single anchored point with `stacked: true` so
|
|
77
|
+
* the renderer can draw a pile + count badge. Deterministic. */
|
|
78
|
+
export declare function layoutTokensInPolygon(polygon: Polygon, count: number, opts: LayoutOptions): TokenLayout;
|
|
79
|
+
export declare function toPolygon(pairs: ReadonlyArray<readonly [number, number]>): Polygon;
|
|
80
|
+
export declare function fromPolygon(polygon: Polygon): [number, number][];
|
|
81
|
+
export declare function distance(a: Point, b: Point): number;
|
|
82
|
+
export interface AuditEntry {
|
|
83
|
+
id: string;
|
|
84
|
+
polygon: Polygon;
|
|
85
|
+
count: number;
|
|
86
|
+
}
|
|
87
|
+
export interface AuditResult {
|
|
88
|
+
regions: number;
|
|
89
|
+
/** Region ids whose anchor fell outside the polygon (should be empty). */
|
|
90
|
+
anchorsOutside: string[];
|
|
91
|
+
/** Total tokens placed outside their polygon (should be 0). */
|
|
92
|
+
tokenBleed: number;
|
|
93
|
+
/** Region ids that collapsed to a stacked pile. */
|
|
94
|
+
stackedPiles: string[];
|
|
95
|
+
/** Smallest anchor clearance across all regions. */
|
|
96
|
+
minClearance: number;
|
|
97
|
+
/** Region id with the smallest clearance. */
|
|
98
|
+
tightestRegion: string | null;
|
|
99
|
+
}
|
|
100
|
+
/** Headless verification of a whole map's token layout — the CI-able core of the
|
|
101
|
+
* per-game audit overlay (the visual page stays per-game; this is the math it
|
|
102
|
+
* and CI both call). Lays out each region and checks containment. */
|
|
103
|
+
export declare function auditLayout(entries: AuditEntry[], opts: LayoutOptions): AuditResult;
|
|
104
|
+
/** Approximate intersection-over-union of two polygons via grid sampling over
|
|
105
|
+
* the combined bounding box. Robust to concavity (no polygon clipping).
|
|
106
|
+
* `samples` is the grid resolution per axis (default 64 → 4096 test points).
|
|
107
|
+
* Deterministic. */
|
|
108
|
+
export declare function polygonIoU(a: Polygon, b: Polygon, samples?: number): number;
|
|
109
|
+
export type Edge = [string, string];
|
|
110
|
+
/** Undirected adjacency derived from polygon geometry: two regions are adjacent
|
|
111
|
+
* when their boundaries come within `tolerance`. Rough/hand-traced polygons
|
|
112
|
+
* rarely share exact edges, so a tolerance is required. O(n²) with a bbox
|
|
113
|
+
* pre-filter — fine for a few hundred regions run occasionally (validation, not
|
|
114
|
+
* a hot path). Returns sorted, de-duplicated, normalized edges. */
|
|
115
|
+
export declare function adjacencyFromPolygons(polygons: Record<string, Polygon>, tolerance: number): Edge[];
|
|
116
|
+
export interface AdjacencyDiff {
|
|
117
|
+
shared: Edge[];
|
|
118
|
+
/** Edges in A but not B. */
|
|
119
|
+
onlyA: Edge[];
|
|
120
|
+
/** Edges in B but not A. */
|
|
121
|
+
onlyB: Edge[];
|
|
122
|
+
}
|
|
123
|
+
/** Set-diff two undirected edge lists (edge endpoint order is normalized). Use
|
|
124
|
+
* to compare polygon-derived adjacency against the engine's known adjacency —
|
|
125
|
+
* the strongest, roughness-immune validation signal. */
|
|
126
|
+
export declare function diffAdjacency(a: Edge[], b: Edge[]): AdjacencyDiff;
|
|
127
|
+
export interface RegionMatch {
|
|
128
|
+
a: string;
|
|
129
|
+
b: string;
|
|
130
|
+
iou: number;
|
|
131
|
+
anchorDistance: number;
|
|
132
|
+
}
|
|
133
|
+
export interface RegionMatchResult {
|
|
134
|
+
matches: RegionMatch[];
|
|
135
|
+
/** Region ids in A with no B match above minIoU (a split, or missing in B). */
|
|
136
|
+
unmatchedA: string[];
|
|
137
|
+
/** Region ids in B never matched (a merge, or extra in B). */
|
|
138
|
+
unmatchedB: string[];
|
|
139
|
+
}
|
|
140
|
+
/** Match two named polygon sets (e.g. extracted vs a human reference) by best
|
|
141
|
+
* IoU. The roughness-tolerant comparison: use it to confirm a 1:1 region
|
|
142
|
+
* correspondence and flag merges/splits — NOT to score vertex precision. Greedy
|
|
143
|
+
* per A-region. `minIoU` is the matching threshold (default 0.5); keep it low,
|
|
144
|
+
* because a rough reference legitimately overlaps a precise extraction at well
|
|
145
|
+
* under 1.0. */
|
|
146
|
+
export declare function matchRegions(a: Record<string, Polygon>, b: Record<string, Polygon>, opts?: {
|
|
147
|
+
minIoU?: number;
|
|
148
|
+
samples?: number;
|
|
149
|
+
}): RegionMatchResult;
|
|
150
|
+
//# sourceMappingURL=geo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geo.d.ts","sourceRoot":"","sources":["../../src/core/geo.ts"],"names":[],"mappings":"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"}
|
package/dist/core/geo.js
ADDED
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
// Pure 2D polygon geometry for map games — no DOM, no rendering. Territory
|
|
2
|
+
// polygons live per-game (the data); this module is the shared math that turns a
|
|
3
|
+
// polygon + a token count into where the tokens go, anchored at the polygon's
|
|
4
|
+
// visual centre and kept inside its boundary.
|
|
5
|
+
//
|
|
6
|
+
// Coordinates are in whatever space the caller uses (typically pixels in the map
|
|
7
|
+
// image). Everything here is deterministic — no RNG — so the same state always
|
|
8
|
+
// lays out identically. See docs/territory-polygons-design.md.
|
|
9
|
+
export function boundingBox(polygon) {
|
|
10
|
+
if (polygon.length === 0)
|
|
11
|
+
throw new Error('boundingBox: empty polygon');
|
|
12
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
13
|
+
for (const p of polygon) {
|
|
14
|
+
if (p.x < minX)
|
|
15
|
+
minX = p.x;
|
|
16
|
+
if (p.y < minY)
|
|
17
|
+
minY = p.y;
|
|
18
|
+
if (p.x > maxX)
|
|
19
|
+
maxX = p.x;
|
|
20
|
+
if (p.y > maxY)
|
|
21
|
+
maxY = p.y;
|
|
22
|
+
}
|
|
23
|
+
return { minX, minY, maxX, maxY };
|
|
24
|
+
}
|
|
25
|
+
/** Signed area (shoelace). Positive for counter-clockwise rings. */
|
|
26
|
+
export function signedArea(polygon) {
|
|
27
|
+
let sum = 0;
|
|
28
|
+
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
|
|
29
|
+
sum += (polygon[j].x + polygon[i].x) * (polygon[j].y - polygon[i].y);
|
|
30
|
+
}
|
|
31
|
+
return sum / 2;
|
|
32
|
+
}
|
|
33
|
+
export function area(polygon) {
|
|
34
|
+
return Math.abs(signedArea(polygon));
|
|
35
|
+
}
|
|
36
|
+
/** Area-weighted polygon centroid. NOTE: for a concave shape this can fall
|
|
37
|
+
* outside the polygon — do not use it to anchor tokens. Use
|
|
38
|
+
* poleOfInaccessibility instead. Kept for comparison / degenerate fallback. */
|
|
39
|
+
export function centroid(polygon) {
|
|
40
|
+
let cx = 0, cy = 0, a = 0;
|
|
41
|
+
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
|
|
42
|
+
const cross = polygon[j].x * polygon[i].y - polygon[i].x * polygon[j].y;
|
|
43
|
+
cx += (polygon[j].x + polygon[i].x) * cross;
|
|
44
|
+
cy += (polygon[j].y + polygon[i].y) * cross;
|
|
45
|
+
a += cross;
|
|
46
|
+
}
|
|
47
|
+
if (a === 0) {
|
|
48
|
+
// Degenerate (zero area): fall back to the mean of vertices.
|
|
49
|
+
const n = polygon.length;
|
|
50
|
+
return {
|
|
51
|
+
x: polygon.reduce((s, p) => s + p.x, 0) / n,
|
|
52
|
+
y: polygon.reduce((s, p) => s + p.y, 0) / n,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
a *= 3;
|
|
56
|
+
return { x: cx / a, y: cy / a };
|
|
57
|
+
}
|
|
58
|
+
export function pointInPolygon(point, polygon) {
|
|
59
|
+
let inside = false;
|
|
60
|
+
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
|
|
61
|
+
const a = polygon[i], b = polygon[j];
|
|
62
|
+
if ((a.y > point.y) !== (b.y > point.y) &&
|
|
63
|
+
point.x < ((b.x - a.x) * (point.y - a.y)) / (b.y - a.y) + a.x) {
|
|
64
|
+
inside = !inside;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return inside;
|
|
68
|
+
}
|
|
69
|
+
function segmentDistSq(p, a, b) {
|
|
70
|
+
let x = a.x, y = a.y;
|
|
71
|
+
let dx = b.x - x, dy = b.y - y;
|
|
72
|
+
if (dx !== 0 || dy !== 0) {
|
|
73
|
+
const t = ((p.x - x) * dx + (p.y - y) * dy) / (dx * dx + dy * dy);
|
|
74
|
+
if (t > 1) {
|
|
75
|
+
x = b.x;
|
|
76
|
+
y = b.y;
|
|
77
|
+
}
|
|
78
|
+
else if (t > 0) {
|
|
79
|
+
x += dx * t;
|
|
80
|
+
y += dy * t;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
dx = p.x - x;
|
|
84
|
+
dy = p.y - y;
|
|
85
|
+
return dx * dx + dy * dy;
|
|
86
|
+
}
|
|
87
|
+
/** Signed distance from a point to the polygon boundary: positive inside,
|
|
88
|
+
* negative outside, magnitude = distance to the nearest edge. */
|
|
89
|
+
export function signedDistanceToPolygon(point, polygon) {
|
|
90
|
+
let minSq = Infinity;
|
|
91
|
+
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
|
|
92
|
+
minSq = Math.min(minSq, segmentDistSq(point, polygon[i], polygon[j]));
|
|
93
|
+
}
|
|
94
|
+
const dist = Math.sqrt(minSq);
|
|
95
|
+
return pointInPolygon(point, polygon) ? dist : -dist;
|
|
96
|
+
}
|
|
97
|
+
function makeCell(x, y, h, polygon) {
|
|
98
|
+
const d = signedDistanceToPolygon({ x, y }, polygon);
|
|
99
|
+
return { x, y, h, d, max: d + h * Math.SQRT2 };
|
|
100
|
+
}
|
|
101
|
+
// Binary max-heap keyed on cell.max.
|
|
102
|
+
class CellHeap {
|
|
103
|
+
items = [];
|
|
104
|
+
get size() { return this.items.length; }
|
|
105
|
+
push(c) {
|
|
106
|
+
const a = this.items;
|
|
107
|
+
a.push(c);
|
|
108
|
+
let i = a.length - 1;
|
|
109
|
+
while (i > 0) {
|
|
110
|
+
const parent = (i - 1) >> 1;
|
|
111
|
+
if (a[parent].max >= a[i].max)
|
|
112
|
+
break;
|
|
113
|
+
[a[parent], a[i]] = [a[i], a[parent]];
|
|
114
|
+
i = parent;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
pop() {
|
|
118
|
+
const a = this.items;
|
|
119
|
+
const top = a[0];
|
|
120
|
+
const last = a.pop();
|
|
121
|
+
if (a.length > 0) {
|
|
122
|
+
a[0] = last;
|
|
123
|
+
let i = 0;
|
|
124
|
+
for (;;) {
|
|
125
|
+
const l = 2 * i + 1, r = 2 * i + 2;
|
|
126
|
+
let largest = i;
|
|
127
|
+
if (l < a.length && a[l].max > a[largest].max)
|
|
128
|
+
largest = l;
|
|
129
|
+
if (r < a.length && a[r].max > a[largest].max)
|
|
130
|
+
largest = r;
|
|
131
|
+
if (largest === i)
|
|
132
|
+
break;
|
|
133
|
+
[a[largest], a[i]] = [a[i], a[largest]];
|
|
134
|
+
i = largest;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return top;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/** The interior point farthest from any edge — the "visual centre" used for map
|
|
141
|
+
* labels — together with its clearance (the largest inscribed-circle radius at
|
|
142
|
+
* that point). Always inside the polygon (for a valid simple polygon) and in
|
|
143
|
+
* its thickest part. This is the correct anchor for a token cluster.
|
|
144
|
+
*
|
|
145
|
+
* `precision` is in COORDINATE UNITS: smaller = more accurate, slower. The
|
|
146
|
+
* default 1.0 assumes pixel-scale coordinates (≈ one pixel). For normalized
|
|
147
|
+
* 0..1 polygons, 1.0 is larger than the whole shape and the search won't
|
|
148
|
+
* subdivide — pass ~1e-3 instead. */
|
|
149
|
+
export function poleOfInaccessibilityWithClearance(polygon, precision = 1.0) {
|
|
150
|
+
const bb = boundingBox(polygon);
|
|
151
|
+
const width = bb.maxX - bb.minX;
|
|
152
|
+
const height = bb.maxY - bb.minY;
|
|
153
|
+
const cellSize = Math.min(width, height);
|
|
154
|
+
if (cellSize === 0)
|
|
155
|
+
return { point: { x: bb.minX, y: bb.minY }, clearance: 0 };
|
|
156
|
+
const heap = new CellHeap();
|
|
157
|
+
const h0 = cellSize / 2;
|
|
158
|
+
for (let x = bb.minX; x < bb.maxX; x += cellSize) {
|
|
159
|
+
for (let y = bb.minY; y < bb.maxY; y += cellSize) {
|
|
160
|
+
heap.push(makeCell(x + h0, y + h0, h0, polygon));
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// Seed best with the centroid and the bbox centre.
|
|
164
|
+
const c = centroid(polygon);
|
|
165
|
+
let best = makeCell(c.x, c.y, 0, polygon);
|
|
166
|
+
const bboxCell = makeCell(bb.minX + width / 2, bb.minY + height / 2, 0, polygon);
|
|
167
|
+
if (bboxCell.d > best.d)
|
|
168
|
+
best = bboxCell;
|
|
169
|
+
while (heap.size > 0) {
|
|
170
|
+
const cell = heap.pop();
|
|
171
|
+
if (cell.d > best.d)
|
|
172
|
+
best = cell;
|
|
173
|
+
if (cell.max - best.d <= precision)
|
|
174
|
+
continue;
|
|
175
|
+
const h = cell.h / 2;
|
|
176
|
+
heap.push(makeCell(cell.x - h, cell.y - h, h, polygon));
|
|
177
|
+
heap.push(makeCell(cell.x + h, cell.y - h, h, polygon));
|
|
178
|
+
heap.push(makeCell(cell.x - h, cell.y + h, h, polygon));
|
|
179
|
+
heap.push(makeCell(cell.x + h, cell.y + h, h, polygon));
|
|
180
|
+
}
|
|
181
|
+
return { point: { x: best.x, y: best.y }, clearance: best.d };
|
|
182
|
+
}
|
|
183
|
+
/** The anchor point only. See poleOfInaccessibilityWithClearance for the
|
|
184
|
+
* clearance radius (and the `precision` note — for normalized 0..1 coordinates
|
|
185
|
+
* pass ~1e-3, not the pixel-scale default of 1.0). */
|
|
186
|
+
export function poleOfInaccessibility(polygon, precision = 1.0) {
|
|
187
|
+
return poleOfInaccessibilityWithClearance(polygon, precision).point;
|
|
188
|
+
}
|
|
189
|
+
// Concentric-ring cluster positions around a centre. Ring k holds 6k points, so
|
|
190
|
+
// the cluster grows outward roughly evenly. `spacing` is the ring-radius step.
|
|
191
|
+
function clusterPositions(center, count, spacing) {
|
|
192
|
+
const pts = [{ x: center.x, y: center.y }];
|
|
193
|
+
for (let ring = 1; pts.length < count; ring++) {
|
|
194
|
+
const inRing = 6 * ring;
|
|
195
|
+
for (let i = 0; i < inRing && pts.length < count; i++) {
|
|
196
|
+
const angle = (2 * Math.PI * i) / inRing;
|
|
197
|
+
pts.push({
|
|
198
|
+
x: center.x + ring * spacing * Math.cos(angle),
|
|
199
|
+
y: center.y + ring * spacing * Math.sin(angle),
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return pts;
|
|
204
|
+
}
|
|
205
|
+
function clusterFits(pts, polygon, clearance) {
|
|
206
|
+
for (const p of pts) {
|
|
207
|
+
if (signedDistanceToPolygon(p, polygon) < clearance)
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
return true;
|
|
211
|
+
}
|
|
212
|
+
/** Lay out `count` tokens inside `polygon`, clustered at its visual centre and
|
|
213
|
+
* kept within the boundary. Shrinks the cluster to fit; if even the shrunk
|
|
214
|
+
* cluster won't fit, returns a single anchored point with `stacked: true` so
|
|
215
|
+
* the renderer can draw a pile + count badge. Deterministic. */
|
|
216
|
+
export function layoutTokensInPolygon(polygon, count, opts) {
|
|
217
|
+
const anchor = opts.anchor ?? poleOfInaccessibility(polygon, opts.precision ?? 1.0);
|
|
218
|
+
const gap = opts.gap ?? opts.tokenRadius * 0.3;
|
|
219
|
+
const minScale = opts.minScale ?? 0.4;
|
|
220
|
+
if (count <= 0)
|
|
221
|
+
return { anchor, points: [], scale: 1, stacked: false };
|
|
222
|
+
if (count === 1) {
|
|
223
|
+
const fits = signedDistanceToPolygon(anchor, polygon) >= opts.tokenRadius;
|
|
224
|
+
return { anchor, points: [anchor], scale: fits ? 1 : minScale, stacked: !fits };
|
|
225
|
+
}
|
|
226
|
+
const step = 2 * opts.tokenRadius + gap;
|
|
227
|
+
// Try full size, then shrink in 0.1 increments down to minScale.
|
|
228
|
+
for (let scale = 1.0; scale >= minScale - 1e-9; scale -= 0.1) {
|
|
229
|
+
const pts = clusterPositions(anchor, count, step * scale);
|
|
230
|
+
if (clusterFits(pts, polygon, opts.tokenRadius * scale)) {
|
|
231
|
+
return { anchor, points: pts, scale: Math.max(scale, minScale), stacked: false };
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
// Won't fit even shrunk — collapse to a single anchored pile.
|
|
235
|
+
return { anchor, points: [anchor], scale: minScale, stacked: true };
|
|
236
|
+
}
|
|
237
|
+
// --- conversion helpers ---------------------------------------------------
|
|
238
|
+
// On disk, polygons are [x,y] pairs (clip-path, GeoJSON-ish, VASSAL/SVG exports);
|
|
239
|
+
// in memory the geo functions take {x,y}. These save every consumer re-writing
|
|
240
|
+
// the same adapter.
|
|
241
|
+
export function toPolygon(pairs) {
|
|
242
|
+
return pairs.map(([x, y]) => ({ x, y }));
|
|
243
|
+
}
|
|
244
|
+
export function fromPolygon(polygon) {
|
|
245
|
+
return polygon.map((p) => [p.x, p.y]);
|
|
246
|
+
}
|
|
247
|
+
export function distance(a, b) {
|
|
248
|
+
return Math.hypot(a.x - b.x, a.y - b.y);
|
|
249
|
+
}
|
|
250
|
+
/** Headless verification of a whole map's token layout — the CI-able core of the
|
|
251
|
+
* per-game audit overlay (the visual page stays per-game; this is the math it
|
|
252
|
+
* and CI both call). Lays out each region and checks containment. */
|
|
253
|
+
export function auditLayout(entries, opts) {
|
|
254
|
+
const anchorsOutside = [];
|
|
255
|
+
const stackedPiles = [];
|
|
256
|
+
let tokenBleed = 0;
|
|
257
|
+
let minClearance = Infinity;
|
|
258
|
+
let tightestRegion = null;
|
|
259
|
+
for (const { id, polygon, count } of entries) {
|
|
260
|
+
const { point: anchor, clearance } = poleOfInaccessibilityWithClearance(polygon, opts.precision ?? 1.0);
|
|
261
|
+
if (clearance <= 0)
|
|
262
|
+
anchorsOutside.push(id);
|
|
263
|
+
if (clearance < minClearance) {
|
|
264
|
+
minClearance = clearance;
|
|
265
|
+
tightestRegion = id;
|
|
266
|
+
}
|
|
267
|
+
const layout = layoutTokensInPolygon(polygon, count, { ...opts, anchor });
|
|
268
|
+
if (layout.stacked) {
|
|
269
|
+
stackedPiles.push(id);
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
for (const p of layout.points) {
|
|
273
|
+
if (signedDistanceToPolygon(p, polygon) < 0)
|
|
274
|
+
tokenBleed++;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return {
|
|
279
|
+
regions: entries.length,
|
|
280
|
+
anchorsOutside,
|
|
281
|
+
tokenBleed,
|
|
282
|
+
stackedPiles,
|
|
283
|
+
minClearance: minClearance === Infinity ? 0 : minClearance,
|
|
284
|
+
tightestRegion,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
// --- comparison / validation (extraction vs a reference) ------------------
|
|
288
|
+
// Roughness-tolerant ways to validate auto-extracted polygons against a human
|
|
289
|
+
// reference (or vice versa). Compare TOPOLOGY (count, 1:1 matching, adjacency,
|
|
290
|
+
// anchor proximity), NOT vertex precision — a rough reference legitimately
|
|
291
|
+
// overlaps a precise extraction at well under IoU 1.0.
|
|
292
|
+
function segSegDistSq(a1, a2, b1, b2) {
|
|
293
|
+
// Min of the four endpoint-to-opposite-segment distances. (For the adjacency
|
|
294
|
+
// use-case we don't need the exact crossing test — touching boundaries give a
|
|
295
|
+
// near-zero distance either way.)
|
|
296
|
+
return Math.min(segmentDistSq(a1, b1, b2), segmentDistSq(a2, b1, b2), segmentDistSq(b1, a1, a2), segmentDistSq(b2, a1, a2));
|
|
297
|
+
}
|
|
298
|
+
function boundaryDistance(a, b) {
|
|
299
|
+
let minSq = Infinity;
|
|
300
|
+
for (let i = 0, ai = a.length - 1; i < a.length; ai = i++) {
|
|
301
|
+
for (let j = 0, bj = b.length - 1; j < b.length; bj = j++) {
|
|
302
|
+
const d = segSegDistSq(a[ai], a[i], b[bj], b[j]);
|
|
303
|
+
if (d < minSq)
|
|
304
|
+
minSq = d;
|
|
305
|
+
if (minSq === 0)
|
|
306
|
+
return 0;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
return Math.sqrt(minSq);
|
|
310
|
+
}
|
|
311
|
+
/** Approximate intersection-over-union of two polygons via grid sampling over
|
|
312
|
+
* the combined bounding box. Robust to concavity (no polygon clipping).
|
|
313
|
+
* `samples` is the grid resolution per axis (default 64 → 4096 test points).
|
|
314
|
+
* Deterministic. */
|
|
315
|
+
export function polygonIoU(a, b, samples = 64) {
|
|
316
|
+
const ba = boundingBox(a), bb = boundingBox(b);
|
|
317
|
+
const minX = Math.min(ba.minX, bb.minX), minY = Math.min(ba.minY, bb.minY);
|
|
318
|
+
const maxX = Math.max(ba.maxX, bb.maxX), maxY = Math.max(ba.maxY, bb.maxY);
|
|
319
|
+
const w = maxX - minX, h = maxY - minY;
|
|
320
|
+
if (w <= 0 || h <= 0)
|
|
321
|
+
return 0;
|
|
322
|
+
let inter = 0, uni = 0;
|
|
323
|
+
for (let i = 0; i < samples; i++) {
|
|
324
|
+
const x = minX + ((i + 0.5) * w) / samples;
|
|
325
|
+
for (let j = 0; j < samples; j++) {
|
|
326
|
+
const y = minY + ((j + 0.5) * h) / samples;
|
|
327
|
+
const inA = pointInPolygon({ x, y }, a);
|
|
328
|
+
const inB = pointInPolygon({ x, y }, b);
|
|
329
|
+
if (inA || inB)
|
|
330
|
+
uni++;
|
|
331
|
+
if (inA && inB)
|
|
332
|
+
inter++;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return uni === 0 ? 0 : inter / uni;
|
|
336
|
+
}
|
|
337
|
+
/** Undirected adjacency derived from polygon geometry: two regions are adjacent
|
|
338
|
+
* when their boundaries come within `tolerance`. Rough/hand-traced polygons
|
|
339
|
+
* rarely share exact edges, so a tolerance is required. O(n²) with a bbox
|
|
340
|
+
* pre-filter — fine for a few hundred regions run occasionally (validation, not
|
|
341
|
+
* a hot path). Returns sorted, de-duplicated, normalized edges. */
|
|
342
|
+
export function adjacencyFromPolygons(polygons, tolerance) {
|
|
343
|
+
const ids = Object.keys(polygons);
|
|
344
|
+
const bboxes = {};
|
|
345
|
+
for (const id of ids)
|
|
346
|
+
bboxes[id] = boundingBox(polygons[id]);
|
|
347
|
+
const edges = [];
|
|
348
|
+
for (let i = 0; i < ids.length; i++) {
|
|
349
|
+
for (let j = i + 1; j < ids.length; j++) {
|
|
350
|
+
const a = ids[i], b = ids[j];
|
|
351
|
+
const ba = bboxes[a], bb = bboxes[b];
|
|
352
|
+
if (ba.minX - tolerance > bb.maxX || bb.minX - tolerance > ba.maxX ||
|
|
353
|
+
ba.minY - tolerance > bb.maxY || bb.minY - tolerance > ba.maxY)
|
|
354
|
+
continue;
|
|
355
|
+
if (boundaryDistance(polygons[a], polygons[b]) <= tolerance) {
|
|
356
|
+
edges.push(a < b ? [a, b] : [b, a]);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
edges.sort((e, f) => (e[0] === f[0] ? e[1].localeCompare(f[1]) : e[0].localeCompare(f[0])));
|
|
361
|
+
return edges;
|
|
362
|
+
}
|
|
363
|
+
/** Set-diff two undirected edge lists (edge endpoint order is normalized). Use
|
|
364
|
+
* to compare polygon-derived adjacency against the engine's known adjacency —
|
|
365
|
+
* the strongest, roughness-immune validation signal. */
|
|
366
|
+
export function diffAdjacency(a, b) {
|
|
367
|
+
const key = (e) => (e[0] < e[1] ? `${e[0]}|${e[1]}` : `${e[1]}|${e[0]}`);
|
|
368
|
+
const setA = new Set(a.map(key));
|
|
369
|
+
const setB = new Set(b.map(key));
|
|
370
|
+
const shared = [], onlyA = [], onlyB = [];
|
|
371
|
+
for (const e of a)
|
|
372
|
+
(setB.has(key(e)) ? shared : onlyA).push(e);
|
|
373
|
+
for (const e of b)
|
|
374
|
+
if (!setA.has(key(e)))
|
|
375
|
+
onlyB.push(e);
|
|
376
|
+
return { shared, onlyA, onlyB };
|
|
377
|
+
}
|
|
378
|
+
/** Match two named polygon sets (e.g. extracted vs a human reference) by best
|
|
379
|
+
* IoU. The roughness-tolerant comparison: use it to confirm a 1:1 region
|
|
380
|
+
* correspondence and flag merges/splits — NOT to score vertex precision. Greedy
|
|
381
|
+
* per A-region. `minIoU` is the matching threshold (default 0.5); keep it low,
|
|
382
|
+
* because a rough reference legitimately overlaps a precise extraction at well
|
|
383
|
+
* under 1.0. */
|
|
384
|
+
export function matchRegions(a, b, opts = {}) {
|
|
385
|
+
const minIoU = opts.minIoU ?? 0.5;
|
|
386
|
+
const samples = opts.samples ?? 48;
|
|
387
|
+
const idsA = Object.keys(a), idsB = Object.keys(b);
|
|
388
|
+
const bboxesB = {};
|
|
389
|
+
for (const id of idsB)
|
|
390
|
+
bboxesB[id] = boundingBox(b[id]);
|
|
391
|
+
const matches = [];
|
|
392
|
+
const matchedB = new Set();
|
|
393
|
+
const unmatchedA = [];
|
|
394
|
+
for (const ia of idsA) {
|
|
395
|
+
const pa = a[ia];
|
|
396
|
+
const ba = boundingBox(pa);
|
|
397
|
+
let best = null;
|
|
398
|
+
for (const ib of idsB) {
|
|
399
|
+
const bbB = bboxesB[ib];
|
|
400
|
+
if (ba.minX > bbB.maxX || bbB.minX > ba.maxX ||
|
|
401
|
+
ba.minY > bbB.maxY || bbB.minY > ba.maxY)
|
|
402
|
+
continue; // bbox pre-filter
|
|
403
|
+
const iou = polygonIoU(pa, b[ib], samples);
|
|
404
|
+
if (!best || iou > best.iou)
|
|
405
|
+
best = { id: ib, iou };
|
|
406
|
+
}
|
|
407
|
+
if (best && best.iou >= minIoU) {
|
|
408
|
+
const anchorDistance = distance(poleOfInaccessibility(pa), poleOfInaccessibility(b[best.id]));
|
|
409
|
+
matches.push({ a: ia, b: best.id, iou: best.iou, anchorDistance });
|
|
410
|
+
matchedB.add(best.id);
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
unmatchedA.push(ia);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
const unmatchedB = idsB.filter((id) => !matchedB.has(id));
|
|
417
|
+
return { matches, unmatchedA, unmatchedB };
|
|
418
|
+
}
|
|
419
|
+
//# sourceMappingURL=geo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geo.js","sourceRoot":"","sources":["../../src/core/geo.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,4 +4,5 @@ export { StructuredLog, type LogEntry } from './core/log.js';
|
|
|
4
4
|
export { EffectContext, type ChoiceRequest, type ChoiceResponse } from './core/effects.js';
|
|
5
5
|
export { type GameAdapter, type GameResult } from './core/adapter.js';
|
|
6
6
|
export { type PlayerController, type ControllerContext, RandomAI, ScriptedController, } from './core/controller.js';
|
|
7
|
+
export { type Point, type Polygon, type BBox, type LayoutOptions, type TokenLayout, type PoleResult, type AuditEntry, type AuditResult, type Edge, type AdjacencyDiff, type RegionMatch, type RegionMatchResult, boundingBox, signedArea, area, centroid, pointInPolygon, signedDistanceToPolygon, poleOfInaccessibility, poleOfInaccessibilityWithClearance, layoutTokensInPolygon, toPolygon, fromPolygon, distance, auditLayout, polygonIoU, adjacencyFromPolygons, diffAdjacency, matchRegions, } from './core/geo.js';
|
|
7
8
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,KAAK,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC3F,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,QAAQ,EACR,kBAAkB,GACnB,MAAM,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,KAAK,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC3F,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,QAAQ,EACR,kBAAkB,GACnB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,KAAK,KAAK,EACV,KAAK,OAAO,EACZ,KAAK,IAAI,EACT,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,IAAI,EACT,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,WAAW,EACX,UAAU,EACV,IAAI,EACJ,QAAQ,EACR,cAAc,EACd,uBAAuB,EACvB,qBAAqB,EACrB,kCAAkC,EAClC,qBAAqB,EACrB,SAAS,EACT,WAAW,EACX,QAAQ,EACR,WAAW,EACX,UAAU,EACV,qBAAqB,EACrB,aAAa,EACb,YAAY,GACb,MAAM,eAAe,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -3,4 +3,5 @@ export { jsonCodec } from './core/codec.js';
|
|
|
3
3
|
export { StructuredLog } from './core/log.js';
|
|
4
4
|
export { EffectContext } from './core/effects.js';
|
|
5
5
|
export { RandomAI, ScriptedController, } from './core/controller.js';
|
|
6
|
+
export { boundingBox, signedArea, area, centroid, pointInPolygon, signedDistanceToPolygon, poleOfInaccessibility, poleOfInaccessibilityWithClearance, layoutTokensInPolygon, toPolygon, fromPolygon, distance, auditLayout, polygonIoU, adjacencyFromPolygons, diffAdjacency, matchRegions, } from './core/geo.js';
|
|
6
7
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACpC,OAAO,EAAE,SAAS,EAAc,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAiB,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,aAAa,EAA2C,MAAM,mBAAmB,CAAC;AAE3F,OAAO,EAGL,QAAQ,EACR,kBAAkB,GACnB,MAAM,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACpC,OAAO,EAAE,SAAS,EAAc,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAiB,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,aAAa,EAA2C,MAAM,mBAAmB,CAAC;AAE3F,OAAO,EAGL,QAAQ,EACR,kBAAkB,GACnB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAaL,WAAW,EACX,UAAU,EACV,IAAI,EACJ,QAAQ,EACR,cAAc,EACd,uBAAuB,EACvB,qBAAqB,EACrB,kCAAkC,EAClC,qBAAqB,EACrB,SAAS,EACT,WAAW,EACX,QAAQ,EACR,WAAW,EACX,UAAU,EACV,qBAAqB,EACrB,aAAa,EACb,YAAY,GACb,MAAM,eAAe,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "digital-boardgame-framework",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "Foundation library for turn-based digital boardgames: deterministic engine plumbing, async multiplayer, agent-friendly bug triage.",
|
|
5
5
|
"keywords": ["boardgame", "board-game", "multiplayer", "async-multiplayer", "turn-based", "game-framework", "supabase", "cloudflare-pages"],
|
|
6
6
|
"author": "John Champaign",
|