@wemap/geo 11.5.0 → 11.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +200 -26
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +198 -22
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/graph/GeoGraph.ts +14 -5
- package/src/types.ts +3 -2
package/dist/index.js
CHANGED
|
@@ -5,12 +5,10 @@ var __publicField = (obj, key, value) => {
|
|
|
5
5
|
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
6
6
|
return value;
|
|
7
7
|
};
|
|
8
|
-
Object.
|
|
8
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
9
9
|
const maths = require("@wemap/maths");
|
|
10
10
|
const utils = require("@wemap/utils");
|
|
11
11
|
const Logger = require("@wemap/logger");
|
|
12
|
-
const _interopDefaultLegacy = (e) => e && typeof e === "object" && "default" in e ? e : { default: e };
|
|
13
|
-
const Logger__default = /* @__PURE__ */ _interopDefaultLegacy(Logger);
|
|
14
12
|
const R_MAJOR = 6378137;
|
|
15
13
|
const R_MINOR = 63567523142e-4;
|
|
16
14
|
const EARTH_GRAVITY = 9.80665;
|
|
@@ -26,21 +24,21 @@ const R_MINOR_4 = R_MINOR_2 * R_MINOR_2;
|
|
|
26
24
|
const CIRCUMFERENCE = R_MAJOR * 2 * Math.PI;
|
|
27
25
|
const Constants = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
28
26
|
__proto__: null,
|
|
29
|
-
|
|
30
|
-
R_MINOR,
|
|
27
|
+
CIRCUMFERENCE,
|
|
31
28
|
EARTH_GRAVITY,
|
|
32
|
-
EPS_DEG_MM,
|
|
33
|
-
EPS_MM,
|
|
34
|
-
ELLIPSOID_FLATNESS,
|
|
35
29
|
ECCENTRICITY,
|
|
36
30
|
ECCENTRICITY_2,
|
|
31
|
+
ELLIPSOID_FLATNESS,
|
|
32
|
+
EPS_DEG_MM,
|
|
33
|
+
EPS_MM,
|
|
34
|
+
R_MAJOR,
|
|
37
35
|
R_MAJOR_2,
|
|
38
36
|
R_MAJOR_4,
|
|
37
|
+
R_MINOR,
|
|
39
38
|
R_MINOR_2,
|
|
40
|
-
R_MINOR_4
|
|
41
|
-
CIRCUMFERENCE
|
|
39
|
+
R_MINOR_4
|
|
42
40
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
43
|
-
const _Level = class {
|
|
41
|
+
const _Level = class _Level {
|
|
44
42
|
static checkType(level) {
|
|
45
43
|
if (level === null) {
|
|
46
44
|
return;
|
|
@@ -59,6 +57,9 @@ const _Level = class {
|
|
|
59
57
|
}
|
|
60
58
|
throw Error(`Unknown level format: ${level}`);
|
|
61
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Return true if the level is a range, false otherwise
|
|
62
|
+
*/
|
|
62
63
|
static isRange(level) {
|
|
63
64
|
if (_Level.VERIFY_TYPING) {
|
|
64
65
|
this.checkType(level);
|
|
@@ -77,6 +78,9 @@ const _Level = class {
|
|
|
77
78
|
}
|
|
78
79
|
return [level[0], level[1]];
|
|
79
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* Create a level from a string (eg. 1, -2, 1;2, -2;3, 2;-1, 0.5;1 ...)
|
|
83
|
+
*/
|
|
80
84
|
static fromString(str) {
|
|
81
85
|
if (str === null) {
|
|
82
86
|
return null;
|
|
@@ -105,6 +109,11 @@ const _Level = class {
|
|
|
105
109
|
}
|
|
106
110
|
throw Error(`Cannot parse following level: ${str}`);
|
|
107
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* Returns if a level is contained in another
|
|
114
|
+
* @param {null|number|[number, number]} container The container level
|
|
115
|
+
* @param {null|number|[number, number]} targeted The targeted level
|
|
116
|
+
*/
|
|
108
117
|
static contains(container, targeted) {
|
|
109
118
|
if (_Level.VERIFY_TYPING) {
|
|
110
119
|
this.checkType(container);
|
|
@@ -127,6 +136,9 @@ const _Level = class {
|
|
|
127
136
|
}
|
|
128
137
|
return container <= targeted[0] && container >= targeted[1];
|
|
129
138
|
}
|
|
139
|
+
/**
|
|
140
|
+
* Retrieve the intersection of two levels
|
|
141
|
+
*/
|
|
130
142
|
static intersection(first, second) {
|
|
131
143
|
if (_Level.VERIFY_TYPING) {
|
|
132
144
|
this.checkType(first);
|
|
@@ -160,6 +172,12 @@ const _Level = class {
|
|
|
160
172
|
}
|
|
161
173
|
return up < low ? null : [low, up];
|
|
162
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* Retrieve the intersection of two levels
|
|
177
|
+
* @param {null|number|[number, number]} first The first level
|
|
178
|
+
* @param {null|number|[number, number]} second The second level
|
|
179
|
+
* @returns {boolean}
|
|
180
|
+
*/
|
|
163
181
|
static intersect(first, second) {
|
|
164
182
|
if (_Level.VERIFY_TYPING) {
|
|
165
183
|
this.checkType(first);
|
|
@@ -170,6 +188,9 @@ const _Level = class {
|
|
|
170
188
|
}
|
|
171
189
|
return this.intersection(first, second) !== null;
|
|
172
190
|
}
|
|
191
|
+
/**
|
|
192
|
+
* Retrieve the union of two levels
|
|
193
|
+
*/
|
|
173
194
|
static union(first, second) {
|
|
174
195
|
if (_Level.VERIFY_TYPING) {
|
|
175
196
|
this.checkType(first);
|
|
@@ -203,6 +224,12 @@ const _Level = class {
|
|
|
203
224
|
}
|
|
204
225
|
return [low, up];
|
|
205
226
|
}
|
|
227
|
+
/**
|
|
228
|
+
* Multiply a level by a factor
|
|
229
|
+
* @param {null|number|[number, number]} level the level to multiply
|
|
230
|
+
* @param {number} factor
|
|
231
|
+
* @returns {null|number|[number, number]}
|
|
232
|
+
*/
|
|
206
233
|
static multiplyBy(level, factor) {
|
|
207
234
|
if (_Level.VERIFY_TYPING) {
|
|
208
235
|
this.checkType(level);
|
|
@@ -269,8 +296,8 @@ const _Level = class {
|
|
|
269
296
|
return null;
|
|
270
297
|
}
|
|
271
298
|
};
|
|
299
|
+
__publicField(_Level, "VERIFY_TYPING", false);
|
|
272
300
|
let Level = _Level;
|
|
273
|
-
__publicField(Level, "VERIFY_TYPING", false);
|
|
274
301
|
class Coordinates {
|
|
275
302
|
constructor(lat, lng, alt = null, level = null) {
|
|
276
303
|
__publicField(this, "_lat");
|
|
@@ -318,6 +345,10 @@ class Coordinates {
|
|
|
318
345
|
set longitude(_) {
|
|
319
346
|
throw new Error("Please use Coordinates#lng setter instead of Coordinate#longitude");
|
|
320
347
|
}
|
|
348
|
+
/**
|
|
349
|
+
* alt does not denote the altitude of a point but its height from
|
|
350
|
+
* the "level" field (if defined) or from the ground
|
|
351
|
+
*/
|
|
321
352
|
get alt() {
|
|
322
353
|
return this._alt;
|
|
323
354
|
}
|
|
@@ -332,6 +363,9 @@ class Coordinates {
|
|
|
332
363
|
Level.checkType(level);
|
|
333
364
|
this._level = level;
|
|
334
365
|
}
|
|
366
|
+
/**
|
|
367
|
+
* Deep clone coordinates
|
|
368
|
+
*/
|
|
335
369
|
clone() {
|
|
336
370
|
const output = new Coordinates(this.lat, this.lng, this.alt);
|
|
337
371
|
if (this.level !== null) {
|
|
@@ -356,11 +390,18 @@ class Coordinates {
|
|
|
356
390
|
equals(other) {
|
|
357
391
|
return Coordinates.equals(this, other);
|
|
358
392
|
}
|
|
393
|
+
/**
|
|
394
|
+
* @throws {Error} if elevation is defined and point altitude is not defined
|
|
395
|
+
*/
|
|
359
396
|
destinationPoint(distance, bearing, elevation = null) {
|
|
360
397
|
const newPoint = this.clone();
|
|
361
398
|
newPoint.move(distance, bearing, elevation);
|
|
362
399
|
return newPoint;
|
|
363
400
|
}
|
|
401
|
+
/**
|
|
402
|
+
* Source: http://www.movable-type.co.uk/scripts/latlong.html#destPoint
|
|
403
|
+
* @throws {Error} if elevation is defined and point altitude is not defined
|
|
404
|
+
*/
|
|
364
405
|
move(distance, bearing, elevation = null) {
|
|
365
406
|
const dR = distance / R_MAJOR;
|
|
366
407
|
const cosDr = Math.cos(dR);
|
|
@@ -384,6 +425,9 @@ class Coordinates {
|
|
|
384
425
|
}
|
|
385
426
|
return this;
|
|
386
427
|
}
|
|
428
|
+
/**
|
|
429
|
+
* Returns a distance between two points in meters
|
|
430
|
+
*/
|
|
387
431
|
distanceTo(location2) {
|
|
388
432
|
const lat1 = this.lat;
|
|
389
433
|
const lng1 = this.lng;
|
|
@@ -418,6 +462,11 @@ class Coordinates {
|
|
|
418
462
|
static bearingTo(point1, point2) {
|
|
419
463
|
return point1.bearingTo(point2);
|
|
420
464
|
}
|
|
465
|
+
/**
|
|
466
|
+
* ECEF Transformations
|
|
467
|
+
* Here we used a light version of ECEF considering earth
|
|
468
|
+
* as a sphere instead of an ellipse
|
|
469
|
+
*/
|
|
421
470
|
get enuToEcefRotation() {
|
|
422
471
|
const rot1 = maths.Quaternion.fromAxisAngle([0, 0, 1], Math.PI / 2 + maths.deg2rad(this.lng));
|
|
423
472
|
const rot2 = maths.Quaternion.fromAxisAngle([1, 0, 0], Math.PI / 2 - maths.deg2rad(this.lat));
|
|
@@ -428,6 +477,10 @@ class Coordinates {
|
|
|
428
477
|
const rot2 = maths.Quaternion.fromAxisAngle([0, 0, 1], -maths.deg2rad(this.lng) - Math.PI / 2);
|
|
429
478
|
return maths.Quaternion.multiply(rot1, rot2);
|
|
430
479
|
}
|
|
480
|
+
/**
|
|
481
|
+
* https://gist.github.com/klucar/1536194
|
|
482
|
+
* Adapted for spherical formula
|
|
483
|
+
*/
|
|
431
484
|
get ecef() {
|
|
432
485
|
if (!this._ecef) {
|
|
433
486
|
const lat = maths.deg2rad(this.lat);
|
|
@@ -453,6 +506,10 @@ class Coordinates {
|
|
|
453
506
|
newPoint._ecef = ecef;
|
|
454
507
|
return newPoint;
|
|
455
508
|
}
|
|
509
|
+
/**
|
|
510
|
+
* https://stackoverflow.com/questions/1299567/how-to-calculate-distance-from-a-point-to-a-line-segment-on-a-sphere
|
|
511
|
+
* Adapted to ECEF
|
|
512
|
+
*/
|
|
456
513
|
getSegmentProjection(p1, p2) {
|
|
457
514
|
const a = maths.Vector3.normalize(p1.ecef);
|
|
458
515
|
const b = maths.Vector3.normalize(p2.ecef);
|
|
@@ -480,6 +537,9 @@ class Coordinates {
|
|
|
480
537
|
}
|
|
481
538
|
return projection;
|
|
482
539
|
}
|
|
540
|
+
/**
|
|
541
|
+
* Input / Output
|
|
542
|
+
*/
|
|
483
543
|
toString() {
|
|
484
544
|
let str = "[" + this._lat.toFixed(7) + ", " + this._lng.toFixed(7);
|
|
485
545
|
if (this._alt !== null) {
|
|
@@ -571,6 +631,8 @@ class UserPosition extends Coordinates {
|
|
|
571
631
|
newPoint.move(distance, bearing, elevation);
|
|
572
632
|
return newPoint;
|
|
573
633
|
}
|
|
634
|
+
// Create a UserPosition with lat, lng, alt from Coordinates coordinates and
|
|
635
|
+
// other fields from another UserPosition
|
|
574
636
|
static fromCoordinates(coordinates) {
|
|
575
637
|
return new UserPosition(
|
|
576
638
|
coordinates.lat,
|
|
@@ -742,11 +804,11 @@ function calcDistance(coords) {
|
|
|
742
804
|
}
|
|
743
805
|
const Utils = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
744
806
|
__proto__: null,
|
|
807
|
+
calcDistance,
|
|
808
|
+
geolocationPositionToUserPosition,
|
|
745
809
|
sampleRoute,
|
|
746
|
-
trimRoute,
|
|
747
810
|
simplifyRoute,
|
|
748
|
-
|
|
749
|
-
calcDistance
|
|
811
|
+
trimRoute
|
|
750
812
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
751
813
|
class BoundingBox {
|
|
752
814
|
constructor(northEast, southWest) {
|
|
@@ -758,14 +820,23 @@ class BoundingBox {
|
|
|
758
820
|
throw new Error("Incorrect bounding box");
|
|
759
821
|
}
|
|
760
822
|
}
|
|
823
|
+
/**
|
|
824
|
+
* Returns the geographical coordinate equidistant from the bounding box's corners.
|
|
825
|
+
*/
|
|
761
826
|
get center() {
|
|
762
827
|
const latCenter = (this.southWest.lat + this.northEast.lat) / 2;
|
|
763
828
|
const lngCenter = (this.northEast.lng + this.southWest.lng) / 2;
|
|
764
829
|
return new Coordinates(latCenter, lngCenter);
|
|
765
830
|
}
|
|
831
|
+
/**
|
|
832
|
+
* Check if a point is contained in the bounding box.
|
|
833
|
+
*/
|
|
766
834
|
contains(point) {
|
|
767
835
|
return point.lat <= this.northEast.lat && point.lat >= this.southWest.lat && point.lng <= this.northEast.lng && point.lng >= this.southWest.lng;
|
|
768
836
|
}
|
|
837
|
+
/**
|
|
838
|
+
* Extend the bounds to include a given LngLat or LngLatBounds.
|
|
839
|
+
*/
|
|
769
840
|
extend(obj) {
|
|
770
841
|
const sw = this.southWest, ne = this.northEast;
|
|
771
842
|
let sw2, ne2;
|
|
@@ -788,6 +859,10 @@ class BoundingBox {
|
|
|
788
859
|
);
|
|
789
860
|
return this;
|
|
790
861
|
}
|
|
862
|
+
/**
|
|
863
|
+
* This method extends the bounding box with a value in meters
|
|
864
|
+
* /*\ This method is not precise as distance differs in function of latitude
|
|
865
|
+
*/
|
|
791
866
|
extendsWithMeasure(measure) {
|
|
792
867
|
if (typeof measure !== "number") {
|
|
793
868
|
throw new Error("measure is not a number");
|
|
@@ -796,6 +871,11 @@ class BoundingBox {
|
|
|
796
871
|
this.southWest = this.southWest.clone().destinationPoint(measure, -Math.PI / 2).destinationPoint(measure, Math.PI);
|
|
797
872
|
return this;
|
|
798
873
|
}
|
|
874
|
+
/**
|
|
875
|
+
* Returns bounds created by extending or retracting the current bounds by a given ratio in each direction.
|
|
876
|
+
* For example, a ratio of 0.5 extends the bounds by 50% in each direction.
|
|
877
|
+
* Negative values will retract the bounds.
|
|
878
|
+
*/
|
|
799
879
|
pad(bufferRatio) {
|
|
800
880
|
const sw = this.southWest;
|
|
801
881
|
const ne = this.northEast;
|
|
@@ -805,27 +885,51 @@ class BoundingBox {
|
|
|
805
885
|
this.northEast = new Coordinates(ne.lat + heightBuffer, ne.lng + widthBuffer);
|
|
806
886
|
return this;
|
|
807
887
|
}
|
|
888
|
+
/**
|
|
889
|
+
* Returns the southwest corner of the bounding box.
|
|
890
|
+
*/
|
|
808
891
|
getSouthWest() {
|
|
809
892
|
return this.southWest;
|
|
810
893
|
}
|
|
894
|
+
/**
|
|
895
|
+
* Returns the northeast corner of the bounding box.
|
|
896
|
+
*/
|
|
811
897
|
getNorthEast() {
|
|
812
898
|
return this.northEast;
|
|
813
899
|
}
|
|
900
|
+
/**
|
|
901
|
+
* Returns the northwest corner of the bounding box.
|
|
902
|
+
*/
|
|
814
903
|
getNorthWest() {
|
|
815
904
|
return new Coordinates(this.getNorth(), this.getWest());
|
|
816
905
|
}
|
|
906
|
+
/**
|
|
907
|
+
* Returns the southeast corner of the bounding box.
|
|
908
|
+
*/
|
|
817
909
|
getSouthEast() {
|
|
818
910
|
return new Coordinates(this.getSouth(), this.getEast());
|
|
819
911
|
}
|
|
912
|
+
/**
|
|
913
|
+
* Returns the west edge of the bounding box.
|
|
914
|
+
*/
|
|
820
915
|
getWest() {
|
|
821
916
|
return this.southWest.lng;
|
|
822
917
|
}
|
|
918
|
+
/**
|
|
919
|
+
* Returns the south edge of the bounding box.
|
|
920
|
+
*/
|
|
823
921
|
getSouth() {
|
|
824
922
|
return this.southWest.lat;
|
|
825
923
|
}
|
|
924
|
+
/**
|
|
925
|
+
* Returns the east edge of the bounding box.
|
|
926
|
+
*/
|
|
826
927
|
getEast() {
|
|
827
928
|
return this.northEast.lng;
|
|
828
929
|
}
|
|
930
|
+
/**
|
|
931
|
+
* Returns the north edge of the bounding box.
|
|
932
|
+
*/
|
|
829
933
|
getNorth() {
|
|
830
934
|
return this.northEast.lat;
|
|
831
935
|
}
|
|
@@ -835,6 +939,9 @@ class BoundingBox {
|
|
|
835
939
|
equals(other) {
|
|
836
940
|
return BoundingBox.equals(this, other);
|
|
837
941
|
}
|
|
942
|
+
/**
|
|
943
|
+
* Create a BoundingBox from a WSEN array
|
|
944
|
+
*/
|
|
838
945
|
static fromArray(bounds) {
|
|
839
946
|
return new BoundingBox(
|
|
840
947
|
new Coordinates(bounds[3], bounds[2]),
|
|
@@ -850,6 +957,9 @@ class BoundingBox {
|
|
|
850
957
|
new BoundingBox(coords[0], coords[0])
|
|
851
958
|
);
|
|
852
959
|
}
|
|
960
|
+
/**
|
|
961
|
+
* Returns the WSEN array
|
|
962
|
+
*/
|
|
853
963
|
toArray() {
|
|
854
964
|
return [this.getWest(), this.getSouth(), this.getEast(), this.getNorth()];
|
|
855
965
|
}
|
|
@@ -887,6 +997,12 @@ class RelativePosition {
|
|
|
887
997
|
clone() {
|
|
888
998
|
return new RelativePosition(this.x, this.y, this.z, this.time, this.accuracy, this.bearing);
|
|
889
999
|
}
|
|
1000
|
+
/**
|
|
1001
|
+
* Compares two RelativePosition
|
|
1002
|
+
* @param {RelativePosition} pos1 position 1
|
|
1003
|
+
* @param {RelativePosition} pos2 position 2
|
|
1004
|
+
* @param {Number} eps x, y, z epsilon in meters (default: 1e-3 [= 1mm])
|
|
1005
|
+
*/
|
|
890
1006
|
static equals(pos1, pos2, eps = EPS_MM) {
|
|
891
1007
|
if (pos1 === null && pos1 === pos2) {
|
|
892
1008
|
return true;
|
|
@@ -922,6 +1038,9 @@ class GeoRef {
|
|
|
922
1038
|
__publicField(this, "heading", 0);
|
|
923
1039
|
this.origin = origin;
|
|
924
1040
|
}
|
|
1041
|
+
/**
|
|
1042
|
+
* LocalPosition in ENU frame
|
|
1043
|
+
*/
|
|
925
1044
|
localToWorld(localPosition) {
|
|
926
1045
|
const enuTranslationScaled = maths.Vector3.multiplyScalar(localPosition, this.scale);
|
|
927
1046
|
const rotationOffset = maths.Quaternion.fromAxisAngle([0, 0, 1], this.heading);
|
|
@@ -930,6 +1049,9 @@ class GeoRef {
|
|
|
930
1049
|
const ecef = maths.Vector3.sum(this.origin.ecef, ecefTranslation);
|
|
931
1050
|
return Coordinates.fromECEF(ecef);
|
|
932
1051
|
}
|
|
1052
|
+
/**
|
|
1053
|
+
* LocalPosition in ENU frame
|
|
1054
|
+
*/
|
|
933
1055
|
worldToLocal(coords) {
|
|
934
1056
|
const rotationOffset = maths.Quaternion.fromAxisAngle([0, 0, 1], -this.heading);
|
|
935
1057
|
const ecefToEnuRotationOrigin = maths.Quaternion.multiply(this.origin.ecefToEnuRotation, rotationOffset);
|
|
@@ -1047,6 +1169,9 @@ class Attitude {
|
|
|
1047
1169
|
clone() {
|
|
1048
1170
|
return new Attitude(this.quaternion.slice(0), this.time, this.accuracy);
|
|
1049
1171
|
}
|
|
1172
|
+
/**
|
|
1173
|
+
* Calculate the relative attitude between two given attitudes
|
|
1174
|
+
*/
|
|
1050
1175
|
static diff(attitudeStart, attitudeEnd) {
|
|
1051
1176
|
const quaternionDiff = maths.Quaternion.multiply(
|
|
1052
1177
|
maths.Quaternion.inverse(attitudeStart.quaternion),
|
|
@@ -1088,6 +1213,11 @@ class AbsoluteHeading {
|
|
|
1088
1213
|
this.accuracy
|
|
1089
1214
|
);
|
|
1090
1215
|
}
|
|
1216
|
+
/**
|
|
1217
|
+
* Compares two AbsoluteHeading
|
|
1218
|
+
* @param {AbsoluteHeading} heading1 heading 1
|
|
1219
|
+
* @param {AbsoluteHeading} heading2 heading 2
|
|
1220
|
+
*/
|
|
1091
1221
|
static equals(heading1, heading2) {
|
|
1092
1222
|
if (heading1 === null && heading1 === heading2) {
|
|
1093
1223
|
return true;
|
|
@@ -1145,12 +1275,18 @@ class GeoGraphEdge extends utils.GraphEdge {
|
|
|
1145
1275
|
Level.checkType(level);
|
|
1146
1276
|
this._level = level;
|
|
1147
1277
|
}
|
|
1278
|
+
/**
|
|
1279
|
+
* Get edge bearing from vertex1 to vertex2
|
|
1280
|
+
*/
|
|
1148
1281
|
get bearing() {
|
|
1149
1282
|
if (!this._computedSizeAndBearing) {
|
|
1150
1283
|
this._computeSizeAndBearing();
|
|
1151
1284
|
}
|
|
1152
1285
|
return this._bearing;
|
|
1153
1286
|
}
|
|
1287
|
+
/**
|
|
1288
|
+
* get edge length
|
|
1289
|
+
*/
|
|
1154
1290
|
get length() {
|
|
1155
1291
|
if (!this._computedSizeAndBearing) {
|
|
1156
1292
|
this._computeSizeAndBearing();
|
|
@@ -1179,6 +1315,9 @@ class GeoGraphVertex extends utils.GraphVertex {
|
|
|
1179
1315
|
bearingTo(other) {
|
|
1180
1316
|
return this.coords.bearingTo(other.coords);
|
|
1181
1317
|
}
|
|
1318
|
+
/**
|
|
1319
|
+
* Does not include "edges" property
|
|
1320
|
+
*/
|
|
1182
1321
|
toJson() {
|
|
1183
1322
|
return this.coords.toCompressedJson();
|
|
1184
1323
|
}
|
|
@@ -1202,6 +1341,9 @@ class GeoGraphVertex extends utils.GraphVertex {
|
|
|
1202
1341
|
}
|
|
1203
1342
|
this.coords.level = tmpLevel;
|
|
1204
1343
|
}
|
|
1344
|
+
/**
|
|
1345
|
+
* We suppose inferVertexLevelFromEdges() was called before
|
|
1346
|
+
*/
|
|
1205
1347
|
inferVertexLevelByNeighboors() {
|
|
1206
1348
|
const { level } = this.coords;
|
|
1207
1349
|
if (level === null || !Level.isRange(level)) {
|
|
@@ -1218,6 +1360,9 @@ class GeoGraphVertex extends utils.GraphVertex {
|
|
|
1218
1360
|
}
|
|
1219
1361
|
return true;
|
|
1220
1362
|
}
|
|
1363
|
+
/**
|
|
1364
|
+
* We suppose inferVertexLevelFromEdges() and inferVertexLevelByNeighboors() were called before
|
|
1365
|
+
*/
|
|
1221
1366
|
inferVertexLevelByRecursion() {
|
|
1222
1367
|
const { level } = this.coords;
|
|
1223
1368
|
if (level === null || !Level.isRange(level)) {
|
|
@@ -1282,13 +1427,21 @@ class GeoGraph extends utils.Graph {
|
|
|
1282
1427
|
return boundingBox;
|
|
1283
1428
|
}
|
|
1284
1429
|
toCompressedJson() {
|
|
1430
|
+
const createEdgeExtras = (edge) => {
|
|
1431
|
+
const extras = {};
|
|
1432
|
+
if (edge.isOneway) {
|
|
1433
|
+
extras.oneway = true;
|
|
1434
|
+
}
|
|
1435
|
+
return extras;
|
|
1436
|
+
};
|
|
1285
1437
|
return {
|
|
1286
1438
|
vertices: this.vertices.map((vertex) => vertex.toJson()),
|
|
1287
1439
|
edges: this.edges.map((edge) => {
|
|
1288
1440
|
const vertex1Idx = this.vertices.indexOf(edge.vertex1);
|
|
1289
1441
|
const vertex2Idx = this.vertices.indexOf(edge.vertex2);
|
|
1290
|
-
|
|
1291
|
-
|
|
1442
|
+
const edgeExtras = createEdgeExtras(edge);
|
|
1443
|
+
if (Object.keys(edgeExtras).length > 0) {
|
|
1444
|
+
return [vertex1Idx, vertex2Idx, edge.level, edgeExtras];
|
|
1292
1445
|
}
|
|
1293
1446
|
if (edge.level !== null) {
|
|
1294
1447
|
return [vertex1Idx, vertex2Idx, edge.level];
|
|
@@ -1306,8 +1459,9 @@ class GeoGraph extends utils.Graph {
|
|
|
1306
1459
|
geograph.vertices[jsonEdge[1]],
|
|
1307
1460
|
{ level: jsonEdge.length > 2 ? jsonEdge[2] : null }
|
|
1308
1461
|
);
|
|
1309
|
-
|
|
1310
|
-
|
|
1462
|
+
const extras = jsonEdge.length > 3 ? jsonEdge[3] : {};
|
|
1463
|
+
if (typeof extras.oneway !== "undefined") {
|
|
1464
|
+
edge.isOneway = extras.oneway;
|
|
1311
1465
|
}
|
|
1312
1466
|
return edge;
|
|
1313
1467
|
});
|
|
@@ -1342,6 +1496,10 @@ class GeoGraph extends utils.Graph {
|
|
|
1342
1496
|
}
|
|
1343
1497
|
return geograph;
|
|
1344
1498
|
}
|
|
1499
|
+
/**
|
|
1500
|
+
* Create edges From MultiLevel Itinerary for a given level
|
|
1501
|
+
* @param useMultiLevelEdges use segments which intersect both levels (stairs, elevators...)
|
|
1502
|
+
*/
|
|
1345
1503
|
getEdgesAtLevel(targetLevel, useMultiLevelEdges = true) {
|
|
1346
1504
|
return this.edges.filter(
|
|
1347
1505
|
({ level }) => useMultiLevelEdges ? Level.intersect(targetLevel, level) : Level.contains(targetLevel, level)
|
|
@@ -1369,7 +1527,7 @@ class GeoGraphProjection {
|
|
|
1369
1527
|
this.nearestElement = nearestElement;
|
|
1370
1528
|
}
|
|
1371
1529
|
}
|
|
1372
|
-
const _GeoGraphProjectionHandler = class {
|
|
1530
|
+
const _GeoGraphProjectionHandler = class _GeoGraphProjectionHandler {
|
|
1373
1531
|
constructor(graph = null) {
|
|
1374
1532
|
__publicField(this, "graph", null);
|
|
1375
1533
|
__publicField(this, "_maxDistance", Number.MAX_VALUE);
|
|
@@ -1388,6 +1546,12 @@ const _GeoGraphProjectionHandler = class {
|
|
|
1388
1546
|
get maxDistance() {
|
|
1389
1547
|
return this._maxDistance;
|
|
1390
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
|
+
*/
|
|
1391
1555
|
_shouldProjectOnEdgeAndVertices(edge, location, useBearing, useMultiLevelSegments, acceptEdgeFn) {
|
|
1392
1556
|
if (!acceptEdgeFn(edge)) {
|
|
1393
1557
|
return [false, false, false];
|
|
@@ -1419,11 +1583,21 @@ const _GeoGraphProjectionHandler = class {
|
|
|
1419
1583
|
toCoordinates.lng = fromCoordinates.lng;
|
|
1420
1584
|
toCoordinates.level = Level.clone(fromCoordinates.level);
|
|
1421
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
|
+
*/
|
|
1422
1591
|
static _handleLevelsWithIOVertices(projection, location, projectionVertex) {
|
|
1423
1592
|
if (location.level === null && projectionVertex.io) {
|
|
1424
1593
|
projection.level = null;
|
|
1425
1594
|
}
|
|
1426
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
|
+
*/
|
|
1427
1601
|
getProjection(location, useDistance = false, useBearing = false, useMultiLevelSegments = true, acceptEdgeFn = () => true) {
|
|
1428
1602
|
if (this.graph === null) {
|
|
1429
1603
|
throw new Error("Graph has not been set yet");
|
|
@@ -1496,10 +1670,10 @@ const _GeoGraphProjectionHandler = class {
|
|
|
1496
1670
|
);
|
|
1497
1671
|
}
|
|
1498
1672
|
};
|
|
1499
|
-
|
|
1500
|
-
__publicField(GeoGraphProjectionHandler, "_updateProjectionLevelFromEdge", (_edge, _projection) => {
|
|
1673
|
+
__publicField(_GeoGraphProjectionHandler, "_updateProjectionLevelFromEdge", (_edge, _projection) => {
|
|
1501
1674
|
_projection.level = Level.clone(_edge.level);
|
|
1502
1675
|
});
|
|
1676
|
+
let GeoGraphProjectionHandler = _GeoGraphProjectionHandler;
|
|
1503
1677
|
class GeoGraphItinerary extends GeoGraph {
|
|
1504
1678
|
constructor(start, end, vertices, edges, edgesWeights) {
|
|
1505
1679
|
super(vertices, edges);
|
|
@@ -1522,7 +1696,7 @@ class GeoGraphItinerary extends GeoGraph {
|
|
|
1522
1696
|
const prevVertex = arr[idx - 1];
|
|
1523
1697
|
const edge = GeoGraphEdge.getEdgeByVertices(prevVertex.edges, prevVertex, vertex);
|
|
1524
1698
|
if (!edge) {
|
|
1525
|
-
|
|
1699
|
+
Logger.error("Cannot retrieve edge to create itinerary");
|
|
1526
1700
|
return;
|
|
1527
1701
|
}
|
|
1528
1702
|
edges.push(new GeoGraphEdge(
|
|
@@ -1561,7 +1735,7 @@ class NoRouteFoundError extends Error {
|
|
|
1561
1735
|
return message;
|
|
1562
1736
|
}
|
|
1563
1737
|
}
|
|
1564
|
-
const _GeoGraphRouter = class {
|
|
1738
|
+
const _GeoGraphRouter = class _GeoGraphRouter {
|
|
1565
1739
|
constructor(graph) {
|
|
1566
1740
|
__publicField(this, "_mapMatching");
|
|
1567
1741
|
__publicField(this, "_graph");
|
|
@@ -1720,11 +1894,11 @@ const _GeoGraphRouter = class {
|
|
|
1720
1894
|
return GeoGraphItinerary.fromGraphVertices(start.coords, end.coords, path, edgesWeights);
|
|
1721
1895
|
}
|
|
1722
1896
|
};
|
|
1723
|
-
|
|
1724
|
-
__publicField(GeoGraphRouter, "DEFAULT_OPTIONS", {
|
|
1897
|
+
__publicField(_GeoGraphRouter, "DEFAULT_OPTIONS", {
|
|
1725
1898
|
projectionMaxDistance: 50,
|
|
1726
1899
|
weightEdgeFn: (edge) => edge.length
|
|
1727
1900
|
});
|
|
1901
|
+
let GeoGraphRouter = _GeoGraphRouter;
|
|
1728
1902
|
exports.AbsoluteHeading = AbsoluteHeading;
|
|
1729
1903
|
exports.Attitude = Attitude;
|
|
1730
1904
|
exports.BoundingBox = BoundingBox;
|