@wemap/geo 13.2.3 → 14.2.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.
Files changed (34) hide show
  1. package/README.md +2 -0
  2. package/dist/index.d.ts +14 -13
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +1049 -2
  5. package/dist/src/Constants.d.ts +1 -0
  6. package/dist/src/Constants.d.ts.map +1 -0
  7. package/dist/src/Utils.d.ts +4 -3
  8. package/dist/src/Utils.d.ts.map +1 -0
  9. package/dist/src/coordinates/BoundingBox.d.ts +2 -1
  10. package/dist/src/coordinates/BoundingBox.d.ts.map +1 -0
  11. package/dist/src/coordinates/Coordinates.d.ts +3 -2
  12. package/dist/src/coordinates/Coordinates.d.ts.map +1 -0
  13. package/dist/src/coordinates/GeoRef.d.ts +6 -5
  14. package/dist/src/coordinates/GeoRef.d.ts.map +1 -0
  15. package/dist/src/coordinates/GeoRelativePosition.d.ts +2 -1
  16. package/dist/src/coordinates/GeoRelativePosition.d.ts.map +1 -0
  17. package/dist/src/coordinates/Level.d.ts +1 -0
  18. package/dist/src/coordinates/Level.d.ts.map +1 -0
  19. package/dist/src/coordinates/RelativePosition.d.ts +2 -1
  20. package/dist/src/coordinates/RelativePosition.d.ts.map +1 -0
  21. package/dist/src/coordinates/UserPosition.d.ts +3 -2
  22. package/dist/src/coordinates/UserPosition.d.ts.map +1 -0
  23. package/dist/src/rotations/AbsoluteHeading.d.ts +3 -2
  24. package/dist/src/rotations/AbsoluteHeading.d.ts.map +1 -0
  25. package/dist/src/rotations/Attitude.d.ts +2 -1
  26. package/dist/src/rotations/Attitude.d.ts.map +1 -0
  27. package/dist/src/types.d.ts +2 -1
  28. package/dist/src/types.d.ts.map +1 -0
  29. package/dist/vitest.config.d.ts +3 -0
  30. package/dist/vitest.config.d.ts.map +1 -0
  31. package/package.json +28 -53
  32. package/dist/index.js.map +0 -1
  33. package/dist/index.mjs +0 -1348
  34. package/dist/index.mjs.map +0 -1
