@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/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.2.4",
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.2",
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.2",
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": "07aa72961281f31b4c71d97e2afab2e512e76332"
55
+ "gitHead": "61e38edddc0dc58fa32750b69939a580b204442e"
56
56
  }
@@ -19,6 +19,7 @@ const levelChange2: LevelChange = {
19
19
  const levelChange3: LevelChange = {
20
20
  direction: 'up',
21
21
  difference: 3,
22
+ // TODO: change to 'escalator'
22
23
  type: 'conveyor'
23
24
  };
24
25
 
@@ -1,4 +1,5 @@
1
- export type LevelChangeType = 'elevator' | 'conveyor' | 'stairs';
1
+ // TODO: remove conveying
2
+ export type LevelChangeType = 'elevator' | 'escalator' | 'stairs' | 'moving walkway' | 'conveyor';
2
3
 
3
4
  export type LevelChange = {
4
5
  direction: 'up' | 'down';
@@ -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, GeoGraphRouterOptions } from '@wemap/geo';
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, { GeoGraphTripRouterOptions } from '../wemap-osm/OsmRouter.js';
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 : GeoGraphRouterOptions | GeoGraphTripRouterOptions
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 nodes: OsmVertex[] = [];
44
+ const vertices: OsmVertex[] = [];
45
45
  const edges: OsmEdge[] = [];
46
46
 
47
- const nodesCreated: { [key: number]: OsmVertex } = {};
48
- const elevatorNodes: OsmVertex[] = [];
47
+ const elevatorVertices: OsmVertex[] = [];
49
48
 
50
- const getOrCreateNode = (osmNode: OsmNode) => {
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
- if (osmNode.tags.highway === 'elevator') {
58
- elevatorNodes.push(node);
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 node;
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 firstNode = getOrCreateNode(way.nodes[0]);
70
- for (let i = 1; i < way.nodes.length; i++) {
71
- const secondNode = getOrCreateNode(way.nodes[i]);
72
-
73
- const edge = new GeoGraphEdge(firstNode, secondNode,
74
- { data: way, name: way.tags.name, level: way.level }
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.forEach(node => {
87
- const connectedWays = node.ways.filter(otherWay => otherWay != way);
88
- if (connectedWays.length) {
89
- const graphVertex = getOrCreateNode(node);
90
- graphVertex.data.tags.highway = 'elevator';
91
- elevatorNodes.push(graphVertex);
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
- elevatorNodes.forEach(node => {
156
+ elevatorVertices.forEach(node => {
97
157
  // We have to clone this node for each connected edge
98
- OsmGraph.createNodesAndEdgesFromElevator(nodes, edges, node);
158
+ OsmGraph.createNodesAndEdgesFromElevator(vertices, edges, node);
99
159
  });
100
160
 
101
- return new OsmGraph(nodes, edges, true);
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
- nodes: OsmVertex[],
182
+ vertices: OsmVertex[],
123
183
  edges: OsmEdge[],
124
- elevatorNode: OsmVertex
184
+ elevatorVertex: OsmVertex
125
185
  ) {
126
186
 
127
- const createdNodes: OsmVertex[] = [];
187
+ const createdVertices: OsmVertex[] = [];
128
188
  const getOrCreateLevelVertex = (level: number | null) => {
129
- let levelVertex = createdNodes.find(({ coords }) => Level.equals(level, coords.level));
189
+ let levelVertex = createdVertices.find(({ coords }) => Level.equals(level, coords.level));
130
190
  if (!levelVertex) {
131
- levelVertex = new GeoGraphVertex(elevatorNode.coords.clone(), {
132
- data: elevatorNode.data,
133
- name: `${elevatorNode.name} (elevator lvl: ${level})`
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
- createdNodes.push(levelVertex);
137
- nodes.push(levelVertex);
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
- elevatorNode.edges.forEach(edge => {
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 === elevatorNode) {
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 < createdNodes.length; i++) {
159
- for (let j = i + 1; j < createdNodes.length; j++) {
217
+ for (let i = 0; i < createdVertices.length; i++) {
218
+ for (let j = i + 1; j < createdVertices.length; j++) {
160
219
 
161
- const createdNode1 = createdNodes[i];
162
- const createdNode2 = createdNodes[j];
220
+ const createdVertex1 = createdVertices[i];
221
+ const createdVertex2 = createdVertices[j];
163
222
 
164
- if (createdNode1.coords.level === null || createdNode2.coords.level === null) {
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(createdNode1.coords.level as number, createdNode2.coords.level as number);
170
- const maxLevel = Math.max(createdNode1.coords.level as number, createdNode2.coords.level as number);
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
- createdNode1,
174
- createdNode2,
175
- { data: elevatorNode.data, name: elevatorNode.name, level: [minLevel, maxLevel] }
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 = nodes.indexOf(elevatorNode);
241
+ const elevatorNodeIndex = vertices.indexOf(elevatorVertex);
183
242
  if (elevatorNodeIndex > -1) {
184
- nodes.splice(elevatorNodeIndex, 1);
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
+ });