@wemap/geo 3.1.15 → 3.1.20

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/package.json CHANGED
@@ -12,7 +12,7 @@
12
12
  "directory": "packages/geo"
13
13
  },
14
14
  "name": "@wemap/geo",
15
- "version": "3.1.15",
15
+ "version": "3.1.20",
16
16
  "bugs": {
17
17
  "url": "https://github.com/wemap/wemap-modules-js/issues"
18
18
  },
@@ -33,5 +33,5 @@
33
33
  "lodash.isnumber": "^3.0.3",
34
34
  "lodash.isstring": "^4.0.1"
35
35
  },
36
- "gitHead": "44d9ad40afa3e6522a01bc86891082a753199f9a"
36
+ "gitHead": "f7c26f0b16ec1d0d3ec5ca7efe6440424e18d3fb"
37
37
  }
package/src/Constants.js CHANGED
@@ -10,7 +10,7 @@ const Constants = {
10
10
  EPS_DEG_MM: 1e-8,
11
11
 
12
12
  /**
13
- * epsilon in meters which corresponds to q millimeter
13
+ * epsilon in meters which corresponds to 1 millimeter
14
14
  */
15
15
  EPS_MM: 1e-3
16
16
  };
package/src/Utils.js CHANGED
@@ -1,3 +1,4 @@
1
+ /* eslint-disable max-statements */
1
2
  import Coordinates from './coordinates/Coordinates';
2
3
 
