@wemap/routers 12.11.4 → 12.11.5
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 +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1220 -37
- package/dist/index.mjs.map +1 -1
- package/helpers/InstructionManager.ts +184 -0
- package/helpers/InstructionManagerV1.ts +95 -0
- package/package.json +5 -5
- package/dist/OsrmRemoteRouter-df92c42f.cjs +0 -2
- package/dist/OsrmRemoteRouter-df92c42f.cjs.map +0 -1
- package/dist/OsrmRemoteRouter-e0076e4a.js +0 -1214
- package/dist/OsrmRemoteRouter-e0076e4a.js.map +0 -1
- package/dist/helpers/InstructionManager.js +0 -2
- package/dist/helpers/InstructionManager.js.map +0 -1
- package/dist/helpers/InstructionManager.mjs +0 -159
- package/dist/helpers/InstructionManager.mjs.map +0 -1
- package/dist/helpers/InstructionManagerV1.js +0 -2
- package/dist/helpers/InstructionManagerV1.js.map +0 -1
- package/dist/helpers/InstructionManagerV1.mjs +0 -87
- package/dist/helpers/InstructionManagerV1.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -4,16 +4,14 @@ var __publicField = (obj, key, value) => {
|
|
|
4
4
|
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5
5
|
return value;
|
|
6
6
|
};
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
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";
|
|
9
10
|
import salesman from "@wemap/salesman.js";
|
|
10
|
-
import { Level, Coordinates, Utils } from "@wemap/geo";
|
|
11
11
|
import { OsmNode, OsmParser } from "@wemap/osm";
|
|
12
|
-
import Logger from "@wemap/logger";
|
|
13
12
|
import polyline from "@mapbox/polyline";
|
|
14
13
|
import pointInPolygon from "@turf/boolean-point-in-polygon";
|
|
15
14
|
import convexHullFn from "@turf/convex";
|
|
16
|
-
import "@wemap/maths";
|
|
17
15
|
function routerRequestToJson(routerRequest) {
|
|
18
16
|
const { origin, destination, waypoints, ...rest } = routerRequest;
|
|
19
17
|
return {
|
|
@@ -23,6 +21,921 @@ function routerRequestToJson(routerRequest) {
|
|
|
23
21
|
...rest
|
|
24
22
|
};
|
|
25
23
|
}
|
|
24
|
+
const _Edge = class _Edge {
|
|
25
|
+
constructor(vertex1, vertex2, properties = {}, id = _Edge.currentUniqueId++) {
|
|
26
|
+
__publicField(this, "level");
|
|
27
|
+
/** Edge bearing from vertex1 to vertex2 */
|
|
28
|
+
__publicField(this, "bearing");
|
|
29
|
+
__publicField(this, "length");
|
|
30
|
+
this.vertex1 = vertex1;
|
|
31
|
+
this.vertex2 = vertex2;
|
|
32
|
+
this.properties = properties;
|
|
33
|
+
this.id = id;
|
|
34
|
+
this.level = Level.union(vertex1.coords.level, vertex2.coords.level);
|
|
35
|
+
this.length = this.vertex1.distanceTo(this.vertex2);
|
|
36
|
+
this.bearing = this.vertex1.bearingTo(this.vertex2);
|
|
37
|
+
}
|
|
38
|
+
static getEdgeByVertices(edges, vertex1, vertex2) {
|
|
39
|
+
return edges.find(
|
|
40
|
+
(edge) => vertex1 === edge.vertex1 && vertex2 === edge.vertex2 || vertex2 === edge.vertex1 && vertex1 === edge.vertex2
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
reverseProperties() {
|
|
44
|
+
const { properties } = this;
|
|
45
|
+
if (properties.incline) {
|
|
46
|
+
properties.incline = properties.incline === "up" ? "down" : "up";
|
|
47
|
+
}
|
|
48
|
+
if (properties.isOneway) {
|
|
49
|
+
properties.isOneway = false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
__publicField(_Edge, "currentUniqueId", 0);
|
|
54
|
+
let Edge = _Edge;
|
|
55
|
+
class GraphProjection {
|
|
56
|
+
constructor(origin, distanceFromNearestElement, coords, nearestElement) {
|
|
57
|
+
this.origin = origin;
|
|
58
|
+
this.distanceFromNearestElement = distanceFromNearestElement;
|
|
59
|
+
this.coords = coords;
|
|
60
|
+
this.nearestElement = nearestElement;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
class Vertex {
|
|
64
|
+
constructor(coords, properties = {}) {
|
|
65
|
+
__publicField(this, "id", -1);
|
|
66
|
+
this.coords = coords;
|
|
67
|
+
this.properties = properties;
|
|
68
|
+
}
|
|
69
|
+
distanceTo(other) {
|
|
70
|
+
return this.coords.distanceTo(other.coords);
|
|
71
|
+
}
|
|
72
|
+
bearingTo(other) {
|
|
73
|
+
return this.coords.bearingTo(other.coords);
|
|
74
|
+
}
|
|
75
|
+
toJson() {
|
|
76
|
+
return {
|
|
77
|
+
id: this.id,
|
|
78
|
+
coords: this.coords.toCompressedJson(),
|
|
79
|
+
...Object.keys(this.properties).length > 0 && { properties: this.properties }
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
static fromJson(json) {
|
|
83
|
+
const v = new Vertex(
|
|
84
|
+
Coordinates.fromCompressedJson(json.coords),
|
|
85
|
+
json.properties
|
|
86
|
+
);
|
|
87
|
+
v.id = json.id;
|
|
88
|
+
return v;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
class Graph {
|
|
92
|
+
constructor(vertices, edges) {
|
|
93
|
+
/**
|
|
94
|
+
* exitVertices are vertices that have at least one indoor edge and one outdoor edge
|
|
95
|
+
* They are stored because the Level model cannot handle an indoor and outdoor state like [null, 1] or [null, [1,2]]
|
|
96
|
+
* This vertices are used to cover the projection case:
|
|
97
|
+
* - if projection origin is null, an exit vertex can be used
|
|
98
|
+
* - if projection origin is not null, the intersection level with an exit vertex can be used
|
|
99
|
+
*/
|
|
100
|
+
__publicField(this, "exitVertices");
|
|
101
|
+
this.vertices = vertices;
|
|
102
|
+
this.edges = edges;
|
|
103
|
+
const nullVertices = edges.filter((e) => e.level === null).map((e) => [e.vertex1, e.vertex2]).flat();
|
|
104
|
+
const levelVertices = edges.filter((e) => e.level !== null).map((e) => [e.vertex1, e.vertex2]).flat();
|
|
105
|
+
this.exitVertices = new Set(nullVertices.filter((v1) => levelVertices.includes(v1)));
|
|
106
|
+
}
|
|
107
|
+
getEdgeByVertices(vertex1, vertex2) {
|
|
108
|
+
return Edge.getEdgeByVertices(this.edges, vertex1, vertex2);
|
|
109
|
+
}
|
|
110
|
+
getVertexByCoords(coords) {
|
|
111
|
+
return Graph.getVertexByCoords(this.vertices, coords);
|
|
112
|
+
}
|
|
113
|
+
static getVertexByCoords(vertices, coords) {
|
|
114
|
+
return vertices.find((vertex) => vertex.coords.equals(coords));
|
|
115
|
+
}
|
|
116
|
+
getVertexByName(name) {
|
|
117
|
+
return this.vertices.find((vertex) => vertex.properties.name === name);
|
|
118
|
+
}
|
|
119
|
+
getEdgeByName(name) {
|
|
120
|
+
return this.edges.find((edge) => edge.properties.name === name);
|
|
121
|
+
}
|
|
122
|
+
getBoundingBox(extendedMeasure) {
|
|
123
|
+
if (!this.vertices.length) {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
const boundingBox = BoundingBox.fromCoordinates(this.vertices.map((vertex) => vertex.coords));
|
|
127
|
+
if (extendedMeasure) {
|
|
128
|
+
boundingBox.extendsWithMeasure(extendedMeasure);
|
|
129
|
+
}
|
|
130
|
+
return boundingBox;
|
|
131
|
+
}
|
|
132
|
+
getProjection(origin, options = {}) {
|
|
133
|
+
const useMaxDistance = "maxDistance" in options;
|
|
134
|
+
const maxDistance = options.maxDistance;
|
|
135
|
+
const useMaxBearingAngle = "maxBearingAngle" in options;
|
|
136
|
+
if (useMaxBearingAngle && (!(origin instanceof UserPosition) || origin.bearing === null))
|
|
137
|
+
return null;
|
|
138
|
+
const maxBearingAngle = options.maxBearingAngle;
|
|
139
|
+
const useAcceptEdgeFn = "acceptEdgeFn" in options;
|
|
140
|
+
const useMultiLevelSegments = !("useMultiLevelSegments" in options) || options.useMultiLevelSegments;
|
|
141
|
+
let bestProjection = null;
|
|
142
|
+
const adaptProjectionCoords = (projCoords) => {
|
|
143
|
+
if (!(origin instanceof UserPosition))
|
|
144
|
+
return projCoords;
|
|
145
|
+
const p = origin.clone();
|
|
146
|
+
p.lat = projCoords.lat;
|
|
147
|
+
p.lng = projCoords.lng;
|
|
148
|
+
p.level = projCoords.level;
|
|
149
|
+
p.alt = projCoords.alt;
|
|
150
|
+
p.heightFromFloor = projCoords.heightFromFloor;
|
|
151
|
+
p.heightFromGround = projCoords.heightFromGround;
|
|
152
|
+
return p;
|
|
153
|
+
};
|
|
154
|
+
this.edges.forEach((edge) => {
|
|
155
|
+
if (useAcceptEdgeFn && !options.acceptEdgeFn(edge))
|
|
156
|
+
return;
|
|
157
|
+
if (!useMultiLevelSegments && Level.isRange(edge.level))
|
|
158
|
+
return;
|
|
159
|
+
if (!Level.intersect(edge.level, origin.level))
|
|
160
|
+
return;
|
|
161
|
+
if (useMaxBearingAngle) {
|
|
162
|
+
if (diffAngleLines(edge.bearing, origin.bearing) > maxBearingAngle)
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
const segmentProjection = origin.getSegmentProjection(edge.vertex1.coords, edge.vertex2.coords);
|
|
166
|
+
if (!segmentProjection)
|
|
167
|
+
return;
|
|
168
|
+
const distanceToSegment = segmentProjection.distanceTo(origin);
|
|
169
|
+
if (useMaxDistance && distanceToSegment > maxDistance)
|
|
170
|
+
return;
|
|
171
|
+
if (distanceToSegment < ((bestProjection == null ? void 0 : bestProjection.distanceFromNearestElement) ?? Number.MAX_VALUE)) {
|
|
172
|
+
bestProjection = new GraphProjection(origin, distanceToSegment, adaptProjectionCoords(segmentProjection), edge);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
if (useMaxBearingAngle) {
|
|
176
|
+
return bestProjection;
|
|
177
|
+
}
|
|
178
|
+
this.vertices.forEach((vertex) => {
|
|
179
|
+
let vertexCoords = vertex.coords;
|
|
180
|
+
if (this.exitVertices.has(vertex) && origin.level === null) {
|
|
181
|
+
vertexCoords = vertex.coords.clone();
|
|
182
|
+
vertexCoords.level = null;
|
|
183
|
+
}
|
|
184
|
+
if (!useMultiLevelSegments && Level.isRange(vertexCoords.level))
|
|
185
|
+
return;
|
|
186
|
+
if (!Level.intersect(vertexCoords.level, origin.level))
|
|
187
|
+
return;
|
|
188
|
+
const distanceToVertex = vertexCoords.distanceTo(origin);
|
|
189
|
+
if (distanceToVertex < Constants.EPS_MM) {
|
|
190
|
+
bestProjection = new GraphProjection(origin, 0, adaptProjectionCoords(vertexCoords), vertex);
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
if (useMaxDistance && distanceToVertex > maxDistance)
|
|
194
|
+
return;
|
|
195
|
+
if (distanceToVertex < ((bestProjection == null ? void 0 : bestProjection.distanceFromNearestElement) ?? Number.MAX_VALUE)) {
|
|
196
|
+
bestProjection = new GraphProjection(origin, distanceToVertex, adaptProjectionCoords(vertexCoords), vertex);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
return bestProjection;
|
|
200
|
+
}
|
|
201
|
+
toJson() {
|
|
202
|
+
return {
|
|
203
|
+
vertices: this.vertices.map((vertex) => vertex.toJson()),
|
|
204
|
+
edges: this.edges.map((edge) => ({
|
|
205
|
+
id: edge.id,
|
|
206
|
+
vertex1Idx: this.vertices.indexOf(edge.vertex1),
|
|
207
|
+
vertex2Idx: this.vertices.indexOf(edge.vertex2),
|
|
208
|
+
...Object.keys(edge.properties).length > 0 && { properties: edge.properties }
|
|
209
|
+
}))
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
static fromJson(json) {
|
|
213
|
+
const vertices = json.vertices.map((vertex) => Vertex.fromJson(vertex));
|
|
214
|
+
const edges = json.edges.map((jsonEdge) => new Edge(
|
|
215
|
+
vertices[jsonEdge.vertex1Idx],
|
|
216
|
+
vertices[jsonEdge.vertex2Idx],
|
|
217
|
+
jsonEdge.properties,
|
|
218
|
+
jsonEdge.id
|
|
219
|
+
));
|
|
220
|
+
return new Graph(vertices, edges);
|
|
221
|
+
}
|
|
222
|
+
/** @deprecated */
|
|
223
|
+
toCompressedJson() {
|
|
224
|
+
return {
|
|
225
|
+
vertices: this.vertices.map((vertex) => vertex.coords.toCompressedJson()),
|
|
226
|
+
verticesIds: this.vertices.map((vertex) => vertex.id),
|
|
227
|
+
edges: this.edges.map((edge) => {
|
|
228
|
+
const vertex1Idx = this.vertices.indexOf(edge.vertex1);
|
|
229
|
+
const vertex2Idx = this.vertices.indexOf(edge.vertex2);
|
|
230
|
+
const edgeExtras = edge.properties;
|
|
231
|
+
if (Object.keys(edgeExtras).length > 0) {
|
|
232
|
+
return [vertex1Idx, vertex2Idx, edgeExtras];
|
|
233
|
+
}
|
|
234
|
+
return [vertex1Idx, vertex2Idx];
|
|
235
|
+
})
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
/** @deprecated */
|
|
239
|
+
static fromCompressedJson(json) {
|
|
240
|
+
const vertices = json.vertices.map((vertex) => new Vertex(Coordinates.fromCompressedJson(vertex)));
|
|
241
|
+
const edges = json.edges.map((jsonEdge) => new Edge(
|
|
242
|
+
vertices[jsonEdge[0]],
|
|
243
|
+
vertices[jsonEdge[1]],
|
|
244
|
+
jsonEdge.length > 2 ? jsonEdge[2] : {}
|
|
245
|
+
));
|
|
246
|
+
return new Graph(vertices, edges);
|
|
247
|
+
}
|
|
248
|
+
static fromCoordinatesSegments(segments) {
|
|
249
|
+
const vertices = [];
|
|
250
|
+
const edges = [];
|
|
251
|
+
const getOrCreateVertex = (coords) => {
|
|
252
|
+
const vertex = vertices.find((otherVertex) => otherVertex.coords.equals(coords));
|
|
253
|
+
if (vertex) {
|
|
254
|
+
return vertex;
|
|
255
|
+
}
|
|
256
|
+
const newVertex = new Vertex(coords);
|
|
257
|
+
vertices.push(newVertex);
|
|
258
|
+
return newVertex;
|
|
259
|
+
};
|
|
260
|
+
for (const segment of segments) {
|
|
261
|
+
let previousVertex = null;
|
|
262
|
+
for (const coords of segment) {
|
|
263
|
+
const currentVertex = getOrCreateVertex(coords);
|
|
264
|
+
if (previousVertex) {
|
|
265
|
+
edges.push(new Edge(currentVertex, previousVertex));
|
|
266
|
+
}
|
|
267
|
+
previousVertex = currentVertex;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return new Graph(vertices, edges);
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Create edges From MultiLevel Itinerary for a given level
|
|
274
|
+
* @param useMultiLevelEdges use segments which intersect both levels (stairs, elevators...)
|
|
275
|
+
*/
|
|
276
|
+
getEdgesAtLevel(targetLevel, useMultiLevelEdges = true) {
|
|
277
|
+
return this.edges.filter(
|
|
278
|
+
({ level }) => useMultiLevelEdges ? Level.intersect(targetLevel, level) : Level.contains(targetLevel, level)
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
toDetailedString() {
|
|
282
|
+
let output = `--- Network ---
|
|
283
|
+
Vertices: ${this.vertices.length}
|
|
284
|
+
Edges: ${this.edges.length}
|
|
285
|
+
---
|
|
286
|
+
Vertices
|
|
287
|
+
`;
|
|
288
|
+
this.vertices.forEach((vertex) => {
|
|
289
|
+
output += vertex.id;
|
|
290
|
+
const vertexProps = vertex.properties;
|
|
291
|
+
if (Object.keys(vertexProps).length !== 0) {
|
|
292
|
+
output += ` ${vertexProps}`;
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
output += "---\nEdges\n";
|
|
296
|
+
this.edges.forEach((edge) => {
|
|
297
|
+
output += `${edge.id} - [v1: ${edge.vertex1.id}, v2: ${edge.vertex2.id}]`;
|
|
298
|
+
const edgeProps = edge.properties;
|
|
299
|
+
if (Object.keys(edgeProps).length !== 0) {
|
|
300
|
+
output += ` ${edgeProps}`;
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
output += "---";
|
|
304
|
+
return output;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
function getDurationFromLength(length, speed = 5) {
|
|
308
|
+
return length / (speed * 1e3 / 3600);
|
|
309
|
+
}
|
|
310
|
+
function isTransitModePublicTransport(transitMode) {
|
|
311
|
+
return [
|
|
312
|
+
"AIRPLANE",
|
|
313
|
+
"BOAT",
|
|
314
|
+
"BUS",
|
|
315
|
+
"FERRY",
|
|
316
|
+
"FUNICULAR",
|
|
317
|
+
"METRO",
|
|
318
|
+
"MULTI",
|
|
319
|
+
"TRAIN",
|
|
320
|
+
"TRAM"
|
|
321
|
+
].includes(transitMode);
|
|
322
|
+
}
|
|
323
|
+
function areTransitAndTravelModeConsistent(transitMode, travelMode) {
|
|
324
|
+
return transitMode === travelMode || isTransitModePublicTransport(transitMode) && travelMode === "TRANSIT" || transitMode === "WALK" && travelMode === "TRANSIT";
|
|
325
|
+
}
|
|
326
|
+
function stepToJson(step) {
|
|
327
|
+
return {
|
|
328
|
+
...step.firstStep && { firstStep: true },
|
|
329
|
+
...step.lastStep && { lastStep: true },
|
|
330
|
+
number: step.number,
|
|
331
|
+
coords: step.coords.toCompressedJson(),
|
|
332
|
+
...step.name !== null && { name: step.name },
|
|
333
|
+
angle: Number(step.angle.toFixed(2)),
|
|
334
|
+
previousBearing: Number(step.previousBearing.toFixed(2)),
|
|
335
|
+
nextBearing: Number(step.nextBearing.toFixed(2)),
|
|
336
|
+
distance: Number(step.distance.toFixed(1)),
|
|
337
|
+
duration: Number(step.duration.toFixed(1)),
|
|
338
|
+
...step.levelChange !== null && { levelChange: step.levelChange },
|
|
339
|
+
...step.extras && Object.keys(step.extras).length !== 0 && { extras: step.extras }
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
function jsonToStep(json) {
|
|
343
|
+
return Object.assign({}, json, {
|
|
344
|
+
coords: Coordinates.fromCompressedJson(json.coords),
|
|
345
|
+
firstStep: Boolean(json.firstStep),
|
|
346
|
+
lastStep: Boolean(json.lastStep),
|
|
347
|
+
name: json.name || null,
|
|
348
|
+
levelChange: json.levelChange || null,
|
|
349
|
+
extras: json.extras || null
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
function stepEquals(step1, step2) {
|
|
353
|
+
var _a, _b, _c, _d, _e, _f;
|
|
354
|
+
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;
|
|
355
|
+
}
|
|
356
|
+
class GraphRoute extends Graph {
|
|
357
|
+
constructor(start, end, vertices, edges, edgesWeights) {
|
|
358
|
+
super(vertices, edges);
|
|
359
|
+
this.start = start;
|
|
360
|
+
this.end = end;
|
|
361
|
+
this.vertices = vertices;
|
|
362
|
+
this.edges = edges;
|
|
363
|
+
this.edgesWeights = edgesWeights;
|
|
364
|
+
}
|
|
365
|
+
// /!\ Does not clone vertices
|
|
366
|
+
// /!\ Create new Edges but does not deep clone properties
|
|
367
|
+
// /!\ Does not revert edge oneway property
|
|
368
|
+
reverse() {
|
|
369
|
+
const vertices = this.vertices.slice().reverse();
|
|
370
|
+
const edges = this.edges.slice().reverse();
|
|
371
|
+
const edgesWeights = this.edgesWeights.slice().reverse();
|
|
372
|
+
edges.map((oldEdge) => new Edge(oldEdge.vertex2, oldEdge.vertex1, oldEdge.properties));
|
|
373
|
+
return new GraphRoute(this.start, this.end, vertices, edges, edgesWeights);
|
|
374
|
+
}
|
|
375
|
+
static fromCoordinates(start, end, coordinates) {
|
|
376
|
+
const graph = Graph.fromCoordinatesSegments([coordinates]);
|
|
377
|
+
const edgesWeights = graph.edges.map((e) => getDurationFromLength(e.length));
|
|
378
|
+
return new GraphRoute(start, end, graph.vertices, graph.edges, edgesWeights);
|
|
379
|
+
}
|
|
380
|
+
get hasRoute() {
|
|
381
|
+
return Boolean(this.vertices.length);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
const SKIP_STEP_ANGLE_MAX = deg2rad(20);
|
|
385
|
+
class StepsBuilder {
|
|
386
|
+
constructor() {
|
|
387
|
+
__publicField(this, "start", null);
|
|
388
|
+
__publicField(this, "end", null);
|
|
389
|
+
__publicField(this, "pathCoords", null);
|
|
390
|
+
__publicField(this, "stepsInfo", []);
|
|
391
|
+
}
|
|
392
|
+
setStart(start) {
|
|
393
|
+
this.start = start;
|
|
394
|
+
return this;
|
|
395
|
+
}
|
|
396
|
+
setEnd(end) {
|
|
397
|
+
this.end = end;
|
|
398
|
+
return this;
|
|
399
|
+
}
|
|
400
|
+
setPathCoords(pathCoords) {
|
|
401
|
+
this.pathCoords = pathCoords;
|
|
402
|
+
return this;
|
|
403
|
+
}
|
|
404
|
+
setStepsInfo(stepsInfo) {
|
|
405
|
+
this.stepsInfo = stepsInfo;
|
|
406
|
+
return this;
|
|
407
|
+
}
|
|
408
|
+
addStepInfo(stepInfo) {
|
|
409
|
+
this.stepsInfo.push(stepInfo);
|
|
410
|
+
return this;
|
|
411
|
+
}
|
|
412
|
+
setGraphRoute(graphRoute) {
|
|
413
|
+
const stepsInfo = [];
|
|
414
|
+
const { start, end } = graphRoute;
|
|
415
|
+
if (!graphRoute.hasRoute) {
|
|
416
|
+
return this;
|
|
417
|
+
}
|
|
418
|
+
let currentStep = null;
|
|
419
|
+
let previousBearing = start.bearingTo(graphRoute.vertices[0].coords);
|
|
420
|
+
for (let i = 0; i < graphRoute.vertices.length - 1; i++) {
|
|
421
|
+
const isFirstStep = i === 0;
|
|
422
|
+
const vertex = graphRoute.vertices[i];
|
|
423
|
+
const currentCoords = vertex.coords;
|
|
424
|
+
const nextVertex = graphRoute.vertices[i + 1];
|
|
425
|
+
const nextCoords = nextVertex.coords;
|
|
426
|
+
const edge = graphRoute.edges[i];
|
|
427
|
+
const nextBearing = vertex.bearingTo(nextVertex);
|
|
428
|
+
const angle = diffAngle(previousBearing, nextBearing + Math.PI);
|
|
429
|
+
const previousStep = stepsInfo.length ? stepsInfo[stepsInfo.length - 1] : null;
|
|
430
|
+
const { isSubwayEntrance, isGate, subwayEntranceRef } = vertex.properties;
|
|
431
|
+
const { isElevator, areEscalators, areStairs, isMovingWalkway, incline } = edge.properties;
|
|
432
|
+
let levelChangeType = null;
|
|
433
|
+
if (isElevator) {
|
|
434
|
+
levelChangeType = "elevator";
|
|
435
|
+
} else if (areEscalators) {
|
|
436
|
+
levelChangeType = "escalator";
|
|
437
|
+
} else if (areStairs) {
|
|
438
|
+
levelChangeType = "stairs";
|
|
439
|
+
} else if (isMovingWalkway) {
|
|
440
|
+
levelChangeType = "moving walkway";
|
|
441
|
+
} else {
|
|
442
|
+
levelChangeType = "incline plane";
|
|
443
|
+
}
|
|
444
|
+
let forceLevelChange;
|
|
445
|
+
if ((areStairs || isElevator) && incline && !(previousStep == null ? void 0 : previousStep.levelChange)) {
|
|
446
|
+
forceLevelChange = incline;
|
|
447
|
+
}
|
|
448
|
+
const previousEdge = i > 0 ? graphRoute.edges[i - 1] : null;
|
|
449
|
+
const previousEdgeProperties = (previousEdge == null ? void 0 : previousEdge.properties) || {};
|
|
450
|
+
const forceEndOfLevelChange = Boolean(
|
|
451
|
+
previousEdgeProperties.incline && previousEdgeProperties.areStairs && (!incline || !areStairs)
|
|
452
|
+
);
|
|
453
|
+
const isEntrance = vertex.properties.isSubwayEntrance;
|
|
454
|
+
const stepName = edge.properties.name || null;
|
|
455
|
+
const duration = graphRoute.edgesWeights[i];
|
|
456
|
+
const stepExtras = {
|
|
457
|
+
...isSubwayEntrance && { isSubwayEntrance },
|
|
458
|
+
...subwayEntranceRef && { subwayEntranceRef },
|
|
459
|
+
...isGate && { isGate }
|
|
460
|
+
};
|
|
461
|
+
let splitByAngle = Math.abs(diffAngle(Math.PI, angle)) >= SKIP_STEP_ANGLE_MAX;
|
|
462
|
+
const splitByLevel = Level.isRange(edge.level) && !Level.isRange(currentCoords.level) || forceLevelChange;
|
|
463
|
+
splitByAngle = splitByAngle && !(currentCoords.level && Level.isRange(currentCoords.level));
|
|
464
|
+
const splitByEndOfLevelChange = (previousStep == null ? void 0 : previousStep.levelChange) && !Level.isRange(currentCoords.level) || forceEndOfLevelChange;
|
|
465
|
+
const splitStepCondition = splitByAngle || splitByLevel || splitByEndOfLevelChange || isEntrance;
|
|
466
|
+
if (isFirstStep || splitStepCondition) {
|
|
467
|
+
let levelChange;
|
|
468
|
+
if (splitByLevel) {
|
|
469
|
+
const difference = Level.diff(currentCoords.level, nextCoords.level) || 0;
|
|
470
|
+
let direction = difference > 0 ? "up" : "down";
|
|
471
|
+
if (forceLevelChange) {
|
|
472
|
+
direction = forceLevelChange;
|
|
473
|
+
}
|
|
474
|
+
levelChange = {
|
|
475
|
+
difference,
|
|
476
|
+
direction,
|
|
477
|
+
...levelChangeType && { type: levelChangeType }
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
currentStep = {
|
|
481
|
+
coords: currentCoords,
|
|
482
|
+
...stepName && { name: stepName },
|
|
483
|
+
extras: stepExtras,
|
|
484
|
+
levelChange,
|
|
485
|
+
distance: 0,
|
|
486
|
+
duration: 0
|
|
487
|
+
};
|
|
488
|
+
stepsInfo.push(currentStep);
|
|
489
|
+
}
|
|
490
|
+
currentStep.distance += currentCoords.distanceTo(nextCoords);
|
|
491
|
+
currentStep.duration += duration;
|
|
492
|
+
previousBearing = nextBearing;
|
|
493
|
+
}
|
|
494
|
+
const lastCoords = graphRoute.vertices[graphRoute.vertices.length - 1].coords;
|
|
495
|
+
if (!Coordinates.equals(lastCoords, end)) {
|
|
496
|
+
stepsInfo.push({ coords: lastCoords });
|
|
497
|
+
}
|
|
498
|
+
this.setStart(start);
|
|
499
|
+
this.setEnd(end);
|
|
500
|
+
this.setPathCoords(graphRoute.vertices.map((v) => v.coords));
|
|
501
|
+
this.setStepsInfo(stepsInfo);
|
|
502
|
+
return this;
|
|
503
|
+
}
|
|
504
|
+
build() {
|
|
505
|
+
const { pathCoords, start, end } = this;
|
|
506
|
+
if (!pathCoords) {
|
|
507
|
+
Logger.warn(`StepsBuilder: Missing "pathCoords" property to build steps`);
|
|
508
|
+
return [];
|
|
509
|
+
}
|
|
510
|
+
if (!start) {
|
|
511
|
+
Logger.warn(`StepsBuilder: Missing "from" property to build steps`);
|
|
512
|
+
return [];
|
|
513
|
+
}
|
|
514
|
+
if (!end) {
|
|
515
|
+
Logger.warn(`StepsBuilder: Missing "to" property to build steps`);
|
|
516
|
+
return [];
|
|
517
|
+
}
|
|
518
|
+
if (this.stepsInfo.length === 0) {
|
|
519
|
+
this.setGraphRoute(GraphRoute.fromCoordinates(start, end, pathCoords));
|
|
520
|
+
}
|
|
521
|
+
const { stepsInfo } = this;
|
|
522
|
+
return stepsInfo.map((stepInfo, stepId) => {
|
|
523
|
+
const coordsId = pathCoords.findIndex((coords) => coords.equals(stepInfo.coords));
|
|
524
|
+
if (coordsId === -1) {
|
|
525
|
+
throw new Error("Cannot find step coordinates in itinerary coordinates.");
|
|
526
|
+
}
|
|
527
|
+
const coordsBeforeStep = coordsId === 0 ? start : pathCoords[coordsId - 1];
|
|
528
|
+
const coordsAfterStep = coordsId === pathCoords.length - 1 ? end : pathCoords[coordsId + 1];
|
|
529
|
+
const previousBearing = coordsBeforeStep.bearingTo(stepInfo.coords);
|
|
530
|
+
const nextBearing = stepInfo.coords.bearingTo(coordsAfterStep);
|
|
531
|
+
let distance = 0;
|
|
532
|
+
const isLastStep = stepId === stepsInfo.length - 1;
|
|
533
|
+
const coordsToStopCalculation = isLastStep ? pathCoords[pathCoords.length - 1] : stepsInfo[stepId + 1].coords;
|
|
534
|
+
let currentCoordsId = coordsId;
|
|
535
|
+
while (!pathCoords[currentCoordsId].equals(coordsToStopCalculation)) {
|
|
536
|
+
distance += pathCoords[currentCoordsId].distanceTo(pathCoords[currentCoordsId + 1]);
|
|
537
|
+
currentCoordsId++;
|
|
538
|
+
}
|
|
539
|
+
return {
|
|
540
|
+
coords: stepInfo.coords,
|
|
541
|
+
name: stepInfo.name || null,
|
|
542
|
+
number: stepId + 1,
|
|
543
|
+
previousBearing,
|
|
544
|
+
nextBearing,
|
|
545
|
+
angle: diffAngle(previousBearing, nextBearing + Math.PI),
|
|
546
|
+
firstStep: stepId === 0,
|
|
547
|
+
lastStep: isLastStep,
|
|
548
|
+
distance,
|
|
549
|
+
// stepInfo.distance is overwritten
|
|
550
|
+
duration: stepInfo.duration || getDurationFromLength(distance),
|
|
551
|
+
levelChange: stepInfo.levelChange || null,
|
|
552
|
+
extras: stepInfo.extras || null
|
|
553
|
+
};
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
class Leg {
|
|
558
|
+
constructor({
|
|
559
|
+
start,
|
|
560
|
+
end,
|
|
561
|
+
coords,
|
|
562
|
+
transitMode,
|
|
563
|
+
duration,
|
|
564
|
+
startTime,
|
|
565
|
+
endTime,
|
|
566
|
+
transportInfo,
|
|
567
|
+
steps
|
|
568
|
+
}) {
|
|
569
|
+
__publicField(this, "start");
|
|
570
|
+
__publicField(this, "end");
|
|
571
|
+
__publicField(this, "coords");
|
|
572
|
+
__publicField(this, "distance");
|
|
573
|
+
__publicField(this, "transitMode");
|
|
574
|
+
__publicField(this, "duration");
|
|
575
|
+
__publicField(this, "startTime");
|
|
576
|
+
__publicField(this, "endTime");
|
|
577
|
+
__publicField(this, "steps");
|
|
578
|
+
__publicField(this, "transportInfo");
|
|
579
|
+
this.start = {
|
|
580
|
+
name: start.name || null,
|
|
581
|
+
coords: start.coords
|
|
582
|
+
};
|
|
583
|
+
this.end = {
|
|
584
|
+
name: end.name || null,
|
|
585
|
+
coords: end.coords
|
|
586
|
+
};
|
|
587
|
+
this.coords = coords;
|
|
588
|
+
this.transitMode = transitMode;
|
|
589
|
+
this.distance = Utils.calcDistance(coords);
|
|
590
|
+
this.duration = typeof duration === "number" ? duration : getDurationFromLength(this.distance);
|
|
591
|
+
this.startTime = typeof startTime === "number" ? startTime : null;
|
|
592
|
+
this.endTime = typeof endTime === "number" ? endTime : null;
|
|
593
|
+
this.transportInfo = transportInfo || null;
|
|
594
|
+
this.steps = Array.isArray(steps) ? steps : new StepsBuilder().setStart(start.coords).setEnd(end.coords).setPathCoords(coords).build();
|
|
595
|
+
}
|
|
596
|
+
isPublicTransport() {
|
|
597
|
+
return isTransitModePublicTransport(this.transitMode);
|
|
598
|
+
}
|
|
599
|
+
toGraph() {
|
|
600
|
+
return Graph.fromCoordinatesSegments([this.coords]);
|
|
601
|
+
}
|
|
602
|
+
static equals(obj1, obj2) {
|
|
603
|
+
var _a, _b;
|
|
604
|
+
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));
|
|
605
|
+
if (!intermediate) {
|
|
606
|
+
return false;
|
|
607
|
+
}
|
|
608
|
+
let i;
|
|
609
|
+
for (i = 0; i < obj1.coords.length; i++) {
|
|
610
|
+
if (!obj1.coords[i].equals(obj2.coords[i])) {
|
|
611
|
+
return false;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
for (i = 0; i < obj1.steps.length; i++) {
|
|
615
|
+
if (!stepEquals(obj1.steps[i], obj2.steps[i])) {
|
|
616
|
+
return false;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
if (obj1.transportInfo !== obj2.transportInfo) {
|
|
620
|
+
if (obj1.transportInfo === null || obj2.transportInfo === null) {
|
|
621
|
+
return false;
|
|
622
|
+
}
|
|
623
|
+
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) {
|
|
624
|
+
return false;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
return true;
|
|
628
|
+
}
|
|
629
|
+
equals(obj) {
|
|
630
|
+
return Leg.equals(this, obj);
|
|
631
|
+
}
|
|
632
|
+
toJson() {
|
|
633
|
+
return {
|
|
634
|
+
transitMode: this.transitMode,
|
|
635
|
+
start: {
|
|
636
|
+
coords: this.start.coords.toCompressedJson(),
|
|
637
|
+
...this.start.name && { name: this.start.name }
|
|
638
|
+
},
|
|
639
|
+
end: {
|
|
640
|
+
coords: this.end.coords.toCompressedJson(),
|
|
641
|
+
...this.end.name && { name: this.end.name }
|
|
642
|
+
},
|
|
643
|
+
distance: Number(this.distance.toFixed(1)),
|
|
644
|
+
duration: Number(this.duration.toFixed(1)),
|
|
645
|
+
coords: this.coords.map((coords) => coords.toCompressedJson()),
|
|
646
|
+
steps: this.steps.map(stepToJson),
|
|
647
|
+
...this.startTime !== null && { startTime: this.startTime },
|
|
648
|
+
...this.endTime !== null && { endTime: this.endTime },
|
|
649
|
+
...this.transportInfo !== null && { transportInfo: this.transportInfo }
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
static fromJson(json) {
|
|
653
|
+
var _a;
|
|
654
|
+
const leg = new Leg(Object.assign({}, json, {
|
|
655
|
+
start: {
|
|
656
|
+
coords: Coordinates.fromCompressedJson(json.start.coords),
|
|
657
|
+
name: json.start.name || null
|
|
658
|
+
},
|
|
659
|
+
end: {
|
|
660
|
+
coords: Coordinates.fromCompressedJson(json.end.coords),
|
|
661
|
+
name: json.end.name || null
|
|
662
|
+
},
|
|
663
|
+
coords: json.coords.map(Coordinates.fromCompressedJson),
|
|
664
|
+
steps: ((_a = json.steps) == null ? void 0 : _a.map(jsonToStep)) || null
|
|
665
|
+
}));
|
|
666
|
+
return leg;
|
|
667
|
+
}
|
|
668
|
+
static fromGraphRoute(graphRoute, transitMode = "WALK") {
|
|
669
|
+
return new Leg({
|
|
670
|
+
start: { coords: graphRoute.start },
|
|
671
|
+
end: { coords: graphRoute.end },
|
|
672
|
+
coords: graphRoute.vertices.map((vertex) => vertex.coords),
|
|
673
|
+
duration: graphRoute.edgesWeights.reduce((acc, weight) => acc + weight, 0),
|
|
674
|
+
transitMode,
|
|
675
|
+
steps: new StepsBuilder().setGraphRoute(graphRoute).build()
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
// TODO: Remove when possible...
|
|
679
|
+
// Livemap specific
|
|
680
|
+
multiplyLevel(levelFactor) {
|
|
681
|
+
this.start.coords.level = Level.multiplyBy(this.start.coords.level, levelFactor);
|
|
682
|
+
this.end.coords.level = Level.multiplyBy(this.end.coords.level, levelFactor);
|
|
683
|
+
for (const coords of this.coords) {
|
|
684
|
+
coords.level = Level.multiplyBy(coords.level, levelFactor);
|
|
685
|
+
}
|
|
686
|
+
this.steps.forEach((step) => {
|
|
687
|
+
step.coords.level = Level.multiplyBy(step.coords.level, levelFactor);
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
class Itinerary {
|
|
692
|
+
constructor({
|
|
693
|
+
origin,
|
|
694
|
+
destination,
|
|
695
|
+
duration,
|
|
696
|
+
legs,
|
|
697
|
+
startTime,
|
|
698
|
+
endTime
|
|
699
|
+
}) {
|
|
700
|
+
__publicField(this, "origin");
|
|
701
|
+
__publicField(this, "destination");
|
|
702
|
+
__publicField(this, "duration");
|
|
703
|
+
__publicField(this, "legs");
|
|
704
|
+
__publicField(this, "_transitMode", null);
|
|
705
|
+
__publicField(this, "startTime");
|
|
706
|
+
__publicField(this, "endTime");
|
|
707
|
+
__publicField(this, "_coords", null);
|
|
708
|
+
__publicField(this, "_distance", null);
|
|
709
|
+
this.origin = origin;
|
|
710
|
+
this.destination = destination;
|
|
711
|
+
this.legs = legs;
|
|
712
|
+
if (typeof duration === "number") {
|
|
713
|
+
this.duration = duration;
|
|
714
|
+
} else {
|
|
715
|
+
this.duration = this.legs.reduce((dur, leg) => dur + leg.duration, 0);
|
|
716
|
+
}
|
|
717
|
+
this.startTime = typeof startTime === "number" ? startTime : null;
|
|
718
|
+
this.endTime = typeof endTime === "number" ? endTime : null;
|
|
719
|
+
this.updateStepsFromLegs();
|
|
720
|
+
}
|
|
721
|
+
set coords(_) {
|
|
722
|
+
throw new Error("Itinerary.coords cannot be set. They are calculated from Itinerary.legs.");
|
|
723
|
+
}
|
|
724
|
+
get coords() {
|
|
725
|
+
if (!this._coords) {
|
|
726
|
+
this._coords = this.legs.map((leg) => leg.coords).flat().filter((coords, idx, arr) => idx === 0 || !arr[idx - 1].equals(coords));
|
|
727
|
+
}
|
|
728
|
+
return this._coords;
|
|
729
|
+
}
|
|
730
|
+
set steps(_) {
|
|
731
|
+
throw new Error("Itinerary.step cannot be set. They are calculated from Itinerary.legs.");
|
|
732
|
+
}
|
|
733
|
+
get steps() {
|
|
734
|
+
return this.legs.map((leg) => leg.steps).flat();
|
|
735
|
+
}
|
|
736
|
+
set transitMode(_) {
|
|
737
|
+
throw new Error("Itinerary.transitMode cannot be set. They are calculated from Itinerary.legs.");
|
|
738
|
+
}
|
|
739
|
+
// Transit mode will return MULTI if there are several transit modes except WALK
|
|
740
|
+
// Else it will return the only transit mode
|
|
741
|
+
// fallback to WALK if no transit mode
|
|
742
|
+
get transitMode() {
|
|
743
|
+
if (!this._transitMode) {
|
|
744
|
+
const legTransitModes = new Set(this.legs.map((leg) => leg.transitMode));
|
|
745
|
+
legTransitModes.delete("WALK");
|
|
746
|
+
if (legTransitModes.size > 1) {
|
|
747
|
+
this._transitMode = "MULTI";
|
|
748
|
+
return this._transitMode;
|
|
749
|
+
}
|
|
750
|
+
if (legTransitModes.size === 1) {
|
|
751
|
+
this._transitMode = legTransitModes.values().next().value;
|
|
752
|
+
return this._transitMode;
|
|
753
|
+
}
|
|
754
|
+
this._transitMode = "WALK";
|
|
755
|
+
}
|
|
756
|
+
return this._transitMode;
|
|
757
|
+
}
|
|
758
|
+
set distance(_) {
|
|
759
|
+
throw new Error("Itinerary.distance cannot be set. They are calculated from Itinerary.legs.");
|
|
760
|
+
}
|
|
761
|
+
get distance() {
|
|
762
|
+
if (this._distance === null) {
|
|
763
|
+
this._distance = Utils.calcDistance(this.coords);
|
|
764
|
+
}
|
|
765
|
+
return this._distance;
|
|
766
|
+
}
|
|
767
|
+
toGraph() {
|
|
768
|
+
return Graph.fromCoordinatesSegments([this.coords]);
|
|
769
|
+
}
|
|
770
|
+
static fromItineraries(...itineraries) {
|
|
771
|
+
return new Itinerary({
|
|
772
|
+
origin: itineraries[0].origin,
|
|
773
|
+
destination: itineraries[itineraries.length - 1].destination,
|
|
774
|
+
legs: itineraries.map((itinerary) => itinerary.legs).flat()
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
/**
|
|
778
|
+
* Convert lat/lng/level? points to Itinerary
|
|
779
|
+
*/
|
|
780
|
+
static fromOrderedPointsArray(points, start, end) {
|
|
781
|
+
const pointToCoordinates = (point) => new Coordinates(point[0], point[1], null, point[2]);
|
|
782
|
+
return this.fromOrderedCoordinates(
|
|
783
|
+
points.map(pointToCoordinates),
|
|
784
|
+
pointToCoordinates(start),
|
|
785
|
+
pointToCoordinates(end)
|
|
786
|
+
);
|
|
787
|
+
}
|
|
788
|
+
/**
|
|
789
|
+
* Convert ordered Coordinates to Itinerary
|
|
790
|
+
*/
|
|
791
|
+
static fromOrderedCoordinates(coords, origin, destination, transitMode = "WALK") {
|
|
792
|
+
const steps = new StepsBuilder().setPathCoords(coords).setStart(origin).setEnd(destination).build();
|
|
793
|
+
const leg = new Leg({
|
|
794
|
+
start: { coords: origin },
|
|
795
|
+
end: { coords: destination },
|
|
796
|
+
coords,
|
|
797
|
+
transitMode,
|
|
798
|
+
steps
|
|
799
|
+
});
|
|
800
|
+
return new Itinerary({ origin, destination, legs: [leg] });
|
|
801
|
+
}
|
|
802
|
+
static equals(obj1, obj2) {
|
|
803
|
+
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;
|
|
804
|
+
if (!intermediate) {
|
|
805
|
+
return false;
|
|
806
|
+
}
|
|
807
|
+
for (let i = 0; i < obj1.legs.length; i++) {
|
|
808
|
+
if (!obj1.legs[i].equals(obj2.legs[i])) {
|
|
809
|
+
return false;
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
return true;
|
|
813
|
+
}
|
|
814
|
+
equals(obj) {
|
|
815
|
+
return Itinerary.equals(this, obj);
|
|
816
|
+
}
|
|
817
|
+
toJson() {
|
|
818
|
+
return {
|
|
819
|
+
origin: this.origin.toJson(),
|
|
820
|
+
destination: this.destination.toJson(),
|
|
821
|
+
distance: Number(this.distance.toFixed(1)),
|
|
822
|
+
duration: Number(this.duration.toFixed(1)),
|
|
823
|
+
transitMode: this.transitMode,
|
|
824
|
+
legs: this.legs.map((leg) => leg.toJson()),
|
|
825
|
+
...this.startTime !== null && { startTime: this.startTime },
|
|
826
|
+
...this.endTime !== null && { endTime: this.endTime }
|
|
827
|
+
};
|
|
828
|
+
}
|
|
829
|
+
static fromJson(json) {
|
|
830
|
+
return new Itinerary({
|
|
831
|
+
origin: Coordinates.fromJson(json.origin),
|
|
832
|
+
destination: Coordinates.fromJson(json.destination),
|
|
833
|
+
duration: json.duration,
|
|
834
|
+
legs: json.legs.map(Leg.fromJson),
|
|
835
|
+
startTime: json.startTime,
|
|
836
|
+
endTime: json.endTime
|
|
837
|
+
});
|
|
838
|
+
}
|
|
839
|
+
static fromGraphRoute(graphRoute, transitMode = "WALK") {
|
|
840
|
+
const leg = Leg.fromGraphRoute(graphRoute, transitMode);
|
|
841
|
+
return new Itinerary({
|
|
842
|
+
origin: graphRoute.start,
|
|
843
|
+
destination: graphRoute.end,
|
|
844
|
+
legs: [leg]
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
// TODO: Remove when possible...
|
|
848
|
+
// Livemap specific
|
|
849
|
+
multiplyLevel(levelFactor) {
|
|
850
|
+
this.origin.level = Level.multiplyBy(this.origin.level, levelFactor);
|
|
851
|
+
this.destination.level = Level.multiplyBy(this.destination.level, levelFactor);
|
|
852
|
+
this.legs.forEach((leg) => leg.multiplyLevel(levelFactor));
|
|
853
|
+
}
|
|
854
|
+
// TODO: Remove when possible...
|
|
855
|
+
// Livemap specific
|
|
856
|
+
forceUnknownLevelTo0() {
|
|
857
|
+
this.origin.level = this.origin.level || 0;
|
|
858
|
+
this.destination.level = this.destination.level || 0;
|
|
859
|
+
for (const leg of this.legs) {
|
|
860
|
+
leg.start.coords.level = leg.start.coords.level || 0;
|
|
861
|
+
leg.end.coords.level = leg.end.coords.level || 0;
|
|
862
|
+
for (const coords of leg.coords) {
|
|
863
|
+
coords.level = coords.level || 0;
|
|
864
|
+
}
|
|
865
|
+
if (leg.steps) {
|
|
866
|
+
for (const step of leg.steps) {
|
|
867
|
+
step.coords.level = step.coords.level || 0;
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
if (this._coords) {
|
|
872
|
+
for (const coords of this._coords) {
|
|
873
|
+
coords.level = coords.level || 0;
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
toGeoJson() {
|
|
878
|
+
const transformToPoint = (point, name, type) => ({
|
|
879
|
+
type: "Feature",
|
|
880
|
+
properties: { name, level: point.level, ...type && { type } },
|
|
881
|
+
geometry: {
|
|
882
|
+
type: "Point",
|
|
883
|
+
coordinates: [point.lng, point.lat]
|
|
884
|
+
}
|
|
885
|
+
});
|
|
886
|
+
const transformToMultiLineStrings = (segments, level) => ({
|
|
887
|
+
type: "Feature",
|
|
888
|
+
properties: { level, name: level == null ? void 0 : level.toString() },
|
|
889
|
+
geometry: {
|
|
890
|
+
type: "MultiLineString",
|
|
891
|
+
coordinates: segments.map((s) => s.map(({ lat, lng }) => [lng, lat]))
|
|
892
|
+
}
|
|
893
|
+
});
|
|
894
|
+
const levelsOfItinerary = [...new Set(this.coords.map((c) => Level.toString(c.level)))].map(Level.fromString);
|
|
895
|
+
const segmentsSplitted = levelsOfItinerary.map((loi) => [loi, Utils.createSegmentsAtLevel(this.coords, loi, true)]);
|
|
896
|
+
const multiLineStrings = segmentsSplitted.map(([loi, segments]) => transformToMultiLineStrings(segments, loi));
|
|
897
|
+
const legsStarts = this.legs.map((leg, idx) => transformToPoint(leg.start.coords, `Leg ${idx} start`, "leg-start"));
|
|
898
|
+
const legsEnds = this.legs.map((leg, idx) => transformToPoint(leg.end.coords, `Leg ${idx} end`, "leg-end"));
|
|
899
|
+
const steps = this.steps.map((step) => transformToPoint(step.coords, `Step ${step.number}`, "step"));
|
|
900
|
+
return {
|
|
901
|
+
type: "FeatureCollection",
|
|
902
|
+
features: [
|
|
903
|
+
transformToPoint(this.origin, "origin", "origin"),
|
|
904
|
+
transformToPoint(this.destination, "destination", "destination"),
|
|
905
|
+
...multiLineStrings,
|
|
906
|
+
...legsStarts,
|
|
907
|
+
...legsEnds,
|
|
908
|
+
...steps
|
|
909
|
+
]
|
|
910
|
+
};
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* TODO: Remove it in router v3
|
|
914
|
+
* Update steps info thanks to the coordinates of the whole itinerary.
|
|
915
|
+
* This method will update:
|
|
916
|
+
* - all steps number
|
|
917
|
+
* - first/last steps
|
|
918
|
+
* - previousBearing/nextBearing/angle of first and last step of each leg
|
|
919
|
+
*/
|
|
920
|
+
updateStepsFromLegs() {
|
|
921
|
+
const itineraryCoords = this.coords.filter((coords, idx, arr) => idx === 0 || !arr[idx - 1].equals(coords));
|
|
922
|
+
const steps = this.legs.map((leg) => leg.steps).flat();
|
|
923
|
+
steps.map((step, stepId) => {
|
|
924
|
+
const coordsId = itineraryCoords.findIndex((coords) => coords.equals(step.coords));
|
|
925
|
+
if (coordsId === -1) {
|
|
926
|
+
throw new Error("Cannot find step coordinates in itinerary coordinates.");
|
|
927
|
+
}
|
|
928
|
+
const coordsBeforeStep = coordsId === 0 ? this.origin : itineraryCoords[coordsId - 1];
|
|
929
|
+
const coordsAfterStep = coordsId === itineraryCoords.length - 1 ? this.destination : itineraryCoords[coordsId + 1];
|
|
930
|
+
step.previousBearing = coordsBeforeStep.bearingTo(step.coords);
|
|
931
|
+
step.nextBearing = step.coords.bearingTo(coordsAfterStep);
|
|
932
|
+
step.angle = diffAngle(step.previousBearing, step.nextBearing + Math.PI);
|
|
933
|
+
step.number = stepId + 1;
|
|
934
|
+
step.firstStep = stepId === 0;
|
|
935
|
+
step.lastStep = stepId === steps.length - 1;
|
|
936
|
+
});
|
|
937
|
+
}
|
|
938
|
+
}
|
|
26
939
|
var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
|
|
27
940
|
var uaParser = { exports: {} };
|
|
28
941
|
(function(module, exports) {
|
|
@@ -1579,20 +2492,20 @@ class GraphRouterEngineResults {
|
|
|
1579
2492
|
}
|
|
1580
2493
|
};
|
|
1581
2494
|
}),
|
|
1582
|
-
...graph.edges.map((
|
|
1583
|
-
const level =
|
|
2495
|
+
...graph.edges.map((e) => {
|
|
2496
|
+
const level = e.level;
|
|
1584
2497
|
return {
|
|
1585
2498
|
type: "Feature",
|
|
1586
2499
|
properties: {
|
|
1587
|
-
id:
|
|
2500
|
+
id: e.id,
|
|
1588
2501
|
...level !== null && { level },
|
|
1589
|
-
...
|
|
2502
|
+
...e.properties
|
|
1590
2503
|
},
|
|
1591
2504
|
geometry: {
|
|
1592
2505
|
type: "LineString",
|
|
1593
2506
|
coordinates: [
|
|
1594
|
-
[
|
|
1595
|
-
[
|
|
2507
|
+
[e.vertex1.coords.lng, e.vertex1.coords.lat],
|
|
2508
|
+
[e.vertex2.coords.lng, e.vertex2.coords.lat]
|
|
1596
2509
|
]
|
|
1597
2510
|
}
|
|
1598
2511
|
};
|
|
@@ -1612,9 +2525,9 @@ class GraphRouterEngine {
|
|
|
1612
2525
|
const q = new Set(inputVertices);
|
|
1613
2526
|
const dist = Array(q.size).fill(Number.MAX_VALUE);
|
|
1614
2527
|
const prev = new Array(q.size).fill(null);
|
|
1615
|
-
const edges = inputEdges.filter((
|
|
2528
|
+
const edges = inputEdges.filter((e) => {
|
|
1616
2529
|
var _a;
|
|
1617
|
-
return (((_a = options.acceptEdgeFn) == null ? void 0 : _a.call(options,
|
|
2530
|
+
return (((_a = options.acceptEdgeFn) == null ? void 0 : _a.call(options, e)) ?? true) && !this.disabledEdges.has(e);
|
|
1618
2531
|
});
|
|
1619
2532
|
const weightEdgeFn = options.weightEdgeFn || ((edge) => edge.length);
|
|
1620
2533
|
const getVertexWithMinDistance = (vertices) => {
|
|
@@ -1698,9 +2611,9 @@ class GraphRouterEngine {
|
|
|
1698
2611
|
"type": "Feature",
|
|
1699
2612
|
"geometry": {
|
|
1700
2613
|
"type": "MultiLineString",
|
|
1701
|
-
"coordinates": edges.map((
|
|
1702
|
-
[
|
|
1703
|
-
[
|
|
2614
|
+
"coordinates": edges.map((e) => [
|
|
2615
|
+
[e.vertex1.coords.lng, e.vertex1.coords.lat],
|
|
2616
|
+
[e.vertex2.coords.lng, e.vertex2.coords.lat]
|
|
1704
2617
|
])
|
|
1705
2618
|
},
|
|
1706
2619
|
"properties": {
|
|
@@ -2024,7 +2937,7 @@ const _OsmGraphUtils = class _OsmGraphUtils {
|
|
|
2024
2937
|
}
|
|
2025
2938
|
if (verticesOfEachLevel.length === 1 && verticesOfEachLevel[0].coords.level === null) {
|
|
2026
2939
|
const vertex = verticesOfEachLevel[0];
|
|
2027
|
-
const vertexEdges = edges.filter((
|
|
2940
|
+
const vertexEdges = edges.filter((e) => e.vertex1 === vertex || e.vertex2 === vertex);
|
|
2028
2941
|
if (vertexEdges.length > 1) {
|
|
2029
2942
|
const elevatorVertices2 = [vertex];
|
|
2030
2943
|
for (let i = 1; i < vertexEdges.length; i++) {
|
|
@@ -2061,6 +2974,64 @@ __publicField(_OsmGraphUtils, "DEFAULT_WAY_SELECTOR", (way) => {
|
|
|
2061
2974
|
return way.tags.highway && !_OsmGraphUtils.RESTRICTED_PEDESTRIANS_HIGHWAYS.includes(way.tags.highway) && !isElevatorArea || way.tags.footway === "sidewalk" || way.tags.public_transport === "platform" || way.tags.railway === "platform";
|
|
2062
2975
|
});
|
|
2063
2976
|
let OsmGraphUtils = _OsmGraphUtils;
|
|
2977
|
+
class RemoteRouter {
|
|
2978
|
+
}
|
|
2979
|
+
var StatusCode = /* @__PURE__ */ ((StatusCode2) => {
|
|
2980
|
+
StatusCode2[StatusCode2["OK"] = 0] = "OK";
|
|
2981
|
+
StatusCode2[StatusCode2["CANCELLED"] = 1] = "CANCELLED";
|
|
2982
|
+
StatusCode2[StatusCode2["UNKNOWN"] = 2] = "UNKNOWN";
|
|
2983
|
+
StatusCode2[StatusCode2["INVALID_ARGUMENT"] = 3] = "INVALID_ARGUMENT";
|
|
2984
|
+
StatusCode2[StatusCode2["NOT_FOUND"] = 5] = "NOT_FOUND";
|
|
2985
|
+
StatusCode2[StatusCode2["UNIMPLEMENTED"] = 12] = "UNIMPLEMENTED";
|
|
2986
|
+
StatusCode2[StatusCode2["INTERNAL"] = 13] = "INTERNAL";
|
|
2987
|
+
StatusCode2[StatusCode2["UNAVAILABLE"] = 14] = "UNAVAILABLE";
|
|
2988
|
+
StatusCode2[StatusCode2["UNAUTHENTICATED"] = 16] = "UNAUTHENTICATED";
|
|
2989
|
+
return StatusCode2;
|
|
2990
|
+
})(StatusCode || {});
|
|
2991
|
+
class RoutingError extends Error {
|
|
2992
|
+
constructor(code = StatusCode.UNKNOWN, message) {
|
|
2993
|
+
super(message);
|
|
2994
|
+
__publicField(this, "customMapName");
|
|
2995
|
+
this.code = code;
|
|
2996
|
+
}
|
|
2997
|
+
static notFound(details) {
|
|
2998
|
+
return new RoutingError(StatusCode.NOT_FOUND, `Cannot found an itinerary. Details: ${details}`);
|
|
2999
|
+
}
|
|
3000
|
+
}
|
|
3001
|
+
class WemapMultiRoutingError extends RoutingError {
|
|
3002
|
+
constructor(code = StatusCode.UNKNOWN, mapName, message) {
|
|
3003
|
+
super(code, message);
|
|
3004
|
+
this.code = code;
|
|
3005
|
+
this.mapName = mapName;
|
|
3006
|
+
this.mapName = mapName;
|
|
3007
|
+
}
|
|
3008
|
+
static notFound(mapName, details) {
|
|
3009
|
+
return new WemapMultiRoutingError(StatusCode.NOT_FOUND, mapName, `Cannot found an itinerary in map ${mapName}. Details: ${details || "No details"}`);
|
|
3010
|
+
}
|
|
3011
|
+
}
|
|
3012
|
+
class RemoteRoutingError extends RoutingError {
|
|
3013
|
+
constructor(code = StatusCode.UNKNOWN, routerName, message) {
|
|
3014
|
+
super(code, message);
|
|
3015
|
+
this.code = code;
|
|
3016
|
+
this.routerName = routerName;
|
|
3017
|
+
this.routerName = routerName;
|
|
3018
|
+
}
|
|
3019
|
+
static notFound(routerName, details) {
|
|
3020
|
+
return new RemoteRoutingError(StatusCode.NOT_FOUND, routerName, `Cannot found an itinerary with ${routerName}. Details: ${details || "No details"}`);
|
|
3021
|
+
}
|
|
3022
|
+
static missingApiKey(routerName, details) {
|
|
3023
|
+
return new RemoteRoutingError(StatusCode.UNAUTHENTICATED, routerName, `API key is missing for ${routerName}. Details: ${details}`);
|
|
3024
|
+
}
|
|
3025
|
+
static unreachableServer(routerName, url) {
|
|
3026
|
+
return new RemoteRoutingError(StatusCode.NOT_FOUND, routerName, `Remote router server ${routerName} is unreachable. URL: ${url}`);
|
|
3027
|
+
}
|
|
3028
|
+
static responseNotParsing(routerName, url) {
|
|
3029
|
+
return new RemoteRoutingError(StatusCode.NOT_FOUND, routerName, `Remote router server response ${routerName} cannot be parsed. URL: ${url}`);
|
|
3030
|
+
}
|
|
3031
|
+
static travelModeUnimplemented(routerName, travelMode) {
|
|
3032
|
+
return new RemoteRoutingError(StatusCode.UNIMPLEMENTED, routerName, `Travel mode "${travelMode}" is not implemented for ${routerName}`);
|
|
3033
|
+
}
|
|
3034
|
+
}
|
|
2064
3035
|
function dateWithTimeZone(year, month, day, hour, minute, second, timeZone = "Europe/Paris") {
|
|
2065
3036
|
const date = new Date(Date.UTC(year, month, day, hour, minute, second));
|
|
2066
3037
|
const utcDate = new Date(date.toLocaleString("en-US", { timeZone: "UTC" }));
|
|
@@ -3178,6 +4149,218 @@ class IdfmRemoteRouter extends RemoteRouter {
|
|
|
3178
4149
|
}
|
|
3179
4150
|
}
|
|
3180
4151
|
const IdfmRemoteRouter$1 = new IdfmRemoteRouter();
|
|
4152
|
+
const outputModeCorrespondance = /* @__PURE__ */ new Map();
|
|
4153
|
+
outputModeCorrespondance.set("CAR", "CAR");
|
|
4154
|
+
outputModeCorrespondance.set("WALK", "WALK");
|
|
4155
|
+
outputModeCorrespondance.set("BIKE", "BIKE");
|
|
4156
|
+
class OsrmRemoteRouter extends RemoteRouter {
|
|
4157
|
+
constructor() {
|
|
4158
|
+
super(...arguments);
|
|
4159
|
+
__publicField(this, "inputModeCorrespondance", (routerRequest) => {
|
|
4160
|
+
var _a;
|
|
4161
|
+
const { travelMode, travelModePreference: preference } = routerRequest;
|
|
4162
|
+
if (travelMode === "WALK" && ((_a = routerRequest.itineraryModifiers) == null ? void 0 : _a.isWheelchair))
|
|
4163
|
+
return "pmr";
|
|
4164
|
+
if (travelMode === "WALK")
|
|
4165
|
+
return "walking";
|
|
4166
|
+
if (travelMode === "BIKE") {
|
|
4167
|
+
if (preference === "FASTEST")
|
|
4168
|
+
return "bike-fastest";
|
|
4169
|
+
if (preference === "SAFEST")
|
|
4170
|
+
return "bike-safest";
|
|
4171
|
+
if (preference === "TOURISM")
|
|
4172
|
+
return "bike-safest";
|
|
4173
|
+
return "bike-safest";
|
|
4174
|
+
}
|
|
4175
|
+
if (travelMode === "CAR")
|
|
4176
|
+
return "driving";
|
|
4177
|
+
throw RemoteRoutingError.travelModeUnimplemented(this.rname, travelMode);
|
|
4178
|
+
});
|
|
4179
|
+
}
|
|
4180
|
+
get rname() {
|
|
4181
|
+
return "osrm";
|
|
4182
|
+
}
|
|
4183
|
+
async getItineraries(endpointUrl, routerRequest) {
|
|
4184
|
+
const url = this.getURL(endpointUrl, routerRequest);
|
|
4185
|
+
const res = await fetch(url).catch(() => {
|
|
4186
|
+
throw RemoteRoutingError.unreachableServer(this.rname, url);
|
|
4187
|
+
});
|
|
4188
|
+
const jsonResponse = await res.json().catch(() => {
|
|
4189
|
+
throw RemoteRoutingError.responseNotParsing(this.rname, url);
|
|
4190
|
+
});
|
|
4191
|
+
return this.parseResponse(jsonResponse, routerRequest.origin, routerRequest.destination, routerRequest.travelMode);
|
|
4192
|
+
}
|
|
4193
|
+
/**
|
|
4194
|
+
* @throws {TravelModeCorrespondanceNotFound}
|
|
4195
|
+
*/
|
|
4196
|
+
getURL(endpointUrl, routerRequest) {
|
|
4197
|
+
const { origin, destination } = routerRequest;
|
|
4198
|
+
const osrmMode = this.inputModeCorrespondance(routerRequest);
|
|
4199
|
+
const waypoints = [origin, ...routerRequest.waypoints || [], destination];
|
|
4200
|
+
let url = endpointUrl + "/route/v1/" + osrmMode + "/";
|
|
4201
|
+
url += waypoints.map((waypoint) => [waypoint.longitude + "," + waypoint.latitude]).join(";");
|
|
4202
|
+
url += "?geometries=geojson&overview=full&steps=true";
|
|
4203
|
+
routerRequest.provideItineraryAlternatives && (url += "&alternatives=true");
|
|
4204
|
+
return url;
|
|
4205
|
+
}
|
|
4206
|
+
coordinatesToJson({ lat, lng, level }) {
|
|
4207
|
+
if (level === null) {
|
|
4208
|
+
return [lng, lat];
|
|
4209
|
+
}
|
|
4210
|
+
if (Level.isRange(level)) {
|
|
4211
|
+
return [lng, lat, level[0]];
|
|
4212
|
+
}
|
|
4213
|
+
return [lng, lat, level];
|
|
4214
|
+
}
|
|
4215
|
+
/**
|
|
4216
|
+
* @param {object} json
|
|
4217
|
+
* @returns {Coordinates}
|
|
4218
|
+
*/
|
|
4219
|
+
jsonToCoordinates(json) {
|
|
4220
|
+
const coords = new Coordinates(json[1], json[0]);
|
|
4221
|
+
if (json.length > 2) {
|
|
4222
|
+
coords.level = json[2];
|
|
4223
|
+
}
|
|
4224
|
+
return coords;
|
|
4225
|
+
}
|
|
4226
|
+
getModifierFromAngle(_angle) {
|
|
4227
|
+
const angle = positiveMod(rad2deg(_angle), 360);
|
|
4228
|
+
if (angle > 0 && angle < 60) {
|
|
4229
|
+
return "sharp right";
|
|
4230
|
+
}
|
|
4231
|
+
if (angle >= 60 && angle < 140) {
|
|
4232
|
+
return "right";
|
|
4233
|
+
}
|
|
4234
|
+
if (angle >= 140 && angle < 160) {
|
|
4235
|
+
return "slight right";
|
|
4236
|
+
}
|
|
4237
|
+
if (angle >= 160 && angle <= 200) {
|
|
4238
|
+
return "straight";
|
|
4239
|
+
}
|
|
4240
|
+
if (angle > 200 && angle <= 220) {
|
|
4241
|
+
return "slight left";
|
|
4242
|
+
}
|
|
4243
|
+
if (angle > 220 && angle <= 300) {
|
|
4244
|
+
return "left";
|
|
4245
|
+
}
|
|
4246
|
+
if (angle > 300 && angle < 360) {
|
|
4247
|
+
return "sharp left";
|
|
4248
|
+
}
|
|
4249
|
+
return "u turn";
|
|
4250
|
+
}
|
|
4251
|
+
noRouteFoundJson(message) {
|
|
4252
|
+
return {
|
|
4253
|
+
"code": "NoRoute",
|
|
4254
|
+
message
|
|
4255
|
+
};
|
|
4256
|
+
}
|
|
4257
|
+
/**
|
|
4258
|
+
* @deprecated
|
|
4259
|
+
*/
|
|
4260
|
+
itineraryToOsrmJson(itinerary) {
|
|
4261
|
+
const lastLegId = itinerary.legs.length - 1;
|
|
4262
|
+
const itinerarySteps = itinerary.steps;
|
|
4263
|
+
const jsonLegs = itinerary.legs.map(({ distance, duration, coords }, idLeg) => {
|
|
4264
|
+
const legSteps = itinerarySteps.filter(
|
|
4265
|
+
(step) => coords.find((_coords) => _coords.equals(step.coords))
|
|
4266
|
+
);
|
|
4267
|
+
const lastStepId = legSteps.length - 1;
|
|
4268
|
+
return {
|
|
4269
|
+
distance,
|
|
4270
|
+
duration: duration || 0,
|
|
4271
|
+
steps: legSteps.map((step, idStep, arr) => {
|
|
4272
|
+
let type = idStep === 0 && idLeg === 0 ? "depart" : "turn";
|
|
4273
|
+
type = idStep === lastStepId && idLeg === lastLegId ? "arrive" : type;
|
|
4274
|
+
const stepCoordsIdx = coords.findIndex((p) => p.equals(step.coords));
|
|
4275
|
+
const nextStepCoordsIdx = idStep === lastStepId ? stepCoordsIdx : coords.findIndex((p) => p.equals(arr[idStep + 1].coords));
|
|
4276
|
+
const osrmStep = {
|
|
4277
|
+
geometry: {
|
|
4278
|
+
type: "LineString",
|
|
4279
|
+
coordinates: coords.slice(stepCoordsIdx, nextStepCoordsIdx + 1).map(this.coordinatesToJson)
|
|
4280
|
+
},
|
|
4281
|
+
distance: step.distance,
|
|
4282
|
+
duration: step.duration || 0,
|
|
4283
|
+
...step.name && { name: step.name },
|
|
4284
|
+
maneuver: {
|
|
4285
|
+
bearing_before: rad2deg(step.previousBearing),
|
|
4286
|
+
bearing_after: rad2deg(step.nextBearing),
|
|
4287
|
+
location: this.coordinatesToJson(step.coords),
|
|
4288
|
+
modifier: this.getModifierFromAngle(step.angle),
|
|
4289
|
+
type
|
|
4290
|
+
}
|
|
4291
|
+
};
|
|
4292
|
+
return osrmStep;
|
|
4293
|
+
})
|
|
4294
|
+
};
|
|
4295
|
+
});
|
|
4296
|
+
return {
|
|
4297
|
+
"code": "Ok",
|
|
4298
|
+
"routes": [
|
|
4299
|
+
{
|
|
4300
|
+
"geometry": {
|
|
4301
|
+
"type": "LineString",
|
|
4302
|
+
"coordinates": itinerary.coords.map(this.coordinatesToJson)
|
|
4303
|
+
},
|
|
4304
|
+
"legs": jsonLegs,
|
|
4305
|
+
"distance": itinerary.distance,
|
|
4306
|
+
"duration": itinerary.duration,
|
|
4307
|
+
"weight_name": "routability",
|
|
4308
|
+
"weight": 0
|
|
4309
|
+
}
|
|
4310
|
+
],
|
|
4311
|
+
"waypoints": []
|
|
4312
|
+
};
|
|
4313
|
+
}
|
|
4314
|
+
parseResponse(json, origin, destination, travelMode) {
|
|
4315
|
+
const transitMode = outputModeCorrespondance.get(travelMode);
|
|
4316
|
+
const { routes: jsonRoutes } = json;
|
|
4317
|
+
if (!jsonRoutes) {
|
|
4318
|
+
throw RemoteRoutingError.notFound(this.rname, json.message);
|
|
4319
|
+
}
|
|
4320
|
+
return jsonRoutes.map((jsonItinerary) => {
|
|
4321
|
+
const legs = jsonItinerary.legs.map((jsonLeg) => {
|
|
4322
|
+
var _a;
|
|
4323
|
+
const legCoords = jsonLeg.steps.map((step) => step.geometry.coordinates.map(this.jsonToCoordinates)).flat().filter((coords, idx, arr) => idx === 0 || !arr[idx - 1].equals(coords));
|
|
4324
|
+
const startCoords = legCoords[0];
|
|
4325
|
+
const endCoords = legCoords[legCoords.length - 1];
|
|
4326
|
+
const stepsBuilder = new StepsBuilder().setPathCoords(legCoords).setStart(startCoords).setEnd(endCoords);
|
|
4327
|
+
(_a = jsonLeg.steps) == null ? void 0 : _a.forEach(({ maneuver, name, distance, duration }) => {
|
|
4328
|
+
const stepCoords = this.jsonToCoordinates(maneuver.location);
|
|
4329
|
+
const distances = legCoords.map((coords) => coords.distanceTo(stepCoords));
|
|
4330
|
+
const idStepCoordsInLeg = distances.indexOf(Math.min(...distances));
|
|
4331
|
+
if (idStepCoordsInLeg < 0) {
|
|
4332
|
+
throw new Error("Osrm Parser: Cannot find step coords in leg coordinates");
|
|
4333
|
+
}
|
|
4334
|
+
stepsBuilder.addStepInfo({
|
|
4335
|
+
coords: legCoords[idStepCoordsInLeg],
|
|
4336
|
+
name,
|
|
4337
|
+
distance,
|
|
4338
|
+
duration
|
|
4339
|
+
});
|
|
4340
|
+
});
|
|
4341
|
+
return new Leg({
|
|
4342
|
+
transitMode,
|
|
4343
|
+
duration: jsonLeg.duration,
|
|
4344
|
+
coords: legCoords,
|
|
4345
|
+
start: {
|
|
4346
|
+
coords: startCoords
|
|
4347
|
+
},
|
|
4348
|
+
end: {
|
|
4349
|
+
coords: endCoords
|
|
4350
|
+
},
|
|
4351
|
+
steps: stepsBuilder.build()
|
|
4352
|
+
});
|
|
4353
|
+
});
|
|
4354
|
+
return new Itinerary({
|
|
4355
|
+
duration: jsonItinerary.duration,
|
|
4356
|
+
origin,
|
|
4357
|
+
destination,
|
|
4358
|
+
legs
|
|
4359
|
+
});
|
|
4360
|
+
});
|
|
4361
|
+
}
|
|
4362
|
+
}
|
|
4363
|
+
const OsrmRemoteRouter$1 = new OsrmRemoteRouter();
|
|
3181
4364
|
function isLegPT(leg) {
|
|
3182
4365
|
return leg.mode === "BUS" || leg.mode === "TRAM";
|
|
3183
4366
|
}
|
|
@@ -3333,7 +4516,7 @@ const remoteRouters = [
|
|
|
3333
4516
|
NavitiaRemoteRouter$1,
|
|
3334
4517
|
DeutscheBahnRemoteRouter$1,
|
|
3335
4518
|
IdfmRemoteRouter$1,
|
|
3336
|
-
OsrmRemoteRouter,
|
|
4519
|
+
OsrmRemoteRouter$1,
|
|
3337
4520
|
OtpRemoteRouter$1,
|
|
3338
4521
|
WemapMultiRemoteRouter$1
|
|
3339
4522
|
];
|
|
@@ -3439,11 +4622,11 @@ class WemapMultiRouter {
|
|
|
3439
4622
|
};
|
|
3440
4623
|
try {
|
|
3441
4624
|
remoteRouterItineraries = await RemoteRouterManager$1.getItinerariesWithFallback(newRouterRequest, fallbackStrategy);
|
|
3442
|
-
} catch (
|
|
3443
|
-
if (
|
|
3444
|
-
|
|
4625
|
+
} catch (e) {
|
|
4626
|
+
if (e instanceof RemoteRoutingError) {
|
|
4627
|
+
e.message = customError(e.message);
|
|
3445
4628
|
}
|
|
3446
|
-
throw
|
|
4629
|
+
throw e;
|
|
3447
4630
|
}
|
|
3448
4631
|
ioMapItinerary = Itinerary.fromGraphRoute(ioMapRoute);
|
|
3449
4632
|
return remoteRouterItineraries.map(
|
|
@@ -3472,11 +4655,11 @@ class WemapMultiRouter {
|
|
|
3472
4655
|
};
|
|
3473
4656
|
try {
|
|
3474
4657
|
remoteRouterItineraries = await RemoteRouterManager$1.getItinerariesWithFallback(newRouterRequest, fallbackStrategy);
|
|
3475
|
-
} catch (
|
|
3476
|
-
if (
|
|
3477
|
-
|
|
4658
|
+
} catch (e) {
|
|
4659
|
+
if (e instanceof RemoteRoutingError) {
|
|
4660
|
+
e.message = customError(e.message);
|
|
3478
4661
|
}
|
|
3479
|
-
throw
|
|
4662
|
+
throw e;
|
|
3480
4663
|
}
|
|
3481
4664
|
ioMapItinerary = Itinerary.fromGraphRoute(ioMapRoute);
|
|
3482
4665
|
return remoteRouterItineraries.map(
|
|
@@ -3519,11 +4702,11 @@ class WemapMultiRouter {
|
|
|
3519
4702
|
};
|
|
3520
4703
|
try {
|
|
3521
4704
|
remoteRouterItineraries = await RemoteRouterManager$1.getItinerariesWithFallback(newRouterRequest, fallbackStrategy);
|
|
3522
|
-
} catch (
|
|
3523
|
-
if (
|
|
3524
|
-
|
|
4705
|
+
} catch (e) {
|
|
4706
|
+
if (e instanceof RemoteRoutingError) {
|
|
4707
|
+
e.message = customError(e.message);
|
|
3525
4708
|
}
|
|
3526
|
-
throw
|
|
4709
|
+
throw e;
|
|
3527
4710
|
}
|
|
3528
4711
|
return remoteRouterItineraries.map(
|
|
3529
4712
|
(remoteRouterItinerary) => Itinerary.fromItineraries(
|
|
@@ -3574,8 +4757,8 @@ class CustomGraphMap {
|
|
|
3574
4757
|
let osmModel;
|
|
3575
4758
|
try {
|
|
3576
4759
|
osmModel = OsmParser.parseOsmXmlString(osmXmlString);
|
|
3577
|
-
} catch (
|
|
3578
|
-
errors.couldNotParseFile =
|
|
4760
|
+
} catch (e) {
|
|
4761
|
+
errors.couldNotParseFile = e instanceof Error ? e.message : "Unknown error";
|
|
3579
4762
|
callbackErrors == null ? void 0 : callbackErrors(errors);
|
|
3580
4763
|
return;
|
|
3581
4764
|
}
|
|
@@ -3693,7 +4876,7 @@ class CustomGraphMapTester {
|
|
|
3693
4876
|
static createReport(osmXmlString) {
|
|
3694
4877
|
var _a;
|
|
3695
4878
|
let customGraphMapErrors;
|
|
3696
|
-
const customGraphMap = CustomGraphMap.fromOsmXml(osmXmlString, null, (
|
|
4879
|
+
const customGraphMap = CustomGraphMap.fromOsmXml(osmXmlString, null, (e) => customGraphMapErrors = e);
|
|
3697
4880
|
const errors = [];
|
|
3698
4881
|
if ((customGraphMapErrors == null ? void 0 : customGraphMapErrors.couldNotParseFile) || !customGraphMap) {
|
|
3699
4882
|
errors.push({
|
|
@@ -3857,7 +5040,7 @@ export {
|
|
|
3857
5040
|
Edge,
|
|
3858
5041
|
GeoveloRemoteRouter$1 as GeoveloRemoteRouter,
|
|
3859
5042
|
Graph,
|
|
3860
|
-
|
|
5043
|
+
GraphProjection,
|
|
3861
5044
|
GraphRoute,
|
|
3862
5045
|
GraphRouter,
|
|
3863
5046
|
GraphRouterOptionsBuilder,
|
|
@@ -3868,12 +5051,12 @@ export {
|
|
|
3868
5051
|
NavitiaRemoteRouter$1 as NavitiaRemoteRouter,
|
|
3869
5052
|
NoRouteFoundError,
|
|
3870
5053
|
OsmGraphUtils,
|
|
3871
|
-
OsrmRemoteRouter,
|
|
5054
|
+
OsrmRemoteRouter$1 as OsrmRemoteRouter,
|
|
3872
5055
|
OtpRemoteRouter$1 as OtpRemoteRouter,
|
|
3873
5056
|
RemoteRouterManager$1 as RemoteRouterManager,
|
|
3874
5057
|
RemoteRoutingError,
|
|
3875
|
-
|
|
3876
|
-
|
|
5058
|
+
RoutingError,
|
|
5059
|
+
StatusCode,
|
|
3877
5060
|
Vertex,
|
|
3878
5061
|
WemapMultiRemoteRouter$1 as WemapMultiRemoteRouter,
|
|
3879
5062
|
WemapMultiRouter,
|