@wemap/routers 11.5.0 → 11.8.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 +182 -27
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +169 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
- package/src/wemap-multi/CustomNetworkMap.ts +5 -0
- package/src/wemap-multi/WemapMultiRouter.ts +25 -0
- package/src/wemap-osm/OsmRouter.ts +28 -1
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ var __publicField = (obj, key, value) => {
|
|
|
5
5
|
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
6
6
|
return value;
|
|
7
7
|
};
|
|
8
|
-
Object.
|
|
8
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
9
9
|
const geo = require("@wemap/geo");
|
|
10
10
|
const maths = require("@wemap/maths");
|
|
11
11
|
const salesman = require("@wemap/salesman.js");
|
|
@@ -14,12 +14,6 @@ const Logger = require("@wemap/logger");
|
|
|
14
14
|
const Polyline = require("@mapbox/polyline");
|
|
15
15
|
const pointInPolygon = require("@turf/boolean-point-in-polygon");
|
|
16
16
|
const convexHullFn = require("@turf/convex");
|
|
17
|
-
const _interopDefaultLegacy = (e) => e && typeof e === "object" && "default" in e ? e : { default: e };
|
|
18
|
-
const salesman__default = /* @__PURE__ */ _interopDefaultLegacy(salesman);
|
|
19
|
-
const Logger__default = /* @__PURE__ */ _interopDefaultLegacy(Logger);
|
|
20
|
-
const Polyline__default = /* @__PURE__ */ _interopDefaultLegacy(Polyline);
|
|
21
|
-
const pointInPolygon__default = /* @__PURE__ */ _interopDefaultLegacy(pointInPolygon);
|
|
22
|
-
const convexHullFn__default = /* @__PURE__ */ _interopDefaultLegacy(convexHullFn);
|
|
23
17
|
function getDurationFromLength(length, speed = 5) {
|
|
24
18
|
return length / (speed * 1e3 / 3600);
|
|
25
19
|
}
|
|
@@ -245,6 +239,8 @@ class Leg {
|
|
|
245
239
|
stepsGenerationRules
|
|
246
240
|
});
|
|
247
241
|
}
|
|
242
|
+
// TODO: Remove when possible...
|
|
243
|
+
// Livemap specific
|
|
248
244
|
multiplyLevel(levelFactor) {
|
|
249
245
|
this.from.coords.level = geo.Level.multiplyBy(this.from.coords.level, levelFactor);
|
|
250
246
|
this.to.coords.level = geo.Level.multiplyBy(this.to.coords.level, levelFactor);
|
|
@@ -285,6 +281,7 @@ class Leg {
|
|
|
285
281
|
firstStep: stepId === 0,
|
|
286
282
|
lastStep: stepId === stepsInfo.length - 1,
|
|
287
283
|
distance,
|
|
284
|
+
// stepInfo.distance is overwritten
|
|
288
285
|
duration: stepInfo.duration || getDurationFromLength(distance),
|
|
289
286
|
levelChange: stepInfo.levelChange || null,
|
|
290
287
|
extras: stepInfo.extras || null
|
|
@@ -384,6 +381,9 @@ class Itinerary {
|
|
|
384
381
|
legs
|
|
385
382
|
});
|
|
386
383
|
}
|
|
384
|
+
/**
|
|
385
|
+
* Convert lat/lng/level? points to Itinerary
|
|
386
|
+
*/
|
|
387
387
|
static fromOrderedPointsArray(points, start, end) {
|
|
388
388
|
const pointToCoordinates = (point) => new geo.Coordinates(point[0], point[1], null, point[2]);
|
|
389
389
|
return this.fromOrderedCoordinates(
|
|
@@ -392,6 +392,9 @@ class Itinerary {
|
|
|
392
392
|
pointToCoordinates(end)
|
|
393
393
|
);
|
|
394
394
|
}
|
|
395
|
+
/**
|
|
396
|
+
* Convert ordered Coordinates to Itinerary
|
|
397
|
+
*/
|
|
395
398
|
static fromOrderedCoordinates(coords, from, to, mode = "WALK") {
|
|
396
399
|
const leg = new Leg({
|
|
397
400
|
from: { coords: from },
|
|
@@ -446,11 +449,15 @@ class Itinerary {
|
|
|
446
449
|
legs: [leg]
|
|
447
450
|
});
|
|
448
451
|
}
|
|
452
|
+
// TODO: Remove when possible...
|
|
453
|
+
// Livemap specific
|
|
449
454
|
multiplyLevel(levelFactor) {
|
|
450
455
|
this.from.level = geo.Level.multiplyBy(this.from.level, levelFactor);
|
|
451
456
|
this.to.level = geo.Level.multiplyBy(this.to.level, levelFactor);
|
|
452
457
|
this.legs.forEach((leg) => leg.multiplyLevel(levelFactor));
|
|
453
458
|
}
|
|
459
|
+
// TODO: Remove when possible...
|
|
460
|
+
// Livemap specific
|
|
454
461
|
forceUnknownLevelTo0() {
|
|
455
462
|
this.from.level = this.from.level || 0;
|
|
456
463
|
this.to.level = this.to.level || 0;
|
|
@@ -482,6 +489,14 @@ class Itinerary {
|
|
|
482
489
|
}
|
|
483
490
|
};
|
|
484
491
|
}
|
|
492
|
+
/**
|
|
493
|
+
* Update steps info thanks to the coordinates of the whole itinerary.
|
|
494
|
+
* This method will update:
|
|
495
|
+
* - all steps number
|
|
496
|
+
* - first/last steps
|
|
497
|
+
* - previousBearing/nextBearing/angle of first and last step of each leg
|
|
498
|
+
* - distance/duration of first and last step of each leg
|
|
499
|
+
*/
|
|
485
500
|
updateStepsFromLegs() {
|
|
486
501
|
const itineraryCoords = this.coords.filter((coords, idx, arr) => idx === 0 || !arr[idx - 1].equals(coords));
|
|
487
502
|
const steps = this.legs.map((leg) => leg.steps).flat();
|
|
@@ -566,6 +581,8 @@ class RouterResponse {
|
|
|
566
581
|
error: json.error
|
|
567
582
|
});
|
|
568
583
|
}
|
|
584
|
+
// TODO: Remove when possible...
|
|
585
|
+
// Livemap specific
|
|
569
586
|
multiplyLevel(levelFactor) {
|
|
570
587
|
this.from.level = geo.Level.multiplyBy(this.from.level, levelFactor);
|
|
571
588
|
this.to.level = geo.Level.multiplyBy(this.to.level, levelFactor);
|
|
@@ -579,7 +596,7 @@ const DEFAULT_WAY_SELECTOR = (way) => {
|
|
|
579
596
|
const isElevatorArea = way.tags.highway === "elevator" && way.isArea;
|
|
580
597
|
return HIGHWAYS_PEDESTRIANS.includes(way.tags.highway) && !isElevatorArea && !["no", "private"].includes(way.tags.access) || way.tags.footway === "sidewalk" || way.tags.public_transport === "platform" || way.tags.railway === "platform";
|
|
581
598
|
};
|
|
582
|
-
const _OsmGraph = class extends geo.GeoGraph {
|
|
599
|
+
const _OsmGraph = class _OsmGraph extends geo.GeoGraph {
|
|
583
600
|
getVertexByCoords(coords) {
|
|
584
601
|
return geo.GeoGraph.getVertexByCoords(this.vertices, coords);
|
|
585
602
|
}
|
|
@@ -741,9 +758,9 @@ const _OsmGraph = class extends geo.GeoGraph {
|
|
|
741
758
|
}
|
|
742
759
|
}
|
|
743
760
|
};
|
|
761
|
+
__publicField(_OsmGraph, "HIGHWAYS_PEDESTRIANS", HIGHWAYS_PEDESTRIANS);
|
|
762
|
+
__publicField(_OsmGraph, "DEFAULT_WAY_SELECTOR", DEFAULT_WAY_SELECTOR);
|
|
744
763
|
let OsmGraph = _OsmGraph;
|
|
745
|
-
__publicField(OsmGraph, "HIGHWAYS_PEDESTRIANS", HIGHWAYS_PEDESTRIANS);
|
|
746
|
-
__publicField(OsmGraph, "DEFAULT_WAY_SELECTOR", DEFAULT_WAY_SELECTOR);
|
|
747
764
|
const buildStepsRules = (graphItinerary) => (currentCoords, nextCoords, previousStep) => {
|
|
748
765
|
var _a, _b, _c, _d, _e;
|
|
749
766
|
const edges = graphItinerary.edges;
|
|
@@ -808,7 +825,7 @@ const buildStepsRules = (graphItinerary) => (currentCoords, nextCoords, previous
|
|
|
808
825
|
...forceEndOfLevelChange && { forceEndOfLevelChange }
|
|
809
826
|
};
|
|
810
827
|
};
|
|
811
|
-
const _WemapOsmRouter = class extends geo.GeoGraphRouter {
|
|
828
|
+
const _WemapOsmRouter = class _WemapOsmRouter extends geo.GeoGraphRouter {
|
|
812
829
|
constructor(graph) {
|
|
813
830
|
super(graph);
|
|
814
831
|
}
|
|
@@ -822,6 +839,21 @@ const _WemapOsmRouter = class extends geo.GeoGraphRouter {
|
|
|
822
839
|
const graphItinerary = this.getShortestPath(start, end, options);
|
|
823
840
|
return Itinerary.fromGraphItinerary(graphItinerary, "WALK", buildStepsRules(graphItinerary));
|
|
824
841
|
}
|
|
842
|
+
getShortestPaths(start, ends, options = _WemapOsmRouter.DEFAULT_OPTIONS) {
|
|
843
|
+
return super.getShortestPaths(start, ends, options);
|
|
844
|
+
}
|
|
845
|
+
getItineraries(start, ends, options = _WemapOsmRouter.DEFAULT_OPTIONS) {
|
|
846
|
+
const graphItineraries = this.getShortestPaths(start, ends, options);
|
|
847
|
+
return graphItineraries.map((graphItinerary, idx) => {
|
|
848
|
+
if (graphItinerary === null || !graphItinerary.edges.length) {
|
|
849
|
+
const startCoords = start instanceof geo.GeoGraphVertex ? start.coords : start;
|
|
850
|
+
const end = ends[idx];
|
|
851
|
+
const endCoords = end instanceof geo.GeoGraphVertex ? end.coords : end;
|
|
852
|
+
return new Itinerary({ from: startCoords, to: endCoords, legs: [] });
|
|
853
|
+
}
|
|
854
|
+
return Itinerary.fromGraphItinerary(graphItinerary, "WALK", buildStepsRules(graphItinerary));
|
|
855
|
+
});
|
|
856
|
+
}
|
|
825
857
|
static getTurnInfoFromAngle(_angle) {
|
|
826
858
|
let direction, directionExtra;
|
|
827
859
|
const directionAngle = maths.rad2deg(maths.diffAngle(_angle, Math.PI));
|
|
@@ -840,12 +872,12 @@ const _WemapOsmRouter = class extends geo.GeoGraphRouter {
|
|
|
840
872
|
}
|
|
841
873
|
getShortestTrip(waypoints, options = _WemapOsmRouter.DEFAULT_TRIP_OPTIONS) {
|
|
842
874
|
const points = waypoints.map((waypoint) => {
|
|
843
|
-
const point = new
|
|
875
|
+
const point = new salesman.Point(0, 0);
|
|
844
876
|
point.coords = waypoint;
|
|
845
877
|
return point;
|
|
846
878
|
});
|
|
847
879
|
const cache = [];
|
|
848
|
-
const solution =
|
|
880
|
+
const solution = salesman.solve(points, options.tspTempCoeff, void 0, (p, q) => {
|
|
849
881
|
const osmItinerary = this.getShortestPath(
|
|
850
882
|
p.coords,
|
|
851
883
|
q.coords,
|
|
@@ -919,10 +951,10 @@ const _WemapOsmRouter = class extends geo.GeoGraphRouter {
|
|
|
919
951
|
);
|
|
920
952
|
}
|
|
921
953
|
};
|
|
954
|
+
__publicField(_WemapOsmRouter, "DEFAULT_OPTIONS", _WemapOsmRouter.buildOptions());
|
|
955
|
+
__publicField(_WemapOsmRouter, "WITHOUT_STAIRS_OPTIONS", _WemapOsmRouter.buildOptions({ useStairs: false }));
|
|
956
|
+
__publicField(_WemapOsmRouter, "DEFAULT_TRIP_OPTIONS", _WemapOsmRouter.buildTripOptions());
|
|
922
957
|
let WemapOsmRouter = _WemapOsmRouter;
|
|
923
|
-
__publicField(WemapOsmRouter, "DEFAULT_OPTIONS", _WemapOsmRouter.buildOptions());
|
|
924
|
-
__publicField(WemapOsmRouter, "WITHOUT_STAIRS_OPTIONS", _WemapOsmRouter.buildOptions({ useStairs: false }));
|
|
925
|
-
__publicField(WemapOsmRouter, "DEFAULT_TRIP_OPTIONS", _WemapOsmRouter.buildTripOptions());
|
|
926
958
|
class RemoteRouter {
|
|
927
959
|
}
|
|
928
960
|
class RemoteRouterServerUnreachable extends Error {
|
|
@@ -1022,9 +1054,17 @@ function parseWKTGeometry(wktGeometry) {
|
|
|
1022
1054
|
});
|
|
1023
1055
|
}
|
|
1024
1056
|
class CitywayRemoteRouter extends RemoteRouter {
|
|
1057
|
+
/**
|
|
1058
|
+
* @override
|
|
1059
|
+
*/
|
|
1025
1060
|
get rname() {
|
|
1026
1061
|
return "cityway";
|
|
1027
1062
|
}
|
|
1063
|
+
/**
|
|
1064
|
+
* @override
|
|
1065
|
+
* @throws {RoutingModeCorrespondanceNotFound}
|
|
1066
|
+
* @throws {RemoteRouterServerUnreachable}
|
|
1067
|
+
*/
|
|
1028
1068
|
async getItineraries(endpointUrl, mode, waypoints) {
|
|
1029
1069
|
const url = this.getURL(endpointUrl, mode, waypoints);
|
|
1030
1070
|
const res = await fetch(url).catch(() => {
|
|
@@ -1035,13 +1075,16 @@ class CitywayRemoteRouter extends RemoteRouter {
|
|
|
1035
1075
|
});
|
|
1036
1076
|
return this.createRouterResponseFromJson(jsonResponse, waypoints[0], waypoints[1]);
|
|
1037
1077
|
}
|
|
1078
|
+
/**
|
|
1079
|
+
* @throws {RoutingModeCorrespondanceNotFound}
|
|
1080
|
+
*/
|
|
1038
1081
|
getURL(endpointUrl, mode, waypoints) {
|
|
1039
1082
|
const citywayMode = inputModeCorrespondance$2.get(mode);
|
|
1040
1083
|
if (!citywayMode) {
|
|
1041
1084
|
throw new RoutingModeCorrespondanceNotFound(this.rname, mode);
|
|
1042
1085
|
}
|
|
1043
1086
|
if (waypoints.length > 2) {
|
|
1044
|
-
|
|
1087
|
+
Logger.warn(`${this.rname} router uses only the first 2 waypoints (asked ${waypoints.length})`);
|
|
1045
1088
|
}
|
|
1046
1089
|
const fromPlace = `DepartureLatitude=${waypoints[0].latitude}&DepartureLongitude=${waypoints[0].longitude}`;
|
|
1047
1090
|
const toPlace = `ArrivalLatitude=${waypoints[1].latitude}&ArrivalLongitude=${waypoints[1].longitude}`;
|
|
@@ -1051,6 +1094,11 @@ class CitywayRemoteRouter extends RemoteRouter {
|
|
|
1051
1094
|
search = (search ? `${search}&` : "?") + `${fromPlace}&${toPlace}&${queryMode}`;
|
|
1052
1095
|
return `${url.origin}${url.pathname}${search}`;
|
|
1053
1096
|
}
|
|
1097
|
+
/**
|
|
1098
|
+
* Generate multi itineraries from Cityway JSON
|
|
1099
|
+
* @returns {!RouterResponse}
|
|
1100
|
+
* @example https://preprod.api.lia2.cityway.fr/journeyplanner/api/opt/PlanTrips/json?DepartureLatitude=49.51509388236216&DepartureLongitude=0.09341749619366316&ArrivalLatitude=49.5067090188444&ArrivalLongitude=0.1694842115417831&DepartureType=COORDINATES&ArrivalType=COORDINATES
|
|
1101
|
+
*/
|
|
1054
1102
|
createRouterResponseFromJson(json, from, to) {
|
|
1055
1103
|
const routerResponse = new RouterResponse({ routerName: this.rname, from, to });
|
|
1056
1104
|
if (json.StatusCode !== 200 || !json.Data || !json.Data.length) {
|
|
@@ -1144,7 +1192,7 @@ class CitywayRemoteRouter extends RemoteRouter {
|
|
|
1144
1192
|
distance: jsonLeg.Distance
|
|
1145
1193
|
}];
|
|
1146
1194
|
} else {
|
|
1147
|
-
|
|
1195
|
+
Logger.warn(`[CitywayParser] Unknown leg mode: ${jsonLeg.TransportMode}`);
|
|
1148
1196
|
continue;
|
|
1149
1197
|
}
|
|
1150
1198
|
const leg = new Leg({
|
|
@@ -1172,6 +1220,10 @@ class CitywayRemoteRouter extends RemoteRouter {
|
|
|
1172
1220
|
}
|
|
1173
1221
|
return routerResponse;
|
|
1174
1222
|
}
|
|
1223
|
+
/**
|
|
1224
|
+
* @param {string} iso8601Duration
|
|
1225
|
+
* @see https://stackoverflow.com/a/29153059/2239938
|
|
1226
|
+
*/
|
|
1175
1227
|
parseDuration(iso8601Duration) {
|
|
1176
1228
|
const iso8601DurationRegex = /(-)?P(?:([.,\d]+)Y)?(?:([.,\d]+)M)?(?:([.,\d]+)W)?(?:([.,\d]+)D)?T(?:([.,\d]+)H)?(?:([.,\d]+)M)?(?:([.,\d]+)S)?/;
|
|
1177
1229
|
const matches = iso8601Duration.match(iso8601DurationRegex);
|
|
@@ -1187,9 +1239,16 @@ class CitywayRemoteRouter extends RemoteRouter {
|
|
|
1187
1239
|
}
|
|
1188
1240
|
const CitywayRemoteRouter$1 = new CitywayRemoteRouter();
|
|
1189
1241
|
class DeutscheBahnRemoteRouter extends RemoteRouter {
|
|
1242
|
+
/**
|
|
1243
|
+
* @override
|
|
1244
|
+
*/
|
|
1190
1245
|
get rname() {
|
|
1191
1246
|
return "deutsche-bahn";
|
|
1192
1247
|
}
|
|
1248
|
+
/**
|
|
1249
|
+
* @override
|
|
1250
|
+
* @throws {RemoteRouterServerUnreachable}
|
|
1251
|
+
*/
|
|
1193
1252
|
async getItineraries(endpointUrl, mode, waypoints) {
|
|
1194
1253
|
const url = this.getURL(endpointUrl, mode, waypoints);
|
|
1195
1254
|
const res = await fetch(url).catch(() => {
|
|
@@ -1245,7 +1304,7 @@ routingModeCorrespondance.set("Funicular", "FUNICULAR");
|
|
|
1245
1304
|
routingModeCorrespondance.set("LocalTrain", "TRAIN");
|
|
1246
1305
|
routingModeCorrespondance.set("LongDistanceTrain", "TRAIN");
|
|
1247
1306
|
routingModeCorrespondance.set("Metro", "METRO");
|
|
1248
|
-
routingModeCorrespondance.set("
|
|
1307
|
+
routingModeCorrespondance.set("Métro", "METRO");
|
|
1249
1308
|
routingModeCorrespondance.set("RailShuttle", "TRAIN");
|
|
1250
1309
|
routingModeCorrespondance.set("RapidTransit", "BUS");
|
|
1251
1310
|
routingModeCorrespondance.set("Shuttle", "BUS");
|
|
@@ -1300,9 +1359,16 @@ function dateStringToTimestamp(stringDate, timeZone) {
|
|
|
1300
1359
|
).getTime();
|
|
1301
1360
|
}
|
|
1302
1361
|
class IdfmRemoteRouter extends RemoteRouter {
|
|
1362
|
+
/**
|
|
1363
|
+
* @override
|
|
1364
|
+
*/
|
|
1303
1365
|
get rname() {
|
|
1304
1366
|
return "idfm";
|
|
1305
1367
|
}
|
|
1368
|
+
/**
|
|
1369
|
+
* @throws {IdfmRemoteRouterTokenError}
|
|
1370
|
+
* @throws {RemoteRouterServerUnreachable}
|
|
1371
|
+
*/
|
|
1306
1372
|
async getItineraries(endpointUrl, mode, waypoints, options = {}) {
|
|
1307
1373
|
const url = this.getURL(endpointUrl, mode, waypoints, options);
|
|
1308
1374
|
const res = await fetch(url, {
|
|
@@ -1326,7 +1392,7 @@ class IdfmRemoteRouter extends RemoteRouter {
|
|
|
1326
1392
|
}
|
|
1327
1393
|
getURL(endpointUrl, mode, waypoints, options) {
|
|
1328
1394
|
if (waypoints.length > 2) {
|
|
1329
|
-
|
|
1395
|
+
Logger.warn(`${this.rname} router uses only the first 2 waypoints (asked ${waypoints.length})`);
|
|
1330
1396
|
}
|
|
1331
1397
|
const url = new URL(endpointUrl);
|
|
1332
1398
|
const coreParams = new URLSearchParams();
|
|
@@ -1391,6 +1457,11 @@ class IdfmRemoteRouter extends RemoteRouter {
|
|
|
1391
1457
|
to
|
|
1392
1458
|
};
|
|
1393
1459
|
}
|
|
1460
|
+
/**
|
|
1461
|
+
* Since the IDFM API does not provide coords for each step, we need to compute them
|
|
1462
|
+
* We trim the coordinates of the leg with the distance of each step and keep the last result as the coords of the step
|
|
1463
|
+
* @param {Leg} leg
|
|
1464
|
+
*/
|
|
1394
1465
|
findStepsCoord(legCoords, steps) {
|
|
1395
1466
|
const coords = legCoords;
|
|
1396
1467
|
const duplicatedCoords = [...coords];
|
|
@@ -1516,9 +1587,16 @@ inputModeCorrespondance$1.set("BIKE", "bike");
|
|
|
1516
1587
|
inputModeCorrespondance$1.set("BUS", "bus");
|
|
1517
1588
|
inputModeCorrespondance$1.set("MULTI", "walking");
|
|
1518
1589
|
class OsrmRemoteRouter extends RemoteRouter {
|
|
1590
|
+
/**
|
|
1591
|
+
* @override
|
|
1592
|
+
*/
|
|
1519
1593
|
get rname() {
|
|
1520
1594
|
return "osrm";
|
|
1521
1595
|
}
|
|
1596
|
+
/**
|
|
1597
|
+
* @throws {RemoteRouterServerUnreachable}
|
|
1598
|
+
* @throws {RoutingModeCorrespondanceNotFound}
|
|
1599
|
+
*/
|
|
1522
1600
|
async getItineraries(endpointUrl, mode, waypoints, options = {}) {
|
|
1523
1601
|
const url = this.getURL(endpointUrl, mode, waypoints, options);
|
|
1524
1602
|
const res = await fetch(url).catch(() => {
|
|
@@ -1532,6 +1610,9 @@ class OsrmRemoteRouter extends RemoteRouter {
|
|
|
1532
1610
|
const osrmMode = inputModeCorrespondance$1.get(mode);
|
|
1533
1611
|
return this.createRouterResponseFromJson(jsonResponse, from, to, osrmMode);
|
|
1534
1612
|
}
|
|
1613
|
+
/**
|
|
1614
|
+
* @throws {RoutingModeCorrespondanceNotFound}
|
|
1615
|
+
*/
|
|
1535
1616
|
getURL(endpointUrl, mode, waypoints, options = {}) {
|
|
1536
1617
|
let osrmMode = inputModeCorrespondance$1.get(mode);
|
|
1537
1618
|
if (!osrmMode) {
|
|
@@ -1554,6 +1635,10 @@ class OsrmRemoteRouter extends RemoteRouter {
|
|
|
1554
1635
|
}
|
|
1555
1636
|
return [lng, lat, level];
|
|
1556
1637
|
}
|
|
1638
|
+
/**
|
|
1639
|
+
* @param {object} json
|
|
1640
|
+
* @returns {Coordinates}
|
|
1641
|
+
*/
|
|
1557
1642
|
jsonToCoordinates(json) {
|
|
1558
1643
|
const coords = new geo.Coordinates(json[1], json[0]);
|
|
1559
1644
|
if (json.length > 2) {
|
|
@@ -1592,6 +1677,9 @@ class OsrmRemoteRouter extends RemoteRouter {
|
|
|
1592
1677
|
message
|
|
1593
1678
|
};
|
|
1594
1679
|
}
|
|
1680
|
+
/**
|
|
1681
|
+
* @deprecated
|
|
1682
|
+
*/
|
|
1595
1683
|
itineraryToOsrmJson(itinerary) {
|
|
1596
1684
|
const lastLegId = itinerary.legs.length - 1;
|
|
1597
1685
|
const itinerarySteps = itinerary.steps;
|
|
@@ -1715,6 +1803,10 @@ class OtpRemoteRouter extends RemoteRouter {
|
|
|
1715
1803
|
get rname() {
|
|
1716
1804
|
return "otp";
|
|
1717
1805
|
}
|
|
1806
|
+
/**
|
|
1807
|
+
* @throws {RemoteRouterServerUnreachable}
|
|
1808
|
+
* @throws {RoutingModeCorrespondanceNotFound}
|
|
1809
|
+
*/
|
|
1718
1810
|
async getItineraries(endpointUrl, mode, waypoints) {
|
|
1719
1811
|
const url = this.getURL(endpointUrl, mode, waypoints);
|
|
1720
1812
|
const res = await fetch(url).catch(() => {
|
|
@@ -1725,13 +1817,16 @@ class OtpRemoteRouter extends RemoteRouter {
|
|
|
1725
1817
|
});
|
|
1726
1818
|
return this.createRouterResponseFromJson(jsonResponse, waypoints[0], waypoints[1]);
|
|
1727
1819
|
}
|
|
1820
|
+
/**
|
|
1821
|
+
* @throws {RoutingModeCorrespondanceNotFound}
|
|
1822
|
+
*/
|
|
1728
1823
|
getURL(endpointUrl, mode, waypoints) {
|
|
1729
1824
|
const otpMode = inputModeCorrespondance.get(mode);
|
|
1730
1825
|
if (!otpMode) {
|
|
1731
1826
|
throw new RoutingModeCorrespondanceNotFound(this.rname, mode);
|
|
1732
1827
|
}
|
|
1733
1828
|
if (waypoints.length > 2) {
|
|
1734
|
-
|
|
1829
|
+
Logger.warn(`${this.rname} router uses only the first 2 waypoints (asked ${waypoints.length})`);
|
|
1735
1830
|
}
|
|
1736
1831
|
const fromPlace = `fromPlace=${waypoints[0].latitude},${waypoints[0].longitude}`;
|
|
1737
1832
|
const toPlace = `toPlace=${waypoints[1].latitude},${waypoints[1].longitude}`;
|
|
@@ -1741,6 +1836,9 @@ class OtpRemoteRouter extends RemoteRouter {
|
|
|
1741
1836
|
search = (search ? `${search}&` : "?") + `${fromPlace}&${toPlace}&${queryMode}`;
|
|
1742
1837
|
return `${url.origin}${url.pathname}${search}`;
|
|
1743
1838
|
}
|
|
1839
|
+
/**
|
|
1840
|
+
* Generate multi itineraries from OTP JSON
|
|
1841
|
+
*/
|
|
1744
1842
|
createRouterResponseFromJson(json, from, to) {
|
|
1745
1843
|
const routerResponse = new RouterResponse({ routerName: this.rname, from, to });
|
|
1746
1844
|
const { plan: jsonPlan } = json;
|
|
@@ -1752,7 +1850,7 @@ class OtpRemoteRouter extends RemoteRouter {
|
|
|
1752
1850
|
for (const jsonItinerary of jsonPlan.itineraries) {
|
|
1753
1851
|
const legs = [];
|
|
1754
1852
|
for (const jsonLeg of jsonItinerary.legs) {
|
|
1755
|
-
const legCoords =
|
|
1853
|
+
const legCoords = Polyline.decode(jsonLeg.legGeometry.points).map(([lat, lon]) => new geo.Coordinates(lat, lon));
|
|
1756
1854
|
let transportInfo;
|
|
1757
1855
|
let minStepsInfo;
|
|
1758
1856
|
if (isLegPT(jsonLeg)) {
|
|
@@ -1872,6 +1970,11 @@ class RemoteRouterManager {
|
|
|
1872
1970
|
getRouterByName(name) {
|
|
1873
1971
|
return remoteRouters.find((remoteRouter) => remoteRouter.rname === name);
|
|
1874
1972
|
}
|
|
1973
|
+
/**
|
|
1974
|
+
* @throws {RemoteRouterServerUnreachable}
|
|
1975
|
+
* @throws {RoutingModeCorrespondanceNotFound}
|
|
1976
|
+
* @throws {IdfmRemoteRouterTokenError}
|
|
1977
|
+
*/
|
|
1875
1978
|
async getItineraries(name, endpointUrl, mode, waypoints, options) {
|
|
1876
1979
|
const router = this.getRouterByName(name);
|
|
1877
1980
|
if (!router) {
|
|
@@ -1879,6 +1982,11 @@ class RemoteRouterManager {
|
|
|
1879
1982
|
}
|
|
1880
1983
|
return router.getItineraries(endpointUrl, mode, waypoints, options);
|
|
1881
1984
|
}
|
|
1985
|
+
/**
|
|
1986
|
+
* @throws {RemoteRouterServerUnreachable}
|
|
1987
|
+
* @throws {RoutingModeCorrespondanceNotFound}
|
|
1988
|
+
* @throws {IdfmRemoteRouterTokenError}
|
|
1989
|
+
*/
|
|
1882
1990
|
async getItinerariesWithFallback(remoteRouters2, mode, waypoints, options) {
|
|
1883
1991
|
let routerResponse;
|
|
1884
1992
|
for (const { name, endpointUrl } of remoteRouters2) {
|
|
@@ -1920,7 +2028,7 @@ class WemapMultiRouter {
|
|
|
1920
2028
|
if (ioMapsToTest.length !== targetMaps.length) {
|
|
1921
2029
|
ioMapsToTest.forEach((map) => {
|
|
1922
2030
|
if (map.name && !targetMaps.includes(map.name)) {
|
|
1923
|
-
|
|
2031
|
+
Logger.warn(`CustomNetworkMap "${map.name}" not found in WemapMultiRouter`);
|
|
1924
2032
|
}
|
|
1925
2033
|
});
|
|
1926
2034
|
}
|
|
@@ -1961,10 +2069,26 @@ class WemapMultiRouter {
|
|
|
1961
2069
|
itineraries: [tripItinerary]
|
|
1962
2070
|
});
|
|
1963
2071
|
}
|
|
2072
|
+
async getItinerariesMultipleDestinations(start, ends, options = null) {
|
|
2073
|
+
const ioMapsToTest = this.getIoMapsFromOptions(options);
|
|
2074
|
+
const mapOfWaypoints = [start, ...ends].reduce((map, waypoint) => {
|
|
2075
|
+
const mapOfThisWaypoint = ioMapsToTest.find((map2) => map2.isPointInside(waypoint)) || null;
|
|
2076
|
+
if (mapOfThisWaypoint && map && mapOfThisWaypoint !== map) {
|
|
2077
|
+
throw Error(`Cannot handle this itineraries, because two points are on different maps (${mapOfThisWaypoint} and ${mapOfWaypoints}). Multi-map multiple destinations are not implemented.`);
|
|
2078
|
+
}
|
|
2079
|
+
return mapOfThisWaypoint;
|
|
2080
|
+
}, null);
|
|
2081
|
+
const wemapOsmRouterOptions = this.convertOptionsToWemapOsmOptions(options);
|
|
2082
|
+
const itineraries = mapOfWaypoints.getItinerariesMultipleDestinationsInsideMap(start, ends, wemapOsmRouterOptions);
|
|
2083
|
+
return {
|
|
2084
|
+
routerName: this.rname,
|
|
2085
|
+
itineraries
|
|
2086
|
+
};
|
|
2087
|
+
}
|
|
1964
2088
|
async getItineraries(mode, waypoints, options = null) {
|
|
1965
2089
|
var _a;
|
|
1966
2090
|
if (waypoints.length > 2) {
|
|
1967
|
-
|
|
2091
|
+
Logger.warn(`WemapMultiRouter uses only the first 2 waypoints (asked ${waypoints.length})`);
|
|
1968
2092
|
}
|
|
1969
2093
|
const start = waypoints[0];
|
|
1970
2094
|
const end = waypoints[1];
|
|
@@ -2143,7 +2267,7 @@ class CustomNetworkMap {
|
|
|
2143
2267
|
this.bounds = bounds;
|
|
2144
2268
|
} else {
|
|
2145
2269
|
const polygon = [graph.vertices.map((vertex) => [vertex.coords.lng, vertex.coords.lat])];
|
|
2146
|
-
const convexHull =
|
|
2270
|
+
const convexHull = convexHullFn({ type: "polygon", coordinates: polygon });
|
|
2147
2271
|
if (!convexHull) {
|
|
2148
2272
|
throw new Error(`Cannot calculate convexHull of network "${name}"`);
|
|
2149
2273
|
}
|
|
@@ -2182,8 +2306,14 @@ class CustomNetworkMap {
|
|
|
2182
2306
|
return new CustomNetworkMap(graph, entryPoints, bounds, name);
|
|
2183
2307
|
}
|
|
2184
2308
|
isPointInside(coordinates) {
|
|
2185
|
-
return
|
|
2186
|
-
}
|
|
2309
|
+
return pointInPolygon([coordinates.lng, coordinates.lat], this.bounds);
|
|
2310
|
+
}
|
|
2311
|
+
/**
|
|
2312
|
+
* Get the list of entry points sorted by the lowest distance between:
|
|
2313
|
+
* start -> entry point -> end
|
|
2314
|
+
* (as the crow flies)
|
|
2315
|
+
*
|
|
2316
|
+
*/
|
|
2187
2317
|
getOrderedEntryPointsSortedByDistance(start, end) {
|
|
2188
2318
|
const entryPointsCopy = [...this.entryPoints];
|
|
2189
2319
|
const levelDiffFactor = 50;
|
|
@@ -2197,6 +2327,17 @@ class CustomNetworkMap {
|
|
|
2197
2327
|
return distance2D + levelDiff * levelDiffFactor;
|
|
2198
2328
|
});
|
|
2199
2329
|
}
|
|
2330
|
+
/**
|
|
2331
|
+
* Get the best itinerary from any entry point to an end coordinates.
|
|
2332
|
+
*
|
|
2333
|
+
* The algorithm works as following:
|
|
2334
|
+
* 1 - Entry points are sorted using distance (as the crow flies) between start - entry point - end
|
|
2335
|
+
* 2 - Try to calculate an itinerary from the first entry point to the end coordinates.
|
|
2336
|
+
* 3 - If an itinerary is found, it is returned. Otherwise it tries from the next entry point.
|
|
2337
|
+
*
|
|
2338
|
+
* /!\ start is only used to sort the entry points (step 1).
|
|
2339
|
+
*
|
|
2340
|
+
*/
|
|
2200
2341
|
getBestItineraryFromEntryPointsToEnd(start, end, options) {
|
|
2201
2342
|
const sortedEntryPoints = this.getOrderedEntryPointsSortedByDistance(start, end);
|
|
2202
2343
|
for (const entryPoint of sortedEntryPoints) {
|
|
@@ -2211,6 +2352,17 @@ class CustomNetworkMap {
|
|
|
2211
2352
|
`No route found from entry points to ${end.toString()} in map: ${this.name}`
|
|
2212
2353
|
);
|
|
2213
2354
|
}
|
|
2355
|
+
/**
|
|
2356
|
+
* Get the best itinerary from start coordinates to any entry point.
|
|
2357
|
+
*
|
|
2358
|
+
* The algorithm works as following:
|
|
2359
|
+
* 1 - Entry points are sorted using distance (as the crow flies) between start - entry point - end
|
|
2360
|
+
* 2 - Try to calculate an itinerary from the start coordinates to the first entry point.
|
|
2361
|
+
* 3 - If an itinerary is found, it is returned. Otherwise it tries to the next entry point.
|
|
2362
|
+
*
|
|
2363
|
+
* /!\ end is only used to sort the entry points (step 1).
|
|
2364
|
+
*
|
|
2365
|
+
*/
|
|
2214
2366
|
getBestItineraryFromStartToEntryPoints(start, end, options) {
|
|
2215
2367
|
const sortedEntryPoints = this.getOrderedEntryPointsSortedByDistance(start, end);
|
|
2216
2368
|
for (const entryPoint of sortedEntryPoints) {
|
|
@@ -2231,6 +2383,9 @@ class CustomNetworkMap {
|
|
|
2231
2383
|
getTripInsideMap(waypoints, options) {
|
|
2232
2384
|
return this.router.getTripItinerary(waypoints, options);
|
|
2233
2385
|
}
|
|
2386
|
+
getItinerariesMultipleDestinationsInsideMap(start, ends, options) {
|
|
2387
|
+
return this.router.getItineraries(start, ends, options);
|
|
2388
|
+
}
|
|
2234
2389
|
enableWay(osmId) {
|
|
2235
2390
|
this.graph.edges.filter((edge) => edge.data.id === osmId).forEach((e) => this.router.disabledEdges.delete(e));
|
|
2236
2391
|
this.disabledWays.delete(osmId);
|