@wemap/positioning 2.2.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.
- package/debug/arcore-absolute.html +16 -0
- package/package.json +1 -1
- package/src/PositioningHandler.js +19 -5
- package/src/components/AbsoluteAttitudeComponent.jsx +2 -2
- package/src/components/ArCoreAbsoluteComponent.jsx +100 -0
- package/src/components/ArCoreComponent.jsx +3 -3
- package/src/components/GnssWifiPdrComponent.jsx +2 -2
- package/src/components/MapComponent.jsx +29 -18
- package/src/components/PdrComponent.jsx +3 -3
- package/src/components/PositioningPoseComponent.jsx +3 -3
- package/src/components/index.js +2 -0
- package/src/providers/Provider.js +2 -2
- package/src/providers/ProviderOptions.js +1 -1
- package/src/providers/attitude/AbsoluteAttitudeProvider.js +6 -6
- package/src/providers/others/MapMatchingProvider.js +19 -19
- package/src/providers/pose/ArCoreAbsoluteProvider.js +186 -0
- package/src/providers/pose/ArCoreProvider.js +31 -43
- package/src/providers/pose/GnssWifiPdrProvider.js +20 -20
- package/src/providers/pose/PoseProvider.js +1 -1
- package/src/providers/pose/pdr/PdrProvider.js +38 -38
- package/src/providers/pose/pdr/helpers/Smoother.js +33 -33
- package/src/providers/pose/pdr/helpers/Smoother.spec.js +7 -7
- package/src/providers/position/GnssWifiProvider.js +5 -5
- package/src/providers/position/IpProvider.js +2 -2
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/* eslint-disable max-statements */
|
|
2
|
+
import { Attitude } from '@wemap/geo';
|
|
3
|
+
|
|
4
|
+
import Provider from '../Provider';
|
|
5
|
+
import EventType from '../../events/EventType';
|
|
6
|
+
import ArCoreProvider from './ArCoreProvider';
|
|
7
|
+
import {
|
|
8
|
+
Quaternion, Vector3
|
|
9
|
+
} from '@wemap/maths';
|
|
10
|
+
import ImuProvider from '../others/ImuProvider';
|
|
11
|
+
import ProviderError from '../../events/ProviderError';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Pose provider is the provider used by the PositioningHandler. It uses the best fusion
|
|
15
|
+
* of what he can and provides an AbsoluteAttitude and an AbsolutePosition as an output.
|
|
16
|
+
*/
|
|
17
|
+
class ArCoreAbsoluteProvider extends Provider {
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @override
|
|
21
|
+
*/
|
|
22
|
+
constructor(onEvent, onError, options) {
|
|
23
|
+
super(onEvent, onError, options);
|
|
24
|
+
|
|
25
|
+
this.arCoreProvider = new ArCoreProvider(
|
|
26
|
+
e => this.onArCoreEvent(e),
|
|
27
|
+
e => this.onArCoreError(e),
|
|
28
|
+
options);
|
|
29
|
+
|
|
30
|
+
this.imuProvider = new ImuProvider(
|
|
31
|
+
this.onImuEvent,
|
|
32
|
+
this.onImuError,
|
|
33
|
+
Object.assign(options || {}, { require: [EventType.AngularRate] })
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @override
|
|
39
|
+
*/
|
|
40
|
+
static get displayName() {
|
|
41
|
+
return 'ArCore absolute provider';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @override
|
|
46
|
+
*/
|
|
47
|
+
static get eventsType() {
|
|
48
|
+
return [EventType.AbsoluteAttitude, EventType.AbsolutePosition];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Return the list of required providers
|
|
53
|
+
*/
|
|
54
|
+
static get requiredProviders() {
|
|
55
|
+
return [ArCoreProvider, ImuProvider];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @override
|
|
60
|
+
*/
|
|
61
|
+
startInternal() {
|
|
62
|
+
this.arCoreProvider.start();
|
|
63
|
+
this.imuProvider.start();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @override
|
|
68
|
+
*/
|
|
69
|
+
stopInternal() {
|
|
70
|
+
this.arCoreProvider.stop();
|
|
71
|
+
this.imuProvider.stop();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* @override
|
|
76
|
+
*/
|
|
77
|
+
static checkAvailabilityErrors() {
|
|
78
|
+
return ArCoreProvider.checkAvailabilityErrors().concat(
|
|
79
|
+
ImuProvider.checkAvailabilityErrors()
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
onArCoreEvent = events => {
|
|
84
|
+
events.forEach(event => {
|
|
85
|
+
if (event.dataType === EventType.RelativeAttitude) {
|
|
86
|
+
|
|
87
|
+
// const previousAttitude = this.relativeAttitude;
|
|
88
|
+
this.relativeAttitude = event.data;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* The two following blocks cannot be called in the same call because this.waitingForceHeading
|
|
92
|
+
* if exists, is called before the first this.relativeAttitude assigment. So, this.waitingForceHeading
|
|
93
|
+
* and previousAttitude should not be defined in the same time.
|
|
94
|
+
*/
|
|
95
|
+
|
|
96
|
+
if (typeof this.waitingForceHeading !== 'undefined') {
|
|
97
|
+
/**
|
|
98
|
+
* waitingForceHeading is set by setHeading() if this.relativeAttitude does not exist
|
|
99
|
+
* At this moment, this.relativeAttitude is defined, so we can call setHeading again
|
|
100
|
+
*/
|
|
101
|
+
this.setHeading(this.waitingForceHeading);
|
|
102
|
+
delete this.waitingForceHeading;
|
|
103
|
+
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// if (previousAttitude && this.absoluteAttitude) {
|
|
107
|
+
// /**
|
|
108
|
+
// * Sometimes ArCore has "orientation jumps" around z-axis.
|
|
109
|
+
// * Here we try to detect and remove them.
|
|
110
|
+
// */
|
|
111
|
+
// const dist = Quaternion.distance(event.data.quaternion, previousAttitude.quaternion);
|
|
112
|
+
// if (typeof this.angularRate !== 'undefined') {
|
|
113
|
+
// const velocity = Vector3.norm(this.angularRate);
|
|
114
|
+
// if (dist > deg2rad(10) && velocity < deg2rad(4)) {
|
|
115
|
+
// this.setHeading(this.absoluteAttitude.heading);
|
|
116
|
+
// }
|
|
117
|
+
// }
|
|
118
|
+
// }
|
|
119
|
+
|
|
120
|
+
if (this.offsetQuat) {
|
|
121
|
+
const absoluteQuaternion = Quaternion.multiply(this.offsetQuat, this.relativeAttitude.quaternion);
|
|
122
|
+
this.absoluteAttitude = new Attitude(absoluteQuaternion);
|
|
123
|
+
this.notify(this.createEvent(EventType.AbsoluteAttitude, this.absoluteAttitude, event.timestamp));
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (event.dataType === EventType.RelativePosition) {
|
|
128
|
+
|
|
129
|
+
if (this.oldRelativePos && this.offsetAngle
|
|
130
|
+
&& !ArCoreAbsoluteProvider.positionEquals(this.oldRelativePos, event.data)) {
|
|
131
|
+
|
|
132
|
+
const diffPos = Vector3.subtract(event.data, this.oldRelativePos);
|
|
133
|
+
const dist = Math.sqrt(diffPos[0] ** 2 + diffPos[2] ** 2);
|
|
134
|
+
const bearing = Math.atan2(diffPos[0], -diffPos[2]) - this.offsetAngle;
|
|
135
|
+
this.position = this.position.destinationPoint(dist, bearing, diffPos[1]);
|
|
136
|
+
this.notify(this.createEvent(EventType.AbsolutePosition, this.position, event.timestamp));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
this.oldRelativePos = event.data;
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
static positionEquals(pos1, pos2) {
|
|
145
|
+
return pos1[0] === pos2[0] && pos1[1] === pos2[1] && pos1[2] === pos2[2];
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
onArCoreError = arCoreErrors => {
|
|
149
|
+
this.notifyError(...(
|
|
150
|
+
ProviderError.modifyArrayDataType(arCoreErrors, EventType.AbsoluteAttitude).concat(
|
|
151
|
+
ProviderError.modifyArrayDataType(arCoreErrors, EventType.AbsolutePosition)
|
|
152
|
+
))
|
|
153
|
+
);
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
onImuEvent = events => {
|
|
157
|
+
this.angularRate = events[0].data;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
onImuError = imuErrors => {
|
|
161
|
+
this.notifyError(...(
|
|
162
|
+
ProviderError.modifyArrayDataType(imuErrors, EventType.AbsoluteAttitude).concat(
|
|
163
|
+
ProviderError.modifyArrayDataType(imuErrors, EventType.AbsolutePosition)
|
|
164
|
+
))
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
setHeading(heading) {
|
|
169
|
+
|
|
170
|
+
if (!this.relativeAttitude) {
|
|
171
|
+
this.waitingForceHeading = heading;
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
this.offsetAngle = this.relativeAttitude.heading - heading;
|
|
176
|
+
this.offsetQuat = Quaternion.fromAxisAngle([0, 0, 1], this.offsetAngle);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
setPosition(position) {
|
|
180
|
+
this.position = position.clone();
|
|
181
|
+
this.position.provider = this.constructor.name;
|
|
182
|
+
this.notify(this.createEvent(EventType.AbsolutePosition, this.position));
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export default ArCoreAbsoluteProvider;
|
|
@@ -3,6 +3,7 @@ import { Attitude } from '@wemap/geo';
|
|
|
3
3
|
import Provider from '../Provider';
|
|
4
4
|
import EventType from '../../events/EventType';
|
|
5
5
|
import MissingArCoreError from '../../errors/MissingArCoreError';
|
|
6
|
+
import MissingNativeInterfaceError from '../../errors/MissingNativeInterfaceError';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Pose provider is the provider used by the PositioningHandler. It uses the best fusion
|
|
@@ -10,14 +11,6 @@ import MissingArCoreError from '../../errors/MissingArCoreError';
|
|
|
10
11
|
*/
|
|
11
12
|
class ArCoreProvider extends Provider {
|
|
12
13
|
|
|
13
|
-
/**
|
|
14
|
-
* @override
|
|
15
|
-
*/
|
|
16
|
-
constructor(onEvent, onError, options) {
|
|
17
|
-
super(onEvent, onError, options);
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
|
|
21
14
|
/**
|
|
22
15
|
* @override
|
|
23
16
|
*/
|
|
@@ -43,12 +36,9 @@ class ArCoreProvider extends Provider {
|
|
|
43
36
|
* @override
|
|
44
37
|
*/
|
|
45
38
|
startInternal() {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
this.notifyError(nativeProvider);
|
|
49
|
-
return;
|
|
39
|
+
if (ArCoreProvider.nativeProvider) {
|
|
40
|
+
ArCoreProvider.nativeProvider.start();
|
|
50
41
|
}
|
|
51
|
-
nativeProvider.start();
|
|
52
42
|
|
|
53
43
|
this.pullDataLoop();
|
|
54
44
|
}
|
|
@@ -57,12 +47,9 @@ class ArCoreProvider extends Provider {
|
|
|
57
47
|
* @override
|
|
58
48
|
*/
|
|
59
49
|
stopInternal() {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
this.notifyError(nativeProvider);
|
|
63
|
-
return;
|
|
50
|
+
if (ArCoreProvider.nativeProvider) {
|
|
51
|
+
ArCoreProvider.nativeProvider.stop();
|
|
64
52
|
}
|
|
65
|
-
nativeProvider.stop();
|
|
66
53
|
}
|
|
67
54
|
|
|
68
55
|
pullDataLoop = () => {
|
|
@@ -71,13 +58,7 @@ class ArCoreProvider extends Provider {
|
|
|
71
58
|
return;
|
|
72
59
|
}
|
|
73
60
|
|
|
74
|
-
const
|
|
75
|
-
if (Array.isArray(nativeProvider)) {
|
|
76
|
-
this.notifyError(...nativeProvider);
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const pose = JSON.parse(nativeProvider.getInfo());
|
|
61
|
+
const pose = JSON.parse(ArCoreProvider.nativeProvider.getInfo());
|
|
81
62
|
if (pose.length !== 0) {
|
|
82
63
|
const attitude = new Attitude(pose.slice(0, 4));
|
|
83
64
|
const position = pose.slice(4, 7);
|
|
@@ -90,17 +71,22 @@ class ArCoreProvider extends Provider {
|
|
|
90
71
|
requestAnimationFrame(this.pullDataLoop);
|
|
91
72
|
}
|
|
92
73
|
|
|
93
|
-
static
|
|
94
|
-
|
|
74
|
+
static get nativeProvider() {
|
|
75
|
+
|
|
76
|
+
if (!this._nativeProvider) {
|
|
77
|
+
|
|
78
|
+
if (!this.nativeInterface) {
|
|
79
|
+
throw new MissingNativeInterfaceError();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
this._nativeProvider = this.nativeInterface.getArCoreProvider();
|
|
83
|
+
if (!this._nativeProvider) {
|
|
84
|
+
throw new MissingArCoreError();
|
|
85
|
+
}
|
|
95
86
|
|
|
96
|
-
if (!nativeInterface) {
|
|
97
|
-
return [
|
|
98
|
-
this.createMissingNativeInterfaceError(EventType.RelativeAttitude),
|
|
99
|
-
this.createMissingNativeInterfaceError(EventType.RelativePosition)
|
|
100
|
-
];
|
|
101
87
|
}
|
|
102
88
|
|
|
103
|
-
return
|
|
89
|
+
return this._nativeProvider;
|
|
104
90
|
}
|
|
105
91
|
|
|
106
92
|
/**
|
|
@@ -108,19 +94,21 @@ class ArCoreProvider extends Provider {
|
|
|
108
94
|
*/
|
|
109
95
|
static checkAvailabilityErrors() {
|
|
110
96
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
97
|
+
try {
|
|
98
|
+
const nativeProvider = this.nativeProvider;
|
|
99
|
+
|
|
100
|
+
if (!nativeProvider.checkAvailability()) {
|
|
101
|
+
throw new MissingArCoreError();
|
|
102
|
+
}
|
|
115
103
|
|
|
116
|
-
|
|
117
|
-
return [
|
|
104
|
+
} catch (e) {
|
|
105
|
+
return [
|
|
106
|
+
this.createError(EventType.RelativeAttitude, e),
|
|
107
|
+
this.createError(EventType.RelativePosition, e)
|
|
108
|
+
];
|
|
118
109
|
}
|
|
119
110
|
|
|
120
|
-
return [
|
|
121
|
-
this.createError(EventType.RelativeAttitude, new MissingArCoreError()),
|
|
122
|
-
this.createError(EventType.RelativePosition, new MissingArCoreError())
|
|
123
|
-
];
|
|
111
|
+
return [];
|
|
124
112
|
}
|
|
125
113
|
}
|
|
126
114
|
|
|
@@ -84,7 +84,7 @@ class GnssWifiPdrProvider extends MapMatchingProvider {
|
|
|
84
84
|
onPdrEvent(pdrEvent) {
|
|
85
85
|
pdrEvent.forEach(event => {
|
|
86
86
|
if (event.dataType === EventType.AbsolutePosition) {
|
|
87
|
-
this.
|
|
87
|
+
this.position = event.data;
|
|
88
88
|
} else if (event.dataType === EventType.AbsoluteAttitude) {
|
|
89
89
|
this.attitude = event.data;
|
|
90
90
|
}
|
|
@@ -98,39 +98,39 @@ class GnssWifiPdrProvider extends MapMatchingProvider {
|
|
|
98
98
|
onGnssWifiEvent(events) {
|
|
99
99
|
|
|
100
100
|
const gnssWifiEvent = events[0];
|
|
101
|
-
const
|
|
101
|
+
const position = gnssWifiEvent.data;
|
|
102
102
|
|
|
103
103
|
// This should be called to update True North / Magnetic North declination
|
|
104
|
-
this.absoluteAttitudeProvider.
|
|
104
|
+
this.absoluteAttitudeProvider.setPosition(position);
|
|
105
105
|
|
|
106
|
-
if (
|
|
106
|
+
if (position.accuracy > GPF_ACCURACY) {
|
|
107
107
|
return;
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
this.
|
|
111
|
-
this.
|
|
110
|
+
this.gnssPosition = position.clone();
|
|
111
|
+
this.gnssPosition.alt = Constants.DEFAULT_ALTITUDE;
|
|
112
112
|
|
|
113
|
-
if (!this.
|
|
114
|
-
&& this.
|
|
113
|
+
if (!this.position || this.position
|
|
114
|
+
&& this.position.distanceTo(this.gnssPosition) > GPF_DISTANCE) {
|
|
115
115
|
|
|
116
116
|
if (!this.mapMatching || !this.attitude) {
|
|
117
|
-
this.pdrProvider.
|
|
117
|
+
this.pdrProvider.setPosition(this.gnssPosition);
|
|
118
118
|
} else {
|
|
119
119
|
|
|
120
|
-
this.
|
|
121
|
-
const projection = this.mapMatching.getProjection(this.
|
|
120
|
+
this.gnssPosition.bearing = this.attitude.headingDegrees;
|
|
121
|
+
const projection = this.mapMatching.getProjection(this.gnssPosition);
|
|
122
122
|
|
|
123
123
|
if (projection && projection.projection) {
|
|
124
124
|
|
|
125
|
-
// Create a new
|
|
126
|
-
const
|
|
127
|
-
this.pdrProvider.
|
|
125
|
+
// Create a new position from projection and new GNSS position.
|
|
126
|
+
const projectedPosition = WGS84UserPosition.fromWGS84(projection.projection, this.gnssPosition);
|
|
127
|
+
this.pdrProvider.setPosition(projectedPosition);
|
|
128
128
|
|
|
129
129
|
// // If nearest element is an edge, use its orientation to set heading
|
|
130
130
|
// if (projection.nearestElement instanceof Edge) {
|
|
131
131
|
// const edgeBearing = projection.nearestElement.bearing;
|
|
132
|
-
// const diff1 = MathUtils.diffAngle(MathUtils.deg2rad(this.
|
|
133
|
-
// const diff2 = MathUtils.diffAngle(MathUtils.deg2rad(this.
|
|
132
|
+
// const diff1 = MathUtils.diffAngle(MathUtils.deg2rad(this.gnssPosition.bearing), edgeBearing);
|
|
133
|
+
// const diff2 = MathUtils.diffAngle(MathUtils.deg2rad(this.gnssPosition.bearing), edgeBearing + Math.PI);
|
|
134
134
|
// this.pdrProvider.setHeading(diff1 < diff2 ? edgeBearing : edgeBearing + Math.PI);
|
|
135
135
|
// }
|
|
136
136
|
|
|
@@ -139,7 +139,7 @@ class GnssWifiPdrProvider extends MapMatchingProvider {
|
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
} else {
|
|
142
|
-
this.pdrProvider.
|
|
142
|
+
this.pdrProvider.setPosition(this.gnssPosition);
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
145
|
}
|
|
@@ -208,9 +208,9 @@ class GnssWifiPdrProvider extends MapMatchingProvider {
|
|
|
208
208
|
|
|
209
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
210
|
|
|
211
|
-
if (!this.
|
|
211
|
+
if (!this.gnssPosition
|
|
212
212
|
|| itinerary.length < 2
|
|
213
|
-
|| !itinerary.points[0].equalsTo(this.
|
|
213
|
+
|| !itinerary.points[0].equalsTo(this.gnssPosition)) {
|
|
214
214
|
console.warn('Itinerary has not been calculated from GnssWifiPdrProvider and these is not recommanded');
|
|
215
215
|
}
|
|
216
216
|
|
|
@@ -222,7 +222,7 @@ class GnssWifiPdrProvider extends MapMatchingProvider {
|
|
|
222
222
|
}
|
|
223
223
|
const startPoint = WGS84UserPosition.fromWGS84(startEdge.node1);
|
|
224
224
|
startPoint.alt = Constants.DEFAULT_ALTITUDE;
|
|
225
|
-
this.pdrProvider.
|
|
225
|
+
this.pdrProvider.setPosition(startPoint);
|
|
226
226
|
this.pdrProvider.setStepDetectionLockerOrientation(startEdge.getBearing());
|
|
227
227
|
}
|
|
228
228
|
|
|
@@ -19,7 +19,7 @@ class PoseProvider extends Provider {
|
|
|
19
19
|
|
|
20
20
|
this.absoluteAttitudeProvider = new AbsoluteAttitudeProvider(onEvent, e => this.onAbsoluteAttitudeError(e));
|
|
21
21
|
this.gnssWifiProvider = new GnssWifiProvider((events) => {
|
|
22
|
-
this.absoluteAttitudeProvider.
|
|
22
|
+
this.absoluteAttitudeProvider.setPosition(events[0].data);
|
|
23
23
|
onEvent(events);
|
|
24
24
|
}, e => this.onGnssWifiError(e));
|
|
25
25
|
}
|
|
@@ -32,10 +32,10 @@ const DEFAULT_OPTIONS = {
|
|
|
32
32
|
|
|
33
33
|
class PdrProvider extends MapMatchingProvider {
|
|
34
34
|
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
// this.
|
|
38
|
-
|
|
35
|
+
// pdrPosition can be different from this.position
|
|
36
|
+
// pdrPosition is raw position calculated by PdrProvider where
|
|
37
|
+
// this.position is smoothed position.
|
|
38
|
+
pdrPosition = null;
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
41
|
* @override
|
|
@@ -127,18 +127,18 @@ class PdrProvider extends MapMatchingProvider {
|
|
|
127
127
|
this.relativeAttitudeProvider.setOffset(heading);
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
-
|
|
131
|
-
this.
|
|
130
|
+
setPosition(position) {
|
|
131
|
+
this.pdrPosition = position;
|
|
132
132
|
|
|
133
133
|
if (this.options.smoother) {
|
|
134
|
-
this.smoother.
|
|
135
|
-
// this.smoother.
|
|
136
|
-
this.
|
|
134
|
+
this.smoother.generateNextPositions(position, true);
|
|
135
|
+
// this.smoother.pullPosition(position.time) should never return null
|
|
136
|
+
this.position = this.smoother.pullPosition(position.time);
|
|
137
137
|
} else {
|
|
138
|
-
this.
|
|
138
|
+
this.position = position.clone();
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
this.notify(this.createEvent(EventType.AbsolutePosition, this.
|
|
141
|
+
this.notify(this.createEvent(EventType.AbsolutePosition, this.position));
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
/**
|
|
@@ -163,8 +163,8 @@ class PdrProvider extends MapMatchingProvider {
|
|
|
163
163
|
return;
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
-
if (!this.
|
|
167
|
-
// We should wait at least an input
|
|
166
|
+
if (!this.pdrPosition) {
|
|
167
|
+
// We should wait at least an input position for PDR
|
|
168
168
|
return;
|
|
169
169
|
}
|
|
170
170
|
|
|
@@ -201,36 +201,36 @@ class PdrProvider extends MapMatchingProvider {
|
|
|
201
201
|
|
|
202
202
|
if (stepDetected) {
|
|
203
203
|
|
|
204
|
-
this.
|
|
204
|
+
this.pdrPosition = this.calculateNewPosition(this.pdrPosition, timestamp,
|
|
205
205
|
heading, this.stepDetection.lastStepSize);
|
|
206
206
|
|
|
207
207
|
/**
|
|
208
208
|
* Update current_position
|
|
209
209
|
*/
|
|
210
210
|
if (this.options.smoother) {
|
|
211
|
-
this.smoother.
|
|
212
|
-
const
|
|
213
|
-
// At this time,
|
|
211
|
+
this.smoother.generateNextPositions(this.pdrPosition);
|
|
212
|
+
const newPosition = this.smoother.pullPosition(timestamp);
|
|
213
|
+
// At this time, newPosition can be null if a new step has been detected
|
|
214
214
|
// and smoother has not been completely consumed.
|
|
215
|
-
if (
|
|
216
|
-
this.
|
|
215
|
+
if (newPosition) {
|
|
216
|
+
this.position = newPosition;
|
|
217
217
|
}
|
|
218
218
|
} else {
|
|
219
|
-
this.
|
|
219
|
+
this.position = this.pdrPosition;
|
|
220
220
|
}
|
|
221
221
|
|
|
222
222
|
} else if (this.options.smoother) {
|
|
223
|
-
// If no step is detected, we pull last known
|
|
224
|
-
const
|
|
225
|
-
if (!
|
|
223
|
+
// If no step is detected, we pull last known position from smoother until now (timestamp).
|
|
224
|
+
const smoothedPosition = this.smoother.pullPosition(timestamp);
|
|
225
|
+
if (!smoothedPosition) {
|
|
226
226
|
return;
|
|
227
227
|
}
|
|
228
|
-
this.
|
|
228
|
+
this.position = smoothedPosition;
|
|
229
229
|
} else {
|
|
230
230
|
return;
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
-
this.notify(this.createEvent(EventType.AbsolutePosition, this.
|
|
233
|
+
this.notify(this.createEvent(EventType.AbsolutePosition, this.position));
|
|
234
234
|
}
|
|
235
235
|
|
|
236
236
|
onProviderError(errors) {
|
|
@@ -254,39 +254,39 @@ class PdrProvider extends MapMatchingProvider {
|
|
|
254
254
|
);
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
-
|
|
257
|
+
calculateNewPosition(previousPosition, timestamp, heading, stepSize) {
|
|
258
258
|
|
|
259
259
|
/**
|
|
260
260
|
* Compute new_position
|
|
261
261
|
*/
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
262
|
+
const newPositionWithoutMM = previousPosition.clone();
|
|
263
|
+
newPositionWithoutMM.move(stepSize, heading);
|
|
264
|
+
newPositionWithoutMM.bearing = rad2deg(heading);
|
|
265
|
+
newPositionWithoutMM.time = timestamp;
|
|
266
266
|
|
|
267
267
|
if (!this.mapMatching) {
|
|
268
|
-
return
|
|
268
|
+
return newPositionWithoutMM;
|
|
269
269
|
}
|
|
270
270
|
|
|
271
|
-
const projection = this.mapMatching.getProjection(
|
|
271
|
+
const projection = this.mapMatching.getProjection(newPositionWithoutMM);
|
|
272
272
|
|
|
273
273
|
if (!projection || !projection.projection) {
|
|
274
|
-
return
|
|
274
|
+
return newPositionWithoutMM;
|
|
275
275
|
}
|
|
276
276
|
|
|
277
277
|
if (projection.distanceFromNearestElement < stepSize) {
|
|
278
|
-
return WGS84UserPosition.fromWGS84(projection.projection,
|
|
278
|
+
return WGS84UserPosition.fromWGS84(projection.projection, newPositionWithoutMM);
|
|
279
279
|
}
|
|
280
280
|
|
|
281
281
|
/**
|
|
282
282
|
* Update new_position
|
|
283
283
|
*/
|
|
284
284
|
const smoothedDistance = projection.distanceFromNearestElement * MM_CONV_SPEED;
|
|
285
|
-
const smoothedBearing =
|
|
286
|
-
const
|
|
287
|
-
|
|
285
|
+
const smoothedBearing = previousPosition.bearingTo(projection.projection);
|
|
286
|
+
const smoothedPosition = previousPosition.clone();
|
|
287
|
+
smoothedPosition.move(smoothedDistance, smoothedBearing);
|
|
288
288
|
|
|
289
|
-
return WGS84UserPosition.fromWGS84(
|
|
289
|
+
return WGS84UserPosition.fromWGS84(smoothedPosition, newPositionWithoutMM);
|
|
290
290
|
}
|
|
291
291
|
|
|
292
292
|
|