@wemap/routers 7.1.1 → 7.2.1
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/rr-wemap-meta-multi-level.json +256 -0
- package/dist/wemap-routers.es.js +3691 -0
- package/dist/wemap-routers.es.js.map +1 -0
- package/package.json +4 -4
- package/src/Utils.js +55 -0
- package/src/Utils.spec.js +60 -0
- package/src/remote/RemoteRouterUtils.js +11 -0
- package/src/remote/idfm/IdfmRemoteRouter.js +36 -13
- package/src/wemap-meta/WemapMetaRouter.js +78 -63
package/src/Utils.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
|
|
2
|
+
import RouterResponse from './model/RouterResponse.js';
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* Get route duration
|
|
3
6
|
* @param {Number} speed in km/h
|
|
@@ -6,3 +9,55 @@
|
|
|
6
9
|
export function getDurationFromLength(length, speed = 5) {
|
|
7
10
|
return length / (speed * 1000 / 3600);
|
|
8
11
|
}
|
|
12
|
+
|
|
13
|
+
/* eslint-disable max-statements */
|
|
14
|
+
/* eslint-disable max-depth */
|
|
15
|
+
/**
|
|
16
|
+
* @param {RouterResponse} routerResponse
|
|
17
|
+
* @param {Number} levelFactor
|
|
18
|
+
*/
|
|
19
|
+
export function multiplyRouterResponseLevel(routerResponse, levelFactor) {
|
|
20
|
+
if (routerResponse.from.level) {
|
|
21
|
+
routerResponse.from.level.multiplyBy(levelFactor);
|
|
22
|
+
}
|
|
23
|
+
if (routerResponse.to.level) {
|
|
24
|
+
routerResponse.to.level.multiplyBy(levelFactor);
|
|
25
|
+
}
|
|
26
|
+
for (const itinerary of routerResponse.itineraries) {
|
|
27
|
+
if (itinerary.from.level) {
|
|
28
|
+
itinerary.from.level.multiplyBy(levelFactor);
|
|
29
|
+
}
|
|
30
|
+
if (itinerary.to.level) {
|
|
31
|
+
itinerary.to.level.multiplyBy(levelFactor);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
for (const leg of itinerary.legs) {
|
|
35
|
+
if (leg.from.coords.level) {
|
|
36
|
+
leg.from.coords.level.multiplyBy(levelFactor);
|
|
37
|
+
}
|
|
38
|
+
if (leg.to.coords.level) {
|
|
39
|
+
leg.to.coords.level.multiplyBy(levelFactor);
|
|
40
|
+
}
|
|
41
|
+
for (const coords of leg.coords) {
|
|
42
|
+
if (coords.level) {
|
|
43
|
+
coords.level.multiplyBy(levelFactor);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (leg.steps) {
|
|
47
|
+
for (const step of leg.steps) {
|
|
48
|
+
if (step.coords.level) {
|
|
49
|
+
step.coords.level.multiplyBy(levelFactor);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (itinerary._coords) {
|
|
56
|
+
for (const coords of itinerary._coords) {
|
|
57
|
+
if (coords.level) {
|
|
58
|
+
coords.level.multiplyBy(levelFactor);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/* eslint-disable max-statements */
|
|
2
|
+
import chai from 'chai';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
|
|
7
|
+
import RouterResponse from './model/RouterResponse.js';
|
|
8
|
+
import { multiplyRouterResponseLevel } from './Utils.js';
|
|
9
|
+
|
|
10
|
+
const { expect } = chai;
|
|
11
|
+
|
|
12
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
const assetsPath = path.resolve(__dirname, '../assets');
|
|
14
|
+
|
|
15
|
+
describe('Routers Utils', () => {
|
|
16
|
+
|
|
17
|
+
it('multiplyRouterResponseLevel', () => {
|
|
18
|
+
|
|
19
|
+
const filePath = path.resolve(assetsPath, 'rr-wemap-meta-multi-level.json');
|
|
20
|
+
const fileString = fs.readFileSync(filePath, 'utf8');
|
|
21
|
+
const json = JSON.parse(fileString);
|
|
22
|
+
|
|
23
|
+
const routerResponse = RouterResponse.fromJson(json);
|
|
24
|
+
multiplyRouterResponseLevel(routerResponse, 5);
|
|
25
|
+
|
|
26
|
+
expect(routerResponse.from.level.val).equal(10);
|
|
27
|
+
expect(routerResponse.to.level.val).equal(5);
|
|
28
|
+
|
|
29
|
+
const itinerary = routerResponse.itineraries[0];
|
|
30
|
+
expect(itinerary.from.level.val).equal(10);
|
|
31
|
+
expect(itinerary.to.level.val).equal(5);
|
|
32
|
+
|
|
33
|
+
const leg = itinerary.legs[0];
|
|
34
|
+
expect(leg.from.coords.level.val).equal(10);
|
|
35
|
+
expect(leg.to.coords.level.val).equal(5);
|
|
36
|
+
|
|
37
|
+
for (let i = 0; i < leg.coords.length; i++) {
|
|
38
|
+
if (i <= 6) {
|
|
39
|
+
expect(leg.coords[i].level.val).equal(10);
|
|
40
|
+
} else if (i <= 8) {
|
|
41
|
+
expect(leg.coords[i].level.up).equal(10);
|
|
42
|
+
expect(leg.coords[i].level.low).equal(5);
|
|
43
|
+
} else {
|
|
44
|
+
expect(leg.coords[i].level.val).equal(5);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const { steps } = leg;
|
|
49
|
+
for (let i = 0; i < steps.length; i++) {
|
|
50
|
+
if (i <= 5) {
|
|
51
|
+
expect(steps[i].coords.level.val).equal(10);
|
|
52
|
+
} else {
|
|
53
|
+
expect(steps[i].coords.level.val).equal(5);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
});
|
|
60
|
+
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import { NoRouteFoundError } from '@wemap/geo';
|
|
1
2
|
import { diffAngle } from '@wemap/maths';
|
|
2
3
|
|
|
3
4
|
import Itinerary from '../model/Itinerary.js';
|
|
5
|
+
import IdfmRemoteRouterTokenError from './idfm/IdfmRemoteRouterTokenError.js';
|
|
6
|
+
import RemoteRouterServerUnreachable from './RemoteRouterServerUnreachable.js';
|
|
7
|
+
import RoutingModeCorrespondanceNotFound from './RoutingModeCorrespondanceNotFound.js';
|
|
4
8
|
|
|
5
9
|
|
|
6
10
|
/**
|
|
@@ -76,3 +80,10 @@ export function dateWithTimeZone(year, month, day, hour, minute, second, timeZon
|
|
|
76
80
|
|
|
77
81
|
return date;
|
|
78
82
|
}
|
|
83
|
+
|
|
84
|
+
export function isRoutingError(e) {
|
|
85
|
+
return e instanceof RemoteRouterServerUnreachable
|
|
86
|
+
|| e instanceof RoutingModeCorrespondanceNotFound
|
|
87
|
+
|| e instanceof IdfmRemoteRouterTokenError
|
|
88
|
+
|| e instanceof NoRouteFoundError;
|
|
89
|
+
}
|
|
@@ -103,14 +103,37 @@ class IdfmRemoteRouter extends RemoteRouter {
|
|
|
103
103
|
|
|
104
104
|
const url = this.getURL(endpointUrl, mode, waypoints);
|
|
105
105
|
|
|
106
|
-
const res = await fetch(url, {
|
|
106
|
+
const res = await (fetch(url, {
|
|
107
107
|
method: 'GET',
|
|
108
108
|
headers: { Authorization: 'Bearer ' + this.token }
|
|
109
|
+
}).catch(() => {
|
|
110
|
+
throw new RemoteRouterServerUnreachable(this.rname, url);
|
|
111
|
+
}));
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
const response = await res.json().catch(() => {
|
|
115
|
+
throw new RemoteRouterServerUnreachable(this.rname, url);
|
|
109
116
|
});
|
|
117
|
+
|
|
118
|
+
// When IDFM failed to calculate an itinerary (ie. start or end
|
|
119
|
+
// point is far from network), it respond a 404 with an error message
|
|
120
|
+
if (res.status === 404) {
|
|
121
|
+
let errorMessage = 'no details.';
|
|
122
|
+
if (response && 'error' in response && 'message' in response.error) {
|
|
123
|
+
errorMessage = response.error.message;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const routerResponse = new RouterResponse();
|
|
127
|
+
routerResponse.routerName = this.rname;
|
|
128
|
+
routerResponse.from = waypoints[0];
|
|
129
|
+
routerResponse.to = waypoints[1];
|
|
130
|
+
routerResponse.error = errorMessage;
|
|
131
|
+
return routerResponse;
|
|
132
|
+
}
|
|
133
|
+
|
|
110
134
|
if (res.status !== 200) {
|
|
111
135
|
throw new RemoteRouterServerUnreachable(this.rname, url);
|
|
112
136
|
}
|
|
113
|
-
const response = await res.json();
|
|
114
137
|
|
|
115
138
|
return this.createRouterResponseFromJson(response);
|
|
116
139
|
}
|
|
@@ -181,17 +204,17 @@ class IdfmRemoteRouter extends RemoteRouter {
|
|
|
181
204
|
|
|
182
205
|
let query = '';
|
|
183
206
|
switch (mode) {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
207
|
+
case Constants.ROUTING_MODE.WALK:
|
|
208
|
+
query = this.getWalkingQuery();
|
|
209
|
+
break;
|
|
210
|
+
case Constants.ROUTING_MODE.BIKE:
|
|
211
|
+
query = this.getBikeQuery();
|
|
212
|
+
break;
|
|
213
|
+
case Constants.ROUTING_MODE.CAR:
|
|
214
|
+
query = this.getCarQuery();
|
|
215
|
+
break;
|
|
216
|
+
default:
|
|
217
|
+
break;
|
|
195
218
|
}
|
|
196
219
|
|
|
197
220
|
url = `${url.origin}${url.pathname}${search}${query}`;
|
|
@@ -7,6 +7,7 @@ import Logger from '@wemap/logger';
|
|
|
7
7
|
import IOMap from './IOMap.js';
|
|
8
8
|
import WemapMetaRouterOptions from './WemapMetaRouterOptions.js';
|
|
9
9
|
import RemoteRouterManager from '../remote/RemoteRouterManager.js';
|
|
10
|
+
import { isRoutingError } from '../remote/RemoteRouterUtils.js';
|
|
10
11
|
import WemapMetaRemoteRouterOptions from '../remote/wemap-meta/WemapMetaRemoteRouterOptions.js';
|
|
11
12
|
import WemapRouterOptions from '../wemap/WemapRouterOptions.js';
|
|
12
13
|
import RouterResponse from '../model/RouterResponse.js';
|
|
@@ -63,6 +64,12 @@ class WemapMetaRouter {
|
|
|
63
64
|
const start = waypoints[0];
|
|
64
65
|
const end = waypoints[1];
|
|
65
66
|
|
|
67
|
+
const routerResponse = new RouterResponse();
|
|
68
|
+
routerResponse.routerName = this.rname;
|
|
69
|
+
routerResponse.from = start;
|
|
70
|
+
routerResponse.to = end;
|
|
71
|
+
|
|
72
|
+
|
|
66
73
|
// Avoid cycles on remoteRouters
|
|
67
74
|
const remoteRouters = options.remoteRouters.filter(
|
|
68
75
|
({ name }) => name !== WemapMetaRemoteRouterOptions.rname
|
|
@@ -101,7 +108,15 @@ class WemapMetaRouter {
|
|
|
101
108
|
* 3 - intersection of this.maps and options.targetMaps is empty
|
|
102
109
|
*/
|
|
103
110
|
if (!ioMapsToTest.length) {
|
|
104
|
-
|
|
111
|
+
try {
|
|
112
|
+
return await RemoteRouterManager.getItinerariesWithFallback(remoteRouters, mode, waypoints);
|
|
113
|
+
} catch (e) {
|
|
114
|
+
if (!isRoutingError(e)) {
|
|
115
|
+
throw e;
|
|
116
|
+
}
|
|
117
|
+
routerResponse.error = e.message;
|
|
118
|
+
return routerResponse;
|
|
119
|
+
}
|
|
105
120
|
}
|
|
106
121
|
|
|
107
122
|
|
|
@@ -114,10 +129,8 @@ class WemapMetaRouter {
|
|
|
114
129
|
*
|
|
115
130
|
*/
|
|
116
131
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
routerResponse.to = end;
|
|
120
|
-
|
|
132
|
+
/** @type {Itinerary} */
|
|
133
|
+
let ioMapItinerary;
|
|
121
134
|
|
|
122
135
|
// Find the first map where the "start" is inside.
|
|
123
136
|
const mapWithStart = ioMapsToTest.find(map => map.isPointInside(start));
|
|
@@ -134,9 +147,17 @@ class WemapMetaRouter {
|
|
|
134
147
|
*/
|
|
135
148
|
if (mapWithStart && mapWithStart.isPointInside(end)) {
|
|
136
149
|
|
|
137
|
-
|
|
150
|
+
try {
|
|
151
|
+
ioMapItinerary = mapWithStart.getItineraryInsideMap(start, end, wemapRouterOptions);
|
|
152
|
+
} catch (e) {
|
|
153
|
+
if (!isRoutingError(e)) {
|
|
154
|
+
throw e;
|
|
155
|
+
}
|
|
156
|
+
routerResponse.error = `${e.message} - on map ${mapWithStart.name}.`;
|
|
157
|
+
return routerResponse;
|
|
158
|
+
}
|
|
138
159
|
|
|
139
|
-
routerResponse.itineraries.push(
|
|
160
|
+
routerResponse.itineraries.push(ioMapItinerary);
|
|
140
161
|
routerResponse.routerName = [this.rname, WemapRouter.rname];
|
|
141
162
|
|
|
142
163
|
return routerResponse;
|
|
@@ -146,21 +167,27 @@ class WemapMetaRouter {
|
|
|
146
167
|
// Note: At this step, mapWithEnd is necessarily different from mapWithStart
|
|
147
168
|
const mapWithEnd = ioMapsToTest.find(map => map.isPointInside(end));
|
|
148
169
|
|
|
170
|
+
|
|
171
|
+
/** @type {RouterResponse} */
|
|
172
|
+
let remoteRouterResponse;
|
|
173
|
+
|
|
149
174
|
/*
|
|
150
175
|
* Case 2
|
|
151
176
|
*
|
|
152
177
|
* If no io map have been found for "start" and "end", therefore use remote router.
|
|
153
178
|
*/
|
|
154
179
|
if (!mapWithStart && !mapWithEnd) {
|
|
155
|
-
|
|
180
|
+
try {
|
|
181
|
+
return await RemoteRouterManager.getItinerariesWithFallback(remoteRouters, mode, waypoints);
|
|
182
|
+
} catch (e) {
|
|
183
|
+
if (!isRoutingError(e)) {
|
|
184
|
+
throw e;
|
|
185
|
+
}
|
|
186
|
+
routerResponse.error = e.message;
|
|
187
|
+
return routerResponse;
|
|
188
|
+
}
|
|
156
189
|
}
|
|
157
190
|
|
|
158
|
-
/** @type {RouterResponse} */
|
|
159
|
-
let remoteRouterResponse;
|
|
160
|
-
|
|
161
|
-
/** @type {Itinerary} */
|
|
162
|
-
let ioMapItinerary;
|
|
163
|
-
|
|
164
191
|
/**
|
|
165
192
|
* Case 3
|
|
166
193
|
*
|
|
@@ -184,23 +211,21 @@ class WemapMetaRouter {
|
|
|
184
211
|
|
|
185
212
|
try {
|
|
186
213
|
ioMapItinerary = mapWithStart.getBestItineraryFromStartToEntryPoints(start, end, wemapRouterOptions);
|
|
214
|
+
remoteRouterResponse = await RemoteRouterManager.getItinerariesWithFallback(
|
|
215
|
+
remoteRouters, mode, [ioMapItinerary.to, end]
|
|
216
|
+
);
|
|
217
|
+
if (!remoteRouterResponse.itineraries.length) {
|
|
218
|
+
throw new NoRouteFoundError(ioMapItinerary.to, end, remoteRouterResponse.error);
|
|
219
|
+
}
|
|
187
220
|
} catch (e) {
|
|
188
|
-
if (!(e
|
|
221
|
+
if (!isRoutingError(e)) {
|
|
189
222
|
throw e;
|
|
190
223
|
}
|
|
191
|
-
routerResponse.error =
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
);
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
if (!remoteRouterResponse.itineraries.length) {
|
|
200
|
-
routerResponse.error = `Tried to calculate an itinerary from "start"
|
|
201
|
-
to "entrypoints" using wemap router on local map "${mapWithStart.name}" and
|
|
202
|
-
an itinerary from "entrypoints" to "end" using remote routers
|
|
203
|
-
(${remoteRouters.map(r => r.name).join(', ')}), but failed.`;
|
|
224
|
+
routerResponse.error = 'Tried to calculate an itinerary from "start" '
|
|
225
|
+
+ `to "entrypoints" using wemap router on local map "${mapWithStart.name}" and `
|
|
226
|
+
+ 'an itinerary from "entrypoints" to "end" using remote routers '
|
|
227
|
+
+ `(${remoteRouters.map(r => r.name).join(', ')}), but failed. `
|
|
228
|
+
+ `Details: ${e.message}.`;
|
|
204
229
|
return routerResponse;
|
|
205
230
|
}
|
|
206
231
|
|
|
@@ -240,22 +265,21 @@ class WemapMetaRouter {
|
|
|
240
265
|
*/
|
|
241
266
|
try {
|
|
242
267
|
ioMapItinerary = mapWithEnd.getBestItineraryFromEntryPointsToEnd(start, end, wemapRouterOptions);
|
|
268
|
+
remoteRouterResponse = await RemoteRouterManager.getItinerariesWithFallback(
|
|
269
|
+
remoteRouters, mode, [start, ioMapItinerary.from]
|
|
270
|
+
);
|
|
271
|
+
if (!remoteRouterResponse.itineraries.length) {
|
|
272
|
+
throw new NoRouteFoundError(start, ioMapItinerary.from, remoteRouterResponse.error);
|
|
273
|
+
}
|
|
243
274
|
} catch (e) {
|
|
244
|
-
if (!(e
|
|
275
|
+
if (!isRoutingError(e)) {
|
|
245
276
|
throw e;
|
|
246
277
|
}
|
|
247
|
-
routerResponse.error =
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
);
|
|
253
|
-
|
|
254
|
-
if (!remoteRouterResponse.itineraries.length) {
|
|
255
|
-
routerResponse.error = `Tried to calculate an itinerary from "start" to "entrypoints"
|
|
256
|
-
using remote routers (${remoteRouters.map(r => r.name).join(', ')}) and an
|
|
257
|
-
itinerary from "entrypoints" to "end" using wemap router on local map
|
|
258
|
-
"${mapWithEnd.name}", but failed.`;
|
|
278
|
+
routerResponse.error = 'Tried to calculate an itinerary from "start" to "entrypoints" '
|
|
279
|
+
+ `using remote routers (${remoteRouters.map(r => r.name).join(', ')}) and an `
|
|
280
|
+
+ 'itinerary from "entrypoints" to "end" using wemap router on local map '
|
|
281
|
+
+ `"${mapWithEnd.name}", but failed. `
|
|
282
|
+
+ `Details: ${e.message}.`;
|
|
259
283
|
return routerResponse;
|
|
260
284
|
}
|
|
261
285
|
|
|
@@ -298,32 +322,23 @@ class WemapMetaRouter {
|
|
|
298
322
|
let ioMapItinerary1, ioMapItinerary2;
|
|
299
323
|
try {
|
|
300
324
|
ioMapItinerary1 = mapWithStart.getBestItineraryFromStartToEntryPoints(start, end, wemapRouterOptions);
|
|
301
|
-
} catch (e) {
|
|
302
|
-
if (!(e instanceof NoRouteFoundError)) {
|
|
303
|
-
throw e;
|
|
304
|
-
}
|
|
305
|
-
routerResponse.error = `${e.message} - on map ${mapWithStart.name}.`;
|
|
306
|
-
return routerResponse;
|
|
307
|
-
}
|
|
308
|
-
try {
|
|
309
325
|
ioMapItinerary2 = mapWithEnd.getBestItineraryFromEntryPointsToEnd(start, end, wemapRouterOptions);
|
|
326
|
+
remoteRouterResponse = await RemoteRouterManager.getItinerariesWithFallback(
|
|
327
|
+
remoteRouters, mode, [ioMapItinerary1.to, ioMapItinerary2.from]
|
|
328
|
+
);
|
|
329
|
+
if (!remoteRouterResponse.itineraries.length) {
|
|
330
|
+
throw new NoRouteFoundError(ioMapItinerary1.to, ioMapItinerary2.from, remoteRouterResponse.error);
|
|
331
|
+
}
|
|
310
332
|
} catch (e) {
|
|
311
|
-
if (!(e
|
|
333
|
+
if (!isRoutingError(e)) {
|
|
312
334
|
throw e;
|
|
313
335
|
}
|
|
314
|
-
routerResponse.error =
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
if (!remoteRouterResponse.itineraries.length) {
|
|
322
|
-
routerResponse.error = `Tried to calculate an itinerary from "start" to "entrypoints1"
|
|
323
|
-
using wemap router on local map "${mapWithStart.name}", an itinerary from
|
|
324
|
-
"entrypoints1" to "entrypoints2" using remote routers
|
|
325
|
-
(${remoteRouters.map(r => r.name).join(', ')}) and an itinerary from "entrypoints2"
|
|
326
|
-
to "end" using wemap router on local map "${mapWithEnd.name}", but failed.`;
|
|
336
|
+
routerResponse.error = 'Tried to calculate an itinerary from "start" to "entrypoints1" '
|
|
337
|
+
+ `using wemap router on local map "${mapWithStart.name}", an itinerary from `
|
|
338
|
+
+ '"entrypoints1" to "entrypoints2" using remote routers '
|
|
339
|
+
+ `(${remoteRouters.map(r => r.name).join(', ')}) and an itinerary from "entrypoints2" `
|
|
340
|
+
+ `to "end" using wemap router on local map "${mapWithEnd.name}", but failed. `
|
|
341
|
+
+ `Details: ${e.message}.`;
|
|
327
342
|
return routerResponse;
|
|
328
343
|
}
|
|
329
344
|
|