@wemap/providers 6.0.0 → 6.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.
- package/dist/wemap-providers.es.js +1041 -12
- package/dist/wemap-providers.es.js.map +1 -1
- package/package.json +4 -3
- package/src/Providers.js +2 -0
- package/src/ProvidersInterface.js +1 -1
- package/src/ProvidersOptions.js +14 -2
- package/src/mapmatching/MapMatchingHandler.js +1 -1
- package/src/providers/Provider.js +8 -1
- package/src/providers/position/absolute/AbsolutePosition.js +25 -7
- package/src/providers/vision/VisionRelocalization.js +272 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { deg2rad, Vector3, Matrix, Quaternion, Matrix3, Matrix4, Vector, Rotations, std, diffAngleLines, diffAngle, rad2deg } from '@wemap/maths';
|
|
2
2
|
import { BrowserUtils, Browser, PromiseUtils, TimeUtils } from '@wemap/utils';
|
|
3
3
|
import Logger from '@wemap/logger';
|
|
4
|
-
import { Attitude, RelativePosition, Constants as Constants$1, MapMatching, UserPosition, GraphEdge, AbsoluteHeading, GeoRelativePosition as GeoRelativePosition$1
|
|
4
|
+
import { GraphUtils, Level, Coordinates, Network, GraphRouterOptions, Attitude, RelativePosition, Constants as Constants$1, MapMatching, UserPosition, GraphEdge, AbsoluteHeading, GeoRelativePosition as GeoRelativePosition$1 } from '@wemap/geo';
|
|
5
5
|
import geomagnetism from '@wemap/geomagnetism';
|
|
6
|
-
import
|
|
6
|
+
import '@wemap/osm';
|
|
7
|
+
import { SharedCameras, Camera, CameraUtils } from '@wemap/camera';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Event data types handled by {@link ProviderEvent}
|
|
@@ -185,10 +186,18 @@ const ProvidersOptions = {
|
|
|
185
186
|
|
|
186
187
|
/**
|
|
187
188
|
* Providers listed here will not be used by the system
|
|
188
|
-
* List of {@link Provider#
|
|
189
|
+
* List of {@link Provider#pname}
|
|
189
190
|
*/
|
|
190
191
|
ignoreProviders: [],
|
|
191
192
|
|
|
193
|
+
/**
|
|
194
|
+
* Some providers are not used by default (VPS, QRCodeScanner) because they
|
|
195
|
+
* require data from an optional external service or because they drain more
|
|
196
|
+
* battery. They can be added to this list to be used
|
|
197
|
+
* List of {@link Provider#pname}
|
|
198
|
+
*/
|
|
199
|
+
optionalProviders: ['VisionRelocalization'],
|
|
200
|
+
|
|
192
201
|
/**
|
|
193
202
|
* Define the list of EventType that are optionals
|
|
194
203
|
* List of {@link EventType}
|
|
@@ -201,7 +210,11 @@ const ProvidersOptions = {
|
|
|
201
210
|
|
|
202
211
|
stepdetectionlocker: true,
|
|
203
212
|
|
|
204
|
-
smoother: true
|
|
213
|
+
smoother: true,
|
|
214
|
+
|
|
215
|
+
get hasVps() {
|
|
216
|
+
return this.optionalProviders.includes('VisionRelocalization');
|
|
217
|
+
}
|
|
205
218
|
};
|
|
206
219
|
|
|
207
220
|
/**
|
|
@@ -321,9 +334,16 @@ class Provider {
|
|
|
321
334
|
return false;
|
|
322
335
|
}
|
|
323
336
|
|
|
337
|
+
/**
|
|
338
|
+
* Description of the function
|
|
339
|
+
* @name onEventsFunction
|
|
340
|
+
* @function
|
|
341
|
+
* @param {ProviderEvent[]} events the array of provider events
|
|
342
|
+
*/
|
|
343
|
+
|
|
324
344
|
/**
|
|
325
345
|
*
|
|
326
|
-
* @param {
|
|
346
|
+
* @param {onEventsFunction} onEvents
|
|
327
347
|
* @param {Function} onError
|
|
328
348
|
* @param {Boolean} startIfNecessary
|
|
329
349
|
* @returns {Number}
|
|
@@ -883,6 +903,724 @@ class MissingMagnetometerError extends MissingSensorError {
|
|
|
883
903
|
}
|
|
884
904
|
}
|
|
885
905
|
|
|
906
|
+
class LevelChange {
|
|
907
|
+
|
|
908
|
+
/** @type {!string} [up|down] */
|
|
909
|
+
direction;
|
|
910
|
+
|
|
911
|
+
/** @type {!number} [-2, -1, 1, ...] */
|
|
912
|
+
difference;
|
|
913
|
+
|
|
914
|
+
/** @type {?string} [elevator|conveyor|stairs] */
|
|
915
|
+
type = null;
|
|
916
|
+
|
|
917
|
+
/**
|
|
918
|
+
* @param {GraphNode<OsmElement>} firstNode
|
|
919
|
+
* @param {GraphNode<OsmElement>} secondNode
|
|
920
|
+
* @returns {LevelChange}
|
|
921
|
+
*/
|
|
922
|
+
static fromTwoNodes(firstNode, secondNode) {
|
|
923
|
+
|
|
924
|
+
const levelChange = new LevelChange();
|
|
925
|
+
|
|
926
|
+
const edge = GraphUtils.getEdgeByNodes(firstNode.edges, firstNode, secondNode);
|
|
927
|
+
|
|
928
|
+
if (edge.builtFrom.isElevator) {
|
|
929
|
+
levelChange.type = 'elevator';
|
|
930
|
+
} else if (edge.builtFrom.isConveying) {
|
|
931
|
+
levelChange.type = 'conveyor';
|
|
932
|
+
} else if (edge.builtFrom.areStairs) {
|
|
933
|
+
levelChange.type = 'stairs';
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
levelChange.difference = Level.diff(firstNode.coords.level, secondNode.coords.level);
|
|
937
|
+
levelChange.direction = levelChange.difference > 0 ? 'up' : 'down';
|
|
938
|
+
|
|
939
|
+
return levelChange;
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
/**
|
|
943
|
+
* @returns {object}
|
|
944
|
+
*/
|
|
945
|
+
toJson() {
|
|
946
|
+
return {
|
|
947
|
+
direction: this.direction,
|
|
948
|
+
difference: this.difference,
|
|
949
|
+
type: this.type
|
|
950
|
+
};
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
/**
|
|
954
|
+
* @param {object} json
|
|
955
|
+
* @returns {LevelChange}
|
|
956
|
+
*/
|
|
957
|
+
static fromJson(json) {
|
|
958
|
+
const levelChange = new LevelChange();
|
|
959
|
+
levelChange.direction = json.direction;
|
|
960
|
+
levelChange.difference = json.difference;
|
|
961
|
+
levelChange.type = json.type;
|
|
962
|
+
return levelChange;
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
class Step {
|
|
967
|
+
|
|
968
|
+
/** @type {!boolean} */
|
|
969
|
+
firstStep = false;
|
|
970
|
+
|
|
971
|
+
/** @type {!boolean} */
|
|
972
|
+
lastStep = false;
|
|
973
|
+
|
|
974
|
+
/** @type {!number} */
|
|
975
|
+
number;
|
|
976
|
+
|
|
977
|
+
/** @type {!Coordinates} */
|
|
978
|
+
coords = [];
|
|
979
|
+
|
|
980
|
+
|
|
981
|
+
/** @type {!number} */
|
|
982
|
+
angle;
|
|
983
|
+
|
|
984
|
+
/** @type {!number} */
|
|
985
|
+
previousBearing;
|
|
986
|
+
|
|
987
|
+
/** @type {!number} */
|
|
988
|
+
nextBearing;
|
|
989
|
+
|
|
990
|
+
|
|
991
|
+
/** @type {!number} */
|
|
992
|
+
distance;
|
|
993
|
+
|
|
994
|
+
/** @type {?number} */
|
|
995
|
+
duration = null;
|
|
996
|
+
|
|
997
|
+
/** @type {?string} */
|
|
998
|
+
name = null;
|
|
999
|
+
|
|
1000
|
+
|
|
1001
|
+
/** @type {?LevelChange} */
|
|
1002
|
+
levelChange = null;
|
|
1003
|
+
|
|
1004
|
+
/** @type {?{?subwayEntrance: boolean, ?subwayEntranceRef: string}} */
|
|
1005
|
+
extras = {};
|
|
1006
|
+
|
|
1007
|
+
/** @type {!number} */
|
|
1008
|
+
_idCoordsInLeg = null;
|
|
1009
|
+
|
|
1010
|
+
/**
|
|
1011
|
+
* @returns {object}
|
|
1012
|
+
*/
|
|
1013
|
+
toJson() {
|
|
1014
|
+
const output = {
|
|
1015
|
+
number: this.number,
|
|
1016
|
+
coords: this.coords.toCompressedJson(),
|
|
1017
|
+
angle: this.angle,
|
|
1018
|
+
previousBearing: this.previousBearing,
|
|
1019
|
+
nextBearing: this.nextBearing,
|
|
1020
|
+
distance: this.distance,
|
|
1021
|
+
_idCoordsInLeg: this._idCoordsInLeg
|
|
1022
|
+
};
|
|
1023
|
+
if (this.firstStep) {
|
|
1024
|
+
output.firstStep = true;
|
|
1025
|
+
}
|
|
1026
|
+
if (this.lastStep) {
|
|
1027
|
+
output.lastStep = true;
|
|
1028
|
+
}
|
|
1029
|
+
if (this.duration !== null) {
|
|
1030
|
+
output.duration = this.duration;
|
|
1031
|
+
}
|
|
1032
|
+
if (this.name !== null) {
|
|
1033
|
+
output.name = this.name;
|
|
1034
|
+
}
|
|
1035
|
+
if (this.levelChange !== null) {
|
|
1036
|
+
output.levelChange = this.levelChange.toJson();
|
|
1037
|
+
}
|
|
1038
|
+
if (this.extras && Object.keys(this.extras).length !== 0) {
|
|
1039
|
+
output.extras = this.extras;
|
|
1040
|
+
}
|
|
1041
|
+
return output;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
/**
|
|
1045
|
+
* @param {object} json
|
|
1046
|
+
* @returns {Step}
|
|
1047
|
+
*/
|
|
1048
|
+
static fromJson(json) {
|
|
1049
|
+
const step = new Step();
|
|
1050
|
+
step.number = json.number;
|
|
1051
|
+
step.coords = Coordinates.fromCompressedJson(json.coords);
|
|
1052
|
+
step.angle = json.angle;
|
|
1053
|
+
step.previousBearing = json.previousBearing;
|
|
1054
|
+
step.nextBearing = json.nextBearing;
|
|
1055
|
+
step.distance = json.distance;
|
|
1056
|
+
step._idCoordsInLeg = json._idCoordsInLeg;
|
|
1057
|
+
if (json.firstStep) {
|
|
1058
|
+
step.firstStep = json.firstStep;
|
|
1059
|
+
}
|
|
1060
|
+
if (json.lastStep) {
|
|
1061
|
+
step.lastStep = json.lastStep;
|
|
1062
|
+
}
|
|
1063
|
+
if (json.duration) {
|
|
1064
|
+
step.duration = json.duration;
|
|
1065
|
+
}
|
|
1066
|
+
if (json.name) {
|
|
1067
|
+
step.name = json.name;
|
|
1068
|
+
}
|
|
1069
|
+
if (json.levelChange) {
|
|
1070
|
+
step.levelChange = LevelChange.fromJson(json.levelChange);
|
|
1071
|
+
}
|
|
1072
|
+
if (json.extras) {
|
|
1073
|
+
step.extras = json.extras;
|
|
1074
|
+
}
|
|
1075
|
+
return step;
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
class Leg {
|
|
1080
|
+
|
|
1081
|
+
/** @type {!string} can be WALK, BIKE, BUS, TRAM, CAR, FUNICULAR */
|
|
1082
|
+
mode;
|
|
1083
|
+
|
|
1084
|
+
/** @type {!number} */
|
|
1085
|
+
distance;
|
|
1086
|
+
|
|
1087
|
+
/** @type {!number} */
|
|
1088
|
+
duration;
|
|
1089
|
+
|
|
1090
|
+
/** @type {?number} */
|
|
1091
|
+
startTime = null;
|
|
1092
|
+
|
|
1093
|
+
/** @type {?number} */
|
|
1094
|
+
endTime = null;
|
|
1095
|
+
|
|
1096
|
+
/** @type {!{name: ?string, coords: !Coordinates}} */
|
|
1097
|
+
from;
|
|
1098
|
+
|
|
1099
|
+
/** @type {!{name: ?string, coords: !Coordinates}} */
|
|
1100
|
+
to;
|
|
1101
|
+
|
|
1102
|
+
/** @type {!Coordinates[]} */
|
|
1103
|
+
coords;
|
|
1104
|
+
|
|
1105
|
+
/** @type {?{name: !string, routeColor: ?string, routeTextColor: ?string, directionName: ?string}} */
|
|
1106
|
+
transportInfo = null;
|
|
1107
|
+
|
|
1108
|
+
/** @type {?(Step[])} */
|
|
1109
|
+
steps = null;
|
|
1110
|
+
|
|
1111
|
+
/**
|
|
1112
|
+
* @returns {Network}
|
|
1113
|
+
*/
|
|
1114
|
+
toNetwork() {
|
|
1115
|
+
return Network.fromCoordinates([this.coords]);
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
/**
|
|
1119
|
+
* @returns {object}
|
|
1120
|
+
*/
|
|
1121
|
+
toJson() {
|
|
1122
|
+
const output = {
|
|
1123
|
+
mode: this.mode,
|
|
1124
|
+
from: { coords: this.from.coords.toCompressedJson() },
|
|
1125
|
+
to: { coords: this.to.coords.toCompressedJson() },
|
|
1126
|
+
distance: this.distance,
|
|
1127
|
+
duration: this.duration,
|
|
1128
|
+
coords: this.coords.map(coords => coords.toCompressedJson())
|
|
1129
|
+
};
|
|
1130
|
+
if (this.from.name) {
|
|
1131
|
+
output.from.name = this.from.name;
|
|
1132
|
+
}
|
|
1133
|
+
if (this.to.name) {
|
|
1134
|
+
output.to.name = this.to.name;
|
|
1135
|
+
}
|
|
1136
|
+
if (this.startTime !== null) {
|
|
1137
|
+
output.startTime = this.startTime;
|
|
1138
|
+
}
|
|
1139
|
+
if (this.endTime !== null) {
|
|
1140
|
+
output.endTime = this.endTime;
|
|
1141
|
+
}
|
|
1142
|
+
if (this.transportInfo !== null) {
|
|
1143
|
+
output.transportInfo = this.transportInfo;
|
|
1144
|
+
}
|
|
1145
|
+
if (this.steps !== null && this.steps.length > 0) {
|
|
1146
|
+
output.steps = this.steps.map(step => step.toJson());
|
|
1147
|
+
}
|
|
1148
|
+
return output;
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
|
|
1152
|
+
/**
|
|
1153
|
+
* @param {object} json
|
|
1154
|
+
* @returns {Leg}
|
|
1155
|
+
*/
|
|
1156
|
+
static fromJson(json) {
|
|
1157
|
+
const leg = new Leg();
|
|
1158
|
+
leg.mode = json.mode;
|
|
1159
|
+
leg.from = { coords: Coordinates.fromCompressedJson(json.from.coords) };
|
|
1160
|
+
leg.to = { coords: Coordinates.fromCompressedJson(json.to.coords) };
|
|
1161
|
+
leg.distance = json.distance;
|
|
1162
|
+
leg.duration = json.duration;
|
|
1163
|
+
leg.coords = json.coords.map(Coordinates.fromCompressedJson);
|
|
1164
|
+
if (json.from.name) {
|
|
1165
|
+
leg.from.name = json.from.name;
|
|
1166
|
+
}
|
|
1167
|
+
if (json.to.name) {
|
|
1168
|
+
leg.to.name = json.to.name;
|
|
1169
|
+
}
|
|
1170
|
+
if (json.startTime) {
|
|
1171
|
+
leg.startTime = json.startTime;
|
|
1172
|
+
}
|
|
1173
|
+
if (json.endTime) {
|
|
1174
|
+
leg.endTime = json.endTime;
|
|
1175
|
+
}
|
|
1176
|
+
if (json.transportInfo) {
|
|
1177
|
+
leg.transportInfo = json.transportInfo;
|
|
1178
|
+
}
|
|
1179
|
+
if (json.steps) {
|
|
1180
|
+
leg.steps = json.steps.map(Step.fromJson);
|
|
1181
|
+
}
|
|
1182
|
+
return leg;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
/**
|
|
1188
|
+
* Get route duration
|
|
1189
|
+
* @param {Number} speed in km/h
|
|
1190
|
+
* @returns {Number} duration in seconds
|
|
1191
|
+
*/
|
|
1192
|
+
function getDurationFromLength(length, speed = 5) {
|
|
1193
|
+
return length / (speed * 1000 / 3600);
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
/* eslint-disable max-statements */
|
|
1197
|
+
|
|
1198
|
+
/**
|
|
1199
|
+
* Main attributes are:
|
|
1200
|
+
* nodes: the ordered list of Node
|
|
1201
|
+
* edges: the ordered list of Edge
|
|
1202
|
+
* start: the start point (Coordinates)
|
|
1203
|
+
* end: the end point (Coordinates)
|
|
1204
|
+
* length: the route length
|
|
1205
|
+
*/
|
|
1206
|
+
class Itinerary {
|
|
1207
|
+
|
|
1208
|
+
/** @type {!Coordinates} */
|
|
1209
|
+
from;
|
|
1210
|
+
|
|
1211
|
+
/** @type {!Coordinates} */
|
|
1212
|
+
to;
|
|
1213
|
+
|
|
1214
|
+
/** @type {!number} */
|
|
1215
|
+
distance;
|
|
1216
|
+
|
|
1217
|
+
/** @type {!number} */
|
|
1218
|
+
duration;
|
|
1219
|
+
|
|
1220
|
+
/** @type {!string} can be WALK, BIKE, CAR, PT */
|
|
1221
|
+
_mode;
|
|
1222
|
+
|
|
1223
|
+
/** @type {?number} */
|
|
1224
|
+
startTime = null;
|
|
1225
|
+
|
|
1226
|
+
/** @type {?number} */
|
|
1227
|
+
endTime = null;
|
|
1228
|
+
|
|
1229
|
+
/** @type {!(Leg[])} */
|
|
1230
|
+
legs = [];
|
|
1231
|
+
|
|
1232
|
+
/** @type {?Coordinates[]} */
|
|
1233
|
+
_coords = null;
|
|
1234
|
+
|
|
1235
|
+
set coords(_) {
|
|
1236
|
+
throw new Error('Itinerary.coords cannot be set. They are calculated from Itinerary.legs.');
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
/** @type {!(Coordinates[])} */
|
|
1240
|
+
get coords() {
|
|
1241
|
+
if (!this._coords) {
|
|
1242
|
+
// Returns the coordinates contained in all legs and remove duplicates between array
|
|
1243
|
+
this._coords = this.legs.reduce((acc, val) => {
|
|
1244
|
+
const isDuplicate = acc.length && val.coords.length && acc[acc.length - 1].equalsTo(val.coords[0]);
|
|
1245
|
+
acc.push(...val.coords.slice(isDuplicate ? 1 : 0));
|
|
1246
|
+
return acc;
|
|
1247
|
+
}, []);
|
|
1248
|
+
}
|
|
1249
|
+
return this._coords;
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
set steps(_) {
|
|
1253
|
+
throw new Error('Itinerary.step cannot be set. They are calculated from Itinerary.legs.');
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
/** @type {!(Step[])} */
|
|
1257
|
+
get steps() {
|
|
1258
|
+
return this.legs.map(leg => leg.steps).flat();
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
set mode(_) {
|
|
1262
|
+
throw new Error('Itinerary.mode cannot be set. They are calculated from Itinerary.legs.');
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
get mode() {
|
|
1266
|
+
if (!this._mode) {
|
|
1267
|
+
let isPublicTransport;
|
|
1268
|
+
let isBicycle;
|
|
1269
|
+
let isDriving;
|
|
1270
|
+
|
|
1271
|
+
this.legs.forEach((leg) => {
|
|
1272
|
+
isPublicTransport = isPublicTransport || ['BUS', 'FUNICULAR', 'TRAM', 'TRAIN'].includes(leg.mode);
|
|
1273
|
+
isBicycle = isBicycle || ['BIKE', 'BICYCLE'].includes(leg.mode);
|
|
1274
|
+
isDriving = isDriving || leg.mode === 'CAR';
|
|
1275
|
+
});
|
|
1276
|
+
|
|
1277
|
+
if (isPublicTransport) {
|
|
1278
|
+
this._mode = 'PT';
|
|
1279
|
+
} else if (isDriving) {
|
|
1280
|
+
this._mode = 'CAR';
|
|
1281
|
+
} else if (isBicycle) {
|
|
1282
|
+
this._mode = 'BIKE';
|
|
1283
|
+
} else {
|
|
1284
|
+
this._mode = 'WALK';
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
return this._mode;
|
|
1289
|
+
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
/**
|
|
1293
|
+
* @returns {Network}
|
|
1294
|
+
*/
|
|
1295
|
+
toNetwork() {
|
|
1296
|
+
return Network.fromCoordinates([this.coords]);
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
/**
|
|
1300
|
+
* @param {Itinerary[]} itineraries
|
|
1301
|
+
* @returns {Itinerary}
|
|
1302
|
+
*/
|
|
1303
|
+
static fromItineraries(...itineraries) {
|
|
1304
|
+
const itinerary = new Itinerary();
|
|
1305
|
+
itinerary.from = itineraries[0].from;
|
|
1306
|
+
itinerary.to = itineraries[itineraries.length - 1].to;
|
|
1307
|
+
itinerary.distance = 0;
|
|
1308
|
+
itinerary.duration = 0;
|
|
1309
|
+
itinerary.legs = [];
|
|
1310
|
+
|
|
1311
|
+
itineraries.forEach(_itinerary => {
|
|
1312
|
+
itinerary.distance += _itinerary.distance;
|
|
1313
|
+
itinerary.duration += _itinerary.duration;
|
|
1314
|
+
itinerary.legs.push(..._itinerary.legs);
|
|
1315
|
+
itinerary.legs.forEach(leg => {
|
|
1316
|
+
leg.steps[0].firstStep = false;
|
|
1317
|
+
leg.steps[leg.steps.length - 1].lastStep = false;
|
|
1318
|
+
});
|
|
1319
|
+
});
|
|
1320
|
+
|
|
1321
|
+
itinerary.legs[0].steps[0].firstStep = true;
|
|
1322
|
+
const lastLeg = itinerary.legs[itinerary.legs.length - 1];
|
|
1323
|
+
lastLeg.steps[lastLeg.steps.length - 1].lastStep = true;
|
|
1324
|
+
|
|
1325
|
+
return itinerary;
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
/**
|
|
1329
|
+
* Convert lat/lng/level points to Itinerary
|
|
1330
|
+
* @param {number[][]} points 2D points array of lat/lng/level (level is optional)
|
|
1331
|
+
* @param {Coordinates} from
|
|
1332
|
+
* @param {Coordinates} to
|
|
1333
|
+
* @param {string} mode
|
|
1334
|
+
* @returns {Itinerary}
|
|
1335
|
+
*/
|
|
1336
|
+
static fromOrderedPointsArray(points, start, end) {
|
|
1337
|
+
|
|
1338
|
+
const pointToCoordinates = point => new Coordinates(point[0], point[1], null, point[2]);
|
|
1339
|
+
|
|
1340
|
+
return this.fromOrderedCoordinates(
|
|
1341
|
+
points.map(pointToCoordinates),
|
|
1342
|
+
pointToCoordinates(start),
|
|
1343
|
+
pointToCoordinates(end)
|
|
1344
|
+
);
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
/**
|
|
1348
|
+
* Convert ordered Coordinates to Itinerary
|
|
1349
|
+
* @param {Coordinates[]} points
|
|
1350
|
+
* @param {Coordinates} from
|
|
1351
|
+
* @param {Coordinates} to
|
|
1352
|
+
* @param {string} mode
|
|
1353
|
+
* @returns {Itinerary}
|
|
1354
|
+
*/
|
|
1355
|
+
static fromOrderedCoordinates(points, from, to, mode = 'WALK') {
|
|
1356
|
+
|
|
1357
|
+
const itinerary = new Itinerary();
|
|
1358
|
+
itinerary.from = from;
|
|
1359
|
+
itinerary.to = to;
|
|
1360
|
+
|
|
1361
|
+
const leg = new Leg();
|
|
1362
|
+
leg.mode = mode;
|
|
1363
|
+
leg.from = { name: null, coords: from };
|
|
1364
|
+
leg.to = { name: null, coords: to };
|
|
1365
|
+
|
|
1366
|
+
leg.coords = points;
|
|
1367
|
+
leg.distance = points.reduce((acc, coords, idx, arr) => {
|
|
1368
|
+
if (idx !== 0) {
|
|
1369
|
+
return acc + arr[idx - 1].distanceTo(coords);
|
|
1370
|
+
}
|
|
1371
|
+
return acc;
|
|
1372
|
+
}, 0);
|
|
1373
|
+
leg.duration = getDurationFromLength(leg.distance);
|
|
1374
|
+
itinerary.legs.push(leg);
|
|
1375
|
+
|
|
1376
|
+
itinerary.distance = leg.distance;
|
|
1377
|
+
itinerary.duration = leg.duration;
|
|
1378
|
+
|
|
1379
|
+
return itinerary;
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
/**
|
|
1383
|
+
* @returns {object}
|
|
1384
|
+
*/
|
|
1385
|
+
toJson() {
|
|
1386
|
+
const output = {
|
|
1387
|
+
from: this.from.toCompressedJson(),
|
|
1388
|
+
to: this.to.toCompressedJson(),
|
|
1389
|
+
distance: this.distance,
|
|
1390
|
+
duration: this.duration,
|
|
1391
|
+
mode: this.mode,
|
|
1392
|
+
legs: this.legs.map(leg => leg.toJson())
|
|
1393
|
+
};
|
|
1394
|
+
if (this.startTime !== null) {
|
|
1395
|
+
output.startTime = this.startTime;
|
|
1396
|
+
}
|
|
1397
|
+
if (this.endTime !== null) {
|
|
1398
|
+
output.endTime = this.endTime;
|
|
1399
|
+
}
|
|
1400
|
+
return output;
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
/**
|
|
1404
|
+
* @param {object} json
|
|
1405
|
+
* @returns {Itinerary}
|
|
1406
|
+
*/
|
|
1407
|
+
static fromJson(json) {
|
|
1408
|
+
const itinerary = new Itinerary();
|
|
1409
|
+
itinerary.from = Coordinates.fromCompressedJson(json.from);
|
|
1410
|
+
itinerary.to = Coordinates.fromCompressedJson(json.to);
|
|
1411
|
+
itinerary.distance = json.distance;
|
|
1412
|
+
itinerary.duration = json.duration;
|
|
1413
|
+
itinerary.legs = json.legs.map(Leg.fromJson);
|
|
1414
|
+
if (json.startTime) {
|
|
1415
|
+
itinerary.startTime = json.startTime;
|
|
1416
|
+
}
|
|
1417
|
+
if (json.endTime) {
|
|
1418
|
+
itinerary.endTime = json.endTime;
|
|
1419
|
+
}
|
|
1420
|
+
return itinerary;
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
class WemapRouterOptions extends GraphRouterOptions {
|
|
1425
|
+
|
|
1426
|
+
/** @type {WemapRouterOptions} */
|
|
1427
|
+
static DEFAULT = new WemapRouterOptions();
|
|
1428
|
+
|
|
1429
|
+
/**
|
|
1430
|
+
* @returns {WemapRouterOptions}
|
|
1431
|
+
*/
|
|
1432
|
+
static get WITHOUT_STAIRS() {
|
|
1433
|
+
const options = new WemapRouterOptions();
|
|
1434
|
+
options.acceptEdgeFn = edge => edge.builtFrom.tags.highway !== 'steps';
|
|
1435
|
+
return options;
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
/**
|
|
1439
|
+
* Get route duration
|
|
1440
|
+
* @param {Number} speed in km/h
|
|
1441
|
+
*/
|
|
1442
|
+
static getDurationFromLength(length, speed = 5) {
|
|
1443
|
+
return length / (speed * 1000 / 3600);
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
/** @type {function(GraphEdge<OsmElement>):boolean} */
|
|
1447
|
+
weightEdgeFn = edge => edge.builtFrom.isElevator ? 30 : WemapRouterOptions.getDurationFromLength(edge.length);
|
|
1448
|
+
|
|
1449
|
+
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
/* eslint-disable complexity */
|
|
1453
|
+
|
|
1454
|
+
deg2rad(20);
|
|
1455
|
+
|
|
1456
|
+
function createCommonjsModule(fn) {
|
|
1457
|
+
var module = { exports: {} };
|
|
1458
|
+
return fn(module, module.exports), module.exports;
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
createCommonjsModule(function (module) {
|
|
1462
|
+
|
|
1463
|
+
/**
|
|
1464
|
+
* Based off of [the offical Google document](https://developers.google.com/maps/documentation/utilities/polylinealgorithm)
|
|
1465
|
+
*
|
|
1466
|
+
* Some parts from [this implementation](http://facstaff.unca.edu/mcmcclur/GoogleMaps/EncodePolyline/PolylineEncoder.js)
|
|
1467
|
+
* by [Mark McClure](http://facstaff.unca.edu/mcmcclur/)
|
|
1468
|
+
*
|
|
1469
|
+
* @module polyline
|
|
1470
|
+
*/
|
|
1471
|
+
|
|
1472
|
+
var polyline = {};
|
|
1473
|
+
|
|
1474
|
+
function py2_round(value) {
|
|
1475
|
+
// Google's polyline algorithm uses the same rounding strategy as Python 2, which is different from JS for negative values
|
|
1476
|
+
return Math.floor(Math.abs(value) + 0.5) * (value >= 0 ? 1 : -1);
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
function encode(current, previous, factor) {
|
|
1480
|
+
current = py2_round(current * factor);
|
|
1481
|
+
previous = py2_round(previous * factor);
|
|
1482
|
+
var coordinate = current - previous;
|
|
1483
|
+
coordinate <<= 1;
|
|
1484
|
+
if (current - previous < 0) {
|
|
1485
|
+
coordinate = ~coordinate;
|
|
1486
|
+
}
|
|
1487
|
+
var output = '';
|
|
1488
|
+
while (coordinate >= 0x20) {
|
|
1489
|
+
output += String.fromCharCode((0x20 | (coordinate & 0x1f)) + 63);
|
|
1490
|
+
coordinate >>= 5;
|
|
1491
|
+
}
|
|
1492
|
+
output += String.fromCharCode(coordinate + 63);
|
|
1493
|
+
return output;
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
/**
|
|
1497
|
+
* Decodes to a [latitude, longitude] coordinates array.
|
|
1498
|
+
*
|
|
1499
|
+
* This is adapted from the implementation in Project-OSRM.
|
|
1500
|
+
*
|
|
1501
|
+
* @param {String} str
|
|
1502
|
+
* @param {Number} precision
|
|
1503
|
+
* @returns {Array}
|
|
1504
|
+
*
|
|
1505
|
+
* @see https://github.com/Project-OSRM/osrm-frontend/blob/master/WebContent/routing/OSRM.RoutingGeometry.js
|
|
1506
|
+
*/
|
|
1507
|
+
polyline.decode = function(str, precision) {
|
|
1508
|
+
var index = 0,
|
|
1509
|
+
lat = 0,
|
|
1510
|
+
lng = 0,
|
|
1511
|
+
coordinates = [],
|
|
1512
|
+
shift = 0,
|
|
1513
|
+
result = 0,
|
|
1514
|
+
byte = null,
|
|
1515
|
+
latitude_change,
|
|
1516
|
+
longitude_change,
|
|
1517
|
+
factor = Math.pow(10, Number.isInteger(precision) ? precision : 5);
|
|
1518
|
+
|
|
1519
|
+
// Coordinates have variable length when encoded, so just keep
|
|
1520
|
+
// track of whether we've hit the end of the string. In each
|
|
1521
|
+
// loop iteration, a single coordinate is decoded.
|
|
1522
|
+
while (index < str.length) {
|
|
1523
|
+
|
|
1524
|
+
// Reset shift, result, and byte
|
|
1525
|
+
byte = null;
|
|
1526
|
+
shift = 0;
|
|
1527
|
+
result = 0;
|
|
1528
|
+
|
|
1529
|
+
do {
|
|
1530
|
+
byte = str.charCodeAt(index++) - 63;
|
|
1531
|
+
result |= (byte & 0x1f) << shift;
|
|
1532
|
+
shift += 5;
|
|
1533
|
+
} while (byte >= 0x20);
|
|
1534
|
+
|
|
1535
|
+
latitude_change = ((result & 1) ? ~(result >> 1) : (result >> 1));
|
|
1536
|
+
|
|
1537
|
+
shift = result = 0;
|
|
1538
|
+
|
|
1539
|
+
do {
|
|
1540
|
+
byte = str.charCodeAt(index++) - 63;
|
|
1541
|
+
result |= (byte & 0x1f) << shift;
|
|
1542
|
+
shift += 5;
|
|
1543
|
+
} while (byte >= 0x20);
|
|
1544
|
+
|
|
1545
|
+
longitude_change = ((result & 1) ? ~(result >> 1) : (result >> 1));
|
|
1546
|
+
|
|
1547
|
+
lat += latitude_change;
|
|
1548
|
+
lng += longitude_change;
|
|
1549
|
+
|
|
1550
|
+
coordinates.push([lat / factor, lng / factor]);
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
return coordinates;
|
|
1554
|
+
};
|
|
1555
|
+
|
|
1556
|
+
/**
|
|
1557
|
+
* Encodes the given [latitude, longitude] coordinates array.
|
|
1558
|
+
*
|
|
1559
|
+
* @param {Array.<Array.<Number>>} coordinates
|
|
1560
|
+
* @param {Number} precision
|
|
1561
|
+
* @returns {String}
|
|
1562
|
+
*/
|
|
1563
|
+
polyline.encode = function(coordinates, precision) {
|
|
1564
|
+
if (!coordinates.length) { return ''; }
|
|
1565
|
+
|
|
1566
|
+
var factor = Math.pow(10, Number.isInteger(precision) ? precision : 5),
|
|
1567
|
+
output = encode(coordinates[0][0], 0, factor) + encode(coordinates[0][1], 0, factor);
|
|
1568
|
+
|
|
1569
|
+
for (var i = 1; i < coordinates.length; i++) {
|
|
1570
|
+
var a = coordinates[i], b = coordinates[i - 1];
|
|
1571
|
+
output += encode(a[0], b[0], factor);
|
|
1572
|
+
output += encode(a[1], b[1], factor);
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
return output;
|
|
1576
|
+
};
|
|
1577
|
+
|
|
1578
|
+
function flipped(coords) {
|
|
1579
|
+
var flipped = [];
|
|
1580
|
+
for (var i = 0; i < coords.length; i++) {
|
|
1581
|
+
var coord = coords[i].slice();
|
|
1582
|
+
flipped.push([coord[1], coord[0]]);
|
|
1583
|
+
}
|
|
1584
|
+
return flipped;
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
/**
|
|
1588
|
+
* Encodes a GeoJSON LineString feature/geometry.
|
|
1589
|
+
*
|
|
1590
|
+
* @param {Object} geojson
|
|
1591
|
+
* @param {Number} precision
|
|
1592
|
+
* @returns {String}
|
|
1593
|
+
*/
|
|
1594
|
+
polyline.fromGeoJSON = function(geojson, precision) {
|
|
1595
|
+
if (geojson && geojson.type === 'Feature') {
|
|
1596
|
+
geojson = geojson.geometry;
|
|
1597
|
+
}
|
|
1598
|
+
if (!geojson || geojson.type !== 'LineString') {
|
|
1599
|
+
throw new Error('Input must be a GeoJSON LineString');
|
|
1600
|
+
}
|
|
1601
|
+
return polyline.encode(flipped(geojson.coordinates), precision);
|
|
1602
|
+
};
|
|
1603
|
+
|
|
1604
|
+
/**
|
|
1605
|
+
* Decodes to a GeoJSON LineString geometry.
|
|
1606
|
+
*
|
|
1607
|
+
* @param {String} str
|
|
1608
|
+
* @param {Number} precision
|
|
1609
|
+
* @returns {Object}
|
|
1610
|
+
*/
|
|
1611
|
+
polyline.toGeoJSON = function(str, precision) {
|
|
1612
|
+
var coords = polyline.decode(str, precision);
|
|
1613
|
+
return {
|
|
1614
|
+
type: 'LineString',
|
|
1615
|
+
coordinates: flipped(coords)
|
|
1616
|
+
};
|
|
1617
|
+
};
|
|
1618
|
+
|
|
1619
|
+
if (module.exports) {
|
|
1620
|
+
module.exports = polyline;
|
|
1621
|
+
}
|
|
1622
|
+
});
|
|
1623
|
+
|
|
886
1624
|
const DEFAULT_RELATIVE_NOISES = {
|
|
887
1625
|
acc: 0.5,
|
|
888
1626
|
gyr: 0.3
|
|
@@ -2933,6 +3671,277 @@ class GeoRelativePosition extends Provider {
|
|
|
2933
3671
|
|
|
2934
3672
|
var GeoRelativePositionProvider = new GeoRelativePosition();
|
|
2935
3673
|
|
|
3674
|
+
function preciseTime() {
|
|
3675
|
+
if (typeof window !== 'undefined' && window.performance) {
|
|
3676
|
+
return window.performance.now();
|
|
3677
|
+
}
|
|
3678
|
+
const hrtime = process.hrtime();
|
|
3679
|
+
return Math.round((hrtime[0] * 1e3) + (hrtime[1] / 1e6));
|
|
3680
|
+
}
|
|
3681
|
+
|
|
3682
|
+
/* eslint-disable max-statements */
|
|
3683
|
+
|
|
3684
|
+
class VisionRelocalization extends Provider {
|
|
3685
|
+
|
|
3686
|
+
// static SERVICE_URL = 'http://localhost:45678/';
|
|
3687
|
+
static SERVICE_URL = 'https://vps.maaap.it/';
|
|
3688
|
+
static MAP_ID = 'wemap';
|
|
3689
|
+
static MIN_TIME_BETWEEN_TWO_REQUESTS = 1000;
|
|
3690
|
+
|
|
3691
|
+
/** @type {boolean} */
|
|
3692
|
+
_serverError = false;
|
|
3693
|
+
|
|
3694
|
+
/** @type {boolean} */
|
|
3695
|
+
_cameraError = false;
|
|
3696
|
+
|
|
3697
|
+
/** @type {Camera} */
|
|
3698
|
+
_camera = null;
|
|
3699
|
+
|
|
3700
|
+
/**
|
|
3701
|
+
* @override
|
|
3702
|
+
*/
|
|
3703
|
+
static get pname() {
|
|
3704
|
+
return 'VisionRelocalization';
|
|
3705
|
+
}
|
|
3706
|
+
|
|
3707
|
+
/**
|
|
3708
|
+
* @override
|
|
3709
|
+
*/
|
|
3710
|
+
static get eventsType() {
|
|
3711
|
+
return [EventType.AbsoluteAttitude, EventType.AbsolutePosition];
|
|
3712
|
+
}
|
|
3713
|
+
|
|
3714
|
+
/**
|
|
3715
|
+
* @override
|
|
3716
|
+
*/
|
|
3717
|
+
get _availability() {
|
|
3718
|
+
return Promise.resolve();
|
|
3719
|
+
}
|
|
3720
|
+
|
|
3721
|
+
/**
|
|
3722
|
+
* @override
|
|
3723
|
+
*/
|
|
3724
|
+
start() {
|
|
3725
|
+
|
|
3726
|
+
// 1. Add listeners on shared cameras to detect new cameras
|
|
3727
|
+
SharedCameras.on('added', this._onCameraDetected);
|
|
3728
|
+
SharedCameras.on('removed', this._onCameraRemoved);
|
|
3729
|
+
|
|
3730
|
+
// 2. If a camera already exists, use it
|
|
3731
|
+
if (SharedCameras.list.length) {
|
|
3732
|
+
if (SharedCameras.list.length > 1) {
|
|
3733
|
+
Logger.warn('It seems that more than 1 camera has been detected'
|
|
3734
|
+
+ ' for VPS. Taking the first...');
|
|
3735
|
+
}
|
|
3736
|
+
this._useCamera(SharedCameras.list[0].camera);
|
|
3737
|
+
}
|
|
3738
|
+
}
|
|
3739
|
+
|
|
3740
|
+
/**
|
|
3741
|
+
* @override
|
|
3742
|
+
*/
|
|
3743
|
+
stop() {
|
|
3744
|
+
SharedCameras.off('added', this._onCameraDetected);
|
|
3745
|
+
SharedCameras.off('removed', this._onCameraRemoved);
|
|
3746
|
+
|
|
3747
|
+
this._camera = null;
|
|
3748
|
+
}
|
|
3749
|
+
|
|
3750
|
+
|
|
3751
|
+
_onCameraDetected = ({ camera }) => {
|
|
3752
|
+
if (this._camera) {
|
|
3753
|
+
Logger.warn('It seems that more than 1 camera has been detected'
|
|
3754
|
+
+ ' for VPS. Taking the first...');
|
|
3755
|
+
}
|
|
3756
|
+
this._useCamera(camera);
|
|
3757
|
+
}
|
|
3758
|
+
|
|
3759
|
+
_onCameraRemoved = () => {
|
|
3760
|
+
if (this._camera) {
|
|
3761
|
+
this._camera.off('started', this._internalStart);
|
|
3762
|
+
this._camera.off('stopped', this._internalStop);
|
|
3763
|
+
} else {
|
|
3764
|
+
Logger.warn('There is no previously detected camera but once has stopped');
|
|
3765
|
+
}
|
|
3766
|
+
this._camera = null;
|
|
3767
|
+
}
|
|
3768
|
+
|
|
3769
|
+
/**
|
|
3770
|
+
* @param {Camera} camera
|
|
3771
|
+
*/
|
|
3772
|
+
_useCamera(camera) {
|
|
3773
|
+
this._camera = camera;
|
|
3774
|
+
|
|
3775
|
+
camera.on('started', this._internalStart);
|
|
3776
|
+
camera.on('stopped', this._internalStop);
|
|
3777
|
+
|
|
3778
|
+
if (camera.isStarted) {
|
|
3779
|
+
this._internalStart();
|
|
3780
|
+
}
|
|
3781
|
+
}
|
|
3782
|
+
|
|
3783
|
+
|
|
3784
|
+
_internalStart = async () => {
|
|
3785
|
+
|
|
3786
|
+
this._serverError = false;
|
|
3787
|
+
|
|
3788
|
+
let lastTimestamp = -1;
|
|
3789
|
+
|
|
3790
|
+
while (this.state !== ProviderState.STOPPPED) {
|
|
3791
|
+
|
|
3792
|
+
const diffTime = preciseTime() - lastTimestamp;
|
|
3793
|
+
const timeToWait = Math.max(0, VisionRelocalization.MIN_TIME_BETWEEN_TWO_REQUESTS - diffTime);
|
|
3794
|
+
await new Promise(resolve => setTimeout(resolve, timeToWait));
|
|
3795
|
+
|
|
3796
|
+
if (this.state === ProviderState.STOPPPED) {
|
|
3797
|
+
break;
|
|
3798
|
+
}
|
|
3799
|
+
|
|
3800
|
+
const url = VisionRelocalization.SERVICE_URL + VisionRelocalization.MAP_ID;
|
|
3801
|
+
|
|
3802
|
+
// 1. Prepare the request
|
|
3803
|
+
if (!this._camera || this._camera.state !== Camera.State.STARTED) {
|
|
3804
|
+
break;
|
|
3805
|
+
}
|
|
3806
|
+
const payload = await this._prepareRequest();
|
|
3807
|
+
|
|
3808
|
+
if (this.state === ProviderState.STOPPPED) {
|
|
3809
|
+
break;
|
|
3810
|
+
}
|
|
3811
|
+
|
|
3812
|
+
// 2. Send the request
|
|
3813
|
+
const serverResponse = await fetch(url, {
|
|
3814
|
+
method: 'POST',
|
|
3815
|
+
body: JSON.stringify(payload),
|
|
3816
|
+
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }
|
|
3817
|
+
});
|
|
3818
|
+
|
|
3819
|
+
if (this.state === ProviderState.STOPPPED) {
|
|
3820
|
+
break;
|
|
3821
|
+
}
|
|
3822
|
+
|
|
3823
|
+
// 3. Parse the response
|
|
3824
|
+
const events = await this._parseResponse(serverResponse, url, payload.time);
|
|
3825
|
+
if (this._serverError || this.state === ProviderState.STOPPPED) {
|
|
3826
|
+
break;
|
|
3827
|
+
}
|
|
3828
|
+
|
|
3829
|
+
// 4. Notify events
|
|
3830
|
+
if (events.length) {
|
|
3831
|
+
this.notify(...events);
|
|
3832
|
+
}
|
|
3833
|
+
|
|
3834
|
+
lastTimestamp = preciseTime();
|
|
3835
|
+
}
|
|
3836
|
+
|
|
3837
|
+
if (this.state !== ProviderState.STOPPPED) {
|
|
3838
|
+
this.stop();
|
|
3839
|
+
}
|
|
3840
|
+
}
|
|
3841
|
+
|
|
3842
|
+
_internalStop = () => {
|
|
3843
|
+
// do nothing
|
|
3844
|
+
}
|
|
3845
|
+
|
|
3846
|
+
|
|
3847
|
+
/**
|
|
3848
|
+
* @returns {Object}
|
|
3849
|
+
*/
|
|
3850
|
+
async _prepareRequest() {
|
|
3851
|
+
|
|
3852
|
+
const camera = this._camera;
|
|
3853
|
+
|
|
3854
|
+
// Retrieve the image
|
|
3855
|
+
const image = await camera.currentImage;
|
|
3856
|
+
const time = preciseTime();
|
|
3857
|
+
// TODO: move the grayscale conversion in the currentImage getter
|
|
3858
|
+
CameraUtils.convertToGrayscale(image);
|
|
3859
|
+
const reducedImage = CameraUtils.reduceImageSize(image, 1280);
|
|
3860
|
+
// const reducedImage = CameraUtils.reduceImageSize(image, 720, 720);
|
|
3861
|
+
const { height, width } = reducedImage;
|
|
3862
|
+
const base64Image = CameraUtils.canvasToBase64(reducedImage);
|
|
3863
|
+
|
|
3864
|
+
// Retrieve the calibration matrix
|
|
3865
|
+
const calibration = CameraUtils.createCameraCalibrationFromWidthHeightFov(
|
|
3866
|
+
width, height, deg2rad(camera.hardwareVerticalFov)
|
|
3867
|
+
);
|
|
3868
|
+
|
|
3869
|
+
// Build the payload
|
|
3870
|
+
return {
|
|
3871
|
+
calibration,
|
|
3872
|
+
size: [width, height],
|
|
3873
|
+
image: base64Image,
|
|
3874
|
+
time
|
|
3875
|
+
};
|
|
3876
|
+
}
|
|
3877
|
+
|
|
3878
|
+
/**
|
|
3879
|
+
* @param {Response} res
|
|
3880
|
+
* @param {String} url
|
|
3881
|
+
* @param {Number} requestTime
|
|
3882
|
+
* @returns {ProviderEvent[]}
|
|
3883
|
+
*/
|
|
3884
|
+
async _parseResponse(res, url, requestTime) {
|
|
3885
|
+
if (res.status !== 200) {
|
|
3886
|
+
Logger.warn(`The VPS server (${url}) has encountered a problem`);
|
|
3887
|
+
this._serverError = true;
|
|
3888
|
+
return [];
|
|
3889
|
+
}
|
|
3890
|
+
|
|
3891
|
+
const json = await res.json();
|
|
3892
|
+
if (json.error) {
|
|
3893
|
+
return [];
|
|
3894
|
+
}
|
|
3895
|
+
|
|
3896
|
+
const { attitude, userPosition } = VisionRelocalization._parseJsonResponse(json, requestTime);
|
|
3897
|
+
|
|
3898
|
+
const events = [
|
|
3899
|
+
this.createEvent(EventType.AbsoluteAttitude, attitude),
|
|
3900
|
+
this.createEvent(EventType.AbsolutePosition, userPosition)
|
|
3901
|
+
];
|
|
3902
|
+
|
|
3903
|
+
return events;
|
|
3904
|
+
}
|
|
3905
|
+
|
|
3906
|
+
|
|
3907
|
+
static _parseJsonResponse(json, requestTime) {
|
|
3908
|
+
|
|
3909
|
+
const quaternion = [
|
|
3910
|
+
json.attitude.w,
|
|
3911
|
+
json.attitude.x,
|
|
3912
|
+
json.attitude.y,
|
|
3913
|
+
json.attitude.z
|
|
3914
|
+
];
|
|
3915
|
+
const quaternionNorm = Quaternion.norm(quaternion);
|
|
3916
|
+
quaternion[0] /= quaternionNorm;
|
|
3917
|
+
quaternion[1] /= quaternionNorm;
|
|
3918
|
+
quaternion[2] /= quaternionNorm;
|
|
3919
|
+
quaternion[3] /= quaternionNorm;
|
|
3920
|
+
|
|
3921
|
+
const quaternionWithScreenRotation = Quaternion.multiply(
|
|
3922
|
+
Quaternion.fromAxisAngle([0, 0, 1], deg2rad(window.orientation || 0)), quaternion
|
|
3923
|
+
);
|
|
3924
|
+
|
|
3925
|
+
const attitude = new Attitude(quaternionWithScreenRotation, requestTime, 0);
|
|
3926
|
+
|
|
3927
|
+
|
|
3928
|
+
const userPosition = new UserPosition(
|
|
3929
|
+
json.coordinates.lat,
|
|
3930
|
+
json.coordinates.lng,
|
|
3931
|
+
json.coordinates.alt,
|
|
3932
|
+
json.coordinates.level ? new Level(json.coordinates.level) : null,
|
|
3933
|
+
requestTime,
|
|
3934
|
+
0,
|
|
3935
|
+
attitude.heading
|
|
3936
|
+
);
|
|
3937
|
+
|
|
3938
|
+
|
|
3939
|
+
return { userPosition, attitude };
|
|
3940
|
+
}
|
|
3941
|
+
}
|
|
3942
|
+
|
|
3943
|
+
var VisionRelocalization$1 = new VisionRelocalization();
|
|
3944
|
+
|
|
2936
3945
|
class AbsolutePosition extends Provider {
|
|
2937
3946
|
|
|
2938
3947
|
// Use the new absolute position if its accuracy is at least x times better than the last one.
|
|
@@ -2990,13 +3999,29 @@ class AbsolutePosition extends Provider {
|
|
|
2990
3999
|
// do nothing
|
|
2991
4000
|
});
|
|
2992
4001
|
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
events
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
4002
|
+
if (ProvidersOptions.hasVps) {
|
|
4003
|
+
|
|
4004
|
+
const vpsProviderId = VisionRelocalization$1.addEventListener(events => {
|
|
4005
|
+
for (const providerEvent of events) {
|
|
4006
|
+
if (providerEvent.dataType === EventType.AbsolutePosition) {
|
|
4007
|
+
this._onAbsolutePosition(providerEvent);
|
|
4008
|
+
VisionRelocalization$1.removeEventListener(vpsProviderId);
|
|
4009
|
+
return;
|
|
4010
|
+
}
|
|
4011
|
+
}
|
|
4012
|
+
});
|
|
4013
|
+
|
|
4014
|
+
} else {
|
|
4015
|
+
|
|
4016
|
+
this._gnssWifiProviderId = GnssWifi$1.addEventListener(
|
|
4017
|
+
events => {
|
|
4018
|
+
// bearing from GnssWifi is not reliable for our usecase
|
|
4019
|
+
events[0].data.bearing = null;
|
|
4020
|
+
this._onAbsolutePosition(events[0], false);
|
|
4021
|
+
}
|
|
4022
|
+
);
|
|
4023
|
+
|
|
4024
|
+
}
|
|
3000
4025
|
|
|
3001
4026
|
this._mapMatchingHandlerId = MapMatchingHandler$1.addEventListener();
|
|
3002
4027
|
}
|
|
@@ -4267,6 +5292,7 @@ var Providers = /*#__PURE__*/Object.freeze({
|
|
|
4267
5292
|
GnssWifi: GnssWifi$1,
|
|
4268
5293
|
Ip: Ip$1,
|
|
4269
5294
|
AbsolutePosition: AbsolutePosition$1,
|
|
5295
|
+
VisionRelocalization: VisionRelocalization$1,
|
|
4270
5296
|
Barcode: Barcode$1,
|
|
4271
5297
|
CameraNative: CameraNative$1,
|
|
4272
5298
|
CameraProjectionMatrix: CameraProjectionMatrix$1
|
|
@@ -4357,6 +5383,9 @@ class ProvidersInterface {
|
|
|
4357
5383
|
case EventType.CameraProjectionMatrix:
|
|
4358
5384
|
return CameraProjectionMatrix$1;
|
|
4359
5385
|
|
|
5386
|
+
case EventType.MagnetometerNeedCalibration:
|
|
5387
|
+
return MagnetometerCalibrationDetector$1;
|
|
5388
|
+
|
|
4360
5389
|
default:
|
|
4361
5390
|
throw new Error(`Unable to deal with this event type: ${eventType}`);
|
|
4362
5391
|
}
|