minotor 7.0.2 → 8.0.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/.cspell.json +11 -1
- package/CHANGELOG.md +8 -3
- package/README.md +26 -24
- package/dist/cli.mjs +1243 -267
- package/dist/cli.mjs.map +1 -1
- package/dist/gtfs/transfers.d.ts +13 -4
- package/dist/gtfs/trips.d.ts +12 -7
- package/dist/parser.cjs.js +494 -71
- package/dist/parser.cjs.js.map +1 -1
- package/dist/parser.esm.js +494 -71
- package/dist/parser.esm.js.map +1 -1
- package/dist/router.cjs.js +1 -1
- package/dist/router.cjs.js.map +1 -1
- package/dist/router.d.ts +2 -2
- package/dist/router.esm.js +1 -1
- package/dist/router.esm.js.map +1 -1
- package/dist/router.umd.js +1 -1
- package/dist/router.umd.js.map +1 -1
- package/dist/routing/__tests__/plotter.test.d.ts +1 -0
- package/dist/routing/plotter.d.ts +42 -3
- package/dist/routing/result.d.ts +23 -7
- package/dist/routing/route.d.ts +2 -0
- package/dist/routing/router.d.ts +78 -19
- package/dist/timetable/__tests__/tripId.test.d.ts +1 -0
- package/dist/timetable/io.d.ts +4 -2
- package/dist/timetable/proto/timetable.d.ts +13 -1
- package/dist/timetable/route.d.ts +41 -8
- package/dist/timetable/timetable.d.ts +18 -3
- package/dist/timetable/tripId.d.ts +15 -0
- package/package.json +1 -1
- package/src/__e2e__/router.test.ts +114 -105
- package/src/__e2e__/timetable/stops.bin +2 -2
- package/src/__e2e__/timetable/timetable.bin +2 -2
- package/src/cli/repl.ts +259 -1
- package/src/gtfs/__tests__/transfers.test.ts +468 -12
- package/src/gtfs/__tests__/trips.test.ts +350 -28
- package/src/gtfs/parser.ts +16 -4
- package/src/gtfs/transfers.ts +61 -18
- package/src/gtfs/trips.ts +97 -22
- package/src/router.ts +2 -2
- package/src/routing/__tests__/plotter.test.ts +230 -0
- package/src/routing/__tests__/result.test.ts +486 -125
- package/src/routing/__tests__/route.test.ts +7 -3
- package/src/routing/__tests__/router.test.ts +378 -172
- package/src/routing/plotter.ts +279 -48
- package/src/routing/result.ts +114 -34
- package/src/routing/route.ts +0 -3
- package/src/routing/router.ts +332 -211
- package/src/timetable/__tests__/io.test.ts +33 -1
- package/src/timetable/__tests__/route.test.ts +10 -3
- package/src/timetable/__tests__/timetable.test.ts +225 -57
- package/src/timetable/__tests__/tripId.test.ts +27 -0
- package/src/timetable/io.ts +71 -10
- package/src/timetable/proto/timetable.proto +14 -2
- package/src/timetable/proto/timetable.ts +218 -20
- package/src/timetable/route.ts +152 -19
- package/src/timetable/timetable.ts +45 -6
- package/src/timetable/tripId.ts +29 -0
|
@@ -58,7 +58,13 @@ describe('Route', () => {
|
|
|
58
58
|
const stops = new Uint32Array([1001, 1002]);
|
|
59
59
|
const serviceRouteId = 0;
|
|
60
60
|
|
|
61
|
-
const route = new Route(
|
|
61
|
+
const route = new Route(
|
|
62
|
+
0,
|
|
63
|
+
stopTimes,
|
|
64
|
+
pickUpDropOffTypes,
|
|
65
|
+
stops,
|
|
66
|
+
serviceRouteId,
|
|
67
|
+
);
|
|
62
68
|
|
|
63
69
|
describe('constructor', () => {
|
|
64
70
|
it('should create a route with correct properties', () => {
|
|
@@ -68,6 +74,7 @@ describe('Route', () => {
|
|
|
68
74
|
|
|
69
75
|
it('should handle empty route', () => {
|
|
70
76
|
const emptyRoute = new Route(
|
|
77
|
+
0,
|
|
71
78
|
new Uint16Array([]),
|
|
72
79
|
new Uint8Array([]),
|
|
73
80
|
new Uint32Array([]),
|
|
@@ -104,14 +111,14 @@ describe('Route', () => {
|
|
|
104
111
|
it('should throw error when stopA is not found', () => {
|
|
105
112
|
assert.throws(
|
|
106
113
|
() => route.isBefore(9999, 1002),
|
|
107
|
-
/Stop index
|
|
114
|
+
/Stop index not found for 9999 in route 0/,
|
|
108
115
|
);
|
|
109
116
|
});
|
|
110
117
|
|
|
111
118
|
it('should throw error when stopB is not found', () => {
|
|
112
119
|
assert.throws(
|
|
113
120
|
() => route.isBefore(1001, 9999),
|
|
114
|
-
/Stop index
|
|
121
|
+
/Stop index not found for 9999 in route 0/,
|
|
115
122
|
);
|
|
116
123
|
});
|
|
117
124
|
});
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
import assert from 'node:assert';
|
|
2
2
|
import { describe, it } from 'node:test';
|
|
3
3
|
|
|
4
|
-
import { encodePickUpDropOffTypes } from '../../gtfs/trips.js';
|
|
5
4
|
import { Duration } from '../duration.js';
|
|
6
|
-
import { NOT_AVAILABLE,
|
|
5
|
+
import { NOT_AVAILABLE, Route } from '../route.js';
|
|
7
6
|
import { Time } from '../time.js';
|
|
8
7
|
import {
|
|
9
8
|
RouteType,
|
|
10
9
|
ServiceRoute,
|
|
11
10
|
StopAdjacency,
|
|
12
11
|
Timetable,
|
|
12
|
+
TripBoarding,
|
|
13
13
|
} from '../timetable.js';
|
|
14
|
+
import { encode } from '../tripId.js';
|
|
14
15
|
|
|
15
16
|
describe('Timetable', () => {
|
|
16
17
|
const stopsAdjacency: StopAdjacency[] = [
|
|
17
|
-
{
|
|
18
|
+
{ routes: [] },
|
|
18
19
|
{
|
|
19
20
|
transfers: [{ destination: 2, type: 'RECOMMENDED' }],
|
|
20
21
|
routes: [0, 1],
|
|
@@ -30,40 +31,65 @@ describe('Timetable', () => {
|
|
|
30
31
|
routes: [1, 0],
|
|
31
32
|
},
|
|
32
33
|
{
|
|
33
|
-
transfers: [],
|
|
34
34
|
routes: [],
|
|
35
35
|
},
|
|
36
36
|
];
|
|
37
37
|
|
|
38
|
-
const route1 =
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
38
|
+
const route1 = Route.of({
|
|
39
|
+
id: 0,
|
|
40
|
+
serviceRouteId: 0,
|
|
41
|
+
trips: [
|
|
42
|
+
{
|
|
43
|
+
stops: [
|
|
44
|
+
{
|
|
45
|
+
id: 1,
|
|
46
|
+
arrivalTime: Time.fromHMS(16, 40, 0),
|
|
47
|
+
departureTime: Time.fromHMS(16, 50, 0),
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
id: 2,
|
|
51
|
+
arrivalTime: Time.fromHMS(17, 20, 0),
|
|
52
|
+
departureTime: Time.fromHMS(17, 30, 0),
|
|
53
|
+
pickUpType: NOT_AVAILABLE,
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
stops: [
|
|
59
|
+
{
|
|
60
|
+
id: 1,
|
|
61
|
+
arrivalTime: Time.fromHMS(18, 0, 0),
|
|
62
|
+
departureTime: Time.fromHMS(18, 10, 0),
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: 2,
|
|
66
|
+
arrivalTime: Time.fromHMS(19, 0, 0),
|
|
67
|
+
departureTime: Time.fromHMS(19, 10, 0),
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
});
|
|
73
|
+
const route2 = Route.of({
|
|
74
|
+
id: 1,
|
|
75
|
+
serviceRouteId: 1,
|
|
76
|
+
trips: [
|
|
77
|
+
{
|
|
78
|
+
stops: [
|
|
79
|
+
{
|
|
80
|
+
id: 2,
|
|
81
|
+
arrivalTime: Time.fromHMS(18, 20, 0),
|
|
82
|
+
departureTime: Time.fromHMS(18, 30, 0),
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: 1,
|
|
86
|
+
arrivalTime: Time.fromHMS(19, 0, 0),
|
|
87
|
+
departureTime: Time.fromHMS(19, 10, 0),
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
});
|
|
67
93
|
const routesAdjacency = [route1, route2];
|
|
68
94
|
const routes: ServiceRoute[] = [
|
|
69
95
|
{ type: 'RAIL', name: 'Route 1', routes: [0] },
|
|
@@ -115,31 +141,173 @@ describe('Timetable', () => {
|
|
|
115
141
|
const tripIndex = route.findEarliestTrip(2);
|
|
116
142
|
assert.strictEqual(tripIndex, 1);
|
|
117
143
|
});
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
[
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
144
|
+
describe('findReachableRoutes', () => {
|
|
145
|
+
it('should find reachable routes from a single stop', () => {
|
|
146
|
+
const fromStops = new Set([1]);
|
|
147
|
+
const reachableRoutes = sampleTimetable.findReachableRoutes(fromStops);
|
|
148
|
+
assert.strictEqual(reachableRoutes.size, 2);
|
|
149
|
+
assert.deepStrictEqual(
|
|
150
|
+
reachableRoutes,
|
|
151
|
+
new Map([
|
|
152
|
+
[route1, 1],
|
|
153
|
+
[route2, 1],
|
|
154
|
+
]),
|
|
155
|
+
);
|
|
156
|
+
});
|
|
130
157
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
158
|
+
it('should find reachable routes from multiple stops', () => {
|
|
159
|
+
const fromStops = new Set([1, 2]);
|
|
160
|
+
const reachableRoutes = sampleTimetable.findReachableRoutes(fromStops);
|
|
161
|
+
assert.strictEqual(reachableRoutes.size, 2);
|
|
162
|
+
|
|
163
|
+
assert.deepStrictEqual(
|
|
164
|
+
reachableRoutes,
|
|
165
|
+
new Map([
|
|
166
|
+
[route1, 1],
|
|
167
|
+
[route2, 2],
|
|
168
|
+
]),
|
|
169
|
+
);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('should find no reachable routes from stops with no routes', () => {
|
|
173
|
+
const fromStops = new Set([3]); // Stop 3 has no routes in sample timetable
|
|
174
|
+
const reachableRoutes = sampleTimetable.findReachableRoutes(fromStops);
|
|
175
|
+
assert.strictEqual(reachableRoutes.size, 0);
|
|
176
|
+
assert.deepStrictEqual(reachableRoutes, new Map());
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('should find no reachable routes from empty stop set', () => {
|
|
180
|
+
const fromStops = new Set<number>();
|
|
181
|
+
const reachableRoutes = sampleTimetable.findReachableRoutes(fromStops);
|
|
182
|
+
assert.strictEqual(reachableRoutes.size, 0);
|
|
183
|
+
assert.deepStrictEqual(reachableRoutes, new Map());
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it('should find no reachable routes from non-existent stops', () => {
|
|
187
|
+
const fromStops = new Set([999, 1000]); // Non-existent stops
|
|
188
|
+
const reachableRoutes = sampleTimetable.findReachableRoutes(fromStops);
|
|
189
|
+
assert.strictEqual(reachableRoutes.size, 0);
|
|
190
|
+
assert.deepStrictEqual(reachableRoutes, new Map());
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('should filter routes by transport modes correctly', () => {
|
|
194
|
+
const fromStops = new Set([1]);
|
|
195
|
+
|
|
196
|
+
const railRoutes = sampleTimetable.findReachableRoutes(
|
|
197
|
+
fromStops,
|
|
198
|
+
new Set<RouteType>(['RAIL']),
|
|
199
|
+
);
|
|
200
|
+
assert.strictEqual(railRoutes.size, 2);
|
|
201
|
+
assert.deepStrictEqual(
|
|
202
|
+
railRoutes,
|
|
203
|
+
new Map([
|
|
204
|
+
[route1, 1],
|
|
205
|
+
[route2, 1],
|
|
206
|
+
]),
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
const busRoutes = sampleTimetable.findReachableRoutes(
|
|
210
|
+
fromStops,
|
|
211
|
+
new Set<RouteType>(['BUS']),
|
|
212
|
+
);
|
|
213
|
+
assert.strictEqual(busRoutes.size, 0);
|
|
214
|
+
assert.deepStrictEqual(busRoutes, new Map());
|
|
215
|
+
|
|
216
|
+
const multiModeRoutes = sampleTimetable.findReachableRoutes(
|
|
217
|
+
fromStops,
|
|
218
|
+
new Set<RouteType>(['RAIL', 'BUS', 'SUBWAY']),
|
|
219
|
+
);
|
|
220
|
+
assert.strictEqual(multiModeRoutes.size, 2);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('should return earliest hop-on stop when route is accessible from multiple stops', () => {
|
|
224
|
+
// Create scenario where same route is accessible from multiple stops in the query
|
|
225
|
+
// route1 has stops [1, 2] in that order, so we need to test with those actual stops
|
|
226
|
+
const fromStops = new Set([1, 2]); // Both stops are on route1
|
|
227
|
+
const reachableRoutes = sampleTimetable.findReachableRoutes(fromStops);
|
|
228
|
+
|
|
229
|
+
// route1 should use stop 1 (earlier on the route than stop 2)
|
|
230
|
+
// route2 should use stop 2 (earlier on route2 which has [2, 1])
|
|
231
|
+
assert.strictEqual(reachableRoutes.size, 2);
|
|
232
|
+
assert.deepStrictEqual(
|
|
233
|
+
reachableRoutes,
|
|
234
|
+
new Map([
|
|
235
|
+
[route1, 1], // Stop 1 comes before stop 2 on route1
|
|
236
|
+
[route2, 2], // Stop 2 comes before stop 1 on route2
|
|
237
|
+
]),
|
|
238
|
+
);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
describe('getContinuousTrips', () => {
|
|
242
|
+
it('should return empty array when stop has no trip continuations', () => {
|
|
243
|
+
const continuousTrips = sampleTimetable.getContinuousTrips(1, 0, 0);
|
|
244
|
+
assert.deepStrictEqual(continuousTrips, []);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it('should return empty array when stop has trip continuations but not for the specified trip', () => {
|
|
248
|
+
// Create a timetable with trip continuations that don't match the query
|
|
249
|
+
const stopsWithContinuations: StopAdjacency[] = [
|
|
250
|
+
{ routes: [] },
|
|
251
|
+
{
|
|
252
|
+
routes: [0, 1],
|
|
253
|
+
tripContinuations: new Map([
|
|
254
|
+
[encode(0, 1), [{ hopOnStop: 2, routeId: 1, tripIndex: 0 }]], // Different trip index
|
|
255
|
+
]),
|
|
256
|
+
},
|
|
257
|
+
{ routes: [1] },
|
|
258
|
+
];
|
|
259
|
+
|
|
260
|
+
const timetableWithContinuations = new Timetable(
|
|
261
|
+
stopsWithContinuations,
|
|
262
|
+
routesAdjacency,
|
|
263
|
+
routes,
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
const continuousTrips = timetableWithContinuations.getContinuousTrips(
|
|
267
|
+
1,
|
|
268
|
+
0,
|
|
269
|
+
0,
|
|
270
|
+
); // Query trip index 0, but continuations are for trip index 1
|
|
271
|
+
assert.deepStrictEqual(continuousTrips, []);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it('should return trip continuations when they exist for the specified trip', () => {
|
|
275
|
+
const expectedContinuations: TripBoarding[] = [
|
|
276
|
+
{ hopOnStop: 2, routeId: 1, tripIndex: 0 },
|
|
277
|
+
{ hopOnStop: 2, routeId: 1, tripIndex: 1 },
|
|
278
|
+
];
|
|
279
|
+
|
|
280
|
+
const stopsWithContinuations: StopAdjacency[] = [
|
|
281
|
+
{ routes: [] },
|
|
282
|
+
{
|
|
283
|
+
routes: [0, 1],
|
|
284
|
+
tripContinuations: new Map([
|
|
285
|
+
[encode(0, 0), expectedContinuations], // Trip continuations for route 0, trip 0
|
|
286
|
+
]),
|
|
287
|
+
},
|
|
288
|
+
{ routes: [1] },
|
|
289
|
+
];
|
|
290
|
+
|
|
291
|
+
const timetableWithContinuations = new Timetable(
|
|
292
|
+
stopsWithContinuations,
|
|
293
|
+
routesAdjacency,
|
|
294
|
+
routes,
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
const continuousTrips = timetableWithContinuations.getContinuousTrips(
|
|
298
|
+
1,
|
|
299
|
+
0,
|
|
300
|
+
0,
|
|
301
|
+
);
|
|
302
|
+
assert.deepStrictEqual(continuousTrips, expectedContinuations);
|
|
303
|
+
});
|
|
136
304
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
305
|
+
it('should throw error when querying non-existent stop', () => {
|
|
306
|
+
assert.throws(
|
|
307
|
+
() => sampleTimetable.getContinuousTrips(999, 0, 0),
|
|
308
|
+
/Stop ID 999 not found/,
|
|
309
|
+
);
|
|
310
|
+
});
|
|
311
|
+
});
|
|
144
312
|
});
|
|
145
313
|
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import assert from 'node:assert';
|
|
2
|
+
import { describe, it } from 'node:test';
|
|
3
|
+
|
|
4
|
+
import { RouteId, TripRouteIndex } from '../route.js';
|
|
5
|
+
import { decode, encode } from '../tripId.js';
|
|
6
|
+
|
|
7
|
+
describe('tripId', () => {
|
|
8
|
+
it('should maintain identity for encode/decode round-trip', () => {
|
|
9
|
+
const testCases: [RouteId, TripRouteIndex][] = [
|
|
10
|
+
[0, 0],
|
|
11
|
+
[1, 1],
|
|
12
|
+
[1000, 500],
|
|
13
|
+
[65535, 32767],
|
|
14
|
+
[131071, 0],
|
|
15
|
+
[0, 32767],
|
|
16
|
+
[(1 << 17) - 1, (1 << 15) - 1], // Maximum values
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
testCases.forEach(([routeId, tripIndex]) => {
|
|
20
|
+
const tripId = encode(routeId, tripIndex);
|
|
21
|
+
const [decodedRouteId, decodedTripIndex] = decode(tripId);
|
|
22
|
+
|
|
23
|
+
assert.strictEqual(decodedRouteId, routeId);
|
|
24
|
+
assert.strictEqual(decodedTripIndex, tripIndex);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
});
|
package/src/timetable/io.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
ServiceRoute as ProtoServiceRoute,
|
|
6
6
|
StopAdjacency as ProtoStopAdjacency,
|
|
7
7
|
TransferType as ProtoTransferType,
|
|
8
|
+
TripContinuationEntry as ProtoTripContinuationEntry,
|
|
8
9
|
} from './proto/timetable.js';
|
|
9
10
|
import { Route } from './route.js';
|
|
10
11
|
import {
|
|
@@ -14,6 +15,7 @@ import {
|
|
|
14
15
|
StopAdjacency,
|
|
15
16
|
Transfer,
|
|
16
17
|
TransferType,
|
|
18
|
+
TripBoarding,
|
|
17
19
|
} from './timetable.js';
|
|
18
20
|
|
|
19
21
|
export type SerializedRoute = {
|
|
@@ -125,14 +127,19 @@ export const serializeStopsAdjacency = (
|
|
|
125
127
|
): ProtoStopAdjacency[] => {
|
|
126
128
|
return stopsAdjacency.map((value) => {
|
|
127
129
|
return {
|
|
128
|
-
transfers: value.transfers
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
130
|
+
transfers: value.transfers
|
|
131
|
+
? value.transfers.map((transfer) => ({
|
|
132
|
+
destination: transfer.destination,
|
|
133
|
+
type: serializeTransferType(transfer.type),
|
|
134
|
+
...(transfer.minTransferTime !== undefined && {
|
|
135
|
+
minTransferTime: transfer.minTransferTime.toSeconds(),
|
|
136
|
+
}),
|
|
137
|
+
}))
|
|
138
|
+
: [],
|
|
135
139
|
routes: value.routes,
|
|
140
|
+
tripContinuations: value.tripContinuations
|
|
141
|
+
? serializeTripContinuations(value.tripContinuations)
|
|
142
|
+
: [],
|
|
136
143
|
};
|
|
137
144
|
});
|
|
138
145
|
};
|
|
@@ -190,10 +197,22 @@ export const deserializeStopsAdjacency = (
|
|
|
190
197
|
transfers.push(newTransfer);
|
|
191
198
|
}
|
|
192
199
|
|
|
193
|
-
|
|
194
|
-
transfers: transfers,
|
|
200
|
+
const stopAdjacency: StopAdjacency = {
|
|
195
201
|
routes: value.routes,
|
|
196
|
-
}
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
if (transfers.length > 0) {
|
|
205
|
+
stopAdjacency.transfers = transfers;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const deserializedTripContinuations = deserializeTripContinuations(
|
|
209
|
+
value.tripContinuations,
|
|
210
|
+
);
|
|
211
|
+
if (deserializedTripContinuations.size > 0) {
|
|
212
|
+
stopAdjacency.tripContinuations = deserializedTripContinuations;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
result.push(stopAdjacency);
|
|
197
216
|
}
|
|
198
217
|
|
|
199
218
|
return result;
|
|
@@ -210,6 +229,7 @@ export const deserializeRoutesAdjacency = (
|
|
|
210
229
|
const stops = bytesToUint32Array(value.stops);
|
|
211
230
|
routesAdjacency.push(
|
|
212
231
|
new Route(
|
|
232
|
+
i,
|
|
213
233
|
bytesToUint16Array(value.stopTimes),
|
|
214
234
|
value.pickUpDropOffTypes,
|
|
215
235
|
stops,
|
|
@@ -319,3 +339,44 @@ const serializeRouteType = (type: RouteType): ProtoRouteType => {
|
|
|
319
339
|
return ProtoRouteType.MONORAIL;
|
|
320
340
|
}
|
|
321
341
|
};
|
|
342
|
+
|
|
343
|
+
export const serializeTripContinuations = (
|
|
344
|
+
tripContinuations: Map<number, TripBoarding[]>,
|
|
345
|
+
): ProtoTripContinuationEntry[] => {
|
|
346
|
+
const result: ProtoTripContinuationEntry[] = [];
|
|
347
|
+
|
|
348
|
+
for (const [key, value] of tripContinuations.entries()) {
|
|
349
|
+
result.push({
|
|
350
|
+
key: key,
|
|
351
|
+
value: value.map((tripBoarding) => ({
|
|
352
|
+
hopOnStop: tripBoarding.hopOnStop,
|
|
353
|
+
routeId: tripBoarding.routeId,
|
|
354
|
+
tripIndex: tripBoarding.tripIndex,
|
|
355
|
+
})),
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return result;
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
export const deserializeTripContinuations = (
|
|
363
|
+
protoTripContinuations: ProtoTripContinuationEntry[],
|
|
364
|
+
): Map<number, TripBoarding[]> => {
|
|
365
|
+
const result = new Map<number, TripBoarding[]>();
|
|
366
|
+
|
|
367
|
+
for (let i = 0; i < protoTripContinuations.length; i++) {
|
|
368
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
369
|
+
const entry = protoTripContinuations[i]!;
|
|
370
|
+
const tripBoardings: TripBoarding[] = entry.value.map(
|
|
371
|
+
(protoTripBoarding) => ({
|
|
372
|
+
hopOnStop: protoTripBoarding.hopOnStop,
|
|
373
|
+
routeId: protoTripBoarding.routeId,
|
|
374
|
+
tripIndex: protoTripBoarding.tripIndex,
|
|
375
|
+
}),
|
|
376
|
+
);
|
|
377
|
+
|
|
378
|
+
result.set(entry.key, tripBoardings);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return result;
|
|
382
|
+
};
|
|
@@ -40,9 +40,21 @@ message Transfer {
|
|
|
40
40
|
optional uint32 minTransferTime = 3;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
message TripBoarding {
|
|
44
|
+
uint32 hopOnStop = 1;
|
|
45
|
+
uint32 routeId = 2;
|
|
46
|
+
uint32 tripIndex = 3;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
message TripContinuationEntry {
|
|
50
|
+
uint32 key = 1;
|
|
51
|
+
repeated TripBoarding value = 2;
|
|
52
|
+
}
|
|
53
|
+
|
|
43
54
|
message StopAdjacency {
|
|
44
|
-
repeated
|
|
45
|
-
repeated
|
|
55
|
+
repeated uint32 routes = 1;
|
|
56
|
+
repeated Transfer transfers = 2;
|
|
57
|
+
repeated TripContinuationEntry tripContinuations = 3;
|
|
46
58
|
}
|
|
47
59
|
|
|
48
60
|
enum RouteType {
|