@bloomsparkagency/wayfinding - Wayfinding Engine
The wayfinding package calculates high-performance, multi-floor routing paths through indoor buildings. It constructs an internal connectivity graph directly from IMDF properties and executes search calculations inside a background Web Worker using Comlink RPC.
🧮 Multi-Floor Graph Calculations & A*
The wayfinding engine builds a network graph from two layers of connectivity: same-floor links and vertical transitions.
1. Same-Floor Connectivity
Same-floor routing paths are calculated directly by evaluating IMDF features:
- Units & Openings: IMDF
Unitpolygons connect to other units through adjacentOpeningfeatures (pedestrian openings, service doors, or ramps). - Avenue Nodes: Center-points of openings become graph nodes; paths are traced through unit centers to form edges.
2. Vertical Connection Inference (Stairs & Elevators)
Since standard IMDF Opening features only define same-floor links, the engine automatically infers vertical transitions:
- Proximity Matching: The compiler scans for features with categories matching
stairs,elevator,escalator, orramp. - Anchor Alignment: If the IMDF
Anchordisplay_pointcoordinate of a vertical transition feature on Floor A aligns horizontally within 5 meters of an equivalent vertical transition feature on Floor B (adjacent levels), a directed vertical edge is created in the graph. - Weight Penalty Settings:
- Elevators: Fixed travel-time penalty of 30 seconds per floor transition.
- Stairs: Travel-time penalty calculated as: $$\text{Time} = \frac{\text{Floor Height (meters)}}{1.2\text{ m/s}}$$
- Escalators: Travel-time penalty of 15 seconds per floor.
3. Accessible Mode (accessible: true)
When accessibility parameters are passed, the A* engine recalculates routing options:
- Stair & Escalator Culling: Graph edges corresponding to
stairsandescalatorcategories are assigned an edge weight ofInfinity(complete exclusion). - Ramps & Elevators Only: Routing paths are restricted exclusively to
rampandelevatorvertical linkages.
⚙️ Routing APIs
import { IMDFArchive } from '@bloomsparkagency/imdf';
/** Compile an IMDF archive into a wayfinding graph. Cached inside the Web Worker. */
export function buildGraph(archive: IMDFArchive): WayfindingGraph;
/** Finds the shortest path between two room/feature IDs. */
export function getDirections(
graph: WayfindingGraph,
originUnitId: string,
destUnitId: string,
opts?: RouteOptions
): RouteResult;
/** Identifies paths visiting multiple stops in sequential order. */
export function getDirectionsMultiDestination(
graph: WayfindingGraph,
originUnitId: string,
destUnitIds: string[],
opts?: RouteOptions
): RouteResult;
export interface RouteOptions {
/** If true, filters out stairs and escalators. */
accessible?: boolean;
/** Apply Chaikin smoothing algorithms to round off raw zig-zag line edges. */
smoothing?: boolean;
/** Block specific unit/opening UUIDs (e.g. temporary maintenance closures). */
excludedConnectionIds?: string[];
/** Specific areas on the map that increase A* edge costs (e.g. crowded main lobbies). */
avoidanceZones?: { coordinates: [number, number][]; costMultiplier: number }[];
}
export interface RouteResult {
legs: RouteLeg[];
totalDistance: number; // in meters
totalDuration: number; // in seconds
}
export interface RouteLeg {
floorId: string;
floorOrdinal: number;
/** GeoJSON LineString coordinates for the path on this level. */
coordinates: [number, number][];
/** Navigational maneuvers, e.g. "Take elevator to Floor 3" */
instruction: string;
distance: number;
}🔍 Search Index Compilation (MiniSearch)
To power search inputs, the wayfinding package compiles a text-search index over spatial attributes:
- Index Compilation: Built once inside the Web Worker after the IMDF finishes loading.
- Fields Scanned:
unit.name,unit.alt_name,amenity.category,occupant.name, and custom keywords. - No Full Rebuilds: When drawing modifications are saved in the editor, incremental events are posted:typescript
worker.miniSearch.add(newFeature); worker.miniSearch.update(modifiedFeature); worker.miniSearch.remove(deletedFeatureId); - Zero Main-Thread Block: The search index query is executed asynchronously in the background. Selecting a search result fires
Camera.focusOn(feature)and centers the map view instantly.
