@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.
Files changed (49) hide show
  1. package/assets/bureaux-wemap-montpellier-network.osm +162 -0
  2. package/assets/gare-de-lyon-extract.osm +174 -0
  3. package/assets/itinerary-deutsche-bahn-1.json +368 -0
  4. package/assets/itinerary-grenoble-otp-1.json +1536 -0
  5. package/assets/itinerary-grenoble-otp-2.json +1092 -0
  6. package/assets/itinerary-lehavre-cityway-1.json +6799 -0
  7. package/assets/itinerary-lehavre-cityway-2.json +2133 -0
  8. package/assets/itinerary-lehavre-cityway-3.json +12577 -0
  9. package/assets/itinerary-lehavre-cityway-4.json +1451 -0
  10. package/assets/itinerary-lehavre-cityway-5.json +5925 -0
  11. package/assets/itinerary-montpellier-osrm-3.json +1 -0
  12. package/assets/itinerary-montpellier-outdoor-without-steps.json +110 -0
  13. package/assets/itinerary-montpellier-outdoor.json +513 -0
  14. package/assets/itinerary-with-duplicate-nodes.json +110 -0
  15. package/assets/network-conveying-backward.osm +74 -0
  16. package/assets/network-elevator.osm +48 -0
  17. package/assets/network-simple.osm +27 -0
  18. package/assets/network-with-modifiers.osm +39 -0
  19. package/assets/one-way.osm +46 -0
  20. package/dist/wemap-osm.es.js +2012 -0
  21. package/dist/wemap-osm.es.js.map +1 -0
  22. package/index.js +24 -0
  23. package/package.json +35 -0
  24. package/src/ItineraryInfoManager.js +148 -0
  25. package/src/ItineraryInfoManager.spec.js +54 -0
  26. package/src/Utils.js +64 -0
  27. package/src/cityway/CitywayUtils.js +240 -0
  28. package/src/cityway/CitywayUtils.spec.js +109 -0
  29. package/src/deutsche-bahn/DeutscheBahnRouterUtils.js +91 -0
  30. package/src/deutsche-bahn/DeutscheBahnRouterUtils.spec.js +54 -0
  31. package/src/model/Itinerary.js +197 -0
  32. package/src/model/Itinerary.type.spec.js +105 -0
  33. package/src/model/ItineraryInfo.js +34 -0
  34. package/src/model/Leg.js +113 -0
  35. package/src/model/LevelChange.js +65 -0
  36. package/src/model/RouterResponse.js +19 -0
  37. package/src/model/RouterResponse.type.spec.js +24 -0
  38. package/src/model/Step.js +118 -0
  39. package/src/osrm/OsrmUtils.js +269 -0
  40. package/src/osrm/OsrmUtils.spec.js +457 -0
  41. package/src/otp/OtpUtils.js +150 -0
  42. package/src/otp/OtpUtils.spec.js +97 -0
  43. package/src/wemap/WemapNetworkUtils.js +195 -0
  44. package/src/wemap/WemapNetworkUtils.spec.js +109 -0
  45. package/src/wemap/WemapRouter.js +27 -0
  46. package/src/wemap/WemapRouter.spec.js +221 -0
  47. package/src/wemap/WemapRouterOptions.js +32 -0
  48. package/src/wemap/WemapRouterUtils.js +46 -0
  49. package/src/wemap/WemapStepsGeneration.js +104 -0
