UNPKG

minotor

Version:

A lightweight client-side transit routing library.

205 lines (204 loc) 8.27 kB
import { StopId } from '../stops/stops.js'; import { StopRouteIndex } from '../timetable/route.js'; import { Duration, Time } from '../timetable/time.js'; import { TransferType, TripStop } from '../timetable/timetable.js'; import { AccessPoint } from './access.js'; import type { IRaptorState } from './raptor.js'; /** * Sentinel value used in the internal arrival-time array to mark stops not yet reached. * 0xFFFF = 65 535 minutes ≈ 45.5 days, safely beyond any realistic transit arrival time. */ export declare const UNREACHED_TIME: Time; export type OriginNode = { stopId: StopId; arrival: Time; }; export type AccessEdge = { arrival: Time; from: StopId; to: StopId; duration: Duration; }; /** A boarded transit trip that carries the passenger from one stop to another. */ export type VehicleEdge = TripStop & { arrival: Time; hopOffStopIndex: StopRouteIndex; /** modeling in-seat transfer */ continuationOf?: VehicleEdge; }; /** A walking or guaranteed connection between two stops. */ export type TransferEdge = { arrival: Time; from: StopId; to: StopId; type: TransferType; minTransferTime?: Duration; }; export type RoutingEdge = OriginNode | AccessEdge | VehicleEdge | TransferEdge; /** The earliest arrival at a stop together with how many legs were needed to reach it. */ export type Arrival = { arrival: Time; legNumber: number; }; /** * Encapsulates all mutable state for a single RAPTOR routing query. */ export declare class RoutingState implements IRaptorState { /** Origin stop IDs for this query. */ origins: StopId[]; /** Destination stop IDs for this query. */ readonly destinations: StopId[]; /** * Routing graph: the best edge used to reach each stop, per round. * Indexed as graph[round][stopId]. Entries are undefined for stops not * reached in that particular round. */ readonly graph: (RoutingEdge | undefined)[][]; /** * Earliest arrival time at each stop (minutes from midnight), indexed by stop ID. * Pre-filled with UNREACHED_TIME; updated exclusively through updateArrival(). * Not readonly so that fromTestData() can replace the arrays directly. */ private earliestArrivalTimes; /** * Round number (leg count) in which each stop was first reached, indexed by stop ID. * Zero-initialized by the typed array; updated exclusively through updateArrival(). * Not readonly so that fromTestData() can replace the arrays directly. */ private earliestArrivalLegs; /** * Fast O(1) membership test for destination stops. * Built once at construction time from the `destinations` array. */ private readonly destinationSet; /** * Cached best arrival time at any destination stop, kept up-to-date by * {@link updateArrival} so that destination pruning is always O(1). */ private _destinationBest; /** * Maximum arrival time allowed for this run. Defaults to UNREACHED_TIME when * the query has no maxDuration limit. */ maxArrivalTime: Time; /** * Query-level maximum duration, retained so resetFor() can recompute the * absolute max arrival time for each departure-time iteration. */ private readonly maxDuration?; /** * Every stop that has received an arrival improvement during the current run, * in the order the improvements occurred. Used by {@link resetFor} to clear * only the touched entries instead of scanning the entire array. */ private readonly reachedStops; constructor(departureTime: Time, destinations: StopId[], accessPaths: AccessPoint[], nbStops: number, maxRounds?: number, maxDuration?: Duration); /** * Seeds round-0 arrivals and {@link origins} from a set of access paths. * Called by the constructor and by {@link resetFor}. * Assumes {@link earliestArrivalTimes} and {@link graph}[0] are already * allocated and in their "cleared" state (all entries at UNREACHED_TIME / * undefined) before this method runs. */ private seedAccessPaths; /** Total number of stops in the timetable */ get nbStops(): number; /** * Returns the earliest known arrival time at a stop. * Returns UNREACHED_TIME if the stop has not been reached yet. */ arrivalTime(stop: StopId): Time; /** * Earliest arrival at any destination stop; {@link UNREACHED_TIME} if none * has been reached yet. Updated automatically by {@link updateArrival}. O(1). */ get destinationBest(): Time; /** * In standard RAPTOR the improvement bound is simply the per-run earliest * arrival; the `round` argument is ignored. */ improvementBound(_round: number, stop: StopId): Time; /** No-op in standard RAPTOR — there are no shared cross-run labels to propagate. */ initRound(_round: number): void; /** * Records a new earliest arrival at a stop. * * @param stop The stop that was reached. * @param time The arrival time in minutes from midnight. * @param leg The round number (number of transit legs taken so far). */ updateArrival(stop: StopId, time: Time, leg: number): void; /** * Resets this state for a new departure-time iteration **without * reallocating** the underlying arrays. * * Only the stops recorded in {@link reachedStops} are touched — all other * entries are already at their initial bound values. * * After this call the state is equivalent to a freshly constructed * {@link RoutingState} for the given `depTime` and `accessPaths`. * * @param depTime New origin departure time. * @param accessPaths Access legs for this departure-time slot. */ resetFor(depTime: Time, accessPaths: AccessPoint[]): void; /** * Iterates over every stop that has been reached, yielding its stop ID, * earliest arrival time, and the number of legs taken to reach it. * * Unreached stops (those still at UNREACHED_TIME) are skipped entirely. * * @example * ```ts * for (const { stop, arrival, legNumber } of routingState.arrivals()) { * console.log(`Stop ${stop}: arrived at ${arrival} after ${legNumber} leg(s)`); * } * ``` */ arrivals(): Generator<{ stop: StopId; arrival: Time; legNumber: number; }>; /** * Finds the earliest arrival time at any stop from a given set of destinations. * * @param routingState The routing state containing arrival times and destinations. * @returns The earliest arrival time among the provided destinations. */ earliestArrivalAtAnyDestination(): Time; /** * Returns the earliest arrival at a stop as an {@link Arrival} object, * or undefined if the stop has not been reached. */ getArrival(stop: StopId): Arrival | undefined; /** * Returns `true` if `stop` is one of the query's destination stops. * O(1) — backed by a `Set` built at construction time. */ isDestination(stop: StopId): boolean; /** * Creates a {@link RoutingState} from fully-specified raw data. * * Use this in tests instead of constructing the object through the production * constructor, which is designed for incremental algorithm state. * * @param nbStops Total number of stops (sets array sizes). * @param origins Origin stop IDs. * @param destinations Destination stop IDs. * @param arrivals Each entry is `[stop, time, leg]` — the earliest arrival * time in minutes and the round number for one stop. * @param graph One element per round. Each round is a sparse list of * `[stop, edge]` pairs; stops absent from the list are * left as `undefined` in the dense output array. * * @internal For use in tests only. */ static fromTestData({ nbStops, origins, destinations, arrivals, graph, }: { nbStops: number; origins?: StopId[]; destinations?: StopId[]; arrivals?: [stop: StopId, time: Time, leg: number][]; graph?: [stop: StopId, edge: RoutingEdge][][]; }): RoutingState; }