@wemap/providers 3.0.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 (102) hide show
  1. package/babel.config.js +11 -0
  2. package/config.json +4 -0
  3. package/debug/absolute-attitude.html +16 -0
  4. package/debug/absolute-position.html +16 -0
  5. package/debug/attitude.html +16 -0
  6. package/debug/components/AbsoluteAttitudeComponent.jsx +142 -0
  7. package/debug/components/AbsolutePositionComponent.jsx +79 -0
  8. package/debug/components/AttitudeComponent.jsx +40 -0
  9. package/debug/components/Common.css +27 -0
  10. package/debug/components/GnssWifiComponent.jsx +53 -0
  11. package/debug/components/ImuComponent.jsx +53 -0
  12. package/debug/components/InclinationComponent.jsx +68 -0
  13. package/debug/components/MapComponent.jsx +366 -0
  14. package/debug/components/NavigationConfig.js +112 -0
  15. package/debug/components/PoseComponent.jsx +168 -0
  16. package/debug/components/RelativeAttitudeComponent.jsx +85 -0
  17. package/debug/components/StartStopComponent.jsx +45 -0
  18. package/debug/components/StepDetectionComponent.jsx +39 -0
  19. package/debug/components/Utils.js +216 -0
  20. package/debug/components/index.js +30 -0
  21. package/debug/components/old/PositioningComponent.jsx +29 -0
  22. package/debug/components/old/PositioningInclinationComponent.jsx +82 -0
  23. package/debug/components/old/PositioningPoseComponent.jsx +117 -0
  24. package/debug/gnss-wifi.html +16 -0
  25. package/debug/imu.html +16 -0
  26. package/debug/inclination.html +16 -0
  27. package/debug/pose.html +16 -0
  28. package/debug/positioning-legacy.html +16 -0
  29. package/debug/relative-attitude.html +16 -0
  30. package/debug/step-detection.html +16 -0
  31. package/index.js +7 -0
  32. package/package.json +67 -0
  33. package/src/Providers.js +80 -0
  34. package/src/ProvidersInterface.js +125 -0
  35. package/src/ProvidersOptions.js +29 -0
  36. package/src/errors/AskImuOnDesktopError.js +9 -0
  37. package/src/errors/ContainsIgnoredProviderError.js +9 -0
  38. package/src/errors/GeolocationApiMissingError.js +9 -0
  39. package/src/errors/GeolocationPermissionDeniedError.js +9 -0
  40. package/src/errors/GeolocationPositionUnavailableError.js +9 -0
  41. package/src/errors/IpResolveServerError.js +9 -0
  42. package/src/errors/MissingAccelerometerError.js +11 -0
  43. package/src/errors/MissingArCoreError.js +9 -0
  44. package/src/errors/MissingGyroscopeError.js +11 -0
  45. package/src/errors/MissingMagnetometerError.js +9 -0
  46. package/src/errors/MissingNativeInterfaceError.js +9 -0
  47. package/src/errors/MissingSensorError.js +14 -0
  48. package/src/errors/NoProviderFoundError.js +9 -0
  49. package/src/events/Availability.js +44 -0
  50. package/src/events/EventType.js +33 -0
  51. package/src/events/ProviderEvent.js +32 -0
  52. package/src/events/ProvidersLogger.js +83 -0
  53. package/src/providers/Constants.js +5 -0
  54. package/src/providers/FakeProvider.spec.js +57 -0
  55. package/src/providers/MetaProvider.js +42 -0
  56. package/src/providers/Provider.js +314 -0
  57. package/src/providers/Provider.spec.js +136 -0
  58. package/src/providers/ProviderState.js +5 -0
  59. package/src/providers/attitude/AttitudeProvider.js +63 -0
  60. package/src/providers/attitude/EkfAttitude.js +224 -0
  61. package/src/providers/attitude/EkfAttitude.spec.js +114 -0
  62. package/src/providers/attitude/absolute/AbsoluteAttitudeFromBrowserProvider.js +224 -0
  63. package/src/providers/attitude/absolute/AbsoluteAttitudeFromRelAttProvider.js +134 -0
  64. package/src/providers/attitude/absolute/AbsoluteAttitudeProvider.js +143 -0
  65. package/src/providers/attitude/relative/RelativeAttitudeFromBrowserProvider.js +89 -0
  66. package/src/providers/attitude/relative/RelativeAttitudeFromEkfProvider.js +114 -0
  67. package/src/providers/attitude/relative/RelativeAttitudeProvider.js +103 -0
  68. package/src/providers/imu/AccelerometerProvider.js +61 -0
  69. package/src/providers/imu/GyroscopeProvider.js +61 -0
  70. package/src/providers/imu/ImuProvider.js +122 -0
  71. package/src/providers/inclination/InclinationFromAccProvider.js +87 -0
  72. package/src/providers/inclination/InclinationFromAttitudeProvider.js +77 -0
  73. package/src/providers/inclination/InclinationProvider.js +69 -0
  74. package/src/providers/legacy/AbsolutePdrProvider.js +258 -0
  75. package/src/providers/legacy/ArCoreAbsoluteProvider.js +230 -0
  76. package/src/providers/legacy/GnssWifiPdrProvider.js +217 -0
  77. package/src/providers/legacy/MapMatchingProvider.js +65 -0
  78. package/src/providers/legacy/PdrProvider.old.js +300 -0
  79. package/src/providers/legacy/PoseProvider.js +68 -0
  80. package/src/providers/legacy/helpers/HeadingUnlocker.js +47 -0
  81. package/src/providers/legacy/helpers/HeadingUnlocker.spec.js +53 -0
  82. package/src/providers/legacy/helpers/Smoother.js +92 -0
  83. package/src/providers/legacy/helpers/Smoother.spec.js +426 -0
  84. package/src/providers/legacy/helpers/ThugDetector.js +37 -0
  85. package/src/providers/others/CameraNativeProvider.js +44 -0
  86. package/src/providers/position/absolute/AbsolutePositionFromRelProvider.js +109 -0
  87. package/src/providers/position/absolute/AbsolutePositionProvider.js +172 -0
  88. package/src/providers/position/absolute/GnssWifiProvider.js +122 -0
  89. package/src/providers/position/absolute/IpProvider.js +68 -0
  90. package/src/providers/position/relative/ArCoreProvider.js +197 -0
  91. package/src/providers/position/relative/GeoRelativePositionFromArCoreProvider.js +85 -0
  92. package/src/providers/position/relative/GeoRelativePositionProvider.js +66 -0
  93. package/src/providers/position/relative/PdrProvider.js +132 -0
  94. package/src/providers/steps/StepDetectionLadetto.js +67 -0
  95. package/src/providers/steps/StepDetectionMinMaxPeaks.js +80 -0
  96. package/src/providers/steps/StepDetectionMinMaxPeaks2.js +108 -0
  97. package/src/providers/steps/StepDetectionProvider.js +100 -0
  98. package/src/smoothers/PositionSmoother.js +86 -0
  99. package/src/smoothers/PositionSmoother.spec.js +55 -0
  100. package/webpack/webpack.common.js +20 -0
  101. package/webpack/webpack.dev.js +24 -0
  102. package/webpack/webpack.prod.js +15 -0
