@wemap/providers 9.1.1 → 10.0.0-alpha.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/index.d.ts +68 -9
- package/index.js +5 -4
- package/package.json +8 -8
- package/src/mapmatching/MapMatchingHandler.js +18 -149
- package/src/providers/position/absolute/AbsolutePosition.js +16 -68
- package/src/providers/position/absolute/PoleStar.js +1 -2
- package/src/providers/steps/StepDetector.js +1 -14
- package/src/providers/steps/StraightLineDetector.js +3 -14
- package/src/providers/vision/{ImageRelocalization.js → vps/ImageRelocalization.js} +15 -39
- package/src/providers/vision/{Vps.js → vps/Vps.js} +10 -64
- package/src/providers/vision/{VpsMetadata.js → vps/VpsMetadata.js} +16 -17
- package/src/providers/vision/vps/VpsRequest.js +29 -0
- package/src/providers/vision/vps/VpsResponse.js +23 -0
- package/src/mapmatching/MapMatchingHandler.spec.js +0 -136
- /package/src/providers/vision/{VpsSchema.json → vps/VpsSchema.json} +0 -0
package/index.d.ts
CHANGED
|
@@ -1,23 +1,82 @@
|
|
|
1
1
|
import { Calibration } from "@wemap/camera";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
Attitude, AttitudeJson,
|
|
4
|
+
UserPosition, UserPositionJson
|
|
5
|
+
} from "@wemap/geo";
|
|
3
6
|
import { Quaternion_t } from "@wemap/maths";
|
|
7
|
+
import { UserAgentWithDetails } from "@wemap/utils";
|
|
4
8
|
|
|
5
9
|
declare module '@wemap/providers' {
|
|
6
10
|
|
|
11
|
+
export type CoarsePoseJson = {
|
|
12
|
+
attitude?: AttitudeJson,
|
|
13
|
+
position?: UserPositionJson,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type CoarsePose = {
|
|
17
|
+
attitude?: Attitude,
|
|
18
|
+
position?: UserPosition,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type VpsMetadataJson = {
|
|
22
|
+
size: [number, number], // [width, height]
|
|
23
|
+
calibration?: Calibration,
|
|
24
|
+
time?: number,
|
|
25
|
+
coarse?: CoarsePoseJson,
|
|
26
|
+
userAgent?: UserAgentWithDetails
|
|
27
|
+
}
|
|
28
|
+
|
|
7
29
|
export class VpsMetadata {
|
|
8
30
|
|
|
9
31
|
size: { width: number, height: number };
|
|
10
32
|
calibration?: Calibration;
|
|
11
33
|
time?: number;
|
|
12
|
-
coarse
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
34
|
+
coarse?: CoarsePose;
|
|
35
|
+
userAgent?: UserAgentWithDetails;
|
|
36
|
+
|
|
37
|
+
toJson(): VpsMetadataJson;
|
|
38
|
+
static fromJson(json: VpsMetadataJson): VpsMetadata;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export type VpsRequestJson = VpsMetadataJson & {
|
|
42
|
+
image: string
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class VpsRequest {
|
|
46
|
+
image: string;
|
|
47
|
+
metadata: VpsMetadata;
|
|
48
|
+
|
|
49
|
+
toJson(): VpsRequestJson;
|
|
50
|
+
static fromJson(json: VpsRequestJson): VpsRequest
|
|
20
51
|
}
|
|
21
52
|
|
|
53
|
+
export type VpsResponseJson = {
|
|
54
|
+
attitude: AttitudeJson,
|
|
55
|
+
coordinates: UserPositionJson
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export class VpsResponse {
|
|
59
|
+
attitude: Attitude;
|
|
60
|
+
coordinates: UserPosition;
|
|
61
|
+
|
|
62
|
+
toJson(): VpsResponseJson;
|
|
63
|
+
static fromJson(json: VpsResponseJson): VpsResponse;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export class ImageRelocalization {
|
|
67
|
+
|
|
68
|
+
static _prepareRequest(
|
|
69
|
+
imageCanvas: HTMLCanvasElement,
|
|
70
|
+
calibration?: Calibration,
|
|
71
|
+
coarsePose?: CoarsePose
|
|
72
|
+
): VpsRequest
|
|
73
|
+
|
|
74
|
+
static relocalize(
|
|
75
|
+
endpointUrl: string, imageCanvas: HTMLCanvasElement,
|
|
76
|
+
calibration?: Calibration, coarsePose?: CoarsePose
|
|
77
|
+
): Promise<VpsResponse>;
|
|
78
|
+
|
|
79
|
+
static getHeadingFromQuaternion(quaternion: Quaternion_t): number;
|
|
80
|
+
}
|
|
22
81
|
}
|
|
23
82
|
|
package/index.js
CHANGED
|
@@ -9,7 +9,9 @@ export { default as MapMatchingHandler } from './src/mapmatching/MapMatchingHand
|
|
|
9
9
|
export { default as PositionSmoother } from './src/smoothers/PositionSmoother.js';
|
|
10
10
|
export { default as AttitudeSmoother } from './src/smoothers/AttitudeSmoother.js';
|
|
11
11
|
|
|
12
|
-
export { default as VpsMetadata } from './src/providers/vision/VpsMetadata.js';
|
|
12
|
+
export { default as VpsMetadata } from './src/providers/vision/vps/VpsMetadata.js';
|
|
13
|
+
export { default as VpsRequest } from './src/providers/vision/vps/VpsRequest.js';
|
|
14
|
+
export { default as VpsResponse } from './src/providers/vision/vps/VpsResponse.js';
|
|
13
15
|
|
|
14
16
|
export { default as ProvidersLoggerOld } from './src/events/ProvidersLoggerOld.js';
|
|
15
17
|
|
|
@@ -35,7 +37,6 @@ export { default as Inclination } from './src/providers/inclination/Inclination.
|
|
|
35
37
|
|
|
36
38
|
export { default as StepDetector } from './src/providers/steps/StepDetector.js';
|
|
37
39
|
export { default as StraightLineDetector } from './src/providers/steps/StraightLineDetector.js';
|
|
38
|
-
export { default as StepDetectionMinMaxPeaks2 } from './src/providers/steps/StepDetectionMinMaxPeaks2.js';
|
|
39
40
|
|
|
40
41
|
export { default as Pdr } from './src/providers/position/relative/Pdr.js';
|
|
41
42
|
export { default as GeoRelativePositionFromArCore } from './src/providers/position/relative/GeoRelativePositionFromArCore.js';
|
|
@@ -47,8 +48,8 @@ export { default as Ip } from './src/providers/position/absolute/Ip.js';
|
|
|
47
48
|
export { default as AbsolutePosition } from './src/providers/position/absolute/AbsolutePosition.js';
|
|
48
49
|
|
|
49
50
|
export { default as ArCore } from './src/providers/vision/ArCore.js';
|
|
50
|
-
export { default as ImageRelocalization } from './src/providers/vision/ImageRelocalization.js';
|
|
51
|
-
export { default as Vps } from './src/providers/vision/Vps.js';
|
|
51
|
+
export { default as ImageRelocalization } from './src/providers/vision/vps/ImageRelocalization.js';
|
|
52
|
+
export { default as Vps } from './src/providers/vision/vps/Vps.js';
|
|
52
53
|
export { default as Barcode } from './src/providers/vision/Barcode.js';
|
|
53
54
|
|
|
54
55
|
export { default as CameraNative } from './src/providers/others/CameraNative.js';
|
package/package.json
CHANGED
|
@@ -8,15 +8,15 @@
|
|
|
8
8
|
"Guillaume Pannetier <guillaume.pannetier@getwemap.com>"
|
|
9
9
|
],
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@wemap/camera": "^
|
|
12
|
-
"@wemap/geo": "^
|
|
11
|
+
"@wemap/camera": "^10.0.0-alpha.0",
|
|
12
|
+
"@wemap/geo": "^10.0.0-alpha.0",
|
|
13
13
|
"@wemap/geomagnetism": "^0.1.1",
|
|
14
14
|
"@wemap/logger": "^9.0.0",
|
|
15
|
-
"@wemap/map": "^
|
|
15
|
+
"@wemap/map": "^10.0.0-alpha.0",
|
|
16
16
|
"@wemap/maths": "^9.0.0",
|
|
17
|
-
"@wemap/osm": "^
|
|
18
|
-
"@wemap/routers": "^
|
|
19
|
-
"@wemap/utils": "^
|
|
17
|
+
"@wemap/osm": "^10.0.0-alpha.0",
|
|
18
|
+
"@wemap/routers": "^10.0.0-alpha.0",
|
|
19
|
+
"@wemap/utils": "^10.0.0-alpha.0"
|
|
20
20
|
},
|
|
21
21
|
"description": "A package using different geoloc systems",
|
|
22
22
|
"devDependencies": {
|
|
@@ -42,6 +42,6 @@
|
|
|
42
42
|
"url": "git+https://github.com/wemap/wemap-modules-js.git"
|
|
43
43
|
},
|
|
44
44
|
"type": "module",
|
|
45
|
-
"version": "
|
|
46
|
-
"gitHead": "
|
|
45
|
+
"version": "10.0.0-alpha.0",
|
|
46
|
+
"gitHead": "d98a62dea33f5bcd93bc0eda133242da9fe441e3"
|
|
47
47
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable max-statements */
|
|
2
2
|
import {
|
|
3
|
-
AbsoluteHeading, GraphEdge,
|
|
3
|
+
AbsoluteHeading, GraphEdge, MapMatching, Network, GraphProjection, UserPosition
|
|
4
4
|
} from '@wemap/geo';
|
|
5
5
|
import { deg2rad, diffAngle, diffAngleLines } from '@wemap/maths';
|
|
6
6
|
import { Itinerary } from '@wemap/routers';
|
|
@@ -35,55 +35,28 @@ class MapMatchingHandler extends Provider {
|
|
|
35
35
|
static DEFAULT_USE_ITINERARY_START_AS_POSITION = false;
|
|
36
36
|
|
|
37
37
|
/** @type {boolean} */
|
|
38
|
-
static
|
|
38
|
+
static ORIENTATION_MATCHING = true;
|
|
39
39
|
|
|
40
40
|
/** @type {number} in meters */
|
|
41
|
-
static
|
|
42
|
-
|
|
43
|
-
/** @type {number} in meters */
|
|
44
|
-
static DEFAULT_DISABLE_MM_CLOSE_TO_A_TURN_DISTANCE = 2;
|
|
41
|
+
static MM_HUGE_JUMP_DISTANCE = 3;
|
|
45
42
|
|
|
46
43
|
/** @type {number} */
|
|
47
|
-
static
|
|
44
|
+
static MIN_STEPS_BETWEEN_ORIENTATION_MATCHING = 3;
|
|
48
45
|
|
|
49
46
|
/** @type {number} */
|
|
50
|
-
static
|
|
47
|
+
static MIN_STEPS_FOR_ORIENTATION_MATCHING = 5;
|
|
51
48
|
|
|
52
49
|
/** @type {number} */
|
|
53
|
-
static
|
|
50
|
+
static LAST_PROJECTIONS_WINDOW_SIZE = 3;
|
|
54
51
|
|
|
55
52
|
/** @type {number} */
|
|
56
|
-
static
|
|
53
|
+
static LAST_PROJECTIONS_EDGE_ANGLE_THRESHOLD = deg2rad(3);
|
|
57
54
|
|
|
58
55
|
/** @type {MapMatching} */
|
|
59
56
|
_mapMatching;
|
|
60
57
|
|
|
61
58
|
/** @type {number} */
|
|
62
|
-
_mapMatchingMinDistance
|
|
63
|
-
|
|
64
|
-
/** @type {boolean} */
|
|
65
|
-
_useItineraryStartAsPosition = MapMatchingHandler.DEFAULT_USE_ITINERARY_START_AS_POSITION;
|
|
66
|
-
|
|
67
|
-
/** @type {boolean} */
|
|
68
|
-
_useOrientationMatching = MapMatchingHandler.DEFAULT_USE_ORIENTATION_MATCHING;
|
|
69
|
-
|
|
70
|
-
/** @type {number} */
|
|
71
|
-
_hugeJumpDistance = MapMatchingHandler.DEFAULT_MM_HUGE_JUMP_DISTANCE;
|
|
72
|
-
|
|
73
|
-
/** @type {number} */
|
|
74
|
-
_disableMMCloseToATurnDistance = MapMatchingHandler.DEFAULT_DISABLE_MM_CLOSE_TO_A_TURN_DISTANCE;
|
|
75
|
-
|
|
76
|
-
/** @type {number} */
|
|
77
|
-
_minStepsBetweenOrientationMatching = MapMatchingHandler.DEFAULT_MIN_STEPS_BETWEEN_ORIENTATION_MATCHING;
|
|
78
|
-
|
|
79
|
-
/** @type {number} */
|
|
80
|
-
_minStepsForOrientationMatching = MapMatchingHandler.DEFAULT_MIN_STEPS_FOR_ORIENTATION_MATCHING;
|
|
81
|
-
|
|
82
|
-
/** @type {number} */
|
|
83
|
-
_lastProjectionsWindowSize = MapMatchingHandler.DEFAULT_LAST_PROJECTIONS_WINDOW_SIZE;
|
|
84
|
-
|
|
85
|
-
/** @type {number} */
|
|
86
|
-
_lastProjectionsEdgeAngleThreshold = MapMatchingHandler.DEFAULT_LAST_PROJECTIONS_EDGE_ANGLE_THRESHOLD;
|
|
59
|
+
_mapMatchingMinDistance;
|
|
87
60
|
|
|
88
61
|
/** @type {boolean} */
|
|
89
62
|
_internalProvidersStarted = false;
|
|
@@ -113,6 +86,8 @@ class MapMatchingHandler extends Provider {
|
|
|
113
86
|
this._mapMatching = new MapMatching();
|
|
114
87
|
this._mapMatching.maxDistance = MapMatchingHandler.DEFAULT_MM_MAX_DIST;
|
|
115
88
|
this._mapMatching.maxAngleBearing = MapMatchingHandler.DEFAULT_MM_MAX_ANGLE;
|
|
89
|
+
this._mapMatchingMinDistance = MapMatchingHandler.DEFAULT_MM_MIN_DIST;
|
|
90
|
+
this._useItineraryStartAsPosition = MapMatchingHandler.DEFAULT_USE_ITINERARY_START_AS_POSITION;
|
|
116
91
|
}
|
|
117
92
|
|
|
118
93
|
/**
|
|
@@ -304,7 +279,7 @@ class MapMatchingHandler extends Provider {
|
|
|
304
279
|
|
|
305
280
|
// newPosition must not be used after this line
|
|
306
281
|
|
|
307
|
-
const thisWillBeAHugeJump = projectionWithBearing.distanceFromNearestElement >
|
|
282
|
+
const thisWillBeAHugeJump = projectionWithBearing.distanceFromNearestElement > MapMatchingHandler.MM_HUGE_JUMP_DISTANCE;
|
|
308
283
|
|
|
309
284
|
// In case of a huge jump, be sure the user is in a straight line
|
|
310
285
|
if (thisWillBeAHugeJump && !StraightLineDetector.isStraight()) {
|
|
@@ -346,11 +321,11 @@ class MapMatchingHandler extends Provider {
|
|
|
346
321
|
if (projection) {
|
|
347
322
|
this._projectionsWithAbsAndWithoutRelAttitudeInARow = [];
|
|
348
323
|
this._lastProjections.push(projection);
|
|
349
|
-
if (this._lastProjections.length >
|
|
324
|
+
if (this._lastProjections.length > MapMatchingHandler.LAST_PROJECTIONS_WINDOW_SIZE) {
|
|
350
325
|
this._lastProjections.shift();
|
|
351
326
|
}
|
|
352
327
|
|
|
353
|
-
const thisWillBeAHugeJump = projection.distanceFromNearestElement >
|
|
328
|
+
const thisWillBeAHugeJump = projection.distanceFromNearestElement > MapMatchingHandler.MM_HUGE_JUMP_DISTANCE;
|
|
354
329
|
|
|
355
330
|
// In case of a huge jump, be sure the user is in a straight line
|
|
356
331
|
if (thisWillBeAHugeJump && !StraightLineDetector.isStraight()) {
|
|
@@ -370,13 +345,6 @@ class MapMatchingHandler extends Provider {
|
|
|
370
345
|
return true;
|
|
371
346
|
}
|
|
372
347
|
|
|
373
|
-
// Detector to avoid map-matching close to network turns
|
|
374
|
-
if (this._disableMMCloseToATurnDistance > 0
|
|
375
|
-
&& this._hasTurnInCircle(projection.projection, this._disableMMCloseToATurnDistance)) {
|
|
376
|
-
AbsolutePosition.notify(positionEvent);
|
|
377
|
-
return true;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
348
|
AbsolutePosition.notify(this.createEvent(
|
|
381
349
|
EventType.AbsolutePosition,
|
|
382
350
|
projection.projection,
|
|
@@ -408,7 +376,7 @@ class MapMatchingHandler extends Provider {
|
|
|
408
376
|
}
|
|
409
377
|
|
|
410
378
|
this._lastProjections.push(projectionWithAbs);
|
|
411
|
-
if (this._lastProjections.length >
|
|
379
|
+
if (this._lastProjections.length > MapMatchingHandler.LAST_PROJECTIONS_WINDOW_SIZE) {
|
|
412
380
|
this._lastProjections.shift();
|
|
413
381
|
}
|
|
414
382
|
|
|
@@ -473,57 +441,22 @@ class MapMatchingHandler extends Provider {
|
|
|
473
441
|
return !this._lastProjections.some(projection =>
|
|
474
442
|
!(projection.nearestElement instanceof GraphEdge)
|
|
475
443
|
|| (diffAngleLines(projection.nearestElement.bearing, firstProjection.nearestElement.bearing)
|
|
476
|
-
>
|
|
444
|
+
> MapMatchingHandler.LAST_PROJECTIONS_EDGE_ANGLE_THRESHOLD)
|
|
477
445
|
);
|
|
478
446
|
}
|
|
479
447
|
|
|
480
|
-
/**
|
|
481
|
-
* @param {GraphNode} node
|
|
482
|
-
* @returns {boolean}
|
|
483
|
-
*/
|
|
484
|
-
_nodeHasTurn(node) {
|
|
485
|
-
const { edges } = node;
|
|
486
|
-
for (let i = 0; i < edges.length; i++) {
|
|
487
|
-
for (let j = i + 1; j < edges.length; j++) {
|
|
488
|
-
const angle = diffAngleLines(edges[i].bearing, edges[j].bearing);
|
|
489
|
-
if (angle > MapMatchingHandler.DEFAULT_MM_MAX_ANGLE) {
|
|
490
|
-
return true;
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
return false;
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
/**
|
|
498
|
-
* @param {Coordinates} center
|
|
499
|
-
* @param {number} radius
|
|
500
|
-
* @returns {boolean}
|
|
501
|
-
*/
|
|
502
|
-
_hasTurnInCircle(center, radius) {
|
|
503
|
-
/** @type {Network} */
|
|
504
|
-
const network = this._mapMatching.network;
|
|
505
|
-
if (!network) {
|
|
506
|
-
return false;
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
return network.nodes.filter(node =>
|
|
510
|
-
node.coords.distanceTo(center) <= radius
|
|
511
|
-
&& Level.intersect(node.coords.level, center.level)
|
|
512
|
-
).some(this._nodeHasTurn);
|
|
513
|
-
}
|
|
514
|
-
|
|
515
448
|
/**
|
|
516
449
|
* @param {Projection} projection
|
|
517
450
|
*/
|
|
518
451
|
tryOrientationMatching(projection) {
|
|
519
452
|
|
|
520
|
-
if (!
|
|
453
|
+
if (!MapMatchingHandler.ORIENTATION_MATCHING) {
|
|
521
454
|
return;
|
|
522
455
|
}
|
|
523
456
|
|
|
524
457
|
if (this.state !== ProviderState.STARTED
|
|
525
|
-
|| this._countStepsFromLastMatching <
|
|
526
|
-
|| StraightLineDetector.numStepsDetectedFromLastTurn <
|
|
458
|
+
|| this._countStepsFromLastMatching < MapMatchingHandler.MIN_STEPS_BETWEEN_ORIENTATION_MATCHING
|
|
459
|
+
|| StraightLineDetector.numStepsDetectedFromLastTurn < MapMatchingHandler.MIN_STEPS_FOR_ORIENTATION_MATCHING) {
|
|
527
460
|
return;
|
|
528
461
|
}
|
|
529
462
|
|
|
@@ -591,70 +524,6 @@ class MapMatchingHandler extends Provider {
|
|
|
591
524
|
set useItineraryStartAsPosition(useItineraryStartAsPosition) {
|
|
592
525
|
this._useItineraryStartAsPosition = useItineraryStartAsPosition;
|
|
593
526
|
}
|
|
594
|
-
|
|
595
|
-
get useOrientationMatching() {
|
|
596
|
-
return this._useOrientationMatching;
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
set useOrientationMatching(useOrientationMatching) {
|
|
600
|
-
this._useOrientationMatching = useOrientationMatching;
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
get hugeJumpDistance() {
|
|
604
|
-
return this._hugeJumpDistance;
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
set hugeJumpDistance(hugeJumpDistance) {
|
|
608
|
-
this._hugeJumpDistance = hugeJumpDistance;
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
get disableMMCloseToATurnDistance() {
|
|
612
|
-
return this._disableMMCloseToATurnDistance;
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
set disableMMCloseToATurnDistance(disableMMCloseToATurnDistance) {
|
|
616
|
-
this._disableMMCloseToATurnDistance = disableMMCloseToATurnDistance;
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
get useOrientationMatching() {
|
|
620
|
-
return this._useOrientationMatching;
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
set useOrientationMatching(useOrientationMatching) {
|
|
624
|
-
this._useOrientationMatching = useOrientationMatching;
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
get minStepsBetweenOrientationMatching() {
|
|
628
|
-
return this._minStepsBetweenOrientationMatching;
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
set minStepsBetweenOrientationMatching(minStepsBetweenOrientationMatching) {
|
|
632
|
-
this._minStepsBetweenOrientationMatching = minStepsBetweenOrientationMatching;
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
get minStepsForOrientationMatching() {
|
|
636
|
-
return this._minStepsForOrientationMatching;
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
set minStepsForOrientationMatching(minStepsForOrientationMatching) {
|
|
640
|
-
this._minStepsForOrientationMatching = minStepsForOrientationMatching;
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
get lastProjectionsWindowSize() {
|
|
644
|
-
return this._lastProjectionsWindowSize;
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
set lastProjectionsWindowSize(lastProjectionsWindowSize) {
|
|
648
|
-
this._lastProjectionsWindowSize = lastProjectionsWindowSize;
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
get lastProjectionsEdgeAngleThreshold() {
|
|
652
|
-
return this._lastProjectionsEdgeAngleThreshold;
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
set lastProjectionsEdgeAngleThreshold(lastProjectionsEdgeAngleThreshold) {
|
|
656
|
-
this._lastProjectionsEdgeAngleThreshold = lastProjectionsEdgeAngleThreshold;
|
|
657
|
-
}
|
|
658
527
|
}
|
|
659
528
|
|
|
660
529
|
export default new MapMatchingHandler();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { UserPosition, GeoRelativePosition
|
|
1
|
+
import { UserPosition, GeoRelativePosition } from '@wemap/geo';
|
|
2
2
|
import { PromiseUtils, TimeUtils } from '@wemap/utils';
|
|
3
3
|
|
|
4
4
|
import Provider from '../../Provider.js';
|
|
@@ -9,7 +9,7 @@ import GnssWifi from './GnssWifi.js';
|
|
|
9
9
|
import { default as GeoRelativePositionProvider } from '../relative/GeoRelativePosition.js';
|
|
10
10
|
import ProvidersOptions from '../../../ProvidersOptions.js';
|
|
11
11
|
import ProviderState from '../../ProviderState.js';
|
|
12
|
-
import Vps from '../../vision/Vps.js';
|
|
12
|
+
import Vps from '../../vision/vps/Vps.js';
|
|
13
13
|
import PoleStar from './PoleStar.js';
|
|
14
14
|
|
|
15
15
|
class AbsolutePosition extends Provider {
|
|
@@ -20,9 +20,6 @@ class AbsolutePosition extends Provider {
|
|
|
20
20
|
/** @type {boolean} */
|
|
21
21
|
static USE_MM_FOR_FEED = true;
|
|
22
22
|
|
|
23
|
-
/** @type {boolean} */
|
|
24
|
-
useAllAbsolutePositions = false;
|
|
25
|
-
|
|
26
23
|
/** @type {number?} */
|
|
27
24
|
_gnssWifiProviderId;
|
|
28
25
|
|
|
@@ -53,18 +50,10 @@ class AbsolutePosition extends Provider {
|
|
|
53
50
|
* @override
|
|
54
51
|
*/
|
|
55
52
|
get _availability() {
|
|
56
|
-
|
|
57
|
-
const providersToCheck = [
|
|
53
|
+
return PromiseUtils.any([
|
|
58
54
|
GeoRelativePositionProvider.availability,
|
|
59
55
|
GnssWifi.availability
|
|
60
|
-
];
|
|
61
|
-
if (ProvidersOptions.hasPoleStar) {
|
|
62
|
-
providersToCheck.push(PoleStar.availability);
|
|
63
|
-
}
|
|
64
|
-
if (ProvidersOptions.hasVps) {
|
|
65
|
-
providersToCheck.push(Vps.availability);
|
|
66
|
-
}
|
|
67
|
-
return PromiseUtils.any(providersToCheck);
|
|
56
|
+
]);
|
|
68
57
|
}
|
|
69
58
|
|
|
70
59
|
|
|
@@ -157,54 +146,6 @@ class AbsolutePosition extends Provider {
|
|
|
157
146
|
MapMatchingHandler.removeEventListener(this._mapMatchingHandlerId);
|
|
158
147
|
}
|
|
159
148
|
|
|
160
|
-
/**
|
|
161
|
-
* @param {ProviderEvent<UserPosition>} newPositionEvent
|
|
162
|
-
* @param {boolean} canContainLevel
|
|
163
|
-
* @returns {boolean}
|
|
164
|
-
*/
|
|
165
|
-
_shouldTakeIntoAccountNewAbsolutePosition(newPositionEvent, canContainLevel = true) {
|
|
166
|
-
|
|
167
|
-
const newPosition = newPositionEvent.data;
|
|
168
|
-
const lastPosition = this.lastEvent ? this.lastEvent.data : null;
|
|
169
|
-
|
|
170
|
-
// 1. Verifiy if it is the first known absolute position
|
|
171
|
-
if (!lastPosition) {
|
|
172
|
-
return true;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// 2. Is the new position accuracy is better enough than the last position accuracy
|
|
176
|
-
const isBetterEnough = newPosition.accuracy * AbsolutePosition.ACCURACY_RELOC_RATIO <= lastPosition.accuracy;
|
|
177
|
-
if (isBetterEnough) {
|
|
178
|
-
return true;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// 3.a. Is the new position is far from the new one (regarding accuracy)
|
|
182
|
-
// This condition return true if the two positions accuracy circles does not intersect.
|
|
183
|
-
// This is important if the person put the current page in the background during a while. But,
|
|
184
|
-
// could be dangerous if two providers do not provide close positions (ping-pong effect). This
|
|
185
|
-
// is why the 3.b. condition has been added.
|
|
186
|
-
// TODO: add a routine to augment the current position accuracy when the page is in background
|
|
187
|
-
const isFarEnough = lastPosition.distanceTo(newPosition) > lastPosition.accuracy + newPosition.accuracy;
|
|
188
|
-
|
|
189
|
-
// 3.b. Added on 16/06/22
|
|
190
|
-
// The goal of this condition is to avoid continuous jumps between positions from two providers
|
|
191
|
-
// (i.e. GnssWifi and PoleStar)
|
|
192
|
-
const isFarEnoughAndAccuracyIsBetter = isFarEnough && newPosition.accuracy <= lastPosition.accuracy;
|
|
193
|
-
|
|
194
|
-
if (isBetterEnough && isFarEnoughAndAccuracyIsBetter) {
|
|
195
|
-
return true;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// 4. Added on 23/06/22
|
|
199
|
-
// The goal of this condition is to take into account levels change when map-matching is not enabled / set
|
|
200
|
-
const isChangingLevel = canContainLevel && !Level.equals(newPosition.level, lastPosition.level);
|
|
201
|
-
if (isChangingLevel) {
|
|
202
|
-
return true;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
return false;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
149
|
/**
|
|
209
150
|
* @param {ProviderEvent<UserPosition>} positionEvent
|
|
210
151
|
* @param {boolean} canContainLevel
|
|
@@ -212,15 +153,22 @@ class AbsolutePosition extends Provider {
|
|
|
212
153
|
*/
|
|
213
154
|
_onAbsolutePosition(positionEvent, canContainLevel = true) {
|
|
214
155
|
|
|
215
|
-
if (!this._shouldTakeIntoAccountNewAbsolutePosition(positionEvent, canContainLevel)
|
|
216
|
-
&& !this.useAllAbsolutePositions) {
|
|
217
|
-
return false;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
156
|
const newPosition = positionEvent.data.clone();
|
|
221
157
|
const lastPosition = this.lastEvent ? this.lastEvent.data : null;
|
|
222
158
|
|
|
223
159
|
if (lastPosition) {
|
|
160
|
+
|
|
161
|
+
// Is the new position accuracy is better enough than the last position accuracy
|
|
162
|
+
const isBetterEnough = newPosition.accuracy * AbsolutePosition.ACCURACY_RELOC_RATIO <= lastPosition.accuracy;
|
|
163
|
+
|
|
164
|
+
// Is the new position is far from the new one (regarding accuracy)
|
|
165
|
+
// This is important if the person put the current page in the background during a while
|
|
166
|
+
const isFarEnough = lastPosition.distanceTo(newPosition) > lastPosition.accuracy + newPosition.accuracy;
|
|
167
|
+
|
|
168
|
+
if (!isBetterEnough && !isFarEnough) {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
|
|
224
172
|
if (!canContainLevel) {
|
|
225
173
|
newPosition.level = lastPosition.level;
|
|
226
174
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/* eslint-disable no-bitwise */
|
|
2
2
|
|
|
3
3
|
import { UserPosition } from '@wemap/geo';
|
|
4
|
-
import { deg2rad } from '@wemap/maths';
|
|
5
4
|
import { TimeUtils } from '@wemap/utils';
|
|
6
5
|
|
|
7
6
|
import Provider from '../../Provider.js';
|
|
@@ -98,7 +97,7 @@ class PoleStar extends Provider {
|
|
|
98
97
|
json.alt / 5,
|
|
99
98
|
timestamp,
|
|
100
99
|
json.accuracy,
|
|
101
|
-
|
|
100
|
+
json.bearing,
|
|
102
101
|
this.pname);
|
|
103
102
|
|
|
104
103
|
this.notify(this.createEvent(
|
|
@@ -11,11 +11,6 @@ import StepDetectionMinMaxPeaks2 from './StepDetectionMinMaxPeaks2.js';
|
|
|
11
11
|
|
|
12
12
|
class StepDetector extends Provider {
|
|
13
13
|
|
|
14
|
-
/** @type {number} */
|
|
15
|
-
static DEFAULT_STEP_SIZE_MULTIPLIER = 1;
|
|
16
|
-
|
|
17
|
-
_stepSizeMultiplier = StepDetector.DEFAULT_STEP_SIZE_MULTIPLIER;
|
|
18
|
-
|
|
19
14
|
constructor() {
|
|
20
15
|
super();
|
|
21
16
|
this.stepDetector = new StepDetectionMinMaxPeaks2();
|
|
@@ -89,7 +84,7 @@ class StepDetector extends Provider {
|
|
|
89
84
|
const stepDetected = this.stepDetector.compute(timestamp, linearAcc, this.angularRateEvent.data.values);
|
|
90
85
|
|
|
91
86
|
if (stepDetected) {
|
|
92
|
-
const size = this.stepDetector.lastStepSize
|
|
87
|
+
const size = this.stepDetector.lastStepSize;
|
|
93
88
|
this.numOfSteps++;
|
|
94
89
|
this.notify(this.createEvent(
|
|
95
90
|
EventType.Step, {
|
|
@@ -107,14 +102,6 @@ class StepDetector extends Provider {
|
|
|
107
102
|
linearAcc[2] -= GeoConstants.EARTH_GRAVITY;
|
|
108
103
|
return linearAcc;
|
|
109
104
|
}
|
|
110
|
-
|
|
111
|
-
set stepSizeMultiplier(stepSizeMultiplier) {
|
|
112
|
-
this._stepSizeMultiplier = stepSizeMultiplier;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
get stepSizeMultiplier() {
|
|
116
|
-
return this._stepSizeMultiplier;
|
|
117
|
-
}
|
|
118
105
|
}
|
|
119
106
|
|
|
120
107
|
export default new StepDetector();
|
|
@@ -6,7 +6,7 @@ import EventType from '../../events/EventType.js';
|
|
|
6
6
|
class StraightLineDetector extends Provider {
|
|
7
7
|
|
|
8
8
|
/** @type {number} */
|
|
9
|
-
static
|
|
9
|
+
static STEPS_CONSIDERED_FOR_STRAIGHT_LINE = 2;
|
|
10
10
|
|
|
11
11
|
/** @type {number?} */
|
|
12
12
|
_turnDetectorProviderId = null;
|
|
@@ -17,9 +17,6 @@ class StraightLineDetector extends Provider {
|
|
|
17
17
|
/** @type {number} */
|
|
18
18
|
_countSteps = 0;
|
|
19
19
|
|
|
20
|
-
/** @type {number} */
|
|
21
|
-
_stepsConsideredForStraightLine = StraightLineDetector.DEFAULT_STEPS_CONSIDERED_FOR_STRAIGHT_LINE;
|
|
22
|
-
|
|
23
20
|
/**
|
|
24
21
|
* @override
|
|
25
22
|
*/
|
|
@@ -44,7 +41,7 @@ class StraightLineDetector extends Provider {
|
|
|
44
41
|
}
|
|
45
42
|
|
|
46
43
|
_onTurn = (event) => {
|
|
47
|
-
if (this._countSteps >=
|
|
44
|
+
if (this._countSteps >= StraightLineDetector.STEPS_CONSIDERED_FOR_STRAIGHT_LINE) {
|
|
48
45
|
|
|
49
46
|
const fromEvents = [event];
|
|
50
47
|
if (StepDetector.lastEvent !== null) {
|
|
@@ -60,7 +57,7 @@ class StraightLineDetector extends Provider {
|
|
|
60
57
|
_onStep = (event) => {
|
|
61
58
|
this._countSteps++;
|
|
62
59
|
|
|
63
|
-
if (this._countSteps ===
|
|
60
|
+
if (this._countSteps === StraightLineDetector.STEPS_CONSIDERED_FOR_STRAIGHT_LINE) {
|
|
64
61
|
|
|
65
62
|
const fromEvents = [event];
|
|
66
63
|
if (TurnDectector.lastEvent !== null) {
|
|
@@ -82,14 +79,6 @@ class StraightLineDetector extends Provider {
|
|
|
82
79
|
get numStepsDetectedFromLastTurn() {
|
|
83
80
|
return this._countSteps;
|
|
84
81
|
}
|
|
85
|
-
|
|
86
|
-
get stepsConsideredForStraightLine() {
|
|
87
|
-
return this._stepsConsideredForStraightLine;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
set stepsConsideredForStraightLine(stepsConsideredForStraightLine) {
|
|
91
|
-
this._stepsConsideredForStraightLine = stepsConsideredForStraightLine;
|
|
92
|
-
}
|
|
93
82
|
}
|
|
94
83
|
|
|
95
84
|
export default new StraightLineDetector();
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import UAParser from 'ua-parser-js';
|
|
2
|
+
|
|
1
3
|
import { CameraUtils } from '@wemap/camera';
|
|
2
4
|
import { Attitude, Coordinates, UserPosition } from '@wemap/geo';
|
|
3
5
|
import Logger from '@wemap/logger';
|
|
4
6
|
import { TimeUtils } from '@wemap/utils';
|
|
5
7
|
|
|
6
|
-
import
|
|
8
|
+
import VpsRequest from './VpsRequest.js';
|
|
9
|
+
import VpsResponse from './VpsResponse.js';
|
|
7
10
|
|
|
8
11
|
class ImageRelocalization {
|
|
9
12
|
|
|
@@ -11,49 +14,24 @@ class ImageRelocalization {
|
|
|
11
14
|
* @param {HTMLCanvasElement} imageCanvas
|
|
12
15
|
* @param {{intrinsic:number[], distortions:number[]}} calibration
|
|
13
16
|
* @param {{position: Coordinates, positionAccuracy: number}} coarsePose
|
|
14
|
-
* @returns {
|
|
17
|
+
* @returns {VpsRequest}
|
|
15
18
|
*/
|
|
16
19
|
static _prepareRequest(imageCanvas, calibration, coarsePose) {
|
|
17
|
-
const
|
|
20
|
+
const request = new VpsRequest();
|
|
21
|
+
const { metadata } = request;
|
|
22
|
+
|
|
23
|
+
metadata.time = TimeUtils.preciseTime() / 1e3;
|
|
18
24
|
|
|
19
25
|
CameraUtils.convertToGrayscale(imageCanvas);
|
|
20
26
|
const reducedImage = CameraUtils.reduceImageSize(imageCanvas, 1280);
|
|
21
|
-
|
|
27
|
+
request.image = reducedImage;
|
|
22
28
|
|
|
23
|
-
const metadata = new VpsMetadata();
|
|
24
|
-
metadata.time = requestTime;
|
|
25
29
|
metadata.size = { width: reducedImage.width, height: reducedImage.height };
|
|
26
30
|
metadata.calibration = calibration;
|
|
27
31
|
metadata.coarse = coarsePose;
|
|
32
|
+
metadata.userAgent = (new UAParser()).getResult();
|
|
28
33
|
|
|
29
|
-
return
|
|
30
|
-
image: base64Image,
|
|
31
|
-
...metadata.toJson()
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* @param {object} json
|
|
37
|
-
* @returns {{userPosition: UserPosition, attitude: Attitude}}
|
|
38
|
-
*/
|
|
39
|
-
static _parseJsonResponse(json, requestTime = null) {
|
|
40
|
-
|
|
41
|
-
const attitude = new Attitude([
|
|
42
|
-
json.attitude.w, json.attitude.x,
|
|
43
|
-
json.attitude.y, json.attitude.z
|
|
44
|
-
], requestTime, 0);
|
|
45
|
-
|
|
46
|
-
const userPosition = new UserPosition(
|
|
47
|
-
json.coordinates.lat,
|
|
48
|
-
json.coordinates.lng,
|
|
49
|
-
json.coordinates.alt,
|
|
50
|
-
typeof json.coordinates.level === 'undefined' ? null : json.coordinates.level,
|
|
51
|
-
requestTime,
|
|
52
|
-
0,
|
|
53
|
-
attitude.heading
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
return { userPosition, attitude };
|
|
34
|
+
return request;
|
|
57
35
|
}
|
|
58
36
|
|
|
59
37
|
/**
|
|
@@ -66,14 +44,14 @@ class ImageRelocalization {
|
|
|
66
44
|
static async relocalize(endpointUrl, imageCanvas, calibration = null, coarsePose = null) {
|
|
67
45
|
|
|
68
46
|
// 1. Prepare the request
|
|
69
|
-
const
|
|
47
|
+
const vpsRequest = this._prepareRequest(imageCanvas, calibration, coarsePose);
|
|
70
48
|
|
|
71
49
|
// 2. Send the request
|
|
72
50
|
let serverResponse;
|
|
73
51
|
try {
|
|
74
52
|
serverResponse = await fetch(endpointUrl, {
|
|
75
53
|
method: 'POST',
|
|
76
|
-
body: JSON.stringify(
|
|
54
|
+
body: JSON.stringify(vpsRequest.toJson()),
|
|
77
55
|
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }
|
|
78
56
|
});
|
|
79
57
|
} catch (e) {
|
|
@@ -91,9 +69,7 @@ class ImageRelocalization {
|
|
|
91
69
|
}
|
|
92
70
|
|
|
93
71
|
// 3. Parse the response
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
return { userPosition, attitude };
|
|
72
|
+
return VpsResponse.fromJson(json);
|
|
97
73
|
}
|
|
98
74
|
|
|
99
75
|
static getHeadingFromQuaternion(quaternion) {
|
|
@@ -5,20 +5,15 @@ import Logger from '@wemap/logger';
|
|
|
5
5
|
import { Quaternion, deg2rad } from '@wemap/maths';
|
|
6
6
|
import { TimeUtils } from '@wemap/utils';
|
|
7
7
|
|
|
8
|
-
import EventType from '
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import ProviderState from '../ProviderState.js';
|
|
8
|
+
import EventType from '../../../events/EventType.js';
|
|
9
|
+
import Provider from '../../Provider.js';
|
|
10
|
+
import ProviderState from '../../ProviderState.js';
|
|
12
11
|
import ImageRelocalization from './ImageRelocalization.js';
|
|
13
12
|
|
|
14
13
|
class Vps extends Provider {
|
|
15
14
|
|
|
16
15
|
static MIN_TIME_BETWEEN_TWO_REQUESTS = 1000;
|
|
17
16
|
|
|
18
|
-
static DEFAULT_MIN_INCLINATION_FOR_REQUEST = deg2rad(60);
|
|
19
|
-
|
|
20
|
-
static DEFAULT_WAIT_TIME_MIN_INCLINATION_FOR_REQUEST = 200;
|
|
21
|
-
|
|
22
17
|
static CAMERA_TO_SMARTPHONE_ROT = Quaternion.fromAxisAngle([1, 0, 0], Math.PI);
|
|
23
18
|
|
|
24
19
|
/** @type {boolean} */
|
|
@@ -33,14 +28,6 @@ class Vps extends Provider {
|
|
|
33
28
|
/** @type {?string} */
|
|
34
29
|
_endpoint = null;
|
|
35
30
|
|
|
36
|
-
/** @type {?number} */
|
|
37
|
-
_inclinationProviderId = null;
|
|
38
|
-
|
|
39
|
-
/** @type {number} */
|
|
40
|
-
_minInclinationForRequest = Vps.DEFAULT_MIN_INCLINATION_FOR_REQUEST;
|
|
41
|
-
|
|
42
|
-
/** @type {number} */
|
|
43
|
-
_waitTimeMinInclinationForRequest = Vps.DEFAULT_WAIT_TIME_MIN_INCLINATION_FOR_REQUEST;
|
|
44
31
|
|
|
45
32
|
/**
|
|
46
33
|
* @override
|
|
@@ -80,9 +67,6 @@ class Vps extends Provider {
|
|
|
80
67
|
}
|
|
81
68
|
this._useCamera(SharedCameras.list[0].camera);
|
|
82
69
|
}
|
|
83
|
-
|
|
84
|
-
// 3. Inclination
|
|
85
|
-
this._inclinationProviderId = Inclination.addEventListener();
|
|
86
70
|
}
|
|
87
71
|
|
|
88
72
|
/**
|
|
@@ -93,8 +77,13 @@ class Vps extends Provider {
|
|
|
93
77
|
SharedCameras.off('removed', this._onCameraRemoved);
|
|
94
78
|
|
|
95
79
|
this._camera = null;
|
|
80
|
+
}
|
|
96
81
|
|
|
97
|
-
|
|
82
|
+
/**
|
|
83
|
+
* @param {string} endpoint
|
|
84
|
+
*/
|
|
85
|
+
setEndpoint(endpoint) {
|
|
86
|
+
this._endpoint = endpoint;
|
|
98
87
|
}
|
|
99
88
|
|
|
100
89
|
_onCameraDetected = ({ camera }) => {
|
|
@@ -153,14 +142,6 @@ class Vps extends Provider {
|
|
|
153
142
|
break;
|
|
154
143
|
}
|
|
155
144
|
|
|
156
|
-
// 2.a. Do not send an image if smartphone looks at the floor
|
|
157
|
-
const inclination = Inclination.lastEvent ? Inclination.lastEvent.data : null;
|
|
158
|
-
if (inclination !== null
|
|
159
|
-
&& inclination < this._minInclinationForRequest) {
|
|
160
|
-
await new Promise(resolve => setTimeout(resolve, this._waitTimeMinInclinationForRequest));
|
|
161
|
-
continue;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
145
|
// 3. Get current image from camera and relocalize it.
|
|
165
146
|
const image = await this._camera.currentImage;
|
|
166
147
|
const res = await ImageRelocalization.relocalize(this._endpoint, image);
|
|
@@ -182,14 +163,6 @@ class Vps extends Provider {
|
|
|
182
163
|
);
|
|
183
164
|
const attitude = new Attitude(deviceQuaternion, res.attitude.time, res.attitude.accuracy);
|
|
184
165
|
|
|
185
|
-
// [16/06/22] Force VPS accuracy to 5m if the information does not exist
|
|
186
|
-
// this allows to correctly fuse positions from different providers (VPS,
|
|
187
|
-
// GnssWifi, Pole Star...)
|
|
188
|
-
const devicePosition = res.userPosition.clone();
|
|
189
|
-
if (devicePosition.accuracy === null) {
|
|
190
|
-
devicePosition.accuracy = 5;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
166
|
// 5. Finally, notify the listeners if the VPS is not stopped
|
|
194
167
|
if (this.state === ProviderState.STOPPED) {
|
|
195
168
|
break;
|
|
@@ -197,7 +170,7 @@ class Vps extends Provider {
|
|
|
197
170
|
|
|
198
171
|
this.notify(
|
|
199
172
|
this.createEvent(EventType.AbsoluteAttitude, attitude),
|
|
200
|
-
this.createEvent(EventType.AbsolutePosition,
|
|
173
|
+
this.createEvent(EventType.AbsolutePosition, res.userPosition)
|
|
201
174
|
);
|
|
202
175
|
|
|
203
176
|
}
|
|
@@ -206,33 +179,6 @@ class Vps extends Provider {
|
|
|
206
179
|
_internalStop = () => {
|
|
207
180
|
// do nothing
|
|
208
181
|
}
|
|
209
|
-
|
|
210
|
-
get endpoint() {
|
|
211
|
-
return this._endpoint;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* @param {string} endpoint
|
|
216
|
-
*/
|
|
217
|
-
set endpoint(endpoint) {
|
|
218
|
-
this._endpoint = endpoint;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
get minInclinationForRequest() {
|
|
222
|
-
return this._minInclinationForRequest;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
set minInclinationForRequest(minInclinationForRequest) {
|
|
226
|
-
this._minInclinationForRequest = minInclinationForRequest;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
get waitTimeMinInclinationForRequest() {
|
|
230
|
-
return this._waitTimeMinInclinationForRequest;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
set waitTimeMinInclinationForRequest(waitTimeMinInclinationForRequest) {
|
|
234
|
-
this._waitTimeMinInclinationForRequest = waitTimeMinInclinationForRequest;
|
|
235
|
-
}
|
|
236
182
|
}
|
|
237
183
|
|
|
238
184
|
export default new Vps();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Attitude, UserPosition } from '@wemap/geo';
|
|
2
2
|
|
|
3
3
|
class VpsMetadata {
|
|
4
4
|
|
|
@@ -11,11 +11,14 @@ class VpsMetadata {
|
|
|
11
11
|
/** @type {?number} */
|
|
12
12
|
time;
|
|
13
13
|
|
|
14
|
-
/** @type {?{position
|
|
14
|
+
/** @type {?{position?: UserPosition, attitude?: Attitude}} */
|
|
15
15
|
coarse;
|
|
16
16
|
|
|
17
|
+
/** @type {object} */
|
|
18
|
+
userAgent;
|
|
19
|
+
|
|
17
20
|
/**
|
|
18
|
-
* @returns {
|
|
21
|
+
* @returns {VpsMetadata}
|
|
19
22
|
*/
|
|
20
23
|
toJson() {
|
|
21
24
|
const output = { size: [this.size.width, this.size.height] };
|
|
@@ -27,18 +30,16 @@ class VpsMetadata {
|
|
|
27
30
|
}
|
|
28
31
|
if (this.coarse) {
|
|
29
32
|
output.coarse = {};
|
|
30
|
-
|
|
31
33
|
if (this.coarse.attitude) {
|
|
32
|
-
output.coarse.attitude = this.coarse.attitude;
|
|
34
|
+
output.coarse.attitude = this.coarse.attitude.toJson();
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
if (this.coarse.position) {
|
|
36
38
|
output.coarse.position = this.coarse.position.toJson();
|
|
37
39
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
40
|
+
}
|
|
41
|
+
if (typeof this.userAgent === 'object') {
|
|
42
|
+
output.userAgent = this.userAgent;
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
return output;
|
|
@@ -46,7 +47,7 @@ class VpsMetadata {
|
|
|
46
47
|
|
|
47
48
|
/**
|
|
48
49
|
* @param {object} json
|
|
49
|
-
* @returns {
|
|
50
|
+
* @returns {VpsMetadata}
|
|
50
51
|
*/
|
|
51
52
|
static fromJson(json) {
|
|
52
53
|
const output = new VpsMetadata();
|
|
@@ -62,18 +63,16 @@ class VpsMetadata {
|
|
|
62
63
|
}
|
|
63
64
|
if (json.coarse) {
|
|
64
65
|
output.coarse = {};
|
|
65
|
-
|
|
66
66
|
if (json.coarse.attitude) {
|
|
67
|
-
output.coarse.attitude = json.coarse.attitude;
|
|
67
|
+
output.coarse.attitude = Attitude.fromJson(json.coarse.attitude);
|
|
68
68
|
}
|
|
69
|
-
|
|
70
69
|
if (json.coarse.position) {
|
|
71
|
-
output.coarse.position =
|
|
72
|
-
}
|
|
73
|
-
if (json.coarse.positionAccuracy) {
|
|
74
|
-
output.coarse.positionAccuracy = json.coarse.positionAccuracy;
|
|
70
|
+
output.coarse.position = UserPosition.fromJson(json.coarse.position);
|
|
75
71
|
}
|
|
76
72
|
}
|
|
73
|
+
if (typeof json.userAgent === 'object') {
|
|
74
|
+
output.userAgent = json.userAgent;
|
|
75
|
+
}
|
|
77
76
|
return output;
|
|
78
77
|
}
|
|
79
78
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { CameraUtils } from '@wemap/camera';
|
|
2
|
+
|
|
3
|
+
import VpsMetadata from './VpsMetadata.js';
|
|
4
|
+
|
|
5
|
+
class VpsRequest {
|
|
6
|
+
|
|
7
|
+
/** @type {VpsMetadata} */
|
|
8
|
+
metadata = new VpsMetadata();
|
|
9
|
+
|
|
10
|
+
/** @type {HTMLCanvasElement} */
|
|
11
|
+
image;
|
|
12
|
+
|
|
13
|
+
toJson() {
|
|
14
|
+
const base64Image = CameraUtils.canvasToBase64(this.image);
|
|
15
|
+
return {
|
|
16
|
+
image: base64Image,
|
|
17
|
+
...this.metadata.toJson()
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static fromJson(json) {
|
|
22
|
+
const vpsRequest = new VpsRequest();
|
|
23
|
+
vpsRequest.metadata = VpsMetadata.fromJson(json);
|
|
24
|
+
vpsRequest.image = CameraUtils.base64ToCanvas(json.image);
|
|
25
|
+
return vpsRequest;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export default VpsRequest;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Attitude, UserPosition } from '@wemap/geo';
|
|
2
|
+
|
|
3
|
+
class VpsResponse {
|
|
4
|
+
|
|
5
|
+
/** @type {Attitude} */
|
|
6
|
+
attitude;
|
|
7
|
+
|
|
8
|
+
/** @type {UserPosition} */
|
|
9
|
+
position;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {object} json
|
|
13
|
+
* @returns {VpsResponse}
|
|
14
|
+
*/
|
|
15
|
+
fromJson(json) {
|
|
16
|
+
const response = new VpsResponse();
|
|
17
|
+
response.attitude = Attitude.fromJson(json.attitude);
|
|
18
|
+
response.userPosition = UserPosition.fromJson(json.userPosition);
|
|
19
|
+
return response;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default VpsResponse;
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
/* eslint-disable max-statements */
|
|
2
|
-
import chai from 'chai';
|
|
3
|
-
import { Coordinates, Network } from '@wemap/geo';
|
|
4
|
-
import { deg2rad } from '@wemap/maths';
|
|
5
|
-
import { Itinerary } from '@wemap/routers';
|
|
6
|
-
import MMH from './MapMatchingHandler.js';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const { expect } = chai;
|
|
10
|
-
|
|
11
|
-
describe('MapMatchingHandler', () => {
|
|
12
|
-
|
|
13
|
-
const p0 = new Coordinates(0, 0, null, 0);
|
|
14
|
-
const p1 = p0.destinationPoint(5, 0);
|
|
15
|
-
const p2 = p1.destinationPoint(5, Math.PI / 2);
|
|
16
|
-
const p3 = p1.destinationPoint(10, 0);
|
|
17
|
-
const p4 = p0.destinationPoint(2, deg2rad(10));
|
|
18
|
-
|
|
19
|
-
const pos1 = p0.clone();
|
|
20
|
-
const pos2 = pos1.destinationPoint(3, 0);
|
|
21
|
-
const pos3 = pos2.destinationPoint(10, 0);
|
|
22
|
-
|
|
23
|
-
it('_hasTurnInCircle - itinerary', () => {
|
|
24
|
-
|
|
25
|
-
expect(MMH._hasTurnInCircle(pos1, Number.MAX_VALUE)).is.false;
|
|
26
|
-
|
|
27
|
-
// p4 -> p1 -> p2 is a turn
|
|
28
|
-
MMH.itinerary = Itinerary.fromOrderedCoordinates([p0, p4, p1, p2]);
|
|
29
|
-
|
|
30
|
-
expect(MMH._nodeHasTurn(MMH.network.getNodeByCoords(p0))).is.false;
|
|
31
|
-
expect(MMH._nodeHasTurn(MMH.network.getNodeByCoords(p1))).is.true;
|
|
32
|
-
expect(MMH._nodeHasTurn(MMH.network.getNodeByCoords(p2))).is.false;
|
|
33
|
-
expect(MMH._nodeHasTurn(MMH.network.getNodeByCoords(p4))).is.false;
|
|
34
|
-
|
|
35
|
-
expect(MMH._hasTurnInCircle(pos1, 1)).is.false;
|
|
36
|
-
expect(MMH._hasTurnInCircle(pos1, 3)).is.false;
|
|
37
|
-
expect(MMH._hasTurnInCircle(pos1, 10)).is.true;
|
|
38
|
-
expect(MMH._hasTurnInCircle(pos2, 1)).is.false;
|
|
39
|
-
expect(MMH._hasTurnInCircle(pos2, 3)).is.true;
|
|
40
|
-
expect(MMH._hasTurnInCircle(pos2, 10)).is.true;
|
|
41
|
-
expect(MMH._hasTurnInCircle(pos3, 1)).is.false;
|
|
42
|
-
expect(MMH._hasTurnInCircle(pos3, 3)).is.false;
|
|
43
|
-
expect(MMH._hasTurnInCircle(pos3, 10)).is.true;
|
|
44
|
-
|
|
45
|
-
// Straight line
|
|
46
|
-
MMH.itinerary = Itinerary.fromOrderedCoordinates([p0, p4, p1, p3]);
|
|
47
|
-
|
|
48
|
-
expect(MMH._nodeHasTurn(MMH.network.getNodeByCoords(p1))).is.false;
|
|
49
|
-
expect(MMH._nodeHasTurn(MMH.network.getNodeByCoords(p4))).is.false;
|
|
50
|
-
|
|
51
|
-
expect(MMH._hasTurnInCircle(pos1, 10)).is.false;
|
|
52
|
-
expect(MMH._hasTurnInCircle(pos2, 10)).is.false;
|
|
53
|
-
expect(MMH._hasTurnInCircle(pos3, 10)).is.false;
|
|
54
|
-
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
it('_hasTurnInCircle - network', () => {
|
|
59
|
-
|
|
60
|
-
// p1 has turns
|
|
61
|
-
MMH.network = Network.fromCoordinates([[p0, p4, p1], [p1, p2], [p3, p1]]);
|
|
62
|
-
|
|
63
|
-
expect(MMH._nodeHasTurn(MMH.network.getNodeByCoords(p1))).is.true;
|
|
64
|
-
expect(MMH._nodeHasTurn(MMH.network.getNodeByCoords(p4))).is.false;
|
|
65
|
-
|
|
66
|
-
expect(MMH._hasTurnInCircle(pos1, 1)).is.false;
|
|
67
|
-
expect(MMH._hasTurnInCircle(pos1, 3)).is.false;
|
|
68
|
-
expect(MMH._hasTurnInCircle(pos1, 10)).is.true;
|
|
69
|
-
expect(MMH._hasTurnInCircle(pos2, 1)).is.false;
|
|
70
|
-
expect(MMH._hasTurnInCircle(pos2, 3)).is.true;
|
|
71
|
-
expect(MMH._hasTurnInCircle(pos2, 10)).is.true;
|
|
72
|
-
expect(MMH._hasTurnInCircle(pos3, 1)).is.false;
|
|
73
|
-
expect(MMH._hasTurnInCircle(pos3, 3)).is.false;
|
|
74
|
-
expect(MMH._hasTurnInCircle(pos3, 10)).is.true;
|
|
75
|
-
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
const p10 = new Coordinates(0, 0, null, 1);
|
|
79
|
-
const p11 = p10.destinationPoint(5, 0);
|
|
80
|
-
const p12 = p11.destinationPoint(5, Math.PI / 2);
|
|
81
|
-
const p13 = p11.destinationPoint(10, 0);
|
|
82
|
-
|
|
83
|
-
const pos12 = p10.clone().destinationPoint(3, 0);
|
|
84
|
-
const pos012 = new Coordinates(0, 0, null, [0, 1]).destinationPoint(3, 0);
|
|
85
|
-
|
|
86
|
-
it('_hasTurnInCircle - multi-levels', () => {
|
|
87
|
-
|
|
88
|
-
// level 1 is a straight line
|
|
89
|
-
MMH.network = Network.fromCoordinates([
|
|
90
|
-
[p0, p4, p1], [p1, p2], [p3, p1],
|
|
91
|
-
[p10, p11, p13]
|
|
92
|
-
]);
|
|
93
|
-
|
|
94
|
-
expect(MMH._nodeHasTurn(MMH.network.getNodeByCoords(p1))).is.true;
|
|
95
|
-
expect(MMH._nodeHasTurn(MMH.network.getNodeByCoords(p11))).is.false;
|
|
96
|
-
|
|
97
|
-
expect(MMH._hasTurnInCircle(pos2, 1)).is.false;
|
|
98
|
-
expect(MMH._hasTurnInCircle(pos2, 3)).is.true;
|
|
99
|
-
expect(MMH._hasTurnInCircle(pos2, 10)).is.true;
|
|
100
|
-
expect(MMH._hasTurnInCircle(pos12, 1)).is.false;
|
|
101
|
-
expect(MMH._hasTurnInCircle(pos12, 3)).is.false;
|
|
102
|
-
expect(MMH._hasTurnInCircle(pos12, 10)).is.false;
|
|
103
|
-
expect(MMH._hasTurnInCircle(pos012, 1)).is.false;
|
|
104
|
-
expect(MMH._hasTurnInCircle(pos012, 3)).is.true;
|
|
105
|
-
expect(MMH._hasTurnInCircle(pos012, 10)).is.true;
|
|
106
|
-
|
|
107
|
-
// Changing level
|
|
108
|
-
// straight line
|
|
109
|
-
MMH.network = Network.fromCoordinates([
|
|
110
|
-
[p0, p4, p11], [p11, p13]
|
|
111
|
-
]);
|
|
112
|
-
expect(MMH._nodeHasTurn(MMH.network.getNodeByCoords(p4))).is.false;
|
|
113
|
-
expect(MMH._hasTurnInCircle(pos2, Number.MAX_VALUE)).is.false;
|
|
114
|
-
expect(MMH._hasTurnInCircle(pos12, Number.MAX_VALUE)).is.false;
|
|
115
|
-
expect(MMH._hasTurnInCircle(pos012, Number.MAX_VALUE)).is.false;
|
|
116
|
-
|
|
117
|
-
// Changing level
|
|
118
|
-
// turn in p11
|
|
119
|
-
MMH.network = Network.fromCoordinates([
|
|
120
|
-
[p0, p4, p11], [p11, p12], [p11, p13]
|
|
121
|
-
]);
|
|
122
|
-
|
|
123
|
-
expect(MMH._nodeHasTurn(MMH.network.getNodeByCoords(p11))).is.true;
|
|
124
|
-
expect(MMH._hasTurnInCircle(pos2, 1)).is.false;
|
|
125
|
-
expect(MMH._hasTurnInCircle(pos2, 3)).is.false;
|
|
126
|
-
expect(MMH._hasTurnInCircle(pos2, 10)).is.false;
|
|
127
|
-
expect(MMH._hasTurnInCircle(pos12, 1)).is.false;
|
|
128
|
-
expect(MMH._hasTurnInCircle(pos12, 3)).is.true;
|
|
129
|
-
expect(MMH._hasTurnInCircle(pos12, 10)).is.true;
|
|
130
|
-
expect(MMH._hasTurnInCircle(pos012, 1)).is.false;
|
|
131
|
-
expect(MMH._hasTurnInCircle(pos012, 3)).is.true;
|
|
132
|
-
expect(MMH._hasTurnInCircle(pos012, 10)).is.true;
|
|
133
|
-
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
});
|
|
File without changes
|