@wemap/geo 11.8.2 → 12.0.0-alpha.11

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 CHANGED
@@ -7,8 +7,6 @@ var __publicField = (obj, key, value) => {
7
7
  };
8
8
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
9
9
  const maths = require("@wemap/maths");
10
- const utils = require("@wemap/utils");
11
- const Logger = require("@wemap/logger");
12
10
  const R_MAJOR = 6378137;
13
11
  const R_MINOR = 63567523142e-4;
14
12
  const EARTH_GRAVITY = 9.80665;
@@ -62,13 +60,13 @@ const _Level = class _Level {
62
60
  */
63
61
  static isRange(level) {
64
62
  if (_Level.VERIFY_TYPING) {
65
- this.checkType(level);
63
+ _Level.checkType(level);
66
64
  }
67
65
  return Array.isArray(level);
68
66
  }
69
67
  static clone(level) {
70
68
  if (_Level.VERIFY_TYPING) {
71
- this.checkType(level);
69
+ _Level.checkType(level);
72
70
  }
73
71
  if (level === null) {
74
72
  return null;
@@ -96,14 +94,14 @@ const _Level = class _Level {
96
94
  const levels = splited.map((str2) => Number(str2));
97
95
  const low = Math.min(...levels);
98
96
  const up = Math.max(...levels);
99
- this.checkType([low, up]);
97
+ _Level.checkType([low, up]);
100
98
  return [low, up];
101
99
  } else {
102
100
  const rangeSeparator = str.substring(1).indexOf("-") + 1;
103
101
  if (rangeSeparator > 0) {
104
102
  const low = Number(str.substring(0, rangeSeparator));
105
103
  const up = Number(str.substring(rangeSeparator + 1));
106
- this.checkType([low, up]);
104
+ _Level.checkType([low, up]);
107
105
  return [low, up];
108
106
  }
109
107
  }
@@ -116,8 +114,8 @@ const _Level = class _Level {
116
114
  */
117
115
  static contains(container, targeted) {
118
116
  if (_Level.VERIFY_TYPING) {
119
- this.checkType(container);
120
- this.checkType(targeted);
117
+ _Level.checkType(container);
118
+ _Level.checkType(targeted);
121
119
  }
122
120
  if (container === targeted) {
123
121
  return true;
@@ -138,29 +136,40 @@ const _Level = class _Level {
138
136
  }
139
137
  /**
140
138
  * Retrieve the intersection of two levels
139
+ * null n null => null
140
+ * null n 1 => null // Conception choice
141
+ * null n [1,2] => null // Conception choice
142
+ * 1 n 1 => 1
143
+ * 1 n 2 => null
144
+ * 1 n [1,2] => 1
145
+ * 1 n [0,2] => 1
146
+ * 1 n [2,3] => null
147
+ * [1,2] n [1,2] => [1,2]
148
+ * [1,2] n [2,3] => 2
149
+ * [1,2] n [3,4] => null
141
150
  */
142
151
  static intersection(first, second) {
143
152
  if (_Level.VERIFY_TYPING) {
144
- this.checkType(first);
145
- this.checkType(second);
153
+ _Level.checkType(first);
154
+ _Level.checkType(second);
146
155
  }
147
156
  if (first === null || second === null) {
148
157
  return null;
149
158
  }
150
- if (this.equals(first, second)) {
151
- return this.clone(first);
159
+ if (_Level.equals(first, second)) {
160
+ return _Level.clone(first);
152
161
  }
153
162
  if (typeof first === "number" && typeof second === "number") {
154
163
  return first === second ? first : null;
155
164
  }
156
165
  if (Array.isArray(first) && !Array.isArray(second)) {
157
- if (this.contains(first, second)) {
166
+ if (_Level.contains(first, second)) {
158
167
  return second;
159
168
  }
160
169
  return null;
161
170
  }
162
171
  if (!Array.isArray(first) && Array.isArray(second)) {
163
- if (this.contains(second, first)) {
172
+ if (_Level.contains(second, first)) {
164
173
  return first;
165
174
  }
166
175
  return null;
@@ -180,30 +189,41 @@ const _Level = class _Level {
180
189
  */
181
190
  static intersect(first, second) {
182
191
  if (_Level.VERIFY_TYPING) {
183
- this.checkType(first);
184
- this.checkType(second);
192
+ _Level.checkType(first);
193
+ _Level.checkType(second);
185
194
  }
186
195
  if (first === null && second === null) {
187
196
  return true;
188
197
  }
189
- return this.intersection(first, second) !== null;
198
+ return _Level.intersection(first, second) !== null;
190
199
  }
191
200
  /**
192
201
  * Retrieve the union of two levels
202
+ * null u null => null
203
+ * null u 1 => null // Conception choice
204
+ * null u [1,2] => null // Conception choice
205
+ * 1 u 1 => 1
206
+ * 1 u 2 => [1,2]
207
+ * 1 u [1,2] => [1,2]
208
+ * 1 u [0,2] => [0,2]
209
+ * 1 u [2,3] => [1,3]
210
+ * [1,2] u [1,2] => [1,2]
211
+ * [1,2] u [2,3] => [1,3]
212
+ * [1,2] u [3,4] => [1,4]
193
213
  */
194
214
  static union(first, second) {
195
215
  if (_Level.VERIFY_TYPING) {
196
- this.checkType(first);
197
- this.checkType(second);
216
+ _Level.checkType(first);
217
+ _Level.checkType(second);
198
218
  }
199
219
  if (first === second) {
200
- return this.clone(first);
220
+ return _Level.clone(first);
201
221
  }
202
222
  if (second === null) {
203
- return this.clone(first);
223
+ return null;
204
224
  }
205
225
  if (first === null) {
206
- return this.clone(second);
226
+ return null;
207
227
  }
208
228
  let low, up;
209
229
  if (!Array.isArray(first) && !Array.isArray(second)) {
@@ -232,7 +252,7 @@ const _Level = class _Level {
232
252
  */
233
253
  static multiplyBy(level, factor) {
234
254
  if (_Level.VERIFY_TYPING) {
235
- this.checkType(level);
255
+ _Level.checkType(level);
236
256
  }
237
257
  if (level === null) {
238
258
  return null;
@@ -241,7 +261,7 @@ const _Level = class _Level {
241
261
  }
242
262
  static toString(level) {
243
263
  if (_Level.VERIFY_TYPING) {
244
- this.checkType(level);
264
+ _Level.checkType(level);
245
265
  }
246
266
  if (level === null) {
247
267
  return null;
@@ -250,8 +270,8 @@ const _Level = class _Level {
250
270
  }
251
271
  static equals(first, second) {
252
272
  if (_Level.VERIFY_TYPING) {
253
- this.checkType(first);
254
- this.checkType(second);
273
+ _Level.checkType(first);
274
+ _Level.checkType(second);
255
275
  }
256
276
  if (first === second) {
257
277
  return true;
@@ -263,8 +283,8 @@ const _Level = class _Level {
263
283
  }
264
284
  static diff(first, second) {
265
285
  if (_Level.VERIFY_TYPING) {
266
- this.checkType(first);
267
- this.checkType(second);
286
+ _Level.checkType(first);
287
+ _Level.checkType(second);
268
288
  }
269
289
  if (first === null || second === null) {
270
290
  return null;
@@ -530,7 +550,7 @@ class Coordinates {
530
550
  poseCoordinates.lat,
531
551
  poseCoordinates.lng,
532
552
  alt,
533
- Level.intersection(p1.level, p2.level)
553
+ Level.union(p1.level, p2.level)
534
554
  );
535
555
  if (Math.abs(p1.distanceTo(p2) - p1.distanceTo(projection) - p2.distanceTo(projection)) > EPS_MM) {
536
556
  return null;
@@ -567,26 +587,15 @@ class Coordinates {
567
587
  return [
568
588
  Number(this.lat.toFixed(8)),
569
589
  Number(this.lng.toFixed(8)),
570
- this.alt === null ? null : Number(this.alt.toFixed(3)),
571
590
  this.level
572
591
  ];
573
592
  }
574
- if (this.alt !== null) {
575
- return [
576
- Number(this.lat.toFixed(8)),
577
- Number(this.lng.toFixed(8)),
578
- Number(this.alt.toFixed(3))
579
- ];
580
- }
581
593
  return [Number(this.lat.toFixed(8)), Number(this.lng.toFixed(8))];
582
594
  }
583
595
  static fromCompressedJson(json) {
584
596
  const coords = new Coordinates(json[0], json[1]);
585
597
  if (json.length > 2) {
586
- coords.alt = json[2];
587
- }
588
- if (json.length > 3) {
589
- coords.level = json[3];
598
+ coords.level = json[2];
590
599
  }
591
600
  return coords;
592
601
  }
@@ -802,9 +811,34 @@ function geolocationPositionToUserPosition(geolocationPosition) {
802
811
  function calcDistance(coords) {
803
812
  return coords.reduce((acc, coords2, idx, arr) => acc + (idx ? arr[idx - 1].distanceTo(coords2) : 0), 0);
804
813
  }
814
+ function createSegmentsAtLevel(itineraryCoords, segmentsLevel, useMultiLevelSegments = true) {
815
+ const itineraryCoordsLength = itineraryCoords.length;
816
+ let previousLevelCorrespond = false;
817
+ const segments = [];
818
+ let coordinates = [];
819
+ for (let i = 0; i < itineraryCoordsLength; i++) {
820
+ const coords = itineraryCoords[i];
821
+ const levelCorrespond = Level.intersect(segmentsLevel, coords.level);
822
+ if (useMultiLevelSegments && !levelCorrespond && previousLevelCorrespond) {
823
+ coordinates.push(coords);
824
+ } else if (levelCorrespond) {
825
+ if (!previousLevelCorrespond) {
826
+ coordinates = [];
827
+ segments.push(coordinates);
828
+ if (useMultiLevelSegments && i !== 0) {
829
+ coordinates.push(itineraryCoords[i - 1]);
830
+ }
831
+ }
832
+ coordinates.push(coords);
833
+ }
834
+ previousLevelCorrespond = levelCorrespond;
835
+ }
836
+ return segments;
837
+ }
805
838
  const Utils = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
806
839
  __proto__: null,
807
840
  calcDistance,
841
+ createSegmentsAtLevel,
808
842
  geolocationPositionToUserPosition,
809
843
  sampleRoute,
810
844
  simplifyRoute,
@@ -1244,810 +1278,14 @@ class AbsoluteHeading {
1244
1278
  return new AbsoluteHeading(this.heading, this.time, this.accuracy);
1245
1279
  }
1246
1280
  }
1247
- class GeoGraphEdge extends utils.GraphEdge {
1248
- constructor(vertex1, vertex2, params) {
1249
- super(vertex1, vertex2, params);
1250
- __publicField(this, "_level", null);
1251
- __publicField(this, "_bearing", null);
1252
- __publicField(this, "_length", null);
1253
- __publicField(this, "_computedSizeAndBearing", false);
1254
- __publicField(this, "isOneway", false);
1255
- Object.assign(this, params);
1256
- }
1257
- set vertex1(vertex) {
1258
- super.vertex1 = vertex;
1259
- this._computedSizeAndBearing = false;
1260
- }
1261
- get vertex1() {
1262
- return this._vertex1;
1263
- }
1264
- set vertex2(vertex) {
1265
- super.vertex2 = vertex;
1266
- this._computedSizeAndBearing = false;
1267
- }
1268
- get vertex2() {
1269
- return this._vertex2;
1270
- }
1271
- get level() {
1272
- return this._level;
1273
- }
1274
- set level(level) {
1275
- Level.checkType(level);
1276
- this._level = level;
1277
- }
1278
- /**
1279
- * Get edge bearing from vertex1 to vertex2
1280
- */
1281
- get bearing() {
1282
- if (!this._computedSizeAndBearing) {
1283
- this._computeSizeAndBearing();
1284
- }
1285
- return this._bearing;
1286
- }
1287
- /**
1288
- * get edge length
1289
- */
1290
- get length() {
1291
- if (!this._computedSizeAndBearing) {
1292
- this._computeSizeAndBearing();
1293
- }
1294
- return this._length;
1295
- }
1296
- _computeSizeAndBearing() {
1297
- this._length = this.vertex1.distanceTo(this.vertex2);
1298
- this._bearing = this.vertex1.bearingTo(this.vertex2);
1299
- this._computedSizeAndBearing = true;
1300
- }
1301
- static getEdgeByVertices(edges, vertex1, vertex2) {
1302
- return super.getEdgeByVertices(edges, vertex1, vertex2);
1303
- }
1304
- }
1305
- class GeoGraphVertex extends utils.GraphVertex {
1306
- constructor(coords, params) {
1307
- super(params);
1308
- __publicField(this, "coords");
1309
- __publicField(this, "io", false);
1310
- this.coords = coords;
1311
- }
1312
- distanceTo(other) {
1313
- return this.coords.distanceTo(other.coords);
1314
- }
1315
- bearingTo(other) {
1316
- return this.coords.bearingTo(other.coords);
1317
- }
1318
- /**
1319
- * Does not include "edges" property
1320
- */
1321
- toJson() {
1322
- return this.coords.toCompressedJson();
1323
- }
1324
- static fromJson(json) {
1325
- return new GeoGraphVertex(Coordinates.fromCompressedJson(json));
1326
- }
1327
- inferVertexLevelFromEdges() {
1328
- let tmpLevel = null;
1329
- for (let i = 0; i < this.edges.length; i++) {
1330
- const edge = this.edges[i];
1331
- if (edge.level !== null) {
1332
- if (tmpLevel === null) {
1333
- tmpLevel = Level.clone(edge.level);
1334
- } else {
1335
- tmpLevel = Level.intersection(tmpLevel, edge.level);
1336
- if (tmpLevel === null) {
1337
- throw Error("Something bad happend during parsing: We cannot retrieve vertex level from adjacent ways: " + this.coords);
1338
- }
1339
- }
1340
- }
1341
- }
1342
- this.coords.level = tmpLevel;
1343
- }
1344
- /**
1345
- * We suppose inferVertexLevelFromEdges() was called before
1346
- */
1347
- inferVertexLevelByNeighboors() {
1348
- const { level } = this.coords;
1349
- if (level === null || !Level.isRange(level)) {
1350
- return true;
1351
- }
1352
- let tmpLevel = null;
1353
- for (let i = 0; i < this.edges.length; i++) {
1354
- const edge = this.edges[i];
1355
- const otherVertex = edge.vertex1 === this ? edge.vertex2 : edge.vertex1;
1356
- tmpLevel = Level.union(otherVertex.coords.level, tmpLevel);
1357
- }
1358
- if (tmpLevel === null || !Level.isRange(tmpLevel)) {
1359
- this.coords.level = tmpLevel === level[0] ? level[1] : level[0];
1360
- }
1361
- return true;
1362
- }
1363
- /**
1364
- * We suppose inferVertexLevelFromEdges() and inferVertexLevelByNeighboors() were called before
1365
- */
1366
- inferVertexLevelByRecursion() {
1367
- const { level } = this.coords;
1368
- if (level === null || !Level.isRange(level)) {
1369
- return;
1370
- }
1371
- if (this.edges.length > 1) {
1372
- return;
1373
- }
1374
- const lookForLevel = (vertex, visitedVertices) => {
1375
- visitedVertices.push(vertex);
1376
- if (vertex.coords.level === null) {
1377
- return null;
1378
- }
1379
- if (!Level.isRange(vertex.coords.level)) {
1380
- return vertex.coords.level;
1381
- }
1382
- let tmpLevel = null;
1383
- for (let i = 0; i < vertex.edges.length; i++) {
1384
- const edge = vertex.edges[i];
1385
- const otherVertex = edge.vertex1 === vertex ? edge.vertex2 : edge.vertex1;
1386
- if (!visitedVertices.includes(otherVertex)) {
1387
- tmpLevel = Level.union(lookForLevel(otherVertex, visitedVertices), tmpLevel);
1388
- }
1389
- }
1390
- return tmpLevel;
1391
- };
1392
- const othersLevels = lookForLevel(this, []);
1393
- if (othersLevels !== null) {
1394
- if (!Level.isRange(othersLevels)) {
1395
- this.coords.level = othersLevels === level[0] ? level[1] : level[0];
1396
- return;
1397
- }
1398
- throw Error("Level of: " + this.coords.toString() + " cannot be decided");
1399
- }
1400
- }
1401
- }
1402
- class GeoGraph extends utils.Graph {
1403
- constructor(vertices, edges, generateVerticesLevels = false) {
1404
- super(vertices, edges);
1405
- generateVerticesLevels && this.generateVerticesLevels();
1406
- }
1407
- getVertexByCoords(coords) {
1408
- return GeoGraph.getVertexByCoords(this.vertices, coords);
1409
- }
1410
- static getVertexByCoords(vertices, coords) {
1411
- return vertices.find((vertex) => vertex.coords.equals(coords));
1412
- }
1413
- getVertexByName(name) {
1414
- return super.getVertexByName(name);
1415
- }
1416
- getEdgeByName(name) {
1417
- return super.getEdgeByName(name);
1418
- }
1419
- getBoundingBox(extendedMeasure) {
1420
- if (!this.vertices.length) {
1421
- return null;
1422
- }
1423
- const boundingBox = BoundingBox.fromCoordinates(this.vertices.map((vertex) => vertex.coords));
1424
- if (extendedMeasure) {
1425
- boundingBox.extendsWithMeasure(extendedMeasure);
1426
- }
1427
- return boundingBox;
1428
- }
1429
- toCompressedJson() {
1430
- const createEdgeExtras = (edge) => {
1431
- const extras = {};
1432
- if (edge.isOneway) {
1433
- extras.oneway = true;
1434
- }
1435
- return extras;
1436
- };
1437
- return {
1438
- vertices: this.vertices.map((vertex) => vertex.toJson()),
1439
- edges: this.edges.map((edge) => {
1440
- const vertex1Idx = this.vertices.indexOf(edge.vertex1);
1441
- const vertex2Idx = this.vertices.indexOf(edge.vertex2);
1442
- const edgeExtras = createEdgeExtras(edge);
1443
- if (Object.keys(edgeExtras).length > 0) {
1444
- return [vertex1Idx, vertex2Idx, edge.level, edgeExtras];
1445
- }
1446
- if (edge.level !== null) {
1447
- return [vertex1Idx, vertex2Idx, edge.level];
1448
- }
1449
- return [vertex1Idx, vertex2Idx];
1450
- })
1451
- };
1452
- }
1453
- static fromCompressedJson(json) {
1454
- const geograph = new GeoGraph();
1455
- geograph.vertices = json.vertices.map((vertex) => GeoGraphVertex.fromJson(vertex));
1456
- geograph.edges = json.edges.map((jsonEdge) => {
1457
- const edge = new GeoGraphEdge(
1458
- geograph.vertices[jsonEdge[0]],
1459
- geograph.vertices[jsonEdge[1]],
1460
- { level: jsonEdge.length > 2 ? jsonEdge[2] : null }
1461
- );
1462
- const extras = jsonEdge.length > 3 ? jsonEdge[3] : {};
1463
- if (typeof extras.oneway !== "undefined") {
1464
- edge.isOneway = extras.oneway;
1465
- }
1466
- return edge;
1467
- });
1468
- return geograph;
1469
- }
1470
- static fromCoordinates(segments) {
1471
- const geograph = new GeoGraph();
1472
- const getOrCreateVertex = (coords) => {
1473
- const vertex = geograph.vertices.find((otherVertex) => otherVertex.coords.equals(coords));
1474
- if (vertex) {
1475
- return vertex;
1476
- }
1477
- const newVertex = new GeoGraphVertex(coords);
1478
- geograph.vertices.push(newVertex);
1479
- return newVertex;
1480
- };
1481
- const createEdgeFromVertices = (vertex1, vertex2) => new GeoGraphEdge(
1482
- vertex1,
1483
- vertex2,
1484
- { level: Level.union(vertex1.coords.level, vertex2.coords.level) }
1485
- );
1486
- for (const segment of segments) {
1487
- let previousVertex = null;
1488
- for (const coords of segment) {
1489
- const currentVertex = getOrCreateVertex(coords);
1490
- if (previousVertex) {
1491
- const edge = createEdgeFromVertices(currentVertex, previousVertex);
1492
- geograph.edges.push(edge);
1493
- }
1494
- previousVertex = currentVertex;
1495
- }
1496
- }
1497
- return geograph;
1498
- }
1499
- /**
1500
- * Create edges From MultiLevel Itinerary for a given level
1501
- * @param useMultiLevelEdges use segments which intersect both levels (stairs, elevators...)
1502
- */
1503
- getEdgesAtLevel(targetLevel, useMultiLevelEdges = true) {
1504
- return this.edges.filter(
1505
- ({ level }) => useMultiLevelEdges ? Level.intersect(targetLevel, level) : Level.contains(targetLevel, level)
1506
- );
1507
- }
1508
- generateVerticesLevels() {
1509
- const { vertices } = this;
1510
- vertices.forEach((vertex) => vertex.inferVertexLevelFromEdges());
1511
- vertices.forEach((vertex) => vertex.inferVertexLevelByNeighboors());
1512
- vertices.forEach((vertex) => vertex.inferVertexLevelByRecursion());
1513
- vertices.forEach((vertex) => {
1514
- vertex.io = vertex.coords.level !== null && vertex.edges.some((edge) => edge.level === null);
1515
- });
1516
- }
1517
- }
1518
- class GeoGraphProjection {
1519
- constructor(origin, distanceFromNearestElement, coords, nearestElement) {
1520
- __publicField(this, "origin");
1521
- __publicField(this, "distanceFromNearestElement");
1522
- __publicField(this, "coords");
1523
- __publicField(this, "nearestElement");
1524
- this.origin = origin;
1525
- this.distanceFromNearestElement = distanceFromNearestElement;
1526
- this.coords = coords;
1527
- this.nearestElement = nearestElement;
1528
- }
1529
- }
1530
- const _GeoGraphProjectionHandler = class _GeoGraphProjectionHandler {
1531
- constructor(graph = null) {
1532
- __publicField(this, "graph", null);
1533
- __publicField(this, "_maxDistance", Number.MAX_VALUE);
1534
- __publicField(this, "_maxAngleBearing", Math.PI);
1535
- this.graph = graph;
1536
- }
1537
- set maxAngleBearing(maxAngleBearing) {
1538
- this._maxAngleBearing = maxAngleBearing;
1539
- }
1540
- get maxAngleBearing() {
1541
- return this._maxAngleBearing;
1542
- }
1543
- set maxDistance(maxDistance) {
1544
- this._maxDistance = maxDistance;
1545
- }
1546
- get maxDistance() {
1547
- return this._maxDistance;
1548
- }
1549
- /**
1550
- * Check if the specified edge and its vertices can be used for projection
1551
- * @returns an array of two elements.
1552
- * First is true if projection will be used on the specified edge, false otherwise.
1553
- * Second is true if projection will be used on the vertices of the specified edge, false otherwise.
1554
- */
1555
- _shouldProjectOnEdgeAndVertices(edge, location, useBearing, useMultiLevelSegments, acceptEdgeFn) {
1556
- if (!acceptEdgeFn(edge)) {
1557
- return [false, false, false];
1558
- }
1559
- let checkEdge = Level.intersect(location.level, edge.level);
1560
- let checkVertex1 = Level.intersect(location.level, edge.vertex1.coords.level);
1561
- let checkVertex2 = Level.intersect(location.level, edge.vertex2.coords.level);
1562
- checkVertex1 = checkVertex1 || edge.vertex1.io && location.level === null;
1563
- checkVertex2 = checkVertex2 || edge.vertex2.io && location.level === null;
1564
- if (!useMultiLevelSegments) {
1565
- checkEdge = checkEdge && !Level.isRange(edge.level);
1566
- checkVertex1 = checkVertex1 && !Level.isRange(edge.vertex1.coords.level);
1567
- checkVertex2 = checkVertex2 && !Level.isRange(edge.vertex2.coords.level);
1568
- }
1569
- if (useBearing) {
1570
- if (checkEdge) {
1571
- const diffAngle = maths.diffAngleLines(edge.bearing, location.bearing);
1572
- if (diffAngle > this._maxAngleBearing) {
1573
- checkEdge = false;
1574
- }
1575
- }
1576
- checkVertex1 = false;
1577
- checkVertex2 = false;
1578
- }
1579
- return [checkEdge, checkVertex1, checkVertex2];
1580
- }
1581
- static _assignLatLngLevel(fromCoordinates, toCoordinates) {
1582
- toCoordinates.lat = fromCoordinates.lat;
1583
- toCoordinates.lng = fromCoordinates.lng;
1584
- toCoordinates.level = Level.clone(fromCoordinates.level);
1585
- }
1586
- /**
1587
- * IO Vertices are typical because they have a non-null level but projection car works on them.
1588
- * This function handles the case where the projection is on an IO vertex and a location with
1589
- * a null level is required.
1590
- */
1591
- static _handleLevelsWithIOVertices(projection, location, projectionVertex) {
1592
- if (location.level === null && projectionVertex.io) {
1593
- projection.level = null;
1594
- }
1595
- }
1596
- /**
1597
- * Main function for map-matching, the networks have to be set before calling this function
1598
- * The function will returns a GraphProjection object given a coordinates object and a set
1599
- * of options (useDistance, useBearing, useMultiLevelSegments, acceptEdgeFn).
1600
- */
1601
- getProjection(location, useDistance = false, useBearing = false, useMultiLevelSegments = true, acceptEdgeFn = () => true) {
1602
- if (this.graph === null) {
1603
- throw new Error("Graph has not been set yet");
1604
- }
1605
- if (useBearing && (!("bearing" in location && location.bearing !== null) || !this._maxAngleBearing)) {
1606
- return null;
1607
- }
1608
- let distanceFromNearestElement = Number.MAX_VALUE;
1609
- const projection = location.clone();
1610
- let nearestElement = null;
1611
- const isProjectionBetter = (distanceOfNewProjection) => {
1612
- return distanceOfNewProjection < distanceFromNearestElement && (!useDistance || distanceOfNewProjection <= this._maxDistance);
1613
- };
1614
- for (const edge of this.graph.edges) {
1615
- const [checkEdge, checkVertex1, checkVertex2] = this._shouldProjectOnEdgeAndVertices(
1616
- edge,
1617
- location,
1618
- useBearing,
1619
- useMultiLevelSegments,
1620
- acceptEdgeFn
1621
- );
1622
- if (checkVertex1) {
1623
- const distVertex1 = location.distanceTo(edge.vertex1.coords);
1624
- if (isProjectionBetter(distVertex1) || distVertex1 <= EPS_MM) {
1625
- distanceFromNearestElement = distVertex1;
1626
- nearestElement = edge.vertex1;
1627
- _GeoGraphProjectionHandler._assignLatLngLevel(edge.vertex1.coords, projection);
1628
- _GeoGraphProjectionHandler._handleLevelsWithIOVertices(projection, location, edge.vertex1);
1629
- if (distVertex1 <= EPS_MM) {
1630
- break;
1631
- }
1632
- }
1633
- }
1634
- if (checkVertex2) {
1635
- const distVertex2 = location.distanceTo(edge.vertex2.coords);
1636
- if (isProjectionBetter(distVertex2) || distVertex2 <= EPS_MM) {
1637
- distanceFromNearestElement = distVertex2;
1638
- nearestElement = edge.vertex2;
1639
- _GeoGraphProjectionHandler._assignLatLngLevel(edge.vertex2.coords, projection);
1640
- _GeoGraphProjectionHandler._handleLevelsWithIOVertices(projection, location, edge.vertex2);
1641
- if (distVertex2 <= EPS_MM) {
1642
- break;
1643
- }
1644
- }
1645
- }
1646
- if (checkEdge) {
1647
- const segmentProjection = location.getSegmentProjection(edge.vertex1.coords, edge.vertex2.coords);
1648
- if (segmentProjection) {
1649
- const distEdge = location.distanceTo(segmentProjection);
1650
- if (isProjectionBetter(distEdge)) {
1651
- distanceFromNearestElement = distEdge;
1652
- nearestElement = edge;
1653
- _GeoGraphProjectionHandler._assignLatLngLevel(segmentProjection, projection);
1654
- _GeoGraphProjectionHandler._updateProjectionLevelFromEdge(edge, projection);
1655
- }
1656
- }
1657
- }
1658
- }
1659
- if (!nearestElement) {
1660
- return null;
1661
- }
1662
- if (projection instanceof UserPosition && projection.accuracy !== null) {
1663
- projection.accuracy += distanceFromNearestElement;
1664
- }
1665
- return new GeoGraphProjection(
1666
- location,
1667
- distanceFromNearestElement,
1668
- projection,
1669
- nearestElement
1670
- );
1671
- }
1672
- };
1673
- __publicField(_GeoGraphProjectionHandler, "_updateProjectionLevelFromEdge", (_edge, _projection) => {
1674
- _projection.level = Level.clone(_edge.level);
1675
- });
1676
- let GeoGraphProjectionHandler = _GeoGraphProjectionHandler;
1677
- class GeoGraphItinerary extends GeoGraph {
1678
- constructor(start, end, vertices, edges, edgesWeights) {
1679
- super(vertices, edges);
1680
- this.start = start;
1681
- this.end = end;
1682
- this.edgesWeights = edgesWeights;
1683
- }
1684
- static fromGraphVertices(start, end, networkVertices, edgesWeights) {
1685
- const vertices = networkVertices.map((vertex) => {
1686
- return new GeoGraphVertex(
1687
- vertex.coords.clone(),
1688
- { name: vertex.name, id: vertex.id, data: vertex.data, io: vertex.io }
1689
- );
1690
- });
1691
- const edges = [];
1692
- networkVertices.forEach((vertex, idx, arr) => {
1693
- if (idx === 0) {
1694
- return;
1695
- }
1696
- const prevVertex = arr[idx - 1];
1697
- const edge = GeoGraphEdge.getEdgeByVertices(prevVertex.edges, prevVertex, vertex);
1698
- if (!edge) {
1699
- Logger.error("Cannot retrieve edge to create itinerary");
1700
- return;
1701
- }
1702
- edges.push(new GeoGraphEdge(
1703
- vertices[idx - 1],
1704
- vertices[idx],
1705
- { name: edge.name, id: edge.id, data: edge.data, level: edge.level, isOneway: edge.isOneway }
1706
- ));
1707
- });
1708
- return new GeoGraphItinerary(start, end, vertices, edges, edgesWeights);
1709
- }
1710
- }
1711
- class NoRouteFoundError extends Error {
1712
- constructor(start, end, details = null) {
1713
- super();
1714
- this.start = start;
1715
- this.end = end;
1716
- this.details = details;
1717
- }
1718
- get startStr() {
1719
- if (this.start instanceof GeoGraphVertex) {
1720
- return `GeoGraphVertex ${this.start.coords.toString()}`;
1721
- }
1722
- return this.start.toString();
1723
- }
1724
- get endStr() {
1725
- if (this.end instanceof GeoGraphVertex) {
1726
- return `GeoGraphVertex ${this.end.coords.toString()}`;
1727
- }
1728
- if (Array.isArray(this.end)) {
1729
- return this.end.map((p) => p instanceof GeoGraphVertex ? p.coords.toString() : p.toString()).join(",");
1730
- }
1731
- return this.end.toString();
1732
- }
1733
- get message() {
1734
- let message = `No route found from ${this.startStr} to ${this.endStr}.`;
1735
- if (this.details) {
1736
- message += ` Details: ${this.details}`;
1737
- }
1738
- return message;
1739
- }
1740
- }
1741
- const _GeoGraphRouter = class _GeoGraphRouter {
1742
- constructor(graph) {
1743
- __publicField(this, "_mapMatching");
1744
- __publicField(this, "_graph");
1745
- __publicField(this, "disabledEdges", /* @__PURE__ */ new Set());
1746
- this._graph = graph;
1747
- this._mapMatching = new GeoGraphProjectionHandler(graph);
1748
- }
1749
- getShortestPath(start, end, options = _GeoGraphRouter.DEFAULT_OPTIONS) {
1750
- const { acceptEdgeFn, weightEdgeFn, projectionMaxDistance } = options;
1751
- this._mapMatching.maxDistance = projectionMaxDistance;
1752
- const createdVertices = [];
1753
- const retrieveOrCreateNearestVertex = (point) => {
1754
- if (point instanceof GeoGraphVertex) {
1755
- return point;
1756
- }
1757
- const closeVertex = this._graph.getVertexByCoords(point);
1758
- if (closeVertex) {
1759
- return closeVertex;
1760
- }
1761
- const proj = this._mapMatching.getProjection(point, true, false, false, options.acceptEdgeFn);
1762
- if (!proj) {
1763
- let message = `Point ${point.toString()} is too far from the graph > ${this._mapMatching.maxDistance.toFixed(0)} meters.`;
1764
- if (point.level !== null) {
1765
- message += ` If it is a multi-level map, please verify if you have a graph at level ${Level.toString(point.level)}.`;
1766
- }
1767
- throw new NoRouteFoundError(start, end, message);
1768
- }
1769
- if (proj.nearestElement instanceof GeoGraphVertex) {
1770
- return proj.nearestElement;
1771
- }
1772
- const vertexCreated = this.createVertexInsideEdge(
1773
- proj.nearestElement,
1774
- proj.coords
1775
- );
1776
- createdVertices.push(vertexCreated);
1777
- return vertexCreated;
1778
- };
1779
- const removeCreatedVertices = () => {
1780
- while (createdVertices.length) {
1781
- this.removeVertexFromPreviouslyCreatedEdge(createdVertices.pop());
1782
- }
1783
- };
1784
- const startVertex = retrieveOrCreateNearestVertex(start);
1785
- const endVertex = retrieveOrCreateNearestVertex(end);
1786
- const startCoords = start instanceof GeoGraphVertex ? start.coords : start;
1787
- const endCoords = end instanceof GeoGraphVertex ? end.coords : end;
1788
- let graphItinerary;
1789
- if (startVertex === endVertex) {
1790
- graphItinerary = GeoGraphItinerary.fromGraphVertices(
1791
- startCoords,
1792
- endCoords,
1793
- [startVertex],
1794
- []
1795
- );
1796
- } else {
1797
- graphItinerary = this.getShortestPathBetweenGeoGraphVertices(
1798
- startVertex,
1799
- endVertex,
1800
- weightEdgeFn,
1801
- acceptEdgeFn
1802
- );
1803
- }
1804
- graphItinerary.start = startCoords;
1805
- graphItinerary.end = endCoords;
1806
- removeCreatedVertices();
1807
- if (!graphItinerary.vertices.length) {
1808
- throw new NoRouteFoundError(start, end);
1809
- }
1810
- return graphItinerary;
1811
- }
1812
- getShortestPaths(start, ends, options = _GeoGraphRouter.DEFAULT_OPTIONS) {
1813
- const { acceptEdgeFn, weightEdgeFn, projectionMaxDistance } = options;
1814
- this._mapMatching.maxDistance = projectionMaxDistance;
1815
- const createdVertices = [];
1816
- const retrieveOrCreateNearestVertex = (point, options2 = _GeoGraphRouter.DEFAULT_OPTIONS) => {
1817
- if (point instanceof GeoGraphVertex) {
1818
- return point;
1819
- }
1820
- const closeVertex = this._graph.getVertexByCoords(point);
1821
- if (closeVertex) {
1822
- return closeVertex;
1823
- }
1824
- const proj = this._mapMatching.getProjection(point, true, false, false, options2.acceptEdgeFn);
1825
- if (!proj) {
1826
- return null;
1827
- }
1828
- if (proj.nearestElement instanceof GeoGraphVertex) {
1829
- return proj.nearestElement;
1830
- }
1831
- const vertexCreated = this.createVertexInsideEdge(
1832
- proj.nearestElement,
1833
- proj.coords
1834
- );
1835
- createdVertices.push(vertexCreated);
1836
- return vertexCreated;
1837
- };
1838
- const removeCreatedVertices = () => {
1839
- while (createdVertices.length) {
1840
- this.removeVertexFromPreviouslyCreatedEdge(createdVertices.pop());
1841
- }
1842
- };
1843
- const startVertex = retrieveOrCreateNearestVertex(start);
1844
- const endsStruct = ends.map((e) => ({
1845
- input: e,
1846
- vertex: retrieveOrCreateNearestVertex(e),
1847
- itinerary: null
1848
- }));
1849
- const startCoords = start instanceof GeoGraphVertex ? start.coords : start;
1850
- if (!startVertex) {
1851
- let message = `Point ${startCoords.toString()} is too far from the graph > ${this._mapMatching.maxDistance.toFixed(0)} meters.`;
1852
- if (startCoords.level !== null) {
1853
- message += ` If it is a multi-level map, please verify if you have a graph at level ${Level.toString(startCoords.level)}.`;
1854
- }
1855
- throw new NoRouteFoundError(start, ends, message);
1856
- }
1857
- const endsStructFiltered = endsStruct.filter((v) => v.vertex != null);
1858
- const graphItineraries = this.getShortestPathsBetweenGeoGraphVertices(
1859
- startVertex,
1860
- endsStructFiltered.map((v) => v.vertex),
1861
- weightEdgeFn,
1862
- acceptEdgeFn
1863
- );
1864
- graphItineraries.forEach((itinerary, idx) => {
1865
- itinerary.start = startCoords;
1866
- const endStructFiltered = endsStructFiltered[idx];
1867
- endStructFiltered.itinerary = itinerary;
1868
- });
1869
- removeCreatedVertices();
1870
- endsStructFiltered.forEach((e) => {
1871
- if (e.itinerary !== null) {
1872
- e.itinerary.end = e.input instanceof GeoGraphVertex ? e.input.coords : e.input;
1873
- }
1874
- });
1875
- return endsStruct.map((end) => {
1876
- const endFiltered = endsStructFiltered.find((e) => e.input === end.input);
1877
- if (endFiltered)
1878
- return endFiltered.itinerary;
1879
- const endCoords = end.input instanceof GeoGraphVertex ? end.input.coords : end.input;
1880
- return GeoGraphItinerary.fromGraphVertices(startCoords, endCoords, [], []);
1881
- });
1882
- }
1883
- createVertexInsideEdge(edge, point) {
1884
- const a = edge.vertex1;
1885
- const b = edge.vertex2;
1886
- const m = new GeoGraphVertex(point, { name: `proj on ${edge.name || null} (tmp)` });
1887
- const newEdgesParams = { name: `splitted ${edge.name || null} (tmp)`, data: edge.data, isOneway: edge.isOneway, level: edge.level };
1888
- const u = new GeoGraphEdge(a, m, newEdgesParams);
1889
- const v = new GeoGraphEdge(m, b, newEdgesParams);
1890
- a.edges = a.edges.filter((_edge) => _edge !== edge);
1891
- b.edges = b.edges.filter((_edge) => _edge !== edge);
1892
- this._graph.vertices.push(m);
1893
- this._graph.edges.push(u, v);
1894
- this._graph.edges = this._graph.edges.filter(
1895
- (_edge) => _edge !== edge
1896
- );
1897
- return m;
1898
- }
1899
- removeVertexFromPreviouslyCreatedEdge(_vertex) {
1900
- const isUfirstEdge = _vertex.edges[0].vertex2 === _vertex;
1901
- const u = _vertex.edges[isUfirstEdge ? 0 : 1];
1902
- const v = _vertex.edges[isUfirstEdge ? 1 : 0];
1903
- u.vertex1.edges = u.vertex1.edges.filter((edge) => edge !== u);
1904
- v.vertex2.edges = v.vertex2.edges.filter((edge) => edge !== v);
1905
- const oldEdgeName = u.name.substring("splitted ".length, u.name.length - " (tmp)".length);
1906
- const oldEdgeParams = { name: oldEdgeName, data: u.data, isOneway: u.isOneway, level: u.level };
1907
- const oldEdge = new GeoGraphEdge(u.vertex1, v.vertex2, oldEdgeParams);
1908
- this._graph.edges.push(oldEdge);
1909
- this._graph.vertices = this._graph.vertices.filter((vertex) => vertex !== _vertex);
1910
- this._graph.edges = this._graph.edges.filter(
1911
- (edge) => edge !== u && edge !== v
1912
- );
1913
- }
1914
- getShortestPathBetweenGeoGraphVertices(start, end, weightFn, acceptEdgeFn) {
1915
- const distanceMap = {}, checking = {}, vertexList = {}, vertices = {}, parentVertices = {}, path = [];
1916
- this._graph.vertices.forEach((vertex) => {
1917
- vertices[vertex.id] = vertex;
1918
- distanceMap[vertex.id] = Infinity;
1919
- checking[vertex.id] = null;
1920
- vertexList[vertex.id] = true;
1921
- });
1922
- distanceMap[start.id] = 0;
1923
- while (Object.keys(vertexList).length > 0) {
1924
- const keys = Object.keys(vertexList).map(Number);
1925
- const current = Number(
1926
- keys.reduce((_checking, vertexId) => {
1927
- return distanceMap[_checking] > distanceMap[vertexId] ? vertexId : _checking;
1928
- }, keys[0])
1929
- );
1930
- this._graph.edges.filter((edge) => {
1931
- if (acceptEdgeFn && !acceptEdgeFn(edge) || this.disabledEdges.has(edge)) {
1932
- return false;
1933
- }
1934
- const from = edge.vertex1.id, to = edge.vertex2.id;
1935
- return from === current || to === current;
1936
- }).forEach((edge) => {
1937
- let to, from, reversed = false;
1938
- if (edge.vertex1.id === current) {
1939
- to = edge.vertex2.id;
1940
- from = edge.vertex1.id;
1941
- } else {
1942
- to = edge.vertex1.id;
1943
- from = edge.vertex2.id;
1944
- reversed = true;
1945
- }
1946
- if (edge.isOneway && reversed) {
1947
- return;
1948
- }
1949
- const distance = distanceMap[current] + weightFn(edge);
1950
- if (distanceMap[to] > distance) {
1951
- distanceMap[to] = distance;
1952
- checking[to] = current;
1953
- parentVertices[to] = from;
1954
- }
1955
- });
1956
- delete vertexList[current];
1957
- }
1958
- const edgesWeights = [];
1959
- let endId = end.id;
1960
- while (typeof parentVertices[endId] !== "undefined") {
1961
- path.unshift(vertices[endId]);
1962
- edgesWeights.unshift(distanceMap[endId] - distanceMap[parentVertices[endId]]);
1963
- endId = parentVertices[endId];
1964
- }
1965
- if (path.length !== 0) {
1966
- path.unshift(start);
1967
- }
1968
- return GeoGraphItinerary.fromGraphVertices(start.coords, end.coords, path, edgesWeights);
1969
- }
1970
- getShortestPathsBetweenGeoGraphVertices(start, ends, weightFn, acceptEdgeFn) {
1971
- const distanceMap = {}, checking = {}, vertexList = {}, vertices = {}, parentVertices = {};
1972
- this._graph.vertices.forEach((vertex) => {
1973
- vertices[vertex.id] = vertex;
1974
- distanceMap[vertex.id] = Infinity;
1975
- checking[vertex.id] = null;
1976
- vertexList[vertex.id] = true;
1977
- });
1978
- distanceMap[start.id] = 0;
1979
- while (Object.keys(vertexList).length > 0) {
1980
- const keys = Object.keys(vertexList).map(Number);
1981
- const current = Number(
1982
- keys.reduce((_checking, vertexId) => {
1983
- return distanceMap[_checking] > distanceMap[vertexId] ? vertexId : _checking;
1984
- }, keys[0])
1985
- );
1986
- this._graph.edges.filter((edge) => {
1987
- if (acceptEdgeFn && !acceptEdgeFn(edge) || this.disabledEdges.has(edge)) {
1988
- return false;
1989
- }
1990
- const from = edge.vertex1.id, to = edge.vertex2.id;
1991
- return from === current || to === current;
1992
- }).forEach((edge) => {
1993
- let to, from, reversed = false;
1994
- if (edge.vertex1.id === current) {
1995
- to = edge.vertex2.id;
1996
- from = edge.vertex1.id;
1997
- } else {
1998
- to = edge.vertex1.id;
1999
- from = edge.vertex2.id;
2000
- reversed = true;
2001
- }
2002
- if (edge.isOneway && reversed) {
2003
- return;
2004
- }
2005
- const distance = distanceMap[current] + weightFn(edge);
2006
- if (distanceMap[to] > distance) {
2007
- distanceMap[to] = distance;
2008
- checking[to] = current;
2009
- parentVertices[to] = from;
2010
- }
2011
- });
2012
- delete vertexList[current];
2013
- }
2014
- return ends.map((end) => {
2015
- const edgesWeights = [];
2016
- const path = [];
2017
- let endId = end.id;
2018
- while (typeof parentVertices[endId] !== "undefined") {
2019
- path.unshift(vertices[endId]);
2020
- edgesWeights.unshift(distanceMap[endId] - distanceMap[parentVertices[endId]]);
2021
- endId = parentVertices[endId];
2022
- }
2023
- if (path.length !== 0) {
2024
- path.unshift(start);
2025
- }
2026
- return GeoGraphItinerary.fromGraphVertices(start.coords, end.coords, path, edgesWeights);
2027
- });
2028
- }
2029
- };
2030
- __publicField(_GeoGraphRouter, "DEFAULT_OPTIONS", {
2031
- projectionMaxDistance: 50,
2032
- weightEdgeFn: (edge) => edge.length
2033
- });
2034
- let GeoGraphRouter = _GeoGraphRouter;
2035
1281
  exports.AbsoluteHeading = AbsoluteHeading;
2036
1282
  exports.Attitude = Attitude;
2037
1283
  exports.BoundingBox = BoundingBox;
2038
1284
  exports.Constants = Constants;
2039
1285
  exports.Coordinates = Coordinates;
2040
- exports.GeoGraph = GeoGraph;
2041
- exports.GeoGraphEdge = GeoGraphEdge;
2042
- exports.GeoGraphItinerary = GeoGraphItinerary;
2043
- exports.GeoGraphProjection = GeoGraphProjection;
2044
- exports.GeoGraphProjectionHandler = GeoGraphProjectionHandler;
2045
- exports.GeoGraphRouter = GeoGraphRouter;
2046
- exports.GeoGraphVertex = GeoGraphVertex;
2047
1286
  exports.GeoRef = GeoRef;
2048
1287
  exports.GeoRelativePosition = GeoRelativePosition;
2049
1288
  exports.Level = Level;
2050
- exports.NoRouteFoundError = NoRouteFoundError;
2051
1289
  exports.RelativePosition = RelativePosition;
2052
1290
  exports.UserPosition = UserPosition;
2053
1291
  exports.Utils = Utils;