3
4
  class Utils {
@@ -8,39 +9,118 @@ class Utils {
8
9
  * @param {*} stepSize step size to sample
9
10
  * @param {*} maxLength max route length to sample
10
11
  */
11
- static sampleRoute(route, stepSize = 0.7, maxLength = Number.MAX_VALUE) {
12
+ static sampleRoute(route, stepSize = 0.7, startSampling = 0, length = Number.MAX_VALUE) {
12
13
 
13
- let p1, p2 = null;
14
- let bearing, distance;
14
+ const endSampling = startSampling + length;
15
15
 
16
16
  const sampledRoute = [];
17
- let reportedDistance = 0;
18
- let totalDistance = 0;
19
17
 
20
- for (let i = 0; i < route.length - 1; i++) {
18
+ let lastSample = null;
21
19
 
22
- p1 = route[i];
23
- p2 = route[i + 1];
20
+ let totalDistanceTraveled = 0;
21
+ let distanceToNextSample;
22
+ let startFound = false;
24
23
 
25
- bearing = p1.bearingTo(p2);
26
- distance = p1.distanceTo(p2);
24
+ for (let segmentIndex = 0; segmentIndex < route.length - 1; segmentIndex++) {
27
25
 
28
- if (distance > 0) {
29
- let ratio = reportedDistance / distance;
30
- while (ratio < 1 && totalDistance < maxLength) {
31
- const newPoint = p1.destinationPoint(ratio * distance, bearing);
32
- newPoint.bearing = bearing;
33
- sampledRoute.push(newPoint);
34
- ratio += stepSize / distance;
35
- totalDistance += stepSize;
26
+ const p1 = route[segmentIndex];
27
+ const p2 = route[segmentIndex + 1];
28
+ const segmentSize = p1.distanceTo(p2);
29
+ const segmentBearing = p1.bearingTo(p2);
30
+
31
+ let distanceTraveledOnSegment = 0;
32
+
33
+ if (!startFound) {
34
+ if (startSampling < totalDistanceTraveled + segmentSize) {
35
+ startFound = true;
36
+ distanceToNextSample = startSampling - totalDistanceTraveled;
37
+ } else {
38
+ totalDistanceTraveled += segmentSize;
39
+ continue;
36
40
  }
37
- reportedDistance = (ratio - 1) * distance;
38
41
  }
42
+
43
+ lastSample = p1;
44
+ while (distanceTraveledOnSegment + distanceToNextSample < segmentSize
45
+ && totalDistanceTraveled + distanceToNextSample <= endSampling) {
46
+
47
+ const newPoint = lastSample.destinationPoint(distanceToNextSample, segmentBearing);
48
+ newPoint.bearing = segmentBearing;
49
+ sampledRoute.push(newPoint);
50
+ lastSample = newPoint;
51
+
52
+ distanceTraveledOnSegment += distanceToNextSample;
53
+ totalDistanceTraveled += distanceToNextSample;
54
+ distanceToNextSample = stepSize;
55
+ }
56
+
57
+ if (totalDistanceTraveled + distanceToNextSample > endSampling) {
58
+ break;
59
+ }
60
+
61
+ const rest = segmentSize - distanceTraveledOnSegment;
62
+ totalDistanceTraveled += rest;
63
+ distanceToNextSample -= rest;
39
64
  }
40
- sampledRoute.push(p2);
41
65
 
42
66
  return sampledRoute;
43
67
  }
68
+
69
+ /**
70
+ * Trim a route of Coordinates
71
+ * @param {Array.<Coordinates>} route ordered points
72
+ * @param {Coordinates} startPosition position where the trim starts. startPosition has to be on the route.
73
+ * @param {*} maxLength max route length
74
+ */
75
+ static trimRoute(route, startPosition = route[0], length = Number.MAX_VALUE) {
76
+
77
+ const newRoute = [];
78
+ let previousPoint;
79
+
80
+ let currentPointIndex;
81
+ let cumulativeDistance = 0;
82
+
83
+ for (currentPointIndex = 1; currentPointIndex < route.length; currentPointIndex++) {
84
+
85
+ const p1 = route[currentPointIndex - 1];
86
+ const p2 = route[currentPointIndex];
87
+
88
+ if (startPosition.equalsTo(p1)) {
89
+ newRoute.push(p1);
90
+ previousPoint = p1;
91
+ break;
92
+ }
93
+
94
+ const proj = startPosition.getSegmentProjection(p1, p2);
95
+ if (proj && proj.equalsTo(startPosition) && !proj.equalsTo(p2)) {
96
+ newRoute.push(proj);
97
+ previousPoint = proj;
98
+ break;
99
+ }
100
+ }
101
+
102
+ if (!newRoute.length) {
103
+ throw new Error('startPosition is not on the route');
104
+ }
105
+
106
+ while (currentPointIndex < route.length) {
107
+ const currentPoint = route[currentPointIndex];
108
+ const dist = previousPoint.distanceTo(currentPoint);
109
+ if (cumulativeDistance + dist >= length) {
110
+ const bearing = previousPoint.bearingTo(currentPoint);
111
+ const remainingLength = length - cumulativeDistance;
112
+ const end = previousPoint.destinationPoint(remainingLength, bearing);
113
+ newRoute.push(end);
114
+ break;
115
+ }
116
+ newRoute.push(currentPoint);
117
+ previousPoint = currentPoint;
118
+ cumulativeDistance += dist;
119
+ currentPointIndex++;
120
+ }
121
+
122
+ return newRoute;
123
+ }
44
124
  }
45
125
 
46
126
  export default Utils;
package/src/Utils.spec.js CHANGED
@@ -1,8 +1,12 @@
1
- import { expect } from 'chai';
1
+ /* eslint-disable max-statements */
2
+ import chai from 'chai';
3
+ import chaiAlmost from 'chai-almost';
2
4
 
3
5
  import Utils from './Utils';
4
6
  import Coordinates from './coordinates/Coordinates';
5
7
 
8
+ const expect = chai.expect;
9
+ chai.use(chaiAlmost(1e-3));
6
10
 
7
11
  describe('Geo Utils', () => {
8
12
 
@@ -10,30 +14,92 @@ describe('Geo Utils', () => {
10
14
 
11
15
  let samples;
12
16
 
13
- const route = [
14
- new Coordinates(45.0, 5.0),
15
- new Coordinates(45.000735, 5.0007303),
16
- new Coordinates(45.000735, 5.0007303),
17
- new Coordinates(45.0003702, 5.0011008)
18
- ];
17
+ const p1 = new Coordinates(45.0, 5.0);
18
+ const p2 = p1.destinationPoint(100, Math.PI / 4);
19
+ const p3 = p2.destinationPoint(49.9, Math.PI / 2);
20
+ const route = [p1, p2, p3];
19
21
 
20
- samples = Utils.sampleRoute(route, 10);
21
- expect(samples.length).equals(16);
22
-
23
- // Do not consider the last point
24
- for (let i = 0; i < samples.length - 2; i++) {
25
- // Do not consider the turn, only straight lines
26
- if (i === 9) {
22
+ samples = Utils.sampleRoute(route);
23
+ expect(samples.length).equals(Math.ceil(149.9 / 0.7));
24
+ for (let i = 0; i < samples.length - 1; i++) {
25
+ // Ignore the crow flies for the turn
26
+ if (i === Math.floor(100 / 0.7)) {
27
27
  i++;
28
28
  }
29
- expect(10 - samples[i].distanceTo(samples[i + 1])).is.below(1e-8);
29
+ expect(samples[i].distanceTo(samples[i + 1])).to.almost.equal(0.7);
30
30
  }
31
31
 
32
- samples = Utils.sampleRoute(route, 10, 100);
33
- expect(samples.length).equals(11);
32
+ samples = Utils.sampleRoute(route, 10);
33
+ expect(samples.length).equals(15);
34
+ for (let i = 0; i < samples.length - 1; i++) {
35
+ expect(samples[i].distanceTo(samples[i + 1])).to.almost.equal(i === 14 ? 9.9 : 10);
36
+ }
37
+
38
+ samples = Utils.sampleRoute(route, 10, 0, 99.9);
39
+ expect(samples.length).equals(10);
40
+
41
+
42
+ samples = Utils.sampleRoute(route, 10, 50, 12);
43
+ expect(samples.length).equals(2);
44
+
45
+ samples = Utils.sampleRoute(route, 10, 50, 100);
46
+ expect(samples.length).equals(10);
47
+
48
+ samples = Utils.sampleRoute(route, 10, 110, 12);
49
+ expect(samples.length).equals(2);
34
50
 
35
- samples = Utils.sampleRoute(route);
36
- expect(samples.length).equals(216);
37
51
  });
38
52
 
53
+ it('trimRoute', () => {
54
+
55
+ let newRoute;
56
+
57
+ const p1 = new Coordinates(45.0, 5.0);
58
+ const p2 = p1.destinationPoint(100, Math.PI / 4);
59
+ const p3 = p2.destinationPoint(49.9, Math.PI / 2);
60
+ const route = [p1, p2, p3];
61
+
62
+ expect(() => Utils.trimRoute(route, new Coordinates(0, 0))).throw(Error);
63
+
64
+ newRoute = Utils.trimRoute(route);
65
+ expect(newRoute.length).equals(3);
66
+ for (let i = 0; i < newRoute.length - 1; i++) {
67
+ expect(newRoute[i].equalsTo(route[i])).true;
68
+ }
69
+
70
+ newRoute = Utils.trimRoute(route, p1, 100);
71
+ expect(newRoute.length).equals(2);
72
+ expect(newRoute[0].equalsTo(p1)).true;
73
+ expect(newRoute[1].equalsTo(p2)).true;
74
+
75
+ newRoute = Utils.trimRoute(route, p1, 90);
76
+ expect(newRoute.length).equals(2);
77
+ expect(newRoute[0].equalsTo(p1)).true;
78
+ expect(newRoute[1].equalsTo(p1.destinationPoint(90, Math.PI / 4))).true;
79
+
80
+ newRoute = Utils.trimRoute(route, p2, 10);
81
+ expect(newRoute.length).equals(2);
82
+ expect(newRoute[0].equalsTo(p2)).true;
83
+ expect(newRoute[1].equalsTo(p2.destinationPoint(10, Math.PI / 2))).true;
84
+
85
+ const p4 = p1.destinationPoint(20, Math.PI / 4);
86
+ newRoute = Utils.trimRoute(route, p4);
87
+ expect(newRoute.length).equals(3);
88
+ expect(newRoute[0].equalsTo(p4)).true;
89
+ expect(newRoute[1].equalsTo(p2)).true;
90
+ expect(newRoute[2].equalsTo(p3)).true;
91
+
92
+ const p5 = p2.destinationPoint(20, Math.PI / 2);
93
+ newRoute = Utils.trimRoute(route, p4, 100);
94
+ expect(newRoute.length).equals(3);
95
+ expect(newRoute[0].equalsTo(p4)).true;
96
+ expect(newRoute[1].equalsTo(p2)).true;
97
+ expect(newRoute[2].equalsTo(p5)).true;
98
+
99
+ newRoute = Utils.trimRoute(route, p4, 200);
100
+ expect(newRoute.length).equals(3);
101
+ expect(newRoute[0].equalsTo(p4)).true;
102
+ expect(newRoute[1].equalsTo(p2)).true;
103
+ expect(newRoute[2].equalsTo(p3)).true;
104
+ });
39
105
  });