@wemap/providers 5.6.1 → 5.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  import { deg2rad, Vector3, Matrix, Quaternion, Matrix3, Matrix4, Vector, Rotations, std, diffAngleLines, diffAngle, rad2deg } from '@wemap/maths';
2
2
  import { BrowserUtils, Browser, PromiseUtils, TimeUtils } from '@wemap/utils';
3
3
  import Logger from '@wemap/logger';
4
- import { Attitude, RelativePosition, AbsoluteHeading, Constants as Constants$1, MapMatching, UserPosition, GraphEdge, GeoRelativePosition as GeoRelativePosition$1, Network } from '@wemap/geo';
4
+ import { Attitude, RelativePosition, Constants as Constants$1, MapMatching, UserPosition, GraphEdge, AbsoluteHeading, GeoRelativePosition as GeoRelativePosition$1, Network } from '@wemap/geo';
5
5
  import geomagnetism from '@wemap/geomagnetism';
6
6
  import { Itinerary } from '@wemap/osm';
7
7
 
@@ -14,6 +14,7 @@ var EventType = {
14
14
  MagneticField: 'MAGNETIC_FIELD',
15
15
  AngularRate: 'ANGULAR_RATE',
16
16
  Acceleration: 'ACCELERATION',
17
+ MagnetometerNeedCalibration: 'MAGNETOMETER_NEED_CALIBRATION',
17
18
 
18
19
  RelativeAttitude: 'RELATIVE_ATTITUDE',
19
20
  AbsoluteAttitude: 'ABSOLUTE_ATTITUDE',
@@ -876,6 +877,12 @@ class HighRotationsDetector extends Provider {
876
877
 
877
878
  var HighRotationsDetector$1 = new HighRotationsDetector();
878
879
 
880
+ class MissingMagnetometerError extends MissingSensorError {
881
+ constructor(message) {
882
+ super(message);
883
+ }
884
+ }
885
+
879
886
  const DEFAULT_RELATIVE_NOISES = {
880
887
  acc: 0.5,
881
888
  gyr: 0.3
@@ -1196,86 +1203,6 @@ class RelativeAttitudeFromEkf extends Provider {
1196
1203
 
1197
1204
  var RelativeAttitudeFromEkf$1 = new RelativeAttitudeFromEkf();
1198
1205
 
1199
- class RelativeAttitudeFromInertial extends Provider {
1200
-
1201
- /**
1202
- * default relative attitude drift in rad.second-1
1203
- */
1204
- DEFAULT_DRIFT = deg2rad(5) / 60;
1205
-
1206
-
1207
- /**
1208
- * @override
1209
- */
1210
- static get pname() {
1211
- return 'RelativeAttitudeFromInertial';
1212
- }
1213
-
1214
- /**
1215
- * @override
1216
- */
1217
- static get eventsType() {
1218
- return [EventType.RelativeAttitude];
1219
- }
1220
-
1221
- /**
1222
- * @override
1223
- */
1224
- get _availability() {
1225
- return PromiseUtils.any([
1226
- RelativeAttitudeFromEkf$1.availability,
1227
- RelativeAttitudeFromBrowser$1.availability,
1228
- HighRotationsDetector$1.availability
1229
- ]);
1230
- }
1231
-
1232
- /**
1233
- * @override
1234
- */
1235
- start() {
1236
-
1237
- RelativeAttitudeFromEkf$1.availability
1238
- .then(() => (this.provider = RelativeAttitudeFromEkf$1))
1239
- .catch(() => (this.provider = RelativeAttitudeFromBrowser$1))
1240
- .finally(() => {
1241
- this.listenerId = this.provider.addEventListener(
1242
- events => this._parseEvent(events[0]),
1243
- error => this.notifyError(error)
1244
- );
1245
- this._highRotationsDetector = HighRotationsDetector$1.addEventListener(
1246
- () => {},
1247
- error => this.notifyError(error)
1248
- );
1249
- });
1250
- }
1251
-
1252
- /**
1253
- * @param {ProviderEvent<Attitude>} event
1254
- */
1255
- _parseEvent(event) {
1256
- const relativeAttitudeEvent = event.clone();
1257
- if (HighRotationsDetector$1.isInProgress()) {
1258
- let accuracy = relativeAttitudeEvent.data.accuracy + (this.DEFAULT_DRIFT * 100);
1259
- accuracy = Math.min(accuracy, Math.PI);
1260
- relativeAttitudeEvent.data.accuracy = accuracy;
1261
- }
1262
- this.notify(relativeAttitudeEvent);
1263
- }
1264
-
1265
- /**
1266
- * @override
1267
- */
1268
- stop() {
1269
- if (this.provider) {
1270
- this.provider.removeEventListener(this.listenerId);
1271
- this.provider = null;
1272
- }
1273
- HighRotationsDetector$1.removeEventListener(this._highRotationsDetector);
1274
- }
1275
- }
1276
-
1277
- var RelativeAttitudeFromInertial$1 = new RelativeAttitudeFromInertial();
1278
-
1279
1206
  /**
1280
1207
  * Relative attitude provider gives the device attitude in a custom frame (x-right, y-front, z-up) using
1281
1208
  * browser deviceorientation
@@ -1363,6 +1290,86 @@ class RelativeAttitudeFromBrowser extends Provider {
1363
1290
 
1364
1291
  var RelativeAttitudeFromBrowser$1 = new RelativeAttitudeFromBrowser();
1365
1292
 
1293
+ class RelativeAttitudeFromInertial extends Provider {
1294
+
1295
+ /**
1296
+ * default relative attitude drift in rad.second-1
1297
+ */
1298
+ DEFAULT_DRIFT = deg2rad(5) / 60;
1299
+
1300
+
1301
+ /**
1302
+ * @override
1303
+ */
1304
+ static get pname() {
1305
+ return 'RelativeAttitudeFromInertial';
1306
+ }
1307
+
1308
+ /**
1309
+ * @override
1310
+ */
1311
+ static get eventsType() {
1312
+ return [EventType.RelativeAttitude];
1313
+ }
1314
+
1315
+ /**
1316
+ * @override
1317
+ */
1318
+ get _availability() {
1319
+ return PromiseUtils.any([
1320
+ RelativeAttitudeFromEkf$1.availability,
1321
+ RelativeAttitudeFromBrowser$1.availability,
1322
+ HighRotationsDetector$1.availability
1323
+ ]);
1324
+ }
1325
+
1326
+ /**
1327
+ * @override
1328
+ */
1329
+ start() {
1330
+
1331
+ RelativeAttitudeFromEkf$1.availability
1332
+ .then(() => (this.provider = RelativeAttitudeFromEkf$1))
1333
+ .catch(() => (this.provider = RelativeAttitudeFromBrowser$1))
1334
+ .finally(() => {
1335
+ this.listenerId = this.provider.addEventListener(
1336
+ events => this._parseEvent(events[0]),
1337
+ error => this.notifyError(error)
1338
+ );
1339
+ this._highRotationsDetector = HighRotationsDetector$1.addEventListener(
1340
+ () => {},
1341
+ error => this.notifyError(error)
1342
+ );
1343
+ });
1344
+ }
1345
+
1346
+ /**
1347
+ * @param {ProviderEvent<Attitude>} event
1348
+ */
1349
+ _parseEvent(event) {
1350
+ const relativeAttitudeEvent = event.clone();
1351
+ if (HighRotationsDetector$1.isInProgress()) {
1352
+ let accuracy = relativeAttitudeEvent.data.accuracy + (this.DEFAULT_DRIFT * 100);
1353
+ accuracy = Math.min(accuracy, Math.PI);
1354
+ relativeAttitudeEvent.data.accuracy = accuracy;
1355
+ }
1356
+ this.notify(relativeAttitudeEvent);
1357
+ }
1358
+
1359
+ /**
1360
+ * @override
1361
+ */
1362
+ stop() {
1363
+ if (this.provider) {
1364
+ this.provider.removeEventListener(this.listenerId);
1365
+ this.provider = null;
1366
+ }
1367
+ HighRotationsDetector$1.removeEventListener(this._highRotationsDetector);
1368
+ }
1369
+ }
1370
+
1371
+ var RelativeAttitudeFromInertial$1 = new RelativeAttitudeFromInertial();
1372
+
1366
1373
  class MissingArCoreError extends Error {
1367
1374
 
1368
1375
  static DEFAULT_MESSAGE = 'ARCore is missing';
@@ -1658,327 +1665,70 @@ class RelativeAttitude extends Provider {
1658
1665
 
1659
1666
  var RelativeAttitude$1 = new RelativeAttitude();
1660
1667
 
1661
- class MissingMagnetometerError extends MissingSensorError {
1662
- constructor(message) {
1663
- super(message);
1664
- }
1665
- }
1666
-
1667
- /**
1668
- * Absolute attitude provider gives the device attitude in East-North-Up (ENU) frame
1669
- */
1670
- class AbsoluteAttitude extends Provider {
1671
-
1672
- /** @type {boolean} */
1673
- _attitudeFromBrowserErrored = false;
1674
-
1675
- /** @type {boolean} */
1676
- _attitudeFromRelativeErrored = false;
1677
-
1678
- /*
1679
- * RELATIVE
1680
- */
1681
-
1682
- /** @type {Attitude} */
1683
- _relativeAttitude = null;
1684
-
1685
- /** @type {number} in radians/s */
1686
- _relativeAccuracy = 0;
1687
-
1688
- /** @type {ProviderEvent<Attitude|AbsoluteHeading>} */
1689
- _lastForcedHeadingEvent;
1668
+ class TurnDetector extends Provider {
1690
1669
 
1691
- /** @type {number[]} quaternion offset from relative to absolute */
1692
- _relAbsQuat;
1670
+ // in seconds
1671
+ static SLIDING_WINDOW_TIME = 0.3;
1693
1672
 
1673
+ static STD_THRESHOLD = 0.075;
1694
1674
 
1695
- constructor() {
1696
- super();
1675
+ /** @type {number} in seconds */
1676
+ static CONSIDER_TURN_UNTIL = 1;
1697
1677
 
1698
- this._attitudeFromBrowserErrored = false;
1699
- this._attitudeFromRelativeErrored = false;
1700
- }
1678
+ /** @type {number[]} */
1679
+ slidingWindow = [];
1701
1680
 
1702
1681
  /**
1703
1682
  * @override
1704
1683
  */
1705
1684
  static get pname() {
1706
- return 'AbsoluteAttitude';
1685
+ return 'TurnDetector';
1707
1686
  }
1708
1687
 
1709
1688
  /**
1710
1689
  * @override
1711
1690
  */
1712
1691
  static get eventsType() {
1713
- return [EventType.AbsoluteAttitude];
1692
+ return [EventType.Turn];
1714
1693
  }
1715
1694
 
1716
1695
  /**
1717
1696
  * @override
1718
1697
  */
1719
1698
  get _availability() {
1720
- return PromiseUtils.any([
1721
- AbsoluteAttitudeFromBrowser$1.availability,
1722
- RelativeAttitude$1.availability
1723
- ]);
1699
+ return RelativeAttitude$1.availability;
1724
1700
  }
1725
1701
 
1726
1702
  /**
1727
1703
  * @override
1728
1704
  */
1729
1705
  start() {
1730
-
1731
- this.fromBrowserProviderId = AbsoluteAttitudeFromBrowser$1.addEventListener(
1732
- events => this._onAttitudeFromBrowser(events[0]),
1733
- error => {
1734
- this._attitudeFromBrowserErrored = true;
1735
- this.onError(error);
1736
- }
1737
- );
1738
-
1739
- this.relativeAttitudeProviderId = RelativeAttitude$1.addEventListener(
1740
- events => this._onRelativeAttitudeEvent(events[0]),
1741
- error => {
1742
- this._attitudeFromRelativeErrored = true;
1743
- this.onError(error);
1744
- }
1706
+ this.providerId = RelativeAttitude$1.addEventListener(
1707
+ events => this._parseRelativeAttitude(events[0]),
1708
+ error => this.notifyError(error)
1745
1709
  );
1746
-
1747
1710
  }
1748
1711
 
1749
1712
  /**
1750
1713
  * @override
1751
1714
  */
1752
1715
  stop() {
1753
- AbsoluteAttitudeFromBrowser$1.removeEventListener(this.fromBrowserProviderId);
1754
- RelativeAttitude$1.removeEventListener(this.relativeAttitudeProviderId);
1716
+ RelativeAttitude$1.removeEventListener(this.providerId);
1755
1717
  }
1756
1718
 
1757
- onError(error) {
1758
- if (this._attitudeFromBrowserErrored && this._attitudeFromRelativeErrored) {
1759
- this.notifyError(error);
1719
+ isTurning() {
1720
+ if (!this.lastEvent || !RelativeAttitude$1.lastEvent) {
1721
+ return false;
1760
1722
  }
1761
- }
1762
1723
 
1724
+ const diffTime = RelativeAttitude$1.lastEvent.data.time - this.lastEvent.data.timestamp;
1725
+ return diffTime < TurnDetector.CONSIDER_TURN_UNTIL;
1726
+ }
1763
1727
 
1764
1728
  /**
1765
- * @param {ProviderEvent<Attitude|AbsoluteHeading>} absoluteHeadingEvent
1729
+ * @private
1766
1730
  */
1767
- _forceHeadingForRelative = (absoluteHeadingEvent) => {
1768
-
1769
- if (this.lastEvent && absoluteHeadingEvent.data.accuracy > this.lastEvent.data.accuracy) {
1770
- return;
1771
- }
1772
-
1773
-
1774
- /**
1775
- * @param {Attitude} relativeAttitude
1776
- */
1777
- const calcForceHeading = (relativeAttitude) => {
1778
- const currentRelativeHeading = relativeAttitude.heading;
1779
-
1780
- this._relAbsQuat = Quaternion.fromAxisAngle(
1781
- [0, 0, 1],
1782
- currentRelativeHeading - absoluteHeadingEvent.data.heading
1783
- );
1784
-
1785
- this._relativeAccuracy = 0;
1786
- this._lastForcedHeadingEvent = absoluteHeadingEvent;
1787
- };
1788
-
1789
- // If relativeAttitude does not exist yet, wait the next
1790
- if (this._relativeAttitude) {
1791
- calcForceHeading(this._relativeAttitude);
1792
- return;
1793
- }
1794
-
1795
- // If this._relativeAttitude does not exist, wait the first value
1796
- // /!\ This works only if the relative attitude event is provided rapidly.
1797
- const providerId = RelativeAttitude$1.addEventListener(
1798
- events => {
1799
- calcForceHeading(events[0].data);
1800
- RelativeAttitude$1.removeEventListener(providerId);
1801
- }
1802
- );
1803
-
1804
- };
1805
-
1806
- /**
1807
- * @param {ProviderEvent<Attitude>} event
1808
- */
1809
- _onRelativeAttitudeEvent(event) {
1810
-
1811
- const { quaternion, accuracy, time } = event.data;
1812
-
1813
- // Calculate relative accuracy
1814
- if (this._relativeAttitude) {
1815
- this._relativeAccuracy += (time - this._relativeAttitude.time) * accuracy;
1816
- }
1817
-
1818
- // Keep the relative attitude event for the calculation of relAbsQuat
1819
- // /!\ Keep this even if forced heading is not set /!\
1820
- this._relativeAttitude = event.data;
1821
-
1822
-
1823
- if (!this._lastForcedHeadingEvent) {
1824
- return;
1825
- }
1826
-
1827
- const accuracyWithRelative = Math.min(
1828
- this._lastForcedHeadingEvent.data.accuracy + this._relativeAccuracy,
1829
- Math.PI
1830
- );
1831
-
1832
- let newAccuracy = accuracyWithRelative;
1833
- let relAbsQuat = this._relAbsQuat;
1834
-
1835
- if (this._eventFromBrowser) {
1836
-
1837
- const {
1838
- accuracy: accuracyWithAbsolute,
1839
- heading: headingFromAbsolute
1840
- } = this._eventFromBrowser.data;
1841
-
1842
- if (accuracyWithAbsolute < accuracyWithRelative) {
1843
- newAccuracy = accuracyWithAbsolute;
1844
- relAbsQuat = Quaternion.fromAxisAngle([0, 0, 1], event.data.heading - headingFromAbsolute);
1845
- }
1846
- }
1847
-
1848
- const absoluteQuat = Quaternion.multiply(relAbsQuat, quaternion);
1849
- const attitude = new Attitude(absoluteQuat, time, newAccuracy);
1850
-
1851
- this.notify(this.createEvent(
1852
- EventType.AbsoluteAttitude,
1853
- attitude,
1854
- [event, this._lastForcedHeadingEvent]
1855
- ));
1856
- }
1857
-
1858
-
1859
- /**
1860
- * @param {ProviderEvent<Attitude>} event
1861
- */
1862
- _onAttitudeFromBrowser(event) {
1863
- this._eventFromBrowser = event;
1864
-
1865
- if (!this._lastForcedHeadingEvent) {
1866
- this._forceHeadingForRelative(event);
1867
- return;
1868
- }
1869
-
1870
- // Absolute attitude from browser is not used anymore due to magnetometer inaccuracy on pitch and roll
1871
- }
1872
-
1873
- /**
1874
- * @override
1875
- * @param {AbsoluteHeading|Attitude|ProviderEvent} data
1876
- */
1877
- feed(data) {
1878
-
1879
- if (data instanceof AbsoluteHeading) {
1880
-
1881
- if (data.time === null) {
1882
- throw Error('the time of the absolute heading is not defined');
1883
- }
1884
- if (data.accuracy === null) {
1885
- throw Error('the accuracy of the absolute heading is not defined');
1886
- }
1887
-
1888
- this._forceHeadingForRelative(new ProviderEvent(EventType.AbsoluteHeading, data));
1889
-
1890
- } else if (data instanceof Attitude) {
1891
-
1892
- if (data.time === null) {
1893
- throw Error('the time of the attitude is not defined');
1894
- }
1895
- if (data.accuracy === null) {
1896
- throw Error('the accuracy of the attitude is not defined');
1897
- }
1898
-
1899
- this._forceHeadingForRelative(new ProviderEvent(EventType.AbsoluteHeading, data));
1900
-
1901
- } else if (data instanceof ProviderEvent) {
1902
-
1903
- if (data.dataType !== EventType.AbsoluteHeading
1904
- || !(data.data instanceof AbsoluteHeading)) {
1905
- throw Error('the provider event is not an AbsoluteHeading');
1906
- }
1907
-
1908
- this._forceHeadingForRelative(data);
1909
-
1910
- } else {
1911
- throw new Error('data is nor an AbsoluteHeading or an Attitude object');
1912
- }
1913
- }
1914
- }
1915
-
1916
- var AbsoluteAttitude$1 = new AbsoluteAttitude();
1917
-
1918
- class TurnDetector extends Provider {
1919
-
1920
- // in seconds
1921
- static SLIDING_WINDOW_TIME = 0.3;
1922
-
1923
- static STD_THRESHOLD = 0.075;
1924
-
1925
- /** @type {number} in seconds */
1926
- static CONSIDER_TURN_UNTIL = 1;
1927
-
1928
- /** @type {number[]} */
1929
- slidingWindow = [];
1930
-
1931
- /**
1932
- * @override
1933
- */
1934
- static get pname() {
1935
- return 'TurnDetector';
1936
- }
1937
-
1938
- /**
1939
- * @override
1940
- */
1941
- static get eventsType() {
1942
- return [EventType.Turn];
1943
- }
1944
-
1945
- /**
1946
- * @override
1947
- */
1948
- get _availability() {
1949
- return RelativeAttitude$1.availability;
1950
- }
1951
-
1952
- /**
1953
- * @override
1954
- */
1955
- start() {
1956
- this.providerId = RelativeAttitude$1.addEventListener(
1957
- events => this._parseRelativeAttitude(events[0]),
1958
- error => this.notifyError(error)
1959
- );
1960
- }
1961
-
1962
- /**
1963
- * @override
1964
- */
1965
- stop() {
1966
- RelativeAttitude$1.removeEventListener(this.providerId);
1967
- }
1968
-
1969
- isTurning() {
1970
- if (!this.lastEvent || !RelativeAttitude$1.lastEvent) {
1971
- return false;
1972
- }
1973
-
1974
- const diffTime = RelativeAttitude$1.lastEvent.data.time - this.lastEvent.data.timestamp;
1975
- return diffTime < TurnDetector.CONSIDER_TURN_UNTIL;
1976
- }
1977
-
1978
- /**
1979
- * @private
1980
- */
1981
- _parseRelativeAttitude = relativeAttitudeEvent => {
1731
+ _parseRelativeAttitude = relativeAttitudeEvent => {
1982
1732
 
1983
1733
  const { heading, time: timestamp } = relativeAttitudeEvent.data;
1984
1734
 
@@ -3884,6 +3634,392 @@ class Inclination extends Provider {
3884
3634
 
3885
3635
  var Inclination$1 = new Inclination();
3886
3636
 
3637
+ /* eslint-disable max-statements */
3638
+
3639
+ /**
3640
+ * Absolute attitude provider gives the device attitude in East-North-Up (ENU) frame
3641
+ */
3642
+ class AbsoluteAttitude extends Provider {
3643
+
3644
+ /** @type {number} */
3645
+ static REL_ABS_DIVERGENCE_ANGLE_THRESHOLD = deg2rad(25);
3646
+
3647
+ /** @type {number} in seconds */
3648
+ static REL_ABS_DIVERGENCE_TIME_THRESHOLD = 2.5;
3649
+
3650
+ /** @type {number} */
3651
+ static REL_ABS_DIVERGENCE_INCLINATION_THRESHOLD = deg2rad(15);
3652
+
3653
+ /** @type {boolean} */
3654
+ _attitudeFromBrowserErrored = false;
3655
+
3656
+ /** @type {boolean} */
3657
+ _attitudeFromRelativeErrored = false;
3658
+
3659
+ /*
3660
+ * RELATIVE
3661
+ */
3662
+
3663
+ /** @type {Attitude} */
3664
+ _relativeAttitude = null;
3665
+
3666
+ /** @type {number} in radians/s */
3667
+ _relativeAccuracy = 0;
3668
+
3669
+ /** @type {ProviderEvent<Attitude|AbsoluteHeading>} */
3670
+ _lastForcedHeadingEvent;
3671
+
3672
+ /** @type {number[]} quaternion offset from relative to absolute */
3673
+ _relAbsQuat;
3674
+
3675
+ /** @type {boolean} */
3676
+ _wasHighRotationInProgress = false;
3677
+
3678
+ /** @type {?number} */
3679
+ _timeFirstDivergence = null;
3680
+
3681
+
3682
+ constructor() {
3683
+ super();
3684
+
3685
+ this._attitudeFromBrowserErrored = false;
3686
+ this._attitudeFromRelativeErrored = false;
3687
+ }
3688
+
3689
+ /**
3690
+ * @override
3691
+ */
3692
+ static get pname() {
3693
+ return 'AbsoluteAttitude';
3694
+ }
3695
+
3696
+ /**
3697
+ * @override
3698
+ */
3699
+ static get eventsType() {
3700
+ return [EventType.AbsoluteAttitude];
3701
+ }
3702
+
3703
+ /**
3704
+ * @override
3705
+ */
3706
+ get _availability() {
3707
+ return PromiseUtils.any([
3708
+ AbsoluteAttitudeFromBrowser$1.availability,
3709
+ RelativeAttitude$1.availability
3710
+ ]);
3711
+ }
3712
+
3713
+ /**
3714
+ * @override
3715
+ */
3716
+ start() {
3717
+
3718
+ this.fromBrowserProviderId = AbsoluteAttitudeFromBrowser$1.addEventListener(
3719
+ events => this._onAttitudeFromBrowser(events[0]),
3720
+ error => {
3721
+ this._attitudeFromBrowserErrored = true;
3722
+ this.onError(error);
3723
+ }
3724
+ );
3725
+
3726
+ this.relativeAttitudeProviderId = RelativeAttitude$1.addEventListener(
3727
+ events => this._onRelativeAttitudeEvent(events[0]),
3728
+ error => {
3729
+ this._attitudeFromRelativeErrored = true;
3730
+ this.onError(error);
3731
+ }
3732
+ );
3733
+
3734
+ this.inclinationProviderId = Inclination$1.addEventListener();
3735
+
3736
+ this.highRotationDetectorId = HighRotationsDetector$1.addEventListener();
3737
+ }
3738
+
3739
+ /**
3740
+ * @override
3741
+ */
3742
+ stop() {
3743
+ AbsoluteAttitudeFromBrowser$1.removeEventListener(this.fromBrowserProviderId);
3744
+ RelativeAttitude$1.removeEventListener(this.relativeAttitudeProviderId);
3745
+ Inclination$1.removeEventListener(this.inclinationProviderId);
3746
+ HighRotationsDetector$1.removeEventListener(this.highRotationDetectorId);
3747
+ }
3748
+
3749
+ onError(error) {
3750
+ if (this._attitudeFromBrowserErrored && this._attitudeFromRelativeErrored) {
3751
+ this.notifyError(error);
3752
+ }
3753
+ }
3754
+
3755
+
3756
+ /**
3757
+ * @param {ProviderEvent<Attitude|AbsoluteHeading>} absoluteHeadingEvent
3758
+ */
3759
+ _forceHeadingForRelative = (absoluteHeadingEvent) => {
3760
+
3761
+ if (this.lastEvent && absoluteHeadingEvent.data.accuracy > this.lastEvent.data.accuracy) {
3762
+ return;
3763
+ }
3764
+
3765
+
3766
+ /**
3767
+ * @param {Attitude} relativeAttitude
3768
+ */
3769
+ const calcForceHeading = (relativeAttitude) => {
3770
+ const currentRelativeHeading = relativeAttitude.heading;
3771
+
3772
+ this._relAbsQuat = Quaternion.fromAxisAngle(
3773
+ [0, 0, 1],
3774
+ currentRelativeHeading - absoluteHeadingEvent.data.heading
3775
+ );
3776
+
3777
+ this._relativeAccuracy = 0;
3778
+ this._lastForcedHeadingEvent = absoluteHeadingEvent;
3779
+ };
3780
+
3781
+ // If relativeAttitude does not exist yet, wait the next
3782
+ if (this._relativeAttitude) {
3783
+ calcForceHeading(this._relativeAttitude);
3784
+ return;
3785
+ }
3786
+
3787
+ // If this._relativeAttitude does not exist, wait the first value
3788
+ // /!\ This works only if the relative attitude event is provided rapidly.
3789
+ const providerId = RelativeAttitude$1.addEventListener(
3790
+ events => {
3791
+ calcForceHeading(events[0].data);
3792
+ RelativeAttitude$1.removeEventListener(providerId);
3793
+ }
3794
+ );
3795
+
3796
+ };
3797
+
3798
+ /**
3799
+ * @param {ProviderEvent<Attitude>} event
3800
+ */
3801
+ _onRelativeAttitudeEvent(event) {
3802
+
3803
+ const { quaternion, accuracy, time } = event.data;
3804
+
3805
+ // Calculate relative accuracy
3806
+ if (this._relativeAttitude) {
3807
+ this._relativeAccuracy += (time - this._relativeAttitude.time) * accuracy;
3808
+ }
3809
+
3810
+ // Keep the relative attitude event for the calculation of relAbsQuat
3811
+ // /!\ Keep this even if forced heading is not set /!\
3812
+ this._relativeAttitude = event.data;
3813
+
3814
+
3815
+ if (!this._lastForcedHeadingEvent) {
3816
+ return;
3817
+ }
3818
+
3819
+ const accuracyWithRelative = Math.min(
3820
+ this._lastForcedHeadingEvent.data.accuracy + this._relativeAccuracy,
3821
+ Math.PI
3822
+ );
3823
+
3824
+ const highRotationInProgress = HighRotationsDetector$1.isInProgress();
3825
+
3826
+ let magnetometerNeedCalibrationEvent = null;
3827
+ let divergenceDetected = false;
3828
+
3829
+ if (this._eventFromBrowser) {
3830
+
3831
+ const {
3832
+ accuracy: accuracyWithAbsolute,
3833
+ heading: headingFromAbsolute
3834
+ } = this._eventFromBrowser.data;
3835
+
3836
+ if (this._wasHighRotationInProgress && !highRotationInProgress) {
3837
+ // Update heading for relative if it the end of high rotations
3838
+ // (probably due to a magnetometer calibratiton)
3839
+ this._forceHeadingForRelative(this._eventFromBrowser);
3840
+
3841
+ } else if (accuracyWithAbsolute < accuracyWithRelative) {
3842
+ // Update heading for relative if:
3843
+ // (1) accuracy from absolute is better than relative
3844
+ // (2) heading divergence is greater than REL_ABS_DIVERGENCE_THRESHOLD
3845
+ const relativeQuaternion = Quaternion.multiply(this._relAbsQuat, quaternion);
3846
+ const relativeAttitude = new Attitude(relativeQuaternion);
3847
+ const angle = Math.abs(diffAngle(relativeAttitude.heading, headingFromAbsolute));
3848
+ const inclination = Inclination$1.lastEvent.data;
3849
+
3850
+
3851
+ if (angle > AbsoluteAttitude.REL_ABS_DIVERGENCE_ANGLE_THRESHOLD
3852
+ && Math.abs(inclination - Math.PI / 4) > AbsoluteAttitude.REL_ABS_DIVERGENCE_INCLINATION_THRESHOLD
3853
+ ) {
3854
+ divergenceDetected = true;
3855
+
3856
+ // Be sure before forcing heading
3857
+ if (this._timeFirstDivergence !== null
3858
+ && time - this._timeFirstDivergence > AbsoluteAttitude.REL_ABS_DIVERGENCE_TIME_THRESHOLD) {
3859
+
3860
+ this._forceHeadingForRelative(this._eventFromBrowser);
3861
+ magnetometerNeedCalibrationEvent = this.createEvent(
3862
+ EventType.MagnetometerNeedCalibration,
3863
+ {
3864
+ angle
3865
+ }, [event, this._lastForcedHeadingEvent]
3866
+ );
3867
+ this._timeFirstDivergence = null;
3868
+ } else if (this._timeFirstDivergence === null) {
3869
+ this._timeFirstDivergence = time;
3870
+ }
3871
+
3872
+ }
3873
+ }
3874
+
3875
+ }
3876
+
3877
+ if (!divergenceDetected) {
3878
+ this._timeFirstDivergence = null;
3879
+ }
3880
+
3881
+ this._wasHighRotationInProgress = highRotationInProgress;
3882
+
3883
+ const absoluteQuat = Quaternion.multiply(this._relAbsQuat, quaternion);
3884
+ const attitude = new Attitude(absoluteQuat, time, accuracyWithRelative);
3885
+
3886
+ const eventsToNotify = [
3887
+ this.createEvent(
3888
+ EventType.AbsoluteAttitude,
3889
+ attitude,
3890
+ [event, this._lastForcedHeadingEvent]
3891
+ )
3892
+ ];
3893
+ if (magnetometerNeedCalibrationEvent) {
3894
+ eventsToNotify.push(magnetometerNeedCalibrationEvent);
3895
+ }
3896
+
3897
+ this.notify(...eventsToNotify);
3898
+ }
3899
+
3900
+
3901
+ /**
3902
+ * @param {ProviderEvent<Attitude>} event
3903
+ */
3904
+ _onAttitudeFromBrowser(event) {
3905
+ this._eventFromBrowser = event;
3906
+
3907
+ if (!this._lastForcedHeadingEvent) {
3908
+ this._forceHeadingForRelative(event);
3909
+ return;
3910
+ }
3911
+
3912
+ // Absolute attitude from browser is not used anymore due to magnetometer inaccuracy on pitch and roll
3913
+ }
3914
+
3915
+ /**
3916
+ * @override
3917
+ * @param {AbsoluteHeading|Attitude|ProviderEvent} data
3918
+ */
3919
+ feed(data) {
3920
+
3921
+ if (data instanceof AbsoluteHeading) {
3922
+
3923
+ if (data.time === null) {
3924
+ throw Error('the time of the absolute heading is not defined');
3925
+ }
3926
+ if (data.accuracy === null) {
3927
+ throw Error('the accuracy of the absolute heading is not defined');
3928
+ }
3929
+
3930
+ this._forceHeadingForRelative(new ProviderEvent(EventType.AbsoluteHeading, data));
3931
+
3932
+ } else if (data instanceof Attitude) {
3933
+
3934
+ if (data.time === null) {
3935
+ throw Error('the time of the attitude is not defined');
3936
+ }
3937
+ if (data.accuracy === null) {
3938
+ throw Error('the accuracy of the attitude is not defined');
3939
+ }
3940
+
3941
+ this._forceHeadingForRelative(new ProviderEvent(EventType.AbsoluteHeading, data));
3942
+
3943
+ } else if (data instanceof ProviderEvent) {
3944
+
3945
+ if (data.dataType !== EventType.AbsoluteHeading
3946
+ || !(data.data instanceof AbsoluteHeading)) {
3947
+ throw Error('the provider event is not an AbsoluteHeading');
3948
+ }
3949
+
3950
+ this._forceHeadingForRelative(data);
3951
+
3952
+ } else {
3953
+ throw new Error('data is nor an AbsoluteHeading or an Attitude object');
3954
+ }
3955
+ }
3956
+ }
3957
+
3958
+ var AbsoluteAttitude$1 = new AbsoluteAttitude();
3959
+
3960
+ class MagnetometerCalibrationDetector extends Provider {
3961
+
3962
+ /**
3963
+ * @override
3964
+ */
3965
+ static get pname() {
3966
+ return 'MagnetometerCalibrationDetector';
3967
+ }
3968
+
3969
+
3970
+ /**
3971
+ * @override
3972
+ */
3973
+ static get eventsType() {
3974
+ return [EventType.MagnetometerNeedCalibration];
3975
+ }
3976
+
3977
+ /**
3978
+ * @override
3979
+ */
3980
+ get _availability() {
3981
+ return AbsoluteAttitude$1.availability;
3982
+ }
3983
+
3984
+ /**
3985
+ * @override
3986
+ */
3987
+ start() {
3988
+ this.providerId = AbsoluteAttitude$1.addEventListener(
3989
+ events => this._parseAbsoluteAttitudeEvents(events),
3990
+ error => this.notifyError(error),
3991
+ false
3992
+ );
3993
+ }
3994
+
3995
+ /**
3996
+ * @override
3997
+ */
3998
+ stop() {
3999
+ AbsoluteAttitude$1.removeEventListener(this.providerId);
4000
+ }
4001
+
4002
+ /**
4003
+ * @private
4004
+ * @param {ProviderEvent[]} absoluteAttitudeEvents
4005
+ */
4006
+ _parseAbsoluteAttitudeEvents = absoluteAttitudeEvents => {
4007
+
4008
+ if (absoluteAttitudeEvents.length < 2) {
4009
+ return;
4010
+ }
4011
+
4012
+ const magnetometerNeedCalibrationEvent = absoluteAttitudeEvents[1];
4013
+ if (magnetometerNeedCalibrationEvent.dataType !== EventType.MagnetometerNeedCalibration) {
4014
+ return;
4015
+ }
4016
+
4017
+ this.notify(magnetometerNeedCalibrationEvent);
4018
+ }
4019
+ }
4020
+
4021
+ var MagnetometerCalibrationDetector$1 = new MagnetometerCalibrationDetector();
4022
+
3887
4023
  class IpResolveServerError extends Error {
3888
4024
 
3889
4025
  static DEFAULT_MESSAGE = 'IP Resolver failed';
@@ -4111,6 +4247,7 @@ var Providers = /*#__PURE__*/Object.freeze({
4111
4247
  Accelerometer: Accelerometer$1,
4112
4248
  Gyroscope: Gyroscope$1,
4113
4249
  HighRotationsDetector: HighRotationsDetector$1,
4250
+ MagnetometerCalibrationDetector: MagnetometerCalibrationDetector$1,
4114
4251
  RelativeAttitudeFromBrowser: RelativeAttitudeFromBrowser$1,
4115
4252
  RelativeAttitudeFromEkf: RelativeAttitudeFromEkf$1,
4116
4253
  RelativeAttitudeFromInertial: RelativeAttitudeFromInertial$1,