@wemap/routers 11.2.4 → 11.3.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/dist/index.js +146 -89
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +146 -89
- package/dist/index.mjs.map +1 -1
- package/index.ts +1 -0
- package/package.json +4 -4
- package/src/model/LevelChange.spec.ts +1 -0
- package/src/model/LevelChange.ts +2 -1
- package/src/wemap-multi/CustomNetworkMap.ts +5 -5
- package/src/wemap-multi/WemapMultiRouter.ts +5 -8
- package/src/wemap-multi/WemapMultiRouterOptions.ts +2 -7
- package/src/wemap-osm/OsmGraph.ts +120 -61
- package/src/wemap-osm/OsmRouter.elevators.spec.ts +105 -0
- package/src/wemap-osm/OsmRouter.ts +61 -33
- package/src/wemap-osm/OsmRouterOptions.ts +12 -0
package/index.ts
CHANGED
|
@@ -12,6 +12,7 @@ export type { RoutingMode } from './src/model/RoutingMode.js';
|
|
|
12
12
|
/* Wemap Router */
|
|
13
13
|
export { default as OsmGraph, type OsmVertex, type OsmEdge, type OsmVertexData, type OsmEdgeData } from './src/wemap-osm/OsmGraph.js';
|
|
14
14
|
export { default as OsmRouter, type OsmItinerary } from './src/wemap-osm/OsmRouter.js';
|
|
15
|
+
export {type OsmRouterOptions } from './src/wemap-osm/OsmRouterOptions.js';
|
|
15
16
|
|
|
16
17
|
export { default as WemapMultiRouter } from './src/wemap-multi/WemapMultiRouter.js';
|
|
17
18
|
export { default as CustomNetworkMap } from './src/wemap-multi/CustomNetworkMap.js';
|
package/package.json
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"directory": "packages/routers"
|
|
13
13
|
},
|
|
14
14
|
"name": "@wemap/routers",
|
|
15
|
-
"version": "11.
|
|
15
|
+
"version": "11.3.0",
|
|
16
16
|
"bugs": {
|
|
17
17
|
"url": "https://github.com/wemap/wemap-modules-js/issues"
|
|
18
18
|
},
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
"@turf/convex": "^6.5.0",
|
|
35
35
|
"@turf/helpers": "^6.5.0",
|
|
36
36
|
"@types/mapbox__polyline": "^1.0.2",
|
|
37
|
-
"@wemap/geo": "^11.0
|
|
37
|
+
"@wemap/geo": "^11.3.0",
|
|
38
38
|
"@wemap/logger": "^11.0.1",
|
|
39
39
|
"@wemap/maths": "^11.0.1",
|
|
40
|
-
"@wemap/osm": "^11.0
|
|
40
|
+
"@wemap/osm": "^11.3.0",
|
|
41
41
|
"@wemap/salesman.js": "^2.1.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
@@ -52,5 +52,5 @@
|
|
|
52
52
|
},
|
|
53
53
|
"./helpers/*": "./helpers/*"
|
|
54
54
|
},
|
|
55
|
-
"gitHead": "
|
|
55
|
+
"gitHead": "61e38edddc0dc58fa32750b69939a580b204442e"
|
|
56
56
|
}
|
package/src/model/LevelChange.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { Position, MultiPolygon } from '@turf/helpers';
|
|
|
5
5
|
import { Coordinates, GeoGraphRouterOptions, Level, NoRouteFoundError } from '@wemap/geo';
|
|
6
6
|
import { OsmParser } from '@wemap/osm';
|
|
7
7
|
|
|
8
|
-
import OsmGraph, { OsmVertex } from '../wemap-osm/OsmGraph.js';
|
|
8
|
+
import OsmGraph, { OsmEdgeData, OsmVertex, OsmVertexData } from '../wemap-osm/OsmGraph.js';
|
|
9
9
|
import WemapOsmRouter from '../wemap-osm/OsmRouter.js';
|
|
10
10
|
|
|
11
11
|
class CustomNetworkMap {
|
|
@@ -129,7 +129,7 @@ class CustomNetworkMap {
|
|
|
129
129
|
* /!\ start is only used to sort the entry points (step 1).
|
|
130
130
|
*
|
|
131
131
|
*/
|
|
132
|
-
getBestItineraryFromEntryPointsToEnd(start: Coordinates, end: Coordinates, options: GeoGraphRouterOptions) {
|
|
132
|
+
getBestItineraryFromEntryPointsToEnd(start: Coordinates, end: Coordinates, options: GeoGraphRouterOptions<OsmVertexData, OsmEdgeData>) {
|
|
133
133
|
|
|
134
134
|
const sortedEntryPoints = this.getOrderedEntryPointsSortedByDistance(start, end);
|
|
135
135
|
for (const entryPoint of sortedEntryPoints) {
|
|
@@ -156,7 +156,7 @@ class CustomNetworkMap {
|
|
|
156
156
|
* /!\ end is only used to sort the entry points (step 1).
|
|
157
157
|
*
|
|
158
158
|
*/
|
|
159
|
-
getBestItineraryFromStartToEntryPoints(start: Coordinates, end: Coordinates, options: GeoGraphRouterOptions) {
|
|
159
|
+
getBestItineraryFromStartToEntryPoints(start: Coordinates, end: Coordinates, options: GeoGraphRouterOptions<OsmVertexData, OsmEdgeData>) {
|
|
160
160
|
|
|
161
161
|
const sortedEntryPoints = this.getOrderedEntryPointsSortedByDistance(start, end);
|
|
162
162
|
for (const entryPoint of sortedEntryPoints) {
|
|
@@ -171,12 +171,12 @@ class CustomNetworkMap {
|
|
|
171
171
|
);
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
getItineraryInsideMap(start: Coordinates, end: Coordinates, options: GeoGraphRouterOptions) {
|
|
174
|
+
getItineraryInsideMap(start: Coordinates, end: Coordinates, options: GeoGraphRouterOptions<OsmVertexData, OsmEdgeData>) {
|
|
175
175
|
// Call the Wemap router to get the shortest path
|
|
176
176
|
return this.router.getItinerary(start, end, options);
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
-
getTripInsideMap(waypoints: Coordinates[], options: GeoGraphRouterOptions) {
|
|
179
|
+
getTripInsideMap(waypoints: Coordinates[], options: GeoGraphRouterOptions<OsmVertexData, OsmEdgeData>) {
|
|
180
180
|
// Call the Wemap router to get the shortest trip itinerary
|
|
181
181
|
return this.router.getTripItinerary(waypoints, options);
|
|
182
182
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* eslint-disable complexity */
|
|
2
2
|
/* eslint-disable max-statements */
|
|
3
3
|
|
|
4
|
-
import { Coordinates, NoRouteFoundError
|
|
4
|
+
import { Coordinates, NoRouteFoundError } from '@wemap/geo';
|
|
5
5
|
import Logger from '@wemap/logger';
|
|
6
6
|
|
|
7
7
|
import CustomNetworkMap from './CustomNetworkMap.js';
|
|
@@ -9,7 +9,7 @@ import { WemapMultiRouterOptions } from './WemapMultiRouterOptions.js';
|
|
|
9
9
|
import RemoteRouterManager from '../remote/RemoteRouterManager.js';
|
|
10
10
|
import { isRoutingError } from '../remote/RemoteRouterUtils.js';
|
|
11
11
|
import RouterResponse from '../model/RouterResponse.js';
|
|
12
|
-
import WemapOsmRouter
|
|
12
|
+
import WemapOsmRouter from '../wemap-osm/OsmRouter.js';
|
|
13
13
|
import Itinerary from '../model/Itinerary.js';
|
|
14
14
|
import { RoutingMode } from '../model/RoutingMode.js';
|
|
15
15
|
import WemapMultiRemoteRouter from '../remote/wemap-multi/WemapMultiRemoteRouter.js';
|
|
@@ -57,14 +57,11 @@ class WemapMultiRouter {
|
|
|
57
57
|
return ioMapsToTest;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
private convertOptionsToWemapOsmOptions(options: WemapMultiRouterOptions | null) {
|
|
60
|
+
private convertOptionsToWemapOsmOptions(options: WemapMultiRouterOptions | null = null) {
|
|
61
61
|
// Create WemapOsmRouterOptions from WemapMultiRouterOptions
|
|
62
|
-
const outputOptions
|
|
63
|
-
= !options || !('useStairs' in options) || options.useStairs
|
|
64
|
-
? WemapOsmRouter.DEFAULT_OPTIONS
|
|
65
|
-
: WemapOsmRouter.WITHOUT_STAIRS_OPTIONS;
|
|
62
|
+
const outputOptions = WemapOsmRouter.buildOptions(options ? options : {});
|
|
66
63
|
|
|
67
|
-
if(typeof options?.tspTempCoeff !== 'undefined') {
|
|
64
|
+
if (typeof options?.tspTempCoeff !== 'undefined') {
|
|
68
65
|
(outputOptions as any).tspTempCoeff = options.tspTempCoeff;
|
|
69
66
|
}
|
|
70
67
|
return outputOptions;
|
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
import { RemoteRouterName } from "../remote/RemoteRouterManager.js";
|
|
2
|
+
import { OsmRouterOptions } from "../wemap-osm/OsmRouterOptions.js";
|
|
2
3
|
|
|
3
|
-
export type WemapMultiRouterOptions = {
|
|
4
|
-
|
|
5
|
-
useStairs?: boolean;
|
|
4
|
+
export type WemapMultiRouterOptions = OsmRouterOptions & {
|
|
6
5
|
|
|
7
6
|
targetMaps?: string[] | null;
|
|
8
7
|
|
|
9
|
-
isTrip?: boolean;
|
|
10
|
-
|
|
11
|
-
tspTempCoeff?: number;
|
|
12
|
-
|
|
13
8
|
/**
|
|
14
9
|
* List of ordered remote routers (first of the list, first tested)
|
|
15
10
|
* Algorithm will try the first router and if it fails continue
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { Coordinates, GeoGraph, GeoGraphEdge, GeoGraphVertex, Level } from '@wemap/geo';
|
|
1
|
+
import { Coordinates, GeoGraph, GeoGraphEdge, GeoGraphVertex, Level, Level_t } from '@wemap/geo';
|
|
2
2
|
import { OsmModel, OsmNode, OsmWay } from '@wemap/osm';
|
|
3
3
|
|
|
4
4
|
const HIGHWAYS_PEDESTRIANS = ['footway', 'steps', 'pedestrian', 'living_street', 'path', 'track', 'sidewalk', 'elevator'];
|
|
5
5
|
|
|
6
6
|
const DEFAULT_WAY_SELECTOR = (way: OsmWay) => {
|
|
7
7
|
const isElevatorArea = way.tags.highway === 'elevator' && way.isArea
|
|
8
|
-
return HIGHWAYS_PEDESTRIANS.includes(way.tags.highway)
|
|
9
|
-
&& !isElevatorArea
|
|
8
|
+
return HIGHWAYS_PEDESTRIANS.includes(way.tags.highway)
|
|
9
|
+
&& !isElevatorArea
|
|
10
10
|
&& !['no', 'private'].includes(way.tags.access)
|
|
11
11
|
|| way.tags.footway === 'sidewalk'
|
|
12
12
|
|| way.tags.public_transport === 'platform'
|
|
13
13
|
|| way.tags.railway === 'platform';
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
export type OsmVertexData = OsmNode;
|
|
16
|
+
export type OsmVertexData = OsmNode | OsmWay;
|
|
17
17
|
export type OsmEdgeData = OsmWay | OsmNode;
|
|
18
18
|
|
|
19
19
|
export type OsmVertex = GeoGraphVertex<OsmVertexData, OsmEdgeData> & { data: OsmVertexData };
|
|
@@ -41,24 +41,54 @@ export default class OsmGraph extends GeoGraph<OsmVertexData, OsmEdgeData> {
|
|
|
41
41
|
|
|
42
42
|
static fromOsmModel(osmModel: OsmModel, waySelectionFilter = DEFAULT_WAY_SELECTOR) {
|
|
43
43
|
|
|
44
|
-
const
|
|
44
|
+
const vertices: OsmVertex[] = [];
|
|
45
45
|
const edges: OsmEdge[] = [];
|
|
46
46
|
|
|
47
|
-
const
|
|
48
|
-
const elevatorNodes: OsmVertex[] = [];
|
|
47
|
+
const elevatorVertices: OsmVertex[] = [];
|
|
49
48
|
|
|
50
|
-
const
|
|
51
|
-
let node = nodesCreated[osmNode.id];
|
|
52
|
-
if (!node) {
|
|
53
|
-
node = new GeoGraphVertex(osmNode.coords, { data: osmNode, name: osmNode.tags.name }) as OsmVertex;
|
|
54
|
-
nodesCreated[osmNode.id] = node;
|
|
55
|
-
nodes.push(node);
|
|
49
|
+
const getOrCreateVertex = (osmNode: OsmNode, forceLevel: Level_t = null) => {
|
|
56
50
|
|
|
57
|
-
|
|
58
|
-
|
|
51
|
+
// Due to `repeat_on` tags in OSM model, it's not possible to compare osmIds to find corresponding vertex
|
|
52
|
+
let vertex: OsmVertex | null = vertices.find(vertex =>
|
|
53
|
+
vertex.data.id === osmNode.id
|
|
54
|
+
&& (
|
|
55
|
+
(forceLevel !== null)
|
|
56
|
+
? Level.intersect(vertex.coords.level, forceLevel)
|
|
57
|
+
: true
|
|
58
|
+
)
|
|
59
|
+
) || null;
|
|
60
|
+
|
|
61
|
+
if (vertex) { return vertex; }
|
|
62
|
+
|
|
63
|
+
if (vertices.find(v => v.data.id === osmNode.id)) {
|
|
64
|
+
throw `An error occured because repeat_on as not been set on node ${osmNode.coords} for level ${forceLevel}`;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
let levelsToGenerate: Level_t[] = [null];
|
|
68
|
+
if ('level' in osmNode.tags) {
|
|
69
|
+
levelsToGenerate = [osmNode.coords.level];
|
|
70
|
+
if ('repeat_on' in osmNode.tags) {
|
|
71
|
+
levelsToGenerate.push(...osmNode.tags.repeat_on.split(';').map(Level.fromString));
|
|
72
|
+
}
|
|
73
|
+
} else if (forceLevel !== null) {
|
|
74
|
+
levelsToGenerate = [forceLevel];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
levelsToGenerate.forEach(level => {
|
|
78
|
+
const newVertex = new GeoGraphVertex(osmNode.coords.clone(), { data: osmNode, name: osmNode.tags.name }) as OsmVertex;
|
|
79
|
+
newVertex.coords.level = level;
|
|
80
|
+
vertices.push(newVertex);
|
|
81
|
+
|
|
82
|
+
if (Level.intersect(newVertex.coords.level, forceLevel)
|
|
83
|
+
|| forceLevel === null && 'level' in osmNode.tags) {
|
|
84
|
+
vertex = newVertex;
|
|
59
85
|
}
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
if (osmNode.tags.highway === 'elevator' && vertex) {
|
|
89
|
+
elevatorVertices.push(vertex);
|
|
60
90
|
}
|
|
61
|
-
return
|
|
91
|
+
return vertex! as OsmVertex;
|
|
62
92
|
};
|
|
63
93
|
|
|
64
94
|
osmModel.ways.forEach(way => {
|
|
@@ -66,39 +96,69 @@ export default class OsmGraph extends GeoGraph<OsmVertexData, OsmEdgeData> {
|
|
|
66
96
|
return;
|
|
67
97
|
}
|
|
68
98
|
|
|
69
|
-
let
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
) as OsmEdge;
|
|
76
|
-
OsmGraph.manageOneWay(edge, way);
|
|
77
|
-
edges.push(edge);
|
|
78
|
-
firstNode = secondNode;
|
|
99
|
+
let levelsToGenerate: Level_t[] = [null];
|
|
100
|
+
if ('level' in way.tags) {
|
|
101
|
+
levelsToGenerate = [way.level];
|
|
102
|
+
if ('repeat_on' in way.tags) {
|
|
103
|
+
levelsToGenerate.push(...way.tags.repeat_on.split(';').map(Level.fromString));
|
|
104
|
+
}
|
|
79
105
|
}
|
|
80
106
|
|
|
107
|
+
levelsToGenerate.forEach(level => {
|
|
108
|
+
|
|
109
|
+
let firstVertex = getOrCreateVertex(way.nodes[0], level);
|
|
110
|
+
|
|
111
|
+
for (let i = 1; i < way.nodes.length; i++) {
|
|
112
|
+
|
|
113
|
+
const secondVertex = getOrCreateVertex(way.nodes[i], level);
|
|
114
|
+
|
|
115
|
+
const edge = new GeoGraphEdge(firstVertex, secondVertex,
|
|
116
|
+
{ data: way, name: way.tags.name, level }
|
|
117
|
+
) as OsmEdge;
|
|
118
|
+
OsmGraph.manageOneWay(edge, way);
|
|
119
|
+
edges.push(edge);
|
|
120
|
+
firstVertex = secondVertex;
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
81
124
|
});
|
|
82
125
|
|
|
126
|
+
// Manage elevators without explicit navigation graph inside.
|
|
83
127
|
osmModel.ways
|
|
84
128
|
.filter(way => way.isElevator)
|
|
85
129
|
.forEach(way => {
|
|
86
|
-
way.nodes.
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
130
|
+
const entryVertices = way.nodes.map(node => vertices.filter(v => v.data.id === node.id)).flat();
|
|
131
|
+
const elevatorLevel = entryVertices.reduce((acc, v) => Level.union(acc, v.coords.level), null as Level_t);
|
|
132
|
+
|
|
133
|
+
// Horrible method but works for macro-problems
|
|
134
|
+
const elevatorCenter = way.nodes
|
|
135
|
+
.reduce((acc, node) => [acc[0] + node.coords.lat, acc[1] + node.coords.lng], [0, 0])
|
|
136
|
+
.map(val => val / way.nodes.length);
|
|
137
|
+
|
|
138
|
+
const elevatorCenterCoords = new Coordinates(elevatorCenter[0], elevatorCenter[1], null, elevatorLevel);
|
|
139
|
+
const elevatorCenterVertex = new GeoGraphVertex<OsmVertexData, OsmEdgeData>(elevatorCenterCoords, { data: way, name: way.tags.name }) as OsmVertex;
|
|
140
|
+
vertices.push(elevatorCenterVertex);
|
|
141
|
+
|
|
142
|
+
entryVertices.forEach(entryVertex => {
|
|
143
|
+
const newEdge = new GeoGraphEdge(
|
|
144
|
+
elevatorCenterVertex,
|
|
145
|
+
entryVertex,
|
|
146
|
+
{
|
|
147
|
+
level: Level.intersection(elevatorCenterVertex.coords.level, entryVertex.coords.level),
|
|
148
|
+
data: way
|
|
149
|
+
}
|
|
150
|
+
) as OsmEdge;
|
|
151
|
+
edges.push(newEdge);
|
|
152
|
+
});
|
|
153
|
+
elevatorVertices.push(elevatorCenterVertex);
|
|
94
154
|
});
|
|
95
155
|
|
|
96
|
-
|
|
156
|
+
elevatorVertices.forEach(node => {
|
|
97
157
|
// We have to clone this node for each connected edge
|
|
98
|
-
OsmGraph.createNodesAndEdgesFromElevator(
|
|
158
|
+
OsmGraph.createNodesAndEdgesFromElevator(vertices, edges, node);
|
|
99
159
|
});
|
|
100
160
|
|
|
101
|
-
return new OsmGraph(
|
|
161
|
+
return new OsmGraph(vertices, edges, true);
|
|
102
162
|
}
|
|
103
163
|
|
|
104
164
|
|
|
@@ -119,69 +179,68 @@ export default class OsmGraph extends GeoGraph<OsmVertexData, OsmEdgeData> {
|
|
|
119
179
|
|
|
120
180
|
|
|
121
181
|
private static createNodesAndEdgesFromElevator(
|
|
122
|
-
|
|
182
|
+
vertices: OsmVertex[],
|
|
123
183
|
edges: OsmEdge[],
|
|
124
|
-
|
|
184
|
+
elevatorVertex: OsmVertex
|
|
125
185
|
) {
|
|
126
186
|
|
|
127
|
-
const
|
|
187
|
+
const createdVertices: OsmVertex[] = [];
|
|
128
188
|
const getOrCreateLevelVertex = (level: number | null) => {
|
|
129
|
-
let levelVertex =
|
|
189
|
+
let levelVertex = createdVertices.find(({ coords }) => Level.equals(level, coords.level));
|
|
130
190
|
if (!levelVertex) {
|
|
131
|
-
levelVertex = new GeoGraphVertex(
|
|
132
|
-
data:
|
|
133
|
-
name: `${
|
|
191
|
+
levelVertex = new GeoGraphVertex(elevatorVertex.coords.clone(), {
|
|
192
|
+
data: elevatorVertex.data,
|
|
193
|
+
name: `${elevatorVertex.name} (elevator lvl: ${level})`
|
|
134
194
|
}) as OsmVertex;
|
|
135
195
|
levelVertex.coords.level = level;
|
|
136
|
-
|
|
137
|
-
|
|
196
|
+
createdVertices.push(levelVertex);
|
|
197
|
+
vertices.push(levelVertex);
|
|
138
198
|
}
|
|
139
199
|
return levelVertex;
|
|
140
200
|
};
|
|
141
201
|
|
|
142
202
|
// Create nodes from node.edges
|
|
143
|
-
|
|
203
|
+
elevatorVertex.edges.forEach(edge => {
|
|
144
204
|
if (Level.isRange(edge.level)) {
|
|
145
205
|
throw new Error('Cannot handle this elevator edge due to ambiguity');
|
|
146
206
|
}
|
|
147
207
|
|
|
148
208
|
const levelVertex = getOrCreateLevelVertex(edge.level);
|
|
149
|
-
if (edge.vertex1 ===
|
|
209
|
+
if (edge.vertex1 === elevatorVertex) {
|
|
150
210
|
edge.vertex1 = levelVertex;
|
|
151
211
|
} else {
|
|
152
212
|
edge.vertex2 = levelVertex;
|
|
153
213
|
}
|
|
154
|
-
levelVertex.edges.push(edge);
|
|
155
214
|
});
|
|
156
215
|
|
|
157
216
|
// Create edges from createdNodes
|
|
158
|
-
for (let i = 0; i <
|
|
159
|
-
for (let j = i + 1; j <
|
|
217
|
+
for (let i = 0; i < createdVertices.length; i++) {
|
|
218
|
+
for (let j = i + 1; j < createdVertices.length; j++) {
|
|
160
219
|
|
|
161
|
-
const
|
|
162
|
-
const
|
|
220
|
+
const createdVertex1 = createdVertices[i];
|
|
221
|
+
const createdVertex2 = createdVertices[j];
|
|
163
222
|
|
|
164
|
-
if (
|
|
223
|
+
if (createdVertex1.coords.level === null || createdVertex2.coords.level === null) {
|
|
165
224
|
// TODO: not the best approach... but cannot do better with [number, number] range for levels
|
|
166
225
|
continue;
|
|
167
226
|
}
|
|
168
227
|
|
|
169
|
-
const minLevel = Math.min(
|
|
170
|
-
const maxLevel = Math.max(
|
|
228
|
+
const minLevel = Math.min(createdVertex1.coords.level as number, createdVertex2.coords.level as number);
|
|
229
|
+
const maxLevel = Math.max(createdVertex1.coords.level as number, createdVertex2.coords.level as number);
|
|
171
230
|
|
|
172
231
|
const newEdge = new GeoGraphEdge<OsmVertexData, OsmEdgeData>(
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
{ data:
|
|
232
|
+
createdVertex1,
|
|
233
|
+
createdVertex2,
|
|
234
|
+
{ data: elevatorVertex.data, name: elevatorVertex.name, level: [minLevel, maxLevel] }
|
|
176
235
|
) as OsmEdge;
|
|
177
236
|
edges.push(newEdge);
|
|
178
237
|
}
|
|
179
238
|
}
|
|
180
239
|
|
|
181
240
|
// Remove the historical elevator node from the network
|
|
182
|
-
const elevatorNodeIndex =
|
|
241
|
+
const elevatorNodeIndex = vertices.indexOf(elevatorVertex);
|
|
183
242
|
if (elevatorNodeIndex > -1) {
|
|
184
|
-
|
|
243
|
+
vertices.splice(elevatorNodeIndex, 1);
|
|
185
244
|
}
|
|
186
245
|
}
|
|
187
246
|
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import chai from 'chai';
|
|
2
|
+
import chaiAlmost from 'chai-almost';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
|
|
7
|
+
import { OsmParser } from '@wemap/osm';
|
|
8
|
+
|
|
9
|
+
import OsmRouter from './OsmRouter.js';
|
|
10
|
+
import OsmGraph from './OsmGraph.js';
|
|
11
|
+
|
|
12
|
+
const { expect } = chai;
|
|
13
|
+
chai.use(chaiAlmost(0.01));
|
|
14
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
const filePath = path.resolve(__dirname, '../../../osm/assets/elevator-models.osm');
|
|
18
|
+
const osmXmlString = fs.readFileSync(filePath, 'utf8');
|
|
19
|
+
const osmModel = OsmParser.parseOsmXmlString(osmXmlString);
|
|
20
|
+
const graph = OsmGraph.fromOsmModel(osmModel);
|
|
21
|
+
const router = new OsmRouter(graph);
|
|
22
|
+
|
|
23
|
+
const n = (nodeName: string) => graph.getVertexByName(nodeName)!.coords
|
|
24
|
+
|
|
25
|
+
describe('OsmRouter Elevators - Case 1', () => {
|
|
26
|
+
|
|
27
|
+
it('Itinerary 1', () => {
|
|
28
|
+
expect(router.getShortestPath(n('s1'), n('f1a')).edges.length).not.equals(0)
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('Itinerary 2', () => {
|
|
32
|
+
expect(router.getShortestPath(n('s1'), n('f1b')).edges.length).not.equals(0)
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('Itinerary 3', () => {
|
|
36
|
+
expect(router.getShortestPath(n('s1'), n('f1c')).edges.length).not.equals(0)
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
describe('OsmRouter Elevators - Case 2', () => {
|
|
43
|
+
|
|
44
|
+
it('Itinerary 1', () => {
|
|
45
|
+
expect(router.getShortestPath(n('s2'), n('f2a')).edges.length).not.equals(0)
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('Itinerary 2', () => {
|
|
49
|
+
expect(router.getShortestPath(n('s2'), n('f2b')).edges.length).not.equals(0)
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('Itinerary 3', () => {
|
|
53
|
+
expect(router.getShortestPath(n('s2'), n('f2c')).edges.length).not.equals(0)
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
describe('OsmRouter Elevators - Case 3', () => {
|
|
60
|
+
|
|
61
|
+
it('Itinerary 1', () => {
|
|
62
|
+
expect(router.getShortestPath(n('s3'), n('f3a')).edges.length).not.equals(0)
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('Itinerary 2', () => {
|
|
66
|
+
expect(router.getShortestPath(n('s3'), n('f3b')).edges.length).not.equals(0)
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('Itinerary 3', () => {
|
|
70
|
+
expect(router.getShortestPath(n('s3'), n('f3c')).edges.length).not.equals(0)
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe('OsmRouter Elevators - Case 4', () => {
|
|
76
|
+
|
|
77
|
+
it('Itinerary 1', () => {
|
|
78
|
+
expect(router.getShortestPath(n('s4'), n('f4a')).edges.length).not.equals(0)
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('Itinerary 2', () => {
|
|
82
|
+
expect(router.getShortestPath(n('s4'), n('f4b')).edges.length).not.equals(0)
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('Itinerary 3', () => {
|
|
86
|
+
expect(router.getShortestPath(n('s4'), n('f4c')).edges.length).not.equals(0)
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe('OsmRouter Elevators - Case 5', () => {
|
|
92
|
+
|
|
93
|
+
it('Itinerary 1', () => {
|
|
94
|
+
expect(router.getShortestPath(n('s5'), n('f5a')).edges.length).not.equals(0)
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('Itinerary 2', () => {
|
|
98
|
+
expect(router.getShortestPath(n('s5'), n('f5b')).edges.length).not.equals(0)
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('Itinerary 3', () => {
|
|
102
|
+
expect(router.getShortestPath(n('s5'), n('f5c')).edges.length).not.equals(0)
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
});
|