@expofp/wayfinding-compiler 0.0.0-experimental.3b0db16 → 0.0.0-stage
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/README.md +2 -445
- package/package.json +3 -34
- package/dist/index.d.ts +0 -14
- package/dist/index.js +0 -3
- package/dist/lib/attach.d.ts +0 -43
- package/dist/lib/attach.js +0 -199
- package/dist/lib/axes.d.ts +0 -76
- package/dist/lib/axes.js +0 -103
- package/dist/lib/blockers.d.ts +0 -134
- package/dist/lib/blockers.js +0 -289
- package/dist/lib/cell-array.d.ts +0 -14
- package/dist/lib/cell-array.js +0 -25
- package/dist/lib/compile-layer.d.ts +0 -41
- package/dist/lib/compile-layer.js +0 -241
- package/dist/lib/compile-wayfinding.d.ts +0 -90
- package/dist/lib/compile-wayfinding.js +0 -203
- package/dist/lib/connect.d.ts +0 -35
- package/dist/lib/connect.js +0 -206
- package/dist/lib/diagnostics.d.ts +0 -190
- package/dist/lib/diagnostics.js +0 -634
- package/dist/lib/doorways.d.ts +0 -78
- package/dist/lib/doorways.js +0 -331
- package/dist/lib/emit-network.d.ts +0 -47
- package/dist/lib/emit-network.js +0 -105
- package/dist/lib/emit-v1.d.ts +0 -31
- package/dist/lib/emit-v1.js +0 -56
- package/dist/lib/entries.d.ts +0 -123
- package/dist/lib/entries.js +0 -448
- package/dist/lib/floor-grids.d.ts +0 -48
- package/dist/lib/floor-grids.js +0 -185
- package/dist/lib/framing.d.ts +0 -20
- package/dist/lib/framing.js +0 -187
- package/dist/lib/geom/boolean-ops.d.ts +0 -21
- package/dist/lib/geom/boolean-ops.js +0 -1
- package/dist/lib/geom/clipper2-ops.d.ts +0 -7
- package/dist/lib/geom/clipper2-ops.js +0 -50
- package/dist/lib/geom/footprint.d.ts +0 -26
- package/dist/lib/geom/footprint.js +0 -203
- package/dist/lib/geom/frames.d.ts +0 -116
- package/dist/lib/geom/frames.js +0 -233
- package/dist/lib/geom/mesh-outline.d.ts +0 -13
- package/dist/lib/geom/mesh-outline.js +0 -90
- package/dist/lib/geom/normalize.d.ts +0 -28
- package/dist/lib/geom/normalize.js +0 -118
- package/dist/lib/geom/point-key.d.ts +0 -16
- package/dist/lib/geom/point-key.js +0 -15
- package/dist/lib/geom/primitives.d.ts +0 -105
- package/dist/lib/geom/primitives.js +0 -184
- package/dist/lib/geom/split-crossings.d.ts +0 -14
- package/dist/lib/geom/split-crossings.js +0 -171
- package/dist/lib/geom/types.d.ts +0 -9
- package/dist/lib/geom/types.js +0 -1
- package/dist/lib/geom/walls.d.ts +0 -31
- package/dist/lib/geom/walls.js +0 -71
- package/dist/lib/graph-invariants.d.ts +0 -49
- package/dist/lib/graph-invariants.js +0 -129
- package/dist/lib/graph-types.d.ts +0 -143
- package/dist/lib/graph-types.js +0 -7
- package/dist/lib/mask.d.ts +0 -54
- package/dist/lib/mask.js +0 -210
- package/dist/lib/min-heap.d.ts +0 -24
- package/dist/lib/min-heap.js +0 -73
- package/dist/lib/network-build.d.ts +0 -21
- package/dist/lib/network-build.js +0 -4
- package/dist/lib/network-graph.d.ts +0 -80
- package/dist/lib/network-graph.js +0 -467
- package/dist/lib/network-sizes.d.ts +0 -29
- package/dist/lib/network-sizes.js +0 -22
- package/dist/lib/network-store.d.ts +0 -173
- package/dist/lib/network-store.js +0 -430
- package/dist/lib/openings.d.ts +0 -54
- package/dist/lib/openings.js +0 -387
- package/dist/lib/place-path.d.ts +0 -47
- package/dist/lib/place-path.js +0 -346
- package/dist/lib/post-passes.d.ts +0 -31
- package/dist/lib/post-passes.js +0 -305
- package/dist/lib/reachability.d.ts +0 -58
- package/dist/lib/reachability.js +0 -220
- package/dist/lib/report.d.ts +0 -49
- package/dist/lib/report.js +0 -374
- package/dist/lib/router.d.ts +0 -111
- package/dist/lib/router.js +0 -388
- package/dist/lib/runs.d.ts +0 -92
- package/dist/lib/runs.js +0 -232
- package/dist/lib/scale.d.ts +0 -58
- package/dist/lib/scale.js +0 -185
- package/dist/lib/steiner-network.d.ts +0 -19
- package/dist/lib/steiner-network.js +0 -183
- package/dist/lib/strip.d.ts +0 -43
- package/dist/lib/strip.js +0 -200
- package/dist/lib/stubs.d.ts +0 -84
- package/dist/lib/stubs.js +0 -316
- package/dist/lib/transitions.d.ts +0 -72
- package/dist/lib/transitions.js +0 -191
- package/dist/lib/types.d.ts +0 -126
- package/dist/lib/types.js +0 -1
- package/dist/lib/validate-source.d.ts +0 -41
- package/dist/lib/validate-source.js +0 -133
- package/dist/lib/walkable.d.ts +0 -104
- package/dist/lib/walkable.js +0 -140
package/dist/lib/attach.js
DELETED
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
// Attach: each stub ends where it first meets the network — a line, or another stub, which then
|
|
2
|
-
// ends there too, so the meeting is a node. A stub that meets nothing is taken to the network by an
|
|
3
|
-
// elbow to the nearest line a free way reaches, else by a raster path laid like a growth path; one
|
|
4
|
-
// that cannot attach is retried from its destination's next way in.
|
|
5
|
-
import { dockFor } from './entries.js';
|
|
6
|
-
import { linkOnto, nearestFrame } from './geom/frames.js';
|
|
7
|
-
import { POINT_EPS } from './geom/point-key.js';
|
|
8
|
-
import { rayVsSegment, segmentsCross } from './geom/primitives.js';
|
|
9
|
-
import { NODE_SNAP } from './graph-types.js';
|
|
10
|
-
import { sideOf } from './stubs.js';
|
|
11
|
-
/**
|
|
12
|
-
* The first network line a ray meets. A line lying along the ray is met at its nearer end when that is
|
|
13
|
-
* ahead, else at its far end.
|
|
14
|
-
* @param store The network.
|
|
15
|
-
* @param ox Ray origin x.
|
|
16
|
-
* @param oy Ray origin y.
|
|
17
|
-
* @param nx Ray direction x.
|
|
18
|
-
* @param ny Ray direction y.
|
|
19
|
-
* @param maxT How far to look.
|
|
20
|
-
* @returns The segment id and distance, or null within `maxT`.
|
|
21
|
-
*/
|
|
22
|
-
export function firstNetworkAlong(store, ox, oy, nx, ny, maxT) {
|
|
23
|
-
let best = null;
|
|
24
|
-
const hit = [0, 0];
|
|
25
|
-
const visit = (id, x0, y0, x1, y1) => {
|
|
26
|
-
let t = Infinity;
|
|
27
|
-
if (rayVsSegment(hit, ox, oy, nx, ny, x0, y0, x1, y1)) {
|
|
28
|
-
if (hit[1] >= -1e-9 && hit[1] <= 1 + 1e-9)
|
|
29
|
-
t = hit[0];
|
|
30
|
-
}
|
|
31
|
-
else if (Math.abs(-(x0 - ox) * ny + (y0 - oy) * nx) <= 0.01) {
|
|
32
|
-
const a0 = (x0 - ox) * nx + (y0 - oy) * ny;
|
|
33
|
-
const a1 = (x1 - ox) * nx + (y1 - oy) * ny;
|
|
34
|
-
const near = Math.min(a0, a1);
|
|
35
|
-
t = near > NODE_SNAP ? near : Math.max(a0, a1);
|
|
36
|
-
}
|
|
37
|
-
if (!isFinite(t) || t <= NODE_SNAP || t > maxT)
|
|
38
|
-
return;
|
|
39
|
-
if (!best || t < best.t - 1e-9)
|
|
40
|
-
best = { id, t };
|
|
41
|
-
};
|
|
42
|
-
// Only lines near the ray can meet it; both walks go in id order, so ties settle alike.
|
|
43
|
-
if (isFinite(maxT)) {
|
|
44
|
-
const ex = ox + nx * maxT;
|
|
45
|
-
const ey = oy + ny * maxT;
|
|
46
|
-
store.forEachNear(Math.min(ox, ex) - NODE_SNAP, Math.min(oy, ey) - NODE_SNAP, Math.max(ox, ex) + NODE_SNAP, Math.max(oy, ey) + NODE_SNAP, visit);
|
|
47
|
-
}
|
|
48
|
-
else
|
|
49
|
-
store.forEach(visit);
|
|
50
|
-
return best;
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Attaches every stub to the network, retrying a destination's next way in when one fails.
|
|
54
|
-
* @param attaching What the attach reads and extends.
|
|
55
|
-
* @returns The whiskers: the stubs attached, in the order they attached.
|
|
56
|
-
*/
|
|
57
|
-
export function attachStubs(attaching) {
|
|
58
|
-
const { plan, store, connector, router, frames, blockers, destinationOf, mayLay, note } = attaching;
|
|
59
|
-
const whiskers = [];
|
|
60
|
-
/**
|
|
61
|
-
* Where a run from a foot first meets the network: a network line, or another stub crossing it
|
|
62
|
-
* away from that stub's foot and tip — whichever comes first. A crossed stub counts only when its
|
|
63
|
-
* tip is on the network and the rest of its run may be a line.
|
|
64
|
-
* @param ox Foot x.
|
|
65
|
-
* @param oy Foot y.
|
|
66
|
-
* @param dx Unit direction of the run, x.
|
|
67
|
-
* @param dy Unit direction, y.
|
|
68
|
-
* @param maxT How far along the run to look.
|
|
69
|
-
* @returns The distance along the run and how to join the network there, or null.
|
|
70
|
-
*/
|
|
71
|
-
const meetingAlong = (ox, oy, dx, dy, maxT) => {
|
|
72
|
-
const met = firstNetworkAlong(store, ox, oy, dx, dy, maxT);
|
|
73
|
-
const hit = [0, 0];
|
|
74
|
-
let crossed = null;
|
|
75
|
-
for (const other of whiskers) {
|
|
76
|
-
const length = Math.hypot(other.tx - other.mx, other.ty - other.my);
|
|
77
|
-
if (!rayVsSegment(hit, ox, oy, dx, dy, other.mx, other.my, other.tx, other.ty))
|
|
78
|
-
continue;
|
|
79
|
-
const [t, s] = hit;
|
|
80
|
-
if (t <= NODE_SNAP || t > (met?.t ?? maxT))
|
|
81
|
-
continue;
|
|
82
|
-
if (s * length <= NODE_SNAP || (1 - s) * length <= NODE_SNAP)
|
|
83
|
-
continue;
|
|
84
|
-
if (!crossed || t < crossed.t - 1e-9)
|
|
85
|
-
crossed = { other, t };
|
|
86
|
-
}
|
|
87
|
-
if (crossed) {
|
|
88
|
-
const { other, t } = crossed;
|
|
89
|
-
const at = [+(ox + dx * t).toFixed(2), +(oy + dy * t).toFixed(2)];
|
|
90
|
-
// The crossed stub ends at the meeting, the rest of its run a line to its tip.
|
|
91
|
-
if (store.hasNode(other.tx, other.ty) && mayLay([at[0], at[1], other.tx, other.ty]))
|
|
92
|
-
return {
|
|
93
|
-
t,
|
|
94
|
-
joinAt: () => {
|
|
95
|
-
connector.add([at[0], at[1], other.tx, other.ty]);
|
|
96
|
-
[other.tx, other.ty] = at;
|
|
97
|
-
},
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
return met && { t: met.t, joinAt: ([x, y]) => store.splitAt(met.id, x, y) };
|
|
101
|
-
};
|
|
102
|
-
/**
|
|
103
|
-
* The walkable router cell of a point on its direction's grid, else the plan's.
|
|
104
|
-
* @param x Point x.
|
|
105
|
-
* @param y Point y.
|
|
106
|
-
* @param frame The direction.
|
|
107
|
-
* @returns The cell, or -1 when off the floor.
|
|
108
|
-
*/
|
|
109
|
-
const cellAt = (x, y, frame) => {
|
|
110
|
-
for (const f of [frame, frames[0]]) {
|
|
111
|
-
const cell = router.cellIn(x, y, f);
|
|
112
|
-
if (cell >= 0)
|
|
113
|
-
return router.ok[cell] ? cell : -1;
|
|
114
|
-
}
|
|
115
|
-
return -1;
|
|
116
|
-
};
|
|
117
|
-
/**
|
|
118
|
-
* Joins a tip standing off the network: an elbow to the nearest freely reachable line, else a
|
|
119
|
-
* raster path laid on the lines of its way.
|
|
120
|
-
* @param stub The stub.
|
|
121
|
-
* @returns True when joined.
|
|
122
|
-
*/
|
|
123
|
-
const connectTip = (stub) => {
|
|
124
|
-
const tip = [stub.tx, stub.ty];
|
|
125
|
-
if (store.hasNode(tip[0], tip[1]))
|
|
126
|
-
return true;
|
|
127
|
-
// No network at all (a plan with one destination): the stub's own run is its line.
|
|
128
|
-
if (!store.size) {
|
|
129
|
-
const line = [stub.mx, stub.my, tip[0], tip[1]];
|
|
130
|
-
if (!mayLay(line))
|
|
131
|
-
return false;
|
|
132
|
-
connector.add(line);
|
|
133
|
-
return true;
|
|
134
|
-
}
|
|
135
|
-
// A link crosses no stub attached so far: a route would walk past that destination and back.
|
|
136
|
-
const clear = (seg) => mayLay(seg) && !whiskers.some((w) => segmentsCross(seg, [w.mx, w.my, w.tx, w.ty]));
|
|
137
|
-
const found = store.nearestLawful(tip[0], tip[1], (_, qx, qy) => clear([tip[0], tip[1], qx, qy]));
|
|
138
|
-
const link = found &&
|
|
139
|
-
linkOnto(frames[nearestFrame(frames, ...runOf(found.id))], tip, store.coords(found.id), found.at, clear);
|
|
140
|
-
if (found && link) {
|
|
141
|
-
store.splitAt(found.id, link.at[0], link.at[1]);
|
|
142
|
-
for (const leg of link.legs)
|
|
143
|
-
connector.add(leg);
|
|
144
|
-
return true;
|
|
145
|
-
}
|
|
146
|
-
// On the tip's own grid, so the path leaves square to its face.
|
|
147
|
-
const frame = stub.frame ?? frames[0];
|
|
148
|
-
const tipCell = cellAt(tip[0], tip[1], frame);
|
|
149
|
-
if (tipCell < 0)
|
|
150
|
-
return false;
|
|
151
|
-
// Search from the tip so the cost follows the path length, not the network size; reversed to
|
|
152
|
-
// run tip first.
|
|
153
|
-
const cells = router.route([tipCell], connector.onNetwork)?.reverse() ?? null;
|
|
154
|
-
const head = { at: tip, normal: [stub.nx, stub.ny], frame };
|
|
155
|
-
// Reaching the destination outweighs the whisker rule when its only way crosses one.
|
|
156
|
-
return (cells !== null && (connector.layPath(cells, head, clear) || connector.layPath(cells, head)));
|
|
157
|
-
};
|
|
158
|
-
const runOf = (id) => {
|
|
159
|
-
const [x0, y0, x1, y1] = store.coords(id);
|
|
160
|
-
return [x1 - x0, y1 - y0];
|
|
161
|
-
};
|
|
162
|
-
/** Sides of each destination a whisker already serves. */
|
|
163
|
-
const servedSides = new Map();
|
|
164
|
-
const pending = [...plan.stubs];
|
|
165
|
-
// A for-of walks the retries pushed while it runs.
|
|
166
|
-
for (const stub of pending) {
|
|
167
|
-
const d = destinationOf.get(stub.id);
|
|
168
|
-
const retry = () => {
|
|
169
|
-
const next = plan.retry(stub, servedSides, whiskers);
|
|
170
|
-
if (next)
|
|
171
|
-
pending.push(next);
|
|
172
|
-
};
|
|
173
|
-
// The tip stops at the first network line or stub within its reach.
|
|
174
|
-
const meeting = meetingAlong(stub.mx, stub.my, stub.nx, stub.ny, stub.reach + 1.1 * POINT_EPS);
|
|
175
|
-
if (meeting) {
|
|
176
|
-
const tip = [
|
|
177
|
-
+(stub.mx + stub.nx * meeting.t).toFixed(2),
|
|
178
|
-
+(stub.my + stub.ny * meeting.t).toFixed(2),
|
|
179
|
-
];
|
|
180
|
-
// No lawful dock from the meeting, no way in.
|
|
181
|
-
if (!dockFor(d, stub.way, tip, blockers)) {
|
|
182
|
-
note(d.id, 'way-in-blocked', { at: tip });
|
|
183
|
-
retry();
|
|
184
|
-
continue;
|
|
185
|
-
}
|
|
186
|
-
meeting.joinAt(tip);
|
|
187
|
-
[stub.tx, stub.ty] = tip;
|
|
188
|
-
}
|
|
189
|
-
else if (!connectTip(stub)) {
|
|
190
|
-
note(d.id, router.cellsOf(stub.tx, stub.ty).some((c) => router.ok[c]) ? 'cut-off' : 'no-floor', { at: [stub.tx, stub.ty] });
|
|
191
|
-
retry();
|
|
192
|
-
continue;
|
|
193
|
-
}
|
|
194
|
-
whiskers.push(stub);
|
|
195
|
-
if (stub.kind === 'face')
|
|
196
|
-
servedSides.set(stub.id, (servedSides.get(stub.id) ?? new Set()).add(sideOf(stub.way)));
|
|
197
|
-
}
|
|
198
|
-
return whiskers;
|
|
199
|
-
}
|
package/dist/lib/axes.d.ts
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { type Frame } from './geom/frames.js';
|
|
2
|
-
/** A stub tip read in a frame: the line it lies on runs square to its stub. */
|
|
3
|
-
interface TipOnAxis {
|
|
4
|
-
/** Coordinate across the aisle: the line the tip lies on. */
|
|
5
|
-
readonly c: number;
|
|
6
|
-
/** Coordinate along the aisle. */
|
|
7
|
-
readonly along: number;
|
|
8
|
-
/**
|
|
9
|
-
* Where across its line may lie: a comfortable clearance from its face and from what stands across.
|
|
10
|
-
* Absent for no bound.
|
|
11
|
-
*/
|
|
12
|
-
readonly may?: readonly [number, number];
|
|
13
|
-
}
|
|
14
|
-
/** One aisle's line in a frame: along the frame's first axis (`horiz`) or its second. */
|
|
15
|
-
export interface AisleAxis {
|
|
16
|
-
/** The frame. */
|
|
17
|
-
readonly frame: Frame;
|
|
18
|
-
/** The line runs along the frame's first axis; across is the second. */
|
|
19
|
-
readonly horiz: boolean;
|
|
20
|
-
/** The across coordinate. */
|
|
21
|
-
readonly c: number;
|
|
22
|
-
/** Where the line starts: as far back from the first tip as the floor is free along it. */
|
|
23
|
-
readonly lo: number;
|
|
24
|
-
/** Where the line ends: as far on from the last tip as the floor is free along it. */
|
|
25
|
-
readonly hi: number;
|
|
26
|
-
}
|
|
27
|
-
/** One aisle's axis: its across coordinate, its reach along, and its tips. */
|
|
28
|
-
export interface Axis<T extends TipOnAxis> {
|
|
29
|
-
/** The across coordinate: the lower median of the tips', so half the stubs keep their length. */
|
|
30
|
-
readonly c: number;
|
|
31
|
-
/** Where the line starts along. */
|
|
32
|
-
readonly lo: number;
|
|
33
|
-
/** Where the line ends along. */
|
|
34
|
-
readonly hi: number;
|
|
35
|
-
/** The tips on it, in order along. */
|
|
36
|
-
readonly tips: T[];
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* A point in a frame as `[along, across]` of a line orientation.
|
|
40
|
-
* @param frame The frame.
|
|
41
|
-
* @param horiz Lines along the frame's first axis.
|
|
42
|
-
* @param x Plan x.
|
|
43
|
-
* @param y Plan y.
|
|
44
|
-
* @returns Along and across.
|
|
45
|
-
*/
|
|
46
|
-
export declare function alongAcross(frame: Frame, horiz: boolean, x: number, y: number): [number, number];
|
|
47
|
-
/**
|
|
48
|
-
* Reads a tip into a frame.
|
|
49
|
-
* @param frame The frame.
|
|
50
|
-
* @param x Tip x.
|
|
51
|
-
* @param y Tip y.
|
|
52
|
-
* @param nx Stub direction x.
|
|
53
|
-
* @param ny Stub direction y.
|
|
54
|
-
* @returns Whether its line runs along the frame's first axis, and its coordinates across and along.
|
|
55
|
-
*/
|
|
56
|
-
export declare function tipInFrame(frame: Frame, x: number, y: number, nx: number, ny: number): {
|
|
57
|
-
horiz: boolean;
|
|
58
|
-
c: number;
|
|
59
|
-
along: number;
|
|
60
|
-
};
|
|
61
|
-
/**
|
|
62
|
-
* Groups the tips of one direction and orientation into aisles. Tips the raster cannot tell apart
|
|
63
|
-
* across (within `align`) lie on one row; a row's line reaches along as far as the floor is free
|
|
64
|
-
* beyond its end tips. A row joins the aisle whose rows all lie within `snap` of it across, since no
|
|
65
|
-
* corridor fits between them, when their lines' reaches overlap along and one line may serve every
|
|
66
|
-
* tip — the tips' bands keep two aisles that merely share open floor apart. The axis lies at the
|
|
67
|
-
* lower median of the aisle's tips, within where every tip's line may lie.
|
|
68
|
-
* @param tips The tips.
|
|
69
|
-
* @param align Across distance within which tips lie on one row.
|
|
70
|
-
* @param snap Across distance within which the rows of one aisle lie.
|
|
71
|
-
* @param reach How far the floor is free along the row's line from a tip, forward (`1`) or back (`-1`).
|
|
72
|
-
* @returns The aisles' axes.
|
|
73
|
-
*/
|
|
74
|
-
export declare function aisleAxes<T extends TipOnAxis>(tips: readonly T[], align: number, snap: number, reach: (tip: T, sign: 1 | -1) => number): Axis<T>[];
|
|
75
|
-
export {};
|
|
76
|
-
//# sourceMappingURL=axes.d.ts.map
|
package/dist/lib/axes.js
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
// Aisle axes: the lines the stub tips of one direction define, one per aisle. A stub ends in the middle
|
|
2
|
-
// of the aisle in front of its face, so the tips of the stands along an aisle lie on its line; the axis
|
|
3
|
-
// is where that line goes, and every pass lays the aisle's line there.
|
|
4
|
-
import { toFrame } from './geom/frames.js';
|
|
5
|
-
/**
|
|
6
|
-
* A point in a frame as `[along, across]` of a line orientation.
|
|
7
|
-
* @param frame The frame.
|
|
8
|
-
* @param horiz Lines along the frame's first axis.
|
|
9
|
-
* @param x Plan x.
|
|
10
|
-
* @param y Plan y.
|
|
11
|
-
* @returns Along and across.
|
|
12
|
-
*/
|
|
13
|
-
export function alongAcross(frame, horiz, x, y) {
|
|
14
|
-
const [u, v] = toFrame(frame, x, y);
|
|
15
|
-
return horiz ? [u, v] : [v, u];
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Reads a tip into a frame.
|
|
19
|
-
* @param frame The frame.
|
|
20
|
-
* @param x Tip x.
|
|
21
|
-
* @param y Tip y.
|
|
22
|
-
* @param nx Stub direction x.
|
|
23
|
-
* @param ny Stub direction y.
|
|
24
|
-
* @returns Whether its line runs along the frame's first axis, and its coordinates across and along.
|
|
25
|
-
*/
|
|
26
|
-
export function tipInFrame(frame, x, y, nx, ny) {
|
|
27
|
-
const [nu, nv] = toFrame(frame, nx, ny);
|
|
28
|
-
const horiz = Math.abs(nv) > Math.abs(nu);
|
|
29
|
-
const [along, c] = alongAcross(frame, horiz, x, y);
|
|
30
|
-
return { horiz, c, along };
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Groups the tips of one direction and orientation into aisles. Tips the raster cannot tell apart
|
|
34
|
-
* across (within `align`) lie on one row; a row's line reaches along as far as the floor is free
|
|
35
|
-
* beyond its end tips. A row joins the aisle whose rows all lie within `snap` of it across, since no
|
|
36
|
-
* corridor fits between them, when their lines' reaches overlap along and one line may serve every
|
|
37
|
-
* tip — the tips' bands keep two aisles that merely share open floor apart. The axis lies at the
|
|
38
|
-
* lower median of the aisle's tips, within where every tip's line may lie.
|
|
39
|
-
* @param tips The tips.
|
|
40
|
-
* @param align Across distance within which tips lie on one row.
|
|
41
|
-
* @param snap Across distance within which the rows of one aisle lie.
|
|
42
|
-
* @param reach How far the floor is free along the row's line from a tip, forward (`1`) or back (`-1`).
|
|
43
|
-
* @returns The aisles' axes.
|
|
44
|
-
*/
|
|
45
|
-
export function aisleAxes(tips, align, snap, reach) {
|
|
46
|
-
const sorted = [...tips].sort((a, b) => a.c - b.c || a.along - b.along);
|
|
47
|
-
const rows = [];
|
|
48
|
-
for (const tip of sorted) {
|
|
49
|
-
const row = rows[rows.length - 1];
|
|
50
|
-
if (row && tip.c - row[row.length - 1].c <= align)
|
|
51
|
-
row.push(tip);
|
|
52
|
-
else
|
|
53
|
-
rows.push([tip]);
|
|
54
|
-
}
|
|
55
|
-
const meet = (a, b) => [
|
|
56
|
-
Math.max(a[0], b[0]),
|
|
57
|
-
Math.min(a[1], b[1]),
|
|
58
|
-
];
|
|
59
|
-
const span = rows.map((row) => {
|
|
60
|
-
const ordered = [...row].sort((a, b) => a.along - b.along);
|
|
61
|
-
const first = ordered[0];
|
|
62
|
-
const last = ordered[ordered.length - 1];
|
|
63
|
-
// Tips whose bands share no line still form the row: the line then stays among the tips.
|
|
64
|
-
const may = row.reduce((m, t) => (t.may ? meet(m, t.may) : m), [-Infinity, Infinity]);
|
|
65
|
-
return {
|
|
66
|
-
lo: first.along - reach(first, -1),
|
|
67
|
-
hi: last.along + reach(last, 1),
|
|
68
|
-
c: row.reduce((sum, t) => sum + t.c, 0) / row.length,
|
|
69
|
-
may: may[0] <= may[1] ? may : [row[0].c, row[row.length - 1].c],
|
|
70
|
-
};
|
|
71
|
-
});
|
|
72
|
-
const overlap = (i, j) => span[j].lo <= span[i].hi && span[i].lo <= span[j].hi;
|
|
73
|
-
// Rows come in order across, so an aisle's first row is its lowest: a row joins the nearest aisle
|
|
74
|
-
// whose first row is within `snap`, else starts one.
|
|
75
|
-
const aisles = [];
|
|
76
|
-
for (let i = 0; i < rows.length; i++) {
|
|
77
|
-
let home;
|
|
78
|
-
for (let k = aisles.length - 1; k >= 0 && span[i].c - span[aisles[k].rows[0]].c <= snap; k--) {
|
|
79
|
-
const may = meet(aisles[k].may, span[i].may);
|
|
80
|
-
if (may[0] <= may[1] && aisles[k].rows.some((j) => overlap(i, j))) {
|
|
81
|
-
home = aisles[k];
|
|
82
|
-
home.may = may;
|
|
83
|
-
break;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
if (home)
|
|
87
|
-
home.rows.push(i);
|
|
88
|
-
else
|
|
89
|
-
aisles.push({ rows: [i], may: span[i].may });
|
|
90
|
-
}
|
|
91
|
-
return aisles.map(({ rows: members, may }) => {
|
|
92
|
-
const all = members.flatMap((i) => rows[i]);
|
|
93
|
-
const across = all.map((t) => t.c).sort((a, b) => a - b);
|
|
94
|
-
const ordered = [...all].sort((a, b) => a.along - b.along || a.c - b.c);
|
|
95
|
-
const median = across[Math.floor((across.length - 1) / 2)];
|
|
96
|
-
return {
|
|
97
|
-
c: Math.min(Math.max(median, may[0]), may[1]),
|
|
98
|
-
lo: Math.min(...members.map((i) => span[i].lo)),
|
|
99
|
-
hi: Math.max(...members.map((i) => span[i].hi)),
|
|
100
|
-
tips: ordered,
|
|
101
|
-
};
|
|
102
|
-
});
|
|
103
|
-
}
|
package/dist/lib/blockers.d.ts
DELETED
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
import type { Doorway } from './doorways.js';
|
|
2
|
-
import type { Box, Ring, Segment } from './geom/types.js';
|
|
3
|
-
import { type RouteNetworkDestination } from './graph-types.js';
|
|
4
|
-
/** What a straight run may not cross: walls, outlines of non-crossable destinations, doorway gaps. */
|
|
5
|
-
export interface Blockers {
|
|
6
|
-
/** Wall segments. */
|
|
7
|
-
readonly walls: readonly Segment[];
|
|
8
|
-
/** Outline edges of every destination not walked through, by id. */
|
|
9
|
-
readonly solid: readonly {
|
|
10
|
-
readonly id: string;
|
|
11
|
-
readonly edges: readonly Segment[];
|
|
12
|
-
}[];
|
|
13
|
-
/** Doorway gaps; a stub from a face may not pass through one. */
|
|
14
|
-
readonly gaps: readonly Segment[];
|
|
15
|
-
/** Destinations entered through doorways: the walls they line stand in for their outlines. */
|
|
16
|
-
readonly walled: ReadonlySet<string>;
|
|
17
|
-
/** Wall spans an entrance's dock may cross — its openings — by the entrance's id. */
|
|
18
|
-
readonly passes?: ReadonlyMap<string, readonly Segment[]>;
|
|
19
|
-
}
|
|
20
|
-
/** What a blocker segment is. */
|
|
21
|
-
export declare enum BlockerKind {
|
|
22
|
-
Wall = 0,
|
|
23
|
-
Solid = 1,
|
|
24
|
-
Gap = 2
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Blocker segments bucketed by the cells their bounds cover. It only narrows the candidates: a segment it
|
|
28
|
-
* leaves out has bounds apart from the query's, so no test could hold for it.
|
|
29
|
-
*/
|
|
30
|
-
export declare class SegmentGrid {
|
|
31
|
-
/** Every blocker segment, in {@link Blockers} order: walls, then outlines, then gaps. */
|
|
32
|
-
readonly segs: Segment[];
|
|
33
|
-
/** What each segment is. */
|
|
34
|
-
readonly from: BlockerKind[];
|
|
35
|
-
/** Owning destination of a solid edge; empty for walls and gaps. */
|
|
36
|
-
readonly owner: string[];
|
|
37
|
-
private readonly cells;
|
|
38
|
-
private readonly seen;
|
|
39
|
-
private stamp;
|
|
40
|
-
/** Bounds of the filed cells, so a ray knows when it has left them all. */
|
|
41
|
-
private c0;
|
|
42
|
-
private c1;
|
|
43
|
-
private r0;
|
|
44
|
-
private r1;
|
|
45
|
-
constructor(blockers: Blockers);
|
|
46
|
-
private cover;
|
|
47
|
-
/**
|
|
48
|
-
* Walk the cells a ray passes through, nearest first, handing each segment once.
|
|
49
|
-
* @param ox Ray origin x.
|
|
50
|
-
* @param oy Ray origin y.
|
|
51
|
-
* @param nx Ray direction x.
|
|
52
|
-
* @param ny Ray direction y.
|
|
53
|
-
* @param from Ray parameter to start at.
|
|
54
|
-
* @param visit Gets a cell's new segments and the parameter where the ray leaves it; true stops.
|
|
55
|
-
*/
|
|
56
|
-
alongRay(ox: number, oy: number, nx: number, ny: number, from: number, visit: (ids: readonly number[], leaves: number) => boolean): void;
|
|
57
|
-
/**
|
|
58
|
-
* Segments whose bounds meet a box, each once, in {@link Blockers} order.
|
|
59
|
-
* @param x0 Box min x.
|
|
60
|
-
* @param y0 Box min y.
|
|
61
|
-
* @param x1 Box max x.
|
|
62
|
-
* @param y1 Box max y.
|
|
63
|
-
* @returns Their positions in {@link segs}.
|
|
64
|
-
*/
|
|
65
|
-
near(x0: number, y0: number, x1: number, y1: number): number[];
|
|
66
|
-
/**
|
|
67
|
-
* Whether a segment crosses any blocker of one kind (exact `segmentsCross` on the candidates).
|
|
68
|
-
* @param seg The segment.
|
|
69
|
-
* @param from Blocker kind.
|
|
70
|
-
* @param except Destination whose own edges do not count.
|
|
71
|
-
* @returns True when one crosses it.
|
|
72
|
-
*/
|
|
73
|
-
crosses(seg: Segment, from: BlockerKind, except?: string): boolean;
|
|
74
|
-
/**
|
|
75
|
-
* The blockers of one kind a segment crosses (exact `segmentsCross` on the candidates).
|
|
76
|
-
* @param seg The segment.
|
|
77
|
-
* @param from Blocker kind.
|
|
78
|
-
* @param except Destination whose own edges do not count.
|
|
79
|
-
* @returns The blockers crossed.
|
|
80
|
-
*/
|
|
81
|
-
crossing(seg: Segment, from: BlockerKind, except?: string): Segment[];
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Walls and outlines whose bounds meet a box.
|
|
85
|
-
* @param blockers The blockers.
|
|
86
|
-
* @param box The box.
|
|
87
|
-
* @returns Each segment with its owning destination; no owner for a wall.
|
|
88
|
-
*/
|
|
89
|
-
export declare function blockersNear(blockers: Blockers, box: Box): {
|
|
90
|
-
readonly seg: Segment;
|
|
91
|
-
readonly owner?: string;
|
|
92
|
-
}[];
|
|
93
|
-
/**
|
|
94
|
-
* The index of a blockers object, built once and kept with it.
|
|
95
|
-
* @param blockers The blockers.
|
|
96
|
-
* @returns Their index.
|
|
97
|
-
*/
|
|
98
|
-
export declare function blockerGrid(blockers: Blockers): SegmentGrid;
|
|
99
|
-
/**
|
|
100
|
-
* Whether a segment crosses a wall, a closed doorway side or the outline of a destination nobody
|
|
101
|
-
* walks through: the rule every network line keeps.
|
|
102
|
-
* @param blockers The blockers.
|
|
103
|
-
* @param seg The segment.
|
|
104
|
-
* @returns True when it crosses one.
|
|
105
|
-
*/
|
|
106
|
-
export declare function crossesBlocker(blockers: Blockers, seg: Segment): boolean;
|
|
107
|
-
/**
|
|
108
|
-
* What a run out of a destination may not cross, read once for the layer.
|
|
109
|
-
* @param destinations Every destination on the layer.
|
|
110
|
-
* @param walls The layer's wall segments.
|
|
111
|
-
* @param doors The layer's doorways.
|
|
112
|
-
* @param drawn The rest of each destination's drawing, by the destination's id.
|
|
113
|
-
* @param walled Destinations entered through doorways: the walls they line stand in for them.
|
|
114
|
-
* @param passes Wall spans an entrance's dock may cross, by the entrance's id.
|
|
115
|
-
* @returns The blockers.
|
|
116
|
-
*/
|
|
117
|
-
export declare function blockersOf(destinations: readonly RouteNetworkDestination[], walls: readonly Segment[], doors: readonly Doorway[], drawn?: readonly {
|
|
118
|
-
readonly id: string;
|
|
119
|
-
readonly ring: Ring;
|
|
120
|
-
}[], walled?: ReadonlySet<string>, passes?: ReadonlyMap<string, readonly Segment[]>): Blockers;
|
|
121
|
-
/**
|
|
122
|
-
* How far a ray runs before it meets a blocker, by exact intersection, and what it met.
|
|
123
|
-
* @param ox Ray origin x.
|
|
124
|
-
* @param oy Ray origin y.
|
|
125
|
-
* @param nx Ray direction x.
|
|
126
|
-
* @param ny Ray direction y.
|
|
127
|
-
* @param ownId Destination the ray leaves.
|
|
128
|
-
* @param own `'skip'` ignores its outline; `'ahead'` counts only the outline ahead of the start.
|
|
129
|
-
* @param withGaps Whether a doorway gap stops the ray.
|
|
130
|
-
* @param blockers What the ray may meet.
|
|
131
|
-
* @returns The distance, or `Infinity` when the ray meets nothing.
|
|
132
|
-
*/
|
|
133
|
-
export declare function freeRun(ox: number, oy: number, nx: number, ny: number, ownId: string, own: 'skip' | 'ahead', withGaps: boolean, blockers: Blockers): number;
|
|
134
|
-
//# sourceMappingURL=blockers.d.ts.map
|