@@ -0,0 +1,269 @@
1
+ /* eslint-disable max-statements */
2
+
3
+ import { Level, Coordinates } from '@wemap/geo';
4
+ import { rad2deg, positiveMod } from '@wemap/maths';
5
+
6
+ import Itinerary from '../model/Itinerary.js';
7
+ import Leg from '../model/Leg.js';
8
+ import LevelChange from '../model/LevelChange.js';
9
+ import RouterResponse from '../model/RouterResponse.js';
10
+ import Step from '../model/Step.js';
11
+ import { generateStepsMetadata } from '../Utils.js';
12
+
13
+ /**
14
+ * @param {Coordinates} coordinates
15
+ * @returns {object}
16
+ */
17
+ export function coordinatesToJson(coordinates) {
18
+ const output = [coordinates.lng, coordinates.lat];
19
+ if (coordinates.level) {
20
+ output.push(coordinates.level.toString());
21
+ }
22
+ return output;
23
+ }
24
+
25
+ /**
26
+ * @param {object} json
27
+ * @returns {Coordinates}
28
+ */
29
+ export function jsonToCoordinates(json) {
30
+ const output = new Coordinates(json[1], json[0]);
31
+ if (json.length > 2) {
32
+ output.level = Level.fromString(json[2]);
33
+ }
34
+ return output;
35
+ }
36
+
37
+ export function nodesToJsonCoords(nodes) {
38
+ return nodes.map(node => coordinatesToJson(node.coords));
39
+ }
40
+
41
+
42
+ export function getModifierFromAngle(_angle) {
43
+
44
+ const angle = positiveMod(rad2deg(_angle), 360);
45
+
46
+ if (angle > 0 && angle < 60) {
47
+ return 'sharp right';
48
+ }
49
+ if (angle >= 60 && angle < 140) {
50
+ return 'right';
51
+ }
52
+ if (angle >= 140 && angle < 160) {
53
+ return 'slight right';
54
+ }
55
+ if (angle >= 160 && angle <= 200) {
56
+ return 'straight';
57
+ }
58
+ if (angle > 200 && angle <= 220) {
59
+ return 'slight left';
60
+ }
61
+ if (angle > 220 && angle <= 300) {
62
+ return 'left';
63
+ }
64
+ if (angle > 300 && angle < 360) {
65
+ return 'sharp left';
66
+ }
67
+ return 'u turn';
68
+ }
69
+
70
+
71
+ export function noRouteFoundJson(message) {
72
+ return {
73
+ 'code': 'NoRoute',
74
+ message
75
+ };
76
+ }
77
+
78
+ /**
79
+ * @param {Itinerary} itinerary
80
+ * @returns {object}
81
+ */
82
+ export function itineraryToOsrmJson(itinerary) {
83
+
84
+ const lastLegId = itinerary.legs.length - 1;
85
+
86
+ const jsonLegs = itinerary.legs.map(({ distance, duration, coords, steps }, idLeg) => {
87
+
88
+ const lastStepId = steps.length - 1;
89
+
90
+ return {
91
+ distance,
92
+ duration,
93
+ steps: steps.map((step, idStep, arr) => {
94
+
95
+ let type = idStep === 0 && idLeg === 0 ? 'depart' : 'turn';
96
+ type = idStep === lastStepId && idLeg === lastLegId ? 'arrive' : type;
97
+
98
+ const stepCoordsIdx = coords.findIndex(p => p.equalsTo(step.coords));
99
+ const nextStepCoordsIdx = idStep === lastStepId
100
+ ? stepCoordsIdx
101
+ : coords.findIndex(p => p.equalsTo(arr[idStep + 1].coords));
102
+
103
+ const jsonStep = {
104
+ geometry: {
105
+ type: 'LineString',
106
+ coordinates: coords.slice(stepCoordsIdx, nextStepCoordsIdx + 1).map(coordinatesToJson)
107
+ },
108
+ distance: step.distance,
109
+ duration: step.duration,
110
+ name: step.name,
111
+ maneuver: {
112
+ bearing_before: rad2deg(step.previousBearing),
113
+ bearing_after: rad2deg(step.nextBearing),
114
+ location: coordinatesToJson(step.coords),
115
+ modifier: getModifierFromAngle(step.angle),
116
+ type
117
+ }
118
+ };
119
+ if (step.levelChange !== null) {
120
+ jsonStep.levelChange = step.levelChange.toJson();
121
+ }
122
+ if (typeof step.extras === 'object' && Object.keys(step.extras).length !== 0) {
123
+ jsonStep.extras = step.extras;
124
+ }
125
+
126
+ return jsonStep;
127
+ })
128
+ };
129
+ });
130
+
131
+ return {
132
+ 'code': 'Ok',
133
+ 'routes': [
134
+ {
135
+ 'geometry': {
136
+ 'type': 'LineString',
137
+ 'coordinates': itinerary.coords.map(coordinatesToJson)
138
+ },
139
+ 'legs': jsonLegs,
140
+ 'distance': itinerary.distance,
141
+ 'duration': itinerary.duration,
142
+ 'weight_name': 'routability',
143
+ 'weight': 0
144
+ }
145
+ ],
146
+ 'waypoints': []
147
+ };
148
+ }
149
+
150
+
151
+ /**
152
+ * @param {object} jsonSteps
153
+ * @param {Coordinates[]} legCoords
154
+ * @returns {Step[]}
155
+ */
156
+ function parseJsonSteps(jsonSteps, legCoords) {
157
+
158
+ if (!jsonSteps) {
159
+ return [];
160
+ }
161
+
162
+ return jsonSteps.map(jsonStep => {
163
+
164
+ const step = new Step();
165
+ step.coords = jsonToCoordinates(jsonStep.maneuver.location);
166
+
167
+ // Sometimes, OSRM step does not have the same coordinates than a point in legCoords.
168
+ // ex: first step of https://routing.getwemap.com/route/v1/walking/2.33222164147,48.87084765712;2.3320734,48.8730212?geometries=geojson&overview=full&steps=true
169
+ // That is why we look for the closest point.
170
+ const distances = legCoords.map(coords => coords.distanceTo(step.coords));
171
+ const idStepCoordsInLeg = distances.indexOf(Math.min(...distances));
172
+ if (idStepCoordsInLeg < 0) {
173
+ throw new Error('Osrm Parser: Cannot find step coords in leg coordinates');
174
+ }
175
+ step._idCoordsInLeg = idStepCoordsInLeg;
176
+
177
+ step.name = jsonStep.name;
178
+ step.levelChange = jsonStep.levelChange ? LevelChange.fromJson(jsonStep.levelChange) : null;
179
+
180
+ step.distance = jsonStep.distance;
181
+ step.duration = jsonStep.duration;
182
+
183
+ if (jsonStep.extras && jsonStep.extras.subwayEntrance) {
184
+ step.extras.subwayEntrance = true;
185
+ if (jsonStep.extras.subwayEntranceRef) {
186
+ step.extras.subwayEntranceRef = jsonStep.extras.subwayEntranceRef;
187
+ }
188
+ }
189
+
190
+ return step;
191
+ });
192
+ }
193
+
194
+
195
+ /**
196
+ * Generate multi itineraries from OSRM JSON
197
+ * @param {object} json JSON file provided by OSRM.
198
+ * @param {Coordinates} from itinerary start
199
+ * @param {Coordinates} to itinerary end
200
+ * @param {?string} routingMode [walking|driving|bicycle]
201
+ * @returns {?RouterResponse}
202
+ */
203
+ export function createRouterResponseFromJson(json, from, to, routingMode = 'walking') {
204
+
205
+ const { routes: jsonRoutes } = json;
206
+
207
+ if (!jsonRoutes) {
208
+ return null;
209
+ }
210
+
211
+ const routingModeCorrespondance = new Map();
212
+ routingModeCorrespondance.set('walking', 'WALK');
213
+ routingModeCorrespondance.set('driving', 'CAR');
214
+ routingModeCorrespondance.set('bicycle', 'BIKE');
215
+ const mode = routingModeCorrespondance.get(routingMode) || null;
216
+
217
+ const routerResponse = new RouterResponse();
218
+ routerResponse.routerName = 'osrm';
219
+
220
+ routerResponse.from = from;
221
+ routerResponse.to = to;
222
+
223
+ for (const jsonItinerary of jsonRoutes) {
224
+
225
+ const itinerary = new Itinerary();
226
+
227
+ // itinerary.coords = jsonItinerary.geometry.coordinates.map(jsonToCoordinates);
228
+ itinerary.distance = jsonItinerary.distance;
229
+ itinerary.duration = jsonItinerary.duration;
230
+ itinerary.from = from;
231
+ itinerary.to = to;
232
+
233
+ routerResponse.itineraries.push(itinerary);
234
+
235
+ for (const jsonLeg of jsonItinerary.legs) {
236
+
237
+ const leg = new Leg();
238
+
239
+ leg.mode = mode;
240
+ leg.distance = jsonLeg.distance;
241
+ leg.duration = jsonLeg.duration;
242
+
243
+ leg.coords = jsonLeg.steps
244
+ .map(step => step.geometry.coordinates.map(jsonToCoordinates))
245
+ .flat()
246
+ // Remove duplicates
247
+ .filter((coords, idx, arr) => idx === 0 || !arr[idx - 1].equalsTo(coords));
248
+
249
+ leg.from = {
250
+ name: null,
251
+ coords: leg.coords[0]
252
+ };
253
+ leg.to = {
254
+ name: null,
255
+ coords: leg.coords[leg.coords.length - 1]
256
+ };
257
+
258
+ leg.steps = parseJsonSteps(jsonLeg.steps, leg.coords);
259
+
260
+ itinerary.legs.push(leg);
261
+ }
262
+
263
+ // All legs have to be parsed before computing steps metadata
264
+ generateStepsMetadata(itinerary);
265
+
266
+ }
267
+
268
+ return routerResponse;
269
+ }