@wemap/providers 4.0.1 → 4.0.4

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 (35) hide show
  1. package/debug/dist/index.html +1 -0
  2. package/debug/dist/turn-detection.html +19 -0
  3. package/debug/index.js +2 -0
  4. package/debug/src/AbsoluteAttitudeComponent.jsx +0 -10
  5. package/debug/src/StepDetectionComponent.jsx +3 -3
  6. package/debug/src/TurnDetectionComponent.jsx +47 -0
  7. package/debug/src/Utils.js +24 -0
  8. package/package.json +7 -9
  9. package/src/Providers.js +5 -4
  10. package/src/ProvidersInterface.js +5 -6
  11. package/src/events/EventType.js +5 -1
  12. package/src/events/ProviderEvent.js +7 -0
  13. package/src/mapmatching/MapMatchingHandler.js +370 -53
  14. package/src/providers/Provider.js +42 -8
  15. package/src/providers/Provider.spec.js +3 -4
  16. package/src/providers/attitude/TurnDectector.js +71 -0
  17. package/src/providers/attitude/absolute/AbsoluteAttitude.js +123 -65
  18. package/src/providers/attitude/relative/RelativeAttitude.js +1 -3
  19. package/src/providers/attitude/relative/RelativeAttitudeFromBrowser.js +1 -2
  20. package/src/providers/attitude/relative/RelativeAttitudeFromEkf.js +1 -2
  21. package/src/providers/attitude/relative/RelativeAttitudeFromInertial.js +19 -2
  22. package/src/providers/imu/HighRotationsDetector.js +62 -0
  23. package/src/providers/inclination/Inclination.js +2 -2
  24. package/src/providers/others/CameraNative.js +2 -2
  25. package/src/providers/others/CameraProjectionMatrix.js +2 -2
  26. package/src/providers/position/absolute/AbsolutePosition.js +112 -82
  27. package/src/providers/position/relative/GeoRelativePosition.js +2 -2
  28. package/src/providers/position/relative/Pdr.js +4 -4
  29. package/src/providers/steps/{StepDetection.js → StepDetector.js} +4 -4
  30. package/src/providers/steps/StraightLineDetector.js +84 -0
  31. package/src/smoothers/AttitudeSmoother.js +94 -59
  32. package/src/providers/MetaProvider.js +0 -44
  33. package/src/providers/attitude/absolute/AbsoluteAttitudeFromRelAtt.js +0 -133
  34. package/src/providers/attitude/absolute/AbsoluteAttitudeFused.js +0 -166
  35. package/src/providers/position/absolute/AbsolutePositionFromRel.js +0 -106
@@ -0,0 +1,71 @@
1
+ import { std } from '@wemap/maths';
2
+
3
+ import EventType from '../../events/EventType.js';
4
+ import RelativeAttitude from './relative/RelativeAttitude.js';
5
+ import Provider from '../Provider.js';
6
+
7
+ class TurnDetector extends Provider {
8
+
9
+ // in seconds
10
+ static SLIDING_WINDOW_TIME = 0.3;
11
+
12
+ static STD_THRESHOLD = 0.075;
13
+
14
+ /** @type {number} in seconds */
15
+ static CONSIDER_TURN_UNTIL = 1;
16
+
17
+ /** @type {number[]} */
18
+ slidingWindow = [];
19
+
20
+ /**
21
+ * @override
22
+ */
23
+ static get pname() {
24
+ return 'TurnDetector';
25
+ }
26
+
27
+ /**
28
+ * @override
29
+ */
30
+ start() {
31
+ this.providerId = RelativeAttitude.addEventListener(
32
+ events => this._parseRelativeAttitude(events[0]),
33
+ error => this.notifyError(error)
34
+ );
35
+ }
36
+
37
+ /**
38
+ * @override
39
+ */
40
+ stop() {
41
+ RelativeAttitude.removeEventListener(this.providerId);
42
+ }
43
+
44
+ isTurning() {
45
+ if (!this.lastEvent || !RelativeAttitude.lastEvent) {
46
+ return false;
47
+ }
48
+
49
+ const diffTime = RelativeAttitude.lastEvent.data.time - this.lastEvent.data.timestamp;
50
+ return diffTime < TurnDetector.CONSIDER_TURN_UNTIL;
51
+ }
52
+
53
+ /**
54
+ * @private
55
+ */
56
+ _parseRelativeAttitude = relativeAttitudeEvent => {
57
+
58
+ const { heading, time: timestamp } = relativeAttitudeEvent.data;
59
+
60
+ this.slidingWindow = this.slidingWindow.filter(item => item[0] >= timestamp - TurnDetector.SLIDING_WINDOW_TIME);
61
+ this.slidingWindow.push([timestamp, heading]);
62
+
63
+ const stdVal = std(this.slidingWindow.map(item => item[1]));
64
+ if (stdVal > TurnDetector.STD_THRESHOLD) {
65
+ this.notify(this.createEvent(EventType.Turn, { timestamp }, [relativeAttitudeEvent]));
66
+ }
67
+
68
+ }
69
+ }
70
+
71
+ export default new TurnDetector();
@@ -1,25 +1,46 @@
1
- import {
2
- AbsoluteHeading, Attitude
3
- } from '@wemap/geo';
1
+ import { AbsoluteHeading, Attitude } from '@wemap/geo';
2
+ import { Quaternion } from '@wemap/maths';
4
3
  import { PromiseUtils } from '@wemap/utils';
