@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 CHANGED
@@ -1,23 +1,82 @@
1
1
  import { Calibration } from "@wemap/camera";
2
- import { Coordinates } from "@wemap/geo";
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
- attitude?: Quaternion_t,
14
- position: Coordinates,
15
- positionAccuracy: number
16
- }
17
-
18
- toJson(): object;
19
- static fromJson(json: object): VpsMetadata;
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": "^9.0.8",
12
- "@wemap/geo": "^9.1.1",
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": "^9.1.1",
15
+ "@wemap/map": "^10.0.0-alpha.0",
16
16
  "@wemap/maths": "^9.0.0",
17
- "@wemap/osm": "^9.1.1",
18
- "@wemap/routers": "^9.1.1",
19
- "@wemap/utils": "^9.0.0"
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": "9.1.1",
46
- "gitHead": "bf6a54cf4f886ebac773549339ada8f98c0b7f7f"
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, Level, MapMatching, Network, GraphProjection, UserPosition
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 DEFAULT_USE_ORIENTATION_MATCHING = true;
38
+ static ORIENTATION_MATCHING = true;
39
39
 
40
40
  /** @type {number} in meters */
41
- static DEFAULT_MM_HUGE_JUMP_DISTANCE = 3;
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 DEFAULT_MIN_STEPS_BETWEEN_ORIENTATION_MATCHING = 3;
44
+ static MIN_STEPS_BETWEEN_ORIENTATION_MATCHING = 3;
48
45
 
49
46
  /** @type {number} */
50
- static DEFAULT_MIN_STEPS_FOR_ORIENTATION_MATCHING = 5;
47
+ static MIN_STEPS_FOR_ORIENTATION_MATCHING = 5;
51
48
 
52
49
  /** @type {number} */
53
- static DEFAULT_LAST_PROJECTIONS_WINDOW_SIZE = 3;
50
+ static LAST_PROJECTIONS_WINDOW_SIZE = 3;
54
51
 
55
52
  /** @type {number} */
56
- static DEFAULT_LAST_PROJECTIONS_EDGE_ANGLE_THRESHOLD = deg2rad(3);
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 = MapMatchingHandler.DEFAULT_MM_MIN_DIST;
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 > this._hugeJumpDistance;
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 > this._lastProjectionsWindowSize) {
324
+ if (this._lastProjections.length > MapMatchingHandler.LAST_PROJECTIONS_WINDOW_SIZE) {
350
325
  this._lastProjections.shift();
351
326
  }
352
327
 
353
- const thisWillBeAHugeJump = projection.distanceFromNearestElement > this._hugeJumpDistance;
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 > this._lastProjectionsWindowSize) {
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
- > this._lastProjectionsEdgeAngleThreshold)
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 (!this._useOrientationMatching) {
453
+ if (!MapMatchingHandler.ORIENTATION_MATCHING) {
521
454
  return;
522
455
  }
523
456
 
524
457
  if (this.state !== ProviderState.STARTED
525
- || this._countStepsFromLastMatching < this._minStepsBetweenOrientationMatching
526
- || StraightLineDetector.numStepsDetectedFromLastTurn < this._minStepsForOrientationMatching) {
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, Level } from '@wemap/geo';
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
- deg2rad(json.bearing),
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 * this._stepSizeMultiplier;
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 DEFAULT_STEPS_CONSIDERED_FOR_STRAIGHT_LINE = 2;
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 >= this._stepsConsideredForStraightLine) {
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 === this._stepsConsideredForStraightLine) {
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 VpsMetadata from './VpsMetadata.js';
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 {object}
17
+ * @returns {VpsRequest}
15
18
  */
16
19
  static _prepareRequest(imageCanvas, calibration, coarsePose) {
17
- const requestTime = TimeUtils.preciseTime() / 1e3;
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
- const base64Image = CameraUtils.canvasToBase64(reducedImage);
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 jsonPayload = this._prepareRequest(imageCanvas, calibration, coarsePose);
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(jsonPayload),
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
- const { userPosition, attitude } = this._parseJsonResponse(json, jsonPayload.time);
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 '../../events/EventType.js';
9
- import Inclination from '../inclination/Inclination.js';
10
- import Provider from '../Provider.js';
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
- Inclination.removeEventListener(this._inclinationProviderId);
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, devicePosition)
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 { Coordinates } from '@wemap/geo';
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: Coordinates, positionAccuracy: number, ?attitude: [number, number, number, number]}} */
14
+ /** @type {?{position?: UserPosition, attitude?: Attitude}} */
15
15
  coarse;
16
16
 
17
+ /** @type {object} */
18
+ userAgent;
19
+
17
20
  /**
18
- * @returns {object}
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
- if (this.coarse.positionAccuracy) {
40
- output.coarse.positionAccuracy = this.coarse.positionAccuracy;
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 {Coordinates}
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 = Coordinates.fromJson(json.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
- });