@expofp/wayfinding-compiler 0.0.0-bootstrap.0

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.
Files changed (110) hide show
  1. package/README.md +446 -0
  2. package/dist/index.d.ts +14 -0
  3. package/dist/index.js +3 -0
  4. package/dist/lib/attach.d.ts +43 -0
  5. package/dist/lib/attach.js +199 -0
  6. package/dist/lib/axes.d.ts +76 -0
  7. package/dist/lib/axes.js +103 -0
  8. package/dist/lib/blockers.d.ts +134 -0
  9. package/dist/lib/blockers.js +289 -0
  10. package/dist/lib/cell-array.d.ts +14 -0
  11. package/dist/lib/cell-array.js +25 -0
  12. package/dist/lib/centering.d.ts +14 -0
  13. package/dist/lib/centering.js +88 -0
  14. package/dist/lib/compile-layer.d.ts +41 -0
  15. package/dist/lib/compile-layer.js +241 -0
  16. package/dist/lib/compile-wayfinding.d.ts +90 -0
  17. package/dist/lib/compile-wayfinding.js +203 -0
  18. package/dist/lib/connect.d.ts +35 -0
  19. package/dist/lib/connect.js +206 -0
  20. package/dist/lib/diagnostics.d.ts +190 -0
  21. package/dist/lib/diagnostics.js +634 -0
  22. package/dist/lib/doorways.d.ts +78 -0
  23. package/dist/lib/doorways.js +331 -0
  24. package/dist/lib/emit-network.d.ts +47 -0
  25. package/dist/lib/emit-network.js +105 -0
  26. package/dist/lib/emit-v1.d.ts +31 -0
  27. package/dist/lib/emit-v1.js +56 -0
  28. package/dist/lib/entries.d.ts +123 -0
  29. package/dist/lib/entries.js +448 -0
  30. package/dist/lib/floor-grids.d.ts +48 -0
  31. package/dist/lib/floor-grids.js +185 -0
  32. package/dist/lib/framing.d.ts +20 -0
  33. package/dist/lib/framing.js +187 -0
  34. package/dist/lib/geom/boolean-ops.d.ts +21 -0
  35. package/dist/lib/geom/boolean-ops.js +1 -0
  36. package/dist/lib/geom/clipper2-ops.d.ts +7 -0
  37. package/dist/lib/geom/clipper2-ops.js +50 -0
  38. package/dist/lib/geom/footprint.d.ts +26 -0
  39. package/dist/lib/geom/footprint.js +203 -0
  40. package/dist/lib/geom/frames.d.ts +116 -0
  41. package/dist/lib/geom/frames.js +233 -0
  42. package/dist/lib/geom/mesh-outline.d.ts +13 -0
  43. package/dist/lib/geom/mesh-outline.js +90 -0
  44. package/dist/lib/geom/normalize.d.ts +28 -0
  45. package/dist/lib/geom/normalize.js +118 -0
  46. package/dist/lib/geom/point-key.d.ts +16 -0
  47. package/dist/lib/geom/point-key.js +15 -0
  48. package/dist/lib/geom/primitives.d.ts +105 -0
  49. package/dist/lib/geom/primitives.js +184 -0
  50. package/dist/lib/geom/split-crossings.d.ts +14 -0
  51. package/dist/lib/geom/split-crossings.js +171 -0
  52. package/dist/lib/geom/types.d.ts +9 -0
  53. package/dist/lib/geom/types.js +1 -0
  54. package/dist/lib/geom/walls.d.ts +31 -0
  55. package/dist/lib/geom/walls.js +71 -0
  56. package/dist/lib/graph-invariants.d.ts +49 -0
  57. package/dist/lib/graph-invariants.js +129 -0
  58. package/dist/lib/graph-types.d.ts +143 -0
  59. package/dist/lib/graph-types.js +7 -0
  60. package/dist/lib/grid-network.d.ts +20 -0
  61. package/dist/lib/grid-network.js +349 -0
  62. package/dist/lib/lattice-map.d.ts +19 -0
  63. package/dist/lib/lattice-map.js +92 -0
  64. package/dist/lib/lattice-network.d.ts +32 -0
  65. package/dist/lib/lattice-network.js +289 -0
  66. package/dist/lib/mask.d.ts +54 -0
  67. package/dist/lib/mask.js +210 -0
  68. package/dist/lib/min-heap.d.ts +24 -0
  69. package/dist/lib/min-heap.js +73 -0
  70. package/dist/lib/network-build.d.ts +21 -0
  71. package/dist/lib/network-build.js +4 -0
  72. package/dist/lib/network-graph.d.ts +80 -0
  73. package/dist/lib/network-graph.js +467 -0
  74. package/dist/lib/network-setup.d.ts +50 -0
  75. package/dist/lib/network-setup.js +76 -0
  76. package/dist/lib/network-sizes.d.ts +29 -0
  77. package/dist/lib/network-sizes.js +22 -0
  78. package/dist/lib/network-store.d.ts +173 -0
  79. package/dist/lib/network-store.js +430 -0
  80. package/dist/lib/openings.d.ts +54 -0
  81. package/dist/lib/openings.js +387 -0
  82. package/dist/lib/place-path.d.ts +47 -0
  83. package/dist/lib/place-path.js +346 -0
  84. package/dist/lib/post-passes.d.ts +31 -0
  85. package/dist/lib/post-passes.js +305 -0
  86. package/dist/lib/reachability.d.ts +58 -0
  87. package/dist/lib/reachability.js +220 -0
  88. package/dist/lib/report.d.ts +49 -0
  89. package/dist/lib/report.js +374 -0
  90. package/dist/lib/router.d.ts +111 -0
  91. package/dist/lib/router.js +388 -0
  92. package/dist/lib/runs.d.ts +92 -0
  93. package/dist/lib/runs.js +232 -0
  94. package/dist/lib/scale.d.ts +58 -0
  95. package/dist/lib/scale.js +185 -0
  96. package/dist/lib/steiner-network.d.ts +19 -0
  97. package/dist/lib/steiner-network.js +183 -0
  98. package/dist/lib/strip.d.ts +43 -0
  99. package/dist/lib/strip.js +200 -0
  100. package/dist/lib/stubs.d.ts +84 -0
  101. package/dist/lib/stubs.js +316 -0
  102. package/dist/lib/transitions.d.ts +72 -0
  103. package/dist/lib/transitions.js +191 -0
  104. package/dist/lib/types.d.ts +126 -0
  105. package/dist/lib/types.js +1 -0
  106. package/dist/lib/validate-source.d.ts +41 -0
  107. package/dist/lib/validate-source.js +133 -0
  108. package/dist/lib/walkable.d.ts +104 -0
  109. package/dist/lib/walkable.js +140 -0
  110. package/package.json +37 -0
