@wemap/positioning 2.1.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/debug/arcore-absolute.html +16 -0
  2. package/debug/arcore.html +16 -0
  3. package/package.json +2 -1
  4. package/src/PositioningHandler.js +19 -5
  5. package/src/components/AbsoluteAttitudeComponent.jsx +2 -2
  6. package/src/components/ArCoreAbsoluteComponent.jsx +100 -0
  7. package/src/components/ArCoreComponent.jsx +74 -0
  8. package/src/components/GnssWifiComponent.jsx +14 -2
  9. package/src/components/GnssWifiPdrComponent.jsx +11 -2
  10. package/src/components/MapComponent.jsx +237 -0
  11. package/src/components/PdrComponent.jsx +12 -3
  12. package/src/components/PoseComponent.jsx +7 -0
  13. package/src/components/PositioningPoseComponent.jsx +12 -3
  14. package/src/components/Utils.js +18 -0
  15. package/src/components/index.js +4 -0
  16. package/src/errors/MissingArCoreError.js +9 -0
  17. package/src/errors/MissingNativeInterfaceError.js +9 -0
  18. package/src/providers/Provider.js +15 -3
  19. package/src/providers/ProviderOptions.js +1 -1
  20. package/src/providers/attitude/AbsoluteAttitudeProvider.js +6 -6
  21. package/src/providers/others/MapMatchingProvider.js +19 -19
  22. package/src/providers/pose/ArCoreAbsoluteProvider.js +186 -0
  23. package/src/providers/pose/ArCoreProvider.js +115 -0
  24. package/src/providers/pose/GnssWifiPdrProvider.js +20 -20
  25. package/src/providers/pose/PoseProvider.js +1 -1
  26. package/src/providers/pose/pdr/PdrProvider.js +39 -39
  27. package/src/providers/pose/pdr/helpers/Smoother.js +33 -33
  28. package/src/providers/pose/pdr/helpers/Smoother.spec.js +7 -7
  29. package/src/providers/position/GnssWifiProvider.js +5 -5
  30. package/src/providers/position/IpProvider.js +2 -2
  31. package/webpack/webpack.common.js +1 -1
  32. package/src.old/Constants.js +0 -11
  33. package/src.old/NavigationHandler.js +0 -244
  34. package/src.old/Pose.js +0 -8
  35. package/src.old/attitude/AttitudeHandler.js +0 -342
  36. package/src.old/attitude/EkfAttitude.js +0 -238
  37. package/src.old/attitude/EkfAttitude.spec.js +0 -116
  38. package/src.old/components/AbsoluteAttitude.jsx +0 -136
  39. package/src.old/components/Imu.jsx +0 -89
  40. package/src.old/components/LocationSource.jsx +0 -434
  41. package/src.old/components/Logger.jsx +0 -113
  42. package/src.old/components/NavigationDebugApp.jsx +0 -106
  43. package/src.old/components/Others.jsx +0 -121
  44. package/src.old/components/RelativeAttitude.jsx +0 -104
  45. package/src.old/components/Utils.js +0 -35
  46. package/src.old/components/index.js +0 -13
  47. package/src.old/index.js +0 -7
  48. package/src.old/providers/FixedLocationImuLocationSource.js +0 -66
  49. package/src.old/providers/GnssLocationSource.js +0 -118
  50. package/src.old/providers/GnssPdrLocationSource.js +0 -182
  51. package/src.old/providers/IPLocationSource.js +0 -96
  52. package/src.old/providers/LocationSource.js +0 -290
  53. package/src.old/providers/PdrLocationSource.js +0 -320
  54. package/src.old/providers/ProvidersLogger.js +0 -77
  55. package/src.old/providers/pdr/HeadingUnlocker.js +0 -41
  56. package/src.old/providers/pdr/HeadingUnlocker.spec.js +0 -26
  57. package/src.old/providers/pdr/Smoother.js +0 -90
  58. package/src.old/providers/pdr/Smoother.spec.js +0 -424
  59. package/src.old/providers/pdr/ThugDetector.js +0 -37
  60. package/src.old/providers/steps/StepDetection.js +0 -7
  61. package/src.old/providers/steps/StepDetectionLadetto.js +0 -67
  62. package/src.old/providers/steps/StepDetectionMinMaxPeaks.js +0 -80
  63. package/src.old/providers/steps/StepDetectionMinMaxPeaks2.js +0 -108
  64. package/src.old/sensors/SensorsCompatibility.js +0 -486
  65. package/src.old/sensors/SensorsCompatibility.spec.js +0 -270
  66. package/src.old/sensors/SensorsLogger.js +0 -94
  67. package/src.old/sensors/SensorsLoggerUtils.js +0 -35
