@wemap/geo 3.2.16 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -1,25 +1,25 @@
1
- import Constants from './src/Constants.js';
2
- import Utils from './src/Utils.js';
1
+ export { default as Constants } from './src/Constants.js';
2
+ export * as Utils from './src/Utils.js';
3
3
 
4
- import Attitude from './src/rotations/Attitude.js';
5
- import AbsoluteHeading from './src/rotations/AbsoluteHeading.js';
4
+ /** Coordinates */
5
+ export { default as BoundingBox } from './src/coordinates/BoundingBox.js';
6
+ export { default as GeoRelativePosition } from './src/coordinates/GeoRelativePosition.js';
7
+ export { default as Level } from './src/coordinates/Level.js';
8
+ export { default as RelativePosition } from './src/coordinates/RelativePosition.js';
9
+ export { default as Coordinates } from './src/coordinates/Coordinates.js';
10
+ export { default as UserPosition } from './src/coordinates/UserPosition.js';
6
11
 
7
- import BoundingBox from './src/coordinates/BoundingBox.js';
8
- import GeoRelativePosition from './src/coordinates/GeoRelativePosition.js';
9
- import Level from './src/coordinates/Level.js';
10
- import RelativePosition from './src/coordinates/RelativePosition.js';
11
- import Coordinates from './src/coordinates/Coordinates.js';
12
- import UserPosition from './src/coordinates/UserPosition.js';
12
+ /** Rotations */
13
+ export { default as Attitude } from './src/rotations/Attitude.js';
14
+ export { default as AbsoluteHeading } from './src/rotations/AbsoluteHeading.js';
13
15
 
14
- export {
15
- AbsoluteHeading,
16
- Attitude,
17
- BoundingBox,
18
- Constants,
19
- GeoRelativePosition,
20
- Level,
21
- RelativePosition,
22
- Utils,
23
- Coordinates,
24
- UserPosition
25
- };
16
+ /** Router */
17
+ export { default as Edge } from './src/graph/Edge.js';
18
+ export { default as GraphRouter } from './src/graph/GraphRouter.js';
19
+ export { default as Itinerary } from './src/graph/Itinerary.js';
20
+ export { default as Network } from './src/graph/Network.js';
21
+ export { default as Node } from './src/graph/Node.js';
22
+ export { default as MapMatching } from './src/graph/MapMatching.js';
23
+ export { default as Step } from './src/graph/Step.js';
24
+ export * as GraphUtils from './src/graph/Utils.js';
25
+ export { default as NoRouteFoundError } from './src/graph/NoRouteFoundError.js';
package/package.json CHANGED
@@ -12,7 +12,7 @@
12
12
  "directory": "packages/geo"
13
13
  },
14
14
  "name": "@wemap/geo",
15
- "version": "3.2.16",
15
+ "version": "4.0.0",
16
16
  "bugs": {
17
17
  "url": "https://github.com/wemap/wemap-modules-js/issues"
18
18
  },
@@ -22,12 +22,13 @@
22
22
  "keywords": [
23
23
  "utils",
24
24
  "geo",
25
+ "graph",
25
26
  "wemap"
26
27
  ],
27
28
  "license": "ISC",
28
29
  "dependencies": {
29
- "@wemap/logger": "^3.2.3",
30
- "@wemap/maths": "^3.2.15"
30
+ "@wemap/logger": "^4.0.0",
31
+ "@wemap/maths": "^4.0.0"
31
32
  },
32
- "gitHead": "01e6c2ed3b4f24b230cb6a774fe159e7b20b810a"
33
+ "gitHead": "8b72858590fc2ff33fbea4f090de8cd353a7445f"
33
34
  }