package/dist/index.mjs DELETED
@@ -1,1348 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
- var __publicField = (obj, key, value) => {
4
- __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
- return value;
6
- };
7
- import { wrap, deg2rad, rad2deg, Quaternion, Vector3, positiveMod, Rotations } from "@wemap/maths";
8
- import booleanPointInPolygon from "@turf/boolean-point-in-polygon";
9
- const R_MAJOR = 6378137;
10
- const R_MINOR = 63567523142e-4;
11
- const EARTH_GRAVITY = 9.80665;
12
- const EPS_DEG_MM = 1e-8;
13
- const EPS_MM = 1e-3;
14
- const ELLIPSOID_FLATNESS = (R_MAJOR - R_MINOR) / R_MAJOR;
15
- const ECCENTRICITY = Math.sqrt(ELLIPSOID_FLATNESS * (2 - ELLIPSOID_FLATNESS));
16
- const ECCENTRICITY_2 = ECCENTRICITY * ECCENTRICITY;
17
- const R_MAJOR_2 = R_MAJOR * R_MAJOR;
18
- const R_MAJOR_4 = R_MAJOR_2 * R_MAJOR_2;
19
- const R_MINOR_2 = R_MINOR * R_MINOR;
20
- const R_MINOR_4 = R_MINOR_2 * R_MINOR_2;
21
- const CIRCUMFERENCE = R_MAJOR * 2 * Math.PI;
22
- const Constants = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
23
- __proto__: null,
24
- CIRCUMFERENCE,
25
- EARTH_GRAVITY,
26
- ECCENTRICITY,
27
- ECCENTRICITY_2,
28
- ELLIPSOID_FLATNESS,
29
- EPS_DEG_MM,
30
- EPS_MM,
31
- R_MAJOR,
32
- R_MAJOR_2,
33
- R_MAJOR_4,
34
- R_MINOR,
35
- R_MINOR_2,
36
- R_MINOR_4
37
- }, Symbol.toStringTag, { value: "Module" }));
38
- const _Level = class _Level {
39
- static checkType(level) {
40
- if (level === null) {
41
- return;
42
- }
43
- if (typeof level === "number" && !isNaN(level)) {
44
- return;
45
- }
46
- if (Array.isArray(level) && level.length === 2) {
47
- const [low, up] = level;
48
- if (typeof low === "number" && !isNaN(low) && typeof up === "number" && !isNaN(up)) {
49
- if (low > up || low === up) {
50
- throw Error(`Invalid level range: [${low}, ${up}]`);
51
- }
52
- return;
53
- }
54
- }
55
- throw Error(`Unknown level format: ${level}`);
56
- }
57
- /**
58
- * Return true if the level is a range, false otherwise
59
- */
60
- static isRange(level) {
61
- if (_Level.VERIFY_TYPING) {
62
- _Level.checkType(level);
63
- }
64
- return Array.isArray(level);
65
- }
66
- static clone(level) {
67
- if (_Level.VERIFY_TYPING) {
68
- _Level.checkType(level);
69
- }
70
- if (level === null) {
71
- return null;
72
- }
73
- if (typeof level === "number") {
74
- return level;
75
- }
76
- return [level[0], level[1]];
77
- }
78
- /**
79
- * Create a level from a string (eg. 1, -2, 1;2, -2;3, 2;-1, 0.5;1 ...)
80
- */
81
- static fromString(str) {
82
- if (str === null) {
83
- return null;
84
- }
85
- if (typeof str !== "string" || !str.length) {
86
- throw Error(`argument must be a non empty string, got ${typeof str}`);
87
- }
88
- if (!isNaN(Number(str))) {
89
- return parseFloat(str);
90
- }
91
- const splited = str.split(";");
92
- if (splited.length > 1) {
93
- const levels = splited.map((str2) => Number(str2));
94
- const low = Math.min(...levels);
95
- const up = Math.max(...levels);
96
- _Level.checkType([low, up]);
97
- return [low, up];
98
- } else {
99
- const rangeSeparator = str.substring(1).indexOf("-") + 1;
100
- if (rangeSeparator > 0) {
101
- const low = Number(str.substring(0, rangeSeparator));
102
- const up = Number(str.substring(rangeSeparator + 1));
103
- _Level.checkType([low, up]);
104
- return [low, up];
105
- }
106
- }
107
- throw Error(`Cannot parse following level: ${str}`);
108
- }
109
- /**
110
- * Returns if a level is contained in another
111
- * @param {null|number|[number, number]} container The container level
112
- * @param {null|number|[number, number]} targeted The targeted level
113
- */
114
- static contains(container, targeted) {
115
- if (_Level.VERIFY_TYPING) {
116
- _Level.checkType(container);
117
- _Level.checkType(targeted);
118
- }
119
- if (container === targeted) {
120
- return true;
121
- }
122
- if (Array.isArray(container)) {
123
- if (Array.isArray(targeted)) {
124
- return container[0] <= targeted[0] && container[1] >= targeted[1];
125
- }
126
- if (targeted === null) {
127
- return false;
128
- }
129
- return container[0] <= targeted && container[1] >= targeted;
130
- }
131
- if (container === null || targeted === null) {
132
- return false;
133
- }
134
- return container <= targeted[0] && container >= targeted[1];
135
- }
136
- /**
137
- * Retrieve the intersection of two levels
138
- * null n null => null
139
- * null n 1 => null // Conception choice
140
- * null n [1,2] => null // Conception choice
141
- * 1 n 1 => 1
142
- * 1 n 2 => null
143
- * 1 n [1,2] => 1
144
- * 1 n [0,2] => 1
145
- * 1 n [2,3] => null
146
- * [1,2] n [1,2] => [1,2]
147
- * [1,2] n [2,3] => 2
148
- * [1,2] n [3,4] => null
149
- */
150
- static intersection(first, second) {
151
- if (_Level.VERIFY_TYPING) {
152
- _Level.checkType(first);
153
- _Level.checkType(second);
154
- }
155
- if (first === null || second === null) {
156
- return null;
157
- }
158
- if (_Level.equals(first, second)) {
159
- return _Level.clone(first);
160
- }
161
- if (typeof first === "number" && typeof second === "number") {
162
- return first === second ? first : null;
163
- }
164
- if (Array.isArray(first) && !Array.isArray(second)) {
165
- if (_Level.contains(first, second)) {
166
- return second;
167
- }
168
- return null;
169
- }
170
- if (!Array.isArray(first) && Array.isArray(second)) {
171
- if (_Level.contains(second, first)) {
172
- return first;
173
- }
174
- return null;
175
- }
176
- const low = Math.max(first[0], second[0]);
177
- const up = Math.min(first[1], second[1]);
178
- if (up === low) {
179
- return up;
180
- }
181
- return up < low ? null : [low, up];
182
- }
183
- /**
184
- * Retrieve the intersection of two levels
185
- * @param {null|number|[number, number]} first The first level
186
- * @param {null|number|[number, number]} second The second level
187
- * @returns {boolean}
188
- */
189
- static intersect(first, second) {
190
- if (_Level.VERIFY_TYPING) {
191
- _Level.checkType(first);
192
- _Level.checkType(second);
193
- }
194
- if (first === null && second === null) {
195
- return true;
196
- }
197
- return _Level.intersection(first, second) !== null;
198
- }
199
- /**
200
- * Retrieve the union of two levels
201
- * null u null => null
202
- * null u 1 => null // Conception choice
203
- * null u [1,2] => null // Conception choice
204
- * 1 u 1 => 1
205
- * 1 u 2 => [1,2]
206
- * 1 u [1,2] => [1,2]
207
- * 1 u [0,2] => [0,2]
208
- * 1 u [2,3] => [1,3]
209
- * [1,2] u [1,2] => [1,2]
210
- * [1,2] u [2,3] => [1,3]
211
- * [1,2] u [3,4] => [1,4]
212
- */
213
- static union(first, second) {
214
- if (_Level.VERIFY_TYPING) {
215
- _Level.checkType(first);
216
- _Level.checkType(second);
217
- }
218
- if (first === second) {
219
- return _Level.clone(first);
220
- }
221
- if (second === null) {
222
- return null;
223
- }
224
- if (first === null) {
225
- return null;
226
- }
227
- let low, up;
228
- if (!Array.isArray(first) && !Array.isArray(second)) {
229
- low = Math.min(first, second);
230
- up = Math.max(first, second);
231
- } else if (Array.isArray(first) && !Array.isArray(second)) {
232
- low = Math.min(first[0], second);
233
- up = Math.max(first[1], second);
234
- } else if (!Array.isArray(first) && Array.isArray(second)) {
235
- low = Math.min(second[0], first);
236
- up = Math.max(second[1], first);
237
- } else {
238
- low = Math.min(first[0], second[0]);
239
- up = Math.max(first[1], second[1]);
240
- }
241
- if (low === up) {
242
- return low;
243
- }
244
- return [low, up];
245
- }
246
- /**
247
- * Multiply a level by a factor
248
- * @param {null|number|[number, number]} level the level to multiply
249
- * @param {number} factor
250
- * @returns {null|number|[number, number]}
251
- */
252
- static multiplyBy(level, factor) {
253
- if (_Level.VERIFY_TYPING) {
254
- _Level.checkType(level);
255
- }
256
- if (level === null) {
257
- return null;
258
- }
259
- return Array.isArray(level) ? [level[0] * factor, level[1] * factor] : level * factor;
260
- }
261
- static toString(level) {
262
- if (_Level.VERIFY_TYPING) {
263
- _Level.checkType(level);
264
- }
265
- if (level === null) {
266
- return null;
267
- }
268
- return Array.isArray(level) ? level[0] + ";" + level[1] : String(level);
269
- }
270
- static equals(first, second) {
271
- if (_Level.VERIFY_TYPING) {
272
- _Level.checkType(first);
273
- _Level.checkType(second);
274
- }
275
- if (first === second) {
276
- return true;
277
- }
278
- if (Array.isArray(first) && Array.isArray(second)) {
279
- return first[0] === second[0] && first[1] === second[1];
280
- }
281
- return false;
282
- }
283
- static diff(first, second) {
284
- if (_Level.VERIFY_TYPING) {
285
- _Level.checkType(first);
286
- _Level.checkType(second);
287
- }
288
- if (first === null || second === null) {
289
- return null;
290
- }
291
- if (!Array.isArray(first) && !Array.isArray(second)) {
292
- return second - first;
293
- }
294
- if (Array.isArray(first) && !Array.isArray(second)) {
295
- if (first[0] === second) {
296
- return second - first[1];
297
- }
298
- if (first[1] === second) {
299
- return second - first[0];
300
- }
301
- return null;
302
- }
303
- if (Array.isArray(second) && !Array.isArray(first)) {
304
- if (first === second[0]) {
305
- return second[1] - first;
306
- }
307
- if (first === second[1]) {
308
- return second[0] - first;
309
- }
310
- return null;
311
- }
312
- if (_Level.equals(first, second)) {
313
- return 0;
314
- }
315
- return null;
316
- }
317
- };
318
- __publicField(_Level, "VERIFY_TYPING", false);
319
- let Level = _Level;
320
- class Coordinates {
321
- constructor(lat, lng, alt = null, level = null) {
322
- __publicField(this, "_lat");
323
- __publicField(this, "_lng");
324
- __publicField(this, "_alt", null);
325
- __publicField(this, "_level", null);
326
- __publicField(this, "_heightFromFloor", null);
327
- __publicField(this, "_heightFromGround", null);
328
- __publicField(this, "_ecef");
329
- __publicField(this, "autoWrap", true);
330
- this.lat = lat;
331
- this.lng = lng;
332
- this.alt = alt;
333
- this.level = level;
334
- this._ecef = null;
335
- }
336
- get lat() {
337
- return this._lat;
338
- }
339
- set lat(lat) {
340
- if (Math.abs(lat) <= 90) {
341
- this._lat = lat;
342
- } else {
343
- throw new Error(`lat argument is not in [-90; 90], value is ${lat}`);
344
- }
345
- this._ecef = null;
346
- }
347
- get latitude() {
348
- return this._lat;
349
- }
350
- set latitude(_) {
351
- throw new Error("Please use Coordinates#lat setter instead of Coordinate#latitude");
352
- }
353
- get lng() {
354
- return this._lng;
355
- }
356
- set lng(lng) {
357
- this._lng = lng;
358
- if (this.autoWrap) {
359
- this.wrap();
360
- }
361
- this._ecef = null;
362
- }
363
- get longitude() {
364
- return this._lng;
365
- }
366
- set longitude(_) {
367
- throw new Error("Please use Coordinates#lng setter instead of Coordinate#longitude");
368
- }
369
- /**
370
- * alt does not denote the altitude of a point but its height from
371
- * the "level" field (if defined) or from the ground
372
- */
373
- get alt() {
374
- return this._alt;
375
- }
376
- set alt(alt) {
377
- this._alt = alt;
378
- this._ecef = null;
379
- }
380
- get level() {
381
- return this._level;
382
- }
383
- set level(level) {
384
- Level.checkType(level);
385
- this._level = level;
386
- }
387
- get heightFromFloor() {
388
- return this._heightFromFloor;
389
- }
390
- set heightFromFloor(heightFromFloor) {
391
- this._heightFromFloor = heightFromFloor;
392
- }
393
- get heightFromGround() {
394
- return this._heightFromGround;
395
- }
396
- set heightFromGround(heightFromGround) {
397
- this._heightFromGround = heightFromGround;
398
- }
399
- /**
400
- * Deep clone coordinates
401
- */
402
- clone() {
403
- const output = new Coordinates(this.lat, this.lng, this.alt);
404
- if (this.level !== null) {
405
- output.level = Level.clone(this.level);
406
- }
407
- return output;
408
- }
409
- wrap() {
410
- if (this._lng <= -180 || this._lng > 180) {
411
- this._lng = wrap(this._lng, -180, 180);
412
- }
413
- }
414
- static equals(pos1, pos2, eps = EPS_DEG_MM, epsAlt = EPS_MM) {
415
- if (!this.equalsWithoutLevel(pos1, pos2, eps, epsAlt)) {
416
- return false;
417
- }
418
- if (pos1 === null || pos2 === null) {
419
- return true;
420
- }
421
- return Level.equals(pos1.level, pos2.level);
422
- }
423
- equals(other) {
424
- return Coordinates.equals(this, other);
425
- }
426
- static equalsWithoutLevel(pos1, pos2, eps = EPS_DEG_MM, epsAlt = EPS_MM) {
427
- if (pos1 === null && pos1 === pos2) {
428
- return true;
429
- }
430
- if (!(pos1 instanceof Coordinates) || !(pos2 instanceof Coordinates)) {
431
- return false;
432
- }
433
- return Math.abs(pos2.lat - pos1.lat) < eps && Math.abs(pos2.lng - pos1.lng) < eps && (pos1.alt === pos2.alt || pos1.alt !== null && pos2.alt !== null && Math.abs(pos2.alt - pos1.alt) < epsAlt);
434
- }
435
- equalsWithoutLevel(other, eps = EPS_DEG_MM, epsAlt = EPS_MM) {
436
- return Coordinates.equalsWithoutLevel(this, other, eps, epsAlt);
437
- }
438
- /**
439
- * @throws {Error} if elevation is defined and point altitude is not defined
440
- */
441
- destinationPoint(distance, bearing, elevation = null) {
442
- const newPoint = this.clone();
443
- newPoint.move(distance, bearing, elevation);
444
- return newPoint;
445
- }
446
- /**
447
- * Source: http://www.movable-type.co.uk/scripts/latlong.html#destPoint
448
- * @throws {Error} if elevation is defined and point altitude is not defined
449
- */
450
- move(distance, bearing, elevation = null) {
451
- const dR = distance / R_MAJOR;
452
- const cosDr = Math.cos(dR);
453
- const sinDr = Math.sin(dR);
454
- const phi1 = deg2rad(this.lat);
455
- const lambda1 = deg2rad(this.lng);
456
- const phi2 = Math.asin(
457
- Math.sin(phi1) * cosDr + Math.cos(phi1) * sinDr * Math.cos(bearing)
458
- );
459
- const lambda2 = lambda1 + Math.atan2(
460
- Math.sin(bearing) * sinDr * Math.cos(phi1),
461
- cosDr - Math.sin(phi1) * Math.sin(phi2)
462
- );
463
- this.lat = rad2deg(phi2);
464
- this.lng = rad2deg(lambda2);
465
- if (elevation !== null) {
466
- if (this.alt === null) {
467
- throw new Error("Point altitude is not defined");
468
- }
469
- this.alt += elevation;
470
- }
471
- return this;
472
- }
473
- /**
474
- * Returns a distance between two points in meters
475
- */
476
- distanceTo(location2) {
477
- const lat1 = this.lat;
478
- const lng1 = this.lng;
479
- const lat2 = location2.lat;
480
- const lng2 = location2.lng;
481
- const dlat = deg2rad(lat2 - lat1);
482
- const dlng = deg2rad(lng2 - lng1);
483
- const dlngsin = Math.sin(dlng / 2);
484
- const dlatsin = Math.sin(dlat / 2);
485
- const lat1rad = deg2rad(lat1);
486
- const lat1cos = Math.cos(lat1rad);
487
- const lat2rad = deg2rad(lat2);
488
- const lat2cos = Math.cos(lat2rad);
489
- const angle = dlatsin * dlatsin + lat1cos * lat2cos * dlngsin * dlngsin;
490
- const tangy = Math.sqrt(angle);
491
- const tangx = Math.sqrt(1 - angle);
492
- const cosn = 2 * Math.atan2(tangy, tangx);
493
- return R_MAJOR * cosn;
494
- }
495
- static distanceBetween(point1, point2) {
496
- return point1.distanceTo(point2);
497
- }
498
- bearingTo(location2) {
499
- const lat1 = deg2rad(this.lat);
500
- const lat2 = deg2rad(location2.lat);
501
- const diffLng = deg2rad(location2.lng - this.lng);
502
- return Math.atan2(
503
- Math.sin(diffLng) * Math.cos(lat2),
504
- Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(diffLng)
505
- );
506
- }
507
- static bearingTo(point1, point2) {
508
- return point1.bearingTo(point2);
509
- }
510
- /**
511
- * ECEF Transformations
512
- * Here we used a light version of ECEF considering earth
513
- * as a sphere instead of an ellipse
514
- */
515
- get enuToEcefRotation() {
516
- const rot1 = Quaternion.fromAxisAngle([0, 0, 1], Math.PI / 2 + deg2rad(this.lng));
517
- const rot2 = Quaternion.fromAxisAngle([1, 0, 0], Math.PI / 2 - deg2rad(this.lat));
518
- return Quaternion.multiply(rot1, rot2);
519
- }
520
- get ecefToEnuRotation() {
521
- const rot1 = Quaternion.fromAxisAngle([1, 0, 0], deg2rad(this.lat) - Math.PI / 2);
522
- const rot2 = Quaternion.fromAxisAngle([0, 0, 1], -deg2rad(this.lng) - Math.PI / 2);
523
- return Quaternion.multiply(rot1, rot2);
524
- }
525
- /**
526
- * https://gist.github.com/klucar/1536194
527
- * Adapted for spherical formula
528
- */
529
- get ecef() {
530
- if (!this._ecef) {
531
- const lat = deg2rad(this.lat);
532
- const lng = deg2rad(this.lng);
533
- const alt = this.alt || 0;
534
- const x = (R_MAJOR + alt) * Math.cos(lat) * Math.cos(lng);
535
- const y = (R_MAJOR + alt) * Math.cos(lat) * Math.sin(lng);
536
- const z = (R_MAJOR + alt) * Math.sin(lat);
537
- this._ecef = [x, y, z];
538
- }
539
- return this._ecef;
540
- }
541
- static fromECEF(ecef) {
542
- const x = ecef[0];
543
- const y = ecef[1];
544
- const z = ecef[2];
545
- const p = Math.sqrt(x ** 2 + y ** 2);
546
- let lng = Math.atan2(y, x);
547
- const lat = Math.atan2(z, p);
548
- const alt = p / Math.cos(lat) - R_MAJOR;
549
- lng = lng % (2 * Math.PI);
550
- const newPoint = new Coordinates(rad2deg(lat), rad2deg(lng), alt);
551
- newPoint._ecef = ecef;
552
- return newPoint;
553
- }
554
- /**
555
- * https://stackoverflow.com/questions/1299567/how-to-calculate-distance-from-a-point-to-a-line-segment-on-a-sphere
556
- * Adapted to ECEF
557
- */
558
- getSegmentProjection(p1, p2) {
559
- const a = Vector3.normalize(p1.ecef);
560
- const b = Vector3.normalize(p2.ecef);
561
- const c = Vector3.normalize(this.ecef);
562
- const G = Vector3.cross(a, b);
563
- if (Vector3.norm(G) === 0) {
564
- return null;
565
- }
566
- const F = Vector3.cross(c, G);
567
- const t = Vector3.normalize(Vector3.cross(G, F));
568
- const posECEF = Vector3.multiplyScalar(t, R_MAJOR);
569
- const poseCoordinates = Coordinates.fromECEF(posECEF);
570
- let alt;
571
- if (p1.alt !== null && p2.alt !== null) {
572
- alt = (p1.alt + p2.alt) / 2;
573
- }
574
- const projection = new Coordinates(
575
- poseCoordinates.lat,
576
- poseCoordinates.lng,
577
- alt,
578
- Level.union(p1.level, p2.level)
579
- );
580
- if (Math.abs(p1.distanceTo(p2) - p1.distanceTo(projection) - p2.distanceTo(projection)) > EPS_MM) {
581
- return null;
582
- }
583
- return projection;
584
- }
585
- /**
586
- * Input / Output
587
- */
588
- toString() {
589
- let str = "[" + this._lat.toFixed(7) + ", " + this._lng.toFixed(7);
590
- if (this._alt !== null) {
591
- str += ", " + this._alt.toFixed(2);
592
- }
593
- if (this._level !== null) {
594
- str += ", [" + Level.toString(this._level) + "]";
595
- }
596
- str += "]";
597
- return str;
598
- }
599
- toJson() {
600
- return {
601
- lat: Number(this.lat.toFixed(8)),
602
- lng: Number(this.lng.toFixed(8)),
603
- ...this.alt !== null && { alt: Number(this.alt.toFixed(3)) },
604
- ...this.level !== null && { level: this.level }
605
- };
606
- }
607
- static fromJson(json) {
608
- return new Coordinates(json.lat, json.lng, json.alt, json.level);
609
- }
610
- toCompressedJson() {
611
- if (this.level !== null) {
612
- return [
613
- Number(this.lat.toFixed(8)),
614
- Number(this.lng.toFixed(8)),
615
- this.level
616
- ];
617
- }
618
- return [Number(this.lat.toFixed(8)), Number(this.lng.toFixed(8))];
619
- }
620
- static fromCompressedJson(json) {
621
- const coords = new Coordinates(json[0], json[1]);
622
- if (json.length > 2) {
623
- coords.level = json[2];
624
- }
625
- return coords;
626
- }
627
- }
628
- class UserPosition extends Coordinates {
629
- constructor(lat, lng, alt = null, level = null, time = null, accuracy = null, bearing = null) {
630
- super(lat, lng, alt, level);
631
- __publicField(this, "_time", null);
632
- __publicField(this, "_accuracy", null);
633
- __publicField(this, "_bearing", null);
634
- this.time = time;
635
- this.accuracy = accuracy;
636
- this.bearing = bearing;
637
- }
638
- get time() {
639
- return this._time;
640
- }
641
- set time(time) {
642
- this._time = time;
643
- }
644
- get accuracy() {
645
- return this._accuracy;
646
- }
647
- set accuracy(accuracy) {
648
- if (accuracy !== null && accuracy < 0) {
649
- throw new Error("accuracy argument is not a positive number");
650
- }
651
- this._accuracy = accuracy;
652
- }
653
- get bearing() {
654
- return this._bearing;
655
- }
656
- set bearing(bearing) {
657
- this._bearing = bearing !== null ? bearing % (2 * Math.PI) : null;
658
- }
659
- move(distance, bearing, elevation = null) {
660
- super.move(distance, bearing, elevation);
661
- return this;
662
- }
663
- destinationPoint(distance, bearing, elevation = null) {
664
- const newPoint = this.clone();
665
- newPoint.move(distance, bearing, elevation);
666
- return newPoint;
667
- }
668
- // Create a UserPosition with lat, lng, alt from Coordinates coordinates and
669
- // other fields from another UserPosition
670
- static fromCoordinates(coordinates) {
671
- return new UserPosition(
672
- coordinates.lat,
673
- coordinates.lng,
674
- coordinates.alt,
675
- coordinates.level
676
- );
677
- }
678
- clone() {
679
- const cloned = UserPosition.fromCoordinates(super.clone());
680
- cloned.time = this.time;
681
- cloned.accuracy = this.accuracy;
682
- cloned.bearing = this.bearing;
683
- return cloned;
684
- }
685
- static equals(pos1, pos2, eps = EPS_DEG_MM, epsAlt = EPS_MM) {
686
- if (pos1 === null && pos1 === pos2) {
687
- return true;
688
- }
689
- if (!(pos1 instanceof UserPosition) || !(pos2 instanceof UserPosition)) {
690
- return false;
691
- }
692
- if (!super.equals(pos1, pos2, eps, epsAlt)) {
693
- return false;
694
- }
695
- return pos1.time === pos2.time && pos1.accuracy === pos2.accuracy && pos1.bearing === pos2.bearing;
696
- }
697
- equals(other, eps = EPS_DEG_MM, epsAlt = EPS_MM) {
698
- return UserPosition.equals(this, other, eps, epsAlt);
699
- }
700
- toJson() {
701
- return {
702
- ...super.toJson(),
703
- ...this.time !== null && { time: this.time },
704
- ...this.accuracy !== null && { accuracy: this.accuracy },
705
- ...this.bearing !== null && { bearing: this.bearing }
706
- };
707
- }
708
- static fromJson(json) {
709
- const position = UserPosition.fromCoordinates(Coordinates.fromJson(json));
710
- if (typeof json.time !== "undefined") {
711
- position.time = json.time;
712
- }
713
- if (typeof json.accuracy !== "undefined") {
714
- position.accuracy = json.accuracy;
715
- }
716
- if (typeof json.bearing !== "undefined") {
717
- position.bearing = json.bearing;
718
- }
719
- return position;
720
- }
721
- }
722
- function sampleRoute(route, stepSize = 0.7, startSampling = 0, length = Number.MAX_VALUE) {
723
- const endSampling = startSampling + length;
724
- const sampledRoute = [];
725
- let lastSample;
726
- let totalDistanceTraveled = 0;
727
- let distanceToNextSample = 0;
728
- let startFound = false;
729
- for (let segmentIndex = 0; segmentIndex < route.length - 1; segmentIndex++) {
730
- const p1 = route[segmentIndex];
731
- const p2 = route[segmentIndex + 1];
732
- const segmentSize = p1.distanceTo(p2);
733
- const segmentBearing = p1.bearingTo(p2);
734
- let distanceTraveledOnSegment = 0;
735
- if (!startFound) {
736
- if (startSampling < totalDistanceTraveled + segmentSize) {
737
- startFound = true;
738
- distanceToNextSample = startSampling - totalDistanceTraveled;
739
- } else {
740
- totalDistanceTraveled += segmentSize;
741
- continue;
742
- }
743
- }
744
- lastSample = Object.assign(p1.clone(), { bearing: segmentBearing });
745
- while (distanceTraveledOnSegment + distanceToNextSample < segmentSize && totalDistanceTraveled + distanceToNextSample <= endSampling) {
746
- const newPoint = lastSample.destinationPoint(distanceToNextSample, segmentBearing);
747
- newPoint.bearing = segmentBearing;
748
- sampledRoute.push(newPoint);
749
- lastSample = newPoint;
750
- distanceTraveledOnSegment += distanceToNextSample;
751
- totalDistanceTraveled += distanceToNextSample;
752
- distanceToNextSample = stepSize;
753
- }
754
- if (totalDistanceTraveled + distanceToNextSample > endSampling) {
755
- break;
756
- }
757
- const rest = segmentSize - distanceTraveledOnSegment;
758
- totalDistanceTraveled += rest;
759
- distanceToNextSample -= rest;
760
- }
761
- return sampledRoute;
762
- }
763
- function trimRoute(route, startPosition = route[0], length = Number.MAX_VALUE) {
764
- const newRoute = [];
765
- let previousPoint = null;
766
- let currentPointIndex;
767
- let cumulativeDistance = 0;
768
- if (route.length <= 1) {
769
- throw new Error("Route must have at least 2 points");
770
- }
771
- for (currentPointIndex = 1; currentPointIndex < route.length; currentPointIndex++) {
772
- const p1 = route[currentPointIndex - 1];
773
- const p2 = route[currentPointIndex];
774
- if (Coordinates.equals(startPosition, p1)) {
775
- newRoute.push(p1);
776
- previousPoint = p1;
777
- break;
778
- }
779
- const proj = startPosition.getSegmentProjection(p1, p2);
780
- if (proj && Coordinates.equals(startPosition, proj) && !proj.equals(p2)) {
781
- newRoute.push(proj);
782
- previousPoint = proj;
783
- break;
784
- }
785
- }
786
- if (!newRoute.length) {
787
- throw new Error("startPosition is not on the route");
788
- }
789
- while (previousPoint && currentPointIndex < route.length) {
790
- const currentPoint = route[currentPointIndex];
791
- const dist = previousPoint.distanceTo(currentPoint);
792
- if (cumulativeDistance + dist >= length || Math.abs(cumulativeDistance + dist - length) <= EPS_MM) {
793
- const bearing = previousPoint.bearingTo(currentPoint);
794
- const remainingLength = length - cumulativeDistance;
795
- const end = previousPoint.destinationPoint(remainingLength, bearing);
796
- newRoute.push(end);
797
- break;
798
- }
799
- newRoute.push(currentPoint);
800
- previousPoint = currentPoint;
801
- cumulativeDistance += dist;
802
- currentPointIndex++;
803
- }
804
- return newRoute;
805
- }
806
- function simplifyRoute(coords, precisionAngle = deg2rad(5)) {
807
- const isClosed = coords[0].equals(coords[coords.length - 1]);
808
- let newRoute = coords.slice(0, coords.length - (isClosed ? 1 : 0));
809
- const len = newRoute.length;
810
- for (let i = isClosed ? 0 : 1; i < len; i++) {
811
- const p0 = coords[positiveMod(i - 1, len)];
812
- const p1 = coords[i];
813
- const p2 = coords[positiveMod(i + 1, len)];
814
- const seg1Dir = p0.bearingTo(p1);
815
- const seg2Dir = p1.bearingTo(p2);
816
- if (Math.abs(seg2Dir - seg1Dir) < precisionAngle) {
817
- newRoute = newRoute.filter((coord) => coord !== p1);
818
- }
819
- }
820
- if (isClosed) {
821
- newRoute.push(newRoute[0]);
822
- }
823
- return newRoute;
824
- }
825
- function geolocationPositionToUserPosition(geolocationPosition) {
826
- if (geolocationPosition === null) {
827
- return null;
828
- }
829
- const { latitude, longitude, accuracy, heading } = geolocationPosition.coords;
830
- const userPosition = new UserPosition(latitude, longitude);
831
- userPosition.time = geolocationPosition.timestamp;
832
- userPosition.accuracy = accuracy;
833
- userPosition.bearing = heading ? deg2rad(heading) : null;
834
- return userPosition;
835
- }
836
- function calcDistance(coords) {
837
- return coords.reduce((acc, coords2, idx, arr) => acc + (idx ? arr[idx - 1].distanceTo(coords2) : 0), 0);
838
- }
839
- function createSegmentsAtLevel(itineraryCoords, segmentsLevel, useMultiLevelSegments = true) {
840
- const itineraryCoordsLength = itineraryCoords.length;
841
- let previousLevelCorrespond = false;
842
- const segments = [];
843
- let coordinates = [];
844
- for (let i = 0; i < itineraryCoordsLength; i++) {
845
- const coords = itineraryCoords[i];
846
- const levelCorrespond = Level.intersect(segmentsLevel, coords.level);
847
- if (useMultiLevelSegments && !levelCorrespond && previousLevelCorrespond) {
848
- coordinates.push(coords);
849
- } else if (levelCorrespond) {
850
- if (!previousLevelCorrespond) {
851
- coordinates = [];
852
- segments.push(coordinates);
853
- if (useMultiLevelSegments && i !== 0) {
854
- coordinates.push(itineraryCoords[i - 1]);
855
- }
856
- }
857
- coordinates.push(coords);
858
- }
859
- previousLevelCorrespond = levelCorrespond;
860
- }
861
- return segments;
862
- }
863
- const Utils = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
864
- __proto__: null,
865
- calcDistance,
866
- createSegmentsAtLevel,
867
- geolocationPositionToUserPosition,
868
- sampleRoute,
869
- simplifyRoute,
870
- trimRoute
871
- }, Symbol.toStringTag, { value: "Module" }));
872
- class BoundingBox {
873
- constructor(northEast, southWest) {
874
- __publicField(this, "northEast");
875
- __publicField(this, "southWest");
876
- this.northEast = northEast;
877
- this.southWest = southWest;
878
- if (this.northEast && this.southWest && this.getNorth() < this.getSouth()) {
879
- throw new Error("Incorrect bounding box");
880
- }
881
- }
882
- /**
883
- * Returns the geographical coordinate equidistant from the bounding box's corners.
884
- */
885
- get center() {
886
- const latCenter = (this.southWest.lat + this.northEast.lat) / 2;
887
- const lngCenter = (this.northEast.lng + this.southWest.lng) / 2;
888
- return new Coordinates(latCenter, lngCenter);
889
- }
890
- /**
891
- * Check if a point is contained in the bounding box.
892
- */
893
- contains(point) {
894
- return point.lat <= this.northEast.lat && point.lat >= this.southWest.lat && point.lng <= this.northEast.lng && point.lng >= this.southWest.lng;
895
- }
896
- /**
897
- * Extend the bounds to include a given LngLat or LngLatBounds.
898
- */
899
- extend(obj) {
900
- const sw = this.southWest, ne = this.northEast;
901
- let sw2, ne2;
902
- if (obj instanceof Coordinates) {
903
- sw2 = obj;
904
- ne2 = obj;
905
- } else if (obj instanceof BoundingBox) {
906
- sw2 = obj.southWest;
907
- ne2 = obj.northEast;
908
- } else {
909
- throw new Error("Unknown parameter");
910
- }
911
- this.southWest = new Coordinates(
912
- Math.min(sw2.lat, sw.lat),
913
- Math.min(sw2.lng, sw.lng)
914
- );
915
- this.northEast = new Coordinates(
916
- Math.max(ne2.lat, ne.lat),
917
- Math.max(ne2.lng, ne.lng)
918
- );
919
- return this;
920
- }
921
- /**
922
- * This method extends the bounding box with a value in meters
923
- * /*\ This method is not precise as distance differs in function of latitude
924
- */
925
- extendsWithMeasure(measure) {
926
- if (typeof measure !== "number") {
927
- throw new Error("measure is not a number");
928
- }
929
- this.northEast = this.northEast.destinationPoint(measure, 0).move(measure, Math.PI / 2);
930
- this.southWest = this.southWest.clone().destinationPoint(measure, -Math.PI / 2).destinationPoint(measure, Math.PI);
931
- return this;
932
- }
933
- /**
934
- * Returns bounds created by extending or retracting the current bounds by a given ratio in each direction.
935
- * For example, a ratio of 0.5 extends the bounds by 50% in each direction.
936
- * Negative values will retract the bounds.
937
- */
938
- pad(bufferRatio) {
939
- const sw = this.southWest;
940
- const ne = this.northEast;
941
- const heightBuffer = Math.abs(sw.lat - ne.lat) * bufferRatio;
942
- const widthBuffer = Math.abs(sw.lng - ne.lng) * bufferRatio;
943
- this.southWest = new Coordinates(sw.lat - heightBuffer, sw.lng - widthBuffer);
944
- this.northEast = new Coordinates(ne.lat + heightBuffer, ne.lng + widthBuffer);
945
- return this;
946
- }
947
- /**
948
- * Returns the southwest corner of the bounding box.
949
- */
950
- getSouthWest() {
951
- return this.southWest;
952
- }
953
- /**
954
- * Returns the northeast corner of the bounding box.
955
- */
956
- getNorthEast() {
957
- return this.northEast;
958
- }
959
- /**
960
- * Returns the northwest corner of the bounding box.
961
- */
962
- getNorthWest() {
963
- return new Coordinates(this.getNorth(), this.getWest());
964
- }
965
- /**
966
- * Returns the southeast corner of the bounding box.
967
- */
968
- getSouthEast() {
969
- return new Coordinates(this.getSouth(), this.getEast());
970
- }
971
- /**
972
- * Returns the west edge of the bounding box.
973
- */
974
- getWest() {
975
- return this.southWest.lng;
976
- }
977
- /**
978
- * Returns the south edge of the bounding box.
979
- */
980
- getSouth() {
981
- return this.southWest.lat;
982
- }
983
- /**
984
- * Returns the east edge of the bounding box.
985
- */
986
- getEast() {
987
- return this.northEast.lng;
988
- }
989
- /**
990
- * Returns the north edge of the bounding box.
991
- */
992
- getNorth() {
993
- return this.northEast.lat;
994
- }
995
- static equals(bb1, bb2) {
996
- return Coordinates.equals(bb1.northEast, bb2.northEast) && Coordinates.equals(bb1.southWest, bb2.southWest);
997
- }
998
- equals(other) {
999
- return BoundingBox.equals(this, other);
1000
- }
1001
- /**
1002
- * Create a BoundingBox from a WSEN array
1003
- */
1004
- static fromArray(bounds) {
1005
- return new BoundingBox(
1006
- new Coordinates(bounds[3], bounds[2]),
1007
- new Coordinates(bounds[1], bounds[0])
1008
- );
1009
- }
1010
- static fromCoordinates(coords) {
1011
- if (coords.length === 0) {
1012
- return null;
1013
- }
1014
- return coords.reduce(
1015
- (acc, _coords) => acc.extend(_coords),
1016
- new BoundingBox(coords[0], coords[0])
1017
- );
1018
- }
1019
- /**
1020
- * Returns the WSEN array
1021
- */
1022
- toArray() {
1023
- return [this.getWest(), this.getSouth(), this.getEast(), this.getNorth()];
1024
- }
1025
- }
1026
- class RelativePosition {
1027
- constructor(x, y, z, time = null, accuracy = null, bearing = null) {
1028
- __publicField(this, "x");
1029
- __publicField(this, "y");
1030
- __publicField(this, "z");
1031
- __publicField(this, "time", null);
1032
- __publicField(this, "_accuracy", null);
1033
- __publicField(this, "_bearing", null);
1034
- this.x = x;
1035
- this.y = y;
1036
- this.z = z;
1037
- this.time = time;
1038
- this.accuracy = accuracy;
1039
- this.bearing = bearing;
1040
- }
1041
- get accuracy() {
1042
- return this._accuracy;
1043
- }
1044
- set accuracy(accuracy) {
1045
- if (accuracy !== null && accuracy < 0) {
1046
- throw new Error("accuracy argument is not a positive number");
1047
- }
1048
- this._accuracy = accuracy;
1049
- }
1050
- get bearing() {
1051
- return this._bearing;
1052
- }
1053
- set bearing(bearing) {
1054
- this._bearing = bearing !== null ? bearing % (2 * Math.PI) : null;
1055
- }
1056
- clone() {
1057
- return new RelativePosition(this.x, this.y, this.z, this.time, this.accuracy, this.bearing);
1058
- }
1059
- /**
1060
- * Compares two RelativePosition
1061
- * @param {RelativePosition} pos1 position 1
1062
- * @param {RelativePosition} pos2 position 2
1063
- * @param {Number} eps x, y, z epsilon in meters (default: 1e-3 [= 1mm])
1064
- */
1065
- static equals(pos1, pos2, eps = EPS_MM) {
1066
- if (pos1 === null && pos1 === pos2) {
1067
- return true;
1068
- }
1069
- if (!(pos1 instanceof RelativePosition) || !(pos2 instanceof RelativePosition)) {
1070
- return false;
1071
- }
1072
- return Math.abs(pos2.x - pos1.x) < eps && Math.abs(pos2.y - pos1.y) < eps && Math.abs(pos2.z - pos1.z) < eps && pos1.time === pos2.time && pos1.accuracy === pos2.accuracy && pos1.bearing === pos2.bearing;
1073
- }
1074
- equals(other) {
1075
- return RelativePosition.equals(this, other);
1076
- }
1077
- toJson() {
1078
- return {
1079
- x: this.x,
1080
- y: this.y,
1081
- z: this.z,
1082
- ...this.time !== null && { time: this.time },
1083
- ...this.accuracy !== null && { accuracy: this.accuracy },
1084
- ...this.bearing !== null && { bearing: this.bearing }
1085
- };
1086
- }
1087
- static fromJson(json) {
1088
- return new RelativePosition(json.x, json.y, json.z, json.time, json.accuracy, json.bearing);
1089
- }
1090
- }
1091
- class GeoRelativePosition extends RelativePosition {
1092
- }
1093
- class GeoRef {
1094
- constructor(origin, buildingLevels = []) {
1095
- __publicField(this, "scale", 1);
1096
- __publicField(this, "heading", 0);
1097
- this.origin = origin;
1098
- this.buildingLevels = buildingLevels;
1099
- }
1100
- /**
1101
- * LocalPosition in ENU frame
1102
- */
1103
- localToWorld(localPosition) {
1104
- const enuTranslationScaled = Vector3.multiplyScalar(localPosition, this.scale);
1105
- const rotationOffset = Quaternion.fromAxisAngle([0, 0, 1], this.heading);
1106
- const enuToEcefRotationOrigin = Quaternion.multiply(rotationOffset, this.origin.enuToEcefRotation);
1107
- const ecefTranslation = Quaternion.rotate(enuToEcefRotationOrigin, enuTranslationScaled);
1108
- const ecef = Vector3.sum(this.origin.ecef, ecefTranslation);
1109
- const coordinates = Coordinates.fromECEF(ecef);
1110
- const alt = coordinates.alt;
1111
- coordinates.heightFromGround = coordinates.alt - this.origin.alt;
1112
- const updateLevelAndHeightFromFloor = (buildingLevel) => {
1113
- coordinates.level = buildingLevel.id;
1114
- coordinates.heightFromFloor = alt - buildingLevel.floorAltitude;
1115
- };
1116
- if (!this.buildingLevels.length) {
1117
- return coordinates;
1118
- }
1119
- const correspondedLevelsByAltitude = this.buildingLevels.filter(
1120
- (buildingLevel) => alt >= buildingLevel.floorAltitude && alt <= buildingLevel.ceilingAltitude
1121
- );
1122
- if (!correspondedLevelsByAltitude.length) {
1123
- return coordinates;
1124
- }
1125
- const levelByAltitude = correspondedLevelsByAltitude[0];
1126
- const geojsonPt = [coordinates.lng, coordinates.lat];
1127
- const levelsWithCoverage = correspondedLevelsByAltitude.filter((l) => l.geometries.length);
1128
- if (!levelsWithCoverage.length) {
1129
- updateLevelAndHeightFromFloor(levelByAltitude);
1130
- return coordinates;
1131
- }
1132
- const correspondedLevelsByCoverage = levelsWithCoverage.filter((l) => l.geometries.some((geom) => booleanPointInPolygon(geojsonPt, geom)));
1133
- const levelByCoverage = correspondedLevelsByCoverage[0];
1134
- if (!levelByCoverage) {
1135
- return coordinates;
1136
- }
1137
- updateLevelAndHeightFromFloor(levelByCoverage);
1138
- return coordinates;
1139
- }
1140
- /**
1141
- * LocalPosition in ENU frame
1142
- */
1143
- worldToLocal(coords) {
1144
- const rotationOffset = Quaternion.fromAxisAngle([0, 0, 1], -this.heading);
1145
- const ecefToEnuRotationOrigin = Quaternion.multiply(this.origin.ecefToEnuRotation, rotationOffset);
1146
- const ecefTranslation = Vector3.subtract(coords.ecef, this.origin.ecef);
1147
- const ecefTranslationScaled = Vector3.multiplyScalar(ecefTranslation, 1 / this.scale);
1148
- return Quaternion.rotate(ecefToEnuRotationOrigin, ecefTranslationScaled);
1149
- }
1150
- toJson() {
1151
- return {
1152
- origin: this.origin.toJson(),
1153
- ...this.scale !== 1 && { scale: this.scale },
1154
- ...this.heading !== 0 && { heading: this.heading }
1155
- };
1156
- }
1157
- static fromJson(json) {
1158
- const geoRef = new GeoRef(Coordinates.fromJson(json.origin));
1159
- geoRef.scale = typeof json.scale !== "undefined" ? json.scale : 1;
1160
- geoRef.heading = typeof json.heading !== "undefined" ? json.heading : 0;
1161
- return geoRef;
1162
- }
1163
- }
1164
- class Attitude {
1165
- constructor(quaternion, time = null, accuracy = null) {
1166
- __publicField(this, "_quaternion", [1, 0, 0, 0]);
1167
- __publicField(this, "_heading", null);
1168
- __publicField(this, "_eulerAngles", null);
1169
- __publicField(this, "_time", null);
1170
- __publicField(this, "_accuracy", null);
1171
- this.quaternion = quaternion;
1172
- this.time = time;
1173
- this.accuracy = accuracy;
1174
- }
1175
- static unitary() {
1176
- return new Attitude([1, 0, 0, 0]);
1177
- }
1178
- get quaternion() {
1179
- return this._quaternion;
1180
- }
1181
- set quaternion(quaternion) {
1182
- if (Math.abs(1 - Quaternion.norm(quaternion)) > 1e-4) {
1183
- throw new Error("quaternion is not a unit quaternion");
1184
- }
1185
- this._quaternion = quaternion;
1186
- this._heading = null;
1187
- this._eulerAngles = null;
1188
- }
1189
- get time() {
1190
- return this._time;
1191
- }
1192
- set time(time) {
1193
- this._time = time;
1194
- }
1195
- get accuracy() {
1196
- return this._accuracy;
1197
- }
1198
- set accuracy(accuracy) {
1199
- if (accuracy !== null && (accuracy < 0 || accuracy > Math.PI)) {
1200
- throw new Error("accuracy argument (" + accuracy + ") is not in range [0; PI]");
1201
- }
1202
- this._accuracy = accuracy;
1203
- }
1204
- get eulerAngles() {
1205
- if (this._eulerAngles === null) {
1206
- this._eulerAngles = Rotations.quaternionToEulerZXY(this.quaternion);
1207
- }
1208
- return this._eulerAngles;
1209
- }
1210
- get eulerAnglesDegrees() {
1211
- return this.eulerAngles.map((x) => rad2deg(x));
1212
- }
1213
- get heading() {
1214
- if (this._heading === null) {
1215
- let offset = 0;
1216
- if (typeof window !== "undefined" && window && window.orientation) {
1217
- offset = deg2rad(window.orientation);
1218
- }
1219
- this._heading = Rotations.getHeadingFromQuaternion(this.quaternion) + offset;
1220
- }
1221
- return this._heading;
1222
- }
1223
- get headingDegrees() {
1224
- return rad2deg(this.heading);
1225
- }
1226
- static equals(att1, att2) {
1227
- if (att1 === null && att1 === att2) {
1228
- return true;
1229
- }
1230
- if (!(att1 instanceof Attitude) || !(att2 instanceof Attitude)) {
1231
- return false;
1232
- }
1233
- if (att1 === att2) {
1234
- return true;
1235
- }
1236
- return Quaternion.equals(att1.quaternion, att2.quaternion);
1237
- }
1238
- equals(other) {
1239
- return Attitude.equals(this, other);
1240
- }
1241
- toJson() {
1242
- if (this.time === null && this.accuracy === null) {
1243
- return this.quaternion;
1244
- }
1245
- return {
1246
- q: this.quaternion,
1247
- ...this.time !== null && { time: this.time },
1248
- ...this.accuracy !== null && { accuracy: this.accuracy }
1249
- };
1250
- }
1251
- static fromJson(json) {
1252
- if (Array.isArray(json)) {
1253
- return new Attitude(json, null, null);
1254
- }
1255
- return new Attitude(json.q, json.time, json.accuracy);
1256
- }
1257
- clone() {
1258
- return new Attitude(this.quaternion.slice(0), this.time, this.accuracy);
1259
- }
1260
- /**
1261
- * Calculate the relative attitude between two given attitudes
1262
- */
1263
- static diff(attitudeStart, attitudeEnd) {
1264
- const quaternionDiff = Quaternion.multiply(
1265
- Quaternion.inverse(attitudeStart.quaternion),
1266
- attitudeEnd.quaternion
1267
- );
1268
- let timeDiff = null;
1269
- if (attitudeEnd.time !== null && attitudeStart.time !== null) {
1270
- timeDiff = attitudeEnd.time - attitudeStart.time;
1271
- }
1272
- let accuracyDiff = null;
1273
- if (attitudeStart.accuracy !== null && attitudeEnd.accuracy !== null) {
1274
- accuracyDiff = Math.max(attitudeEnd.accuracy - attitudeStart.accuracy);
1275
- }
1276
- return new Attitude(quaternionDiff, timeDiff, accuracyDiff);
1277
- }
1278
- }
1279
- class AbsoluteHeading {
1280
- constructor(heading, time = null, accuracy = null) {
1281
- __publicField(this, "heading");
1282
- __publicField(this, "time", null);
1283
- __publicField(this, "_accuracy", null);
1284
- this.heading = heading;
1285
- this.time = time;
1286
- this.accuracy = accuracy;
1287
- }
1288
- get accuracy() {
1289
- return this._accuracy;
1290
- }
1291
- set accuracy(accuracy) {
1292
- if (accuracy !== null && (accuracy < 0 || accuracy > Math.PI)) {
1293
- throw new Error("accuracy argument (" + accuracy + ") is not in range [0; PI]");
1294
- }
1295
- this._accuracy = accuracy;
1296
- }
1297
- toAttitude() {
1298
- return new Attitude(
1299
- Quaternion.fromAxisAngle([0, 0, 1], -this.heading),
1300
- this.time,
1301
- this.accuracy
1302
- );
1303
- }
1304
- /**
1305
- * Compares two AbsoluteHeading
1306
- * @param {AbsoluteHeading} heading1 heading 1
1307
- * @param {AbsoluteHeading} heading2 heading 2
1308
- */
1309
- static equals(heading1, heading2) {
1310
- if (heading1 === null && heading1 === heading2) {
1311
- return true;
1312
- }
1313
- if (!(heading1 instanceof AbsoluteHeading) || !(heading2 instanceof AbsoluteHeading)) {
1314
- return false;
1315
- }
1316
- return Math.abs(heading1.heading - heading2.heading) < 1e-8;
1317
- }
1318
- equals(other) {
1319
- return AbsoluteHeading.equals(this, other);
1320
- }
1321
- toJson() {
1322
- return {
1323
- heading: this.heading,
1324
- ...this.time !== null && { time: this.time },
1325
- ...this.accuracy !== null && { accuracy: this.accuracy }
1326
- };
1327
- }
1328
- static fromJson(json) {
1329
- return new AbsoluteHeading(json.heading, json.time, json.accuracy);
1330
- }
1331
- clone() {
1332
- return new AbsoluteHeading(this.heading, this.time, this.accuracy);
1333
- }
1334
- }
1335
- export {
1336
- AbsoluteHeading,
1337
- Attitude,
1338
- BoundingBox,
1339
- Constants,
1340
- Coordinates,
1341
- GeoRef,
1342
- GeoRelativePosition,
1343
- Level,
1344
- RelativePosition,
1345
- UserPosition,
1346
- Utils
1347
- };
1348
- //# sourceMappingURL=index.mjs.map