package/README.md ADDED
@@ -0,0 +1,446 @@
1
+ # @expofp/wayfinding-compiler
2
+
3
+ Framework-neutral **wayfinding compiler** for the ExpoFP SDK: it turns raw plan geometry into a routing
4
+ graph: `lines` and `lineEnds`, in the shape of the v1 graph format, its lines not cut where they meet
5
+ (see "The emitted graph"). Pure functions only — no React, no MobX, no live stores,
6
+ no I/O. The same input always yields the same output (covered by a determinism test).
7
+
8
+ This package is the production home of the #1365 auto-routing spike. The plan and per-task status live
9
+ in the tracker: #1221 (phase 1), #1441 (phase 2), #1442 (phase 3). The route-network model it ships —
10
+ `steiner` — is described under "Route network" below.
11
+
12
+ ## Entry points
13
+
14
+ ```ts
15
+ import { compileWayfinding, type WayfindingSource } from '@expofp/wayfinding-compiler';
16
+
17
+ const source: WayfindingSource = {
18
+ layers: [{ layer: '1', walls, destinations }], // walls: flat [x,y,…] polylines; destinations: footprints
19
+ };
20
+
21
+ const { graph, report } = compileWayfinding(source); // graph: { lines, lineEnds } (v1 shape)
22
+ const debug = compileWayfinding(source, { debug: true }); // + layers, reachability, diagnostics
23
+ ```
24
+
25
+ - **`compileWayfinding(source)`** — the main entry. Returns `{ graph, report }`: the graph in the v1
26
+ shape (`lines` + `lineEnds`, not cut where they meet), and the report a designer reads — `outcome` (`built` / `built-with-gaps` / `not-built`), a one-line
27
+ `summary`, POI `counts`, and `problems` grouped by floor and reason, each with the POI names and where
28
+ to look on the plan.
29
+ - **`compileWayfinding(source, { debug: true })`** — the same single pass, adding every stage's artifacts
30
+ per layer (raw inputs, walkable area, route network), the `reachability` of the emitted graph (its
31
+ connected parts and the part every POI is bound to) and `diagnostics` — every technical fact, stage
32
+ by stage — as plain serializable data: what a debug overlay draws. The full catalog of facts is the
33
+ debug-report table under "Diagnostics and the report" below. `debug: { invariants: true }` also
34
+ checks the emitted graph against the geometric invariants (`graph-invariants.ts`: no line through a
35
+ wall or an unserved POI, every dock ending inside its ring; lines may cross or end on one another,
36
+ the converter cuts them there) and appends
37
+ the findings as the `graph` stage. The sweep is pairwise and costs a sizable share of the compile on
38
+ a large plan — about a third more on the largest fixture — so it is opted into, never implied by
39
+ `debug: true`.
40
+ - **`validateWayfindingSource(source)`** — what is wrong with a plan, as a list of `SourceIssue`
41
+ (`severity`, `code`, `message`, and the layer, id and position it belongs to). The same findings are
42
+ part of every compile's report and diagnostics.
43
+
44
+ ### The emitted graph
45
+
46
+ The graph has the shape of the v1 format, `lines` + `lineEnds`, with one difference from what
47
+ `wf.data.js` holds: its lines are not cut where they meet. An aisle is one line, a stub ends on its span,
48
+ and two aisles cross whole — as a designer draws them. The graph is not written to `wf.data.js` as it
49
+ stands. Designer saves its lines like hand-drawn ones, and the converter that builds `wf.data.js` from
50
+ the saved lines (`fpsync2`) cuts every line where another crosses it or ends within 0.1 plan units of it
51
+ — 3 cm in feet, 10 cm in meters. The report counts an end joined within the same 0.1 plan units, so it
52
+ says what the converter will join on any scale. An end the compiler emits lies within 2 cm of the line it
53
+ stops at, since a line off the plan's axes holds no point of the centimeter grid exactly: on a drawing in
54
+ tenths (before `fp-ver 5`, 1 cm or 3 mm per 0.1 unit) such an end may stay unjoined, and the report shows
55
+ it so. What a viewer reads is joined end to end, which is all the current runtime (`@expofp/wayfinding`
56
+ on `main`) and every released viewer join lines by. A reader that takes the compiler's graph directly has
57
+ to cut the lines itself.
58
+
59
+ A transition edge joins two stops of one shaft on different floors and carries:
60
+
61
+ - `virtual: true` — how the current runtime (`@expofp/wayfinding` on `main`, and every released viewer)
62
+ tells a floor change from a walk, prices it and places the floor-change markers.
63
+ - `kind` (`stairs`, `escalator` or `elevator`) and `transitionId` — v1 extensions the current runtime
64
+ ignores. The v2 runtime (`feat/wayfinding-v2-graph-format`) reads them first: `kind` makes the edge a
65
+ transition priced by its policy, `transitionId` keeps a lift serving three floors one shaft.
66
+
67
+ `@expofp/schema` describes the fields the current runtime reads; the extensions join it with the runtime
68
+ that reads them.
69
+
70
+ ### What the report says
71
+
72
+ `compileWayfinding` never throws over the plan: a plan it cannot read at all — an unnamed layer, a scale
73
+ that is not a scale — comes back `not-built`, with an empty graph and a `plan-invalid` problem. A
74
+ coordinate that is not a number stops only what it touches: a wall skips its floor (a `plan-invalid`
75
+ problem for that floor), a POI or a transition is left out and reported, and the rest of the plan
76
+ compiles. Everything else a compile can carry on around is compiled around and reported: a floor
77
+ that got no floor, or spans more than routes are built over (a plan in the wrong units, a stray drawing
78
+ far off), POI that got no dock (with the reason the stage proved — a POI standing outside the building
79
+ outline is told apart from one with no floor in front, and the problem points at the stub tip where the
80
+ failing way in ends, when one is known), POI on a part of the network the main
81
+ part does not reach, and shafts that name no kind, do not join their floors, or are left docked on one
82
+ floor only. POI that share an id, or
83
+ have none, each dock by their own geometry. One fact makes one problem — a floor that is not built is one
84
+ problem, not one per POI standing on it — and the main part of the network is the one most POI are bound
85
+ to. The reachability behind it is read off the emitted graph by the graph's own rules: nodes joined by
86
+ exact coordinates, lines joined where one ends within 0.1 plan units of another's span or crosses it
87
+ (the converter cuts the lines there), a POI bound to the `lineEnds` inside its `dock ?? polygon`.
88
+
89
+ ### Diagnostics and the report
90
+
91
+ One compile speaks to two readers. The **user report** (`CompileResult.report`, built by `report.ts`)
92
+ is for the designer: problems grouped by floor and reason, one fact — one message, in ready English.
93
+ The **debug report** (`WayfindingDebugResult.diagnostics`, produced stage by stage in
94
+ `diagnostics.ts`) is every technical fact the compile established, as plain data for a debug overlay.
95
+ Both are documented here in full; the tables are the contract.
96
+
97
+ #### User report
98
+
99
+ `report.outcome` is `built` when the graph has lines and no problem is left, `built-with-gaps` when it
100
+ has lines and problems, `not-built` when nothing was emitted. `report.counts` counts source POI only
101
+ (`poi`, `poiConnected`, `poiNotConnected`, `poiOnDetachedParts`, `networkParts`,
102
+ `floorsWithoutFloor`); transition pads are not counted. Each problem carries the `poi` it touches
103
+ (with the names the plan gave) and a `highlight` saying where to look, in plan units.
104
+
105
+ Substitutions, used throughout: `{floor}` is the floor's name — `Floor "BG"`, or `The floor` for the
106
+ one unnamed floor (`floor "BG"` / `the floor` inside a sentence); `{n}` is a count; `{names}` lists up
107
+ to 8 POI names and counts the rest (`A, B and 3 more`), a POI with no id as `unnamed POI`; singular and
108
+ plural (`is`/`are`, `it`/`they`) follow the count.
109
+
110
+ | Kind | Cause | When | Message |
111
+ | ---------------------- | ---------------------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
112
+ | `plan-invalid` | `layer-id-missing` | a layer has no id; the plan is not built | `A floor has no id; the plan cannot be built.` |
113
+ | `plan-invalid` | `units-per-meter-invalid` | the scale is not a positive finite number | `The plan's units per meter is {value}; it must be a positive number. Check the plan's units and map anchors.` |
114
+ | `plan-invalid` | `wall-coordinate-not-finite` | a wall coordinate is `NaN`/infinite; that floor alone is skipped | `{floor}: a wall has a coordinate that is not a number; the floor is not built.` |
115
+ | `nothing-to-build` | `no-floors` | the plan has no layers | `Nothing to build: the plan has no floors.` |
116
+ | `nothing-to-build` | `nothing-drawn` | every layer has neither walls nor POI | `Nothing to build: the plan has no walls and no POI.` |
117
+ | `floor-not-built` | `no-walls` | the layer has POI but no walls | `{floor}: no floor could be built — the floor has no walls, so there is nothing to build routes inside. {n} POI stand on it.` |
118
+ | `floor-not-built` | `outline-open` | no wall run closes into an outer contour | `{floor}: no floor could be built — the outer walls do not close into a contour. Check the outer walls of this floor.` |
119
+ | `floor-not-built` | `carved-away` | walls and footprints cover the whole contour | `{floor}: no floor could be built — the walls and POI drawn on it cover it whole.` |
120
+ | `floor-not-built` | `too-large` | the floor spans more than routes are built over | `{floor}: no floor could be built — it spans more than routes are built over. Check the plan's units, and any wall or POI drawn far from the hall.` |
121
+ | `poi-not-connected` | `coordinate-not-finite` | a footprint coordinate is `NaN`/infinite | `{floor}: {n} POI is/are not connected to the routes — it has/they have a coordinate that is not a number: {names}.` |
122
+ | `poi-not-connected` | `footprint-empty` | the footprint encloses no area | `… — they have no outline the plan can read: {names}.` |
123
+ | `poi-not-connected` | `dock-empty` | the `dock` ring encloses no area | `… — the rectangle routes arrive at has no area: {names}.` |
124
+ | `poi-not-connected` | `outside-building` | `no-floor` with the POI outside the outline | `… — it stands/they stand outside the building outline; routes are built inside it only: {names}.` |
125
+ | `poi-not-connected` | `entrance-far-from-walls` | an entrance outside the building with no wall within 10 m | `… — it stands/they stand more than 10 m from the nearest wall; an entrance outside the building is connected only within 10 m of a wall: {names}.` |
126
+ | `poi-not-connected` | `no-floor-behind-wall` | an entrance outside the building whose walls in reach have no floor behind them | `… — no wall near it/them opens onto floor; check that the building outline closes and that nothing stands right behind the wall: {names}.` |
127
+ | `poi-not-connected` | `no-floor-in-front` | `no-floor` inside the building | `… — there is no floor to stand on in front of it/them: {names}.` |
128
+ | `poi-not-connected` | `no-way-in` | walled in on every side | `… — they have no open side and no doorway: {names}.` |
129
+ | `poi-not-connected` | `approach-blocked` | every way in breaks a dock rule (`way-in-blocked`) | `… — a wall or another POI stands right in front of every way in: {names}.` |
130
+ | `poi-not-connected` | `cut-off` | its floor is a pocket no route reaches | `… — the floor in front of them is a pocket no route reaches: {names}.` |
131
+ | `poi-not-connected` | `lost-while-tidying` | attached, then lost to a later pass (`detached`) | `… — they were attached, then lost while the routes were tidied — reason unknown: {names}.` |
132
+ | `poi-not-connected` | `unknown` | no stage proved a cause | `… — reason unknown: {names}.` |
133
+ | `network-split` | `no-link-found` | a POI is bound off the main part AND the network stage recorded the refusal to tie | `{floor}: the routes fall into {n} separate parts: the growth found no lawful link and no floor path between the parts. {n} POI is/are on parts not connected to the rest: {names}.` |
134
+ | `network-split` | `unknown` | a POI is bound off the main part, with no recorded refusal | `{floor}: the routes fall into {n} separate parts. {n} POI is/are on parts not connected to the rest: {names}.` |
135
+ | `floors-not-connected` | `floor-detached` | the main part never reaches this floor, and a POI stands on it | `{floor}: its routes are not connected to the rest of the plan; no transition joins them. {n} POI is/are cut off: {names}.` |
136
+ | `floors-not-connected` | `transition-kind-missing` | a transition names no kind | `{transition} names no kind (stairs, escalator, elevator…) and is left out.` |
137
+ | `floors-not-connected` | `transition-coordinate-not-finite` | a stop coordinate is `NaN`/infinite | `{transition} has a stop whose coordinate is not a number and is left out.` |
138
+ | `floors-not-connected` | `transition-too-few-stops` | fewer than two known floors served | `{transition} serves fewer than two floors.` |
139
+ | `floors-not-connected` | `transition-stop-unknown-layer` | a stop names a layer the plan lacks | `{transition} names a floor the plan does not have: "{layer}".` |
140
+ | `floors-not-connected` | `transition-single-floor` | the shaft docked on one floor only | `{transition} is connected to the routes of {floor} only, so it joins no floors.` |
141
+ | `floors-not-connected` | `transition-stop-no-dock` | a stop got no dock on its layer; the stop is named when it has an id | `{transition} does not reach the routes of {floor} (stop "{id}").` |
142
+
143
+ `{transition}` is `Transition "{id}"`, or `A transition` when the plan gave none. Problems are sorted
144
+ by kind (the order of the table) and then by the plan's layer order. The one-line `summary` restates
145
+ the outcome with the counts.
146
+
147
+ #### Debug report
148
+
149
+ Every fact is a `Diagnostic`: `code`, `severity` (`error` — the plan or part of it cannot be read;
150
+ `warning` — part of the result is lost or doubtful; `info` — what a stage did), `stage`, one technical
151
+ English `message`, and where it applies: `layer`, a `ref` into the source (`kind` +
152
+ `layer`/`index`/`id`), `geometry` to draw (`bounds`/`point`/`lines`, plan units; `lines` are indices
153
+ into `graph.lines`), and `facts` — the stage's own numbers. Stages come in run order: `input`,
154
+ `scale`, then per layer `normalize` → `walkable` → `network` → `emit`, then `transitions`,
155
+ `reachability`, and — only under `debug: { invariants: true }` — `graph` last.
156
+
157
+ | Code | Severity | Stage | When | Message | Context |
158
+ | ----------------------------------- | ----------------------------------- | ------------ | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
159
+ | `no-layers` | warning | input | the plan has no layers | `the plan has no layers` | — |
160
+ | `layer-id-missing` | error | input | a layer has no id | `a layer has no id` | — |
161
+ | `layer-id-duplicate` | warning | input | two layers share an id | `two layers share an id` | ref layer |
162
+ | `destination-id-missing` | warning | input | a destination has no id | `a destination has no id` | ref destination (layer, index) |
163
+ | `destination-id-duplicate` | warning | input | two destinations on one layer share an id | `two destinations share an id` | ref destination |
164
+ | `destination-coordinate-not-finite` | warning | input | a footprint coordinate is `NaN`/infinite; the POI is left out | `a coordinate of the footprint is not a finite number` | ref destination |
165
+ | `destination-footprint-empty` | warning | input | no ring of the footprint encloses area | `the footprint encloses no area` | ref destination |
166
+ | `destination-dock-empty` | warning | input | the `dock` ring encloses no area | `the dock ring encloses no area` | ref destination |
167
+ | `wall-coordinate-not-finite` | error | input | a wall coordinate is `NaN`/infinite; the floor is skipped | `a wall coordinate is not a finite number` | ref layer |
168
+ | `transition-kind-missing` | warning | input | a transition names no kind; it is left out | `a transition names no kind` | ref transition (id) |
169
+ | `transition-coordinate-not-finite` | warning | input | a stop coordinate is `NaN`/infinite; the transition is left out | `a transition stop coordinate is not a finite number` | ref transition (id, index) |
170
+ | `transition-too-few-stops` | warning | input | fewer than two known floors served | `a transition serves fewer than two floors` | ref transition (id) |
171
+ | `units-per-meter-invalid` | error | input | the scale is not a positive finite number | `unitsPerMeter must be a finite number above zero` | — |
172
+ | `units-assumed-meters` | info | scale | the plan states no `unitsPerMeter` | `the plan states no units per meter; it is read as meters` | — |
173
+ | `wall-entry-empty` | warning | normalize | a wall entry cleans to nothing | `the wall entry cleans to no wall piece and is dropped` | ref wall (entry index) |
174
+ | `wall-entry-split` | info | normalize | one entry holds several runs | `the wall entry describes {n} separate runs, not one polyline` | ref wall; facts `runs` |
175
+ | `wall-entry-odd-length` | warning | normalize | an entry holds an odd count of numbers | `the wall entry holds an odd count of numbers; the last one names no point and is dropped` | ref wall |
176
+ | `footprint-shape` | info / warning (`bounds-oversized`) | normalize | a footprint drawn as pieces got its outline | one sentence per shape: `traced`, `hull`, `rectilinear`, `bounds`, `bounds-oversized`, `dock` (see `SHAPE_MESSAGES`) | ref destination; facts `how`, `parts` |
177
+ | `footprint-clipped` | info | normalize | the walls cut the footprint back | `the footprint ran over its walls and is cut back to the largest piece they leave` | ref destination |
178
+ | `crossable-inferred` | warning | normalize | a destination is read as walk-through | `the footprint holds other destinations, so it is walked in, not around` / `the footprint stands before the only way into another destination, so routes may cross it` | ref destination; facts `by`, `victims?` |
179
+ | `entrance-openings` | info | normalize | an entrance is reached through a wall or a doorway the walls leave | `routes reach the entrance through the wall inside its bounds, at {n} place(s)` / `the entrance stands {d} m outside the building; routes reach it through the doorway the walls leave` / `… through the nearest wall with floor behind it` | ref destination; geometry points (where the docks cross the wall); facts `by`, `openings`, `distance?` |
180
+ | `entrance-no-wall` | info | normalize | an entrance inside the building stands across no wall | `the entrance stands across no wall and is reached like any POI` | ref destination |
181
+ | `layer-no-walls` | warning | walkable | POI but no walls | `the layer has POI but no walls, so no floor is built` | ref layer; facts counts, `destinations` |
182
+ | `layer-no-outer-contour` | warning | walkable | no closed outer contour | `no wall run closes into an outer contour, so no floor is built` | ref layer; facts counts, `destinations` |
183
+ | `floor-carved-away` | warning | walkable | the contour closes but nothing is left | `the outer contour closes, but walls and footprints cover all of it` | ref layer; facts counts, `destinations` |
184
+ | `floor-built` | info | walkable | the floor is built | `the floor is built` | ref layer; facts counts, `areaM2` |
185
+ | `floor-too-large` | warning | walkable | the floor exceeds the raster budget | `the floor spans more than routes are built over, so no floor is built` | ref layer; facts `widthM`, `heightM`, `destinations` |
186
+ | `destination-unreached` | warning | network | the POI got no dock; shows in the report as `poi-not-connected` with the mapped cause | `the POI got no dock a route can end at ({reason})` | ref destination; geometry point (the failing tip); facts `reason`, `outside?`, `nearestWall?`, `floorBehind?`, `by?` |
187
+ | `doorways-found` | info | network | the stage ran; the count may be 0 | `the walls leave {n} doorway(s) on the layer` | ref layer; facts `count` |
188
+ | `network-shortcuts` | info | network | shortcut links were cut in | `{n} shortcut link(s) are cut in where the network sent a route the long way round` | ref layer; facts `count` |
189
+ | `network-pieces-untied` | warning | network | the ties gave up with pieces left; proves `network-split.cause = 'no-link-found'` on its floor | `the layer's network is left in {n} pieces: the growth found no lawful link and no floor path between them` | ref layer; facts `pieces` (total, not extra) |
190
+ | `floor-pieces-unserved` | info | network | walkable pieces serve nothing and are left out | `{n} walkable floor piece(s) hold no destination and no doorway, so no network is built over them` | ref layer; facts `count` |
191
+ | `network-parts-before-emit` | info | network | the part count before the emit | `the layer's network has {n} part(s) before the emit, shafts not counted` | ref layer; facts `count` |
192
+ | `path-segment-collapsed` | info | emit | segments shorter than the centimeter grid were skipped | `{n} path segment(s) collapse to a point on the centimeter grid and emit no line` | ref layer; facts `count` |
193
+ | `dock-collapsed` | warning | emit | a dock's ends snap to one node: its `lineEnd` stands with no line | `the dock collapses to a point on the centimeter grid: its line end is emitted with no line of its own` | ref destination (source index when known) |
194
+ | `transition-stop-bound` | info | transitions | where a stop rides in | `the transition stop stands in the open and gets a pad of its own` / `the transition stop rides in on the dock of "{name}"` | ref transition-stop; geometry point; facts `pointId?`, `pad`, `destination?` |
195
+ | `transition-stop-ambiguous` | warning | transitions | a stop stands in several destinations | `the transition stop stands in {n} destinations and rides in on the smallest` | ref transition-stop; geometry point; facts `pointId?`, `destinations` |
196
+ | `transition-stop-no-dock` | warning | transitions | the stop's floor gave it no dock | `a transition stop got no dock on its layer, so the shaft does not reach that floor` | ref transition-stop; geometry point; facts `reason`, `pointId?` |
197
+ | `transition-stop-unknown-layer` | warning | transitions | the stop names a layer the plan lacks | `a transition stop names a layer the plan does not have` | ref transition-stop; facts `reason`, `pointId?` |
198
+ | `transition-single-floor` | warning | transitions | the shaft docked on one floor only | `the shaft docked on one floor only, so it connects nothing` | ref transition; geometry points; facts `kind` |
199
+ | `network-split` | warning | reachability | the emitted graph falls into parts | `the emitted graph falls into {n} parts` | facts `nodes[]`, `poi[]` per part |
200
+ | `destination-on-detached-part` | warning | reachability | the POI is bound off the main part | `the POI is bound to a part of the graph the main part does not reach` | ref destination; facts `part` |
201
+ | `destination-unbound` | warning | reachability | no `lineEnd` lies inside the POI | `no line end lies inside the POI` | ref destination |
202
+ | `destination-split-across-parts` | warning | reachability | the POI has ends on several parts | `the POI has line ends on more than one part` | ref destination |
203
+ | `binding-mismatch` | warning | reachability | the network stage and the binding disagree, on a floor the stage ran on, for a POI it was given | `the network stage reports the POI unreached, yet a line end lies inside it` / `…reached, yet no line end lies inside it` | ref destination |
204
+ | `line-end-unowned` | warning | reachability | ends inside no POI that start no shaft | `{n} line end(s) lie inside no POI and start no shaft` | facts `ends` |
205
+ | `line-end-shared` | warning | reachability | ends inside more than one POI | `{n} line end(s) lie inside more than one POI` | facts `ends` |
206
+ | `line-crosses-wall` | warning | graph | a segment or a dock crosses a wall | `the line crosses a wall of its layer` | ref layer; geometry lines (+ point for a dock) |
207
+ | `line-crosses-poi` | warning | graph | a segment or a dock passes through a POI it is not serving | `the line passes through a destination it is not serving` | ref layer; geometry lines (+ point for a dock) |
208
+ | `dock-outside-ring` | warning | graph | a dock's tip lies inside no `dock ?? polygon` ring | `the dock ends inside no ring a destination is bound by` | ref layer; geometry lines + point |
209
+
210
+ Where a fact is also visible in the user report, the two differ on purpose: the diagnostic is the
211
+ technical fact with the stage's own words and numbers (`destination-unreached` with
212
+ `facts.reason: 'way-in-blocked'`), the report problem is the proven cause in ready text
213
+ (`poi-not-connected`, cause `approach-blocked`). The mapping: `destination-unreached` reasons
214
+ `no-floor`/`no-way-in`/`way-in-blocked`/`cut-off`/`detached` become `poi-not-connected` causes
215
+ `no-floor-in-front` (or `outside-building` by `facts.outside` — for an entrance, `no-floor-behind-wall` by
216
+ `facts.floorBehind` or `entrance-far-from-walls` by `facts.nearestWall`)/`no-way-in`/`approach-blocked`/
217
+ `cut-off`/`lost-while-tidying`; input facts `destination-coordinate-not-finite`,
218
+ `destination-dock-empty`, `destination-footprint-empty` take priority in that order;
219
+ `network-pieces-untied` turns `network-split`'s cause to `no-link-found`; the `graph` stage never
220
+ reaches the report.
221
+
222
+ ### Reusing the walkable area
223
+
224
+ The walkable stage depends only on the walls and the carved footprints — never on the route network.
225
+ `compileWayfinding(source, { walkable })` takes ready areas by layer id and skips the stage for each of
226
+ them, so a caller iterating on the route-network generator, or holding the artifacts of an earlier
227
+ compile of the same geometry, pays for the network alone. `CompileProgress.cached` says which stages
228
+ were handed their artifact rather than running. The saving is small — the walkable stage is some 6–17%
229
+ of a compile on real plans, the network is the rest.
230
+
231
+ The compile is synchronous and takes seconds on a large plan: call it from a worker. On the main
232
+ thread `onProgress` fires, but nothing is repainted until the compile returns.
233
+
234
+ ```ts
235
+ const first = compileWayfinding(source, { debug: true });
236
+ const walkable = Object.fromEntries(first.layers.map((l) => [l.layer, l.walkable]));
237
+
238
+ const again = compileWayfinding(source, { debug: true, walkable }); // route network only
239
+ ```
240
+
241
+ The package is **booth-agnostic**: a `destination` is any footprint a route must reach (obstacle + POI +
242
+ connection point). The efp glue maps a booth to one; the compiler never sees the word "booth". A
243
+ destination with `crossable: true` (a bag check, a
244
+ security gate) stays walkable and the route may pass through it. The caller states that flag, and the
245
+ compiler adds two readings of its own: a destination holding smaller destinations inside it is a zone
246
+ people walk about in rather than an obstacle, and a footprint that leaves another destination no lawful
247
+ way in at all — while being reachable itself — is the ground a route has to cross to arrive.
248
+ A destination with `entrance: true` is a way into the building: routes reach it through the wall it
249
+ stands across, inside its bounds, and one outside the building through the nearest wall with floor
250
+ behind it (see [Entrances go through the walls](#entrances-go-through-the-walls)).
251
+
252
+ ### Footprints given as pieces, and where a route lands
253
+
254
+ A destination whose real shape is not a polygon the plan can state — a round bar, an L-shaped lounge, a
255
+ cloverleaf hall, a pictogram in two parts — supplies **`parts`** instead: the raw pieces (triangles,
256
+ sub-shapes) it is drawn from. They replace `polygon`. The compiler reads the outline off the mesh's own
257
+ edges — an edge no two pieces share is on the boundary (`geom/mesh-outline.ts`) — and carves the largest
258
+ outer ring as it is, however many corners it turns. A mesh whose edges do not close falls back to the
259
+ older reading (`geom/footprint.ts`): its convex hull when the pieces fill ≥ 95 % of it and the hull has at
260
+ most six vertices, a traced outline when it is one loop of at most twelve axis-aligned edges, and its
261
+ bounding box otherwise; a mesh of more than 64 pieces is boxed without tracing.
262
+
263
+ The drawing and the `dock` rectangle are two statements about one place, so the footprint is the two
264
+ joined. A piece identical to the rectangle is the rectangle delivered twice and is left out of the
265
+ reading: laid over the drawing it runs along the drawing's own edges, those edges are then seen twice,
266
+ and the ring that closed through them disappears with them — a room read as a frame around itself. Where
267
+ the drawing falls into separate blocks, the footprint is the block the rectangle stands in, read from the
268
+ drawing's own rings rather than from the traced answer, which gives one ring and gives the biggest. The
269
+ other blocks are drawn all the same, so they are carved out of the floor as obstacles no route arrives
270
+ at.
271
+
272
+ A destination may also name a **`dock`** — a CONVEX ring inside the footprint that a route endpoint must
273
+ land in. Supply it when the host identifies a destination by a rectangle of its own, especially when its
274
+ containment test only accepts convex polygons. The ways in are then laid from the ring: the middle of each
275
+ of its sides is where the dock ends, and the side's outward normal carries it to the footprint, where the
276
+ whisker leaves — dock end, foot and tip on one line.
277
+
278
+ ## Stages
279
+
280
+ `compile-wayfinding.ts` runs the plan: validation and scale, the transition stops, each layer through
281
+ `compile-layer.ts` (the destinations read as the stages see them, then the stages below), the emit and the
282
+ report.
283
+
284
+ | Stage | Module | What it does |
285
+ | ------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
286
+ | Normalize | `geom/normalize.ts` | Reads raw wall entries into their real runs (`cleanPolylineRuns`; `geom/walls.ts` runs it over every entry) and cleans destination rings (`cleanRing`). |
287
+ | Walkable area | `walkable.ts` | interior(building outlines) − obstacles − wall strips; the outlines come from `@expofp/wayfinding-geometry`. |
288
+ | Route network | `steiner-network.ts` | The network along the directions the plan is drawn in, one module per pass (named below): a stub per open face, the aisle axes the stub tips define, rows and perimeters on them, one growth over an eroded raster joining the pieces and lone tips with every path laid on those axes, then the passes listed below. |
289
+ | Emit v1 | `emit-v1.ts` | Restates the network as `lines` + `lineEnds` (the v1 graph), moving no point; what collapses on the centimeter grid is counted and reported (`path-segment-collapsed`, `dock-collapsed`). |
290
+
291
+ ### The floor a plan draws
292
+
293
+ The floor starts inside the building outlines the walls draw (`buildingOutlines` of
294
+ `@expofp/wayfinding-geometry`, the rule the runtime reads the same walls with; the rule is in that
295
+ package's README). The compiler sets no `maxBridge`, so every opening closes and some floor is built. A
296
+ bridge closing an outline borders the floor and is no wall: strips, blockers and doorways read the walls
297
+ as drawn. Walls that draw no outline leave the layer with walls but no floor (`floor-not-built`, cause
298
+ `outline-open`).
299
+
300
+ ### Entrances go through the walls
301
+
302
+ An `entrance` destination (`openings.ts`) is a way into the building. The walls stay whole — the
303
+ walkable area, the blockers and the invariants read them as drawn — and the entrance gets an opening:
304
+ a doorway it owns, standing on the floor half a person past the wall's thickness, from which its dock
305
+ runs back through the wall. That dock is the one line that may cross a wall, and only inside the
306
+ opening's span (`Blockers.passes`); the entrance is reached through its openings alone, never from a
307
+ face. An opening on a doorway the walls already leave is that doorway.
308
+
309
+ - **Across a wall**: every wall piece inside the entrance's bounds (`dock`, else `polygon`) is an
310
+ opening, through its middle, onto each side with floor behind the wall. Pieces on one line (within a
311
+ wall's thickness) are one opening, however many vertices or polylines draw the wall. A piece shorter
312
+ than a person makes no opening, nor does a wall with no floor on either side.
313
+ - **Outside the building**, across no wall: a doorway the walls already leave comes first — the
314
+ stretch of the building outline no wall runs along, at least a person wide, nearest the entrance's
315
+ middle within 10 m (`ENTRANCE_REACH`), with floor behind it and no wall between; the dock runs through
316
+ it and crosses no wall. Only with no such doorway in reach: of the walls within 10 m of its bounds,
317
+ the one nearest to its middle that has floor and a person's clearance on the side away from the
318
+ entrance, with no other wall between, is the opening, where the bounds project onto it, at least a
319
+ person wide around the entrance's middle; the dock runs from it through the wall to the entrance. The
320
+ choice is deterministic, so an entrance between two buildings joins the nearer one. No wall in reach,
321
+ or none that qualifies (an outline that does not close, a second line right behind the wall), opens
322
+ nothing: the entrance is reported with the distance and whether such a wall was found
323
+ (`destination-unreached`, facts `nearestWall`, `floorBehind`), never joined by guesswork.
324
+ - Inside the building and across no wall, an entrance is reached like any POI (`entrance-no-wall`).
325
+
326
+ The graph invariants let an entrance's dock cross a wall (`line-crosses-wall` is not raised for a dock
327
+ that ends in an entrance); every other line keeps the rule.
328
+
329
+ ### Route network: the steiner network
330
+
331
+ The raster router works on a soft-eroded clearance field (≥ 0.8 m free; 0.3–0.8 m passable at ~9× cost,
332
+ so a doorway is taken only when no wider path exists) with turn and wall-proximity penalties, which keeps
333
+ axes straight and centered. Doorways come from the gaps the walls leave: a gap counts when nothing is drawn
334
+ across its span — no wall, and no outline of a destination nobody walks through, unless that destination is
335
+ the one the doorway opens into. Gaps between two wall pieces on one line are read first; the line closing a polyline's own
336
+ ends counts where the polyline turns more than half a turn and neither end is already a jamb of such a gap.
337
+ A doorway opens into the destination whose outline it lies on or in; the one destination standing in the room the polyline encloses, POI walked through such as an exit or a stair left out — a room holding more is a hall, its door a way into the space the network reaches; or the outline straight ahead within a person's clearance. The passes, in order:
338
+
339
+ 1. **Directions, mask and router** (`floor-grids.ts`, `mask.ts`, `router.ts`) — the directions the destinations are drawn in (`geom/frames.ts`: each by
340
+ its longest side, two sides being one direction while the raster cannot tell them apart along their
341
+ length; a destination whose reach — a stub's length around it — meets no other's of the same direction
342
+ is a stand set at an angle and opens none, and so do stands turned in a hall drawn square: the hall is
343
+ read from the first wall along each of the direction's four ways from each stand's middle, by the length
344
+ that runs along the direction against the length along the plan's axes). For each, the walkable rings without the pieces of floor
345
+ nobody stands in (no destination, no transition stop), a clearance field, and a coarser router grid whose
346
+ seams block steps across thin walls — the plan's own grid over the whole floor, a turned direction's over
347
+ its destinations and their reach. The router walks all the grids as one: a cell with room to turn steps
348
+ onto the same spot of another grid at the cost of a turn (anywhere, on a grid with no room to turn), so
349
+ along an aisle the grid of its own direction wins, running straight where the others climb stairs. A
350
+ doorway is open only at its middle — one person's clearance and a cell either side; the rest of the gap is
351
+ closed in the mask and blocked like the wall beside it. Every doorway's throat counts a person's
352
+ clearance at its middle, however narrow the gap, so a route can pass a door the wall's own thickness
353
+ would otherwise strangle.
354
+ 2. **Stubs** (`stubs.ts`) — every way into a destination (`entries.ts`, over `blockers.ts` and `strip.ts`: each edge with room in front of it and every
355
+ doorway that opens into it, measured by exact rays rather than raster probes; a destination with a
356
+ docking ring is entered from the ring's sides, a doorway dock runs along the doorway's normal, or else to
357
+ the ring side facing it) gets a stub, one per side (one in all for a `terminal` destination, doorways
358
+ first): square out of the face to the middle of the aisle ahead, so the stubs from both sides of an
359
+ aisle meet on one line. The aisle is as wide as what stands across the face — other destinations'
360
+ outlines, or wall lines (their doorways included) that a destination entered through doorways lines
361
+ within a person's width behind them — over half the face's width or more (a doorway reads its own
362
+ width), so a room corner or a gap in the row across does not set it, and a hall wall has no row
363
+ across. The stub runs to the middle when the rows on both sides may run that far: a row is two or
364
+ more ways whose aisle middles lie on one line, however their fronts step, and its stubs may run past
365
+ their own length while the run is still a stub (at most `MAX_STRETCH` more of its own length) and
366
+ the detour that adds for two neighbors along the row, out and back, stays within `MAX_STRETCH` of
367
+ the walk along their fronts — the row's pitch. A lone face has no row to share a line with (the side
368
+ across answers by its face alone when it has no row), and an aisle narrower than a person is none.
369
+ Otherwise — open floor, a hall wall, a row across that may not — the stub is half the free run and
370
+ its own length at most. Each with a lawful dock from there; the dock is one straight run from the
371
+ tip to its end. A way in whose dock would cross a wall,
372
+ another destination's outline or a doorway is not laid at all, and the destination is reported with a
373
+ reason.
374
+ 3. **Aisle axes** (`axes.ts`; `stubs.ts` defines them from the stubs and runs the stubs to them) — per
375
+ direction, tips the raster cannot tell apart across (one cell) lie on
376
+ one row; a row's line reaches along as far as a person walks beyond its end tips (a strip half a
377
+ person wide either side, clear of walls, outlines and doorways, and never past the floor's own
378
+ size). Rows within one aisle's width (twice the clearance) of each other whose lines' reaches
379
+ overlap along share an axis when one line may serve them all — no nearer than a comfortable
380
+ clearance to any tip's face or to what stands across it; a row whose tips' bands share no line is
381
+ bounded by the tips themselves — at the lower median of their tips across, within that. The stubs that end mid-aisle
382
+ define the aisles' lines first; a stub with open floor ahead runs to such a line ahead of it when no
383
+ corridor fits between the two or its row may run that far, and the rest line up among themselves.
384
+ Each stub then runs to its aisle's axis when its dock stays lawful, over floor only. Destinations
385
+ people walk through frame nothing.
386
+ 4. **Rows, rungs and perimeters** (`framing.ts`) — the row along each axis between neighboring tips (a tip
387
+ that could not reach the axis gets a leg to it); a rung between two stubs that face each other on one
388
+ line across an aisle — the shortest way between the two stands, and the line both stubs run along —
389
+ laid onto an aisle's axis running their way within a corridor's width when there is one (legs bring
390
+ the tips over, and only the parts its row has not laid yet), so an aisle keeps one line; and each
391
+ destination's tips chained into a perimeter with square corners, along the direction's axes. A link
392
+ is laid wherever the floor is free, at any length.
393
+ 5. **Growth** (`connect.ts`; each path laid by `place-path.ts`, its runs placed by `runs.ts`) — one search
394
+ over the raster from the largest piece of the network to every
395
+ other piece and every tip standing off it, reseeded from what it cannot reach, so islands the main
396
+ network cannot reach still meet. Every straight run of a path is laid on the line its place defines —
397
+ the doorway's middle where it passes one, its aisle's axis, else the middle of its corridor (nearest
398
+ blocker each side along its whole length; an open hall wider than the run is long has none). A run is
399
+ pulled no farther than a tip stands from its axis plus half a cell (the clearance plus half a pitch),
400
+ and "along" or "across" is read as the raster tells directions apart over the length in question. Each
401
+ end meets what it joins at a node: square across the line its own line meets, along a line running the
402
+ same way, else by an elbow. A piece the router cannot reach — its cells too tight, or claimed by
403
+ another piece — is tied by an elbow from one of its nodes, else by a raster path from its own cells.
404
+ The pieces the growth and the ties could not join are returned as a count and land in
405
+ `stats.untiedPieces`.
406
+ 6. **Attach** (`attach.ts`) — each stub ends where it first meets the network: a line, or another stub, which then
407
+ ends there too, so the meeting is a node. A stub that has attached is a whisker (`Whisker`, and `anatomy.whiskers` in the
408
+ debug artifacts): its foot on the face, its tip a node of the network. A stub that meets nothing is taken to the network by an
409
+ elbow to the nearest line a free way reaches, else by a raster path laid like a growth path; a stub
410
+ whose tip no line can reach is reported with a reason. Then every line that ends nowhere goes: growth
411
+ reached tips whose stubs met a nearer line, and a dangling end that is no tip serves nothing.
412
+ 7. **`completeLines`** (`post-passes.ts`) — a dangling end along an axis of any direction is extended to the first line it
413
+ meets, until no end is left to extend.
414
+ 8. **`shortcutDetours`** (`post-passes.ts`) — a link is cut in where the walk along the network is over twice the walk
415
+ across the floor, one link per network point; laid like a growth path. No link laid after the attach
416
+ crosses a stub short of its tip: a route would walk past that destination and back. The links cut
417
+ in are returned as a count and land in `stats.shortcuts`.
418
+ 9. **Emit** (`emit-network.ts`) — a doorway dock that turns for a side of its ring gets a line of the network from its tip to
419
+ the doorway's middle and leaves from there; `splitCrossings` (`geom/split-crossings.ts`) makes every
420
+ meeting a vertex; the docks are drawn from the tips into the destinations. A straight run is emitted as
421
+ one line through every meeting on it (`joinStraightRuns`, `network-graph.ts`): an aisle is one line, movable as one in the editor, the stubs
422
+ meeting it end on its span, and two aisles cross whole. The converter cuts a line where another
423
+ ends on it or crosses it when it builds `wf.data.js`. Of the network's pieces, the one with most docks is
424
+ emitted, and each further piece only when it docks a destination no emitted piece does — a piece the
425
+ floor cuts off serves what nothing else can, and nothing else. Every destination without a dock is
426
+ listed in `stats.unreached` with why, and with the facts the stage proved: whether it stands outside
427
+ the building, where the failing way in ends, and which emit check took a `detached` one's whisker.
428
+ Besides `unreached` and `components`, `stats` carries the layer's counts: the doorways found
429
+ (`doorways`), the shortcut links (`shortcuts`), the pieces left untied (`untiedPieces`, only when
430
+ some are), and the walkable floor pieces no destination or doorway serves (`unservedFloorPieces`,
431
+ likewise).
432
+
433
+ Network sizes: fixed in `network-sizes.ts` (`NETWORK_SIZES`), validated on the fixture plans. Every
434
+ other distance the stage reads is derived from them or from the plan: the raster cell for what lies on
435
+ one line, the clearance for what shares an aisle, exact rays for how far a line reaches; the shortcut
436
+ limits (`MAX_STRETCH` and the pass budgets) are the one open item.
437
+
438
+ ## Boundaries
439
+
440
+ - **Pure & deterministic.** No I/O, no globals, no framework coupling — safe in Node and the browser.
441
+ - **Geometry cleanup is owned here.** Mechanical normalization of the raw geometry (vertex dedup,
442
+ run splitting, collinear collapse) happens in this compiler, not in the data pipeline.
443
+ - **Boolean ops isolated.** All `clipper2-ts` calls sit behind the internal `BooleanOps` adapter
444
+ (`geom/clipper2-ops.ts` is the only module importing clipper) — swapping the backend is one file.
445
+ - **Self-contained geometry.** Coordinate primitives (`Ring`, `Vec2`) live in `geom/types.ts`;
446
+ `clipper2-ts` is the package's only runtime dependency besides `tslib`.
@@ -0,0 +1,14 @@
1
+ export { compileWayfinding } from './lib/compile-wayfinding.js';
2
+ export type { SourceDestination, SourceTransition, SourceTransitionPoint, WayfindingLayerSource, WayfindingSource, } from './lib/types.js';
3
+ export type { WfV1Graph, WfV1Line, WfV1Point } from './lib/types.js';
4
+ export type { SourceIssue } from './lib/validate-source.js';
5
+ export { validateWayfindingSource } from './lib/validate-source.js';
6
+ export type { CompileOptions, CompileProgress, CompileResult, LayerDebug, WayfindingDebugResult, } from './lib/compile-wayfinding.js';
7
+ export type { Diagnostic, Highlight, Severity, SourceRef, Stage } from './lib/diagnostics.js';
8
+ export type { WallLine } from './lib/geom/normalize.js';
9
+ export type { RouteNetwork, RouteNetworkDock, UnreachedReason } from './lib/graph-types.js';
10
+ export type { NetworkPart, PoiBinding, PoiRef, Reachability } from './lib/reachability.js';
11
+ export type { CompileReport, Outcome, Problem, ProblemKind } from './lib/report.js';
12
+ export type { WalkableArea } from './lib/walkable.js';
13
+ export type { Ring, Vec2 } from './lib/geom/types.js';
14
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ // Public API: entry points and their data contracts. Everything else is internal.
2
+ export { compileWayfinding } from './lib/compile-wayfinding.js';
3
+ export { validateWayfindingSource } from './lib/validate-source.js';
@@ -0,0 +1,43 @@
1
+ import type { Connector } from './connect.js';
2
+ import { type Whisker } from './entries.js';
3
+ import type { Segment } from './geom/types.js';
4
+ import type { NetworkBuild } from './network-build.js';
5
+ import type { NetworkStore } from './network-store.js';
6
+ import type { Router } from './router.js';
7
+ import { type StubPlan } from './stubs.js';
8
+ /**
9
+ * The first network line a ray meets. A line lying along the ray is met at its nearer end when that is
10
+ * ahead, else at its far end.
11
+ * @param store The network.
12
+ * @param ox Ray origin x.
13
+ * @param oy Ray origin y.
14
+ * @param nx Ray direction x.
15
+ * @param ny Ray direction y.
16
+ * @param maxT How far to look.
17
+ * @returns The segment id and distance, or null within `maxT`.
18
+ */
19
+ export declare function firstNetworkAlong(store: NetworkStore, ox: number, oy: number, nx: number, ny: number, maxT: number): {
20
+ id: number;
21
+ t: number;
22
+ } | null;
23
+ /** What attaching the stubs reads and extends. */
24
+ interface Attaching extends NetworkBuild {
25
+ /** The stubs planned, and how to retry one that fails. */
26
+ readonly plan: StubPlan;
27
+ /** The network; extended in place. */
28
+ readonly store: NetworkStore;
29
+ /** Lays the links and the raster paths. */
30
+ readonly connector: Connector;
31
+ /** The raster router. */
32
+ readonly router: Router;
33
+ /** Whether a line may be laid. */
34
+ readonly mayLay: (seg: Segment) => boolean;
35
+ }
36
+ /**
37
+ * Attaches every stub to the network, retrying a destination's next way in when one fails.
38
+ * @param attaching What the attach reads and extends.
39
+ * @returns The whiskers: the stubs attached, in the order they attached.
40
+ */
41
+ export declare function attachStubs(attaching: Attaching): Whisker[];
42
+ export {};
43
+ //# sourceMappingURL=attach.d.ts.map