minotor 11.1.2 → 11.2.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 (71) hide show
  1. package/.cspell.json +7 -1
  2. package/CHANGELOG.md +3 -3
  3. package/README.md +111 -86
  4. package/dist/cli/perf.d.ts +57 -18
  5. package/dist/cli.mjs +1371 -342
  6. package/dist/cli.mjs.map +1 -1
  7. package/dist/parser.cjs.js +57 -4
  8. package/dist/parser.cjs.js.map +1 -1
  9. package/dist/parser.esm.js +57 -4
  10. package/dist/parser.esm.js.map +1 -1
  11. package/dist/router.cjs.js +1 -1
  12. package/dist/router.cjs.js.map +1 -1
  13. package/dist/router.d.ts +5 -5
  14. package/dist/router.esm.js +1 -1
  15. package/dist/router.esm.js.map +1 -1
  16. package/dist/router.umd.js +1 -1
  17. package/dist/router.umd.js.map +1 -1
  18. package/dist/routing/__tests__/access.test.d.ts +1 -0
  19. package/dist/routing/__tests__/plainRouter.test.d.ts +1 -0
  20. package/dist/routing/__tests__/rangeResult.test.d.ts +1 -0
  21. package/dist/routing/__tests__/rangeRouter.test.d.ts +1 -0
  22. package/dist/routing/__tests__/rangeState.test.d.ts +1 -0
  23. package/dist/routing/__tests__/raptor.test.d.ts +1 -0
  24. package/dist/routing/__tests__/state.test.d.ts +1 -0
  25. package/dist/routing/access.d.ts +55 -0
  26. package/dist/routing/plainRouter.d.ts +21 -0
  27. package/dist/routing/plotter.d.ts +9 -0
  28. package/dist/routing/query.d.ts +132 -13
  29. package/dist/routing/rangeResult.d.ts +155 -0
  30. package/dist/routing/rangeRouter.d.ts +24 -0
  31. package/dist/routing/rangeState.d.ts +83 -0
  32. package/dist/routing/raptor.d.ts +96 -0
  33. package/dist/routing/result.d.ts +27 -7
  34. package/dist/routing/route.d.ts +5 -21
  35. package/dist/routing/router.d.ts +20 -91
  36. package/dist/routing/state.d.ts +92 -17
  37. package/dist/timetable/route.d.ts +8 -0
  38. package/dist/timetable/timetable.d.ts +17 -1
  39. package/package.json +1 -1
  40. package/src/__e2e__/benchmark.json +18 -0
  41. package/src/__e2e__/router.test.ts +461 -127
  42. package/src/cli/minotor.ts +39 -3
  43. package/src/cli/perf.ts +324 -60
  44. package/src/cli/repl.ts +96 -41
  45. package/src/router.ts +11 -3
  46. package/src/routing/__tests__/access.test.ts +294 -0
  47. package/src/routing/__tests__/plainRouter.test.ts +1633 -0
  48. package/src/routing/__tests__/plotter.test.ts +8 -8
  49. package/src/routing/__tests__/rangeResult.test.ts +273 -0
  50. package/src/routing/__tests__/rangeRouter.test.ts +472 -0
  51. package/src/routing/__tests__/rangeState.test.ts +246 -0
  52. package/src/routing/__tests__/raptor.test.ts +366 -0
  53. package/src/routing/__tests__/result.test.ts +27 -27
  54. package/src/routing/__tests__/route.test.ts +28 -0
  55. package/src/routing/__tests__/router.test.ts +75 -1587
  56. package/src/routing/__tests__/state.test.ts +78 -0
  57. package/src/routing/access.ts +144 -0
  58. package/src/routing/plainRouter.ts +60 -0
  59. package/src/routing/plotter.ts +53 -6
  60. package/src/routing/query.ts +116 -13
  61. package/src/routing/rangeResult.ts +292 -0
  62. package/src/routing/rangeRouter.ts +167 -0
  63. package/src/routing/rangeState.ts +150 -0
  64. package/src/routing/raptor.ts +416 -0
  65. package/src/routing/result.ts +68 -26
  66. package/src/routing/route.ts +15 -53
  67. package/src/routing/router.ts +40 -480
  68. package/src/routing/state.ts +191 -32
  69. package/src/timetable/__tests__/timetable.test.ts +373 -0
  70. package/src/timetable/route.ts +16 -4
  71. package/src/timetable/timetable.ts +54 -1