5
4
 
6
- import MetaProvider from '../../MetaProvider.js';
5
+ import Provider from '../../Provider.js';
7
6
  import EventType from '../../../events/EventType.js';
8
7
  import AbsoluteAttitudeFromBrowser from './AbsoluteAttitudeFromBrowser.js';
9
- import AbsoluteAttitudeFromRelAtt from './AbsoluteAttitudeFromRelAtt.js';
10
- import AbsoluteAttitudeFused from './AbsoluteAttitudeFused.js';
8
+ import RelativeAttitude from '../relative/RelativeAttitude.js';
9
+ import ProviderEvent from '../../../events/ProviderEvent.js';
11
10
 
12
11
  /**
13
12
  * Absolute attitude provider gives the device attitude in East-North-Up (ENU) frame
14
13
  */
15
- class AbsoluteAttitude extends MetaProvider {
14
+ class AbsoluteAttitude extends Provider {
15
+
16
+ /** @type {boolean} */
17
+ _attitudeFromBrowserErrored = false;
18
+
19
+ /** @type {boolean} */
20
+ _attitudeFromRelativeErrored = false;
21
+
22
+ /*
23
+ * RELATIVE
24
+ */
25
+
26
+ /** @type {Attitude} */
27
+ _relativeAttitude = null;
28
+
29
+ /** @type {number} in radians/s */
30
+ _relativeAccuracy = 0;
31
+
32
+ /** @type {ProviderEvent<Attitude|AbsoluteHeading>} */
33
+ _lastForcedHeadingEvent;
34
+
35
+ /** @type {number[]} quaternion offset from relative to absolute */
36
+ _relAbsQuat;
37
+
16
38
 
17
39
  constructor() {
18
40
  super();
19
41
 
20
- this.attitudeFromBrowserErrored = false;
21
- this.attitudeFromRelAttErrored = false;
22
- this.attitudeFusedErrored = false;
42
+ this._attitudeFromBrowserErrored = false;
43
+ this._attitudeFromRelativeErrored = false;
23
44
  }
24
45
 
25
46
  /**
@@ -42,8 +63,7 @@ class AbsoluteAttitude extends MetaProvider {
42
63
  get _availability() {
43
64
  return PromiseUtils.any([
44
65
  AbsoluteAttitudeFromBrowser.availability,
45
- AbsoluteAttitudeFromRelAtt.availability,
46
- AbsoluteAttitudeFused.availability
66
+ RelativeAttitude.availability
47
67
  ]);
48
68
  }
49
69
 
@@ -53,87 +73,122 @@ class AbsoluteAttitude extends MetaProvider {
53
73
  start() {
54
74
 
55
75
  this.fromBrowserProviderId = AbsoluteAttitudeFromBrowser.addEventListener(
56
- events => this.onAttitudeFromBrowser(events[0]),
76
+ events => this._onAttitudeFromBrowser(events[0]),
57
77
  error => {
58
- this.attitudeFromBrowserErrored = true;
78
+ this._attitudeFromBrowserErrored = true;
59
79
  this.onError(error);
60
80
  }
61
81
  );
62
82
 
63
- this.fromRelAttProviderId = AbsoluteAttitudeFromRelAtt.addEventListener(
64
- events => this.onAttitudeFromRelAtt(events[0]),
83
+ this.relativeAttitudeProviderId = RelativeAttitude.addEventListener(
84
+ events => this._onRelativeAttitudeEvent(events[0]),
65
85
  error => {
66
- this.attitudeFromRelAttErrored = true;
67
- this.onError(error);
86
+ this._attitudeFromRelativeErrored = true;
87
+ this.notifyError(error);
68
88
  }
69
89
  );
70
90
 
71
- this.fusedProviderId = AbsoluteAttitudeFused.addEventListener(
72
- events => this.onAttitudeFused(events[0]),
73
- error => {
74
- this.attitudeFusedErrored = true;
75
- this.onError(error);
76
- }
77
- );
91
+ }
92
+
93
+ /**
94
+ * @override
95
+ */
96
+ stop() {
97
+ AbsoluteAttitudeFromBrowser.removeEventListener(this.fromBrowserProviderId);
98
+ RelativeAttitude.removeEventListener(this.relativeAttitudeProviderId);
78
99
  }
79
100
 
80
101
  onError(error) {
81
- if (this.attitudeFromBrowserErrored
82
- && this.attitudeFromRelAttErrored
83
- && this.attitudeFusedErrored) {
102
+ if (this._attitudeFromBrowserErrored && this._attitudeFromRelativeErrored) {
84
103
  this.notifyError(error);
85
104
  }
86
105
  }
87
106
 
88
- onAttitudeFromBrowser(event) {
89
- this.eventFromBrowser = event;
90
107
 
108
+ /**
109
+ * @param {ProviderEvent<Attitude|AbsoluteHeading>} absoluteHeadingEvent
110
+ */
111
+ _forceHeadingForRelative = (absoluteHeadingEvent, force = false) => {
91
112
 
92
- if (this.eventFromRelAtt && this.eventFromRelAtt.data.accuracy < event.data.accuracy) {
93
- return;
94
- }
95
- if (this.eventFromFused && this.eventFromFused.data.accuracy < event.data.accuracy) {
113
+ if (!force && this.lastEvent
114
+ && absoluteHeadingEvent.data.accuracy > this.lastEvent.data.accuracy) {
96
115
  return;
97
116
  }
98
- this.notify(event.clone());
99
- }
100
117
 
101
- onAttitudeFromRelAtt(event) {
102
- this.eventFromRelAtt = event;
118
+ const currentRelativeHeading = this._relativeAttitude ? this._relativeAttitude.heading : 0;
103
119
 
104
- if (this.eventFromBrowser && this.eventFromBrowser.data.accuracy < event.data.accuracy) {
105
- return;
106
- }
107
- if (this.eventFromFused && this.eventFromFused.data.accuracy < event.data.accuracy) {
120
+ this._relAbsQuat = Quaternion.fromAxisAngle(
121
+ [0, 0, 1],
122
+ currentRelativeHeading - absoluteHeadingEvent.data.heading
123
+ );
124
+
125
+ this._relativeAccuracy = 0;
126
+ this._lastForcedHeadingEvent = absoluteHeadingEvent;
127
+ };
128
+
129
+ /**
130
+ * @param {ProviderEvent<Attitude>} event
131
+ */
132
+ _onRelativeAttitudeEvent(event) {
133
+
134
+ if (!this._lastForcedHeadingEvent) {
108
135
  return;
109
136
  }
110
- this.notify(event.clone());
111
- }
112
137
 
113
- onAttitudeFused(event) {
114
- this.eventFromFused = event;
138
+ const { quaternion, accuracy, time } = event.data;
115
139
 
116
- if (this.eventFromBrowser && this.eventFromBrowser.data.accuracy < event.data.accuracy) {
117
- return;
140
+ // Calculate relative accuracy
141
+ if (this._relativeAttitude) {
142
+ this._relativeAccuracy += (time - this._relativeAttitude.time) * accuracy;
118
143
  }
119
- if (this.eventFromRelAtt && this.eventFromRelAtt.data.accuracy < event.data.accuracy) {
120
- return;
144
+ // Keep the relative attitude event for the calculation of relAbsQuat
145
+ this._relativeAttitude = event.data;
146
+
147
+ const accuracyWithRelative = Math.min(
148
+ this._lastForcedHeadingEvent.data.accuracy + this._relativeAccuracy,
149
+ Math.PI
150
+ );
151
+ const accuracyWithAbsolute = this._eventFromBrowser.data.accuracy;
152
+
153
+ let newAccuracy;
154
+ let relAbsQuat;
155
+ if (accuracyWithAbsolute < accuracyWithRelative) {
156
+ const currentHeading = this._relativeAttitude ? this._relativeAttitude.heading : 0;
157
+ newAccuracy = accuracyWithAbsolute;
158
+ relAbsQuat = Quaternion.fromAxisAngle([0, 0, 1], currentHeading - this._eventFromBrowser.data.heading);
159
+ } else {
160
+ newAccuracy = accuracyWithRelative;
161
+ relAbsQuat = this._relAbsQuat;
121
162
  }
122
- this.notify(event.clone());
163
+
164
+ const absoluteQuat = Quaternion.multiply(relAbsQuat, quaternion);
165
+ const attitude = new Attitude(absoluteQuat, time, newAccuracy);
166
+
167
+ this.notify(this.createEvent(
168
+ EventType.AbsoluteAttitude,
169
+ attitude,
170
+ [event, this._lastForcedHeadingEvent]
171
+ ));
123
172
  }
124
173
 
174
+
125
175
  /**
126
- * @override
176
+ * @param {ProviderEvent<Attitude>} event
127
177
  */
128
- stop() {
129
- AbsoluteAttitudeFromBrowser.removeEventListener(this.fromBrowserProviderId);
130
- AbsoluteAttitudeFromRelAtt.removeEventListener(this.fromRelAttProviderId);
131
- AbsoluteAttitudeFused.removeEventListener(this.fusedProviderId);
178
+ _onAttitudeFromBrowser(event) {
179
+ this._eventFromBrowser = event;
180
+
181
+ if (!this._lastForcedHeadingEvent) {
182
+ this._forceHeadingForRelative(event);
183
+ return;
184
+ }
185
+
186
+ // Absolute attitude from browser is not used anymore due to magnetometer inaccuracy on pitch and roll
132
187
  }
133
188
 
134
189
  /**
135
190
  * @override
136
- * @param {AbsoluteHeading|Attitude} data
191
+ * @param {AbsoluteHeading|Attitude|ProviderEvent} data
137
192
  */
138
193
  feed(data) {
139
194
 
@@ -146,10 +201,7 @@ class AbsoluteAttitude extends MetaProvider {
146
201
  throw Error('the accuracy of the absolute heading is not defined');
147
202
  }
148
203
 
149
- this.notify(this.createEvent(
150
- EventType.AbsoluteAttitude,
151
- data.toAttitude()
152
- ));
204
+ this._forceHeadingForRelative(new ProviderEvent(EventType.AbsoluteHeading, data));
153
205
 
154
206
  } else if (data instanceof Attitude) {
155
207
 
@@ -160,10 +212,16 @@ class AbsoluteAttitude extends MetaProvider {
160
212
  throw Error('the accuracy of the attitude is not defined');
161
213
  }
162
214
 
163
- this.notify(this.createEvent(
164
- EventType.AbsoluteAttitude,
165
- data
166
- ));
215
+ this._forceHeadingForRelative(new ProviderEvent(EventType.AbsoluteHeading, data));
216
+
217
+ } else if (data instanceof ProviderEvent) {
218
+
219
+ if (data.dataType !== EventType.AbsoluteHeading
220
+ || !(data.data instanceof AbsoluteHeading)) {
221
+ throw Error('the provider event is not an AbsoluteHeading');
222
+ }
223
+
224
+ this._forceHeadingForRelative(data);
167
225
 
168
226
  } else {
169
227
  throw new Error('data is nor an AbsoluteHeading or an Attitude object');
@@ -1,5 +1,3 @@
1
- import noop from 'lodash.noop';
2
-
3
1
  import Provider from '../../Provider.js';
4
2
  import EventType from '../../../events/EventType.js';
5
3
  import ProviderState from '../../ProviderState.js';
@@ -84,7 +82,7 @@ class RelativeAttitude extends Provider {
84
82
  this.notify(relativeAttitudeEvent.clone());
85
83
  }
86
84
  },
87
- noop,
85
+ () => {},
88
86
  false
89
87
  );
90
88
  };
@@ -88,8 +88,7 @@ class RelativeAttitudeFromBrowser extends Provider {
88
88
  const quaternion = Rotations.eulerToQuaternionZXYDegrees([e.alpha, e.beta, e.gamma]);
89
89
  const attitude = new Attitude(quaternion,
90
90
  e.timeStamp / 1e3,
91
- RelativeAttitudeFromInertial.DEFAULT_DRIFT,
92
- this.pname
91
+ RelativeAttitudeFromInertial.DEFAULT_DRIFT
93
92
  );
94
93
  this.notify(this.createEvent(EventType.RelativeAttitude, attitude));
95
94
  };
@@ -99,8 +99,7 @@ class RelativeAttitudeFromEkf extends Provider {
99
99
  if (quaternion) {
100
100
  const attitude = new Attitude(quaternion,
101
101
  timestamp,
102
- RelativeAttitudeFromInertial.DEFAULT_DRIFT,
103
- this.pname
102
+ RelativeAttitudeFromInertial.DEFAULT_DRIFT
104
103
  );
105
104
  this.notify(this.createEvent(
106
105
  EventType.RelativeAttitude,
@@ -1,10 +1,13 @@
1
+ import { Attitude } from '@wemap/geo';
1
2
  import { deg2rad } from '@wemap/maths';
2
3
  import { PromiseUtils } from '@wemap/utils';
3
4
 
4
5
  import Provider from '../../Provider.js';
6
+ import ProviderEvent from '../../../events/ProviderEvent.js';
5
7
  import EventType from '../../../events/EventType.js';
6
8
  import RelativeAttitudeFromEkf from './RelativeAttitudeFromEkf.js';
7
9
  import RelativeAttitudeFromBrowser from './RelativeAttitudeFromBrowser.js';
10
+ import HighRotationsDetector from '../../imu/HighRotationsDetector.js';
8
11
 
9
12
 
10
13
  class RelativeAttitudeFromInertial extends Provider {
@@ -12,7 +15,7 @@ class RelativeAttitudeFromInertial extends Provider {
12
15
  /**
13
16
  * default relative attitude drift in rad.second-1
14
17
  */
15
- static DEFAULT_DRIFT = deg2rad(5) / 60;
18
+ DEFAULT_DRIFT = deg2rad(5) / 60;
16
19
 
17
20
 
18
21
  /**
@@ -49,11 +52,24 @@ class RelativeAttitudeFromInertial extends Provider {
49
52
  .catch(() => (this.provider = RelativeAttitudeFromBrowser))
50
53
  .finally(() => {
51
54
  this.listenerId = this.provider.addEventListener(
52
- events => this.notify(events[0].clone()),
55
+ events => this._parseEvent(events[0]),
53
56
  error => this.notifyError(error)
54
57
  );
58
+ this._highRotationsDetector = HighRotationsDetector.addEventListener();
55
59
  });
60
+ }
56
61
 
62
+ /**
63
+ * @param {ProviderEvent<Attitude>} event
64
+ */
65
+ _parseEvent(event) {
66
+ const relativeAttitudeEvent = event.clone();
67
+ if (HighRotationsDetector.isInProgress()) {
68
+ let accuracy = relativeAttitudeEvent.data.accuracy + (this.DEFAULT_DRIFT * 100);
69
+ accuracy = Math.min(accuracy, Math.PI);
70
+ relativeAttitudeEvent.data.accuracy = accuracy;
71
+ }
72
+ this.notify(relativeAttitudeEvent);
57
73
  }
58
74
 
59
75
  /**
@@ -64,6 +80,7 @@ class RelativeAttitudeFromInertial extends Provider {
64
80
  this.provider.removeEventListener(this.listenerId);
65
81
  this.provider = null;
66
82
  }
83
+ HighRotationsDetector.removeEventListener(this._highRotationsDetector);
67
84
  }
68
85
  }
69
86
 
@@ -0,0 +1,62 @@
1
+ import { Vector3 } from '@wemap/maths';
2
+
3
+ import EventType from '../../events/EventType.js';
4
+ import Provider from '../Provider.js';
5
+ import Gyroscope from './Gyroscope.js';
6
+
7
+ class HighRotationsDetector extends Provider {
8
+
9
+ // in radians by second
10
+ static THRESHOLD = 10;
11
+
12
+ /** @type {number} in seconds */
13
+ static DELAY_CONSIDERATION = 3;
14
+
15
+ /**
16
+ * @override
17
+ */
18
+ static get pname() {
19
+ return 'HighRotationsDetector';
20
+ }
21
+
22
+ /**
23
+ * @override
24
+ */
25
+ start() {
26
+ this.providerId = Gyroscope.addEventListener(
27
+ events => this._parseGyroscopeEvent(events[0]),
28
+ error => this.notifyError(error)
29
+ );
30
+ }
31
+
32
+ /**
33
+ * @override
34
+ */
35
+ stop() {
36
+ Gyroscope.removeEventListener(this.providerId);
37
+ }
38
+
39
+ isInProgress() {
40
+ if (!this.lastEvent || !Gyroscope.lastEvent) {
41
+ return false;
42
+ }
43
+
44
+ const diffTime = Gyroscope.lastEvent.data.timestamp - this.lastEvent.data.timestamp;
45
+ return diffTime < HighRotationsDetector.DELAY_CONSIDERATION;
46
+ }
47
+
48
+ /**
49
+ * @private
50
+ */
51
+ _parseGyroscopeEvent = gyroscopeEvent => {
52
+
53
+ const { values, timestamp } = gyroscopeEvent.data;
54
+ const speed = Vector3.norm(values);
55
+ if (speed > HighRotationsDetector.THRESHOLD) {
56
+ this.notify(this.createEvent(EventType.HighRotation, { timestamp }, [gyroscopeEvent]));
57
+ }
58
+
59
+ }
60
+ }
61
+
62
+ export default new HighRotationsDetector();
@@ -1,6 +1,6 @@
1
1
  import { PromiseUtils } from '@wemap/utils';
2
2
 
3
- import MetaProvider from '../MetaProvider.js';
3
+ import Provider from '../Provider.js';
4
4
  import EventType from '../../events/EventType.js';
5
5
  import InclinationFromAcc from './InclinationFromAcc.js';
6
6
  import InclinationFromRelativeAttitude from './InclinationFromRelativeAttitude.js';
@@ -11,7 +11,7 @@ import InclinationFromRelativeAttitude from './InclinationFromRelativeAttitude.j
11
11
  * when the device is layed on a table, inclination = 0
12
12
  * This provider use window.orientation to return a result in function of screen orientation
13
13
  */
14
- class Inclination extends MetaProvider {
14
+ class Inclination extends Provider {
15
15
 
16
16
  /**
17
17
  * @override
@@ -1,9 +1,9 @@
1
- import MetaProvider from '../MetaProvider.js';
1
+ import Provider from '../Provider.js';
2
2
  import EventType from '../../events/EventType.js';
3
3
  import { ArCore } from '../../Providers.js';
4
4
  import ProviderState from '../ProviderState.js';
5
5
 
6
- class CameraNative extends MetaProvider {
6
+ class CameraNative extends Provider {
7
7
 
8
8
  /**
9
9
  * @override
@@ -1,8 +1,8 @@
1
- import MetaProvider from '../MetaProvider.js';
1
+ import Provider from '../Provider.js';
2
2
  import EventType from '../../events/EventType.js';
3
3
  import ArCore from '../position/relative/ArCore.js';
4
4
 
5
- class CameraProjectionMatrix extends MetaProvider {
5
+ class CameraProjectionMatrix extends Provider {
6
6
 
7
7
  /**
8
8
  * @override