@wemap/geo 4.0.13 → 5.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 +18 -11
- package/package.json +4 -4
- package/src/Utils.spec.js +38 -0
- package/src/graph/{Edge.js → GraphEdge.js} +33 -94
- package/src/graph/GraphEdge.spec.js +91 -0
- package/src/graph/{Node.js → GraphNode.js} +29 -67
- package/src/graph/GraphNode.spec.js +203 -0
- package/src/graph/{Projection.js → GraphProjection.js} +4 -4
- package/src/graph/GraphUtils.js +17 -0
- package/src/graph/MapMatching.js +7 -5
- package/src/graph/MapMatching.spec.js +26 -26
- package/src/graph/Network.js +85 -48
- package/src/graph/Network.spec.js +66 -15
- package/src/router/GraphItinerary.js +70 -0
- package/src/router/GraphItinerary.spec.js +18 -0
- package/src/{graph → router}/GraphRouter.js +52 -52
- package/src/{graph → router}/GraphRouter.spec.js +54 -96
- package/src/router/GraphRouterOptions.js +19 -0
- package/src/{graph → router}/NoRouteFoundError.js +1 -1
- package/tests/CommonTest.js +6 -6
- package/src/graph/Edge.spec.js +0 -131
- package/src/graph/Itinerary.js +0 -529
- package/src/graph/Itinerary.spec.js +0 -811
- package/src/graph/ItineraryInfo.js +0 -29
- package/src/graph/LevelChange.js +0 -43
- package/src/graph/Node.spec.js +0 -227
- package/src/graph/Step.js +0 -99
- package/src/graph/StepsGeneration.js +0 -119
- package/src/graph/Utils.js +0 -7
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/* eslint-disable no-new */
|
|
2
|
+
import chai from 'chai';
|
|
3
|
+
|
|
4
|
+
import Logger from '@wemap/logger';
|
|
5
|
+
|
|
6
|
+
import Coordinates from '../coordinates/Coordinates.js';
|
|
7
|
+
import Level from '../coordinates/Level.js';
|
|
8
|
+
|
|
9
|
+
import GraphNode from './GraphNode.js';
|
|
10
|
+
import GraphEdge from './GraphEdge.js';
|
|
11
|
+
|
|
12
|
+
Logger.enable(false);
|
|
13
|
+
|
|
14
|
+
const { expect } = chai;
|
|
15
|
+
|
|
16
|
+
describe('GraphNode', () => {
|
|
17
|
+
|
|
18
|
+
it('creation', () => {
|
|
19
|
+
|
|
20
|
+
expect(() => new GraphNode()).throw(Error);
|
|
21
|
+
expect(() => new GraphNode({
|
|
22
|
+
lat: 45,
|
|
23
|
+
lng: 5
|
|
24
|
+
})).throw(Error);
|
|
25
|
+
expect(() => new GraphNode(new Coordinates(0, 0))).not.throw(Error);
|
|
26
|
+
expect(() => new GraphNode(new Coordinates(0, 0), 'foo')).not.throw(Error);
|
|
27
|
+
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
const pos1 = new Coordinates(45, 5);
|
|
32
|
+
const pos2 = new Coordinates(46, 5);
|
|
33
|
+
const node1 = new GraphNode(pos1);
|
|
34
|
+
const node2 = new GraphNode(pos2);
|
|
35
|
+
|
|
36
|
+
it('distanceTo', () => {
|
|
37
|
+
expect(node1.distanceTo(node2)).equals(pos1.distanceTo(pos2));
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('bearingTo', () => {
|
|
41
|
+
expect(node1.bearingTo(node2)).equals(pos1.bearingTo(pos2));
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('equalsTo', () => {
|
|
45
|
+
expect(node1.equalsTo(node2)).false;
|
|
46
|
+
expect(node1.equalsTo(node1)).true;
|
|
47
|
+
expect(new GraphNode(pos1).equalsTo(node1)).true;
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('clone', () => {
|
|
51
|
+
|
|
52
|
+
const node = new GraphNode(pos1);
|
|
53
|
+
|
|
54
|
+
const nodeBis = node.clone();
|
|
55
|
+
expect(nodeBis.coords).equals(node.coords);
|
|
56
|
+
nodeBis.edges.forEach((val, idx) => expect(val).equals(node.edges[idx]));
|
|
57
|
+
expect(nodeBis.builtFrom).equals(node.builtFrom);
|
|
58
|
+
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('toJson / fromJson', () => {
|
|
62
|
+
|
|
63
|
+
const node = new GraphNode(pos1);
|
|
64
|
+
|
|
65
|
+
const jsonNode = node.toJson();
|
|
66
|
+
expect(jsonNode).deep.equals([45, 5]);
|
|
67
|
+
|
|
68
|
+
const nodeBis = GraphNode.fromJson(jsonNode);
|
|
69
|
+
expect(nodeBis.coords.equalsTo(node.coords)).true;
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// eslint-disable-next-line max-statements
|
|
73
|
+
it('generateNodesLevels', () => {
|
|
74
|
+
|
|
75
|
+
const cleanNodes = count => [...Array(count)].map((_ignore, idx) => new GraphNode(new Coordinates(0, 0), 'n' + idx));
|
|
76
|
+
const cleanNodesWithAdjEdges = (...levelEdges) => {
|
|
77
|
+
const _nodes = cleanNodes(levelEdges.length + 1);
|
|
78
|
+
levelEdges.forEach((level, idx) => new GraphEdge(_nodes[0], _nodes[idx + 1], level));
|
|
79
|
+
return _nodes;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
let nodes;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Simple case with only adjacent nodes
|
|
86
|
+
*/
|
|
87
|
+
|
|
88
|
+
nodes = cleanNodesWithAdjEdges(new Level(1), new Level(0));
|
|
89
|
+
expect(GraphNode.generateNodesLevels(nodes)).false;
|
|
90
|
+
expect(nodes[0].coords.level).is.null;
|
|
91
|
+
|
|
92
|
+
nodes = cleanNodesWithAdjEdges(new Level(1), new Level(1));
|
|
93
|
+
expect(GraphNode.generateNodesLevels(nodes)).true;
|
|
94
|
+
expect(Level.equalsTo(nodes[0].coords.level, new Level(1))).true;
|
|
95
|
+
|
|
96
|
+
nodes = cleanNodesWithAdjEdges(new Level(1), new Level(1, 2));
|
|
97
|
+
expect(GraphNode.generateNodesLevels(nodes)).true;
|
|
98
|
+
expect(Level.equalsTo(nodes[0].coords.level, new Level(1))).true;
|
|
99
|
+
|
|
100
|
+
nodes = cleanNodesWithAdjEdges(new Level(0, 1), new Level(1, 2));
|
|
101
|
+
expect(GraphNode.generateNodesLevels(nodes)).true;
|
|
102
|
+
expect(Level.equalsTo(nodes[0].coords.level, new Level(1))).true;
|
|
103
|
+
|
|
104
|
+
nodes = cleanNodesWithAdjEdges(new Level(0, 1));
|
|
105
|
+
expect(GraphNode.generateNodesLevels(nodes)).true;
|
|
106
|
+
expect(Level.equalsTo(nodes[0].coords.level, new Level(0, 1))).true;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* More complex cases with no adjacent edges
|
|
110
|
+
*/
|
|
111
|
+
|
|
112
|
+
nodes = cleanNodes(4);
|
|
113
|
+
new GraphEdge(nodes[0], nodes[1], new Level(1), 'e0');
|
|
114
|
+
new GraphEdge(nodes[1], nodes[2], new Level(1, 2), 'e1');
|
|
115
|
+
new GraphEdge(nodes[2], nodes[3], new Level(1, 2), 'e2');
|
|
116
|
+
expect(GraphNode.generateNodesLevels(nodes)).true;
|
|
117
|
+
expect(Level.equalsTo(nodes[0].coords.level, new Level(1))).true;
|
|
118
|
+
expect(Level.equalsTo(nodes[1].coords.level, new Level(1))).true;
|
|
119
|
+
expect(Level.equalsTo(nodes[2].coords.level, new Level(1, 2))).true;
|
|
120
|
+
expect(Level.equalsTo(nodes[3].coords.level, new Level(2))).true;
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
nodes = cleanNodes(5);
|
|
124
|
+
new GraphEdge(nodes[0], nodes[1], new Level(1), 'e0');
|
|
125
|
+
new GraphEdge(nodes[1], nodes[2], new Level(1, 2), 'e1');
|
|
126
|
+
new GraphEdge(nodes[2], nodes[3], new Level(1, 2), 'e2');
|
|
127
|
+
new GraphEdge(nodes[2], nodes[4], null, 'e3');
|
|
128
|
+
expect(GraphNode.generateNodesLevels(nodes)).true;
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
nodes = cleanNodes(4);
|
|
132
|
+
new GraphEdge(nodes[0], nodes[1], new Level(1), 'e0');
|
|
133
|
+
new GraphEdge(nodes[1], nodes[2], new Level(0, 1), 'e1');
|
|
134
|
+
new GraphEdge(nodes[2], nodes[3], new Level(0, 1), 'e2');
|
|
135
|
+
expect(GraphNode.generateNodesLevels(nodes)).true;
|
|
136
|
+
expect(Level.equalsTo(nodes[0].coords.level, new Level(1))).true;
|
|
137
|
+
expect(Level.equalsTo(nodes[1].coords.level, new Level(1))).true;
|
|
138
|
+
expect(Level.equalsTo(nodes[2].coords.level, new Level(0, 1))).true;
|
|
139
|
+
expect(Level.equalsTo(nodes[3].coords.level, new Level(0))).true;
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
nodes = cleanNodes(4);
|
|
143
|
+
new GraphEdge(nodes[0], nodes[1], new Level(1), 'e0');
|
|
144
|
+
new GraphEdge(nodes[1], nodes[2], new Level(1, 2), 'e1');
|
|
145
|
+
new GraphEdge(nodes[2], nodes[3], new Level(1, 2), 'e2');
|
|
146
|
+
new GraphEdge(nodes[1], nodes[3], new Level(1), 'e3');
|
|
147
|
+
expect(GraphNode.generateNodesLevels(nodes)).true;
|
|
148
|
+
expect(Level.equalsTo(nodes[0].coords.level, new Level(1))).true;
|
|
149
|
+
expect(Level.equalsTo(nodes[1].coords.level, new Level(1))).true;
|
|
150
|
+
expect(Level.equalsTo(nodes[2].coords.level, new Level(2))).true;
|
|
151
|
+
expect(Level.equalsTo(nodes[3].coords.level, new Level(1))).true;
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
nodes = cleanNodes(4);
|
|
155
|
+
new GraphEdge(nodes[0], nodes[1], new Level(1), 'e0');
|
|
156
|
+
new GraphEdge(nodes[1], nodes[2], new Level(0, 1), 'e1');
|
|
157
|
+
new GraphEdge(nodes[2], nodes[3], new Level(0, 1), 'e2');
|
|
158
|
+
new GraphEdge(nodes[1], nodes[3], new Level(1), 'e3');
|
|
159
|
+
expect(GraphNode.generateNodesLevels(nodes)).true;
|
|
160
|
+
expect(Level.equalsTo(nodes[0].coords.level, new Level(1))).true;
|
|
161
|
+
expect(Level.equalsTo(nodes[1].coords.level, new Level(1))).true;
|
|
162
|
+
expect(Level.equalsTo(nodes[2].coords.level, new Level(0))).true;
|
|
163
|
+
expect(Level.equalsTo(nodes[3].coords.level, new Level(1))).true;
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
nodes = cleanNodes(6);
|
|
167
|
+
new GraphEdge(nodes[0], nodes[1], new Level(1), 'e0');
|
|
168
|
+
new GraphEdge(nodes[1], nodes[2], new Level(1, 2), 'e1');
|
|
169
|
+
new GraphEdge(nodes[2], nodes[3], new Level(1, 2), 'e2');
|
|
170
|
+
new GraphEdge(nodes[2], nodes[4], new Level(1, 2), 'e3');
|
|
171
|
+
new GraphEdge(nodes[4], nodes[5], new Level(2), 'e4');
|
|
172
|
+
expect(GraphNode.generateNodesLevels(nodes)).false;
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
nodes = cleanNodes(5);
|
|
176
|
+
new GraphEdge(nodes[0], nodes[1], new Level(1, 2));
|
|
177
|
+
new GraphEdge(nodes[1], nodes[2], new Level(1, 2));
|
|
178
|
+
new GraphEdge(nodes[2], nodes[3], new Level(1, 2));
|
|
179
|
+
new GraphEdge(nodes[3], nodes[4], new Level(1));
|
|
180
|
+
expect(GraphNode.generateNodesLevels(nodes)).true;
|
|
181
|
+
expect(Level.equalsTo(nodes[0].coords.level, new Level(2))).true;
|
|
182
|
+
expect(Level.equalsTo(nodes[1].coords.level, new Level(1, 2))).true;
|
|
183
|
+
expect(Level.equalsTo(nodes[2].coords.level, new Level(1, 2))).true;
|
|
184
|
+
expect(Level.equalsTo(nodes[3].coords.level, new Level(1))).true;
|
|
185
|
+
expect(Level.equalsTo(nodes[4].coords.level, new Level(1))).true;
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
nodes = cleanNodes(6);
|
|
189
|
+
new GraphEdge(nodes[0], nodes[1], new Level(0), 'e0');
|
|
190
|
+
new GraphEdge(nodes[1], nodes[2], new Level(0, 1), 'e1');
|
|
191
|
+
new GraphEdge(nodes[2], nodes[3], new Level(0, 1), 'e2');
|
|
192
|
+
new GraphEdge(nodes[3], nodes[4], new Level(0, 1), 'e3');
|
|
193
|
+
new GraphEdge(nodes[4], nodes[5], new Level(1), 'e4');
|
|
194
|
+
expect(GraphNode.generateNodesLevels(nodes)).true;
|
|
195
|
+
expect(Level.equalsTo(nodes[1].coords.level, new Level(0))).true;
|
|
196
|
+
expect(Level.equalsTo(nodes[1].coords.level, new Level(0))).true;
|
|
197
|
+
expect(Level.equalsTo(nodes[2].coords.level, new Level(0, 1))).true;
|
|
198
|
+
expect(Level.equalsTo(nodes[3].coords.level, new Level(0, 1))).true;
|
|
199
|
+
expect(Level.equalsTo(nodes[4].coords.level, new Level(1))).true;
|
|
200
|
+
expect(Level.equalsTo(nodes[5].coords.level, new Level(1))).true;
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import Coordinates from '../coordinates/Coordinates.js';
|
|
2
|
-
import Edge from './
|
|
3
|
-
import Node from './
|
|
2
|
+
import Edge from './GraphEdge.js';
|
|
3
|
+
import Node from './GraphNode.js';
|
|
4
4
|
|
|
5
|
-
class
|
|
5
|
+
class GraphProjection {
|
|
6
6
|
|
|
7
7
|
/** @type {Coordinates} */
|
|
8
8
|
origin;
|
|
@@ -18,4 +18,4 @@ class Projection {
|
|
|
18
18
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
export default
|
|
21
|
+
export default GraphProjection;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
|
|
2
|
+
import GraphEdge from './GraphEdge.js';
|
|
3
|
+
import GraphNode from './GraphNode.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @template T
|
|
7
|
+
* @param {GraphEdge<T>[]} edges
|
|
8
|
+
* @param {GraphNode<T>} node1
|
|
9
|
+
* @param {GraphNode<T>} node2
|
|
10
|
+
* @returns {?GraphEdge<T>}
|
|
11
|
+
*/
|
|
12
|
+
export function getEdgeByNodes(edges, node1, node2) {
|
|
13
|
+
return edges.find(edge =>
|
|
14
|
+
node1 === edge.node1 && node2 === edge.node2
|
|
15
|
+
|| node2 === edge.node1 && node1 === edge.node2
|
|
16
|
+
);
|
|
17
|
+
}
|
package/src/graph/MapMatching.js
CHANGED
|
@@ -4,10 +4,11 @@ import { diffAngleLines } from '@wemap/maths';
|
|
|
4
4
|
|
|
5
5
|
import Constants from '../Constants.js';
|
|
6
6
|
import Coordinates from '../coordinates/Coordinates.js';
|
|
7
|
+
import UserPosition from '../coordinates/UserPosition.js';
|
|
7
8
|
import Level from '../coordinates/Level.js';
|
|
8
9
|
|
|
9
10
|
import Network from './Network.js';
|
|
10
|
-
import
|
|
11
|
+
import GraphProjection from './GraphProjection.js';
|
|
11
12
|
|
|
12
13
|
class MapMatching {
|
|
13
14
|
|
|
@@ -146,7 +147,7 @@ class MapMatching {
|
|
|
146
147
|
* @param {boolean} useBearing
|
|
147
148
|
* @param {boolean} useMultiLevelSegments
|
|
148
149
|
* @param {function} acceptEdgeFn
|
|
149
|
-
* @returns {
|
|
150
|
+
* @returns {GraphProjection}
|
|
150
151
|
*/
|
|
151
152
|
getProjection(location, useDistance = false, useBearing = false,
|
|
152
153
|
useMultiLevelSegments = true, acceptEdgeFn = () => true) {
|
|
@@ -163,7 +164,7 @@ class MapMatching {
|
|
|
163
164
|
return null;
|
|
164
165
|
}
|
|
165
166
|
|
|
166
|
-
const projection = new
|
|
167
|
+
const projection = new GraphProjection();
|
|
167
168
|
projection.origin = location;
|
|
168
169
|
projection.distanceFromNearestElement = Number.MAX_VALUE;
|
|
169
170
|
projection.projection = location.clone();
|
|
@@ -231,8 +232,9 @@ class MapMatching {
|
|
|
231
232
|
return null;
|
|
232
233
|
}
|
|
233
234
|
|
|
234
|
-
projection.projection
|
|
235
|
-
|
|
235
|
+
if (projection.projection instanceof UserPosition) {
|
|
236
|
+
projection.projection.accuracy += projection.distanceFromNearestElement;
|
|
237
|
+
}
|
|
236
238
|
return projection;
|
|
237
239
|
}
|
|
238
240
|
|
|
@@ -8,10 +8,10 @@ import Coordinates from '../coordinates/Coordinates.js';
|
|
|
8
8
|
import Level from '../coordinates/Level.js';
|
|
9
9
|
import UserPosition from '../coordinates/UserPosition.js';
|
|
10
10
|
|
|
11
|
-
import
|
|
11
|
+
import GraphEdge from './GraphEdge.js';
|
|
12
|
+
import GraphNode from './GraphNode.js';
|
|
12
13
|
import MapMatching from './MapMatching.js';
|
|
13
14
|
import Network from './Network.js';
|
|
14
|
-
import Node from './Node.js';
|
|
15
15
|
|
|
16
16
|
import { network } from '../../tests/CommonTest.js';
|
|
17
17
|
|
|
@@ -20,14 +20,14 @@ const { expect } = chai;
|
|
|
20
20
|
describe('MapMatching', () => {
|
|
21
21
|
|
|
22
22
|
const nodes = [
|
|
23
|
-
new
|
|
24
|
-
new
|
|
25
|
-
new
|
|
23
|
+
new GraphNode(new Coordinates(43.6091194, 3.884099), 'p0'),
|
|
24
|
+
new GraphNode(new Coordinates(43.6093629, 3.8842777), 'p1'),
|
|
25
|
+
new GraphNode(new Coordinates(43.6092785, 3.8845052), 'p2')
|
|
26
26
|
];
|
|
27
27
|
|
|
28
28
|
const edges = [
|
|
29
|
-
new
|
|
30
|
-
new
|
|
29
|
+
new GraphEdge(nodes[0], nodes[1], null, 'e0'),
|
|
30
|
+
new GraphEdge(nodes[1], nodes[2], null, 'e1')
|
|
31
31
|
];
|
|
32
32
|
|
|
33
33
|
let mapMatching;
|
|
@@ -70,17 +70,17 @@ describe('MapMatching', () => {
|
|
|
70
70
|
|
|
71
71
|
result = mapMatching.getProjection(location);
|
|
72
72
|
expect(result).is.not.null;
|
|
73
|
-
expect(result.nearestElement).instanceOf(
|
|
74
|
-
expect(result.nearestElement.
|
|
73
|
+
expect(result.nearestElement).instanceOf(GraphEdge);
|
|
74
|
+
expect(result.nearestElement.builtFrom).equal('e0');
|
|
75
75
|
expect(result.projection.distanceTo(expected)).to.below(Constants.EPS_MM);
|
|
76
76
|
expect(Level.equalsTo(expected.level, result.projection.level)).true;
|
|
77
77
|
|
|
78
78
|
const owNodes = [
|
|
79
|
-
new
|
|
80
|
-
new
|
|
79
|
+
new GraphNode(new Coordinates(43.6091194, 3.884099, 5)),
|
|
80
|
+
new GraphNode(new Coordinates(43.6093629, 3.8842777, 10))
|
|
81
81
|
];
|
|
82
82
|
const owNetwork = new Network(owNodes, [
|
|
83
|
-
new
|
|
83
|
+
new GraphEdge(owNodes[0], owNodes[1])
|
|
84
84
|
]);
|
|
85
85
|
const owMapMatching = new MapMatching(owNetwork);
|
|
86
86
|
result = owMapMatching.getProjection(new Coordinates(43.6092086, 3.8842598, 10));
|
|
@@ -95,8 +95,8 @@ describe('MapMatching', () => {
|
|
|
95
95
|
location.bearing = deg2rad(101.9);
|
|
96
96
|
result = mapMatching.getProjection(location, true, true);
|
|
97
97
|
expect(result).is.not.null;
|
|
98
|
-
expect(result.nearestElement).instanceOf(
|
|
99
|
-
expect(result.nearestElement.
|
|
98
|
+
expect(result.nearestElement).instanceOf(GraphEdge);
|
|
99
|
+
expect(result.nearestElement.builtFrom).equal('e1');
|
|
100
100
|
expect(result.projection.distanceTo(expected)).to.below(Constants.EPS_MM);
|
|
101
101
|
expect(Level.equalsTo(expected.level, result.projection.level)).true;
|
|
102
102
|
});
|
|
@@ -107,24 +107,24 @@ describe('MapMatching', () => {
|
|
|
107
107
|
|
|
108
108
|
pointToTest = nodes[0].coords.destinationPoint(0.0001, nodes[0].bearingTo(nodes[1]));
|
|
109
109
|
result = mapMatching.getProjection(pointToTest);
|
|
110
|
-
expect(result.nearestElement).instanceOf(
|
|
111
|
-
expect(result.nearestElement.
|
|
110
|
+
expect(result.nearestElement).instanceOf(GraphNode);
|
|
111
|
+
expect(result.nearestElement.builtFrom).equal('p0');
|
|
112
112
|
|
|
113
113
|
pointToTest = nodes[1].coords.destinationPoint(0.0001, nodes[1].bearingTo(nodes[0]));
|
|
114
114
|
result = mapMatching.getProjection(pointToTest);
|
|
115
|
-
expect(result.nearestElement).instanceOf(
|
|
116
|
-
expect(result.nearestElement.
|
|
115
|
+
expect(result.nearestElement).instanceOf(GraphNode);
|
|
116
|
+
expect(result.nearestElement.builtFrom).equal('p1');
|
|
117
117
|
|
|
118
118
|
pointToTest = nodes[0].coords.destinationPoint(0.005, nodes[0].bearingTo(nodes[1]));
|
|
119
119
|
result = mapMatching.getProjection(pointToTest);
|
|
120
|
-
expect(result.nearestElement).instanceOf(
|
|
121
|
-
expect(result.nearestElement.
|
|
120
|
+
expect(result.nearestElement).instanceOf(GraphEdge);
|
|
121
|
+
expect(result.nearestElement.builtFrom).equal('e0');
|
|
122
122
|
expect(result.projection.distanceTo(pointToTest)).to.below(Constants.EPS_MM);
|
|
123
123
|
|
|
124
124
|
pointToTest = nodes[1].coords.destinationPoint(0.005, nodes[1].bearingTo(nodes[0]));
|
|
125
125
|
result = mapMatching.getProjection(pointToTest);
|
|
126
|
-
expect(result.nearestElement).instanceOf(
|
|
127
|
-
expect(result.nearestElement.
|
|
126
|
+
expect(result.nearestElement).instanceOf(GraphEdge);
|
|
127
|
+
expect(result.nearestElement.builtFrom).equal('e0');
|
|
128
128
|
expect(result.projection.distanceTo(pointToTest)).to.below(Constants.EPS_MM);
|
|
129
129
|
|
|
130
130
|
});
|
|
@@ -243,12 +243,12 @@ describe('MapMatching - multilevels', () => {
|
|
|
243
243
|
currentPosition = new Coordinates(43.6093381, 3.8841926, null, new Level(1));
|
|
244
244
|
projection = mapMatching.getProjection(currentPosition, true, false, false);
|
|
245
245
|
expect(projection).is.not.null;
|
|
246
|
-
expect(projection.nearestElement.
|
|
246
|
+
expect(projection.nearestElement.builtFrom).equals('p14');
|
|
247
247
|
|
|
248
248
|
currentPosition = new Coordinates(43.6093381, 3.8841926, null, new Level(2));
|
|
249
249
|
projection = mapMatching.getProjection(currentPosition, true, false, false);
|
|
250
250
|
expect(projection).is.not.null;
|
|
251
|
-
expect(projection.nearestElement.
|
|
251
|
+
expect(projection.nearestElement.builtFrom).equals('p11');
|
|
252
252
|
|
|
253
253
|
|
|
254
254
|
// On Segments
|
|
@@ -260,12 +260,12 @@ describe('MapMatching - multilevels', () => {
|
|
|
260
260
|
currentPosition = new Coordinates(43.6093258, 3.8842272, null, new Level(1));
|
|
261
261
|
projection = mapMatching.getProjection(currentPosition, true, false, false);
|
|
262
262
|
expect(projection).is.not.null;
|
|
263
|
-
expect(projection.nearestElement.
|
|
263
|
+
expect(projection.nearestElement.builtFrom).equals('e14');
|
|
264
264
|
|
|
265
265
|
currentPosition = new Coordinates(43.6093258, 3.8842272, null, new Level(2));
|
|
266
266
|
projection = mapMatching.getProjection(currentPosition, true, false, false);
|
|
267
267
|
expect(projection).is.not.null;
|
|
268
|
-
expect(projection.nearestElement.
|
|
268
|
+
expect(projection.nearestElement.builtFrom).equals('e10');
|
|
269
269
|
|
|
270
270
|
});
|
|
271
271
|
|
package/src/graph/Network.js
CHANGED
|
@@ -1,23 +1,28 @@
|
|
|
1
1
|
import BoundingBox from '../coordinates/BoundingBox.js';
|
|
2
2
|
import Coordinates from '../coordinates/Coordinates.js';
|
|
3
|
+
import Level from '../coordinates/Level.js';
|
|
3
4
|
|
|
4
|
-
import
|
|
5
|
-
import
|
|
5
|
+
import GraphEdge from './GraphEdge.js';
|
|
6
|
+
import GraphNode from './GraphNode.js';
|
|
7
|
+
import { getEdgeByNodes } from './GraphUtils.js';
|
|
6
8
|
|
|
7
9
|
/**
|
|
10
|
+
* @template T
|
|
11
|
+
*
|
|
8
12
|
* A typical network with nodes (Node) and edges (Edge)
|
|
9
13
|
*/
|
|
10
14
|
class Network {
|
|
11
15
|
|
|
12
|
-
/** @type {
|
|
16
|
+
/** @type {GraphNode<T>[]} */
|
|
13
17
|
nodes;
|
|
14
18
|
|
|
15
|
-
/** @type {
|
|
19
|
+
/** @type {GraphEdge<T>[]} */
|
|
16
20
|
edges;
|
|
17
21
|
|
|
18
22
|
/**
|
|
19
|
-
* @
|
|
20
|
-
* @param {
|
|
23
|
+
* @template T
|
|
24
|
+
* @param {GraphNode<T>[]} nodes
|
|
25
|
+
* @param {GraphEdge<T>[]} edges
|
|
21
26
|
*/
|
|
22
27
|
constructor(nodes, edges) {
|
|
23
28
|
this.nodes = Array.isArray(nodes) ? nodes : [];
|
|
@@ -25,50 +30,24 @@ class Network {
|
|
|
25
30
|
}
|
|
26
31
|
|
|
27
32
|
/**
|
|
33
|
+
* @template T
|
|
28
34
|
* @param {Coordinates} coords
|
|
29
|
-
* @returns {?
|
|
35
|
+
* @returns {?GraphNode<T>}
|
|
30
36
|
*/
|
|
31
37
|
getNodeByCoords(coords) {
|
|
32
38
|
return this.nodes.find(node => node.coords.equalsTo(coords));
|
|
33
39
|
}
|
|
34
40
|
|
|
35
41
|
/**
|
|
36
|
-
* @
|
|
37
|
-
* @
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
return this.nodes.find(node => node.name === name);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* @param {Node} node1
|
|
45
|
-
* @param {Node} node2
|
|
46
|
-
* @returns {?Edge}
|
|
42
|
+
* @template T
|
|
43
|
+
* @param {GraphNode<T>} node1
|
|
44
|
+
* @param {GraphNode<T>} node2
|
|
45
|
+
* @returns {?GraphEdge<T>}
|
|
47
46
|
*/
|
|
48
47
|
getEdgeByNodes(node1, node2) {
|
|
49
|
-
return
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* @param {string} name
|
|
54
|
-
* @returns {?Edge}
|
|
55
|
-
*/
|
|
56
|
-
getEdgeByName(name) {
|
|
57
|
-
return this.edges.find(edge => edge.name === name);
|
|
48
|
+
return getEdgeByNodes(this.edges, node1, node2);
|
|
58
49
|
}
|
|
59
50
|
|
|
60
|
-
/**
|
|
61
|
-
* @param {Edge[]} edges
|
|
62
|
-
* @param {Node} node1
|
|
63
|
-
* @param {Node} node2
|
|
64
|
-
* @returns {?Edge}
|
|
65
|
-
*/
|
|
66
|
-
static getEdgeByNodes(edges, node1, node2) {
|
|
67
|
-
return edges.find(edge =>
|
|
68
|
-
node1 === edge.node1 && node2 === edge.node2
|
|
69
|
-
|| node2 === edge.node1 && node1 === edge.node2
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
51
|
|
|
73
52
|
/**
|
|
74
53
|
* @param {?number} extendedMeasure
|
|
@@ -93,12 +72,12 @@ class Network {
|
|
|
93
72
|
|
|
94
73
|
let nodeToStringFn = _nodeToStringFn;
|
|
95
74
|
if (!nodeToStringFn) {
|
|
96
|
-
nodeToStringFn = node => `${node.
|
|
75
|
+
nodeToStringFn = node => `${node.builtFrom}`;
|
|
97
76
|
}
|
|
98
77
|
|
|
99
78
|
let edgeToStringFn = _edgeToStringFn;
|
|
100
79
|
if (!_edgeToStringFn) {
|
|
101
|
-
edgeToStringFn = edge => `${edge.
|
|
80
|
+
edgeToStringFn = edge => `${edge.builtFrom}`;
|
|
102
81
|
}
|
|
103
82
|
|
|
104
83
|
let output
|
|
@@ -131,9 +110,14 @@ class Network {
|
|
|
131
110
|
this.nodes.indexOf(edge.node1),
|
|
132
111
|
this.nodes.indexOf(edge.node2)
|
|
133
112
|
];
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
113
|
+
if (edge.level !== null) {
|
|
114
|
+
output.push(edge.level.toString());
|
|
115
|
+
}
|
|
116
|
+
if (edge.isOneway) {
|
|
117
|
+
if (edge.level === null) {
|
|
118
|
+
output.push(null);
|
|
119
|
+
}
|
|
120
|
+
output.push(true);
|
|
137
121
|
}
|
|
138
122
|
return output;
|
|
139
123
|
})
|
|
@@ -148,21 +132,74 @@ class Network {
|
|
|
148
132
|
|
|
149
133
|
const network = new Network();
|
|
150
134
|
|
|
151
|
-
network.nodes = json.nodes.map(
|
|
135
|
+
network.nodes = json.nodes.map(GraphNode.fromJson);
|
|
152
136
|
|
|
153
137
|
network.edges = json.edges.map(jsonEdge => {
|
|
154
|
-
const edge = new
|
|
138
|
+
const edge = new GraphEdge(
|
|
155
139
|
network.nodes[jsonEdge[0]],
|
|
156
140
|
network.nodes[jsonEdge[1]]
|
|
157
141
|
);
|
|
158
|
-
if (jsonEdge.length > 2) {
|
|
159
|
-
edge.
|
|
142
|
+
if (jsonEdge.length > 2 && jsonEdge[2] !== null) {
|
|
143
|
+
edge.level = Level.fromString(jsonEdge[2]);
|
|
144
|
+
}
|
|
145
|
+
if (jsonEdge.length > 3 && jsonEdge[3]) {
|
|
146
|
+
edge.isOneway = true;
|
|
160
147
|
}
|
|
161
148
|
return edge;
|
|
162
149
|
});
|
|
163
150
|
|
|
164
151
|
return network;
|
|
165
152
|
}
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Convert Array of Coordinates array to a network
|
|
157
|
+
* @param {Coordinates[][]} segments
|
|
158
|
+
* @returns {Network}
|
|
159
|
+
*/
|
|
160
|
+
static fromCoordinates(segments) {
|
|
161
|
+
|
|
162
|
+
const network = new Network();
|
|
163
|
+
|
|
164
|
+
const getOrCreateNode = coords =>
|
|
165
|
+
network.nodes.find(_coords => _coords.equalsTo(coords)) || new GraphNode(coords);
|
|
166
|
+
|
|
167
|
+
const createEdgeFromCoords = (coords1, coords2) =>
|
|
168
|
+
new GraphEdge(coords1, coords2, Level.union(coords1.level, coords2.level));
|
|
169
|
+
|
|
170
|
+
for (const segment of segments) {
|
|
171
|
+
|
|
172
|
+
let previousNode = null;
|
|
173
|
+
for (const coords of segment) {
|
|
174
|
+
const currentNode = getOrCreateNode(coords);
|
|
175
|
+
|
|
176
|
+
if (previousNode) {
|
|
177
|
+
const edge = createEdgeFromCoords(currentNode, previousNode);
|
|
178
|
+
network.edges.push(edge);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
network.nodes.push(currentNode);
|
|
182
|
+
previousNode = currentNode;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return network;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Create edges From MultiLevel Itinerary for a given level
|
|
191
|
+
* @param {Level} targetLevel level for selection.
|
|
192
|
+
* @param {Boolean} useMultiLevelEdges use segments which intersect both levels (stairs, elevators...)
|
|
193
|
+
* @returns {GraphEdge[]} Ordered edges
|
|
194
|
+
*/
|
|
195
|
+
getEdgesAtLevel(targetLevel, useMultiLevelEdges = true) {
|
|
196
|
+
return this.edges.filter(
|
|
197
|
+
({ level }) => useMultiLevelEdges
|
|
198
|
+
? Level.intersect(targetLevel, level) !== null
|
|
199
|
+
: Level.contains(targetLevel, level)
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
166
203
|
}
|
|
167
204
|
|
|
168
205
|
export default Network;
|