@@ -1,30 +1,17 @@
1
- /* eslint-disable @typescript-eslint/no-non-null-assertion */
2
- import { StopId } from '../stops/stops.js';
3
1
  import { StopsIndex } from '../stops/stopsIndex.js';
4
- import {
5
- NOT_AVAILABLE,
6
- Route,
7
- StopRouteIndex,
8
- TripRouteIndex,
9
- } from '../timetable/route.js';
10
- import {
11
- Duration,
12
- DURATION_ZERO,
13
- Time,
14
- TIME_ORIGIN,
15
- } from '../timetable/time.js';
16
- import { Timetable, TripStop } from '../timetable/timetable.js';
17
- import { Query, QueryOptions } from './query.js';
2
+ import { Timetable } from '../timetable/timetable.js';
3
+ import { AccessFinder } from './access.js';
4
+ import { PlainRouter } from './plainRouter.js';
5
+ import { Query, RangeQuery } from './query.js';
6
+ import { RangeResult } from './rangeResult.js';
7
+ import { RangeRouter } from './rangeRouter.js';
8
+ import { Raptor } from './raptor.js';
18
9
  import { Result } from './result.js';
19
- import {
20
- RoutingEdge,
21
- RoutingState,
22
- TransferEdge,
23
- UNREACHED_TIME,
24
- VehicleEdge,
25
- } from './state.js';
26
10
 
