@wemap/geo 4.0.14 → 5.0.3

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.
@@ -3,6 +3,10 @@ import chai from 'chai';
3
3
  import Constants from '../Constants.js';
4
4
  import Coordinates from '../coordinates/Coordinates.js';
5
5
  import Network from './Network.js';
6
+ import GraphNode from './GraphNode.js';
7
+ import GraphEdge from './GraphEdge.js';
8
+
9
+ import Level from '../coordinates/Level.js';
6
10
 
7
11
  import {
8
12
  nodes, edges, network
@@ -26,7 +30,7 @@ describe('Network', () => {
26
30
 
27
31
  let node = network.getNodeByCoords(nodes[2].coords.clone());
28
32
  expect(node).not.null;
29
- expect(node.name).equals('p2');
33
+ expect(node.builtFrom).equals('p2');
30
34
 
31
35
  node = network.getNodeByCoords(new Coordinates(43.601888, 3.8841263));
32
36
  expect(node).undefined;
@@ -36,23 +40,12 @@ describe('Network', () => {
36
40
 
37
41
  let edge = network.getEdgeByNodes(nodes[1], nodes[2]);
38
42
  expect(edge).not.null;
39
- expect(edge.name).equals('e0');
43
+ expect(edge.builtFrom).equals('e0');
40
44
 
41
45
  edge = network.getEdgeByNodes(nodes[0], nodes[2]);
42
46
  expect(edge).undefined;
43
47
  });
44
48
 
45
- it('getEdgeByName', () => {
46
-
47
- let edge = network.getEdgeByName('e1');
48
- expect(edge).not.null;
49
- expect(edge.name).equals('e1');
50
- expect(edge).equals(edges[1]);
51
-
52
- edge = network.getEdgeByName('abc');
53
- expect(edge).undefined;
54
- });
55
-
56
49
  it('getBoundingBox', () => {
57
50
 
58
51
  let boundingBox = network.getBoundingBox();
@@ -85,11 +78,69 @@ describe('Network', () => {
85
78
  const networkBis = Network.fromCompressedJson(networkJson);
86
79
 
87
80
  networkBis.nodes.forEach((node, i) => {
88
- expect(node.equalsTo(network.nodes[i])).is.true;
81
+ expect(node.coords.equalsTo(network.nodes[i].coords)).is.true;
89
82
  });
90
83
 
91
84
  networkBis.edges.forEach((edge, i) => {
92
- expect(edge.equalsTo(network.edges[i])).is.true;
85
+ expect(edge.node1.coords.equalsTo(network.edges[i].node1.coords)).is.true;
86
+ expect(edge.node2.coords.equalsTo(network.edges[i].node2.coords)).is.true;
87
+ expect(edge.isOneway).equals(network.edges[i].isOneway);
93
88
  });
94
89
  });
90
+
91
+
92
+ it('getEdgesAtLevel', () => {
93
+
94
+ const _nodes = [
95
+ new GraphNode(new Coordinates(43.6091194, 3.884099, null, new Level(0)), 'p0'),
96
+ new GraphNode(new Coordinates(43.6093629, 3.8842777, null, new Level(0)), 'p1'),
97
+ new GraphNode(new Coordinates(43.6094654, 3.8842167, null, new Level(0, 1)), 'p2'),
98
+ new GraphNode(new Coordinates(43.6094902, 3.8843416, null, new Level(1)), 'p3'),
99
+ new GraphNode(new Coordinates(43.6095463, 3.8843837, null, new Level(1)), 'p4'),
100
+ new GraphNode(new Coordinates(43.6095552, 3.8844971, null, new Level(2)), 'p5'),
101
+ new GraphNode(new Coordinates(43.6095908, 3.8844662, null, new Level(1)), 'p6'),
102
+ new GraphNode(new Coordinates(43.6096412, 3.8844706, null, new Level(1)), 'p7')
103
+ ];
104
+
105
+ const _edges = [
106
+ new GraphEdge(_nodes[0], _nodes[1], new Level(0), 'e0'),
107
+ new GraphEdge(_nodes[1], _nodes[2], new Level(0), 'e1'),
108
+ new GraphEdge(_nodes[2], _nodes[3], new Level(1), 'e2'),
109
+ new GraphEdge(_nodes[3], _nodes[4], new Level(1), 'e3'),
110
+ new GraphEdge(_nodes[4], _nodes[5], new Level(1, 2), 'e4'),
111
+ new GraphEdge(_nodes[5], _nodes[6], new Level(1, 2), 'e5'),
112
+ new GraphEdge(_nodes[6], _nodes[7], new Level(1), 'e6')
113
+ ];
114
+
115
+ const _network = new Network(_nodes, _edges);
116
+
117
+ const edgesAtLevel0 = _network.getEdgesAtLevel(new Level(0), false);
118
+ expect(edgesAtLevel0.length).equals(2);
119
+ expect(edgesAtLevel0[0].builtFrom).equals('e0');
120
+ expect(edgesAtLevel0[1].builtFrom).equals('e1');
121
+
122
+ const segmentsAtLevel1 = _network.getEdgesAtLevel(new Level(1), false);
123
+ expect(segmentsAtLevel1.length).equals(3);
124
+ expect(segmentsAtLevel1[0].builtFrom).equals('e2');
125
+ expect(segmentsAtLevel1[1].builtFrom).equals('e3');
126
+ expect(segmentsAtLevel1[2].builtFrom).equals('e6');
127
+
128
+ const segmentsAtLevel2 = _network.getEdgesAtLevel(new Level(2), false);
129
+ expect(segmentsAtLevel2.length).equals(0);
130
+ const segmentsAtLevel2b = _network.getEdgesAtLevel(new Level(2), true);
131
+ expect(segmentsAtLevel2b.length).equals(2);
132
+
133
+ const edgesAtLevel01 = _network.getEdgesAtLevel(new Level(0, 1), false);
134
+ expect(edgesAtLevel01.length).equals(5);
135
+ const edgesAtLevel01b = _network.getEdgesAtLevel(new Level(0, 1), true);
136
+ expect(edgesAtLevel01b.length).equals(7);
137
+
138
+ const edgesAtLevel12 = _network.getEdgesAtLevel(new Level(1, 2), false);
139
+ expect(edgesAtLevel12.length).equals(5);
140
+
141
+ const edgesAtLevel02 = _network.getEdgesAtLevel(new Level(0, 2), false);
142
+ expect(edgesAtLevel02.length).equals(7);
143
+
144
+ });
145
+
95
146
  });
@@ -0,0 +1,70 @@
1
+ import Coordinates from '../coordinates/Coordinates.js';
2
+ import GraphNode from '../graph/GraphNode.js';
3
+ import GraphEdge from '../graph/GraphEdge.js';
4
+ import { getEdgeByNodes } from '../graph/GraphUtils.js';
5
+
6
+ /**
7
+ * @template T
8
+ */
9
+ class GraphItinerary {
10
+
11
+ /** @type {Coordinates} */
12
+ start;
13
+
14
+ /** @type {Coordinates} */
15
+ end;
16
+
17
+ /** @type {GraphNode<T>[]} */
18
+ nodes;
19
+
20
+ /** @type {GraphEdge<T>[]} */
21
+ edges;
22
+
23
+ /** @type {number[]} */
24
+ edgesWeights;
25
+
26
+
27
+ /**
28
+ * @template T
29
+ * @param {GraphNode<T>[]} networkNodes
30
+ * @param {number[]} edgesWeights
31
+ * @returns {GraphItinerary<T>}
32
+ */
33
+ static fromNetworkNodes(networkNodes, edgesWeights) {
34
+ const itinerary = new GraphItinerary();
35
+ itinerary.edgesWeights = edgesWeights;
36
+
37
+ itinerary.nodes = networkNodes.map(node => {
38
+ const newNode = node.clone();
39
+ // Remove node edges, they will be added later.
40
+ newNode.edges = [];
41
+ return newNode;
42
+ });
43
+
44
+ itinerary.edges = [];
45
+ networkNodes.forEach((node, idx, arr) => {
46
+ if (idx === 0) {
47
+ return;
48
+ }
49
+
50
+ // Retrieve network edge
51
+ const prevNode = arr[idx - 1];
52
+ const edge = getEdgeByNodes(prevNode.edges, prevNode, node);
53
+
54
+ // Create itinerary edge
55
+ const newEdge = new GraphEdge(
56
+ itinerary.nodes[idx - 1],
57
+ itinerary.nodes[idx],
58
+ edge.level,
59
+ edge.builtFrom
60
+ );
61
+ newEdge.isOneway = edge.isOneway;
62
+ itinerary.edges.push(newEdge);
63
+ });
64
+
65
+ return itinerary;
66
+
67
+ }
68
+ }
69
+
70
+ export default GraphItinerary;
@@ -0,0 +1,18 @@
1
+ import chai from 'chai';
2
+
3
+ import GraphItinerary from './GraphItinerary.js';
4
+
5
+ const { expect } = chai;
6
+
7
+ /**
8
+ * @param {GraphItinerary} itinerary
9
+ */
10
+ export function isReadable(itinerary) {
11
+ for (let i = 0; i < itinerary.nodes.length; i++) {
12
+ const node = itinerary.nodes[i];
13
+ if (i !== itinerary.nodes.length - 1) {
14
+ expect(itinerary.edges[i].node1).equal(node);
15
+ expect(itinerary.edges[i].node2).equal(itinerary.nodes[i + 1]);
16
+ }
17
+ }
18
+ }
@@ -1,59 +1,55 @@
1
1
  import Coordinates from '../coordinates/Coordinates.js';
2
2
 
3
- import Edge from './Edge.js';
4
- import Itinerary from './Itinerary.js';
5
- import Network from './Network.js';
6
- import Node from './Node.js';
7
- import MapMatching from './MapMatching.js';
8
- import { getDurationFromLength } from './Utils.js';
9
- import NoRouteFoundError from './NoRouteFoundError.js';
3
+ import GraphEdge from '../graph/GraphEdge.js';
4
+ import Network from '../graph/Network.js';
5
+ import GraphNode from '../graph/GraphNode.js';
6
+ import MapMatching from '../graph/MapMatching.js';
10
7
 
11
- const DEFAULT_MM_DISTANCE = 50;
12
- const DEFAULT_OPTIONS = { useStairs: true };
8
+ import NoRouteFoundError from './NoRouteFoundError.js';
9
+ import GraphRouterOptions from './GraphRouterOptions.js';
10
+ import GraphItinerary from './GraphItinerary.js';
13
11
 
12
+ /**
13
+ * @template T
14
+ * @abstract
15
+ */
14
16
  class GraphRouter {
15
17
 
16
- /** @type {function} */
17
- static defaultWeightFn = edge => edge.isElevator ? 30 : getDurationFromLength(edge.length);
18
-
19
- /** @type {!Network} */
18
+ /** @type {!Network<T>} */
20
19
  _network;
21
20
 
22
21
  /**
23
- * @param {!Network} network
24
- * @param {number} mapMatchingMaxDistance
22
+ * @param {!Network<T>} network
25
23
  */
26
- constructor(network, mapMatchingMaxDistance = DEFAULT_MM_DISTANCE) {
24
+ constructor(network) {
27
25
  this._network = network;
28
26
  this._mapMatching = new MapMatching(network);
29
- this._mapMatching.maxDistance = mapMatchingMaxDistance;
30
27
  }
31
28
 
32
29
  /**
33
- *
34
- * @param {!Node|!Coordinates} start
35
- * @param {!Node|!Coordinates} end
36
- * @param {object} _options
37
- * @returns {Itinerary}
30
+ * @template T
31
+ * @param {!GraphNode<T>|!Coordinates} start
32
+ * @param {!GraphNode<T>|!Coordinates} end
33
+ * @param {GraphRouterOptions} _options
34
+ * @returns {GraphItinerary<T>}
38
35
  */
39
- getShortestPath(start, end, _options) {
36
+ getShortestPath(start, end, options = new GraphRouterOptions()) {
40
37
 
41
- if (!(start instanceof Node) && !(start instanceof Coordinates)) {
38
+ if (!(start instanceof GraphNode) && !(start instanceof Coordinates)) {
42
39
  throw new Error('Unknown start type');
43
40
  }
44
41
 
45
- if (!(end instanceof Node) && !(end instanceof Coordinates)) {
42
+ if (!(end instanceof GraphNode) && !(end instanceof Coordinates)) {
46
43
  throw new Error('Unknown end type');
47
44
  }
48
45
 
49
- const options = Object.assign({}, DEFAULT_OPTIONS, _options);
50
- const acceptEdgeFn = options.useStairs ? () => true : edge => !edge.isStairs;
51
- const weightEdgeFn = GraphRouter.defaultWeightFn;
46
+ const { acceptEdgeFn, weightEdgeFn, projectionMaxDistance } = options;
47
+ this._mapMatching.maxDistance = projectionMaxDistance;
52
48
 
53
49
  const createdNodes = [];
54
50
 
55
51
  const retrieveOrCreateNearestNode = point => {
56
- if (point instanceof Node) {
52
+ if (point instanceof GraphNode) {
57
53
  return point;
58
54
  }
59
55
 
@@ -69,7 +65,7 @@ class GraphRouter {
69
65
  + `> ${this._mapMatching.maxDistance.toFixed(0)} meters`
70
66
  );
71
67
  }
72
- if (proj.nearestElement instanceof Node) {
68
+ if (proj.nearestElement instanceof GraphNode) {
73
69
  return proj.nearestElement;
74
70
  }
75
71
  // if (proj.nearestElement instanceof Edge)
@@ -87,39 +83,39 @@ class GraphRouter {
87
83
  }
88
84
  };
89
85
 
90
- try {
91
- const startNode = retrieveOrCreateNearestNode(start);
92
- const endNode = retrieveOrCreateNearestNode(end);
86
+ const startNode = retrieveOrCreateNearestNode(start);
87
+ const endNode = retrieveOrCreateNearestNode(end);
93
88
 
94
- const path = this.getShortestPathInternal(startNode, endNode, acceptEdgeFn, weightEdgeFn);
95
-
96
- if (!path || !path.length) {
97
- throw new NoRouteFoundError(start, end);
98
- }
89
+ const graphItinerary = this.getShortestPathBetweenGraphNodes(
90
+ startNode,
91
+ endNode,
92
+ acceptEdgeFn,
93
+ weightEdgeFn
94
+ );
95
+ graphItinerary.start = start instanceof GraphNode ? start.coords : start;
96
+ graphItinerary.end = end instanceof GraphNode ? end.coords : end;
99
97
 
100
- const route = Itinerary.fromNetworkNodes(path,
101
- start instanceof Node ? start._coords : start,
102
- end instanceof Node ? end.coords : end);
98
+ removeCreatedNodes();
103
99
 
104
- removeCreatedNodes();
105
- return route;
106
- } catch (e) {
107
- removeCreatedNodes();
108
- throw e;
100
+ if (!graphItinerary.nodes.length) {
101
+ throw new NoRouteFoundError(start, end);
109
102
  }
103
+
104
+ return graphItinerary;
105
+
110
106
  }
111
107
 
112
108
  /**
113
- * @param {Edge} edge
109
+ * @param {GraphEdge<T>} edge
114
110
  * @param {Coordinates} point
115
111
  */
116
112
  createNodeInsideEdge(edge, point) {
117
113
  const a = edge.node1;
118
114
  const b = edge.node2;
119
115
 
120
- const m = new Node(point);
116
+ const m = new GraphNode(point);
121
117
  m.coords.level = edge.level;
122
- m.name = edge.name;
118
+ m.builtFrom = edge.builtFrom;
123
119
 
124
120
  const u = edge.clone();
125
121
  u.node1 = a;
@@ -143,7 +139,7 @@ class GraphRouter {
143
139
  }
144
140
 
145
141
  /**
146
- * @param {Node} _node
142
+ * @param {GraphNode<T>} _node
147
143
  */
148
144
  removeNodeFromPreviouslyCreatedEdge(_node) {
149
145
  const u = _node.edges[0];
@@ -163,7 +159,7 @@ class GraphRouter {
163
159
  );
164
160
  }
165
161
 
166
- getShortestPathInternal(start, end, acceptEdgeFn, weightFn) {
162
+ getShortestPathBetweenGraphNodes(start, end, acceptEdgeFn, weightFn) {
167
163
  const distanceMap = {},
168
164
  checking = {},
169
165
  vertexList = {},
@@ -247,11 +243,14 @@ class GraphRouter {
247
243
  delete vertexList[current];
248
244
  }
249
245
 
246
+ const edgesWeights = [];
247
+
250
248
  // now we have the most efficient paths for all vertices
251
249
  // build the path for the user specified vertex(end)
252
250
  let endId = end.uniqueRouterId;
253
251
  while (parentVertices[endId]) {
254
252
  path.unshift(vertexNodes[endId]);
253
+ edgesWeights.unshift(distanceMap[endId] - distanceMap[parentVertices[endId]]);
255
254
  endId = parentVertices[endId];
256
255
  }
257
256
  if (path.length !== 0) {
@@ -263,7 +262,8 @@ class GraphRouter {
263
262
  delete vertex.uniqueRouterId;
264
263
  });
265
264
 
266
- return path;
265
+ // This clone the itinerary and temporary nodes
266
+ return GraphItinerary.fromNetworkNodes(path, edgesWeights);
267
267
  }
268
268
  }
269
269
  export default GraphRouter;