@wemap/positioning 1.2.2 → 2.1.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 (108) hide show
  1. package/.eslintrc.json +4 -2
  2. package/debug/absolute-attitude.html +16 -0
  3. package/debug/gnss-wifi-pdr.html +16 -0
  4. package/debug/gnss-wifi.html +16 -0
  5. package/debug/imu.html +16 -0
  6. package/debug/inclination.html +16 -0
  7. package/debug/pdr.html +16 -0
  8. package/debug/pose.html +16 -0
  9. package/debug/positioning.html +16 -0
  10. package/debug/relative-attitude.html +16 -0
  11. package/package.json +6 -4
  12. package/src/PositioningHandler.js +124 -0
  13. package/src/components/AbsoluteAttitudeComponent.jsx +104 -0
  14. package/src/components/GnssWifiComponent.jsx +46 -0
  15. package/src/components/GnssWifiPdrComponent.jsx +85 -0
  16. package/src/components/ImuComponent.jsx +100 -0
  17. package/src/components/InclinationComponent.jsx +53 -0
  18. package/src/components/PdrComponent.jsx +88 -0
  19. package/src/components/PoseComponent.jsx +74 -0
  20. package/src/components/PositioningComponent.jsx +26 -0
  21. package/src/components/PositioningInclinationComponent.jsx +76 -0
  22. package/src/components/PositioningPoseComponent.jsx +111 -0
  23. package/src/components/RelativeAttitudeComponent.jsx +82 -0
  24. package/src/components/StartStopComponent.jsx +50 -0
  25. package/src/components/Utils.js +41 -2
  26. package/src/components/index.js +19 -2
  27. package/src/errors/AskImuOnDesktopError.js +9 -0
  28. package/src/errors/GeolocationApiMissingError.js +9 -0
  29. package/src/errors/GeolocationPermissionDeniedError.js +9 -0
  30. package/src/errors/GeolocationPositionUnavailableError.js +9 -0
  31. package/src/errors/IpResolveServerError.js +9 -0
  32. package/src/errors/MissingAccelerometerError.js +11 -0
  33. package/src/errors/MissingGyroscopeError.js +11 -0
  34. package/src/errors/MissingMagnetometerError.js +9 -0
  35. package/src/errors/MissingSensorError.js +14 -0
  36. package/src/events/EventType.js +20 -0
  37. package/src/events/ProviderError.js +52 -0
  38. package/src/events/ProviderEvent.js +35 -0
  39. package/src/index.js +3 -4
  40. package/src/providers/Constants.js +5 -0
  41. package/src/providers/FakeAbsolutePositionProvider.js +56 -0
  42. package/src/providers/Provider.js +218 -0
  43. package/src/providers/ProviderOptions.js +28 -0
  44. package/src/providers/ProvidersLogger.js +3 -3
  45. package/src/providers/attitude/AbsoluteAttitudeProvider.js +207 -0
  46. package/src/providers/attitude/EkfAttitude.js +238 -0
  47. package/src/providers/attitude/EkfAttitude.spec.js +116 -0
  48. package/src/providers/attitude/RelativeAttitudeProvider.js +129 -0
  49. package/src/providers/others/ImuProvider.js +186 -0
  50. package/src/providers/others/InclinationProvider.js +107 -0
  51. package/src/providers/others/MapMatchingProvider.js +147 -0
  52. package/src/providers/pose/GnssWifiPdrProvider.js +233 -0
  53. package/src/providers/pose/PoseProvider.js +90 -0
  54. package/src/providers/pose/pdr/PdrProvider.js +352 -0
  55. package/src/providers/pose/pdr/helpers/HeadingUnlocker.js +41 -0
  56. package/src/providers/pose/pdr/helpers/HeadingUnlocker.spec.js +26 -0
  57. package/src/providers/pose/pdr/helpers/Smoother.js +90 -0
  58. package/src/providers/pose/pdr/helpers/Smoother.spec.js +424 -0
  59. package/src/providers/pose/pdr/helpers/ThugDetector.js +37 -0
  60. package/src/providers/pose/pdr/steps/StepDetection.js +7 -0
  61. package/src/providers/pose/pdr/steps/StepDetectionLadetto.js +67 -0
  62. package/src/providers/pose/pdr/steps/StepDetectionMinMaxPeaks.js +80 -0
  63. package/src/providers/pose/pdr/steps/StepDetectionMinMaxPeaks2.js +108 -0
  64. package/src/providers/position/GnssWifiProvider.js +129 -0
  65. package/src/providers/position/IpProvider.js +75 -0
  66. package/src.old/components/Utils.js +35 -0
  67. package/src.old/components/index.js +13 -0
  68. package/src.old/index.js +7 -0
  69. package/{src → src.old}/providers/GnssPdrLocationSource.js +1 -1
  70. package/src.old/providers/ProvidersLogger.js +77 -0
  71. package/webpack/webpack.dev.js +1 -1
  72. package/debug/index.html +0 -15
  73. package/debug/index.old.html +0 -37
  74. package/scripts/release-github.js +0 -216
  75. package/src.new/NavigationHandler.js +0 -62
  76. package/src.new/index.js +0 -3
  77. package/src.new/providers/FakeLocationSource.js +0 -39
  78. /package/{src → src.old}/Constants.js +0 -0
  79. /package/{src → src.old}/NavigationHandler.js +0 -0
  80. /package/{src → src.old}/Pose.js +0 -0
  81. /package/{src → src.old}/attitude/AttitudeHandler.js +0 -0
  82. /package/{src → src.old}/attitude/EkfAttitude.js +0 -0
  83. /package/{src → src.old}/attitude/EkfAttitude.spec.js +0 -0
  84. /package/{src → src.old}/components/AbsoluteAttitude.jsx +0 -0
  85. /package/{src → src.old}/components/Imu.jsx +0 -0
  86. /package/{src → src.old}/components/LocationSource.jsx +0 -0
  87. /package/{src → src.old}/components/Logger.jsx +0 -0
  88. /package/{src → src.old}/components/NavigationDebugApp.jsx +0 -0
  89. /package/{src → src.old}/components/Others.jsx +0 -0
  90. /package/{src → src.old}/components/RelativeAttitude.jsx +0 -0
  91. /package/{src → src.old}/providers/FixedLocationImuLocationSource.js +0 -0
  92. /package/{src → src.old}/providers/GnssLocationSource.js +0 -0
  93. /package/{src → src.old}/providers/IPLocationSource.js +0 -0
  94. /package/{src → src.old}/providers/LocationSource.js +0 -0
  95. /package/{src → src.old}/providers/PdrLocationSource.js +0 -0
  96. /package/{src → src.old}/providers/pdr/HeadingUnlocker.js +0 -0
  97. /package/{src → src.old}/providers/pdr/HeadingUnlocker.spec.js +0 -0
  98. /package/{src → src.old}/providers/pdr/Smoother.js +0 -0
  99. /package/{src → src.old}/providers/pdr/Smoother.spec.js +0 -0
  100. /package/{src → src.old}/providers/pdr/ThugDetector.js +0 -0
  101. /package/{src → src.old}/providers/steps/StepDetection.js +0 -0
  102. /package/{src → src.old}/providers/steps/StepDetectionLadetto.js +0 -0
  103. /package/{src → src.old}/providers/steps/StepDetectionMinMaxPeaks.js +0 -0
  104. /package/{src → src.old}/providers/steps/StepDetectionMinMaxPeaks2.js +0 -0
  105. /package/{src → src.old}/sensors/SensorsCompatibility.js +0 -0
  106. /package/{src → src.old}/sensors/SensorsCompatibility.spec.js +0 -0
  107. /package/{src → src.old}/sensors/SensorsLogger.js +0 -0
  108. /package/{src → src.old}/sensors/SensorsLoggerUtils.js +0 -0
