@golemio/pid 2.14.2-dev.1360232209 → 2.14.2
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/integration-engine/vehicle-positions/ioc/Di.js +9 -14
- package/dist/integration-engine/vehicle-positions/ioc/Di.js.map +1 -1
- package/dist/integration-engine/vehicle-positions/ioc/VPContainerToken.d.ts +0 -3
- package/dist/integration-engine/vehicle-positions/ioc/VPContainerToken.js +0 -3
- package/dist/integration-engine/vehicle-positions/ioc/VPContainerToken.js.map +1 -1
- package/dist/integration-engine/vehicle-positions/workers/gtfs-rt/tasks/GenerateFilesTask.js +2 -3
- package/dist/integration-engine/vehicle-positions/workers/gtfs-rt/tasks/GenerateFilesTask.js.map +1 -1
- package/dist/integration-engine/vehicle-positions/workers/runs/helpers/regional-bus/RegionalBusMessageFilter.d.ts +4 -1
- package/dist/integration-engine/vehicle-positions/workers/runs/helpers/regional-bus/RegionalBusMessageFilter.js +27 -11
- package/dist/integration-engine/vehicle-positions/workers/runs/helpers/regional-bus/RegionalBusMessageFilter.js.map +1 -1
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/data-access/PositionsRepository.js +3 -11
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/data-access/PositionsRepository.js.map +1 -1
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/PositionsManager.d.ts +13 -16
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/PositionsManager.js +399 -427
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/PositionsManager.js.map +1 -1
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/ValidToCalculator.d.ts +6 -15
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/ValidToCalculator.js +45 -71
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/ValidToCalculator.js.map +1 -1
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/regional-bus/RegionalBusPositionsManager.d.ts +10 -13
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/regional-bus/RegionalBusPositionsManager.js +347 -366
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/regional-bus/RegionalBusPositionsManager.js.map +1 -1
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/interfaces/VPInterfaces.d.ts +2 -2
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/tasks/ProcessRegionalBusPositionsTask.d.ts +0 -1
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/tasks/ProcessRegionalBusPositionsTask.js +5 -8
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/tasks/ProcessRegionalBusPositionsTask.js.map +1 -1
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/tasks/UpdateDelayTask.d.ts +0 -1
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/tasks/UpdateDelayTask.js +6 -5
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/tasks/UpdateDelayTask.js.map +1 -1
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/transformations/MpvMessageTransformation.d.ts +6 -3
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/transformations/MpvMessageTransformation.js +20 -11
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/transformations/MpvMessageTransformation.js.map +1 -1
- package/dist/output-gateway/public/routers/v1/PublicDeparturesRouter.js +1 -1
- package/dist/output-gateway/public/routers/v1/helpers/CustomStopIdGroupValidator.d.ts +0 -1
- package/dist/output-gateway/public/routers/v1/helpers/CustomStopIdGroupValidator.js +16 -38
- package/dist/output-gateway/public/routers/v1/helpers/CustomStopIdGroupValidator.js.map +1 -1
- package/docs/openapi-output.yaml +2 -4
- package/package.json +3 -3
- package/db/migrations/postgresql/20240612135256-fix-delay-in-view-future-stop-times.js +0 -53
- package/db/migrations/postgresql/20240701093122-fix-delay-in-view-v-public-vehiclepositions-past-stop-times.js +0 -53
- package/db/migrations/postgresql/sqls/20240612135256-fix-delay-in-view-future-stop-times-down.sql +0 -82
- package/db/migrations/postgresql/sqls/20240612135256-fix-delay-in-view-future-stop-times-up.sql +0 -93
- package/db/migrations/postgresql/sqls/20240701093122-fix-delay-in-view-v-public-vehiclepositions-past-stop-times-down.sql +0 -31
- package/db/migrations/postgresql/sqls/20240701093122-fix-delay-in-view-v-public-vehiclepositions-past-stop-times-up.sql +0 -38
|
@@ -15,12 +15,6 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
15
15
|
}) : function(o, v) {
|
|
16
16
|
o["default"] = v;
|
|
17
17
|
});
|
|
18
|
-
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
19
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
20
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
21
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
22
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
23
|
-
};
|
|
24
18
|
var __importStar = (this && this.__importStar) || function (mod) {
|
|
25
19
|
if (mod && mod.__esModule) return mod;
|
|
26
20
|
var result = {};
|
|
@@ -28,12 +22,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
28
22
|
__setModuleDefault(result, mod);
|
|
29
23
|
return result;
|
|
30
24
|
};
|
|
31
|
-
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
32
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
33
|
-
};
|
|
34
|
-
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
35
|
-
return function (target, key) { decorator(target, key, paramIndex); }
|
|
36
|
-
};
|
|
37
25
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
38
26
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
39
27
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -46,422 +34,21 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
46
34
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
47
35
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
48
36
|
};
|
|
37
|
+
var _a;
|
|
49
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
-
exports.PositionsManager = void 0;
|
|
51
|
-
const VPContainerToken_1 = require("../../../ioc/VPContainerToken");
|
|
52
|
-
const moment_timezone_1 = __importDefault(require("@golemio/core/dist/shared/moment-timezone"));
|
|
53
|
-
const tsyringe_1 = require("@golemio/core/dist/shared/tsyringe");
|
|
54
39
|
const turf = __importStar(require("@turf/turf"));
|
|
40
|
+
const moment_timezone_1 = __importDefault(require("@golemio/core/dist/shared/moment-timezone"));
|
|
55
41
|
const const_1 = require("../../../../../const");
|
|
56
42
|
const RouteTypeEnums_1 = require("../../../../../helpers/RouteTypeEnums");
|
|
57
43
|
const DPPUtils_1 = __importDefault(require("./DPPUtils"));
|
|
58
44
|
const DateTimeUtils_1 = require("./DateTimeUtils");
|
|
59
45
|
const PositionHandlerEnum_1 = require("./PositionHandlerEnum");
|
|
60
|
-
const ValidToCalculator_1 = require("./ValidToCalculator");
|
|
46
|
+
const ValidToCalculator_1 = __importDefault(require("./ValidToCalculator"));
|
|
61
47
|
const AnchorPointSegmenter_1 = require("./anchor-points/AnchorPointSegmenter");
|
|
62
48
|
const ComputeDelayHelper_1 = __importDefault(require("./compute-positions/ComputeDelayHelper"));
|
|
63
49
|
const ONE_DAY_IN_SECONDS = 24 * 60 * 60;
|
|
64
50
|
const ONE_SECOND_IN_MILLIS = 1000;
|
|
65
|
-
|
|
66
|
-
constructor(validToCalculator) {
|
|
67
|
-
this.validToCalculator = validToCalculator;
|
|
68
|
-
/**
|
|
69
|
-
* Compute positions and return computed positions
|
|
70
|
-
*
|
|
71
|
-
* @param {ITripPositionsWithGTFS} tripPositions - Trip positions with shape anchors data
|
|
72
|
-
* @returns {Promise<IProcessedPositions>} - Returns computed/updated positions
|
|
73
|
-
*/
|
|
74
|
-
this.computePositions = (tripPositions, schedule) => __awaiter(this, void 0, void 0, function* () {
|
|
75
|
-
const startTimestamp = tripPositions.start_timestamp.getTime();
|
|
76
|
-
const startDayTimestamp = this.getStartDayTimestamp(startTimestamp, tripPositions.gtfsData.shapes_anchor_points[0].time_scheduled_seconds);
|
|
77
|
-
const gtfsRouteType = tripPositions.gtfs_route_type;
|
|
78
|
-
const context = this.getCurrentContext(tripPositions);
|
|
79
|
-
const computedPositions = [];
|
|
80
|
-
const endTimestamp = tripPositions.end_timestamp;
|
|
81
|
-
return this.updatePositions({ tripPositions, startTimestamp, endTimestamp, startDayTimestamp, context, computedPositions, gtfsRouteType }, schedule);
|
|
82
|
-
});
|
|
83
|
-
/**
|
|
84
|
-
* Takes position one by one, set proper handler for type of position, and do the process of position
|
|
85
|
-
*
|
|
86
|
-
* @param {number} i - Iteration
|
|
87
|
-
* @param {IUpdatePositionsIteratorOptions} options - Initial options
|
|
88
|
-
* @param {number} cb - Callback function of iterator
|
|
89
|
-
* @returns {void} - void
|
|
90
|
-
*/
|
|
91
|
-
this.updatePositions = (options, schedule) => __awaiter(this, void 0, void 0, function* () {
|
|
92
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
93
|
-
const { tripPositions, startDayTimestamp, startTimestamp, endTimestamp, context, computedPositions, gtfsRouteType } = options;
|
|
94
|
-
for (let i = 0; i < tripPositions.positions.length; i++) {
|
|
95
|
-
const position = tripPositions.positions[i];
|
|
96
|
-
let positionToUpdate = null;
|
|
97
|
-
// situations
|
|
98
|
-
switch (this.setPositionUpdateHandler(position)) {
|
|
99
|
-
case PositionHandlerEnum_1.PositionHandlerEnum.TRACKING:
|
|
100
|
-
const currentPosition = turf.point([position.lng, position.lat], {
|
|
101
|
-
id: position.id,
|
|
102
|
-
origin_time: position.origin_time,
|
|
103
|
-
origin_timestamp: position.origin_timestamp,
|
|
104
|
-
scheduled_timestamp: position.scheduled_timestamp,
|
|
105
|
-
this_stop_id: position.this_stop_id,
|
|
106
|
-
tcp_event: position.tcp_event,
|
|
107
|
-
});
|
|
108
|
-
positionToUpdate = this.getEstimatedPoint(tripPositions.gtfsData, currentPosition, context, startDayTimestamp, tripPositions.gtfs_route_type);
|
|
109
|
-
if (positionToUpdate.state_position !== const_1.StatePositionEnum.MISMATCHED) {
|
|
110
|
-
positionToUpdate = ComputeDelayHelper_1.default.updatePositionToUpdate(context, positionToUpdate, position, gtfsRouteType);
|
|
111
|
-
}
|
|
112
|
-
positionToUpdate.bearing = (_a = position.bearing) !== null && _a !== void 0 ? _a : positionToUpdate.bearing;
|
|
113
|
-
break;
|
|
114
|
-
case PositionHandlerEnum_1.PositionHandlerEnum.NOT_TRACKING:
|
|
115
|
-
// if there is no previous positions with tracking status, set position as before_track
|
|
116
|
-
const firstShapesAnchorPoint = tripPositions.gtfsData.shapes_anchor_points[0];
|
|
117
|
-
if (context.lastPositionTracking === null &&
|
|
118
|
-
(endTimestamp === null ||
|
|
119
|
-
position.scheduled_timestamp === null ||
|
|
120
|
-
endTimestamp > position.scheduled_timestamp)) {
|
|
121
|
-
const firstStopTime = tripPositions.gtfsData.stop_times[0];
|
|
122
|
-
// if there is propagated delay we can use it for new position
|
|
123
|
-
const lastPositionDelayed = context.lastPositionBeforeTrackDelayed;
|
|
124
|
-
// if there is no delay to duplicate and DPP trip is far from start then invisible
|
|
125
|
-
const setAsInvisible = !lastPositionDelayed &&
|
|
126
|
-
DPPUtils_1.default.isInvisible(tripPositions.agency_name_scheduled, position.origin_timestamp, startTimestamp, [position.lng, position.lat], firstShapesAnchorPoint.coordinates, schedule, tripPositions.gtfs_trip_id, context.lastPositionTracking, position.is_tracked);
|
|
127
|
-
positionToUpdate = Object.assign({ id: position.id, next_stop_arrival_time: new Date(startDayTimestamp + firstStopTime.arrival_time_seconds * 1000), next_stop_departure_time: new Date(startDayTimestamp + firstStopTime.departure_time_seconds * 1000), next_stop_id: firstStopTime.stop_id, next_stop_sequence: firstStopTime.stop_sequence, next_stop_name: firstStopTime.stop.stop_name, shape_dist_traveled: firstStopTime.shape_dist_traveled, state_position: setAsInvisible ? const_1.StatePositionEnum.INVISIBLE : const_1.StatePositionEnum.BEFORE_TRACK, state_process: const_1.StateProcessEnum.PROCESSED }, (firstStopTime.stop_headsign && {
|
|
128
|
-
last_stop_headsign: firstStopTime.stop_headsign,
|
|
129
|
-
}));
|
|
130
|
-
if (positionToUpdate.state_position === const_1.StatePositionEnum.BEFORE_TRACK) {
|
|
131
|
-
positionToUpdate.delay = this.getDelayBeforeTrack((_b = lastPositionDelayed === null || lastPositionDelayed === void 0 ? void 0 : lastPositionDelayed.delay) !== null && _b !== void 0 ? _b : position.delay, firstStopTime.departure_time_seconds, position.origin_timestamp.getTime(), startDayTimestamp);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
// if there is tracking 2 position with same origin_timestamp then this position is duplicate
|
|
136
|
-
const statePosition = position.origin_timestamp.getTime() === context.lastPositionOriginTimestamp ||
|
|
137
|
-
tripPositions.positions.findIndex((positionItem) => positionItem.origin_timestamp.getTime() === position.origin_timestamp.getTime() &&
|
|
138
|
-
positionItem.is_tracked) >= 0
|
|
139
|
-
? const_1.StatePositionEnum.DUPLICATE
|
|
140
|
-
: const_1.StatePositionEnum.AFTER_TRACK;
|
|
141
|
-
const lastShapesAnchorPoint = tripPositions.gtfsData.shapes_anchor_points[tripPositions.gtfsData.shapes_anchor_points.length - 1];
|
|
142
|
-
const lastStopTime = tripPositions.gtfsData.stop_times[tripPositions.gtfsData.stop_times.length - 1];
|
|
143
|
-
// set as invisible if there are some AFTER_TRACK before
|
|
144
|
-
const setAsInvisible = DPPUtils_1.default.isInvisible(tripPositions.agency_name_scheduled, position.origin_timestamp, startTimestamp, [position.lng, position.lat], firstShapesAnchorPoint.coordinates, schedule, tripPositions.gtfs_trip_id, context.lastPositionTracking, position.is_tracked) && statePosition === const_1.StatePositionEnum.AFTER_TRACK;
|
|
145
|
-
positionToUpdate = Object.assign({ id: position.id, last_stop_arrival_time: new Date(startDayTimestamp + lastShapesAnchorPoint.time_scheduled_seconds * 1000), last_stop_departure_time: new Date(startDayTimestamp + lastShapesAnchorPoint.time_scheduled_seconds * 1000), last_stop_id: lastStopTime.stop_id, last_stop_sequence: lastShapesAnchorPoint.last_stop_sequence, shape_dist_traveled: lastShapesAnchorPoint.shape_dist_traveled, state_position: setAsInvisible ? const_1.StatePositionEnum.INVISIBLE : statePosition, state_process: const_1.StateProcessEnum.PROCESSED, delay: (_c = position.delay) !== null && _c !== void 0 ? _c : null }, (lastStopTime.stop_headsign && {
|
|
146
|
-
last_stop_headsign: lastStopTime.stop_headsign,
|
|
147
|
-
}));
|
|
148
|
-
positionToUpdate = ComputeDelayHelper_1.default.updatePositionToUpdate(context, positionToUpdate, position, gtfsRouteType);
|
|
149
|
-
}
|
|
150
|
-
break;
|
|
151
|
-
case PositionHandlerEnum_1.PositionHandlerEnum.CANCELED:
|
|
152
|
-
positionToUpdate = {
|
|
153
|
-
id: position.id,
|
|
154
|
-
lat: (_f = (_d = position.lat) !== null && _d !== void 0 ? _d : (_e = context.lastPositionTracking) === null || _e === void 0 ? void 0 : _e.geometry.coordinates[1]) !== null && _f !== void 0 ? _f : null,
|
|
155
|
-
lng: (_j = (_g = position.lng) !== null && _g !== void 0 ? _g : (_h = context.lastPositionTracking) === null || _h === void 0 ? void 0 : _h.geometry.coordinates[0]) !== null && _j !== void 0 ? _j : null,
|
|
156
|
-
state_position: const_1.StatePositionEnum.CANCELED,
|
|
157
|
-
state_process: const_1.StateProcessEnum.PROCESSED,
|
|
158
|
-
};
|
|
159
|
-
if (positionToUpdate.lat === null || positionToUpdate.lng === null) {
|
|
160
|
-
positionToUpdate = null;
|
|
161
|
-
}
|
|
162
|
-
break;
|
|
163
|
-
case PositionHandlerEnum_1.PositionHandlerEnum.DO_NOTHING:
|
|
164
|
-
break;
|
|
165
|
-
default:
|
|
166
|
-
break;
|
|
167
|
-
}
|
|
168
|
-
// if not null push to update
|
|
169
|
-
if (positionToUpdate) {
|
|
170
|
-
(_k = positionToUpdate.is_tracked) !== null && _k !== void 0 ? _k : (positionToUpdate.is_tracked = position.is_tracked);
|
|
171
|
-
positionToUpdate.valid_to = this.validToCalculator.getValidToAttribute(positionToUpdate, position, gtfsRouteType, tripPositions.gtfsData, startTimestamp);
|
|
172
|
-
computedPositions.push(positionToUpdate);
|
|
173
|
-
}
|
|
174
|
-
else {
|
|
175
|
-
computedPositions.push(null);
|
|
176
|
-
}
|
|
177
|
-
context.lastPositionState = (_l = positionToUpdate === null || positionToUpdate === void 0 ? void 0 : positionToUpdate.state_position) !== null && _l !== void 0 ? _l : position.state_position;
|
|
178
|
-
// set last known BEFORE_TRACK_DELAYED position
|
|
179
|
-
if (position.state_position === const_1.StatePositionEnum.BEFORE_TRACK_DELAYED) {
|
|
180
|
-
context.lastPositionBeforeTrackDelayed = {
|
|
181
|
-
delay: (_m = positionToUpdate === null || positionToUpdate === void 0 ? void 0 : positionToUpdate.delay) !== null && _m !== void 0 ? _m : position.delay,
|
|
182
|
-
origin_timestamp: (_o = positionToUpdate === null || positionToUpdate === void 0 ? void 0 : positionToUpdate.origin_timestamp) !== null && _o !== void 0 ? _o : position.origin_timestamp,
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
// set last position tracking (only for at_stop and on_track)
|
|
186
|
-
if ((positionToUpdate === null || positionToUpdate === void 0 ? void 0 : positionToUpdate.state_position) === const_1.StatePositionEnum.AT_STOP ||
|
|
187
|
-
(positionToUpdate === null || positionToUpdate === void 0 ? void 0 : positionToUpdate.state_position) === const_1.StatePositionEnum.ON_TRACK ||
|
|
188
|
-
position.state_position === const_1.StatePositionEnum.AT_STOP ||
|
|
189
|
-
position.state_position === const_1.StatePositionEnum.ON_TRACK) {
|
|
190
|
-
context.lastPositionTracking = turf.point([position.lng, position.lat], Object.assign(Object.assign({}, position), positionToUpdate));
|
|
191
|
-
}
|
|
192
|
-
// set new first position at stop streak if this stop seqence is set and it is not same as before
|
|
193
|
-
if (positionToUpdate
|
|
194
|
-
? positionToUpdate.this_stop_sequence &&
|
|
195
|
-
context.atStopStreak.stop_sequence !== positionToUpdate.this_stop_sequence
|
|
196
|
-
: position.this_stop_sequence && context.atStopStreak.stop_sequence !== position.this_stop_sequence) {
|
|
197
|
-
context.atStopStreak.stop_sequence = positionToUpdate
|
|
198
|
-
? positionToUpdate.this_stop_sequence
|
|
199
|
-
: position.this_stop_sequence;
|
|
200
|
-
context.atStopStreak.firstPositionTimestamp = position.origin_timestamp.getTime();
|
|
201
|
-
context.atStopStreak.firstPositionDelay = positionToUpdate ? positionToUpdate.delay : position.delay;
|
|
202
|
-
}
|
|
203
|
-
// IF currently valid updated position / position was processed before
|
|
204
|
-
// and it is NOT AT_STOP
|
|
205
|
-
// then disrupt atStopStreak
|
|
206
|
-
if (positionToUpdate &&
|
|
207
|
-
positionToUpdate.state_position !== const_1.StatePositionEnum.MISMATCHED &&
|
|
208
|
-
!positionToUpdate.this_stop_sequence) {
|
|
209
|
-
context.atStopStreak.stop_sequence = null;
|
|
210
|
-
}
|
|
211
|
-
else if (!positionToUpdate && !position.this_stop_sequence) {
|
|
212
|
-
context.atStopStreak.stop_sequence = null;
|
|
213
|
-
}
|
|
214
|
-
// duplicated or mismatched position should not be considered at all
|
|
215
|
-
if ((positionToUpdate === null || positionToUpdate === void 0 ? void 0 : positionToUpdate.state_position) !== const_1.StatePositionEnum.DUPLICATE &&
|
|
216
|
-
(positionToUpdate === null || positionToUpdate === void 0 ? void 0 : positionToUpdate.state_position) !== const_1.StatePositionEnum.INVISIBLE &&
|
|
217
|
-
(positionToUpdate === null || positionToUpdate === void 0 ? void 0 : positionToUpdate.state_position) !== const_1.StatePositionEnum.MISMATCHED) {
|
|
218
|
-
context.lastPositionId = position.id;
|
|
219
|
-
context.lastPositionCanceled = position.is_canceled;
|
|
220
|
-
context.lastPositionOriginTimestamp = position.origin_timestamp.getTime();
|
|
221
|
-
ComputeDelayHelper_1.default.updateContext(context, positionToUpdate, position, gtfsRouteType);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
return {
|
|
225
|
-
context,
|
|
226
|
-
positions: computedPositions,
|
|
227
|
-
};
|
|
228
|
-
});
|
|
229
|
-
this.getCurrentContext = (tripPositions) => {
|
|
230
|
-
var _a;
|
|
231
|
-
const context = (_a = tripPositions.last_position_context) !== null && _a !== void 0 ? _a : {
|
|
232
|
-
atStopStreak: {
|
|
233
|
-
stop_sequence: null,
|
|
234
|
-
firstPositionTimestamp: null,
|
|
235
|
-
firstPositionDelay: null,
|
|
236
|
-
},
|
|
237
|
-
lastPositionLastStop: {
|
|
238
|
-
id: null,
|
|
239
|
-
sequence: null,
|
|
240
|
-
arrival_time: null,
|
|
241
|
-
arrival_delay: null,
|
|
242
|
-
departure_time: null,
|
|
243
|
-
departure_delay: null,
|
|
244
|
-
},
|
|
245
|
-
lastPositionDelay: null,
|
|
246
|
-
lastPositionId: null,
|
|
247
|
-
lastPositionOriginTimestamp: null,
|
|
248
|
-
lastPositionTracking: null,
|
|
249
|
-
lastPositionCanceled: null,
|
|
250
|
-
lastPositionBeforeTrackDelayed: null,
|
|
251
|
-
lastPositionState: null,
|
|
252
|
-
tripId: tripPositions.id,
|
|
253
|
-
};
|
|
254
|
-
return context;
|
|
255
|
-
};
|
|
256
|
-
/**
|
|
257
|
-
* Decide how to process input position data
|
|
258
|
-
*
|
|
259
|
-
* @param {IVPTripsPositionAttributes} position - Input vehiclepositions_positions row data
|
|
260
|
-
* @returns {PositionHandlerEnum} - Returns action handler enum
|
|
261
|
-
*/
|
|
262
|
-
this.setPositionUpdateHandler = (position) => {
|
|
263
|
-
if (position.state_process === const_1.StateProcessEnum.PROCESSED)
|
|
264
|
-
return PositionHandlerEnum_1.PositionHandlerEnum.DO_NOTHING;
|
|
265
|
-
else if (position.is_canceled)
|
|
266
|
-
return PositionHandlerEnum_1.PositionHandlerEnum.CANCELED;
|
|
267
|
-
else if (position.is_tracked)
|
|
268
|
-
return PositionHandlerEnum_1.PositionHandlerEnum.TRACKING;
|
|
269
|
-
else
|
|
270
|
-
return PositionHandlerEnum_1.PositionHandlerEnum.NOT_TRACKING;
|
|
271
|
-
};
|
|
272
|
-
/**
|
|
273
|
-
* Returns estimate of point on shape, where the trip should be with appropriate delay
|
|
274
|
-
*
|
|
275
|
-
* @param {IShapeAnchorPoint[]} tripShapePoints - Precalculated trip shape equidistant points with scheduled times
|
|
276
|
-
* @param {Feature<Point, ICurrentPositionProperties>} currentPosition - Current position of trip
|
|
277
|
-
* @param {IVPTripsLastPositionContext | null} context - Context state, holds information about previous positions
|
|
278
|
-
* @param {number} startDayTimestamp - Unix timestamp of midnight before trip starts
|
|
279
|
-
* @returns {IPositionToUpdate} - Position object to update
|
|
280
|
-
*/
|
|
281
|
-
this.getEstimatedPoint = (tripGtfsData, currentPosition, context, startDayTimestamp, gtfsRouteType) => {
|
|
282
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
283
|
-
const anchorPointSegmenter = new AnchorPointSegmenter_1.AnchorPointSegmenter(tripGtfsData.shapes_anchor_points, currentPosition);
|
|
284
|
-
const defaultStatePosition = const_1.StatePositionEnum.OFF_TRACK;
|
|
285
|
-
// Initial value
|
|
286
|
-
let estimatedPoint = Object.assign({ id: currentPosition.properties.id, state_position: defaultStatePosition, state_process: const_1.StateProcessEnum.PROCESSED, tcp_event: currentPosition.properties.tcp_event, valid_to: this.validToCalculator.getDefaultValidToAttribute(currentPosition.properties.origin_timestamp) }, (context &&
|
|
287
|
-
((_a = context.lastPositionTracking) === null || _a === void 0 ? void 0 : _a.properties.last_stop_sequence) && {
|
|
288
|
-
shape_dist_traveled: (_b = context.lastPositionTracking) === null || _b === void 0 ? void 0 : _b.properties.shape_dist_traveled,
|
|
289
|
-
last_stop_arrival_time: ((_c = context.lastPositionTracking) === null || _c === void 0 ? void 0 : _c.properties.last_stop_arrival_time)
|
|
290
|
-
? new Date((_d = context.lastPositionTracking) === null || _d === void 0 ? void 0 : _d.properties.last_stop_arrival_time)
|
|
291
|
-
: undefined,
|
|
292
|
-
last_stop_departure_time: ((_e = context.lastPositionTracking) === null || _e === void 0 ? void 0 : _e.properties.last_stop_departure_time)
|
|
293
|
-
? new Date((_f = context.lastPositionTracking) === null || _f === void 0 ? void 0 : _f.properties.last_stop_departure_time)
|
|
294
|
-
: undefined,
|
|
295
|
-
last_stop_sequence: (_g = context.lastPositionTracking) === null || _g === void 0 ? void 0 : _g.properties.last_stop_sequence,
|
|
296
|
-
last_stop_id: (_h = context.lastPositionTracking) === null || _h === void 0 ? void 0 : _h.properties.last_stop_id,
|
|
297
|
-
}));
|
|
298
|
-
let lastStopSequence = null;
|
|
299
|
-
if ((context === null || context === void 0 ? void 0 : context.lastPositionState) === const_1.StatePositionEnum.BEFORE_TRACK) {
|
|
300
|
-
lastStopSequence = 1;
|
|
301
|
-
}
|
|
302
|
-
else if (context === null || context === void 0 ? void 0 : context.lastPositionTracking) {
|
|
303
|
-
lastStopSequence = context.lastPositionTracking.properties.last_stop_sequence;
|
|
304
|
-
}
|
|
305
|
-
const closesPoint = anchorPointSegmenter.getClosesPoint(lastStopSequence);
|
|
306
|
-
if (!closesPoint) {
|
|
307
|
-
return estimatedPoint;
|
|
308
|
-
}
|
|
309
|
-
return this.getClosestPoint(currentPosition, context, startDayTimestamp, closesPoint, tripGtfsData, gtfsRouteType);
|
|
310
|
-
};
|
|
311
|
-
/**
|
|
312
|
-
* Picks only one closest point for multiple possible points based on delay of last position and stop times
|
|
313
|
-
*
|
|
314
|
-
* @param {Feature<Point, ICurrentPositionProperties>} currentPosition - Feature Point of current position
|
|
315
|
-
* @param {IVPTripsLastPositionContext | null} context - Context state, holds information about previous positions
|
|
316
|
-
* @param {number} startDayTimestamp - Unix timestamp of start of the day
|
|
317
|
-
* @param {IShapeAnchorPoint[]} closestPts - All closest points of possible segments
|
|
318
|
-
* @param {IComputationTrip} tripGtfsData - GTFS data and all set of known positions
|
|
319
|
-
* @returns {IPositionToUpdate} - Result point as position to update in DB
|
|
320
|
-
*/
|
|
321
|
-
this.getClosestPoint = (currentPosition, context, startDayTimestamp, thisClosestPoint, tripGtfsData, gtfsRouteType) => {
|
|
322
|
-
// want to find minimum difference of our prediction, where the bus should be
|
|
323
|
-
const tripShapePoints = tripGtfsData.shapes_anchor_points;
|
|
324
|
-
const tripStopTimes = tripGtfsData.stop_times;
|
|
325
|
-
const firstTripShapePoint = tripShapePoints[0];
|
|
326
|
-
const lastTripShapePoint = tripShapePoints[tripShapePoints.length - 1];
|
|
327
|
-
const timeScheduledTimestamp = DateTimeUtils_1.DateTimeUtils.getStopDateTimeForDayStart(
|
|
328
|
-
// take stop arrival time if is point at stop
|
|
329
|
-
thisClosestPoint.this_stop_sequence
|
|
330
|
-
? tripStopTimes[thisClosestPoint.this_stop_sequence - 1].arrival_time_seconds
|
|
331
|
-
: thisClosestPoint.time_scheduled_seconds, startDayTimestamp);
|
|
332
|
-
let timeDelayInSeconds = Math.round((currentPosition.properties.origin_timestamp.getTime() - timeScheduledTimestamp.getTime()) / 1000);
|
|
333
|
-
const isBusOrTram = gtfsRouteType === RouteTypeEnums_1.GTFSRouteTypeEnum.BUS ||
|
|
334
|
-
gtfsRouteType === RouteTypeEnums_1.GTFSRouteTypeEnum.TROLLEYBUS ||
|
|
335
|
-
gtfsRouteType === RouteTypeEnums_1.GTFSRouteTypeEnum.TRAM;
|
|
336
|
-
// push trip into nearest at_stop shape anchor point if trip "P" event (TCP tram or bus)
|
|
337
|
-
if (isBusOrTram &&
|
|
338
|
-
currentPosition.properties.tcp_event === const_1.TCPEventEnum.ARRIVAL_ANNOUNCED &&
|
|
339
|
-
thisClosestPoint.this_stop_sequence === null) {
|
|
340
|
-
if (thisClosestPoint.last_stop_sequence === 1 && !(context === null || context === void 0 ? void 0 : context.lastPositionTracking)) {
|
|
341
|
-
thisClosestPoint = firstTripShapePoint;
|
|
342
|
-
}
|
|
343
|
-
else {
|
|
344
|
-
let movingShapePointIndex = thisClosestPoint.index;
|
|
345
|
-
while (thisClosestPoint.this_stop_sequence === null && movingShapePointIndex < lastTripShapePoint.index) {
|
|
346
|
-
movingShapePointIndex++;
|
|
347
|
-
thisClosestPoint = tripShapePoints[movingShapePointIndex];
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
// lets correct delay if it is at stop
|
|
352
|
-
if (thisClosestPoint.this_stop_sequence) {
|
|
353
|
-
const thisStopSequence = thisClosestPoint.this_stop_sequence;
|
|
354
|
-
timeDelayInSeconds = this.getCorrectedTimeDelay(timeDelayInSeconds, context, currentPosition, thisStopSequence, {
|
|
355
|
-
departureTime: tripStopTimes[thisStopSequence - 1].departure_time_seconds,
|
|
356
|
-
arrivalTime: tripStopTimes[thisStopSequence - 1].arrival_time_seconds,
|
|
357
|
-
});
|
|
358
|
-
// delay can not be negative if the vehicle is at the first stop
|
|
359
|
-
if (thisStopSequence === firstTripShapePoint.this_stop_sequence) {
|
|
360
|
-
timeDelayInSeconds = Math.max(timeDelayInSeconds, 0);
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
let { statePosition, thisStopSequence, lastStopSequence, nextStopSequence } = this.getStateAndStopSequences(gtfsRouteType, tripStopTimes, thisClosestPoint, currentPosition.properties, context);
|
|
364
|
-
// test if TCP trip with DEPARTURED event should not be at stop (not applied for last stop)
|
|
365
|
-
if (currentPosition.properties.tcp_event === const_1.TCPEventEnum.DEPARTURED &&
|
|
366
|
-
thisStopSequence !== lastTripShapePoint.this_stop_sequence) {
|
|
367
|
-
statePosition = const_1.StatePositionEnum.ON_TRACK;
|
|
368
|
-
}
|
|
369
|
-
if (isBusOrTram && this.isAfterTrack(lastStopSequence, lastTripShapePoint)) {
|
|
370
|
-
statePosition = const_1.StatePositionEnum.AFTER_TRACK;
|
|
371
|
-
thisStopSequence = lastTripShapePoint.this_stop_sequence;
|
|
372
|
-
lastStopSequence = lastTripShapePoint.last_stop_sequence;
|
|
373
|
-
nextStopSequence = lastTripShapePoint.next_stop_sequence;
|
|
374
|
-
timeDelayInSeconds = 0;
|
|
375
|
-
}
|
|
376
|
-
// save it for result
|
|
377
|
-
const estimatedPoint = {
|
|
378
|
-
id: currentPosition.properties.id,
|
|
379
|
-
bearing: thisClosestPoint.bearing,
|
|
380
|
-
shape_dist_traveled: thisClosestPoint.shape_dist_traveled,
|
|
381
|
-
next_stop_id: tripStopTimes[nextStopSequence - 1].stop_id,
|
|
382
|
-
last_stop_id: tripStopTimes[lastStopSequence - 1].stop_id,
|
|
383
|
-
next_stop_name: tripStopTimes[nextStopSequence - 1].stop.stop_name,
|
|
384
|
-
last_stop_name: tripStopTimes[lastStopSequence - 1].stop.stop_name,
|
|
385
|
-
next_stop_sequence: nextStopSequence,
|
|
386
|
-
last_stop_sequence: lastStopSequence,
|
|
387
|
-
next_stop_arrival_time: DateTimeUtils_1.DateTimeUtils.getStopDateTimeForDayStart(tripStopTimes[nextStopSequence - 1].arrival_time_seconds, startDayTimestamp),
|
|
388
|
-
last_stop_arrival_time: DateTimeUtils_1.DateTimeUtils.getStopDateTimeForDayStart(tripStopTimes[lastStopSequence - 1].arrival_time_seconds, startDayTimestamp),
|
|
389
|
-
next_stop_departure_time: DateTimeUtils_1.DateTimeUtils.getStopDateTimeForDayStart(tripStopTimes[nextStopSequence - 1].departure_time_seconds, startDayTimestamp),
|
|
390
|
-
last_stop_departure_time: DateTimeUtils_1.DateTimeUtils.getStopDateTimeForDayStart(tripStopTimes[lastStopSequence - 1].departure_time_seconds, startDayTimestamp),
|
|
391
|
-
delay: timeDelayInSeconds,
|
|
392
|
-
this_stop_id: (statePosition === const_1.StatePositionEnum.AT_STOP &&
|
|
393
|
-
thisStopSequence &&
|
|
394
|
-
tripStopTimes[thisStopSequence - 1].stop_id) ||
|
|
395
|
-
undefined,
|
|
396
|
-
this_stop_name: (statePosition === const_1.StatePositionEnum.AT_STOP &&
|
|
397
|
-
thisStopSequence &&
|
|
398
|
-
tripStopTimes[thisStopSequence - 1].stop.stop_name) ||
|
|
399
|
-
undefined,
|
|
400
|
-
this_stop_sequence: (statePosition === const_1.StatePositionEnum.AT_STOP && thisStopSequence) || undefined,
|
|
401
|
-
last_stop_headsign: tripStopTimes[lastStopSequence - 1].stop_headsign || undefined,
|
|
402
|
-
state_position: statePosition,
|
|
403
|
-
state_process: const_1.StateProcessEnum.PROCESSED,
|
|
404
|
-
valid_to: this.validToCalculator.getDefaultValidToAttribute(currentPosition.properties.origin_timestamp),
|
|
405
|
-
is_tracked: statePosition !== const_1.StatePositionEnum.AFTER_TRACK && statePosition !== const_1.StatePositionEnum.MISMATCHED,
|
|
406
|
-
};
|
|
407
|
-
return estimatedPoint;
|
|
408
|
-
};
|
|
409
|
-
/**
|
|
410
|
-
* Corrects time delay at stop with dwelling time
|
|
411
|
-
*
|
|
412
|
-
* @param {number} timeDelay - Initial computed delay in seconds, can be negative for trip ahead
|
|
413
|
-
* @param {IVPTripsLastPositionContext | null} context - Context state, holds information about previous positions
|
|
414
|
-
* @param {Feature<Point, ICurrentPositionProperties>} currentPosition - Feature Point of current position
|
|
415
|
-
* @param {IShapeAnchorPoint} thisClosestPoint - Closest point of shape anchors
|
|
416
|
-
* @param { departureTime: number; arrivalTime: number } stopTimes - departure and arrival stop times in seconds
|
|
417
|
-
* @returns {number} - Result delay in seconds, can be negative for trip ahead
|
|
418
|
-
*/
|
|
419
|
-
this.getCorrectedTimeDelay = (timeDelay, context, currentPosition, thisStopSequence, stopTimes) => {
|
|
420
|
-
// compute dwell time in stop, most common is zero
|
|
421
|
-
const stopDwellTimeSeconds = stopTimes.departureTime - stopTimes.arrivalTime;
|
|
422
|
-
// if dwell time is sheduled as zero, return initial computed delay
|
|
423
|
-
if (stopDwellTimeSeconds <= 0) {
|
|
424
|
-
return timeDelay;
|
|
425
|
-
}
|
|
426
|
-
// if last position was not in this same stop or there is no last position at all
|
|
427
|
-
if (!context || context.atStopStreak.stop_sequence !== thisStopSequence) {
|
|
428
|
-
// timeDelay >= 0 trip is DELAYED
|
|
429
|
-
// we presume it will lower delay by shortening its scheduled dwell time,
|
|
430
|
-
// cant go under zero of course, trip should not go ahead
|
|
431
|
-
// else trip is AHeAD
|
|
432
|
-
// left computed delay as it was
|
|
433
|
-
return timeDelay >= 0 ? Math.max(timeDelay - stopDwellTimeSeconds, 0) : timeDelay;
|
|
434
|
-
}
|
|
435
|
-
// we presume that first position at same stop is real arrival time
|
|
436
|
-
if (context.atStopStreak.firstPositionDelay >= 0) {
|
|
437
|
-
// trip was DELAYED before
|
|
438
|
-
// we presume it will lower delay by shortening its scheduled dwell time,
|
|
439
|
-
// cant go under zero of course, trip should not go ahead
|
|
440
|
-
return Math.max(timeDelay - stopDwellTimeSeconds, 0);
|
|
441
|
-
}
|
|
442
|
-
// trip was AHEAD before
|
|
443
|
-
// real dwell time so far
|
|
444
|
-
const realDwellTimeSeconds = Math.round((currentPosition.properties.origin_timestamp.getTime() - context.atStopStreak.firstPositionTimestamp) / 1000);
|
|
445
|
-
// if real dwell is longer than scheduled, then add to negative delay time
|
|
446
|
-
return context.atStopStreak.firstPositionDelay + Math.max(realDwellTimeSeconds - stopDwellTimeSeconds, 0);
|
|
447
|
-
};
|
|
448
|
-
/**
|
|
449
|
-
* Compute UTC timestamp of start of day when trip starts
|
|
450
|
-
*
|
|
451
|
-
* @param {number} startTimestamp - Unix timestamp of start of the trip
|
|
452
|
-
* @param {number} firstStopTimeScheduledSeconds - Number of seconds from midnight of first stop departure
|
|
453
|
-
* @returns {number} - Returns unix timestamp in milliseconds.
|
|
454
|
-
*/
|
|
455
|
-
this.getStartDayTimestamp = (startTimestamp, firstStopTimeScheduledSeconds) => {
|
|
456
|
-
let startDayTimestamp = moment_timezone_1.default.utc(startTimestamp).tz("Europe/Prague").startOf("day");
|
|
457
|
-
const stopTimeDayOverflow = Math.floor(firstStopTimeScheduledSeconds / ONE_DAY_IN_SECONDS);
|
|
458
|
-
// if trip has 24+ stop times set real startDay to yesterday
|
|
459
|
-
if (stopTimeDayOverflow > 0) {
|
|
460
|
-
startDayTimestamp.subtract(1, "day");
|
|
461
|
-
}
|
|
462
|
-
return startDayTimestamp.valueOf();
|
|
463
|
-
};
|
|
464
|
-
}
|
|
51
|
+
class PositionsManager {
|
|
465
52
|
/**
|
|
466
53
|
* Get delay in seconds for positions before track to ensure correct delay propagation
|
|
467
54
|
*
|
|
@@ -473,7 +60,7 @@ let PositionsManager = exports.PositionsManager = class PositionsManager {
|
|
|
473
60
|
* @param positionOriginUnixTimestamp The Unix Epoch timestamp of the current position, in milliseconds
|
|
474
61
|
* @param startDayUnixTimestamp The Unix Epoch timestamp of the start of the service day, in milliseconds
|
|
475
62
|
*/
|
|
476
|
-
getDelayBeforeTrack(lastPositionDelay, firstStopDepartureTime, positionOriginUnixTimestamp, startDayUnixTimestamp) {
|
|
63
|
+
static getDelayBeforeTrack(lastPositionDelay, firstStopDepartureTime, positionOriginUnixTimestamp, startDayUnixTimestamp) {
|
|
477
64
|
if (typeof lastPositionDelay !== "number") {
|
|
478
65
|
return null;
|
|
479
66
|
}
|
|
@@ -485,8 +72,8 @@ let PositionsManager = exports.PositionsManager = class PositionsManager {
|
|
|
485
72
|
const positionOriginTimeInSeconds = Math.floor(positionOriginUnixTimestamp / ONE_SECOND_IN_MILLIS);
|
|
486
73
|
return Math.max(lastPositionDelay, positionOriginTimeInSeconds - departureTimeInSeconds);
|
|
487
74
|
}
|
|
488
|
-
getStateAndStopSequences(gtfsRouteType, tripStopTimes, thisClosestPoint, positionProperties, context) {
|
|
489
|
-
var
|
|
75
|
+
static getStateAndStopSequences(gtfsRouteType, tripStopTimes, thisClosestPoint, positionProperties, context) {
|
|
76
|
+
var _b;
|
|
490
77
|
let statePosition = thisClosestPoint.this_stop_sequence ? const_1.StatePositionEnum.AT_STOP : const_1.StatePositionEnum.ON_TRACK;
|
|
491
78
|
let thisStopSequence = thisClosestPoint.this_stop_sequence;
|
|
492
79
|
let lastStopSequence = thisClosestPoint.last_stop_sequence;
|
|
@@ -496,7 +83,7 @@ let PositionsManager = exports.PositionsManager = class PositionsManager {
|
|
|
496
83
|
positionProperties.tcp_event === const_1.TCPEventEnum.TIME &&
|
|
497
84
|
(context === null || context === void 0 ? void 0 : context.lastPositionTracking)) {
|
|
498
85
|
const previousPositionTcpEvent = context.lastPositionTracking.properties.tcp_event;
|
|
499
|
-
const previousLastStopSequence = (
|
|
86
|
+
const previousLastStopSequence = (_b = context.lastPositionTracking.properties.last_stop_sequence) !== null && _b !== void 0 ? _b : 0;
|
|
500
87
|
// if previous position was 'P' and current last stop sequence is lower than the previous last stop sequence
|
|
501
88
|
// or if previous position was 'O', current position is at stop
|
|
502
89
|
// and current last stop sequence is lower than the previous last stop sequence
|
|
@@ -526,14 +113,399 @@ let PositionsManager = exports.PositionsManager = class PositionsManager {
|
|
|
526
113
|
nextStopSequence,
|
|
527
114
|
};
|
|
528
115
|
}
|
|
529
|
-
isAfterTrack(lastStopSequence, lastTripShapePoint) {
|
|
116
|
+
static isAfterTrack(lastStopSequence, lastTripShapePoint) {
|
|
530
117
|
// Trip is terminated OR the vehicle is close to/in the terminus
|
|
531
118
|
return lastStopSequence >= lastTripShapePoint.last_stop_sequence;
|
|
532
119
|
}
|
|
120
|
+
}
|
|
121
|
+
_a = PositionsManager;
|
|
122
|
+
/**
|
|
123
|
+
* Compute positions and return computed positions
|
|
124
|
+
*
|
|
125
|
+
* @param {ITripPositionsWithGTFS} tripPositions - Trip positions with shape anchors data
|
|
126
|
+
* @returns {Promise<IProcessedPositions>} - Returns computed/updated positions
|
|
127
|
+
*/
|
|
128
|
+
PositionsManager.computePositions = (tripPositions, schedule) => __awaiter(void 0, void 0, void 0, function* () {
|
|
129
|
+
const startTimestamp = tripPositions.start_timestamp.getTime();
|
|
130
|
+
const startDayTimestamp = _a.getStartDayTimestamp(startTimestamp, tripPositions.gtfsData.shapes_anchor_points[0].time_scheduled_seconds);
|
|
131
|
+
const gtfsRouteType = tripPositions.gtfs_route_type;
|
|
132
|
+
const context = PositionsManager.getCurrentContext(tripPositions);
|
|
133
|
+
const computedPositions = [];
|
|
134
|
+
const endTimestamp = tripPositions.end_timestamp;
|
|
135
|
+
return PositionsManager.updatePositions({ tripPositions, startTimestamp, endTimestamp, startDayTimestamp, context, computedPositions, gtfsRouteType }, schedule);
|
|
136
|
+
});
|
|
137
|
+
/**
|
|
138
|
+
* Takes position one by one, set proper handler for type of position, and do the process of position
|
|
139
|
+
*
|
|
140
|
+
* @param {number} i - Iteration
|
|
141
|
+
* @param {IUpdatePositionsIteratorOptions} options - Initial options
|
|
142
|
+
* @param {number} cb - Callback function of iterator
|
|
143
|
+
* @returns {void} - void
|
|
144
|
+
*/
|
|
145
|
+
PositionsManager.updatePositions = (options, schedule) => __awaiter(void 0, void 0, void 0, function* () {
|
|
146
|
+
var _b, _c, _d, _e, _f, _g, _h;
|
|
147
|
+
const { tripPositions, startDayTimestamp, startTimestamp, endTimestamp, context, computedPositions, gtfsRouteType } = options;
|
|
148
|
+
for (let i = 0; i < tripPositions.positions.length; i++) {
|
|
149
|
+
const position = tripPositions.positions[i];
|
|
150
|
+
let positionToUpdate = null;
|
|
151
|
+
// situations
|
|
152
|
+
switch (_a.setPositionUpdateHandler(position)) {
|
|
153
|
+
case PositionHandlerEnum_1.PositionHandlerEnum.TRACKING:
|
|
154
|
+
const currentPosition = turf.point([position.lng, position.lat], {
|
|
155
|
+
id: position.id,
|
|
156
|
+
origin_time: position.origin_time,
|
|
157
|
+
origin_timestamp: position.origin_timestamp,
|
|
158
|
+
scheduled_timestamp: position.scheduled_timestamp,
|
|
159
|
+
this_stop_id: position.this_stop_id,
|
|
160
|
+
tcp_event: position.tcp_event,
|
|
161
|
+
});
|
|
162
|
+
positionToUpdate = _a.getEstimatedPoint(tripPositions.gtfsData, currentPosition, context, startDayTimestamp, tripPositions.gtfs_route_type);
|
|
163
|
+
if (positionToUpdate.state_position !== const_1.StatePositionEnum.MISMATCHED) {
|
|
164
|
+
positionToUpdate = ComputeDelayHelper_1.default.updatePositionToUpdate(context, positionToUpdate, position, gtfsRouteType);
|
|
165
|
+
}
|
|
166
|
+
positionToUpdate.bearing = (_b = position.bearing) !== null && _b !== void 0 ? _b : positionToUpdate.bearing;
|
|
167
|
+
break;
|
|
168
|
+
case PositionHandlerEnum_1.PositionHandlerEnum.NOT_TRACKING:
|
|
169
|
+
// if there is no previous positions with tracking status, set position as before_track
|
|
170
|
+
const firstShapesAnchorPoint = tripPositions.gtfsData.shapes_anchor_points[0];
|
|
171
|
+
if (context.lastPositionTracking === null &&
|
|
172
|
+
(endTimestamp === null ||
|
|
173
|
+
position.scheduled_timestamp === null ||
|
|
174
|
+
endTimestamp > position.scheduled_timestamp)) {
|
|
175
|
+
const firstStopTime = tripPositions.gtfsData.stop_times[0];
|
|
176
|
+
// if there is propagated delay we can use it for new position
|
|
177
|
+
const lastPositionDelayed = context.lastPositionBeforeTrackDelayed;
|
|
178
|
+
// if there is no delay to duplicate and DPP trip is far from start then invisible
|
|
179
|
+
const setAsInvisible = !lastPositionDelayed &&
|
|
180
|
+
DPPUtils_1.default.isInvisible(tripPositions.agency_name_scheduled, position.origin_timestamp, startTimestamp, [position.lng, position.lat], firstShapesAnchorPoint.coordinates, schedule, tripPositions.gtfs_trip_id, context.lastPositionTracking, position.is_tracked);
|
|
181
|
+
positionToUpdate = Object.assign({ id: position.id, next_stop_arrival_time: new Date(startDayTimestamp + firstStopTime.arrival_time_seconds * 1000), next_stop_departure_time: new Date(startDayTimestamp + firstStopTime.departure_time_seconds * 1000), next_stop_id: firstStopTime.stop_id, next_stop_sequence: firstStopTime.stop_sequence, next_stop_name: firstStopTime.stop.stop_name, shape_dist_traveled: firstStopTime.shape_dist_traveled, state_position: setAsInvisible ? const_1.StatePositionEnum.INVISIBLE : const_1.StatePositionEnum.BEFORE_TRACK, state_process: const_1.StateProcessEnum.PROCESSED }, (firstStopTime.stop_headsign && {
|
|
182
|
+
last_stop_headsign: firstStopTime.stop_headsign,
|
|
183
|
+
}));
|
|
184
|
+
if (positionToUpdate.state_position === const_1.StatePositionEnum.BEFORE_TRACK) {
|
|
185
|
+
positionToUpdate.delay = _a.getDelayBeforeTrack((_c = lastPositionDelayed === null || lastPositionDelayed === void 0 ? void 0 : lastPositionDelayed.delay) !== null && _c !== void 0 ? _c : position.delay, firstStopTime.departure_time_seconds, position.origin_timestamp.getTime(), startDayTimestamp);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
// if there is tracking 2 position with same origin_timestamp then this position is duplicate
|
|
190
|
+
const statePosition = position.origin_timestamp.getTime() === context.lastPositionOriginTimestamp ||
|
|
191
|
+
tripPositions.positions.findIndex((positionItem) => positionItem.origin_timestamp.getTime() === position.origin_timestamp.getTime() &&
|
|
192
|
+
positionItem.is_tracked) >= 0
|
|
193
|
+
? const_1.StatePositionEnum.DUPLICATE
|
|
194
|
+
: const_1.StatePositionEnum.AFTER_TRACK;
|
|
195
|
+
const lastShapesAnchorPoint = tripPositions.gtfsData.shapes_anchor_points[tripPositions.gtfsData.shapes_anchor_points.length - 1];
|
|
196
|
+
const lastStopTime = tripPositions.gtfsData.stop_times[tripPositions.gtfsData.stop_times.length - 1];
|
|
197
|
+
// set as invisible if there are some AFTER_TRACK before
|
|
198
|
+
const setAsInvisible = DPPUtils_1.default.isInvisible(tripPositions.agency_name_scheduled, position.origin_timestamp, startTimestamp, [position.lng, position.lat], firstShapesAnchorPoint.coordinates, schedule, tripPositions.gtfs_trip_id, context.lastPositionTracking, position.is_tracked) && statePosition === const_1.StatePositionEnum.AFTER_TRACK;
|
|
199
|
+
positionToUpdate = Object.assign({ id: position.id, last_stop_arrival_time: new Date(startDayTimestamp + lastShapesAnchorPoint.time_scheduled_seconds * 1000), last_stop_departure_time: new Date(startDayTimestamp + lastShapesAnchorPoint.time_scheduled_seconds * 1000), last_stop_id: lastStopTime.stop_id, last_stop_sequence: lastShapesAnchorPoint.last_stop_sequence, shape_dist_traveled: lastShapesAnchorPoint.shape_dist_traveled, state_position: setAsInvisible ? const_1.StatePositionEnum.INVISIBLE : statePosition, state_process: const_1.StateProcessEnum.PROCESSED, delay: (_d = position.delay) !== null && _d !== void 0 ? _d : null }, (lastStopTime.stop_headsign && {
|
|
200
|
+
last_stop_headsign: lastStopTime.stop_headsign,
|
|
201
|
+
}));
|
|
202
|
+
positionToUpdate = ComputeDelayHelper_1.default.updatePositionToUpdate(context, positionToUpdate, position, gtfsRouteType);
|
|
203
|
+
}
|
|
204
|
+
break;
|
|
205
|
+
case PositionHandlerEnum_1.PositionHandlerEnum.CANCELED:
|
|
206
|
+
positionToUpdate = {
|
|
207
|
+
id: position.id,
|
|
208
|
+
state_position: const_1.StatePositionEnum.CANCELED,
|
|
209
|
+
state_process: const_1.StateProcessEnum.PROCESSED,
|
|
210
|
+
};
|
|
211
|
+
break;
|
|
212
|
+
case PositionHandlerEnum_1.PositionHandlerEnum.DO_NOTHING:
|
|
213
|
+
break;
|
|
214
|
+
default:
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
// if not null push to update
|
|
218
|
+
if (positionToUpdate) {
|
|
219
|
+
(_e = positionToUpdate.is_tracked) !== null && _e !== void 0 ? _e : (positionToUpdate.is_tracked = position.is_tracked);
|
|
220
|
+
positionToUpdate.valid_to = ValidToCalculator_1.default.getValidToAttribute(positionToUpdate, position, gtfsRouteType, tripPositions.gtfsData, startTimestamp, startDayTimestamp);
|
|
221
|
+
computedPositions.push(positionToUpdate);
|
|
222
|
+
}
|
|
223
|
+
context.lastPositionState = (_f = positionToUpdate === null || positionToUpdate === void 0 ? void 0 : positionToUpdate.state_position) !== null && _f !== void 0 ? _f : position.state_position;
|
|
224
|
+
// set last known BEFORE_TRACK_DELAYED position
|
|
225
|
+
if (position.state_position === const_1.StatePositionEnum.BEFORE_TRACK_DELAYED) {
|
|
226
|
+
context.lastPositionBeforeTrackDelayed = {
|
|
227
|
+
delay: (_g = positionToUpdate === null || positionToUpdate === void 0 ? void 0 : positionToUpdate.delay) !== null && _g !== void 0 ? _g : position.delay,
|
|
228
|
+
origin_timestamp: (_h = positionToUpdate === null || positionToUpdate === void 0 ? void 0 : positionToUpdate.origin_timestamp) !== null && _h !== void 0 ? _h : position.origin_timestamp,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
// set last position tracking (only for at_stop and on_track)
|
|
232
|
+
if ((positionToUpdate === null || positionToUpdate === void 0 ? void 0 : positionToUpdate.state_position) === const_1.StatePositionEnum.AT_STOP ||
|
|
233
|
+
(positionToUpdate === null || positionToUpdate === void 0 ? void 0 : positionToUpdate.state_position) === const_1.StatePositionEnum.ON_TRACK ||
|
|
234
|
+
position.state_position === const_1.StatePositionEnum.AT_STOP ||
|
|
235
|
+
position.state_position === const_1.StatePositionEnum.ON_TRACK) {
|
|
236
|
+
context.lastPositionTracking = turf.point([position.lng, position.lat], Object.assign(Object.assign({}, position), positionToUpdate));
|
|
237
|
+
}
|
|
238
|
+
// set new first position at stop streak if this stop seqence is set and it is not same as before
|
|
239
|
+
if (positionToUpdate
|
|
240
|
+
? positionToUpdate.this_stop_sequence &&
|
|
241
|
+
context.atStopStreak.stop_sequence !== positionToUpdate.this_stop_sequence
|
|
242
|
+
: position.this_stop_sequence && context.atStopStreak.stop_sequence !== position.this_stop_sequence) {
|
|
243
|
+
context.atStopStreak.stop_sequence = positionToUpdate
|
|
244
|
+
? positionToUpdate.this_stop_sequence
|
|
245
|
+
: position.this_stop_sequence;
|
|
246
|
+
context.atStopStreak.firstPositionTimestamp = position.origin_timestamp.getTime();
|
|
247
|
+
context.atStopStreak.firstPositionDelay = positionToUpdate ? positionToUpdate.delay : position.delay;
|
|
248
|
+
}
|
|
249
|
+
// IF currently valid updated position / position was processed before
|
|
250
|
+
// and it is NOT AT_STOP
|
|
251
|
+
// then disrupt atStopStreak
|
|
252
|
+
if (positionToUpdate &&
|
|
253
|
+
positionToUpdate.state_position !== const_1.StatePositionEnum.MISMATCHED &&
|
|
254
|
+
!positionToUpdate.this_stop_sequence) {
|
|
255
|
+
context.atStopStreak.stop_sequence = null;
|
|
256
|
+
}
|
|
257
|
+
else if (!positionToUpdate && !position.this_stop_sequence) {
|
|
258
|
+
context.atStopStreak.stop_sequence = null;
|
|
259
|
+
}
|
|
260
|
+
// duplicated or mismatched position should not be considered at all
|
|
261
|
+
if ((positionToUpdate === null || positionToUpdate === void 0 ? void 0 : positionToUpdate.state_position) !== const_1.StatePositionEnum.DUPLICATE &&
|
|
262
|
+
(positionToUpdate === null || positionToUpdate === void 0 ? void 0 : positionToUpdate.state_position) !== const_1.StatePositionEnum.INVISIBLE &&
|
|
263
|
+
(positionToUpdate === null || positionToUpdate === void 0 ? void 0 : positionToUpdate.state_position) !== const_1.StatePositionEnum.MISMATCHED) {
|
|
264
|
+
context.lastPositionId = position.id;
|
|
265
|
+
context.lastPositionCanceled = position.is_canceled;
|
|
266
|
+
context.lastPositionOriginTimestamp = position.origin_timestamp.getTime();
|
|
267
|
+
ComputeDelayHelper_1.default.updateContext(context, positionToUpdate, position, gtfsRouteType);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return {
|
|
271
|
+
context,
|
|
272
|
+
positions: computedPositions,
|
|
273
|
+
};
|
|
274
|
+
});
|
|
275
|
+
PositionsManager.getCurrentContext = (tripPositions) => {
|
|
276
|
+
var _b;
|
|
277
|
+
const context = (_b = tripPositions.last_position_context) !== null && _b !== void 0 ? _b : {
|
|
278
|
+
atStopStreak: {
|
|
279
|
+
stop_sequence: null,
|
|
280
|
+
firstPositionTimestamp: null,
|
|
281
|
+
firstPositionDelay: null,
|
|
282
|
+
},
|
|
283
|
+
lastPositionLastStop: {
|
|
284
|
+
id: null,
|
|
285
|
+
sequence: null,
|
|
286
|
+
arrival_time: null,
|
|
287
|
+
arrival_delay: null,
|
|
288
|
+
departure_time: null,
|
|
289
|
+
departure_delay: null,
|
|
290
|
+
},
|
|
291
|
+
lastPositionDelay: null,
|
|
292
|
+
lastPositionId: null,
|
|
293
|
+
lastPositionOriginTimestamp: null,
|
|
294
|
+
lastPositionTracking: null,
|
|
295
|
+
lastPositionCanceled: null,
|
|
296
|
+
lastPositionBeforeTrackDelayed: null,
|
|
297
|
+
lastPositionState: null,
|
|
298
|
+
tripId: tripPositions.id,
|
|
299
|
+
};
|
|
300
|
+
return context;
|
|
301
|
+
};
|
|
302
|
+
/**
|
|
303
|
+
* Decide how to process input position data
|
|
304
|
+
*
|
|
305
|
+
* @param {IVPTripsPositionAttributes} position - Input vehiclepositions_positions row data
|
|
306
|
+
* @returns {PositionHandlerEnum} - Returns action handler enum
|
|
307
|
+
*/
|
|
308
|
+
PositionsManager.setPositionUpdateHandler = (position) => {
|
|
309
|
+
if (position.state_process === const_1.StateProcessEnum.PROCESSED)
|
|
310
|
+
return PositionHandlerEnum_1.PositionHandlerEnum.DO_NOTHING;
|
|
311
|
+
else if (position.is_canceled)
|
|
312
|
+
return PositionHandlerEnum_1.PositionHandlerEnum.CANCELED;
|
|
313
|
+
else if (position.is_tracked)
|
|
314
|
+
return PositionHandlerEnum_1.PositionHandlerEnum.TRACKING;
|
|
315
|
+
else
|
|
316
|
+
return PositionHandlerEnum_1.PositionHandlerEnum.NOT_TRACKING;
|
|
317
|
+
};
|
|
318
|
+
/**
|
|
319
|
+
* Returns estimate of point on shape, where the trip should be with appropriate delay
|
|
320
|
+
*
|
|
321
|
+
* @param {IShapeAnchorPoint[]} tripShapePoints - Precalculated trip shape equidistant points with scheduled times
|
|
322
|
+
* @param {Feature<Point, ICurrentPositionProperties>} currentPosition - Current position of trip
|
|
323
|
+
* @param {IVPTripsLastPositionContext | null} context - Context state, holds information about previous positions
|
|
324
|
+
* @param {number} startDayTimestamp - Unix timestamp of midnight before trip starts
|
|
325
|
+
* @returns {IPositionToUpdate} - Position object to update
|
|
326
|
+
*/
|
|
327
|
+
PositionsManager.getEstimatedPoint = (tripGtfsData, currentPosition, context, startDayTimestamp, gtfsRouteType) => {
|
|
328
|
+
var _b, _c, _d, _e, _f, _g, _h, _j;
|
|
329
|
+
const anchorPointSegmenter = new AnchorPointSegmenter_1.AnchorPointSegmenter(tripGtfsData.shapes_anchor_points, currentPosition);
|
|
330
|
+
const defaultStatePosition = const_1.StatePositionEnum.OFF_TRACK;
|
|
331
|
+
// Initial value
|
|
332
|
+
let estimatedPoint = Object.assign({ id: currentPosition.properties.id, state_position: defaultStatePosition, state_process: const_1.StateProcessEnum.PROCESSED, tcp_event: currentPosition.properties.tcp_event, valid_to: ValidToCalculator_1.default.getDefaultValidToAttribute(currentPosition.properties.origin_timestamp) }, (context &&
|
|
333
|
+
((_b = context.lastPositionTracking) === null || _b === void 0 ? void 0 : _b.properties.last_stop_sequence) && {
|
|
334
|
+
shape_dist_traveled: (_c = context.lastPositionTracking) === null || _c === void 0 ? void 0 : _c.properties.shape_dist_traveled,
|
|
335
|
+
last_stop_arrival_time: ((_d = context.lastPositionTracking) === null || _d === void 0 ? void 0 : _d.properties.last_stop_arrival_time)
|
|
336
|
+
? new Date((_e = context.lastPositionTracking) === null || _e === void 0 ? void 0 : _e.properties.last_stop_arrival_time)
|
|
337
|
+
: undefined,
|
|
338
|
+
last_stop_departure_time: ((_f = context.lastPositionTracking) === null || _f === void 0 ? void 0 : _f.properties.last_stop_departure_time)
|
|
339
|
+
? new Date((_g = context.lastPositionTracking) === null || _g === void 0 ? void 0 : _g.properties.last_stop_departure_time)
|
|
340
|
+
: undefined,
|
|
341
|
+
last_stop_sequence: (_h = context.lastPositionTracking) === null || _h === void 0 ? void 0 : _h.properties.last_stop_sequence,
|
|
342
|
+
last_stop_id: (_j = context.lastPositionTracking) === null || _j === void 0 ? void 0 : _j.properties.last_stop_id,
|
|
343
|
+
}));
|
|
344
|
+
let lastStopSequence = null;
|
|
345
|
+
if ((context === null || context === void 0 ? void 0 : context.lastPositionState) === const_1.StatePositionEnum.BEFORE_TRACK) {
|
|
346
|
+
lastStopSequence = 1;
|
|
347
|
+
}
|
|
348
|
+
else if (context === null || context === void 0 ? void 0 : context.lastPositionTracking) {
|
|
349
|
+
lastStopSequence = context.lastPositionTracking.properties.last_stop_sequence;
|
|
350
|
+
}
|
|
351
|
+
const closesPoint = anchorPointSegmenter.getClosesPoint(lastStopSequence);
|
|
352
|
+
if (!closesPoint) {
|
|
353
|
+
return estimatedPoint;
|
|
354
|
+
}
|
|
355
|
+
return _a.getClosestPoint(currentPosition, context, startDayTimestamp, closesPoint, tripGtfsData, gtfsRouteType);
|
|
356
|
+
};
|
|
357
|
+
/**
|
|
358
|
+
* Picks only one closest point for multiple possible points based on delay of last position and stop times
|
|
359
|
+
*
|
|
360
|
+
* @param {Feature<Point, ICurrentPositionProperties>} currentPosition - Feature Point of current position
|
|
361
|
+
* @param {IVPTripsLastPositionContext | null} context - Context state, holds information about previous positions
|
|
362
|
+
* @param {number} startDayTimestamp - Unix timestamp of start of the day
|
|
363
|
+
* @param {IShapeAnchorPoint[]} closestPts - All closest points of possible segments
|
|
364
|
+
* @param {IComputationTrip} tripGtfsData - GTFS data and all set of known positions
|
|
365
|
+
* @returns {IPositionToUpdate} - Result point as position to update in DB
|
|
366
|
+
*/
|
|
367
|
+
PositionsManager.getClosestPoint = (currentPosition, context, startDayTimestamp, thisClosestPoint, tripGtfsData, gtfsRouteType) => {
|
|
368
|
+
// want to find minimum difference of our prediction, where the bus should be
|
|
369
|
+
const tripShapePoints = tripGtfsData.shapes_anchor_points;
|
|
370
|
+
const tripStopTimes = tripGtfsData.stop_times;
|
|
371
|
+
const firstTripShapePoint = tripShapePoints[0];
|
|
372
|
+
const lastTripShapePoint = tripShapePoints[tripShapePoints.length - 1];
|
|
373
|
+
const timeScheduledTimestamp = DateTimeUtils_1.DateTimeUtils.getStopDateTimeForDayStart(
|
|
374
|
+
// take stop arrival time if is point at stop
|
|
375
|
+
thisClosestPoint.this_stop_sequence
|
|
376
|
+
? tripStopTimes[thisClosestPoint.this_stop_sequence - 1].arrival_time_seconds
|
|
377
|
+
: thisClosestPoint.time_scheduled_seconds, startDayTimestamp);
|
|
378
|
+
let timeDelayInSeconds = Math.round((currentPosition.properties.origin_timestamp.getTime() - timeScheduledTimestamp.getTime()) / 1000);
|
|
379
|
+
const isBusOrTram = gtfsRouteType === RouteTypeEnums_1.GTFSRouteTypeEnum.BUS ||
|
|
380
|
+
gtfsRouteType === RouteTypeEnums_1.GTFSRouteTypeEnum.TROLLEYBUS ||
|
|
381
|
+
gtfsRouteType === RouteTypeEnums_1.GTFSRouteTypeEnum.TRAM;
|
|
382
|
+
// push trip into nearest at_stop shape anchor point if trip "P" event (TCP tram or bus)
|
|
383
|
+
if (isBusOrTram &&
|
|
384
|
+
currentPosition.properties.tcp_event === const_1.TCPEventEnum.ARRIVAL_ANNOUNCED &&
|
|
385
|
+
thisClosestPoint.this_stop_sequence === null) {
|
|
386
|
+
if (thisClosestPoint.last_stop_sequence === 1 && !(context === null || context === void 0 ? void 0 : context.lastPositionTracking)) {
|
|
387
|
+
thisClosestPoint = firstTripShapePoint;
|
|
388
|
+
}
|
|
389
|
+
else {
|
|
390
|
+
let movingShapePointIndex = thisClosestPoint.index;
|
|
391
|
+
while (thisClosestPoint.this_stop_sequence === null && movingShapePointIndex < lastTripShapePoint.index) {
|
|
392
|
+
movingShapePointIndex++;
|
|
393
|
+
thisClosestPoint = tripShapePoints[movingShapePointIndex];
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
// lets correct delay if it is at stop
|
|
398
|
+
if (thisClosestPoint.this_stop_sequence) {
|
|
399
|
+
const thisStopSequence = thisClosestPoint.this_stop_sequence;
|
|
400
|
+
timeDelayInSeconds = _a.getCorrectedTimeDelay(timeDelayInSeconds, context, currentPosition, thisStopSequence, {
|
|
401
|
+
departureTime: tripStopTimes[thisStopSequence - 1].departure_time_seconds,
|
|
402
|
+
arrivalTime: tripStopTimes[thisStopSequence - 1].arrival_time_seconds,
|
|
403
|
+
});
|
|
404
|
+
// delay can not be negative if the vehicle is at the first stop
|
|
405
|
+
if (thisStopSequence === firstTripShapePoint.this_stop_sequence) {
|
|
406
|
+
timeDelayInSeconds = Math.max(timeDelayInSeconds, 0);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
let { statePosition, thisStopSequence, lastStopSequence, nextStopSequence } = PositionsManager.getStateAndStopSequences(gtfsRouteType, tripStopTimes, thisClosestPoint, currentPosition.properties, context);
|
|
410
|
+
// test if TCP trip with DEPARTURED event should not be at stop (not applied for last stop)
|
|
411
|
+
if (currentPosition.properties.tcp_event === const_1.TCPEventEnum.DEPARTURED &&
|
|
412
|
+
thisStopSequence !== lastTripShapePoint.this_stop_sequence) {
|
|
413
|
+
statePosition = const_1.StatePositionEnum.ON_TRACK;
|
|
414
|
+
}
|
|
415
|
+
if (isBusOrTram && PositionsManager.isAfterTrack(lastStopSequence, lastTripShapePoint)) {
|
|
416
|
+
statePosition = const_1.StatePositionEnum.AFTER_TRACK;
|
|
417
|
+
thisStopSequence = lastTripShapePoint.this_stop_sequence;
|
|
418
|
+
lastStopSequence = lastTripShapePoint.last_stop_sequence;
|
|
419
|
+
nextStopSequence = lastTripShapePoint.next_stop_sequence;
|
|
420
|
+
timeDelayInSeconds = 0;
|
|
421
|
+
}
|
|
422
|
+
// save it for result
|
|
423
|
+
const estimatedPoint = {
|
|
424
|
+
id: currentPosition.properties.id,
|
|
425
|
+
bearing: thisClosestPoint.bearing,
|
|
426
|
+
shape_dist_traveled: thisClosestPoint.shape_dist_traveled,
|
|
427
|
+
next_stop_id: tripStopTimes[nextStopSequence - 1].stop_id,
|
|
428
|
+
last_stop_id: tripStopTimes[lastStopSequence - 1].stop_id,
|
|
429
|
+
next_stop_name: tripStopTimes[nextStopSequence - 1].stop.stop_name,
|
|
430
|
+
last_stop_name: tripStopTimes[lastStopSequence - 1].stop.stop_name,
|
|
431
|
+
next_stop_sequence: nextStopSequence,
|
|
432
|
+
last_stop_sequence: lastStopSequence,
|
|
433
|
+
next_stop_arrival_time: DateTimeUtils_1.DateTimeUtils.getStopDateTimeForDayStart(tripStopTimes[nextStopSequence - 1].arrival_time_seconds, startDayTimestamp),
|
|
434
|
+
last_stop_arrival_time: DateTimeUtils_1.DateTimeUtils.getStopDateTimeForDayStart(tripStopTimes[lastStopSequence - 1].arrival_time_seconds, startDayTimestamp),
|
|
435
|
+
next_stop_departure_time: DateTimeUtils_1.DateTimeUtils.getStopDateTimeForDayStart(tripStopTimes[nextStopSequence - 1].departure_time_seconds, startDayTimestamp),
|
|
436
|
+
last_stop_departure_time: DateTimeUtils_1.DateTimeUtils.getStopDateTimeForDayStart(tripStopTimes[lastStopSequence - 1].departure_time_seconds, startDayTimestamp),
|
|
437
|
+
delay: timeDelayInSeconds,
|
|
438
|
+
this_stop_id: (statePosition === const_1.StatePositionEnum.AT_STOP &&
|
|
439
|
+
thisStopSequence &&
|
|
440
|
+
tripStopTimes[thisStopSequence - 1].stop_id) ||
|
|
441
|
+
undefined,
|
|
442
|
+
this_stop_name: (statePosition === const_1.StatePositionEnum.AT_STOP &&
|
|
443
|
+
thisStopSequence &&
|
|
444
|
+
tripStopTimes[thisStopSequence - 1].stop.stop_name) ||
|
|
445
|
+
undefined,
|
|
446
|
+
this_stop_sequence: (statePosition === const_1.StatePositionEnum.AT_STOP && thisStopSequence) || undefined,
|
|
447
|
+
last_stop_headsign: tripStopTimes[lastStopSequence - 1].stop_headsign || undefined,
|
|
448
|
+
state_position: statePosition,
|
|
449
|
+
state_process: const_1.StateProcessEnum.PROCESSED,
|
|
450
|
+
valid_to: ValidToCalculator_1.default.getDefaultValidToAttribute(currentPosition.properties.origin_timestamp),
|
|
451
|
+
is_tracked: statePosition !== const_1.StatePositionEnum.AFTER_TRACK && statePosition !== const_1.StatePositionEnum.MISMATCHED,
|
|
452
|
+
};
|
|
453
|
+
return estimatedPoint;
|
|
454
|
+
};
|
|
455
|
+
/**
|
|
456
|
+
* Corrects time delay at stop with dwelling time
|
|
457
|
+
*
|
|
458
|
+
* @param {number} timeDelay - Initial computed delay in seconds, can be negative for trip ahead
|
|
459
|
+
* @param {IVPTripsLastPositionContext | null} context - Context state, holds information about previous positions
|
|
460
|
+
* @param {Feature<Point, ICurrentPositionProperties>} currentPosition - Feature Point of current position
|
|
461
|
+
* @param {IShapeAnchorPoint} thisClosestPoint - Closest point of shape anchors
|
|
462
|
+
* @param { departureTime: number; arrivalTime: number } stopTimes - departure and arrival stop times in seconds
|
|
463
|
+
* @returns {number} - Result delay in seconds, can be negative for trip ahead
|
|
464
|
+
*/
|
|
465
|
+
PositionsManager.getCorrectedTimeDelay = (timeDelay, context, currentPosition, thisStopSequence, stopTimes) => {
|
|
466
|
+
// compute dwell time in stop, most common is zero
|
|
467
|
+
const stopDwellTimeSeconds = stopTimes.departureTime - stopTimes.arrivalTime;
|
|
468
|
+
// if dwell time is sheduled as zero, return initial computed delay
|
|
469
|
+
if (stopDwellTimeSeconds <= 0) {
|
|
470
|
+
return timeDelay;
|
|
471
|
+
}
|
|
472
|
+
// if last position was not in this same stop or there is no last position at all
|
|
473
|
+
if (!context || context.atStopStreak.stop_sequence !== thisStopSequence) {
|
|
474
|
+
// timeDelay >= 0 trip is DELAYED
|
|
475
|
+
// we presume it will lower delay by shortening its scheduled dwell time,
|
|
476
|
+
// cant go under zero of course, trip should not go ahead
|
|
477
|
+
// else trip is AHeAD
|
|
478
|
+
// left computed delay as it was
|
|
479
|
+
return timeDelay >= 0 ? Math.max(timeDelay - stopDwellTimeSeconds, 0) : timeDelay;
|
|
480
|
+
}
|
|
481
|
+
// we presume that first position at same stop is real arrival time
|
|
482
|
+
if (context.atStopStreak.firstPositionDelay >= 0) {
|
|
483
|
+
// trip was DELAYED before
|
|
484
|
+
// we presume it will lower delay by shortening its scheduled dwell time,
|
|
485
|
+
// cant go under zero of course, trip should not go ahead
|
|
486
|
+
return Math.max(timeDelay - stopDwellTimeSeconds, 0);
|
|
487
|
+
}
|
|
488
|
+
// trip was AHEAD before
|
|
489
|
+
// real dwell time so far
|
|
490
|
+
const realDwellTimeSeconds = Math.round((currentPosition.properties.origin_timestamp.getTime() - context.atStopStreak.firstPositionTimestamp) / 1000);
|
|
491
|
+
// if real dwell is longer than scheduled, then add to negative delay time
|
|
492
|
+
return context.atStopStreak.firstPositionDelay + Math.max(realDwellTimeSeconds - stopDwellTimeSeconds, 0);
|
|
493
|
+
};
|
|
494
|
+
/**
|
|
495
|
+
* Compute UTC timestamp of start of day when trip starts
|
|
496
|
+
*
|
|
497
|
+
* @param {number} startTimestamp - Unix timestamp of start of the trip
|
|
498
|
+
* @param {number} firstStopTimeScheduledSeconds - Number of seconds from midnight of first stop departure
|
|
499
|
+
* @returns {number} - Returns unix timestamp in milliseconds.
|
|
500
|
+
*/
|
|
501
|
+
PositionsManager.getStartDayTimestamp = (startTimestamp, firstStopTimeScheduledSeconds) => {
|
|
502
|
+
let startDayTimestamp = moment_timezone_1.default.utc(startTimestamp).tz("Europe/Prague").startOf("day");
|
|
503
|
+
const stopTimeDayOverflow = Math.floor(firstStopTimeScheduledSeconds / ONE_DAY_IN_SECONDS);
|
|
504
|
+
// if trip has 24+ stop times set real startDay to yesterday
|
|
505
|
+
if (stopTimeDayOverflow > 0) {
|
|
506
|
+
startDayTimestamp.subtract(1, "day");
|
|
507
|
+
}
|
|
508
|
+
return startDayTimestamp.valueOf();
|
|
533
509
|
};
|
|
534
|
-
exports.
|
|
535
|
-
(0, tsyringe_1.injectable)(),
|
|
536
|
-
__param(0, (0, tsyringe_1.inject)(VPContainerToken_1.VPContainerToken.ValidToCalculator)),
|
|
537
|
-
__metadata("design:paramtypes", [ValidToCalculator_1.ValidToCalculator])
|
|
538
|
-
], PositionsManager);
|
|
510
|
+
exports.default = PositionsManager;
|
|
539
511
|
//# sourceMappingURL=PositionsManager.js.map
|