@wemap/geo 11.0.0-alpha.0 → 11.0.0-alpha.12
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 +11 -5
- package/src/Utils.ts +4 -4
- package/src/coordinates/BoundingBox.ts +17 -33
- package/src/graph/GraphEdge.ts +8 -8
- package/src/graph/GraphNode.spec.ts +5 -3
- package/src/graph/GraphNode.ts +12 -12
- package/src/graph/GraphProjection.ts +3 -3
- package/src/graph/GraphUtils.ts +5 -5
- package/src/graph/MapMatching.ts +7 -7
- package/src/graph/Network.spec.ts +5 -2
- package/src/graph/Network.ts +24 -25
- package/src/router/GraphItinerary.spec.ts +1 -1
- package/src/router/GraphItinerary.ts +11 -11
- package/src/router/GraphRouter.spec.ts +16 -16
- package/src/router/GraphRouter.ts +34 -34
- package/src/router/GraphRouterOptions.ts +3 -3
- package/tests/CommonTest.ts +8 -6
- package/dist/index.js +0 -1633
- package/dist/index.js.map +0 -1
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"Guillaume Pannetier <guillaume.pannetier@getwemap.com>"
|
|
6
6
|
],
|
|
7
7
|
"description": "Wemap geo utils package",
|
|
8
|
-
"
|
|
8
|
+
"main": "dist/index.js",
|
|
9
9
|
"types": "index.ts",
|
|
10
10
|
"repository": {
|
|
11
11
|
"type": "git",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"directory": "packages/geo"
|
|
14
14
|
},
|
|
15
15
|
"name": "@wemap/geo",
|
|
16
|
-
"version": "11.0.0-alpha.
|
|
16
|
+
"version": "11.0.0-alpha.12",
|
|
17
17
|
"bugs": {
|
|
18
18
|
"url": "https://github.com/wemap/wemap-modules-js/issues"
|
|
19
19
|
},
|
|
@@ -31,11 +31,17 @@
|
|
|
31
31
|
],
|
|
32
32
|
"license": "ISC",
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@wemap/logger": "^11.0.0-alpha.
|
|
35
|
-
"@wemap/maths": "^11.0.0-alpha.
|
|
34
|
+
"@wemap/logger": "^11.0.0-alpha.4",
|
|
35
|
+
"@wemap/maths": "^11.0.0-alpha.12"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"jsdom-global": "^3.0.2"
|
|
39
39
|
},
|
|
40
|
-
"
|
|
40
|
+
"exports": {
|
|
41
|
+
".": {
|
|
42
|
+
"import": "./dist/index.mjs",
|
|
43
|
+
"require": "./dist/index.js"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"gitHead": "42a1aece349e6db3151938ebc9b3d85daf9bb90d"
|
|
41
47
|
}
|
package/src/Utils.ts
CHANGED
|
@@ -6,13 +6,13 @@ import { EPS_MM } from './Constants.js';
|
|
|
6
6
|
import Coordinates from './coordinates/Coordinates.js';
|
|
7
7
|
import UserPosition from './coordinates/UserPosition.js';
|
|
8
8
|
|
|
9
|
-
type RouteSample = Coordinates & { bearing: number };
|
|
9
|
+
export type RouteSample = Coordinates & { bearing: number };
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Sample a route of Coordinates
|
|
13
|
-
* @param
|
|
14
|
-
* @param
|
|
15
|
-
* @param
|
|
13
|
+
* @param route ordered points
|
|
14
|
+
* @param stepSize step size to sample
|
|
15
|
+
* @param maxLength max route length to sample
|
|
16
16
|
*/
|
|
17
17
|
export function sampleRoute(
|
|
18
18
|
route: Coordinates[],
|
|
@@ -16,8 +16,6 @@ class BoundingBox {
|
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Returns the geographical coordinate equidistant from the bounding box's corners.
|
|
19
|
-
*
|
|
20
|
-
* @returns {Coordinates} The bounding box's center.
|
|
21
19
|
*/
|
|
22
20
|
get center(): Coordinates {
|
|
23
21
|
const latCenter = (this.southWest.lat + this.northEast.lat) / 2;
|
|
@@ -27,8 +25,6 @@ class BoundingBox {
|
|
|
27
25
|
|
|
28
26
|
/**
|
|
29
27
|
* Check if a point is contained in the bounding box.
|
|
30
|
-
*
|
|
31
|
-
* @returns {Coordinates} The point to analyze.
|
|
32
28
|
*/
|
|
33
29
|
contains(point: Coordinates): boolean {
|
|
34
30
|
return point.lat <= this.northEast.lat
|
|
@@ -39,9 +35,6 @@ class BoundingBox {
|
|
|
39
35
|
|
|
40
36
|
/**
|
|
41
37
|
* Extend the bounds to include a given LngLat or LngLatBounds.
|
|
42
|
-
*
|
|
43
|
-
* @param {Coordinates|BoundingBox} obj object to extend to
|
|
44
|
-
* @returns {BoundingBox} `this`
|
|
45
38
|
*/
|
|
46
39
|
extend(obj: Coordinates | BoundingBox): BoundingBox {
|
|
47
40
|
const sw = this.southWest,
|
|
@@ -74,7 +67,6 @@ class BoundingBox {
|
|
|
74
67
|
/**
|
|
75
68
|
* This method extends the bounding box with a value in meters
|
|
76
69
|
* /*\ This method is not precise as distance differs in function of latitude
|
|
77
|
-
* @param {!number} measure in meters
|
|
78
70
|
*/
|
|
79
71
|
extendsWithMeasure(measure: number): BoundingBox {
|
|
80
72
|
|
|
@@ -97,8 +89,6 @@ class BoundingBox {
|
|
|
97
89
|
* Returns bounds created by extending or retracting the current bounds by a given ratio in each direction.
|
|
98
90
|
* For example, a ratio of 0.5 extends the bounds by 50% in each direction.
|
|
99
91
|
* Negative values will retract the bounds.
|
|
100
|
-
* @param {Number} bufferRatio
|
|
101
|
-
* @returns {BoundingBox} `this`
|
|
102
92
|
*/
|
|
103
93
|
pad(bufferRatio: number): BoundingBox {
|
|
104
94
|
const sw = this.southWest;
|
|
@@ -115,8 +105,6 @@ class BoundingBox {
|
|
|
115
105
|
|
|
116
106
|
/**
|
|
117
107
|
* Returns the southwest corner of the bounding box.
|
|
118
|
-
*
|
|
119
|
-
* @returns {Coordinates} The southwest corner of the bounding box.
|
|
120
108
|
*/
|
|
121
109
|
getSouthWest() {
|
|
122
110
|
return this.southWest;
|
|
@@ -124,63 +112,49 @@ class BoundingBox {
|
|
|
124
112
|
|
|
125
113
|
/**
|
|
126
114
|
* Returns the northeast corner of the bounding box.
|
|
127
|
-
|
|
128
|
-
* @returns {Coordinates} The northeast corner of the bounding box.
|
|
129
|
-
*/
|
|
115
|
+
*/
|
|
130
116
|
getNorthEast() {
|
|
131
117
|
return this.northEast;
|
|
132
118
|
}
|
|
133
119
|
|
|
134
120
|
/**
|
|
135
121
|
* Returns the northwest corner of the bounding box.
|
|
136
|
-
|
|
137
|
-
* @returns {Coordinates} The northwest corner of the bounding box.
|
|
138
|
-
*/
|
|
122
|
+
*/
|
|
139
123
|
getNorthWest() {
|
|
140
124
|
return new Coordinates(this.getNorth(), this.getWest());
|
|
141
125
|
}
|
|
142
126
|
|
|
143
127
|
/**
|
|
144
128
|
* Returns the southeast corner of the bounding box.
|
|
145
|
-
|
|
146
|
-
* @returns {LngLat} The southeast corner of the bounding box.
|
|
147
|
-
*/
|
|
129
|
+
*/
|
|
148
130
|
getSouthEast() {
|
|
149
131
|
return new Coordinates(this.getSouth(), this.getEast());
|
|
150
132
|
}
|
|
151
133
|
|
|
152
134
|
/**
|
|
153
135
|
* Returns the west edge of the bounding box.
|
|
154
|
-
|
|
155
|
-
* @returns {number} The west edge of the bounding box.
|
|
156
|
-
*/
|
|
136
|
+
*/
|
|
157
137
|
getWest() {
|
|
158
138
|
return this.southWest.lng;
|
|
159
139
|
}
|
|
160
140
|
|
|
161
141
|
/**
|
|
162
142
|
* Returns the south edge of the bounding box.
|
|
163
|
-
|
|
164
|
-
* @returns {number} The south edge of the bounding box.
|
|
165
|
-
*/
|
|
143
|
+
*/
|
|
166
144
|
getSouth() {
|
|
167
145
|
return this.southWest.lat;
|
|
168
146
|
}
|
|
169
147
|
|
|
170
148
|
/**
|
|
171
149
|
* Returns the east edge of the bounding box.
|
|
172
|
-
|
|
173
|
-
* @returns {number} The east edge of the bounding box.
|
|
174
|
-
*/
|
|
150
|
+
*/
|
|
175
151
|
getEast() {
|
|
176
152
|
return this.northEast.lng;
|
|
177
153
|
}
|
|
178
154
|
|
|
179
155
|
/**
|
|
180
156
|
* Returns the north edge of the bounding box.
|
|
181
|
-
|
|
182
|
-
* @returns {number} The north edge of the bounding box.
|
|
183
|
-
*/
|
|
157
|
+
*/
|
|
184
158
|
getNorth() {
|
|
185
159
|
return this.northEast.lat;
|
|
186
160
|
}
|
|
@@ -204,6 +178,16 @@ class BoundingBox {
|
|
|
204
178
|
);
|
|
205
179
|
}
|
|
206
180
|
|
|
181
|
+
static fromCoordinates(coords: Coordinates[]) {
|
|
182
|
+
if (coords.length === 0) {
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
return coords.reduce(
|
|
186
|
+
(acc, _coords) => acc.extend(_coords),
|
|
187
|
+
new BoundingBox(coords[0], coords[0])
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
|
|
207
191
|
/**
|
|
208
192
|
* Returns the WSEN array
|
|
209
193
|
*/
|
package/src/graph/GraphEdge.ts
CHANGED
|
@@ -7,10 +7,10 @@ import { Level_t } from '../types.js';
|
|
|
7
7
|
* An edge is mostly issued from an OsmWay, but this is not always the case.
|
|
8
8
|
* For example, edges created by mapmatching.
|
|
9
9
|
*/
|
|
10
|
-
class GraphEdge<
|
|
10
|
+
class GraphEdge<E = unknown, N = unknown> {
|
|
11
11
|
|
|
12
|
-
private _node1!: GraphNode<
|
|
13
|
-
private _node2!: GraphNode<
|
|
12
|
+
private _node1!: GraphNode<N, E>;
|
|
13
|
+
private _node2!: GraphNode<N, E>;
|
|
14
14
|
private _level: Level_t = null;
|
|
15
15
|
|
|
16
16
|
private _bearing: number | null = null;
|
|
@@ -18,12 +18,12 @@ class GraphEdge<T = unknown> {
|
|
|
18
18
|
|
|
19
19
|
private _computedSizeAndBearing = false;
|
|
20
20
|
|
|
21
|
-
builtFrom:
|
|
21
|
+
builtFrom: E | null;
|
|
22
22
|
|
|
23
23
|
isOneway = false;
|
|
24
24
|
|
|
25
|
-
constructor(node1: GraphNode<
|
|
26
|
-
level: Level_t = null, builtFrom:
|
|
25
|
+
constructor(node1: GraphNode<N, E>, node2: GraphNode<N, E>,
|
|
26
|
+
level: Level_t = null, builtFrom: E | null = null,
|
|
27
27
|
) {
|
|
28
28
|
this.node1 = node1;
|
|
29
29
|
this.node2 = node2;
|
|
@@ -106,7 +106,7 @@ class GraphEdge<T = unknown> {
|
|
|
106
106
|
this._computedSizeAndBearing = true;
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
equals(other: GraphEdge<
|
|
109
|
+
equals(other: GraphEdge<E, N>) {
|
|
110
110
|
|
|
111
111
|
if (this === other) {
|
|
112
112
|
return true;
|
|
@@ -124,7 +124,7 @@ class GraphEdge<T = unknown> {
|
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
clone() {
|
|
127
|
-
const edge = new GraphEdge<
|
|
127
|
+
const edge = new GraphEdge<E, N>(this.node1, this.node2, this.level, this.builtFrom);
|
|
128
128
|
edge.isOneway = this.isOneway;
|
|
129
129
|
return edge;
|
|
130
130
|
}
|
|
@@ -16,6 +16,8 @@ const { expect } = chai;
|
|
|
16
16
|
|
|
17
17
|
describe('GraphNode', () => {
|
|
18
18
|
|
|
19
|
+
type N = string;
|
|
20
|
+
type E = string;
|
|
19
21
|
|
|
20
22
|
it('creation', () => {
|
|
21
23
|
|
|
@@ -69,14 +71,14 @@ describe('GraphNode', () => {
|
|
|
69
71
|
// eslint-disable-next-line max-statements
|
|
70
72
|
it('generateNodesLevels', () => {
|
|
71
73
|
|
|
72
|
-
const cleanNodes = (count: number) => [...Array(count)].map((_ignore, idx) => new GraphNode<
|
|
74
|
+
const cleanNodes = (count: number) => [...Array(count)].map((_ignore, idx) => new GraphNode<N, E>(new Coordinates(0, 0), `n${idx}`));
|
|
73
75
|
const cleanNodesWithAdjEdges = (...levelEdges: Level_t[]) => {
|
|
74
76
|
const _nodes = cleanNodes(levelEdges.length + 1);
|
|
75
|
-
levelEdges.forEach((level, idx) => new GraphEdge<
|
|
77
|
+
levelEdges.forEach((level, idx) => new GraphEdge<E | null>(_nodes[0], _nodes[idx + 1], level));
|
|
76
78
|
return _nodes;
|
|
77
79
|
};
|
|
78
80
|
|
|
79
|
-
let nodes: GraphNode<
|
|
81
|
+
let nodes: GraphNode<N>[];
|
|
80
82
|
|
|
81
83
|
/**
|
|
82
84
|
* Simple case with only adjacent nodes
|
package/src/graph/GraphNode.ts
CHANGED
|
@@ -5,35 +5,35 @@ import { GraphNodeJson, Level_t } from '../types.js';
|
|
|
5
5
|
import GraphEdge from './GraphEdge.js';
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
class GraphNode<
|
|
8
|
+
class GraphNode<N = unknown, E = unknown> {
|
|
9
9
|
|
|
10
10
|
coords: Coordinates;
|
|
11
11
|
|
|
12
|
-
edges: GraphEdge<
|
|
13
|
-
builtFrom:
|
|
12
|
+
edges: GraphEdge<E, N>[] = [];
|
|
13
|
+
builtFrom: N | null;
|
|
14
14
|
io = false;
|
|
15
15
|
|
|
16
|
-
constructor(coords: Coordinates, builtFrom:
|
|
16
|
+
constructor(coords: Coordinates, builtFrom: N | null = null) {
|
|
17
17
|
this.coords = coords;
|
|
18
18
|
this.builtFrom = builtFrom;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
distanceTo(other: GraphNode<
|
|
21
|
+
distanceTo(other: GraphNode<N, E>) {
|
|
22
22
|
return this.coords.distanceTo(other.coords);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
bearingTo(other: GraphNode<
|
|
25
|
+
bearingTo(other: GraphNode<N, E>) {
|
|
26
26
|
return this.coords.bearingTo(other.coords);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
equals(other: GraphNode<
|
|
29
|
+
equals(other: GraphNode<N, E>) {
|
|
30
30
|
return this.coords.equals(other.coords)
|
|
31
31
|
&& this.builtFrom === other.builtFrom;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
clone() {
|
|
36
|
-
const node = new GraphNode<
|
|
36
|
+
const node = new GraphNode<N, E>(this.coords, this.builtFrom);
|
|
37
37
|
node.edges = this.edges.slice(0);
|
|
38
38
|
node.io = this.io;
|
|
39
39
|
return node;
|
|
@@ -46,8 +46,8 @@ class GraphNode<T = unknown> {
|
|
|
46
46
|
return this.coords.toCompressedJson();
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
static fromJson<
|
|
50
|
-
return new GraphNode<
|
|
49
|
+
static fromJson<N2, E2>(json: GraphNodeJson, builtFrom: N2 | null = null) {
|
|
50
|
+
return new GraphNode<N2, E2>(Coordinates.fromCompressedJson(json), builtFrom);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
_generateLevelFromEdges() {
|
|
@@ -89,7 +89,7 @@ class GraphNode<T = unknown> {
|
|
|
89
89
|
* This method looks for single level nodes recursively from a multi-level node
|
|
90
90
|
* The result of this method is an union of all single level nodes found.
|
|
91
91
|
*/
|
|
92
|
-
const lookForLevel = (node: GraphNode<
|
|
92
|
+
const lookForLevel = (node: GraphNode<N, E>, visitedNodes: GraphNode<N, E>[]): Level_t => {
|
|
93
93
|
|
|
94
94
|
visitedNodes.push(node);
|
|
95
95
|
|
|
@@ -156,7 +156,7 @@ class GraphNode<T = unknown> {
|
|
|
156
156
|
return true;
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
-
static generateNodesLevels<
|
|
159
|
+
static generateNodesLevels<N2, E2>(nodes: GraphNode<N2, E2>[]) {
|
|
160
160
|
|
|
161
161
|
nodes.forEach(node => node._generateLevelFromEdges());
|
|
162
162
|
|
|
@@ -2,15 +2,15 @@ import Coordinates from '../coordinates/Coordinates.js';
|
|
|
2
2
|
import GraphEdge from './GraphEdge.js';
|
|
3
3
|
import GraphNode from './GraphNode.js';
|
|
4
4
|
|
|
5
|
-
class GraphProjection<
|
|
5
|
+
class GraphProjection<N = unknown, E = unknown, U extends Coordinates = Coordinates> {
|
|
6
6
|
|
|
7
7
|
origin: U;
|
|
8
8
|
distanceFromNearestElement: number;
|
|
9
9
|
coords: U;
|
|
10
|
-
nearestElement: GraphNode<
|
|
10
|
+
nearestElement: GraphNode<N, E> | GraphEdge<E, N>;
|
|
11
11
|
|
|
12
12
|
constructor(origin: U, distanceFromNearestElement: number,
|
|
13
|
-
coords: U, nearestElement: GraphNode<
|
|
13
|
+
coords: U, nearestElement: GraphNode<N, E> | GraphEdge<E, N>
|
|
14
14
|
) {
|
|
15
15
|
this.origin = origin;
|
|
16
16
|
this.distanceFromNearestElement = distanceFromNearestElement;
|
package/src/graph/GraphUtils.ts
CHANGED
|
@@ -3,9 +3,9 @@ import Coordinates from '../coordinates/Coordinates.js';
|
|
|
3
3
|
import GraphEdge from './GraphEdge.js';
|
|
4
4
|
import GraphNode from './GraphNode.js';
|
|
5
5
|
|
|
6
|
-
export function getEdgeByNodes<
|
|
7
|
-
edges: GraphEdge<
|
|
8
|
-
node1: GraphNode<
|
|
6
|
+
export function getEdgeByNodes<E, N>(
|
|
7
|
+
edges: GraphEdge<E, N>[],
|
|
8
|
+
node1: GraphNode<N, E>, node2: GraphNode<N, E>
|
|
9
9
|
) {
|
|
10
10
|
return edges.find(edge => node1 === edge.node1 && node2 === edge.node2
|
|
11
11
|
|| node2 === edge.node1 && node1 === edge.node2
|
|
@@ -13,8 +13,8 @@ export function getEdgeByNodes<T>(
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
export function getNodeByCoords<
|
|
17
|
-
nodes: GraphNode<
|
|
16
|
+
export function getNodeByCoords<N, E>(
|
|
17
|
+
nodes: GraphNode<N, E>[],
|
|
18
18
|
coords: Coordinates
|
|
19
19
|
) {
|
|
20
20
|
return nodes.find(node => node.coords.equals(coords));
|
package/src/graph/MapMatching.ts
CHANGED
|
@@ -12,14 +12,14 @@ import GraphEdge from './GraphEdge.js';
|
|
|
12
12
|
import GraphNode from './GraphNode.js';
|
|
13
13
|
import { EPS_MM } from '../Constants.js';
|
|
14
14
|
|
|
15
|
-
class MapMatching<
|
|
15
|
+
class MapMatching<N = unknown, E = unknown> {
|
|
16
16
|
|
|
17
|
-
network: Network<
|
|
17
|
+
network: Network<N, E> | null = null;
|
|
18
18
|
|
|
19
19
|
private _maxDistance = Number.MAX_VALUE;
|
|
20
20
|
private _maxAngleBearing = Math.PI;
|
|
21
21
|
|
|
22
|
-
constructor(network: Network<
|
|
22
|
+
constructor(network: Network<N, E> | null = null) {
|
|
23
23
|
this.network = network;
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -47,11 +47,11 @@ class MapMatching<T = unknown> {
|
|
|
47
47
|
* Second is true if projection will be used on the nodes of the specified edge, false otherwise.
|
|
48
48
|
*/
|
|
49
49
|
_shouldProjectOnEdgeAndNodes(
|
|
50
|
-
edge: GraphEdge<
|
|
50
|
+
edge: GraphEdge<E, N>,
|
|
51
51
|
location: Coordinates | UserPosition,
|
|
52
52
|
useBearing: boolean,
|
|
53
53
|
useMultiLevelSegments: boolean,
|
|
54
|
-
acceptEdgeFn: (edge: GraphEdge<
|
|
54
|
+
acceptEdgeFn: (edge: GraphEdge<E, N>) => boolean) {
|
|
55
55
|
|
|
56
56
|
// ignore projections if edge is not accepted
|
|
57
57
|
if (!acceptEdgeFn(edge)) {
|
|
@@ -124,7 +124,7 @@ class MapMatching<T = unknown> {
|
|
|
124
124
|
useDistance = false,
|
|
125
125
|
useBearing = false,
|
|
126
126
|
useMultiLevelSegments = true,
|
|
127
|
-
acceptEdgeFn: (edge: GraphEdge<
|
|
127
|
+
acceptEdgeFn: (edge: GraphEdge<E, N>) => boolean = () => true) {
|
|
128
128
|
|
|
129
129
|
if (this.network === null) {
|
|
130
130
|
throw new Error('Network has not been set yet');
|
|
@@ -212,7 +212,7 @@ class MapMatching<T = unknown> {
|
|
|
212
212
|
projection.accuracy += distanceFromNearestElement;
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
-
return new GraphProjection<
|
|
215
|
+
return new GraphProjection<N, E, U>(
|
|
216
216
|
location,
|
|
217
217
|
distanceFromNearestElement,
|
|
218
218
|
projection,
|
|
@@ -15,6 +15,9 @@ const { expect } = chai;
|
|
|
15
15
|
|
|
16
16
|
describe('Network', () => {
|
|
17
17
|
|
|
18
|
+
type N = string;
|
|
19
|
+
type E = string;
|
|
20
|
+
|
|
18
21
|
it('creation', () => {
|
|
19
22
|
|
|
20
23
|
expect(() => new Network()).not.throw(Error);
|
|
@@ -65,8 +68,8 @@ describe('Network', () => {
|
|
|
65
68
|
|
|
66
69
|
it('toDetailedString', () => {
|
|
67
70
|
|
|
68
|
-
const nodeFn = (node: GraphNode<
|
|
69
|
-
const edgeFn = (edge: GraphEdge<
|
|
71
|
+
const nodeFn = (node: GraphNode<N, E>) => node.builtFrom || '';
|
|
72
|
+
const edgeFn = (edge: GraphEdge<E, N>) => edge.builtFrom || '';
|
|
70
73
|
expect(() => network.toDetailedString(nodeFn, edgeFn)).not.throw(Error);
|
|
71
74
|
|
|
72
75
|
});
|
package/src/graph/Network.ts
CHANGED
|
@@ -11,17 +11,12 @@ import { getEdgeByNodes } from './GraphUtils.js';
|
|
|
11
11
|
* TODO: rename to GraphNetwork
|
|
12
12
|
* A typical network with nodes (Node) and edges (Edge)
|
|
13
13
|
*/
|
|
14
|
-
class Network<
|
|
14
|
+
class Network<N = unknown, E = unknown> {
|
|
15
15
|
|
|
16
|
-
nodes: GraphNode<
|
|
17
|
-
edges: GraphEdge<
|
|
16
|
+
nodes: GraphNode<N, E>[];
|
|
17
|
+
edges: GraphEdge<E, N>[];
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
* @template T
|
|
21
|
-
* @param {GraphNode<T>[]} nodes
|
|
22
|
-
* @param {GraphEdge<T>[]} edges
|
|
23
|
-
*/
|
|
24
|
-
constructor(nodes?: GraphNode<T>[], edges?: GraphEdge<T>[]) {
|
|
19
|
+
constructor(nodes?: GraphNode<N, E>[], edges?: GraphEdge<E, N>[]) {
|
|
25
20
|
this.nodes = Array.isArray(nodes) ? nodes : [];
|
|
26
21
|
this.edges = Array.isArray(edges) ? edges : [];
|
|
27
22
|
}
|
|
@@ -31,7 +26,7 @@ class Network<T = unknown> {
|
|
|
31
26
|
return this.nodes.find(node => node.coords.equals(coords));
|
|
32
27
|
}
|
|
33
28
|
|
|
34
|
-
getEdgeByNodes(node1: GraphNode<
|
|
29
|
+
getEdgeByNodes(node1: GraphNode<N>, node2: GraphNode<N>) {
|
|
35
30
|
return getEdgeByNodes(this.edges, node1, node2);
|
|
36
31
|
}
|
|
37
32
|
|
|
@@ -39,10 +34,7 @@ class Network<T = unknown> {
|
|
|
39
34
|
if (!this.nodes.length) {
|
|
40
35
|
return null;
|
|
41
36
|
}
|
|
42
|
-
const boundingBox = this.nodes.
|
|
43
|
-
(acc, node) => acc.extend(node.coords),
|
|
44
|
-
new BoundingBox(this.nodes[0].coords, this.nodes[0].coords)
|
|
45
|
-
);
|
|
37
|
+
const boundingBox = BoundingBox.fromCoordinates(this.nodes.map(node => node.coords)) as BoundingBox;
|
|
46
38
|
if (extendedMeasure) {
|
|
47
39
|
boundingBox.extendsWithMeasure(extendedMeasure);
|
|
48
40
|
}
|
|
@@ -50,8 +42,8 @@ class Network<T = unknown> {
|
|
|
50
42
|
}
|
|
51
43
|
|
|
52
44
|
toDetailedString(
|
|
53
|
-
_nodeToStringFn: (node: GraphNode<
|
|
54
|
-
_edgeToStringFn: (
|
|
45
|
+
_nodeToStringFn: (node: GraphNode<N, E>) => string,
|
|
46
|
+
_edgeToStringFn: (edge: GraphEdge<E, N>) => string
|
|
55
47
|
) {
|
|
56
48
|
|
|
57
49
|
let nodeToStringFn = _nodeToStringFn;
|
|
@@ -102,14 +94,14 @@ class Network<T = unknown> {
|
|
|
102
94
|
}
|
|
103
95
|
|
|
104
96
|
|
|
105
|
-
static fromCompressedJson<
|
|
97
|
+
static fromCompressedJson<N2, E2>(json: NetworkJson) {
|
|
106
98
|
|
|
107
|
-
const network = new Network<
|
|
99
|
+
const network = new Network<N2 | null, E2 | null>();
|
|
108
100
|
|
|
109
|
-
network.nodes = json.nodes.map(node => GraphNode.fromJson(node, null));
|
|
101
|
+
network.nodes = json.nodes.map(node => GraphNode.fromJson<N2, E2>(node, null));
|
|
110
102
|
|
|
111
103
|
network.edges = json.edges.map(jsonEdge => {
|
|
112
|
-
const edge = new GraphEdge(
|
|
104
|
+
const edge = new GraphEdge<E2 | null, N2 | null>(
|
|
113
105
|
network.nodes[jsonEdge[0]],
|
|
114
106
|
network.nodes[jsonEdge[1]],
|
|
115
107
|
jsonEdge[2],
|
|
@@ -125,23 +117,30 @@ class Network<T = unknown> {
|
|
|
125
117
|
}
|
|
126
118
|
|
|
127
119
|
|
|
128
|
-
static fromCoordinates<
|
|
120
|
+
static fromCoordinates<N2, E2>(segments: Coordinates[][]) {
|
|
129
121
|
|
|
130
|
-
const network = new Network<
|
|
122
|
+
const network = new Network<N2 | null, E2 | null>();
|
|
131
123
|
|
|
132
124
|
const getOrCreateNode = (coords: Coordinates) => {
|
|
133
125
|
const node = network.nodes.find(otherNode => otherNode.coords.equals(coords));
|
|
134
126
|
if (node) {
|
|
135
127
|
return node;
|
|
136
128
|
}
|
|
137
|
-
const newNode = new GraphNode<
|
|
129
|
+
const newNode = new GraphNode<N2 | null, E2 | null>(coords, null);
|
|
138
130
|
network.nodes.push(newNode);
|
|
139
131
|
return newNode;
|
|
140
132
|
};
|
|
141
133
|
|
|
142
134
|
|
|
143
|
-
const createEdgeFromNodes = (
|
|
144
|
-
|
|
135
|
+
const createEdgeFromNodes = (
|
|
136
|
+
node1: GraphNode<N2 | null, E2 | null>,
|
|
137
|
+
node2: GraphNode<N2 | null, E2 | null>
|
|
138
|
+
) => new GraphEdge<E2 | null, N2 | null>(
|
|
139
|
+
node1,
|
|
140
|
+
node2,
|
|
141
|
+
Level.union(node1.coords.level, node2.coords.level),
|
|
142
|
+
null
|
|
143
|
+
);
|
|
145
144
|
|
|
146
145
|
for (const segment of segments) {
|
|
147
146
|
|
|
@@ -3,7 +3,7 @@ import GraphItinerary from './GraphItinerary';
|
|
|
3
3
|
|
|
4
4
|
const { expect } = chai;
|
|
5
5
|
|
|
6
|
-
export function isReadable
|
|
6
|
+
export function isReadable(itinerary: GraphItinerary) {
|
|
7
7
|
for (let i = 0; i < itinerary.nodes.length; i++) {
|
|
8
8
|
const node = itinerary.nodes[i];
|
|
9
9
|
if (i !== itinerary.nodes.length - 1) {
|
|
@@ -5,19 +5,19 @@ import GraphEdge from '../graph/GraphEdge.js';
|
|
|
5
5
|
import { getEdgeByNodes } from '../graph/GraphUtils.js';
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
class GraphItinerary<
|
|
8
|
+
class GraphItinerary<N = unknown, E = unknown> {
|
|
9
9
|
|
|
10
10
|
start: Coordinates;
|
|
11
11
|
end: Coordinates;
|
|
12
12
|
|
|
13
|
-
nodes: GraphNode<
|
|
14
|
-
edges: GraphEdge<
|
|
13
|
+
nodes: GraphNode<N, E>[];
|
|
14
|
+
edges: GraphEdge<E, N>[];
|
|
15
15
|
|
|
16
16
|
edgesWeights: number[];
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
protected constructor(
|
|
19
19
|
start: Coordinates, end: Coordinates,
|
|
20
|
-
nodes: GraphNode<
|
|
20
|
+
nodes: GraphNode<N, E>[], edges: GraphEdge<E, N>[],
|
|
21
21
|
edgesWeights: number[]
|
|
22
22
|
) {
|
|
23
23
|
this.start = start;
|
|
@@ -27,9 +27,9 @@ class GraphItinerary<T> {
|
|
|
27
27
|
this.edgesWeights = edgesWeights;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
static fromNetworkNodes<
|
|
30
|
+
static fromNetworkNodes<N2, E2>(
|
|
31
31
|
start: Coordinates, end: Coordinates,
|
|
32
|
-
networkNodes: GraphNode<
|
|
32
|
+
networkNodes: GraphNode<N2, E2>[], edgesWeights: number[]
|
|
33
33
|
) {
|
|
34
34
|
|
|
35
35
|
const nodes = networkNodes.map(node => {
|
|
@@ -47,7 +47,7 @@ class GraphItinerary<T> {
|
|
|
47
47
|
return newNode;
|
|
48
48
|
});
|
|
49
49
|
|
|
50
|
-
const edges: GraphEdge<
|
|
50
|
+
const edges: GraphEdge<E2, N2>[] = [];
|
|
51
51
|
networkNodes.forEach((node, idx, arr) => {
|
|
52
52
|
if (idx === 0) {
|
|
53
53
|
return;
|
|
@@ -55,7 +55,7 @@ class GraphItinerary<T> {
|
|
|
55
55
|
|
|
56
56
|
// Retrieve network edge
|
|
57
57
|
const prevNode = arr[idx - 1];
|
|
58
|
-
const edge = getEdgeByNodes
|
|
58
|
+
const edge = getEdgeByNodes(prevNode.edges, prevNode, node);
|
|
59
59
|
|
|
60
60
|
if (!edge) {
|
|
61
61
|
Logger.error('Cannot retrieve edge to create itinerary');
|
|
@@ -63,7 +63,7 @@ class GraphItinerary<T> {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
// Create itinerary edge
|
|
66
|
-
const newEdge = new GraphEdge
|
|
66
|
+
const newEdge = new GraphEdge(
|
|
67
67
|
nodes[idx - 1],
|
|
68
68
|
nodes[idx],
|
|
69
69
|
edge.level,
|
|
@@ -73,7 +73,7 @@ class GraphItinerary<T> {
|
|
|
73
73
|
edges.push(newEdge);
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
-
return new GraphItinerary
|
|
76
|
+
return new GraphItinerary(start, end, nodes, edges, edgesWeights);
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
|