@wemap/providers 10.11.1 → 10.11.2

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 ADDED
@@ -0,0 +1,3273 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
+ var __publicField = (obj, key, value) => {
5
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
6
+ return value;
7
+ };
8
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
9
+ const geo = require("@wemap/geo");
10
+ const maths = require("@wemap/maths");
11
+ const routers = require("@wemap/routers");
12
+ const utils = require("@wemap/utils");
13
+ const Logger = require("@wemap/logger");
14
+ const geomagnetism = require("@wemap/geomagnetism");
15
+ const camera = require("@wemap/camera");
16
+ const _interopDefaultLegacy = (e) => e && typeof e === "object" && "default" in e ? e : { default: e };
17
+ const Logger__default = /* @__PURE__ */ _interopDefaultLegacy(Logger);
18
+ const geomagnetism__default = /* @__PURE__ */ _interopDefaultLegacy(geomagnetism);
19
+ class RelativeAttitude extends geo.Attitude {
20
+ }
21
+ class AbsoluteAttitude extends geo.Attitude {
22
+ }
23
+ class AbsolutePosition extends geo.UserPosition {
24
+ }
25
+ const ProvidersOptions = {
26
+ useMapMatching: true,
27
+ ignoreProviders: [],
28
+ optionalProviders: [],
29
+ stopOnError: true,
30
+ checkAvailabilityOnStart: true,
31
+ get hasPoleStar() {
32
+ return this.optionalProviders.includes("PoleStar");
33
+ }
34
+ };
35
+ class ProvidersLoggerOld {
36
+ constructor() {
37
+ __publicField(this, "_enabled", false);
38
+ __publicField(this, "currentId", 0);
39
+ __publicField(this, "objectsIdMap", /* @__PURE__ */ new WeakMap());
40
+ __publicField(this, "pushEvents", {});
41
+ __publicField(this, "pushEventsRef", {});
42
+ __publicField(this, "interval");
43
+ __publicField(this, "initDate");
44
+ }
45
+ get enabled() {
46
+ return this._enabled;
47
+ }
48
+ set enabled(_newVal) {
49
+ this._enabled = _newVal;
50
+ }
51
+ initializeInterval() {
52
+ if (this.interval) {
53
+ return;
54
+ }
55
+ this.interval = window.setInterval(() => {
56
+ for (const [key, value] of Object.entries(this.pushEvents)) {
57
+ Logger__default.default.debug("Received " + value + " notifications from " + this.pushEventsRef[Number(key)].getName() + " last second");
58
+ }
59
+ this.pushEvents = {};
60
+ this.pushEventsRef = {};
61
+ }, 1e3);
62
+ }
63
+ getObjectId(object) {
64
+ if (!this.objectsIdMap.has(object)) {
65
+ this.objectsIdMap.set(object, ++this.currentId);
66
+ }
67
+ return this.objectsIdMap.get(object);
68
+ }
69
+ addEvent(object, method) {
70
+ if (!this.enabled) {
71
+ return;
72
+ }
73
+ if (!this.initDate) {
74
+ this.initDate = Date.now();
75
+ }
76
+ this.initializeInterval();
77
+ const objectId = this.getObjectId(object);
78
+ const objectClassName = object.getName();
79
+ Logger__default.default.debug(objectClassName + "[" + objectId + "]." + method);
80
+ }
81
+ incrementNotifications(object) {
82
+ if (!this.enabled) {
83
+ return;
84
+ }
85
+ const objectId = this.getObjectId(object);
86
+ let counter = this.pushEvents[objectId];
87
+ if (!counter) {
88
+ counter = 0;
89
+ this.pushEventsRef[objectId] = object;
90
+ }
91
+ this.pushEvents[objectId] = counter + 1;
92
+ }
93
+ }
94
+ const ProvidersLoggerOld$1 = new ProvidersLoggerOld();
95
+ const _ContainsIgnoredProviderError = class extends Error {
96
+ constructor(message) {
97
+ super(message || _ContainsIgnoredProviderError.DEFAULT_MESSAGE);
98
+ }
99
+ };
100
+ let ContainsIgnoredProviderError = _ContainsIgnoredProviderError;
101
+ __publicField(ContainsIgnoredProviderError, "DEFAULT_MESSAGE", "Contains ignored provider");
102
+ const _Provider = class {
103
+ constructor() {
104
+ __publicField(this, "id");
105
+ __publicField(this, "state", "stopped");
106
+ __publicField(this, "_lastEvent", null);
107
+ __publicField(this, "_eventsCallbacks", []);
108
+ __publicField(this, "_monitoringCallbacks", []);
109
+ __publicField(this, "notify", (event) => {
110
+ ProvidersLoggerOld$1.incrementNotifications(this);
111
+ this._eventsCallbacks.forEach((cb) => {
112
+ var _a;
113
+ return (_a = cb.onEvent) == null ? void 0 : _a.call(cb, event);
114
+ });
115
+ this._lastEvent = event;
116
+ });
117
+ __publicField(this, "notifyError", (error) => {
118
+ this._eventsCallbacks.forEach(({
119
+ id,
120
+ onError
121
+ }) => {
122
+ if (ProvidersOptions.stopOnError) {
123
+ this.removeEventListener(id);
124
+ }
125
+ onError == null ? void 0 : onError(error);
126
+ });
127
+ });
128
+ this.id = _Provider._uniqueId++;
129
+ ProvidersLoggerOld$1.addEvent(this, "constructor");
130
+ }
131
+ getAvailability() {
132
+ if (ProvidersOptions.ignoreProviders.includes(this.getName())) {
133
+ return Promise.resolve(new ContainsIgnoredProviderError());
134
+ }
135
+ return this.availability();
136
+ }
137
+ get hasNativeInterface() {
138
+ return Boolean(this.nativeInterface);
139
+ }
140
+ get nativeInterface() {
141
+ return typeof window !== "undefined" && window.__nativeProviders || null;
142
+ }
143
+ get nativeJsInterface() {
144
+ if (typeof window === "undefined") {
145
+ return null;
146
+ }
147
+ if (!window.__nativeJsProviders) {
148
+ window.__nativeJsProviders = {};
149
+ }
150
+ return window.__nativeJsProviders;
151
+ }
152
+ get useCameraNatively() {
153
+ return false;
154
+ }
155
+ addEventListener(onEvent = null, onError = null, startIfNecessary = true) {
156
+ const id = ++_Provider._callbackUniqueId;
157
+ this._eventsCallbacks.push({
158
+ id,
159
+ onEvent: onEvent || (() => {
160
+ }),
161
+ onError: onError || (() => {
162
+ }),
163
+ optional: !startIfNecessary
164
+ });
165
+ if (!startIfNecessary) {
166
+ return id;
167
+ }
168
+ if (this.state !== "stopped") {
169
+ return id;
170
+ }
171
+ this.state = "starting";
172
+ let availabilityPromise = Promise.resolve();
173
+ if (ProvidersOptions.checkAvailabilityOnStart) {
174
+ availabilityPromise = this.getAvailability();
175
+ }
176
+ (async () => {
177
+ const error = await availabilityPromise;
178
+ if (error) {
179
+ this.state = "stopped";
180
+ this.notifyError(error);
181
+ return;
182
+ }
183
+ ProvidersLoggerOld$1.addEvent(this, "start");
184
+ this.start();
185
+ this.state = "started";
186
+ this._monitoringCallbacks.forEach((cb) => {
187
+ var _a;
188
+ return (_a = cb.onStarted) == null ? void 0 : _a.call(cb);
189
+ });
190
+ })();
191
+ return id;
192
+ }
193
+ removeEventListener(callbackUniqueId) {
194
+ const callback = this._eventsCallbacks.find((_callback) => _callback.id === callbackUniqueId);
195
+ if (!callback) {
196
+ return;
197
+ }
198
+ this._eventsCallbacks = this._eventsCallbacks.filter((_callback) => _callback !== callback);
199
+ if (callback.optional) {
200
+ return;
201
+ }
202
+ if (this._eventsCallbacks.find((_callback) => !_callback.optional)) {
203
+ return;
204
+ }
205
+ if (this.state === "stopped") {
206
+ return;
207
+ }
208
+ ProvidersLoggerOld$1.addEvent(this, "stop");
209
+ this.stop();
210
+ this.state = "stopped";
211
+ this._monitoringCallbacks.forEach((cb) => {
212
+ var _a;
213
+ return (_a = cb.onStopped) == null ? void 0 : _a.call(cb);
214
+ });
215
+ }
216
+ addMonitoringListener(onStarted, onStopped) {
217
+ const id = _Provider._callbackUniqueId++;
218
+ this._monitoringCallbacks.push({
219
+ id,
220
+ onStarted: onStarted || null,
221
+ onStopped: onStopped || null
222
+ });
223
+ return id;
224
+ }
225
+ removeMonitoringListener(callbackUniqueId) {
226
+ this._monitoringCallbacks = this._monitoringCallbacks.filter(
227
+ (_callback) => _callback.id !== callbackUniqueId
228
+ );
229
+ }
230
+ get lastEvent() {
231
+ return this._lastEvent;
232
+ }
233
+ };
234
+ let Provider = _Provider;
235
+ __publicField(Provider, "_callbackUniqueId", 0);
236
+ __publicField(Provider, "_uniqueId", 1);
237
+ class AvailabilityHelper {
238
+ static async every(availabilityPromises) {
239
+ for (const aPr of availabilityPromises) {
240
+ const error = await aPr;
241
+ if (error) {
242
+ return error;
243
+ }
244
+ }
245
+ return null;
246
+ }
247
+ static async some(availabilityPromises) {
248
+ let firstError;
249
+ for (const aPr of availabilityPromises) {
250
+ const error = await aPr;
251
+ if (!error) {
252
+ return null;
253
+ } else if (!firstError) {
254
+ firstError = error;
255
+ }
256
+ }
257
+ return firstError || null;
258
+ }
259
+ }
260
+ const _AskImuOnDesktopError = class extends Error {
261
+ constructor(message) {
262
+ super(message || _AskImuOnDesktopError.DEFAULT_MESSAGE);
263
+ }
264
+ };
265
+ let AskImuOnDesktopError = _AskImuOnDesktopError;
266
+ __publicField(AskImuOnDesktopError, "DEFAULT_MESSAGE", "It seems that you ask for IMU events on a desktop browser");
267
+ const _MissingSensorError = class extends Error {
268
+ constructor(message) {
269
+ super(message || _MissingSensorError.DEFAULT_MESSAGE);
270
+ }
271
+ from(fromMessage) {
272
+ this.message += " from " + fromMessage;
273
+ return this;
274
+ }
275
+ };
276
+ let MissingSensorError = _MissingSensorError;
277
+ __publicField(MissingSensorError, "DEFAULT_MESSAGE", "Impossible to retrieve events, a sensor is missing");
278
+ class MissingMagnetometerError extends MissingSensorError {
279
+ constructor(message) {
280
+ super(message);
281
+ }
282
+ }
283
+ const _GeolocationApiMissingError = class extends Error {
284
+ constructor(message) {
285
+ super(message || _GeolocationApiMissingError.DEFAULT_MESSAGE);
286
+ }
287
+ };
288
+ let GeolocationApiMissingError = _GeolocationApiMissingError;
289
+ __publicField(GeolocationApiMissingError, "DEFAULT_MESSAGE", "Geolocation api is missing");
290
+ const _GeolocationPermissionDeniedError = class extends Error {
291
+ constructor(message) {
292
+ super(message || _GeolocationPermissionDeniedError.DEFAULT_MESSAGE);
293
+ }
294
+ };
295
+ let GeolocationPermissionDeniedError = _GeolocationPermissionDeniedError;
296
+ __publicField(GeolocationPermissionDeniedError, "DEFAULT_MESSAGE", "Geolocation permission denied");
297
+ const _GeolocationPositionUnavailableError = class extends Error {
298
+ constructor(message) {
299
+ super(message || _GeolocationPositionUnavailableError.DEFAULT_MESSAGE);
300
+ }
301
+ };
302
+ let GeolocationPositionUnavailableError = _GeolocationPositionUnavailableError;
303
+ __publicField(GeolocationPositionUnavailableError, "DEFAULT_MESSAGE", "Geolocation position unavailable");
304
+ const Constants = {
305
+ DEFAULT_ALTITUDE: 1.6
306
+ };
307
+ const _GnssWifiProvider = class extends Provider {
308
+ constructor() {
309
+ super(...arguments);
310
+ __publicField(this, "geoLocationId");
311
+ __publicField(this, "getName", () => "GnssWifi");
312
+ __publicField(this, "onNewPosition", (geolocation) => {
313
+ const { coords } = geolocation;
314
+ if (!coords) {
315
+ return;
316
+ }
317
+ let bearing;
318
+ if (coords.heading) {
319
+ bearing = maths.deg2rad(coords.heading);
320
+ }
321
+ const timestamp = utils.TimeUtils.unixTimestampToPreciseTime(geolocation.timestamp) / 1e3;
322
+ const position = new geo.UserPosition(
323
+ coords.latitude,
324
+ coords.longitude,
325
+ Constants.DEFAULT_ALTITUDE,
326
+ null,
327
+ timestamp,
328
+ coords.accuracy,
329
+ bearing
330
+ );
331
+ this.notify(position);
332
+ });
333
+ __publicField(this, "onPositionError", (error) => {
334
+ Logger__default.default.warn(`[Providers] watchPosition error: [${error.code}] ${error.message}`);
335
+ let customError;
336
+ switch (error.code) {
337
+ case 1:
338
+ customError = new GeolocationPermissionDeniedError(error.message);
339
+ break;
340
+ case 2:
341
+ customError = new GeolocationPositionUnavailableError(error.message);
342
+ break;
343
+ default:
344
+ customError = new Error(error.message);
345
+ }
346
+ this.notifyError(customError);
347
+ });
348
+ }
349
+ availability() {
350
+ return typeof navigator === "object" && navigator.geolocation ? Promise.resolve() : Promise.resolve(new GeolocationApiMissingError());
351
+ }
352
+ start() {
353
+ setTimeout(() => {
354
+ this.geoLocationId = navigator.geolocation.watchPosition(
355
+ this.onNewPosition,
356
+ this.onPositionError,
357
+ _GnssWifiProvider.POSITION_OPTIONS
358
+ );
359
+ }, 150);
360
+ }
361
+ stop() {
362
+ if (typeof this.geoLocationId !== "undefined") {
363
+ navigator.geolocation.clearWatch(this.geoLocationId);
364
+ }
365
+ }
366
+ };
367
+ let GnssWifiProvider = _GnssWifiProvider;
368
+ __publicField(GnssWifiProvider, "POSITION_OPTIONS", {
369
+ enableHighAccuracy: true,
370
+ timeout: Infinity,
371
+ maximumAge: 0
372
+ });
373
+ const GnssWifiProvider$1 = new GnssWifiProvider();
374
+ const _MissingArCoreError = class extends Error {
375
+ constructor(message) {
376
+ super(message || _MissingArCoreError.DEFAULT_MESSAGE);
377
+ }
378
+ };
379
+ let MissingArCoreError = _MissingArCoreError;
380
+ __publicField(MissingArCoreError, "DEFAULT_MESSAGE", "ARCore is missing");
381
+ const _MissingNativeInterfaceError = class extends Error {
382
+ constructor(message) {
383
+ super(message || _MissingNativeInterfaceError.DEFAULT_MESSAGE);
384
+ }
385
+ };
386
+ let MissingNativeInterfaceError = _MissingNativeInterfaceError;
387
+ __publicField(MissingNativeInterfaceError, "DEFAULT_MESSAGE", "Native interface is missing. You are maybe trying to execute a code which is not available in a web browser");
388
+ const _ArCoreProvider = class extends Provider {
389
+ constructor() {
390
+ super(...arguments);
391
+ __publicField(this, "_nativeProvider");
392
+ __publicField(this, "previousPosition", [0, 0, 0]);
393
+ __publicField(this, "getName", () => "ArCore");
394
+ __publicField(this, "pullDataLoop", () => {
395
+ if (this.state === "stopped") {
396
+ return;
397
+ }
398
+ const payload = JSON.parse(this.nativeProvider.getInfo());
399
+ if (payload.length > 1) {
400
+ this.parsePayload(payload);
401
+ }
402
+ requestAnimationFrame(this.pullDataLoop);
403
+ });
404
+ }
405
+ availability() {
406
+ try {
407
+ const nativeProvider = this.nativeProvider;
408
+ if (!nativeProvider.checkAvailability()) {
409
+ return Promise.resolve(new MissingArCoreError());
410
+ }
411
+ } catch (e) {
412
+ return Promise.resolve(e);
413
+ }
414
+ return Promise.resolve();
415
+ }
416
+ start() {
417
+ var _a;
418
+ (_a = this.nativeProvider) == null ? void 0 : _a.start();
419
+ this.pullDataLoop();
420
+ }
421
+ stop() {
422
+ var _a;
423
+ (_a = this.nativeProvider) == null ? void 0 : _a.stop();
424
+ }
425
+ parsePayload(payload) {
426
+ const ref = payload[0];
427
+ let bufferIndex = 1;
428
+ let attitude, position, cameraProjection, barcode;
429
+ const time = utils.TimeUtils.preciseTime() / 1e3;
430
+ if (ref & _ArCoreProvider.Payload.Pose.ref) {
431
+ attitude = new RelativeAttitude(
432
+ payload.slice(bufferIndex, bufferIndex + 4),
433
+ time,
434
+ _ArCoreProvider.RELATIVE_ATTITUDE_DRIFT
435
+ );
436
+ const newPosition = [
437
+ payload[bufferIndex + 4],
438
+ payload[bufferIndex + 5],
439
+ payload[bufferIndex + 6]
440
+ ];
441
+ position = new geo.RelativePosition(
442
+ newPosition[0] - this.previousPosition[0],
443
+ newPosition[1] - this.previousPosition[1],
444
+ newPosition[2] - this.previousPosition[2],
445
+ time,
446
+ 1e-4
447
+ );
448
+ this.previousPosition = newPosition;
449
+ bufferIndex += _ArCoreProvider.Payload.Pose.size;
450
+ }
451
+ if (ref & _ArCoreProvider.Payload.Barcode.ref) {
452
+ barcode = payload[bufferIndex];
453
+ bufferIndex += _ArCoreProvider.Payload.Barcode.size;
454
+ }
455
+ if (ref & _ArCoreProvider.Payload.ProjMat.ref) {
456
+ cameraProjection = payload.slice(bufferIndex, bufferIndex + _ArCoreProvider.Payload.ProjMat.size);
457
+ bufferIndex += _ArCoreProvider.Payload.ProjMat.size;
458
+ }
459
+ this.notify({
460
+ relativePosition: position,
461
+ relativeAttitude: attitude,
462
+ ...barcode && { barcode },
463
+ ...cameraProjection && { cameraProjection }
464
+ });
465
+ }
466
+ get nativeProvider() {
467
+ if (!this._nativeProvider) {
468
+ if (!this.nativeInterface) {
469
+ throw new MissingNativeInterfaceError();
470
+ }
471
+ this._nativeProvider = this.nativeInterface.getArCoreProvider();
472
+ if (!this._nativeProvider) {
473
+ throw new MissingArCoreError();
474
+ }
475
+ }
476
+ return this._nativeProvider;
477
+ }
478
+ enableBarcodeScanner() {
479
+ try {
480
+ this.nativeProvider.enableBarcodeScanner();
481
+ } catch (e) {
482
+ this.notifyError(e);
483
+ }
484
+ }
485
+ disableBarcodeScanner() {
486
+ try {
487
+ this.nativeProvider.disableBarcodeScanner();
488
+ } catch (e) {
489
+ this.notifyError(e);
490
+ }
491
+ }
492
+ get useCameraNatively() {
493
+ return true;
494
+ }
495
+ };
496
+ let ArCoreProvider = _ArCoreProvider;
497
+ __publicField(ArCoreProvider, "Payload", {
498
+ Pose: {
499
+ ref: 2 ** 0,
500
+ size: 7
501
+ },
502
+ Barcode: {
503
+ ref: 2 ** 1,
504
+ size: 1
505
+ },
506
+ ProjMat: {
507
+ ref: 2 ** 2,
508
+ size: 16
509
+ },
510
+ ImageRef: {
511
+ ref: 2 ** 3,
512
+ size: 1
513
+ }
514
+ });
515
+ __publicField(ArCoreProvider, "RELATIVE_ATTITUDE_DRIFT", maths.deg2rad(3) / 60);
516
+ const ArCoreProvider$1 = new ArCoreProvider();
517
+ class GeoRelativePositionFromArCoreProvider extends Provider {
518
+ constructor() {
519
+ super(...arguments);
520
+ __publicField(this, "absoluteAttitudeProviderId");
521
+ __publicField(this, "arCoreProviderId");
522
+ __publicField(this, "absoluteAttitudeEvent");
523
+ __publicField(this, "getName", () => "GeoRelativePositionFromArCore");
524
+ __publicField(this, "onArCoreEvents", (event) => {
525
+ const relativeAttitudeEvent = event.relativeAttitude;
526
+ const relativePositionEvent = event.relativePosition;
527
+ if (relativeAttitudeEvent && relativePositionEvent && this.absoluteAttitudeEvent) {
528
+ this.compute(relativePositionEvent, relativeAttitudeEvent, this.absoluteAttitudeEvent);
529
+ }
530
+ });
531
+ }
532
+ availability() {
533
+ return AvailabilityHelper.every([
534
+ ArCoreProvider$1.getAvailability(),
535
+ AbsoluteAttitudeProvider$1.getAvailability()
536
+ ]);
537
+ }
538
+ start() {
539
+ this.arCoreProviderId = ArCoreProvider$1.addEventListener(
540
+ this.onArCoreEvents,
541
+ this.notifyError
542
+ );
543
+ this.absoluteAttitudeProviderId = AbsoluteAttitudeProvider$1.addEventListener(
544
+ (event) => this.absoluteAttitudeEvent = event,
545
+ this.notifyError
546
+ );
547
+ }
548
+ stop() {
549
+ ArCoreProvider$1.removeEventListener(this.arCoreProviderId);
550
+ AbsoluteAttitudeProvider$1.removeEventListener(this.absoluteAttitudeProviderId);
551
+ }
552
+ compute(relativePosition, relativeAttitude, absoluteAttitude) {
553
+ const rotation = absoluteAttitude.heading - relativeAttitude.heading;
554
+ const east = Math.cos(rotation) * relativePosition.x - Math.sin(rotation) * relativePosition.z;
555
+ const north = -Math.sin(rotation) * relativePosition.x - Math.cos(rotation) * relativePosition.z;
556
+ const up = relativePosition.y;
557
+ const position = new geo.GeoRelativePosition(
558
+ east,
559
+ north,
560
+ up,
561
+ relativePosition.time,
562
+ 0,
563
+ absoluteAttitude.heading
564
+ );
565
+ this.notify(position);
566
+ }
567
+ }
568
+ const GeoRelativePositionFromArCoreProvider$1 = new GeoRelativePositionFromArCoreProvider();
569
+ const DEFAULT_RELATIVE_NOISES = {
570
+ acc: 0.5,
571
+ gyr: 0.3
572
+ };
573
+ const DEFAULT_ABSOLUTE_NOISES = {
574
+ acc: 0.5,
575
+ gyr: 0.3,
576
+ yc: 2
577
+ };
578
+ class EkfAttitude {
579
+ constructor(accRef = [0, 0, 1], ycRef = [-1, 0, 0]) {
580
+ __publicField(this, "P");
581
+ __publicField(this, "accRef");
582
+ __publicField(this, "cRef");
583
+ __publicField(this, "noises");
584
+ __publicField(this, "quaternion");
585
+ this.accRef = accRef;
586
+ this.cRef = ycRef;
587
+ this.P = maths.Matrix4.fromDiagVector(Array(4).fill(0.1 ** 2));
588
+ this.quaternion = null;
589
+ this.noises = {};
590
+ this.setRelativeNoises(DEFAULT_RELATIVE_NOISES);
591
+ this.setAbsoluteNoises(DEFAULT_ABSOLUTE_NOISES);
592
+ }
593
+ setRelativeNoises(relativeNoises) {
594
+ this.noises.relative = {
595
+ acc: maths.Matrix3.diag(Array(3).fill(relativeNoises.acc ** 2)),
596
+ gyr: maths.Matrix3.diag(Array(3).fill(relativeNoises.gyr ** 2))
597
+ };
598
+ }
599
+ setAbsoluteNoises(absoluteNoises) {
600
+ this.noises.absolute = {
601
+ acc: maths.Matrix3.diag(Array(3).fill(absoluteNoises.acc ** 2)),
602
+ gyr: maths.Matrix3.diag(Array(3).fill(absoluteNoises.gyr ** 2)),
603
+ yc: maths.Matrix3.diag(Array(3).fill(absoluteNoises.yc ** 2))
604
+ };
605
+ }
606
+ tryInitialize(acc, mag) {
607
+ const accNormalized = maths.Vector3.normalize(acc);
608
+ if (mag) {
609
+ const magNormalized = maths.Vector3.normalize(mag);
610
+ const H = maths.Vector3.normalize(maths.Vector3.cross(magNormalized, accNormalized));
611
+ const M = maths.Vector3.cross(accNormalized, H);
612
+ const R = [
613
+ [H[0], M[0], accNormalized[0]],
614
+ [H[1], M[1], accNormalized[1]],
615
+ [H[2], M[2], accNormalized[2]]
616
+ ];
617
+ this.quaternion = maths.Quaternion.fromMatrix3Matlab(R);
618
+ } else {
619
+ const r = maths.Vector3.dot(accNormalized, this.accRef) + 1;
620
+ const v = maths.Vector3.cross(accNormalized, this.accRef);
621
+ let quaternion = [r, v[0], v[1], v[2]];
622
+ quaternion = maths.Quaternion.normalize(quaternion);
623
+ this.quaternion = quaternion;
624
+ }
625
+ return this.quaternion;
626
+ }
627
+ update(diffTime, acc, gyr, mag) {
628
+ if (!this.quaternion) {
629
+ return this.tryInitialize(acc, mag);
630
+ }
631
+ let q = this.quaternion;
632
+ const qArray = q;
633
+ const gyrInt = maths.Vector3.multiplyScalar(gyr, 0.5 * diffTime);
634
+ const F = this.computeC([1, gyrInt[0], gyrInt[1], gyrInt[2]]);
635
+ const qAPriori = maths.Matrix4.multiplyVector(F, q);
636
+ const E1 = maths.Matrix3.diag([qArray[0], qArray[0], qArray[0]]);
637
+ const eSkew = maths.Matrix3.skew([qArray[1], qArray[2], qArray[3]]);
638
+ const qPart = [-1 * qArray[1], -1 * qArray[2], -1 * qArray[3]];
639
+ const E = maths.Matrix.concatRow([qPart], maths.Matrix3.sum(eSkew, E1));
640
+ const Qk = maths.Matrix4.multiplyScalar(
641
+ maths.Matrix.multiply(
642
+ maths.Matrix.multiply(E, this.noises[mag ? "absolute" : "relative"].gyr),
643
+ maths.Matrix.transpose(E)
644
+ ),
645
+ (diffTime / 2) ** 2
646
+ );
647
+ const pAPriori = maths.Matrix4.sum(
648
+ maths.Matrix4.multiply(
649
+ maths.Matrix4.multiply(F, this.P),
650
+ maths.Matrix4.transpose(F)
651
+ ),
652
+ Qk
653
+ );
654
+ const accNormalized = maths.Vector3.normalize(acc);
655
+ let dz, K, H;
656
+ if (mag) {
657
+ const magNormalized = maths.Vector3.normalize(mag);
658
+ const yc = maths.Vector3.cross(accNormalized, magNormalized);
659
+ const ycNormalized = maths.Vector3.normalize(yc);
660
+ const dzYc = maths.Vector3.subtract(ycNormalized, maths.Quaternion.rotateMatlab(qAPriori, this.cRef));
661
+ const dzAcc = maths.Vector3.subtract(accNormalized, maths.Quaternion.rotateMatlab(qAPriori, this.accRef));
662
+ dz = maths.Vector.concat(dzYc, dzAcc);
663
+ const HYc = this.jacobianES(qAPriori, this.cRef);
664
+ const HAcc = this.jacobianES(qAPriori, this.accRef);
665
+ H = maths.Matrix.concatRow(HYc, HAcc);
666
+ const RYc = maths.Matrix.concatLine(this.noises.absolute.yc, maths.Matrix3.zeros);
667
+ const RAcc = maths.Matrix.concatLine(maths.Matrix3.zeros, this.noises.absolute.acc);
668
+ const R = maths.Matrix.concatRow(RYc, RAcc);
669
+ K = maths.Matrix.multiply(
670
+ maths.Matrix.multiply(pAPriori, maths.Matrix.transpose(H)),
671
+ maths.Matrix.inverse(
672
+ maths.Matrix.sum(
673
+ maths.Matrix.multiply(
674
+ maths.Matrix.multiply(H, pAPriori),
675
+ maths.Matrix.transpose(H)
676
+ ),
677
+ R
678
+ )
679
+ )
680
+ );
681
+ } else {
682
+ dz = maths.Vector3.subtract(accNormalized, maths.Quaternion.rotateMatlab(qAPriori, this.accRef));
683
+ H = this.jacobianES(qAPriori, this.accRef);
684
+ const R = this.noises.relative.acc;
685
+ K = maths.Matrix.multiply(
686
+ maths.Matrix.multiply(pAPriori, maths.Matrix.transpose(H)),
687
+ maths.Matrix3.inverse(
688
+ maths.Matrix3.sum(
689
+ maths.Matrix.multiply(
690
+ maths.Matrix.multiply(H, pAPriori),
691
+ maths.Matrix.transpose(H)
692
+ ),
693
+ R
694
+ )
695
+ )
696
+ );
697
+ }
698
+ q = maths.Quaternion.sum(
699
+ qAPriori,
700
+ maths.Matrix.multiplyVector(K, dz)
701
+ );
702
+ const P = maths.Matrix4.multiply(
703
+ maths.Matrix4.subtract(
704
+ maths.Matrix4.identity,
705
+ maths.Matrix.multiply(K, H)
706
+ ),
707
+ pAPriori
708
+ );
709
+ q = maths.Quaternion.normalize(q);
710
+ this.quaternion = q;
711
+ this.P = P;
712
+ return q;
713
+ }
714
+ computeC(b) {
715
+ return [
716
+ [b[0], -b[1], -b[2], -b[3]],
717
+ [b[1], b[0], b[3], -b[2]],
718
+ [b[2], -b[3], b[0], b[1]],
719
+ [b[3], b[2], -b[1], b[0]]
720
+ ];
721
+ }
722
+ jacobianES(q, v) {
723
+ const [qw, qx, qy, qz] = q;
724
+ const [vx, vy, vz] = v;
725
+ return [
726
+ [2 * qz * vy - 2 * qy * vz, 2 * qy * vy + 2 * qz * vz, 2 * qx * vy - 2 * qw * vz - 4 * qy * vx, 2 * qw * vy + 2 * qx * vz - 4 * qz * vx],
727
+ [2 * qx * vz - 2 * qz * vx, 2 * qw * vz - 4 * qx * vy + 2 * qy * vx, 2 * qx * vx + 2 * qz * vz, 2 * qy * vz - 2 * qw * vx - 4 * qz * vy],
728
+ [2 * qy * vx - 2 * qx * vy, 2 * qz * vx - 4 * qx * vz - 2 * qw * vy, 2 * qw * vx - 4 * qy * vz + 2 * qz * vy, 2 * qx * vx + 2 * qy * vy]
729
+ ];
730
+ }
731
+ }
732
+ class ImuProvider extends Provider {
733
+ constructor() {
734
+ super(...arguments);
735
+ __publicField(this, "getName", () => "IMU");
736
+ __publicField(this, "parseDeviceMotionEvent", (e) => {
737
+ const timestamp = e.timeStamp / 1e3;
738
+ let acc;
739
+ if (e.accelerationIncludingGravity) {
740
+ const {
741
+ x,
742
+ y,
743
+ z
744
+ } = e.accelerationIncludingGravity;
745
+ if (typeof x === "number" && typeof y === "number" && typeof z === "number") {
746
+ acc = [x, y, z];
747
+ if (utils.BrowserUtils.name === utils.Browser.SAFARI || utils.BrowserUtils.name === utils.Browser.IOS_WEBVIEW) {
748
+ acc[0] *= -1;
749
+ acc[1] *= -1;
750
+ acc[2] *= -1;
751
+ }
752
+ }
753
+ }
754
+ let gyr;
755
+ if (e.rotationRate) {
756
+ const {
757
+ alpha,
758
+ beta,
759
+ gamma
760
+ } = e.rotationRate;
761
+ if (typeof alpha === "number" && typeof beta === "number" && typeof gamma === "number") {
762
+ gyr = [maths.deg2rad(alpha), maths.deg2rad(beta), maths.deg2rad(gamma)];
763
+ }
764
+ }
765
+ if (acc || gyr) {
766
+ this.notify({
767
+ ...acc && { acceleration: { timestamp, values: acc } },
768
+ ...gyr && { angularRate: { timestamp, values: gyr } }
769
+ });
770
+ }
771
+ });
772
+ }
773
+ availability() {
774
+ return utils.BrowserUtils.isMobile ? Promise.resolve() : Promise.resolve(new AskImuOnDesktopError());
775
+ }
776
+ start() {
777
+ const subscribe = () => window.addEventListener("devicemotion", this.parseDeviceMotionEvent, true);
778
+ const requestPermission = DeviceMotionEvent.requestPermission || void 0;
779
+ if (requestPermission) {
780
+ requestPermission().then((response) => {
781
+ if (response !== "granted") {
782
+ throw new Error("Permission not granted");
783
+ }
784
+ subscribe();
785
+ }).catch(this.notifyError);
786
+ } else {
787
+ subscribe();
788
+ }
789
+ }
790
+ stop() {
791
+ window.removeEventListener("devicemotion", this.parseDeviceMotionEvent, true);
792
+ }
793
+ }
794
+ const ImuProvider$1 = new ImuProvider();
795
+ const _MissingAccelerometerError = class extends MissingSensorError {
796
+ constructor(message) {
797
+ super(message || _MissingAccelerometerError.DEFAULT_MESSAGE);
798
+ }
799
+ };
800
+ let MissingAccelerometerError = _MissingAccelerometerError;
801
+ __publicField(MissingAccelerometerError, "DEFAULT_MESSAGE", "Impossible to retrieve Acceleration data");
802
+ class AccelerometerProvider extends Provider {
803
+ constructor() {
804
+ super(...arguments);
805
+ __publicField(this, "imuProviderId");
806
+ __publicField(this, "getName", () => "Accelerometer");
807
+ __publicField(this, "availability", () => ImuProvider$1.getAvailability());
808
+ }
809
+ start() {
810
+ this.imuProviderId = ImuProvider$1.addEventListener((event) => {
811
+ event.acceleration ? this.notify(event.acceleration) : this.notifyError(new MissingAccelerometerError().from("devicemotion"));
812
+ }, this.notifyError);
813
+ }
814
+ stop() {
815
+ ImuProvider$1.removeEventListener(this.imuProviderId);
816
+ }
817
+ }
818
+ const AccelerometerProvider$1 = new AccelerometerProvider();
819
+ class MissingGyroscopeError extends MissingSensorError {
820
+ constructor(message) {
821
+ super(message || MissingSensorError.DEFAULT_MESSAGE);
822
+ }
823
+ }
824
+ __publicField(MissingGyroscopeError, "DEFAULT_MESSAGE", "Impossible to retrieve Angular Rate data");
825
+ class GyroscopeProvider extends Provider {
826
+ constructor() {
827
+ super(...arguments);
828
+ __publicField(this, "imuProviderId");
829
+ __publicField(this, "getName", () => "Gyroscope");
830
+ __publicField(this, "availability", () => ImuProvider$1.getAvailability());
831
+ }
832
+ start() {
833
+ this.imuProviderId = ImuProvider$1.addEventListener((event) => {
834
+ event.angularRate ? this.notify(event.angularRate) : this.notifyError(new MissingGyroscopeError().from("devicemotion"));
835
+ }, this.notifyError);
836
+ }
837
+ stop() {
838
+ ImuProvider$1.removeEventListener(this.imuProviderId);
839
+ }
840
+ }
841
+ const GyroscopeProvider$1 = new GyroscopeProvider();
842
+ const _RelativeAttitudeFromEkf = class extends Provider {
843
+ constructor() {
844
+ super(...arguments);
845
+ __publicField(this, "accelerometerProviderId");
846
+ __publicField(this, "ekfAttitude", new EkfAttitude());
847
+ __publicField(this, "gyroscopeEvent");
848
+ __publicField(this, "gyroscopeProviderId");
849
+ __publicField(this, "lastTimestamp", 0);
850
+ __publicField(this, "getName", () => "RelativeAttitudeFromEkf");
851
+ __publicField(this, "onAccelerometerEvent", (accelerationEvent) => {
852
+ if (!this.gyroscopeEvent) {
853
+ return;
854
+ }
855
+ const {
856
+ values: acceleration,
857
+ timestamp
858
+ } = accelerationEvent;
859
+ if (this.lastTimestamp === 0) {
860
+ this.lastTimestamp = timestamp;
861
+ return;
862
+ }
863
+ const diffTime = timestamp - this.lastTimestamp;
864
+ this.lastTimestamp = timestamp;
865
+ const quaternion = this.ekfAttitude.update(
866
+ diffTime,
867
+ acceleration,
868
+ this.gyroscopeEvent.values
869
+ );
870
+ if (quaternion) {
871
+ const attitude = new RelativeAttitude(
872
+ quaternion,
873
+ timestamp,
874
+ _RelativeAttitudeFromEkf.DEFAULT_DRIFT
875
+ );
876
+ this.notify(attitude);
877
+ }
878
+ });
879
+ }
880
+ availability() {
881
+ return AvailabilityHelper.every([
882
+ AccelerometerProvider$1.getAvailability(),
883
+ GyroscopeProvider$1.getAvailability()
884
+ ]);
885
+ }
886
+ start() {
887
+ this.accelerometerProviderId = AccelerometerProvider$1.addEventListener(
888
+ (event) => this.onAccelerometerEvent(event),
889
+ (error) => this.notifyError(error)
890
+ );
891
+ this.gyroscopeProviderId = GyroscopeProvider$1.addEventListener(
892
+ (event) => this.gyroscopeEvent = event,
893
+ (error) => this.notifyError(error)
894
+ );
895
+ }
896
+ stop() {
897
+ AccelerometerProvider$1.removeEventListener(this.accelerometerProviderId);
898
+ GyroscopeProvider$1.removeEventListener(this.gyroscopeProviderId);
899
+ }
900
+ };
901
+ let RelativeAttitudeFromEkf = _RelativeAttitudeFromEkf;
902
+ __publicField(RelativeAttitudeFromEkf, "DEFAULT_DRIFT", maths.deg2rad(5) / 60);
903
+ const RelativeAttitudeFromEkfProvider = new RelativeAttitudeFromEkf();
904
+ const _RelativeAttitudeFromBrowser = class extends Provider {
905
+ constructor() {
906
+ super(...arguments);
907
+ __publicField(this, "getName", () => "RelativeAttitudeFromBrowser");
908
+ __publicField(this, "onDeviceOrientationEvent", (e) => {
909
+ if (typeof e.alpha !== "number" || typeof e.beta !== "number" || typeof e.gamma !== "number") {
910
+ this.notifyError(new MissingSensorError().from("deviceorientation"));
911
+ return;
912
+ }
913
+ const quaternion = maths.Rotations.eulerToQuaternionZXYDegrees([e.alpha, e.beta, e.gamma]);
914
+ const attitude = new RelativeAttitude(
915
+ quaternion,
916
+ e.timeStamp / 1e3,
917
+ _RelativeAttitudeFromBrowser.DEFAULT_DRIFT
918
+ );
919
+ this.notify(attitude);
920
+ });
921
+ }
922
+ availability() {
923
+ return utils.BrowserUtils.isMobile ? Promise.resolve() : Promise.resolve(new AskImuOnDesktopError());
924
+ }
925
+ start() {
926
+ const subscribe = () => window.addEventListener("deviceorientation", this.onDeviceOrientationEvent, true);
927
+ const requestPermission = DeviceOrientationEvent.requestPermission || void 0;
928
+ if (requestPermission) {
929
+ requestPermission().then((response) => {
930
+ if (response !== "granted") {
931
+ throw new Error("Permission not granted");
932
+ }
933
+ subscribe();
934
+ }).catch((error) => this.notifyError(error));
935
+ } else {
936
+ subscribe();
937
+ }
938
+ }
939
+ stop() {
940
+ window.removeEventListener("deviceorientation", this.onDeviceOrientationEvent, true);
941
+ }
942
+ };
943
+ let RelativeAttitudeFromBrowser = _RelativeAttitudeFromBrowser;
944
+ __publicField(RelativeAttitudeFromBrowser, "DEFAULT_DRIFT", maths.deg2rad(5) / 60);
945
+ const RelativeAttitudeFromBrowser$1 = new RelativeAttitudeFromBrowser();
946
+ const _HighRotationsProvider = class extends Provider {
947
+ constructor() {
948
+ super(...arguments);
949
+ __publicField(this, "gyroscopeProviderId");
950
+ __publicField(this, "getName", () => "HighRotationsProvider");
951
+ __publicField(this, "availability", () => GyroscopeProvider$1.getAvailability());
952
+ __publicField(this, "_parseGyroscopeEvent", (gyroscopeEvent) => {
953
+ const { values, timestamp } = gyroscopeEvent;
954
+ const speed = maths.Vector3.norm(values);
955
+ if (speed > _HighRotationsProvider.THRESHOLD) {
956
+ this.notify({ timestamp });
957
+ }
958
+ });
959
+ }
960
+ start() {
961
+ this.gyroscopeProviderId = GyroscopeProvider$1.addEventListener(
962
+ this._parseGyroscopeEvent,
963
+ this.notifyError
964
+ );
965
+ }
966
+ stop() {
967
+ GyroscopeProvider$1.removeEventListener(this.gyroscopeProviderId);
968
+ }
969
+ isInProgress() {
970
+ if (!this.lastEvent || !GyroscopeProvider$1.lastEvent) {
971
+ return false;
972
+ }
973
+ const diffTime = GyroscopeProvider$1.lastEvent.timestamp - this.lastEvent.timestamp;
974
+ return diffTime < _HighRotationsProvider.DELAY_CONSIDERATION;
975
+ }
976
+ };
977
+ let HighRotationsProvider = _HighRotationsProvider;
978
+ __publicField(HighRotationsProvider, "THRESHOLD", 10);
979
+ __publicField(HighRotationsProvider, "DELAY_CONSIDERATION", 3);
980
+ const HighRotationsProvider$1 = new HighRotationsProvider();
981
+ const _RelativeAttitudeFromInertial = class extends Provider {
982
+ constructor() {
983
+ super(...arguments);
984
+ __publicField(this, "_highRotationsProviderId");
985
+ __publicField(this, "listenerId");
986
+ __publicField(this, "provider");
987
+ __publicField(this, "getName", () => "RelativeAttitudeFromInertial");
988
+ }
989
+ availability() {
990
+ return AvailabilityHelper.some([
991
+ RelativeAttitudeFromEkfProvider.getAvailability(),
992
+ RelativeAttitudeFromBrowser$1.getAvailability()
993
+ ]);
994
+ }
995
+ start() {
996
+ RelativeAttitudeFromEkfProvider.getAvailability().then((availabilityError) => {
997
+ this.provider = !availabilityError ? RelativeAttitudeFromEkfProvider : RelativeAttitudeFromBrowser$1;
998
+ this.listenerId = this.provider.addEventListener(
999
+ (event) => this._parseEvent(event),
1000
+ this.notifyError
1001
+ );
1002
+ this._highRotationsProviderId = HighRotationsProvider$1.addEventListener(
1003
+ null,
1004
+ this.notifyError
1005
+ );
1006
+ });
1007
+ }
1008
+ _parseEvent(event) {
1009
+ const relativeAttitude = event.clone();
1010
+ if (HighRotationsProvider$1.isInProgress()) {
1011
+ let accuracy = (relativeAttitude.accuracy || 0) + _RelativeAttitudeFromInertial.DEFAULT_DRIFT * 100;
1012
+ accuracy = Math.min(accuracy, Math.PI);
1013
+ relativeAttitude.accuracy = accuracy;
1014
+ }
1015
+ this.notify(relativeAttitude);
1016
+ }
1017
+ stop() {
1018
+ if (this.provider) {
1019
+ this.provider.removeEventListener(this.listenerId);
1020
+ delete this.provider;
1021
+ }
1022
+ HighRotationsProvider$1.removeEventListener(this._highRotationsProviderId);
1023
+ }
1024
+ };
1025
+ let RelativeAttitudeFromInertial = _RelativeAttitudeFromInertial;
1026
+ __publicField(RelativeAttitudeFromInertial, "DEFAULT_DRIFT", maths.deg2rad(5) / 60);
1027
+ const RelativeAttitudeFromInertialProvider = new RelativeAttitudeFromInertial();
1028
+ const _StepDetectionLadetto = class {
1029
+ constructor() {
1030
+ __publicField(this, "frequency", 0);
1031
+ __publicField(this, "lastVerticalAcc", 0);
1032
+ __publicField(this, "maxAcceleration", 0);
1033
+ __publicField(this, "lastStepTimestamp", -_StepDetectionLadetto.MIN_TIME_BETWEEN_STEPS);
1034
+ }
1035
+ compute(timestamp, linearAcc) {
1036
+ let stepDetected = false;
1037
+ const verticalAcc = linearAcc[2];
1038
+ const timeInterval = timestamp - this.lastStepTimestamp;
1039
+ const upfront = verticalAcc > this.lastVerticalAcc;
1040
+ if (upfront) {
1041
+ if (verticalAcc > this.maxAcceleration) {
1042
+ this.maxAcceleration = verticalAcc;
1043
+ }
1044
+ } else if (this.maxAcceleration > _StepDetectionLadetto.VERTICAL_ACC_POSITIVE_PEAK_THRESHOLD && timeInterval > _StepDetectionLadetto.MIN_TIME_BETWEEN_STEPS) {
1045
+ this.maxAcceleration = 0;
1046
+ const diffTime = timestamp - this.lastStepTimestamp;
1047
+ this.frequency = Math.min(Math.max(1 / diffTime, _StepDetectionLadetto.MIN_FRENQUENCY), _StepDetectionLadetto.MAX_FRENQUENCY);
1048
+ stepDetected = true;
1049
+ this.lastStepTimestamp = timestamp;
1050
+ } else {
1051
+ this.maxAcceleration = 0;
1052
+ }
1053
+ this.lastVerticalAcc = verticalAcc;
1054
+ return stepDetected;
1055
+ }
1056
+ get lastStepSize() {
1057
+ if (!this.frequency) {
1058
+ return 0;
1059
+ }
1060
+ const kParamA = 0.45;
1061
+ const kParamB = 0.2;
1062
+ return kParamA + kParamB * this.frequency;
1063
+ }
1064
+ get speed() {
1065
+ return this.lastStepTimestamp ? this.lastStepSize * this.frequency : 0;
1066
+ }
1067
+ };
1068
+ let StepDetectionLadetto = _StepDetectionLadetto;
1069
+ __publicField(StepDetectionLadetto, "MIN_TIME_BETWEEN_STEPS", 0.4);
1070
+ __publicField(StepDetectionLadetto, "MAX_FRENQUENCY", 4);
1071
+ __publicField(StepDetectionLadetto, "MIN_FRENQUENCY", 1);
1072
+ __publicField(StepDetectionLadetto, "VERTICAL_ACC_POSITIVE_PEAK_THRESHOLD", 1);
1073
+ const _StepDetectionMinMaxPeaks = class {
1074
+ constructor() {
1075
+ __publicField(this, "frequency", 0);
1076
+ __publicField(this, "lastStepTimestamp", -_StepDetectionMinMaxPeaks.MIN_TIME_BETWEEN_STEPS);
1077
+ __publicField(this, "slidingWindow", []);
1078
+ }
1079
+ compute(timestamp, linearAcc) {
1080
+ if (this.lastStepTimestamp && this.lastStepTimestamp + _StepDetectionMinMaxPeaks.MIN_TIME_BETWEEN_STEPS > timestamp) {
1081
+ return false;
1082
+ }
1083
+ let maxValue = Number.MIN_SAFE_INTEGER;
1084
+ let minValue = Number.MAX_SAFE_INTEGER;
1085
+ const windowTime = _StepDetectionMinMaxPeaks.WINDOW_TIME;
1086
+ this.slidingWindow.forEach((item, index, object) => {
1087
+ if (item.timestamp < timestamp - windowTime) {
1088
+ object.splice(index, 1);
1089
+ } else {
1090
+ maxValue = Math.max(item.verticalAcc, maxValue);
1091
+ minValue = Math.min(item.verticalAcc, minValue);
1092
+ }
1093
+ });
1094
+ this.slidingWindow.push({
1095
+ timestamp,
1096
+ verticalAcc: linearAcc[2]
1097
+ });
1098
+ if (maxValue > _StepDetectionMinMaxPeaks.VERTICAL_ACC_POSITIVE_PEAK_THRESHOLD && minValue < _StepDetectionMinMaxPeaks.VERTICAL_ACC_NEGATIVE_PEAK_THRESHOLD) {
1099
+ const timeInterval = this.lastStepTimestamp ? timestamp - this.lastStepTimestamp : 1;
1100
+ this.frequency = Math.min(Math.max(1 / timeInterval, _StepDetectionMinMaxPeaks.MIN_FRENQUENCY), _StepDetectionMinMaxPeaks.MAX_FRENQUENCY);
1101
+ this.lastStepTimestamp = timestamp;
1102
+ return true;
1103
+ }
1104
+ return false;
1105
+ }
1106
+ get lastStepSize() {
1107
+ if (!this.frequency) {
1108
+ return 0;
1109
+ }
1110
+ const kParamA = 0.45;
1111
+ const kParamB = 0.2;
1112
+ return kParamA + kParamB * this.frequency;
1113
+ }
1114
+ get speed() {
1115
+ return this.lastStepTimestamp ? this.lastStepSize * this.frequency : 0;
1116
+ }
1117
+ };
1118
+ let StepDetectionMinMaxPeaks = _StepDetectionMinMaxPeaks;
1119
+ __publicField(StepDetectionMinMaxPeaks, "WINDOW_TIME", 0.3);
1120
+ __publicField(StepDetectionMinMaxPeaks, "MIN_TIME_BETWEEN_STEPS", 0.4);
1121
+ __publicField(StepDetectionMinMaxPeaks, "MAX_FRENQUENCY", 4);
1122
+ __publicField(StepDetectionMinMaxPeaks, "MIN_FRENQUENCY", 1);
1123
+ __publicField(StepDetectionMinMaxPeaks, "VERTICAL_ACC_POSITIVE_PEAK_THRESHOLD", 1.5);
1124
+ __publicField(StepDetectionMinMaxPeaks, "VERTICAL_ACC_NEGATIVE_PEAK_THRESHOLD", -1);
1125
+ const _StepDetectionMinMaxPeaks2 = class {
1126
+ constructor() {
1127
+ __publicField(this, "frequency", 0);
1128
+ __publicField(this, "influence", 0.2);
1129
+ __publicField(this, "slidingWindow", []);
1130
+ __publicField(this, "lastStepTimestamp", -_StepDetectionMinMaxPeaks2.MIN_TIME_BETWEEN_STEPS);
1131
+ __publicField(this, "previousVerticalAcc", 0);
1132
+ }
1133
+ compute(timestamp, linearAcc, angularRate) {
1134
+ const verticalAcc = this.influence * (linearAcc[2] * 2) + (1 - this.influence) * this.previousVerticalAcc;
1135
+ this.previousVerticalAcc = verticalAcc;
1136
+ if (Math.sqrt(angularRate[0] ** 2 + angularRate[1] ** 2 + angularRate[2] ** 2) > 0.75) {
1137
+ return false;
1138
+ }
1139
+ if (this.lastStepTimestamp && this.lastStepTimestamp + _StepDetectionMinMaxPeaks2.MIN_TIME_BETWEEN_STEPS > timestamp) {
1140
+ return false;
1141
+ }
1142
+ let maxValue = Number.MIN_SAFE_INTEGER;
1143
+ let minValue = Number.MAX_SAFE_INTEGER;
1144
+ this.slidingWindow.forEach((item, index, object) => {
1145
+ if (item.timestamp < timestamp - _StepDetectionMinMaxPeaks2.WINDOW_TIME) {
1146
+ object.splice(index, 1);
1147
+ } else {
1148
+ maxValue = Math.max(item.verticalAcc, maxValue);
1149
+ minValue = Math.min(item.verticalAcc, minValue);
1150
+ }
1151
+ });
1152
+ this.slidingWindow.push({
1153
+ timestamp,
1154
+ verticalAcc
1155
+ });
1156
+ if (maxValue > _StepDetectionMinMaxPeaks2.VERTICAL_ACC_POSITIVE_PEAK_THRESHOLD && minValue < _StepDetectionMinMaxPeaks2.VERTICAL_ACC_NEGATIVE_PEAK_THRESHOLD) {
1157
+ const timeInterval = this.lastStepTimestamp ? timestamp - this.lastStepTimestamp : 1;
1158
+ this.frequency = Math.min(Math.max(1 / timeInterval, _StepDetectionMinMaxPeaks2.MIN_FRENQUENCY), _StepDetectionMinMaxPeaks2.MAX_FRENQUENCY);
1159
+ this.lastStepTimestamp = timestamp;
1160
+ return true;
1161
+ }
1162
+ return false;
1163
+ }
1164
+ get lastStepSize() {
1165
+ if (!this.frequency) {
1166
+ return 0;
1167
+ }
1168
+ const kParamA = 0.45;
1169
+ const kParamB = 0.2;
1170
+ return kParamA + kParamB * this.frequency;
1171
+ }
1172
+ get speed() {
1173
+ return this.lastStepSize && this.frequency ? this.lastStepSize * this.frequency : 0;
1174
+ }
1175
+ mean(data) {
1176
+ let sum = 0, mean = 0;
1177
+ for (let i = 0; i < data.length; ++i) {
1178
+ sum += data[i].verticalAcc;
1179
+ }
1180
+ mean = sum / data.length;
1181
+ return mean;
1182
+ }
1183
+ stddev(data) {
1184
+ const theMean = this.mean(data);
1185
+ let standardDeviation = 0;
1186
+ for (let i = 0; i < data.length; ++i) {
1187
+ standardDeviation += (data[i].verticalAcc - theMean) ** 2;
1188
+ }
1189
+ return Math.sqrt(standardDeviation / data.length);
1190
+ }
1191
+ };
1192
+ let StepDetectionMinMaxPeaks2 = _StepDetectionMinMaxPeaks2;
1193
+ __publicField(StepDetectionMinMaxPeaks2, "WINDOW_TIME", 0.3);
1194
+ __publicField(StepDetectionMinMaxPeaks2, "MIN_TIME_BETWEEN_STEPS", 0.4);
1195
+ __publicField(StepDetectionMinMaxPeaks2, "MAX_FRENQUENCY", 4);
1196
+ __publicField(StepDetectionMinMaxPeaks2, "MIN_FRENQUENCY", 1);
1197
+ __publicField(StepDetectionMinMaxPeaks2, "VERTICAL_ACC_POSITIVE_PEAK_THRESHOLD", 0.75);
1198
+ __publicField(StepDetectionMinMaxPeaks2, "VERTICAL_ACC_NEGATIVE_PEAK_THRESHOLD", -0.3);
1199
+ const _StepDetectionMinMaxPeaks3 = class {
1200
+ constructor() {
1201
+ __publicField(this, "frequency", 0);
1202
+ __publicField(this, "influence", 0.05);
1203
+ __publicField(this, "slidingWindow", []);
1204
+ __publicField(this, "lastStepTimestamp", -_StepDetectionMinMaxPeaks3.MIN_TIME_BETWEEN_STEPS);
1205
+ __publicField(this, "previousVerticalAcc", 0);
1206
+ __publicField(this, "previousHorizontalAcc", 0);
1207
+ }
1208
+ compute(timestamp, linearAcc) {
1209
+ const verticalAcc = this.influence * linearAcc[2] + (1 - this.influence) * this.previousVerticalAcc;
1210
+ this.previousVerticalAcc = verticalAcc;
1211
+ this.slidingWindow = this.slidingWindow.filter(
1212
+ (item) => item.timestamp >= timestamp - _StepDetectionMinMaxPeaks3.WINDOW_TIME
1213
+ );
1214
+ this.slidingWindow.push({ timestamp, verticalAcc });
1215
+ const isTooEarlyForANewStep = this.lastStepTimestamp && this.lastStepTimestamp + _StepDetectionMinMaxPeaks3.MIN_TIME_BETWEEN_STEPS > timestamp;
1216
+ if (isTooEarlyForANewStep) {
1217
+ return false;
1218
+ }
1219
+ let maxValue = Number.MIN_VALUE;
1220
+ let maxValueIdx = -1;
1221
+ let foundMaxPeakHigherThanThreshold = false;
1222
+ this.slidingWindow.forEach((item, idx) => {
1223
+ if (item.verticalAcc > maxValue && item.verticalAcc >= _StepDetectionMinMaxPeaks3.VERTICAL_ACC_POSITIVE_PEAK_THRESHOLD) {
1224
+ maxValue = item.verticalAcc;
1225
+ maxValueIdx = idx;
1226
+ foundMaxPeakHigherThanThreshold = true;
1227
+ }
1228
+ });
1229
+ if (!foundMaxPeakHigherThanThreshold) {
1230
+ return false;
1231
+ }
1232
+ let hasLowNegativeValueBeforeMaxPeak = false;
1233
+ let minValueBeforeMaxPeak = Number.MAX_VALUE;
1234
+ for (let i = 0; i < maxValueIdx; i++) {
1235
+ const curValue = this.slidingWindow[i].verticalAcc;
1236
+ minValueBeforeMaxPeak = Math.min(minValueBeforeMaxPeak, curValue);
1237
+ if (curValue < _StepDetectionMinMaxPeaks3.VERTICAL_ACC_NEGATIVE_PEAK_THRESHOLD) {
1238
+ hasLowNegativeValueBeforeMaxPeak = true;
1239
+ break;
1240
+ }
1241
+ }
1242
+ if (!hasLowNegativeValueBeforeMaxPeak) {
1243
+ return false;
1244
+ }
1245
+ const diffMinMax = maxValue - minValueBeforeMaxPeak;
1246
+ const targetValue = maxValue - 0.5 * diffMinMax;
1247
+ let targetValueFoundAfterMaxPeak = false;
1248
+ for (let i = maxValueIdx + 1; i < this.slidingWindow.length; i++) {
1249
+ if (this.slidingWindow[i].verticalAcc <= targetValue) {
1250
+ targetValueFoundAfterMaxPeak = true;
1251
+ break;
1252
+ }
1253
+ }
1254
+ if (!targetValueFoundAfterMaxPeak) {
1255
+ return false;
1256
+ }
1257
+ const timeInterval = this.lastStepTimestamp ? timestamp - this.lastStepTimestamp : 1;
1258
+ this.frequency = Math.min(Math.max(1 / timeInterval, _StepDetectionMinMaxPeaks3.MIN_FRENQUENCY), _StepDetectionMinMaxPeaks3.MAX_FRENQUENCY);
1259
+ this.lastStepTimestamp = timestamp;
1260
+ return true;
1261
+ }
1262
+ get lastStepSize() {
1263
+ if (!this.frequency) {
1264
+ return 0;
1265
+ }
1266
+ const kParamA = 0.45;
1267
+ const kParamB = 0.2;
1268
+ return kParamA + kParamB * this.frequency;
1269
+ }
1270
+ get speed() {
1271
+ return this.lastStepSize && this.frequency ? this.lastStepSize * this.frequency : 0;
1272
+ }
1273
+ mean(data) {
1274
+ let sum = 0, mean = 0;
1275
+ for (let i = 0; i < data.length; ++i) {
1276
+ sum += data[i];
1277
+ }
1278
+ mean = sum / data.length;
1279
+ return mean;
1280
+ }
1281
+ stddev(data) {
1282
+ const theMean = this.mean(data);
1283
+ let standardDeviation = 0;
1284
+ for (let i = 0; i < data.length; ++i) {
1285
+ standardDeviation += (data[i] - theMean) ** 2;
1286
+ }
1287
+ return Math.sqrt(standardDeviation / data.length);
1288
+ }
1289
+ };
1290
+ let StepDetectionMinMaxPeaks3 = _StepDetectionMinMaxPeaks3;
1291
+ __publicField(StepDetectionMinMaxPeaks3, "WINDOW_TIME", 0.6);
1292
+ __publicField(StepDetectionMinMaxPeaks3, "MIN_TIME_BETWEEN_STEPS", 0.6);
1293
+ __publicField(StepDetectionMinMaxPeaks3, "MAX_FRENQUENCY", 4);
1294
+ __publicField(StepDetectionMinMaxPeaks3, "MIN_FRENQUENCY", 1);
1295
+ __publicField(StepDetectionMinMaxPeaks3, "VERTICAL_ACC_POSITIVE_PEAK_THRESHOLD", 0.2);
1296
+ __publicField(StepDetectionMinMaxPeaks3, "VERTICAL_ACC_NEGATIVE_PEAK_THRESHOLD", -0.1);
1297
+ const _StepProvider = class extends Provider {
1298
+ constructor() {
1299
+ super();
1300
+ __publicField(this, "accelerometerProviderId");
1301
+ __publicField(this, "attitudeProviderId");
1302
+ __publicField(this, "gyroscopeProviderId");
1303
+ __publicField(this, "angularRateEvent");
1304
+ __publicField(this, "attitudeEvent");
1305
+ __publicField(this, "numOfSteps", 0);
1306
+ __publicField(this, "stepDetector");
1307
+ __publicField(this, "_stepSizeMultiplier", _StepProvider.DEFAULT_STEP_SIZE_MULTIPLIER);
1308
+ __publicField(this, "_algorithm", _StepProvider.DEFAULT_ALGORITHM);
1309
+ __publicField(this, "_accValues", []);
1310
+ __publicField(this, "getName", () => "StepDetector");
1311
+ this.algorithm = this._algorithm;
1312
+ }
1313
+ availability() {
1314
+ return AvailabilityHelper.every([
1315
+ AccelerometerProvider$1.getAvailability(),
1316
+ GyroscopeProvider$1.getAvailability(),
1317
+ RelativeAttitudeFromInertialProvider.getAvailability()
1318
+ ]);
1319
+ }
1320
+ start() {
1321
+ this.numOfSteps = 0;
1322
+ this.accelerometerProviderId = AccelerometerProvider$1.addEventListener(
1323
+ this.onAccelerometerEvent,
1324
+ this.notifyError
1325
+ );
1326
+ this.gyroscopeProviderId = GyroscopeProvider$1.addEventListener(
1327
+ (event) => this.angularRateEvent = event,
1328
+ this.notifyError
1329
+ );
1330
+ this.attitudeProviderId = RelativeAttitudeFromInertialProvider.addEventListener(
1331
+ (event) => this.attitudeEvent = event,
1332
+ this.notifyError
1333
+ );
1334
+ }
1335
+ stop() {
1336
+ AccelerometerProvider$1.removeEventListener(this.accelerometerProviderId);
1337
+ GyroscopeProvider$1.removeEventListener(this.gyroscopeProviderId);
1338
+ RelativeAttitudeFromInertialProvider.removeEventListener(this.attitudeProviderId);
1339
+ }
1340
+ onAccelerometerEvent(accelerationEvent) {
1341
+ if (!this.attitudeEvent || !this.angularRateEvent) {
1342
+ return;
1343
+ }
1344
+ const {
1345
+ values: acceleration,
1346
+ timestamp
1347
+ } = accelerationEvent;
1348
+ const linearAcc = _StepProvider.computeLinearAcceleration(
1349
+ this.attitudeEvent.quaternion,
1350
+ acceleration
1351
+ );
1352
+ const stepDetected = this.stepDetector.compute(timestamp, linearAcc, this.angularRateEvent.values);
1353
+ if (stepDetected) {
1354
+ const size = this.stepDetector.lastStepSize * this._stepSizeMultiplier;
1355
+ this.numOfSteps++;
1356
+ this.notify({ size, number: this.numOfSteps });
1357
+ }
1358
+ }
1359
+ static computeLinearAcceleration(quaternion, acc) {
1360
+ const linearAcc = maths.Quaternion.rotateMatlab(maths.Quaternion.inverse(quaternion), acc);
1361
+ linearAcc[2] -= geo.Constants.EARTH_GRAVITY;
1362
+ return linearAcc;
1363
+ }
1364
+ set stepSizeMultiplier(stepSizeMultiplier) {
1365
+ this._stepSizeMultiplier = stepSizeMultiplier;
1366
+ }
1367
+ get stepSizeMultiplier() {
1368
+ return this._stepSizeMultiplier;
1369
+ }
1370
+ set algorithm(algorithm) {
1371
+ switch (algorithm) {
1372
+ case "ladetto":
1373
+ this.stepDetector = new StepDetectionLadetto();
1374
+ break;
1375
+ case "minMaxPeaks":
1376
+ this.stepDetector = new StepDetectionMinMaxPeaks();
1377
+ break;
1378
+ case "minMaxPeaks2":
1379
+ this.stepDetector = new StepDetectionMinMaxPeaks2();
1380
+ break;
1381
+ case "minMaxPeaks3":
1382
+ default:
1383
+ algorithm = "minMaxPeaks3";
1384
+ this.stepDetector = new StepDetectionMinMaxPeaks3();
1385
+ break;
1386
+ }
1387
+ this._algorithm = algorithm;
1388
+ }
1389
+ get algorithm() {
1390
+ return this._algorithm;
1391
+ }
1392
+ };
1393
+ let StepProvider = _StepProvider;
1394
+ __publicField(StepProvider, "DEFAULT_STEP_SIZE_MULTIPLIER", 1);
1395
+ __publicField(StepProvider, "DEFAULT_ALGORITHM", "minMaxPeaks3");
1396
+ const StepProvider$1 = new StepProvider();
1397
+ class PdrProvider extends Provider {
1398
+ constructor() {
1399
+ super(...arguments);
1400
+ __publicField(this, "absoluteAttitudeProviderId");
1401
+ __publicField(this, "stepDetectionProviderId");
1402
+ __publicField(this, "attitudeEvent");
1403
+ __publicField(this, "misalignmentError", maths.deg2rad(3));
1404
+ __publicField(this, "getName", () => "Pdr");
1405
+ __publicField(this, "onStepEvent", (stepEvent) => {
1406
+ if (!this.attitudeEvent) {
1407
+ return;
1408
+ }
1409
+ const stepSize = stepEvent.size;
1410
+ const deviceAttitude = this.attitudeEvent;
1411
+ const deviceDirection = deviceAttitude.heading;
1412
+ const deviceDirectionAccuracy = deviceAttitude.accuracy + this.misalignmentError;
1413
+ const accuracy = stepSize / 2 * Math.sin(deviceDirectionAccuracy / 2);
1414
+ const timestamp = deviceAttitude.time;
1415
+ const position = new geo.GeoRelativePosition(
1416
+ stepSize * Math.sin(deviceDirection),
1417
+ stepSize * Math.cos(deviceDirection),
1418
+ 0,
1419
+ timestamp,
1420
+ accuracy,
1421
+ deviceDirection
1422
+ );
1423
+ this.notify(position);
1424
+ });
1425
+ }
1426
+ availability() {
1427
+ return AvailabilityHelper.every([
1428
+ StepProvider$1.getAvailability(),
1429
+ AbsoluteAttitudeProvider$1.getAvailability()
1430
+ ]);
1431
+ }
1432
+ start() {
1433
+ this.stepDetectionProviderId = StepProvider$1.addEventListener(
1434
+ this.onStepEvent,
1435
+ this.notifyError
1436
+ );
1437
+ this.absoluteAttitudeProviderId = AbsoluteAttitudeProvider$1.addEventListener(
1438
+ (event) => this.attitudeEvent = event,
1439
+ this.notifyError
1440
+ );
1441
+ }
1442
+ stop() {
1443
+ StepProvider$1.removeEventListener(this.stepDetectionProviderId);
1444
+ AbsoluteAttitudeProvider$1.removeEventListener(this.absoluteAttitudeProviderId);
1445
+ }
1446
+ }
1447
+ const PdrProvider$1 = new PdrProvider();
1448
+ class GeoRelativePositionProvider extends Provider {
1449
+ constructor() {
1450
+ super(...arguments);
1451
+ __publicField(this, "providerId");
1452
+ __publicField(this, "geoRelativeProvider");
1453
+ __publicField(this, "getName", () => "GeoRelativePosition");
1454
+ }
1455
+ availability() {
1456
+ return AvailabilityHelper.some([
1457
+ PdrProvider$1.getAvailability(),
1458
+ GeoRelativePositionFromArCoreProvider$1.getAvailability()
1459
+ ]);
1460
+ }
1461
+ async start() {
1462
+ const availabilityError = await GeoRelativePositionFromArCoreProvider$1.getAvailability();
1463
+ this.geoRelativeProvider = availabilityError ? PdrProvider$1 : GeoRelativePositionFromArCoreProvider$1;
1464
+ this.providerId = this.geoRelativeProvider.addEventListener(this.notify, this.notifyError);
1465
+ }
1466
+ stop() {
1467
+ var _a;
1468
+ (_a = this.geoRelativeProvider) == null ? void 0 : _a.removeEventListener(this.providerId);
1469
+ delete this.geoRelativeProvider;
1470
+ }
1471
+ }
1472
+ const GeoRelativePositionProvider$1 = new GeoRelativePositionProvider();
1473
+ class InclinationFromAccProvider extends Provider {
1474
+ constructor() {
1475
+ super(...arguments);
1476
+ __publicField(this, "providerId");
1477
+ __publicField(this, "getName", () => "InclinationFromAcc");
1478
+ __publicField(this, "availability", () => AccelerometerProvider$1.getAvailability());
1479
+ __publicField(this, "onAccelerometerEvent", (accelerometerEvent) => {
1480
+ const acc = accelerometerEvent.values;
1481
+ const screenOrientation = window.orientation || 0;
1482
+ const sizeAcc = Math.sqrt(acc[0] * acc[0] + acc[1] * acc[1] + acc[2] * acc[2]);
1483
+ const accNormalized = [acc[0] / sizeAcc, acc[1] / sizeAcc, acc[2] / sizeAcc];
1484
+ const q = [accNormalized[2] + 1, accNormalized[1], -accNormalized[0], 0];
1485
+ const qSize = Math.sqrt(q[0] * q[0] + q[1] * q[1] + q[2] * q[2]);
1486
+ const qNormalized = [q[0] / qSize, q[1] / qSize, q[2] / qSize, 0];
1487
+ let inclination;
1488
+ if (screenOrientation === 0) {
1489
+ inclination = Math.asin(2 * qNormalized[1] * qNormalized[0]);
1490
+ } else if (screenOrientation === 90) {
1491
+ inclination = -Math.asin(2 * qNormalized[2] * qNormalized[0]);
1492
+ } else if (screenOrientation === -90) {
1493
+ inclination = Math.asin(2 * qNormalized[2] * qNormalized[0]);
1494
+ } else {
1495
+ inclination = -Math.asin(2 * qNormalized[1] * qNormalized[0]);
1496
+ }
1497
+ this.notify(inclination);
1498
+ });
1499
+ }
1500
+ start() {
1501
+ this.providerId = AccelerometerProvider$1.addEventListener(
1502
+ this.onAccelerometerEvent,
1503
+ this.notifyError
1504
+ );
1505
+ }
1506
+ stop() {
1507
+ AccelerometerProvider$1.removeEventListener(this.providerId);
1508
+ }
1509
+ }
1510
+ const InclinationFromAccProvider$1 = new InclinationFromAccProvider();
1511
+ class InclinationFromRelativeAttitudeProvider extends Provider {
1512
+ constructor() {
1513
+ super(...arguments);
1514
+ __publicField(this, "providerId");
1515
+ __publicField(this, "getName", () => "InclinationFromRelativeAttitude");
1516
+ __publicField(this, "availability", () => RelativeAttitudeFromInertialProvider.getAvailability());
1517
+ }
1518
+ start() {
1519
+ this.providerId = RelativeAttitudeFromInertialProvider.addEventListener(
1520
+ (attitudeEvent) => {
1521
+ const inclination = this.enuQuatToInclination(attitudeEvent.quaternion);
1522
+ this.notify(inclination);
1523
+ },
1524
+ this.notifyError
1525
+ );
1526
+ }
1527
+ stop() {
1528
+ RelativeAttitudeFromInertialProvider.removeEventListener(this.providerId);
1529
+ }
1530
+ enuQuatToInclination(q) {
1531
+ const screenOrientation = window.orientation || 0;
1532
+ if (screenOrientation === 0) {
1533
+ return Math.asin(2 * (q[2] * q[3] + q[1] * q[0]));
1534
+ } else if (screenOrientation === 90) {
1535
+ return Math.asin(2 * (q[1] * q[3] - q[2] * q[0]));
1536
+ } else if (screenOrientation === -90) {
1537
+ return Math.asin(2 * (q[2] * q[0] - q[1] * q[3]));
1538
+ }
1539
+ return -Math.asin(2 * (q[2] * q[3] + q[1] * q[0]));
1540
+ }
1541
+ }
1542
+ const InclinationFromRelativeAttitudeProvider$1 = new InclinationFromRelativeAttitudeProvider();
1543
+ class InclinationProvider extends Provider {
1544
+ constructor() {
1545
+ super(...arguments);
1546
+ __publicField(this, "provider");
1547
+ __publicField(this, "providerId");
1548
+ __publicField(this, "getName", () => "Inclination");
1549
+ }
1550
+ availability() {
1551
+ return AvailabilityHelper.some([
1552
+ InclinationFromAccProvider$1.getAvailability(),
1553
+ InclinationFromRelativeAttitudeProvider$1.getAvailability()
1554
+ ]);
1555
+ }
1556
+ async start() {
1557
+ const startInclinationFromAcc = () => {
1558
+ this.provider = InclinationFromAccProvider$1;
1559
+ this.providerId = this.provider.addEventListener(
1560
+ this.notify,
1561
+ this.notifyError
1562
+ );
1563
+ };
1564
+ if (await InclinationFromRelativeAttitudeProvider$1.getAvailability()) {
1565
+ this.provider = InclinationFromRelativeAttitudeProvider$1;
1566
+ this.providerId = this.provider.addEventListener(
1567
+ this.notify,
1568
+ () => {
1569
+ InclinationFromRelativeAttitudeProvider$1.removeEventListener(this.providerId);
1570
+ startInclinationFromAcc();
1571
+ }
1572
+ );
1573
+ } else {
1574
+ startInclinationFromAcc();
1575
+ }
1576
+ }
1577
+ stop() {
1578
+ if (this.provider) {
1579
+ this.provider.removeEventListener(this.providerId);
1580
+ }
1581
+ }
1582
+ }
1583
+ const InclinationProvider$1 = new InclinationProvider();
1584
+ class VpsMetadata {
1585
+ constructor(size, calibration = null, coarse = null, device = null) {
1586
+ this.size = size;
1587
+ this.calibration = calibration;
1588
+ this.coarse = coarse;
1589
+ this.device = device;
1590
+ }
1591
+ toJson() {
1592
+ return {
1593
+ size: [this.size.width, this.size.height],
1594
+ ...this.calibration && { calibration: this.calibration },
1595
+ ...this.coarse && {
1596
+ coarse: {
1597
+ ...this.coarse.attitude && { attitude: this.coarse.attitude.toJson() },
1598
+ ...this.coarse.position && { position: this.coarse.position.toJson() }
1599
+ }
1600
+ },
1601
+ ...typeof this.device === "object" && { device: this.device }
1602
+ };
1603
+ }
1604
+ static fromJson(json) {
1605
+ var _a, _b;
1606
+ return new VpsMetadata(
1607
+ {
1608
+ width: json.size[0],
1609
+ height: json.size[1]
1610
+ },
1611
+ json.calibration,
1612
+ {
1613
+ ...((_a = json.coarse) == null ? void 0 : _a.position) && { position: geo.UserPosition.fromJson(json.coarse.position) },
1614
+ ...((_b = json.coarse) == null ? void 0 : _b.attitude) && { attitude: geo.Attitude.fromJson(json.coarse.attitude) }
1615
+ },
1616
+ json.device
1617
+ );
1618
+ }
1619
+ }
1620
+ class VpsRequest {
1621
+ constructor(metadata, image) {
1622
+ this.metadata = metadata;
1623
+ this.image = image;
1624
+ }
1625
+ toJson() {
1626
+ const base64Image = camera.canvasToBase64(this.image);
1627
+ return {
1628
+ image: base64Image,
1629
+ ...this.metadata.toJson()
1630
+ };
1631
+ }
1632
+ static fromJson(json) {
1633
+ return new VpsRequest(
1634
+ VpsMetadata.fromJson(json),
1635
+ camera.base64ToCanvas(json.image)
1636
+ );
1637
+ }
1638
+ }
1639
+ class VpsResponse {
1640
+ constructor(success, attitude = null, position = null) {
1641
+ this.success = success;
1642
+ this.attitude = attitude;
1643
+ this.position = position;
1644
+ }
1645
+ toJson() {
1646
+ var _a, _b;
1647
+ return {
1648
+ success: this.success,
1649
+ attitude: (_a = this.attitude) == null ? void 0 : _a.toJson(),
1650
+ position: (_b = this.position) == null ? void 0 : _b.toJson()
1651
+ };
1652
+ }
1653
+ static fromJson(json, imageRecordTime = null) {
1654
+ let attitude = null;
1655
+ if (json.attitude) {
1656
+ attitude = geo.Attitude.fromJson(json.attitude);
1657
+ attitude.time = imageRecordTime;
1658
+ }
1659
+ let position = null;
1660
+ if (json.position) {
1661
+ position = geo.UserPosition.fromJson(json.position);
1662
+ position.time = imageRecordTime;
1663
+ }
1664
+ return new VpsResponse(json.success, attitude, position);
1665
+ }
1666
+ }
1667
+ class ImageRelocalization {
1668
+ static _prepareRequest(imageCanvas, calibration = null, coarsePose = null) {
1669
+ camera.convertToGrayscale(imageCanvas);
1670
+ const reducedImage = camera.reduceImageSize(imageCanvas, 1280);
1671
+ const metadata = new VpsMetadata(
1672
+ { width: reducedImage.width, height: reducedImage.height },
1673
+ calibration,
1674
+ coarsePose,
1675
+ utils.UserAgentUtils.getDeviceFromUserAgent()
1676
+ );
1677
+ return new VpsRequest(metadata, reducedImage);
1678
+ }
1679
+ static async relocalize(endpointUrl, imageCanvas, calibration = null, coarsePose = null, customHeaders = null) {
1680
+ const timeBeforeRequest = utils.TimeUtils.preciseTime() / 1e3;
1681
+ const vpsRequest = this._prepareRequest(imageCanvas, calibration, coarsePose);
1682
+ let serverResponse;
1683
+ try {
1684
+ const body = JSON.stringify(vpsRequest.toJson());
1685
+ Logger__default.default.debug(`[VPS] Request (${(body.length / 1024).toFixed(0)} kB) sent to server ${endpointUrl}`);
1686
+ serverResponse = await fetch(endpointUrl, {
1687
+ method: "POST",
1688
+ body,
1689
+ headers: Object.assign(
1690
+ { "Content-Type": "application/json", "Accept": "application/json" },
1691
+ customHeaders ? customHeaders : {}
1692
+ )
1693
+ });
1694
+ } catch (e) {
1695
+ Logger__default.default.debug("[VPS] Server respond error");
1696
+ return null;
1697
+ }
1698
+ if (serverResponse.status !== 200) {
1699
+ Logger__default.default.debug("[VPS] Server respond error");
1700
+ return null;
1701
+ }
1702
+ const json = await serverResponse.json();
1703
+ const res = VpsResponse.fromJson(json, timeBeforeRequest);
1704
+ Logger__default.default.debug(`[VPS] Server respond ${res.success ? "success" : "not found"}`);
1705
+ return res;
1706
+ }
1707
+ static getHeadingFromQuaternion(quaternion) {
1708
+ const [qw, qx, qy, qz] = quaternion;
1709
+ const s = Math.sqrt(2) / 2;
1710
+ const C = [s * (qw - qx), s * (qw + qx), s * (qy + qz), s * (qz - qy)];
1711
+ return -Math.atan2(2 * C[3] * C[0] - 2 * C[2] * C[1], 1 - 2 * C[1] ** 2 - 2 * C[3] ** 2);
1712
+ }
1713
+ }
1714
+ class RelativeRotationCalc {
1715
+ constructor() {
1716
+ __publicField(this, "_providerId");
1717
+ __publicField(this, "_isRunning", false);
1718
+ __publicField(this, "_dataOnStart", null);
1719
+ }
1720
+ tickStart() {
1721
+ this._dataOnStart = null;
1722
+ if (this._isRunning) {
1723
+ return;
1724
+ }
1725
+ this._isRunning = true;
1726
+ this._providerId = RelativeAttitudeFromBrowser$1.addEventListener((event) => {
1727
+ if (!this._dataOnStart) {
1728
+ this._dataOnStart = event;
1729
+ }
1730
+ });
1731
+ }
1732
+ tickEnd() {
1733
+ if (!this._isRunning) {
1734
+ Logger__default.default.warn("You have to call tickStart before tickEnd");
1735
+ return null;
1736
+ }
1737
+ this._internalStop();
1738
+ if (!this._dataOnStart) {
1739
+ Logger__default.default.warn("Delay was too short between tickStart and tickEnd or RelativeAttitudeProvider cannot be retrieved.");
1740
+ return null;
1741
+ }
1742
+ const dataOnEnd = RelativeAttitudeFromBrowser$1.lastEvent;
1743
+ return geo.Attitude.diff(this._dataOnStart, dataOnEnd);
1744
+ }
1745
+ _internalStop() {
1746
+ RelativeAttitudeFromBrowser$1.removeEventListener(this._providerId);
1747
+ delete this._providerId;
1748
+ this._isRunning = false;
1749
+ }
1750
+ release() {
1751
+ if (this._isRunning) {
1752
+ this._internalStop();
1753
+ }
1754
+ }
1755
+ }
1756
+ const _MissingPoleStarError = class extends Error {
1757
+ constructor(message) {
1758
+ super(message || _MissingPoleStarError.DEFAULT_MESSAGE);
1759
+ }
1760
+ };
1761
+ let MissingPoleStarError = _MissingPoleStarError;
1762
+ __publicField(MissingPoleStarError, "DEFAULT_MESSAGE", "PoleStar is missing");
1763
+ class PoleStarProvider extends Provider {
1764
+ constructor() {
1765
+ super();
1766
+ __publicField(this, "getName", () => "PoleStar");
1767
+ this.addMethodsToNativeJsProvider();
1768
+ }
1769
+ availability() {
1770
+ try {
1771
+ this.nativeProvider.checkAvailability();
1772
+ return Promise.resolve();
1773
+ } catch (e) {
1774
+ return Promise.resolve(e);
1775
+ }
1776
+ }
1777
+ setApiKey(apiKey) {
1778
+ this.nativeProvider.setApiKey(apiKey);
1779
+ }
1780
+ start() {
1781
+ this.nativeProvider.start();
1782
+ }
1783
+ stop() {
1784
+ this.nativeProvider.stop();
1785
+ }
1786
+ get nativeProvider() {
1787
+ if (!this.nativeInterface) {
1788
+ throw new MissingNativeInterfaceError();
1789
+ }
1790
+ const nativeProvider = this.nativeInterface.getPoleStarProvider();
1791
+ if (!nativeProvider) {
1792
+ throw new MissingPoleStarError();
1793
+ }
1794
+ return nativeProvider;
1795
+ }
1796
+ addMethodsToNativeJsProvider() {
1797
+ if (!this.nativeJsInterface) {
1798
+ return;
1799
+ }
1800
+ this.nativeJsInterface.polestar = {
1801
+ callbackError: (errorMessage) => this.notifyError(new Error(errorMessage)),
1802
+ callbackPosition: (jsonString) => {
1803
+ const json = JSON.parse(jsonString);
1804
+ const timestamp = utils.TimeUtils.unixTimestampToPreciseTime(json.time) / 1e3;
1805
+ const position = new AbsolutePosition(
1806
+ json.lat,
1807
+ json.lng,
1808
+ Constants.DEFAULT_ALTITUDE,
1809
+ json.alt / 5,
1810
+ timestamp,
1811
+ json.accuracy,
1812
+ maths.deg2rad(json.bearing)
1813
+ );
1814
+ this.notify(position);
1815
+ }
1816
+ };
1817
+ }
1818
+ }
1819
+ const PoleStarProvider$1 = new PoleStarProvider();
1820
+ const _VpsProvider = class extends Provider {
1821
+ constructor() {
1822
+ super(...arguments);
1823
+ __publicField(this, "_relativeRotationCalc");
1824
+ __publicField(this, "_serverError", false);
1825
+ __publicField(this, "_cameraError", false);
1826
+ __publicField(this, "_camera", null);
1827
+ __publicField(this, "_endpoint", null);
1828
+ __publicField(this, "_inclinationProviderId");
1829
+ __publicField(this, "_minInclinationForRequest", _VpsProvider.DEFAULT_MIN_INCLINATION_FOR_REQUEST);
1830
+ __publicField(this, "_waitTimeMinInclinationForRequest", _VpsProvider.DEFAULT_WAIT_TIME_MIN_INCLINATION_FOR_REQUEST);
1831
+ __publicField(this, "_useCoarsePose", _VpsProvider.DEFAULT_USE_COARSE_POSE);
1832
+ __publicField(this, "getName", () => "Vps");
1833
+ __publicField(this, "availability", () => camera.Camera.checkAvailability());
1834
+ __publicField(this, "_onCameraDetected", ({ camera: camera2 }) => {
1835
+ if (this._camera) {
1836
+ Logger__default.default.warn("It seems that more than 1 camera has been detected for VPS. Taking the first...");
1837
+ }
1838
+ this._useCamera(camera2);
1839
+ });
1840
+ __publicField(this, "_onCameraRemoved", () => {
1841
+ if (this._camera) {
1842
+ this._camera.off("started", this._internalStart);
1843
+ this._camera.off("stopped", this._internalStop);
1844
+ } else {
1845
+ Logger__default.default.warn("There is no previously detected camera but once has stopped");
1846
+ }
1847
+ this._camera = null;
1848
+ });
1849
+ __publicField(this, "_internalStart", async () => {
1850
+ var _a, _b;
1851
+ if (!this._endpoint) {
1852
+ this.notifyError(new Error("VPS endpoint has not been set before calling start()"));
1853
+ return;
1854
+ }
1855
+ let lastRequestTime = null;
1856
+ const isProviderStopped = () => this.state === "stopped";
1857
+ while (!isProviderStopped()) {
1858
+ if (lastRequestTime !== null) {
1859
+ const diffTime = utils.TimeUtils.preciseTime() - lastRequestTime;
1860
+ const timeToWait = Math.max(0, _VpsProvider.MIN_TIME_BETWEEN_TWO_REQUESTS - diffTime);
1861
+ await new Promise((resolve) => setTimeout(resolve, timeToWait));
1862
+ }
1863
+ lastRequestTime = utils.TimeUtils.preciseTime();
1864
+ if (isProviderStopped() || !this._camera || this._camera.state !== "started") {
1865
+ break;
1866
+ }
1867
+ const inclination = InclinationProvider$1.lastEvent ? InclinationProvider$1.lastEvent : null;
1868
+ if (inclination !== null && inclination < this._minInclinationForRequest) {
1869
+ await new Promise((resolve) => setTimeout(resolve, this._waitTimeMinInclinationForRequest));
1870
+ continue;
1871
+ }
1872
+ (_a = this._relativeRotationCalc) == null ? void 0 : _a.tickStart();
1873
+ const image = await this._camera.currentImage;
1874
+ if (!image) {
1875
+ continue;
1876
+ }
1877
+ let coarsePose = null;
1878
+ const bestCoarsePosition = AbsolutePositionProvider$1.getBestPositionEvent(GnssWifiProvider$1.lastEvent, PoleStarProvider$1.lastEvent);
1879
+ if (this._useCoarsePose && (bestCoarsePosition || AbsoluteAttitudeProvider$1.lastEvent)) {
1880
+ coarsePose = {
1881
+ ...bestCoarsePosition && { position: bestCoarsePosition },
1882
+ ...AbsoluteAttitudeProvider$1.lastEvent && { attitude: AbsoluteAttitudeProvider$1.lastEvent }
1883
+ };
1884
+ }
1885
+ const res = await ImageRelocalization.relocalize(this._endpoint, image, null, coarsePose);
1886
+ if (!res || !res.success) {
1887
+ continue;
1888
+ }
1889
+ const enuToCameraRot = res.attitude.quaternion;
1890
+ const enuToSmartphoneRot = maths.Quaternion.multiply(
1891
+ enuToCameraRot,
1892
+ _VpsProvider.CAMERA_TO_SMARTPHONE_ROT
1893
+ );
1894
+ const deviceQuaternion = maths.Quaternion.multiply(
1895
+ maths.Quaternion.fromAxisAngle([0, 0, 1], maths.deg2rad(window.orientation || 0)),
1896
+ enuToSmartphoneRot
1897
+ );
1898
+ const diffAttitude = ((_b = this._relativeRotationCalc) == null ? void 0 : _b.tickEnd()) || new geo.Attitude([1, 0, 0, 0]);
1899
+ const deviceQuaternionWithRelOffset = maths.Quaternion.multiply(
1900
+ deviceQuaternion,
1901
+ diffAttitude.quaternion
1902
+ );
1903
+ const attitude = new AbsoluteAttitude(
1904
+ deviceQuaternionWithRelOffset,
1905
+ res.attitude.time,
1906
+ res.attitude.accuracy
1907
+ );
1908
+ const devicePosition = res.position.clone();
1909
+ if (devicePosition.accuracy === null) {
1910
+ devicePosition.accuracy = 5;
1911
+ }
1912
+ if (isProviderStopped()) {
1913
+ break;
1914
+ }
1915
+ this.notify({
1916
+ absoluteAttitude: attitude,
1917
+ absolutePosition: devicePosition
1918
+ });
1919
+ }
1920
+ });
1921
+ __publicField(this, "_internalStop", () => {
1922
+ });
1923
+ }
1924
+ start() {
1925
+ this._inclinationProviderId = InclinationProvider$1.addEventListener();
1926
+ this._relativeRotationCalc = new RelativeRotationCalc();
1927
+ camera.SharedCameras.on("added", this._onCameraDetected);
1928
+ camera.SharedCameras.on("removed", this._onCameraRemoved);
1929
+ if (camera.SharedCameras.list.length) {
1930
+ if (camera.SharedCameras.list.length > 1) {
1931
+ Logger__default.default.warn("It seems that more than 1 camera has been detected for VPS. Taking the first...");
1932
+ }
1933
+ this._useCamera(camera.SharedCameras.list[0].camera);
1934
+ }
1935
+ }
1936
+ stop() {
1937
+ var _a;
1938
+ InclinationProvider$1.removeEventListener(this._inclinationProviderId);
1939
+ (_a = this._relativeRotationCalc) == null ? void 0 : _a.release();
1940
+ camera.SharedCameras.off("added", this._onCameraDetected);
1941
+ camera.SharedCameras.off("removed", this._onCameraRemoved);
1942
+ this._camera = null;
1943
+ }
1944
+ _useCamera(camera2) {
1945
+ this._camera = camera2;
1946
+ camera2.on("started", this._internalStart);
1947
+ camera2.on("stopped", this._internalStop);
1948
+ if (camera2.state === "started") {
1949
+ this._internalStart();
1950
+ }
1951
+ }
1952
+ get endpoint() {
1953
+ return this._endpoint;
1954
+ }
1955
+ set endpoint(endpoint) {
1956
+ this._endpoint = endpoint;
1957
+ }
1958
+ get minInclinationForRequest() {
1959
+ return this._minInclinationForRequest;
1960
+ }
1961
+ set minInclinationForRequest(minInclinationForRequest) {
1962
+ this._minInclinationForRequest = minInclinationForRequest;
1963
+ }
1964
+ get waitTimeMinInclinationForRequest() {
1965
+ return this._waitTimeMinInclinationForRequest;
1966
+ }
1967
+ set waitTimeMinInclinationForRequest(waitTimeMinInclinationForRequest) {
1968
+ this._waitTimeMinInclinationForRequest = waitTimeMinInclinationForRequest;
1969
+ }
1970
+ get useCoarsePose() {
1971
+ return this._useCoarsePose;
1972
+ }
1973
+ set useCoarsePose(useCoarsePose) {
1974
+ this._useCoarsePose = useCoarsePose;
1975
+ }
1976
+ };
1977
+ let VpsProvider = _VpsProvider;
1978
+ __publicField(VpsProvider, "MIN_TIME_BETWEEN_TWO_REQUESTS", 1e3);
1979
+ __publicField(VpsProvider, "DEFAULT_MIN_INCLINATION_FOR_REQUEST", maths.deg2rad(60));
1980
+ __publicField(VpsProvider, "DEFAULT_WAIT_TIME_MIN_INCLINATION_FOR_REQUEST", 200);
1981
+ __publicField(VpsProvider, "DEFAULT_USE_COARSE_POSE", true);
1982
+ __publicField(VpsProvider, "CAMERA_TO_SMARTPHONE_ROT", maths.Quaternion.fromAxisAngle([1, 0, 0], Math.PI));
1983
+ const VpsProvider$1 = new VpsProvider();
1984
+ const _AbsolutePositionProvider = class extends Provider {
1985
+ constructor() {
1986
+ super(...arguments);
1987
+ __publicField(this, "_polestarProviderId");
1988
+ __publicField(this, "_vpsProviderId");
1989
+ __publicField(this, "_gnssWifiProviderId");
1990
+ __publicField(this, "_relativePositionProviderId");
1991
+ __publicField(this, "_mapMatchingHandlerId");
1992
+ __publicField(this, "useAllAbsolutePositions", false);
1993
+ __publicField(this, "_waitUntilNextVpsPosition", false);
1994
+ __publicField(this, "_lastPolestarFix", null);
1995
+ __publicField(this, "getName", () => "AbsolutePosition");
1996
+ }
1997
+ availability() {
1998
+ return AvailabilityHelper.some([
1999
+ GeoRelativePositionProvider$1.getAvailability(),
2000
+ GnssWifiProvider$1.getAvailability(),
2001
+ ...ProvidersOptions.hasPoleStar ? [PoleStarProvider$1.getAvailability()] : [],
2002
+ VpsProvider$1.getAvailability()
2003
+ ]);
2004
+ }
2005
+ start() {
2006
+ GeoRelativePositionProvider$1.getAvailability().then((error) => {
2007
+ if (!error) {
2008
+ this._relativePositionProviderId = GeoRelativePositionProvider$1.addEventListener(this._onRelativePosition);
2009
+ }
2010
+ });
2011
+ this._gnssWifiProviderId = GnssWifiProvider$1.addEventListener(
2012
+ (event) => {
2013
+ const clone = event.clone();
2014
+ clone.bearing = null;
2015
+ this._onAbsolutePosition(clone, false);
2016
+ }
2017
+ );
2018
+ this._vpsProviderId = VpsProvider$1.addEventListener(
2019
+ (event) => this._onAbsolutePosition(event.absolutePosition),
2020
+ this.notifyError,
2021
+ false
2022
+ );
2023
+ if (ProvidersOptions.hasPoleStar) {
2024
+ this._polestarProviderId = PoleStarProvider$1.addEventListener((polestarPositionEvent) => {
2025
+ var _a;
2026
+ this._lastPolestarFix = utils.TimeUtils.preciseTime();
2027
+ const psPositionUsed = this._onAbsolutePosition(polestarPositionEvent);
2028
+ if (!psPositionUsed && ((_a = this.lastEvent) == null ? void 0 : _a.level) === null) {
2029
+ const lastPositionWithLevel = this.lastEvent.clone();
2030
+ lastPositionWithLevel.level = polestarPositionEvent.level;
2031
+ this.notify(lastPositionWithLevel);
2032
+ }
2033
+ });
2034
+ }
2035
+ this._mapMatchingHandlerId = MapMatchingHandler$1.addEventListener();
2036
+ }
2037
+ stop() {
2038
+ if (this._relativePositionProviderId) {
2039
+ GeoRelativePositionProvider$1.removeEventListener(this._relativePositionProviderId);
2040
+ delete this._relativePositionProviderId;
2041
+ }
2042
+ if (this._gnssWifiProviderId) {
2043
+ GnssWifiProvider$1.removeEventListener(this._gnssWifiProviderId);
2044
+ delete this._gnssWifiProviderId;
2045
+ }
2046
+ if (this._vpsProviderId) {
2047
+ VpsProvider$1.removeEventListener(this._vpsProviderId);
2048
+ delete this._vpsProviderId;
2049
+ }
2050
+ if (this._polestarProviderId) {
2051
+ PoleStarProvider$1.removeEventListener(this._polestarProviderId);
2052
+ delete this._polestarProviderId;
2053
+ }
2054
+ MapMatchingHandler$1.removeEventListener(this._mapMatchingHandlerId);
2055
+ }
2056
+ _shouldTakeIntoAccountNewAbsolutePosition(newPositionEvent, canContainLevel = true) {
2057
+ const newPosition = newPositionEvent;
2058
+ const lastPosition = this.lastEvent || null;
2059
+ if (!lastPosition) {
2060
+ return true;
2061
+ }
2062
+ const isBetterEnough = newPosition.accuracy * _AbsolutePositionProvider.ACCURACY_RELOC_RATIO <= lastPosition.accuracy;
2063
+ if (isBetterEnough) {
2064
+ return true;
2065
+ }
2066
+ const isFarEnough = lastPosition.distanceTo(newPosition) > lastPosition.accuracy + newPosition.accuracy;
2067
+ if (isFarEnough) {
2068
+ return true;
2069
+ }
2070
+ const isFarEnoughAndAccuracyIsBetter = isFarEnough && newPosition.accuracy <= lastPosition.accuracy;
2071
+ if (isBetterEnough && isFarEnoughAndAccuracyIsBetter) {
2072
+ return true;
2073
+ }
2074
+ const isChangingLevel = canContainLevel && !geo.Level.equals(newPosition.level, lastPosition.level);
2075
+ if (isChangingLevel) {
2076
+ return true;
2077
+ }
2078
+ return false;
2079
+ }
2080
+ _onAbsolutePosition(positionEvent, canContainLevel = true) {
2081
+ if (!this._shouldTakeIntoAccountNewAbsolutePosition(positionEvent, canContainLevel) && !this.useAllAbsolutePositions) {
2082
+ return false;
2083
+ }
2084
+ const newPosition = positionEvent.clone();
2085
+ const lastPosition = this.lastEvent ? this.lastEvent : null;
2086
+ if (lastPosition) {
2087
+ if (!canContainLevel) {
2088
+ newPosition.level = lastPosition.level;
2089
+ }
2090
+ if (newPosition.bearing === null) {
2091
+ newPosition.bearing = lastPosition.bearing;
2092
+ }
2093
+ }
2094
+ if (!MapMatchingHandler$1.canUseMapMatching()) {
2095
+ this.notify(newPosition);
2096
+ return true;
2097
+ }
2098
+ return MapMatchingHandler$1.notifyPositionFromAbsolute(newPosition);
2099
+ }
2100
+ _onRelativePosition(relativeEvent) {
2101
+ if (!this.lastEvent || this._waitUntilNextVpsPosition) {
2102
+ return false;
2103
+ }
2104
+ const lastPosition = this.lastEvent;
2105
+ const offsetPos = relativeEvent;
2106
+ const dist = Math.sqrt(offsetPos.x ** 2 + offsetPos.y ** 2);
2107
+ const bearing = Math.atan2(offsetPos.x, offsetPos.y);
2108
+ const alt = lastPosition.alt !== null ? offsetPos.z : null;
2109
+ const newPosition = lastPosition.destinationPoint(dist, bearing, alt);
2110
+ newPosition.bearing = offsetPos.bearing;
2111
+ newPosition.time = offsetPos.time;
2112
+ newPosition.accuracy += offsetPos.accuracy;
2113
+ if (!MapMatchingHandler$1.canUseMapMatching()) {
2114
+ this.notify(newPosition);
2115
+ return true;
2116
+ }
2117
+ return MapMatchingHandler$1.notifyPositionFromRelative(newPosition);
2118
+ }
2119
+ feed(data) {
2120
+ let newPositionEvent;
2121
+ if (data instanceof geo.UserPosition) {
2122
+ if (data.time === null) {
2123
+ throw Error("the time of the position is not defined");
2124
+ }
2125
+ if (data.accuracy === null) {
2126
+ throw Error("the accuracy of the position is not defined");
2127
+ }
2128
+ newPositionEvent = data;
2129
+ } else {
2130
+ throw new Error("data is nor an UserPosition or an AbsolutePositionEvent");
2131
+ }
2132
+ if (!_AbsolutePositionProvider.USE_MM_FOR_FEED || !MapMatchingHandler$1.canUseMapMatching()) {
2133
+ this.notify(newPositionEvent);
2134
+ return;
2135
+ }
2136
+ MapMatchingHandler$1.notifyPositionFromFeed(newPositionEvent);
2137
+ }
2138
+ getBestPositionEvent(...absolutePositionEvents) {
2139
+ return absolutePositionEvents.reduce((best, value) => {
2140
+ if (!best) {
2141
+ return value;
2142
+ }
2143
+ if (!value || value.accuracy === null || value.time === null) {
2144
+ return best;
2145
+ }
2146
+ const { accuracy: curAccuracy, time: curTime } = value;
2147
+ const { accuracy: bestAccuracy, time: bestTime } = best;
2148
+ return curAccuracy < bestAccuracy + 1.3888 * (curTime - bestTime) ? value : best;
2149
+ }, null);
2150
+ }
2151
+ };
2152
+ let AbsolutePositionProvider = _AbsolutePositionProvider;
2153
+ __publicField(AbsolutePositionProvider, "ACCURACY_RELOC_RATIO", 1);
2154
+ __publicField(AbsolutePositionProvider, "USE_MM_FOR_FEED", true);
2155
+ const AbsolutePositionProvider$1 = new AbsolutePositionProvider();
2156
+ class AbsoluteAttitudeFromBrowser extends Provider {
2157
+ constructor() {
2158
+ super(...arguments);
2159
+ __publicField(this, "DEFAULT_ACCURACY", maths.deg2rad(15));
2160
+ __publicField(this, "absolutePositionProviderId");
2161
+ __publicField(this, "absolutePositionEvent");
2162
+ __publicField(this, "declinationQuaternion");
2163
+ __publicField(this, "magQuaternion");
2164
+ __publicField(this, "magQuaternionTimestamp");
2165
+ __publicField(this, "iosPreviousQuat");
2166
+ __publicField(this, "iosIsSkyMode", null);
2167
+ __publicField(this, "getName", () => "AbsoluteAttitudeFromBrowser");
2168
+ __publicField(this, "onDeviceOrientationChromeEvent", (e) => {
2169
+ this.magQuaternionTimestamp = e.timeStamp / 1e3;
2170
+ if (typeof e.alpha !== "number" || typeof e.beta !== "number" || typeof e.gamma !== "number") {
2171
+ this.notifyError(new MissingSensorError().from("deviceorientationabsolute"));
2172
+ return;
2173
+ }
2174
+ this.magQuaternion = maths.Rotations.eulerToQuaternionZXYDegrees(
2175
+ [e.alpha, e.beta, e.gamma]
2176
+ );
2177
+ this.compute();
2178
+ });
2179
+ __publicField(this, "onDeviceOrientationSafariEvent", (e) => {
2180
+ this.magQuaternionTimestamp = e.timeStamp / 1e3;
2181
+ if (typeof e.beta !== "number" || typeof e.gamma !== "number") {
2182
+ this.notifyError(new MissingSensorError().from("deviceorientation"));
2183
+ return;
2184
+ }
2185
+ if (typeof e.webkitCompassHeading !== "number") {
2186
+ super.notifyError(new MissingMagnetometerError().from("deviceorientation"));
2187
+ return;
2188
+ }
2189
+ let alpha;
2190
+ const [qw, qx, qy, qz] = maths.Rotations.eulerToQuaternionZXYDegrees([e.webkitCompassHeading, e.beta, e.gamma]);
2191
+ const groundAngle = maths.rad2deg(Math.acos(qw ** 2 - qx ** 2 - qy ** 2 + qz ** 2));
2192
+ let isSkyMode = null;
2193
+ if (groundAngle > 136) {
2194
+ isSkyMode = true;
2195
+ } else if (groundAngle < 134) {
2196
+ isSkyMode = false;
2197
+ } else if (this.iosPreviousQuat && this.iosIsSkyMode !== null) {
2198
+ isSkyMode = maths.Quaternion.distance([qw, qx, qy, qz], this.iosPreviousQuat) < 0.5 ? this.iosIsSkyMode : !this.iosIsSkyMode;
2199
+ }
2200
+ this.iosPreviousQuat = [qw, qx, qy, qz];
2201
+ this.iosIsSkyMode = isSkyMode;
2202
+ if (typeof isSkyMode === "undefined") {
2203
+ return;
2204
+ }
2205
+ if (isSkyMode) {
2206
+ alpha = 180 - e.webkitCompassHeading;
2207
+ } else {
2208
+ alpha = AbsoluteAttitudeFromBrowser.webkitCompassToHeading(
2209
+ e.webkitCompassHeading,
2210
+ e.beta,
2211
+ e.gamma
2212
+ );
2213
+ }
2214
+ this.magQuaternion = maths.Rotations.eulerToQuaternionZXYDegrees([alpha, e.beta, e.gamma]);
2215
+ this.compute();
2216
+ });
2217
+ __publicField(this, "onAbsolutePositionEvent", (position) => {
2218
+ this.absolutePositionEvent = position;
2219
+ const wmmResult = geomagnetism__default.default.model().point([position.lat, position.lng]);
2220
+ this.declinationQuaternion = maths.Quaternion.fromAxisAngle([0, 0, 1], -maths.deg2rad(wmmResult.decl));
2221
+ AbsolutePositionProvider$1.removeEventListener(this.absolutePositionProviderId);
2222
+ delete this.absolutePositionProviderId;
2223
+ this.compute();
2224
+ });
2225
+ }
2226
+ availability() {
2227
+ return utils.BrowserUtils.isMobile ? Promise.resolve() : Promise.resolve(new AskImuOnDesktopError());
2228
+ }
2229
+ start() {
2230
+ const subscribe = () => {
2231
+ switch (utils.BrowserUtils.name) {
2232
+ case utils.Browser.CHROME:
2233
+ window.addEventListener(
2234
+ "deviceorientationabsolute",
2235
+ this.onDeviceOrientationChromeEvent,
2236
+ true
2237
+ );
2238
+ break;
2239
+ case utils.Browser.SAFARI:
2240
+ case utils.Browser.IOS_WEBVIEW:
2241
+ window.addEventListener(
2242
+ "deviceorientation",
2243
+ this.onDeviceOrientationSafariEvent,
2244
+ true
2245
+ );
2246
+ break;
2247
+ }
2248
+ };
2249
+ const requestPermission = DeviceOrientationEvent.requestPermission || void 0;
2250
+ if (requestPermission) {
2251
+ requestPermission().then((response) => {
2252
+ if (response !== "granted") {
2253
+ throw new Error("Permission not granted");
2254
+ }
2255
+ subscribe();
2256
+ }).catch(this.notifyError);
2257
+ } else {
2258
+ subscribe();
2259
+ }
2260
+ const lastAbsolutePosition = AbsolutePositionProvider$1.lastEvent;
2261
+ if (lastAbsolutePosition) {
2262
+ this.onAbsolutePositionEvent(lastAbsolutePosition);
2263
+ } else {
2264
+ this.absolutePositionProviderId = AbsolutePositionProvider$1.addEventListener(
2265
+ this.onAbsolutePositionEvent,
2266
+ this.notifyError,
2267
+ false
2268
+ );
2269
+ }
2270
+ }
2271
+ stop() {
2272
+ switch (utils.BrowserUtils.name) {
2273
+ case utils.Browser.CHROME:
2274
+ window.removeEventListener(
2275
+ "deviceorientationabsolute",
2276
+ this.onDeviceOrientationChromeEvent,
2277
+ true
2278
+ );
2279
+ break;
2280
+ case utils.Browser.SAFARI:
2281
+ case utils.Browser.IOS_WEBVIEW:
2282
+ window.removeEventListener(
2283
+ "deviceorientation",
2284
+ this.onDeviceOrientationSafariEvent,
2285
+ true
2286
+ );
2287
+ break;
2288
+ }
2289
+ AbsolutePositionProvider$1.removeEventListener(this.absolutePositionProviderId);
2290
+ }
2291
+ compute() {
2292
+ if (!this.declinationQuaternion || !this.magQuaternion || !this.absolutePositionEvent) {
2293
+ return;
2294
+ }
2295
+ const trueQuaternion = maths.Quaternion.multiply(this.declinationQuaternion, this.magQuaternion);
2296
+ const attitude = new AbsoluteAttitude(trueQuaternion, this.magQuaternionTimestamp, this.DEFAULT_ACCURACY);
2297
+ this.notify(attitude);
2298
+ }
2299
+ static webkitCompassToHeading(_webkitCompassHeading, _beta, _gamma) {
2300
+ const webkitCompassHeading = maths.deg2rad(_webkitCompassHeading);
2301
+ const beta = maths.deg2rad(_beta);
2302
+ const gamma = maths.deg2rad(_gamma);
2303
+ const c1 = Math.cos(webkitCompassHeading / 2);
2304
+ const c2 = Math.cos(beta / 2);
2305
+ const c3 = Math.cos(gamma / 2);
2306
+ const s1 = Math.sin(webkitCompassHeading / 2);
2307
+ const s2 = Math.sin(beta / 2);
2308
+ const s3 = Math.sin(gamma / 2);
2309
+ const qw = c1 * c2 * c3 - s1 * s2 * s3;
2310
+ const qz = s1 * c2 * c3 + c1 * s2 * s3;
2311
+ return maths.rad2deg(-2 * Math.atan(qz / qw));
2312
+ }
2313
+ }
2314
+ const AbsoluteAttitudeFromBrowser$1 = new AbsoluteAttitudeFromBrowser();
2315
+ class RelativeAttitudeProvider extends Provider {
2316
+ constructor() {
2317
+ super(...arguments);
2318
+ __publicField(this, "arCoreMonitoringId");
2319
+ __publicField(this, "arCoreProviderId");
2320
+ __publicField(this, "inertialProviderId");
2321
+ __publicField(this, "getName", () => "RelativeAttitude");
2322
+ __publicField(this, "availability", () => RelativeAttitudeFromInertialProvider.getAvailability());
2323
+ __publicField(this, "listenInertial", () => {
2324
+ this.inertialProviderId = RelativeAttitudeFromInertialProvider.addEventListener(
2325
+ this.notify,
2326
+ this.notifyError
2327
+ );
2328
+ });
2329
+ __publicField(this, "unlistenInertial", () => {
2330
+ RelativeAttitudeFromInertialProvider.removeEventListener(this.inertialProviderId);
2331
+ });
2332
+ __publicField(this, "listenArCore", () => {
2333
+ this.arCoreProviderId = ArCoreProvider$1.addEventListener(
2334
+ (event) => this.notify(event.relativeAttitude),
2335
+ null,
2336
+ false
2337
+ );
2338
+ });
2339
+ __publicField(this, "unlistenArCore", () => {
2340
+ ArCoreProvider$1.removeEventListener(this.arCoreProviderId);
2341
+ });
2342
+ }
2343
+ start() {
2344
+ this.arCoreMonitoringId = ArCoreProvider$1.addMonitoringListener(
2345
+ () => {
2346
+ this.listenArCore();
2347
+ this.unlistenInertial();
2348
+ },
2349
+ () => {
2350
+ this.unlistenArCore();
2351
+ this.listenInertial();
2352
+ }
2353
+ );
2354
+ if (ArCoreProvider$1.state === "started") {
2355
+ this.listenArCore();
2356
+ } else {
2357
+ this.listenInertial();
2358
+ }
2359
+ }
2360
+ stop() {
2361
+ ArCoreProvider$1.removeMonitoringListener(this.arCoreMonitoringId);
2362
+ this.unlistenArCore();
2363
+ this.unlistenInertial();
2364
+ }
2365
+ }
2366
+ const RelativeAttitudeProvider$1 = new RelativeAttitudeProvider();
2367
+ const _AbsoluteAttitudeProvider = class extends Provider {
2368
+ constructor() {
2369
+ super(...arguments);
2370
+ __publicField(this, "_absAttitudeFromBrowser");
2371
+ __publicField(this, "_vpsProviderId");
2372
+ __publicField(this, "fromBrowserProviderId");
2373
+ __publicField(this, "highRotationProviderId");
2374
+ __publicField(this, "inclinationProviderId");
2375
+ __publicField(this, "relativeAttitudeProviderId");
2376
+ __publicField(this, "_attitudeFromBrowserErrored", false);
2377
+ __publicField(this, "_attitudeFromRelativeErrored", false);
2378
+ __publicField(this, "_relativeAttitude", null);
2379
+ __publicField(this, "_relativeAccuracy", 0);
2380
+ __publicField(this, "_lastForcedHeadingEvent");
2381
+ __publicField(this, "_relAbsQuat");
2382
+ __publicField(this, "_wasHighRotationInProgress", false);
2383
+ __publicField(this, "_timeFirstDivergence", null);
2384
+ __publicField(this, "_callbackMagCalibration");
2385
+ __publicField(this, "getName", () => "AbsoluteAttitude");
2386
+ __publicField(this, "_onError", (error) => {
2387
+ if (this._attitudeFromBrowserErrored && this._attitudeFromRelativeErrored) {
2388
+ this.notifyError(error);
2389
+ }
2390
+ });
2391
+ __publicField(this, "_forceHeadingForRelative", (absoluteHeadingEvent) => {
2392
+ if (this.lastEvent && absoluteHeadingEvent.accuracy > this.lastEvent.accuracy) {
2393
+ return;
2394
+ }
2395
+ const calcForceHeading = (relativeAttitude) => {
2396
+ const currentRelativeHeading = relativeAttitude.heading;
2397
+ this._relAbsQuat = maths.Quaternion.fromAxisAngle(
2398
+ [0, 0, 1],
2399
+ currentRelativeHeading - absoluteHeadingEvent.heading
2400
+ );
2401
+ this._relativeAccuracy = 0;
2402
+ this._lastForcedHeadingEvent = absoluteHeadingEvent;
2403
+ };
2404
+ if (this._relativeAttitude) {
2405
+ calcForceHeading(this._relativeAttitude);
2406
+ return;
2407
+ }
2408
+ const providerId = RelativeAttitudeProvider$1.addEventListener(
2409
+ (event) => {
2410
+ calcForceHeading(event);
2411
+ RelativeAttitudeProvider$1.removeEventListener(providerId);
2412
+ }
2413
+ );
2414
+ });
2415
+ __publicField(this, "_onRelativeAttitudeEvent", (event) => {
2416
+ var _a;
2417
+ const { quaternion, accuracy, time } = event;
2418
+ if (this._relativeAttitude) {
2419
+ this._relativeAccuracy += (time - this._relativeAttitude.time) * accuracy;
2420
+ }
2421
+ this._relativeAttitude = event;
2422
+ if (!this._lastForcedHeadingEvent || !this._relAbsQuat) {
2423
+ return;
2424
+ }
2425
+ const accuracyWithRelative = Math.min(
2426
+ (this._lastForcedHeadingEvent.accuracy || 0) + this._relativeAccuracy,
2427
+ Math.PI
2428
+ );
2429
+ const highRotationInProgress = HighRotationsProvider$1.isInProgress();
2430
+ let divergenceDetected = false;
2431
+ if (this._absAttitudeFromBrowser) {
2432
+ const {
2433
+ accuracy: accuracyWithAbsolute,
2434
+ heading: headingFromAbsolute
2435
+ } = this._absAttitudeFromBrowser;
2436
+ if (this._wasHighRotationInProgress && !highRotationInProgress) {
2437
+ this._forceHeadingForRelative(this._absAttitudeFromBrowser);
2438
+ } else if (accuracyWithAbsolute < accuracyWithRelative) {
2439
+ const relativeQuaternion = maths.Quaternion.multiply(this._relAbsQuat, quaternion);
2440
+ const relativeAttitude = new geo.Attitude(relativeQuaternion);
2441
+ const angle = Math.abs(maths.diffAngle(relativeAttitude.heading, headingFromAbsolute));
2442
+ const inclination = InclinationProvider$1.lastEvent;
2443
+ if (angle > _AbsoluteAttitudeProvider.REL_ABS_DIVERGENCE_ANGLE_THRESHOLD && inclination !== null && Math.abs(inclination - Math.PI / 4) > _AbsoluteAttitudeProvider.REL_ABS_DIVERGENCE_INCLINATION_THRESHOLD) {
2444
+ divergenceDetected = true;
2445
+ if (this._timeFirstDivergence !== null && time - this._timeFirstDivergence > _AbsoluteAttitudeProvider.REL_ABS_DIVERGENCE_TIME_THRESHOLD) {
2446
+ this._forceHeadingForRelative(this._absAttitudeFromBrowser);
2447
+ (_a = this._callbackMagCalibration) == null ? void 0 : _a.call(this, { angle });
2448
+ this._timeFirstDivergence = null;
2449
+ } else if (this._timeFirstDivergence === null) {
2450
+ this._timeFirstDivergence = time;
2451
+ }
2452
+ }
2453
+ }
2454
+ }
2455
+ if (!divergenceDetected) {
2456
+ this._timeFirstDivergence = null;
2457
+ }
2458
+ this._wasHighRotationInProgress = highRotationInProgress;
2459
+ const absoluteQuat = maths.Quaternion.multiply(this._relAbsQuat, quaternion);
2460
+ const attitude = new AbsoluteAttitude(absoluteQuat, time, accuracyWithRelative);
2461
+ this.notify(attitude);
2462
+ });
2463
+ __publicField(this, "_onAttitudeFromBrowser", (event) => {
2464
+ this._absAttitudeFromBrowser = event;
2465
+ if (!this._lastForcedHeadingEvent) {
2466
+ this._forceHeadingForRelative(event);
2467
+ return;
2468
+ }
2469
+ });
2470
+ __publicField(this, "_onAttitudeFromVps", (event) => {
2471
+ this._forceHeadingForRelative(event);
2472
+ });
2473
+ }
2474
+ availability() {
2475
+ return AvailabilityHelper.some([
2476
+ AbsoluteAttitudeFromBrowser$1.getAvailability(),
2477
+ RelativeAttitudeProvider$1.getAvailability()
2478
+ ]);
2479
+ }
2480
+ start() {
2481
+ this.fromBrowserProviderId = AbsoluteAttitudeFromBrowser$1.addEventListener(
2482
+ this._onAttitudeFromBrowser,
2483
+ (error) => {
2484
+ this._attitudeFromBrowserErrored = true;
2485
+ this._onError(error);
2486
+ }
2487
+ );
2488
+ this._vpsProviderId = VpsProvider$1.addEventListener(
2489
+ (event) => this._onAttitudeFromVps(event.absoluteAttitude),
2490
+ (error) => this.notifyError(error),
2491
+ false
2492
+ );
2493
+ this.relativeAttitudeProviderId = RelativeAttitudeProvider$1.addEventListener(
2494
+ this._onRelativeAttitudeEvent,
2495
+ (error) => {
2496
+ this._attitudeFromRelativeErrored = true;
2497
+ this._onError(error);
2498
+ }
2499
+ );
2500
+ this.inclinationProviderId = InclinationProvider$1.addEventListener();
2501
+ this.highRotationProviderId = HighRotationsProvider$1.addEventListener();
2502
+ }
2503
+ stop() {
2504
+ AbsoluteAttitudeFromBrowser$1.removeEventListener(this.fromBrowserProviderId);
2505
+ RelativeAttitudeProvider$1.removeEventListener(this.relativeAttitudeProviderId);
2506
+ InclinationProvider$1.removeEventListener(this.inclinationProviderId);
2507
+ HighRotationsProvider$1.removeEventListener(this.highRotationProviderId);
2508
+ VpsProvider$1.removeEventListener(this._vpsProviderId);
2509
+ }
2510
+ _setCallbackMagCalibration(cb) {
2511
+ this._callbackMagCalibration = cb;
2512
+ }
2513
+ feed(data) {
2514
+ if (data instanceof geo.AbsoluteHeading) {
2515
+ if (data.time === null) {
2516
+ throw Error("the time of the absolute heading is not defined");
2517
+ }
2518
+ if (data.accuracy === null) {
2519
+ throw Error("the accuracy of the absolute heading is not defined");
2520
+ }
2521
+ this._forceHeadingForRelative(data);
2522
+ } else if (data instanceof AbsoluteAttitude) {
2523
+ if (data.time === null) {
2524
+ throw Error("the time of the attitude is not defined");
2525
+ }
2526
+ if (data.accuracy === null) {
2527
+ throw Error("the accuracy of the attitude is not defined");
2528
+ }
2529
+ this._forceHeadingForRelative(data);
2530
+ } else {
2531
+ throw new Error("data is nor an AbsoluteHeading or an Attitude object");
2532
+ }
2533
+ }
2534
+ };
2535
+ let AbsoluteAttitudeProvider = _AbsoluteAttitudeProvider;
2536
+ __publicField(AbsoluteAttitudeProvider, "REL_ABS_DIVERGENCE_ANGLE_THRESHOLD", maths.deg2rad(25));
2537
+ __publicField(AbsoluteAttitudeProvider, "REL_ABS_DIVERGENCE_TIME_THRESHOLD", 2.5);
2538
+ __publicField(AbsoluteAttitudeProvider, "REL_ABS_DIVERGENCE_INCLINATION_THRESHOLD", maths.deg2rad(15));
2539
+ const AbsoluteAttitudeProvider$1 = new AbsoluteAttitudeProvider();
2540
+ const _TurnProvider = class extends Provider {
2541
+ constructor() {
2542
+ super(...arguments);
2543
+ __publicField(this, "providerId");
2544
+ __publicField(this, "slidingWindow", []);
2545
+ __publicField(this, "getName", () => "Turn");
2546
+ __publicField(this, "availability", () => RelativeAttitudeProvider$1.getAvailability());
2547
+ __publicField(this, "_parseRelativeAttitude", (relativeAttitudeEvent) => {
2548
+ const { heading } = relativeAttitudeEvent;
2549
+ const timestamp = relativeAttitudeEvent.time;
2550
+ this.slidingWindow = this.slidingWindow.filter((item) => item[0] >= timestamp - _TurnProvider.SLIDING_WINDOW_TIME);
2551
+ this.slidingWindow.push([timestamp, heading]);
2552
+ const stdVal = maths.std(this.slidingWindow.map((item) => item[1]));
2553
+ if (stdVal > _TurnProvider.STD_THRESHOLD) {
2554
+ this.notify({ timestamp });
2555
+ }
2556
+ });
2557
+ }
2558
+ start() {
2559
+ this.providerId = RelativeAttitudeProvider$1.addEventListener(
2560
+ this._parseRelativeAttitude,
2561
+ this.notifyError
2562
+ );
2563
+ }
2564
+ stop() {
2565
+ RelativeAttitudeProvider$1.removeEventListener(this.providerId);
2566
+ }
2567
+ isTurning() {
2568
+ if (!this.lastEvent || !RelativeAttitudeProvider$1.lastEvent) {
2569
+ return false;
2570
+ }
2571
+ const diffTime = RelativeAttitudeProvider$1.lastEvent.time - this.lastEvent.timestamp;
2572
+ return diffTime < _TurnProvider.CONSIDER_TURN_UNTIL;
2573
+ }
2574
+ };
2575
+ let TurnProvider = _TurnProvider;
2576
+ __publicField(TurnProvider, "SLIDING_WINDOW_TIME", 0.3);
2577
+ __publicField(TurnProvider, "STD_THRESHOLD", 0.075);
2578
+ __publicField(TurnProvider, "CONSIDER_TURN_UNTIL", 1);
2579
+ const TurnProvider$1 = new TurnProvider();
2580
+ const _StraightLineProvider = class extends Provider {
2581
+ constructor() {
2582
+ super(...arguments);
2583
+ __publicField(this, "_turnProviderId");
2584
+ __publicField(this, "_stepProviderId");
2585
+ __publicField(this, "_countSteps", 0);
2586
+ __publicField(this, "_stepsConsideredForStraightLine", _StraightLineProvider.DEFAULT_STEPS_CONSIDERED_FOR_STRAIGHT_LINE);
2587
+ __publicField(this, "getName", () => "StraightLine");
2588
+ __publicField(this, "_onTurn", () => {
2589
+ if (this._countSteps >= this._stepsConsideredForStraightLine) {
2590
+ this.notify(false);
2591
+ }
2592
+ this._countSteps = 0;
2593
+ });
2594
+ __publicField(this, "_onStep", () => {
2595
+ this._countSteps++;
2596
+ if (this._countSteps === this._stepsConsideredForStraightLine) {
2597
+ this.notify(true);
2598
+ }
2599
+ });
2600
+ }
2601
+ availability() {
2602
+ return AvailabilityHelper.every([
2603
+ TurnProvider$1.getAvailability(),
2604
+ StepProvider$1.getAvailability()
2605
+ ]);
2606
+ }
2607
+ start() {
2608
+ this._turnProviderId = TurnProvider$1.addEventListener(this._onTurn);
2609
+ this._stepProviderId = StepProvider$1.addEventListener(this._onStep);
2610
+ }
2611
+ stop() {
2612
+ TurnProvider$1.removeEventListener(this._turnProviderId);
2613
+ StepProvider$1.removeEventListener(this._stepProviderId);
2614
+ }
2615
+ isStraight() {
2616
+ return this._countSteps >= this._stepsConsideredForStraightLine;
2617
+ }
2618
+ get numStepsDetectedFromLastTurn() {
2619
+ return this._countSteps;
2620
+ }
2621
+ get stepsConsideredForStraightLine() {
2622
+ return this._stepsConsideredForStraightLine;
2623
+ }
2624
+ set stepsConsideredForStraightLine(stepsConsideredForStraightLine) {
2625
+ this._stepsConsideredForStraightLine = stepsConsideredForStraightLine;
2626
+ }
2627
+ };
2628
+ let StraightLineProvider = _StraightLineProvider;
2629
+ __publicField(StraightLineProvider, "DEFAULT_STEPS_CONSIDERED_FOR_STRAIGHT_LINE", 2);
2630
+ const StraightLineProvider$1 = new StraightLineProvider();
2631
+ const _MapMatchingHandler = class extends Provider {
2632
+ constructor() {
2633
+ super();
2634
+ __publicField(this, "_mapMatchingMinDistance", _MapMatchingHandler.DEFAULT_MM_MIN_DIST);
2635
+ __publicField(this, "_useItineraryStartAsPosition", _MapMatchingHandler.DEFAULT_USE_ITINERARY_START_AS_POSITION);
2636
+ __publicField(this, "_useOrientationMatching", _MapMatchingHandler.DEFAULT_USE_ORIENTATION_MATCHING);
2637
+ __publicField(this, "_hugeJumpDistance", _MapMatchingHandler.DEFAULT_MM_HUGE_JUMP_DISTANCE);
2638
+ __publicField(this, "_disableMMCloseToATurnDistance", _MapMatchingHandler.DEFAULT_DISABLE_MM_CLOSE_TO_A_TURN_DISTANCE);
2639
+ __publicField(this, "_minStepsBetweenOrientationMatching", _MapMatchingHandler.DEFAULT_MIN_STEPS_BETWEEN_ORIENTATION_MATCHING);
2640
+ __publicField(this, "_minStepsForOrientationMatching", _MapMatchingHandler.DEFAULT_MIN_STEPS_FOR_ORIENTATION_MATCHING);
2641
+ __publicField(this, "_lastProjectionsWindowSize", _MapMatchingHandler.DEFAULT_LAST_PROJECTIONS_WINDOW_SIZE);
2642
+ __publicField(this, "_lastProjectionsEdgeAngleThreshold", _MapMatchingHandler.DEFAULT_LAST_PROJECTIONS_EDGE_ANGLE_THRESHOLD);
2643
+ __publicField(this, "_mapMatching");
2644
+ __publicField(this, "_internalProvidersStarted", false);
2645
+ __publicField(this, "_straightLineProviderId");
2646
+ __publicField(this, "_turnProviderId");
2647
+ __publicField(this, "_stepProviderId");
2648
+ __publicField(this, "_projectionsWithAbsAndWithoutRelAttitudeInARow", []);
2649
+ __publicField(this, "_countStepsFromLastMatching", 0);
2650
+ __publicField(this, "_lastProjections", []);
2651
+ __publicField(this, "_itineraryInfoManager", null);
2652
+ __publicField(this, "getName", () => "MapMatchingHandler");
2653
+ __publicField(this, "availability", () => Promise.resolve());
2654
+ __publicField(this, "_manageStartStop", () => {
2655
+ if (this.network && !this._internalProvidersStarted) {
2656
+ this._startInternalProviders();
2657
+ } else if (!this.network && this._internalProvidersStarted) {
2658
+ this._stopInternalProviders();
2659
+ }
2660
+ });
2661
+ this._mapMatching = new geo.MapMatching();
2662
+ this._mapMatching.maxDistance = _MapMatchingHandler.DEFAULT_MM_MAX_DIST;
2663
+ this._mapMatching.maxAngleBearing = _MapMatchingHandler.DEFAULT_MM_MAX_ANGLE;
2664
+ }
2665
+ start() {
2666
+ if (this.network) {
2667
+ this._startInternalProviders();
2668
+ }
2669
+ }
2670
+ stop() {
2671
+ this._stopInternalProviders();
2672
+ }
2673
+ _startInternalProviders() {
2674
+ if (this.enabled && this._internalProvidersStarted) {
2675
+ return;
2676
+ }
2677
+ this._straightLineProviderId = StraightLineProvider$1.addEventListener();
2678
+ this._turnProviderId = TurnProvider$1.addEventListener();
2679
+ this._stepProviderId = StepProvider$1.addEventListener(() => this._countStepsFromLastMatching++);
2680
+ this._internalProvidersStarted = true;
2681
+ }
2682
+ _stopInternalProviders() {
2683
+ if (this.enabled && !this._internalProvidersStarted) {
2684
+ return;
2685
+ }
2686
+ StraightLineProvider$1.removeEventListener(this._straightLineProviderId);
2687
+ TurnProvider$1.removeEventListener(this._turnProviderId);
2688
+ StepProvider$1.removeEventListener(this._stepProviderId);
2689
+ this._internalProvidersStarted = false;
2690
+ }
2691
+ get enabled() {
2692
+ return ProvidersOptions.useMapMatching;
2693
+ }
2694
+ get network() {
2695
+ return this._mapMatching.network;
2696
+ }
2697
+ set network(network) {
2698
+ this._mapMatching.network = network;
2699
+ this._itineraryInfoManager = null;
2700
+ this.notify({ ...network && { network } });
2701
+ this._manageStartStop();
2702
+ if (this.canUseMapMatching())
2703
+ ;
2704
+ }
2705
+ set itinerary(itinerary) {
2706
+ this._mapMatching.network = itinerary ? itinerary.toNetwork() : null;
2707
+ this._itineraryInfoManager = new routers.ItineraryInfoManager(itinerary);
2708
+ this.notify({ ...itinerary && { itinerary } });
2709
+ this._manageStartStop();
2710
+ if (this.canUseMapMatching() && itinerary) {
2711
+ this._notifyPositionFromItineraryInput(itinerary);
2712
+ }
2713
+ }
2714
+ canUseMapMatching() {
2715
+ return this.enabled && this.network;
2716
+ }
2717
+ _notifyPositionFromItineraryInput(itinerary) {
2718
+ if (!this._useItineraryStartAsPosition || itinerary.from) {
2719
+ return;
2720
+ }
2721
+ const lastPosition = AbsolutePositionProvider$1.lastEvent || null;
2722
+ const newPosition = geo.UserPosition.fromCoordinates(itinerary.from);
2723
+ if (lastPosition) {
2724
+ newPosition.alt = lastPosition.alt;
2725
+ newPosition.time = lastPosition.time;
2726
+ newPosition.accuracy = lastPosition.accuracy + newPosition.distanceTo(lastPosition);
2727
+ newPosition.bearing = lastPosition.bearing;
2728
+ } else if (itinerary.coords.length >= 2) {
2729
+ newPosition.alt = Constants.DEFAULT_ALTITUDE;
2730
+ newPosition.time = utils.TimeUtils.preciseTime();
2731
+ newPosition.accuracy = 0;
2732
+ newPosition.bearing = itinerary.coords[0].bearingTo(itinerary.coords[1]);
2733
+ } else {
2734
+ return;
2735
+ }
2736
+ const projection = this.getProjection(newPosition, true);
2737
+ if (projection) {
2738
+ AbsolutePositionProvider$1.notify(projection.coords);
2739
+ } else {
2740
+ AbsolutePositionProvider$1.notify(newPosition);
2741
+ }
2742
+ return;
2743
+ }
2744
+ notifyPositionFromFeed(newPositionEvent) {
2745
+ const projection = this.getProjection(newPositionEvent, true, false);
2746
+ if (!projection) {
2747
+ AbsolutePositionProvider$1.notify(newPositionEvent);
2748
+ return;
2749
+ }
2750
+ AbsolutePositionProvider$1.notify(projection.coords);
2751
+ }
2752
+ notifyPositionFromAbsolute(newPosition) {
2753
+ let projectionWithBearing = null;
2754
+ if (newPosition.bearing !== null) {
2755
+ projectionWithBearing = this.getProjection(newPosition, true, true);
2756
+ }
2757
+ if (!projectionWithBearing) {
2758
+ AbsolutePositionProvider$1.notify(newPosition);
2759
+ return true;
2760
+ }
2761
+ const thisWillBeAHugeJump = projectionWithBearing.distanceFromNearestElement > this._hugeJumpDistance;
2762
+ if (thisWillBeAHugeJump && !StraightLineProvider$1.isStraight()) {
2763
+ return false;
2764
+ }
2765
+ if (thisWillBeAHugeJump && this._detectWrongBigJump(projectionWithBearing)) {
2766
+ return false;
2767
+ }
2768
+ AbsolutePositionProvider$1.notify(projectionWithBearing.coords);
2769
+ this.tryOrientationMatching(projectionWithBearing);
2770
+ return true;
2771
+ }
2772
+ notifyPositionFromRelative(newPosition) {
2773
+ var _a;
2774
+ if (TurnProvider$1.isTurning()) {
2775
+ this._projectionsWithAbsAndWithoutRelAttitudeInARow = [];
2776
+ this._lastProjections = [];
2777
+ AbsolutePositionProvider$1.notify(newPosition);
2778
+ return true;
2779
+ }
2780
+ const projection = this.getProjection(newPosition, true, true);
2781
+ if (projection) {
2782
+ this._projectionsWithAbsAndWithoutRelAttitudeInARow = [];
2783
+ this._lastProjections.push(projection);
2784
+ if (this._lastProjections.length > this._lastProjectionsWindowSize) {
2785
+ this._lastProjections.shift();
2786
+ }
2787
+ const thisWillBeAHugeJump = projection.distanceFromNearestElement > this._hugeJumpDistance;
2788
+ if (thisWillBeAHugeJump && !StraightLineProvider$1.isStraight()) {
2789
+ AbsolutePositionProvider$1.notify(newPosition);
2790
+ return true;
2791
+ }
2792
+ if (thisWillBeAHugeJump && this._detectWrongBigJump(projection)) {
2793
+ AbsolutePositionProvider$1.notify(newPosition);
2794
+ return true;
2795
+ }
2796
+ if (!this._areLastProjectionsInTheSameDirection()) {
2797
+ AbsolutePositionProvider$1.notify(newPosition);
2798
+ return true;
2799
+ }
2800
+ if (this._disableMMCloseToATurnDistance > 0 && this._hasTurnInCircle(projection.coords, this._disableMMCloseToATurnDistance)) {
2801
+ AbsolutePositionProvider$1.notify(newPosition);
2802
+ return true;
2803
+ }
2804
+ AbsolutePositionProvider$1.notify(projection.coords);
2805
+ this.tryOrientationMatching(projection);
2806
+ return true;
2807
+ }
2808
+ if (StraightLineProvider$1.isStraight()) {
2809
+ const testedPosition = newPosition.clone();
2810
+ testedPosition.bearing = ((_a = AbsoluteAttitudeFromBrowser$1.lastEvent) == null ? void 0 : _a.heading) || null;
2811
+ const projectionWithAbs = this.getProjection(testedPosition, true, true);
2812
+ if (projectionWithAbs) {
2813
+ this._projectionsWithAbsAndWithoutRelAttitudeInARow.push(projectionWithAbs);
2814
+ if (this._projectionsWithAbsAndWithoutRelAttitudeInARow.length < 3) {
2815
+ AbsolutePositionProvider$1.notify(newPosition);
2816
+ return true;
2817
+ }
2818
+ this._lastProjections.push(projectionWithAbs);
2819
+ if (this._lastProjections.length > this._lastProjectionsWindowSize) {
2820
+ this._lastProjections.shift();
2821
+ }
2822
+ if (!this._areLastProjectionsInTheSameDirection()) {
2823
+ AbsolutePositionProvider$1.notify(newPosition);
2824
+ return true;
2825
+ }
2826
+ AbsolutePositionProvider$1.notify(projectionWithAbs.coords);
2827
+ this.tryOrientationMatching(projectionWithAbs);
2828
+ return true;
2829
+ }
2830
+ }
2831
+ this._projectionsWithAbsAndWithoutRelAttitudeInARow = [];
2832
+ this._lastProjections = [];
2833
+ AbsolutePositionProvider$1.notify(newPosition);
2834
+ return true;
2835
+ }
2836
+ _detectWrongBigJump(projection) {
2837
+ if (this._itineraryInfoManager && AbsolutePositionProvider$1.lastEvent) {
2838
+ const infoPrevious = this._itineraryInfoManager.getInfo(AbsolutePositionProvider$1.lastEvent);
2839
+ const infoProjection = this._itineraryInfoManager.getInfo(projection.coords);
2840
+ if (infoPrevious && infoProjection && infoPrevious.traveledDistance > infoProjection.traveledDistance && infoPrevious.traveledDistance - infoProjection.traveledDistance > projection.origin.accuracy && projection.distanceFromNearestElement > projection.origin.accuracy && projection.origin.distanceTo(AbsolutePositionProvider$1.lastEvent) < projection.origin.accuracy + AbsolutePositionProvider$1.lastEvent.accuracy) {
2841
+ return true;
2842
+ }
2843
+ }
2844
+ return false;
2845
+ }
2846
+ _areLastProjectionsInTheSameDirection() {
2847
+ if (this._lastProjections.length === 0) {
2848
+ return false;
2849
+ }
2850
+ const firstProjection = this._lastProjections[0];
2851
+ return !this._lastProjections.some(
2852
+ (projection) => !(projection.nearestElement instanceof geo.GraphEdge) || !(firstProjection.nearestElement instanceof geo.GraphEdge) || maths.diffAngleLines(projection.nearestElement.bearing, firstProjection.nearestElement.bearing) > this._lastProjectionsEdgeAngleThreshold
2853
+ );
2854
+ }
2855
+ _nodeHasTurn(node) {
2856
+ const { edges } = node;
2857
+ for (let i = 0; i < edges.length; i++) {
2858
+ for (let j = i + 1; j < edges.length; j++) {
2859
+ const angle = maths.diffAngleLines(edges[i].bearing, edges[j].bearing);
2860
+ if (angle > _MapMatchingHandler.DEFAULT_MM_MAX_ANGLE) {
2861
+ return true;
2862
+ }
2863
+ }
2864
+ }
2865
+ return false;
2866
+ }
2867
+ _hasTurnInCircle(center, radius) {
2868
+ const network = this._mapMatching.network;
2869
+ if (!network) {
2870
+ return false;
2871
+ }
2872
+ return network.nodes.filter(
2873
+ (node) => node.coords.distanceTo(center) <= radius && geo.Level.intersect(node.coords.level, center.level)
2874
+ ).some(this._nodeHasTurn);
2875
+ }
2876
+ tryOrientationMatching(projection) {
2877
+ if (!this._useOrientationMatching) {
2878
+ return;
2879
+ }
2880
+ if (this.state !== "started" || this._countStepsFromLastMatching < this._minStepsBetweenOrientationMatching || StraightLineProvider$1.numStepsDetectedFromLastTurn < this._minStepsForOrientationMatching) {
2881
+ return;
2882
+ }
2883
+ const { nearestElement, origin } = projection;
2884
+ if (!(nearestElement instanceof geo.GraphEdge)) {
2885
+ return;
2886
+ }
2887
+ let matchingDirection;
2888
+ const matchingDirectionAngle1 = maths.diffAngle(nearestElement.bearing, origin.bearing);
2889
+ const matchingDirectionAngle2 = maths.diffAngle(nearestElement.bearing + Math.PI, origin.bearing);
2890
+ if (Math.abs(matchingDirectionAngle1) < Math.abs(matchingDirectionAngle2)) {
2891
+ matchingDirection = nearestElement.bearing;
2892
+ } else {
2893
+ matchingDirection = (nearestElement.bearing + Math.PI) % (2 * Math.PI);
2894
+ }
2895
+ const matchedHeading = new geo.AbsoluteHeading(
2896
+ matchingDirection,
2897
+ origin.time,
2898
+ 0
2899
+ );
2900
+ AbsoluteAttitudeProvider$1._forceHeadingForRelative(matchedHeading);
2901
+ this._countStepsFromLastMatching = 0;
2902
+ }
2903
+ getProjection(position, useDistance, useBearing) {
2904
+ return this._mapMatching.getProjection(position, useDistance, useBearing);
2905
+ }
2906
+ get maxDistance() {
2907
+ return this._mapMatching.maxDistance;
2908
+ }
2909
+ set maxDistance(maxDistance) {
2910
+ this._mapMatching.maxDistance = maxDistance;
2911
+ }
2912
+ get minDistance() {
2913
+ return this._mapMatchingMinDistance;
2914
+ }
2915
+ set minDistance(minDistance) {
2916
+ this._mapMatchingMinDistance = minDistance;
2917
+ }
2918
+ get maxAngleBearing() {
2919
+ return this._mapMatching.maxAngleBearing;
2920
+ }
2921
+ set maxAngleBearing(maxAngleBearing) {
2922
+ this._mapMatching.maxAngleBearing = maxAngleBearing;
2923
+ }
2924
+ get useItineraryStartAsPosition() {
2925
+ return this._useItineraryStartAsPosition;
2926
+ }
2927
+ set useItineraryStartAsPosition(useItineraryStartAsPosition) {
2928
+ this._useItineraryStartAsPosition = useItineraryStartAsPosition;
2929
+ }
2930
+ get useOrientationMatching() {
2931
+ return this._useOrientationMatching;
2932
+ }
2933
+ set useOrientationMatching(useOrientationMatching) {
2934
+ this._useOrientationMatching = useOrientationMatching;
2935
+ }
2936
+ get hugeJumpDistance() {
2937
+ return this._hugeJumpDistance;
2938
+ }
2939
+ set hugeJumpDistance(hugeJumpDistance) {
2940
+ this._hugeJumpDistance = hugeJumpDistance;
2941
+ }
2942
+ get disableMMCloseToATurnDistance() {
2943
+ return this._disableMMCloseToATurnDistance;
2944
+ }
2945
+ set disableMMCloseToATurnDistance(disableMMCloseToATurnDistance) {
2946
+ this._disableMMCloseToATurnDistance = disableMMCloseToATurnDistance;
2947
+ }
2948
+ get minStepsBetweenOrientationMatching() {
2949
+ return this._minStepsBetweenOrientationMatching;
2950
+ }
2951
+ set minStepsBetweenOrientationMatching(minStepsBetweenOrientationMatching) {
2952
+ this._minStepsBetweenOrientationMatching = minStepsBetweenOrientationMatching;
2953
+ }
2954
+ get minStepsForOrientationMatching() {
2955
+ return this._minStepsForOrientationMatching;
2956
+ }
2957
+ set minStepsForOrientationMatching(minStepsForOrientationMatching) {
2958
+ this._minStepsForOrientationMatching = minStepsForOrientationMatching;
2959
+ }
2960
+ get lastProjectionsWindowSize() {
2961
+ return this._lastProjectionsWindowSize;
2962
+ }
2963
+ set lastProjectionsWindowSize(lastProjectionsWindowSize) {
2964
+ this._lastProjectionsWindowSize = lastProjectionsWindowSize;
2965
+ }
2966
+ get lastProjectionsEdgeAngleThreshold() {
2967
+ return this._lastProjectionsEdgeAngleThreshold;
2968
+ }
2969
+ set lastProjectionsEdgeAngleThreshold(lastProjectionsEdgeAngleThreshold) {
2970
+ this._lastProjectionsEdgeAngleThreshold = lastProjectionsEdgeAngleThreshold;
2971
+ }
2972
+ };
2973
+ let MapMatchingHandler = _MapMatchingHandler;
2974
+ __publicField(MapMatchingHandler, "DEFAULT_MM_MAX_ANGLE", maths.deg2rad(30));
2975
+ __publicField(MapMatchingHandler, "DEFAULT_MM_MAX_DIST", 30);
2976
+ __publicField(MapMatchingHandler, "DEFAULT_MM_MIN_DIST", 0);
2977
+ __publicField(MapMatchingHandler, "DEFAULT_USE_ITINERARY_START_AS_POSITION", false);
2978
+ __publicField(MapMatchingHandler, "DEFAULT_USE_ORIENTATION_MATCHING", true);
2979
+ __publicField(MapMatchingHandler, "DEFAULT_MM_HUGE_JUMP_DISTANCE", 3);
2980
+ __publicField(MapMatchingHandler, "DEFAULT_DISABLE_MM_CLOSE_TO_A_TURN_DISTANCE", 2);
2981
+ __publicField(MapMatchingHandler, "DEFAULT_MIN_STEPS_BETWEEN_ORIENTATION_MATCHING", 3);
2982
+ __publicField(MapMatchingHandler, "DEFAULT_MIN_STEPS_FOR_ORIENTATION_MATCHING", 5);
2983
+ __publicField(MapMatchingHandler, "DEFAULT_LAST_PROJECTIONS_WINDOW_SIZE", 3);
2984
+ __publicField(MapMatchingHandler, "DEFAULT_LAST_PROJECTIONS_EDGE_ANGLE_THRESHOLD", maths.deg2rad(3));
2985
+ const MapMatchingHandler$1 = new MapMatchingHandler();
2986
+ const _PositionSmoother = class {
2987
+ constructor(callback, frequency = _PositionSmoother.DEFAULT_FREQUENCY) {
2988
+ __publicField(this, "positionsQueue", []);
2989
+ __publicField(this, "previousPosition", null);
2990
+ __publicField(this, "timeoutNotify");
2991
+ __publicField(this, "_notifyNext", () => {
2992
+ var _a;
2993
+ if (!this.positionsQueue.length)
2994
+ return;
2995
+ (_a = this.callback) == null ? void 0 : _a.call(this, this.positionsQueue.shift());
2996
+ if (this.positionsQueue.length !== 0) {
2997
+ this.timeoutNotify = setTimeout(this._notifyNext, 1e3 / this.frequency);
2998
+ } else {
2999
+ delete this.timeoutNotify;
3000
+ }
3001
+ });
3002
+ this.callback = callback;
3003
+ this.frequency = frequency;
3004
+ }
3005
+ feed(newPosition, flybyTime = _PositionSmoother.DEFAULT_FLYBY_TIME) {
3006
+ if (!(newPosition instanceof geo.UserPosition)) {
3007
+ throw new TypeError("newPosition is not instance of UserPosition");
3008
+ }
3009
+ if (newPosition.time === null) {
3010
+ throw new Error("newPosition does not have time property");
3011
+ }
3012
+ let previousPosition;
3013
+ if (this.positionsQueue.length !== 0) {
3014
+ previousPosition = this.positionsQueue[0];
3015
+ this.positionsQueue = [];
3016
+ } else {
3017
+ previousPosition = this.previousPosition;
3018
+ }
3019
+ if (previousPosition) {
3020
+ const refTimestamp = newPosition.time;
3021
+ const distance = previousPosition.distanceTo(newPosition);
3022
+ const azimuth = previousPosition.bearingTo(newPosition);
3023
+ let i = 1;
3024
+ const nSamples = this.frequency * flybyTime + 1;
3025
+ const newPositionLevel = geo.Level.clone(newPosition.level);
3026
+ while (i < nSamples + 1) {
3027
+ const smoothedPosition = previousPosition.destinationPoint(distance * i / nSamples, azimuth);
3028
+ smoothedPosition.time = refTimestamp + (i - 1) / this.frequency;
3029
+ smoothedPosition.level = newPositionLevel;
3030
+ smoothedPosition.bearing = newPosition.bearing;
3031
+ smoothedPosition.accuracy = Math.max(
3032
+ smoothedPosition.accuracy + (newPosition.accuracy - smoothedPosition.accuracy) * i / nSamples,
3033
+ 0
3034
+ );
3035
+ this.positionsQueue.push(smoothedPosition);
3036
+ i++;
3037
+ }
3038
+ if (this.timeoutNotify) {
3039
+ clearTimeout(this.timeoutNotify);
3040
+ }
3041
+ } else {
3042
+ this.positionsQueue.push(newPosition.clone());
3043
+ }
3044
+ this.previousPosition = newPosition;
3045
+ this._notifyNext();
3046
+ }
3047
+ clear() {
3048
+ clearTimeout(this.timeoutNotify);
3049
+ delete this.timeoutNotify;
3050
+ this.positionsQueue = [];
3051
+ }
3052
+ };
3053
+ let PositionSmoother = _PositionSmoother;
3054
+ __publicField(PositionSmoother, "DEFAULT_FREQUENCY", 60);
3055
+ __publicField(PositionSmoother, "DEFAULT_FLYBY_TIME", 1);
3056
+ const _AttitudeSmoother = class {
3057
+ constructor(callback) {
3058
+ __publicField(this, "_previousAttitude");
3059
+ __publicField(this, "_smoothing", null);
3060
+ this.callback = callback;
3061
+ }
3062
+ feed(newAttitude) {
3063
+ if (newAttitude.time === null) {
3064
+ throw new Error("newAttitude does not have time property");
3065
+ }
3066
+ const { _previousAttitude: previousAttitude } = this;
3067
+ this._previousAttitude = newAttitude;
3068
+ if (!previousAttitude) {
3069
+ this.callback(newAttitude);
3070
+ return;
3071
+ }
3072
+ if (_AttitudeSmoother.isJump(previousAttitude, newAttitude)) {
3073
+ const fromAttitude = this._smoothing === null ? previousAttitude : this._smoothing.interpAttitude(previousAttitude);
3074
+ const fromHeading = fromAttitude.heading;
3075
+ const toHeading = newAttitude.heading;
3076
+ const diffAngleHeading = maths.diffAngle(toHeading, fromHeading);
3077
+ const isHighJump = Math.abs(diffAngleHeading) < _AttitudeSmoother.HIGH_JUMP_THRESHOLD;
3078
+ const rotationSpeedConvergence = isHighJump ? _AttitudeSmoother.ROTATION_SPEED_CONVERGENCE : _AttitudeSmoother.ROTATION_SPEED_HIGH_JUMP_CONVERGENCE;
3079
+ const fromTime = fromAttitude.time;
3080
+ const timeToConsume = Math.abs(diffAngleHeading) / rotationSpeedConvergence;
3081
+ const multiplier = diffAngleHeading < 0 ? -1 : 1;
3082
+ this._smoothing = {
3083
+ toTime: fromTime + timeToConsume,
3084
+ interpAttitude: (attitude) => {
3085
+ const angle = rotationSpeedConvergence * (attitude.time - fromTime);
3086
+ const interpHeading = fromHeading + angle * multiplier;
3087
+ const offsetQuat = maths.Quaternion.fromAxisAngle([0, 0, 1], toHeading - interpHeading);
3088
+ const interpQuat = maths.Quaternion.multiply(offsetQuat, attitude.quaternion);
3089
+ return new geo.Attitude(interpQuat, attitude.time, attitude.accuracy);
3090
+ }
3091
+ };
3092
+ }
3093
+ if (this._smoothing !== null) {
3094
+ if (newAttitude.time >= this._smoothing.toTime) {
3095
+ this._smoothing = null;
3096
+ } else {
3097
+ const interpAttitude = this._smoothing.interpAttitude(newAttitude);
3098
+ this.callback(interpAttitude);
3099
+ return;
3100
+ }
3101
+ }
3102
+ this.callback(newAttitude);
3103
+ }
3104
+ static isJump(previousAttitude, newAttitude) {
3105
+ const fromHeading = previousAttitude.heading;
3106
+ const toHeading = newAttitude.heading;
3107
+ const diffAngleHeading = maths.diffAngle(toHeading, fromHeading);
3108
+ const diffTime = newAttitude.time - previousAttitude.time;
3109
+ const [qw, qx, qy, qz] = newAttitude.quaternion;
3110
+ const distToPitchThreshold = Math.abs(Math.asin(2 * (qw * qx + qy * qz)) - Math.PI / 4);
3111
+ if (distToPitchThreshold < _AttitudeSmoother.PITCH_UNCERTAINITY_HEADING_THRESHOLD) {
3112
+ return false;
3113
+ }
3114
+ return Math.abs(diffAngleHeading) > _AttitudeSmoother.ROTATION_SPEED_JUMP_THRESHOLD * diffTime;
3115
+ }
3116
+ };
3117
+ let AttitudeSmoother = _AttitudeSmoother;
3118
+ __publicField(AttitudeSmoother, "ROTATION_SPEED_JUMP_THRESHOLD", maths.deg2rad(180));
3119
+ __publicField(AttitudeSmoother, "ROTATION_SPEED_CONVERGENCE", maths.deg2rad(10));
3120
+ __publicField(AttitudeSmoother, "HIGH_JUMP_THRESHOLD", maths.deg2rad(20));
3121
+ __publicField(AttitudeSmoother, "ROTATION_SPEED_HIGH_JUMP_CONVERGENCE", maths.deg2rad(100));
3122
+ __publicField(AttitudeSmoother, "PITCH_UNCERTAINITY_HEADING_THRESHOLD", maths.deg2rad(5));
3123
+ class MagnetometerCalibrationProvider extends Provider {
3124
+ constructor() {
3125
+ super();
3126
+ __publicField(this, "getName", () => "MagnetometerCalibrationProvider");
3127
+ __publicField(this, "availability", () => AbsoluteAttitudeProvider$1.getAvailability());
3128
+ AbsoluteAttitudeProvider$1._setCallbackMagCalibration((e) => this.state === "started" && this.notify(e));
3129
+ }
3130
+ start() {
3131
+ }
3132
+ stop() {
3133
+ }
3134
+ }
3135
+ const MagnetometerCalibrationProvider$1 = new MagnetometerCalibrationProvider();
3136
+ const _IpResolveServerError = class extends Error {
3137
+ constructor(message) {
3138
+ super(message || _IpResolveServerError.DEFAULT_MESSAGE);
3139
+ }
3140
+ };
3141
+ let IpResolveServerError = _IpResolveServerError;
3142
+ __publicField(IpResolveServerError, "DEFAULT_MESSAGE", "IP Resolver failed");
3143
+ class IpProvider extends Provider {
3144
+ constructor() {
3145
+ super(...arguments);
3146
+ __publicField(this, "getName", () => "Ip");
3147
+ __publicField(this, "availability", () => Promise.resolve());
3148
+ }
3149
+ async start() {
3150
+ const response = await fetch("https://ipinfo.io/geo?token=24a7ca2f3b489d");
3151
+ if (!response) {
3152
+ this.notifyError(new IpResolveServerError());
3153
+ return;
3154
+ }
3155
+ const timestamp = utils.TimeUtils.preciseTime() / 1e3;
3156
+ const latLngStr = (await response.json()).loc.split(",");
3157
+ const position = new geo.UserPosition(
3158
+ parseFloat(latLngStr[0]),
3159
+ parseFloat(latLngStr[1]),
3160
+ null,
3161
+ null,
3162
+ timestamp,
3163
+ 1e5
3164
+ );
3165
+ this.notify(position);
3166
+ }
3167
+ stop() {
3168
+ }
3169
+ }
3170
+ const IpProvider$1 = new IpProvider();
3171
+ class BarcodePoleStarProvider extends Provider {
3172
+ constructor() {
3173
+ super(...arguments);
3174
+ __publicField(this, "providerId");
3175
+ __publicField(this, "getName", () => "Barcode");
3176
+ __publicField(this, "availability", () => ArCoreProvider$1.getAvailability());
3177
+ }
3178
+ start() {
3179
+ ArCoreProvider$1.enableBarcodeScanner();
3180
+ this.providerId = ArCoreProvider$1.addEventListener(
3181
+ (event) => event.barcode && this.notify(event.barcode),
3182
+ this.notifyError
3183
+ );
3184
+ }
3185
+ stop() {
3186
+ ArCoreProvider$1.disableBarcodeScanner();
3187
+ ArCoreProvider$1.removeEventListener(this.providerId);
3188
+ }
3189
+ }
3190
+ const BarcodeProvider = new BarcodePoleStarProvider();
3191
+ class CameraNativeProvider extends Provider {
3192
+ constructor() {
3193
+ super(...arguments);
3194
+ __publicField(this, "providerId");
3195
+ __publicField(this, "getName", () => "CameraNative");
3196
+ __publicField(this, "availability", () => Promise.resolve());
3197
+ }
3198
+ start() {
3199
+ if (ArCoreProvider$1.state !== "stopped") {
3200
+ this.notify("started");
3201
+ }
3202
+ this.providerId = ArCoreProvider$1.addMonitoringListener(
3203
+ () => this.notify("started"),
3204
+ () => this.notify("stopped")
3205
+ );
3206
+ }
3207
+ stop() {
3208
+ ArCoreProvider$1.removeMonitoringListener(this.providerId);
3209
+ }
3210
+ }
3211
+ const CameraNativeProvider$1 = new CameraNativeProvider();
3212
+ class CameraProjectionMatrixProvider extends Provider {
3213
+ constructor() {
3214
+ super(...arguments);
3215
+ __publicField(this, "providerId");
3216
+ __publicField(this, "getName", () => "CameraProjectionMatrix");
3217
+ __publicField(this, "availability", () => ArCoreProvider$1.getAvailability());
3218
+ }
3219
+ start() {
3220
+ this.providerId = ArCoreProvider$1.addEventListener(
3221
+ (event) => event.cameraProjection && this.notify(event.cameraProjection),
3222
+ this.notifyError
3223
+ );
3224
+ }
3225
+ stop() {
3226
+ ArCoreProvider$1.removeEventListener(this.providerId);
3227
+ }
3228
+ }
3229
+ const CameraProjectionMatrixProvider$1 = new CameraProjectionMatrixProvider();
3230
+ exports.AbsoluteAttitude = AbsoluteAttitude;
3231
+ exports.AbsoluteAttitudeFromBrowserProvider = AbsoluteAttitudeFromBrowser$1;
3232
+ exports.AbsoluteAttitudeProvider = AbsoluteAttitudeProvider$1;
3233
+ exports.AbsolutePosition = AbsolutePosition;
3234
+ exports.AbsolutePositionProvider = AbsolutePositionProvider$1;
3235
+ exports.AccelerometerProvider = AccelerometerProvider$1;
3236
+ exports.ArCoreProvider = ArCoreProvider$1;
3237
+ exports.AttitudeSmoother = AttitudeSmoother;
3238
+ exports.BarcodeProvider = BarcodeProvider;
3239
+ exports.CameraNativeProvider = CameraNativeProvider$1;
3240
+ exports.CameraProjectionMatrixProvider = CameraProjectionMatrixProvider$1;
3241
+ exports.GeoRelativePositionFromArCoreProvider = GeoRelativePositionFromArCoreProvider$1;
3242
+ exports.GeoRelativePositionProvider = GeoRelativePositionProvider$1;
3243
+ exports.GnssWifiProvider = GnssWifiProvider$1;
3244
+ exports.GyroscopeProvider = GyroscopeProvider$1;
3245
+ exports.HighRotationsProvider = HighRotationsProvider$1;
3246
+ exports.ImageRelocalization = ImageRelocalization;
3247
+ exports.ImuProvider = ImuProvider$1;
3248
+ exports.InclinationFromAccProvider = InclinationFromAccProvider$1;
3249
+ exports.InclinationFromRelativeAttitudeProvider = InclinationFromRelativeAttitudeProvider$1;
3250
+ exports.InclinationProvider = InclinationProvider$1;
3251
+ exports.IpProvider = IpProvider$1;
3252
+ exports.MagnetometerCalibrationProvider = MagnetometerCalibrationProvider$1;
3253
+ exports.MapMatchingHandler = MapMatchingHandler$1;
3254
+ exports.PdrProvider = PdrProvider$1;
3255
+ exports.PoleStarProvider = PoleStarProvider$1;
3256
+ exports.PositionSmoother = PositionSmoother;
3257
+ exports.ProvidersLoggerOld = ProvidersLoggerOld$1;
3258
+ exports.ProvidersOptions = ProvidersOptions;
3259
+ exports.RelativeAttitude = RelativeAttitude;
3260
+ exports.RelativeAttitudeFromBrowserProvider = RelativeAttitudeFromBrowser$1;
3261
+ exports.RelativeAttitudeFromEkfProvider = RelativeAttitudeFromEkfProvider;
3262
+ exports.RelativeAttitudeFromInertialProvider = RelativeAttitudeFromInertialProvider;
3263
+ exports.RelativeAttitudeProvider = RelativeAttitudeProvider$1;
3264
+ exports.StepDetectionMinMaxPeaks2 = StepDetectionMinMaxPeaks2;
3265
+ exports.StepDetectionMinMaxPeaks3 = StepDetectionMinMaxPeaks3;
3266
+ exports.StepProvider = StepProvider$1;
3267
+ exports.StraightLineProvider = StraightLineProvider$1;
3268
+ exports.TurnProvider = TurnProvider$1;
3269
+ exports.VpsMetadata = VpsMetadata;
3270
+ exports.VpsProvider = VpsProvider$1;
3271
+ exports.VpsRequest = VpsRequest;
3272
+ exports.VpsResponse = VpsResponse;
3273
+ //# sourceMappingURL=index.js.map