@wemap/routers 10.11.0 → 10.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1990 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
+ var __publicField = (obj, key, value) => {
5
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
6
+ return value;
7
+ };
8
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
9
+ const geo = require("@wemap/geo");
10
+ const maths = require("@wemap/maths");
11
+ const osm = require("@wemap/osm");
12
+ const Logger = require("@wemap/logger");
13
+ const Polyline = require("@mapbox/polyline");
14
+ const pointInPolygon = require("@turf/boolean-point-in-polygon");
15
+ const convexHullFn = require("@turf/convex");
16
+ const helpers = require("@turf/helpers");
17
+ const _interopDefaultLegacy = (e) => e && typeof e === "object" && "default" in e ? e : { default: e };
18
+ const Logger__default = /* @__PURE__ */ _interopDefaultLegacy(Logger);
19
+ const Polyline__default = /* @__PURE__ */ _interopDefaultLegacy(Polyline);
20
+ const pointInPolygon__default = /* @__PURE__ */ _interopDefaultLegacy(pointInPolygon);
21
+ const convexHullFn__default = /* @__PURE__ */ _interopDefaultLegacy(convexHullFn);
22
+ function getDurationFromLength(length, speed = 5) {
23
+ return length / (speed * 1e3 / 3600);
24
+ }
25
+ function areLevelChangeEquals(l1, l2) {
26
+ return l1 === l2 || l1.difference === l2.difference && l1.direction === l2.direction && l1.type === l2.type;
27
+ }
28
+ class StepInfo {
29
+ constructor({
30
+ coords,
31
+ distance,
32
+ name,
33
+ levelChange,
34
+ extras,
35
+ duration
36
+ }) {
37
+ __publicField(this, "coords");
38
+ __publicField(this, "name");
39
+ __publicField(this, "distance");
40
+ __publicField(this, "duration");
41
+ __publicField(this, "levelChange");
42
+ __publicField(this, "extras");
43
+ this.coords = coords;
44
+ this.name = name || null;
45
+ this.distance = typeof distance === "number" ? distance : null;
46
+ this.duration = typeof duration === "number" ? duration : null;
47
+ this.levelChange = levelChange || null;
48
+ this.extras = extras || null;
49
+ }
50
+ static equals(obj1, obj2) {
51
+ return obj1.coords.equals(obj2.coords) && obj1.distance === obj2.distance && obj1.duration === obj2.duration && obj1.name === obj2.name && (obj1.levelChange === obj2.levelChange || obj1.levelChange && obj2.levelChange && areLevelChangeEquals(obj1.levelChange, obj2.levelChange));
52
+ }
53
+ equals(obj) {
54
+ return StepInfo.equals(this, obj);
55
+ }
56
+ toJson() {
57
+ return {
58
+ coords: this.coords.toCompressedJson(),
59
+ ...this.distance !== null && { distance: this.distance },
60
+ ...this.duration !== null && { duration: this.duration },
61
+ ...this.name !== null && { name: this.name },
62
+ ...this.levelChange !== null && { levelChange: this.levelChange },
63
+ ...this.extras && Object.keys(this.extras).length !== 0 && { extras: this.extras }
64
+ };
65
+ }
66
+ static fromJson(json) {
67
+ return new StepInfo(Object.assign({}, json, {
68
+ coords: geo.Coordinates.fromCompressedJson(json.coords)
69
+ }));
70
+ }
71
+ }
72
+ const SKIP_STEP_ANGLE_MAX = maths.deg2rad(20);
73
+ function generateSteps(leg, rules) {
74
+ const steps = [];
75
+ const { from, to, coords: coordsArray } = leg;
76
+ let currentStep = null;
77
+ let previousBearing = from.coords.bearingTo(coordsArray[0]);
78
+ for (let i = 0; i < coordsArray.length - 1; i++) {
79
+ const isFirstStep = i === 0;
80
+ const currentCoords = coordsArray[i];
81
+ const nextCoords = coordsArray[i + 1];
82
+ const edgeLevel = geo.Level.union(currentCoords.level, nextCoords.level);
83
+ const nextBearing = currentCoords.bearingTo(nextCoords);
84
+ const angle = maths.diffAngle(previousBearing, nextBearing + Math.PI);
85
+ let splitByAngle = Math.abs(maths.diffAngle(Math.PI, angle)) >= SKIP_STEP_ANGLE_MAX;
86
+ const splitByLevel = geo.Level.isRange(edgeLevel) && !geo.Level.isRange(currentCoords.level);
87
+ splitByAngle = splitByAngle && !(currentCoords.level && geo.Level.isRange(currentCoords.level));
88
+ const customRules = rules == null ? void 0 : rules(currentCoords, nextCoords);
89
+ const splitStepCondition = splitByAngle || splitByLevel || (customRules == null ? void 0 : customRules.createNewStep);
90
+ if (isFirstStep || splitStepCondition) {
91
+ let levelChange;
92
+ if (splitByLevel) {
93
+ const difference = geo.Level.diff(currentCoords.level, nextCoords.level);
94
+ const direction = difference > 0 ? "up" : "down";
95
+ levelChange = { difference, direction, type: customRules == null ? void 0 : customRules.levelChangeType };
96
+ }
97
+ if (currentStep && currentStep.duration === 0) {
98
+ currentStep.duration = null;
99
+ }
100
+ currentStep = new StepInfo({
101
+ coords: currentCoords,
102
+ name: customRules == null ? void 0 : customRules.stepName,
103
+ extras: customRules == null ? void 0 : customRules.stepExtras,
104
+ levelChange,
105
+ distance: 0,
106
+ duration: 0
107
+ });
108
+ steps.push(currentStep);
109
+ }
110
+ currentStep.distance += currentCoords.distanceTo(nextCoords);
111
+ if (customRules == null ? void 0 : customRules.duration) {
112
+ currentStep.duration += customRules == null ? void 0 : customRules.duration;
113
+ }
114
+ previousBearing = nextBearing;
115
+ }
116
+ const lastCoords = coordsArray[coordsArray.length - 1];
117
+ if (!geo.Coordinates.equals(lastCoords, to.coords)) {
118
+ steps.push(new StepInfo({ coords: lastCoords }));
119
+ }
120
+ return steps;
121
+ }
122
+ function isRoutingModePublicTransport(routingMode) {
123
+ return [
124
+ "AIRPLANE",
125
+ "BOAT",
126
+ "BUS",
127
+ "FERRY",
128
+ "FUNICULAR",
129
+ "METRO",
130
+ "TRAIN",
131
+ "TRAM"
132
+ ].includes(routingMode);
133
+ }
134
+ class Leg {
135
+ constructor({
136
+ from,
137
+ to,
138
+ coords,
139
+ mode,
140
+ duration,
141
+ startTime,
142
+ endTime,
143
+ transportInfo,
144
+ ...otherParams
145
+ }) {
146
+ __publicField(this, "from");
147
+ __publicField(this, "to");
148
+ __publicField(this, "coords");
149
+ __publicField(this, "distance");
150
+ __publicField(this, "mode");
151
+ __publicField(this, "duration");
152
+ __publicField(this, "startTime");
153
+ __publicField(this, "endTime");
154
+ __publicField(this, "stepsInfo");
155
+ __publicField(this, "transportInfo");
156
+ this.from = {
157
+ name: from.name || null,
158
+ coords: from.coords
159
+ };
160
+ this.to = {
161
+ name: to.name || null,
162
+ coords: to.coords
163
+ };
164
+ this.coords = coords;
165
+ this.mode = mode;
166
+ this.distance = geo.Utils.calcDistance(coords);
167
+ this.duration = typeof duration === "number" ? duration : getDurationFromLength(this.distance);
168
+ this.startTime = typeof startTime === "number" ? startTime : null;
169
+ this.endTime = typeof endTime === "number" ? endTime : null;
170
+ this.transportInfo = transportInfo || null;
171
+ this.stepsInfo = "stepsInfo" in otherParams ? otherParams.stepsInfo : generateSteps(this, otherParams.stepsGenerationRules);
172
+ }
173
+ isPublicTransport() {
174
+ return isRoutingModePublicTransport(this.mode);
175
+ }
176
+ toNetwork() {
177
+ return geo.Network.fromCoordinates([this.coords]);
178
+ }
179
+ static equals(obj1, obj2) {
180
+ var _a, _b;
181
+ const intermediate = obj1.mode === obj2.mode && obj1.duration === obj2.duration && obj1.startTime === obj2.startTime && obj1.endTime === obj2.endTime && obj1.from.name === obj2.from.name && obj1.from.coords.equals(obj2.from.coords) && obj1.to.name === obj2.to.name && obj1.to.coords.equals(obj2.to.coords) && obj1.coords.length === obj2.coords.length && (obj1.stepsInfo === obj2.stepsInfo || ((_a = obj1.stepsInfo) == null ? void 0 : _a.length) === ((_b = obj2.stepsInfo) == null ? void 0 : _b.length));
182
+ if (!intermediate) {
183
+ return false;
184
+ }
185
+ let i;
186
+ for (i = 0; i < obj1.coords.length; i++) {
187
+ if (!obj1.coords[i].equals(obj2.coords[i])) {
188
+ return false;
189
+ }
190
+ }
191
+ if (obj1.stepsInfo && obj2.stepsInfo) {
192
+ for (i = 0; i < obj1.stepsInfo.length; i++) {
193
+ if (!obj1.stepsInfo[i].equals(obj2.stepsInfo[i])) {
194
+ return false;
195
+ }
196
+ }
197
+ }
198
+ if (obj1.transportInfo !== obj2.transportInfo) {
199
+ if (obj1.transportInfo === null || obj2.transportInfo === null) {
200
+ return false;
201
+ }
202
+ if (obj1.transportInfo.name !== obj2.transportInfo.name || obj1.transportInfo.routeColor !== obj2.transportInfo.routeColor || obj1.transportInfo.routeTextColor !== obj2.transportInfo.routeTextColor || obj1.transportInfo.directionName !== obj2.transportInfo.directionName) {
203
+ return false;
204
+ }
205
+ }
206
+ return true;
207
+ }
208
+ equals(obj) {
209
+ return Leg.equals(this, obj);
210
+ }
211
+ toJson() {
212
+ return {
213
+ mode: this.mode,
214
+ from: {
215
+ coords: this.from.coords.toCompressedJson(),
216
+ ...this.from.name && { name: this.from.name }
217
+ },
218
+ to: {
219
+ coords: this.to.coords.toCompressedJson(),
220
+ ...this.to.name && { name: this.to.name }
221
+ },
222
+ duration: this.duration,
223
+ coords: this.coords.map((coords) => coords.toCompressedJson()),
224
+ steps: this.stepsInfo.map((stepInfo) => stepInfo.toJson()),
225
+ ...this.startTime !== null && { startTime: this.startTime },
226
+ ...this.endTime !== null && { endTime: this.endTime },
227
+ ...this.transportInfo !== null && { transportInfo: this.transportInfo }
228
+ };
229
+ }
230
+ static fromJson(json) {
231
+ var _a;
232
+ const leg = new Leg(Object.assign({}, json, {
233
+ from: {
234
+ coords: geo.Coordinates.fromCompressedJson(json.from.coords),
235
+ name: json.from.name || null
236
+ },
237
+ to: {
238
+ coords: geo.Coordinates.fromCompressedJson(json.to.coords),
239
+ name: json.to.name || null
240
+ },
241
+ coords: json.coords.map(geo.Coordinates.fromCompressedJson),
242
+ stepsInfo: ((_a = json.steps) == null ? void 0 : _a.map(StepInfo.fromJson)) || null,
243
+ stepsGenerationRules: void 0
244
+ }));
245
+ return leg;
246
+ }
247
+ static fromGraphItinerary(graphItinerary, mode = "WALK", stepsGenerationRules) {
248
+ return new Leg({
249
+ from: { coords: graphItinerary.start },
250
+ to: { coords: graphItinerary.end },
251
+ coords: graphItinerary.nodes.map((node) => node.coords),
252
+ duration: graphItinerary.edgesWeights.reduce((acc, weight) => acc + weight, 0),
253
+ mode,
254
+ stepsGenerationRules
255
+ });
256
+ }
257
+ multiplyLevel(levelFactor) {
258
+ this.from.coords.level = geo.Level.multiplyBy(this.from.coords.level, levelFactor);
259
+ this.to.coords.level = geo.Level.multiplyBy(this.to.coords.level, levelFactor);
260
+ for (const coords of this.coords) {
261
+ coords.level = geo.Level.multiplyBy(coords.level, levelFactor);
262
+ }
263
+ this.stepsInfo.forEach((step) => {
264
+ step.coords.level = geo.Level.multiplyBy(step.coords.level, levelFactor);
265
+ });
266
+ }
267
+ getSteps(itinerarySteps) {
268
+ return this.stepsInfo.map((stepInfo) => itinerarySteps.find((_step) => _step.coords.equals(stepInfo.coords)));
269
+ }
270
+ }
271
+ class Itinerary {
272
+ constructor({
273
+ from,
274
+ to,
275
+ duration,
276
+ legs,
277
+ startTime,
278
+ endTime
279
+ }) {
280
+ __publicField(this, "from");
281
+ __publicField(this, "to");
282
+ __publicField(this, "duration");
283
+ __publicField(this, "legs");
284
+ __publicField(this, "_mode", null);
285
+ __publicField(this, "startTime");
286
+ __publicField(this, "endTime");
287
+ __publicField(this, "_coords", null);
288
+ __publicField(this, "_steps", null);
289
+ __publicField(this, "_distance", null);
290
+ this.from = from;
291
+ this.to = to;
292
+ this.legs = legs;
293
+ this.duration = typeof duration === "number" ? duration : this.legs.reduce((dur, leg) => dur + leg.duration, 0);
294
+ this.startTime = typeof startTime === "number" ? startTime : null;
295
+ this.endTime = typeof endTime === "number" ? endTime : null;
296
+ }
297
+ set coords(_) {
298
+ throw new Error("Itinerary.coords cannot be set. They are calculated from Itinerary.legs.");
299
+ }
300
+ get coords() {
301
+ if (!this._coords) {
302
+ this._coords = this.legs.map((leg) => leg.coords).flat().filter((coords, idx, arr) => idx === 0 || !arr[idx - 1].equals(coords));
303
+ }
304
+ return this._coords;
305
+ }
306
+ set steps(_) {
307
+ throw new Error("Itinerary.step cannot be set. They are calculated from Itinerary.legs.");
308
+ }
309
+ get steps() {
310
+ if (this._steps) {
311
+ return this._steps;
312
+ }
313
+ const itineraryCoords = this.coords.filter((coords, idx, arr) => idx === 0 || !arr[idx - 1].equals(coords));
314
+ const stepsInfo = this.legs.map((leg) => leg.stepsInfo).flat();
315
+ const steps = stepsInfo.map((stepInfo, stepId) => {
316
+ const coordsId = itineraryCoords.findIndex((coords) => coords.equals(stepInfo.coords));
317
+ if (coordsId === -1) {
318
+ throw new Error("Cannot find step coordinates in itinerary coordinates.");
319
+ }
320
+ const coordsBeforeStep = coordsId === 0 ? this.from : itineraryCoords[coordsId - 1];
321
+ const coordsAfterStep = coordsId === itineraryCoords.length - 1 ? this.to : itineraryCoords[coordsId + 1];
322
+ const previousBearing = coordsBeforeStep.bearingTo(stepInfo.coords);
323
+ const nextBearing = stepInfo.coords.bearingTo(coordsAfterStep);
324
+ let distance = 0;
325
+ const coordsToStopCalculation = stepId !== stepsInfo.length - 1 ? stepsInfo[stepId + 1].coords : itineraryCoords[itineraryCoords.length - 1];
326
+ let currentCoordsId = coordsId;
327
+ while (!itineraryCoords[currentCoordsId].equals(coordsToStopCalculation)) {
328
+ distance += itineraryCoords[currentCoordsId].distanceTo(itineraryCoords[currentCoordsId + 1]);
329
+ currentCoordsId++;
330
+ }
331
+ if (currentCoordsId === itineraryCoords.length - 1) {
332
+ distance += itineraryCoords[currentCoordsId].distanceTo(this.to);
333
+ }
334
+ return {
335
+ ...stepInfo,
336
+ number: stepId + 1,
337
+ previousBearing,
338
+ nextBearing,
339
+ angle: maths.diffAngle(previousBearing, nextBearing + Math.PI),
340
+ firstStep: stepId === 0,
341
+ lastStep: stepId === stepsInfo.length - 1,
342
+ distance,
343
+ duration: stepInfo.duration || getDurationFromLength(distance),
344
+ previousStep: null,
345
+ nextStep: null
346
+ };
347
+ });
348
+ return steps;
349
+ }
350
+ set mode(_) {
351
+ throw new Error("Itinerary.mode cannot be set. They are calculated from Itinerary.legs.");
352
+ }
353
+ get mode() {
354
+ if (!this._mode) {
355
+ let isPublicTransport = false;
356
+ let isBicycle = false;
357
+ let isDriving = false;
358
+ this.legs.forEach((leg) => {
359
+ isPublicTransport = isPublicTransport || isRoutingModePublicTransport(leg.mode);
360
+ isBicycle = isBicycle || leg.mode === "BIKE";
361
+ isDriving = isDriving || leg.mode === "CAR";
362
+ });
363
+ if (isPublicTransport) {
364
+ this._mode = "PT";
365
+ } else if (isDriving) {
366
+ this._mode = "CAR";
367
+ } else if (isBicycle) {
368
+ this._mode = "BIKE";
369
+ } else {
370
+ this._mode = "WALK";
371
+ }
372
+ }
373
+ return this._mode;
374
+ }
375
+ set distance(_) {
376
+ throw new Error("Itinerary.distance cannot be set. They are calculated from Itinerary.legs.");
377
+ }
378
+ get distance() {
379
+ if (this._distance === null) {
380
+ this._distance = geo.Utils.calcDistance(this.coords);
381
+ }
382
+ return this._distance;
383
+ }
384
+ toNetwork() {
385
+ return geo.Network.fromCoordinates([this.coords]);
386
+ }
387
+ static fromItineraries(...itineraries) {
388
+ let duration = 0;
389
+ const legs = [];
390
+ itineraries.forEach((_itinerary) => {
391
+ duration += _itinerary.duration;
392
+ legs.push(..._itinerary.legs);
393
+ });
394
+ return new Itinerary({
395
+ from: itineraries[0].from,
396
+ to: itineraries[itineraries.length - 1].to,
397
+ duration,
398
+ legs
399
+ });
400
+ }
401
+ static fromOrderedPointsArray(points, start, end) {
402
+ const pointToCoordinates = (point) => new geo.Coordinates(point[0], point[1], null, point[2]);
403
+ return this.fromOrderedCoordinates(
404
+ points.map(pointToCoordinates),
405
+ pointToCoordinates(start),
406
+ pointToCoordinates(end)
407
+ );
408
+ }
409
+ static fromOrderedCoordinates(coords, from, to, mode = "WALK") {
410
+ const leg = new Leg({
411
+ from: { coords: from },
412
+ to: { coords: to },
413
+ coords,
414
+ mode
415
+ });
416
+ return new Itinerary({ from, to, legs: [leg] });
417
+ }
418
+ static equals(obj1, obj2) {
419
+ const intermediate = obj1.from.equals(obj2.from) && obj1.to.equals(obj2.to) && obj1.distance === obj2.distance && obj1.duration === obj2.duration && obj1.startTime === obj2.startTime && obj1.endTime === obj2.endTime && obj1.legs.length === obj2.legs.length;
420
+ if (!intermediate) {
421
+ return false;
422
+ }
423
+ for (let i = 0; i < obj1.legs.length; i++) {
424
+ if (!obj1.legs[i].equals(obj2.legs[i])) {
425
+ return false;
426
+ }
427
+ }
428
+ return true;
429
+ }
430
+ equals(obj) {
431
+ return Itinerary.equals(this, obj);
432
+ }
433
+ toJson() {
434
+ return {
435
+ from: this.from.toCompressedJson(),
436
+ to: this.to.toCompressedJson(),
437
+ duration: this.duration,
438
+ mode: this.mode,
439
+ legs: this.legs.map((leg) => leg.toJson()),
440
+ ...this.startTime !== null && { startTime: this.startTime },
441
+ ...this.endTime !== null && { endTime: this.endTime }
442
+ };
443
+ }
444
+ static fromJson(json) {
445
+ return new Itinerary({
446
+ from: geo.Coordinates.fromCompressedJson(json.from),
447
+ to: geo.Coordinates.fromCompressedJson(json.to),
448
+ duration: json.duration,
449
+ legs: json.legs.map(Leg.fromJson),
450
+ startTime: json.startTime,
451
+ endTime: json.endTime
452
+ });
453
+ }
454
+ static fromGraphItinerary(graphItinerary, mode = "WALK", stepsGenerationRules) {
455
+ const leg = Leg.fromGraphItinerary(graphItinerary, mode, stepsGenerationRules);
456
+ return new Itinerary({
457
+ from: graphItinerary.start,
458
+ to: graphItinerary.end,
459
+ duration: leg.duration,
460
+ legs: [leg]
461
+ });
462
+ }
463
+ multiplyLevel(levelFactor) {
464
+ this.from.level = geo.Level.multiplyBy(this.from.level, levelFactor);
465
+ this.to.level = geo.Level.multiplyBy(this.to.level, levelFactor);
466
+ this.legs.forEach((leg) => leg.multiplyLevel(levelFactor));
467
+ }
468
+ forceUnknownLevelTo0() {
469
+ this.from.level = this.from.level || 0;
470
+ this.to.level = this.to.level || 0;
471
+ for (const leg of this.legs) {
472
+ leg.from.coords.level = leg.from.coords.level || 0;
473
+ leg.to.coords.level = leg.to.coords.level || 0;
474
+ for (const coords of leg.coords) {
475
+ coords.level = coords.level || 0;
476
+ }
477
+ if (leg.stepsInfo) {
478
+ for (const step of leg.stepsInfo) {
479
+ step.coords.level = step.coords.level || 0;
480
+ }
481
+ }
482
+ }
483
+ if (this._coords) {
484
+ for (const coords of this._coords) {
485
+ coords.level = coords.level || 0;
486
+ }
487
+ }
488
+ }
489
+ toGeoJson() {
490
+ return {
491
+ type: "Feature",
492
+ properties: {},
493
+ geometry: {
494
+ type: "MultiLineString",
495
+ coordinates: this.legs.map((leg) => leg.coords.map(({ lat, lng }) => [lng, lat]))
496
+ }
497
+ };
498
+ }
499
+ }
500
+ class RouterResponse {
501
+ constructor({
502
+ routerName,
503
+ from,
504
+ to,
505
+ itineraries,
506
+ error
507
+ }) {
508
+ __publicField(this, "routerName");
509
+ __publicField(this, "from");
510
+ __publicField(this, "to");
511
+ __publicField(this, "itineraries");
512
+ __publicField(this, "error");
513
+ this.routerName = routerName;
514
+ this.from = from;
515
+ this.to = to;
516
+ this.itineraries = itineraries || [];
517
+ this.error = error || null;
518
+ }
519
+ static equals(obj1, obj2) {
520
+ const intermediate = obj1.routerName === obj2.routerName && obj1.from.equals(obj2.from) && obj1.to.equals(obj2.to) && obj1.itineraries.length === obj2.itineraries.length;
521
+ if (!intermediate) {
522
+ return false;
523
+ }
524
+ for (let i = 0; i < obj1.itineraries.length; i++) {
525
+ if (!obj1.itineraries[i].equals(obj2.itineraries[i])) {
526
+ return false;
527
+ }
528
+ }
529
+ return true;
530
+ }
531
+ equals(obj) {
532
+ return RouterResponse.equals(this, obj);
533
+ }
534
+ toJson() {
535
+ return {
536
+ routerName: this.routerName,
537
+ from: this.from.toCompressedJson(),
538
+ to: this.to.toCompressedJson(),
539
+ ...this.itineraries.length && { itineraries: this.itineraries.map((itinerary) => itinerary.toJson()) },
540
+ ...this.error && { error: this.error }
541
+ };
542
+ }
543
+ static fromJson(json) {
544
+ var _a;
545
+ return new RouterResponse({
546
+ routerName: json.routerName,
547
+ from: geo.Coordinates.fromCompressedJson(json.from),
548
+ to: geo.Coordinates.fromCompressedJson(json.to),
549
+ itineraries: (_a = json.itineraries) == null ? void 0 : _a.map(Itinerary.fromJson),
550
+ error: json.error
551
+ });
552
+ }
553
+ multiplyLevel(levelFactor) {
554
+ this.from.level = geo.Level.multiplyBy(this.from.level, levelFactor);
555
+ this.to.level = geo.Level.multiplyBy(this.to.level, levelFactor);
556
+ for (const itinerary of this.itineraries) {
557
+ itinerary.multiplyLevel(levelFactor);
558
+ }
559
+ }
560
+ }
561
+ const _WemapOsmRouterOptions = class extends osm.OsmGraphRouterOptions {
562
+ constructor() {
563
+ super(...arguments);
564
+ __publicField(this, "weightEdgeFn", (edge) => edge.builtFrom instanceof osm.OsmNode && edge.builtFrom.isElevator ? 30 : getDurationFromLength(edge.length));
565
+ }
566
+ static get WITHOUT_STAIRS() {
567
+ const options = new _WemapOsmRouterOptions();
568
+ options.acceptEdgeFn = (edge) => {
569
+ var _a;
570
+ return ((_a = edge.builtFrom) == null ? void 0 : _a.tags.highway) !== "steps";
571
+ };
572
+ return options;
573
+ }
574
+ };
575
+ let WemapOsmRouterOptions = _WemapOsmRouterOptions;
576
+ __publicField(WemapOsmRouterOptions, "DEFAULT", new _WemapOsmRouterOptions());
577
+ const buildStepsRules = (graphItinerary) => (currentCoords, nextCoords) => {
578
+ var _a, _b, _c, _d, _e;
579
+ const edges = graphItinerary.edges;
580
+ const nodes = graphItinerary.nodes;
581
+ const node = geo.GraphUtils.getNodeByCoords(nodes, currentCoords);
582
+ const nextNode = geo.GraphUtils.getNodeByCoords(nodes, nextCoords);
583
+ if (!node || !nextNode)
584
+ return {};
585
+ const edge = geo.GraphUtils.getEdgeByNodes(edges, node, nextNode);
586
+ if (!edge)
587
+ return {};
588
+ const edgeId = edges.findIndex((_edge) => _edge === edge);
589
+ const isSubwayEntrance = node ? ((_a = node.builtFrom) == null ? void 0 : _a.tags.railway) === "subway_entrance" : false;
590
+ const isGate = node ? ((_b = node.builtFrom) == null ? void 0 : _b.tags.barrier) === "gate" || ((_c = node.builtFrom) == null ? void 0 : _c.tags.aeroway) === "gate" : false;
591
+ let levelChangeType = null;
592
+ if (edge.builtFrom instanceof osm.OsmNode && edge.builtFrom.isElevator) {
593
+ levelChangeType = "elevator";
594
+ } else if (edge.builtFrom instanceof osm.OsmNode || edge.builtFrom instanceof osm.OsmWay && edge.builtFrom.isConveying) {
595
+ levelChangeType = "conveyor";
596
+ } else if (edge.builtFrom instanceof osm.OsmWay && edge.builtFrom.areStairs) {
597
+ levelChangeType = "stairs";
598
+ }
599
+ return {
600
+ createNewStep: isSubwayEntrance,
601
+ stepName: (_d = edge.builtFrom) == null ? void 0 : _d.tags.name,
602
+ duration: graphItinerary.edgesWeights[edgeId],
603
+ stepExtras: {
604
+ ...isSubwayEntrance && { isSubwayEntrance: true },
605
+ ...isSubwayEntrance && ((_e = node.builtFrom) == null ? void 0 : _e.tags.ref) && { subwayEntranceRef: node.builtFrom.tags.ref },
606
+ ...isGate && { isGate: true }
607
+ },
608
+ ...levelChangeType && { levelChangeType }
609
+ };
610
+ };
611
+ class WemapOsmRouter extends osm.OsmGraphRouter {
612
+ constructor(network) {
613
+ super(network);
614
+ }
615
+ static get rname() {
616
+ return "wemap";
617
+ }
618
+ getShortestPath(start, end, options = new WemapOsmRouterOptions()) {
619
+ return super.getShortestPath(start, end, options);
620
+ }
621
+ getItinerary(start, end, options = new WemapOsmRouterOptions()) {
622
+ const graphItinerary = this.getShortestPath(start, end, options);
623
+ return Itinerary.fromGraphItinerary(graphItinerary, "WALK", buildStepsRules(graphItinerary));
624
+ }
625
+ }
626
+ class RemoteRouter {
627
+ }
628
+ class RemoteRouterServerUnreachable extends Error {
629
+ constructor(name, endpointUrl) {
630
+ super(`Remote router server ${name} is unreachable. URL: ${endpointUrl}`);
631
+ }
632
+ }
633
+ class RoutingModeCorrespondanceNotFound extends Error {
634
+ constructor(routerName, routingMode) {
635
+ super(`routing mode "${routingMode}" correspondance not found for router "${routerName}"`);
636
+ this.routerName = routerName;
637
+ this.routingMode = routingMode;
638
+ }
639
+ }
640
+ function dateWithTimeZone(year, month, day, hour, minute, second, timeZone = "Europe/Paris") {
641
+ const date = new Date(Date.UTC(year, month, day, hour, minute, second));
642
+ const utcDate = new Date(date.toLocaleString("en-US", { timeZone: "UTC" }));
643
+ const tzDate = new Date(date.toLocaleString("en-US", { timeZone }));
644
+ const offset = utcDate.getTime() - tzDate.getTime();
645
+ date.setTime(date.getTime() + offset);
646
+ return date;
647
+ }
648
+ function isRoutingError(e) {
649
+ return e instanceof RemoteRouterServerUnreachable || e instanceof RoutingModeCorrespondanceNotFound || e instanceof geo.NoRouteFoundError;
650
+ }
651
+ function jsonToCoordinates$2(json) {
652
+ return new geo.Coordinates(json.Lat, json.Long);
653
+ }
654
+ function jsonDateToTimestamp(jsonDate) {
655
+ const [dateStr, timeStr] = jsonDate.split(" ");
656
+ const [dayStr, monthStr, yearStr] = dateStr.split("/");
657
+ const [hoursStr, minutesStr, secondsStr] = timeStr.split(":");
658
+ return dateWithTimeZone(
659
+ Number(yearStr),
660
+ Number(monthStr) - 1,
661
+ Number(dayStr),
662
+ Number(hoursStr),
663
+ Number(minutesStr),
664
+ Number(secondsStr)
665
+ ).getTime();
666
+ }
667
+ const inputModeCorrespondance$2 = /* @__PURE__ */ new Map();
668
+ inputModeCorrespondance$2.set("CAR", "Car");
669
+ inputModeCorrespondance$2.set("WALK", "Walk");
670
+ inputModeCorrespondance$2.set("BIKE", "Bike");
671
+ inputModeCorrespondance$2.set("BUS", "PT");
672
+ inputModeCorrespondance$2.set("MULTI", "PT");
673
+ const routingModeCorrespondance$1 = /* @__PURE__ */ new Map();
674
+ routingModeCorrespondance$1.set("WALK", "WALK");
675
+ routingModeCorrespondance$1.set("BICYCLE", "BIKE");
676
+ routingModeCorrespondance$1.set("TRAMWAY", "TRAM");
677
+ routingModeCorrespondance$1.set("METRO", "METRO");
678
+ routingModeCorrespondance$1.set("FUNICULAR", "FUNICULAR");
679
+ routingModeCorrespondance$1.set("BUS", "BUS");
680
+ routingModeCorrespondance$1.set("COACH", "BUS");
681
+ routingModeCorrespondance$1.set("SCHOOL", "BUS");
682
+ routingModeCorrespondance$1.set("BUS_PMR", "BUS");
683
+ routingModeCorrespondance$1.set("MINIBUS", "BUS");
684
+ routingModeCorrespondance$1.set("TROLLEY_BUS", "BUS");
685
+ routingModeCorrespondance$1.set("TAXIBUS", "BUS");
686
+ routingModeCorrespondance$1.set("SHUTTLE", "BUS");
687
+ routingModeCorrespondance$1.set("TRAIN", "TRAIN");
688
+ routingModeCorrespondance$1.set("HST", "TRAIN");
689
+ routingModeCorrespondance$1.set("LOCAL_TRAIN", "TRAIN");
690
+ routingModeCorrespondance$1.set("AIR", "AIRPLANE");
691
+ routingModeCorrespondance$1.set("FERRY", "BOAT");
692
+ routingModeCorrespondance$1.set("TAXI", "UNKNOWN");
693
+ routingModeCorrespondance$1.set("CAR_POOL", "UNKNOWN");
694
+ routingModeCorrespondance$1.set("PRIVATE_VEHICLE", "CAR");
695
+ routingModeCorrespondance$1.set("SCOOTER", "MOTO");
696
+ const planTripType = /* @__PURE__ */ new Map();
697
+ planTripType.set(0, "BUS");
698
+ planTripType.set(1, "WALK");
699
+ planTripType.set(2, "BIKE");
700
+ planTripType.set(3, "CAR");
701
+ planTripType.set(4, "UNKNOWN");
702
+ planTripType.set(5, "UNKNOWN");
703
+ planTripType.set(6, "UNKNOWN");
704
+ planTripType.set(7, "UNKNOWN");
705
+ planTripType.set(8, "UNKNOWN");
706
+ planTripType.set(9, "UNKNOWN");
707
+ planTripType.set(10, "UNKNOWN");
708
+ planTripType.set(11, "UNKNOWN");
709
+ planTripType.set(12, "UNKNOWN");
710
+ planTripType.set(13, "UNKNOWN");
711
+ planTripType.set(14, "UNKNOWN");
712
+ function parseWKTGeometry(wktGeometry) {
713
+ const tmpCoordsStr = wktGeometry.match(/LINESTRING ?\((.*)\)/i);
714
+ const tmpCoordsPt = wktGeometry.match(/POINT ?\((.*)\)/i);
715
+ if (tmpCoordsPt) {
716
+ const [lng, lat] = tmpCoordsPt[1].split(" ");
717
+ return [new geo.Coordinates(Number(lat), Number(lng))];
718
+ }
719
+ return tmpCoordsStr[1].split(",").map((str) => {
720
+ const sp = str.trim().split(" ");
721
+ return new geo.Coordinates(Number(sp[1]), Number(sp[0]));
722
+ });
723
+ }
724
+ class CitywayRemoteRouter extends RemoteRouter {
725
+ get rname() {
726
+ return "cityway";
727
+ }
728
+ async getItineraries(endpointUrl, mode, waypoints) {
729
+ const url = this.getURL(endpointUrl, mode, waypoints);
730
+ const res = await fetch(url).catch(() => {
731
+ throw new RemoteRouterServerUnreachable(this.rname, url);
732
+ });
733
+ const jsonResponse = await res.json().catch(() => {
734
+ throw new RemoteRouterServerUnreachable(this.rname, url);
735
+ });
736
+ return this.createRouterResponseFromJson(jsonResponse, waypoints[0], waypoints[1]);
737
+ }
738
+ getURL(endpointUrl, mode, waypoints) {
739
+ const citywayMode = inputModeCorrespondance$2.get(mode);
740
+ if (!citywayMode) {
741
+ throw new RoutingModeCorrespondanceNotFound(this.rname, mode);
742
+ }
743
+ if (waypoints.length > 2) {
744
+ Logger__default.default.warn(`${this.rname} router uses only the first 2 waypoints (asked ${waypoints.length})`);
745
+ }
746
+ const fromPlace = `DepartureLatitude=${waypoints[0].latitude}&DepartureLongitude=${waypoints[0].longitude}`;
747
+ const toPlace = `ArrivalLatitude=${waypoints[1].latitude}&ArrivalLongitude=${waypoints[1].longitude}`;
748
+ const queryMode = `TripModes=${citywayMode}`;
749
+ const url = new URL(endpointUrl);
750
+ let { search } = url;
751
+ search = (search ? `${search}&` : "?") + `${fromPlace}&${toPlace}&${queryMode}`;
752
+ return `${url.origin}${url.pathname}${search}`;
753
+ }
754
+ createRouterResponseFromJson(json, from, to) {
755
+ const routerResponse = new RouterResponse({ routerName: this.rname, from, to });
756
+ if (json.StatusCode !== 200 || !json.Data || !json.Data.length) {
757
+ return routerResponse;
758
+ }
759
+ const allJsonTrips = json.Data.map(
760
+ (dataObj) => dataObj.response.trips.Trip.map((trip) => ({
761
+ ...trip,
762
+ ...dataObj.hasOwnProperty("PlanTripType") && { PlanTripType: dataObj.PlanTripType }
763
+ }))
764
+ ).flat();
765
+ itineraryLoop:
766
+ for (const trip of allJsonTrips) {
767
+ if (trip.hasOwnProperty("PlanTripType") && planTripType.get(trip.PlanTripType) === "UNKNOWN") {
768
+ continue;
769
+ }
770
+ const legs = [];
771
+ for (const jsonSection of trip.sections.Section) {
772
+ const jsonLeg = jsonSection.Leg ? jsonSection.Leg : jsonSection.PTRide;
773
+ const legMode = routingModeCorrespondance$1.get(jsonLeg.TransportMode);
774
+ const legCoords = [];
775
+ let legFrom, legTo;
776
+ let transportInfo;
777
+ let stepsInfo;
778
+ if (legMode === "UNKNOWN") {
779
+ continue itineraryLoop;
780
+ }
781
+ if (legMode === "WALK" || legMode === "BIKE" || legMode === "CAR") {
782
+ legFrom = {
783
+ name: jsonLeg.Departure.Site.Name,
784
+ coords: jsonToCoordinates$2(jsonLeg.Departure.Site.Position)
785
+ };
786
+ legTo = {
787
+ name: jsonLeg.Arrival.Site.Name,
788
+ coords: jsonToCoordinates$2(jsonLeg.Arrival.Site.Position)
789
+ };
790
+ stepsInfo = [];
791
+ for (const jsonPathLink of jsonLeg.pathLinks.PathLink) {
792
+ let stepCoords;
793
+ if (jsonPathLink.Geometry && jsonPathLink.Geometry !== "Null") {
794
+ stepCoords = parseWKTGeometry(jsonPathLink.Geometry);
795
+ } else {
796
+ stepCoords = [legFrom.coords, legTo.coords];
797
+ }
798
+ stepCoords.forEach((coords, idx) => {
799
+ if (idx !== 0 || legCoords.length === 0 || !legCoords[legCoords.length - 1].equals(coords)) {
800
+ legCoords.push(coords);
801
+ }
802
+ });
803
+ stepsInfo.push(new StepInfo({
804
+ coords: stepCoords[0],
805
+ distance: jsonPathLink.Distance,
806
+ name: jsonPathLink.Departure.Site.Name
807
+ }));
808
+ }
809
+ } else if (isRoutingModePublicTransport(legMode)) {
810
+ legFrom = {
811
+ name: jsonLeg.Departure.StopPlace.Name,
812
+ coords: jsonToCoordinates$2(jsonLeg.Departure.StopPlace.Position)
813
+ };
814
+ legTo = {
815
+ name: jsonLeg.Arrival.StopPlace.Name,
816
+ coords: jsonToCoordinates$2(jsonLeg.Arrival.StopPlace.Position)
817
+ };
818
+ let transportName = jsonLeg.Line.Number;
819
+ if (legMode === "TRAM" && transportName.toLowerCase().includes("tram")) {
820
+ transportName = transportName.substr(5);
821
+ }
822
+ transportInfo = {
823
+ name: transportName,
824
+ routeColor: jsonLeg.Line.Color,
825
+ routeTextColor: jsonLeg.Line.TextColor,
826
+ directionName: jsonLeg.Destination
827
+ };
828
+ for (const jsonStep of jsonLeg.steps.Step) {
829
+ const stepCoords = parseWKTGeometry(jsonStep.Geometry);
830
+ stepCoords.forEach((coords, idx) => {
831
+ if (idx !== 0 || legCoords.length === 0 || !legCoords[legCoords.length - 1].equals(coords)) {
832
+ legCoords.push(coords);
833
+ }
834
+ });
835
+ }
836
+ stepsInfo = [new StepInfo({
837
+ coords: legCoords[0],
838
+ name: jsonLeg.Line.Name,
839
+ distance: jsonLeg.Distance
840
+ })];
841
+ } else {
842
+ Logger__default.default.warn(`[CitywayParser] Unknown leg mode: ${jsonLeg.TransportMode}`);
843
+ continue;
844
+ }
845
+ const leg = new Leg({
846
+ mode: legMode,
847
+ duration: this.parseDuration(jsonLeg.Duration),
848
+ startTime: jsonDateToTimestamp(jsonLeg.Departure.Time),
849
+ endTime: jsonDateToTimestamp(jsonLeg.Arrival.Time),
850
+ coords: legCoords,
851
+ from: legFrom,
852
+ to: legTo,
853
+ transportInfo
854
+ });
855
+ legs.push(leg);
856
+ }
857
+ const itinerary = new Itinerary({
858
+ duration: this.parseDuration(trip.Duration),
859
+ startTime: jsonDateToTimestamp(trip.Departure.Time),
860
+ from: jsonToCoordinates$2(trip.Departure.Site.Position),
861
+ endTime: jsonDateToTimestamp(trip.Arrival.Time),
862
+ to: jsonToCoordinates$2(trip.Arrival.Site.Position),
863
+ legs
864
+ });
865
+ routerResponse.itineraries.push(itinerary);
866
+ }
867
+ return routerResponse;
868
+ }
869
+ parseDuration(iso8601Duration) {
870
+ const iso8601DurationRegex = /(-)?P(?:([.,\d]+)Y)?(?:([.,\d]+)M)?(?:([.,\d]+)W)?(?:([.,\d]+)D)?T(?:([.,\d]+)H)?(?:([.,\d]+)M)?(?:([.,\d]+)S)?/;
871
+ const matches = iso8601Duration.match(iso8601DurationRegex);
872
+ const years = typeof matches[2] === "undefined" ? 0 : Number(matches[2]);
873
+ const months = typeof matches[3] === "undefined" ? 0 : Number(matches[3]);
874
+ const weeks = typeof matches[4] === "undefined" ? 0 : Number(matches[4]);
875
+ const days = typeof matches[5] === "undefined" ? 0 : Number(matches[5]);
876
+ const hours = typeof matches[6] === "undefined" ? 0 : Number(matches[6]);
877
+ const minutes = typeof matches[7] === "undefined" ? 0 : Number(matches[7]);
878
+ const seconds = typeof matches[8] === "undefined" ? 0 : Number(matches[8]);
879
+ return seconds + minutes * 60 + hours * 3600 + days * 86400 + weeks * (86400 * 7) + months * (86400 * 30) + years * (86400 * 365.25);
880
+ }
881
+ }
882
+ const CitywayRemoteRouter$1 = new CitywayRemoteRouter();
883
+ class DeutscheBahnRemoteRouter extends RemoteRouter {
884
+ get rname() {
885
+ return "deutsche-bahn";
886
+ }
887
+ async getItineraries(endpointUrl, mode, waypoints) {
888
+ const url = this.getURL(endpointUrl, mode, waypoints);
889
+ const res = await fetch(url).catch(() => {
890
+ throw new RemoteRouterServerUnreachable(this.rname, url);
891
+ });
892
+ const jsonResponse = await res.json().catch(() => {
893
+ throw new RemoteRouterServerUnreachable(this.rname, url);
894
+ });
895
+ return this.createRouterResponseFromJson(jsonResponse, waypoints[0], waypoints[1]);
896
+ }
897
+ getURL(endpointUrl, mode, waypoints) {
898
+ let url = endpointUrl + "/route/v1/walking/";
899
+ url += waypoints.map((waypoint) => {
900
+ if (waypoint.level !== null) {
901
+ const altitude = geo.Level.isRange(waypoint.level) ? waypoint.level[0] : waypoint.level;
902
+ return waypoint.longitude + "," + waypoint.latitude + "," + altitude;
903
+ }
904
+ return waypoint.longitude + "," + waypoint.latitude;
905
+ }).join(";");
906
+ url += "?geometries=geojson&overview=full&steps=true";
907
+ return url;
908
+ }
909
+ createRouterResponseFromJson(json, from, to) {
910
+ const routerResponse = new RouterResponse({ routerName: this.rname, from, to });
911
+ if (!json.segments) {
912
+ return routerResponse;
913
+ }
914
+ const legs = json.segments.map((segment) => {
915
+ const level = geo.Level.union(segment.fromLevel, segment.toLevel);
916
+ const coords = segment.polyline.map(
917
+ ({ lon, lat }) => new geo.Coordinates(lat, lon, null, level)
918
+ );
919
+ return new Leg({
920
+ mode: "WALK",
921
+ coords,
922
+ from: { coords: coords[0] },
923
+ to: { coords: coords[coords.length - 1] }
924
+ });
925
+ });
926
+ routerResponse.itineraries = [new Itinerary({ from, to, legs })];
927
+ return routerResponse;
928
+ }
929
+ }
930
+ const DeutscheBahnRemoteRouter$1 = new DeutscheBahnRemoteRouter();
931
+ const routingModeCorrespondance = /* @__PURE__ */ new Map();
932
+ routingModeCorrespondance.set("Air", "AIRPLANE");
933
+ routingModeCorrespondance.set("Boat", "BOAT");
934
+ routingModeCorrespondance.set("Bus", "BUS");
935
+ routingModeCorrespondance.set("BusRapidTransit", "BUS");
936
+ routingModeCorrespondance.set("Coach", "BUS");
937
+ routingModeCorrespondance.set("Ferry", "FERRY");
938
+ routingModeCorrespondance.set("Funicular", "FUNICULAR");
939
+ routingModeCorrespondance.set("LocalTrain", "TRAIN");
940
+ routingModeCorrespondance.set("LongDistanceTrain", "TRAIN");
941
+ routingModeCorrespondance.set("Metro", "METRO");
942
+ routingModeCorrespondance.set("M\xE9tro", "METRO");
943
+ routingModeCorrespondance.set("RailShuttle", "TRAIN");
944
+ routingModeCorrespondance.set("RapidTransit", "BUS");
945
+ routingModeCorrespondance.set("Shuttle", "BUS");
946
+ routingModeCorrespondance.set("SuspendedCableCar", "FUNICULAR");
947
+ routingModeCorrespondance.set("Taxi", "TAXI");
948
+ routingModeCorrespondance.set("Train", "TRAIN");
949
+ routingModeCorrespondance.set("RER", "TRAIN");
950
+ routingModeCorrespondance.set("Tramway", "TRAM");
951
+ routingModeCorrespondance.set("walking", "WALK");
952
+ routingModeCorrespondance.set("bike", "BIKE");
953
+ const TRANSPORT_IDS = [
954
+ "physical_mode:Air",
955
+ "physical_mode:Boat",
956
+ "physical_mode:Bus",
957
+ "physical_mode:BusRapidTransit",
958
+ "physical_mode:Coach",
959
+ "physical_mode:Ferry",
960
+ "physical_mode:Funicular",
961
+ "physical_mode:LocalTrain",
962
+ "physical_mode:LongDistanceTrain",
963
+ "physical_mode:Metro",
964
+ "physical_mode:RailShuttle",
965
+ "physical_mode:RapidTransit",
966
+ "physical_mode:Shuttle",
967
+ "physical_mode:SuspendedCableCar",
968
+ "physical_mode:Taxi",
969
+ "physical_mode:Train",
970
+ "physical_mode:Tramway"
971
+ ];
972
+ const apiKey = "qWHj6ax6DMttG8DX6tH9CQARaiTgQ1Di";
973
+ function jsonToCoordinates$1(json) {
974
+ return new geo.Coordinates(Number(json.lat), Number(json.lon));
975
+ }
976
+ function last(array) {
977
+ return array[array.length - 1];
978
+ }
979
+ function dateStringToTimestamp(stringDate, timeZone) {
980
+ const yearStr = stringDate.substr(0, 4);
981
+ const monthStr = stringDate.substr(4, 2);
982
+ const dayStr = stringDate.substr(6, 2);
983
+ const hoursStr = stringDate.substr(9, 2);
984
+ const minutesStr = stringDate.substr(11, 2);
985
+ const secondsStr = stringDate.substr(13, 2);
986
+ return dateWithTimeZone(
987
+ Number(yearStr),
988
+ Number(monthStr) - 1,
989
+ Number(dayStr),
990
+ Number(hoursStr),
991
+ Number(minutesStr),
992
+ Number(secondsStr),
993
+ timeZone
994
+ ).getTime();
995
+ }
996
+ class IdfmRemoteRouter extends RemoteRouter {
997
+ get rname() {
998
+ return "idfm";
999
+ }
1000
+ async getItineraries(endpointUrl, mode, waypoints) {
1001
+ const url = this.getURL(endpointUrl, mode, waypoints);
1002
+ const res = await fetch(url, {
1003
+ method: "GET",
1004
+ headers: { apiKey }
1005
+ }).catch(() => {
1006
+ throw new RemoteRouterServerUnreachable(this.rname, url);
1007
+ });
1008
+ const jsonResponse = await res.json().catch(() => {
1009
+ throw new RemoteRouterServerUnreachable(this.rname, url);
1010
+ });
1011
+ if (jsonResponse && jsonResponse.error) {
1012
+ return new RouterResponse({
1013
+ routerName: this.rname,
1014
+ from: waypoints[0],
1015
+ to: waypoints[1],
1016
+ error: jsonResponse.error.message || "no details."
1017
+ });
1018
+ }
1019
+ return this.createRouterResponseFromJson(jsonResponse, waypoints[0], waypoints[1]);
1020
+ }
1021
+ getURL(endpointUrl, mode, waypoints) {
1022
+ if (waypoints.length > 2) {
1023
+ Logger__default.default.warn(`${this.rname} router uses only the first 2 waypoints (asked ${waypoints.length})`);
1024
+ }
1025
+ const fromPlace = `from=${waypoints[0].longitude};${waypoints[0].latitude}`;
1026
+ const toPlace = `to=${waypoints[1].longitude};${waypoints[1].latitude}`;
1027
+ const url = new URL(endpointUrl);
1028
+ let { search } = url;
1029
+ search = (search ? `${search}&` : "?") + `${fromPlace}&${toPlace}`;
1030
+ let query = "";
1031
+ switch (mode) {
1032
+ case "WALK":
1033
+ query = this.getWalkingQuery();
1034
+ break;
1035
+ case "BIKE":
1036
+ query = this.getBikeQuery();
1037
+ break;
1038
+ case "CAR":
1039
+ query = this.getCarQuery();
1040
+ break;
1041
+ }
1042
+ return `${url.origin}${url.pathname}${search}${query}`;
1043
+ }
1044
+ getCarQuery() {
1045
+ const forbiddenTransport = TRANSPORT_IDS.map((id) => `forbidden_uris[]=${id}`).join("&");
1046
+ const allowCar = "first_section_mode[]=walking&first_section_mode[]=car&last_section_mode[]=walking&last_section_mode[]=car";
1047
+ return `&${forbiddenTransport}&${allowCar}`;
1048
+ }
1049
+ getWalkingQuery() {
1050
+ const forbiddenTransport = TRANSPORT_IDS.map((id) => `forbidden_uris[]=${id}`).join("&");
1051
+ const allowWalking = "first_section_mode[]=walking&last_section_mode[]=walking";
1052
+ return `&${forbiddenTransport}&${allowWalking}`;
1053
+ }
1054
+ getBikeQuery() {
1055
+ const forbiddenTransport = TRANSPORT_IDS.map((id) => `forbidden_uris[]=${id}`).join("&");
1056
+ const allowBike = "first_section_mode[]=bike&last_section_mode[]=bike";
1057
+ return `&${forbiddenTransport}&${allowBike}`;
1058
+ }
1059
+ getSectionCoords(section) {
1060
+ const from = section.from.stop_point ? jsonToCoordinates$1(section.from.stop_point.coord) : jsonToCoordinates$1(section.from.address.coord);
1061
+ const to = section.to.stop_point ? jsonToCoordinates$1(section.to.stop_point.coord) : jsonToCoordinates$1(section.to.address.coord);
1062
+ return {
1063
+ from,
1064
+ to
1065
+ };
1066
+ }
1067
+ findStepsCoord(legCoords, steps) {
1068
+ const coords = legCoords;
1069
+ const duplicatedCoords = [...coords];
1070
+ let previousStep = steps[0];
1071
+ let accumulatedIndex = 0;
1072
+ const outputSteps = [];
1073
+ for (const [idx, step] of steps.entries()) {
1074
+ let newCoords;
1075
+ let _idCoordsInLeg;
1076
+ if (idx === 0) {
1077
+ _idCoordsInLeg = 0;
1078
+ newCoords = coords[0];
1079
+ } else if (idx === steps.length - 1) {
1080
+ _idCoordsInLeg = coords.length - 1;
1081
+ newCoords = last(coords);
1082
+ } else if (duplicatedCoords.length === 1) {
1083
+ accumulatedIndex++;
1084
+ _idCoordsInLeg = accumulatedIndex;
1085
+ newCoords = duplicatedCoords[0];
1086
+ coords[_idCoordsInLeg] = newCoords;
1087
+ } else {
1088
+ const result = geo.Utils.trimRoute(duplicatedCoords, duplicatedCoords[0], previousStep.distance);
1089
+ accumulatedIndex += result.length - 1;
1090
+ duplicatedCoords.splice(0, result.length - 1);
1091
+ _idCoordsInLeg = accumulatedIndex;
1092
+ newCoords = last(result);
1093
+ coords[_idCoordsInLeg] = newCoords;
1094
+ }
1095
+ outputSteps.push({
1096
+ ...step,
1097
+ coords: newCoords
1098
+ });
1099
+ previousStep = step;
1100
+ }
1101
+ return outputSteps;
1102
+ }
1103
+ createRouterResponseFromJson(json, from, to) {
1104
+ var _a;
1105
+ const routerResponse = new RouterResponse({ routerName: this.rname, from, to });
1106
+ if (!json || !json.journeys) {
1107
+ return routerResponse;
1108
+ }
1109
+ const timeZone = json.context.timezone;
1110
+ for (const jsonItinerary of json.journeys) {
1111
+ const legs = [];
1112
+ for (const jsonSection of jsonItinerary.sections) {
1113
+ if (jsonSection.type === "waiting" || jsonSection.type === "transfer") {
1114
+ continue;
1115
+ }
1116
+ const { from: fromSection, to: toSection } = this.getSectionCoords(jsonSection);
1117
+ let existingCoords = [];
1118
+ const legCoords = jsonSection.geojson.coordinates.reduce((acc, [lon, lat]) => {
1119
+ if (!existingCoords.includes(`${lon}-${lat}`)) {
1120
+ existingCoords = existingCoords.concat(`${lon}-${lat}`);
1121
+ acc.push(new geo.Coordinates(lat, lon));
1122
+ }
1123
+ return acc;
1124
+ }, []);
1125
+ let stepsInfo;
1126
+ if (jsonSection.path) {
1127
+ const idfmIntermediateSteps = [];
1128
+ for (const jsonPathLink of jsonSection.path) {
1129
+ idfmIntermediateSteps.push({
1130
+ name: jsonPathLink.name,
1131
+ distance: jsonPathLink.length
1132
+ });
1133
+ }
1134
+ stepsInfo = this.findStepsCoord(legCoords, idfmIntermediateSteps);
1135
+ }
1136
+ const leg = new Leg({
1137
+ mode: routingModeCorrespondance.get(jsonSection.mode),
1138
+ duration: jsonSection.duration,
1139
+ startTime: dateStringToTimestamp(jsonSection.departure_date_time, timeZone),
1140
+ endTime: dateStringToTimestamp(jsonSection.arrival_date_time, timeZone),
1141
+ from: {
1142
+ name: jsonSection.from.name,
1143
+ coords: fromSection
1144
+ },
1145
+ to: {
1146
+ name: jsonSection.to.name,
1147
+ coords: toSection
1148
+ },
1149
+ coords: legCoords,
1150
+ stepsInfo
1151
+ });
1152
+ if (jsonSection.type === "public_transport") {
1153
+ leg.transportInfo = {
1154
+ name: jsonSection.display_informations.code,
1155
+ routeColor: jsonSection.display_informations.color,
1156
+ routeTextColor: jsonSection.display_informations.text_color,
1157
+ directionName: jsonSection.display_informations.direction
1158
+ };
1159
+ leg.mode = routingModeCorrespondance.get(jsonSection.display_informations.physical_mode);
1160
+ const legStep = new StepInfo({
1161
+ coords: leg.coords[0],
1162
+ name: (_a = leg.transportInfo) == null ? void 0 : _a.directionName,
1163
+ distance: jsonSection.geojson.properties[0].length
1164
+ });
1165
+ leg.stepsInfo = [legStep];
1166
+ }
1167
+ legs.push(leg);
1168
+ }
1169
+ const itinerary = new Itinerary({
1170
+ duration: jsonItinerary.duration,
1171
+ startTime: dateStringToTimestamp(jsonItinerary.departure_date_time, timeZone),
1172
+ endTime: dateStringToTimestamp(jsonItinerary.arrival_date_time, timeZone),
1173
+ from: this.getSectionCoords(jsonItinerary.sections[0]).from,
1174
+ to: this.getSectionCoords(last(jsonItinerary.sections)).to,
1175
+ legs
1176
+ });
1177
+ routerResponse.itineraries.push(itinerary);
1178
+ }
1179
+ return routerResponse;
1180
+ }
1181
+ }
1182
+ const IdfmRemoteRouter$1 = new IdfmRemoteRouter();
1183
+ const inputModeCorrespondance$1 = /* @__PURE__ */ new Map();
1184
+ inputModeCorrespondance$1.set("CAR", "driving");
1185
+ inputModeCorrespondance$1.set("WALK", "walking");
1186
+ inputModeCorrespondance$1.set("BIKE", "bike");
1187
+ inputModeCorrespondance$1.set("BUS", "bus");
1188
+ inputModeCorrespondance$1.set("MULTI", "walking");
1189
+ class OsrmRemoteRouter extends RemoteRouter {
1190
+ get rname() {
1191
+ return "osrm";
1192
+ }
1193
+ async getItineraries(endpointUrl, mode, waypoints) {
1194
+ const url = this.getURL(endpointUrl, mode, waypoints);
1195
+ const res = await fetch(url).catch(() => {
1196
+ throw new RemoteRouterServerUnreachable(this.rname, url);
1197
+ });
1198
+ const jsonResponse = await res.json().catch(() => {
1199
+ throw new RemoteRouterServerUnreachable(this.rname, url);
1200
+ });
1201
+ const from = waypoints[0];
1202
+ const to = waypoints[waypoints.length - 1];
1203
+ return this.createRouterResponseFromJson(jsonResponse, from, to);
1204
+ }
1205
+ getURL(endpointUrl, mode, waypoints) {
1206
+ const osrmMode = inputModeCorrespondance$1.get(mode);
1207
+ if (!osrmMode) {
1208
+ throw new RoutingModeCorrespondanceNotFound(this.rname, mode);
1209
+ }
1210
+ let url = endpointUrl + "/route/v1/" + osrmMode + "/";
1211
+ url += waypoints.map((waypoint) => [waypoint.longitude + "," + waypoint.latitude]).join(";");
1212
+ url += "?geometries=geojson&overview=full&steps=true";
1213
+ return url;
1214
+ }
1215
+ coordinatesToJson({ lat, lng, level }) {
1216
+ if (level === null) {
1217
+ return [lng, lat];
1218
+ }
1219
+ if (geo.Level.isRange(level)) {
1220
+ return [lng, lat, level[0]];
1221
+ }
1222
+ return [lng, lat, level];
1223
+ }
1224
+ jsonToCoordinates(json) {
1225
+ const coords = new geo.Coordinates(json[1], json[0]);
1226
+ if (json.length > 2) {
1227
+ coords.level = json[2];
1228
+ }
1229
+ return coords;
1230
+ }
1231
+ getModifierFromAngle(_angle) {
1232
+ const angle = maths.positiveMod(maths.rad2deg(_angle), 360);
1233
+ if (angle > 0 && angle < 60) {
1234
+ return "sharp right";
1235
+ }
1236
+ if (angle >= 60 && angle < 140) {
1237
+ return "right";
1238
+ }
1239
+ if (angle >= 140 && angle < 160) {
1240
+ return "slight right";
1241
+ }
1242
+ if (angle >= 160 && angle <= 200) {
1243
+ return "straight";
1244
+ }
1245
+ if (angle > 200 && angle <= 220) {
1246
+ return "slight left";
1247
+ }
1248
+ if (angle > 220 && angle <= 300) {
1249
+ return "left";
1250
+ }
1251
+ if (angle > 300 && angle < 360) {
1252
+ return "sharp left";
1253
+ }
1254
+ return "u turn";
1255
+ }
1256
+ noRouteFoundJson(message) {
1257
+ return {
1258
+ "code": "NoRoute",
1259
+ message
1260
+ };
1261
+ }
1262
+ itineraryToOsrmJson(itinerary) {
1263
+ const lastLegId = itinerary.legs.length - 1;
1264
+ const itinerarySteps = itinerary.steps;
1265
+ const jsonLegs = itinerary.legs.map(({ distance, duration, coords }, idLeg) => {
1266
+ const legSteps = itinerarySteps.filter(
1267
+ (step) => coords.find((_coords) => _coords.equals(step.coords))
1268
+ );
1269
+ const lastStepId = legSteps.length - 1;
1270
+ return {
1271
+ distance,
1272
+ duration: duration || 0,
1273
+ steps: legSteps.map((step, idStep, arr) => {
1274
+ let type = idStep === 0 && idLeg === 0 ? "depart" : "turn";
1275
+ type = idStep === lastStepId && idLeg === lastLegId ? "arrive" : type;
1276
+ const stepCoordsIdx = coords.findIndex((p) => p.equals(step.coords));
1277
+ const nextStepCoordsIdx = idStep === lastStepId ? stepCoordsIdx : coords.findIndex((p) => p.equals(arr[idStep + 1].coords));
1278
+ const osrmStep = {
1279
+ geometry: {
1280
+ type: "LineString",
1281
+ coordinates: coords.slice(stepCoordsIdx, nextStepCoordsIdx + 1).map(this.coordinatesToJson)
1282
+ },
1283
+ distance: step.distance,
1284
+ duration: step.duration || 0,
1285
+ ...step.name && { name: step.name },
1286
+ maneuver: {
1287
+ bearing_before: maths.rad2deg(step.previousBearing),
1288
+ bearing_after: maths.rad2deg(step.nextBearing),
1289
+ location: this.coordinatesToJson(step.coords),
1290
+ modifier: this.getModifierFromAngle(step.angle),
1291
+ type
1292
+ }
1293
+ };
1294
+ return osrmStep;
1295
+ })
1296
+ };
1297
+ });
1298
+ return {
1299
+ "code": "Ok",
1300
+ "routes": [
1301
+ {
1302
+ "geometry": {
1303
+ "type": "LineString",
1304
+ "coordinates": itinerary.coords.map(this.coordinatesToJson)
1305
+ },
1306
+ "legs": jsonLegs,
1307
+ "distance": itinerary.distance,
1308
+ "duration": itinerary.duration,
1309
+ "weight_name": "routability",
1310
+ "weight": 0
1311
+ }
1312
+ ],
1313
+ "waypoints": []
1314
+ };
1315
+ }
1316
+ createRouterResponseFromJson(json, from, to, routingMode = "walking") {
1317
+ const routerResponse = new RouterResponse({ routerName: this.rname, from, to });
1318
+ const { routes: jsonRoutes } = json;
1319
+ if (!jsonRoutes) {
1320
+ return routerResponse;
1321
+ }
1322
+ const routingModeCorrespondance2 = /* @__PURE__ */ new Map();
1323
+ routingModeCorrespondance2.set("walking", "WALK");
1324
+ routingModeCorrespondance2.set("driving", "CAR");
1325
+ routingModeCorrespondance2.set("bicycle", "BIKE");
1326
+ const mode = routingModeCorrespondance2.get(routingMode) || "WALK";
1327
+ routerResponse.itineraries = jsonRoutes.map((jsonItinerary) => {
1328
+ const legs = jsonItinerary.legs.map((jsonLeg) => {
1329
+ var _a;
1330
+ const legCoords = jsonLeg.steps.map((step) => step.geometry.coordinates.map(this.jsonToCoordinates)).flat().filter((coords, idx, arr) => idx === 0 || !arr[idx - 1].equals(coords));
1331
+ const stepsInfo = (_a = jsonLeg.steps) == null ? void 0 : _a.map(({ maneuver, name, distance, duration }) => {
1332
+ const stepCoords = this.jsonToCoordinates(maneuver.location);
1333
+ const distances = legCoords.map((coords) => coords.distanceTo(stepCoords));
1334
+ const idStepCoordsInLeg = distances.indexOf(Math.min(...distances));
1335
+ if (idStepCoordsInLeg < 0) {
1336
+ throw new Error("Osrm Parser: Cannot find step coords in leg coordinates");
1337
+ }
1338
+ return new StepInfo({
1339
+ coords: stepCoords,
1340
+ name,
1341
+ distance,
1342
+ duration
1343
+ });
1344
+ });
1345
+ return new Leg({
1346
+ mode,
1347
+ duration: jsonLeg.duration,
1348
+ coords: legCoords,
1349
+ from: {
1350
+ coords: legCoords[0]
1351
+ },
1352
+ to: {
1353
+ coords: legCoords[legCoords.length - 1]
1354
+ },
1355
+ stepsInfo
1356
+ });
1357
+ });
1358
+ return new Itinerary({
1359
+ duration: jsonItinerary.duration,
1360
+ from,
1361
+ to,
1362
+ legs
1363
+ });
1364
+ });
1365
+ return routerResponse;
1366
+ }
1367
+ }
1368
+ const OsrmRemoteRouter$1 = new OsrmRemoteRouter();
1369
+ function isLegPT(leg) {
1370
+ return leg.mode === "BUS" || leg.mode === "TRAM";
1371
+ }
1372
+ function jsonToCoordinates(json) {
1373
+ return new geo.Coordinates(json.lat, json.lon);
1374
+ }
1375
+ const inputModeCorrespondance = /* @__PURE__ */ new Map();
1376
+ inputModeCorrespondance.set("CAR", "CAR");
1377
+ inputModeCorrespondance.set("WALK", "WALK");
1378
+ inputModeCorrespondance.set("BIKE", "BICYCLE");
1379
+ inputModeCorrespondance.set("BUS", "WALK,TRANSIT");
1380
+ inputModeCorrespondance.set("MULTI", "WALK,TRANSIT");
1381
+ class OtpRemoteRouter extends RemoteRouter {
1382
+ get rname() {
1383
+ return "otp";
1384
+ }
1385
+ async getItineraries(endpointUrl, mode, waypoints) {
1386
+ const url = this.getURL(endpointUrl, mode, waypoints);
1387
+ const res = await fetch(url).catch(() => {
1388
+ throw new RemoteRouterServerUnreachable(this.rname, url);
1389
+ });
1390
+ const jsonResponse = await res.json().catch(() => {
1391
+ throw new RemoteRouterServerUnreachable(this.rname, url);
1392
+ });
1393
+ return this.createRouterResponseFromJson(jsonResponse, waypoints[0], waypoints[1]);
1394
+ }
1395
+ getURL(endpointUrl, mode, waypoints) {
1396
+ const otpMode = inputModeCorrespondance.get(mode);
1397
+ if (!otpMode) {
1398
+ throw new RoutingModeCorrespondanceNotFound(this.rname, mode);
1399
+ }
1400
+ if (waypoints.length > 2) {
1401
+ Logger__default.default.warn(`${this.rname} router uses only the first 2 waypoints (asked ${waypoints.length})`);
1402
+ }
1403
+ const fromPlace = `fromPlace=${waypoints[0].latitude},${waypoints[0].longitude}`;
1404
+ const toPlace = `toPlace=${waypoints[1].latitude},${waypoints[1].longitude}`;
1405
+ const queryMode = `mode=${otpMode}`;
1406
+ const url = new URL(endpointUrl);
1407
+ let { search } = url;
1408
+ search = (search ? `${search}&` : "?") + `${fromPlace}&${toPlace}&${queryMode}`;
1409
+ return `${url.origin}${url.pathname}${search}`;
1410
+ }
1411
+ createRouterResponseFromJson(json, from, to) {
1412
+ const routerResponse = new RouterResponse({ routerName: this.rname, from, to });
1413
+ const { plan: jsonPlan } = json;
1414
+ if (!jsonPlan) {
1415
+ return routerResponse;
1416
+ }
1417
+ const itinerariesFrom = jsonToCoordinates(jsonPlan.from);
1418
+ const itinerariesTo = jsonToCoordinates(jsonPlan.to);
1419
+ for (const jsonItinerary of jsonPlan.itineraries) {
1420
+ const legs = [];
1421
+ for (const jsonLeg of jsonItinerary.legs) {
1422
+ const legCoords = Polyline__default.default.decode(jsonLeg.legGeometry.points).map(([lat, lon]) => new geo.Coordinates(lat, lon));
1423
+ let transportInfo;
1424
+ let stepsInfo;
1425
+ if (isLegPT(jsonLeg)) {
1426
+ transportInfo = {
1427
+ name: jsonLeg.routeShortName,
1428
+ routeColor: jsonLeg.routeColor,
1429
+ routeTextColor: jsonLeg.routeTextColor,
1430
+ directionName: jsonLeg.headsign
1431
+ };
1432
+ stepsInfo = [new StepInfo({
1433
+ coords: legCoords[0],
1434
+ name: jsonLeg.headsign
1435
+ })];
1436
+ } else {
1437
+ stepsInfo = jsonLeg.steps.map((jsonStep) => {
1438
+ const distances = legCoords.map((coords) => coords.distanceTo(jsonToCoordinates(jsonStep)));
1439
+ const idStepCoordsInLeg = distances.indexOf(Math.min(...distances));
1440
+ if (idStepCoordsInLeg < 0) {
1441
+ throw new Error("OTP Parser: Cannot find closest step");
1442
+ }
1443
+ return new StepInfo({
1444
+ coords: legCoords[idStepCoordsInLeg],
1445
+ name: jsonStep.streetName
1446
+ });
1447
+ });
1448
+ }
1449
+ const leg = new Leg({
1450
+ mode: jsonLeg.mode,
1451
+ duration: jsonLeg.duration,
1452
+ startTime: jsonLeg.startTime,
1453
+ endTime: jsonLeg.endTime,
1454
+ from: {
1455
+ name: jsonLeg.from.name,
1456
+ coords: jsonToCoordinates(jsonLeg.from)
1457
+ },
1458
+ to: {
1459
+ name: jsonLeg.to.name,
1460
+ coords: jsonToCoordinates(jsonLeg.to)
1461
+ },
1462
+ coords: legCoords,
1463
+ transportInfo,
1464
+ stepsInfo
1465
+ });
1466
+ legs.push(leg);
1467
+ }
1468
+ const itinerary = new Itinerary({
1469
+ duration: jsonItinerary.duration,
1470
+ startTime: jsonItinerary.startTime,
1471
+ endTime: jsonItinerary.endTime,
1472
+ from: itinerariesFrom,
1473
+ to: itinerariesTo,
1474
+ legs
1475
+ });
1476
+ routerResponse.itineraries.push(itinerary);
1477
+ }
1478
+ return routerResponse;
1479
+ }
1480
+ }
1481
+ const OtpRemoteRouter$1 = new OtpRemoteRouter();
1482
+ class WemapMultiRemoteRouterPayload {
1483
+ constructor(waypoints, mode, options = null) {
1484
+ this.waypoints = waypoints;
1485
+ this.mode = mode;
1486
+ this.options = options;
1487
+ }
1488
+ toJson() {
1489
+ return {
1490
+ waypoints: this.waypoints.map((coords) => coords.toCompressedJson()),
1491
+ mode: this.mode,
1492
+ ...this.options && { options: this.options }
1493
+ };
1494
+ }
1495
+ static fromJson(json) {
1496
+ return new WemapMultiRemoteRouterPayload(
1497
+ json.waypoints.map(geo.Coordinates.fromCompressedJson),
1498
+ json.mode,
1499
+ json.options
1500
+ );
1501
+ }
1502
+ }
1503
+ class WemapMultiRemoteRouter extends RemoteRouter {
1504
+ get rname() {
1505
+ return "wemap-meta";
1506
+ }
1507
+ async getItineraries(endpointUrl, mode, waypoints, options) {
1508
+ const payload = new WemapMultiRemoteRouterPayload(
1509
+ waypoints,
1510
+ mode,
1511
+ options
1512
+ );
1513
+ const res = await fetch(endpointUrl, {
1514
+ method: "POST",
1515
+ headers: {
1516
+ "Accept": "application/json",
1517
+ "Content-Type": "application/json"
1518
+ },
1519
+ body: JSON.stringify(payload.toJson())
1520
+ }).catch(() => {
1521
+ throw new RemoteRouterServerUnreachable(this.rname, endpointUrl);
1522
+ });
1523
+ const jsonResponse = await res.json().catch(() => {
1524
+ throw new RemoteRouterServerUnreachable(this.rname, endpointUrl);
1525
+ });
1526
+ return RouterResponse.fromJson(jsonResponse);
1527
+ }
1528
+ }
1529
+ const WemapMultiRemoteRouter$1 = new WemapMultiRemoteRouter();
1530
+ class RemoteRouterManager {
1531
+ constructor() {
1532
+ __publicField(this, "remoteRouters", [
1533
+ CitywayRemoteRouter$1,
1534
+ DeutscheBahnRemoteRouter$1,
1535
+ IdfmRemoteRouter$1,
1536
+ OsrmRemoteRouter$1,
1537
+ OtpRemoteRouter$1,
1538
+ WemapMultiRemoteRouter$1
1539
+ ]);
1540
+ }
1541
+ getRouterByName(name) {
1542
+ return this.remoteRouters.find((remoteRouter) => remoteRouter.rname === name);
1543
+ }
1544
+ async getItineraries(name, endpointUrl, mode, waypoints, options) {
1545
+ const router = this.getRouterByName(name);
1546
+ if (!router) {
1547
+ throw new Error(`Unknown "${name}" remote router`);
1548
+ }
1549
+ return router.getItineraries(endpointUrl, mode, waypoints, options);
1550
+ }
1551
+ async getItinerariesWithFallback(remoteRouters, mode, waypoints, options) {
1552
+ let routerResponse;
1553
+ for (const { name, endpointUrl } of remoteRouters) {
1554
+ routerResponse = await this.getItineraries(name, endpointUrl, mode, waypoints, options);
1555
+ if (routerResponse.itineraries.length) {
1556
+ return routerResponse;
1557
+ }
1558
+ }
1559
+ if (!routerResponse) {
1560
+ routerResponse = new RouterResponse({
1561
+ routerName: remoteRouters.map((rr) => rr.name),
1562
+ from: waypoints[0],
1563
+ to: waypoints[waypoints.length]
1564
+ });
1565
+ }
1566
+ return routerResponse;
1567
+ }
1568
+ }
1569
+ const RemoteRouterManager$1 = new RemoteRouterManager();
1570
+ const getRouterNameArray = (routerResponse) => Array.isArray(routerResponse.routerName) ? routerResponse.routerName : [routerResponse.routerName];
1571
+ class WemapMultiRouter {
1572
+ constructor() {
1573
+ __publicField(this, "maps", []);
1574
+ }
1575
+ get rname() {
1576
+ return "wemap-meta";
1577
+ }
1578
+ addIOMap(customNetworkMap) {
1579
+ this.maps.push(customNetworkMap);
1580
+ }
1581
+ removeIOMap(customNetworkMap) {
1582
+ this.maps = this.maps.filter((map) => map !== customNetworkMap);
1583
+ }
1584
+ async getItineraries(mode, waypoints, options) {
1585
+ var _a;
1586
+ if (waypoints.length > 2) {
1587
+ Logger__default.default.warn(`WemapMultiRouter uses only the first 2 waypoints (asked ${waypoints.length})`);
1588
+ }
1589
+ const start = waypoints[0];
1590
+ const end = waypoints[1];
1591
+ const routerResponse = new RouterResponse({
1592
+ routerName: this.rname,
1593
+ from: start,
1594
+ to: end
1595
+ });
1596
+ const remoteRouters = ((_a = options.remoteRouters) == null ? void 0 : _a.filter(({ name }) => name !== WemapMultiRemoteRouter$1.rname)) || [];
1597
+ let ioMapsToTest = this.maps;
1598
+ const { targetMaps } = options;
1599
+ if (targetMaps) {
1600
+ ioMapsToTest = this.maps.filter((map) => map.name && targetMaps.includes(map.name));
1601
+ if (ioMapsToTest.length !== targetMaps.length) {
1602
+ ioMapsToTest.forEach((map) => {
1603
+ if (map.name && !targetMaps.includes(map.name)) {
1604
+ Logger__default.default.warn(`CustomNetworkMap "${map.name}" not found in WemapMultiRouter`);
1605
+ }
1606
+ });
1607
+ }
1608
+ }
1609
+ if (!ioMapsToTest.length) {
1610
+ try {
1611
+ return await RemoteRouterManager$1.getItinerariesWithFallback(remoteRouters, mode, waypoints);
1612
+ } catch (e) {
1613
+ if (!isRoutingError(e)) {
1614
+ throw e;
1615
+ }
1616
+ routerResponse.error = e.message;
1617
+ return routerResponse;
1618
+ }
1619
+ }
1620
+ let ioMapItinerary;
1621
+ const mapWithStart = ioMapsToTest.find((map) => map.isPointInside(start));
1622
+ const wemapOsmRouterOptions = !("useStairs" in options) && options.useStairs ? WemapOsmRouterOptions.DEFAULT : WemapOsmRouterOptions.WITHOUT_STAIRS;
1623
+ if (mapWithStart && mapWithStart.isPointInside(end)) {
1624
+ try {
1625
+ ioMapItinerary = mapWithStart.getItineraryInsideMap(start, end, wemapOsmRouterOptions);
1626
+ } catch (e) {
1627
+ if (!isRoutingError(e)) {
1628
+ throw e;
1629
+ }
1630
+ routerResponse.error = `${e.message} - on map ${mapWithStart.name}.`;
1631
+ return routerResponse;
1632
+ }
1633
+ routerResponse.itineraries.push(ioMapItinerary);
1634
+ routerResponse.routerName = [this.rname, WemapOsmRouter.rname];
1635
+ return routerResponse;
1636
+ }
1637
+ const mapWithEnd = ioMapsToTest.find((map) => map.isPointInside(end));
1638
+ let remoteRouterResponse;
1639
+ if (!mapWithStart && !mapWithEnd) {
1640
+ try {
1641
+ return await RemoteRouterManager$1.getItinerariesWithFallback(remoteRouters, mode, waypoints);
1642
+ } catch (e) {
1643
+ if (!isRoutingError(e)) {
1644
+ throw e;
1645
+ }
1646
+ routerResponse.error = e.message;
1647
+ return routerResponse;
1648
+ }
1649
+ }
1650
+ if (mapWithStart && !mapWithEnd) {
1651
+ if (!mapWithStart.entryPoints.length) {
1652
+ routerResponse.error = `A map including the "start" but the "end" has been
1653
+ found (${mapWithStart.name}), however, no "entrypoints" have been found to go out`;
1654
+ return routerResponse;
1655
+ }
1656
+ try {
1657
+ ioMapItinerary = mapWithStart.getBestItineraryFromStartToEntryPoints(start, end, wemapOsmRouterOptions);
1658
+ remoteRouterResponse = await RemoteRouterManager$1.getItinerariesWithFallback(
1659
+ remoteRouters,
1660
+ mode,
1661
+ [ioMapItinerary.to, end]
1662
+ );
1663
+ if (!remoteRouterResponse.itineraries.length) {
1664
+ throw new geo.NoRouteFoundError(ioMapItinerary.to, end, remoteRouterResponse.error);
1665
+ }
1666
+ } catch (e) {
1667
+ if (!isRoutingError(e)) {
1668
+ throw e;
1669
+ }
1670
+ routerResponse.error = `Tried to calculate an itinerary from "start" to "entrypoints" using wemap router on local map "${mapWithStart.name}" and an itinerary from "entrypoints" to "end" using remote routers (${remoteRouters.map((r) => r.name).join(", ")}), but failed. Details: ${e.message}.`;
1671
+ return routerResponse;
1672
+ }
1673
+ routerResponse.itineraries = remoteRouterResponse.itineraries.map(
1674
+ (remoteRouterItinerary) => Itinerary.fromItineraries(ioMapItinerary, remoteRouterItinerary)
1675
+ );
1676
+ routerResponse.routerName = [this.rname, ...getRouterNameArray(remoteRouterResponse), WemapOsmRouter.rname];
1677
+ return routerResponse;
1678
+ }
1679
+ if (!mapWithStart && mapWithEnd) {
1680
+ if (!mapWithEnd.entryPoints.length) {
1681
+ routerResponse.error = `A map including the "end" but the "start" has been
1682
+ found (${mapWithEnd.name}), however, no "entrypoints" have been found to go in`;
1683
+ return routerResponse;
1684
+ }
1685
+ try {
1686
+ ioMapItinerary = mapWithEnd.getBestItineraryFromEntryPointsToEnd(start, end, wemapOsmRouterOptions);
1687
+ remoteRouterResponse = await RemoteRouterManager$1.getItinerariesWithFallback(
1688
+ remoteRouters,
1689
+ mode,
1690
+ [start, ioMapItinerary.from]
1691
+ );
1692
+ if (!remoteRouterResponse.itineraries.length) {
1693
+ throw new geo.NoRouteFoundError(start, ioMapItinerary.from, remoteRouterResponse.error);
1694
+ }
1695
+ } catch (e) {
1696
+ if (!isRoutingError(e)) {
1697
+ throw e;
1698
+ }
1699
+ routerResponse.error = `Tried to calculate an itinerary from "start" to "entrypoints" using remote routers (${remoteRouters.map((r) => r.name).join(", ")}) and an itinerary from "entrypoints" to "end" using wemap router on local map "${mapWithEnd.name}", but failed. Details: ${e.message}.`;
1700
+ return routerResponse;
1701
+ }
1702
+ routerResponse.itineraries = remoteRouterResponse.itineraries.map(
1703
+ (remoteRouterItinerary) => Itinerary.fromItineraries(remoteRouterItinerary, ioMapItinerary)
1704
+ );
1705
+ routerResponse.routerName = [this.rname, ...getRouterNameArray(remoteRouterResponse), WemapOsmRouter.rname];
1706
+ return routerResponse;
1707
+ }
1708
+ if (mapWithStart && mapWithEnd) {
1709
+ if (!mapWithStart.entryPoints.length) {
1710
+ routerResponse.error = `One map including the "start" (${mapWithStart.name}) and another
1711
+ including the "end" (${mapWithEnd.name}) has been found, however, no "entrypoints" have
1712
+ been found to go out of the start map`;
1713
+ return routerResponse;
1714
+ }
1715
+ if (!mapWithEnd.entryPoints.length) {
1716
+ routerResponse.error = `One map including the "start" (${mapWithStart.name}) and another
1717
+ including the "end" (${mapWithEnd.name}) has been found, however, no "entrypoints" have
1718
+ been found to go in the second map`;
1719
+ return routerResponse;
1720
+ }
1721
+ let ioMapItinerary1, ioMapItinerary2;
1722
+ try {
1723
+ ioMapItinerary1 = mapWithStart.getBestItineraryFromStartToEntryPoints(start, end, wemapOsmRouterOptions);
1724
+ ioMapItinerary2 = mapWithEnd.getBestItineraryFromEntryPointsToEnd(start, end, wemapOsmRouterOptions);
1725
+ remoteRouterResponse = await RemoteRouterManager$1.getItinerariesWithFallback(
1726
+ remoteRouters,
1727
+ mode,
1728
+ [ioMapItinerary1.to, ioMapItinerary2.from]
1729
+ );
1730
+ if (!remoteRouterResponse.itineraries.length) {
1731
+ throw new geo.NoRouteFoundError(ioMapItinerary1.to, ioMapItinerary2.from, remoteRouterResponse.error);
1732
+ }
1733
+ } catch (e) {
1734
+ if (!isRoutingError(e)) {
1735
+ throw e;
1736
+ }
1737
+ routerResponse.error = `Tried to calculate an itinerary from "start" to "entrypoints1" using wemap router on local map "${mapWithStart.name}", an itinerary from "entrypoints1" to "entrypoints2" using remote routers (${remoteRouters.map((r) => r.name).join(", ")}) and an itinerary from "entrypoints2" to "end" using wemap router on local map "${mapWithEnd.name}", but failed. Details: ${e.message}.`;
1738
+ return routerResponse;
1739
+ }
1740
+ routerResponse.itineraries = remoteRouterResponse.itineraries.map(
1741
+ (remoteRouterItinerary) => Itinerary.fromItineraries(
1742
+ ioMapItinerary1,
1743
+ remoteRouterItinerary,
1744
+ ioMapItinerary2
1745
+ )
1746
+ );
1747
+ routerResponse.routerName = [this.rname, ...getRouterNameArray(remoteRouterResponse), WemapOsmRouter.rname];
1748
+ return routerResponse;
1749
+ }
1750
+ throw new Error("Should never happen");
1751
+ }
1752
+ }
1753
+ class CustomNetworkMap {
1754
+ constructor(network, entryPoints, bounds = null, name = null) {
1755
+ __publicField(this, "name");
1756
+ __publicField(this, "network");
1757
+ __publicField(this, "router");
1758
+ __publicField(this, "bounds");
1759
+ __publicField(this, "entryPoints");
1760
+ __publicField(this, "disabledWays", /* @__PURE__ */ new Set());
1761
+ this.name = name;
1762
+ this.network = network;
1763
+ this.router = new WemapOsmRouter(network);
1764
+ entryPoints.forEach((entryPoint) => {
1765
+ if (!network.nodes.includes(entryPoint)) {
1766
+ throw new Error(`Cannot find entry point ${entryPoint.coords.toString()} in network "${name}"`);
1767
+ }
1768
+ });
1769
+ this.entryPoints = entryPoints;
1770
+ if (bounds) {
1771
+ this.bounds = helpers.polygon([bounds.map((coords) => [coords.lng, coords.lat])]);
1772
+ } else {
1773
+ const polygon = [network.nodes.map((node) => [node.coords.lng, node.coords.lat])];
1774
+ const convexHull = convexHullFn__default.default({ type: "polygon", coordinates: polygon });
1775
+ if (!convexHull) {
1776
+ throw new Error(`Cannot calculate convexHull of network "${name}"`);
1777
+ }
1778
+ this.bounds = convexHull;
1779
+ }
1780
+ }
1781
+ static fromOsmXml(osmXmlString, name = null) {
1782
+ const osmModel = osm.OsmParser.parseOsmXmlString(osmXmlString);
1783
+ const network = osm.OsmNetworkUtils.createNetworkFromOsmModel(osmModel);
1784
+ const entryPoints = osmModel.nodes.filter(({ tags }) => tags && tags["wemap:routing-io"]).map((osmNode) => network.getNodeByCoords(osmNode.coords));
1785
+ if (entryPoints.some((el) => el === null) || new Set(entryPoints).size !== entryPoints.length) {
1786
+ throw new Error("Cannot parse wemap:routing-io correctly");
1787
+ }
1788
+ const wayBounds = osmModel.ways.find(({ tags }) => tags["wemap:routing-bounds"]);
1789
+ if (!wayBounds) {
1790
+ throw new Error('Search bounds is undefined. Please use OSM tag : "wemap:routing-bounds=yes"');
1791
+ }
1792
+ const bounds = wayBounds.nodes.map((node) => node.coords);
1793
+ return new CustomNetworkMap(network, entryPoints, bounds, name);
1794
+ }
1795
+ isPointInside(coordinates) {
1796
+ return pointInPolygon__default.default([coordinates.lng, coordinates.lat], this.bounds);
1797
+ }
1798
+ getOrderedEntryPointsSortedByDistance(start, end) {
1799
+ const entryPointsCopy = [...this.entryPoints];
1800
+ return entryPointsCopy.sort(
1801
+ (ep1, ep2) => Number(ep1.coords.distanceTo(start)) + ep1.coords.distanceTo(end) - ep2.coords.distanceTo(start) - ep2.coords.distanceTo(end)
1802
+ );
1803
+ }
1804
+ getBestItineraryFromEntryPointsToEnd(start, end, options) {
1805
+ const sortedEntryPoints = this.getOrderedEntryPointsSortedByDistance(start, end);
1806
+ for (const entryPoint of sortedEntryPoints) {
1807
+ const itinerary = this.router.getItinerary(entryPoint, end, options);
1808
+ if (itinerary) {
1809
+ return itinerary;
1810
+ }
1811
+ }
1812
+ throw new geo.NoRouteFoundError(
1813
+ start,
1814
+ end,
1815
+ `No route found from entry points to ${end.toString()} in map: ${this.name}`
1816
+ );
1817
+ }
1818
+ getBestItineraryFromStartToEntryPoints(start, end, options) {
1819
+ const sortedEntryPoints = this.getOrderedEntryPointsSortedByDistance(start, end);
1820
+ for (const entryPoint of sortedEntryPoints) {
1821
+ const itinerary = this.router.getItinerary(start, entryPoint, options);
1822
+ if (itinerary) {
1823
+ return itinerary;
1824
+ }
1825
+ }
1826
+ throw new geo.NoRouteFoundError(
1827
+ start,
1828
+ end,
1829
+ `No route found from ${start.toString()} to entry points in map: ${this.name}`
1830
+ );
1831
+ }
1832
+ getItineraryInsideMap(start, end, options) {
1833
+ return this.router.getItinerary(start, end, options);
1834
+ }
1835
+ enableWay(osmId) {
1836
+ this.network.edges.filter((edge) => {
1837
+ var _a;
1838
+ return ((_a = edge.builtFrom) == null ? void 0 : _a.id) === osmId;
1839
+ }).forEach((e) => this.router.disabledEdges.delete(e));
1840
+ this.disabledWays.delete(osmId);
1841
+ }
1842
+ disableWay(osmId) {
1843
+ this.network.edges.filter((edge) => {
1844
+ var _a;
1845
+ return ((_a = edge.builtFrom) == null ? void 0 : _a.id) === osmId;
1846
+ }).forEach((e) => this.router.disabledEdges.add(e));
1847
+ this.disabledWays.add(osmId);
1848
+ }
1849
+ }
1850
+ function getTurnInfoFromAngle(_angle) {
1851
+ let direction, directionExtra;
1852
+ const directionAngle = maths.rad2deg(maths.diffAngle(_angle, Math.PI));
1853
+ const directionAngleAbs = Math.abs(directionAngle);
1854
+ if (directionAngleAbs <= 20) {
1855
+ direction = "straight";
1856
+ } else {
1857
+ direction = directionAngle > 0 ? "left" : "right";
1858
+ if (directionAngleAbs < 55) {
1859
+ directionExtra = "slight";
1860
+ } else if (directionAngleAbs > 120) {
1861
+ directionExtra = "sharp";
1862
+ }
1863
+ }
1864
+ return { direction, directionExtra };
1865
+ }
1866
+ const WemapOsmRouterUtils = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1867
+ __proto__: null,
1868
+ getTurnInfoFromAngle
1869
+ }, Symbol.toStringTag, { value: "Module" }));
1870
+ class ItineraryInfoManager {
1871
+ constructor(itinerary = null) {
1872
+ __publicField(this, "_itinerary", null);
1873
+ __publicField(this, "_mapMatching", null);
1874
+ __publicField(this, "_steps", []);
1875
+ __publicField(this, "_coordsNextStep", []);
1876
+ __publicField(this, "_coordsPreviousStep", []);
1877
+ __publicField(this, "_coordsDistanceTraveled", []);
1878
+ __publicField(this, "_coordsLeg", []);
1879
+ this.itinerary = itinerary;
1880
+ }
1881
+ get itinerary() {
1882
+ return this._itinerary;
1883
+ }
1884
+ set itinerary(itinerary) {
1885
+ if (itinerary === null) {
1886
+ this._itinerary = null;
1887
+ return;
1888
+ }
1889
+ this._itinerary = itinerary;
1890
+ this._steps = itinerary.steps;
1891
+ const network = itinerary.toNetwork();
1892
+ this._mapMatching = new geo.MapMatching(network);
1893
+ this._coordsNextStep = new Array(itinerary.coords.length);
1894
+ this._coordsPreviousStep = new Array(itinerary.coords.length);
1895
+ this._coordsDistanceTraveled = new Array(itinerary.coords.length);
1896
+ this._coordsLeg = new Array(itinerary.coords.length);
1897
+ let stepId = 0;
1898
+ let previousStep = null;
1899
+ let nextStep = this._steps[0];
1900
+ let distanceTraveled = 0;
1901
+ itinerary.coords.forEach((coords, idx, arr) => {
1902
+ if (idx !== 0) {
1903
+ distanceTraveled += arr[idx - 1].distanceTo(coords);
1904
+ }
1905
+ this._coordsNextStep[idx] = nextStep;
1906
+ this._coordsPreviousStep[idx] = previousStep;
1907
+ this._coordsDistanceTraveled[idx] = distanceTraveled;
1908
+ this._coordsLeg[idx] = itinerary.legs.find((leg) => leg.coords.includes(coords));
1909
+ if (stepId < this._steps.length && this._steps[stepId].coords.equals(coords)) {
1910
+ previousStep = this._steps[stepId];
1911
+ nextStep = stepId === this._steps.length - 1 ? null : this._steps[stepId + 1];
1912
+ stepId++;
1913
+ }
1914
+ });
1915
+ }
1916
+ getInfo(position) {
1917
+ if (!this._itinerary || !this._mapMatching) {
1918
+ return null;
1919
+ }
1920
+ const projection = this._mapMatching.getProjection(position);
1921
+ if (!projection) {
1922
+ return null;
1923
+ }
1924
+ let itineraryInfo = null;
1925
+ if (projection.nearestElement instanceof geo.GraphNode) {
1926
+ const idx = this._itinerary.coords.findIndex(
1927
+ (coords) => projection.nearestElement.coords === coords
1928
+ );
1929
+ if (idx === -1) {
1930
+ throw new Error("ItineraryInfoManager: could not find projection in itinerary (Node)");
1931
+ }
1932
+ const traveledDistance = this._coordsDistanceTraveled[idx];
1933
+ const remainingDistance = this._itinerary.distance - traveledDistance;
1934
+ itineraryInfo = {
1935
+ nextStep: this._coordsNextStep[idx],
1936
+ previousStep: this._coordsPreviousStep[idx],
1937
+ projection,
1938
+ leg: this._coordsLeg[idx],
1939
+ traveledDistance,
1940
+ remainingDistance,
1941
+ traveledPercentage: traveledDistance / this._itinerary.distance,
1942
+ remainingPercentage: remainingDistance / this._itinerary.distance
1943
+ };
1944
+ } else if (projection.nearestElement instanceof geo.GraphEdge) {
1945
+ let firstNode = projection.nearestElement.node1.coords;
1946
+ let idx = this._itinerary.coords.findIndex((coords) => firstNode === coords);
1947
+ if (idx === -1) {
1948
+ throw new Error("ItineraryInfoManager: could not find projection in itinerary (Edge)");
1949
+ }
1950
+ if (idx === this._itinerary.coords.length - 1 || this._itinerary.coords[idx + 1] !== projection.nearestElement.node2.coords) {
1951
+ firstNode = projection.nearestElement.node2.coords;
1952
+ idx--;
1953
+ }
1954
+ const traveledDistance = this._coordsDistanceTraveled[idx] + projection.coords.distanceTo(firstNode);
1955
+ const remainingDistance = this._itinerary.distance - traveledDistance;
1956
+ itineraryInfo = {
1957
+ nextStep: this._coordsNextStep[idx + 1],
1958
+ previousStep: this._coordsPreviousStep[idx + 1],
1959
+ projection,
1960
+ leg: this._coordsLeg[idx + 1],
1961
+ traveledDistance,
1962
+ remainingDistance,
1963
+ traveledPercentage: traveledDistance / this._itinerary.distance,
1964
+ remainingPercentage: remainingDistance / this._itinerary.distance
1965
+ };
1966
+ }
1967
+ return itineraryInfo;
1968
+ }
1969
+ }
1970
+ exports.CitywayRemoteRouter = CitywayRemoteRouter$1;
1971
+ exports.DeutscheBahnRemoteRouter = DeutscheBahnRemoteRouter$1;
1972
+ exports.IdfmRemoteRouter = IdfmRemoteRouter$1;
1973
+ exports.Itinerary = Itinerary;
1974
+ exports.ItineraryInfoManager = ItineraryInfoManager;
1975
+ exports.Leg = Leg;
1976
+ exports.OsrmRemoteRouter = OsrmRemoteRouter$1;
1977
+ exports.OtpRemoteRouter = OtpRemoteRouter$1;
1978
+ exports.RemoteRouterManager = RemoteRouterManager$1;
1979
+ exports.RemoteRouterServerUnreachable = RemoteRouterServerUnreachable;
1980
+ exports.RouterResponse = RouterResponse;
1981
+ exports.StepInfo = StepInfo;
1982
+ exports.WemapMetaRouterIOMap = CustomNetworkMap;
1983
+ exports.WemapMultiRemoteRouter = WemapMultiRemoteRouter$1;
1984
+ exports.WemapMultiRemoteRouterPayload = WemapMultiRemoteRouterPayload;
1985
+ exports.WemapMultiRouter = WemapMultiRouter;
1986
+ exports.WemapOsmRouter = WemapOsmRouter;
1987
+ exports.WemapOsmRouterOptions = WemapOsmRouterOptions;
1988
+ exports.WemapOsmRouterUtils = WemapOsmRouterUtils;
1989
+ exports.getDurationFromLength = getDurationFromLength;
1990
+ //# sourceMappingURL=index.js.map