@wemap/geo 0.3.7 → 0.3.9

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": "0.3.7",
15
+ "version": "0.3.9",
16
16
  "bugs": {
17
17
  "url": "https://github.com/wemap/wemap-utils-js/issues"
18
18
  },
@@ -31,5 +31,5 @@
31
31
  "lodash.isnumber": "^3.0.3",
32
32
  "lodash.isstring": "^4.0.1"
33
33
  },
34
- "gitHead": "dfef19c363ee76ad4b4e23f9e36912034c10ccca"
34
+ "gitHead": "84a60e64b0968bc45f0f76cc26c08e165dbe6985"
35
35
  }
@@ -113,7 +113,7 @@ class Level {
113
113
  if (second.isInside(first.val)) {
114
114
  return first;
115
115
  }
116
- return first;
116
+ return null;
117
117
  }
118
118
  if (first.isRange && second.isRange) {
119
119
  const up = Math.min(first.up, second.up);
@@ -119,6 +119,20 @@ describe('Level', () => {
119
119
  expect(Level.equalsTo(new Level(-1.5, 1).clone(), new Level(-1.5, 1))).true;
120
120
  });
121
121
 
122
+ it('isInside', () => {
123
+ expect(new Level(0).isInside(0)).true;
124
+ expect(new Level(1).isInside(0)).false;
125
+ expect(new Level(-1).isInside(0)).false;
126
+ expect(new Level(0).isInside(1)).false;
127
+ expect(new Level(0).isInside(-1)).false;
128
+ expect(new Level(0, 2).isInside(0)).true;
129
+ expect(new Level(0, 2).isInside(1)).true;
130
+ expect(new Level(0, 2).isInside(-1)).false;
131
+ expect(new Level(2, 0).isInside(0)).true;
132
+ expect(new Level(2, 0).isInside(1)).true;
133
+ expect(new Level(2, 0).isInside(-1)).false;
134
+ });
135
+
122
136
  it('intersect', () => {
123
137
  expect(Level.intersect(null, null)).is.null;
124
138
 
@@ -138,6 +152,8 @@ describe('Level', () => {
138
152
  expect(Level.equalsTo(Level.intersect(new Level(-3, -1), new Level(-1, 2)), new Level(-1)));
139
153
  expect(Level.intersect(new Level(-3, -2), new Level(-1, 2))).is.null;
140
154
  expect(Level.intersect(new Level(-1, 2), new Level(-3, -2))).is.null;
155
+ expect(Level.intersect(new Level(0), new Level(1, 2))).is.null;
156
+ expect(Level.intersect(new Level(1, 2), new Level(0))).is.null;
141
157
  });
142
158
 
143
159
  it('union', () => {
@@ -159,6 +175,8 @@ describe('Level', () => {
159
175
  expect(Level.equalsTo(Level.union(new Level(-3, -1), new Level(-1, 2)), new Level(-3, 2)));
160
176
  expect(Level.equalsTo(Level.union(new Level(-3, -2), new Level(-1, 2)), new Level(-3, 2)));
161
177
  expect(Level.equalsTo(Level.union(new Level(-1, 2), new Level(-3, -2)), new Level(-3, 2)));
178
+ expect(Level.equalsTo(Level.union(new Level(0), new Level(1, 2)), new Level(0, 2)));
179
+ expect(Level.equalsTo(Level.union(new Level(1, 2), new Level(0)), new Level(0, 2)));
162
180
  });
163
181
 
164
182
  });
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable max-statements */
2
- /* eslint-disable complexity */
2
+
3
3
  import isNumber from 'lodash.isnumber';
4
4
 
5
5
  import { rad2deg } from '@wemap/maths';
@@ -35,7 +35,53 @@ class MapMatching {
35
35
  this.network = network;
36
36
  }
37
37
 
38
- getProjection(location, useDistance = false, useBearing = false, useMultiLevelSegments = true, acceptEdgeFn = () => true) {
38
+ /**
39
+ * Check if the specified edge and its nodes can be used for projection
40
+ * @returns an array of two elements.
41
+ * First is true if projection will be used on the specified edge, false otherwise.
42
+ * Second is true if projection will be used on the nodes of the specified edge, false otherwise.
43
+ */
44
+ _shouldProjectOnEdgeAndNodes(edge, location, useBearing, useMultiLevelSegments, acceptEdgeFn) {
45
+
46
+ if (!acceptEdgeFn(edge)) {
47
+ // if edge selection is not verified
48
+ return [false, false];
49
+ }
50
+
51
+ if (location.level && !location.level.intersect(edge.level)
52
+ || !location.level && edge.level) {
53
+ // if location level is defined and do not intersect targeted level
54
+ return [false, false];
55
+ }
56
+
57
+ // ignore MultiLevelSegments if option used
58
+ const checkEdge = !(!useMultiLevelSegments && edge.level && edge.level.isRange);
59
+
60
+ if (useBearing) {
61
+ // if mapmatching bearing is enabled do not use nodes matching
62
+ if (checkEdge) {
63
+ // condition for optimisation
64
+ const edgeBearing = rad2deg(edge.bearing);
65
+ const diffAngle = MapMatching.diffAngle90(edgeBearing, location.bearing);
66
+ if (diffAngle > this._maxAngleBearing) {
67
+ // Do not try to project if angle is greater than the threshold
68
+ return [false, false];
69
+ }
70
+ }
71
+ return [checkEdge, false];
72
+ }
73
+
74
+ return [checkEdge, true];
75
+ }
76
+
77
+ static _updateProjectionLevelFromEdge = (_edge, _projection) => {
78
+ if (_edge.level) {
79
+ _projection.level = _edge.level.clone();
80
+ }
81
+ };
82
+
83
+ getProjection(location, useDistance = false, useBearing = false,
84
+ useMultiLevelSegments = true, acceptEdgeFn = () => true) {
39
85
 
40
86
  if (!this.network) {
41
87
  return null;
@@ -49,70 +95,52 @@ class MapMatching {
49
95
  return null;
50
96
  }
51
97
 
52
- const updateProjectionLevelFromEdge = (_edge, _projection) => {
53
- if (_edge.level) {
54
- _projection.level = _edge.level.clone();
55
- }
56
- };
57
-
58
98
  const projection = {};
59
99
  projection.origin = location;
60
100
  projection.distanceFromNearestElement = Number.MAX_VALUE;
61
101
 
102
+ const isProjectionBetter = (distanceOfNewProjection) => {
103
+ return distanceOfNewProjection < projection.distanceFromNearestElement
104
+ && (!useDistance || distanceOfNewProjection <= this._maxDistance);
105
+ };
106
+
62
107
  for (let i = 0; i < this.network.edges.length; i++) {
63
108
  const edge = this.network.edges[i];
64
109
 
65
- if (!acceptEdgeFn(edge)) {
66
- continue;
67
- }
110
+ const [checkEdge, checkNodes] = this._shouldProjectOnEdgeAndNodes(
111
+ edge, location, useBearing, useMultiLevelSegments, acceptEdgeFn);
68
112
 
69
- if (!useMultiLevelSegments && edge.level && edge.level.isRange) {
70
- continue;
71
- }
72
-
73
- if (location.level && !location.level.intersect(edge.level)
74
- || !location.level && edge.level) {
75
- continue;
76
- }
77
-
78
- if (useBearing) {
79
- const edgeBearing = rad2deg(edge.bearing);
80
- const diffAngle = MapMatching.diffAngle90(edgeBearing, location.bearing);
81
- if (diffAngle > this._maxAngleBearing) {
82
- continue;
83
- }
84
- } else {
113
+ if (checkNodes) {
85
114
  // Check node 1
86
115
  const distNode1 = location.distanceTo(edge.node1.coords);
87
- if (distNode1 < projection.distanceFromNearestElement
88
- && (!useDistance || distNode1 <= this._maxDistance)) {
116
+ if (isProjectionBetter(distNode1)) {
89
117
  projection.distanceFromNearestElement = distNode1;
90
118
  projection.nearestElement = edge.node1;
91
119
  projection.projection = edge.node1.coords.clone();
92
- updateProjectionLevelFromEdge(edge, projection.projection);
120
+ MapMatching._updateProjectionLevelFromEdge(edge, projection.projection);
93
121
  }
94
122
 
95
123
  // Check node 2
96
124
  const distNode2 = location.distanceTo(edge.node2.coords);
97
- if (distNode2 < projection.distanceFromNearestElement
98
- && (!useDistance || distNode2 <= this._maxDistance)) {
125
+ if (isProjectionBetter(distNode2)) {
99
126
  projection.distanceFromNearestElement = distNode2;
100
127
  projection.nearestElement = edge.node2;
101
128
  projection.projection = edge.node2.coords.clone();
102
- updateProjectionLevelFromEdge(edge, projection.projection);
129
+ MapMatching._updateProjectionLevelFromEdge(edge, projection.projection);
103
130
  }
104
131
  }
105
132
 
106
- // Check edge
107
- const segmentProjection = location.getProjection(edge);
108
- if (segmentProjection) {
109
- updateProjectionLevelFromEdge(edge, segmentProjection);
110
- const distEdge = location.distanceTo(segmentProjection);
111
- if (distEdge < projection.distanceFromNearestElement
112
- && (!useDistance || distEdge <= this._maxDistance)) {
113
- projection.distanceFromNearestElement = distEdge;
114
- projection.nearestElement = edge;
115
- projection.projection = segmentProjection.clone();
133
+ if (checkEdge) {
134
+ // Check edge
135
+ const segmentProjection = location.getProjection(edge);
136
+ if (segmentProjection) {
137
+ const distEdge = location.distanceTo(segmentProjection);
138
+ if (isProjectionBetter(distEdge)) {
139
+ projection.distanceFromNearestElement = distEdge;
140
+ projection.nearestElement = edge;
141
+ projection.projection = segmentProjection.clone();
142
+ MapMatching._updateProjectionLevelFromEdge(edge, projection.projection);
143
+ }
116
144
  }
117
145
  }
118
146
  }
@@ -34,10 +34,6 @@ describe('MapMatching', () => {
34
34
  it('matching node levels', () => {
35
35
  let currentPosition, projection;
36
36
 
37
- /**
38
- * Projection on Nodes
39
- */
40
-
41
37
  currentPosition = new WGS84(43.6091773, 3.8842584, null, null);
42
38
  projection = mapMatching.getProjection(currentPosition);
43
39
  expect(projection).is.null;
@@ -57,10 +53,6 @@ describe('MapMatching', () => {
57
53
  it('matching edge levels', () => {
58
54
  let currentPosition, projection;
59
55
 
60
- /**
61
- * Projection on Edges
62
- */
63
-
64
56
  currentPosition = new WGS84(43.6092811, 3.8842406, null, null);
65
57
  projection = mapMatching.getProjection(currentPosition);
66
58
  expect(projection).is.null;
@@ -80,10 +72,6 @@ describe('MapMatching', () => {
80
72
  it('matching stairs nodes levels', () => {
81
73
  let currentPosition, projection;
82
74
 
83
- /**
84
- * Projection on Edges
85
- */
86
-
87
75
  currentPosition = new WGS84(43.6093691, 3.8842057, null, null);
88
76
  projection = mapMatching.getProjection(currentPosition);
89
77
  expect(projection).is.null;
@@ -103,10 +91,6 @@ describe('MapMatching', () => {
103
91
  it('matching stairs edge levels', () => {
104
92
  let currentPosition, projection;
105
93
 
106
- /**
107
- * Projection on Edges
108
- */
109
-
110
94
  currentPosition = new WGS84(43.6093476, 3.8841978, null, null);
111
95
  projection = mapMatching.getProjection(currentPosition);
112
96
  expect(projection).is.null;
@@ -125,4 +109,25 @@ describe('MapMatching', () => {
125
109
 
126
110
  });
127
111
 
112
+ it('useMultiLevelSegments', () => {
113
+ let currentPosition, projection;
114
+
115
+ // On Nodes
116
+
117
+ currentPosition = new WGS84(43.6093691, 3.8842057, null, new Level(0));
118
+ projection = mapMatching.getProjection(currentPosition, true, false, false);
119
+ expect(projection).is.null;
120
+
121
+ // Next two are complex cases and not yet handled by our system
122
+
123
+ // currentPosition = new WGS84(43.6093691, 3.8842057, null, new Level(1));
124
+ // projection = mapMatching.getProjection(currentPosition, true, false, false);
125
+ // expect(projection.nearestElement).equals(nodes[14]);
126
+
127
+ // currentPosition = new WGS84(43.6093691, 3.8842057, null, new Level(2));
128
+ // projection = mapMatching.getProjection(currentPosition, true, false, false);
129
+ // expect(projection.nearestElement).equals(nodes[11]);
130
+
131
+ });
132
+
128
133
  });