@@ -1,108 +0,0 @@
1
-
2
- // in seconds
3
- const WINDOW_TIME = 0.3;
4
-
5
- // in seconds
6
- const MIN_TIME_BETWEEN_STEPS = 0.4;
7
-
8
- // in Hz
9
- const MAX_FRENQUENCY = 4;
10
- const MIN_FRENQUENCY = 1;
11
-
12
- // in m.s-2
13
- const VERTICAL_ACC_POSITIVE_PEAK_THRESHOLD = 0.75;
14
- const VERTICAL_ACC_NEGATIVE_PEAK_THRESHOLD = -0.3;
15
-
16
-
17
- class StepDetectionMinMaxPeaks2 {
18
-
19
- constructor() {
20
- this.slidingWindow = [];
21
-
22
- this.lastStepTimestamp = -MIN_TIME_BETWEEN_STEPS;
23
- this.previousVerticalAcc = 0;
24
- this.influence = 0.2;
25
- }
26
-
27
-
28
- compute(timestamp, linearAcc, angularRate) {
29
-
30
- const verticalAcc = this.influence * (linearAcc[2] * 2) + (1 - this.influence) * this.previousVerticalAcc;
31
- this.previousVerticalAcc = verticalAcc;
32
-
33
-
34
- if (Math.sqrt(angularRate[0] ** 2 + angularRate[1] ** 2 + angularRate[2] ** 2) > 0.75) {
35
- return false;
36
- }
37
-
38
- if (this.lastStepTimestamp && this.lastStepTimestamp + MIN_TIME_BETWEEN_STEPS > timestamp) {
39
- return false;
40
- }
41
-
42
- let maxValue = Number.MIN_SAFE_INTEGER;
43
- let minValue = Number.MAX_SAFE_INTEGER;
44
-
45
- this.slidingWindow.forEach(function(item, index, object) {
46
- if (item.timestamp < timestamp - WINDOW_TIME) {
47
- object.splice(index, 1);
48
- } else {
49
- maxValue = Math.max(item.verticalAcc, maxValue);
50
- minValue = Math.min(item.verticalAcc, minValue);
51
- }
52
- });
53
- this.slidingWindow.push({
54
- timestamp: timestamp,
55
- verticalAcc: verticalAcc
56
- });
57
-
58
-
59
- if (maxValue > VERTICAL_ACC_POSITIVE_PEAK_THRESHOLD
60
- && minValue < VERTICAL_ACC_NEGATIVE_PEAK_THRESHOLD) {
61
-
62
- const timeInterval = this.lastStepTimestamp ? timestamp - this.lastStepTimestamp : 1;
63
- this.frequency = Math.min(Math.max((1 / timeInterval), MIN_FRENQUENCY), MAX_FRENQUENCY);
64
-
65
- this.lastStepTimestamp = timestamp;
66
- return true;
67
- }
68
-
69
- return false;
70
- }
71
-
72
- get lastStepSize() {
73
-
74
- if (!this.frequency) {
75
- return 0;
76
- }
77
-
78
- const kParamA = 0.45;
79
- const kParamB = 0.2;
80
- return kParamA + kParamB * this.frequency;
81
- }
82
-
83
- get speed() {
84
- return this.lastStepSize && this.frequency ? this.lastStepSize * this.frequency : 0;
85
- }
86
-
87
- mean(data) {
88
- let sum = 0.0, mean = 0.0;
89
-
90
- for (let i = 0; i < data.length; ++i) {
91
- sum += data[i].verticalAcc;
92
- }
93
- mean = sum / data.length;
94
- return mean;
95
- }
96
-
97
- stddev(data) {
98
- const theMean = this.mean(data);
99
- let standardDeviation = 0;
100
- for (let i = 0; i < data.length; ++i) {
101
- standardDeviation += (data[i].verticalAcc - theMean) ** 2;
102
- }
103
-
104
- return Math.sqrt(standardDeviation / data.length);
105
- }
106
- }
107
-
108
- export default StepDetectionMinMaxPeaks2;
@@ -1,486 +0,0 @@
1
- /* global Accelerometer, Gyroscope, Magnetometer, AbsoluteOrientationSensor, RelativeOrientationSensor */
2
-
3
- import {
4
- deg2rad, rad2deg, Quaternion, Rotations
5
- } from '@wemap/maths';
6
-
7
- import SensorsLogger from './SensorsLogger';
8
-
9
-
10
- const BROWSER = {
11
- UNKNOWN: 0,
12
- IOS_SAFARI: 1,
13
- FIREFOX: 2,
14
- OPERA: 3,
15
- ANDROID_CHROME: 4,
16
- ANDROID_STOCK: 5
17
- };
18
-
19
- const defaultMotionSensors = {
20
- accelerometer: true,
21
- gyroscope: true,
22
- magnetometer: true
23
- };
24
-
25
- /**
26
- * 5 April 2019
27
- * The Generic Sensors API methods have been disabled due to a cross-origin problem.
28
- */
29
- /**
30
- * 13 August 2019
31
- * The Generic Sensors API methods have been disabled due to empty notifications when app is fullscreen and have no focus.
32
- */
33
- const ENABLE_GENERIC_SENSORS_API = false;
34
-
35
- /**
36
- * Keep a trace of each instance for SensorsLogger
37
- * TODO: Should be removed when logger will be updated with providers
38
- */
39
- const instances = [];
40
-
41
-
42
- // -----------------------------------
43
- // -----------------------------------
44
- // Overview of compatibilities:
45
- // -----------------------------------
46
- //
47
- // --------
48
- // Chrome Android (v72.0.3626)
49
- // --------
50
- // Accelerometer + Gyroscope: YES (via Sensors API if present or devicemotion otherwise)
51
- // Relative orientation: YES (via RelativeOrientationSensor if present or deviceorientation otherwise but deviceorientation.alpha is unreliable! Sometimes it starts at 0°, sometimes at 270°)
52
- // Absolute orientation: YES (via AbsoluteOrientationSensor if present or deviceorientationabsolute otherwise)
53
- // --------
54
- //
55
- // --------
56
- // Safari iOS (v12.0)
57
- // --------
58
- // Accelerometer + Gyroscope: YES (via devicemotion)
59
- // Relative orientation: YES (via deviceorientation)
60
- // Absolute orientation: YES (via deviceorientation and event.webkitCompassHeading)
61
- // --------
62
- //
63
- // --------
64
- // Opera (v50.2.2426)
65
- // --------
66
- // Accelerometer + Gyroscope: NO (https://developer.mozilla.org/en-US/docs/Web/API/DeviceMotionEvent)
67
- // Relative orientation: NO (https://developer.mozilla.org/en-US/docs/Web/API/Window/ondeviceorientation)
68
- // Absolute orientation: NO (https://developer.mozilla.org/en-US/docs/Web/API/Window/ondeviceorientation)
69
- // devicemotion and deviceorientation send only one callback and data is empty.
70
- // --------
71
- //
72
- // --------
73
- // Firefox (v65.0.1)
74
- // --------
75
- // Accelerometer + Gyroscope: YES (via devicemotion)
76
- // Relative orientation: YES (via deviceorientation)
77
- // Absolute orientation: NO (https://www.fxsitecompat.com/en-CA/docs/2018/various-device-sensor-apis-are-now-deprecated/)
78
- // --------
79
- // -----------------------------------
80
-
81
- class SensorsCompatibility {
82
-
83
- imuTickInterval = null;
84
-
85
- constructor() {
86
- this.browser = this.retrieveBrowser();
87
- instances.push(this);
88
-
89
- this.lastGyroscopeValue = null;
90
- }
91
-
92
- // Parse the user agent to get OS and browser so we know how to normalize values
93
- retrieveBrowser() {
94
- const userAgent = window.navigator.userAgent;
95
- // IOS uses a special property
96
- if (userAgent.match(/(iPad|iPhone|iPod)/i)) {
97
- return BROWSER.IOS_SAFARI;
98
- } else if (userAgent.match(/Firefox/i)) {
99
- return BROWSER.FIREFOX;
100
- } else if (userAgent.match(/Opera/i)) {
101
- return BROWSER.OPERA;
102
- } else if (userAgent.match(/Android/i)) {
103
- // TODO: check with android_stock browser
104
- return BROWSER.ANDROID_CHROME;
105
- }
106
- return BROWSER.UNKNOWN;
107
- }
108
-
109
- setLogger(logger) {
110
-
111
- if (logger && !(logger instanceof SensorsLogger)) {
112
- throw new Error('logger is not an instance of SensorsLogger');
113
- }
114
-
115
- this.logger = logger;
116
- }
117
-
118
- static addLoggerOnKnownInstances(logger) {
119
- instances.forEach(instance => instance.addLogger(logger));
120
- }
121
-
122
- hasArSensors() {
123
- return this.startAbsoluteOrientation(this.stopAbsoluteOrientation);
124
- }
125
-
126
- /*
127
- * Manage Accelerometer - Gyroscope - Magnetometer
128
- */
129
-
130
- startImu(callback, _sensors = defaultMotionSensors, frequency = 60) {
131
-
132
- let isResolved = false;
133
-
134
- const sensors = !_sensors ? defaultMotionSensors : _sensors;
135
-
136
-
137
- if (ENABLE_GENERIC_SENSORS_API) {
138
- if (sensors.accelerometer && window.Accelerometer) {
139
- this.accelerometerSensor = new Accelerometer({ frequency: frequency });
140
- this.accelerometerSensor.start();
141
- }
142
-
143
- if (sensors.gyroscope && window.Gyroscope) {
144
- this.gyroscopeSensor = new Gyroscope({ frequency: frequency });
145
- this.gyroscopeSensor.start();
146
- }
147
-
148
- if (sensors.magnetometer && window.Magnetometer) {
149
- this.magnetometerSensor = new Magnetometer({ frequency: frequency });
150
- this.magnetometerSensor.start();
151
- }
152
- }
153
-
154
- return new Promise((resolve) => {
155
-
156
- const notifyFn = (output) => {
157
- if (sensors.accelerometer && !output.acc
158
- || sensors.gyroscope && !output.gyr
159
- || sensors.magnetometer && !output.mag) {
160
- return;
161
- }
162
-
163
- callback(output);
164
-
165
- if (this.logger) {
166
- if (output.acc) {
167
- this.logger.feed(SensorsLogger.DataType.ACCELEROMETER, output.timestamp, output.acc, true);
168
- }
169
- if (output.gyr) {
170
- this.logger.feed(SensorsLogger.DataType.GYROSCOPE, output.timestamp, output.gyr, true);
171
- }
172
- if (output.mag) {
173
- this.logger.feed(SensorsLogger.DataType.MAGNETOMETER, output.timestamp, output.mag, true);
174
- }
175
- }
176
-
177
- if (!isResolved) {
178
- resolve();
179
- isResolved = true;
180
- }
181
- };
182
-
183
- if (this.accelerometerSensor || this.gyroscopeSensor || this.magnetometerSensor) {
184
-
185
- // Create a scheduler using frequency parameter
186
- const schedulerFn = () => {
187
- this.imuTickInterval = setInterval(() => {
188
- notifyFn(this.onImuTick());
189
- }, 1 / frequency * 1000);
190
- };
191
-
192
- schedulerFn();
193
-
194
- } else if (sensors.accelerometer || sensors.gyroscope || sensors.magnetometer) {
195
-
196
- this.onDeviceMotionEventListener = (e) => {
197
- notifyFn(this.onDeviceMotion(e));
198
- };
199
- window.addEventListener('devicemotion', this.onDeviceMotionEventListener, true);
200
- }
201
-
202
- });
203
- }
204
-
205
- stopImu() {
206
-
207
- if (this.imuTickInterval) {
208
- clearInterval(this.imuTickInterval);
209
- this.imuTickInterval = null;
210
- }
211
-
212
- if (this.accelerometerSensor || this.gyroscopeSensor || this.magnetometerSensor) {
213
- if (this.accelerometerSensor) {
214
- this.accelerometerSensor.stop();
215
- this.accelerometerSensor = null;
216
- }
217
- if (this.gyroscopeSensor) {
218
- this.gyroscopeSensor.stop();
219
- this.gyroscopeSensor = null;
220
- }
221
- if (this.magnetometerSensor) {
222
- this.magnetometerSensor.stop();
223
- this.magnetometerSensor = null;
224
- }
225
- } else if (this.onDeviceMotionEventListener) {
226
- window.removeEventListener('devicemotion', this.onDeviceMotionEventListener, true);
227
- }
228
- }
229
-
230
- onImuTick() {
231
- const acc = this.accelerometerSensor;
232
- const accValues = acc && acc.x ? [acc.x, acc.y, acc.z] : null;
233
-
234
- const gyr = this.gyroscopeSensor;
235
- const gyrValues = gyr && gyr.x ? [gyr.x, gyr.y, gyr.z] : null;
236
-
237
- const mag = this.magnetometerSensor;
238
- const magValues = mag && mag.x ? [mag.x, mag.y, mag.z] : null;
239
-
240
- let timestamp = 0;
241
- if (accValues) {
242
- timestamp = acc.timestamp;
243
- } else if (gyrValues) {
244
- timestamp = gyr.timestamp;
245
- } else if (magValues) {
246
- timestamp = mag.timestamp;
247
- }
248
-
249
- // Alignment of acc and gyr is made by taking the last value of accelerometer, gyroscope and magnetometer.
250
- // This is not perfect but far enough for almost all algorithms.
251
- const output = {
252
- timestamp: timestamp / 1e3,
253
- acc: accValues,
254
- gyr: gyrValues,
255
- mag: magValues
256
- };
257
-
258
- return output;
259
- }
260
-
261
- /**
262
- * Verified for IOS_SAFARI, ANDROID_CHROME, FIREFOX
263
- * Not working for OPERA
264
- * @param {DeviceMotionEvent} e device motion event
265
- */
266
- onDeviceMotion(e) {
267
- const timestamp = e.timeStamp / 1e3;
268
-
269
- let acc = null;
270
-
271
- if (e.accelerationIncludingGravity) {
272
- const {
273
- x, y, z
274
- } = e.accelerationIncludingGravity;
275
-
276
- if (x && y && z) {
277
- acc = [x, y, z];
278
- }
279
- }
280
-
281
- if (this.browser === BROWSER.IOS_SAFARI && acc) {
282
- acc[0] *= -1;
283
- acc[1] *= -1;
284
- acc[2] *= -1;
285
- }
286
-
287
-
288
- let gyr = null;
289
-
290
- if (e.rotationRate) {
291
- const {
292
- alpha, beta, gamma
293
- } = e.rotationRate;
294
-
295
- if (alpha && beta && gamma) {
296
- gyr = [alpha * Math.PI / 180, beta * Math.PI / 180, gamma * Math.PI / 180];
297
- }
298
- }
299
-
300
- const output = {
301
- timestamp: timestamp,
302
- acc: acc,
303
- gyr: gyr,
304
- mag: null
305
- };
306
- return output;
307
- }
308
-
309
-
310
- /*
311
- * Manage absolute orientation
312
- */
313
-
314
- startAbsoluteOrientation(callback, frequency = 60) {
315
-
316
-
317
- let isResolved = false;
318
-
319
- return new Promise((resolve, reject) => {
320
-
321
- const notifyFn = (timestamp, quaternion, extraData) => {
322
- if (!quaternion) {
323
- return;
324
- }
325
-
326
- callback(quaternion, timestamp, extraData);
327
-
328
- if (this.logger) {
329
- this.logger.feed(SensorsLogger.DataType.DEVICE_ORIENTATION_ABSOLUTE, timestamp, quaternion, true);
330
- }
331
-
332
- if (!isResolved) {
333
- resolve();
334
- isResolved = true;
335
- }
336
- };
337
-
338
- if (ENABLE_GENERIC_SENSORS_API && window.AbsoluteOrientationSensor) {
339
- // Cool! The device is compatible with Sensor_API.
340
-
341
- this.absoluteOrientationSensor = new AbsoluteOrientationSensor({ frequency: frequency });
342
- this.absoluteOrientationSensor.addEventListener('reading', (e) => {
343
- if (!e.target.quaternion) {
344
- return;
345
- }
346
- notifyFn(e.timeStamp, Quaternion.xyzw2wxyz(e.target.quaternion));
347
- });
348
- this.absoluteOrientationSensor.start();
349
-
350
- } else {
351
-
352
- switch (this.browser) {
353
-
354
- case BROWSER.ANDROID_CHROME:
355
-
356
- this.onDeviceOrientationAbsoluteEventListener = (e) => {
357
- if (!e.alpha || !e.beta || !e.gamma) {
358
- return;
359
- }
360
- notifyFn(e.timeStamp / 1e3, Rotations.eulerToQuaternionZXYDegrees([e.alpha, e.beta, e.gamma]));
361
- };
362
-
363
- window.addEventListener('deviceorientationabsolute', this.onDeviceOrientationAbsoluteEventListener, true);
364
-
365
- break;
366
-
367
- case BROWSER.IOS_SAFARI:
368
-
369
- this.onDeviceOrientationAbsoluteSafariEventListener = (e) => {
370
-
371
- if (!e.webkitCompassHeading || !e.beta || !e.gamma) {
372
- return;
373
- }
374
-
375
- let webkitCompassHeading = -e.webkitCompassHeading;
376
- if (e.beta > 62) {
377
- webkitCompassHeading = SensorsCompatibility.headingEusToEnu(180 - webkitCompassHeading, e.beta, e.gamma);
378
- }
379
- const quaternion = Rotations.eulerToQuaternionZXYDegrees([webkitCompassHeading, e.beta, e.gamma]);
380
- notifyFn(e.timeStamp / 1e3, quaternion, { 'webkitCompassHeading': e.webkitCompassHeading });
381
- };
382
-
383
- window.addEventListener('deviceorientation', this.onDeviceOrientationAbsoluteSafariEventListener, true);
384
-
385
- // Be Careful: webkitCompassHeading is not continuous.
386
- // It value changes with thresholds: beta > 30deg and beta < 62deg
387
- console.warn('[Sensors] Be careful, you are using webkitCompassHeading on iOS and this method is unreliable (not continuous)');
388
-
389
- break;
390
-
391
- default:
392
- reject(new Error('Your browser cannot provide absolute orientation or we do not know how to parse its data'));
393
- }
394
- }
395
- });
396
- }
397
-
398
- stopAbsoluteOrientation() {
399
- if (this.absoluteOrientationSensor) {
400
- this.absoluteOrientationSensor.stop();
401
- this.absoluteOrientationSensor = null;
402
- } else if (this.onDeviceOrientationAbsoluteEventListener) {
403
- window.removeEventListener('deviceorientationabsolute', this.onDeviceOrientationAbsoluteEventListener, true);
404
- } else if (this.onDeviceOrientationAbsoluteSafariEventListener) {
405
- window.removeEventListener('deviceorientation', this.onDeviceOrientationAbsoluteSafariEventListener, true);
406
- }
407
- }
408
-
409
- static headingEusToEnu(_alpha, _beta, _gamma) {
410
- const alpha = deg2rad(_alpha);
411
- const beta = deg2rad(_beta);
412
- const gamma = deg2rad(_gamma);
413
-
414
- return rad2deg(Math.atan2(
415
- Math.cos(alpha) * Math.sin(gamma) + Math.cos(gamma) * Math.sin(alpha) * Math.sin(beta),
416
- Math.sin(alpha) * Math.sin(gamma) - Math.cos(alpha) * Math.cos(gamma) * Math.sin(beta)));
417
- }
418
-
419
- /*
420
- * Manage relative orientation
421
- */
422
-
423
- startRelativeOrientation(callback, frequency = 60) {
424
-
425
- let isResolved = false;
426
-
427
- return new Promise((resolve) => {
428
-
429
- const notifyFn = (timestamp, quaternion) => {
430
- if (!quaternion) {
431
- return;
432
- }
433
-
434
- if (!isResolved) {
435
- resolve();
436
- isResolved = true;
437
- }
438
-
439
- callback(quaternion, timestamp);
440
-
441
- if (this.logger) {
442
- this.logger.feed(SensorsLogger.DataType.DEVICE_ORIENTATION_RELATIVE, timestamp, quaternion, true);
443
- }
444
- };
445
-
446
- if (ENABLE_GENERIC_SENSORS_API && window.RelativeOrientationSensor) {
447
- // Cool! The device is compatible with Sensor_API.
448
-
449
- this.relativeOrientationSensor = new RelativeOrientationSensor({ frequency: frequency });
450
- this.relativeOrientationSensor.addEventListener('reading', (e) => {
451
- if (!e.target.quaternion) {
452
- return;
453
- }
454
- notifyFn(e.timeStamp / 1e3, Quaternion.xyzw2wxyz(e.target.quaternion));
455
- });
456
- this.relativeOrientationSensor.start();
457
-
458
- } else {
459
-
460
- this.onDeviceOrientationRelativeEventListener = (e) => {
461
- if (!e.alpha || !e.beta || !e.gamma) {
462
- return;
463
- }
464
- notifyFn(e.timeStamp / 1e3, Rotations.eulerToQuaternionZXYDegrees([e.alpha, e.beta, e.gamma]));
465
- };
466
- window.addEventListener('deviceorientation', this.onDeviceOrientationRelativeEventListener, true);
467
-
468
- }
469
-
470
- if (this.browser === BROWSER.ANDROID_CHROME) {
471
- console.warn('[Sensors] Be careful, you are using relative orientation on Android Chrome and this method is unreliable');
472
- }
473
- });
474
- }
475
-
476
- stopRelativeOrientation() {
477
- if (this.relativeOrientationSensor) {
478
- this.relativeOrientationSensor.stop();
479
- this.relativeOrientationSensor = null;
480
- } else if (this.onDeviceOrientationRelativeEventListener) {
481
- window.removeEventListener('deviceorientation', this.onDeviceOrientationRelativeEventListener, true);
482
- }
483
- }
484
- }
485
-
486
- export default SensorsCompatibility;