@@ -0,0 +1,172 @@
1
+ import noop from 'lodash.noop';
2
+
3
+ import { UserPosition } from '@wemap/geo';
4
+ import {
5
+ MapMatching, Network
6
+ } from '@wemap/graph';
7
+ import { deg2rad } from '@wemap/maths';
8
+
9
+ import MetaProvider from '../../MetaProvider';
10
+ import EventType from '../../../events/EventType';
11
+ import ProviderEvent from '../../../events/ProviderEvent';
12
+ import Availability from '../../../events/Availability';
13
+ import {
14
+ AbsolutePositionFromRel, GnssWifi
15
+ } from '../../../Providers';
16
+ import ProvidersOptions from '../../../ProvidersOptions';
17
+
18
+ class AbsolutePositionProvider extends MetaProvider {
19
+
20
+ static ACCURACY_RELOC_RATIO = 2;
21
+ static MM_MAX_ANGLE = deg2rad(20);
22
+ static MM_MAX_DIST = 15;
23
+ static MM_MIN_DIST = 1;
24
+
25
+
26
+ constructor() {
27
+ super();
28
+ this.mapMatching = new MapMatching();
29
+ this.mapMatching.maxDistance = AbsolutePositionProvider.MM_MAX_DIST;
30
+ this.mapMatching.maxAngleBearing = AbsolutePositionProvider.MM_MAX_ANGLE;
31
+ }
32
+
33
+ /**
34
+ * @override
35
+ */
36
+ static get displayName() {
37
+ return 'Absolute position from Relative position';
38
+ }
39
+
40
+ /**
41
+ * @override
42
+ */
43
+ static get eventsType() {
44
+ return [EventType.AbsolutePosition];
45
+ }
46
+
47
+ /**
48
+ * @override
49
+ */
50
+ get _availability() {
51
+ return Availability.union(
52
+ AbsolutePositionFromRel.availability,
53
+ GnssWifi.availability
54
+ );
55
+ }
56
+
57
+
58
+ /**
59
+ * @override
60
+ */
61
+ start() {
62
+ if (AbsolutePositionFromRel.availability.isSupported) {
63
+ this.fromRelPosProviderId = AbsolutePositionFromRel.addEventListener(
64
+ events => this.onAbsolutePositionFromRel(events[0]),
65
+ noop,
66
+ this.name
67
+ );
68
+ }
69
+
70
+ this.gnssWifiProviderId = GnssWifi.addEventListener(
71
+ events => this.onAbsolutePosition(events[0]),
72
+ noop,
73
+ this.name
74
+ );
75
+
76
+ }
77
+
78
+
79
+ /**
80
+ * @override
81
+ */
82
+ stop() {
83
+ if (this.fromRelPosProviderId) {
84
+ AbsolutePositionFromRel.removeEventListener(this.fromRelPosProviderId);
85
+ }
86
+ GnssWifi.removeEventListener(this.gnssWifiProviderId);
87
+ }
88
+
89
+ onAbsolutePosition(newPositionEvent) {
90
+ if (this.lastEvent) {
91
+
92
+ const newPosition = newPositionEvent.data;
93
+ const lastPosition = this.lastEvent.data;
94
+
95
+ if (newPosition.distanceTo(lastPosition) < newPosition.accuracy
96
+ && newPosition.accuracy > lastPosition.accuracy / AbsolutePositionProvider.ACCURACY_RELOC_RATIO) {
97
+ return;
98
+ }
99
+ }
100
+
101
+ this.notify(newPositionEvent.clone());
102
+ }
103
+
104
+ /**
105
+ * @param {ProviderEvent} newPositionEvent
106
+ */
107
+ onAbsolutePositionFromRel(newPositionEvent) {
108
+
109
+ /**
110
+ * If map matching is not used or not set, raw position is returned
111
+ */
112
+ if (!ProvidersOptions.useMapMatching
113
+ || !this.mapMatching.network) {
114
+ this.notify(newPositionEvent.clone());
115
+ return;
116
+ }
117
+
118
+ const newPosition = newPositionEvent.data;
119
+ const projection = this.mapMatching.getProjection(newPosition, true, true);
120
+ if (!projection || !projection.projection) {
121
+ // If no projection has been found, returns the position without map-matching
122
+ this.notify(newPositionEvent.clone());
123
+ return;
124
+ }
125
+
126
+ const projectedPosition = newPosition.clone();
127
+
128
+ // Anyway, the projected level is used for new position
129
+ projectedPosition.level = projection.projection.level;
130
+
131
+ // Do not use projection if it too close from itinerary,
132
+ // this allows left/right movements (ie with ArCore)
133
+ if (projection.distanceFromNearestElement > AbsolutePositionProvider.MM_MIN_DIST) {
134
+ projectedPosition.lat = projection.projection.lat;
135
+ projectedPosition.lng = projection.projection.lng;
136
+ }
137
+
138
+ this.notify(this.createEvent(
139
+ EventType.AbsolutePosition,
140
+ projectedPosition,
141
+ newPositionEvent
142
+ ));
143
+
144
+ }
145
+
146
+ /**
147
+ * @override
148
+ * @param {UserPosition} position
149
+ */
150
+ feed(data) {
151
+ if (data instanceof UserPosition) {
152
+ const position = data;
153
+ if (position.time === null) {
154
+ throw Error('the time of the position is not defined');
155
+ }
156
+ if (position.accuracy === null) {
157
+ throw Error('the accuracy of the position is not defined');
158
+ }
159
+ this.onAbsolutePosition(this.createEvent(
160
+ EventType.AbsolutePosition, position, position.time
161
+ ));
162
+ } else if (data instanceof Network) {
163
+ this.mapMatching.network = data;
164
+ } else {
165
+ throw new Error('Unknown feed object');
166
+ }
167
+
168
+ }
169
+
170
+ }
171
+
172
+ export default AbsolutePositionProvider;
@@ -0,0 +1,122 @@
1
+ import { deg2rad } from '@wemap/maths';
2
+ import { UserPosition } from '@wemap/geo';
3
+ import { TimeUtils } from '@wemap/utils';
4
+
5
+ import EventType from '../../../events/EventType';
6
+ import GeolocationApiMissingError from '../../../errors/GeolocationApiMissingError';
7
+ import Provider from '../../Provider';
8
+ import GeolocationPermissionDeniedError from '../../../errors/GeolocationPermissionDeniedError';
9
+ import GeolocationPositionUnavailableError from '../../../errors/GeolocationPositionUnavailableError';
10
+ import Availability from '../../../events/Availability';
11
+ import Constants from '../../Constants';
12
+
13
+ const POSITION_OPTIONS = {
14
+ enableHighAccuracy: true,
15
+ timeout: Infinity,
16
+ maximumAge: 0
17
+ };
18
+
19
+ /**
20
+ * GnssWifiProvider is a provider based on navigator.geolocation.
21
+ * This API does not allow us to know if the position returned is provided
22
+ * by Wifi Fingerprinting algorithms or by GNSS. That is why the name is
23
+ * "GnssWifi".
24
+ */
25
+ class GnssWifiProvider extends Provider {
26
+
27
+ /**
28
+ * @override
29
+ */
30
+ static get displayName() {
31
+ return 'GNSS / Wifi from Browser';
32
+ }
33
+
34
+ /**
35
+ * @override
36
+ */
37
+ static get eventsType() {
38
+ return [EventType.AbsolutePosition];
39
+ }
40
+
41
+ /**
42
+ * @override
43
+ */
44
+ get _availability() {
45
+ return typeof(navigator) === 'object' && navigator.geolocation
46
+ ? Availability.yes()
47
+ : Availability.no(new GeolocationApiMissingError());
48
+ }
49
+
50
+ /**
51
+ * @override
52
+ */
53
+ start() {
54
+
55
+ this.geoLocationId = navigator.geolocation.watchPosition(
56
+ this.onNewPosition,
57
+ this.onPositionError,
58
+ POSITION_OPTIONS
59
+ );
60
+
61
+ }
62
+
63
+ /**
64
+ * @override
65
+ */
66
+ stop() {
67
+
68
+ navigator.geolocation.clearWatch(this.geoLocationId);
69
+
70
+ }
71
+
72
+ /**
73
+ * @private
74
+ */
75
+ onNewPosition = geolocation => {
76
+ const { coords } = geolocation;
77
+ if (!coords) {
78
+ return;
79
+ }
80
+
81
+ let bearing;
82
+ if (coords.heading) {
83
+ bearing = deg2rad(coords.heading);
84
+ }
85
+
86
+ const timestamp = TimeUtils.unixTimestampToPreciseTime(geolocation.timestamp) / 1e3;
87
+
88
+ const position = new UserPosition(
89
+ coords.latitude,
90
+ coords.longitude,
91
+ Constants.DEFAULT_ALTITUDE,
92
+ null,
93
+ timestamp,
94
+ coords.accuracy,
95
+ bearing,
96
+ this.name);
97
+
98
+ this.notify(this.createEvent(
99
+ EventType.AbsolutePosition, position, timestamp
100
+ ));
101
+
102
+ };
103
+
104
+ onPositionError = error => {
105
+
106
+ let customError;
107
+ switch (error.code) {
108
+ case 1:
109
+ customError = new GeolocationPermissionDeniedError(error.message);
110
+ break;
111
+ case 2:
112
+ customError = new GeolocationPositionUnavailableError(error.message);
113
+ break;
114
+ default:
115
+ customError = new Error(error.message);
116
+ }
117
+
118
+ this.notifyError(customError);
119
+ };
120
+ }
121
+
122
+ export default GnssWifiProvider;
@@ -0,0 +1,68 @@
1
+ import { UserPosition } from '@wemap/geo';
2
+ import { TimeUtils } from '@wemap/utils';
3
+
4
+ import EventType from '../../../events/EventType';
5
+ import Provider from '../../Provider';
6
+ import IpResolveServerError from '../../../errors/IpResolveServerError';
7
+
8
+ /**
9
+ * GnssWifiProvider is a provider based on navigator.geolocation.
10
+ * This API does not allow us to know if the position returned is provided
11
+ * by Wifi Fingerprinting algorithms or by GNSS. That is why the name is
12
+ * "GnssWifi".
13
+ */
14
+ class IpProvider extends Provider {
15
+
16
+ /**
17
+ * @override
18
+ */
19
+ static get displayName() {
20
+ return 'IP from ipinfo.io';
21
+ }
22
+
23
+ /**
24
+ * @override
25
+ */
26
+ static get eventsType() {
27
+ return [EventType.AbsolutePosition];
28
+ }
29
+
30
+ /**
31
+ * @override
32
+ */
33
+ start() {
34
+
35
+ fetch('https://ipinfo.io/geo?token=24a7ca2f3b489d')
36
+ .then((response) => {
37
+ if (!response) {
38
+ this.notifyError(new IpResolveServerError());
39
+ return;
40
+ }
41
+
42
+ const timestamp = TimeUtils.preciseTime / 1e3;
43
+
44
+ const latLngStr = response.loc.split(',');
45
+ const position = new UserPosition(
46
+ parseFloat(latLngStr[0]),
47
+ parseFloat(latLngStr[1]),
48
+ null,
49
+ null,
50
+ timestamp
51
+ );
52
+
53
+ this.notify(this.createEvent(
54
+ EventType.AbsolutePosition, position, timestamp
55
+ ));
56
+ });
57
+ }
58
+
59
+ /**
60
+ * @override
61
+ */
62
+ stop() {
63
+
64
+ }
65
+
66
+ }
67
+
68
+ export default IpProvider;
@@ -0,0 +1,197 @@
1
+ /* eslint-disable no-bitwise */
2
+ import {
3
+ Attitude, RelativePosition
4
+ } from '@wemap/geo';
5
+ import { deg2rad } from '@wemap/maths';
6
+ import { TimeUtils } from '@wemap/utils';
7
+
8
+ import Provider from '../../Provider';
9
+ import EventType from '../../../events/EventType';
10
+ import MissingArCoreError from '../../../errors/MissingArCoreError';
11
+ import MissingNativeInterfaceError from '../../../errors/MissingNativeInterfaceError';
12
+ import Availability from '../../../events/Availability';
13
+ import ProviderState from '../../ProviderState';
14
+
15
+
16
+ const Payload = {
17
+ Pose: {
18
+ ref: 2 ** 0,
19
+ size: 7
20
+ },
21
+ Barcode: {
22
+ ref: 2 ** 1,
23
+ size: 1
24
+ },
25
+ ProjMat: {
26
+ ref: 2 ** 2,
27
+ size: 16
28
+ },
29
+ ImageRef: {
30
+ ref: 2 ** 3,
31
+ size: 1
32
+ }
33
+ };
34
+
35
+ class ArCoreProvider extends Provider {
36
+
37
+ /**
38
+ * default relative attitude drift in rad.second-1
39
+ */
40
+ static RELATIVE_ATTITUDE_DRIFT = deg2rad(3) / 60;
41
+
42
+ previousPosition = [0, 0, 0];
43
+
44
+ /**
45
+ * @override
46
+ */
47
+ static get displayName() {
48
+ return 'ArCore provider';
49
+ }
50
+
51
+ /**
52
+ * @override
53
+ */
54
+ static get eventsType() {
55
+ return [EventType.RelativeAttitude, EventType.RelativePosition, EventType.Barcode];
56
+ }
57
+
58
+
59
+ /**
60
+ * @override
61
+ */
62
+ start() {
63
+ if (this.nativeProvider) {
64
+ this.nativeProvider.start();
65
+ }
66
+
67
+ this.pullDataLoop();
68
+ }
69
+
70
+ /**
71
+ * @override
72
+ */
73
+ stop() {
74
+ if (this.nativeProvider) {
75
+ this.nativeProvider.stop();
76
+ }
77
+ }
78
+
79
+ pullDataLoop = () => {
80
+
81
+ if (this.state === ProviderState.STOPPPED) {
82
+ return;
83
+ }
84
+
85
+ const payload = JSON.parse(this.nativeProvider.getInfo());
86
+ if (payload.length > 1) {
87
+ this.parsePayload(payload);
88
+ }
89
+ requestAnimationFrame(this.pullDataLoop);
90
+ }
91
+
92
+ parsePayload(payload) {
93
+
94
+ const ref = payload[0];
95
+ let bufferIndex = 1;
96
+
97
+ const events = [];
98
+
99
+ const time = TimeUtils.preciseTime / 1e3;
100
+
101
+ if (ref & Payload.Pose.ref) {
102
+
103
+ const attitude = new Attitude(
104
+ payload.slice(bufferIndex, bufferIndex + 4),
105
+ time,
106
+ this.constructor.RELATIVE_ATTITUDE_DRIFT,
107
+ );
108
+ events.push(this.createEvent(EventType.RelativeAttitude, attitude));
109
+
110
+ const newPosition = [payload[bufferIndex + 4], payload[bufferIndex + 5], payload[bufferIndex + 6]];
111
+ const position = new RelativePosition(
112
+ newPosition[0] - this.previousPosition[0],
113
+ newPosition[1] - this.previousPosition[1],
114
+ newPosition[2] - this.previousPosition[2],
115
+ time,
116
+ 1e-4
117
+ );
118
+ this.previousPosition = newPosition;
119
+ events.push(this.createEvent(EventType.RelativePosition, position));
120
+
121
+ bufferIndex += Payload.Pose.size;
122
+ }
123
+
124
+ if (ref & Payload.Barcode.ref) {
125
+ events.push(this.createEvent(EventType.Barcode, payload[bufferIndex]));
126
+ bufferIndex += Payload.Barcode.size;
127
+ }
128
+
129
+ if (ref & Payload.ProjMat.ref) {
130
+ const projMatrix = payload.slice(bufferIndex, bufferIndex + Payload.ProjMat.size);
131
+ events.push(this.createEvent(EventType.ProjectionMatrix, projMatrix));
132
+ bufferIndex += Payload.ProjMat.size;
133
+ }
134
+
135
+ if (events.length !== 0) {
136
+ this.notify(...events);
137
+ }
138
+ }
139
+
140
+
141
+ get nativeProvider() {
142
+
143
+ if (!this._nativeProvider) {
144
+
145
+ if (!this.nativeInterface) {
146
+ throw new MissingNativeInterfaceError();
147
+ }
148
+
149
+ this._nativeProvider = this.nativeInterface.getArCoreProvider();
150
+ if (!this._nativeProvider) {
151
+ throw new MissingArCoreError();
152
+ }
153
+
154
+ }
155
+
156
+ return this._nativeProvider;
157
+ }
158
+
159
+ /**
160
+ * @override
161
+ */
162
+ get _availability() {
163
+ try {
164
+ const nativeProvider = this.nativeProvider;
165
+
166
+ if (!nativeProvider.checkAvailability()) {
167
+ return Availability.no(new MissingArCoreError());
168
+ }
169
+
170
+ } catch (e) {
171
+ return Availability.no(e);
172
+ }
173
+
174
+ return Availability.yes();
175
+ }
176
+
177
+ enableBarcodeScanner() {
178
+ if (this.nativeProvider) {
179
+ this.nativeProvider.enableBarcodeScanner();
180
+ }
181
+ }
182
+
183
+ disableBarcodeScanner() {
184
+ if (this.nativeProvider) {
185
+ this.nativeProvider.disableBarcodeScanner();
186
+ }
187
+ }
188
+
189
+ /**
190
+ * @override
191
+ */
192
+ static get useCameraNatively() {
193
+ return true;
194
+ }
195
+ }
196
+
197
+ export default ArCoreProvider;
@@ -0,0 +1,85 @@
1
+ import { GeoRelativePosition } from '@wemap/geo';
2
+
3
+ import EventType from '../../../events/EventType';
4
+ import Provider from '../../Provider';
5
+ import {
6
+ ArCore, AbsoluteAttitude
7
+ } from '../../../Providers';
8
+
9
+ class GeoRelativePositionFromArCoreProvider extends Provider {
10
+
11
+ /**
12
+ * @override
13
+ */
14
+ get _availability() {
15
+ return ArCore.availability;
16
+ }
17
+
18
+ /**
19
+ * @override
20
+ */
21
+ start() {
22
+
23
+ this.arCoreProviderId = ArCore.addEventListener(
24
+ this.onArCoreEvents,
25
+ this.notifyError,
26
+ this.name);
27
+
28
+ this.absoluteAttitudeProviderId = AbsoluteAttitude.addEventListener(
29
+ events => (this.absoluteAttitudeEvent = events[0]),
30
+ this.notifyError,
31
+ this.name);
32
+ }
33
+
34
+ /**
35
+ * @override
36
+ */
37
+ stop() {
38
+ ArCore.removeEventListener(this.arCoreProviderId);
39
+ AbsoluteAttitude.removeEventListener(this.absoluteAttitudeProviderId);
40
+ }
41
+
42
+ onArCoreEvents = events => {
43
+ const relativeAttitudeEvent = events.find(event => event.dataType === EventType.RelativeAttitude);
44
+ const relativePositionEvent = events.find(event => event.dataType === EventType.RelativePosition);
45
+
46
+ if (relativeAttitudeEvent && relativePositionEvent && this.absoluteAttitudeEvent) {
47
+ this.compute(relativePositionEvent, relativeAttitudeEvent, this.absoluteAttitudeEvent);
48
+ }
49
+ }
50
+
51
+ compute(relativePositionEvent, relativeAttitudeEvent, absoluteAttitudeEvent) {
52
+ const relativePosition = relativePositionEvent.data;
53
+ const relativeAttitude = relativeAttitudeEvent.data;
54
+ const absoluteAttitude = absoluteAttitudeEvent.data;
55
+
56
+ const rotation = absoluteAttitude.heading - relativeAttitude.heading;
57
+
58
+ /**
59
+ * Here, we transform "relativePosition" which is defined in ArCore frame to a relative "position" defined in ENU frame
60
+ */
61
+ const east = Math.cos(rotation) * relativePosition.x - Math.sin(rotation) * relativePosition.z;
62
+ const north = -Math.sin(rotation) * relativePosition.x - Math.cos(rotation) * relativePosition.z;
63
+ const up = relativePosition.y;
64
+
65
+ /**
66
+ * Relative position is defined in ENU frame
67
+ */
68
+ const position = new GeoRelativePosition(
69
+ east,
70
+ north,
71
+ up,
72
+ relativePosition.time,
73
+ 0
74
+ );
75
+
76
+ this.notify(this.createEvent(
77
+ EventType.GeoRelativePosition,
78
+ position,
79
+ relativePosition.time,
80
+ [relativePositionEvent, relativeAttitudeEvent, absoluteAttitudeEvent]
81
+ ));
82
+ }
83
+ }
84
+
85
+ export default GeoRelativePositionFromArCoreProvider;
@@ -0,0 +1,66 @@
1
+ import MetaProvider from '../../MetaProvider';
2
+ import Availability from '../../../events/Availability';
3
+ import EventType from '../../../events/EventType';
4
+ import {
5
+ Pdr, GeoRelativePositionFromArCore
6
+ } from '../../../Providers';
7
+
8
+ class GeoRelativePositionProvider extends MetaProvider {
9
+
10
+ /**
11
+ * @override
12
+ */
13
+ static get displayName() {
14
+ return 'Geo Relative Position';
15
+ }
16
+
17
+ /**
18
+ * @override
19
+ */
20
+ static get eventsType() {
21
+ return [EventType.GeoRelativePosition];
22
+ }
23
+
24
+ /**
25
+ * @override
26
+ */
27
+ get _availability() {
28
+ return Availability.union(
29
+ Pdr.availability,
30
+ GeoRelativePositionFromArCore.availability
31
+ );
32
+ }
33
+
34
+
35
+ /**
36
+ * @override
37
+ */
38
+ start() {
39
+
40
+ if (GeoRelativePositionFromArCore.availability.isSupported) {
41
+ this.geoRelativeProvider = GeoRelativePositionFromArCore;
42
+ } else {
43
+ this.geoRelativeProvider = Pdr;
44
+ }
45
+
46
+ this.providerId = this.geoRelativeProvider.addEventListener(
47
+ events => {
48
+ const event = events.find(_event => _event.dataType === EventType.GeoRelativePosition);
49
+ if (event) {
50
+ this.notify(event.clone());
51
+ }
52
+ },
53
+ this.notifyError,
54
+ this.name
55
+ );
56
+ }
57
+
58
+ /**
59
+ * @override
60
+ */
61
+ stop() {
62
+ this.geoRelativeProvider.removeEventListener(this.providerId);
63
+ }
64
+ }
65
+
66
+ export default GeoRelativePositionProvider;