11
+ export type { ArrivalWithDuration, ParetoRun } from './rangeResult.js';
12
+ export { RangeResult } from './rangeResult.js';
27
13
  export type {
14
+ AccessEdge,
28
15
  Arrival,
29
16
  OriginNode,
30
17
  RoutingEdge,
@@ -33,477 +20,50 @@ export type {
33
20
  } from './state.js';
34
21
  export { RoutingState, UNREACHED_TIME } from './state.js';
35
22
 
36
- type TripContinuation = TripStop & {
37
- previousEdge: VehicleEdge;
38
- };
39
-
40
- type Round = number;
41
-
42
23
  /**
43
- * A public transportation router implementing the RAPTOR algorithm.
44
- * For more information on the RAPTOR algorithm,
45
- * refer to its detailed explanation in the research paper:
46
- * https://www.microsoft.com/en-us/research/wp-content/uploads/2012/01/raptor_alenex.pdf
24
+ * A public transportation router implementing the RAPTOR and Range RAPTOR
25
+ * algorithms.
26
+ *
27
+ * Thin facade over {@link PlainRouter} and {@link RangeRouter}: constructs the
28
+ * shared {@link Raptor} engine and {@link AccessFinder} once and delegates each
29
+ * query to the appropriate router.
30
+ *
31
+ * @see https://www.microsoft.com/en-us/research/wp-content/uploads/2012/01/raptor_alenex.pdf
47
32
  */
48
33
  export class Router {
49
- private readonly timetable: Timetable;
50
- private readonly stopsIndex: StopsIndex;
34
+ private readonly plainRouter: PlainRouter;
35
+ private readonly rangeRouter: RangeRouter;
51
36
 
52
37
  constructor(timetable: Timetable, stopsIndex: StopsIndex) {
53
- this.timetable = timetable;
54
- this.stopsIndex = stopsIndex;
55
- }
56
-
57
- /**
58
- * The main Raptor algorithm implementation.
59
- *
60
- * @param query The query containing the main parameters for the routing.
61
- * @returns A result object containing data structures allowing to reconstruct routes and .
62
- */
63
- route(query: Query): Result {
64
- const routingState = this.initRoutingState(query);
65
- const markedStops = new Set<StopId>(routingState.origins);
66
- // Initial transfer consideration for origins
67
- const newlyMarkedStops = this.considerTransfers(
68
- query,
69
- 0,
70
- markedStops,
71
- routingState,
38
+ const raptor = new Raptor(timetable);
39
+ const accessFinder = new AccessFinder(timetable, stopsIndex);
40
+ this.plainRouter = new PlainRouter(
41
+ timetable,
42
+ stopsIndex,
43
+ accessFinder,
44
+ raptor,
72
45
  );
73
- for (const newStop of newlyMarkedStops) {
74
- markedStops.add(newStop);
75
- }
76
- for (let round = 1; round <= query.options.maxTransfers + 1; round++) {
77
- const edgesAtCurrentRound: (RoutingEdge | undefined)[] = new Array<
78
- RoutingEdge | undefined
79
- >(routingState.nbStops);
80
- routingState.graph.push(edgesAtCurrentRound);
81
- const reachableRoutes = this.timetable.findReachableRoutes(
82
- markedStops,
83
- query.options.transportModes,
84
- );
85
- markedStops.clear();
86
- // for each route that can be reached with at least round - 1 trips
87
- for (const [route, hopOnStopIndex] of reachableRoutes) {
88
- const newlyMarkedStops = this.scanRoute(
89
- route,
90
- hopOnStopIndex,
91
- round,
92
- routingState,
93
- query.options,
94
- );
95
- for (const newStop of newlyMarkedStops) {
96
- markedStops.add(newStop);
97
- }
98
- }
99
- // process in-seat trip continuations
100
- let continuations = this.findTripContinuations(
101
- markedStops,
102
- edgesAtCurrentRound,
103
- );
104
- const stopsFromContinuations = new Set<StopId>();
105
- while (continuations.length > 0) {
106
- stopsFromContinuations.clear();
107
- for (const continuation of continuations) {
108
- const route = this.timetable.getRoute(continuation.routeId)!;
109
- const routeScanResults = this.scanRouteContinuation(
110
- route,
111
- continuation.stopIndex,
112
- round,
113
- routingState,
114
- continuation,
115
- );
116
- for (const newStop of routeScanResults) {
117
- stopsFromContinuations.add(newStop);
118
- }
119
- }
120
- for (const newStop of stopsFromContinuations) {
121
- markedStops.add(newStop);
122
- }
123
- continuations = this.findTripContinuations(
124
- stopsFromContinuations,
125
- edgesAtCurrentRound,
126
- );
127
- }
128
- const newlyMarkedStops = this.considerTransfers(
129
- query,
130
- round,
131
- markedStops,
132
- routingState,
133
- );
134
- for (const newStop of newlyMarkedStops) {
135
- markedStops.add(newStop);
136
- }
137
-
138
- if (markedStops.size === 0) break;
139
- }
140
- return new Result(query, routingState, this.stopsIndex, this.timetable);
141
- }
142
-
143
- /**
144
- * Finds trip continuations for the given marked stops and edges at the current round.
145
- * @param markedStops The set of marked stops.
146
- * @param edgesAtCurrentRound The array of edges at the current round, indexed by stop ID.
147
- * @returns An array of trip continuations.
148
- */
149
- private findTripContinuations(
150
- markedStops: Set<StopId>,
151
- edgesAtCurrentRound: (RoutingEdge | undefined)[],
152
- ): TripContinuation[] {
153
- const continuations: TripContinuation[] = [];
154
- for (const stopId of markedStops) {
155
- const arrival = edgesAtCurrentRound[stopId];
156
- if (!arrival || !('routeId' in arrival)) continue;
157
-
158
- const continuousTrips = this.timetable.getContinuousTrips(
159
- arrival.hopOffStopIndex,
160
- arrival.routeId,
161
- arrival.tripIndex,
162
- );
163
- for (let i = 0; i < continuousTrips.length; i++) {
164
- const trip = continuousTrips[i]!;
165
- continuations.push({
166
- routeId: trip.routeId,
167
- stopIndex: trip.stopIndex,
168
- tripIndex: trip.tripIndex,
169
- previousEdge: arrival,
170
- });
171
- }
172
- }
173
- return continuations;
174
- }
175
-
176
- /**
177
- * Initializes the routing state for the RAPTOR algorithm.
178
- *
179
- * This method sets up the initial data structures needed for route planning,
180
- * including origin and destination stops (considering equivalent stops),
181
- * earliest arrival times, and marked stops for processing.
182
- *
183
- * @param query The routing query containing origin, destination, and departure time
184
- * @returns The initialized routing state with all necessary data structures
185
- */
186
- private initRoutingState(query: Query): RoutingState {
187
- const { from, to, departureTime } = query;
188
- // Consider children or siblings of the "from" stop as potential origins
189
- const origins = this.stopsIndex
190
- .equivalentStops(from)
191
- .map((origin) => origin.id);
192
- // Consider children or siblings of the "to" stop(s) as potential destinations
193
- const destinations = Array.from(to)
194
- .flatMap((destination) => this.stopsIndex.equivalentStops(destination))
195
- .map((destination) => destination.id);
196
- return new RoutingState(
197
- origins,
198
- destinations,
199
- departureTime,
200
- this.timetable.nbStops(),
46
+ this.rangeRouter = new RangeRouter(
47
+ timetable,
48
+ stopsIndex,
49
+ accessFinder,
50
+ raptor,
201
51
  );
202
52
  }
203
53
 
204
54
  /**
205
- * Scans a route for an in-seat trip continuation.
206
- *
207
- * The boarded trip and entry stop are fixed, so there is no need to probe for
208
- * earlier boardings.
209
- *
210
- * @param route The route to scan
211
- * @param hopOnStopIndex The stop index where the continuation begins
212
- * @param round The current RAPTOR round
213
- * @param routingState Current routing state
214
- * @param tripContinuation The in-seat continuation descriptor
215
- */
216
- private scanRouteContinuation(
217
- route: Route,
218
- hopOnStopIndex: StopRouteIndex,
219
- round: Round,
220
- routingState: RoutingState,
221
- tripContinuation: TripContinuation,
222
- ): Set<StopId> {
223
- const newlyMarkedStops = new Set<StopId>();
224
- const edgesAtCurrentRound = routingState.graph[round]!;
225
- const earliestArrivalAtAnyDestination =
226
- this.earliestArrivalAtAnyStop(routingState);
227
-
228
- const nbStops = route.getNbStops();
229
- const routeId = route.id;
230
- const tripIndex = tripContinuation.tripIndex;
231
- const tripStopOffset = route.tripStopOffset(tripIndex);
232
- const previousEdge = tripContinuation.previousEdge;
233
-
234
- for (
235
- let currentStopIndex = hopOnStopIndex;
236
- currentStopIndex < nbStops;
237
- currentStopIndex++
238
- ) {
239
- const currentStop: StopId = route.stops[currentStopIndex]!;
240
- const arrivalTime = route.arrivalAtOffset(
241
- currentStopIndex,
242
- tripStopOffset,
243
- );
244
- const dropOffType = route.dropOffTypeAtOffset(
245
- currentStopIndex,
246
- tripStopOffset,
247
- );
248
- const earliestArrivalAtCurrentStop =
249
- routingState.arrivalTime(currentStop);
250
- if (
251
- dropOffType !== NOT_AVAILABLE &&
252
- arrivalTime < earliestArrivalAtCurrentStop &&
253
- arrivalTime < earliestArrivalAtAnyDestination
254
- ) {
255
- edgesAtCurrentRound[currentStop] = {
256
- routeId,
257
- stopIndex: hopOnStopIndex,
258
- tripIndex,
259
- arrival: arrivalTime,
260
- hopOffStopIndex: currentStopIndex,
261
- continuationOf: previousEdge,
262
- };
263
- routingState.updateArrival(currentStop, arrivalTime, round);
264
- newlyMarkedStops.add(currentStop);
265
- }
266
- }
267
- return newlyMarkedStops;
268
- }
269
-
270
- /**
271
- * Scans a route using the standard RAPTOR boarding logic.
272
- *
273
- * Iterates through all stops from the hop-on point, maintaining the current
274
- * best trip and improving arrival times when possible. At each marked stop it
275
- * also checks whether an earlier (or first) trip can be boarded, upgrading the
276
- * active trip when one is found.
277
- *
278
- * @param route The route to scan
279
- * @param hopOnStopIndex The stop index where passengers can first board
280
- * @param round The current RAPTOR round
281
- * @param routingState Current routing state
282
- * @param options Query options (minTransferTime, etc.)
283
- */
284
- private scanRoute(
285
- route: Route,
286
- hopOnStopIndex: StopRouteIndex,
287
- round: Round,
288
- routingState: RoutingState,
289
- options: QueryOptions,
290
- ): Set<StopId> {
291
- const newlyMarkedStops = new Set<StopId>();
292
- const edgesAtCurrentRound = routingState.graph[round]!;
293
- const edgesAtPreviousRound = routingState.graph[round - 1]!;
294
- const earliestArrivalAtAnyDestination =
295
- this.earliestArrivalAtAnyStop(routingState);
296
-
297
- const nbStops = route.getNbStops();
298
- const routeId = route.id;
299
- let activeTripIndex: TripRouteIndex | undefined;
300
- let activeTripBoardStopIndex = hopOnStopIndex;
301
- // tripStopOffset = activeTripIndex * nbStops, precomputed when the trip changes.
302
- // Only valid while activeTripIndex !== undefined.
303
- let activeTripStopOffset = 0;
304
-
305
- for (
306
- let currentStopIndex = hopOnStopIndex;
307
- currentStopIndex < nbStops;
308
- currentStopIndex++
309
- ) {
310
- const currentStop: StopId = route.stops[currentStopIndex]!;
311
-
312
- // If on a trip, check whether alighting here improves the global best.
313
- if (activeTripIndex !== undefined) {
314
- const arrivalTime = route.arrivalAtOffset(
315
- currentStopIndex,
316
- activeTripStopOffset,
317
- );
318
- const dropOffType = route.dropOffTypeAtOffset(
319
- currentStopIndex,
320
- activeTripStopOffset,
321
- );
322
- const earliestArrivalAtCurrentStop =
323
- routingState.arrivalTime(currentStop);
324
- if (
325
- dropOffType !== NOT_AVAILABLE &&
326
- arrivalTime < earliestArrivalAtCurrentStop &&
327
- arrivalTime < earliestArrivalAtAnyDestination
328
- ) {
329
- edgesAtCurrentRound[currentStop] = {
330
- routeId,
331
- stopIndex: activeTripBoardStopIndex,
332
- tripIndex: activeTripIndex,
333
- arrival: arrivalTime,
334
- hopOffStopIndex: currentStopIndex,
335
- };
336
- routingState.updateArrival(currentStop, arrivalTime, round);
337
- newlyMarkedStops.add(currentStop);
338
- }
339
- }
340
-
341
- // Check whether we can board an earlier (or first) trip at this stop.
342
- const previousEdge = edgesAtPreviousRound[currentStop];
343
- const earliestArrivalOnPreviousRound = previousEdge?.arrival;
344
- if (
345
- earliestArrivalOnPreviousRound !== undefined &&
346
- (activeTripIndex === undefined ||
347
- earliestArrivalOnPreviousRound <=
348
- route.departureFrom(currentStopIndex, activeTripIndex))
349
- ) {
350
- const earliestTrip = route.findEarliestTrip(
351
- currentStopIndex,
352
- earliestArrivalOnPreviousRound,
353
- activeTripIndex,
354
- );
355
- if (earliestTrip === undefined) {
356
- continue;
357
- }
358
-
359
- const firstBoardableTrip = this.findFirstBoardableTrip(
360
- currentStopIndex,
361
- route,
362
- earliestTrip,
363
- earliestArrivalOnPreviousRound,
364
- activeTripIndex,
365
- // provide the previous edge only if it was a vehicle leg
366
- previousEdge && 'routeId' in previousEdge ? previousEdge : undefined,
367
- options.minTransferTime,
368
- );
369
-
370
- if (firstBoardableTrip !== undefined) {
371
- activeTripIndex = firstBoardableTrip;
372
- activeTripBoardStopIndex = currentStopIndex;
373
- activeTripStopOffset = route.tripStopOffset(firstBoardableTrip);
374
- }
375
- }
376
- }
377
- return newlyMarkedStops;
378
- }
379
-
380
- /**
381
- * Finds the first boardable trip on a route at a given stop that meets transfer requirements.
382
- *
383
- * This method searches through trips on a route starting from the earliest trip index reachable
384
- * from the previous edge to find the first trip that can be effectively boarded,
385
- * considering pickup availability, transfer guarantees, and minimum transfer times.
386
- *
387
- * @param stopIndex The index in the route of the stop where boarding is attempted
388
- * @param route The route to search for boardable trips
389
- * @param earliestTrip The earliest trip index to start searching from
390
- * @param after The earliest time after which boarding can occur
391
- * @param beforeTrip Optional upper bound trip index to limit search
392
- * @param previousTrip The previous trip taken (for transfer guarantee checks)
393
- * @param transferTime Minimum time required for transfers between trips
394
- * @returns The trip index of the first boardable trip, or undefined if none found
55
+ * Standard RAPTOR: finds the earliest-arrival journey from `query.from` to
56
+ * `query.to` for the given departure time.
395
57
  */
396
- private findFirstBoardableTrip(
397
- stopIndex: StopRouteIndex,
398
- route: Route,
399
- earliestTrip: TripRouteIndex,
400
- after: Time = TIME_ORIGIN,
401
- beforeTrip?: TripRouteIndex,
402
- previousTrip?: VehicleEdge,
403
- transferTime: Duration = DURATION_ZERO,
404
- ): TripRouteIndex | undefined {
405
- const nbTrips = route.getNbTrips();
406
-
407
- for (let t = earliestTrip; t < (beforeTrip ?? nbTrips); t++) {
408
- const pickup = route.pickUpTypeFrom(stopIndex, t);
409
- if (pickup === NOT_AVAILABLE) {
410
- continue;
411
- }
412
- if (previousTrip === undefined) {
413
- return t;
414
- }
415
-
416
- const isGuaranteed = this.timetable.isTripTransferGuaranteed(
417
- {
418
- stopIndex: previousTrip.hopOffStopIndex,
419
- routeId: previousTrip.routeId,
420
- tripIndex: previousTrip.tripIndex,
421
- },
422
- { stopIndex, routeId: route.id, tripIndex: t },
423
- );
424
- if (isGuaranteed) {
425
- return t;
426
- }
427
- const departure = route.departureFrom(stopIndex, t);
428
- const requiredTime = after + transferTime;
429
- if (departure >= requiredTime) {
430
- return t;
431
- }
432
- }
433
- return undefined;
434
- }
435
-
436
- /**
437
- * Processes all currently marked stops to find available transfers
438
- * and determines if using these transfers would result in earlier arrival times
439
- * at destination stops. It handles different transfer types including in-seat
440
- * transfers and walking transfers with appropriate minimum transfer times.
441
- *
442
- * @param query The routing query containing transfer options and constraints
443
- * @param round The current round number in the RAPTOR algorithm
444
- * @param routingState The current routing state containing arrival times and marked stops
445
- */
446
- private considerTransfers(
447
- query: Query,
448
- round: number,
449
- markedStops: Set<StopId>,
450
- routingState: RoutingState,
451
- ): Set<StopId> {
452
- const { options } = query;
453
- const arrivalsAtCurrentRound = routingState.graph[round]!;
454
- const newlyMarkedStops: Set<StopId> = new Set();
455
- for (const stop of markedStops) {
456
- const currentArrival = arrivalsAtCurrentRound[stop];
457
- // Skip transfers if the last leg was also a transfer
458
- if (!currentArrival || 'type' in currentArrival) continue;
459
- const transfers = this.timetable.getTransfers(stop);
460
- for (let j = 0; j < transfers.length; j++) {
461
- const transfer = transfers[j]!;
462
- let transferTime: Duration;
463
- if (transfer.minTransferTime) {
464
- transferTime = transfer.minTransferTime;
465
- } else if (transfer.type === 'IN_SEAT') {
466
- // TODO not needed anymore now that trip continuations are handled separately
467
- transferTime = DURATION_ZERO;
468
- } else {
469
- transferTime = options.minTransferTime;
470
- }
471
- const arrivalAfterTransfer = currentArrival.arrival + transferTime;
472
- const originalArrival = routingState.arrivalTime(transfer.destination);
473
- if (arrivalAfterTransfer < originalArrival) {
474
- arrivalsAtCurrentRound[transfer.destination] = {
475
- arrival: arrivalAfterTransfer,
476
- from: stop,
477
- to: transfer.destination,
478
- minTransferTime: transfer.minTransferTime,
479
- type: transfer.type,
480
- } as TransferEdge;
481
- routingState.updateArrival(
482
- transfer.destination,
483
- arrivalAfterTransfer,
484
- round,
485
- );
486
- newlyMarkedStops.add(transfer.destination);
487
- }
488
- }
489
- }
490
- return newlyMarkedStops;
58
+ route(query: Query): Result {
59
+ return this.plainRouter.route(query);
491
60
  }
492
61
 
493
62
  /**
494
- * Finds the earliest arrival time at any stop from a given set of destinations.
495
- *
496
- * @param routingState The routing state containing arrival times and destinations.
497
- * @returns The earliest arrival time among the provided destinations.
63
+ * Range RAPTOR: finds all Pareto-optimal journeys within the departure-time
64
+ * window `[query.departureTime, query.lastDepartureTime]`.
498
65
  */
499
- private earliestArrivalAtAnyStop(routingState: RoutingState): Time {
500
- let earliestArrivalAtAnyDestination: Time = UNREACHED_TIME;
501
- for (let i = 0; i < routingState.destinations.length; i++) {
502
- const arrival = routingState.arrivalTime(routingState.destinations[i]!);
503
- if (arrival < earliestArrivalAtAnyDestination) {
504
- earliestArrivalAtAnyDestination = arrival;
505
- }
506
- }
507
- return earliestArrivalAtAnyDestination;
66
+ rangeRoute(query: RangeQuery): RangeResult {
67
+ return this.rangeRouter.rangeRoute(query);
508
68
  }
509
69
  }