@wemap/routers 6.2.2 → 7.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/assets/biocbon-bergere-rdc-network.osm +163 -0
- package/assets/gare-de-lest-network-pp-bounds.osm +1615 -0
- package/dist/wemap-routers.es.js +1811 -695
- package/dist/wemap-routers.es.js.map +1 -1
- package/index.js +13 -5
- package/package.json +9 -6
- package/src/Constants.js +4 -2
- package/src/ItineraryInfoManager.spec.js +2 -2
- package/src/Utils.js +0 -77
- package/src/model/Itinerary.js +41 -5
- package/src/model/Itinerary.spec.js +91 -0
- package/src/model/Itinerary.type.spec.js +3 -78
- package/src/model/Leg.js +89 -19
- package/src/model/Leg.spec.js +110 -0
- package/src/model/Leg.type.spec.js +48 -0
- package/src/model/LevelChange.js +14 -24
- package/src/model/LevelChange.spec.js +78 -0
- package/src/model/LevelChange.type.spec.js +26 -0
- package/src/model/RouterResponse.js +70 -1
- package/src/model/RouterResponse.spec.js +85 -0
- package/src/model/RouterResponse.type.spec.js +7 -4
- package/src/model/Step.js +45 -6
- package/src/model/Step.spec.js +100 -0
- package/src/model/Step.type.spec.js +52 -0
- package/src/remote/RemoteRouter.js +31 -0
- package/src/remote/RemoteRouterManager.js +84 -0
- package/src/remote/RemoteRouterOptions.js +25 -0
- package/src/remote/RemoteRouterServerUnreachable.js +10 -0
- package/src/remote/RemoteRouterUtils.js +78 -0
- package/src/remote/RoutingModeCorrespondanceNotFound.js +18 -0
- package/src/remote/cityway/CitywayRemoteRouter.js +386 -0
- package/src/{cityway/CitywayUtils.spec.js → remote/cityway/CitywayRemoteRouter.spec.js} +19 -18
- package/src/remote/deutsche-bahn/DeutscheBahnRemoteRouter.js +143 -0
- package/src/{deutsche-bahn/DeutscheBahnRouterUtils.spec.js → remote/deutsche-bahn/DeutscheBahnRemoteRouter.spec.js} +7 -6
- package/src/remote/idfm/IdfmRemoteRouter.js +432 -0
- package/src/{idfm/IdfmUtils.spec.js → remote/idfm/IdfmRemoteRouter.spec.js} +7 -6
- package/src/remote/idfm/IdfmRemoteRouterTokenError.js +6 -0
- package/src/remote/osrm/OsrmRemoteRouter.js +331 -0
- package/src/{osrm/OsrmUtils.spec.js → remote/osrm/OsrmRemoteRouter.spec.js} +9 -15
- package/src/remote/otp/OtpRemoteRouter.js +222 -0
- package/src/{otp/OtpUtils.spec.js → remote/otp/OtpRemoteRouter.spec.js} +10 -9
- package/src/remote/wemap-meta/WemapMetaRemoteRouter.js +57 -0
- package/src/remote/wemap-meta/WemapMetaRemoteRouter.spec.js +22 -0
- package/src/remote/wemap-meta/WemapMetaRemoteRouterOptions.js +36 -0
- package/src/remote/wemap-meta/WemapMetaRemoteRouterPayload.js +44 -0
- package/src/wemap/WemapRouter.js +6 -0
- package/src/wemap/WemapRouterUtils.js +10 -4
- package/src/wemap/WemapStepsGeneration.js +36 -9
- package/src/wemap-meta/IOMap.js +191 -0
- package/src/wemap-meta/WemapMetaRouter.js +314 -0
- package/src/wemap-meta/WemapMetaRouter.spec.js +119 -0
- package/src/wemap-meta/WemapMetaRouterOptions.js +20 -0
- package/src/cityway/CitywayUtils.js +0 -252
- package/src/deutsche-bahn/DeutscheBahnRouterUtils.js +0 -91
- package/src/idfm/IdfmUtils.js +0 -247
- package/src/osrm/OsrmUtils.js +0 -269
- package/src/otp/OtpUtils.js +0 -150
package/dist/wemap-routers.es.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Coordinates, Network, GraphRouterOptions, GraphRouter, GraphUtils, Level, GraphEdge, GraphNode, GraphItinerary, Utils, MapMatching } from '@wemap/geo';
|
|
2
2
|
import { OsmWay, OsmNode } from '@wemap/osm';
|
|
3
|
-
import {
|
|
4
|
-
import Polyline from '@mapbox/polyline';
|
|
3
|
+
import { deg2rad, diffAngle, positiveMod, rad2deg } from '@wemap/maths';
|
|
5
4
|
import Logger from '@wemap/logger';
|
|
5
|
+
import Polyline from '@mapbox/polyline';
|
|
6
6
|
|
|
7
7
|
class LevelChange {
|
|
8
8
|
|
|
@@ -16,28 +16,22 @@ class LevelChange {
|
|
|
16
16
|
type = null;
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
* @param {
|
|
20
|
-
* @param {
|
|
21
|
-
* @returns {
|
|
19
|
+
* @param {LevelChange} obj1
|
|
20
|
+
* @param {LevelChange} obj2
|
|
21
|
+
* @returns {Boolean}
|
|
22
22
|
*/
|
|
23
|
-
static
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (edge.builtFrom.isElevator) {
|
|
30
|
-
levelChange.type = 'elevator';
|
|
31
|
-
} else if (edge.builtFrom.isConveying) {
|
|
32
|
-
levelChange.type = 'conveyor';
|
|
33
|
-
} else if (edge.builtFrom.areStairs) {
|
|
34
|
-
levelChange.type = 'stairs';
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
levelChange.difference = Level.diff(firstNode.coords.level, secondNode.coords.level);
|
|
38
|
-
levelChange.direction = levelChange.difference > 0 ? 'up' : 'down';
|
|
23
|
+
static equalsTo(obj1, obj2) {
|
|
24
|
+
return obj1.difference === obj2.difference
|
|
25
|
+
&& obj1.direction === obj2.direction
|
|
26
|
+
&& obj1.type === obj2.type;
|
|
27
|
+
}
|
|
39
28
|
|
|
40
|
-
|
|
29
|
+
/**
|
|
30
|
+
* @param {LevelChange} obj
|
|
31
|
+
* @returns {Boolean}
|
|
32
|
+
*/
|
|
33
|
+
equalsTo(obj) {
|
|
34
|
+
return LevelChange.equalsTo(this, obj);
|
|
41
35
|
}
|
|
42
36
|
|
|
43
37
|
/**
|
|
@@ -108,6 +102,45 @@ class Step {
|
|
|
108
102
|
/** @type {!number} */
|
|
109
103
|
_idCoordsInLeg = null;
|
|
110
104
|
|
|
105
|
+
/**
|
|
106
|
+
* @param {Step} obj1
|
|
107
|
+
* @param {Step} obj2
|
|
108
|
+
* @returns {Boolean}
|
|
109
|
+
*/
|
|
110
|
+
static equalsTo(obj1, obj2) {
|
|
111
|
+
return obj1.firstStep === obj2.firstStep
|
|
112
|
+
&& obj1.lastStep === obj2.lastStep
|
|
113
|
+
&& obj1.number === obj2.number
|
|
114
|
+
&& obj1.coords.equalsTo(obj2.coords)
|
|
115
|
+
&& obj1.angle === obj2.angle
|
|
116
|
+
&& obj1.previousBearing === obj2.previousBearing
|
|
117
|
+
&& obj1.nextBearing === obj2.nextBearing
|
|
118
|
+
&& obj1.distance === obj2.distance
|
|
119
|
+
&& obj1.duration === obj2.duration
|
|
120
|
+
&& obj1.name === obj2.name
|
|
121
|
+
&& (
|
|
122
|
+
obj1.levelChange === obj2.levelChange
|
|
123
|
+
|| obj1.levelChange !== null && obj1.levelChange.equalsTo(obj2.levelChange)
|
|
124
|
+
)
|
|
125
|
+
&& (
|
|
126
|
+
obj1.extras === obj2.extras
|
|
127
|
+
|| (
|
|
128
|
+
obj1.extras !== null
|
|
129
|
+
&& obj1.extras.subwayEntrance === obj2.extras.subwayEntrance
|
|
130
|
+
&& obj1.extras.subwayEntranceRef === obj2.extras.subwayEntranceRef
|
|
131
|
+
)
|
|
132
|
+
)
|
|
133
|
+
&& obj1._idCoordsInLeg === obj2._idCoordsInLeg;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* @param {Step} obj
|
|
138
|
+
* @returns {Boolean}
|
|
139
|
+
*/
|
|
140
|
+
equalsTo(obj) {
|
|
141
|
+
return Step.equalsTo(this, obj);
|
|
142
|
+
}
|
|
143
|
+
|
|
111
144
|
/**
|
|
112
145
|
* @returns {object}
|
|
113
146
|
*/
|
|
@@ -155,31 +188,62 @@ class Step {
|
|
|
155
188
|
step.nextBearing = json.nextBearing;
|
|
156
189
|
step.distance = json.distance;
|
|
157
190
|
step._idCoordsInLeg = json._idCoordsInLeg;
|
|
158
|
-
if (json.firstStep) {
|
|
191
|
+
if (typeof json.firstStep === 'boolean') {
|
|
159
192
|
step.firstStep = json.firstStep;
|
|
160
193
|
}
|
|
161
|
-
if (json.lastStep) {
|
|
194
|
+
if (typeof json.lastStep === 'boolean') {
|
|
162
195
|
step.lastStep = json.lastStep;
|
|
163
196
|
}
|
|
164
|
-
if (json.duration) {
|
|
197
|
+
if (typeof json.duration === 'number') {
|
|
165
198
|
step.duration = json.duration;
|
|
166
199
|
}
|
|
167
|
-
if (json.name) {
|
|
200
|
+
if (typeof json.name === 'string') {
|
|
168
201
|
step.name = json.name;
|
|
169
202
|
}
|
|
170
|
-
if (json.levelChange) {
|
|
203
|
+
if (typeof json.levelChange === 'object') {
|
|
171
204
|
step.levelChange = LevelChange.fromJson(json.levelChange);
|
|
172
205
|
}
|
|
173
|
-
if (json.extras) {
|
|
206
|
+
if (typeof json.extras === 'object') {
|
|
174
207
|
step.extras = json.extras;
|
|
175
208
|
}
|
|
176
209
|
return step;
|
|
177
210
|
}
|
|
178
211
|
}
|
|
179
212
|
|
|
213
|
+
const Constants = {};
|
|
214
|
+
|
|
215
|
+
Constants.ROUTING_MODE = {
|
|
216
|
+
AIRPLANE: 'AIRPLANE',
|
|
217
|
+
BOAT: 'BOAT',
|
|
218
|
+
BIKE: 'BIKE',
|
|
219
|
+
BUS: 'BUS',
|
|
220
|
+
CAR: 'CAR',
|
|
221
|
+
FERRY: 'FERRY',
|
|
222
|
+
FUNICULAR: 'FUNICULAR',
|
|
223
|
+
METRO: 'METRO',
|
|
224
|
+
MOTO: 'MOTO',
|
|
225
|
+
TRAIN: 'TRAIN',
|
|
226
|
+
TAXI: 'TAXI',
|
|
227
|
+
TRAM: 'TRAM',
|
|
228
|
+
WALK: 'WALK',
|
|
229
|
+
MULTI: 'MULTI',
|
|
230
|
+
UNKNOWN: 'UNKNOWN'
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
Constants.PUBLIC_TRANSPORT = [
|
|
234
|
+
Constants.ROUTING_MODE.AIRPLANE,
|
|
235
|
+
Constants.ROUTING_MODE.BOAT,
|
|
236
|
+
Constants.ROUTING_MODE.BUS,
|
|
237
|
+
Constants.ROUTING_MODE.FERRY,
|
|
238
|
+
Constants.ROUTING_MODE.FUNICULAR,
|
|
239
|
+
Constants.ROUTING_MODE.METRO,
|
|
240
|
+
Constants.ROUTING_MODE.TRAIN,
|
|
241
|
+
Constants.ROUTING_MODE.TRAM
|
|
242
|
+
];
|
|
243
|
+
|
|
180
244
|
class Leg {
|
|
181
245
|
|
|
182
|
-
/** @type {!string} can be
|
|
246
|
+
/** @type {!string} can be values in Constants.ROUTING_MODE */
|
|
183
247
|
mode;
|
|
184
248
|
|
|
185
249
|
/** @type {!number} */
|
|
@@ -209,6 +273,10 @@ class Leg {
|
|
|
209
273
|
/** @type {?(Step[])} */
|
|
210
274
|
steps = null;
|
|
211
275
|
|
|
276
|
+
isPublicTransport() {
|
|
277
|
+
return Constants.PUBLIC_TRANSPORT.includes(this.mode);
|
|
278
|
+
}
|
|
279
|
+
|
|
212
280
|
/**
|
|
213
281
|
* @returns {Network}
|
|
214
282
|
*/
|
|
@@ -216,6 +284,72 @@ class Leg {
|
|
|
216
284
|
return Network.fromCoordinates([this.coords]);
|
|
217
285
|
}
|
|
218
286
|
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* @param {Leg} obj1
|
|
290
|
+
* @param {Leg} obj2
|
|
291
|
+
* @returns {Boolean}
|
|
292
|
+
*/
|
|
293
|
+
// eslint-disable-next-line complexity
|
|
294
|
+
static equalsTo(obj1, obj2) {
|
|
295
|
+
const intermediate = obj1.mode === obj2.mode
|
|
296
|
+
&& obj1.distance === obj2.distance
|
|
297
|
+
&& obj1.duration === obj2.duration
|
|
298
|
+
&& obj1.startTime === obj2.startTime
|
|
299
|
+
&& obj1.endTime === obj2.endTime
|
|
300
|
+
&& obj1.from.name === obj2.from.name
|
|
301
|
+
&& obj1.from.coords.equalsTo(obj2.from.coords)
|
|
302
|
+
&& obj1.to.name === obj2.to.name
|
|
303
|
+
&& obj1.to.coords.equalsTo(obj2.to.coords)
|
|
304
|
+
&& obj1.coords.length === obj2.coords.length
|
|
305
|
+
&& (
|
|
306
|
+
obj1.steps === obj2.steps
|
|
307
|
+
|| obj1.steps.length === obj2.steps.length
|
|
308
|
+
);
|
|
309
|
+
|
|
310
|
+
if (!intermediate) {
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
let i;
|
|
315
|
+
for (i = 0; i < obj1.coords.length; i++) {
|
|
316
|
+
if (!obj1.coords[i].equalsTo(obj2.coords[i])) {
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
if (obj1.steps) {
|
|
321
|
+
for (i = 0; i < obj1.steps.length; i++) {
|
|
322
|
+
if (!obj1.steps[i].equalsTo(obj2.steps[i])) {
|
|
323
|
+
return false;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (obj1.transportInfo !== obj2.transportInfo) {
|
|
329
|
+
if (obj1.transportInfo === null) {
|
|
330
|
+
return false;
|
|
331
|
+
}
|
|
332
|
+
if (
|
|
333
|
+
obj1.transportInfo.name !== obj2.transportInfo.name
|
|
334
|
+
|| obj1.transportInfo.routeColor !== obj2.transportInfo.routeColor
|
|
335
|
+
|| obj1.transportInfo.routeTextColor !== obj2.transportInfo.routeTextColor
|
|
336
|
+
|| obj1.transportInfo.directionName !== obj2.transportInfo.directionName
|
|
337
|
+
) {
|
|
338
|
+
return false;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
return true;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* @param {Leg} obj
|
|
347
|
+
* @returns {Boolean}
|
|
348
|
+
*/
|
|
349
|
+
equalsTo(obj) {
|
|
350
|
+
return Leg.equalsTo(this, obj);
|
|
351
|
+
}
|
|
352
|
+
|
|
219
353
|
/**
|
|
220
354
|
* @returns {object}
|
|
221
355
|
*/
|
|
@@ -228,18 +362,18 @@ class Leg {
|
|
|
228
362
|
duration: this.duration,
|
|
229
363
|
coords: this.coords.map(coords => coords.toCompressedJson())
|
|
230
364
|
};
|
|
231
|
-
if (this.from.name) {
|
|
232
|
-
output.from.name = this.from.name;
|
|
233
|
-
}
|
|
234
|
-
if (this.to.name) {
|
|
235
|
-
output.to.name = this.to.name;
|
|
236
|
-
}
|
|
237
365
|
if (this.startTime !== null) {
|
|
238
366
|
output.startTime = this.startTime;
|
|
239
367
|
}
|
|
240
368
|
if (this.endTime !== null) {
|
|
241
369
|
output.endTime = this.endTime;
|
|
242
370
|
}
|
|
371
|
+
if (this.from.name !== null) {
|
|
372
|
+
output.from.name = this.from.name;
|
|
373
|
+
}
|
|
374
|
+
if (this.to.name !== null) {
|
|
375
|
+
output.to.name = this.to.name;
|
|
376
|
+
}
|
|
243
377
|
if (this.transportInfo !== null) {
|
|
244
378
|
output.transportInfo = this.transportInfo;
|
|
245
379
|
}
|
|
@@ -257,27 +391,31 @@ class Leg {
|
|
|
257
391
|
static fromJson(json) {
|
|
258
392
|
const leg = new Leg();
|
|
259
393
|
leg.mode = json.mode;
|
|
260
|
-
leg.from = { coords: Coordinates.fromCompressedJson(json.from.coords) };
|
|
261
|
-
leg.to = { coords: Coordinates.fromCompressedJson(json.to.coords) };
|
|
262
394
|
leg.distance = json.distance;
|
|
263
395
|
leg.duration = json.duration;
|
|
264
|
-
|
|
265
|
-
if (json.
|
|
266
|
-
leg.from.name = json.from.name;
|
|
267
|
-
}
|
|
268
|
-
if (json.to.name) {
|
|
269
|
-
leg.to.name = json.to.name;
|
|
270
|
-
}
|
|
271
|
-
if (json.startTime) {
|
|
396
|
+
|
|
397
|
+
if (typeof json.startTime === 'number') {
|
|
272
398
|
leg.startTime = json.startTime;
|
|
273
399
|
}
|
|
274
|
-
if (json.endTime) {
|
|
400
|
+
if (typeof json.endTime === 'number') {
|
|
275
401
|
leg.endTime = json.endTime;
|
|
276
402
|
}
|
|
277
|
-
|
|
403
|
+
|
|
404
|
+
leg.from = {
|
|
405
|
+
coords: Coordinates.fromCompressedJson(json.from.coords),
|
|
406
|
+
name: typeof json.from.name === 'string' ? json.from.name : null
|
|
407
|
+
};
|
|
408
|
+
leg.to = {
|
|
409
|
+
coords: Coordinates.fromCompressedJson(json.to.coords),
|
|
410
|
+
name: typeof json.to.name === 'string' ? json.to.name : null
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
leg.coords = json.coords.map(Coordinates.fromCompressedJson);
|
|
414
|
+
|
|
415
|
+
if (typeof json.transportInfo === 'object') {
|
|
278
416
|
leg.transportInfo = json.transportInfo;
|
|
279
417
|
}
|
|
280
|
-
if (json.steps) {
|
|
418
|
+
if (typeof json.steps === 'object') {
|
|
281
419
|
leg.steps = json.steps.map(Step.fromJson);
|
|
282
420
|
}
|
|
283
421
|
return leg;
|
|
@@ -294,58 +432,6 @@ function getDurationFromLength(length, speed = 5) {
|
|
|
294
432
|
return length / (speed * 1000 / 3600);
|
|
295
433
|
}
|
|
296
434
|
|
|
297
|
-
|
|
298
|
-
/**
|
|
299
|
-
* @param {Itinerary} itinerary
|
|
300
|
-
*/
|
|
301
|
-
function generateStepsMetadata(itinerary) {
|
|
302
|
-
|
|
303
|
-
let counter = 1;
|
|
304
|
-
|
|
305
|
-
itinerary.legs.forEach((leg, legId) => {
|
|
306
|
-
leg.steps.forEach((step, stepId) => {
|
|
307
|
-
|
|
308
|
-
if (counter === 1) {
|
|
309
|
-
step.firstStep = true;
|
|
310
|
-
}
|
|
311
|
-
if (legId === itinerary.legs.length - 1
|
|
312
|
-
&& stepId === leg.steps.length - 1) {
|
|
313
|
-
step.lastStep = true;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
step.number = counter++;
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
/*
|
|
320
|
-
* Generate previousBearing, nextBearing and angle
|
|
321
|
-
*/
|
|
322
|
-
|
|
323
|
-
let coordsBeforeStep;
|
|
324
|
-
if (step._idCoordsInLeg > 0) {
|
|
325
|
-
coordsBeforeStep = leg.coords[step._idCoordsInLeg - 1];
|
|
326
|
-
} else if (legId === 0) {
|
|
327
|
-
coordsBeforeStep = itinerary.from;
|
|
328
|
-
} else {
|
|
329
|
-
coordsBeforeStep = itinerary.legs[legId - 1].to.coords;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
let coordsAfterStep;
|
|
333
|
-
if (step._idCoordsInLeg !== leg.coords.length - 1) {
|
|
334
|
-
coordsAfterStep = leg.coords[step._idCoordsInLeg + 1];
|
|
335
|
-
} else if (legId === itinerary.legs.length - 1) {
|
|
336
|
-
coordsAfterStep = itinerary.to;
|
|
337
|
-
} else {
|
|
338
|
-
coordsAfterStep = itinerary.legs[legId + 1].from.coords;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
step.previousBearing = coordsBeforeStep.bearingTo(step.coords);
|
|
342
|
-
step.nextBearing = step.coords.bearingTo(coordsAfterStep);
|
|
343
|
-
step.angle = diffAngle(step.previousBearing, step.nextBearing + Math.PI);
|
|
344
|
-
|
|
345
|
-
});
|
|
346
|
-
});
|
|
347
|
-
}
|
|
348
|
-
|
|
349
435
|
/* eslint-disable max-statements */
|
|
350
436
|
|
|
351
437
|
/**
|
|
@@ -417,14 +503,14 @@ class Itinerary {
|
|
|
417
503
|
|
|
418
504
|
get mode() {
|
|
419
505
|
if (!this._mode) {
|
|
420
|
-
let isPublicTransport;
|
|
421
|
-
let isBicycle;
|
|
422
|
-
let isDriving;
|
|
506
|
+
let isPublicTransport = false;
|
|
507
|
+
let isBicycle = false;
|
|
508
|
+
let isDriving = false;
|
|
423
509
|
|
|
424
510
|
this.legs.forEach((leg) => {
|
|
425
|
-
isPublicTransport = isPublicTransport ||
|
|
426
|
-
isBicycle = isBicycle ||
|
|
427
|
-
isDriving = isDriving || leg.mode ===
|
|
511
|
+
isPublicTransport = isPublicTransport || Constants.PUBLIC_TRANSPORT.includes(leg.mode);
|
|
512
|
+
isBicycle = isBicycle || leg.mode === Constants.ROUTING_MODE.BIKE;
|
|
513
|
+
isDriving = isDriving || leg.mode === Constants.ROUTING_MODE.CAR;
|
|
428
514
|
});
|
|
429
515
|
|
|
430
516
|
if (isPublicTransport) {
|
|
@@ -532,6 +618,42 @@ class Itinerary {
|
|
|
532
618
|
return itinerary;
|
|
533
619
|
}
|
|
534
620
|
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* @param {Itinerary} obj1
|
|
624
|
+
* @param {Itinerary} obj2
|
|
625
|
+
* @returns {Boolean}
|
|
626
|
+
*/
|
|
627
|
+
static equalsTo(obj1, obj2) {
|
|
628
|
+
const intermediate = obj1.from.equalsTo(obj2.from)
|
|
629
|
+
&& obj1.to.equalsTo(obj2.to)
|
|
630
|
+
&& obj1.distance === obj2.distance
|
|
631
|
+
&& obj1.duration === obj2.duration
|
|
632
|
+
&& obj1.startTime === obj2.startTime
|
|
633
|
+
&& obj1.endTime === obj2.endTime
|
|
634
|
+
&& obj1.legs.length === obj2.legs.length;
|
|
635
|
+
|
|
636
|
+
if (!intermediate) {
|
|
637
|
+
return false;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
for (let i = 0; i < obj1.legs.length; i++) {
|
|
641
|
+
if (!obj1.legs[i].equalsTo(obj2.legs[i])) {
|
|
642
|
+
return false;
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
return true;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* @param {Itinerary} obj
|
|
651
|
+
* @returns {Boolean}
|
|
652
|
+
*/
|
|
653
|
+
equalsTo(obj) {
|
|
654
|
+
return Itinerary.equalsTo(this, obj);
|
|
655
|
+
}
|
|
656
|
+
|
|
535
657
|
/**
|
|
536
658
|
* @returns {object}
|
|
537
659
|
*/
|
|
@@ -564,10 +686,10 @@ class Itinerary {
|
|
|
564
686
|
itinerary.distance = json.distance;
|
|
565
687
|
itinerary.duration = json.duration;
|
|
566
688
|
itinerary.legs = json.legs.map(Leg.fromJson);
|
|
567
|
-
if (json.startTime) {
|
|
689
|
+
if (typeof json.startTime === 'number') {
|
|
568
690
|
itinerary.startTime = json.startTime;
|
|
569
691
|
}
|
|
570
|
-
if (json.endTime) {
|
|
692
|
+
if (typeof json.endTime === 'number') {
|
|
571
693
|
itinerary.endTime = json.endTime;
|
|
572
694
|
}
|
|
573
695
|
return itinerary;
|
|
@@ -576,7 +698,7 @@ class Itinerary {
|
|
|
576
698
|
|
|
577
699
|
class RouterResponse {
|
|
578
700
|
|
|
579
|
-
/** @type {!string} */
|
|
701
|
+
/** @type {!string|Array<string>} */
|
|
580
702
|
routerName;
|
|
581
703
|
|
|
582
704
|
/** @type {!Coordinates} */
|
|
@@ -587,6 +709,64 @@ class RouterResponse {
|
|
|
587
709
|
|
|
588
710
|
/** @type {!(Itinerary[])} */
|
|
589
711
|
itineraries = [];
|
|
712
|
+
|
|
713
|
+
/**
|
|
714
|
+
* @param {RouterResponse} obj1
|
|
715
|
+
* @param {RouterResponse} obj2
|
|
716
|
+
* @returns {Boolean}
|
|
717
|
+
*/
|
|
718
|
+
static equalsTo(obj1, obj2) {
|
|
719
|
+
const intermediate = obj1.routerName === obj2.routerName
|
|
720
|
+
&& obj1.from.equalsTo(obj2.from)
|
|
721
|
+
&& obj1.to.equalsTo(obj2.to)
|
|
722
|
+
&& obj1.itineraries.length === obj2.itineraries.length;
|
|
723
|
+
|
|
724
|
+
if (!intermediate) {
|
|
725
|
+
return false;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
for (let i = 0; i < obj1.itineraries.length; i++) {
|
|
729
|
+
if (!obj1.itineraries[i].equalsTo(obj2.itineraries[i])) {
|
|
730
|
+
return false;
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
return true;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
/**
|
|
738
|
+
* @param {RouterResponse} obj
|
|
739
|
+
* @returns {Boolean}
|
|
740
|
+
*/
|
|
741
|
+
equalsTo(obj) {
|
|
742
|
+
return RouterResponse.equalsTo(this, obj);
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
* @returns {object}
|
|
748
|
+
*/
|
|
749
|
+
toJson() {
|
|
750
|
+
return {
|
|
751
|
+
routerName: this.routerName,
|
|
752
|
+
from: this.from.toCompressedJson(),
|
|
753
|
+
to: this.to.toCompressedJson(),
|
|
754
|
+
itineraries: this.itineraries.map(itinerary => itinerary.toJson())
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
/**
|
|
759
|
+
* @param {object} json
|
|
760
|
+
* @returns {RouterResponse}
|
|
761
|
+
*/
|
|
762
|
+
static fromJson(json) {
|
|
763
|
+
const routerResponse = new RouterResponse();
|
|
764
|
+
routerResponse.routerName = json.routerName;
|
|
765
|
+
routerResponse.from = Coordinates.fromCompressedJson(json.from);
|
|
766
|
+
routerResponse.to = Coordinates.fromCompressedJson(json.to);
|
|
767
|
+
routerResponse.itineraries = json.itineraries.map(Itinerary.fromJson);
|
|
768
|
+
return routerResponse;
|
|
769
|
+
}
|
|
590
770
|
}
|
|
591
771
|
|
|
592
772
|
class ItineraryInfo {
|
|
@@ -654,6 +834,12 @@ class WemapRouter extends GraphRouter {
|
|
|
654
834
|
super(network);
|
|
655
835
|
}
|
|
656
836
|
|
|
837
|
+
|
|
838
|
+
/** @type {string} */
|
|
839
|
+
static get rname() {
|
|
840
|
+
return 'wemap';
|
|
841
|
+
}
|
|
842
|
+
|
|
657
843
|
/**
|
|
658
844
|
* @param {Coordinates} start
|
|
659
845
|
* @param {Coordinates} end
|
|
@@ -730,7 +916,7 @@ class WemapStepsGeneration {
|
|
|
730
916
|
}
|
|
731
917
|
|
|
732
918
|
if (splitByLevel) {
|
|
733
|
-
currentStep.levelChange =
|
|
919
|
+
currentStep.levelChange = WemapStepsGeneration.levelChangefromTwoNodes(node, nextNode);
|
|
734
920
|
}
|
|
735
921
|
|
|
736
922
|
steps.push(currentStep);
|
|
@@ -746,21 +932,48 @@ class WemapStepsGeneration {
|
|
|
746
932
|
}
|
|
747
933
|
|
|
748
934
|
const lastNode = nodes[nodes.length - 1];
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
lastStep.number = steps.length + 1;
|
|
752
|
-
lastStep.previousBearing = previousBearing;
|
|
753
|
-
lastStep.distance = lastNode.coords.distanceTo(end);
|
|
935
|
+
|
|
936
|
+
// Create a last step if end is not on the network
|
|
754
937
|
if (!Coordinates.equalsTo(lastNode.coords, end)) {
|
|
938
|
+
const lastStep = new Step();
|
|
939
|
+
lastStep.coords = lastNode.coords;
|
|
940
|
+
lastStep.number = steps.length + 1;
|
|
941
|
+
lastStep.previousBearing = previousBearing;
|
|
942
|
+
lastStep.distance = lastNode.coords.distanceTo(end);
|
|
755
943
|
lastStep.nextBearing = lastNode.coords.bearingTo(end);
|
|
756
944
|
lastStep.angle = diffAngle(lastStep.previousBearing, lastStep.nextBearing + Math.PI);
|
|
945
|
+
steps.push(lastStep);
|
|
757
946
|
}
|
|
758
|
-
|
|
759
|
-
steps.
|
|
947
|
+
|
|
948
|
+
steps[steps.length - 1].lastStep = true;
|
|
760
949
|
|
|
761
950
|
return steps;
|
|
762
951
|
}
|
|
763
952
|
|
|
953
|
+
/**
|
|
954
|
+
* @param {GraphNode<OsmElement>} firstNode
|
|
955
|
+
* @param {GraphNode<OsmElement>} secondNode
|
|
956
|
+
* @returns {LevelChange}
|
|
957
|
+
*/
|
|
958
|
+
static levelChangefromTwoNodes(firstNode, secondNode) {
|
|
959
|
+
|
|
960
|
+
const levelChange = new LevelChange();
|
|
961
|
+
|
|
962
|
+
const edge = GraphUtils.getEdgeByNodes(firstNode.edges, firstNode, secondNode);
|
|
963
|
+
|
|
964
|
+
if (edge.builtFrom.isElevator) {
|
|
965
|
+
levelChange.type = 'elevator';
|
|
966
|
+
} else if (edge.builtFrom.isConveying) {
|
|
967
|
+
levelChange.type = 'conveyor';
|
|
968
|
+
} else if (edge.builtFrom.areStairs) {
|
|
969
|
+
levelChange.type = 'stairs';
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
levelChange.difference = Level.diff(firstNode.coords.level, secondNode.coords.level);
|
|
973
|
+
levelChange.direction = levelChange.difference > 0 ? 'up' : 'down';
|
|
974
|
+
|
|
975
|
+
return levelChange;
|
|
976
|
+
}
|
|
764
977
|
}
|
|
765
978
|
|
|
766
979
|
/**
|
|
@@ -768,17 +981,21 @@ class WemapStepsGeneration {
|
|
|
768
981
|
* @param {string} mode
|
|
769
982
|
* @returns {Leg}
|
|
770
983
|
*/
|
|
771
|
-
function createLegFromGraphItinerary(graphItinerary,
|
|
984
|
+
function createLegFromGraphItinerary(graphItinerary,
|
|
985
|
+
mode = Constants.ROUTING_MODE.WALK) {
|
|
772
986
|
|
|
773
987
|
const leg = new Leg();
|
|
774
988
|
|
|
775
|
-
leg.from = { coords: graphItinerary.start };
|
|
776
|
-
leg.to = { coords: graphItinerary.end };
|
|
989
|
+
leg.from = { coords: graphItinerary.start, name: null };
|
|
990
|
+
leg.to = { coords: graphItinerary.end, name: null };
|
|
777
991
|
leg.coords = graphItinerary.nodes.map(node => node.coords);
|
|
778
992
|
leg.distance = graphItinerary.edges.reduce((acc, edge) => acc + edge.length, 0);
|
|
779
993
|
leg.duration = graphItinerary.edgesWeights.reduce((acc, weight) => acc + weight, 0);
|
|
780
994
|
leg.mode = mode;
|
|
781
995
|
leg.steps = WemapStepsGeneration.fromGraphItinerary(graphItinerary);
|
|
996
|
+
leg.steps.forEach(step => {
|
|
997
|
+
step._idCoordsInLeg = leg.coords.findIndex(coords => coords === step.coords);
|
|
998
|
+
});
|
|
782
999
|
|
|
783
1000
|
return leg;
|
|
784
1001
|
}
|
|
@@ -788,7 +1005,8 @@ function createLegFromGraphItinerary(graphItinerary, mode = 'WALK') {
|
|
|
788
1005
|
* @param {string} mode
|
|
789
1006
|
* @returns {Itinerary}
|
|
790
1007
|
*/
|
|
791
|
-
function createItineraryFromGraphItinerary(graphItinerary,
|
|
1008
|
+
function createItineraryFromGraphItinerary(graphItinerary,
|
|
1009
|
+
mode = Constants.ROUTING_MODE.WALK) {
|
|
792
1010
|
|
|
793
1011
|
const leg = createLegFromGraphItinerary(graphItinerary, mode);
|
|
794
1012
|
|
|
@@ -1010,745 +1228,1643 @@ var WemapNetworkUtils = /*#__PURE__*/Object.freeze({
|
|
|
1010
1228
|
createNetworkFromOsmModel: createNetworkFromOsmModel
|
|
1011
1229
|
});
|
|
1012
1230
|
|
|
1013
|
-
/* eslint-disable max-statements */
|
|
1014
|
-
|
|
1015
1231
|
/**
|
|
1016
|
-
* @param {
|
|
1017
|
-
* @returns {object}
|
|
1232
|
+
* @param {Itinerary} itinerary
|
|
1018
1233
|
*/
|
|
1019
|
-
function
|
|
1020
|
-
const output = [coordinates.lng, coordinates.lat];
|
|
1021
|
-
if (coordinates.level) {
|
|
1022
|
-
output.push(coordinates.level.toString());
|
|
1023
|
-
}
|
|
1024
|
-
return output;
|
|
1025
|
-
}
|
|
1234
|
+
function generateStepsMetadata(itinerary) {
|
|
1026
1235
|
|
|
1027
|
-
|
|
1028
|
-
* @param {object} json
|
|
1029
|
-
* @returns {Coordinates}
|
|
1030
|
-
*/
|
|
1031
|
-
function jsonToCoordinates$2(json) {
|
|
1032
|
-
const output = new Coordinates(json[1], json[0]);
|
|
1033
|
-
if (json.length > 2) {
|
|
1034
|
-
output.level = Level.fromString(json[2]);
|
|
1035
|
-
}
|
|
1036
|
-
return output;
|
|
1037
|
-
}
|
|
1236
|
+
let counter = 1;
|
|
1038
1237
|
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
}
|
|
1238
|
+
itinerary.legs.forEach((leg, legId) => {
|
|
1239
|
+
leg.steps.forEach((step, stepId) => {
|
|
1042
1240
|
|
|
1241
|
+
if (counter === 1) {
|
|
1242
|
+
step.firstStep = true;
|
|
1243
|
+
}
|
|
1244
|
+
if (legId === itinerary.legs.length - 1
|
|
1245
|
+
&& stepId === leg.steps.length - 1) {
|
|
1246
|
+
step.lastStep = true;
|
|
1247
|
+
}
|
|
1043
1248
|
|
|
1044
|
-
|
|
1249
|
+
step.number = counter++;
|
|
1045
1250
|
|
|
1046
|
-
const angle = positiveMod(rad2deg(_angle), 360);
|
|
1047
1251
|
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
if (angle >= 60 && angle < 140) {
|
|
1052
|
-
return 'right';
|
|
1053
|
-
}
|
|
1054
|
-
if (angle >= 140 && angle < 160) {
|
|
1055
|
-
return 'slight right';
|
|
1056
|
-
}
|
|
1057
|
-
if (angle >= 160 && angle <= 200) {
|
|
1058
|
-
return 'straight';
|
|
1059
|
-
}
|
|
1060
|
-
if (angle > 200 && angle <= 220) {
|
|
1061
|
-
return 'slight left';
|
|
1062
|
-
}
|
|
1063
|
-
if (angle > 220 && angle <= 300) {
|
|
1064
|
-
return 'left';
|
|
1065
|
-
}
|
|
1066
|
-
if (angle > 300 && angle < 360) {
|
|
1067
|
-
return 'sharp left';
|
|
1068
|
-
}
|
|
1069
|
-
return 'u turn';
|
|
1070
|
-
}
|
|
1252
|
+
/*
|
|
1253
|
+
* Generate previousBearing, nextBearing and angle
|
|
1254
|
+
*/
|
|
1071
1255
|
|
|
1256
|
+
let coordsBeforeStep;
|
|
1257
|
+
if (step._idCoordsInLeg > 0) {
|
|
1258
|
+
coordsBeforeStep = leg.coords[step._idCoordsInLeg - 1];
|
|
1259
|
+
} else if (legId === 0) {
|
|
1260
|
+
coordsBeforeStep = itinerary.from;
|
|
1261
|
+
} else {
|
|
1262
|
+
coordsBeforeStep = itinerary.legs[legId - 1].to.coords;
|
|
1263
|
+
}
|
|
1072
1264
|
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
}
|
|
1265
|
+
let coordsAfterStep;
|
|
1266
|
+
if (step._idCoordsInLeg !== leg.coords.length - 1) {
|
|
1267
|
+
coordsAfterStep = leg.coords[step._idCoordsInLeg + 1];
|
|
1268
|
+
} else if (legId === itinerary.legs.length - 1) {
|
|
1269
|
+
coordsAfterStep = itinerary.to;
|
|
1270
|
+
} else {
|
|
1271
|
+
coordsAfterStep = itinerary.legs[legId + 1].from.coords;
|
|
1272
|
+
}
|
|
1079
1273
|
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1274
|
+
step.previousBearing = coordsBeforeStep.bearingTo(step.coords);
|
|
1275
|
+
step.nextBearing = step.coords.bearingTo(coordsAfterStep);
|
|
1276
|
+
step.angle = diffAngle(step.previousBearing, step.nextBearing + Math.PI);
|
|
1277
|
+
|
|
1278
|
+
});
|
|
1279
|
+
});
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
|
|
1283
|
+
/**
|
|
1284
|
+
* Create and return a date with a given timezone
|
|
1285
|
+
* @param {number} year
|
|
1286
|
+
* @param {number} month
|
|
1287
|
+
* @param {number} day
|
|
1288
|
+
* @param {number} hours
|
|
1289
|
+
* @param {number} minutes
|
|
1290
|
+
* @param {number} seconds
|
|
1291
|
+
* @param {string} timeZone - timezone name (e.g. 'Europe/Paris')
|
|
1083
1292
|
*/
|
|
1084
|
-
function
|
|
1293
|
+
function dateWithTimeZone(year, month, day, hour, minute, second, timeZone = 'Europe/Paris') {
|
|
1294
|
+
const date = new Date(Date.UTC(year, month, day, hour, minute, second));
|
|
1295
|
+
|
|
1296
|
+
const utcDate = new Date(date.toLocaleString('en-US', { timeZone: 'UTC' }));
|
|
1297
|
+
const tzDate = new Date(date.toLocaleString('en-US', { timeZone: timeZone }));
|
|
1298
|
+
const offset = utcDate.getTime() - tzDate.getTime();
|
|
1299
|
+
|
|
1300
|
+
date.setTime(date.getTime() + offset);
|
|
1301
|
+
|
|
1302
|
+
return date;
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
const stringify = (data) => {
|
|
1306
|
+
return Object.keys(data).map(key => {
|
|
1307
|
+
return `${key}=${data[key]}`;
|
|
1308
|
+
});
|
|
1309
|
+
};
|
|
1310
|
+
|
|
1311
|
+
|
|
1312
|
+
const request = async (url, options = {}) => {
|
|
1313
|
+
const responseType = options.responseType || 'json';
|
|
1314
|
+
|
|
1315
|
+
const fetchOptions = {
|
|
1316
|
+
method: options.method || 'GET',
|
|
1317
|
+
headers: {}
|
|
1318
|
+
// headers: new Headers(options.headers || {})
|
|
1319
|
+
};
|
|
1320
|
+
|
|
1321
|
+
if (options.hasOwnProperty('json')) {
|
|
1322
|
+
fetchOptions.headers.append('Content-Type', 'application/json');
|
|
1323
|
+
fetchOptions.body = JSON.stringify(options.json);
|
|
1324
|
+
} else if (options.hasOwnProperty('data')) {
|
|
1325
|
+
fetchOptions.headers.append('Content-Type', 'application/x-www-form-urlencoded;charset=UTF-8');
|
|
1326
|
+
fetchOptions.body = options.data instanceof URLSearchParams ? options.data : stringify(options.data);
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
return fetch(url, fetchOptions).then(response => {
|
|
1330
|
+
if (responseType === 'arraybuffer') {
|
|
1331
|
+
Logger.ok('Request succeeded for: ' + url);
|
|
1332
|
+
return response.arrayBuffer();
|
|
1333
|
+
} else if (responseType === 'json') {
|
|
1334
|
+
return response.json().then((json) => {
|
|
1335
|
+
Logger.ok('Request succeeded for: ' + url);
|
|
1336
|
+
return json;
|
|
1337
|
+
}).catch(() => {
|
|
1338
|
+
Logger.error('Request failed for: ' + url);
|
|
1339
|
+
throw Error('Request failed for: ' + url);
|
|
1340
|
+
});
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
return null;
|
|
1344
|
+
});
|
|
1345
|
+
};
|
|
1346
|
+
|
|
1347
|
+
class RemoteRouterOptions {
|
|
1348
|
+
|
|
1349
|
+
/** @type {boolean} */
|
|
1350
|
+
useStairs = true;
|
|
1351
|
+
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
class RemoteRouter {
|
|
1355
|
+
|
|
1356
|
+
/**
|
|
1357
|
+
* Get the router name
|
|
1358
|
+
* @type {string} the router name
|
|
1359
|
+
*/
|
|
1360
|
+
get rname() {
|
|
1361
|
+
return 'Unknown';
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
/**
|
|
1365
|
+
* @abstract
|
|
1366
|
+
* @param {string} endpointUrl
|
|
1367
|
+
* @param {string} mode see Constants.ITINERARY_MODE
|
|
1368
|
+
* @param {Array<Coordinates>} waypoints
|
|
1369
|
+
* @param {RemoteRouterOptions} options
|
|
1370
|
+
* @returns {!RouterResponse}
|
|
1371
|
+
*/
|
|
1372
|
+
// eslint-disable-next-line no-unused-vars
|
|
1373
|
+
async getItineraries(endpointUrl, mode, waypoints, options = new RemoteRouterOptions()) {
|
|
1374
|
+
throw new Error('RemoteRouter "' + this.rname + '" does not @override getItineraries()');
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
class OsrmRoutingModeCorrespondanceNotFound extends Error {
|
|
1380
|
+
|
|
1381
|
+
/**
|
|
1382
|
+
* @param {!string} routingMode
|
|
1383
|
+
*/
|
|
1384
|
+
constructor(routingMode) {
|
|
1385
|
+
super(`OSRM routing mode correspondance not found: ${routingMode}`);
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
/* eslint-disable max-statements */
|
|
1390
|
+
|
|
1391
|
+
/**
|
|
1392
|
+
* Input mode correspondance
|
|
1393
|
+
*/
|
|
1394
|
+
const inputModeCorrespondance$2 = new Map();
|
|
1395
|
+
inputModeCorrespondance$2.set(Constants.ROUTING_MODE.CAR, 'driving');
|
|
1396
|
+
inputModeCorrespondance$2.set(Constants.ROUTING_MODE.WALK, 'walking');
|
|
1397
|
+
inputModeCorrespondance$2.set(Constants.ROUTING_MODE.BIKE, 'bike');
|
|
1398
|
+
inputModeCorrespondance$2.set(Constants.ROUTING_MODE.BUS, 'bus');
|
|
1399
|
+
inputModeCorrespondance$2.set(Constants.ROUTING_MODE.MULTI, 'walking');
|
|
1400
|
+
|
|
1401
|
+
|
|
1402
|
+
/**
|
|
1403
|
+
* Singleton.
|
|
1404
|
+
*/
|
|
1405
|
+
class OsrmRemoteRouter extends RemoteRouter {
|
|
1406
|
+
|
|
1407
|
+
/**
|
|
1408
|
+
* @override
|
|
1409
|
+
*/
|
|
1410
|
+
get rname() {
|
|
1411
|
+
return 'osrm';
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
/**
|
|
1415
|
+
* @override
|
|
1416
|
+
*/
|
|
1417
|
+
async getItineraries(endpointUrl, mode, waypoints) {
|
|
1418
|
+
const url = this.getURL(endpointUrl, mode, waypoints);
|
|
1419
|
+
const response = await request(url);
|
|
1420
|
+
return this.createRouterResponseFromJson(response, waypoints[0], waypoints[1]);
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
/**
|
|
1424
|
+
* @param {string} endpointUrl
|
|
1425
|
+
* @param {string} mode
|
|
1426
|
+
* @param {Array<Coordinates>} waypoints
|
|
1427
|
+
*/
|
|
1428
|
+
getURL(endpointUrl, mode, waypoints) {
|
|
1429
|
+
|
|
1430
|
+
const osrmMode = inputModeCorrespondance$2.get(mode);
|
|
1431
|
+
if (!osrmMode) {
|
|
1432
|
+
throw new OsrmRoutingModeCorrespondanceNotFound(mode);
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
let url = endpointUrl + '/route/v1/' + osrmMode + '/';
|
|
1436
|
+
url += waypoints.map(waypoint => [waypoint.longitude + ',' + waypoint.latitude]).join(';');
|
|
1437
|
+
url += '?geometries=geojson&overview=full&steps=true';
|
|
1438
|
+
|
|
1439
|
+
return url;
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
/**
|
|
1443
|
+
* @param {Coordinates} coordinates
|
|
1444
|
+
* @returns {object}
|
|
1445
|
+
*/
|
|
1446
|
+
coordinatesToJson(coordinates) {
|
|
1447
|
+
const output = [coordinates.lng, coordinates.lat];
|
|
1448
|
+
if (coordinates.level) {
|
|
1449
|
+
output.push(coordinates.level.toString());
|
|
1450
|
+
}
|
|
1451
|
+
return output;
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
/**
|
|
1455
|
+
* @param {object} json
|
|
1456
|
+
* @returns {Coordinates}
|
|
1457
|
+
*/
|
|
1458
|
+
jsonToCoordinates(json) {
|
|
1459
|
+
const output = new Coordinates(json[1], json[0]);
|
|
1460
|
+
if (json.length > 2) {
|
|
1461
|
+
output.level = Level.fromString(json[2]);
|
|
1462
|
+
}
|
|
1463
|
+
return output;
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
nodesToJsonCoords(nodes) {
|
|
1467
|
+
return nodes.map(node => this.coordinatesToJson(node.coords));
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
|
|
1471
|
+
getModifierFromAngle(_angle) {
|
|
1472
|
+
|
|
1473
|
+
const angle = positiveMod(rad2deg(_angle), 360);
|
|
1474
|
+
|
|
1475
|
+
if (angle > 0 && angle < 60) {
|
|
1476
|
+
return 'sharp right';
|
|
1477
|
+
}
|
|
1478
|
+
if (angle >= 60 && angle < 140) {
|
|
1479
|
+
return 'right';
|
|
1480
|
+
}
|
|
1481
|
+
if (angle >= 140 && angle < 160) {
|
|
1482
|
+
return 'slight right';
|
|
1483
|
+
}
|
|
1484
|
+
if (angle >= 160 && angle <= 200) {
|
|
1485
|
+
return 'straight';
|
|
1486
|
+
}
|
|
1487
|
+
if (angle > 200 && angle <= 220) {
|
|
1488
|
+
return 'slight left';
|
|
1489
|
+
}
|
|
1490
|
+
if (angle > 220 && angle <= 300) {
|
|
1491
|
+
return 'left';
|
|
1492
|
+
}
|
|
1493
|
+
if (angle > 300 && angle < 360) {
|
|
1494
|
+
return 'sharp left';
|
|
1495
|
+
}
|
|
1496
|
+
return 'u turn';
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
|
|
1500
|
+
noRouteFoundJson(message) {
|
|
1501
|
+
return {
|
|
1502
|
+
'code': 'NoRoute',
|
|
1503
|
+
message
|
|
1504
|
+
};
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
/**
|
|
1508
|
+
* @param {Itinerary} itinerary
|
|
1509
|
+
* @returns {object}
|
|
1510
|
+
*/
|
|
1511
|
+
itineraryToOsrmJson(itinerary) {
|
|
1512
|
+
|
|
1513
|
+
const lastLegId = itinerary.legs.length - 1;
|
|
1514
|
+
|
|
1515
|
+
const jsonLegs = itinerary.legs.map(({ distance, duration, coords, steps }, idLeg) => {
|
|
1516
|
+
|
|
1517
|
+
const lastStepId = steps.length - 1;
|
|
1518
|
+
|
|
1519
|
+
return {
|
|
1520
|
+
distance,
|
|
1521
|
+
duration,
|
|
1522
|
+
steps: steps.map((step, idStep, arr) => {
|
|
1523
|
+
|
|
1524
|
+
let type = idStep === 0 && idLeg === 0 ? 'depart' : 'turn';
|
|
1525
|
+
type = idStep === lastStepId && idLeg === lastLegId ? 'arrive' : type;
|
|
1526
|
+
|
|
1527
|
+
const stepCoordsIdx = coords.findIndex(p => p.equalsTo(step.coords));
|
|
1528
|
+
const nextStepCoordsIdx = idStep === lastStepId
|
|
1529
|
+
? stepCoordsIdx
|
|
1530
|
+
: coords.findIndex(p => p.equalsTo(arr[idStep + 1].coords));
|
|
1531
|
+
|
|
1532
|
+
const jsonStep = {
|
|
1533
|
+
geometry: {
|
|
1534
|
+
type: 'LineString',
|
|
1535
|
+
coordinates: coords.slice(stepCoordsIdx, nextStepCoordsIdx + 1).map(this.coordinatesToJson)
|
|
1536
|
+
},
|
|
1537
|
+
distance: step.distance,
|
|
1538
|
+
duration: step.duration,
|
|
1539
|
+
name: step.name,
|
|
1540
|
+
maneuver: {
|
|
1541
|
+
bearing_before: rad2deg(step.previousBearing),
|
|
1542
|
+
bearing_after: rad2deg(step.nextBearing),
|
|
1543
|
+
location: this.coordinatesToJson(step.coords),
|
|
1544
|
+
modifier: this.getModifierFromAngle(step.angle),
|
|
1545
|
+
type
|
|
1546
|
+
}
|
|
1547
|
+
};
|
|
1548
|
+
if (step.levelChange !== null) {
|
|
1549
|
+
jsonStep.levelChange = step.levelChange.toJson();
|
|
1550
|
+
}
|
|
1551
|
+
if (typeof step.extras === 'object' && Object.keys(step.extras).length !== 0) {
|
|
1552
|
+
jsonStep.extras = step.extras;
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
return jsonStep;
|
|
1556
|
+
})
|
|
1557
|
+
};
|
|
1558
|
+
});
|
|
1559
|
+
|
|
1560
|
+
return {
|
|
1561
|
+
'code': 'Ok',
|
|
1562
|
+
'routes': [
|
|
1563
|
+
{
|
|
1564
|
+
'geometry': {
|
|
1565
|
+
'type': 'LineString',
|
|
1566
|
+
'coordinates': itinerary.coords.map(this.coordinatesToJson)
|
|
1567
|
+
},
|
|
1568
|
+
'legs': jsonLegs,
|
|
1569
|
+
'distance': itinerary.distance,
|
|
1570
|
+
'duration': itinerary.duration,
|
|
1571
|
+
'weight_name': 'routability',
|
|
1572
|
+
'weight': 0
|
|
1573
|
+
}
|
|
1574
|
+
],
|
|
1575
|
+
'waypoints': []
|
|
1576
|
+
};
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
/**
|
|
1580
|
+
* @param {object} jsonSteps
|
|
1581
|
+
* @param {Coordinates[]} legCoords
|
|
1582
|
+
* @returns {Step[]}
|
|
1583
|
+
*/
|
|
1584
|
+
parseJsonSteps(jsonSteps, legCoords) {
|
|
1585
|
+
|
|
1586
|
+
if (!jsonSteps) {
|
|
1587
|
+
return [];
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
return jsonSteps.map(jsonStep => {
|
|
1591
|
+
|
|
1592
|
+
const step = new Step();
|
|
1593
|
+
step.coords = this.jsonToCoordinates(jsonStep.maneuver.location);
|
|
1594
|
+
|
|
1595
|
+
// Sometimes, OSRM step does not have the same coordinates than a point in legCoords.
|
|
1596
|
+
// ex: first step of https://routing.getwemap.com/route/v1/walking/2.33222164147,48.87084765712;2.3320734,48.8730212?geometries=geojson&overview=full&steps=true
|
|
1597
|
+
// That is why we look for the closest point.
|
|
1598
|
+
const distances = legCoords.map(coords => coords.distanceTo(step.coords));
|
|
1599
|
+
const idStepCoordsInLeg = distances.indexOf(Math.min(...distances));
|
|
1600
|
+
if (idStepCoordsInLeg < 0) {
|
|
1601
|
+
throw new Error('Osrm Parser: Cannot find step coords in leg coordinates');
|
|
1602
|
+
}
|
|
1603
|
+
step._idCoordsInLeg = idStepCoordsInLeg;
|
|
1604
|
+
|
|
1605
|
+
step.name = jsonStep.name;
|
|
1606
|
+
step.levelChange = jsonStep.levelChange ? LevelChange.fromJson(jsonStep.levelChange) : null;
|
|
1607
|
+
|
|
1608
|
+
step.distance = jsonStep.distance;
|
|
1609
|
+
step.duration = jsonStep.duration;
|
|
1610
|
+
|
|
1611
|
+
if (jsonStep.extras && jsonStep.extras.subwayEntrance) {
|
|
1612
|
+
step.extras.subwayEntrance = true;
|
|
1613
|
+
if (jsonStep.extras.subwayEntranceRef) {
|
|
1614
|
+
step.extras.subwayEntranceRef = jsonStep.extras.subwayEntranceRef;
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
return step;
|
|
1619
|
+
});
|
|
1620
|
+
}
|
|
1621
|
+
|
|
1622
|
+
/**
|
|
1623
|
+
* Generate multi itineraries from OSRM JSON
|
|
1624
|
+
* @param {object} json JSON file provided by OSRM.
|
|
1625
|
+
* @param {Coordinates} from itinerary start
|
|
1626
|
+
* @param {Coordinates} to itinerary end
|
|
1627
|
+
* @param {?string} routingMode [walking|driving|bicycle]
|
|
1628
|
+
* @returns {?RouterResponse}
|
|
1629
|
+
*/
|
|
1630
|
+
createRouterResponseFromJson(json, from, to, routingMode = 'walking') {
|
|
1631
|
+
const { routes: jsonRoutes } = json;
|
|
1632
|
+
|
|
1633
|
+
if (!jsonRoutes) {
|
|
1634
|
+
return null;
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
const routingModeCorrespondance = new Map();
|
|
1638
|
+
routingModeCorrespondance.set('walking', 'WALK');
|
|
1639
|
+
routingModeCorrespondance.set('driving', 'CAR');
|
|
1640
|
+
routingModeCorrespondance.set('bicycle', 'BIKE');
|
|
1641
|
+
const mode = routingModeCorrespondance.get(routingMode) || null;
|
|
1642
|
+
|
|
1643
|
+
const routerResponse = new RouterResponse();
|
|
1644
|
+
routerResponse.routerName = this.rname;
|
|
1645
|
+
|
|
1646
|
+
routerResponse.from = from;
|
|
1647
|
+
routerResponse.to = to;
|
|
1648
|
+
|
|
1649
|
+
for (const jsonItinerary of jsonRoutes) {
|
|
1650
|
+
|
|
1651
|
+
const itinerary = new Itinerary();
|
|
1652
|
+
|
|
1653
|
+
// itinerary.coords = jsonItinerary.geometry.coordinates.map(jsonToCoordinates);
|
|
1654
|
+
itinerary.distance = jsonItinerary.distance;
|
|
1655
|
+
itinerary.duration = jsonItinerary.duration;
|
|
1656
|
+
itinerary.from = from;
|
|
1657
|
+
itinerary.to = to;
|
|
1658
|
+
|
|
1659
|
+
routerResponse.itineraries.push(itinerary);
|
|
1660
|
+
|
|
1661
|
+
for (const jsonLeg of jsonItinerary.legs) {
|
|
1662
|
+
|
|
1663
|
+
const leg = new Leg();
|
|
1664
|
+
|
|
1665
|
+
leg.mode = mode;
|
|
1666
|
+
leg.distance = jsonLeg.distance;
|
|
1667
|
+
leg.duration = jsonLeg.duration;
|
|
1668
|
+
|
|
1669
|
+
leg.coords = jsonLeg.steps
|
|
1670
|
+
.map(step => step.geometry.coordinates.map(this.jsonToCoordinates))
|
|
1671
|
+
.flat()
|
|
1672
|
+
// Remove duplicates
|
|
1673
|
+
.filter((coords, idx, arr) => idx === 0 || !arr[idx - 1].equalsTo(coords));
|
|
1674
|
+
|
|
1675
|
+
leg.from = {
|
|
1676
|
+
name: null,
|
|
1677
|
+
coords: leg.coords[0]
|
|
1678
|
+
};
|
|
1679
|
+
leg.to = {
|
|
1680
|
+
name: null,
|
|
1681
|
+
coords: leg.coords[leg.coords.length - 1]
|
|
1682
|
+
};
|
|
1683
|
+
|
|
1684
|
+
leg.steps = this.parseJsonSteps(jsonLeg.steps, leg.coords);
|
|
1685
|
+
|
|
1686
|
+
itinerary.legs.push(leg);
|
|
1687
|
+
}
|
|
1688
|
+
|
|
1689
|
+
// All legs have to be parsed before computing steps metadata
|
|
1690
|
+
generateStepsMetadata(itinerary);
|
|
1691
|
+
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1694
|
+
return routerResponse;
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
var OsrmRemoteRouter$1 = new OsrmRemoteRouter();
|
|
1699
|
+
|
|
1700
|
+
class OtpRoutingModeCorrespondanceNotFound extends Error {
|
|
1701
|
+
|
|
1702
|
+
/**
|
|
1703
|
+
* @param {!string} routingMode
|
|
1704
|
+
*/
|
|
1705
|
+
constructor(routingMode) {
|
|
1706
|
+
super(`OTP routing mode correspondance not found: ${routingMode}`);
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
/* eslint-disable max-statements */
|
|
1711
|
+
|
|
1712
|
+
/**
|
|
1713
|
+
* Input mode correspondance
|
|
1714
|
+
*/
|
|
1715
|
+
const inputModeCorrespondance$1 = new Map();
|
|
1716
|
+
inputModeCorrespondance$1.set(Constants.ROUTING_MODE.CAR, 'CAR');
|
|
1717
|
+
inputModeCorrespondance$1.set(Constants.ROUTING_MODE.WALK, 'WALK');
|
|
1718
|
+
inputModeCorrespondance$1.set(Constants.ROUTING_MODE.BIKE, 'BICYCLE');
|
|
1719
|
+
inputModeCorrespondance$1.set(Constants.ROUTING_MODE.BUS, 'WALK,TRANSIT');
|
|
1720
|
+
inputModeCorrespondance$1.set(Constants.ROUTING_MODE.MULTI, 'WALK,TRANSIT');
|
|
1721
|
+
|
|
1722
|
+
/**
|
|
1723
|
+
* Singleton.
|
|
1724
|
+
*/
|
|
1725
|
+
class OtpRemoteRouter extends RemoteRouter {
|
|
1726
|
+
|
|
1727
|
+
/**
|
|
1728
|
+
* @override
|
|
1729
|
+
*/
|
|
1730
|
+
get rname() {
|
|
1731
|
+
return 'otp';
|
|
1732
|
+
}
|
|
1733
|
+
|
|
1734
|
+
/**
|
|
1735
|
+
* @override
|
|
1736
|
+
*/
|
|
1737
|
+
async getItineraries(endpointUrl, mode, waypoints) {
|
|
1738
|
+
const url = this.getURL(endpointUrl, mode, waypoints);
|
|
1739
|
+
const response = await request(url);
|
|
1740
|
+
return this.createRouterResponseFromJson(response);
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
/**
|
|
1744
|
+
* @param {string} endpointUrl
|
|
1745
|
+
* @param {string} mode
|
|
1746
|
+
* @param {Array<Coordinates>} waypoints
|
|
1747
|
+
*/
|
|
1748
|
+
getURL(endpointUrl, mode, waypoints) {
|
|
1749
|
+
|
|
1750
|
+
const otpMode = inputModeCorrespondance$1.get(mode);
|
|
1751
|
+
if (!otpMode) {
|
|
1752
|
+
throw new OtpRoutingModeCorrespondanceNotFound(mode);
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
if (waypoints.length > 2) {
|
|
1756
|
+
Logger.warn(`${this.rname} router uses only the first 2 waypoints (asked ${waypoints.length})`);
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1759
|
+
const fromPlace = `fromPlace=${waypoints[0].latitude},${waypoints[0].longitude}`;
|
|
1760
|
+
const toPlace = `toPlace=${waypoints[1].latitude},${waypoints[1].longitude}`;
|
|
1761
|
+
const queryMode = `mode=${otpMode}`;
|
|
1762
|
+
|
|
1763
|
+
const url = new URL(endpointUrl);
|
|
1764
|
+
let { search } = url;
|
|
1765
|
+
search = (search ? `${search}&` : '?') + `${fromPlace}&${toPlace}&${queryMode}`;
|
|
1766
|
+
|
|
1767
|
+
return `${url.origin}${url.pathname}${search}`;
|
|
1768
|
+
}
|
|
1769
|
+
|
|
1770
|
+
/**
|
|
1771
|
+
* @param {object} json
|
|
1772
|
+
* @returns {Coordinates}
|
|
1773
|
+
*/
|
|
1774
|
+
jsonToCoordinates(json) {
|
|
1775
|
+
return new Coordinates(json.lat, json.lon);
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
/**
|
|
1779
|
+
* @param {object} jsonSteps
|
|
1780
|
+
* @param {Coordinates[]} legCoords
|
|
1781
|
+
* @returns {Step[]}
|
|
1782
|
+
*/
|
|
1783
|
+
parseJsonSteps(jsonSteps, legCoords) {
|
|
1784
|
+
|
|
1785
|
+
if (!jsonSteps) {
|
|
1786
|
+
return [];
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1789
|
+
return jsonSteps.map(jsonStep => {
|
|
1790
|
+
|
|
1791
|
+
const step = new Step();
|
|
1792
|
+
const stepCoords = this.jsonToCoordinates(jsonStep);
|
|
1793
|
+
|
|
1794
|
+
// OTP step does not have the same coordinates than a point in legCoords.
|
|
1795
|
+
// That is why we look for the closest point.
|
|
1796
|
+
const distances = legCoords.map(coords => coords.distanceTo(stepCoords));
|
|
1797
|
+
const idStepCoordsInLeg = distances.indexOf(Math.min(...distances));
|
|
1798
|
+
if (idStepCoordsInLeg < 0) {
|
|
1799
|
+
throw new Error('OTP Parser: Cannot find closest step');
|
|
1800
|
+
}
|
|
1801
|
+
step.coords = legCoords[idStepCoordsInLeg];
|
|
1802
|
+
step._idCoordsInLeg = idStepCoordsInLeg;
|
|
1803
|
+
|
|
1804
|
+
step.name = jsonStep.streetName;
|
|
1805
|
+
step.levelChange = null;
|
|
1806
|
+
|
|
1807
|
+
step.distance = jsonStep.distance;
|
|
1808
|
+
|
|
1809
|
+
return step;
|
|
1810
|
+
});
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1813
|
+
/**
|
|
1814
|
+
* Generate multi itineraries from OTP JSON
|
|
1815
|
+
* @param {object} json JSON file provided by OTP.
|
|
1816
|
+
* @returns {?RouterResponse}
|
|
1817
|
+
*/
|
|
1818
|
+
createRouterResponseFromJson(json) {
|
|
1819
|
+
|
|
1820
|
+
const { plan: jsonPlan } = json;
|
|
1821
|
+
|
|
1822
|
+
if (!jsonPlan) {
|
|
1823
|
+
return null;
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
const routerResponse = new RouterResponse();
|
|
1827
|
+
routerResponse.routerName = this.rname;
|
|
1828
|
+
|
|
1829
|
+
routerResponse.from = this.jsonToCoordinates(jsonPlan.from);
|
|
1830
|
+
routerResponse.to = this.jsonToCoordinates(jsonPlan.to);
|
|
1831
|
+
|
|
1832
|
+
for (const jsonItinerary of jsonPlan.itineraries) {
|
|
1833
|
+
|
|
1834
|
+
const itinerary = new Itinerary();
|
|
1835
|
+
|
|
1836
|
+
itinerary.duration = jsonItinerary.duration;
|
|
1837
|
+
itinerary.startTime = jsonItinerary.startTime;
|
|
1838
|
+
itinerary.endTime = jsonItinerary.endTime;
|
|
1839
|
+
itinerary.from = routerResponse.from;
|
|
1840
|
+
itinerary.to = routerResponse.to;
|
|
1841
|
+
|
|
1842
|
+
routerResponse.itineraries.push(itinerary);
|
|
1843
|
+
|
|
1844
|
+
for (const jsonLeg of jsonItinerary.legs) {
|
|
1845
|
+
|
|
1846
|
+
const leg = new Leg();
|
|
1847
|
+
|
|
1848
|
+
leg.mode = jsonLeg.mode;
|
|
1849
|
+
leg.duration = jsonLeg.duration;
|
|
1850
|
+
leg.startTime = jsonLeg.startTime;
|
|
1851
|
+
leg.endTime = jsonLeg.endTime;
|
|
1852
|
+
leg.from = {
|
|
1853
|
+
name: jsonLeg.from.name,
|
|
1854
|
+
coords: this.jsonToCoordinates(jsonLeg.from)
|
|
1855
|
+
};
|
|
1856
|
+
leg.to = {
|
|
1857
|
+
name: jsonLeg.to.name,
|
|
1858
|
+
coords: this.jsonToCoordinates(jsonLeg.to)
|
|
1859
|
+
};
|
|
1860
|
+
leg.coords = Polyline.decode(jsonLeg.legGeometry.points).map(([lat, lon]) => new Coordinates(lat, lon));
|
|
1861
|
+
|
|
1862
|
+
leg.steps = this.parseJsonSteps(jsonLeg.steps, leg.coords);
|
|
1863
|
+
|
|
1864
|
+
if (leg.mode === 'BUS' || leg.mode === 'TRAM') {
|
|
1865
|
+
leg.transportInfo = {
|
|
1866
|
+
name: jsonLeg.route,
|
|
1867
|
+
routeColor: jsonLeg.routeColor,
|
|
1868
|
+
routeTextColor: jsonLeg.routeTextColor,
|
|
1869
|
+
directionName: jsonLeg.headsign
|
|
1870
|
+
};
|
|
1871
|
+
|
|
1872
|
+
const legStep = new Step();
|
|
1873
|
+
legStep.coords = leg.coords[0];
|
|
1874
|
+
legStep._idCoordsInLeg = 0;
|
|
1875
|
+
legStep.name = jsonLeg.headsign;
|
|
1876
|
+
legStep.levelChange = null;
|
|
1877
|
+
legStep.distance = jsonLeg.distance;
|
|
1878
|
+
leg.steps = [legStep];
|
|
1879
|
+
}
|
|
1880
|
+
|
|
1881
|
+
// jsonLeg.distance is not reliable when compared to the array of leg coords.
|
|
1882
|
+
// leg.distance = jsonLeg.distance;
|
|
1883
|
+
leg.distance = leg.coords.reduce((acc, coords, idx, arr) => {
|
|
1884
|
+
if (idx === 0) {
|
|
1885
|
+
return acc;
|
|
1886
|
+
}
|
|
1887
|
+
return acc + arr[idx - 1].distanceTo(coords);
|
|
1888
|
+
}, 0);
|
|
1889
|
+
|
|
1890
|
+
itinerary.legs.push(leg);
|
|
1891
|
+
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1894
|
+
itinerary.distance = itinerary.coords.reduce((acc, coords, idx, arr) => {
|
|
1895
|
+
if (idx === 0) {
|
|
1896
|
+
return acc;
|
|
1897
|
+
}
|
|
1898
|
+
return acc + arr[idx - 1].distanceTo(coords);
|
|
1899
|
+
}, 0);
|
|
1900
|
+
|
|
1901
|
+
// All legs have to be parsed before computing steps metadata
|
|
1902
|
+
generateStepsMetadata(itinerary);
|
|
1903
|
+
}
|
|
1904
|
+
|
|
1905
|
+
return routerResponse;
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
|
|
1909
|
+
var OtpRemoteRouter$1 = new OtpRemoteRouter();
|
|
1910
|
+
|
|
1911
|
+
class CitywayRoutingModeCorrespondanceNotFound extends Error {
|
|
1912
|
+
|
|
1913
|
+
/**
|
|
1914
|
+
* @param {!string} routingMode
|
|
1915
|
+
*/
|
|
1916
|
+
constructor(routingMode) {
|
|
1917
|
+
super(`Cityway routing mode correspondance not found: ${routingMode}`);
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
/* eslint-disable max-depth */
|
|
1922
|
+
|
|
1923
|
+
/**
|
|
1924
|
+
* Input mode correspondance
|
|
1925
|
+
*/
|
|
1926
|
+
const inputModeCorrespondance = new Map();
|
|
1927
|
+
inputModeCorrespondance.set(Constants.ROUTING_MODE.CAR, 'Car');
|
|
1928
|
+
inputModeCorrespondance.set(Constants.ROUTING_MODE.WALK, 'Walk');
|
|
1929
|
+
inputModeCorrespondance.set(Constants.ROUTING_MODE.BIKE, 'Bike');
|
|
1930
|
+
inputModeCorrespondance.set(Constants.ROUTING_MODE.BUS, 'PT');
|
|
1931
|
+
inputModeCorrespondance.set(Constants.ROUTING_MODE.MULTI, 'PT');
|
|
1932
|
+
|
|
1933
|
+
|
|
1934
|
+
/**
|
|
1935
|
+
* List of all routing modes supported by the API
|
|
1936
|
+
*/
|
|
1937
|
+
const routingModeCorrespondance$1 = new Map();
|
|
1938
|
+
routingModeCorrespondance$1.set('WALK', Constants.ROUTING_MODE.WALK);
|
|
1939
|
+
routingModeCorrespondance$1.set('BICYCLE', Constants.ROUTING_MODE.BIKE);
|
|
1940
|
+
routingModeCorrespondance$1.set('TRAMWAY', Constants.ROUTING_MODE.TRAM);
|
|
1941
|
+
routingModeCorrespondance$1.set('METRO', Constants.ROUTING_MODE.METRO);
|
|
1942
|
+
routingModeCorrespondance$1.set('FUNICULAR', Constants.ROUTING_MODE.FUNICULAR);
|
|
1943
|
+
routingModeCorrespondance$1.set('BUS', Constants.ROUTING_MODE.BUS);
|
|
1944
|
+
routingModeCorrespondance$1.set('COACH', Constants.ROUTING_MODE.BUS);
|
|
1945
|
+
routingModeCorrespondance$1.set('SCHOOL', Constants.ROUTING_MODE.BUS);
|
|
1946
|
+
routingModeCorrespondance$1.set('BUS_PMR', Constants.ROUTING_MODE.BUS);
|
|
1947
|
+
routingModeCorrespondance$1.set('MINIBUS', Constants.ROUTING_MODE.BUS);
|
|
1948
|
+
routingModeCorrespondance$1.set('TROLLEY_BUS', Constants.ROUTING_MODE.BUS);
|
|
1949
|
+
routingModeCorrespondance$1.set('TAXIBUS', Constants.ROUTING_MODE.BUS);
|
|
1950
|
+
routingModeCorrespondance$1.set('SHUTTLE', Constants.ROUTING_MODE.BUS);
|
|
1951
|
+
routingModeCorrespondance$1.set('TRAIN', Constants.ROUTING_MODE.TRAIN);
|
|
1952
|
+
routingModeCorrespondance$1.set('HST', Constants.ROUTING_MODE.TRAIN);
|
|
1953
|
+
routingModeCorrespondance$1.set('LOCAL_TRAIN', Constants.ROUTING_MODE.TRAIN);
|
|
1954
|
+
routingModeCorrespondance$1.set('AIR', Constants.ROUTING_MODE.AIRPLANE);
|
|
1955
|
+
routingModeCorrespondance$1.set('FERRY', Constants.ROUTING_MODE.BOAT);
|
|
1956
|
+
routingModeCorrespondance$1.set('TAXI', Constants.ROUTING_MODE.UNKNOWN);
|
|
1957
|
+
routingModeCorrespondance$1.set('CAR_POOL', Constants.ROUTING_MODE.UNKNOWN);
|
|
1958
|
+
routingModeCorrespondance$1.set('PRIVATE_VEHICLE', Constants.ROUTING_MODE.CAR);
|
|
1959
|
+
routingModeCorrespondance$1.set('SCOOTER', Constants.ROUTING_MODE.MOTO);
|
|
1960
|
+
|
|
1961
|
+
/**
|
|
1962
|
+
* List of all plan trip supported by the API
|
|
1963
|
+
* Routing mode UNKNOWN means that the itinerary will not be parsed by the router
|
|
1964
|
+
*/
|
|
1965
|
+
const planTripType = new Map();
|
|
1966
|
+
planTripType.set(0, Constants.ROUTING_MODE.BUS);
|
|
1967
|
+
planTripType.set(1, Constants.ROUTING_MODE.WALK);
|
|
1968
|
+
planTripType.set(2, Constants.ROUTING_MODE.BIKE);
|
|
1969
|
+
planTripType.set(3, Constants.ROUTING_MODE.CAR);
|
|
1970
|
+
planTripType.set(4, Constants.ROUTING_MODE.UNKNOWN);
|
|
1971
|
+
planTripType.set(5, Constants.ROUTING_MODE.UNKNOWN);
|
|
1972
|
+
planTripType.set(6, Constants.ROUTING_MODE.UNKNOWN);
|
|
1973
|
+
planTripType.set(7, Constants.ROUTING_MODE.UNKNOWN);
|
|
1974
|
+
planTripType.set(8, Constants.ROUTING_MODE.UNKNOWN);
|
|
1975
|
+
planTripType.set(9, Constants.ROUTING_MODE.UNKNOWN);
|
|
1976
|
+
planTripType.set(10, Constants.ROUTING_MODE.UNKNOWN);
|
|
1977
|
+
planTripType.set(11, Constants.ROUTING_MODE.UNKNOWN);
|
|
1978
|
+
planTripType.set(12, Constants.ROUTING_MODE.UNKNOWN);
|
|
1979
|
+
planTripType.set(13, Constants.ROUTING_MODE.UNKNOWN);
|
|
1980
|
+
planTripType.set(14, Constants.ROUTING_MODE.UNKNOWN);
|
|
1981
|
+
|
|
1982
|
+
|
|
1983
|
+
/**
|
|
1984
|
+
* Singleton.
|
|
1985
|
+
*/
|
|
1986
|
+
class CitywayRemoteRouter extends RemoteRouter {
|
|
1987
|
+
|
|
1988
|
+
/**
|
|
1989
|
+
* @override
|
|
1990
|
+
*/
|
|
1991
|
+
get rname() {
|
|
1992
|
+
return 'cityway';
|
|
1993
|
+
}
|
|
1994
|
+
|
|
1995
|
+
|
|
1996
|
+
/**
|
|
1997
|
+
* @override
|
|
1998
|
+
*/
|
|
1999
|
+
async getItineraries(endpointUrl, mode, waypoints) {
|
|
2000
|
+
const url = this.getURL(endpointUrl, mode, waypoints);
|
|
2001
|
+
const response = await request(url);
|
|
2002
|
+
return this.createRouterResponseFromJson(response);
|
|
2003
|
+
}
|
|
2004
|
+
|
|
2005
|
+
|
|
2006
|
+
/**
|
|
2007
|
+
* @param {string} endpointUrl
|
|
2008
|
+
* @param {string} mode
|
|
2009
|
+
* @param {Array<Coordinates>} waypoints
|
|
2010
|
+
*/
|
|
2011
|
+
getURL(endpointUrl, mode, waypoints) {
|
|
2012
|
+
const citywayMode = inputModeCorrespondance.get(mode);
|
|
2013
|
+
if (!citywayMode) {
|
|
2014
|
+
throw new CitywayRoutingModeCorrespondanceNotFound(mode);
|
|
2015
|
+
}
|
|
2016
|
+
if (waypoints.length > 2) {
|
|
2017
|
+
Logger.warn(`${this.rname} router uses only the first 2 waypoints (asked ${waypoints.length})`);
|
|
2018
|
+
}
|
|
2019
|
+
const fromPlace = `DepartureLatitude=${waypoints[0].latitude}&DepartureLongitude=${waypoints[0].longitude}`;
|
|
2020
|
+
const toPlace = `ArrivalLatitude=${waypoints[1].latitude}&ArrivalLongitude=${waypoints[1].longitude}`;
|
|
2021
|
+
const queryMode = `TripModes=${citywayMode}`;
|
|
2022
|
+
|
|
2023
|
+
const url = new URL(endpointUrl);
|
|
2024
|
+
let { search } = url;
|
|
2025
|
+
search = (search ? `${search}&` : '?') + `${fromPlace}&${toPlace}&${queryMode}`;
|
|
2026
|
+
|
|
2027
|
+
return `${url.origin}${url.pathname}${search}`;
|
|
2028
|
+
}
|
|
2029
|
+
|
|
2030
|
+
/**
|
|
2031
|
+
* Generate multi itineraries from Cityway JSON
|
|
2032
|
+
* @param {object} json JSON file provided by Cityway.
|
|
2033
|
+
* @returns {?RouterResponse}
|
|
2034
|
+
* @example https://preprod.api.lia2.cityway.fr/journeyplanner/api/opt/PlanTrips/json?DepartureLatitude=49.51509388236216&DepartureLongitude=0.09341749619366316&ArrivalLatitude=49.5067090188444&ArrivalLongitude=0.1694842115417831&DepartureType=COORDINATES&ArrivalType=COORDINATES
|
|
2035
|
+
*/
|
|
2036
|
+
createRouterResponseFromJson(json) {
|
|
2037
|
+
|
|
2038
|
+
if (json.StatusCode !== 200 || !json.Data || !json.Data.length) {
|
|
2039
|
+
return null;
|
|
2040
|
+
}
|
|
2041
|
+
|
|
2042
|
+
const routerResponse = new RouterResponse();
|
|
2043
|
+
routerResponse.routerName = this.rname;
|
|
2044
|
+
|
|
2045
|
+
|
|
2046
|
+
// Do not know if it the best approach, but it works...
|
|
2047
|
+
const allJsonTrips = json.Data.reduce((acc, dataObj) => {
|
|
2048
|
+
acc.push(...dataObj.response.trips.Trip.map(trip => ({
|
|
2049
|
+
...trip,
|
|
2050
|
+
...(dataObj.hasOwnProperty('PlanTripType') ? { PlanTripType: dataObj.PlanTripType } : {})
|
|
2051
|
+
})));
|
|
2052
|
+
return acc;
|
|
2053
|
+
}, []);
|
|
2054
|
+
|
|
2055
|
+
// eslint-disable-next-line no-labels
|
|
2056
|
+
itineraryLoop:
|
|
2057
|
+
for (const trip of allJsonTrips) {
|
|
2058
|
+
|
|
2059
|
+
if (trip.hasOwnProperty('PlanTripType') && planTripType.get(trip.PlanTripType) === Constants.ROUTING_MODE.UNKNOWN) {
|
|
2060
|
+
continue;
|
|
2061
|
+
}
|
|
2062
|
+
|
|
2063
|
+
const itinerary = new Itinerary();
|
|
2064
|
+
|
|
2065
|
+
itinerary.duration = this.parseDuration(trip.Duration);
|
|
2066
|
+
itinerary.startTime = this.jsonDateToTimestamp(trip.Departure.Time);
|
|
2067
|
+
itinerary.from = this.jsonToCoordinates(trip.Departure.Site.Position);
|
|
2068
|
+
itinerary.endTime = this.jsonDateToTimestamp(trip.Arrival.Time);
|
|
2069
|
+
itinerary.to = this.jsonToCoordinates(trip.Arrival.Site.Position);
|
|
2070
|
+
|
|
2071
|
+
for (const jsonSection of trip.sections.Section) {
|
|
2072
|
+
|
|
2073
|
+
const jsonLeg = jsonSection.Leg ? jsonSection.Leg : jsonSection.PTRide;
|
|
2074
|
+
|
|
2075
|
+
const leg = new Leg();
|
|
2076
|
+
|
|
2077
|
+
leg.mode = routingModeCorrespondance$1.get(jsonLeg.TransportMode);
|
|
2078
|
+
leg.duration = this.parseDuration(jsonLeg.Duration);
|
|
2079
|
+
leg.startTime = this.jsonDateToTimestamp(jsonLeg.Departure.Time);
|
|
2080
|
+
leg.endTime = this.jsonDateToTimestamp(jsonLeg.Arrival.Time);
|
|
2081
|
+
leg.coords = [];
|
|
2082
|
+
|
|
2083
|
+
if (leg.mode === Constants.ROUTING_MODE.UNKNOWN) {
|
|
2084
|
+
// eslint-disable-next-line
|
|
2085
|
+
continue itineraryLoop;
|
|
2086
|
+
}
|
|
1085
2087
|
|
|
1086
|
-
|
|
2088
|
+
if (leg.mode === Constants.ROUTING_MODE.WALK
|
|
2089
|
+
|| leg.mode === Constants.ROUTING_MODE.BIKE
|
|
2090
|
+
|| leg.mode === Constants.ROUTING_MODE.CAR) {
|
|
2091
|
+
|
|
2092
|
+
leg.from = {
|
|
2093
|
+
name: jsonLeg.Departure.Site.Name,
|
|
2094
|
+
coords: this.jsonToCoordinates(jsonLeg.Departure.Site.Position)
|
|
2095
|
+
};
|
|
2096
|
+
leg.to = {
|
|
2097
|
+
name: jsonLeg.Arrival.Site.Name,
|
|
2098
|
+
coords: this.jsonToCoordinates(jsonLeg.Arrival.Site.Position)
|
|
2099
|
+
};
|
|
2100
|
+
|
|
2101
|
+
leg.steps = [];
|
|
2102
|
+
for (const jsonPathLink of jsonLeg.pathLinks.PathLink) {
|
|
2103
|
+
const step = new Step();
|
|
2104
|
+
let stepCoords;
|
|
2105
|
+
if (jsonPathLink.Geometry) {
|
|
2106
|
+
stepCoords = this.parseWKTGeometry(jsonPathLink.Geometry);
|
|
2107
|
+
} else {
|
|
2108
|
+
stepCoords = [leg.from.coords, leg.to.coords];
|
|
2109
|
+
}
|
|
2110
|
+
step.coords = stepCoords[0];
|
|
2111
|
+
step._idCoordsInLeg = leg.coords.length;
|
|
2112
|
+
stepCoords.forEach((coords, idx) => {
|
|
2113
|
+
if (
|
|
2114
|
+
idx !== 0
|
|
2115
|
+
|| leg.coords.length === 0
|
|
2116
|
+
|| !leg.coords[leg.coords.length - 1].equalsTo(coords)
|
|
2117
|
+
) {
|
|
2118
|
+
leg.coords.push(coords);
|
|
2119
|
+
}
|
|
2120
|
+
});
|
|
1087
2121
|
|
|
1088
|
-
const jsonLegs = itinerary.legs.map(({ distance, duration, coords, steps }, idLeg) => {
|
|
1089
2122
|
|
|
1090
|
-
|
|
2123
|
+
step.name = jsonPathLink.Departure.Site.Name;
|
|
2124
|
+
step.levelChange = null;
|
|
1091
2125
|
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
steps: steps.map((step, idStep, arr) => {
|
|
1096
|
-
|
|
1097
|
-
let type = idStep === 0 && idLeg === 0 ? 'depart' : 'turn';
|
|
1098
|
-
type = idStep === lastStepId && idLeg === lastLegId ? 'arrive' : type;
|
|
1099
|
-
|
|
1100
|
-
const stepCoordsIdx = coords.findIndex(p => p.equalsTo(step.coords));
|
|
1101
|
-
const nextStepCoordsIdx = idStep === lastStepId
|
|
1102
|
-
? stepCoordsIdx
|
|
1103
|
-
: coords.findIndex(p => p.equalsTo(arr[idStep + 1].coords));
|
|
1104
|
-
|
|
1105
|
-
const jsonStep = {
|
|
1106
|
-
geometry: {
|
|
1107
|
-
type: 'LineString',
|
|
1108
|
-
coordinates: coords.slice(stepCoordsIdx, nextStepCoordsIdx + 1).map(coordinatesToJson)
|
|
1109
|
-
},
|
|
1110
|
-
distance: step.distance,
|
|
1111
|
-
duration: step.duration,
|
|
1112
|
-
name: step.name,
|
|
1113
|
-
maneuver: {
|
|
1114
|
-
bearing_before: rad2deg(step.previousBearing),
|
|
1115
|
-
bearing_after: rad2deg(step.nextBearing),
|
|
1116
|
-
location: coordinatesToJson(step.coords),
|
|
1117
|
-
modifier: getModifierFromAngle(step.angle),
|
|
1118
|
-
type
|
|
2126
|
+
step.distance = jsonPathLink.Distance;
|
|
2127
|
+
|
|
2128
|
+
leg.steps.push(step);
|
|
1119
2129
|
}
|
|
1120
|
-
|
|
1121
|
-
if (
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
2130
|
+
|
|
2131
|
+
} else if (Constants.PUBLIC_TRANSPORT.includes(leg.mode)) {
|
|
2132
|
+
|
|
2133
|
+
leg.from = {
|
|
2134
|
+
name: jsonLeg.Departure.StopPlace.Name,
|
|
2135
|
+
coords: this.jsonToCoordinates(jsonLeg.Departure.StopPlace.Position)
|
|
2136
|
+
};
|
|
2137
|
+
leg.to = {
|
|
2138
|
+
name: jsonLeg.Arrival.StopPlace.Name,
|
|
2139
|
+
coords: this.jsonToCoordinates(jsonLeg.Arrival.StopPlace.Position)
|
|
2140
|
+
};
|
|
2141
|
+
|
|
2142
|
+
let transportName = jsonLeg.Line.Number;
|
|
2143
|
+
if (leg.mode === Constants.ROUTING_MODE.TRAM && transportName.toLowerCase().includes('tram')) {
|
|
2144
|
+
// In order to remove the "TRAM " prefix.
|
|
2145
|
+
transportName = transportName.substr(5);
|
|
2146
|
+
}
|
|
2147
|
+
|
|
2148
|
+
leg.transportInfo = {
|
|
2149
|
+
name: transportName,
|
|
2150
|
+
routeColor: jsonLeg.Line.Color,
|
|
2151
|
+
routeTextColor: jsonLeg.Line.TextColor,
|
|
2152
|
+
directionName: jsonLeg.Destination
|
|
2153
|
+
};
|
|
2154
|
+
|
|
2155
|
+
for (const jsonStep of jsonLeg.steps.Step) {
|
|
2156
|
+
const stepCoords = this.parseWKTGeometry(jsonStep.Geometry);
|
|
2157
|
+
stepCoords.forEach((coords, idx) => {
|
|
2158
|
+
if (
|
|
2159
|
+
idx !== 0
|
|
2160
|
+
|| leg.coords.length === 0
|
|
2161
|
+
|| !leg.coords[leg.coords.length - 1].equalsTo(coords)
|
|
2162
|
+
) {
|
|
2163
|
+
leg.coords.push(coords);
|
|
2164
|
+
}
|
|
2165
|
+
});
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2168
|
+
const legStep = new Step();
|
|
2169
|
+
legStep.coords = leg.coords[0];
|
|
2170
|
+
legStep._idCoordsInLeg = 0;
|
|
2171
|
+
legStep.name = jsonLeg.Line.Name;
|
|
2172
|
+
legStep.levelChange = null;
|
|
2173
|
+
legStep.distance = jsonLeg.Distance;
|
|
2174
|
+
leg.steps = [legStep];
|
|
2175
|
+
} else {
|
|
2176
|
+
Logger.warn(`[CitywayParser] Unknown leg mode: ${jsonLeg.TransportMode}`);
|
|
1126
2177
|
}
|
|
1127
2178
|
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
2179
|
+
leg.distance = leg.coords.reduce((acc, coords, idx, arr) => {
|
|
2180
|
+
if (idx === 0) {
|
|
2181
|
+
return acc;
|
|
2182
|
+
}
|
|
2183
|
+
return acc + arr[idx - 1].distanceTo(coords);
|
|
2184
|
+
}, 0);
|
|
2185
|
+
|
|
2186
|
+
itinerary.legs.push(leg);
|
|
1132
2187
|
|
|
1133
|
-
return {
|
|
1134
|
-
'code': 'Ok',
|
|
1135
|
-
'routes': [
|
|
1136
|
-
{
|
|
1137
|
-
'geometry': {
|
|
1138
|
-
'type': 'LineString',
|
|
1139
|
-
'coordinates': itinerary.coords.map(coordinatesToJson)
|
|
1140
|
-
},
|
|
1141
|
-
'legs': jsonLegs,
|
|
1142
|
-
'distance': itinerary.distance,
|
|
1143
|
-
'duration': itinerary.duration,
|
|
1144
|
-
'weight_name': 'routability',
|
|
1145
|
-
'weight': 0
|
|
1146
2188
|
}
|
|
1147
|
-
],
|
|
1148
|
-
'waypoints': []
|
|
1149
|
-
};
|
|
1150
|
-
}
|
|
1151
2189
|
|
|
2190
|
+
routerResponse.itineraries.push(itinerary);
|
|
1152
2191
|
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
2192
|
+
itinerary.distance = itinerary.coords.reduce((acc, coords, idx, arr) => {
|
|
2193
|
+
if (idx === 0) {
|
|
2194
|
+
return acc;
|
|
2195
|
+
}
|
|
2196
|
+
return acc + arr[idx - 1].distanceTo(coords);
|
|
2197
|
+
}, 0);
|
|
1159
2198
|
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
2199
|
+
// All legs have to be parsed before computing steps metadata
|
|
2200
|
+
generateStepsMetadata(itinerary);
|
|
2201
|
+
}
|
|
1163
2202
|
|
|
1164
|
-
|
|
2203
|
+
routerResponse.from = routerResponse.itineraries[0].from;
|
|
2204
|
+
routerResponse.to = routerResponse.itineraries[routerResponse.itineraries.length - 1].to;
|
|
1165
2205
|
|
|
1166
|
-
|
|
1167
|
-
|
|
2206
|
+
return routerResponse;
|
|
2207
|
+
}
|
|
1168
2208
|
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
}
|
|
1177
|
-
step._idCoordsInLeg = idStepCoordsInLeg;
|
|
2209
|
+
/**
|
|
2210
|
+
* @param {object} json
|
|
2211
|
+
* @returns {Coordinates}
|
|
2212
|
+
*/
|
|
2213
|
+
jsonToCoordinates(json) {
|
|
2214
|
+
return new Coordinates(json.Lat, json.Long);
|
|
2215
|
+
}
|
|
1178
2216
|
|
|
1179
|
-
|
|
1180
|
-
|
|
2217
|
+
/**
|
|
2218
|
+
* @param {string} jsonDate
|
|
2219
|
+
* @returns {number}
|
|
2220
|
+
*/
|
|
2221
|
+
jsonDateToTimestamp(jsonDate) {
|
|
2222
|
+
const [dateStr, timeStr] = jsonDate.split(' ');
|
|
2223
|
+
const [dayStr, monthStr, yearStr] = dateStr.split('/');
|
|
2224
|
+
const [hoursStr, minutesStr, secondsStr] = timeStr.split(':');
|
|
2225
|
+
|
|
2226
|
+
return dateWithTimeZone(
|
|
2227
|
+
Number(yearStr),
|
|
2228
|
+
Number(monthStr) - 1,
|
|
2229
|
+
Number(dayStr),
|
|
2230
|
+
Number(hoursStr),
|
|
2231
|
+
Number(minutesStr),
|
|
2232
|
+
Number(secondsStr)
|
|
2233
|
+
).getTime();
|
|
2234
|
+
}
|
|
1181
2235
|
|
|
1182
|
-
|
|
1183
|
-
|
|
2236
|
+
/**
|
|
2237
|
+
* @param {string} wktGeometry
|
|
2238
|
+
* @returns {Coordinates[]}
|
|
2239
|
+
*/
|
|
2240
|
+
parseWKTGeometry(wktGeometry) {
|
|
2241
|
+
const tmpCoordsStr = wktGeometry.match(/LINESTRING \((.*)\)/i);
|
|
2242
|
+
const tmpCoordsPt = wktGeometry.match(/POINT \((.*)\)/i);
|
|
2243
|
+
if (!tmpCoordsStr && !tmpCoordsPt) {
|
|
2244
|
+
return null;
|
|
2245
|
+
}
|
|
1184
2246
|
|
|
1185
|
-
if (
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
step.extras.subwayEntranceRef = jsonStep.extras.subwayEntranceRef;
|
|
1189
|
-
}
|
|
2247
|
+
if (tmpCoordsPt) {
|
|
2248
|
+
const [lng, lat] = tmpCoordsPt[1].split(' ');
|
|
2249
|
+
return [new Coordinates(Number(lat), Number(lng))];
|
|
1190
2250
|
}
|
|
1191
2251
|
|
|
1192
|
-
return
|
|
1193
|
-
|
|
2252
|
+
return tmpCoordsStr[1].split(',').map(str => {
|
|
2253
|
+
const sp = str.trim().split(' ');
|
|
2254
|
+
return new Coordinates(Number(sp[1]), Number(sp[0]));
|
|
2255
|
+
});
|
|
2256
|
+
}
|
|
2257
|
+
|
|
2258
|
+
/**
|
|
2259
|
+
* @param {string} iso8601Duration
|
|
2260
|
+
* @see https://stackoverflow.com/a/29153059/2239938
|
|
2261
|
+
*/
|
|
2262
|
+
parseDuration(iso8601Duration) {
|
|
2263
|
+
const iso8601DurationRegex = /(-)?P(?:([.,\d]+)Y)?(?:([.,\d]+)M)?(?:([.,\d]+)W)?(?:([.,\d]+)D)?T(?:([.,\d]+)H)?(?:([.,\d]+)M)?(?:([.,\d]+)S)?/;
|
|
2264
|
+
|
|
2265
|
+
var matches = iso8601Duration.match(iso8601DurationRegex);
|
|
2266
|
+
|
|
2267
|
+
// const sign = typeof matches[1] === 'undefined' ? '+' : '-',
|
|
2268
|
+
const years = typeof matches[2] === 'undefined' ? 0 : Number(matches[2]);
|
|
2269
|
+
const months = typeof matches[3] === 'undefined' ? 0 : Number(matches[3]);
|
|
2270
|
+
const weeks = typeof matches[4] === 'undefined' ? 0 : Number(matches[4]);
|
|
2271
|
+
const days = typeof matches[5] === 'undefined' ? 0 : Number(matches[5]);
|
|
2272
|
+
const hours = typeof matches[6] === 'undefined' ? 0 : Number(matches[6]);
|
|
2273
|
+
const minutes = typeof matches[7] === 'undefined' ? 0 : Number(matches[7]);
|
|
2274
|
+
const seconds = typeof matches[8] === 'undefined' ? 0 : Number(matches[8]);
|
|
2275
|
+
|
|
2276
|
+
return seconds
|
|
2277
|
+
+ minutes * 60
|
|
2278
|
+
+ hours * 3600
|
|
2279
|
+
+ days * 86400
|
|
2280
|
+
+ weeks * (86400 * 7)
|
|
2281
|
+
+ months * (86400 * 30)
|
|
2282
|
+
+ years * (86400 * 365.25);
|
|
2283
|
+
}
|
|
1194
2284
|
}
|
|
1195
2285
|
|
|
2286
|
+
var CitywayRemoteRouter$1 = new CitywayRemoteRouter();
|
|
2287
|
+
|
|
2288
|
+
/* eslint-disable max-statements */
|
|
1196
2289
|
|
|
1197
2290
|
/**
|
|
1198
|
-
*
|
|
1199
|
-
* @param {object} json JSON file provided by OSRM.
|
|
1200
|
-
* @param {Coordinates} from itinerary start
|
|
1201
|
-
* @param {Coordinates} to itinerary end
|
|
1202
|
-
* @param {?string} routingMode [walking|driving|bicycle]
|
|
1203
|
-
* @returns {?RouterResponse}
|
|
2291
|
+
* Singleton.
|
|
1204
2292
|
*/
|
|
1205
|
-
|
|
2293
|
+
class DeutscheBahnRemoteRouter extends RemoteRouter {
|
|
1206
2294
|
|
|
1207
|
-
|
|
2295
|
+
/**
|
|
2296
|
+
* @override
|
|
2297
|
+
*/
|
|
2298
|
+
get rname() {
|
|
2299
|
+
return 'deutsche-bahn';
|
|
2300
|
+
}
|
|
1208
2301
|
|
|
1209
|
-
|
|
1210
|
-
|
|
2302
|
+
/**
|
|
2303
|
+
* @override
|
|
2304
|
+
*/
|
|
2305
|
+
async getItineraries(endpointUrl, mode, waypoints) {
|
|
2306
|
+
const url = this.getURL(endpointUrl, mode, waypoints);
|
|
2307
|
+
const response = await request(url);
|
|
2308
|
+
return this.createRouterResponseFromJson(response, waypoints[0], waypoints[1]);
|
|
1211
2309
|
}
|
|
1212
2310
|
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
2311
|
+
/**
|
|
2312
|
+
* @param {string} endpointUrl
|
|
2313
|
+
* @param {string} mode
|
|
2314
|
+
* @param {Array<Coordinates>} waypoints
|
|
2315
|
+
*/
|
|
2316
|
+
getURL(endpointUrl, mode, waypoints) {
|
|
2317
|
+
let url = endpointUrl + '/route/v1/' + mode + '/';
|
|
1218
2318
|
|
|
1219
|
-
|
|
1220
|
-
|
|
2319
|
+
url += waypoints.map(waypoint => {
|
|
2320
|
+
if (waypoint.level) {
|
|
2321
|
+
const altitude = waypoint.level.isRange ? waypoint.level.low : waypoint.level.val;
|
|
1221
2322
|
|
|
1222
|
-
|
|
1223
|
-
|
|
2323
|
+
return waypoint.longitude + ',' + waypoint.latitude + ',' + altitude;
|
|
2324
|
+
}
|
|
1224
2325
|
|
|
1225
|
-
|
|
2326
|
+
return waypoint.longitude + ',' + waypoint.latitude;
|
|
2327
|
+
}).join(';');
|
|
1226
2328
|
|
|
1227
|
-
|
|
2329
|
+
url += '?geometries=geojson&overview=full&steps=true';
|
|
1228
2330
|
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
itinerary.duration = jsonItinerary.duration;
|
|
1232
|
-
itinerary.from = from;
|
|
1233
|
-
itinerary.to = to;
|
|
2331
|
+
return url;
|
|
2332
|
+
}
|
|
1234
2333
|
|
|
1235
|
-
|
|
2334
|
+
/**
|
|
2335
|
+
* Generate multi itineraries from the DB JSON
|
|
2336
|
+
* @param {object} json JSON file provided by the DB.
|
|
2337
|
+
* @param {Coordinates} from itinerary start
|
|
2338
|
+
* @param {Coordinates} to itinerary end
|
|
2339
|
+
* @returns {?RouterResponse}
|
|
2340
|
+
*/
|
|
2341
|
+
createRouterResponseFromJson(json, from, to) {
|
|
1236
2342
|
|
|
1237
|
-
|
|
2343
|
+
const { segments: jsonSegments } = json;
|
|
1238
2344
|
|
|
1239
|
-
|
|
2345
|
+
if (!jsonSegments) {
|
|
2346
|
+
return null;
|
|
2347
|
+
}
|
|
1240
2348
|
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
leg.duration = jsonLeg.duration;
|
|
2349
|
+
const routerResponse = new RouterResponse();
|
|
2350
|
+
routerResponse.routerName = this.rname;
|
|
1244
2351
|
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
.flat()
|
|
1248
|
-
// Remove duplicates
|
|
1249
|
-
.filter((coords, idx, arr) => idx === 0 || !arr[idx - 1].equalsTo(coords));
|
|
2352
|
+
routerResponse.from = from;
|
|
2353
|
+
routerResponse.to = to;
|
|
1250
2354
|
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
2355
|
+
/** @type {GraphEdge<OsmElement>[]} */
|
|
2356
|
+
const edges = [];
|
|
2357
|
+
|
|
2358
|
+
/** @type {GraphNode<OsmElement>[]} */
|
|
2359
|
+
const nodes = [];
|
|
2360
|
+
|
|
2361
|
+
/** @type {number[]} */
|
|
2362
|
+
const edgesWeights = [];
|
|
2363
|
+
|
|
2364
|
+
let id = 1;
|
|
2365
|
+
for (const jsonSegment of jsonSegments) {
|
|
2366
|
+
|
|
2367
|
+
const level = new Level(jsonSegment.fromLevel, jsonSegment.toLevel);
|
|
2368
|
+
const osmWay = new OsmWay(id++, null, level);
|
|
2369
|
+
|
|
2370
|
+
for (const jsonPoint of jsonSegment.polyline) {
|
|
2371
|
+
const coord = new Coordinates(jsonPoint.lat, jsonPoint.lon, null, level);
|
|
2372
|
+
|
|
2373
|
+
if (nodes.length !== 0
|
|
2374
|
+
&& nodes[nodes.length - 1].coords.equalsTo(coord)) {
|
|
2375
|
+
continue;
|
|
2376
|
+
}
|
|
1259
2377
|
|
|
1260
|
-
|
|
2378
|
+
const osmNode = new OsmNode(id++, coord);
|
|
2379
|
+
const node = new GraphNode(osmNode.coords, osmNode);
|
|
1261
2380
|
|
|
1262
|
-
|
|
2381
|
+
if (nodes.length !== 0) {
|
|
2382
|
+
const prevNode = nodes[nodes.length - 1];
|
|
2383
|
+
const edge = new GraphEdge(prevNode, node, level, osmWay);
|
|
2384
|
+
edges.push(edge);
|
|
2385
|
+
edgesWeights.push(prevNode.coords.distanceTo(osmNode));
|
|
2386
|
+
}
|
|
2387
|
+
|
|
2388
|
+
nodes.push(node);
|
|
2389
|
+
|
|
2390
|
+
}
|
|
1263
2391
|
}
|
|
1264
2392
|
|
|
2393
|
+
/** @type {GraphItinerary<OsmElement>} */
|
|
2394
|
+
const graphItinerary = new GraphItinerary();
|
|
2395
|
+
graphItinerary.nodes = nodes;
|
|
2396
|
+
graphItinerary.edges = edges;
|
|
2397
|
+
graphItinerary.edgesWeights = edgesWeights;
|
|
2398
|
+
graphItinerary.start = nodes[0].coords;
|
|
2399
|
+
graphItinerary.end = nodes[nodes.length - 1].coords;
|
|
2400
|
+
|
|
2401
|
+
const points = nodes.map(node => node.coords);
|
|
2402
|
+
const itinerary = Itinerary.fromOrderedCoordinates(points, from, to);
|
|
2403
|
+
itinerary.legs[0].steps = WemapStepsGeneration.fromGraphItinerary(graphItinerary);
|
|
2404
|
+
itinerary.legs[0].steps.map((step, idx) => (step._idCoordsInLeg = idx));
|
|
2405
|
+
|
|
1265
2406
|
// All legs have to be parsed before computing steps metadata
|
|
1266
2407
|
generateStepsMetadata(itinerary);
|
|
1267
2408
|
|
|
1268
|
-
|
|
2409
|
+
routerResponse.itineraries.push(itinerary);
|
|
1269
2410
|
|
|
1270
|
-
|
|
2411
|
+
return routerResponse;
|
|
2412
|
+
}
|
|
1271
2413
|
}
|
|
1272
2414
|
|
|
1273
|
-
var
|
|
1274
|
-
__proto__: null,
|
|
1275
|
-
coordinatesToJson: coordinatesToJson,
|
|
1276
|
-
jsonToCoordinates: jsonToCoordinates$2,
|
|
1277
|
-
nodesToJsonCoords: nodesToJsonCoords,
|
|
1278
|
-
getModifierFromAngle: getModifierFromAngle,
|
|
1279
|
-
noRouteFoundJson: noRouteFoundJson,
|
|
1280
|
-
itineraryToOsrmJson: itineraryToOsrmJson,
|
|
1281
|
-
createRouterResponseFromJson: createRouterResponseFromJson$3
|
|
1282
|
-
});
|
|
2415
|
+
var DeutscheBahnRemoteRouter$1 = new DeutscheBahnRemoteRouter();
|
|
1283
2416
|
|
|
1284
2417
|
/* eslint-disable max-statements */
|
|
1285
2418
|
|
|
1286
2419
|
/**
|
|
1287
|
-
*
|
|
1288
|
-
*
|
|
2420
|
+
* List of all modes supported by the API
|
|
2421
|
+
* http://doc.navitia.io/#physical-mode
|
|
2422
|
+
*/
|
|
2423
|
+
|
|
2424
|
+
const routingModeCorrespondance = new Map();
|
|
2425
|
+
routingModeCorrespondance.set('Air', Constants.ROUTING_MODE.AIRPLANE);
|
|
2426
|
+
routingModeCorrespondance.set('Boat', Constants.ROUTING_MODE.BOAT);
|
|
2427
|
+
routingModeCorrespondance.set('Bus', Constants.ROUTING_MODE.BUS);
|
|
2428
|
+
routingModeCorrespondance.set('BusRapidTransit', Constants.ROUTING_MODE.BUS);
|
|
2429
|
+
routingModeCorrespondance.set('Coach', Constants.ROUTING_MODE.BUS);
|
|
2430
|
+
routingModeCorrespondance.set('Ferry', Constants.ROUTING_MODE.FERRY);
|
|
2431
|
+
routingModeCorrespondance.set('Funicular', Constants.ROUTING_MODE.FUNICULAR);
|
|
2432
|
+
routingModeCorrespondance.set('LocalTrain', Constants.ROUTING_MODE.TRAIN);
|
|
2433
|
+
routingModeCorrespondance.set('LongDistanceTrain', Constants.ROUTING_MODE.TRAIN);
|
|
2434
|
+
routingModeCorrespondance.set('Metro', Constants.ROUTING_MODE.METRO);
|
|
2435
|
+
routingModeCorrespondance.set('Métro', Constants.ROUTING_MODE.METRO);
|
|
2436
|
+
routingModeCorrespondance.set('RailShuttle', Constants.ROUTING_MODE.TRAIN);
|
|
2437
|
+
routingModeCorrespondance.set('RapidTransit', Constants.ROUTING_MODE.BUS);
|
|
2438
|
+
routingModeCorrespondance.set('Shuttle', Constants.ROUTING_MODE.BUS);
|
|
2439
|
+
routingModeCorrespondance.set('SuspendedCableCar', Constants.ROUTING_MODE.FUNICULAR);
|
|
2440
|
+
routingModeCorrespondance.set('Taxi', Constants.ROUTING_MODE.TAXI);
|
|
2441
|
+
routingModeCorrespondance.set('Train', Constants.ROUTING_MODE.TRAIN);
|
|
2442
|
+
routingModeCorrespondance.set('RER', Constants.ROUTING_MODE.TRAIN);
|
|
2443
|
+
routingModeCorrespondance.set('Tramway', Constants.ROUTING_MODE.TRAM);
|
|
2444
|
+
routingModeCorrespondance.set('walking', Constants.ROUTING_MODE.WALK);
|
|
2445
|
+
routingModeCorrespondance.set('bike', Constants.ROUTING_MODE.BIKE);
|
|
2446
|
+
|
|
2447
|
+
/**
|
|
2448
|
+
* List of transports modes
|
|
2449
|
+
*/
|
|
2450
|
+
const TRANSPORT_IDS = [
|
|
2451
|
+
'physical_mode:Air',
|
|
2452
|
+
'physical_mode:Boat',
|
|
2453
|
+
'physical_mode:Bus',
|
|
2454
|
+
'physical_mode:BusRapidTransit',
|
|
2455
|
+
'physical_mode:Coach',
|
|
2456
|
+
'physical_mode:Ferry',
|
|
2457
|
+
'physical_mode:Funicular',
|
|
2458
|
+
'physical_mode:LocalTrain',
|
|
2459
|
+
'physical_mode:LongDistanceTrain',
|
|
2460
|
+
'physical_mode:Metro',
|
|
2461
|
+
'physical_mode:RailShuttle',
|
|
2462
|
+
'physical_mode:RapidTransit',
|
|
2463
|
+
'physical_mode:Shuttle',
|
|
2464
|
+
'physical_mode:SuspendedCableCar',
|
|
2465
|
+
'physical_mode:Taxi',
|
|
2466
|
+
'physical_mode:Train',
|
|
2467
|
+
'physical_mode:Tramway'
|
|
2468
|
+
];
|
|
2469
|
+
|
|
2470
|
+
const clientId = '539eec73-3bb5-4327-bb5e-a52672658592';
|
|
2471
|
+
const clientSecret = '899f4bb9-f1d5-45d3-9f67-530827bb6734';
|
|
2472
|
+
|
|
2473
|
+
/**
|
|
2474
|
+
* Get last item of a given array
|
|
2475
|
+
* @param {Array} array
|
|
2476
|
+
* @returns {any}
|
|
1289
2477
|
*/
|
|
1290
|
-
function
|
|
1291
|
-
return
|
|
2478
|
+
function last(array) {
|
|
2479
|
+
return array[array.length - 1];
|
|
1292
2480
|
}
|
|
1293
2481
|
|
|
1294
2482
|
/**
|
|
1295
|
-
*
|
|
1296
|
-
* @param {Coordinates[]} legCoords
|
|
1297
|
-
* @returns {Step[]}
|
|
2483
|
+
* Singleton.
|
|
1298
2484
|
*/
|
|
1299
|
-
|
|
2485
|
+
class IdfmRemoteRouter extends RemoteRouter {
|
|
1300
2486
|
|
|
1301
|
-
|
|
1302
|
-
|
|
2487
|
+
isLogged = false;
|
|
2488
|
+
token = null;
|
|
2489
|
+
expiresAt = null;
|
|
2490
|
+
|
|
2491
|
+
/**
|
|
2492
|
+
* @override
|
|
2493
|
+
*/
|
|
2494
|
+
get rname() {
|
|
2495
|
+
return 'idfm';
|
|
1303
2496
|
}
|
|
1304
2497
|
|
|
1305
|
-
|
|
2498
|
+
/**
|
|
2499
|
+
* @override
|
|
2500
|
+
*/
|
|
2501
|
+
async getItineraries(endpointUrl, mode, waypoints) {
|
|
2502
|
+
if (!this.canRequestService()) {
|
|
2503
|
+
await this._connect();
|
|
2504
|
+
}
|
|
1306
2505
|
|
|
1307
|
-
const
|
|
1308
|
-
const stepCoords = jsonToCoordinates$1(jsonStep);
|
|
2506
|
+
const url = this.getURL(endpointUrl, mode, waypoints);
|
|
1309
2507
|
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
const idStepCoordsInLeg = distances.indexOf(Math.min(...distances));
|
|
1314
|
-
if (idStepCoordsInLeg < 0) {
|
|
1315
|
-
throw new Error('OTP Parser: Cannot find closest step');
|
|
1316
|
-
}
|
|
1317
|
-
step.coords = legCoords[idStepCoordsInLeg];
|
|
1318
|
-
step._idCoordsInLeg = idStepCoordsInLeg;
|
|
2508
|
+
const response = await request(url, {
|
|
2509
|
+
headers: { Authorization: 'Bearer ' + this.token }
|
|
2510
|
+
});
|
|
1319
2511
|
|
|
1320
|
-
|
|
1321
|
-
|
|
2512
|
+
return this.createRouterResponseFromJson(response);
|
|
2513
|
+
}
|
|
1322
2514
|
|
|
1323
|
-
|
|
2515
|
+
_connect() {
|
|
1324
2516
|
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
2517
|
+
const details = {
|
|
2518
|
+
'grant_type': 'client_credentials',
|
|
2519
|
+
'scope': 'read-data',
|
|
2520
|
+
'client_id': clientId,
|
|
2521
|
+
'client_secret': clientSecret
|
|
2522
|
+
};
|
|
1328
2523
|
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
2524
|
+
const data = new URLSearchParams();
|
|
2525
|
+
for (const property in details) {
|
|
2526
|
+
if (details.hasOwnProperty(property)) {
|
|
2527
|
+
const encodedKey = encodeURIComponent(property);
|
|
2528
|
+
const encodedValue = encodeURIComponent(details[property]);
|
|
2529
|
+
data.append(encodedKey, encodedValue);
|
|
2530
|
+
}
|
|
2531
|
+
}
|
|
1335
2532
|
|
|
1336
|
-
|
|
2533
|
+
return request('https://idfm.getwemap.com/api/oauth/token', {
|
|
2534
|
+
method: 'POST',
|
|
2535
|
+
data
|
|
2536
|
+
}).then((response) => {
|
|
2537
|
+
if (response.access_token) {
|
|
2538
|
+
this.token = response.access_token;
|
|
2539
|
+
this.isLogged = true;
|
|
2540
|
+
this.expiresAt = new Date(new Date().getTime() + response.expires_in * 1000);
|
|
2541
|
+
}
|
|
2542
|
+
});
|
|
2543
|
+
}
|
|
1337
2544
|
|
|
1338
|
-
|
|
1339
|
-
return
|
|
2545
|
+
canRequestService() {
|
|
2546
|
+
return this.token && this.expiresAt && this.expiresAt - new Date() > 0;
|
|
1340
2547
|
}
|
|
1341
2548
|
|
|
1342
|
-
|
|
1343
|
-
|
|
2549
|
+
/**
|
|
2550
|
+
* @param {string} endpointUrl
|
|
2551
|
+
* @param {string} mode
|
|
2552
|
+
* @param {Array<Coordinates>} waypoints
|
|
2553
|
+
*/
|
|
2554
|
+
getURL(endpointUrl, mode, waypoints) {
|
|
1344
2555
|
|
|
1345
|
-
|
|
1346
|
-
|
|
2556
|
+
if (waypoints.length > 2) {
|
|
2557
|
+
Logger.warn(`${this.rname} router uses only the first 2 waypoints (asked ${waypoints.length})`);
|
|
2558
|
+
}
|
|
1347
2559
|
|
|
1348
|
-
|
|
2560
|
+
const fromPlace = `from=${waypoints[0].longitude};${waypoints[0].latitude}`;
|
|
2561
|
+
const toPlace = `to=${waypoints[1].longitude};${waypoints[1].latitude}`;
|
|
2562
|
+
|
|
2563
|
+
let url = new URL(endpointUrl);
|
|
2564
|
+
let { search } = url;
|
|
2565
|
+
search = (search ? `${search}&` : '?') + `${fromPlace}&${toPlace}`;
|
|
2566
|
+
|
|
2567
|
+
let query = '';
|
|
2568
|
+
switch (mode) {
|
|
2569
|
+
case Constants.ITINERARY_MODE.FOOT:
|
|
2570
|
+
query = this.getWalkingQuery();
|
|
2571
|
+
break;
|
|
2572
|
+
case Constants.ITINERARY_MODE.BIKE:
|
|
2573
|
+
query = this.getBikeQuery();
|
|
2574
|
+
break;
|
|
2575
|
+
case Constants.ITINERARY_MODE.DRIVING:
|
|
2576
|
+
query = this.getCarQuery();
|
|
2577
|
+
break;
|
|
2578
|
+
}
|
|
1349
2579
|
|
|
1350
|
-
|
|
2580
|
+
url = `${url.origin}${url.pathname}${search}${query}`;
|
|
1351
2581
|
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
itinerary.endTime = jsonItinerary.endTime;
|
|
1355
|
-
itinerary.from = routerResponse.from;
|
|
1356
|
-
itinerary.to = routerResponse.to;
|
|
2582
|
+
return url;
|
|
2583
|
+
}
|
|
1357
2584
|
|
|
1358
|
-
|
|
2585
|
+
getCarQuery() {
|
|
2586
|
+
const forbiddenTransport = TRANSPORT_IDS.map((id) => `forbidden_uris[]=${id}`).join('&');
|
|
2587
|
+
const allowCar = 'first_section_mode[]=walking&first_section_mode[]=car&last_section_mode[]=walking&last_section_mode[]=car';
|
|
1359
2588
|
|
|
1360
|
-
|
|
2589
|
+
return `&${forbiddenTransport}&${allowCar}`;
|
|
2590
|
+
}
|
|
1361
2591
|
|
|
1362
|
-
|
|
2592
|
+
getWalkingQuery() {
|
|
2593
|
+
const forbiddenTransport = TRANSPORT_IDS.map((id) => `forbidden_uris[]=${id}`).join('&');
|
|
2594
|
+
const allowWalking = 'first_section_mode[]=walking&last_section_mode[]=walking';
|
|
1363
2595
|
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
leg.startTime = jsonLeg.startTime;
|
|
1367
|
-
leg.endTime = jsonLeg.endTime;
|
|
1368
|
-
leg.from = {
|
|
1369
|
-
name: jsonLeg.from.name,
|
|
1370
|
-
coords: jsonToCoordinates$1(jsonLeg.from)
|
|
1371
|
-
};
|
|
1372
|
-
leg.to = {
|
|
1373
|
-
name: jsonLeg.to.name,
|
|
1374
|
-
coords: jsonToCoordinates$1(jsonLeg.to)
|
|
1375
|
-
};
|
|
1376
|
-
leg.coords = Polyline.decode(jsonLeg.legGeometry.points).map(([lat, lon]) => new Coordinates(lat, lon));
|
|
2596
|
+
return `&${forbiddenTransport}&${allowWalking}`;
|
|
2597
|
+
}
|
|
1377
2598
|
|
|
1378
|
-
|
|
2599
|
+
getBikeQuery() {
|
|
2600
|
+
const forbiddenTransport = TRANSPORT_IDS.map((id) => `forbidden_uris[]=${id}`).join('&');
|
|
2601
|
+
const allowBike = 'first_section_mode[]=bike&last_section_mode[]=bike';
|
|
1379
2602
|
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
name: jsonLeg.route,
|
|
1383
|
-
routeColor: jsonLeg.routeColor,
|
|
1384
|
-
routeTextColor: jsonLeg.routeTextColor,
|
|
1385
|
-
directionName: jsonLeg.headsign
|
|
1386
|
-
};
|
|
2603
|
+
return `&${forbiddenTransport}&${allowBike}`;
|
|
2604
|
+
}
|
|
1387
2605
|
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
}
|
|
2606
|
+
/**
|
|
2607
|
+
* @param {object} json
|
|
2608
|
+
* @returns {Coordinates}
|
|
2609
|
+
*/
|
|
2610
|
+
jsonToCoordinates(json) {
|
|
2611
|
+
return new Coordinates(Number(json.lat), Number(json.lon));
|
|
2612
|
+
}
|
|
1396
2613
|
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
if (idx === 0) {
|
|
1401
|
-
return acc;
|
|
1402
|
-
}
|
|
1403
|
-
return acc + arr[idx - 1].distanceTo(coords);
|
|
1404
|
-
}, 0);
|
|
2614
|
+
getSectionCoords(section) {
|
|
2615
|
+
const from = section.from.stop_point ? this.jsonToCoordinates(section.from.stop_point.coord) : this.jsonToCoordinates(section.from.address.coord);
|
|
2616
|
+
const to = section.to.stop_point ? this.jsonToCoordinates(section.to.stop_point.coord) : this.jsonToCoordinates(section.to.address.coord);
|
|
1405
2617
|
|
|
1406
|
-
|
|
2618
|
+
return {
|
|
2619
|
+
from,
|
|
2620
|
+
to
|
|
2621
|
+
};
|
|
2622
|
+
}
|
|
1407
2623
|
|
|
1408
|
-
|
|
2624
|
+
/**
|
|
2625
|
+
* Since the IDFM API does not provide coords for each step, we need to compute them
|
|
2626
|
+
* We trim the coordinates of the leg with the distance of each step and keep the last result as the coords of the step
|
|
2627
|
+
* @param {Leg} leg
|
|
2628
|
+
*/
|
|
2629
|
+
findStepsCoord(leg) {
|
|
2630
|
+
const { steps, coords } = leg;
|
|
2631
|
+
|
|
2632
|
+
const duplicatedCoords = [...coords];
|
|
2633
|
+
let previousStep = steps[0];
|
|
2634
|
+
let accumulatedIndex = 0;
|
|
2635
|
+
|
|
2636
|
+
for (const [idx, step] of steps.entries()) {
|
|
2637
|
+
let newCoords;
|
|
1409
2638
|
|
|
1410
|
-
itinerary.distance = itinerary.coords.reduce((acc, coords, idx, arr) => {
|
|
1411
2639
|
if (idx === 0) {
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
2640
|
+
step._idCoordsInLeg = 0;
|
|
2641
|
+
newCoords = coords[0];
|
|
2642
|
+
} else if (idx === steps.length - 1) {
|
|
2643
|
+
step._idCoordsInLeg = coords.length - 1;
|
|
2644
|
+
newCoords = last(coords);
|
|
2645
|
+
} else if (duplicatedCoords.length === 1) {
|
|
2646
|
+
accumulatedIndex++;
|
|
1416
2647
|
|
|
1417
|
-
|
|
1418
|
-
generateStepsMetadata(itinerary);
|
|
1419
|
-
}
|
|
2648
|
+
step._idCoordsInLeg = accumulatedIndex;
|
|
1420
2649
|
|
|
1421
|
-
|
|
1422
|
-
}
|
|
2650
|
+
newCoords = duplicatedCoords[0];
|
|
1423
2651
|
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
});
|
|
2652
|
+
coords[step._idCoordsInLeg] = newCoords;
|
|
2653
|
+
} else {
|
|
2654
|
+
const result = Utils.trimRoute(duplicatedCoords, duplicatedCoords[0], previousStep.distance);
|
|
2655
|
+
accumulatedIndex += result.length - 1;
|
|
1429
2656
|
|
|
1430
|
-
|
|
2657
|
+
duplicatedCoords.splice(0, result.length - 1);
|
|
1431
2658
|
|
|
1432
|
-
|
|
1433
|
-
* @param {object} json
|
|
1434
|
-
* @returns {Coordinates}
|
|
1435
|
-
*/
|
|
1436
|
-
function jsonToCoordinates(json) {
|
|
1437
|
-
return new Coordinates(json.Lat, json.Long);
|
|
1438
|
-
}
|
|
2659
|
+
step._idCoordsInLeg = accumulatedIndex;
|
|
1439
2660
|
|
|
1440
|
-
|
|
1441
|
-
* @param {string} jsonDate
|
|
1442
|
-
* @returns {number}
|
|
1443
|
-
*/
|
|
1444
|
-
function jsonDateToTimestamp(jsonDate) {
|
|
1445
|
-
const [dateStr, timeStr] = jsonDate.split(' ');
|
|
1446
|
-
const [dayStr, monthStr, yearStr] = dateStr.split('/');
|
|
1447
|
-
const [hoursStr, minutesStr, secondsStr] = timeStr.split(':');
|
|
1448
|
-
const date = new Date(
|
|
1449
|
-
Number(yearStr), Number(monthStr) - 1, Number(dayStr),
|
|
1450
|
-
Number(hoursStr), Number(minutesStr), Number(secondsStr)
|
|
1451
|
-
);
|
|
1452
|
-
return date.getTime();
|
|
1453
|
-
}
|
|
2661
|
+
newCoords = last(result);
|
|
1454
2662
|
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
* @returns {Coordinates[]}
|
|
1458
|
-
*/
|
|
1459
|
-
function parseWKTGeometry(wktGeometry) {
|
|
1460
|
-
const tmpCoordsStr = wktGeometry.match(/LINESTRING \((.*)\)/i);
|
|
1461
|
-
if (!tmpCoordsStr) {
|
|
1462
|
-
return null;
|
|
1463
|
-
}
|
|
1464
|
-
return tmpCoordsStr[1].split(',').map(str => {
|
|
1465
|
-
const sp = str.trim().split(' ');
|
|
1466
|
-
return new Coordinates(Number(sp[1]), Number(sp[0]));
|
|
1467
|
-
});
|
|
1468
|
-
}
|
|
2663
|
+
coords[step._idCoordsInLeg] = newCoords;
|
|
2664
|
+
}
|
|
1469
2665
|
|
|
1470
|
-
|
|
1471
|
-
* @param {string} iso8601Duration
|
|
1472
|
-
* @see https://stackoverflow.com/a/29153059/2239938
|
|
1473
|
-
*/
|
|
1474
|
-
function parseDuration(iso8601Duration) {
|
|
1475
|
-
const iso8601DurationRegex = /(-)?P(?:([.,\d]+)Y)?(?:([.,\d]+)M)?(?:([.,\d]+)W)?(?:([.,\d]+)D)?T(?:([.,\d]+)H)?(?:([.,\d]+)M)?(?:([.,\d]+)S)?/;
|
|
1476
|
-
|
|
1477
|
-
var matches = iso8601Duration.match(iso8601DurationRegex);
|
|
1478
|
-
|
|
1479
|
-
// const sign = typeof matches[1] === 'undefined' ? '+' : '-',
|
|
1480
|
-
const years = typeof matches[2] === 'undefined' ? 0 : Number(matches[2]);
|
|
1481
|
-
const months = typeof matches[3] === 'undefined' ? 0 : Number(matches[3]);
|
|
1482
|
-
const weeks = typeof matches[4] === 'undefined' ? 0 : Number(matches[4]);
|
|
1483
|
-
const days = typeof matches[5] === 'undefined' ? 0 : Number(matches[5]);
|
|
1484
|
-
const hours = typeof matches[6] === 'undefined' ? 0 : Number(matches[6]);
|
|
1485
|
-
const minutes = typeof matches[7] === 'undefined' ? 0 : Number(matches[7]);
|
|
1486
|
-
const seconds = typeof matches[8] === 'undefined' ? 0 : Number(matches[8]);
|
|
1487
|
-
|
|
1488
|
-
return seconds
|
|
1489
|
-
+ minutes * 60
|
|
1490
|
-
+ hours * 3600
|
|
1491
|
-
+ days * 86400
|
|
1492
|
-
+ weeks * (86400 * 7)
|
|
1493
|
-
+ months * (86400 * 30)
|
|
1494
|
-
+ years * (86400 * 365.25);
|
|
1495
|
-
}
|
|
2666
|
+
step.coords = newCoords;
|
|
1496
2667
|
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
* @returns {?RouterResponse}
|
|
1501
|
-
* @example https://preprod.api.lia2.cityway.fr/journeyplanner/api/opt/PlanTrips/json?DepartureLatitude=49.51509388236216&DepartureLongitude=0.09341749619366316&ArrivalLatitude=49.5067090188444&ArrivalLongitude=0.1694842115417831&DepartureType=COORDINATES&ArrivalType=COORDINATES
|
|
1502
|
-
*/
|
|
1503
|
-
function createRouterResponseFromJson$1(json) {
|
|
2668
|
+
previousStep = step;
|
|
2669
|
+
}
|
|
2670
|
+
}
|
|
1504
2671
|
|
|
1505
|
-
|
|
1506
|
-
|
|
2672
|
+
/**
|
|
2673
|
+
* @param {string} stringDate (e.g. 20211117T104516)
|
|
2674
|
+
* @returns {number}
|
|
2675
|
+
*/
|
|
2676
|
+
dateStringToTimestamp(stringDate, timeZone) {
|
|
2677
|
+
const yearStr = stringDate.substr(0, 4);
|
|
2678
|
+
const monthStr = stringDate.substr(4, 2);
|
|
2679
|
+
const dayStr = stringDate.substr(6, 2);
|
|
2680
|
+
const hoursStr = stringDate.substr(9, 2);
|
|
2681
|
+
const minutesStr = stringDate.substr(11, 2);
|
|
2682
|
+
const secondsStr = stringDate.substr(13, 2);
|
|
2683
|
+
|
|
2684
|
+
return dateWithTimeZone(
|
|
2685
|
+
Number(yearStr),
|
|
2686
|
+
Number(monthStr) - 1,
|
|
2687
|
+
Number(dayStr),
|
|
2688
|
+
Number(hoursStr),
|
|
2689
|
+
Number(minutesStr),
|
|
2690
|
+
Number(secondsStr),
|
|
2691
|
+
timeZone
|
|
2692
|
+
).getTime();
|
|
1507
2693
|
}
|
|
1508
2694
|
|
|
1509
|
-
|
|
1510
|
-
|
|
2695
|
+
/**
|
|
2696
|
+
* Generate multi itineraries from OTP JSON
|
|
2697
|
+
* @param {object} json JSON file provided by OTP.
|
|
2698
|
+
* @returns {?RouterResponse}
|
|
2699
|
+
*/
|
|
2700
|
+
createRouterResponseFromJson(json) {
|
|
1511
2701
|
|
|
2702
|
+
if (!json || !json.journeys) {
|
|
2703
|
+
return null;
|
|
2704
|
+
}
|
|
1512
2705
|
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
acc.push(...dataObj.response.trips.Trip);
|
|
1516
|
-
return acc;
|
|
1517
|
-
}, []);
|
|
2706
|
+
const routerResponse = new RouterResponse();
|
|
2707
|
+
routerResponse.routerName = this.rname;
|
|
1518
2708
|
|
|
1519
|
-
|
|
2709
|
+
routerResponse.from = this.getSectionCoords(json.journeys[0].sections[0]).from;
|
|
2710
|
+
routerResponse.to = this.getSectionCoords(last(json.journeys[0].sections)).to;
|
|
1520
2711
|
|
|
1521
|
-
const
|
|
2712
|
+
const timeZone = json.context.timezone;
|
|
1522
2713
|
|
|
1523
|
-
|
|
1524
|
-
itinerary.startTime = jsonDateToTimestamp(trip.Departure.Time);
|
|
1525
|
-
itinerary.from = jsonToCoordinates(trip.Departure.Site.Position);
|
|
1526
|
-
itinerary.endTime = jsonDateToTimestamp(trip.Arrival.Time);
|
|
1527
|
-
itinerary.to = jsonToCoordinates(trip.Arrival.Site.Position);
|
|
1528
|
-
routerResponse.itineraries.push(itinerary);
|
|
2714
|
+
for (const jsonItinerary of json.journeys) {
|
|
1529
2715
|
|
|
1530
|
-
|
|
2716
|
+
const itinerary = new Itinerary();
|
|
1531
2717
|
|
|
1532
|
-
|
|
2718
|
+
itinerary.duration = jsonItinerary.duration;
|
|
2719
|
+
itinerary.startTime = this.dateStringToTimestamp(jsonItinerary.departure_date_time, timeZone);
|
|
2720
|
+
itinerary.endTime = this.dateStringToTimestamp(jsonItinerary.arrival_date_time, timeZone);
|
|
2721
|
+
itinerary.from = routerResponse.from;
|
|
2722
|
+
itinerary.to = routerResponse.to;
|
|
2723
|
+
itinerary.distance = 0;
|
|
1533
2724
|
|
|
1534
|
-
|
|
2725
|
+
routerResponse.itineraries.push(itinerary);
|
|
1535
2726
|
|
|
1536
|
-
|
|
1537
|
-
leg.duration = parseDuration(jsonLeg.Duration);
|
|
1538
|
-
leg.startTime = jsonDateToTimestamp(jsonLeg.Departure.Time);
|
|
1539
|
-
leg.endTime = jsonDateToTimestamp(jsonLeg.Arrival.Time);
|
|
1540
|
-
leg.coords = [];
|
|
2727
|
+
for (const jsonSection of jsonItinerary.sections) {
|
|
1541
2728
|
|
|
1542
|
-
|
|
2729
|
+
if (jsonSection.type === 'waiting' || jsonSection.type === 'transfer') {
|
|
2730
|
+
continue;
|
|
2731
|
+
}
|
|
2732
|
+
|
|
2733
|
+
const leg = new Leg();
|
|
2734
|
+
let existingCoords = [];
|
|
2735
|
+
const { from, to } = this.getSectionCoords(jsonSection);
|
|
2736
|
+
|
|
2737
|
+
leg.distance = 0;
|
|
2738
|
+
leg.mode = routingModeCorrespondance.get(jsonSection.mode);
|
|
2739
|
+
leg.duration = jsonSection.duration;
|
|
2740
|
+
leg.startTime = this.dateStringToTimestamp(jsonSection.departure_date_time, timeZone);
|
|
2741
|
+
leg.endTime = this.dateStringToTimestamp(jsonSection.arrival_date_time, timeZone);
|
|
1543
2742
|
|
|
1544
2743
|
leg.from = {
|
|
1545
|
-
name:
|
|
1546
|
-
coords:
|
|
2744
|
+
name: jsonSection.from.name,
|
|
2745
|
+
coords: from
|
|
1547
2746
|
};
|
|
2747
|
+
|
|
1548
2748
|
leg.to = {
|
|
1549
|
-
name:
|
|
1550
|
-
coords:
|
|
2749
|
+
name: jsonSection.to.name,
|
|
2750
|
+
coords: to
|
|
1551
2751
|
};
|
|
1552
2752
|
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
stepCoords = parseWKTGeometry(jsonPathLink.Geometry);
|
|
1559
|
-
} else {
|
|
1560
|
-
stepCoords = [leg.from.coords, leg.to.coords];
|
|
2753
|
+
// A section can have multiple same coordinates, we need to remove them
|
|
2754
|
+
leg.coords = jsonSection.geojson.coordinates.reduce((acc, [lon, lat]) => {
|
|
2755
|
+
if (!existingCoords.includes(`${lon}-${lat}`)) {
|
|
2756
|
+
existingCoords = existingCoords.concat(`${lon}-${lat}`);
|
|
2757
|
+
acc.push(new Coordinates(lat, lon));
|
|
1561
2758
|
}
|
|
1562
|
-
step.coords = stepCoords[0];
|
|
1563
|
-
step._idCoordsInLeg = leg.coords.length;
|
|
1564
|
-
stepCoords.forEach((coords, idx) => {
|
|
1565
|
-
if (
|
|
1566
|
-
idx !== 0
|
|
1567
|
-
|| leg.coords.length === 0
|
|
1568
|
-
|| !leg.coords[leg.coords.length - 1].equalsTo(coords)
|
|
1569
|
-
) {
|
|
1570
|
-
leg.coords.push(coords);
|
|
1571
|
-
}
|
|
1572
|
-
});
|
|
1573
2759
|
|
|
2760
|
+
return acc;
|
|
2761
|
+
}, []);
|
|
1574
2762
|
|
|
1575
|
-
|
|
1576
|
-
step.levelChange = null;
|
|
2763
|
+
leg.steps = [];
|
|
1577
2764
|
|
|
1578
|
-
|
|
2765
|
+
if (jsonSection.path) {
|
|
2766
|
+
for (const jsonPathLink of jsonSection.path) {
|
|
2767
|
+
const step = new Step();
|
|
1579
2768
|
|
|
1580
|
-
|
|
1581
|
-
}
|
|
2769
|
+
step.levelChange = null;
|
|
1582
2770
|
|
|
1583
|
-
|
|
2771
|
+
step.name = jsonPathLink.name;
|
|
2772
|
+
step.distance = jsonPathLink.length;
|
|
1584
2773
|
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
};
|
|
1589
|
-
leg.to = {
|
|
1590
|
-
name: jsonLeg.Arrival.StopPlace.Name,
|
|
1591
|
-
coords: jsonToCoordinates(jsonLeg.Arrival.StopPlace.Position)
|
|
1592
|
-
};
|
|
2774
|
+
leg.distance += step.distance;
|
|
2775
|
+
leg.steps.push(step);
|
|
2776
|
+
}
|
|
1593
2777
|
|
|
1594
|
-
|
|
1595
|
-
if (leg.mode === 'TRAMWAY') {
|
|
1596
|
-
leg.mode = 'TRAM';
|
|
1597
|
-
// In order to remove the "TRAM " prefix.
|
|
1598
|
-
transportName = transportName.substr(5);
|
|
2778
|
+
this.findStepsCoord(leg);
|
|
1599
2779
|
}
|
|
1600
2780
|
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
2781
|
+
if (jsonSection.type === 'public_transport') {
|
|
2782
|
+
leg.transportInfo = {
|
|
2783
|
+
name: jsonSection.display_informations.code,
|
|
2784
|
+
routeColor: jsonSection.display_informations.color,
|
|
2785
|
+
routeTextColor: jsonSection.display_informations.text_color,
|
|
2786
|
+
directionName: jsonSection.display_informations.direction
|
|
2787
|
+
};
|
|
1607
2788
|
|
|
1608
|
-
|
|
1609
|
-
const stepCoords = parseWKTGeometry(jsonStep.Geometry);
|
|
1610
|
-
stepCoords.forEach((coords, idx) => {
|
|
1611
|
-
if (
|
|
1612
|
-
idx !== 0
|
|
1613
|
-
|| leg.coords.length === 0
|
|
1614
|
-
|| !leg.coords[leg.coords.length - 1].equalsTo(coords)
|
|
1615
|
-
) {
|
|
1616
|
-
leg.coords.push(coords);
|
|
1617
|
-
}
|
|
1618
|
-
});
|
|
1619
|
-
}
|
|
2789
|
+
leg.mode = routingModeCorrespondance.get(jsonSection.display_informations.physical_mode);
|
|
1620
2790
|
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
leg.steps = [legStep];
|
|
1628
|
-
} else {
|
|
1629
|
-
Logger.warn(`[CitywayParser] Unknown leg mode: ${leg.mode}`);
|
|
1630
|
-
}
|
|
2791
|
+
const legStep = new Step();
|
|
2792
|
+
legStep.coords = leg.coords[0];
|
|
2793
|
+
legStep._idCoordsInLeg = 0;
|
|
2794
|
+
legStep.name = leg.transportInfo.directionName;
|
|
2795
|
+
legStep.levelChange = null;
|
|
2796
|
+
legStep.distance = jsonSection.geojson.properties[0].length;
|
|
1631
2797
|
|
|
1632
|
-
|
|
1633
|
-
if (idx === 0) {
|
|
1634
|
-
return acc;
|
|
2798
|
+
leg.steps = [legStep];
|
|
1635
2799
|
}
|
|
1636
|
-
return acc + arr[idx - 1].distanceTo(coords);
|
|
1637
|
-
}, 0);
|
|
1638
2800
|
|
|
1639
|
-
|
|
2801
|
+
itinerary.distance += leg.distance;
|
|
1640
2802
|
|
|
1641
|
-
|
|
2803
|
+
itinerary.legs.push(leg);
|
|
1642
2804
|
|
|
1643
|
-
itinerary.distance = itinerary.coords.reduce((acc, coords, idx, arr) => {
|
|
1644
|
-
if (idx === 0) {
|
|
1645
|
-
return acc;
|
|
1646
2805
|
}
|
|
1647
|
-
return acc + arr[idx - 1].distanceTo(coords);
|
|
1648
|
-
}, 0);
|
|
1649
|
-
|
|
1650
|
-
// All legs have to be parsed before computing steps metadata
|
|
1651
|
-
generateStepsMetadata(itinerary);
|
|
1652
|
-
}
|
|
1653
2806
|
|
|
1654
|
-
|
|
1655
|
-
|
|
2807
|
+
// All legs have to be parsed before computing steps metadata
|
|
2808
|
+
generateStepsMetadata(itinerary);
|
|
2809
|
+
}
|
|
1656
2810
|
|
|
1657
|
-
|
|
2811
|
+
return routerResponse;
|
|
2812
|
+
}
|
|
1658
2813
|
}
|
|
1659
2814
|
|
|
1660
|
-
var
|
|
1661
|
-
__proto__: null,
|
|
1662
|
-
jsonToCoordinates: jsonToCoordinates,
|
|
1663
|
-
createRouterResponseFromJson: createRouterResponseFromJson$1
|
|
1664
|
-
});
|
|
2815
|
+
var IdfmRemoteRouter$1 = new IdfmRemoteRouter();
|
|
1665
2816
|
|
|
1666
2817
|
/* eslint-disable max-statements */
|
|
1667
2818
|
|
|
2819
|
+
|
|
1668
2820
|
/**
|
|
1669
|
-
*
|
|
1670
|
-
* @param {object} json JSON file provided by the DB.
|
|
1671
|
-
* @param {Coordinates} from itinerary start
|
|
1672
|
-
* @param {Coordinates} to itinerary end
|
|
1673
|
-
* @returns {?RouterResponse}
|
|
2821
|
+
* Singleton.
|
|
1674
2822
|
*/
|
|
1675
|
-
|
|
2823
|
+
class WemapMetaRemoteRouter extends RemoteRouter {
|
|
1676
2824
|
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
2825
|
+
/**
|
|
2826
|
+
* @override
|
|
2827
|
+
*/
|
|
2828
|
+
get rname() {
|
|
2829
|
+
return 'wemap-meta';
|
|
1681
2830
|
}
|
|
1682
2831
|
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
/** @type {GraphNode<OsmElement>[]} */
|
|
1693
|
-
const nodes = [];
|
|
1694
|
-
|
|
1695
|
-
/** @type {number[]} */
|
|
1696
|
-
const edgesWeights = [];
|
|
1697
|
-
|
|
1698
|
-
let id = 1;
|
|
1699
|
-
for (const jsonSegment of jsonSegments) {
|
|
1700
|
-
|
|
1701
|
-
const level = new Level(jsonSegment.fromLevel, jsonSegment.toLevel);
|
|
1702
|
-
const osmWay = new OsmWay(id++, null, level);
|
|
1703
|
-
|
|
1704
|
-
for (const jsonPoint of jsonSegment.polyline) {
|
|
1705
|
-
const coord = new Coordinates(jsonPoint.lat, jsonPoint.lon, null, level);
|
|
2832
|
+
/**
|
|
2833
|
+
* @override
|
|
2834
|
+
*/
|
|
2835
|
+
async getItineraries(endpointUrl, mode, waypoints, options) {
|
|
2836
|
+
const url = this.getURL(endpointUrl, mode, waypoints, options);
|
|
2837
|
+
const response = await request(url);
|
|
2838
|
+
return RouterResponse.fromJson(response);
|
|
2839
|
+
}
|
|
1706
2840
|
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
2841
|
+
/**
|
|
2842
|
+
* @param {string} endpointUrl
|
|
2843
|
+
* @param {string} mode
|
|
2844
|
+
* @param {Array<Coordinates>} waypoints
|
|
2845
|
+
* @param {WemapMetaRemoteRouterOptions} options
|
|
2846
|
+
*/
|
|
2847
|
+
getURL(endpointUrl, mode, waypoints, options) {
|
|
1711
2848
|
|
|
1712
|
-
|
|
1713
|
-
const node = new GraphNode(osmNode.coords, osmNode);
|
|
2849
|
+
const url = new URL(endpointUrl);
|
|
1714
2850
|
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
const
|
|
1718
|
-
|
|
1719
|
-
edgesWeights.push(prevNode.coords.distanceTo(osmNode));
|
|
2851
|
+
url.pathname = url.pathname + waypoints.map(waypoint => {
|
|
2852
|
+
if (waypoint.level) {
|
|
2853
|
+
const altitude = waypoint.level.isRange ? waypoint.level.low : waypoint.level.val;
|
|
2854
|
+
return waypoint.longitude + ',' + waypoint.latitude + ',' + altitude;
|
|
1720
2855
|
}
|
|
2856
|
+
return waypoint.longitude + ',' + waypoint.latitude;
|
|
2857
|
+
}).join(';');
|
|
1721
2858
|
|
|
1722
|
-
|
|
2859
|
+
url.searchParams.set('externalRouterName', options.externalRouterName);
|
|
2860
|
+
url.searchParams.set('externalRouterEndpoint', encodeURIComponent(options.externalRouterEndpointUrl));
|
|
2861
|
+
url.searchParams.set('externalRouterMode', mode);
|
|
1723
2862
|
|
|
1724
|
-
|
|
2863
|
+
return url;
|
|
1725
2864
|
}
|
|
1726
|
-
|
|
1727
|
-
/** @type {GraphItinerary<OsmElement>} */
|
|
1728
|
-
const graphItinerary = new GraphItinerary();
|
|
1729
|
-
graphItinerary.nodes = nodes;
|
|
1730
|
-
graphItinerary.edges = edges;
|
|
1731
|
-
graphItinerary.edgesWeights = edgesWeights;
|
|
1732
|
-
graphItinerary.start = nodes[0].coords;
|
|
1733
|
-
graphItinerary.end = nodes[nodes.length - 1].coords;
|
|
1734
|
-
|
|
1735
|
-
const points = nodes.map(node => node.coords);
|
|
1736
|
-
const itinerary = Itinerary.fromOrderedCoordinates(points, from, to);
|
|
1737
|
-
itinerary.legs[0].steps = WemapStepsGeneration.fromGraphItinerary(graphItinerary);
|
|
1738
|
-
itinerary.legs[0].steps.map((step, idx) => (step._idCoordsInLeg = idx));
|
|
1739
|
-
|
|
1740
|
-
// All legs have to be parsed before computing steps metadata
|
|
1741
|
-
generateStepsMetadata(itinerary);
|
|
1742
|
-
|
|
1743
|
-
routerResponse.itineraries.push(itinerary);
|
|
1744
|
-
|
|
1745
|
-
return routerResponse;
|
|
1746
2865
|
}
|
|
1747
2866
|
|
|
1748
|
-
var
|
|
1749
|
-
__proto__: null,
|
|
1750
|
-
createRouterResponseFromJson: createRouterResponseFromJson
|
|
1751
|
-
});
|
|
2867
|
+
var WemapMetaRemoteRouter$1 = new WemapMetaRemoteRouter();
|
|
1752
2868
|
|
|
1753
2869
|
/* eslint-disable max-statements */
|
|
1754
2870
|
|
|
@@ -1891,5 +3007,5 @@ class ItineraryInfoManager {
|
|
|
1891
3007
|
|
|
1892
3008
|
}
|
|
1893
3009
|
|
|
1894
|
-
export {
|
|
3010
|
+
export { CitywayRemoteRouter$1 as CitywayRemoteRouter, DeutscheBahnRemoteRouter$1 as DeutscheBahnRemoteRouter, IdfmRemoteRouter$1 as IdfmRemoteRouter, Itinerary, ItineraryInfo, ItineraryInfoManager, Leg, LevelChange, OsrmRemoteRouter$1 as OsrmRemoteRouter, OtpRemoteRouter$1 as OtpRemoteRouter, RouterResponse, Step, WemapMetaRemoteRouter$1 as WemapMetaRemoteRouter, WemapNetworkUtils, WemapRouter, WemapRouterOptions, WemapRouterUtils, getDurationFromLength };
|
|
1895
3011
|
//# sourceMappingURL=wemap-routers.es.js.map
|