@wemap/providers 3.3.0 → 4.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.
- package/debug/src/AbsoluteAttitudeComponent.jsx +8 -7
- package/debug/src/NavigationConfig.js +7 -8
- package/debug/src/RelativeAttitudeComponent.jsx +3 -3
- package/debug/src/Utils.js +32 -41
- package/index.js +6 -8
- package/package.json +8 -9
- package/src/Providers.js +3 -0
- package/src/ProvidersInterface.js +12 -9
- package/src/events/ProviderEvent.js +0 -2
- package/src/mapmatching/MapMatchingHandler.js +150 -0
- package/src/providers/FakeProvider.spec.js +0 -2
- package/src/providers/Provider.js +3 -8
- package/src/providers/attitude/absolute/AbsoluteAttitudeFromBrowserProvider.js +0 -1
- package/src/providers/attitude/absolute/AbsoluteAttitudeFromRelAttProvider.js +3 -3
- package/src/providers/attitude/absolute/AbsoluteAttitudeFusedProvider.js +166 -0
- package/src/providers/attitude/absolute/AbsoluteAttitudeProvider.js +45 -13
- package/src/providers/attitude/relative/RelativeAttitudeFromBrowserProvider.js +2 -4
- package/src/providers/attitude/relative/RelativeAttitudeFromEkfProvider.js +4 -4
- package/src/providers/imu/ImuProvider.js +8 -2
- package/src/providers/inclination/InclinationFromAccProvider.js +1 -2
- package/src/providers/inclination/InclinationFromRelativeAttitudeProvider.js +0 -1
- package/src/providers/position/absolute/AbsolutePositionFromRelProvider.js +2 -3
- package/src/providers/position/absolute/AbsolutePositionProvider.js +32 -138
- package/src/providers/position/absolute/GnssWifiProvider.js +1 -1
- package/src/providers/position/absolute/IpProvider.js +2 -4
- package/src/providers/position/relative/ArCoreProvider.js +1 -1
- package/src/providers/position/relative/GeoRelativePositionFromArCoreProvider.js +0 -1
- package/src/providers/position/relative/PdrProvider.js +1 -2
- package/src/providers/steps/StepDetectionProvider.js +4 -4
- package/src/smoothers/AttitudeSmoother.js +100 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { Attitude, Edge } from '@wemap/geo';
|
|
2
|
+
import {
|
|
3
|
+
Quaternion, diffAngle
|
|
4
|
+
} from '@wemap/maths';
|
|
5
|
+
|
|
6
|
+
import Provider from '../../Provider.js';
|
|
7
|
+
import EventType from '../../../events/EventType.js';
|
|
8
|
+
import { RelativeAttitude } from '../../../Providers.js';
|
|
9
|
+
import ProviderState from '../../ProviderState.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Absolute attitude provider gives the device attitude in East-North-Up (ENU) frame
|
|
13
|
+
*/
|
|
14
|
+
class AbsoluteAttitudeFusedProvider extends Provider {
|
|
15
|
+
|
|
16
|
+
accuracy = 0;
|
|
17
|
+
isInitialized = false;
|
|
18
|
+
|
|
19
|
+
/** @type {number[]} quaternion */
|
|
20
|
+
zOffset = null;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @override
|
|
24
|
+
*/
|
|
25
|
+
static get pname() {
|
|
26
|
+
return 'AbsoluteAttitudeFused';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @override
|
|
31
|
+
*/
|
|
32
|
+
static get eventsType() {
|
|
33
|
+
return [EventType.AbsoluteAttitude];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @override
|
|
38
|
+
*/
|
|
39
|
+
get _availability() {
|
|
40
|
+
// TODO Enhance
|
|
41
|
+
return RelativeAttitude.availability;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @override
|
|
46
|
+
*/
|
|
47
|
+
start() {
|
|
48
|
+
|
|
49
|
+
this.relativeAttitudeProviderId = RelativeAttitude.addEventListener(
|
|
50
|
+
events => this.onRelativeAttitudeEvent(events[0]),
|
|
51
|
+
error => this.notifyError(error)
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
// this.onAbsoluteAttitudeEvent(AbsoluteAttitude.lastEvent);
|
|
56
|
+
// this.absoluteAttitudeProviderId = AbsoluteAttitude.addEventListener(
|
|
57
|
+
// events => this.onAbsoluteAttitudeEvent(events[0]),
|
|
58
|
+
// error => this.notifyError(error),
|
|
59
|
+
// false
|
|
60
|
+
// );
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @override
|
|
65
|
+
*/
|
|
66
|
+
stop() {
|
|
67
|
+
RelativeAttitude.removeEventListener(this.relativeAttitudeProviderId);
|
|
68
|
+
// AbsoluteAttitude.removeEventListener(this.absoluteAttitudeProviderId);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
mapMatching(projection) {
|
|
72
|
+
|
|
73
|
+
if (this.state !== ProviderState.STARTED) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const {
|
|
78
|
+
nearestElement, origin
|
|
79
|
+
} = projection;
|
|
80
|
+
if (!(nearestElement instanceof Edge)) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
let matchingDirection;
|
|
85
|
+
const matchingDirectionAngle1 = diffAngle(nearestElement.bearing, origin.bearing);
|
|
86
|
+
const matchingDirectionAngle2 = diffAngle(nearestElement.bearing + Math.PI, origin.bearing);
|
|
87
|
+
|
|
88
|
+
if (Math.abs(matchingDirectionAngle1) < Math.abs(matchingDirectionAngle2)) {
|
|
89
|
+
matchingDirection = nearestElement.bearing;
|
|
90
|
+
} else {
|
|
91
|
+
matchingDirection = (nearestElement.bearing + Math.PI) % (2 * Math.PI);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
this.accuracy = 0;
|
|
95
|
+
|
|
96
|
+
// preprocess zOffset for "compute" function
|
|
97
|
+
const currentHeading = this.relativeAttitudeEvent ? this.relativeAttitudeEvent.data.heading : 0;
|
|
98
|
+
this.zOffset = Quaternion.fromAxisAngle([0, 0, 1], -matchingDirection + currentHeading);
|
|
99
|
+
|
|
100
|
+
this.compute();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
onRelativeAttitudeEvent(relativeAttitudeEvent) {
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Calculate relative accuracy
|
|
107
|
+
*/
|
|
108
|
+
if (this.relativeAttitudeEvent) {
|
|
109
|
+
const {
|
|
110
|
+
accuracy, time
|
|
111
|
+
} = relativeAttitudeEvent.data;
|
|
112
|
+
const diffTime = time - this.relativeAttitudeEvent.data.time;
|
|
113
|
+
this.accuracy += diffTime * accuracy;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
this.relativeAttitudeEvent = relativeAttitudeEvent;
|
|
117
|
+
this.compute();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
// onAbsoluteAttitudeEvent = absoluteAttitudeEvent => {
|
|
122
|
+
|
|
123
|
+
// if (!absoluteAttitudeEvent) {
|
|
124
|
+
// return;
|
|
125
|
+
// }
|
|
126
|
+
|
|
127
|
+
// /**
|
|
128
|
+
// * Use absolute attitude events only when they are not from this provider
|
|
129
|
+
// */
|
|
130
|
+
// if (absoluteAttitudeEvent.providersStack.includes(this.pname)
|
|
131
|
+
// || absoluteAttitudeEvent.providersStack.includes(AbsoluteAttitudeFromBrowser.pname)) {
|
|
132
|
+
// return;
|
|
133
|
+
// }
|
|
134
|
+
// this.absoluteAttitudeEvent = absoluteAttitudeEvent;
|
|
135
|
+
// this.accuracy = 0;
|
|
136
|
+
|
|
137
|
+
// // preprocess zOffset for "compute" function
|
|
138
|
+
// const currentHeading = this.relativeAttitudeEvent ? this.relativeAttitudeEvent.data.heading : 0;
|
|
139
|
+
// this.zOffset = Quaternion.fromAxisAngle([0, 0, 1], -absoluteAttitudeEvent.data.heading + currentHeading);
|
|
140
|
+
// };
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
compute() {
|
|
144
|
+
if (!this.zOffset || !this.relativeAttitudeEvent) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const {
|
|
149
|
+
quaternion, time
|
|
150
|
+
} = this.relativeAttitudeEvent.data;
|
|
151
|
+
|
|
152
|
+
const absoluteQuat = Quaternion.multiply(this.zOffset, quaternion);
|
|
153
|
+
const newAccuracy = Math.min(this.accuracy, Math.PI);
|
|
154
|
+
const attitude = new Attitude(absoluteQuat, time, newAccuracy, this.pname);
|
|
155
|
+
|
|
156
|
+
this.notify(this.createEvent(
|
|
157
|
+
EventType.AbsoluteAttitude,
|
|
158
|
+
attitude,
|
|
159
|
+
[this.relativeAttitudeEvent]
|
|
160
|
+
));
|
|
161
|
+
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export default AbsoluteAttitudeFusedProvider;
|
|
@@ -6,7 +6,7 @@ import { PromiseUtils } from '@wemap/utils';
|
|
|
6
6
|
import MetaProvider from '../../MetaProvider.js';
|
|
7
7
|
import EventType from '../../../events/EventType.js';
|
|
8
8
|
import {
|
|
9
|
-
AbsoluteAttitudeFromBrowser, AbsoluteAttitudeFromRelAtt
|
|
9
|
+
AbsoluteAttitudeFromBrowser, AbsoluteAttitudeFromRelAtt, AbsoluteAttitudeFused
|
|
10
10
|
} from '../../../Providers.js';
|
|
11
11
|
|
|
12
12
|
|
|
@@ -20,6 +20,7 @@ class AbsoluteAttitudeProvider extends MetaProvider {
|
|
|
20
20
|
|
|
21
21
|
this.attitudeFromBrowserErrored = false;
|
|
22
22
|
this.attitudeFromRelAttErrored = false;
|
|
23
|
+
this.attitudeFusedErrored = false;
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
/**
|
|
@@ -42,7 +43,8 @@ class AbsoluteAttitudeProvider extends MetaProvider {
|
|
|
42
43
|
get _availability() {
|
|
43
44
|
return PromiseUtils.any([
|
|
44
45
|
AbsoluteAttitudeFromBrowser.availability,
|
|
45
|
-
AbsoluteAttitudeFromRelAtt.availability
|
|
46
|
+
AbsoluteAttitudeFromRelAtt.availability,
|
|
47
|
+
AbsoluteAttitudeFused.availability
|
|
46
48
|
]);
|
|
47
49
|
}
|
|
48
50
|
|
|
@@ -66,28 +68,59 @@ class AbsoluteAttitudeProvider extends MetaProvider {
|
|
|
66
68
|
this.onError(error);
|
|
67
69
|
}
|
|
68
70
|
);
|
|
71
|
+
|
|
72
|
+
this.fusedProviderId = AbsoluteAttitudeFused.addEventListener(
|
|
73
|
+
events => this.onAttitudeFused(events[0]),
|
|
74
|
+
error => {
|
|
75
|
+
this.attitudeFusedErrored = true;
|
|
76
|
+
this.onError(error);
|
|
77
|
+
}
|
|
78
|
+
);
|
|
69
79
|
}
|
|
70
80
|
|
|
71
81
|
onError(error) {
|
|
72
|
-
if (this.attitudeFromBrowserErrored
|
|
82
|
+
if (this.attitudeFromBrowserErrored
|
|
83
|
+
&& this.attitudeFromRelAttErrored
|
|
84
|
+
&& this.attitudeFusedErrored) {
|
|
73
85
|
this.notifyError(error);
|
|
74
86
|
}
|
|
75
87
|
}
|
|
76
88
|
|
|
77
89
|
onAttitudeFromBrowser(event) {
|
|
78
90
|
this.eventFromBrowser = event;
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
if (this.eventFromRelAtt && this.eventFromRelAtt.data.accuracy < event.data.accuracy) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (this.eventFromFused && this.eventFromFused.data.accuracy < event.data.accuracy) {
|
|
97
|
+
return;
|
|
82
98
|
}
|
|
99
|
+
this.notify(event.clone());
|
|
83
100
|
}
|
|
84
101
|
|
|
85
102
|
onAttitudeFromRelAtt(event) {
|
|
86
103
|
this.eventFromRelAtt = event;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
104
|
+
|
|
105
|
+
if (this.eventFromBrowser && this.eventFromBrowser.data.accuracy < event.data.accuracy) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (this.eventFromFused && this.eventFromFused.data.accuracy < event.data.accuracy) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
this.notify(event.clone());
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
onAttitudeFused(event) {
|
|
115
|
+
this.eventFromFused = event;
|
|
116
|
+
|
|
117
|
+
if (this.eventFromBrowser && this.eventFromBrowser.data.accuracy < event.data.accuracy) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (this.eventFromRelAtt && this.eventFromRelAtt.data.accuracy < event.data.accuracy) {
|
|
121
|
+
return;
|
|
90
122
|
}
|
|
123
|
+
this.notify(event.clone());
|
|
91
124
|
}
|
|
92
125
|
|
|
93
126
|
/**
|
|
@@ -96,6 +129,7 @@ class AbsoluteAttitudeProvider extends MetaProvider {
|
|
|
96
129
|
stop() {
|
|
97
130
|
AbsoluteAttitudeFromBrowser.removeEventListener(this.fromBrowserProviderId);
|
|
98
131
|
AbsoluteAttitudeFromRelAtt.removeEventListener(this.fromRelAttProviderId);
|
|
132
|
+
AbsoluteAttitudeFused.removeEventListener(this.fusedProviderId);
|
|
99
133
|
}
|
|
100
134
|
|
|
101
135
|
/**
|
|
@@ -115,8 +149,7 @@ class AbsoluteAttitudeProvider extends MetaProvider {
|
|
|
115
149
|
|
|
116
150
|
this.notify(this.createEvent(
|
|
117
151
|
EventType.AbsoluteAttitude,
|
|
118
|
-
data.toAttitude()
|
|
119
|
-
data.time
|
|
152
|
+
data.toAttitude()
|
|
120
153
|
));
|
|
121
154
|
|
|
122
155
|
} else if (data instanceof Attitude) {
|
|
@@ -130,8 +163,7 @@ class AbsoluteAttitudeProvider extends MetaProvider {
|
|
|
130
163
|
|
|
131
164
|
this.notify(this.createEvent(
|
|
132
165
|
EventType.AbsoluteAttitude,
|
|
133
|
-
data
|
|
134
|
-
data.time
|
|
166
|
+
data
|
|
135
167
|
));
|
|
136
168
|
|
|
137
169
|
} else {
|
|
@@ -80,8 +80,6 @@ class RelativeAttitudeFromBrowserProvider extends Provider {
|
|
|
80
80
|
|
|
81
81
|
onDeviceOrientationEvent = e => {
|
|
82
82
|
|
|
83
|
-
const timestamp = e.timeStamp / 1e3;
|
|
84
|
-
|
|
85
83
|
if (typeof e.alpha !== 'number' || typeof e.beta !== 'number' || typeof e.gamma !== 'number') {
|
|
86
84
|
this.notifyError(new MissingSensorError().from('deviceorientation'));
|
|
87
85
|
return;
|
|
@@ -89,11 +87,11 @@ class RelativeAttitudeFromBrowserProvider extends Provider {
|
|
|
89
87
|
|
|
90
88
|
const quaternion = Rotations.eulerToQuaternionZXYDegrees([e.alpha, e.beta, e.gamma]);
|
|
91
89
|
const attitude = new Attitude(quaternion,
|
|
92
|
-
|
|
90
|
+
e.timeStamp / 1e3,
|
|
93
91
|
RelativeAttitudeFromInertialProvider.DEFAULT_DRIFT,
|
|
94
92
|
this.pname
|
|
95
93
|
);
|
|
96
|
-
this.notify(this.createEvent(EventType.RelativeAttitude, attitude
|
|
94
|
+
this.notify(this.createEvent(EventType.RelativeAttitude, attitude));
|
|
97
95
|
};
|
|
98
96
|
}
|
|
99
97
|
|
|
@@ -82,8 +82,9 @@ class RelativeAttitudeFromEkfProvider extends Provider {
|
|
|
82
82
|
return;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
const
|
|
86
|
-
|
|
85
|
+
const {
|
|
86
|
+
values: acceleration, timestamp
|
|
87
|
+
} = accelerationEvent.data;
|
|
87
88
|
|
|
88
89
|
// Handle timestamps and dt
|
|
89
90
|
if (this.lastTimestamp === 0) {
|
|
@@ -93,7 +94,7 @@ class RelativeAttitudeFromEkfProvider extends Provider {
|
|
|
93
94
|
const diffTime = timestamp - this.lastTimestamp;
|
|
94
95
|
this.lastTimestamp = timestamp;
|
|
95
96
|
|
|
96
|
-
const quaternion = this.ekfAttitude.update(diffTime, acceleration, this.gyroscopeEvent.data);
|
|
97
|
+
const quaternion = this.ekfAttitude.update(diffTime, acceleration, this.gyroscopeEvent.data.values);
|
|
97
98
|
|
|
98
99
|
if (quaternion) {
|
|
99
100
|
const attitude = new Attitude(quaternion,
|
|
@@ -104,7 +105,6 @@ class RelativeAttitudeFromEkfProvider extends Provider {
|
|
|
104
105
|
this.notify(this.createEvent(
|
|
105
106
|
EventType.RelativeAttitude,
|
|
106
107
|
attitude,
|
|
107
|
-
timestamp,
|
|
108
108
|
[accelerationEvent, this.gyroscopeEvent]));
|
|
109
109
|
}
|
|
110
110
|
};
|
|
@@ -105,7 +105,10 @@ class ImuProvider extends Provider {
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
if (acc) {
|
|
108
|
-
events.push(this.createEvent(EventType.Acceleration,
|
|
108
|
+
events.push(this.createEvent(EventType.Acceleration, {
|
|
109
|
+
timestamp,
|
|
110
|
+
values: acc
|
|
111
|
+
}));
|
|
109
112
|
}
|
|
110
113
|
|
|
111
114
|
let gyr;
|
|
@@ -120,7 +123,10 @@ class ImuProvider extends Provider {
|
|
|
120
123
|
}
|
|
121
124
|
|
|
122
125
|
if (gyr) {
|
|
123
|
-
events.push(this.createEvent(EventType.AngularRate,
|
|
126
|
+
events.push(this.createEvent(EventType.AngularRate, {
|
|
127
|
+
timestamp,
|
|
128
|
+
values: gyr
|
|
129
|
+
}));
|
|
124
130
|
}
|
|
125
131
|
|
|
126
132
|
if (events.length !== 0) {
|
|
@@ -53,7 +53,7 @@ class InclinationFromAccProvider extends Provider {
|
|
|
53
53
|
* @private
|
|
54
54
|
*/
|
|
55
55
|
onAccelerometerEvent = accelerometerEvent => {
|
|
56
|
-
const acc = accelerometerEvent.data;
|
|
56
|
+
const acc = accelerometerEvent.data.values;
|
|
57
57
|
|
|
58
58
|
const screenOrientation = window.orientation || 0;
|
|
59
59
|
|
|
@@ -78,7 +78,6 @@ class InclinationFromAccProvider extends Provider {
|
|
|
78
78
|
this.notify(this.createEvent(
|
|
79
79
|
EventType.Inclination,
|
|
80
80
|
inclination,
|
|
81
|
-
accelerometerEvent.timestamp,
|
|
82
81
|
[accelerometerEvent]
|
|
83
82
|
));
|
|
84
83
|
};
|
|
@@ -68,7 +68,7 @@ class AbsolutePositionFromRelProvider extends Provider {
|
|
|
68
68
|
/**
|
|
69
69
|
* Use absolute position events only when they are not from this provider
|
|
70
70
|
*/
|
|
71
|
-
if (absolutePositionEvent.
|
|
71
|
+
if (absolutePositionEvent.data === this.position) {
|
|
72
72
|
return;
|
|
73
73
|
}
|
|
74
74
|
|
|
@@ -91,13 +91,12 @@ class AbsolutePositionFromRelProvider extends Provider {
|
|
|
91
91
|
|
|
92
92
|
this.position = this.position.destinationPoint(dist, bearing, alt);
|
|
93
93
|
this.position.bearing = offsetPos.bearing;
|
|
94
|
-
this.position.time =
|
|
94
|
+
this.position.time = offsetPos.time;
|
|
95
95
|
this.position.accuracy += offsetPos.accuracy;
|
|
96
96
|
|
|
97
97
|
this.notify(this.createEvent(
|
|
98
98
|
EventType.AbsolutePosition,
|
|
99
99
|
this.position,
|
|
100
|
-
event.timestamp,
|
|
101
100
|
[event]
|
|
102
101
|
));
|
|
103
102
|
}
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import noop from 'lodash.noop';
|
|
2
2
|
|
|
3
3
|
import { UserPosition } from '@wemap/geo';
|
|
4
|
-
import {
|
|
5
|
-
MapMatching, Network
|
|
6
|
-
} from '@wemap/graph';
|
|
7
|
-
import { deg2rad } from '@wemap/maths';
|
|
8
4
|
import { PromiseUtils } from '@wemap/utils';
|
|
9
5
|
|
|
10
6
|
import MetaProvider from '../../MetaProvider.js';
|
|
@@ -13,27 +9,20 @@ import ProviderEvent from '../../../events/ProviderEvent.js';
|
|
|
13
9
|
import {
|
|
14
10
|
AbsolutePositionFromRel, GnssWifi
|
|
15
11
|
} from '../../../Providers.js';
|
|
16
|
-
import
|
|
12
|
+
import MapMatchingHandler from '../../../mapmatching/MapMatchingHandler.js';
|
|
17
13
|
|
|
18
14
|
// Position accuracy uncertainty ratio
|
|
19
15
|
const ACCURACY_NEW_POS_EPS_RATIO = 1.5;
|
|
20
16
|
const ACCURACY_RELOC_RATIO = 2;
|
|
21
|
-
const MM_MAX_ANGLE = deg2rad(20);
|
|
22
|
-
const MM_MAX_DIST = 30;
|
|
23
|
-
const MM_MIN_DIST = 0;
|
|
24
17
|
const MM_MIN_TIME = 0.4;
|
|
25
18
|
|
|
26
19
|
class AbsolutePositionProvider extends MetaProvider {
|
|
27
20
|
|
|
21
|
+
/** @type {number} */
|
|
28
22
|
lastMMAttempt = -Infinity;
|
|
29
|
-
lastEventBearing = null;
|
|
30
23
|
|
|
31
24
|
constructor() {
|
|
32
25
|
super();
|
|
33
|
-
this.mapMatching = new MapMatching();
|
|
34
|
-
this.mapMatching.maxDistance = MM_MAX_DIST;
|
|
35
|
-
this.mapMatching.maxAngleBearing = MM_MAX_ANGLE;
|
|
36
|
-
this._mapMatchingMinDistance = MM_MIN_DIST;
|
|
37
26
|
}
|
|
38
27
|
|
|
39
28
|
/**
|
|
@@ -77,7 +66,11 @@ class AbsolutePositionProvider extends MetaProvider {
|
|
|
77
66
|
});
|
|
78
67
|
|
|
79
68
|
this.gnssWifiProviderId = GnssWifi.addEventListener(
|
|
80
|
-
events =>
|
|
69
|
+
events => {
|
|
70
|
+
// bearing from GnssWifi is not reliable for our usecase
|
|
71
|
+
events[0].data.bearing = null;
|
|
72
|
+
this.onAbsolutePosition(events[0], false);
|
|
73
|
+
},
|
|
81
74
|
noop
|
|
82
75
|
);
|
|
83
76
|
|
|
@@ -94,46 +87,33 @@ class AbsolutePositionProvider extends MetaProvider {
|
|
|
94
87
|
GnssWifi.removeEventListener(this.gnssWifiProviderId);
|
|
95
88
|
}
|
|
96
89
|
|
|
90
|
+
/**
|
|
91
|
+
* @param {ProviderEvent} newPositionEvent
|
|
92
|
+
* @param {boolean} canContainLevel
|
|
93
|
+
*/
|
|
97
94
|
onAbsolutePosition(newPositionEvent, canContainLevel = true) {
|
|
98
|
-
let newPosition = newPositionEvent.data;
|
|
99
95
|
|
|
100
|
-
if (!this._useNewAbsolutePosition(
|
|
96
|
+
if (!this._useNewAbsolutePosition(newPositionEvent.data)) {
|
|
101
97
|
return;
|
|
102
98
|
}
|
|
103
99
|
|
|
100
|
+
const newPosition = newPositionEvent.data.clone();
|
|
101
|
+
|
|
104
102
|
if (this.lastEvent && !canContainLevel) {
|
|
105
103
|
newPosition.level = this.lastEvent.data.level;
|
|
106
104
|
}
|
|
107
105
|
|
|
108
|
-
|
|
109
|
-
|
|
106
|
+
// If the new position does not have a bearing, retrieve the bearing from the last position
|
|
107
|
+
if (newPosition.bearing === null && this.lastEvent !== null) {
|
|
108
|
+
newPosition.bearing = this.lastEvent.data.bearing;
|
|
110
109
|
}
|
|
111
110
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
let projectedPosition = null;
|
|
115
|
-
|
|
116
|
-
// Firstly, if lastEvent bearing is known, try to use map-matching with bearing
|
|
117
|
-
if (newPosition.bearing !== null) {
|
|
118
|
-
projectedPosition = this._calcMapMatchingPosition(newPosition, true);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Secondly, if map-matching with bearing did not work, try MM on nodes (without bearing).
|
|
122
|
-
if (!projectedPosition) {
|
|
123
|
-
projectedPosition = this._calcMapMatchingPosition(newPosition, false);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (projectedPosition) {
|
|
127
|
-
newPosition = projectedPosition;
|
|
128
|
-
}
|
|
129
|
-
} else {
|
|
130
|
-
newPosition = newPosition.clone();
|
|
131
|
-
}
|
|
111
|
+
const shouldTryMmOnNodes = !newPositionEvent.providersStack.includes(AbsolutePositionFromRel.pname);
|
|
112
|
+
const position = MapMatchingHandler.calcProjection(newPosition, shouldTryMmOnNodes) || newPosition;
|
|
132
113
|
|
|
133
114
|
this.notify(this.createEvent(
|
|
134
115
|
EventType.AbsolutePosition,
|
|
135
|
-
|
|
136
|
-
newPositionEvent.timestamp,
|
|
116
|
+
position,
|
|
137
117
|
[newPositionEvent]
|
|
138
118
|
));
|
|
139
119
|
|
|
@@ -144,29 +124,20 @@ class AbsolutePositionProvider extends MetaProvider {
|
|
|
144
124
|
*/
|
|
145
125
|
onAbsolutePositionFromRel(newPositionEvent) {
|
|
146
126
|
|
|
147
|
-
let
|
|
148
|
-
|
|
149
|
-
this.lastEventBearing = newPosition.bearing;
|
|
150
|
-
|
|
151
|
-
if (this._shouldHandleMapMatching()
|
|
152
|
-
&& newPositionEvent.data.time - this.lastMMAttempt > MM_MIN_TIME) {
|
|
153
|
-
|
|
154
|
-
// Firstly, try map matching with bearing
|
|
155
|
-
const projectedPosition = this._calcMapMatchingPosition(newPosition, true);
|
|
156
|
-
if (projectedPosition) {
|
|
157
|
-
newPosition = projectedPosition;
|
|
158
|
-
}
|
|
159
|
-
// map matching without bearing is not used to allow user to leave the network.
|
|
127
|
+
let position = newPositionEvent.data;
|
|
160
128
|
|
|
129
|
+
if (newPositionEvent.data.time - this.lastMMAttempt > MM_MIN_TIME) {
|
|
130
|
+
position = MapMatchingHandler.calcProjection(position) || position;
|
|
161
131
|
this.lastMMAttempt = newPositionEvent.data.time;
|
|
162
|
-
}
|
|
163
|
-
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (position === newPositionEvent.data) {
|
|
135
|
+
position = position.clone();
|
|
164
136
|
}
|
|
165
137
|
|
|
166
138
|
this.notify(this.createEvent(
|
|
167
139
|
EventType.AbsolutePosition,
|
|
168
|
-
|
|
169
|
-
newPositionEvent.timestamp,
|
|
140
|
+
position,
|
|
170
141
|
[newPositionEvent]
|
|
171
142
|
));
|
|
172
143
|
}
|
|
@@ -191,38 +162,11 @@ class AbsolutePositionProvider extends MetaProvider {
|
|
|
191
162
|
|
|
192
163
|
}
|
|
193
164
|
|
|
194
|
-
_shouldHandleMapMatching() {
|
|
195
|
-
return ProvidersOptions.useMapMatching && this.mapMatching.network;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
_calcMapMatchingPosition(position, useBearing = true) {
|
|
199
|
-
|
|
200
|
-
const projection = this.mapMatching.getProjection(position, true, useBearing);
|
|
201
|
-
if (!projection || !projection.projection) {
|
|
202
|
-
return null;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// Do not use projection if it too close from itinerary,
|
|
206
|
-
// this allows left/right movements (ie with ArCore)
|
|
207
|
-
if (projection.distanceFromNearestElement < this._mapMatchingMinDistance) {
|
|
208
|
-
return null;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// Do not use projection.projection directly, because position has some specific properties like bearing and altitude
|
|
212
|
-
const projectedPosition = position.clone();
|
|
213
|
-
projectedPosition.lat = projection.projection.lat;
|
|
214
|
-
projectedPosition.lng = projection.projection.lng;
|
|
215
|
-
projectedPosition.level = projection.projection.level;
|
|
216
|
-
|
|
217
|
-
return projectedPosition;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
165
|
/**
|
|
221
166
|
* @override
|
|
222
|
-
* @param {UserPosition
|
|
223
|
-
* @param {EventType} eventType
|
|
167
|
+
* @param {UserPosition} data
|
|
224
168
|
*/
|
|
225
|
-
feed(data
|
|
169
|
+
feed(data) {
|
|
226
170
|
if (data instanceof UserPosition) {
|
|
227
171
|
const position = data;
|
|
228
172
|
if (position.time === null) {
|
|
@@ -231,65 +175,15 @@ class AbsolutePositionProvider extends MetaProvider {
|
|
|
231
175
|
if (position.accuracy === null) {
|
|
232
176
|
throw Error('the accuracy of the position is not defined');
|
|
233
177
|
}
|
|
178
|
+
|
|
234
179
|
this.onAbsolutePosition(this.createEvent(
|
|
235
|
-
EventType.AbsolutePosition, position
|
|
180
|
+
EventType.AbsolutePosition, position
|
|
236
181
|
));
|
|
237
|
-
} else if (data instanceof Network || eventType === EventType.Network) {
|
|
238
|
-
this.mapMatching.network = data;
|
|
239
|
-
|
|
240
|
-
if (this._shouldHandleMapMatching() && this.lastEvent) {
|
|
241
|
-
|
|
242
|
-
const position = this.lastEvent.data;
|
|
243
|
-
let projectedPosition = null;
|
|
244
|
-
|
|
245
|
-
// Firstly, if lastEvent bearing is known, try to use map-matching with bearing
|
|
246
|
-
if (position.bearing !== null) {
|
|
247
|
-
projectedPosition = this._calcMapMatchingPosition(position, true);
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// Secondly, if map-matching with bearing did not work, try MM on nodes (without bearing).
|
|
251
|
-
if (!projectedPosition) {
|
|
252
|
-
projectedPosition = this._calcMapMatchingPosition(position, false);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
if (projectedPosition) {
|
|
256
|
-
this.notify(this.createEvent(
|
|
257
|
-
EventType.AbsolutePosition,
|
|
258
|
-
projectedPosition,
|
|
259
|
-
this.lastEvent
|
|
260
|
-
));
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
182
|
} else {
|
|
265
183
|
throw new Error('Unknown feed object');
|
|
266
184
|
}
|
|
267
|
-
|
|
268
185
|
}
|
|
269
186
|
|
|
270
|
-
get mapMatchingMaxDistance() {
|
|
271
|
-
return this.mapMatching.maxDistance;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
set mapMatchingMaxDistance(maxDistance) {
|
|
275
|
-
this.mapMatching.maxDistance = maxDistance;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
get mapMatchingMinDistance() {
|
|
279
|
-
return this._mapMatchingMinDistance;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
set mapMatchingMinDistance(minDistance) {
|
|
283
|
-
this._mapMatchingMinDistance = minDistance;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
get mapMatchingMaxAngleBearing() {
|
|
287
|
-
return this.mapMatching.maxAngleBearing;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
set mapMatchingMaxAngleBearing(maxAngleBearing) {
|
|
291
|
-
this.mapMatching.maxAngleBearing = maxAngleBearing;
|
|
292
|
-
}
|
|
293
187
|
}
|
|
294
188
|
|
|
295
189
|
export default AbsolutePositionProvider;
|