package/src/Utils.js CHANGED
@@ -6,161 +6,175 @@ import {
6
6
 
7
7
  import Constants from './Constants.js';
8
8
  import Coordinates from './coordinates/Coordinates.js';
9
+ import UserPosition from './coordinates/UserPosition.js';
9
10
 
10
- class Utils {
11
+ /**
12
+ * Sample a route of Coordinates
13
+ * @param {Array.<Coordinates>} route ordered points
14
+ * @param {*} stepSize step size to sample
15
+ * @param {*} maxLength max route length to sample
16
+ */
17
+ export function sampleRoute(route, stepSize = 0.7, startSampling = 0, length = Number.MAX_VALUE) {
11
18
 
12
- /**
13
- * Sample a route of Coordinates
14
- * @param {Array.<Coordinates>} route ordered points
15
- * @param {*} stepSize step size to sample
16
- * @param {*} maxLength max route length to sample
17
- */
18
- static sampleRoute(route, stepSize = 0.7, startSampling = 0, length = Number.MAX_VALUE) {
19
+ const endSampling = startSampling + length;
19
20
 
20
- const endSampling = startSampling + length;
21
+ const sampledRoute = [];
21
22
 
22
- const sampledRoute = [];
23
+ let lastSample = null;
23
24
 
24
- let lastSample = null;
25
+ let totalDistanceTraveled = 0;
26
+ let distanceToNextSample;
27
+ let startFound = false;
25
28
 
26
- let totalDistanceTraveled = 0;
27
- let distanceToNextSample;
28
- let startFound = false;
29
+ for (let segmentIndex = 0; segmentIndex < route.length - 1; segmentIndex++) {
29
30
 
30
- for (let segmentIndex = 0; segmentIndex < route.length - 1; segmentIndex++) {
31
+ const p1 = route[segmentIndex];
32
+ const p2 = route[segmentIndex + 1];
33
+ const segmentSize = p1.distanceTo(p2);
34
+ const segmentBearing = p1.bearingTo(p2);
31
35
 
32
- const p1 = route[segmentIndex];
33
- const p2 = route[segmentIndex + 1];
34
- const segmentSize = p1.distanceTo(p2);
35
- const segmentBearing = p1.bearingTo(p2);
36
+ let distanceTraveledOnSegment = 0;
36
37
 
37
- let distanceTraveledOnSegment = 0;
38
-
39
- if (!startFound) {
40
- if (startSampling < totalDistanceTraveled + segmentSize) {
41
- startFound = true;
42
- distanceToNextSample = startSampling - totalDistanceTraveled;
43
- } else {
44
- totalDistanceTraveled += segmentSize;
45
- continue;
46
- }
38
+ if (!startFound) {
39
+ if (startSampling < totalDistanceTraveled + segmentSize) {
40
+ startFound = true;
41
+ distanceToNextSample = startSampling - totalDistanceTraveled;
42
+ } else {
43
+ totalDistanceTraveled += segmentSize;
44
+ continue;
47
45
  }
46
+ }
48
47
 
49
- lastSample = p1;
50
- while (distanceTraveledOnSegment + distanceToNextSample < segmentSize
51
- && totalDistanceTraveled + distanceToNextSample <= endSampling) {
52
-
53
- const newPoint = lastSample.destinationPoint(distanceToNextSample, segmentBearing);
54
- newPoint.bearing = segmentBearing;
55
- sampledRoute.push(newPoint);
56
- lastSample = newPoint;
48
+ lastSample = p1;
49
+ while (distanceTraveledOnSegment + distanceToNextSample < segmentSize
50
+ && totalDistanceTraveled + distanceToNextSample <= endSampling) {
57
51
 
58
- distanceTraveledOnSegment += distanceToNextSample;
59
- totalDistanceTraveled += distanceToNextSample;
60
- distanceToNextSample = stepSize;
61
- }
52
+ const newPoint = lastSample.destinationPoint(distanceToNextSample, segmentBearing);
53
+ newPoint.bearing = segmentBearing;
54
+ sampledRoute.push(newPoint);
55
+ lastSample = newPoint;
62
56
 
63
- if (totalDistanceTraveled + distanceToNextSample > endSampling) {
64
- break;
65
- }
57
+ distanceTraveledOnSegment += distanceToNextSample;
58
+ totalDistanceTraveled += distanceToNextSample;
59
+ distanceToNextSample = stepSize;
60
+ }
66
61
 
67
- const rest = segmentSize - distanceTraveledOnSegment;
68
- totalDistanceTraveled += rest;
69
- distanceToNextSample -= rest;
62
+ if (totalDistanceTraveled + distanceToNextSample > endSampling) {
63
+ break;
70
64
  }
71
65
 
72
- return sampledRoute;
66
+ const rest = segmentSize - distanceTraveledOnSegment;
67
+ totalDistanceTraveled += rest;
68
+ distanceToNextSample -= rest;
73
69
  }
74
70
 
75
- /**
76
- * Trim a route of Coordinates
77
- * @param {Array.<Coordinates>} route ordered points
78
- * @param {Coordinates} startPosition position where the trim starts. startPosition has to be on the route.
79
- * @param {*} maxLength max route length
80
- */
81
- static trimRoute(route, startPosition = route[0], length = Number.MAX_VALUE) {
71
+ return sampledRoute;
72
+ }
82
73
 
83
- const newRoute = [];
84
- let previousPoint;
74
+ /**
75
+ * Trim a route of Coordinates
76
+ * @param {Array.<Coordinates>} route ordered points
77
+ * @param {Coordinates} startPosition position where the trim starts. startPosition has to be on the route.
78
+ * @param {*} maxLength max route length
79
+ */
80
+ export function trimRoute(route, startPosition = route[0], length = Number.MAX_VALUE) {
85
81
 
86
- let currentPointIndex;
87
- let cumulativeDistance = 0;
82
+ const newRoute = [];
83
+ let previousPoint;
88
84
 
89
- for (currentPointIndex = 1; currentPointIndex < route.length; currentPointIndex++) {
85
+ let currentPointIndex;
86
+ let cumulativeDistance = 0;
90
87
 
91
- const p1 = route[currentPointIndex - 1];
92
- const p2 = route[currentPointIndex];
88
+ for (currentPointIndex = 1; currentPointIndex < route.length; currentPointIndex++) {
93
89
 
94
- if (startPosition.equalsTo(p1)) {
95
- newRoute.push(p1);
96
- previousPoint = p1;
97
- break;
98
- }
90
+ const p1 = route[currentPointIndex - 1];
91
+ const p2 = route[currentPointIndex];
99
92
 
100
- const proj = startPosition.getSegmentProjection(p1, p2);
101
- if (proj && proj.equalsTo(startPosition) && !proj.equalsTo(p2)) {
102
- newRoute.push(proj);
103
- previousPoint = proj;
104
- break;
105
- }
93
+ if (startPosition.equalsTo(p1)) {
94
+ newRoute.push(p1);
95
+ previousPoint = p1;
96
+ break;
106
97
  }
107
98
 
108
- if (!newRoute.length) {
109
- throw new Error('startPosition is not on the route');
99
+ const proj = startPosition.getSegmentProjection(p1, p2);
100
+ if (proj && proj.equalsTo(startPosition) && !proj.equalsTo(p2)) {
101
+ newRoute.push(proj);
102
+ previousPoint = proj;
103
+ break;
110
104
  }
105
+ }
111
106
 
112
- while (currentPointIndex < route.length) {
113
- const currentPoint = route[currentPointIndex];
114
- const dist = previousPoint.distanceTo(currentPoint);
115
- if (cumulativeDistance + dist >= length
116
- || Math.abs(cumulativeDistance + dist - length) <= Constants.EPS_MM) {
117
- const bearing = previousPoint.bearingTo(currentPoint);
118
- const remainingLength = length - cumulativeDistance;
119
- const end = previousPoint.destinationPoint(remainingLength, bearing);
120
- newRoute.push(end);
121
- break;
122
- }
123
- newRoute.push(currentPoint);
124
- previousPoint = currentPoint;
125
- cumulativeDistance += dist;
126
- currentPointIndex++;
127
- }
107
+ if (!newRoute.length) {
108
+ throw new Error('startPosition is not on the route');
109
+ }
128
110
 
129
- return newRoute;
111
+ while (currentPointIndex < route.length) {
112
+ const currentPoint = route[currentPointIndex];
113
+ const dist = previousPoint.distanceTo(currentPoint);
114
+ if (cumulativeDistance + dist >= length
115
+ || Math.abs(cumulativeDistance + dist - length) <= Constants.EPS_MM) {
116
+ const bearing = previousPoint.bearingTo(currentPoint);
117
+ const remainingLength = length - cumulativeDistance;
118
+ const end = previousPoint.destinationPoint(remainingLength, bearing);
119
+ newRoute.push(end);
120
+ break;
121
+ }
122
+ newRoute.push(currentPoint);
123
+ previousPoint = currentPoint;
124
+ cumulativeDistance += dist;
125
+ currentPointIndex++;
130
126
  }
131
127
 
132
- /**
133
- * @param {Coordinates[]} coords
134
- * @param {number} precision
135
- * @returns {Coordinates[]}
136
- */
137
- static simplifyRoute(coords, precisionAngle = deg2rad(5)) {
128
+ return newRoute;
129
+ }
138
130
 
139
- const isClosed = (coords[0].equalsTo(coords[coords.length - 1]));
131
+ /**
132
+ * @param {Coordinates[]} coords
133
+ * @param {number} precision
134
+ * @returns {Coordinates[]}
135
+ */
136
+ export function simplifyRoute(coords, precisionAngle = deg2rad(5)) {
140
137
 
141
- let newRoute = coords.slice(0, coords.length - (isClosed ? 1 : 0));
138
+ const isClosed = (coords[0].equalsTo(coords[coords.length - 1]));
142
139
 
143
- const len = newRoute.length;
144
- for (let i = isClosed ? 0 : 1; i < len; i++) {
140
+ let newRoute = coords.slice(0, coords.length - (isClosed ? 1 : 0));
145
141
 
146
- const p0 = coords[positiveMod(i - 1, len)];
147
- const p1 = coords[i];
148
- const p2 = coords[positiveMod(i + 1, len)];
142
+ const len = newRoute.length;
143
+ for (let i = isClosed ? 0 : 1; i < len; i++) {
149
144
 
150
- const seg1Dir = p0.bearingTo(p1);
151
- const seg2Dir = p1.bearingTo(p2);
145
+ const p0 = coords[positiveMod(i - 1, len)];
146
+ const p1 = coords[i];
147
+ const p2 = coords[positiveMod(i + 1, len)];
152
148
 
153
- if (Math.abs(seg2Dir - seg1Dir) < precisionAngle) {
154
- newRoute = newRoute.filter(coord => coord !== p1);
155
- }
156
- }
149
+ const seg1Dir = p0.bearingTo(p1);
150
+ const seg2Dir = p1.bearingTo(p2);
157
151
 
158
- if (isClosed) {
159
- newRoute.push(newRoute[0]);
152
+ if (Math.abs(seg2Dir - seg1Dir) < precisionAngle) {
153
+ newRoute = newRoute.filter(coord => coord !== p1);
160
154
  }
155
+ }
161
156
 
162
- return newRoute;
157
+ if (isClosed) {
158
+ newRoute.push(newRoute[0]);
163
159
  }
160
+
161
+ return newRoute;
164
162
  }
165
163
 
166
- export default Utils;
164
+ /**
165
+ * @param {GeolocationPosition} geolocationPosition
166
+ * @returns {UserPosition}
167
+ */
168
+ export function geolocationPositionToUserPosition(geolocationPosition) {
169
+ if (geolocationPosition === null) {
170
+ return null;
171
+ }
172
+
173
+ const { latitude, longitude, accuracy, heading } = geolocationPosition.coords;
174
+
175
+ const userPosition = new UserPosition(latitude, longitude);
176
+ userPosition.time = geolocationPosition.timestamp;
177
+ userPosition.accuracy = accuracy;
178
+ userPosition.bearing = heading ? deg2rad(heading) : null;
179
+ return userPosition;
180
+ }
package/src/Utils.spec.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import chai from 'chai';
3
3
  import chaiAlmost from 'chai-almost';
4
4
 
5
- import Utils from './Utils.js';
5
+ import { sampleRoute, simplifyRoute, trimRoute } from './Utils.js';
6
6
  import Coordinates from './coordinates/Coordinates.js';
7
7
 
8
8
  const expect = chai.expect;
@@ -19,7 +19,7 @@ describe('Geo Utils', () => {
19
19
  const p3 = p2.destinationPoint(49.9, Math.PI / 2);
20
20
  const route = [p1, p2, p3];
21
21
 
22
- samples = Utils.sampleRoute(route);
22
+ samples = sampleRoute(route);
23
23
  expect(samples.length).equals(Math.ceil(149.9 / 0.7));
24
24
  for (let i = 0; i < samples.length - 1; i++) {
25
25
  // Ignore the crow flies for the turn
@@ -29,23 +29,23 @@ describe('Geo Utils', () => {
29
29
  expect(samples[i].distanceTo(samples[i + 1])).to.almost.equal(0.7);
30
30
  }
31
31
 
32
- samples = Utils.sampleRoute(route, 10);
32
+ samples = sampleRoute(route, 10);
33
33
  expect(samples.length).equals(15);
34
34
  for (let i = 0; i < samples.length - 1; i++) {
35
35
  expect(samples[i].distanceTo(samples[i + 1])).to.almost.equal(i === 14 ? 9.9 : 10);
36
36
  }
37
37
 
38
- samples = Utils.sampleRoute(route, 10, 0, 99.9);
38
+ samples = sampleRoute(route, 10, 0, 99.9);
39
39
  expect(samples.length).equals(10);
40
40
 
41
41
 
42
- samples = Utils.sampleRoute(route, 10, 50, 12);
42
+ samples = sampleRoute(route, 10, 50, 12);
43
43
  expect(samples.length).equals(2);
44
44
 
45
- samples = Utils.sampleRoute(route, 10, 50, 100);
45
+ samples = sampleRoute(route, 10, 50, 100);
46
46
  expect(samples.length).equals(10);
47
47
 
48
- samples = Utils.sampleRoute(route, 10, 110, 12);
48
+ samples = sampleRoute(route, 10, 110, 12);
49
49
  expect(samples.length).equals(2);
50
50
 
51
51
  });
@@ -59,44 +59,44 @@ describe('Geo Utils', () => {
59
59
  const p3 = p2.destinationPoint(49.9, Math.PI / 2);
60
60
  const route = [p1, p2, p3];
61
61
 
62
- expect(() => Utils.trimRoute(route, new Coordinates(0, 0))).throw(Error);
62
+ expect(() => trimRoute(route, new Coordinates(0, 0))).throw(Error);
63
63
 
64
- newRoute = Utils.trimRoute(route);
64
+ newRoute = trimRoute(route);
65
65
  expect(newRoute.length).equals(3);
66
66
  for (let i = 0; i < newRoute.length - 1; i++) {
67
67
  expect(newRoute[i].equalsTo(route[i])).true;
68
68
  }
69
69
 
70
- newRoute = Utils.trimRoute(route, p1, 100);
70
+ newRoute = trimRoute(route, p1, 100);
71
71
  expect(newRoute.length).equals(2);
72
72
  expect(newRoute[0].equalsTo(p1)).true;
73
73
  expect(newRoute[1].equalsTo(p2)).true;
74
74
 
75
- newRoute = Utils.trimRoute(route, p1, 90);
75
+ newRoute = trimRoute(route, p1, 90);
76
76
  expect(newRoute.length).equals(2);
77
77
  expect(newRoute[0].equalsTo(p1)).true;
78
78
  expect(newRoute[1].equalsTo(p1.destinationPoint(90, Math.PI / 4))).true;
79
79
 
80
- newRoute = Utils.trimRoute(route, p2, 10);
80
+ newRoute = trimRoute(route, p2, 10);
81
81
  expect(newRoute.length).equals(2);
82
82
  expect(newRoute[0].equalsTo(p2)).true;
83
83
  expect(newRoute[1].equalsTo(p2.destinationPoint(10, Math.PI / 2))).true;
84
84
 
85
85
  const p4 = p1.destinationPoint(20, Math.PI / 4);
86
- newRoute = Utils.trimRoute(route, p4);
86
+ newRoute = trimRoute(route, p4);
87
87
  expect(newRoute.length).equals(3);
88
88
  expect(newRoute[0].equalsTo(p4)).true;
89
89
  expect(newRoute[1].equalsTo(p2)).true;
90
90
  expect(newRoute[2].equalsTo(p3)).true;
91
91
 
92
92
  const p5 = p2.destinationPoint(20, Math.PI / 2);
93
- newRoute = Utils.trimRoute(route, p4, 100);
93
+ newRoute = trimRoute(route, p4, 100);
94
94
  expect(newRoute.length).equals(3);
95
95
  expect(newRoute[0].equalsTo(p4)).true;
96
96
  expect(newRoute[1].equalsTo(p2)).true;
97
97
  expect(newRoute[2].equalsTo(p5)).true;
98
98
 
99
- newRoute = Utils.trimRoute(route, p4, 200);
99
+ newRoute = trimRoute(route, p4, 200);
100
100
  expect(newRoute.length).equals(3);
101
101
  expect(newRoute[0].equalsTo(p4)).true;
102
102
  expect(newRoute[1].equalsTo(p2)).true;
@@ -115,7 +115,7 @@ describe('Geo Utils', () => {
115
115
  new Coordinates(48.756350241508265, 2.0550837293345348)
116
116
  ];
117
117
 
118
- routeSimplified = Utils.simplifyRoute(route);
118
+ routeSimplified = simplifyRoute(route);
119
119
  expect(routeSimplified.length).equal(3);
120
120
  expect(routeSimplified).to.include(route[0]);
121
121
  expect(routeSimplified).to.not.include(route[1]);
@@ -133,7 +133,7 @@ describe('Geo Utils', () => {
133
133
  new Coordinates(48.75627274161895, 2.054974197053283)
134
134
  ];
135
135
 
136
- routeSimplified = Utils.simplifyRoute(route);
136
+ routeSimplified = simplifyRoute(route);
137
137
  expect(routeSimplified.length).equal(5);
138
138
  expect(routeSimplified).to.not.include(route[0]);
139
139
  expect(routeSimplified).to.not.include(route[5]);
@@ -171,6 +171,51 @@ describe('Bounding Box', () => {
171
171
  .be.closeTo(measure, 0.05 * measure);
172
172
  });
173
173
 
174
+ it('pad', () => {
175
+
176
+ let distBefore, distAfter;
177
+
178
+ boundingBox = new BoundingBox(northEast, southWest);
179
+ const bufferRatio = 0.3;
180
+ const extended = new BoundingBox(northEast, southWest).pad(bufferRatio);
181
+
182
+
183
+ distBefore = new Coordinates(boundingBox.getNorth(), boundingBox.getWest()).distanceTo(
184
+ new Coordinates(boundingBox.getNorth(), boundingBox.getEast())
185
+ );
186
+ distAfter = new Coordinates(extended.getNorth(), extended.getWest()).distanceTo(
187
+ new Coordinates(extended.getNorth(), extended.getEast())
188
+ );
189
+ expect(distAfter).be.closeTo(distBefore * (1 + bufferRatio * 2), distAfter * 0.05);
190
+
191
+
192
+ distBefore = new Coordinates(boundingBox.getSouth(), boundingBox.getWest()).distanceTo(
193
+ new Coordinates(boundingBox.getSouth(), boundingBox.getEast())
194
+ );
195
+ distAfter = new Coordinates(extended.getSouth(), extended.getWest()).distanceTo(
196
+ new Coordinates(extended.getSouth(), extended.getEast())
197
+ );
198
+ expect(distAfter).be.closeTo(distBefore * (1 + bufferRatio * 2), distAfter * 0.05);
199
+
200
+
201
+ distBefore = new Coordinates(boundingBox.getNorth(), boundingBox.getEast()).distanceTo(
202
+ new Coordinates(boundingBox.getSouth(), boundingBox.getEast())
203
+ );
204
+ distAfter = new Coordinates(extended.getNorth(), extended.getEast()).distanceTo(
205
+ new Coordinates(extended.getSouth(), extended.getEast())
206
+ );
207
+ expect(distAfter).be.closeTo(distBefore * (1 + bufferRatio * 2), distAfter * 0.05);
208
+
209
+
210
+ distBefore = new Coordinates(boundingBox.getNorth(), boundingBox.getWest()).distanceTo(
211
+ new Coordinates(boundingBox.getSouth(), boundingBox.getWest())
212
+ );
213
+ distAfter = new Coordinates(extended.getNorth(), extended.getWest()).distanceTo(
214
+ new Coordinates(extended.getSouth(), extended.getWest())
215
+ );
216
+ expect(distAfter).be.closeTo(distBefore * (1 + bufferRatio * 2), distAfter * 0.05);
217
+ });
218
+
174
219
  it('toArray', () => {
175
220
  expect(new BoundingBox(northEast, southWest).toArray()).deep.equals([-20, -5, 40, 10]);
176
221
  });