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
package/dist/parser.esm.js
CHANGED
|
@@ -12294,41 +12294,191 @@ const Transfer = {
|
|
|
12294
12294
|
return message;
|
|
12295
12295
|
},
|
|
12296
12296
|
};
|
|
12297
|
-
function
|
|
12298
|
-
return {
|
|
12297
|
+
function createBaseTripBoarding() {
|
|
12298
|
+
return { hopOnStop: 0, routeId: 0, tripIndex: 0 };
|
|
12299
12299
|
}
|
|
12300
|
-
const
|
|
12300
|
+
const TripBoarding = {
|
|
12301
12301
|
encode(message, writer = new BinaryWriter()) {
|
|
12302
|
-
|
|
12303
|
-
|
|
12302
|
+
if (message.hopOnStop !== 0) {
|
|
12303
|
+
writer.uint32(8).uint32(message.hopOnStop);
|
|
12304
12304
|
}
|
|
12305
|
-
|
|
12306
|
-
|
|
12307
|
-
|
|
12305
|
+
if (message.routeId !== 0) {
|
|
12306
|
+
writer.uint32(16).uint32(message.routeId);
|
|
12307
|
+
}
|
|
12308
|
+
if (message.tripIndex !== 0) {
|
|
12309
|
+
writer.uint32(24).uint32(message.tripIndex);
|
|
12308
12310
|
}
|
|
12309
|
-
writer.join();
|
|
12310
12311
|
return writer;
|
|
12311
12312
|
},
|
|
12312
12313
|
decode(input, length) {
|
|
12313
12314
|
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
|
|
12314
12315
|
const end = length === undefined ? reader.len : reader.pos + length;
|
|
12315
|
-
const message =
|
|
12316
|
+
const message = createBaseTripBoarding();
|
|
12316
12317
|
while (reader.pos < end) {
|
|
12317
12318
|
const tag = reader.uint32();
|
|
12318
12319
|
switch (tag >>> 3) {
|
|
12319
12320
|
case 1: {
|
|
12320
|
-
if (tag !==
|
|
12321
|
+
if (tag !== 8) {
|
|
12321
12322
|
break;
|
|
12322
12323
|
}
|
|
12323
|
-
message.
|
|
12324
|
+
message.hopOnStop = reader.uint32();
|
|
12325
|
+
continue;
|
|
12326
|
+
}
|
|
12327
|
+
case 2: {
|
|
12328
|
+
if (tag !== 16) {
|
|
12329
|
+
break;
|
|
12330
|
+
}
|
|
12331
|
+
message.routeId = reader.uint32();
|
|
12332
|
+
continue;
|
|
12333
|
+
}
|
|
12334
|
+
case 3: {
|
|
12335
|
+
if (tag !== 24) {
|
|
12336
|
+
break;
|
|
12337
|
+
}
|
|
12338
|
+
message.tripIndex = reader.uint32();
|
|
12339
|
+
continue;
|
|
12340
|
+
}
|
|
12341
|
+
}
|
|
12342
|
+
if ((tag & 7) === 4 || tag === 0) {
|
|
12343
|
+
break;
|
|
12344
|
+
}
|
|
12345
|
+
reader.skip(tag & 7);
|
|
12346
|
+
}
|
|
12347
|
+
return message;
|
|
12348
|
+
},
|
|
12349
|
+
fromJSON(object) {
|
|
12350
|
+
return {
|
|
12351
|
+
hopOnStop: isSet(object.hopOnStop) ? globalThis.Number(object.hopOnStop) : 0,
|
|
12352
|
+
routeId: isSet(object.routeId) ? globalThis.Number(object.routeId) : 0,
|
|
12353
|
+
tripIndex: isSet(object.tripIndex) ? globalThis.Number(object.tripIndex) : 0,
|
|
12354
|
+
};
|
|
12355
|
+
},
|
|
12356
|
+
toJSON(message) {
|
|
12357
|
+
const obj = {};
|
|
12358
|
+
if (message.hopOnStop !== 0) {
|
|
12359
|
+
obj.hopOnStop = Math.round(message.hopOnStop);
|
|
12360
|
+
}
|
|
12361
|
+
if (message.routeId !== 0) {
|
|
12362
|
+
obj.routeId = Math.round(message.routeId);
|
|
12363
|
+
}
|
|
12364
|
+
if (message.tripIndex !== 0) {
|
|
12365
|
+
obj.tripIndex = Math.round(message.tripIndex);
|
|
12366
|
+
}
|
|
12367
|
+
return obj;
|
|
12368
|
+
},
|
|
12369
|
+
create(base) {
|
|
12370
|
+
return TripBoarding.fromPartial(base !== null && base !== void 0 ? base : {});
|
|
12371
|
+
},
|
|
12372
|
+
fromPartial(object) {
|
|
12373
|
+
var _a, _b, _c;
|
|
12374
|
+
const message = createBaseTripBoarding();
|
|
12375
|
+
message.hopOnStop = (_a = object.hopOnStop) !== null && _a !== void 0 ? _a : 0;
|
|
12376
|
+
message.routeId = (_b = object.routeId) !== null && _b !== void 0 ? _b : 0;
|
|
12377
|
+
message.tripIndex = (_c = object.tripIndex) !== null && _c !== void 0 ? _c : 0;
|
|
12378
|
+
return message;
|
|
12379
|
+
},
|
|
12380
|
+
};
|
|
12381
|
+
function createBaseTripContinuationEntry() {
|
|
12382
|
+
return { key: 0, value: [] };
|
|
12383
|
+
}
|
|
12384
|
+
const TripContinuationEntry = {
|
|
12385
|
+
encode(message, writer = new BinaryWriter()) {
|
|
12386
|
+
if (message.key !== 0) {
|
|
12387
|
+
writer.uint32(8).uint32(message.key);
|
|
12388
|
+
}
|
|
12389
|
+
for (const v of message.value) {
|
|
12390
|
+
TripBoarding.encode(v, writer.uint32(18).fork()).join();
|
|
12391
|
+
}
|
|
12392
|
+
return writer;
|
|
12393
|
+
},
|
|
12394
|
+
decode(input, length) {
|
|
12395
|
+
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
|
|
12396
|
+
const end = length === undefined ? reader.len : reader.pos + length;
|
|
12397
|
+
const message = createBaseTripContinuationEntry();
|
|
12398
|
+
while (reader.pos < end) {
|
|
12399
|
+
const tag = reader.uint32();
|
|
12400
|
+
switch (tag >>> 3) {
|
|
12401
|
+
case 1: {
|
|
12402
|
+
if (tag !== 8) {
|
|
12403
|
+
break;
|
|
12404
|
+
}
|
|
12405
|
+
message.key = reader.uint32();
|
|
12324
12406
|
continue;
|
|
12325
12407
|
}
|
|
12326
12408
|
case 2: {
|
|
12327
|
-
if (tag
|
|
12409
|
+
if (tag !== 18) {
|
|
12410
|
+
break;
|
|
12411
|
+
}
|
|
12412
|
+
message.value.push(TripBoarding.decode(reader, reader.uint32()));
|
|
12413
|
+
continue;
|
|
12414
|
+
}
|
|
12415
|
+
}
|
|
12416
|
+
if ((tag & 7) === 4 || tag === 0) {
|
|
12417
|
+
break;
|
|
12418
|
+
}
|
|
12419
|
+
reader.skip(tag & 7);
|
|
12420
|
+
}
|
|
12421
|
+
return message;
|
|
12422
|
+
},
|
|
12423
|
+
fromJSON(object) {
|
|
12424
|
+
return {
|
|
12425
|
+
key: isSet(object.key) ? globalThis.Number(object.key) : 0,
|
|
12426
|
+
value: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.value) ? object.value.map((e) => TripBoarding.fromJSON(e)) : [],
|
|
12427
|
+
};
|
|
12428
|
+
},
|
|
12429
|
+
toJSON(message) {
|
|
12430
|
+
var _a;
|
|
12431
|
+
const obj = {};
|
|
12432
|
+
if (message.key !== 0) {
|
|
12433
|
+
obj.key = Math.round(message.key);
|
|
12434
|
+
}
|
|
12435
|
+
if ((_a = message.value) === null || _a === void 0 ? void 0 : _a.length) {
|
|
12436
|
+
obj.value = message.value.map((e) => TripBoarding.toJSON(e));
|
|
12437
|
+
}
|
|
12438
|
+
return obj;
|
|
12439
|
+
},
|
|
12440
|
+
create(base) {
|
|
12441
|
+
return TripContinuationEntry.fromPartial(base !== null && base !== void 0 ? base : {});
|
|
12442
|
+
},
|
|
12443
|
+
fromPartial(object) {
|
|
12444
|
+
var _a, _b;
|
|
12445
|
+
const message = createBaseTripContinuationEntry();
|
|
12446
|
+
message.key = (_a = object.key) !== null && _a !== void 0 ? _a : 0;
|
|
12447
|
+
message.value = ((_b = object.value) === null || _b === void 0 ? void 0 : _b.map((e) => TripBoarding.fromPartial(e))) || [];
|
|
12448
|
+
return message;
|
|
12449
|
+
},
|
|
12450
|
+
};
|
|
12451
|
+
function createBaseStopAdjacency() {
|
|
12452
|
+
return { routes: [], transfers: [], tripContinuations: [] };
|
|
12453
|
+
}
|
|
12454
|
+
const StopAdjacency = {
|
|
12455
|
+
encode(message, writer = new BinaryWriter()) {
|
|
12456
|
+
writer.uint32(10).fork();
|
|
12457
|
+
for (const v of message.routes) {
|
|
12458
|
+
writer.uint32(v);
|
|
12459
|
+
}
|
|
12460
|
+
writer.join();
|
|
12461
|
+
for (const v of message.transfers) {
|
|
12462
|
+
Transfer.encode(v, writer.uint32(18).fork()).join();
|
|
12463
|
+
}
|
|
12464
|
+
for (const v of message.tripContinuations) {
|
|
12465
|
+
TripContinuationEntry.encode(v, writer.uint32(26).fork()).join();
|
|
12466
|
+
}
|
|
12467
|
+
return writer;
|
|
12468
|
+
},
|
|
12469
|
+
decode(input, length) {
|
|
12470
|
+
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
|
|
12471
|
+
const end = length === undefined ? reader.len : reader.pos + length;
|
|
12472
|
+
const message = createBaseStopAdjacency();
|
|
12473
|
+
while (reader.pos < end) {
|
|
12474
|
+
const tag = reader.uint32();
|
|
12475
|
+
switch (tag >>> 3) {
|
|
12476
|
+
case 1: {
|
|
12477
|
+
if (tag === 8) {
|
|
12328
12478
|
message.routes.push(reader.uint32());
|
|
12329
12479
|
continue;
|
|
12330
12480
|
}
|
|
12331
|
-
if (tag ===
|
|
12481
|
+
if (tag === 10) {
|
|
12332
12482
|
const end2 = reader.uint32() + reader.pos;
|
|
12333
12483
|
while (reader.pos < end2) {
|
|
12334
12484
|
message.routes.push(reader.uint32());
|
|
@@ -12337,6 +12487,20 @@ const StopAdjacency = {
|
|
|
12337
12487
|
}
|
|
12338
12488
|
break;
|
|
12339
12489
|
}
|
|
12490
|
+
case 2: {
|
|
12491
|
+
if (tag !== 18) {
|
|
12492
|
+
break;
|
|
12493
|
+
}
|
|
12494
|
+
message.transfers.push(Transfer.decode(reader, reader.uint32()));
|
|
12495
|
+
continue;
|
|
12496
|
+
}
|
|
12497
|
+
case 3: {
|
|
12498
|
+
if (tag !== 26) {
|
|
12499
|
+
break;
|
|
12500
|
+
}
|
|
12501
|
+
message.tripContinuations.push(TripContinuationEntry.decode(reader, reader.uint32()));
|
|
12502
|
+
continue;
|
|
12503
|
+
}
|
|
12340
12504
|
}
|
|
12341
12505
|
if ((tag & 7) === 4 || tag === 0) {
|
|
12342
12506
|
break;
|
|
@@ -12347,20 +12511,26 @@ const StopAdjacency = {
|
|
|
12347
12511
|
},
|
|
12348
12512
|
fromJSON(object) {
|
|
12349
12513
|
return {
|
|
12514
|
+
routes: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.routes) ? object.routes.map((e) => globalThis.Number(e)) : [],
|
|
12350
12515
|
transfers: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.transfers)
|
|
12351
12516
|
? object.transfers.map((e) => Transfer.fromJSON(e))
|
|
12352
12517
|
: [],
|
|
12353
|
-
|
|
12518
|
+
tripContinuations: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.tripContinuations)
|
|
12519
|
+
? object.tripContinuations.map((e) => TripContinuationEntry.fromJSON(e))
|
|
12520
|
+
: [],
|
|
12354
12521
|
};
|
|
12355
12522
|
},
|
|
12356
12523
|
toJSON(message) {
|
|
12357
|
-
var _a, _b;
|
|
12524
|
+
var _a, _b, _c;
|
|
12358
12525
|
const obj = {};
|
|
12359
|
-
if ((_a = message.
|
|
12526
|
+
if ((_a = message.routes) === null || _a === void 0 ? void 0 : _a.length) {
|
|
12527
|
+
obj.routes = message.routes.map((e) => Math.round(e));
|
|
12528
|
+
}
|
|
12529
|
+
if ((_b = message.transfers) === null || _b === void 0 ? void 0 : _b.length) {
|
|
12360
12530
|
obj.transfers = message.transfers.map((e) => Transfer.toJSON(e));
|
|
12361
12531
|
}
|
|
12362
|
-
if ((
|
|
12363
|
-
obj.
|
|
12532
|
+
if ((_c = message.tripContinuations) === null || _c === void 0 ? void 0 : _c.length) {
|
|
12533
|
+
obj.tripContinuations = message.tripContinuations.map((e) => TripContinuationEntry.toJSON(e));
|
|
12364
12534
|
}
|
|
12365
12535
|
return obj;
|
|
12366
12536
|
},
|
|
@@ -12368,10 +12538,11 @@ const StopAdjacency = {
|
|
|
12368
12538
|
return StopAdjacency.fromPartial(base !== null && base !== void 0 ? base : {});
|
|
12369
12539
|
},
|
|
12370
12540
|
fromPartial(object) {
|
|
12371
|
-
var _a, _b;
|
|
12541
|
+
var _a, _b, _c;
|
|
12372
12542
|
const message = createBaseStopAdjacency();
|
|
12373
|
-
message.
|
|
12374
|
-
message.
|
|
12543
|
+
message.routes = ((_a = object.routes) === null || _a === void 0 ? void 0 : _a.map((e) => e)) || [];
|
|
12544
|
+
message.transfers = ((_b = object.transfers) === null || _b === void 0 ? void 0 : _b.map((e) => Transfer.fromPartial(e))) || [];
|
|
12545
|
+
message.tripContinuations = ((_c = object.tripContinuations) === null || _c === void 0 ? void 0 : _c.map((e) => TripContinuationEntry.fromPartial(e))) || [];
|
|
12375
12546
|
return message;
|
|
12376
12547
|
},
|
|
12377
12548
|
};
|
|
@@ -12860,7 +13031,8 @@ const toPickupDropOffType = (numericalType) => {
|
|
|
12860
13031
|
* A route identifies all trips of a given service route sharing the same list of stops.
|
|
12861
13032
|
*/
|
|
12862
13033
|
class Route {
|
|
12863
|
-
constructor(stopTimes, pickUpDropOffTypes, stops, serviceRouteId) {
|
|
13034
|
+
constructor(id, stopTimes, pickUpDropOffTypes, stops, serviceRouteId) {
|
|
13035
|
+
this.id = id;
|
|
12864
13036
|
this.stopTimes = stopTimes;
|
|
12865
13037
|
this.pickUpDropOffTypes = pickUpDropOffTypes;
|
|
12866
13038
|
this.stops = stops;
|
|
@@ -12873,6 +13045,78 @@ class Route {
|
|
|
12873
13045
|
this.stopIndices.set(stops[i], i);
|
|
12874
13046
|
}
|
|
12875
13047
|
}
|
|
13048
|
+
/**
|
|
13049
|
+
* Creates a new route from multiple trips with their stops.
|
|
13050
|
+
*
|
|
13051
|
+
* @param params The route parameters including ID, service route ID, and trips.
|
|
13052
|
+
* @returns The new route.
|
|
13053
|
+
*/
|
|
13054
|
+
static of(params) {
|
|
13055
|
+
var _a, _b;
|
|
13056
|
+
const { id, serviceRouteId, trips } = params;
|
|
13057
|
+
if (trips.length === 0) {
|
|
13058
|
+
throw new Error('At least one trip must be provided');
|
|
13059
|
+
}
|
|
13060
|
+
// All trips must have the same stops in the same order
|
|
13061
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
13062
|
+
const firstTrip = trips[0];
|
|
13063
|
+
const stopIds = new Uint32Array(firstTrip.stops.map((stop) => stop.id));
|
|
13064
|
+
const numStops = stopIds.length;
|
|
13065
|
+
// Validate all trips have the same stops
|
|
13066
|
+
for (let tripIndex = 1; tripIndex < trips.length; tripIndex++) {
|
|
13067
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
13068
|
+
const trip = trips[tripIndex];
|
|
13069
|
+
if (trip.stops.length !== numStops) {
|
|
13070
|
+
throw new Error(`Trip ${tripIndex} has ${trip.stops.length} stops, expected ${numStops}`);
|
|
13071
|
+
}
|
|
13072
|
+
for (let stopIndex = 0; stopIndex < numStops; stopIndex++) {
|
|
13073
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
13074
|
+
if (trip.stops[stopIndex].id !== stopIds[stopIndex]) {
|
|
13075
|
+
throw new Error(`Trip ${tripIndex} has different stop at index ${stopIndex}`);
|
|
13076
|
+
}
|
|
13077
|
+
}
|
|
13078
|
+
}
|
|
13079
|
+
// Create stopTimes array with arrivals and departures for all trips
|
|
13080
|
+
const stopTimes = new Uint16Array(trips.length * numStops * 2);
|
|
13081
|
+
for (let tripIndex = 0; tripIndex < trips.length; tripIndex++) {
|
|
13082
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
13083
|
+
const trip = trips[tripIndex];
|
|
13084
|
+
for (let stopIndex = 0; stopIndex < numStops; stopIndex++) {
|
|
13085
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
13086
|
+
const stop = trip.stops[stopIndex];
|
|
13087
|
+
const baseIndex = (tripIndex * numStops + stopIndex) * 2;
|
|
13088
|
+
stopTimes[baseIndex] = stop.arrivalTime.toMinutes();
|
|
13089
|
+
stopTimes[baseIndex + 1] = stop.departureTime.toMinutes();
|
|
13090
|
+
}
|
|
13091
|
+
}
|
|
13092
|
+
// Create pickUpDropOffTypes array (2-bit encoded) for all trips
|
|
13093
|
+
const totalStopEntries = trips.length * numStops;
|
|
13094
|
+
const pickUpDropOffTypes = new Uint8Array(Math.ceil(totalStopEntries / 2));
|
|
13095
|
+
for (let tripIndex = 0; tripIndex < trips.length; tripIndex++) {
|
|
13096
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
13097
|
+
const trip = trips[tripIndex];
|
|
13098
|
+
for (let stopIndex = 0; stopIndex < numStops; stopIndex++) {
|
|
13099
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
13100
|
+
const stop = trip.stops[stopIndex];
|
|
13101
|
+
const globalIndex = tripIndex * numStops + stopIndex;
|
|
13102
|
+
const pickUp = (_a = stop.pickUpType) !== null && _a !== void 0 ? _a : REGULAR;
|
|
13103
|
+
const dropOff = (_b = stop.dropOffType) !== null && _b !== void 0 ? _b : REGULAR;
|
|
13104
|
+
const byteIndex = Math.floor(globalIndex / 2);
|
|
13105
|
+
const isSecondPair = globalIndex % 2 === 1;
|
|
13106
|
+
if (isSecondPair) {
|
|
13107
|
+
// Second pair: pickup in upper 2 bits, dropOff in bits 4-5
|
|
13108
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
13109
|
+
pickUpDropOffTypes[byteIndex] |= (pickUp << 6) | (dropOff << 4);
|
|
13110
|
+
}
|
|
13111
|
+
else {
|
|
13112
|
+
// First pair: pickup in bits 2-3, dropOff in lower 2 bits
|
|
13113
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
13114
|
+
pickUpDropOffTypes[byteIndex] |= (pickUp << 2) | dropOff;
|
|
13115
|
+
}
|
|
13116
|
+
}
|
|
13117
|
+
}
|
|
13118
|
+
return new Route(id, stopTimes, pickUpDropOffTypes, stopIds, serviceRouteId);
|
|
13119
|
+
}
|
|
12876
13120
|
/**
|
|
12877
13121
|
* Serializes the Route into binary arrays.
|
|
12878
13122
|
*
|
|
@@ -12896,11 +13140,11 @@ class Route {
|
|
|
12896
13140
|
isBefore(stopA, stopB) {
|
|
12897
13141
|
const stopAIndex = this.stopIndices.get(stopA);
|
|
12898
13142
|
if (stopAIndex === undefined) {
|
|
12899
|
-
throw new Error(`Stop index ${
|
|
13143
|
+
throw new Error(`Stop index not found for ${stopA} in route ${this.serviceRouteId}`);
|
|
12900
13144
|
}
|
|
12901
13145
|
const stopBIndex = this.stopIndices.get(stopB);
|
|
12902
13146
|
if (stopBIndex === undefined) {
|
|
12903
|
-
throw new Error(`Stop index ${
|
|
13147
|
+
throw new Error(`Stop index not found for ${stopB} in route ${this.serviceRouteId}`);
|
|
12904
13148
|
}
|
|
12905
13149
|
return stopAIndex < stopBIndex;
|
|
12906
13150
|
}
|
|
@@ -12912,6 +13156,14 @@ class Route {
|
|
|
12912
13156
|
getNbStops() {
|
|
12913
13157
|
return this.nbStops;
|
|
12914
13158
|
}
|
|
13159
|
+
/**
|
|
13160
|
+
* Retrieves the number of trips in the route.
|
|
13161
|
+
*
|
|
13162
|
+
* @returns The total number of trips in the route.
|
|
13163
|
+
*/
|
|
13164
|
+
getNbTrips() {
|
|
13165
|
+
return this.nbTrips;
|
|
13166
|
+
}
|
|
12915
13167
|
/**
|
|
12916
13168
|
* Finds the ServiceRouteId of the route. It corresponds the identifier
|
|
12917
13169
|
* of the service shown to the end user as a route.
|
|
@@ -12929,7 +13181,7 @@ class Route {
|
|
|
12929
13181
|
* @returns The arrival time at the specified stop and trip as a Time object.
|
|
12930
13182
|
*/
|
|
12931
13183
|
arrivalAt(stopId, tripIndex) {
|
|
12932
|
-
const arrivalIndex = (tripIndex * this.stops.length + this.
|
|
13184
|
+
const arrivalIndex = (tripIndex * this.stops.length + this.stopRouteIndex(stopId)) * 2;
|
|
12933
13185
|
const arrival = this.stopTimes[arrivalIndex];
|
|
12934
13186
|
if (arrival === undefined) {
|
|
12935
13187
|
throw new Error(`Arrival time not found for stop ${stopId} at trip index ${tripIndex} in route ${this.serviceRouteId}`);
|
|
@@ -12944,7 +13196,7 @@ class Route {
|
|
|
12944
13196
|
* @returns The departure time at the specified stop and trip as a Time object.
|
|
12945
13197
|
*/
|
|
12946
13198
|
departureFrom(stopId, tripIndex) {
|
|
12947
|
-
const departureIndex = (tripIndex * this.stops.length + this.
|
|
13199
|
+
const departureIndex = (tripIndex * this.stops.length + this.stopRouteIndex(stopId)) * 2 + 1;
|
|
12948
13200
|
const departure = this.stopTimes[departureIndex];
|
|
12949
13201
|
if (departure === undefined) {
|
|
12950
13202
|
throw new Error(`Departure time not found for stop ${stopId} at trip index ${tripIndex} in route ${this.serviceRouteId}`);
|
|
@@ -12959,7 +13211,7 @@ class Route {
|
|
|
12959
13211
|
* @returns The pick-up type at the specified stop and trip.
|
|
12960
13212
|
*/
|
|
12961
13213
|
pickUpTypeFrom(stopId, tripIndex) {
|
|
12962
|
-
const globalIndex = tripIndex * this.stops.length + this.
|
|
13214
|
+
const globalIndex = tripIndex * this.stops.length + this.stopRouteIndex(stopId);
|
|
12963
13215
|
const byteIndex = Math.floor(globalIndex / 2);
|
|
12964
13216
|
const isSecondPair = globalIndex % 2 === 1;
|
|
12965
13217
|
const byte = this.pickUpDropOffTypes[byteIndex];
|
|
@@ -12979,7 +13231,7 @@ class Route {
|
|
|
12979
13231
|
* @returns The drop-off type at the specified stop and trip.
|
|
12980
13232
|
*/
|
|
12981
13233
|
dropOffTypeAt(stopId, tripIndex) {
|
|
12982
|
-
const globalIndex = tripIndex * this.stops.length + this.
|
|
13234
|
+
const globalIndex = tripIndex * this.stops.length + this.stopRouteIndex(stopId);
|
|
12983
13235
|
const byteIndex = Math.floor(globalIndex / 2);
|
|
12984
13236
|
const isSecondPair = globalIndex % 2 === 1;
|
|
12985
13237
|
const byte = this.pickUpDropOffTypes[byteIndex];
|
|
@@ -13039,13 +13291,25 @@ class Route {
|
|
|
13039
13291
|
* @param stopId The StopId of the stop to locate in the route.
|
|
13040
13292
|
* @returns The index of the stop in the route.
|
|
13041
13293
|
*/
|
|
13042
|
-
|
|
13294
|
+
stopRouteIndex(stopId) {
|
|
13043
13295
|
const stopIndex = this.stopIndices.get(stopId);
|
|
13044
13296
|
if (stopIndex === undefined) {
|
|
13045
13297
|
throw new Error(`Stop index for ${stopId} not found in route ${this.serviceRouteId}`);
|
|
13046
13298
|
}
|
|
13047
13299
|
return stopIndex;
|
|
13048
13300
|
}
|
|
13301
|
+
/**
|
|
13302
|
+
* Retrieves the id of a stop at a given index in a route.
|
|
13303
|
+
* @param stopRouteIndex The route index of the stop.
|
|
13304
|
+
* @returns The id of the stop at the given index in the route.
|
|
13305
|
+
*/
|
|
13306
|
+
stopId(stopRouteIndex) {
|
|
13307
|
+
const stopId = this.stops[stopRouteIndex];
|
|
13308
|
+
if (stopId === undefined) {
|
|
13309
|
+
throw new Error(`StopId for stop at index ${stopRouteIndex} not found in route ${this.serviceRouteId}`);
|
|
13310
|
+
}
|
|
13311
|
+
return stopId;
|
|
13312
|
+
}
|
|
13049
13313
|
}
|
|
13050
13314
|
|
|
13051
13315
|
const isLittleEndian = (() => {
|
|
@@ -13116,10 +13380,15 @@ const bytesToUint16Array = (bytes) => {
|
|
|
13116
13380
|
const serializeStopsAdjacency = (stopsAdjacency) => {
|
|
13117
13381
|
return stopsAdjacency.map((value) => {
|
|
13118
13382
|
return {
|
|
13119
|
-
transfers: value.transfers
|
|
13120
|
-
|
|
13121
|
-
|
|
13383
|
+
transfers: value.transfers
|
|
13384
|
+
? value.transfers.map((transfer) => (Object.assign({ destination: transfer.destination, type: serializeTransferType(transfer.type) }, (transfer.minTransferTime !== undefined && {
|
|
13385
|
+
minTransferTime: transfer.minTransferTime.toSeconds(),
|
|
13386
|
+
}))))
|
|
13387
|
+
: [],
|
|
13122
13388
|
routes: value.routes,
|
|
13389
|
+
tripContinuations: value.tripContinuations
|
|
13390
|
+
? serializeTripContinuations(value.tripContinuations)
|
|
13391
|
+
: [],
|
|
13123
13392
|
};
|
|
13124
13393
|
});
|
|
13125
13394
|
};
|
|
@@ -13159,10 +13428,17 @@ const deserializeStopsAdjacency = (protoStopsAdjacency) => {
|
|
|
13159
13428
|
}));
|
|
13160
13429
|
transfers.push(newTransfer);
|
|
13161
13430
|
}
|
|
13162
|
-
|
|
13163
|
-
transfers: transfers,
|
|
13431
|
+
const stopAdjacency = {
|
|
13164
13432
|
routes: value.routes,
|
|
13165
|
-
}
|
|
13433
|
+
};
|
|
13434
|
+
if (transfers.length > 0) {
|
|
13435
|
+
stopAdjacency.transfers = transfers;
|
|
13436
|
+
}
|
|
13437
|
+
const deserializedTripContinuations = deserializeTripContinuations(value.tripContinuations);
|
|
13438
|
+
if (deserializedTripContinuations.size > 0) {
|
|
13439
|
+
stopAdjacency.tripContinuations = deserializedTripContinuations;
|
|
13440
|
+
}
|
|
13441
|
+
result.push(stopAdjacency);
|
|
13166
13442
|
}
|
|
13167
13443
|
return result;
|
|
13168
13444
|
};
|
|
@@ -13172,7 +13448,7 @@ const deserializeRoutesAdjacency = (protoRoutesAdjacency) => {
|
|
|
13172
13448
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
13173
13449
|
const value = protoRoutesAdjacency[i];
|
|
13174
13450
|
const stops = bytesToUint32Array(value.stops);
|
|
13175
|
-
routesAdjacency.push(new Route(bytesToUint16Array(value.stopTimes), value.pickUpDropOffTypes, stops, value.serviceRouteId));
|
|
13451
|
+
routesAdjacency.push(new Route(i, bytesToUint16Array(value.stopTimes), value.pickUpDropOffTypes, stops, value.serviceRouteId));
|
|
13176
13452
|
}
|
|
13177
13453
|
return routesAdjacency;
|
|
13178
13454
|
};
|
|
@@ -13266,6 +13542,46 @@ const serializeRouteType = (type) => {
|
|
|
13266
13542
|
return RouteType.MONORAIL;
|
|
13267
13543
|
}
|
|
13268
13544
|
};
|
|
13545
|
+
const serializeTripContinuations = (tripContinuations) => {
|
|
13546
|
+
const result = [];
|
|
13547
|
+
for (const [key, value] of tripContinuations.entries()) {
|
|
13548
|
+
result.push({
|
|
13549
|
+
key: key,
|
|
13550
|
+
value: value.map((tripBoarding) => ({
|
|
13551
|
+
hopOnStop: tripBoarding.hopOnStop,
|
|
13552
|
+
routeId: tripBoarding.routeId,
|
|
13553
|
+
tripIndex: tripBoarding.tripIndex,
|
|
13554
|
+
})),
|
|
13555
|
+
});
|
|
13556
|
+
}
|
|
13557
|
+
return result;
|
|
13558
|
+
};
|
|
13559
|
+
const deserializeTripContinuations = (protoTripContinuations) => {
|
|
13560
|
+
const result = new Map();
|
|
13561
|
+
for (let i = 0; i < protoTripContinuations.length; i++) {
|
|
13562
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
13563
|
+
const entry = protoTripContinuations[i];
|
|
13564
|
+
const tripBoardings = entry.value.map((protoTripBoarding) => ({
|
|
13565
|
+
hopOnStop: protoTripBoarding.hopOnStop,
|
|
13566
|
+
routeId: protoTripBoarding.routeId,
|
|
13567
|
+
tripIndex: protoTripBoarding.tripIndex,
|
|
13568
|
+
}));
|
|
13569
|
+
result.set(entry.key, tripBoardings);
|
|
13570
|
+
}
|
|
13571
|
+
return result;
|
|
13572
|
+
};
|
|
13573
|
+
|
|
13574
|
+
// const ROUTE_ID_BITS = 17;
|
|
13575
|
+
const TRIP_INDEX_BITS = 15;
|
|
13576
|
+
/**
|
|
13577
|
+
* Encodes a route ID and trip index into a single trip ID.
|
|
13578
|
+
* @param routeId - The route identifier, needs to fit on 17 bits
|
|
13579
|
+
* @param tripIndex - The index of the trip within the route, needs to fit on 15 bits
|
|
13580
|
+
* @returns The encoded trip ID
|
|
13581
|
+
*/
|
|
13582
|
+
const encode = (routeId, tripIndex) => {
|
|
13583
|
+
return (routeId << TRIP_INDEX_BITS) | tripIndex;
|
|
13584
|
+
};
|
|
13269
13585
|
|
|
13270
13586
|
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
13271
13587
|
const ALL_TRANSPORT_MODES = new Set([
|
|
@@ -13280,7 +13596,8 @@ const ALL_TRANSPORT_MODES = new Set([
|
|
|
13280
13596
|
'TROLLEYBUS',
|
|
13281
13597
|
'MONORAIL',
|
|
13282
13598
|
]);
|
|
13283
|
-
const
|
|
13599
|
+
const EMPTY_TRIP_CONTINUATIONS = [];
|
|
13600
|
+
const CURRENT_VERSION = '0.0.8';
|
|
13284
13601
|
/**
|
|
13285
13602
|
* The internal transit timetable format.
|
|
13286
13603
|
*/
|
|
@@ -13291,9 +13608,10 @@ class Timetable {
|
|
|
13291
13608
|
this.serviceRoutes = routes;
|
|
13292
13609
|
this.activeStops = new Set();
|
|
13293
13610
|
for (let i = 0; i < stopsAdjacency.length; i++) {
|
|
13294
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
13295
13611
|
const stop = stopsAdjacency[i];
|
|
13296
|
-
if (stop.routes.length > 0 ||
|
|
13612
|
+
if (stop.routes.length > 0 ||
|
|
13613
|
+
(stop.transfers && stop.transfers.length > 0) ||
|
|
13614
|
+
(stop.tripContinuations && stop.tripContinuations.size > 0)) {
|
|
13297
13615
|
this.activeStops.add(i);
|
|
13298
13616
|
}
|
|
13299
13617
|
}
|
|
@@ -13356,8 +13674,27 @@ class Timetable {
|
|
|
13356
13674
|
* @returns An array of transfer options available at the stop.
|
|
13357
13675
|
*/
|
|
13358
13676
|
getTransfers(stopId) {
|
|
13359
|
-
|
|
13360
|
-
|
|
13677
|
+
const stopAdjacency = this.stopsAdjacency[stopId];
|
|
13678
|
+
if (!stopAdjacency) {
|
|
13679
|
+
throw new Error(`Stop ID ${stopId} not found`);
|
|
13680
|
+
}
|
|
13681
|
+
return stopAdjacency.transfers || [];
|
|
13682
|
+
}
|
|
13683
|
+
/**
|
|
13684
|
+
* Retrieves all trip continuation options available at the specified stop for a given trip.
|
|
13685
|
+
*
|
|
13686
|
+
* @param stopId - The ID of the stop to get trip continuations for.
|
|
13687
|
+
* @param tripIndex - The index of the trip to get continuations for.
|
|
13688
|
+
* @returns An array of trip continuation options available at the stop for the specified trip.
|
|
13689
|
+
*/
|
|
13690
|
+
getContinuousTrips(stopId, routeId, tripIndex) {
|
|
13691
|
+
var _a;
|
|
13692
|
+
const stopAdjacency = this.stopsAdjacency[stopId];
|
|
13693
|
+
if (!stopAdjacency) {
|
|
13694
|
+
throw new Error(`Stop ID ${stopId} not found`);
|
|
13695
|
+
}
|
|
13696
|
+
return (((_a = stopAdjacency.tripContinuations) === null || _a === void 0 ? void 0 : _a.get(encode(routeId, tripIndex))) ||
|
|
13697
|
+
EMPTY_TRIP_CONTINUATIONS);
|
|
13361
13698
|
}
|
|
13362
13699
|
/**
|
|
13363
13700
|
* Retrieves the service route associated with the given route.
|
|
@@ -15643,6 +15980,7 @@ const parseGtfsLocationType = (gtfsLocationType) => {
|
|
|
15643
15980
|
const parseTransfers = (transfersStream, stopsMap) => __awaiter(void 0, void 0, void 0, function* () {
|
|
15644
15981
|
var _a, e_1, _b, _c;
|
|
15645
15982
|
const transfers = new Map();
|
|
15983
|
+
const tripContinuations = new Map();
|
|
15646
15984
|
try {
|
|
15647
15985
|
for (var _d = true, _e = __asyncValues(parseCsv(transfersStream, [
|
|
15648
15986
|
'transfer_type',
|
|
@@ -15656,25 +15994,48 @@ const parseTransfers = (transfersStream, stopsMap) => __awaiter(void 0, void 0,
|
|
|
15656
15994
|
transferEntry.transfer_type === 5) {
|
|
15657
15995
|
continue;
|
|
15658
15996
|
}
|
|
15659
|
-
if (transferEntry.from_trip_id && transferEntry.to_trip_id) {
|
|
15660
|
-
console.warn(`Unsupported transfer between trips ${transferEntry.from_trip_id} and ${transferEntry.to_trip_id}.`);
|
|
15661
|
-
continue;
|
|
15662
|
-
}
|
|
15663
|
-
if (transferEntry.from_route_id && transferEntry.to_route_id) {
|
|
15664
|
-
console.warn(`Unsupported transfer between routes ${transferEntry.from_route_id} and ${transferEntry.to_route_id}.`);
|
|
15665
|
-
continue;
|
|
15666
|
-
}
|
|
15667
15997
|
if (!transferEntry.from_stop_id || !transferEntry.to_stop_id) {
|
|
15668
15998
|
console.warn(`Missing transfer origin or destination stop.`);
|
|
15669
15999
|
continue;
|
|
15670
16000
|
}
|
|
15671
|
-
if (transferEntry.transfer_type === 2 && !transferEntry.min_transfer_time) {
|
|
15672
|
-
console.info(`Missing minimum transfer time between ${transferEntry.from_stop_id} and ${transferEntry.to_stop_id}.`);
|
|
15673
|
-
}
|
|
15674
16001
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
15675
16002
|
const fromStop = stopsMap.get(transferEntry.from_stop_id);
|
|
15676
16003
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
15677
16004
|
const toStop = stopsMap.get(transferEntry.to_stop_id);
|
|
16005
|
+
if (transferEntry.transfer_type === 4) {
|
|
16006
|
+
if (transferEntry.from_trip_id === undefined ||
|
|
16007
|
+
transferEntry.from_trip_id === '' ||
|
|
16008
|
+
transferEntry.to_trip_id === undefined ||
|
|
16009
|
+
transferEntry.to_trip_id === '') {
|
|
16010
|
+
console.warn(`Unsupported in-seat transfer, missing from_trip_id and/or to_trip_id.`);
|
|
16011
|
+
continue;
|
|
16012
|
+
}
|
|
16013
|
+
const tripBoardingEntry = {
|
|
16014
|
+
fromTrip: transferEntry.from_trip_id,
|
|
16015
|
+
toTrip: transferEntry.to_trip_id,
|
|
16016
|
+
hopOnStop: toStop.id,
|
|
16017
|
+
};
|
|
16018
|
+
const existingBoardings = tripContinuations.get(fromStop.id);
|
|
16019
|
+
if (existingBoardings) {
|
|
16020
|
+
existingBoardings.push(tripBoardingEntry);
|
|
16021
|
+
}
|
|
16022
|
+
else {
|
|
16023
|
+
tripContinuations.set(fromStop.id, [tripBoardingEntry]);
|
|
16024
|
+
}
|
|
16025
|
+
continue;
|
|
16026
|
+
}
|
|
16027
|
+
if (transferEntry.from_trip_id && transferEntry.to_trip_id) {
|
|
16028
|
+
console.warn(`Unsupported transfer of type ${transferEntry.transfer_type} between trips ${transferEntry.from_trip_id} and ${transferEntry.to_trip_id}.`);
|
|
16029
|
+
continue;
|
|
16030
|
+
}
|
|
16031
|
+
if (transferEntry.from_route_id && transferEntry.to_route_id) {
|
|
16032
|
+
console.warn(`Unsupported transfer of type ${transferEntry.transfer_type} between routes ${transferEntry.from_route_id} and ${transferEntry.to_route_id}.`);
|
|
16033
|
+
continue;
|
|
16034
|
+
}
|
|
16035
|
+
if (transferEntry.transfer_type === 2 &&
|
|
16036
|
+
transferEntry.min_transfer_time === undefined) {
|
|
16037
|
+
console.info(`Missing minimum transfer time between ${transferEntry.from_stop_id} and ${transferEntry.to_stop_id}.`);
|
|
16038
|
+
}
|
|
15678
16039
|
const transfer = Object.assign({ destination: toStop.id, type: parseGtfsTransferType(transferEntry.transfer_type) }, (transferEntry.min_transfer_time && {
|
|
15679
16040
|
minTransferTime: Duration.fromSeconds(transferEntry.min_transfer_time),
|
|
15680
16041
|
}));
|
|
@@ -15690,7 +16051,10 @@ const parseTransfers = (transfersStream, stopsMap) => __awaiter(void 0, void 0,
|
|
|
15690
16051
|
}
|
|
15691
16052
|
finally { if (e_1) throw e_1.error; }
|
|
15692
16053
|
}
|
|
15693
|
-
return
|
|
16054
|
+
return {
|
|
16055
|
+
transfers,
|
|
16056
|
+
tripContinuations,
|
|
16057
|
+
};
|
|
15694
16058
|
});
|
|
15695
16059
|
const parseGtfsTransferType = (gtfsTransferType) => {
|
|
15696
16060
|
switch (gtfsTransferType) {
|
|
@@ -15753,11 +16117,13 @@ const finalizeRouteFromBuilder = (builder) => {
|
|
|
15753
16117
|
const stopTimesArray = new Uint16Array(stopsCount * tripsCount * 2);
|
|
15754
16118
|
const allPickUpTypes = [];
|
|
15755
16119
|
const allDropOffTypes = [];
|
|
16120
|
+
const gtfsTripIds = [];
|
|
15756
16121
|
for (let tripIndex = 0; tripIndex < tripsCount; tripIndex++) {
|
|
15757
16122
|
const trip = builder.trips[tripIndex];
|
|
15758
16123
|
if (!trip) {
|
|
15759
16124
|
throw new Error(`Missing trip data at index ${tripIndex}`);
|
|
15760
16125
|
}
|
|
16126
|
+
gtfsTripIds.push(trip.gtfsTripId);
|
|
15761
16127
|
const baseIndex = tripIndex * stopsCount * 2;
|
|
15762
16128
|
for (let stopIndex = 0; stopIndex < stopsCount; stopIndex++) {
|
|
15763
16129
|
const timeIndex = baseIndex + stopIndex * 2;
|
|
@@ -15779,12 +16145,15 @@ const finalizeRouteFromBuilder = (builder) => {
|
|
|
15779
16145
|
}
|
|
15780
16146
|
// Use 2-bit encoding for pickup/drop-off types
|
|
15781
16147
|
const pickUpDropOffTypesArray = encodePickUpDropOffTypes(allPickUpTypes, allDropOffTypes);
|
|
15782
|
-
return
|
|
15783
|
-
|
|
15784
|
-
|
|
15785
|
-
|
|
15786
|
-
|
|
15787
|
-
|
|
16148
|
+
return [
|
|
16149
|
+
{
|
|
16150
|
+
serviceRouteId: builder.serviceRouteId,
|
|
16151
|
+
stops: stopsArray,
|
|
16152
|
+
stopTimes: stopTimesArray,
|
|
16153
|
+
pickUpDropOffTypes: pickUpDropOffTypesArray,
|
|
16154
|
+
},
|
|
16155
|
+
gtfsTripIds,
|
|
16156
|
+
];
|
|
15788
16157
|
};
|
|
15789
16158
|
/**
|
|
15790
16159
|
* Parses the trips.txt file from a GTFS feed
|
|
@@ -15823,11 +16192,12 @@ const parseTrips = (tripsStream, serviceIds, validGtfsRoutes) => __awaiter(void
|
|
|
15823
16192
|
}
|
|
15824
16193
|
return trips;
|
|
15825
16194
|
});
|
|
15826
|
-
const buildStopsAdjacencyStructure = (serviceRoutes, routes, transfersMap, nbStops, activeStops) => {
|
|
15827
|
-
// TODO somehow works when it's a map
|
|
16195
|
+
const buildStopsAdjacencyStructure = (tripsMapping, serviceRoutes, routes, transfersMap, tripContinuationsMap, nbStops, activeStops) => {
|
|
15828
16196
|
const stopsAdjacency = new Array(nbStops);
|
|
15829
16197
|
for (let i = 0; i < nbStops; i++) {
|
|
15830
|
-
stopsAdjacency[i] = {
|
|
16198
|
+
stopsAdjacency[i] = {
|
|
16199
|
+
routes: [],
|
|
16200
|
+
};
|
|
15831
16201
|
}
|
|
15832
16202
|
for (let index = 0; index < routes.length; index++) {
|
|
15833
16203
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
@@ -15852,12 +16222,50 @@ const buildStopsAdjacencyStructure = (serviceRoutes, routes, transfersMap, nbSto
|
|
|
15852
16222
|
const transfer = transfers[i];
|
|
15853
16223
|
if (activeStops.has(stop) || activeStops.has(transfer.destination)) {
|
|
15854
16224
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
15855
|
-
stopsAdjacency[stop]
|
|
16225
|
+
const stopAdj = stopsAdjacency[stop];
|
|
16226
|
+
if (!stopAdj.transfers) {
|
|
16227
|
+
stopAdj.transfers = [];
|
|
16228
|
+
}
|
|
16229
|
+
stopAdj.transfers.push(transfer);
|
|
15856
16230
|
activeStops.add(transfer.destination);
|
|
15857
16231
|
activeStops.add(stop);
|
|
15858
16232
|
}
|
|
15859
16233
|
}
|
|
15860
16234
|
}
|
|
16235
|
+
for (const [stop, tripContinuations] of tripContinuationsMap) {
|
|
16236
|
+
for (let i = 0; i < tripContinuations.length; i++) {
|
|
16237
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
16238
|
+
const tripContinuation = tripContinuations[i];
|
|
16239
|
+
if (activeStops.has(stop) ||
|
|
16240
|
+
activeStops.has(tripContinuation.hopOnStop)) {
|
|
16241
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
16242
|
+
const stopAdj = stopsAdjacency[stop];
|
|
16243
|
+
if (!stopAdj.tripContinuations) {
|
|
16244
|
+
stopAdj.tripContinuations = new Map();
|
|
16245
|
+
}
|
|
16246
|
+
const originTrip = tripsMapping.get(tripContinuation.fromTrip);
|
|
16247
|
+
const destinationTrip = tripsMapping.get(tripContinuation.toTrip);
|
|
16248
|
+
if (destinationTrip === undefined || originTrip === undefined) {
|
|
16249
|
+
continue;
|
|
16250
|
+
}
|
|
16251
|
+
const tripBoarding = {
|
|
16252
|
+
hopOnStop: tripContinuation.hopOnStop,
|
|
16253
|
+
routeId: destinationTrip.routeId,
|
|
16254
|
+
tripIndex: destinationTrip.tripRouteIndex,
|
|
16255
|
+
};
|
|
16256
|
+
const tripId = encode(originTrip.routeId, originTrip.tripRouteIndex);
|
|
16257
|
+
const existingContinuations = stopAdj.tripContinuations.get(tripId);
|
|
16258
|
+
if (existingContinuations) {
|
|
16259
|
+
existingContinuations.push(tripBoarding);
|
|
16260
|
+
}
|
|
16261
|
+
else {
|
|
16262
|
+
stopAdj.tripContinuations.set(tripId, [tripBoarding]);
|
|
16263
|
+
}
|
|
16264
|
+
activeStops.add(tripContinuation.hopOnStop);
|
|
16265
|
+
activeStops.add(stop);
|
|
16266
|
+
}
|
|
16267
|
+
}
|
|
16268
|
+
}
|
|
15861
16269
|
return stopsAdjacency;
|
|
15862
16270
|
};
|
|
15863
16271
|
/**
|
|
@@ -15916,6 +16324,7 @@ const parseStopTimes = (stopTimesStream, stopsMap, activeTripIds, activeStopIds)
|
|
|
15916
16324
|
}
|
|
15917
16325
|
routeBuilder.trips.push({
|
|
15918
16326
|
firstDeparture,
|
|
16327
|
+
gtfsTripId: currentTripId,
|
|
15919
16328
|
arrivalTimes: arrivalTimes,
|
|
15920
16329
|
departureTimes: departureTimes,
|
|
15921
16330
|
pickUpTypes: pickUpTypes,
|
|
@@ -15953,6 +16362,9 @@ const parseStopTimes = (stopTimesStream, stopsMap, activeTripIds, activeStopIds)
|
|
|
15953
16362
|
continue;
|
|
15954
16363
|
}
|
|
15955
16364
|
if (line.pickup_type === '1' && line.drop_off_type === '1') {
|
|
16365
|
+
// Warning: could potentially lead to issues if there is an in-seat transfer
|
|
16366
|
+
// at this stop - it can be not boardable nor alightable but still useful for an in-seat transfer.
|
|
16367
|
+
// This doesn't seem to happen in practice for now so keeping this condition to save memory.
|
|
15956
16368
|
continue;
|
|
15957
16369
|
}
|
|
15958
16370
|
if (currentTripId && line.trip_id !== currentTripId && stops.length > 0) {
|
|
@@ -15989,11 +16401,19 @@ const parseStopTimes = (stopTimesStream, stopsMap, activeTripIds, activeStopIds)
|
|
|
15989
16401
|
addTrip(currentTripId);
|
|
15990
16402
|
}
|
|
15991
16403
|
const routesAdjacency = [];
|
|
16404
|
+
const tripsMapping = new Map();
|
|
15992
16405
|
for (const [, routeBuilder] of routeBuilders) {
|
|
15993
|
-
const routeData = finalizeRouteFromBuilder(routeBuilder);
|
|
15994
|
-
|
|
16406
|
+
const [routeData, gtfsTripIds] = finalizeRouteFromBuilder(routeBuilder);
|
|
16407
|
+
const routeId = routesAdjacency.length;
|
|
16408
|
+
routesAdjacency.push(new Route(routeId, routeData.stopTimes, routeData.pickUpDropOffTypes, routeData.stops, routeData.serviceRouteId));
|
|
16409
|
+
gtfsTripIds.forEach((tripId, index) => {
|
|
16410
|
+
tripsMapping.set(tripId, {
|
|
16411
|
+
routeId,
|
|
16412
|
+
tripRouteIndex: index,
|
|
16413
|
+
});
|
|
16414
|
+
});
|
|
15995
16415
|
}
|
|
15996
|
-
return { routes: routesAdjacency, serviceRoutesMap };
|
|
16416
|
+
return { routes: routesAdjacency, serviceRoutesMap, tripsMapping };
|
|
15997
16417
|
});
|
|
15998
16418
|
const parsePickupDropOffType = (gtfsType) => {
|
|
15999
16419
|
switch (gtfsType) {
|
|
@@ -16072,24 +16492,27 @@ class GtfsParser {
|
|
|
16072
16492
|
const tripsEnd = performance.now();
|
|
16073
16493
|
log.info(`${trips.size} valid trips. (${(tripsEnd - tripsStart).toFixed(2)}ms)`);
|
|
16074
16494
|
let transfers = new Map();
|
|
16495
|
+
let tripContinuations = new Map();
|
|
16075
16496
|
if (entries[TRANSFERS_FILE]) {
|
|
16076
16497
|
log.info(`Parsing ${TRANSFERS_FILE}`);
|
|
16077
16498
|
const transfersStart = performance.now();
|
|
16078
16499
|
const transfersStream = yield zip.stream(TRANSFERS_FILE);
|
|
16079
|
-
transfers = yield parseTransfers(transfersStream, parsedStops);
|
|
16500
|
+
const { transfers: parsedTransfers, tripContinuations: parsedTripContinuations, } = yield parseTransfers(transfersStream, parsedStops);
|
|
16501
|
+
transfers = parsedTransfers;
|
|
16502
|
+
tripContinuations = parsedTripContinuations;
|
|
16080
16503
|
const transfersEnd = performance.now();
|
|
16081
|
-
log.info(`${transfers.size} valid transfers. (${(transfersEnd - transfersStart).toFixed(2)}ms)`);
|
|
16504
|
+
log.info(`${transfers.size} valid transfers and ${tripContinuations.size} trip continuations. (${(transfersEnd - transfersStart).toFixed(2)}ms)`);
|
|
16082
16505
|
}
|
|
16083
16506
|
log.info(`Parsing ${STOP_TIMES_FILE}`);
|
|
16084
16507
|
const stopTimesStart = performance.now();
|
|
16085
16508
|
const stopTimesStream = yield zip.stream(STOP_TIMES_FILE);
|
|
16086
|
-
const { routes, serviceRoutesMap } = yield parseStopTimes(stopTimesStream, parsedStops, trips, activeStopIds);
|
|
16509
|
+
const { routes, serviceRoutesMap, tripsMapping } = yield parseStopTimes(stopTimesStream, parsedStops, trips, activeStopIds);
|
|
16087
16510
|
const serviceRoutes = indexRoutes(validGtfsRoutes, serviceRoutesMap);
|
|
16088
16511
|
const stopTimesEnd = performance.now();
|
|
16089
16512
|
log.info(`${routes.length} valid unique routes. (${(stopTimesEnd - stopTimesStart).toFixed(2)}ms)`);
|
|
16090
16513
|
log.info('Building stops adjacency structure');
|
|
16091
16514
|
const stopsAdjacencyStart = performance.now();
|
|
16092
|
-
const stopsAdjacency = buildStopsAdjacencyStructure(serviceRoutes, routes, transfers, parsedStops.size, activeStopIds);
|
|
16515
|
+
const stopsAdjacency = buildStopsAdjacencyStructure(tripsMapping, serviceRoutes, routes, transfers, tripContinuations, parsedStops.size, activeStopIds);
|
|
16093
16516
|
const stopsAdjacencyEnd = performance.now();
|
|
16094
16517
|
log.info(`${stopsAdjacency.length} valid stops in the structure. (${(stopsAdjacencyEnd - stopsAdjacencyStart).toFixed(2)}ms)`);
|
|
16095
16518
|
yield zip.close();
|