@wemap/routers 12.11.3 → 12.11.4

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.
@@ -0,0 +1,1214 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => {
4
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
+ return value;
6
+ };
7
+ import { Level, Coordinates, BoundingBox, UserPosition, Constants, Utils } from "@wemap/geo";
8
+ import { diffAngleLines, deg2rad, diffAngle, positiveMod, rad2deg } from "@wemap/maths";
9
+ import Logger from "@wemap/logger";
10
+ const _Edge = class _Edge {
11
+ constructor(vertex1, vertex2, properties = {}, id = _Edge.currentUniqueId++) {
12
+ __publicField(this, "level");
13
+ /** Edge bearing from vertex1 to vertex2 */
14
+ __publicField(this, "bearing");
15
+ __publicField(this, "length");
16
+ this.vertex1 = vertex1;
17
+ this.vertex2 = vertex2;
18
+ this.properties = properties;
19
+ this.id = id;
20
+ this.level = Level.union(vertex1.coords.level, vertex2.coords.level);
21
+ this.length = this.vertex1.distanceTo(this.vertex2);
22
+ this.bearing = this.vertex1.bearingTo(this.vertex2);
23
+ }
24
+ static getEdgeByVertices(edges, vertex1, vertex2) {
25
+ return edges.find(
26
+ (edge) => vertex1 === edge.vertex1 && vertex2 === edge.vertex2 || vertex2 === edge.vertex1 && vertex1 === edge.vertex2
27
+ );
28
+ }
29
+ reverseProperties() {
30
+ const { properties } = this;
31
+ if (properties.incline) {
32
+ properties.incline = properties.incline === "up" ? "down" : "up";
33
+ }
34
+ if (properties.isOneway) {
35
+ properties.isOneway = false;
36
+ }
37
+ }
38
+ };
39
+ __publicField(_Edge, "currentUniqueId", 0);
40
+ let Edge = _Edge;
41
+ class GraphProjection {
42
+ constructor(origin, distanceFromNearestElement, coords, nearestElement) {
43
+ this.origin = origin;
44
+ this.distanceFromNearestElement = distanceFromNearestElement;
45
+ this.coords = coords;
46
+ this.nearestElement = nearestElement;
47
+ }
48
+ }
49
+ class Vertex {
50
+ constructor(coords, properties = {}) {
51
+ __publicField(this, "id", -1);
52
+ this.coords = coords;
53
+ this.properties = properties;
54
+ }
55
+ distanceTo(other) {
56
+ return this.coords.distanceTo(other.coords);
57
+ }
58
+ bearingTo(other) {
59
+ return this.coords.bearingTo(other.coords);
60
+ }
61
+ toJson() {
62
+ return {
63
+ id: this.id,
64
+ coords: this.coords.toCompressedJson(),
65
+ ...Object.keys(this.properties).length > 0 && { properties: this.properties }
66
+ };
67
+ }
68
+ static fromJson(json) {
69
+ const v = new Vertex(
70
+ Coordinates.fromCompressedJson(json.coords),
71
+ json.properties
72
+ );
73
+ v.id = json.id;
74
+ return v;
75
+ }
76
+ }
77
+ class Graph {
78
+ constructor(vertices, edges) {
79
+ /**
80
+ * exitVertices are vertices that have at least one indoor edge and one outdoor edge
81
+ * They are stored because the Level model cannot handle an indoor and outdoor state like [null, 1] or [null, [1,2]]
82
+ * This vertices are used to cover the projection case:
83
+ * - if projection origin is null, an exit vertex can be used
84
+ * - if projection origin is not null, the intersection level with an exit vertex can be used
85
+ */
86
+ __publicField(this, "exitVertices");
87
+ this.vertices = vertices;
88
+ this.edges = edges;
89
+ const nullVertices = edges.filter((e) => e.level === null).map((e) => [e.vertex1, e.vertex2]).flat();
90
+ const levelVertices = edges.filter((e) => e.level !== null).map((e) => [e.vertex1, e.vertex2]).flat();
91
+ this.exitVertices = new Set(nullVertices.filter((v1) => levelVertices.includes(v1)));
92
+ }
93
+ getEdgeByVertices(vertex1, vertex2) {
94
+ return Edge.getEdgeByVertices(this.edges, vertex1, vertex2);
95
+ }
96
+ getVertexByCoords(coords) {
97
+ return Graph.getVertexByCoords(this.vertices, coords);
98
+ }
99
+ static getVertexByCoords(vertices, coords) {
100
+ return vertices.find((vertex) => vertex.coords.equals(coords));
101
+ }
102
+ getVertexByName(name) {
103
+ return this.vertices.find((vertex) => vertex.properties.name === name);
104
+ }
105
+ getEdgeByName(name) {
106
+ return this.edges.find((edge) => edge.properties.name === name);
107
+ }
108
+ getBoundingBox(extendedMeasure) {
109
+ if (!this.vertices.length) {
110
+ return null;
111
+ }
112
+ const boundingBox = BoundingBox.fromCoordinates(this.vertices.map((vertex) => vertex.coords));
113
+ if (extendedMeasure) {
114
+ boundingBox.extendsWithMeasure(extendedMeasure);
115
+ }
116
+ return boundingBox;
117
+ }
118
+ getProjection(origin, options = {}) {
119
+ const useMaxDistance = "maxDistance" in options;
120
+ const maxDistance = options.maxDistance;
121
+ const useMaxBearingAngle = "maxBearingAngle" in options;
122
+ if (useMaxBearingAngle && (!(origin instanceof UserPosition) || origin.bearing === null))
123
+ return null;
124
+ const maxBearingAngle = options.maxBearingAngle;
125
+ const useAcceptEdgeFn = "acceptEdgeFn" in options;
126
+ const useMultiLevelSegments = !("useMultiLevelSegments" in options) || options.useMultiLevelSegments;
127
+ let bestProjection = null;
128
+ const adaptProjectionCoords = (projCoords) => {
129
+ if (!(origin instanceof UserPosition))
130
+ return projCoords;
131
+ const p = origin.clone();
132
+ p.lat = projCoords.lat;
133
+ p.lng = projCoords.lng;
134
+ p.level = projCoords.level;
135
+ p.alt = projCoords.alt;
136
+ p.heightFromFloor = projCoords.heightFromFloor;
137
+ p.heightFromGround = projCoords.heightFromGround;
138
+ return p;
139
+ };
140
+ this.edges.forEach((edge) => {
141
+ if (useAcceptEdgeFn && !options.acceptEdgeFn(edge))
142
+ return;
143
+ if (!useMultiLevelSegments && Level.isRange(edge.level))
144
+ return;
145
+ if (!Level.intersect(edge.level, origin.level))
146
+ return;
147
+ if (useMaxBearingAngle) {
148
+ if (diffAngleLines(edge.bearing, origin.bearing) > maxBearingAngle)
149
+ return;
150
+ }
151
+ const segmentProjection = origin.getSegmentProjection(edge.vertex1.coords, edge.vertex2.coords);
152
+ if (!segmentProjection)
153
+ return;
154
+ const distanceToSegment = segmentProjection.distanceTo(origin);
155
+ if (useMaxDistance && distanceToSegment > maxDistance)
156
+ return;
157
+ if (distanceToSegment < ((bestProjection == null ? void 0 : bestProjection.distanceFromNearestElement) ?? Number.MAX_VALUE)) {
158
+ bestProjection = new GraphProjection(origin, distanceToSegment, adaptProjectionCoords(segmentProjection), edge);
159
+ }
160
+ });
161
+ if (useMaxBearingAngle) {
162
+ return bestProjection;
163
+ }
164
+ this.vertices.forEach((vertex) => {
165
+ let vertexCoords = vertex.coords;
166
+ if (this.exitVertices.has(vertex) && origin.level === null) {
167
+ vertexCoords = vertex.coords.clone();
168
+ vertexCoords.level = null;
169
+ }
170
+ if (!useMultiLevelSegments && Level.isRange(vertexCoords.level))
171
+ return;
172
+ if (!Level.intersect(vertexCoords.level, origin.level))
173
+ return;
174
+ const distanceToVertex = vertexCoords.distanceTo(origin);
175
+ if (distanceToVertex < Constants.EPS_MM) {
176
+ bestProjection = new GraphProjection(origin, 0, adaptProjectionCoords(vertexCoords), vertex);
177
+ return;
178
+ }
179
+ if (useMaxDistance && distanceToVertex > maxDistance)
180
+ return;
181
+ if (distanceToVertex < ((bestProjection == null ? void 0 : bestProjection.distanceFromNearestElement) ?? Number.MAX_VALUE)) {
182
+ bestProjection = new GraphProjection(origin, distanceToVertex, adaptProjectionCoords(vertexCoords), vertex);
183
+ }
184
+ });
185
+ return bestProjection;
186
+ }
187
+ toJson() {
188
+ return {
189
+ vertices: this.vertices.map((vertex) => vertex.toJson()),
190
+ edges: this.edges.map((edge) => ({
191
+ id: edge.id,
192
+ vertex1Idx: this.vertices.indexOf(edge.vertex1),
193
+ vertex2Idx: this.vertices.indexOf(edge.vertex2),
194
+ ...Object.keys(edge.properties).length > 0 && { properties: edge.properties }
195
+ }))
196
+ };
197
+ }
198
+ static fromJson(json) {
199
+ const vertices = json.vertices.map((vertex) => Vertex.fromJson(vertex));
200
+ const edges = json.edges.map((jsonEdge) => new Edge(
201
+ vertices[jsonEdge.vertex1Idx],
202
+ vertices[jsonEdge.vertex2Idx],
203
+ jsonEdge.properties,
204
+ jsonEdge.id
205
+ ));
206
+ return new Graph(vertices, edges);
207
+ }
208
+ /** @deprecated */
209
+ toCompressedJson() {
210
+ return {
211
+ vertices: this.vertices.map((vertex) => vertex.coords.toCompressedJson()),
212
+ verticesIds: this.vertices.map((vertex) => vertex.id),
213
+ edges: this.edges.map((edge) => {
214
+ const vertex1Idx = this.vertices.indexOf(edge.vertex1);
215
+ const vertex2Idx = this.vertices.indexOf(edge.vertex2);
216
+ const edgeExtras = edge.properties;
217
+ if (Object.keys(edgeExtras).length > 0) {
218
+ return [vertex1Idx, vertex2Idx, edgeExtras];
219
+ }
220
+ return [vertex1Idx, vertex2Idx];
221
+ })
222
+ };
223
+ }
224
+ /** @deprecated */
225
+ static fromCompressedJson(json) {
226
+ const vertices = json.vertices.map((vertex) => new Vertex(Coordinates.fromCompressedJson(vertex)));
227
+ const edges = json.edges.map((jsonEdge) => new Edge(
228
+ vertices[jsonEdge[0]],
229
+ vertices[jsonEdge[1]],
230
+ jsonEdge.length > 2 ? jsonEdge[2] : {}
231
+ ));
232
+ return new Graph(vertices, edges);
233
+ }
234
+ static fromCoordinatesSegments(segments) {
235
+ const vertices = [];
236
+ const edges = [];
237
+ const getOrCreateVertex = (coords) => {
238
+ const vertex = vertices.find((otherVertex) => otherVertex.coords.equals(coords));
239
+ if (vertex) {
240
+ return vertex;
241
+ }
242
+ const newVertex = new Vertex(coords);
243
+ vertices.push(newVertex);
244
+ return newVertex;
245
+ };
246
+ for (const segment of segments) {
247
+ let previousVertex = null;
248
+ for (const coords of segment) {
249
+ const currentVertex = getOrCreateVertex(coords);
250
+ if (previousVertex) {
251
+ edges.push(new Edge(currentVertex, previousVertex));
252
+ }
253
+ previousVertex = currentVertex;
254
+ }
255
+ }
256
+ return new Graph(vertices, edges);
257
+ }
258
+ /**
259
+ * Create edges From MultiLevel Itinerary for a given level
260
+ * @param useMultiLevelEdges use segments which intersect both levels (stairs, elevators...)
261
+ */
262
+ getEdgesAtLevel(targetLevel, useMultiLevelEdges = true) {
263
+ return this.edges.filter(
264
+ ({ level }) => useMultiLevelEdges ? Level.intersect(targetLevel, level) : Level.contains(targetLevel, level)
265
+ );
266
+ }
267
+ toDetailedString() {
268
+ let output = `--- Network ---
269
+ Vertices: ${this.vertices.length}
270
+ Edges: ${this.edges.length}
271
+ ---
272
+ Vertices
273
+ `;
274
+ this.vertices.forEach((vertex) => {
275
+ output += vertex.id;
276
+ const vertexProps = vertex.properties;
277
+ if (Object.keys(vertexProps).length !== 0) {
278
+ output += ` ${vertexProps}`;
279
+ }
280
+ });
281
+ output += "---\nEdges\n";
282
+ this.edges.forEach((edge) => {
283
+ output += `${edge.id} - [v1: ${edge.vertex1.id}, v2: ${edge.vertex2.id}]`;
284
+ const edgeProps = edge.properties;
285
+ if (Object.keys(edgeProps).length !== 0) {
286
+ output += ` ${edgeProps}`;
287
+ }
288
+ });
289
+ output += "---";
290
+ return output;
291
+ }
292
+ }
293
+ function getDurationFromLength(length, speed = 5) {
294
+ return length / (speed * 1e3 / 3600);
295
+ }
296
+ function isTransitModePublicTransport(transitMode) {
297
+ return [
298
+ "AIRPLANE",
299
+ "BOAT",
300
+ "BUS",
301
+ "FERRY",
302
+ "FUNICULAR",
303
+ "METRO",
304
+ "MULTI",
305
+ "TRAIN",
306
+ "TRAM"
307
+ ].includes(transitMode);
308
+ }
309
+ function areTransitAndTravelModeConsistent(transitMode, travelMode) {
310
+ return transitMode === travelMode || isTransitModePublicTransport(transitMode) && travelMode === "TRANSIT" || transitMode === "WALK" && travelMode === "TRANSIT";
311
+ }
312
+ function stepToJson(step) {
313
+ return {
314
+ ...step.firstStep && { firstStep: true },
315
+ ...step.lastStep && { lastStep: true },
316
+ number: step.number,
317
+ coords: step.coords.toCompressedJson(),
318
+ ...step.name !== null && { name: step.name },
319
+ angle: Number(step.angle.toFixed(2)),
320
+ previousBearing: Number(step.previousBearing.toFixed(2)),
321
+ nextBearing: Number(step.nextBearing.toFixed(2)),
322
+ distance: Number(step.distance.toFixed(1)),
323
+ duration: Number(step.duration.toFixed(1)),
324
+ ...step.levelChange !== null && { levelChange: step.levelChange },
325
+ ...step.extras && Object.keys(step.extras).length !== 0 && { extras: step.extras }
326
+ };
327
+ }
328
+ function jsonToStep(json) {
329
+ return Object.assign({}, json, {
330
+ coords: Coordinates.fromCompressedJson(json.coords),
331
+ firstStep: Boolean(json.firstStep),
332
+ lastStep: Boolean(json.lastStep),
333
+ name: json.name || null,
334
+ levelChange: json.levelChange || null,
335
+ extras: json.extras || null
336
+ });
337
+ }
338
+ function stepEquals(step1, step2) {
339
+ var _a, _b, _c, _d, _e, _f;
340
+ return step1.coords.equals(step2.coords) && Math.abs(step1.angle - step2.angle) <= 5e-3 && Math.abs(step1.distance - step2.distance) <= 0.05 && Math.abs(step1.duration - step2.duration) <= 0.05 && step1.firstStep === step2.firstStep && step1.lastStep === step2.lastStep && ((_a = step1.levelChange) == null ? void 0 : _a.difference) === ((_b = step2.levelChange) == null ? void 0 : _b.difference) && ((_c = step1.levelChange) == null ? void 0 : _c.direction) === ((_d = step2.levelChange) == null ? void 0 : _d.direction) && ((_e = step1.levelChange) == null ? void 0 : _e.type) === ((_f = step2.levelChange) == null ? void 0 : _f.type) && step1.name === step2.name && Math.abs(step1.nextBearing - step2.nextBearing) <= 5e-3 && step1.number === step2.number && Math.abs(step1.previousBearing - step2.previousBearing) <= 5e-3;
341
+ }
342
+ class GraphRoute extends Graph {
343
+ constructor(start, end, vertices, edges, edgesWeights) {
344
+ super(vertices, edges);
345
+ this.start = start;
346
+ this.end = end;
347
+ this.vertices = vertices;
348
+ this.edges = edges;
349
+ this.edgesWeights = edgesWeights;
350
+ }
351
+ // /!\ Does not clone vertices
352
+ // /!\ Create new Edges but does not deep clone properties
353
+ // /!\ Does not revert edge oneway property
354
+ reverse() {
355
+ const vertices = this.vertices.slice().reverse();
356
+ const edges = this.edges.slice().reverse();
357
+ const edgesWeights = this.edgesWeights.slice().reverse();
358
+ edges.map((oldEdge) => new Edge(oldEdge.vertex2, oldEdge.vertex1, oldEdge.properties));
359
+ return new GraphRoute(this.start, this.end, vertices, edges, edgesWeights);
360
+ }
361
+ static fromCoordinates(start, end, coordinates) {
362
+ const graph = Graph.fromCoordinatesSegments([coordinates]);
363
+ const edgesWeights = graph.edges.map((e) => getDurationFromLength(e.length));
364
+ return new GraphRoute(start, end, graph.vertices, graph.edges, edgesWeights);
365
+ }
366
+ get hasRoute() {
367
+ return Boolean(this.vertices.length);
368
+ }
369
+ }
370
+ const SKIP_STEP_ANGLE_MAX = deg2rad(20);
371
+ class StepsBuilder {
372
+ constructor() {
373
+ __publicField(this, "start", null);
374
+ __publicField(this, "end", null);
375
+ __publicField(this, "pathCoords", null);
376
+ __publicField(this, "stepsInfo", []);
377
+ }
378
+ setStart(start) {
379
+ this.start = start;
380
+ return this;
381
+ }
382
+ setEnd(end) {
383
+ this.end = end;
384
+ return this;
385
+ }
386
+ setPathCoords(pathCoords) {
387
+ this.pathCoords = pathCoords;
388
+ return this;
389
+ }
390
+ setStepsInfo(stepsInfo) {
391
+ this.stepsInfo = stepsInfo;
392
+ return this;
393
+ }
394
+ addStepInfo(stepInfo) {
395
+ this.stepsInfo.push(stepInfo);
396
+ return this;
397
+ }
398
+ setGraphRoute(graphRoute) {
399
+ const stepsInfo = [];
400
+ const { start, end } = graphRoute;
401
+ if (!graphRoute.hasRoute) {
402
+ return this;
403
+ }
404
+ let currentStep = null;
405
+ let previousBearing = start.bearingTo(graphRoute.vertices[0].coords);
406
+ for (let i = 0; i < graphRoute.vertices.length - 1; i++) {
407
+ const isFirstStep = i === 0;
408
+ const vertex = graphRoute.vertices[i];
409
+ const currentCoords = vertex.coords;
410
+ const nextVertex = graphRoute.vertices[i + 1];
411
+ const nextCoords = nextVertex.coords;
412
+ const edge = graphRoute.edges[i];
413
+ const nextBearing = vertex.bearingTo(nextVertex);
414
+ const angle = diffAngle(previousBearing, nextBearing + Math.PI);
415
+ const previousStep = stepsInfo.length ? stepsInfo[stepsInfo.length - 1] : null;
416
+ const { isSubwayEntrance, isGate, subwayEntranceRef } = vertex.properties;
417
+ const { isElevator, areEscalators, areStairs, isMovingWalkway, incline } = edge.properties;
418
+ let levelChangeType = null;
419
+ if (isElevator) {
420
+ levelChangeType = "elevator";
421
+ } else if (areEscalators) {
422
+ levelChangeType = "escalator";
423
+ } else if (areStairs) {
424
+ levelChangeType = "stairs";
425
+ } else if (isMovingWalkway) {
426
+ levelChangeType = "moving walkway";
427
+ } else {
428
+ levelChangeType = "incline plane";
429
+ }
430
+ let forceLevelChange;
431
+ if ((areStairs || isElevator) && incline && !(previousStep == null ? void 0 : previousStep.levelChange)) {
432
+ forceLevelChange = incline;
433
+ }
434
+ const previousEdge = i > 0 ? graphRoute.edges[i - 1] : null;
435
+ const previousEdgeProperties = (previousEdge == null ? void 0 : previousEdge.properties) || {};
436
+ const forceEndOfLevelChange = Boolean(
437
+ previousEdgeProperties.incline && previousEdgeProperties.areStairs && (!incline || !areStairs)
438
+ );
439
+ const isEntrance = vertex.properties.isSubwayEntrance;
440
+ const stepName = edge.properties.name || null;
441
+ const duration = graphRoute.edgesWeights[i];
442
+ const stepExtras = {
443
+ ...isSubwayEntrance && { isSubwayEntrance },
444
+ ...subwayEntranceRef && { subwayEntranceRef },
445
+ ...isGate && { isGate }
446
+ };
447
+ let splitByAngle = Math.abs(diffAngle(Math.PI, angle)) >= SKIP_STEP_ANGLE_MAX;
448
+ const splitByLevel = Level.isRange(edge.level) && !Level.isRange(currentCoords.level) || forceLevelChange;
449
+ splitByAngle = splitByAngle && !(currentCoords.level && Level.isRange(currentCoords.level));
450
+ const splitByEndOfLevelChange = (previousStep == null ? void 0 : previousStep.levelChange) && !Level.isRange(currentCoords.level) || forceEndOfLevelChange;
451
+ const splitStepCondition = splitByAngle || splitByLevel || splitByEndOfLevelChange || isEntrance;
452
+ if (isFirstStep || splitStepCondition) {
453
+ let levelChange;
454
+ if (splitByLevel) {
455
+ const difference = Level.diff(currentCoords.level, nextCoords.level) || 0;
456
+ let direction = difference > 0 ? "up" : "down";
457
+ if (forceLevelChange) {
458
+ direction = forceLevelChange;
459
+ }
460
+ levelChange = {
461
+ difference,
462
+ direction,
463
+ ...levelChangeType && { type: levelChangeType }
464
+ };
465
+ }
466
+ currentStep = {
467
+ coords: currentCoords,
468
+ ...stepName && { name: stepName },
469
+ extras: stepExtras,
470
+ levelChange,
471
+ distance: 0,
472
+ duration: 0
473
+ };
474
+ stepsInfo.push(currentStep);
475
+ }
476
+ currentStep.distance += currentCoords.distanceTo(nextCoords);
477
+ currentStep.duration += duration;
478
+ previousBearing = nextBearing;
479
+ }
480
+ const lastCoords = graphRoute.vertices[graphRoute.vertices.length - 1].coords;
481
+ if (!Coordinates.equals(lastCoords, end)) {
482
+ stepsInfo.push({ coords: lastCoords });
483
+ }
484
+ this.setStart(start);
485
+ this.setEnd(end);
486
+ this.setPathCoords(graphRoute.vertices.map((v) => v.coords));
487
+ this.setStepsInfo(stepsInfo);
488
+ return this;
489
+ }
490
+ build() {
491
+ const { pathCoords, start, end } = this;
492
+ if (!pathCoords) {
493
+ Logger.warn(`StepsBuilder: Missing "pathCoords" property to build steps`);
494
+ return [];
495
+ }
496
+ if (!start) {
497
+ Logger.warn(`StepsBuilder: Missing "from" property to build steps`);
498
+ return [];
499
+ }
500
+ if (!end) {
501
+ Logger.warn(`StepsBuilder: Missing "to" property to build steps`);
502
+ return [];
503
+ }
504
+ if (this.stepsInfo.length === 0) {
505
+ this.setGraphRoute(GraphRoute.fromCoordinates(start, end, pathCoords));
506
+ }
507
+ const { stepsInfo } = this;
508
+ return stepsInfo.map((stepInfo, stepId) => {
509
+ const coordsId = pathCoords.findIndex((coords) => coords.equals(stepInfo.coords));
510
+ if (coordsId === -1) {
511
+ throw new Error("Cannot find step coordinates in itinerary coordinates.");
512
+ }
513
+ const coordsBeforeStep = coordsId === 0 ? start : pathCoords[coordsId - 1];
514
+ const coordsAfterStep = coordsId === pathCoords.length - 1 ? end : pathCoords[coordsId + 1];
515
+ const previousBearing = coordsBeforeStep.bearingTo(stepInfo.coords);
516
+ const nextBearing = stepInfo.coords.bearingTo(coordsAfterStep);
517
+ let distance = 0;
518
+ const isLastStep = stepId === stepsInfo.length - 1;
519
+ const coordsToStopCalculation = isLastStep ? pathCoords[pathCoords.length - 1] : stepsInfo[stepId + 1].coords;
520
+ let currentCoordsId = coordsId;
521
+ while (!pathCoords[currentCoordsId].equals(coordsToStopCalculation)) {
522
+ distance += pathCoords[currentCoordsId].distanceTo(pathCoords[currentCoordsId + 1]);
523
+ currentCoordsId++;
524
+ }
525
+ return {
526
+ coords: stepInfo.coords,
527
+ name: stepInfo.name || null,
528
+ number: stepId + 1,
529
+ previousBearing,
530
+ nextBearing,
531
+ angle: diffAngle(previousBearing, nextBearing + Math.PI),
532
+ firstStep: stepId === 0,
533
+ lastStep: isLastStep,
534
+ distance,
535
+ // stepInfo.distance is overwritten
536
+ duration: stepInfo.duration || getDurationFromLength(distance),
537
+ levelChange: stepInfo.levelChange || null,
538
+ extras: stepInfo.extras || null
539
+ };
540
+ });
541
+ }
542
+ }
543
+ class Leg {
544
+ constructor({
545
+ start,
546
+ end,
547
+ coords,
548
+ transitMode,
549
+ duration,
550
+ startTime,
551
+ endTime,
552
+ transportInfo,
553
+ steps
554
+ }) {
555
+ __publicField(this, "start");
556
+ __publicField(this, "end");
557
+ __publicField(this, "coords");
558
+ __publicField(this, "distance");
559
+ __publicField(this, "transitMode");
560
+ __publicField(this, "duration");
561
+ __publicField(this, "startTime");
562
+ __publicField(this, "endTime");
563
+ __publicField(this, "steps");
564
+ __publicField(this, "transportInfo");
565
+ this.start = {
566
+ name: start.name || null,
567
+ coords: start.coords
568
+ };
569
+ this.end = {
570
+ name: end.name || null,
571
+ coords: end.coords
572
+ };
573
+ this.coords = coords;
574
+ this.transitMode = transitMode;
575
+ this.distance = Utils.calcDistance(coords);
576
+ this.duration = typeof duration === "number" ? duration : getDurationFromLength(this.distance);
577
+ this.startTime = typeof startTime === "number" ? startTime : null;
578
+ this.endTime = typeof endTime === "number" ? endTime : null;
579
+ this.transportInfo = transportInfo || null;
580
+ this.steps = Array.isArray(steps) ? steps : new StepsBuilder().setStart(start.coords).setEnd(end.coords).setPathCoords(coords).build();
581
+ }
582
+ isPublicTransport() {
583
+ return isTransitModePublicTransport(this.transitMode);
584
+ }
585
+ toGraph() {
586
+ return Graph.fromCoordinatesSegments([this.coords]);
587
+ }
588
+ static equals(obj1, obj2) {
589
+ var _a, _b;
590
+ const intermediate = obj1.transitMode === obj2.transitMode && Math.abs(obj1.duration - obj2.duration) <= 0.05 && obj1.startTime === obj2.startTime && obj1.endTime === obj2.endTime && obj1.start.name === obj2.start.name && obj1.start.coords.equals(obj2.start.coords) && obj1.end.name === obj2.end.name && obj1.end.coords.equals(obj2.end.coords) && obj1.coords.length === obj2.coords.length && (obj1.steps === obj2.steps || ((_a = obj1.steps) == null ? void 0 : _a.length) === ((_b = obj2.steps) == null ? void 0 : _b.length));
591
+ if (!intermediate) {
592
+ return false;
593
+ }
594
+ let i;
595
+ for (i = 0; i < obj1.coords.length; i++) {
596
+ if (!obj1.coords[i].equals(obj2.coords[i])) {
597
+ return false;
598
+ }
599
+ }
600
+ for (i = 0; i < obj1.steps.length; i++) {
601
+ if (!stepEquals(obj1.steps[i], obj2.steps[i])) {
602
+ return false;
603
+ }
604
+ }
605
+ if (obj1.transportInfo !== obj2.transportInfo) {
606
+ if (obj1.transportInfo === null || obj2.transportInfo === null) {
607
+ return false;
608
+ }
609
+ 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) {
610
+ return false;
611
+ }
612
+ }
613
+ return true;
614
+ }
615
+ equals(obj) {
616
+ return Leg.equals(this, obj);
617
+ }
618
+ toJson() {
619
+ return {
620
+ transitMode: this.transitMode,
621
+ start: {
622
+ coords: this.start.coords.toCompressedJson(),
623
+ ...this.start.name && { name: this.start.name }
624
+ },
625
+ end: {
626
+ coords: this.end.coords.toCompressedJson(),
627
+ ...this.end.name && { name: this.end.name }
628
+ },
629
+ distance: Number(this.distance.toFixed(1)),
630
+ duration: Number(this.duration.toFixed(1)),
631
+ coords: this.coords.map((coords) => coords.toCompressedJson()),
632
+ steps: this.steps.map(stepToJson),
633
+ ...this.startTime !== null && { startTime: this.startTime },
634
+ ...this.endTime !== null && { endTime: this.endTime },
635
+ ...this.transportInfo !== null && { transportInfo: this.transportInfo }
636
+ };
637
+ }
638
+ static fromJson(json) {
639
+ var _a;
640
+ const leg = new Leg(Object.assign({}, json, {
641
+ start: {
642
+ coords: Coordinates.fromCompressedJson(json.start.coords),
643
+ name: json.start.name || null
644
+ },
645
+ end: {
646
+ coords: Coordinates.fromCompressedJson(json.end.coords),
647
+ name: json.end.name || null
648
+ },
649
+ coords: json.coords.map(Coordinates.fromCompressedJson),
650
+ steps: ((_a = json.steps) == null ? void 0 : _a.map(jsonToStep)) || null
651
+ }));
652
+ return leg;
653
+ }
654
+ static fromGraphRoute(graphRoute, transitMode = "WALK") {
655
+ return new Leg({
656
+ start: { coords: graphRoute.start },
657
+ end: { coords: graphRoute.end },
658
+ coords: graphRoute.vertices.map((vertex) => vertex.coords),
659
+ duration: graphRoute.edgesWeights.reduce((acc, weight) => acc + weight, 0),
660
+ transitMode,
661
+ steps: new StepsBuilder().setGraphRoute(graphRoute).build()
662
+ });
663
+ }
664
+ // TODO: Remove when possible...
665
+ // Livemap specific
666
+ multiplyLevel(levelFactor) {
667
+ this.start.coords.level = Level.multiplyBy(this.start.coords.level, levelFactor);
668
+ this.end.coords.level = Level.multiplyBy(this.end.coords.level, levelFactor);
669
+ for (const coords of this.coords) {
670
+ coords.level = Level.multiplyBy(coords.level, levelFactor);
671
+ }
672
+ this.steps.forEach((step) => {
673
+ step.coords.level = Level.multiplyBy(step.coords.level, levelFactor);
674
+ });
675
+ }
676
+ }
677
+ class Itinerary {
678
+ constructor({
679
+ origin,
680
+ destination,
681
+ duration,
682
+ legs,
683
+ startTime,
684
+ endTime
685
+ }) {
686
+ __publicField(this, "origin");
687
+ __publicField(this, "destination");
688
+ __publicField(this, "duration");
689
+ __publicField(this, "legs");
690
+ __publicField(this, "_transitMode", null);
691
+ __publicField(this, "startTime");
692
+ __publicField(this, "endTime");
693
+ __publicField(this, "_coords", null);
694
+ __publicField(this, "_distance", null);
695
+ this.origin = origin;
696
+ this.destination = destination;
697
+ this.legs = legs;
698
+ if (typeof duration === "number") {
699
+ this.duration = duration;
700
+ } else {
701
+ this.duration = this.legs.reduce((dur, leg) => dur + leg.duration, 0);
702
+ }
703
+ this.startTime = typeof startTime === "number" ? startTime : null;
704
+ this.endTime = typeof endTime === "number" ? endTime : null;
705
+ this.updateStepsFromLegs();
706
+ }
707
+ set coords(_) {
708
+ throw new Error("Itinerary.coords cannot be set. They are calculated from Itinerary.legs.");
709
+ }
710
+ get coords() {
711
+ if (!this._coords) {
712
+ this._coords = this.legs.map((leg) => leg.coords).flat().filter((coords, idx, arr) => idx === 0 || !arr[idx - 1].equals(coords));
713
+ }
714
+ return this._coords;
715
+ }
716
+ set steps(_) {
717
+ throw new Error("Itinerary.step cannot be set. They are calculated from Itinerary.legs.");
718
+ }
719
+ get steps() {
720
+ return this.legs.map((leg) => leg.steps).flat();
721
+ }
722
+ set transitMode(_) {
723
+ throw new Error("Itinerary.transitMode cannot be set. They are calculated from Itinerary.legs.");
724
+ }
725
+ // Transit mode will return MULTI if there are several transit modes except WALK
726
+ // Else it will return the only transit mode
727
+ // fallback to WALK if no transit mode
728
+ get transitMode() {
729
+ if (!this._transitMode) {
730
+ const legTransitModes = new Set(this.legs.map((leg) => leg.transitMode));
731
+ legTransitModes.delete("WALK");
732
+ if (legTransitModes.size > 1) {
733
+ this._transitMode = "MULTI";
734
+ return this._transitMode;
735
+ }
736
+ if (legTransitModes.size === 1) {
737
+ this._transitMode = legTransitModes.values().next().value;
738
+ return this._transitMode;
739
+ }
740
+ this._transitMode = "WALK";
741
+ }
742
+ return this._transitMode;
743
+ }
744
+ set distance(_) {
745
+ throw new Error("Itinerary.distance cannot be set. They are calculated from Itinerary.legs.");
746
+ }
747
+ get distance() {
748
+ if (this._distance === null) {
749
+ this._distance = Utils.calcDistance(this.coords);
750
+ }
751
+ return this._distance;
752
+ }
753
+ toGraph() {
754
+ return Graph.fromCoordinatesSegments([this.coords]);
755
+ }
756
+ static fromItineraries(...itineraries) {
757
+ return new Itinerary({
758
+ origin: itineraries[0].origin,
759
+ destination: itineraries[itineraries.length - 1].destination,
760
+ legs: itineraries.map((itinerary) => itinerary.legs).flat()
761
+ });
762
+ }
763
+ /**
764
+ * Convert lat/lng/level? points to Itinerary
765
+ */
766
+ static fromOrderedPointsArray(points, start, end) {
767
+ const pointToCoordinates = (point) => new Coordinates(point[0], point[1], null, point[2]);
768
+ return this.fromOrderedCoordinates(
769
+ points.map(pointToCoordinates),
770
+ pointToCoordinates(start),
771
+ pointToCoordinates(end)
772
+ );
773
+ }
774
+ /**
775
+ * Convert ordered Coordinates to Itinerary
776
+ */
777
+ static fromOrderedCoordinates(coords, origin, destination, transitMode = "WALK") {
778
+ const steps = new StepsBuilder().setPathCoords(coords).setStart(origin).setEnd(destination).build();
779
+ const leg = new Leg({
780
+ start: { coords: origin },
781
+ end: { coords: destination },
782
+ coords,
783
+ transitMode,
784
+ steps
785
+ });
786
+ return new Itinerary({ origin, destination, legs: [leg] });
787
+ }
788
+ static equals(obj1, obj2) {
789
+ const intermediate = obj1.origin.equals(obj2.origin) && obj1.destination.equals(obj2.destination) && Math.abs(obj1.distance - obj2.distance) <= 0.05 && Math.abs(obj1.duration - obj2.duration) <= 0.05 && obj1.startTime === obj2.startTime && obj1.endTime === obj2.endTime && obj1.legs.length === obj2.legs.length;
790
+ if (!intermediate) {
791
+ return false;
792
+ }
793
+ for (let i = 0; i < obj1.legs.length; i++) {
794
+ if (!obj1.legs[i].equals(obj2.legs[i])) {
795
+ return false;
796
+ }
797
+ }
798
+ return true;
799
+ }
800
+ equals(obj) {
801
+ return Itinerary.equals(this, obj);
802
+ }
803
+ toJson() {
804
+ return {
805
+ origin: this.origin.toJson(),
806
+ destination: this.destination.toJson(),
807
+ distance: Number(this.distance.toFixed(1)),
808
+ duration: Number(this.duration.toFixed(1)),
809
+ transitMode: this.transitMode,
810
+ legs: this.legs.map((leg) => leg.toJson()),
811
+ ...this.startTime !== null && { startTime: this.startTime },
812
+ ...this.endTime !== null && { endTime: this.endTime }
813
+ };
814
+ }
815
+ static fromJson(json) {
816
+ return new Itinerary({
817
+ origin: Coordinates.fromJson(json.origin),
818
+ destination: Coordinates.fromJson(json.destination),
819
+ duration: json.duration,
820
+ legs: json.legs.map(Leg.fromJson),
821
+ startTime: json.startTime,
822
+ endTime: json.endTime
823
+ });
824
+ }
825
+ static fromGraphRoute(graphRoute, transitMode = "WALK") {
826
+ const leg = Leg.fromGraphRoute(graphRoute, transitMode);
827
+ return new Itinerary({
828
+ origin: graphRoute.start,
829
+ destination: graphRoute.end,
830
+ legs: [leg]
831
+ });
832
+ }
833
+ // TODO: Remove when possible...
834
+ // Livemap specific
835
+ multiplyLevel(levelFactor) {
836
+ this.origin.level = Level.multiplyBy(this.origin.level, levelFactor);
837
+ this.destination.level = Level.multiplyBy(this.destination.level, levelFactor);
838
+ this.legs.forEach((leg) => leg.multiplyLevel(levelFactor));
839
+ }
840
+ // TODO: Remove when possible...
841
+ // Livemap specific
842
+ forceUnknownLevelTo0() {
843
+ this.origin.level = this.origin.level || 0;
844
+ this.destination.level = this.destination.level || 0;
845
+ for (const leg of this.legs) {
846
+ leg.start.coords.level = leg.start.coords.level || 0;
847
+ leg.end.coords.level = leg.end.coords.level || 0;
848
+ for (const coords of leg.coords) {
849
+ coords.level = coords.level || 0;
850
+ }
851
+ if (leg.steps) {
852
+ for (const step of leg.steps) {
853
+ step.coords.level = step.coords.level || 0;
854
+ }
855
+ }
856
+ }
857
+ if (this._coords) {
858
+ for (const coords of this._coords) {
859
+ coords.level = coords.level || 0;
860
+ }
861
+ }
862
+ }
863
+ toGeoJson() {
864
+ const transformToPoint = (point, name, type) => ({
865
+ type: "Feature",
866
+ properties: { name, level: point.level, ...type && { type } },
867
+ geometry: {
868
+ type: "Point",
869
+ coordinates: [point.lng, point.lat]
870
+ }
871
+ });
872
+ const transformToMultiLineStrings = (segments, level) => ({
873
+ type: "Feature",
874
+ properties: { level, name: level == null ? void 0 : level.toString() },
875
+ geometry: {
876
+ type: "MultiLineString",
877
+ coordinates: segments.map((s) => s.map(({ lat, lng }) => [lng, lat]))
878
+ }
879
+ });
880
+ const levelsOfItinerary = [...new Set(this.coords.map((c) => Level.toString(c.level)))].map(Level.fromString);
881
+ const segmentsSplitted = levelsOfItinerary.map((loi) => [loi, Utils.createSegmentsAtLevel(this.coords, loi, true)]);
882
+ const multiLineStrings = segmentsSplitted.map(([loi, segments]) => transformToMultiLineStrings(segments, loi));
883
+ const legsStarts = this.legs.map((leg, idx) => transformToPoint(leg.start.coords, `Leg ${idx} start`, "leg-start"));
884
+ const legsEnds = this.legs.map((leg, idx) => transformToPoint(leg.end.coords, `Leg ${idx} end`, "leg-end"));
885
+ const steps = this.steps.map((step) => transformToPoint(step.coords, `Step ${step.number}`, "step"));
886
+ return {
887
+ type: "FeatureCollection",
888
+ features: [
889
+ transformToPoint(this.origin, "origin", "origin"),
890
+ transformToPoint(this.destination, "destination", "destination"),
891
+ ...multiLineStrings,
892
+ ...legsStarts,
893
+ ...legsEnds,
894
+ ...steps
895
+ ]
896
+ };
897
+ }
898
+ /**
899
+ * TODO: Remove it in router v3
900
+ * Update steps info thanks to the coordinates of the whole itinerary.
901
+ * This method will update:
902
+ * - all steps number
903
+ * - first/last steps
904
+ * - previousBearing/nextBearing/angle of first and last step of each leg
905
+ */
906
+ updateStepsFromLegs() {
907
+ const itineraryCoords = this.coords.filter((coords, idx, arr) => idx === 0 || !arr[idx - 1].equals(coords));
908
+ const steps = this.legs.map((leg) => leg.steps).flat();
909
+ steps.map((step, stepId) => {
910
+ const coordsId = itineraryCoords.findIndex((coords) => coords.equals(step.coords));
911
+ if (coordsId === -1) {
912
+ throw new Error("Cannot find step coordinates in itinerary coordinates.");
913
+ }
914
+ const coordsBeforeStep = coordsId === 0 ? this.origin : itineraryCoords[coordsId - 1];
915
+ const coordsAfterStep = coordsId === itineraryCoords.length - 1 ? this.destination : itineraryCoords[coordsId + 1];
916
+ step.previousBearing = coordsBeforeStep.bearingTo(step.coords);
917
+ step.nextBearing = step.coords.bearingTo(coordsAfterStep);
918
+ step.angle = diffAngle(step.previousBearing, step.nextBearing + Math.PI);
919
+ step.number = stepId + 1;
920
+ step.firstStep = stepId === 0;
921
+ step.lastStep = stepId === steps.length - 1;
922
+ });
923
+ }
924
+ }
925
+ class RemoteRouter {
926
+ }
927
+ var StatusCode = /* @__PURE__ */ ((StatusCode2) => {
928
+ StatusCode2[StatusCode2["OK"] = 0] = "OK";
929
+ StatusCode2[StatusCode2["CANCELLED"] = 1] = "CANCELLED";
930
+ StatusCode2[StatusCode2["UNKNOWN"] = 2] = "UNKNOWN";
931
+ StatusCode2[StatusCode2["INVALID_ARGUMENT"] = 3] = "INVALID_ARGUMENT";
932
+ StatusCode2[StatusCode2["NOT_FOUND"] = 5] = "NOT_FOUND";
933
+ StatusCode2[StatusCode2["UNIMPLEMENTED"] = 12] = "UNIMPLEMENTED";
934
+ StatusCode2[StatusCode2["INTERNAL"] = 13] = "INTERNAL";
935
+ StatusCode2[StatusCode2["UNAVAILABLE"] = 14] = "UNAVAILABLE";
936
+ StatusCode2[StatusCode2["UNAUTHENTICATED"] = 16] = "UNAUTHENTICATED";
937
+ return StatusCode2;
938
+ })(StatusCode || {});
939
+ class RoutingError extends Error {
940
+ constructor(code = StatusCode.UNKNOWN, message) {
941
+ super(message);
942
+ __publicField(this, "customMapName");
943
+ this.code = code;
944
+ }
945
+ static notFound(details) {
946
+ return new RoutingError(StatusCode.NOT_FOUND, `Cannot found an itinerary. Details: ${details}`);
947
+ }
948
+ }
949
+ class WemapMultiRoutingError extends RoutingError {
950
+ constructor(code = StatusCode.UNKNOWN, mapName, message) {
951
+ super(code, message);
952
+ this.code = code;
953
+ this.mapName = mapName;
954
+ this.mapName = mapName;
955
+ }
956
+ static notFound(mapName, details) {
957
+ return new WemapMultiRoutingError(StatusCode.NOT_FOUND, mapName, `Cannot found an itinerary in map ${mapName}. Details: ${details || "No details"}`);
958
+ }
959
+ }
960
+ class RemoteRoutingError extends RoutingError {
961
+ constructor(code = StatusCode.UNKNOWN, routerName, message) {
962
+ super(code, message);
963
+ this.code = code;
964
+ this.routerName = routerName;
965
+ this.routerName = routerName;
966
+ }
967
+ static notFound(routerName, details) {
968
+ return new RemoteRoutingError(StatusCode.NOT_FOUND, routerName, `Cannot found an itinerary with ${routerName}. Details: ${details || "No details"}`);
969
+ }
970
+ static missingApiKey(routerName, details) {
971
+ return new RemoteRoutingError(StatusCode.UNAUTHENTICATED, routerName, `API key is missing for ${routerName}. Details: ${details}`);
972
+ }
973
+ static unreachableServer(routerName, url) {
974
+ return new RemoteRoutingError(StatusCode.NOT_FOUND, routerName, `Remote router server ${routerName} is unreachable. URL: ${url}`);
975
+ }
976
+ static responseNotParsing(routerName, url) {
977
+ return new RemoteRoutingError(StatusCode.NOT_FOUND, routerName, `Remote router server response ${routerName} cannot be parsed. URL: ${url}`);
978
+ }
979
+ static travelModeUnimplemented(routerName, travelMode) {
980
+ return new RemoteRoutingError(StatusCode.UNIMPLEMENTED, routerName, `Travel mode "${travelMode}" is not implemented for ${routerName}`);
981
+ }
982
+ }
983
+ const outputModeCorrespondance = /* @__PURE__ */ new Map();
984
+ outputModeCorrespondance.set("CAR", "CAR");
985
+ outputModeCorrespondance.set("WALK", "WALK");
986
+ outputModeCorrespondance.set("BIKE", "BIKE");
987
+ class OsrmRemoteRouter extends RemoteRouter {
988
+ constructor() {
989
+ super(...arguments);
990
+ __publicField(this, "inputModeCorrespondance", (routerRequest) => {
991
+ var _a;
992
+ const { travelMode, travelModePreference: preference } = routerRequest;
993
+ if (travelMode === "WALK" && ((_a = routerRequest.itineraryModifiers) == null ? void 0 : _a.isWheelchair))
994
+ return "pmr";
995
+ if (travelMode === "WALK")
996
+ return "walking";
997
+ if (travelMode === "BIKE") {
998
+ if (preference === "FASTEST")
999
+ return "bike-fastest";
1000
+ if (preference === "SAFEST")
1001
+ return "bike-safest";
1002
+ if (preference === "TOURISM")
1003
+ return "bike-safest";
1004
+ return "bike-safest";
1005
+ }
1006
+ if (travelMode === "CAR")
1007
+ return "driving";
1008
+ throw RemoteRoutingError.travelModeUnimplemented(this.rname, travelMode);
1009
+ });
1010
+ }
1011
+ get rname() {
1012
+ return "osrm";
1013
+ }
1014
+ async getItineraries(endpointUrl, routerRequest) {
1015
+ const url = this.getURL(endpointUrl, routerRequest);
1016
+ const res = await fetch(url).catch(() => {
1017
+ throw RemoteRoutingError.unreachableServer(this.rname, url);
1018
+ });
1019
+ const jsonResponse = await res.json().catch(() => {
1020
+ throw RemoteRoutingError.responseNotParsing(this.rname, url);
1021
+ });
1022
+ return this.parseResponse(jsonResponse, routerRequest.origin, routerRequest.destination, routerRequest.travelMode);
1023
+ }
1024
+ /**
1025
+ * @throws {TravelModeCorrespondanceNotFound}
1026
+ */
1027
+ getURL(endpointUrl, routerRequest) {
1028
+ const { origin, destination } = routerRequest;
1029
+ const osrmMode = this.inputModeCorrespondance(routerRequest);
1030
+ const waypoints = [origin, ...routerRequest.waypoints || [], destination];
1031
+ let url = endpointUrl + "/route/v1/" + osrmMode + "/";
1032
+ url += waypoints.map((waypoint) => [waypoint.longitude + "," + waypoint.latitude]).join(";");
1033
+ url += "?geometries=geojson&overview=full&steps=true";
1034
+ routerRequest.provideItineraryAlternatives && (url += "&alternatives=true");
1035
+ return url;
1036
+ }
1037
+ coordinatesToJson({ lat, lng, level }) {
1038
+ if (level === null) {
1039
+ return [lng, lat];
1040
+ }
1041
+ if (Level.isRange(level)) {
1042
+ return [lng, lat, level[0]];
1043
+ }
1044
+ return [lng, lat, level];
1045
+ }
1046
+ /**
1047
+ * @param {object} json
1048
+ * @returns {Coordinates}
1049
+ */
1050
+ jsonToCoordinates(json) {
1051
+ const coords = new Coordinates(json[1], json[0]);
1052
+ if (json.length > 2) {
1053
+ coords.level = json[2];
1054
+ }
1055
+ return coords;
1056
+ }
1057
+ getModifierFromAngle(_angle) {
1058
+ const angle = positiveMod(rad2deg(_angle), 360);
1059
+ if (angle > 0 && angle < 60) {
1060
+ return "sharp right";
1061
+ }
1062
+ if (angle >= 60 && angle < 140) {
1063
+ return "right";
1064
+ }
1065
+ if (angle >= 140 && angle < 160) {
1066
+ return "slight right";
1067
+ }
1068
+ if (angle >= 160 && angle <= 200) {
1069
+ return "straight";
1070
+ }
1071
+ if (angle > 200 && angle <= 220) {
1072
+ return "slight left";
1073
+ }
1074
+ if (angle > 220 && angle <= 300) {
1075
+ return "left";
1076
+ }
1077
+ if (angle > 300 && angle < 360) {
1078
+ return "sharp left";
1079
+ }
1080
+ return "u turn";
1081
+ }
1082
+ noRouteFoundJson(message) {
1083
+ return {
1084
+ "code": "NoRoute",
1085
+ message
1086
+ };
1087
+ }
1088
+ /**
1089
+ * @deprecated
1090
+ */
1091
+ itineraryToOsrmJson(itinerary) {
1092
+ const lastLegId = itinerary.legs.length - 1;
1093
+ const itinerarySteps = itinerary.steps;
1094
+ const jsonLegs = itinerary.legs.map(({ distance, duration, coords }, idLeg) => {
1095
+ const legSteps = itinerarySteps.filter(
1096
+ (step) => coords.find((_coords) => _coords.equals(step.coords))
1097
+ );
1098
+ const lastStepId = legSteps.length - 1;
1099
+ return {
1100
+ distance,
1101
+ duration: duration || 0,
1102
+ steps: legSteps.map((step, idStep, arr) => {
1103
+ let type = idStep === 0 && idLeg === 0 ? "depart" : "turn";
1104
+ type = idStep === lastStepId && idLeg === lastLegId ? "arrive" : type;
1105
+ const stepCoordsIdx = coords.findIndex((p) => p.equals(step.coords));
1106
+ const nextStepCoordsIdx = idStep === lastStepId ? stepCoordsIdx : coords.findIndex((p) => p.equals(arr[idStep + 1].coords));
1107
+ const osrmStep = {
1108
+ geometry: {
1109
+ type: "LineString",
1110
+ coordinates: coords.slice(stepCoordsIdx, nextStepCoordsIdx + 1).map(this.coordinatesToJson)
1111
+ },
1112
+ distance: step.distance,
1113
+ duration: step.duration || 0,
1114
+ ...step.name && { name: step.name },
1115
+ maneuver: {
1116
+ bearing_before: rad2deg(step.previousBearing),
1117
+ bearing_after: rad2deg(step.nextBearing),
1118
+ location: this.coordinatesToJson(step.coords),
1119
+ modifier: this.getModifierFromAngle(step.angle),
1120
+ type
1121
+ }
1122
+ };
1123
+ return osrmStep;
1124
+ })
1125
+ };
1126
+ });
1127
+ return {
1128
+ "code": "Ok",
1129
+ "routes": [
1130
+ {
1131
+ "geometry": {
1132
+ "type": "LineString",
1133
+ "coordinates": itinerary.coords.map(this.coordinatesToJson)
1134
+ },
1135
+ "legs": jsonLegs,
1136
+ "distance": itinerary.distance,
1137
+ "duration": itinerary.duration,
1138
+ "weight_name": "routability",
1139
+ "weight": 0
1140
+ }
1141
+ ],
1142
+ "waypoints": []
1143
+ };
1144
+ }
1145
+ parseResponse(json, origin, destination, travelMode) {
1146
+ const transitMode = outputModeCorrespondance.get(travelMode);
1147
+ const { routes: jsonRoutes } = json;
1148
+ if (!jsonRoutes) {
1149
+ throw RemoteRoutingError.notFound(this.rname, json.message);
1150
+ }
1151
+ return jsonRoutes.map((jsonItinerary) => {
1152
+ const legs = jsonItinerary.legs.map((jsonLeg) => {
1153
+ var _a;
1154
+ const legCoords = jsonLeg.steps.map((step) => step.geometry.coordinates.map(this.jsonToCoordinates)).flat().filter((coords, idx, arr) => idx === 0 || !arr[idx - 1].equals(coords));
1155
+ const startCoords = legCoords[0];
1156
+ const endCoords = legCoords[legCoords.length - 1];
1157
+ const stepsBuilder = new StepsBuilder().setPathCoords(legCoords).setStart(startCoords).setEnd(endCoords);
1158
+ (_a = jsonLeg.steps) == null ? void 0 : _a.forEach(({ maneuver, name, distance, duration }) => {
1159
+ const stepCoords = this.jsonToCoordinates(maneuver.location);
1160
+ const distances = legCoords.map((coords) => coords.distanceTo(stepCoords));
1161
+ const idStepCoordsInLeg = distances.indexOf(Math.min(...distances));
1162
+ if (idStepCoordsInLeg < 0) {
1163
+ throw new Error("Osrm Parser: Cannot find step coords in leg coordinates");
1164
+ }
1165
+ stepsBuilder.addStepInfo({
1166
+ coords: legCoords[idStepCoordsInLeg],
1167
+ name,
1168
+ distance,
1169
+ duration
1170
+ });
1171
+ });
1172
+ return new Leg({
1173
+ transitMode,
1174
+ duration: jsonLeg.duration,
1175
+ coords: legCoords,
1176
+ start: {
1177
+ coords: startCoords
1178
+ },
1179
+ end: {
1180
+ coords: endCoords
1181
+ },
1182
+ steps: stepsBuilder.build()
1183
+ });
1184
+ });
1185
+ return new Itinerary({
1186
+ duration: jsonItinerary.duration,
1187
+ origin,
1188
+ destination,
1189
+ legs
1190
+ });
1191
+ });
1192
+ }
1193
+ }
1194
+ const OsrmRemoteRouter$1 = new OsrmRemoteRouter();
1195
+ export {
1196
+ Edge as E,
1197
+ GraphRoute as G,
1198
+ Itinerary as I,
1199
+ Leg as L,
1200
+ OsrmRemoteRouter$1 as O,
1201
+ RemoteRouter as R,
1202
+ StepsBuilder as S,
1203
+ Vertex as V,
1204
+ WemapMultiRoutingError as W,
1205
+ Graph as a,
1206
+ RemoteRoutingError as b,
1207
+ areTransitAndTravelModeConsistent as c,
1208
+ GraphProjection as d,
1209
+ RoutingError as e,
1210
+ StatusCode as f,
1211
+ getDurationFromLength as g,
1212
+ isTransitModePublicTransport as i
1213
+ };
1214
+ //# sourceMappingURL=OsrmRemoteRouter-e0076e4a.js.map