@wemap/routers 6.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/assets/bureaux-wemap-montpellier-network.osm +162 -0
- package/assets/gare-de-lyon-extract.osm +174 -0
- package/assets/itinerary-deutsche-bahn-1.json +368 -0
- package/assets/itinerary-grenoble-otp-1.json +1536 -0
- package/assets/itinerary-grenoble-otp-2.json +1092 -0
- package/assets/itinerary-lehavre-cityway-1.json +6799 -0
- package/assets/itinerary-lehavre-cityway-2.json +2133 -0
- package/assets/itinerary-lehavre-cityway-3.json +12577 -0
- package/assets/itinerary-lehavre-cityway-4.json +1451 -0
- package/assets/itinerary-lehavre-cityway-5.json +5925 -0
- package/assets/itinerary-montpellier-osrm-3.json +1 -0
- package/assets/itinerary-montpellier-outdoor-without-steps.json +110 -0
- package/assets/itinerary-montpellier-outdoor.json +513 -0
- package/assets/itinerary-with-duplicate-nodes.json +110 -0
- package/assets/network-conveying-backward.osm +74 -0
- package/assets/network-elevator.osm +48 -0
- package/assets/network-simple.osm +27 -0
- package/assets/network-with-modifiers.osm +39 -0
- package/assets/one-way.osm +46 -0
- package/dist/wemap-osm.es.js +2012 -0
- package/dist/wemap-osm.es.js.map +1 -0
- package/index.js +24 -0
- package/package.json +35 -0
- package/src/ItineraryInfoManager.js +148 -0
- package/src/ItineraryInfoManager.spec.js +54 -0
- package/src/Utils.js +64 -0
- package/src/cityway/CitywayUtils.js +240 -0
- package/src/cityway/CitywayUtils.spec.js +109 -0
- package/src/deutsche-bahn/DeutscheBahnRouterUtils.js +91 -0
- package/src/deutsche-bahn/DeutscheBahnRouterUtils.spec.js +54 -0
- package/src/model/Itinerary.js +197 -0
- package/src/model/Itinerary.type.spec.js +105 -0
- package/src/model/ItineraryInfo.js +34 -0
- package/src/model/Leg.js +113 -0
- package/src/model/LevelChange.js +65 -0
- package/src/model/RouterResponse.js +19 -0
- package/src/model/RouterResponse.type.spec.js +24 -0
- package/src/model/Step.js +118 -0
- package/src/osrm/OsrmUtils.js +269 -0
- package/src/osrm/OsrmUtils.spec.js +457 -0
- package/src/otp/OtpUtils.js +150 -0
- package/src/otp/OtpUtils.spec.js +97 -0
- package/src/wemap/WemapNetworkUtils.js +195 -0
- package/src/wemap/WemapNetworkUtils.spec.js +109 -0
- package/src/wemap/WemapRouter.js +27 -0
- package/src/wemap/WemapRouter.spec.js +221 -0
- package/src/wemap/WemapRouterOptions.js +32 -0
- package/src/wemap/WemapRouterUtils.js +46 -0
- package/src/wemap/WemapStepsGeneration.js +104 -0
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
/* eslint-disable max-statements */
|
|
2
|
+
import chai from 'chai';
|
|
3
|
+
import chaiAlmost from 'chai-almost';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
|
|
8
|
+
import { Coordinates } from '@wemap/geo';
|
|
9
|
+
// import { verifyCoherence } from '@wemap/geo/tests/CommonTest.js';
|
|
10
|
+
|
|
11
|
+
// import OsmParser from '../../model/OsmParser.js';
|
|
12
|
+
// import OsmNetworkUtils from '../../network/OsmNetworkUtils.js';
|
|
13
|
+
import {
|
|
14
|
+
// itineraryToOsrmJson,
|
|
15
|
+
// jsonToCoordinates,
|
|
16
|
+
// createItineraryFromJson,
|
|
17
|
+
// getModifierFromAngle,
|
|
18
|
+
// noRouteFoundJson,
|
|
19
|
+
createRouterResponseFromJson
|
|
20
|
+
} from './OsrmUtils.js';
|
|
21
|
+
|
|
22
|
+
import { verifyRouterResponseData } from '../model/RouterResponse.type.spec.js';
|
|
23
|
+
|
|
24
|
+
const { expect } = chai;
|
|
25
|
+
chai.use(chaiAlmost(0.1));
|
|
26
|
+
|
|
27
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
// const load = fileName => {
|
|
31
|
+
// const filePath = path.resolve(__dirname, '../../../assets/' + fileName);
|
|
32
|
+
// const osmXmlString = fs.readFileSync(filePath, 'utf8');
|
|
33
|
+
// const model = OsmParser.parseOsmXmlString(osmXmlString);
|
|
34
|
+
// const network = OsmNetworkUtils.createNetworkFromOsmModel(model);
|
|
35
|
+
// const router = new GraphRouter(network);
|
|
36
|
+
// return {
|
|
37
|
+
// network,
|
|
38
|
+
// router
|
|
39
|
+
// };
|
|
40
|
+
// };
|
|
41
|
+
|
|
42
|
+
// let wemapIndoorItinerary, wemapIndoorJsonItinerary, wemapIndoorStart, wemapIndoorEnd;
|
|
43
|
+
// let wemapOutdoorItinerary, wemapOutdoorJsonItinerary, wemapOutdoorStart, wemapOutdoorEnd;
|
|
44
|
+
|
|
45
|
+
// describe('OsrmUtils - itineraryToOsrmJson', () => {
|
|
46
|
+
|
|
47
|
+
// it('With levels (Bureaux Wemap)', () => {
|
|
48
|
+
|
|
49
|
+
// const {
|
|
50
|
+
// network, router
|
|
51
|
+
// } = load('bureaux-wemap-montpellier-network.osm');
|
|
52
|
+
|
|
53
|
+
// wemapIndoorStart = new Coordinates(43.6092754, 3.8842306, null, new Level(2));
|
|
54
|
+
// wemapIndoorEnd = new Coordinates(43.6092602, 3.8842669, null, new Level(1));
|
|
55
|
+
// const itinerary = router.getShortestPath(wemapIndoorStart, wemapIndoorEnd);
|
|
56
|
+
// wemapIndoorItinerary = itinerary;
|
|
57
|
+
|
|
58
|
+
// const osrmJson = itineraryToOsrmJson(itinerary);
|
|
59
|
+
// wemapIndoorJsonItinerary = osrmJson;
|
|
60
|
+
// const itinerarySteps = itinerary.steps;
|
|
61
|
+
|
|
62
|
+
// const {
|
|
63
|
+
// geometry, legs
|
|
64
|
+
// } = osrmJson.routes[0];
|
|
65
|
+
|
|
66
|
+
// /**
|
|
67
|
+
// * Verify if JSON geometry corresponds to Itinerary points
|
|
68
|
+
// */
|
|
69
|
+
// const { coordinates } = geometry;
|
|
70
|
+
// expect(coordinates.length).equal(11);
|
|
71
|
+
// for (let i = 1; i < 11; i++) {
|
|
72
|
+
// expect(
|
|
73
|
+
// network.getNodeByName('p' + (i + 6)).coords.equalsTo(
|
|
74
|
+
// jsonToCoordinates(coordinates[i]))
|
|
75
|
+
// ).true;
|
|
76
|
+
// }
|
|
77
|
+
|
|
78
|
+
// /**
|
|
79
|
+
// * Verify location, type and modifier of each step
|
|
80
|
+
// */
|
|
81
|
+
// const { steps } = legs[0];
|
|
82
|
+
// for (let i = 0; i < steps.length; i++) {
|
|
83
|
+
// const {
|
|
84
|
+
// location, type
|
|
85
|
+
// } = steps[i].maneuver;
|
|
86
|
+
// expect(itinerarySteps[i].node.coords.equalsTo(jsonToCoordinates(location))).true;
|
|
87
|
+
|
|
88
|
+
// let expectedType;
|
|
89
|
+
// switch (i) {
|
|
90
|
+
// case 0:
|
|
91
|
+
// expectedType = 'depart';
|
|
92
|
+
// break;
|
|
93
|
+
// case steps.length - 1:
|
|
94
|
+
// expectedType = 'arrive';
|
|
95
|
+
// break;
|
|
96
|
+
// default:
|
|
97
|
+
// expectedType = 'turn';
|
|
98
|
+
// }
|
|
99
|
+
// expect(type).equals(expectedType);
|
|
100
|
+
// }
|
|
101
|
+
|
|
102
|
+
// // The first modifier is not mandatory by OSRM.
|
|
103
|
+
// expect(steps[0].maneuver.modifier).equals('left');
|
|
104
|
+
// expect(steps[0].distance).be.closeTo(2.33, 0.01);
|
|
105
|
+
// expect(steps[0].maneuver.bearing_after).be.closeTo(11.90, 0.01);
|
|
106
|
+
|
|
107
|
+
// expect(steps[1].maneuver.modifier).equals('right');
|
|
108
|
+
// expect(steps[1].distance).be.closeTo(1.76, 0.01);
|
|
109
|
+
// expect(steps[1].maneuver.bearing_after).be.closeTo(56.90, 0.01);
|
|
110
|
+
|
|
111
|
+
// expect(steps[2].maneuver.modifier).equals('left');
|
|
112
|
+
// expect(steps[2].distance).be.closeTo(1.15, 0.01);
|
|
113
|
+
// expect(steps[2].maneuver.bearing_after).be.closeTo(11.90, 0.01);
|
|
114
|
+
|
|
115
|
+
// expect(steps[3].maneuver.modifier).equals('left');
|
|
116
|
+
// expect(steps[3].distance).be.closeTo(5.95, 0.01);
|
|
117
|
+
// expect(steps[3].maneuver.bearing_after).be.closeTo(281.93, 0.01);
|
|
118
|
+
|
|
119
|
+
// expect(steps[4].maneuver.modifier).equals('right');
|
|
120
|
+
// expect(steps[4].distance).be.closeTo(10.71, 0.01);
|
|
121
|
+
// expect(steps[4].maneuver.bearing_after).be.closeTo(12.22, 0.01);
|
|
122
|
+
// expect(steps[4].levelChange).is.not.null;
|
|
123
|
+
// expect(steps[4].levelChange.direction).equals('down');
|
|
124
|
+
// expect(steps[4].levelChange.difference).equals(-1);
|
|
125
|
+
// expect(steps[4].levelChange.type).equals('stairs');
|
|
126
|
+
|
|
127
|
+
// expect(steps[5].maneuver.modifier).equals('left');
|
|
128
|
+
// expect(steps[5].distance).be.closeTo(4.23, 0.01);
|
|
129
|
+
// expect(steps[5].maneuver.bearing_after).be.closeTo(102.00, 0.01);
|
|
130
|
+
|
|
131
|
+
// expect(steps[6].maneuver.modifier).equals('right');
|
|
132
|
+
// expect(steps[6].distance).be.closeTo(5.03, 0.01);
|
|
133
|
+
// expect(steps[6].maneuver.bearing_after).be.closeTo(191.75, 0.01);
|
|
134
|
+
|
|
135
|
+
// expect(steps[7].maneuver.modifier).equals('left');
|
|
136
|
+
// expect(steps[7].distance).be.closeTo(0, 0.01);
|
|
137
|
+
// expect(steps[7].maneuver.bearing_after).be.closeTo(0, 0.01);
|
|
138
|
+
|
|
139
|
+
// });
|
|
140
|
+
|
|
141
|
+
// it('Without levels', () => {
|
|
142
|
+
|
|
143
|
+
// const {
|
|
144
|
+
// network, router
|
|
145
|
+
// } = load('network-simple.osm');
|
|
146
|
+
|
|
147
|
+
// const start = network.getNodeByName('p1');
|
|
148
|
+
// const end = network.getNodeByName('p3');
|
|
149
|
+
|
|
150
|
+
// const itinerary = router.getShortestPath(start, end);
|
|
151
|
+
|
|
152
|
+
// wemapOutdoorJsonItinerary = itineraryToOsrmJson(itinerary);
|
|
153
|
+
|
|
154
|
+
// wemapOutdoorStart = start.coords;
|
|
155
|
+
// wemapOutdoorEnd = end.coords;
|
|
156
|
+
// wemapOutdoorItinerary = itinerary;
|
|
157
|
+
// });
|
|
158
|
+
|
|
159
|
+
// it('Itinerary with modifiers', () => {
|
|
160
|
+
|
|
161
|
+
// const {
|
|
162
|
+
// network, router
|
|
163
|
+
// } = load('network-with-modifiers.osm');
|
|
164
|
+
|
|
165
|
+
// const start = network.getNodeByName('start');
|
|
166
|
+
// const end = network.getNodeByName('end');
|
|
167
|
+
|
|
168
|
+
// const itinerary = router.getShortestPath(start, end);
|
|
169
|
+
// expect(() => itineraryToOsrmJson(itinerary)).not.throw(Error);
|
|
170
|
+
|
|
171
|
+
// });
|
|
172
|
+
|
|
173
|
+
// });
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
// describe('OsrmUtils - createItineraryFromJson', () => {
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
// it('Without levels (Montpellier outdoor)', () => {
|
|
180
|
+
|
|
181
|
+
// const filePath = path.resolve(__dirname, '../../../assets/itinerary-montpellier-outdoor.json');
|
|
182
|
+
// const fileString = fs.readFileSync(filePath, 'utf8');
|
|
183
|
+
|
|
184
|
+
// const json = JSON.parse(fileString);
|
|
185
|
+
|
|
186
|
+
// const start = new Coordinates(43.6007871, 3.8757218000000004);
|
|
187
|
+
// const end = new Coordinates(43.598877, 3.873866);
|
|
188
|
+
|
|
189
|
+
// const itinerary = createItineraryFromJson(json, start, end);
|
|
190
|
+
|
|
191
|
+
// expect(json.routes[0].geometry.coordinates.length).equal(itinerary.nodes.length);
|
|
192
|
+
// expect(itinerary.nodes.length).equal(itinerary.edges.length + 1);
|
|
193
|
+
// expect(itinerary.nodes.length).equal(19);
|
|
194
|
+
|
|
195
|
+
// const { steps } = itinerary;
|
|
196
|
+
// expect(steps.length).equal(5);
|
|
197
|
+
|
|
198
|
+
// let step;
|
|
199
|
+
// step = steps[0];
|
|
200
|
+
// expect(Coordinates.equalsTo(step.location, new Coordinates(43.600777, 3.875607))).true;
|
|
201
|
+
// expect(getModifierFromAngle(step.angle)).equals('left');
|
|
202
|
+
// expect(step.nodes.length).equals(6);
|
|
203
|
+
// expect(step.edges.length).equals(5);
|
|
204
|
+
// expect(step.firstStep).true;
|
|
205
|
+
// expect(step.lastStep).false;
|
|
206
|
+
// expect(step.name).equals('');
|
|
207
|
+
|
|
208
|
+
// step = steps[1];
|
|
209
|
+
// expect(Coordinates.equalsTo(step.location, new Coordinates(43.599881, 3.876396))).true;
|
|
210
|
+
// expect(getModifierFromAngle(step.angle)).equals('right');
|
|
211
|
+
// expect(step.nodes.length).equals(12);
|
|
212
|
+
// expect(step.edges.length).equals(11);
|
|
213
|
+
// expect(step.firstStep).false;
|
|
214
|
+
// expect(step.lastStep).false;
|
|
215
|
+
// expect(step.name).equals('Boulevard Vieussens');
|
|
216
|
+
|
|
217
|
+
// step = steps[2];
|
|
218
|
+
// expect(Coordinates.equalsTo(step.location, new Coordinates(43.599577, 3.874655))).true;
|
|
219
|
+
// expect(getModifierFromAngle(step.angle)).equals('left');
|
|
220
|
+
// expect(step.nodes.length).equals(2);
|
|
221
|
+
// expect(step.edges.length).equals(1);
|
|
222
|
+
// expect(step.firstStep).false;
|
|
223
|
+
// expect(step.lastStep).false;
|
|
224
|
+
// expect(step.name).equals('Impasse Bizeray');
|
|
225
|
+
|
|
226
|
+
// step = steps[3];
|
|
227
|
+
// expect(Coordinates.equalsTo(step.location, new Coordinates(43.599063, 3.874623))).true;
|
|
228
|
+
// expect(getModifierFromAngle(step.angle)).equals('right');
|
|
229
|
+
// expect(step.nodes.length).equals(2);
|
|
230
|
+
// expect(step.edges.length).equals(1);
|
|
231
|
+
// expect(step.firstStep).false;
|
|
232
|
+
// expect(step.lastStep).false;
|
|
233
|
+
// expect(step.name).equals('Rue du Docteur Louis Perrier');
|
|
234
|
+
|
|
235
|
+
// step = steps[4];
|
|
236
|
+
// expect(Coordinates.equalsTo(step.location, new Coordinates(43.59906, 3.873865))).true;
|
|
237
|
+
// expect(getModifierFromAngle(step.angle)).equals('left');
|
|
238
|
+
// expect(step.nodes.length).equals(1);
|
|
239
|
+
// expect(step.edges.length).equals(0);
|
|
240
|
+
// expect(step.firstStep).false;
|
|
241
|
+
// expect(step.lastStep).true;
|
|
242
|
+
// expect(step.name).equals('Rue du Docteur Louis Perrier');
|
|
243
|
+
|
|
244
|
+
// expect(itinerary._nextStepsIndexes.length).equals(itinerary.nodes.length);
|
|
245
|
+
// expect(itinerary._nextStepsIndexes[0]).equals(0);
|
|
246
|
+
// for (let i = 1; i <= 5; i++) {
|
|
247
|
+
// expect(itinerary._nextStepsIndexes[i]).equals(1);
|
|
248
|
+
// }
|
|
249
|
+
// for (let i = 6; i <= 16; i++) {
|
|
250
|
+
// expect(itinerary._nextStepsIndexes[i]).equals(2);
|
|
251
|
+
// }
|
|
252
|
+
// expect(itinerary._nextStepsIndexes[17]).equals(3);
|
|
253
|
+
// expect(itinerary._nextStepsIndexes[18]).equals(4);
|
|
254
|
+
// });
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
// it('Without levels (from itineraryToOsrmJson)', () => {
|
|
258
|
+
|
|
259
|
+
// const itinerary = createItineraryFromJson(wemapOutdoorJsonItinerary,
|
|
260
|
+
// wemapOutdoorStart, wemapOutdoorEnd);
|
|
261
|
+
|
|
262
|
+
// expect(itinerary.nodes.length).equal(wemapOutdoorItinerary.nodes.length);
|
|
263
|
+
// for (let i = 0; i < itinerary.nodes.length; i++) {
|
|
264
|
+
// const itineraryNode = itinerary.nodes[i];
|
|
265
|
+
// const wemapItineraryNode = wemapOutdoorItinerary.nodes[i];
|
|
266
|
+
// expect(itineraryNode.coords.equalsTo(wemapItineraryNode.coords)).true;
|
|
267
|
+
// }
|
|
268
|
+
|
|
269
|
+
// expect(itinerary.edges.length).equal(wemapOutdoorItinerary.edges.length);
|
|
270
|
+
// for (let i = 0; i < itinerary.edges.length; i++) {
|
|
271
|
+
// const itineraryEdge = itinerary.edges[i];
|
|
272
|
+
// const wemapItineraryEdge = wemapOutdoorItinerary.edges[i];
|
|
273
|
+
// const firstNode = wemapItineraryEdge[wemapOutdoorItinerary._edgesDirectionReversed[i] ? 'node2' : 'node1'];
|
|
274
|
+
// const secondNode = wemapItineraryEdge[wemapOutdoorItinerary._edgesDirectionReversed[i] ? 'node1' : 'node2'];
|
|
275
|
+
// expect(itineraryEdge.node1.coords.equalsTo(firstNode.coords)).true;
|
|
276
|
+
// expect(itineraryEdge.node2.coords.equalsTo(secondNode.coords)).true;
|
|
277
|
+
// expect(Level.equalsTo(itineraryEdge.level, wemapItineraryEdge.level)).true;
|
|
278
|
+
// }
|
|
279
|
+
|
|
280
|
+
// });
|
|
281
|
+
|
|
282
|
+
// it('Without steps (Montpellier outdoor)', () => {
|
|
283
|
+
|
|
284
|
+
// const filePath = path.resolve(__dirname,
|
|
285
|
+
// '../../../assets/itinerary-montpellier-outdoor-without-steps.json');
|
|
286
|
+
// const fileString = fs.readFileSync(filePath, 'utf8');
|
|
287
|
+
|
|
288
|
+
// const json = JSON.parse(fileString);
|
|
289
|
+
|
|
290
|
+
// const start = new Coordinates(43.6007871, 3.8757218000000004);
|
|
291
|
+
// const end = new Coordinates(43.598877, 3.873866);
|
|
292
|
+
|
|
293
|
+
// const itinerary = createItineraryFromJson(json, start, end);
|
|
294
|
+
|
|
295
|
+
// expect(json.routes[0].geometry.coordinates.length).equal(itinerary.nodes.length);
|
|
296
|
+
// expect(itinerary.nodes.length).equal(itinerary.edges.length + 1);
|
|
297
|
+
// expect(itinerary.nodes.length).equal(19);
|
|
298
|
+
|
|
299
|
+
// const { steps } = itinerary;
|
|
300
|
+
// expect(steps.length).equal(7);
|
|
301
|
+
// });
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
// it('With levels (from itineraryToOsrmJson)', () => {
|
|
305
|
+
|
|
306
|
+
// const itinerary = createItineraryFromJson(wemapIndoorJsonItinerary,
|
|
307
|
+
// wemapIndoorStart, wemapIndoorEnd);
|
|
308
|
+
|
|
309
|
+
// expect(itinerary.nodes.length).equal(wemapIndoorItinerary.nodes.length);
|
|
310
|
+
// for (let i = 0; i < itinerary.nodes.length; i++) {
|
|
311
|
+
// const itineraryNode = itinerary.nodes[i];
|
|
312
|
+
// const wemapItineraryNode = wemapIndoorItinerary.nodes[i];
|
|
313
|
+
// expect(itineraryNode.coords.equalsTo(wemapItineraryNode.coords)).true;
|
|
314
|
+
// }
|
|
315
|
+
|
|
316
|
+
// expect(itinerary.edges.length).equal(wemapIndoorItinerary.edges.length);
|
|
317
|
+
// for (let i = 0; i < itinerary.edges.length; i++) {
|
|
318
|
+
// const itineraryEdge = itinerary.edges[i];
|
|
319
|
+
// const wemapItineraryEdge = wemapIndoorItinerary.edges[i];
|
|
320
|
+
// const firstNode = wemapItineraryEdge[wemapIndoorItinerary._edgesDirectionReversed[i] ? 'node2' : 'node1'];
|
|
321
|
+
// const secondNode = wemapItineraryEdge[wemapIndoorItinerary._edgesDirectionReversed[i] ? 'node1' : 'node2'];
|
|
322
|
+
// expect(itineraryEdge.node1.coords.equalsTo(firstNode.coords)).true;
|
|
323
|
+
// expect(itineraryEdge.node2.coords.equalsTo(secondNode.coords)).true;
|
|
324
|
+
// expect(Level.equalsTo(itineraryEdge.level, wemapItineraryEdge.level)).true;
|
|
325
|
+
// }
|
|
326
|
+
|
|
327
|
+
// });
|
|
328
|
+
|
|
329
|
+
// it('Errored (Montpellier outdoor)', () => {
|
|
330
|
+
|
|
331
|
+
// const filePath = path.resolve(__dirname,
|
|
332
|
+
// '../../../assets/itinerary-with-duplicate-nodes.json');
|
|
333
|
+
// const fileString = fs.readFileSync(filePath, 'utf8');
|
|
334
|
+
|
|
335
|
+
// const json = JSON.parse(fileString);
|
|
336
|
+
|
|
337
|
+
// const start = new Coordinates(44.810569099999995, 4.9503924999999995);
|
|
338
|
+
// const end = new Coordinates(44.302673, 4.556377);
|
|
339
|
+
|
|
340
|
+
// const itinerary = createItineraryFromJson(json, start, end);
|
|
341
|
+
// itinerary.edges.forEach(edge => {
|
|
342
|
+
// expect(edge).instanceOf(Edge);
|
|
343
|
+
// });
|
|
344
|
+
// itinerary.steps.forEach(step => {
|
|
345
|
+
// step.edges.forEach(edge => {
|
|
346
|
+
// expect(edge).instanceOf(Edge);
|
|
347
|
+
// });
|
|
348
|
+
// });
|
|
349
|
+
// });
|
|
350
|
+
|
|
351
|
+
// });
|
|
352
|
+
|
|
353
|
+
// describe('OsrmUtils - itineraryToOsrmJson - createItineraryFromJson - way/node', () => {
|
|
354
|
+
|
|
355
|
+
// it('With levels (Bureaux Wemap)', () => {
|
|
356
|
+
|
|
357
|
+
// const { router } = load('bureaux-wemap-montpellier-network.osm');
|
|
358
|
+
|
|
359
|
+
// const start = new Coordinates(43.6092754, 3.8842306, null, new Level(2));
|
|
360
|
+
// const end = new Coordinates(43.60949854, 3.88452048, null, new Level(0));
|
|
361
|
+
// const itinerary = router.getShortestPath(start, end);
|
|
362
|
+
|
|
363
|
+
// const osrmJson = itineraryToOsrmJson(itinerary);
|
|
364
|
+
// const jsonSteps = osrmJson.routes[0].legs[0].steps;
|
|
365
|
+
|
|
366
|
+
// expect(jsonSteps[0].name).equals('w2');
|
|
367
|
+
// expect(jsonSteps[4].name).equals('p19');
|
|
368
|
+
// expect(jsonSteps[6].name).equals('p21');
|
|
369
|
+
|
|
370
|
+
// const itineraryBis = createItineraryFromJson(osrmJson, start, end);
|
|
371
|
+
// verifyCoherence(itineraryBis);
|
|
372
|
+
|
|
373
|
+
// expect(itineraryBis.nodes.length).equals(itinerary.nodes.length);
|
|
374
|
+
// expect(itineraryBis.edges.length).equals(itinerary.edges.length);
|
|
375
|
+
// expect(itineraryBis.steps.length).equals(itinerary.steps.length);
|
|
376
|
+
// });
|
|
377
|
+
// });
|
|
378
|
+
|
|
379
|
+
// describe('OsrmUtils - Output JSON', () => {
|
|
380
|
+
|
|
381
|
+
// it('noRouteFoundJson', () => {
|
|
382
|
+
// expect(noRouteFoundJson('foo')).deep.equals({
|
|
383
|
+
// 'code': 'NoRoute',
|
|
384
|
+
// 'message': 'foo'
|
|
385
|
+
// });
|
|
386
|
+
// });
|
|
387
|
+
|
|
388
|
+
// });
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
describe('OsrmUtils - createRouterResponseFromJson', () => {
|
|
392
|
+
|
|
393
|
+
it('RouterResponse - 1', () => {
|
|
394
|
+
|
|
395
|
+
const filePath = path.resolve(__dirname, '../../assets/itinerary-montpellier-outdoor.json');
|
|
396
|
+
const fileString = fs.readFileSync(filePath, 'utf8');
|
|
397
|
+
const json = JSON.parse(fileString);
|
|
398
|
+
|
|
399
|
+
const from = new Coordinates(43.6007871, 3.8757218000000004);
|
|
400
|
+
const to = new Coordinates(43.598877, 3.873866);
|
|
401
|
+
const routerResponse = createRouterResponseFromJson(json, from, to);
|
|
402
|
+
verifyRouterResponseData(routerResponse);
|
|
403
|
+
|
|
404
|
+
expect(routerResponse.routerName).equal('osrm');
|
|
405
|
+
expect(routerResponse.itineraries.length).equal(1);
|
|
406
|
+
expect(routerResponse.from.equalsTo(from)).true;
|
|
407
|
+
expect(routerResponse.to.equalsTo(to)).true;
|
|
408
|
+
|
|
409
|
+
const itinerary1 = routerResponse.itineraries[0];
|
|
410
|
+
expect(itinerary1.distance).equal(399.7);
|
|
411
|
+
expect(itinerary1.duration).equal(287.8);
|
|
412
|
+
expect(itinerary1.startTime).is.null;
|
|
413
|
+
expect(itinerary1.endTime).is.null;
|
|
414
|
+
expect(itinerary1.legs.length).equal(1);
|
|
415
|
+
expect(itinerary1.coords.length).equal(19);
|
|
416
|
+
|
|
417
|
+
const itinerary1leg1 = itinerary1.legs[0];
|
|
418
|
+
expect(itinerary1leg1.startTime).is.null;
|
|
419
|
+
expect(itinerary1leg1.endTime).is.null;
|
|
420
|
+
expect(itinerary1leg1.distance).equal(399.7);
|
|
421
|
+
expect(itinerary1leg1.duration).equal(287.8);
|
|
422
|
+
expect(itinerary1leg1.mode).equal('WALK');
|
|
423
|
+
expect(itinerary1leg1.transportInfo).is.null;
|
|
424
|
+
expect(itinerary1leg1.from.name).is.null;
|
|
425
|
+
expect(itinerary1leg1.from.coords.equalsTo(new Coordinates(43.600777, 3.875607))).true;
|
|
426
|
+
expect(itinerary1leg1.to.name).is.null;
|
|
427
|
+
expect(itinerary1leg1.to.coords.equalsTo(new Coordinates(43.59906, 3.873865))).true;
|
|
428
|
+
expect(itinerary1leg1.coords.length).equal(19);
|
|
429
|
+
expect(itinerary1leg1.coords).deep.equal(itinerary1.coords);
|
|
430
|
+
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
it('RouterResponse - 2', () => {
|
|
435
|
+
|
|
436
|
+
const filePath = path.resolve(__dirname, '../../assets/itinerary-montpellier-osrm-3.json');
|
|
437
|
+
const fileString = fs.readFileSync(filePath, 'utf8');
|
|
438
|
+
const json = JSON.parse(fileString);
|
|
439
|
+
|
|
440
|
+
const from = new Coordinates(43.605663, 3.887244);
|
|
441
|
+
const to = new Coordinates(43.6054106, 3.8878106);
|
|
442
|
+
const routerResponse = createRouterResponseFromJson(json, from, to);
|
|
443
|
+
verifyRouterResponseData(routerResponse);
|
|
444
|
+
|
|
445
|
+
expect(routerResponse.routerName).equal('osrm');
|
|
446
|
+
expect(routerResponse.itineraries.length).equal(1);
|
|
447
|
+
expect(routerResponse.from.equalsTo(from)).true;
|
|
448
|
+
expect(routerResponse.to.equalsTo(to)).true;
|
|
449
|
+
|
|
450
|
+
const steps = routerResponse.itineraries[0].steps;
|
|
451
|
+
expect(steps.length).equal(2);
|
|
452
|
+
expect(steps[1].angle).almost.equal(1.575);
|
|
453
|
+
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
});
|
|
457
|
+
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/* eslint-disable max-statements */
|
|
2
|
+
import Polyline from '@mapbox/polyline';
|
|
3
|
+
|
|
4
|
+
import { Coordinates } from '@wemap/geo';
|
|
5
|
+
|
|
6
|
+
import Itinerary from '../model/Itinerary.js';
|
|
7
|
+
import Leg from '../model/Leg.js';
|
|
8
|
+
import RouterResponse from '../model/RouterResponse.js';
|
|
9
|
+
import Step from '../model/Step.js';
|
|
10
|
+
import { generateStepsMetadata } from '../Utils.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @param {object} json
|
|
14
|
+
* @returns {Coordinates}
|
|
15
|
+
*/
|
|
16
|
+
export function jsonToCoordinates(json) {
|
|
17
|
+
return new Coordinates(json.lat, json.lon);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {object} jsonSteps
|
|
22
|
+
* @param {Coordinates[]} legCoords
|
|
23
|
+
* @returns {Step[]}
|
|
24
|
+
*/
|
|
25
|
+
function parseJsonSteps(jsonSteps, legCoords) {
|
|
26
|
+
|
|
27
|
+
if (!jsonSteps) {
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return jsonSteps.map(jsonStep => {
|
|
32
|
+
|
|
33
|
+
const step = new Step();
|
|
34
|
+
const stepCoords = jsonToCoordinates(jsonStep);
|
|
35
|
+
|
|
36
|
+
// OTP step does not have the same coordinates than a point in legCoords.
|
|
37
|
+
// That is why we look for the closest point.
|
|
38
|
+
const distances = legCoords.map(coords => coords.distanceTo(stepCoords));
|
|
39
|
+
const idStepCoordsInLeg = distances.indexOf(Math.min(...distances));
|
|
40
|
+
if (idStepCoordsInLeg < 0) {
|
|
41
|
+
throw new Error('OTP Parser: Cannot find closest step');
|
|
42
|
+
}
|
|
43
|
+
step.coords = legCoords[idStepCoordsInLeg];
|
|
44
|
+
step._idCoordsInLeg = idStepCoordsInLeg;
|
|
45
|
+
|
|
46
|
+
step.name = jsonStep.streetName;
|
|
47
|
+
step.levelChange = null;
|
|
48
|
+
|
|
49
|
+
step.distance = jsonStep.distance;
|
|
50
|
+
|
|
51
|
+
return step;
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Generate multi itineraries from OTP JSON
|
|
57
|
+
* @param {object} json JSON file provided by OTP.
|
|
58
|
+
* @returns {?RouterResponse}
|
|
59
|
+
*/
|
|
60
|
+
export function createRouterResponseFromJson(json) {
|
|
61
|
+
|
|
62
|
+
const { plan: jsonPlan } = json;
|
|
63
|
+
|
|
64
|
+
if (!jsonPlan) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const routerResponse = new RouterResponse();
|
|
69
|
+
routerResponse.routerName = 'otp';
|
|
70
|
+
|
|
71
|
+
routerResponse.from = jsonToCoordinates(jsonPlan.from);
|
|
72
|
+
routerResponse.to = jsonToCoordinates(jsonPlan.to);
|
|
73
|
+
|
|
74
|
+
for (const jsonItinerary of jsonPlan.itineraries) {
|
|
75
|
+
|
|
76
|
+
const itinerary = new Itinerary();
|
|
77
|
+
|
|
78
|
+
itinerary.duration = jsonItinerary.duration;
|
|
79
|
+
itinerary.startTime = jsonItinerary.startTime;
|
|
80
|
+
itinerary.endTime = jsonItinerary.endTime;
|
|
81
|
+
itinerary.from = routerResponse.from;
|
|
82
|
+
itinerary.to = routerResponse.to;
|
|
83
|
+
|
|
84
|
+
routerResponse.itineraries.push(itinerary);
|
|
85
|
+
|
|
86
|
+
for (const jsonLeg of jsonItinerary.legs) {
|
|
87
|
+
|
|
88
|
+
const leg = new Leg();
|
|
89
|
+
|
|
90
|
+
leg.mode = jsonLeg.mode;
|
|
91
|
+
leg.duration = jsonLeg.duration;
|
|
92
|
+
leg.startTime = jsonLeg.startTime;
|
|
93
|
+
leg.endTime = jsonLeg.endTime;
|
|
94
|
+
leg.from = {
|
|
95
|
+
name: jsonLeg.from.name,
|
|
96
|
+
coords: jsonToCoordinates(jsonLeg.from)
|
|
97
|
+
};
|
|
98
|
+
leg.to = {
|
|
99
|
+
name: jsonLeg.to.name,
|
|
100
|
+
coords: jsonToCoordinates(jsonLeg.to)
|
|
101
|
+
};
|
|
102
|
+
leg.coords = Polyline.decode(jsonLeg.legGeometry.points).map(([lat, lon]) => new Coordinates(lat, lon));
|
|
103
|
+
|
|
104
|
+
leg.steps = parseJsonSteps(jsonLeg.steps, leg.coords);
|
|
105
|
+
|
|
106
|
+
if (leg.mode === 'BUS' || leg.mode === 'TRAM') {
|
|
107
|
+
leg.transportInfo = {
|
|
108
|
+
name: jsonLeg.route,
|
|
109
|
+
routeColor: jsonLeg.routeColor,
|
|
110
|
+
routeTextColor: jsonLeg.routeTextColor,
|
|
111
|
+
directionName: jsonLeg.headsign
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const legStep = new Step();
|
|
115
|
+
legStep.coords = leg.coords[0];
|
|
116
|
+
legStep._idCoordsInLeg = 0;
|
|
117
|
+
legStep.name = jsonLeg.headsign;
|
|
118
|
+
legStep.levelChange = null;
|
|
119
|
+
legStep.distance = jsonLeg.distance;
|
|
120
|
+
leg.steps = [legStep];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// jsonLeg.distance is not reliable when compared to the array of leg coords.
|
|
124
|
+
// leg.distance = jsonLeg.distance;
|
|
125
|
+
leg.distance = leg.coords.reduce((acc, coords, idx, arr) => {
|
|
126
|
+
if (idx === 0) {
|
|
127
|
+
return acc;
|
|
128
|
+
}
|
|
129
|
+
return acc + arr[idx - 1].distanceTo(coords);
|
|
130
|
+
}, 0);
|
|
131
|
+
|
|
132
|
+
itinerary.legs.push(leg);
|
|
133
|
+
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
itinerary.distance = itinerary.coords.reduce((acc, coords, idx, arr) => {
|
|
137
|
+
if (idx === 0) {
|
|
138
|
+
return acc;
|
|
139
|
+
}
|
|
140
|
+
return acc + arr[idx - 1].distanceTo(coords);
|
|
141
|
+
}, 0);
|
|
142
|
+
|
|
143
|
+
// All legs have to be parsed before computing steps metadata
|
|
144
|
+
generateStepsMetadata(itinerary);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return routerResponse;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
|