@@ -0,0 +1,186 @@
1
+ import { deg2rad } from '@wemap/maths';
2
+ import {
3
+ Browser, BrowserUtils
4
+ } from '@wemap/utils';
5
+
6
+ import Provider from '../Provider';
7
+ import EventType from '../../events/EventType';
8
+ import MissingAccelerometerError from '../../errors/MissingAccelerometerError';
9
+ import MissingGyroscopeError from '../../errors/MissingGyroscopeError';
10
+ import AskImuOnDesktopError from '../../errors/AskImuOnDesktopError';
11
+
12
+ /**
13
+ * Imu (Inertial Measurement Unit) provider retrieve acceleration data
14
+ * and/or angular rate data from inertial sensors.
15
+ * opions.require has to be defined in order to work
16
+ *
17
+ * -----------------------------------
18
+ * Overview of compatibilities:
19
+ * -----------------------------------
20
+ *
21
+ * Chrome Android (v72.0.3626): YES (via devicemotion)
22
+ * Safari iOS (v12.0): YES (via devicemotion)
23
+ * Opera Android (v50.2.2426): NO {@link https://developer.mozilla.org/en-US/docs/Web/API/DeviceMotionEvent}
24
+ * Firefox Android (v65.0.1): YES (via devicemotion)
25
+ *
26
+ * -----------------------------------
27
+ */
28
+ class ImuProvider extends Provider {
29
+
30
+ requiredSensors = [];
31
+
32
+ /**
33
+ * Constructor of ImuProvider
34
+ * options.require has to be filled by a list of EventType
35
+ * @example options = {require: [EventType.Acceleration, EventType.AngularRate]};
36
+ * @example options = {require: [EventType.Acceleration]};
37
+ *
38
+ * @param {Function} onEvent @see Provider#constructor
39
+ * @param {Function} onError @see Provider#constructor
40
+ * @param {Object} options @see Provider#constructor
41
+ */
42
+ constructor(onEvent, onError, options) {
43
+ super(onEvent, onError, options);
44
+
45
+ if (!options.hasOwnProperty('require')) {
46
+ throw new Error('options.require is missing in ImuProvider constructor');
47
+ }
48
+
49
+ if (options.require.length === 0) {
50
+ throw new Error('option.require is empty');
51
+ }
52
+
53
+ options.require.forEach(elem => {
54
+ if (!ImuProvider.eventsType.includes(elem)) {
55
+ throw new Error(elem + ' is not recognised in options.require');
56
+ }
57
+ });
58
+
59
+ this.requiredSensors = options.require;
60
+ }
61
+
62
+
63
+ /**
64
+ * @override
65
+ */
66
+ static get displayName() {
67
+ return 'Inertial Measurement Unit';
68
+ }
69
+
70
+ /**
71
+ * @override
72
+ */
73
+ static get eventsType() {
74
+ return [EventType.AngularRate, EventType.Acceleration];
75
+ }
76
+
77
+ /**
78
+ * @override
79
+ */
80
+ static checkAvailabilityErrors() {
81
+
82
+ if (BrowserUtils.isMobile) {
83
+ return [];
84
+ }
85
+
86
+ return [
87
+ ImuProvider.createError(
88
+ EventType.AngularRate,
89
+ new AskImuOnDesktopError()
90
+ ),
91
+ ImuProvider.createError(
92
+ EventType.Acceleration,
93
+ new AskImuOnDesktopError()
94
+ )
95
+ ];
96
+ }
97
+
98
+ /**
99
+ * @override
100
+ */
101
+ startInternal() {
102
+ window.addEventListener('devicemotion', this.parseDeviceMotionEvent, true);
103
+ }
104
+
105
+ /**
106
+ * @override
107
+ */
108
+ stopInternal() {
109
+ window.removeEventListener('devicemotion', this.parseDeviceMotionEvent, true);
110
+ }
111
+
112
+ /**
113
+ * devicemotion callback
114
+ * @param {DeviceMotionEvent} e device motion event
115
+ * @returns {ProviderEvent[]} an array of provider events
116
+ * @private
117
+ */
118
+ parseDeviceMotionEvent = e => {
119
+
120
+ const events = [];
121
+
122
+ const timestamp = e.timeStamp / 1e3;
123
+
124
+ if (this.requiredSensors.includes(EventType.Acceleration)) {
125
+
126
+ let acc;
127
+ if (e.accelerationIncludingGravity) {
128
+ const {
129
+ x, y, z
130
+ } = e.accelerationIncludingGravity;
131
+
132
+ if (x && y && z) {
133
+ acc = [x, y, z];
134
+
135
+ if (BrowserUtils.name === Browser.SAFARI) {
136
+ acc[0] *= -1;
137
+ acc[1] *= -1;
138
+ acc[2] *= -1;
139
+ }
140
+ }
141
+ }
142
+
143
+ if (!acc) {
144
+ super.notifyError(this.createError(
145
+ EventType.AngularRate,
146
+ new MissingAccelerometerError().from('devicemotion'),
147
+ timestamp
148
+ ));
149
+ return;
150
+ }
151
+
152
+ events.push(this.createEvent(EventType.Acceleration, acc, timestamp));
153
+ }
154
+
155
+
156
+ if (this.requiredSensors.includes(EventType.AngularRate)) {
157
+
158
+ let gyr;
159
+ if (e.rotationRate) {
160
+ const {
161
+ alpha, beta, gamma
162
+ } = e.rotationRate;
163
+
164
+ if (alpha && beta && gamma) {
165
+ gyr = [deg2rad(alpha), deg2rad(beta), deg2rad(gamma)];
166
+ }
167
+ }
168
+
169
+ if (!gyr) {
170
+ super.notifyError(this.createError(EventType.AngularRate,
171
+ new MissingGyroscopeError().from('devicemotion'),
172
+ timestamp));
173
+ return;
174
+ }
175
+
176
+ events.push(this.createEvent(EventType.AngularRate, gyr, timestamp));
177
+ }
178
+
179
+ if (events.length !== 0) {
180
+ super.notify(...events);
181
+ }
182
+ }
183
+
184
+ }
185
+
186
+ export default ImuProvider;
@@ -0,0 +1,107 @@
1
+ import Provider from '../Provider';
2
+ import EventType from '../../events/EventType';
3
+ import ImuProvider from './ImuProvider';
4
+ import ProviderError from '../../events/ProviderError';
5
+
6
+ /**
7
+ * Inclination provider gives the inclination of the device using Imu Sensor
8
+ * For example, when the top of the device is pointing the sky, inclination = Math.PI/2
9
+ * when the device is layed on a table, inclination = 0
10
+ * This provider use window.orientation to return a result in function of screen orientation
11
+ */
12
+ class InclinationProvider extends Provider {
13
+
14
+ /**
15
+ * @override
16
+ */
17
+ constructor(onEvent, onError, options) {
18
+ super(onEvent, onError, options);
19
+
20
+ this.imuProvider = new ImuProvider(
21
+ this.onImuEvent,
22
+ this.onImuError,
23
+ { require: [EventType.Acceleration] }
24
+ );
25
+ }
26
+
27
+ /**
28
+ * @override
29
+ */
30
+ static get displayName() {
31
+ return 'Inertial Measurement Unit';
32
+ }
33
+
34
+ /**
35
+ * @override
36
+ */
37
+ static get eventsType() {
38
+ return [EventType.Inclination];
39
+ }
40
+
41
+ /**
42
+ * @override
43
+ */
44
+ static get requiredProviders() {
45
+ return [ImuProvider];
46
+ }
47
+
48
+ /**
49
+ * @override
50
+ */
51
+ startInternal() {
52
+ return this.imuProvider.start();
53
+ }
54
+
55
+ /**
56
+ * @override
57
+ */
58
+ stopInternal() {
59
+ return this.imuProvider.stop();
60
+ }
61
+
62
+ /**
63
+ * @private
64
+ */
65
+ onImuEvent = imuEvent => {
66
+ const accelerationEvent = imuEvent[0];
67
+ const acc = accelerationEvent.data;
68
+
69
+ const screenOrientation = window.orientation || 0;
70
+
71
+ const sizeAcc = Math.sqrt(acc[0] * acc[0] + acc[1] * acc[1] + acc[2] * acc[2]);
72
+ const accNormalized = [acc[0] / sizeAcc, acc[1] / sizeAcc, acc[2] / sizeAcc];
73
+
74
+ const q = [accNormalized[2] + 1, accNormalized[1], -accNormalized[0], 0];
75
+ const qSize = Math.sqrt(q[0] * q[0] + q[1] * q[1] + q[2] * q[2]);
76
+ const qNormalized = [q[0] / qSize, q[1] / qSize, q[2] / qSize, 0];
77
+
78
+ let inclination;
79
+ if (screenOrientation === 0) {
80
+ inclination = Math.asin(2 * qNormalized[1] * qNormalized[0]);
81
+ } else if (screenOrientation === 90) {
82
+ inclination = -Math.asin(2 * qNormalized[2] * qNormalized[0]);
83
+ } else if (screenOrientation === -90) {
84
+ inclination = Math.asin(2 * qNormalized[2] * qNormalized[0]);
85
+ } else if (screenOrientation === 180) {
86
+ inclination = -Math.asin(2 * qNormalized[1] * qNormalized[0]);
87
+ }
88
+
89
+ this.notify(this.createEvent(EventType.Inclination, inclination));
90
+ };
91
+
92
+ onImuError = imuErrors => {
93
+ this.notifyError(...ProviderError.modifyArrayDataType(imuErrors, EventType.Inclination));
94
+ }
95
+
96
+ /**
97
+ * @override
98
+ */
99
+ static checkAvailabilityErrors() {
100
+ return ProviderError.modifyArrayDataType(
101
+ super.checkAvailabilityErrors(),
102
+ EventType.Inclination
103
+ );
104
+ }
105
+ }
106
+
107
+ export default InclinationProvider;
@@ -0,0 +1,147 @@
1
+ import Provider from '../Provider';
2
+ import {
3
+ WGS84, Edge, Itinerary, Network, MapMatching
4
+ } from '@wemap/geo';
5
+
6
+ class MapMatchingProvider extends Provider {
7
+
8
+ /**
9
+ * Enable LocationSource mapmatching
10
+ * @param {*} network a network which will be used for map matching
11
+ * @param {*} maxDistance max distance between location and network to match. null disables maxDistance (default: null)
12
+ * @param {*} maxAngleBearing threshold to match a parallel segment for angle between location bearing and segment. null disables this threshold (default: null)
13
+ * @public
14
+ */
15
+ enableMapMatching(network, maxDistance, maxAngleBearing) {
16
+ this.mapMatching = new MapMatching();
17
+ this.mapMatching.maxDistance = maxDistance;
18
+ this.mapMatching.maxAngleBearing = maxAngleBearing;
19
+
20
+ if (network) {
21
+ this.setNetwork(network);
22
+ }
23
+ }
24
+
25
+ /**
26
+ * Update the LocationSource network for mapmatching
27
+ * @param {Network} network a network instance
28
+ * @public
29
+ */
30
+ setNetwork(network) {
31
+ if (!(network instanceof Network)) {
32
+ throw new TypeError(network + ' is not an instance of Network');
33
+ }
34
+ if (!this.mapMatching) {
35
+ throw new Error('MapMatching is not enabled');
36
+ }
37
+ this.mapMatching.setNetwork(network);
38
+ }
39
+
40
+ /**
41
+ * Is mapmatching activated?
42
+ * @returns is mapmatching activated
43
+ * @public
44
+ */
45
+ get hasMapMatching() {
46
+ return this.mapMatching !== null;
47
+ }
48
+
49
+ /**
50
+ * Returns projection of a location on network
51
+ * @param {WGS84} location if location is null, projection of this.pose.location is used
52
+ * @returns The projected location {WGS84} or null.
53
+ * @public
54
+ */
55
+ getProjectionOnNetwork(location = null) {
56
+
57
+ if (!this.mapMatching) {
58
+ return null;
59
+ }
60
+
61
+ let locationToProject = location;
62
+ if (!location) {
63
+ locationToProject = this.pose.location;
64
+ }
65
+ if (!locationToProject) {
66
+ return null;
67
+ }
68
+
69
+ return this.mapMatching.getProjection(locationToProject, false, false);
70
+ }
71
+
72
+
73
+ /**
74
+ * Itinerary
75
+ */
76
+
77
+ /**
78
+ * Update itinerary of Location Source.
79
+ * Itinerary is different from network, it is not used for mapmatching. It can be used for others tricks like HeadingUnlocker
80
+ * @param {Itinerary} itinerary a given itinerary
81
+ * @public
82
+ */
83
+ setItinerary(itinerary) {
84
+ if (!(itinerary instanceof Itinerary)) {
85
+ throw new TypeError(itinerary + ' is not an instance of Itinerary');
86
+ }
87
+ this.itinerary = itinerary;
88
+ }
89
+
90
+
91
+ /**
92
+ * Returns projection and itinerary info of a location on network
93
+ * @param {WGS84} location if location is null, projection of this.pose.location is used
94
+ * @returns An object of the projected location and itinerary info or null.
95
+ * @public
96
+ */
97
+ getItineraryInfo(location = null) {
98
+
99
+ if (!this.itinerary) {
100
+ throw new Error('No itinerary found');
101
+ }
102
+ const projection = this.getProjectionOnNetwork(location);
103
+ if (!projection) {
104
+ return null;
105
+ }
106
+
107
+ const totalDistance = this.itinerary.distance;
108
+ let traveledDistance = 0;
109
+ const edges = this.itinerary.edges;
110
+
111
+ if (projection.nearestElement instanceof WGS84) {
112
+
113
+ for (let i = 0; i < edges.length; i++) {
114
+ const edge = edges[i];
115
+ if (edge.node1.equalsTo(projection.nearestElement)) {
116
+ break;
117
+ }
118
+ traveledDistance += edge.getLength();
119
+ }
120
+
121
+
122
+ } else if (projection.nearestElement instanceof Edge) {
123
+
124
+ for (let i = 0; i < edges.length; i++) {
125
+ const edge = edges[i];
126
+ if (edge.equalsTo(projection.nearestElement)) {
127
+ traveledDistance += edge.node1.distanceTo(projection.projection);
128
+ break;
129
+ }
130
+ traveledDistance += edge.getLength();
131
+ }
132
+
133
+ } else {
134
+ throw new Error('No projection found');
135
+ }
136
+
137
+ return {
138
+ projection: projection,
139
+ traveledDistance,
140
+ traveledPercentage: traveledDistance / totalDistance,
141
+ remainingDistance: totalDistance - traveledDistance,
142
+ remainingPercentage: 1 - traveledDistance / totalDistance
143
+ };
144
+ }
145
+ }
146
+
147
+ export default MapMatchingProvider;
@@ -0,0 +1,233 @@
1
+ /* eslint max-statements: ["error", 40]*/
2
+
3
+ import { WGS84UserPosition } from '@wemap/geo';
4
+
5
+ import MapMatchingProvider from '../others/MapMatchingProvider';
6
+ import PdrProvider from './pdr/PdrProvider';
7
+ import GnssWifiProvider from '../position/GnssWifiProvider';
8
+ import EventType from '../../events/EventType';
9
+ import AbsoluteAttitudeProvider from '../attitude/AbsoluteAttitudeProvider';
10
+ import Constants from '../Constants';
11
+ import ProviderError from '../../events/ProviderError';
12
+
13
+ const GPF_ACCURACY = 25;
14
+ const GPF_DISTANCE = 25;
15
+
16
+ const MM_GNSS_DIST = 20;
17
+ const MM_GNSS_ANGLE = 20;
18
+
19
+ class GnssWifiPdrProvider extends MapMatchingProvider {
20
+
21
+ /**
22
+ * @override
23
+ */
24
+ constructor(onEvent, onError, options) {
25
+ super(onEvent, onError, options);
26
+
27
+ this.pdrProvider = new PdrProvider(e => this.onPdrEvent(e), e => this.onProviderError(e), options);
28
+ this.gnssWifiProvider = new GnssWifiProvider(e => this.onGnssWifiEvent(e), e => this.onProviderError(e), options);
29
+ this.absoluteAttitudeProvider = new AbsoluteAttitudeProvider(
30
+ e => this.onAbsoluteAttitudeEvent(e),
31
+ e => this.onProviderError(e),
32
+ options
33
+ );
34
+
35
+ this.gpsLastUpdate = 0;
36
+ this.isFirstGnssUpdate = true;
37
+ this.isFirstAttitudeUpdate = true;
38
+ }
39
+
40
+
41
+ /**
42
+ * @override
43
+ */
44
+ static get displayName() {
45
+ return 'GnssWifiPdr';
46
+ }
47
+
48
+ /**
49
+ * @override
50
+ */
51
+ static get eventsType() {
52
+ return [EventType.AbsoluteAttitude, EventType.AbsolutePosition];
53
+ }
54
+
55
+ /**
56
+ * @override
57
+ */
58
+ static get requiredProviders() {
59
+ return [PdrProvider, GnssWifiProvider, AbsoluteAttitudeProvider];
60
+ }
61
+
62
+
63
+ /**
64
+ * @override
65
+ */
66
+ startInternal() {
67
+ this.pdrProvider.start();
68
+ this.gnssWifiProvider.start();
69
+ this.absoluteAttitudeProvider.start();
70
+ }
71
+
72
+ /**
73
+ * @override
74
+ */
75
+ stop() {
76
+ this.imuProvider.stop();
77
+ this.gnssWifiProvider.stop();
78
+ this.absoluteAttitudeProvider.stop();
79
+ }
80
+
81
+ /**
82
+ * @private
83
+ */
84
+ onPdrEvent(pdrEvent) {
85
+ pdrEvent.forEach(event => {
86
+ if (event.dataType === EventType.AbsolutePosition) {
87
+ this.location = event.data;
88
+ } else if (event.dataType === EventType.AbsoluteAttitude) {
89
+ this.attitude = event.data;
90
+ }
91
+ });
92
+ this.notify(...pdrEvent);
93
+ }
94
+
95
+ /**
96
+ * @private
97
+ */
98
+ onGnssWifiEvent(events) {
99
+
100
+ const gnssWifiEvent = events[0];
101
+ const location = gnssWifiEvent.data;
102
+
103
+ // This should be called to update True North / Magnetic North declination
104
+ this.absoluteAttitudeProvider.setLocation(location);
105
+
106
+ if (location.accuracy > GPF_ACCURACY) {
107
+ return;
108
+ }
109
+
110
+ this.gnssLocation = location.clone();
111
+ this.gnssLocation.alt = Constants.DEFAULT_ALTITUDE;
112
+
113
+ if (!this.location || this.location
114
+ && this.location.distanceTo(this.gnssLocation) > GPF_DISTANCE) {
115
+
116
+ if (!this.mapMatching || !this.attitude) {
117
+ this.pdrProvider.setLocation(this.gnssLocation);
118
+ } else {
119
+
120
+ this.gnssLocation.bearing = this.attitude.headingDegrees;
121
+ const projection = this.mapMatching.getProjection(this.gnssLocation);
122
+
123
+ if (projection && projection.projection) {
124
+
125
+ // Create a new location from projection and new GNSS location.
126
+ const projectedLocation = WGS84UserPosition.fromWGS84(projection.projection, this.gnssLocation);
127
+ this.pdrProvider.setLocation(projectedLocation);
128
+
129
+ // // If nearest element is an edge, use its orientation to set heading
130
+ // if (projection.nearestElement instanceof Edge) {
131
+ // const edgeBearing = projection.nearestElement.bearing;
132
+ // const diff1 = MathUtils.diffAngle(MathUtils.deg2rad(this.gnssLocation.bearing), edgeBearing);
133
+ // const diff2 = MathUtils.diffAngle(MathUtils.deg2rad(this.gnssLocation.bearing), edgeBearing + Math.PI);
134
+ // this.pdrProvider.setHeading(diff1 < diff2 ? edgeBearing : edgeBearing + Math.PI);
135
+ // }
136
+
137
+ if (this.lastAttitude) {
138
+ this.pdrProvider.setHeading(this.lastAttitude.heading);
139
+ }
140
+
141
+ } else {
142
+ this.pdrProvider.setLocation(this.gnssLocation);
143
+ }
144
+ }
145
+ }
146
+
147
+ }
148
+
149
+ onAbsoluteAttitudeEvent(events) {
150
+
151
+ const attitude = events[0].data;
152
+
153
+ if (this.isFirstAttitudeUpdate) {
154
+ this.pdrProvider.setHeading(attitude.heading);
155
+ this.isFirstAttitudeUpdate = false;
156
+ }
157
+
158
+ this.lastAttitude = attitude;
159
+ }
160
+
161
+ onProviderError(errors) {
162
+ this.notifyError(...ProviderError.modifyArrayDataType(errors, EventType.AbsoluteAttitude));
163
+ this.notifyError(...ProviderError.modifyArrayDataType(errors, EventType.AbsolutePosition));
164
+ }
165
+
166
+ /**
167
+ * @override
168
+ */
169
+ static checkAvailabilityErrors() {
170
+ const errors = super.checkAvailabilityErrors();
171
+ return ProviderError.modifyArrayDataType(
172
+ errors,
173
+ EventType.AbsolutePosition
174
+ ).concat(
175
+ ProviderError.modifyArrayDataType(
176
+ errors,
177
+ EventType.AbsoluteAttitude
178
+ )
179
+ );
180
+ }
181
+
182
+ /**
183
+ * MapMatching
184
+ */
185
+
186
+ enableMapMatching(network = null, maxDistance = MM_GNSS_DIST, maxAngleBearing = MM_GNSS_ANGLE) {
187
+ this.pdrProvider.enableMapMatching(network, maxDistance, maxAngleBearing);
188
+ super.enableMapMatching(network, maxDistance, maxAngleBearing);
189
+ }
190
+
191
+
192
+ setNetwork(network) {
193
+ this.pdrProvider.setNetwork(network);
194
+ super.setNetwork(network);
195
+ }
196
+
197
+ /**
198
+ * Itinerary
199
+ */
200
+
201
+ setItinerary(itinerary) {
202
+
203
+ const isFirstItinerary = !this.itinerary;
204
+
205
+ super.setItinerary(itinerary);
206
+
207
+ if (isFirstItinerary && itinerary.length > 0) {
208
+
209
+ // When the first itinerary is received, first or second node (depending on MM_GNSS_DIST) is used as a starting point. No map-matching is needed here as router already provide the projection in the itinerary (node2 is node1 projection on OSRM network).
210
+
211
+ if (!this.gnssLocation
212
+ || itinerary.length < 2
213
+ || !itinerary.points[0].equalsTo(this.gnssLocation)) {
214
+ console.warn('Itinerary has not been calculated from GnssWifiPdrProvider and these is not recommanded');
215
+ }
216
+
217
+ let startEdge;
218
+ if (itinerary.firstEdge.getLength() <= MM_GNSS_DIST) {
219
+ startEdge = itinerary.firstEdge;
220
+ } else {
221
+ startEdge = itinerary.secondEdge;
222
+ }
223
+ const startPoint = WGS84UserPosition.fromWGS84(startEdge.node1);
224
+ startPoint.alt = Constants.DEFAULT_ALTITUDE;
225
+ this.pdrProvider.setLocation(startPoint);
226
+ this.pdrProvider.setStepDetectionLockerOrientation(startEdge.getBearing());
227
+ }
228
+
229
+ }
230
+
231
+ }
232
+
233
+ export default GnssWifiPdrProvider;