@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,87 @@
1
+ import Provider from '../Provider';
2
+ import EventType from '../../events/EventType';
3
+ import { Accelerometer } from '../../Providers';
4
+
5
+ /**
6
+ * Inclination provider gives the inclination of the device using Imu Sensor
7
+ * For example, when the top of the device is pointing the sky, inclination = Math.PI/2
8
+ * when the device is layed on a table, inclination = 0
9
+ * This provider use window.orientation to return a result in function of screen orientation
10
+ */
11
+ class InclinationFromAccProvider extends Provider {
12
+
13
+
14
+ /**
15
+ * @override
16
+ */
17
+ static get displayName() {
18
+ return 'Inclination from acceleration';
19
+ }
20
+
21
+ /**
22
+ * @override
23
+ */
24
+ static get eventsType() {
25
+ return [EventType.Inclination];
26
+ }
27
+
28
+ /**
29
+ * @override
30
+ */
31
+ get _availability() {
32
+ return Accelerometer.availability;
33
+ }
34
+
35
+ /**
36
+ * @override
37
+ */
38
+ start() {
39
+ this.providerId = Accelerometer.addEventListener(
40
+ events => this.onAccelerometerEvent(events[0]),
41
+ this.notifyError,
42
+ this.name);
43
+ }
44
+
45
+ /**
46
+ * @override
47
+ */
48
+ stop() {
49
+ Accelerometer.removeEventListener(this.providerId);
50
+ }
51
+
52
+ /**
53
+ * @private
54
+ */
55
+ onAccelerometerEvent = accelerometerEvent => {
56
+ const acc = accelerometerEvent.data;
57
+
58
+ const screenOrientation = window.orientation || 0;
59
+
60
+ const sizeAcc = Math.sqrt(acc[0] * acc[0] + acc[1] * acc[1] + acc[2] * acc[2]);
61
+ const accNormalized = [acc[0] / sizeAcc, acc[1] / sizeAcc, acc[2] / sizeAcc];
62
+
63
+ const q = [accNormalized[2] + 1, accNormalized[1], -accNormalized[0], 0];
64
+ const qSize = Math.sqrt(q[0] * q[0] + q[1] * q[1] + q[2] * q[2]);
65
+ const qNormalized = [q[0] / qSize, q[1] / qSize, q[2] / qSize, 0];
66
+
67
+ let inclination;
68
+ if (screenOrientation === 0) {
69
+ inclination = Math.asin(2 * qNormalized[1] * qNormalized[0]);
70
+ } else if (screenOrientation === 90) {
71
+ inclination = -Math.asin(2 * qNormalized[2] * qNormalized[0]);
72
+ } else if (screenOrientation === -90) {
73
+ inclination = Math.asin(2 * qNormalized[2] * qNormalized[0]);
74
+ } else if (screenOrientation === 180) {
75
+ inclination = -Math.asin(2 * qNormalized[1] * qNormalized[0]);
76
+ }
77
+
78
+ this.notify(this.createEvent(
79
+ EventType.Inclination,
80
+ inclination,
81
+ accelerometerEvent.timestamp,
82
+ [accelerometerEvent]
83
+ ));
84
+ };
85
+ }
86
+
87
+ export default InclinationFromAccProvider;
@@ -0,0 +1,77 @@
1
+ import Provider from '../Provider';
2
+ import EventType from '../../events/EventType';
3
+ import { Attitude } from '../../Providers';
4
+
5
+ /**
6
+ * Inclination provider gives the inclination of the device using Relative Attitude
7
+ * For example, when the top of the device is pointing the sky, inclination = Math.PI/2
8
+ * when the device is layed on a table, inclination = 0
9
+ * This provider use window.orientation to return a result in function of screen orientation
10
+ */
11
+ class InclinationFromAttitudeProvider extends Provider {
12
+
13
+ /**
14
+ * @override
15
+ */
16
+ static get displayName() {
17
+ return 'Inclination from attitude';
18
+ }
19
+
20
+ /**
21
+ * @override
22
+ */
23
+ static get eventsType() {
24
+ return [EventType.Inclination];
25
+ }
26
+
27
+ /**
28
+ * @override
29
+ */
30
+ get _availability() {
31
+ return Attitude.availability;
32
+ }
33
+
34
+ /**
35
+ * @override
36
+ */
37
+ start() {
38
+ this.providerId = Attitude.addEventListener(
39
+ events => {
40
+ const attitudeEvent = events[0];
41
+ const inclination = this.constructor.enuQuatToInclination(
42
+ attitudeEvent.data.quaternion
43
+ );
44
+ this.notify(this.createEvent(
45
+ EventType.Inclination,
46
+ inclination,
47
+ attitudeEvent.timestamp,
48
+ [attitudeEvent]
49
+ ));
50
+ },
51
+ this.notifyError,
52
+ this.name);
53
+ }
54
+
55
+ /**
56
+ * @override
57
+ */
58
+ stop() {
59
+ Attitude.removeEventListener(this.providerId);
60
+ }
61
+
62
+ static enuQuatToInclination(q) {
63
+ const screenOrientation = window.orientation || 0;
64
+
65
+ if (screenOrientation === 0) {
66
+ return Math.asin(2 * (q[2] * q[3] + q[1] * q[0]));
67
+ } else if (screenOrientation === 90) {
68
+ return Math.asin(2 * (q[1] * q[3] - q[2] * q[0]));
69
+ } else if (screenOrientation === -90) {
70
+ return Math.asin(2 * (q[2] * q[0] - q[1] * q[3]));
71
+ }
72
+ // else if (screenOrientation === 180)
73
+ return -Math.asin(2 * (q[2] * q[3] + q[1] * q[0]));
74
+ }
75
+ }
76
+
77
+ export default InclinationFromAttitudeProvider;
@@ -0,0 +1,69 @@
1
+ import MetaProvider from '../MetaProvider';
2
+ import EventType from '../../events/EventType';
3
+ import Availability from '../../events/Availability';
4
+ import {
5
+ InclinationFromAttitude, InclinationFromAcc
6
+ } from '../../Providers';
7
+
8
+ /**
9
+ * Inclination provider gives the inclination of the device using Imu Sensor
10
+ * For example, when the top of the device is pointing the sky, inclination = Math.PI/2
11
+ * when the device is layed on a table, inclination = 0
12
+ * This provider use window.orientation to return a result in function of screen orientation
13
+ */
14
+ class InclinationProvider extends MetaProvider {
15
+
16
+ /**
17
+ * @override
18
+ */
19
+ static get eventsType() {
20
+ return [EventType.Inclination];
21
+ }
22
+
23
+ /**
24
+ * @override
25
+ */
26
+ get _availability() {
27
+ return Availability.union(
28
+ InclinationFromAcc.availability,
29
+ InclinationFromAttitude.availability
30
+ );
31
+ }
32
+
33
+ /**
34
+ * @override
35
+ */
36
+ start() {
37
+
38
+ const startInclinationFromAcc = () => {
39
+ this.provider = InclinationFromAcc;
40
+ this.providerId = this.provider.addEventListener(
41
+ events => this.notify(events[0].clone()),
42
+ this.notifyError,
43
+ this.name
44
+ );
45
+ };
46
+
47
+ if (InclinationFromAttitude.availability) {
48
+ this.provider = InclinationFromAttitude;
49
+ this.providerId = this.provider.addEventListener(
50
+ events => this.notify(events[0].clone()),
51
+ () => {
52
+ InclinationFromAttitude.removeEventListener(this.providerId);
53
+ startInclinationFromAcc();
54
+ },
55
+ this.name);
56
+ } else {
57
+ startInclinationFromAcc();
58
+ }
59
+ }
60
+
61
+ /**
62
+ * @override
63
+ */
64
+ stop() {
65
+ this.provider.removeEventListener(this.providerId);
66
+ }
67
+ }
68
+
69
+ export default InclinationProvider;
@@ -0,0 +1,258 @@
1
+ /* eslint-disable max-statements */
2
+ import isNumber from 'lodash.isnumber';
3
+
4
+ import { UserPosition } from '@wemap/geo';
5
+ import {
6
+ Itinerary, MapMatching
7
+ } from '@wemap/graph';
8
+ import {
9
+ deg2rad, Vector3
10
+ } from '@wemap/maths';
11
+
12
+ import Provider from '../Provider';
13
+ import StepDetectionProvider from '../steps/StepDetectionProvider';
14
+ import HeadingUnlocker from './helpers/HeadingUnlocker';
15
+ import Availability from '../../events/Availability';
16
+ import EventType from '../../events/EventType';
17
+ import AbsoluteAttitudeProvider from '../attitude/absolute/AbsoluteAttitudeProvider';
18
+ import PdrProvider from '../position/relative/PdrProvider';
19
+ import ProviderEvent from '../../events/ProviderEvent';
20
+
21
+ class AbsolutePdrProvider extends Provider {
22
+
23
+ position = null;
24
+
25
+ static MM_PDR_ANGLE = deg2rad(20);
26
+ static MM_PDR_DIST = 15;
27
+ static MM_CONV_SPEED = 0.7;
28
+
29
+ static LO_SEGMENT_SIZE = 1.5;
30
+
31
+ /**
32
+ * @override
33
+ */
34
+ constructor() {
35
+ super();
36
+
37
+ this.relativePosition = [0, 0, 0];
38
+
39
+ this.mapMatching = new MapMatching();
40
+ this.mapMatching.maxAngleBearing = this.constructor.MM_PDR_ANGLE;
41
+ this.mapMatching.maxDistance = this.constructor.MM_PDR_DIST;
42
+
43
+ this.stepDetectionLocker = new HeadingUnlocker();
44
+ }
45
+
46
+ /**
47
+ * @override
48
+ */
49
+ static get displayName() {
50
+ return 'Absolute PDR';
51
+ }
52
+
53
+ /**
54
+ * @override
55
+ */
56
+ static get eventsType() {
57
+ return [EventType.AbsoluteAttitude, EventType.AbsolutePosition];
58
+ }
59
+
60
+ /**
61
+ * @override
62
+ */
63
+ static get _availability() {
64
+ return Availability.merge(
65
+ StepDetectionProvider.availability,
66
+ AbsoluteAttitudeProvider.availability
67
+ );
68
+ }
69
+
70
+
71
+ /**
72
+ * @override
73
+ */
74
+ _start() {
75
+
76
+ this.pdrProviderId = this.scheduler.use(PdrProvider,
77
+ events => this.onPdrEvent(events),
78
+ error => this.notifyError(error),
79
+ this.name);
80
+
81
+ /**
82
+ * Position
83
+ */
84
+ const lastPosition = this.dataStore.getLast(EventType.AbsolutePosition);
85
+ if (lastPosition) {
86
+ this.onPositionChanged(lastPosition);
87
+ }
88
+ this.dataStore.addEventListener(EventType.AbsolutePosition, this.onPositionChanged);
89
+
90
+ /**
91
+ * Network
92
+ */
93
+ this.mapMatching.network = this.dataStore.getLast(EventType.Network);
94
+ this.dataStore.addEventListener(EventType.Network, this.onNetworkChanged);
95
+
96
+ /**
97
+ * Itinerary
98
+ */
99
+ const lastItinerary = this.dataStore.getLast(EventType.Itinerary);
100
+ if (lastItinerary) {
101
+ this.onItineraryChanged(lastItinerary);
102
+ }
103
+ this.dataStore.addEventListener(EventType.Itinerary, this.onItineraryChanged);
104
+ }
105
+
106
+ /**
107
+ * @override
108
+ */
109
+ _stop() {
110
+ this.dataStore.removeEventListener(EventType.AbsolutePosition, this.onPositionChanged);
111
+ this.dataStore.removeEventListener(EventType.Network, this.onNetworkChanged);
112
+ this.dataStore.removeEventListener(EventType.Itinerary, this.onItineraryChanged);
113
+ this.scheduler.release(this.pdrProviderId, this.name);
114
+ }
115
+
116
+ onPositionChanged = position => {
117
+ this.position = position.clone();
118
+ this.notify(this.createEvent(EventType.AbsolutePosition, this.position));
119
+ };
120
+
121
+ onNetworkChanged = network => {
122
+ this.mapMatching.network = network;
123
+ }
124
+
125
+ /**
126
+ * @override
127
+ */
128
+ onPdrEvent = events => {
129
+
130
+ events.forEach(event => {
131
+ if (event.dataType === EventType.AbsoluteAttitude) {
132
+ this.attitude = event.data;
133
+ this.notify(event);
134
+ } else {
135
+ this.parseRelativePositionEvent(event);
136
+ }
137
+ });
138
+ }
139
+
140
+ parseRelativePositionEvent(event) {
141
+
142
+ if (this.position && this.attitude
143
+ && (!this.options.stepdetectionlocker
144
+ || !this.stepDetectionLocker.locked
145
+ || !this.stepDetectionLocker.feedHeading(this.attitude.heading))) {
146
+
147
+ this.position = this.calculateNewPosition(this.position, event);
148
+
149
+ this.notify(this.createEvent(EventType.AbsolutePosition, this.position, event.timestamp));
150
+
151
+ } else {
152
+ // this.pdrPosition has not been initialized
153
+ // or
154
+ // Step detection is locked by stepDetectionLocker
155
+ }
156
+
157
+ this.relativePosition = event.data.slice(0);
158
+ }
159
+
160
+ /**
161
+ * Calculate AbsolutePosition from RelativePosition event
162
+ * @param {UserPosition} previousPosition
163
+ * @param {ProviderEvent} event
164
+ */
165
+ calculateNewPosition(previousPosition, event) {
166
+
167
+ const offsetPosition = Vector3.subtract(event.data, this.relativePosition);
168
+
169
+ const dist = Math.sqrt(offsetPosition[0] ** 2 + offsetPosition[2] ** 2);
170
+ const bearing = Math.atan2(offsetPosition[0], -offsetPosition[2]);
171
+
172
+ /**
173
+ * First, compute new position without map-matching
174
+ */
175
+ const newPositionWithoutMM = previousPosition.clone();
176
+ newPositionWithoutMM.move(dist, bearing, offsetPosition[1]);
177
+ newPositionWithoutMM.bearing = bearing;
178
+ newPositionWithoutMM.time = event.timestamp;
179
+ if (isNumber(newPositionWithoutMM.accuracy) && isNumber(this.attitude.accuracy)) {
180
+ // A bad accuracy from PDR is due to three things:
181
+ // - Attitude accuracy
182
+ // - Misalignement (device heading != walking direction)
183
+ // - Step detection false positives / false negatives
184
+ // Following formula only use attitude accuracy with cone formula
185
+ newPositionWithoutMM.accuracy += (dist / 2) * Math.sin(this.attitude.accuracy / 2);
186
+ }
187
+
188
+ if (!this.options.useMapMatching || !this.mapMatching.network) {
189
+ /**
190
+ * If mapMatching is not used or not set, raw position is returned
191
+ */
192
+ return newPositionWithoutMM;
193
+ }
194
+
195
+ /**
196
+ * Secondly, find map-matching projection
197
+ */
198
+ const projection = this.mapMatching.getProjection(newPositionWithoutMM, true, true);
199
+ if (!projection || !projection.projection) {
200
+ /**
201
+ * If no projection has been found, returns the position without map-matching
202
+ */
203
+ return newPositionWithoutMM;
204
+ }
205
+
206
+ const projectedPosition = newPositionWithoutMM;
207
+ projectedPosition.level = projection.projection.level;
208
+
209
+ if (projection.distanceFromNearestElement < dist) {
210
+ /**
211
+ * If projection is not so far from network, projected position is returned
212
+ */
213
+ projectedPosition.lat = projection.projection.lat;
214
+ projectedPosition.lng = projection.projection.lng;
215
+ return projectedPosition;
216
+ }
217
+
218
+ /**
219
+ * If projected position is far from network, we do not project calculated position directly.
220
+ * This allows to adapt map-matching to not stick corridor directly.
221
+ * /!\ This smoothed position is different from the one of Smoother
222
+ */
223
+ const smoothedPosition = projectedPosition;
224
+ smoothedPosition.lat = previousPosition.lat;
225
+ smoothedPosition.lng = previousPosition.lng;
226
+
227
+ const smoothedDistance = projection.distanceFromNearestElement * this.constructor.MM_CONV_SPEED;
228
+ const smoothedBearing = previousPosition.bearingTo(projection.projection);
229
+ smoothedPosition.move(smoothedDistance, smoothedBearing);
230
+
231
+ return smoothedPosition;
232
+ }
233
+
234
+
235
+ /**
236
+ * Itinerary and PDR Locker
237
+ */
238
+
239
+ /**
240
+ * @param {Itinerary} itinerary
241
+ */
242
+ onItineraryChanged = itinerary => {
243
+
244
+ if (!itinerary || itinerary.edges.length === 0) {
245
+ this.stepDetectionLocker.unlock();
246
+ }
247
+
248
+ const edgeAt = itinerary.getEdgeAt(this.constructor.LO_SEGMENT_SIZE);
249
+ if (edgeAt) {
250
+ this.stepDetectionLocker.lock(edgeAt.bearing);
251
+ } else {
252
+ this.stepDetectionLocker.lock(itinerary.edges[0].bearing);
253
+ }
254
+ return;
255
+ }
256
+ }
257
+
258
+ export default AbsolutePdrProvider;