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/CHANGELOG.md +217 -2
- package/README.md +408 -24
- package/dist/{chunk-PXL65P3L.js → chunk-QSIKDM4A.js} +942 -316
- package/dist/index.d.ts +480 -66
- package/dist/index.js +201 -14
- package/dist/worker.js +2 -2
- package/package.json +1 -1
- package/scripts/roadgraph-compile.mjs +30 -7
package/CHANGELOG.md
CHANGED
|
@@ -4,7 +4,214 @@ All notable changes to this project are documented here. The format follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project aims
|
|
5
5
|
to follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
-
## [
|
|
7
|
+
## [0.3.0] - 2026-10-15
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **Conditional restrictions, when a route says when it starts.**
|
|
12
|
+
`router.route(from, to, "fastest", { departAt })` closes the roads shut at
|
|
13
|
+
that moment to both the search and the snapping, and slows the ones a
|
|
14
|
+
conditional speed limit slows. The reported duration is the slowed one, not
|
|
15
|
+
the one the route was planned against.
|
|
16
|
+
|
|
17
|
+
`*:conditional` is read from the access ladder — `access`, `vehicle`,
|
|
18
|
+
`motor_vehicle` and the profile's own key — and from `maxspeed`. Conditions
|
|
19
|
+
resting on time of day, weekday, month, public holiday and the vehicle's own
|
|
20
|
+
dimensions are answered, including windows that run past midnight, seasons
|
|
21
|
+
that span the new year and several windows in one rule. Where more than one
|
|
22
|
+
rule matches, the last wins, which is what OpenStreetMap specifies.
|
|
23
|
+
|
|
24
|
+
Measured on Portugal, where the Ponte 25 de Abril carries
|
|
25
|
+
`hgv:conditional = no @ (05:00-02:00)`: routing Almada to Lisbon, a lorry
|
|
26
|
+
with no departure time takes the bridge in 13.0 km, at 03:00 takes it in
|
|
27
|
+
13.0 km, and at 10:00 detours 63.4 km over the Ponte Vasco da Gama. A car
|
|
28
|
+
crosses in 12.2 km at every hour. 3,328 of Portugal's 2,760,171 edges carry
|
|
29
|
+
a conditional restriction, costing 14.8 kB — the bundle grew from 40.17 MB
|
|
30
|
+
to 40.18 MB — and about 10 ms on a repeat long-distance route.
|
|
31
|
+
|
|
32
|
+
- **Alternative routes.** `routeAlternatives(from, to, preference, { count })`
|
|
33
|
+
returns several routes, best first. It finds the best one, makes the roads
|
|
34
|
+
it used dearer to the search than they really are, and searches again; the
|
|
35
|
+
penalty steers the search and never reaches the answer, so every route is
|
|
36
|
+
reported at the graph's own cost. Candidates far worse than the best, or
|
|
37
|
+
mostly along the same road, are rejected rather than offered, so fewer
|
|
38
|
+
routes than asked for is the normal answer on a network with one obvious
|
|
39
|
+
way through.
|
|
40
|
+
|
|
41
|
+
Porto to Lisbon returned three routes — 312.0 km, 319.0 km and 350.5 km —
|
|
42
|
+
in 3.4 s against 2.5 s for the single route, downloading 3.0 MB beyond the
|
|
43
|
+
29.2 MB the first route needed. A short urban route returned two in 79 ms
|
|
44
|
+
with nothing further to download.
|
|
45
|
+
|
|
46
|
+
- **A departure may name the time zone the roads are in.** `timeZone:
|
|
47
|
+
"Europe/Lisbon"` reads the date there rather than wherever the code runs,
|
|
48
|
+
which is what a restriction written in local time means. Built on `Intl`;
|
|
49
|
+
nothing is bundled for it.
|
|
50
|
+
|
|
51
|
+
- **Weather, who is driving and what for can be answered.**
|
|
52
|
+
`circumstances: { conditions: ["wet"], userGroups: ["resident"],
|
|
53
|
+
purposes: ["delivery"] }` makes the rules resting on them apply.
|
|
54
|
+
Unanswered they never hold, so the behaviour of anyone not passing them is
|
|
55
|
+
unchanged. `unreadableConditions` now counts only what the parser genuinely
|
|
56
|
+
cannot read, which is what its name always claimed.
|
|
57
|
+
|
|
58
|
+
- **Roads the caller knows are shut can be avoided.** `avoid: [{ lat, lng,
|
|
59
|
+
radiusMeters }]` closes everything a circle touches, to the search and to
|
|
60
|
+
snapping alike, for that call only. Roadworks and incidents happen after a
|
|
61
|
+
bundle is compiled and cannot be in it; this is how a caller reading a feed
|
|
62
|
+
of them says so.
|
|
63
|
+
|
|
64
|
+
- **`searchWiderCorridor: false`** keeps an alternatives search to the tiles
|
|
65
|
+
one route needed, trading reach for about three megabytes on a long
|
|
66
|
+
journey.
|
|
67
|
+
|
|
68
|
+
- **The compile report counts `conditionalTurnRestrictionsIgnored`.** A turn
|
|
69
|
+
banned only at certain hours is still banned at every hour; the number now
|
|
70
|
+
says how much of a region that costs. Across Portugal it is 1 relation in
|
|
71
|
+
26,599.
|
|
72
|
+
|
|
73
|
+
### Fixed
|
|
74
|
+
|
|
75
|
+
- **A road is identified by its shape in order, not by a sum of its points.**
|
|
76
|
+
Adding coordinates up does not care which point came first, so a road
|
|
77
|
+
bending north then east and one bending east then north read as the same
|
|
78
|
+
road and one of them would be dropped as a duplicate alternative.
|
|
79
|
+
|
|
80
|
+
- **A closure standing on the date line shuts the roads under it.** The
|
|
81
|
+
projection it was tested against subtracted longitudes at face value, so a
|
|
82
|
+
road a few metres away measured half a world off.
|
|
83
|
+
|
|
84
|
+
- **A rule table too wide for its index stops the compile.** It used to drop
|
|
85
|
+
the surplus rows, which turned a restricted road into an unrestricted one
|
|
86
|
+
with nothing said. A tile holds up to 65,536 distinct conditional values;
|
|
87
|
+
past that the compile fails and names `--tile-size-km` as the way through.
|
|
88
|
+
|
|
89
|
+
- **Two roads joining the same pair of junctions are two roads.** Telling
|
|
90
|
+
alternatives apart by their endpoints alone treated a slip road and the road
|
|
91
|
+
beside it as one, hiding a genuine second way there. The Porto to Lisbon
|
|
92
|
+
corridor holds 12,015 such pairs, none the same length as its twin, so the
|
|
93
|
+
length now separates them while staying equal for the two directions of one
|
|
94
|
+
road.
|
|
95
|
+
|
|
96
|
+
- **Each end of a route counts what it actually drives.** The distance driven
|
|
97
|
+
on the part-roads a route begins and ends on was split evenly between the
|
|
98
|
+
two, which misreports overlap whenever one end joins its road near the far
|
|
99
|
+
junction. `RouteSnap.travelledMeters` now carries the real figure.
|
|
100
|
+
|
|
101
|
+
- **A month selector is read with the window it governs.**
|
|
102
|
+
`no @ (Oct 22:00-06:00)` stopped at midnight on the thirty-first instead of
|
|
103
|
+
running to six on the first of November. `TravelTime` may now carry
|
|
104
|
+
`dayOfMonth`; without one the answer is unchanged, which is right on thirty
|
|
105
|
+
days in thirty-one.
|
|
106
|
+
|
|
107
|
+
- **Alternative options are refused before anything is downloaded**, rather
|
|
108
|
+
than after a remote bundle has been asked for tiles.
|
|
109
|
+
|
|
110
|
+
- **A window named with a day is read as one window.** `no @ (Fr 22:00-06:00)`
|
|
111
|
+
was matched by asking "is it Friday?" and "is it between 22:00 and 06:00?"
|
|
112
|
+
separately, which answered both ends of it backwards: it applied at two on
|
|
113
|
+
Friday morning, before it began, and not at two on Saturday morning, while
|
|
114
|
+
it was still in force. A span running past midnight now belongs to the day
|
|
115
|
+
it starts on, which also fixes Sunday into Monday.
|
|
116
|
+
|
|
117
|
+
- **`24:30` is no longer a time.** It parsed as half past midnight, quietly
|
|
118
|
+
moving a window onto the following day. Only `24:00` is the end of a day.
|
|
119
|
+
|
|
120
|
+
- **A conditional speed limit keeps its units.** `30 mph @ (…)` was read with
|
|
121
|
+
`parseFloat` and became 30 km/h — two-thirds of the real limit, applied to
|
|
122
|
+
the road as fact. It now uses the same parser as a plain `maxspeed`.
|
|
123
|
+
|
|
124
|
+
- **A rule table too wide for its index drops its surplus.** Past 65,535
|
|
125
|
+
distinct values the extra rows were kept and left pointing at rule zero,
|
|
126
|
+
applying one road's restriction to another.
|
|
127
|
+
|
|
128
|
+
- **Alternatives search the corridor that was downloaded for them.** The
|
|
129
|
+
widening that fetches the tiles an alternative could lie in replaced the
|
|
130
|
+
stitched graph, but the search was handed the graph from before it, so the
|
|
131
|
+
tiles were downloaded and discarded. Asking for a single route no longer
|
|
132
|
+
widens the corridor at all.
|
|
133
|
+
|
|
134
|
+
- **Alternatives come back in the order they would be driven**, by their real
|
|
135
|
+
cost, rather than in the order the penalties happened to find them; and two
|
|
136
|
+
routes are told apart by the road they travel rather than by which direction
|
|
137
|
+
of it, so coming back along a road already offered is no longer a different
|
|
138
|
+
way there.
|
|
139
|
+
|
|
140
|
+
- **A bundle compiled for one vehicle now carries its conditional
|
|
141
|
+
restrictions.** They were stored in the per-vehicle chunk, which only exists
|
|
142
|
+
when a bundle holds several vehicles or one whose routes depend on its size.
|
|
143
|
+
A `--profile car` compile wrote the single-chunk layout instead, where
|
|
144
|
+
nothing held them, so every road read as permanently open however carefully
|
|
145
|
+
a route named its departure time. The restrictions now ride in that layout
|
|
146
|
+
too, in a header byte no chunk written before them ever used.
|
|
147
|
+
|
|
148
|
+
Found while comparing bundle sizes between releases: a car-only Portugal
|
|
149
|
+
compiled byte for byte the same under 0.2.0 and 0.3.0, which it should not
|
|
150
|
+
have, since 129 of its ways carry `access:conditional` and 85
|
|
151
|
+
`motor_vehicle:conditional`. Compiled for motorcycle alone, Monaco now
|
|
152
|
+
stores the Avenue Pasteur ban it used to drop, and a route across it travels
|
|
153
|
+
183 m at midday and 3,081 m at 23:00 — the same answers the multi-vehicle
|
|
154
|
+
bundle gives.
|
|
155
|
+
|
|
156
|
+
- **Points on a road the network cannot reach no longer report no route.** The
|
|
157
|
+
road nearest a point is sometimes one nothing may legally enter: a pocket of
|
|
158
|
+
one-way streets behind banned turns, or an island of service roads. A route
|
|
159
|
+
to such a point failed outright, however much of the network lay between.
|
|
160
|
+
|
|
161
|
+
It now finishes on a road a little further off, trying the nearest few in
|
|
162
|
+
turn and taking the first that works, and `destinationSnap.distanceMeters`
|
|
163
|
+
reports how far short it stopped. `finishOnANearbyRoad: false` restores the
|
|
164
|
+
old behaviour of being told plainly that the point cannot be reached.
|
|
165
|
+
|
|
166
|
+
Found on Évora, where `no_left_turn` and `no_right_turn` relations on Rua de
|
|
167
|
+
Serpa Pinto seal the only entry to a street: Lisbon to a point there now
|
|
168
|
+
routes 133.2 km, finishing 23 m away, and Braga to Évora routes 460.2 km
|
|
169
|
+
where both previously failed. Lisbon airport, whose terminal roads are an
|
|
170
|
+
island 527 m from the nearest road a car can reach, routes too.
|
|
171
|
+
|
|
172
|
+
### Added
|
|
173
|
+
|
|
174
|
+
- `edgesWithConditionalRestrictions` in the compile report, beside
|
|
175
|
+
`edgesWithPhysicalLimits`, so a region's conditional data can be counted
|
|
176
|
+
rather than assumed.
|
|
177
|
+
|
|
178
|
+
### Known limitations
|
|
179
|
+
|
|
180
|
+
- **Nothing changes without `departAt`.** Omitting it ignores conditional
|
|
181
|
+
restrictions entirely, which is how the library behaved before.
|
|
182
|
+
- **Only closures are applied.** A road the plain tags already forbid stays
|
|
183
|
+
forbidden where a conditional value would open it, which errs towards
|
|
184
|
+
refusing a usable road rather than permitting a forbidden one.
|
|
185
|
+
- **One moment for the whole route**, rather than an arrival time per edge. A
|
|
186
|
+
long route is judged by when it set out.
|
|
187
|
+
- **`restriction:conditional` on a turn restriction relation is still not
|
|
188
|
+
read.** A morning-peak no-left-turn is enforced at every hour.
|
|
189
|
+
- **Conditions this library cannot answer are counted, not guessed.** Weather,
|
|
190
|
+
user groups, the purpose of access and a stay duration are parsed, reported
|
|
191
|
+
by `unreadableConditions`, and then left to one side with the road open.
|
|
192
|
+
- **`departAt` is the local time of the roads travelled.** No time-zone
|
|
193
|
+
conversion is done and no clock is consulted.
|
|
194
|
+
|
|
195
|
+
Measured against the earlier releases on one machine: routing is as fast as
|
|
196
|
+
0.2.0 — Porto to Lisbon 2,252 ms cold and 206 ms repeated, against 2,252 and
|
|
197
|
+
208 — and the compiler is 1% slower back to back, 8 min 05 s against
|
|
198
|
+
8 min 01 s, for 0.17 GB more memory. The browser build grew from 21.1 kB
|
|
199
|
+
gzipped to 24.8 kB, and the published tarball from 75.9 kB to 91.0 kB.
|
|
200
|
+
|
|
201
|
+
Braga to Évora is the one journey that changed materially, and it changed
|
|
202
|
+
from failing to working: 0.2.0 spent 7.9 s widening its corridor before
|
|
203
|
+
reporting no route, where this release finishes in 2.3 s.
|
|
204
|
+
|
|
205
|
+
### Compatibility
|
|
206
|
+
|
|
207
|
+
A bundle whose roads carry no conditional restriction is byte for byte the
|
|
208
|
+
file 0.2.0 wrote, in both layouts: the new sections live in header bytes that
|
|
209
|
+
every version so far left as zero. Monaco for a car is 26,177 bytes from
|
|
210
|
+
either compiler. Every bundle published so far still opens and routes
|
|
211
|
+
identically.
|
|
212
|
+
|
|
213
|
+
A bundle that does carry conditional restrictions cannot be opened by 0.2.0
|
|
214
|
+
or earlier, which report a truncated chunk.
|
|
8
215
|
|
|
9
216
|
## [0.2.0] - 2026-10-15
|
|
10
217
|
|
|
@@ -114,11 +321,19 @@ ship too, in a bundle of their own. Alternative routes moved to 0.3.0.
|
|
|
114
321
|
|
|
115
322
|
### Known limitations
|
|
116
323
|
|
|
324
|
+
- **Conditional restrictions are not read in this release.**
|
|
325
|
+
`access:conditional`, `restriction:conditional` and `hgv:conditional` are
|
|
326
|
+
ignored, so a street closed to lorries overnight or a square pedestrianised
|
|
327
|
+
on Sundays appears permanently open. It is the limitation most likely to
|
|
328
|
+
make a route wrong rather than merely longer, particularly for a lorry, so
|
|
329
|
+
it was scheduled ahead of alternative routes and is addressed under
|
|
330
|
+
Unreleased above.
|
|
117
331
|
- An active-travel bundle at country scale cannot be compiled with small
|
|
118
332
|
tiles: Portugal for walking and cycling at 40 km tiles exceeds the
|
|
119
333
|
compiler's 3 GB ceiling and is refused. The default 120 km works, at the
|
|
120
334
|
cost of a larger first download for a short urban route.
|
|
121
|
-
- Alternative routes are not in this release; they are planned for 0.3.0
|
|
335
|
+
- Alternative routes are not in this release; they are planned for 0.3.0,
|
|
336
|
+
after conditional restrictions.
|
|
122
337
|
|
|
123
338
|
### Compatibility
|
|
124
339
|
|