roadgraph-router-v2 0.2.0 → 0.3.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.
package/dist/index.d.ts CHANGED
@@ -62,6 +62,8 @@ interface RoadGraph {
62
62
  * for a profile whose routes depend on the vehicle's size. See `./limits`.
63
63
  */
64
64
  edgeLimits?: EdgeLimits;
65
+ /** Conditional restrictions for the edges that carry one; absent when none do. */
66
+ edgeConditions?: EdgeConditions;
65
67
  /**
66
68
  * One bit per turn restriction, saying whether this vehicle obeys it. The
67
69
  * pairs come first, then the sequences. Absent means all of them apply.
@@ -100,6 +102,14 @@ interface RouteSnap {
100
102
  point: Coordinate;
101
103
  /** How far the requested coordinate was from that road. */
102
104
  distanceMeters: number;
105
+ /**
106
+ * How far the route actually travels along that road, for an end that
107
+ * begins or finishes part-way along one. Zero where the end sits on a
108
+ * junction, and zero at the destination of a route that never leaves a
109
+ * single road, whose whole length is reported at the origin instead so
110
+ * that adding the two up gives the route and not twice the route.
111
+ */
112
+ travelledMeters?: number;
103
113
  }
104
114
  interface RouteResult {
105
115
  geometry: GeoJsonLineString;
@@ -139,6 +149,26 @@ interface EdgeLimits {
139
149
  /** Half-tonnes. */
140
150
  weightHalfTonnes: Uint8Array;
141
151
  }
152
+ /**
153
+ * Conditional restrictions for the few edges carrying one: the raw
154
+ * `value @ condition` text, kept as written and parsed when a bundle opens.
155
+ *
156
+ * A side table for the same reason the limits are one — a country has a few
157
+ * thousand of these among millions of edges. The text is deduplicated into
158
+ * `values`, because the same working-hours ban is repeated along every segment
159
+ * of the street it applies to. One edge may have several rows: a lorry ban and
160
+ * a night speed limit are both conditional and both apply.
161
+ */
162
+ interface EdgeConditions {
163
+ /** Sorted by edge, then by kind; an edge may appear more than once. */
164
+ edges: Uint32Array;
165
+ /** What the value means: 0 is access, 1 is a speed limit in km/h. */
166
+ kinds: Uint8Array;
167
+ /** Index into `values`. */
168
+ rules: Uint16Array;
169
+ /** The deduplicated conditional values, as tagged. */
170
+ values: string[];
171
+ }
142
172
  /**
143
173
  * A tile's vehicle-independent half: everything a v7 `shared` chunk holds.
144
174
  * It is not routable on its own — a profile supplies the durations.
@@ -154,6 +184,8 @@ interface ProfileChunk {
154
184
  edgeAccess?: Uint8Array;
155
185
  /** Signed limits for the few edges that state any; absent for vehicles whose size does not matter. */
156
186
  edgeLimits?: EdgeLimits;
187
+ /** Conditional restrictions for the edges that carry one; absent when none do. */
188
+ edgeConditions?: EdgeConditions;
157
189
  /**
158
190
  * One bit per turn restriction the shared chunk holds, saying whether this
159
191
  * vehicle obeys it. `except=hgv` lifts a restriction for lorries and not for
@@ -318,15 +350,76 @@ declare function componentsFor(graph: RoadGraph): Int32Array;
318
350
  /** How many nodes carry each label, so the smaller piece can be recognised. */
319
351
  declare function componentSizes(labels: Int32Array): Map<number, number>;
320
352
 
353
+ /**
354
+ * Roads the caller knows are shut.
355
+ *
356
+ * A compiled bundle is as current as the extract it came from: roadworks, a
357
+ * burst main, a festival closing the square are all things that happened
358
+ * after it was built, and nothing inside it can know about them. What it can
359
+ * do is let whoever does know say so at the time of asking.
360
+ *
361
+ * An area rather than a road, because a caller reading an incident feed has a
362
+ * place and a radius, not an edge number. Anything the circle touches is
363
+ * closed to the search and to snapping, exactly as a tagged restriction would
364
+ * be, so a route neither drives through a closure nor starts in the middle of
365
+ * one.
366
+ */
367
+
368
+ /** A circle of road that cannot be driven, whatever the map says. */
369
+ type AvoidArea = {
370
+ lat: number;
371
+ lng: number;
372
+ /** How far the closure reaches from that point. */
373
+ radiusMeters: number;
374
+ };
375
+ /**
376
+ * Whether any part of this edge lies inside the circle.
377
+ *
378
+ * The whole of each segment counts, not only its ends: a motorway crossing a
379
+ * closed junction may have no shape point anywhere near it, and testing the
380
+ * ends alone would drive a route straight through.
381
+ */
382
+ declare function touchesArea(graph: RoadGraph, edge: number, area: AvoidArea, centre?: Coordinate): boolean;
383
+ /**
384
+ * The access mask with every road the caller has closed cleared as well.
385
+ *
386
+ * Only the roads near each circle are looked at, so closing a junction costs
387
+ * the same whether the graph holds a town or a country.
388
+ */
389
+ declare function accessAvoiding(graph: RoadGraph, areas: AvoidArea[] | undefined, base?: Uint8Array): Uint8Array | undefined;
390
+ /** How many roads these closures take away, for reporting rather than routing. */
391
+ declare function countAvoided(graph: RoadGraph, areas: AvoidArea[] | undefined): number;
392
+
393
+ /**
394
+ * Reading a speed off an OSM tag.
395
+ *
396
+ * It lives on its own because both the profiles and the conditional
397
+ * restrictions need it, and a conditional limit is written in the same units
398
+ * as a plain one: `maxspeed:conditional = 30 mph @ (Mo-Fr 07:00-19:00)` means
399
+ * 30 mph, not 30 km/h.
400
+ */
401
+ /** Kilometres per hour, or null when the value is not a speed this reads. */
402
+ declare function parseMaxSpeedKph(value: string | undefined): number | null;
403
+
321
404
  /**
322
405
  * Routing profiles turn raw OSM tags into routable facts: may a vehicle use
323
406
  * this way, in which directions, and how fast. Keeping the rules behind one
324
407
  * interface lets the compiler stay generic — it never inspects a tag itself —
325
408
  * and lets the rules be unit-tested without a PBF file.
326
409
  */
410
+
327
411
  type OsmTags = Record<string, string | undefined>;
328
412
  /** How a profile may traverse one OSM way. */
329
413
  type WayTraversal = {
414
+ /**
415
+ * Conditional restrictions tagged on the way, kept as written for the
416
+ * router to evaluate against a departure time. They apply to both
417
+ * directions: OSM states these per vehicle class, not per direction.
418
+ */
419
+ conditions?: {
420
+ kind: number;
421
+ value: string;
422
+ }[];
330
423
  /** Travel from the first node reference towards the last is allowed. */
331
424
  forward: boolean;
332
425
  /** Travel from the last node reference towards the first is allowed. */
@@ -398,13 +491,6 @@ interface RoutingProfile {
398
491
  */
399
492
  evaluateBarrier?(tags: OsmTags): boolean;
400
493
  }
401
- /**
402
- * Reads a `maxspeed`-style value. Returns null for every value that is not a
403
- * plain number with an optional unit — country codes such as `PT:urban`,
404
- * `none`, `signals` and `variable` included — so the caller can fall back to a
405
- * class default instead of inventing a country-specific table.
406
- */
407
- declare function parseMaxSpeedKph(value: string | undefined): number | null;
408
494
  /**
409
495
  * Reads a `maxheight`-style value in metres. Feet and inches are accepted
410
496
  * because they are how the limit is written wherever it is signed that way;
@@ -535,6 +621,188 @@ declare function accessForVehicle(graph: RoadGraph, vehicle: VehicleDimensions |
535
621
  /** How many edges this vehicle may not use, for reporting rather than routing. */
536
622
  declare function countBlocked(graph: RoadGraph, vehicle: VehicleDimensions): number;
537
623
 
624
+ /**
625
+ * Conditional restrictions: `hgv:conditional = no @ (Mo-Fr 07:00-19:00)`.
626
+ *
627
+ * A road can be closed overnight, a square pedestrianised on Sundays, a bridge
628
+ * limited to 7.5 tonnes only for vehicles over a certain length. Until now
629
+ * every one of those read as permanently open, which is the limitation most
630
+ * likely to make a route wrong rather than merely longer.
631
+ *
632
+ * The value is a list of `value @ condition` pairs separated by semicolons,
633
+ * and where several match, OpenStreetMap says the **last** one wins — the
634
+ * convention being to write the general rule first and the specific one last.
635
+ *
636
+ * Not every condition can be answered. Weather, a driver's occupation and a
637
+ * stay duration are not things a compiled graph knows, and a rule resting on
638
+ * one is kept but marked, so a caller can count what was not understood
639
+ * instead of being told silently that a road is open.
640
+ */
641
+
642
+ /**
643
+ * How many distinct conditional values one table can hold. The stored index
644
+ * is sixteen bits wide, so the values are numbered 0 to 65535.
645
+ */
646
+ declare const MAX_STORED_VALUES = 65536;
647
+ /** When a journey passes, in the local time of the road it passes on. */
648
+ type TravelTime = {
649
+ /** 0 is Monday, 6 is Sunday. */
650
+ weekday: number;
651
+ /** Minutes since midnight, 0 to 1439. */
652
+ minutes: number;
653
+ /** 1 to 12, for a seasonal rule. */
654
+ month: number;
655
+ /**
656
+ * The day of the month, 1 to 31. Only a span running past midnight needs
657
+ * it, to know whether the morning it ends on began in the month before.
658
+ * Leaving it out treats such a morning as belonging to the current month,
659
+ * which is right on every day but the first.
660
+ */
661
+ dayOfMonth?: number;
662
+ /** Whether it is a public holiday there, which only a caller can know. */
663
+ publicHoliday?: boolean;
664
+ };
665
+ /** A span of minutes within a day, which may run past midnight. */
666
+ type MinuteSpan = {
667
+ from: number;
668
+ to: number;
669
+ };
670
+ /** An inclusive range of weekdays, months, or anything else counted in order. */
671
+ type Range = {
672
+ from: number;
673
+ to: number;
674
+ };
675
+ /** A measurement of the vehicle compared against a number, as `weight>7.5`. */
676
+ type VehicleComparison = {
677
+ property: "weight" | "height" | "width" | "length";
678
+ operator: "<" | "<=" | ">" | ">=" | "=";
679
+ amount: number;
680
+ };
681
+ /** One `(...)` group: every part present must hold for the group to match. */
682
+ type Condition = {
683
+ days?: Range[];
684
+ times?: MinuteSpan[];
685
+ months?: Range[];
686
+ publicHoliday?: boolean;
687
+ vehicle?: VehicleComparison[];
688
+ /**
689
+ * Circumstances this library cannot know by itself: the weather, who is
690
+ * driving, what for. They are read from the tag and answered only by a
691
+ * caller who says so; unanswered, the condition does not hold.
692
+ */
693
+ circumstances?: string[];
694
+ /**
695
+ * The part of the condition this parser could not read at all — a stay
696
+ * duration, a form of words nobody has taught it. A condition carrying one
697
+ * is never matched, and is counted so it can be reported rather than
698
+ * quietly ignored.
699
+ */
700
+ unreadable?: string;
701
+ };
702
+ /**
703
+ * What the caller knows that the map does not: whether it is raining, who is
704
+ * at the wheel, what the journey is for. A conditional rule resting on one of
705
+ * these is ignored unless the answer is given here.
706
+ */
707
+ type Circumstances = {
708
+ /** Named states of the road or sky, such as `wet`, `snow`, `ice`. */
709
+ conditions?: string[];
710
+ /** Who is driving, such as `disabled`, `resident`, `emergency`. */
711
+ userGroups?: string[];
712
+ /** Why, such as `delivery`, `destination`, `agricultural`. */
713
+ purposes?: string[];
714
+ };
715
+ type ConditionalRule = {
716
+ /** What applies when the condition holds: `no`, `destination`, `30`, `7.5`. */
717
+ value: string;
718
+ /** Any of these matching makes the rule apply, as `Mo-Fr 07:00-19:00, Sa 08:00-12:00`. */
719
+ conditions: Condition[];
720
+ };
721
+ /**
722
+ * Reads a `*:conditional` value into its rules. An empty list means the value
723
+ * was not a conditional expression at all.
724
+ */
725
+ declare function parseConditional(value: string | undefined): ConditionalRule[];
726
+ /** Whether one condition group holds at this moment, for this vehicle. */
727
+ declare function conditionHolds(condition: Condition, when: TravelTime, vehicle?: VehicleDimensions, circumstances?: Circumstances): boolean;
728
+ /**
729
+ * What a conditional value comes to at this moment, or null when none of its
730
+ * rules applies. Where several match, the last wins, which is what
731
+ * OpenStreetMap says and why the convention is general first, specific last.
732
+ */
733
+ declare function conditionalValue(rules: ConditionalRule[], when: TravelTime, vehicle?: VehicleDimensions, circumstances?: Circumstances): string | null;
734
+ /**
735
+ * How many of these rules rest on something this parser cannot read at all.
736
+ * A rule resting on the weather or on who is driving is readable and is not
737
+ * counted here; it simply needs a caller to answer it.
738
+ */
739
+ declare function unreadableConditions(rules: ConditionalRule[]): number;
740
+ /**
741
+ * The moment a journey is travelled.
742
+ *
743
+ * Without a time zone the date is read as the machine reads it, which is
744
+ * right when the roads and the reader are in the same place and wrong by
745
+ * however many hours when they are not. Naming the zone the roads are in —
746
+ * `"Europe/Lisbon"` — reads the date there instead, which is what a
747
+ * restriction written in local time means.
748
+ *
749
+ * The zone names are the IANA ones the platform already knows; nothing is
750
+ * bundled for this.
751
+ */
752
+ declare function travelTimeFrom(date: Date, publicHoliday?: boolean, timeZone?: string): TravelTime;
753
+ /** What a stored conditional row says: an access rule or a speed limit. */
754
+ declare const ConditionKind: {
755
+ readonly access: 0;
756
+ readonly maxspeed: 1;
757
+ };
758
+ /** Collects what a compiler found into the stored side table. */
759
+ declare function packEdgeConditions(entries: {
760
+ edge: number;
761
+ kind: number;
762
+ value: string;
763
+ }[]): EdgeConditions | undefined;
764
+ /** A bundle's conditional values parsed once, rather than per edge per search. */
765
+ type ParsedConditions = {
766
+ table: EdgeConditions;
767
+ parsed: ConditionalRule[][];
768
+ };
769
+ declare function parseEdgeConditions(table: EdgeConditions | undefined): ParsedConditions | undefined;
770
+ /**
771
+ * What the conditional rules say about one edge at one moment: whether it is
772
+ * closed, and any speed limit that applies.
773
+ *
774
+ * `destination` and the permit-style values count as closed because this
775
+ * library has no notion of a journey's purpose, and treating "only if you live
776
+ * here" as open would route strangers down a residents' street.
777
+ */
778
+ declare function conditionsOnEdge(conditions: ParsedConditions, edge: number, when: TravelTime, vehicle?: VehicleDimensions, circumstances?: Circumstances): {
779
+ closed: boolean;
780
+ speedKph: number | undefined;
781
+ };
782
+ /**
783
+ * The access mask for a departure time: the graph's own with the roads shut at
784
+ * that moment cleared as well.
785
+ *
786
+ * Only closures are applied. A road whose plain tags already forbid it stays
787
+ * forbidden even where a conditional value would open it, because the stored
788
+ * mask has already dropped it and reopening one would need the compiler to
789
+ * keep roads it currently discards. That errs towards refusing a road that is
790
+ * in fact usable, which is the direction this library errs in everywhere else.
791
+ */
792
+ declare function accessAtTime(graph: Pick<RoadGraph, "edgeTargets" | "edgeAccess">, conditions: ParsedConditions | undefined, when: TravelTime | undefined, vehicle?: VehicleDimensions, base?: Uint8Array, circumstances?: Circumstances): Uint8Array | undefined;
793
+ /** How many edges this moment closes, for reporting rather than routing. */
794
+ declare function countClosedAt(graph: Pick<RoadGraph, "edgeTargets" | "edgeAccess">, conditions: ParsedConditions | undefined, when: TravelTime, vehicle?: VehicleDimensions): number;
795
+ declare function conditionsOf(graph: Pick<RoadGraph, "edgeConditions">): ParsedConditions | undefined;
796
+ /**
797
+ * The edges a conditional speed limit slows at this moment, as whole seconds.
798
+ *
799
+ * A conditional limit may only slow an edge, never speed it up. A faster
800
+ * stored duration is left alone, because the A* bound is built from the
801
+ * profile's ceiling and an edge quicker than the graph says would break the
802
+ * guarantee that the route found is the best one.
803
+ */
804
+ declare function conditionalDurations(graph: Pick<RoadGraph, "edgeTargets" | "edgeDistancesMeters" | "edgeDistanceScale" | "edgeDurationsSeconds" | "edgeDurationScale">, conditions: ParsedConditions | undefined, when: TravelTime, vehicle?: VehicleDimensions, circumstances?: Circumstances): Map<number, number> | undefined;
805
+
538
806
  /**
539
807
  * The nearest routing node to a coordinate. After topology simplification a
540
808
  * node is a junction rather than an arbitrary point on a road, so on a long
@@ -555,74 +823,130 @@ type RouteOptions = {
555
823
  * is too large or too heavy for are closed to the search and to snapping.
556
824
  */
557
825
  vehicle?: VehicleDimensions;
826
+ /**
827
+ * When the journey starts, in the local time of the roads being travelled.
828
+ *
829
+ * Leaving it out ignores every conditional restriction, which is what this
830
+ * library did before it could read them: a road closed only at certain hours
831
+ * counts as open. Supplying it closes the roads shut at that moment and
832
+ * slows the ones a conditional speed limit slows.
833
+ *
834
+ * One moment is used for the whole route rather than an arrival time per
835
+ * edge. A route crossing a boundary as a restriction begins is therefore
836
+ * judged by where it set out, which is the honest limit of a departure time.
837
+ */
838
+ departAt?: Date | TravelTime;
839
+ /** Whether that day is a public holiday, which only a caller can know. */
840
+ publicHoliday?: boolean;
841
+ /**
842
+ * The time zone the roads are in, as an IANA name such as
843
+ * `"Europe/Lisbon"`. A restriction is written in the local time of the road
844
+ * it is on, so a caller routing somewhere other than where it is running
845
+ * should say where. Left out, a `Date` is read as this machine reads it.
846
+ */
847
+ timeZone?: string;
848
+ /**
849
+ * What the map cannot know: whether it is raining, who is driving, what the
850
+ * journey is for. A conditional rule resting on one of these is ignored
851
+ * unless it is answered here, so a road shut `@ (wet)` stays open until a
852
+ * caller says it is wet.
853
+ */
854
+ circumstances?: Circumstances;
855
+ /**
856
+ * Roads the caller knows are shut — roadworks, an incident, an event. A
857
+ * compiled bundle cannot know about any of them; whoever is reading a feed
858
+ * of them can say so here, and the search will neither drive through a
859
+ * closure nor begin in the middle of one.
860
+ */
861
+ avoid?: AvoidArea[];
862
+ /**
863
+ * Multipliers making certain edges dearer to the search than they really
864
+ * are, used to push a search away from a route already found. The route
865
+ * reported back is always priced at the graph's own cost, so a penalty
866
+ * changes which roads are chosen and never what they are said to cost.
867
+ */
868
+ costPenalties?: ReadonlyMap<number, number>;
869
+ /**
870
+ * Whether a route that cannot reach the road nearest its destination may
871
+ * finish on one a little further away. On by default, because the nearest
872
+ * road is sometimes one the network cannot legally enter — a pocket of
873
+ * one-way streets behind banned turns, an island of service roads — and
874
+ * refusing to route at all is a worse answer than finishing nearby.
875
+ *
876
+ * Turn it off to be told plainly that the point asked for cannot be
877
+ * reached. `RouteResult.destinationSnap.distanceMeters` reports how far
878
+ * short a route finished either way.
879
+ */
880
+ finishOnANearbyRoad?: boolean;
558
881
  };
559
882
  declare function route(graph: RoadGraph, from: Coordinate, to: Coordinate, preference?: RoutePreference, options?: RouteOptions): RouteResult;
560
883
 
561
- /** Where a coordinate lands on one directed edge. */
562
- type EdgeProjection = {
563
- edge: number;
564
- source: number;
565
- target: number;
566
- /** How far along the edge the projection sits, 0 at the source and 1 at the target. */
567
- fraction: number;
568
- /** The point on the road itself. */
569
- point: Coordinate;
570
- /** Distance from the queried coordinate to that point. */
571
- distanceMeters: number;
572
- /** Index of the polyline vertex the projection follows, for slicing geometry. */
573
- vertexIndex: number;
574
- polyline: Coordinate[];
575
- };
576
884
  /**
577
- * Snapping a coordinate onto the graph. A `node` snap behaves exactly as this
578
- * package always has; an `edge` snap carries one projection per directed edge
579
- * covering the same stretch of road, so a two-way road offers both directions
580
- * and a one-way road offers only the legal one.
885
+ * Several ways to get there, not just the best one.
886
+ *
887
+ * A second route is only worth offering if it is genuinely different and not
888
+ * much worse. The method here is the simple one: find the best route, make the
889
+ * roads it used dearer to the search than they really are, and search again.
890
+ * A road that is the only sensible way through survives the penalty and is
891
+ * used again; one that was merely convenient gives way to its neighbour.
892
+ *
893
+ * The penalty never reaches the answer. A route is always reported at the
894
+ * graph's own cost, so an alternative's distance and duration are what it
895
+ * would really take, not what the search was told to believe.
896
+ *
897
+ * Candidates are then filtered rather than trusted: one that reuses most of a
898
+ * route already offered, or that is far worse than the best, is not an
899
+ * alternative anybody wants. What comes back is in order, best first.
581
900
  */
582
- type GraphSnap = {
583
- kind: "node";
584
- node: number;
585
- point: Coordinate;
586
- distanceMeters: number;
587
- } | {
588
- kind: "edge";
589
- projections: EdgeProjection[];
590
- point: Coordinate;
591
- distanceMeters: number;
901
+
902
+ type AlternativeRoutesOptions = Omit<RouteOptions, "costPenalties" | "costBound"> & {
903
+ /** How many routes to return at most, the best one included. Default 3. */
904
+ count?: number;
905
+ /**
906
+ * How much worse than the best route an alternative may be. 1.4 allows one
907
+ * taking 40% longer; raising it offers more routes and worse ones.
908
+ */
909
+ maxStretch?: number;
910
+ /**
911
+ * How much of the routes already offered an alternative may reuse, measured
912
+ * by distance. 0.75 rejects one that is three-quarters the same road.
913
+ */
914
+ maxSharing?: number;
915
+ /**
916
+ * How much dearer a road already used is made to look. Too small and the
917
+ * search returns the same route again; too large and it flees onto
918
+ * absurdities. Default 2.
919
+ */
920
+ penaltyFactor?: number;
921
+ /**
922
+ * Whether to download the wider corridor an alternative might lie in.
923
+ *
924
+ * On by default, because an alternative is allowed to be worse than the
925
+ * best by `maxStretch` and the tiles holding one therefore reach further
926
+ * than the tiles that proved the best route. On a long journey that is
927
+ * about three megabytes more map. Turning it off keeps the download to
928
+ * what one route needed and offers only the alternatives already inside
929
+ * it, which on a dense network is usually most of them.
930
+ */
931
+ searchWiderCorridor?: boolean;
592
932
  };
593
933
  /**
594
- * Finds the road nearest to a coordinate. Returns null when nothing routable
595
- * lies within `maxDistanceMeters` of the coordinate — measured to the road
596
- * surface, not to the nearest junction.
934
+ * Rejects options that would make the search unbounded or meaningless.
935
+ *
936
+ * Exported so the public entry point can refuse them before it downloads
937
+ * anything: a caller who passed `count: NaN` should be told so, not billed
938
+ * for a corridor first.
597
939
  */
598
- declare function snapToGraph(graph: RoadGraph, coordinate: Coordinate, maxDistanceMeters?: number, access?: Uint8Array | undefined, accept?: (node: number) => boolean): GraphSnap | null;
599
-
940
+ declare function checkAlternativeOptions(options: AlternativeRoutesOptions): void;
600
941
  /**
601
- * A uniform-grid index over directed edges. Snapping needs the nearest *road*,
602
- * not the nearest junction: after topology simplification a rural edge can run
603
- * for a kilometre without a node, so a node-only index cannot answer "which
604
- * road am I standing on".
942
+ * Routes from one point to another, best first, with up to `count - 1`
943
+ * genuinely different alternatives after it.
605
944
  *
606
- * Each edge is registered in every cell its bounding box touches, which keeps
607
- * construction linear and lookups to a handful of cells.
945
+ * Returns at least the best route; fewer than `count` means the graph held
946
+ * nothing else worth offering, which is the usual answer on a road network
947
+ * with one obvious way through.
608
948
  */
609
- type EdgeSpatialIndex = {
610
- cellSizeDegrees: number;
611
- cells: Map<string, Uint32Array>;
612
- /** Edges whose extent covers too many cells to list individually. */
613
- oversized: Uint32Array;
614
- };
615
- /** Recovers an edge's source node from the CSR offsets. */
616
- declare function edgeSource(graph: RoadGraph, edge: number): number;
617
- /** The full vertex list of a directed edge: source node, shape points, target node. */
618
- declare function edgePolyline(graph: RoadGraph, edge: number, source?: number): Coordinate[];
619
- declare function createEdgeSpatialIndex(graph: RoadGraph, cellSizeDegrees?: number): EdgeSpatialIndex;
620
- declare function edgeSpatialIndexFor(graph: RoadGraph, cellSizeDegrees?: number): EdgeSpatialIndex;
621
- declare function nearbyEdgeIds(index: EdgeSpatialIndex, coordinate: Coordinate, maxDistanceMeters: number): Set<number>;
622
-
623
- /** Builds a uniform-grid index. It can be created after decoding without changing the graph format. */
624
- declare function createSpatialIndex(graph: RoadGraph, cellSizeDegrees?: number): NodeSpatialIndex;
625
- declare function withSpatialIndex(graph: RoadGraph, cellSizeDegrees?: number): RoadGraph;
949
+ declare function routeAlternatives(graph: RoadGraph, from: Coordinate, to: Coordinate, preference?: RoutePreference, options?: AlternativeRoutesOptions): RouteResult[];
626
950
 
627
951
  type FetchLike$2 = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
628
952
  /**
@@ -653,6 +977,8 @@ type RoadRouterOptions = {
653
977
  * High-level route entry point. `open()` accepts an EFRB bundle, an EFRT
654
978
  * manifest, or an already-decoded graph.
655
979
  */
980
+ /** When a journey starts, for the conditional restrictions that depend on it. */
981
+ type DepartureOptions = Pick<RouteOptions, "departAt" | "publicHoliday" | "timeZone" | "circumstances" | "avoid">;
656
982
  declare class RoadRouter {
657
983
  private readonly graph?;
658
984
  private readonly loader?;
@@ -685,7 +1011,12 @@ declare class RoadRouter {
685
1011
  * network once: switching vehicle costs only the small per-vehicle chunks.
686
1012
  */
687
1013
  withProfile(name: string): RoadRouter;
688
- route(from: Coordinate, to: Coordinate, preference?: RoutePreference): Promise<RouteResult>;
1014
+ /**
1015
+ * `when` says when the journey starts, so conditional restrictions apply.
1016
+ * Leaving it out ignores them, which is how this library behaved before it
1017
+ * could read them.
1018
+ */
1019
+ route(from: Coordinate, to: Coordinate, preference?: RoutePreference, when?: DepartureOptions): Promise<RouteResult>;
689
1020
  /**
690
1021
  * Downloads a corridor, routes, then asks whether any tile left out could
691
1022
  * still hold something better. A route through a tile costs at least the
@@ -695,10 +1026,93 @@ declare class RoadRouter {
695
1026
  * graph contains. Because the test measures ground distance rather than
696
1027
  * counting neighbours, the answer does not depend on the tile size.
697
1028
  */
1029
+ /**
1030
+ * Several ways there, best first, with up to `count - 1` alternatives after
1031
+ * it. Fewer than asked for means the network held nothing else worth
1032
+ * offering, which is the usual answer where there is one obvious way.
1033
+ *
1034
+ * Over a bundle this downloads a wider corridor than a single route needs:
1035
+ * an alternative may be worse than the best by as much as `maxStretch`, and
1036
+ * the tiles holding it lie outside the corridor that proved the best route.
1037
+ */
1038
+ routeAlternatives(from: Coordinate, to: Coordinate, preference?: RoutePreference, options?: AlternativeRoutesOptions): Promise<RouteResult[]>;
698
1039
  private routeOverBundle;
1040
+ /**
1041
+ * The same corridor walk, stopping with the graph it settled on as well as
1042
+ * the route. Alternatives need the graph, and need to be able to widen it
1043
+ * once more: a second route may be worse than the best by more than the
1044
+ * corridor was ever sized to hold.
1045
+ */
1046
+ private bestOverBundle;
699
1047
  private routeOverLoader;
700
1048
  }
701
1049
 
1050
+ /** Where a coordinate lands on one directed edge. */
1051
+ type EdgeProjection = {
1052
+ edge: number;
1053
+ source: number;
1054
+ target: number;
1055
+ /** How far along the edge the projection sits, 0 at the source and 1 at the target. */
1056
+ fraction: number;
1057
+ /** The point on the road itself. */
1058
+ point: Coordinate;
1059
+ /** Distance from the queried coordinate to that point. */
1060
+ distanceMeters: number;
1061
+ /** Index of the polyline vertex the projection follows, for slicing geometry. */
1062
+ vertexIndex: number;
1063
+ polyline: Coordinate[];
1064
+ };
1065
+ /**
1066
+ * Snapping a coordinate onto the graph. A `node` snap behaves exactly as this
1067
+ * package always has; an `edge` snap carries one projection per directed edge
1068
+ * covering the same stretch of road, so a two-way road offers both directions
1069
+ * and a one-way road offers only the legal one.
1070
+ */
1071
+ type GraphSnap = {
1072
+ kind: "node";
1073
+ node: number;
1074
+ point: Coordinate;
1075
+ distanceMeters: number;
1076
+ } | {
1077
+ kind: "edge";
1078
+ projections: EdgeProjection[];
1079
+ point: Coordinate;
1080
+ distanceMeters: number;
1081
+ };
1082
+ /**
1083
+ * Finds the road nearest to a coordinate. Returns null when nothing routable
1084
+ * lies within `maxDistanceMeters` of the coordinate — measured to the road
1085
+ * surface, not to the nearest junction.
1086
+ */
1087
+ declare function snapToGraph(graph: RoadGraph, coordinate: Coordinate, maxDistanceMeters?: number, access?: Uint8Array | undefined, accept?: (node: number) => boolean, everyNearbyRoad?: boolean): GraphSnap | null;
1088
+
1089
+ /**
1090
+ * A uniform-grid index over directed edges. Snapping needs the nearest *road*,
1091
+ * not the nearest junction: after topology simplification a rural edge can run
1092
+ * for a kilometre without a node, so a node-only index cannot answer "which
1093
+ * road am I standing on".
1094
+ *
1095
+ * Each edge is registered in every cell its bounding box touches, which keeps
1096
+ * construction linear and lookups to a handful of cells.
1097
+ */
1098
+ type EdgeSpatialIndex = {
1099
+ cellSizeDegrees: number;
1100
+ cells: Map<string, Uint32Array>;
1101
+ /** Edges whose extent covers too many cells to list individually. */
1102
+ oversized: Uint32Array;
1103
+ };
1104
+ /** Recovers an edge's source node from the CSR offsets. */
1105
+ declare function edgeSource(graph: RoadGraph, edge: number): number;
1106
+ /** The full vertex list of a directed edge: source node, shape points, target node. */
1107
+ declare function edgePolyline(graph: RoadGraph, edge: number, source?: number): Coordinate[];
1108
+ declare function createEdgeSpatialIndex(graph: RoadGraph, cellSizeDegrees?: number): EdgeSpatialIndex;
1109
+ declare function edgeSpatialIndexFor(graph: RoadGraph, cellSizeDegrees?: number): EdgeSpatialIndex;
1110
+ declare function nearbyEdgeIds(index: EdgeSpatialIndex, coordinate: Coordinate, maxDistanceMeters: number): Set<number>;
1111
+
1112
+ /** Builds a uniform-grid index. It can be created after decoding without changing the graph format. */
1113
+ declare function createSpatialIndex(graph: RoadGraph, cellSizeDegrees?: number): NodeSpatialIndex;
1114
+ declare function withSpatialIndex(graph: RoadGraph, cellSizeDegrees?: number): RoadGraph;
1115
+
702
1116
  declare const BundleCompression: {
703
1117
  readonly none: 0;
704
1118
  readonly gzip: 1;
@@ -938,4 +1352,4 @@ type GuardedJunctions = {
938
1352
  };
939
1353
  declare function guardedJunctionsFor(graph: RoadGraph, restrictions: TurnRestrictionIndex | null, sequences: TurnSequenceIndex | null): GuardedJunctions;
940
1354
 
941
- export { type BundleBounds, type BundleChunkRef, BundleCompression, type BundleEncodeOptions, type BundleGraphTile, type BundleOpenOptions, type BundleProfiledTile, type BundleTile, type CompactEncodeOptions, type CompactGraphOptions, type Coordinate, type CoordinateStorage, DEFAULT_VEHICLE_PRESET, type EdgeLimits, type EdgeProjection, type EdgeSpatialIndex, type EdgeWeightStorage, type GeoJsonLineString, type GeoJsonPosition, type GraphBounds, type GraphSnap, type GraphTile, type GuardedJunctions, type NodeSpatialIndex, type OsmTags, type ParsedTurnRestriction, type ProfileChunk, ProfileId, type RoadGraph, type RoadGraphBundle, RoadRouter, type RoadRouterOptions, type RouteGraphLoader, type RouteGraphManifest, type RouteOptions, type RoutePreference, type RouteResult, type RouteSnap, RouterError, type RouterErrorCode, type RoutingProfile, type SearchBounds, type SharedRoadGraph, type TurnRestrictionIndex, type TurnRestrictionKind, type TurnSequenceIndex, VEHICLE_PRESETS, VarintReader, VarintWriter, type VehicleDimensions, type VehicleInput, type VehicleLimits, VehiclePresetId, type WayTraversal, accessForVehicle, accessMaskFor, allowsEverything, buildTurnRestrictionIndex, buildTurnSequenceIndex, carRoutingProfile, combineProfiledGraph, compactGraph, componentSizes, componentsFor, countBlocked, createEdgeSpatialIndex, createRouteGraphLoader, createSpatialIndex, decodeGraph, decodeProfileChunk, decodeSharedGraph, distanceToBounds, edgeAllowed, edgePolyline, edgeSource, edgeSpatialIndexFor, encodeCompactGraph, encodeCompressedRoadGraphBundle, encodeGraph, encodeProfileChunk, encodeProfiledRoadGraphBundle, encodeRoadGraphBundle, encodeSharedGraph, findNearestNode, fromDecimetres, fromHalfTonnes, getRoutingProfile, getRoutingProfileById, guardedJunctionsFor, isTurnBanned, maxSpeedMpsFor, mergeRoadGraphs, motorcycleRoutingProfile, nearbyEdgeIds, openRoadGraphBundle, packEdgeLimits, packTurnRestrictions, packTurnSequences, parseLengthMeters, parseMaxSpeedKph, parseWeightTonnes, profileOf, resolveVehicle, route, routingProfiles, searchBoundsFor, snapToGraph, straightLineAtMost, toDecimetres, toHalfTonnes, truckRoutingProfile, unzigzag, vehiclePreset, vehiclePresetName, withSpatialIndex, zigzag };
1355
+ export { type AlternativeRoutesOptions, type AvoidArea, type BundleBounds, type BundleChunkRef, BundleCompression, type BundleEncodeOptions, type BundleGraphTile, type BundleOpenOptions, type BundleProfiledTile, type BundleTile, type Circumstances, type CompactEncodeOptions, type CompactGraphOptions, type Condition, ConditionKind, type ConditionalRule, type Coordinate, type CoordinateStorage, DEFAULT_VEHICLE_PRESET, type DepartureOptions, type EdgeConditions, type EdgeLimits, type EdgeProjection, type EdgeSpatialIndex, type EdgeWeightStorage, type GeoJsonLineString, type GeoJsonPosition, type GraphBounds, type GraphSnap, type GraphTile, type GuardedJunctions, MAX_STORED_VALUES, type MinuteSpan, type NodeSpatialIndex, type OsmTags, type ParsedConditions, type ParsedTurnRestriction, type ProfileChunk, ProfileId, type RoadGraph, type RoadGraphBundle, RoadRouter, type RoadRouterOptions, type RouteGraphLoader, type RouteGraphManifest, type RouteOptions, type RoutePreference, type RouteResult, type RouteSnap, RouterError, type RouterErrorCode, type RoutingProfile, type SearchBounds, type SharedRoadGraph, type TravelTime, type TurnRestrictionIndex, type TurnRestrictionKind, type TurnSequenceIndex, VEHICLE_PRESETS, VarintReader, VarintWriter, type VehicleComparison, type VehicleDimensions, type VehicleInput, type VehicleLimits, VehiclePresetId, type WayTraversal, accessAtTime, accessAvoiding, accessForVehicle, accessMaskFor, allowsEverything, buildTurnRestrictionIndex, buildTurnSequenceIndex, carRoutingProfile, checkAlternativeOptions, combineProfiledGraph, compactGraph, componentSizes, componentsFor, conditionHolds, conditionalDurations, conditionalValue, conditionsOf, conditionsOnEdge, countAvoided, countBlocked, countClosedAt, createEdgeSpatialIndex, createRouteGraphLoader, createSpatialIndex, decodeGraph, decodeProfileChunk, decodeSharedGraph, distanceToBounds, edgeAllowed, edgePolyline, edgeSource, edgeSpatialIndexFor, encodeCompactGraph, encodeCompressedRoadGraphBundle, encodeGraph, encodeProfileChunk, encodeProfiledRoadGraphBundle, encodeRoadGraphBundle, encodeSharedGraph, findNearestNode, fromDecimetres, fromHalfTonnes, getRoutingProfile, getRoutingProfileById, guardedJunctionsFor, isTurnBanned, maxSpeedMpsFor, mergeRoadGraphs, motorcycleRoutingProfile, nearbyEdgeIds, openRoadGraphBundle, packEdgeConditions, packEdgeLimits, packTurnRestrictions, packTurnSequences, parseConditional, parseEdgeConditions, parseLengthMeters, parseMaxSpeedKph, parseWeightTonnes, profileOf, resolveVehicle, route, routeAlternatives, routingProfiles, searchBoundsFor, snapToGraph, straightLineAtMost, toDecimetres, toHalfTonnes, touchesArea, travelTimeFrom, truckRoutingProfile, unreadableConditions, unzigzag, vehiclePreset, vehiclePresetName, withSpatialIndex, zigzag };