@wemap/routers 12.10.8 → 12.11.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 (170) hide show
  1. package/dist/helpers/InstructionManager.d.ts +20 -0
  2. package/dist/helpers/InstructionManagerV1.d.ts +7 -0
  3. package/{index.ts → dist/index.d.ts} +1 -11
  4. package/dist/index.js +1 -5099
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +100 -5
  7. package/dist/index.mjs.map +1 -1
  8. package/dist/src/ItineraryInfoManager.d.ts +31 -0
  9. package/dist/src/RoutingError.d.ts +24 -0
  10. package/{src/StatusCode.ts → dist/src/StatusCode.d.ts} +2 -3
  11. package/dist/src/Utils.d.ts +6 -0
  12. package/dist/src/graph/Edge.d.ts +38 -0
  13. package/dist/src/graph/Graph.d.ts +40 -0
  14. package/dist/src/graph/GraphProjection.d.ts +11 -0
  15. package/dist/src/graph/GraphProjectionOptions.d.ts +7 -0
  16. package/dist/src/graph/GraphRoute.d.ts +19 -0
  17. package/dist/src/graph/GraphRouter.d.ts +20 -0
  18. package/dist/src/graph/GraphRouterEngine.d.ts +80 -0
  19. package/{src/graph/GraphRouterOptions.ts → dist/src/graph/GraphRouterOptions.d.ts} +6 -7
  20. package/dist/src/graph/GraphRouterOptionsBuilder.d.ts +23 -0
  21. package/dist/src/graph/GraphRouterOptionsFactors.d.ts +8 -0
  22. package/dist/src/graph/NoRouteFoundError.d.ts +12 -0
  23. package/dist/src/graph/Vertex.d.ts +19 -0
  24. package/dist/src/model/Itinerary.d.ts +81 -0
  25. package/dist/src/model/Leg.d.ts +66 -0
  26. package/dist/src/model/LevelChange.d.ts +7 -0
  27. package/dist/src/model/RouterRequest.d.ts +42 -0
  28. package/dist/src/model/Step.d.ts +42 -0
  29. package/dist/src/model/StepExtra.d.ts +3 -0
  30. package/dist/src/model/StepsBuilder.d.ts +16 -0
  31. package/dist/src/model/TransitMode.d.ts +5 -0
  32. package/{src/model/TravelMode.ts → dist/src/model/TravelMode.d.ts} +1 -2
  33. package/dist/src/model/generateSteps.d.ts +0 -0
  34. package/{src/remote/RemoteRouter.ts → dist/src/remote/RemoteRouter.d.ts} +2 -7
  35. package/dist/src/remote/RemoteRouterManager.d.ts +731 -0
  36. package/dist/src/remote/RemoteRouterUtils.d.ts +6 -0
  37. package/dist/src/remote/cityway/CitywayRemoteRouter.d.ts +109 -0
  38. package/dist/src/remote/deutsche-bahn/DeutscheBahnRemoteRouter.d.ts +31 -0
  39. package/dist/src/remote/geovelo/GeoveloRemoteRouter.d.ts +106 -0
  40. package/dist/src/remote/idfm/IdfmRemoteRouter.d.ts +123 -0
  41. package/dist/src/remote/navitia/NavitiaRemoteRouter.d.ts +34 -0
  42. package/dist/src/remote/navitia/types.d.ts +87 -0
  43. package/dist/src/remote/osrm/OsrmRemoteRouter.d.ts +70 -0
  44. package/dist/src/remote/otp/OtpRemoteRouter.d.ts +69 -0
  45. package/dist/src/remote/wemap-multi/WemapMultiRemoteRouter.d.ts +19 -0
  46. package/dist/src/types.d.ts +31 -0
  47. package/dist/src/wemap-multi/CustomGraphMap.d.ts +56 -0
  48. package/dist/src/wemap-multi/CustomGraphMapTester.d.ts +39 -0
  49. package/dist/src/wemap-multi/WemapMultiRouter.d.ts +14 -0
  50. package/dist/src/wemap-osm/OsmGraphUtils.d.ts +11 -0
  51. package/dist/tests/CommonTest.d.ts +8 -0
  52. package/package.json +11 -8
  53. package/assets/biocbon-bergere-rdc-network.osm +0 -163
  54. package/assets/bureaux-wemap-montpellier-network.osm +0 -174
  55. package/assets/components.osm +0 -146
  56. package/assets/elevator-models-4.osm +0 -89
  57. package/assets/elevator-models.osm +0 -354
  58. package/assets/exit-graph.osm +0 -25
  59. package/assets/gare-de-lest-network-pp-bounds.osm +0 -1613
  60. package/assets/gare-de-lyon-extract.osm +0 -174
  61. package/assets/geovelo-montpellier.json +0 -1144
  62. package/assets/horizontal-elevator.osm +0 -12
  63. package/assets/itinerary-deutsche-bahn-1.json +0 -368
  64. package/assets/itinerary-grenoble-otp-1.json +0 -1536
  65. package/assets/itinerary-grenoble-otp-2.json +0 -1092
  66. package/assets/itinerary-info-two-points-proj.osm +0 -39
  67. package/assets/itinerary-info-two-points.osm +0 -24
  68. package/assets/itinerary-lehavre-cityway-1.json +0 -6799
  69. package/assets/itinerary-lehavre-cityway-2.json +0 -2133
  70. package/assets/itinerary-lehavre-cityway-3.json +0 -12577
  71. package/assets/itinerary-lehavre-cityway-4.json +0 -1451
  72. package/assets/itinerary-lehavre-cityway-5.json +0 -5925
  73. package/assets/itinerary-lemans-navitia.json +0 -7768
  74. package/assets/itinerary-montpellier-osrm-3.json +0 -185
  75. package/assets/itinerary-montpellier-outdoor-without-steps.json +0 -110
  76. package/assets/itinerary-montpellier-outdoor.json +0 -513
  77. package/assets/itinerary-paris-idfm-2.json +0 -1838
  78. package/assets/itinerary-paris-idfm.json +0 -27727
  79. package/assets/itinerary-step-not-on-path-osrm.json +0 -457
  80. package/assets/itinerary-with-duplicate-nodes.json +0 -110
  81. package/assets/network-conveying-backward.osm +0 -74
  82. package/assets/network-elevator.osm +0 -48
  83. package/assets/network-escalators.osm +0 -50
  84. package/assets/network-simple.osm +0 -27
  85. package/assets/network-steps-same-level.osm +0 -283
  86. package/assets/network-with-modifiers.osm +0 -39
  87. package/assets/one-way.osm +0 -46
  88. package/assets/report-map-1.osm +0 -36
  89. package/assets/report-map-2.osm +0 -29
  90. package/assets/report-map-3.osm +0 -15
  91. package/assets/rr-wemap-multi-indoor-outdoor-indoor.json +0 -1352
  92. package/assets/rr-wemap-multi-indoor-outdoor.json +0 -145
  93. package/assets/rr-wemap-multi-multi-level.json +0 -262
  94. package/assets/rr-wemap-multi-outdoor-indoor.json +0 -145
  95. package/assets/rr-wemap-multi-outdoor-outdoor.json +0 -207
  96. package/assets/rr-wemap-multi-remote-indoor-indoor.json +0 -155
  97. package/assets/rr-wemap-multi-remote-indoor-outdoor-indoor.json +0 -668
  98. package/assets/rr-wemap-multi-remote-indoor-outdoor.json +0 -154
  99. package/assets/rr-wemap-multi-remote-outdoor-indoor.json +0 -179
  100. package/assets/rr-wemap-multi-remote-outdoor-outdoor.json +0 -109
  101. package/assets/stairs-and-exit.osm +0 -47
  102. package/helpers/InstructionManager.ts +0 -184
  103. package/helpers/InstructionManagerV1.ts +0 -95
  104. package/src/ItineraryInfoManager.spec.ts +0 -183
  105. package/src/ItineraryInfoManager.ts +0 -181
  106. package/src/RoutingError.ts +0 -60
  107. package/src/Utils.ts +0 -8
  108. package/src/graph/Edge.spec.ts +0 -32
  109. package/src/graph/Edge.ts +0 -64
  110. package/src/graph/Graph.spec.ts +0 -509
  111. package/src/graph/Graph.ts +0 -272
  112. package/src/graph/GraphProjection.ts +0 -15
  113. package/src/graph/GraphProjectionOptions.ts +0 -8
  114. package/src/graph/GraphRoute.spec.ts +0 -15
  115. package/src/graph/GraphRoute.ts +0 -43
  116. package/src/graph/GraphRouter.spec.ts +0 -317
  117. package/src/graph/GraphRouter.ts +0 -229
  118. package/src/graph/GraphRouterEngine.ts +0 -248
  119. package/src/graph/GraphRouterOptionsBuilder.ts +0 -98
  120. package/src/graph/NoRouteFoundError.ts +0 -39
  121. package/src/graph/Vertex.spec.ts +0 -42
  122. package/src/graph/Vertex.ts +0 -45
  123. package/src/model/Itinerary.spec.ts +0 -134
  124. package/src/model/Itinerary.ts +0 -370
  125. package/src/model/Leg.spec.ts +0 -107
  126. package/src/model/Leg.ts +0 -224
  127. package/src/model/LevelChange.spec.ts +0 -50
  128. package/src/model/LevelChange.ts +0 -14
  129. package/src/model/RouterRequest.ts +0 -33
  130. package/src/model/Step.spec.ts +0 -99
  131. package/src/model/Step.ts +0 -90
  132. package/src/model/StepExtra.ts +0 -1
  133. package/src/model/StepsBuilder.ts +0 -242
  134. package/src/model/TransitMode.spec.ts +0 -31
  135. package/src/model/TransitMode.ts +0 -28
  136. package/src/model/generateSteps.ts +0 -102
  137. package/src/remote/RemoteRouterManager.spec.ts +0 -178
  138. package/src/remote/RemoteRouterManager.ts +0 -72
  139. package/src/remote/RemoteRouterUtils.ts +0 -25
  140. package/src/remote/cityway/CitywayRemoteRouter.spec.ts +0 -122
  141. package/src/remote/cityway/CitywayRemoteRouter.ts +0 -435
  142. package/src/remote/deutsche-bahn/DeutscheBahnRemoteRouter.spec.ts +0 -52
  143. package/src/remote/deutsche-bahn/DeutscheBahnRemoteRouter.ts +0 -85
  144. package/src/remote/geovelo/GeoveloRemoteRouter.spec.ts +0 -54
  145. package/src/remote/geovelo/GeoveloRemoteRouter.ts +0 -293
  146. package/src/remote/idfm/IdfmRemoteRouter.spec.ts +0 -102
  147. package/src/remote/idfm/IdfmRemoteRouter.ts +0 -523
  148. package/src/remote/navitia/NavitiaRemoteRouter.spec.ts +0 -116
  149. package/src/remote/navitia/NavitiaRemoteRouter.ts +0 -445
  150. package/src/remote/navitia/types.ts +0 -73
  151. package/src/remote/osrm/OsrmRemoteRouter.spec.ts +0 -127
  152. package/src/remote/osrm/OsrmRemoteRouter.ts +0 -303
  153. package/src/remote/otp/OtpRemoteRouter.spec.ts +0 -103
  154. package/src/remote/otp/OtpRemoteRouter.ts +0 -223
  155. package/src/remote/wemap-multi/WemapMultiRemoteRouter.spec.ts +0 -103
  156. package/src/remote/wemap-multi/WemapMultiRemoteRouter.ts +0 -56
  157. package/src/types.ts +0 -32
  158. package/src/wemap-multi/CustomGraphMap.spec.ts +0 -40
  159. package/src/wemap-multi/CustomGraphMap.ts +0 -213
  160. package/src/wemap-multi/CustomGraphMapTester.spec.ts +0 -48
  161. package/src/wemap-multi/CustomGraphMapTester.ts +0 -90
  162. package/src/wemap-multi/WemapMultiRouter.spec.ts +0 -138
  163. package/src/wemap-multi/WemapMultiRouter.ts +0 -329
  164. package/src/wemap-osm/OsmGraphUtils.spec.ts +0 -165
  165. package/src/wemap-osm/OsmGraphUtils.ts +0 -173
  166. package/src/wemap-osm/OsmRouter.elevators.spec.ts +0 -106
  167. package/src/wemap-osm/OsmRouter.spec.ts +0 -292
  168. package/tests/CommonTest.ts +0 -78
  169. package/tsconfig.json +0 -3
  170. package/vite.config.ts +0 -4
@@ -1,303 +0,0 @@
1
- /* eslint-disable max-statements */
2
-
3
- import { Coordinates, Level } from '@wemap/geo';
4
- import { rad2deg, positiveMod } from '@wemap/maths';
5
- import { LineString, Position } from 'geojson';
6
-
7
- import Itinerary from '../../model/Itinerary.js';
8
- import Leg from '../../model/Leg.js';
9
- import StepsBuilder from '../../model/StepsBuilder.js';
10
- import RemoteRouter from '../RemoteRouter.js';
11
- import { type TravelMode } from '../../model/TravelMode.js';
12
- import { type TransitMode } from '../../model/TransitMode.js';
13
- import { type RouterRequest } from '../../model/RouterRequest.js';
14
- import { RemoteRoutingError } from '../../RoutingError.js';
15
-
16
- type OsrmCoordinates = Position;
17
- type OsrmModifier = 'sharp right' | 'sharp left' | 'slight right'
18
- | 'slight left' | 'right' | 'left' | 'u turn' | 'straight';
19
- type OsrmManeuverType = 'depart' | 'turn' | 'arrive';
20
- type OsrmStep = {
21
- geometry: LineString,
22
- distance: number,
23
- duration: number,
24
- name?: string,
25
- maneuver: {
26
- bearing_before: number,
27
- bearing_after: number,
28
- location: OsrmCoordinates,
29
- modifier: OsrmModifier,
30
- type: OsrmManeuverType
31
- }
32
- };
33
- type OsrmJson = {
34
- code?: string,
35
- message?: string,
36
- routes?: {
37
- geometry: LineString,
38
- legs: {
39
- distance: number,
40
- duration: number,
41
- steps: OsrmStep[]
42
- }[],
43
- distance: number,
44
- duration: number,
45
- weight_name: string,
46
- weight: number
47
- }[],
48
- waypoints?: []
49
- };
50
-
51
- type OsrmMode = 'driving' | 'walking' | 'bike' | 'pmr' | 'bike-safest' | 'bike-fastest';
52
-
53
- const outputModeCorrespondance = new Map<TravelMode, TransitMode>();
54
- outputModeCorrespondance.set('CAR', 'CAR');
55
- outputModeCorrespondance.set('WALK', 'WALK');
56
- outputModeCorrespondance.set('BIKE', 'BIKE');
57
-
58
- /**
59
- * Singleton.
60
- */
61
- class OsrmRemoteRouter extends RemoteRouter {
62
-
63
- get rname() { return 'osrm' as const; }
64
-
65
- async getItineraries(endpointUrl: string, routerRequest: RouterRequest) {
66
- const url = this.getURL(endpointUrl, routerRequest);
67
-
68
- const res = await (fetch(url).catch(() => {
69
- throw RemoteRoutingError.unreachableServer(this.rname, url);
70
- }));
71
-
72
- const jsonResponse = await res.json().catch(() => {
73
- throw RemoteRoutingError.responseNotParsing(this.rname, url);
74
- });
75
-
76
- return this.parseResponse(jsonResponse, routerRequest.origin, routerRequest.destination, routerRequest.travelMode);
77
- }
78
-
79
- /**
80
- * @throws {TravelModeCorrespondanceNotFound}
81
- */
82
- getURL(endpointUrl: string, routerRequest: RouterRequest) {
83
- const { origin, destination } = routerRequest;
84
-
85
- const osrmMode = this.inputModeCorrespondance(routerRequest);
86
- const waypoints = [origin, ...routerRequest.waypoints || [], destination];
87
-
88
- let url = endpointUrl + '/route/v1/' + osrmMode + '/';
89
- url += waypoints.map(waypoint => [waypoint.longitude + ',' + waypoint.latitude]).join(';');
90
- url += '?geometries=geojson&overview=full&steps=true';
91
- routerRequest.provideItineraryAlternatives && (url += '&alternatives=true')
92
- return url;
93
- }
94
-
95
- inputModeCorrespondance = (routerRequest: RouterRequest): OsrmMode => {
96
- const { travelMode, travelModePreference: preference } = routerRequest;
97
- if (travelMode === 'WALK' && routerRequest.itineraryModifiers?.avoidStairs) return 'pmr';
98
- if (travelMode === 'WALK') return 'walking';
99
- if (travelMode === 'BIKE') {
100
- if (preference === 'FASTEST') return 'bike-fastest';
101
- if (preference === 'SAFEST') return 'bike-safest';
102
- if (preference === 'TOURISM') return 'bike-safest';
103
- return 'bike-safest';
104
- }
105
- if (travelMode === 'CAR') return 'driving';
106
- throw RemoteRoutingError.travelModeUnimplemented(this.rname, travelMode);
107
- }
108
-
109
- coordinatesToJson({ lat, lng, level }: Coordinates): OsrmCoordinates {
110
- if (level === null) {
111
- return [lng, lat];
112
- }
113
- if (Level.isRange(level)) {
114
- return [lng, lat, level[0]];
115
- }
116
- return [lng, lat, level];
117
- }
118
-
119
- /**
120
- * @param {object} json
121
- * @returns {Coordinates}
122
- */
123
- jsonToCoordinates(json: OsrmCoordinates): Coordinates {
124
- const coords = new Coordinates(json[1], json[0]);
125
- if (json.length > 2) {
126
- coords.level = json[2] as number;
127
- }
128
- return coords;
129
- }
130
-
131
- getModifierFromAngle(_angle: number): OsrmModifier {
132
-
133
- const angle = positiveMod(rad2deg(_angle), 360);
134
-
135
- if (angle > 0 && angle < 60) {
136
- return 'sharp right';
137
- }
138
- if (angle >= 60 && angle < 140) {
139
- return 'right';
140
- }
141
- if (angle >= 140 && angle < 160) {
142
- return 'slight right';
143
- }
144
- if (angle >= 160 && angle <= 200) {
145
- return 'straight';
146
- }
147
- if (angle > 200 && angle <= 220) {
148
- return 'slight left';
149
- }
150
- if (angle > 220 && angle <= 300) {
151
- return 'left';
152
- }
153
- if (angle > 300 && angle < 360) {
154
- return 'sharp left';
155
- }
156
- return 'u turn';
157
- }
158
-
159
- noRouteFoundJson(message: object) {
160
- return {
161
- 'code': 'NoRoute',
162
- message
163
- };
164
- }
165
-
166
- /**
167
- * @deprecated
168
- */
169
- itineraryToOsrmJson(itinerary: Itinerary): OsrmJson {
170
-
171
- const lastLegId = itinerary.legs.length - 1;
172
- const itinerarySteps = itinerary.steps;
173
-
174
- const jsonLegs = itinerary.legs.map(({ distance, duration, coords }, idLeg) => {
175
-
176
- // Filter steps which are in leg
177
- const legSteps = itinerarySteps.filter(step =>
178
- coords.find(_coords => _coords.equals(step.coords))
179
- );
180
-
181
- const lastStepId = legSteps.length - 1;
182
-
183
- return {
184
- distance,
185
- duration: duration || 0,
186
- steps: legSteps.map((step, idStep, arr) => {
187
-
188
- let type: OsrmManeuverType = idStep === 0 && idLeg === 0 ? 'depart' : 'turn';
189
- type = idStep === lastStepId && idLeg === lastLegId ? 'arrive' : type;
190
-
191
- const stepCoordsIdx = coords.findIndex(p => p.equals(step.coords));
192
- const nextStepCoordsIdx = idStep === lastStepId
193
- ? stepCoordsIdx
194
- : coords.findIndex(p => p.equals(arr[idStep + 1].coords));
195
-
196
- const osrmStep: OsrmStep = {
197
- geometry: {
198
- type: 'LineString',
199
- coordinates: coords.slice(stepCoordsIdx, nextStepCoordsIdx + 1).map(this.coordinatesToJson)
200
- },
201
- distance: step.distance,
202
- duration: step.duration || 0,
203
- ...(step.name && { name: step.name }),
204
- maneuver: {
205
- bearing_before: rad2deg(step.previousBearing),
206
- bearing_after: rad2deg(step.nextBearing),
207
- location: this.coordinatesToJson(step.coords),
208
- modifier: this.getModifierFromAngle(step.angle),
209
- type
210
- },
211
- };
212
- return osrmStep;
213
- })
214
- };
215
- });
216
-
217
- return {
218
- 'code': 'Ok',
219
- 'routes': [
220
- {
221
- 'geometry': {
222
- 'type': 'LineString',
223
- 'coordinates': itinerary.coords.map(this.coordinatesToJson)
224
- },
225
- 'legs': jsonLegs,
226
- 'distance': itinerary.distance,
227
- 'duration': itinerary.duration,
228
- 'weight_name': 'routability',
229
- 'weight': 0
230
- }
231
- ],
232
- 'waypoints': []
233
- };
234
- }
235
-
236
- parseResponse(json: OsrmJson, origin: Coordinates, destination: Coordinates, travelMode: TravelMode) {
237
-
238
- const transitMode = outputModeCorrespondance.get(travelMode)!;
239
-
240
- const { routes: jsonRoutes } = json;
241
- if (!jsonRoutes) {
242
- throw RemoteRoutingError.notFound(this.rname, json.message);
243
- }
244
-
245
- return jsonRoutes.map(jsonItinerary => {
246
-
247
- const legs = jsonItinerary.legs.map((jsonLeg) => {
248
- const legCoords = jsonLeg.steps
249
- .map(step => step.geometry.coordinates.map(this.jsonToCoordinates))
250
- .flat()
251
- // Remove duplicates
252
- .filter((coords, idx, arr) => idx === 0 || !arr[idx - 1].equals(coords));
253
-
254
- const startCoords = legCoords[0];
255
- const endCoords = legCoords[legCoords.length - 1];
256
-
257
- const stepsBuilder = new StepsBuilder().setPathCoords(legCoords).setStart(startCoords).setEnd(endCoords);
258
- jsonLeg.steps?.forEach(({ maneuver, name, distance, duration }) => {
259
-
260
- const stepCoords = this.jsonToCoordinates(maneuver.location);
261
-
262
- // Sometimes, OSRM step does not have the same coordinates than a point in legCoords.
263
- // ex: first step of https://routing-orsm.getwemap.com/route/v1/walking/2.33222164147,48.87084765712;2.3320734,48.8730212?geometries=geojson&overview=full&steps=true
264
- // That is why we look for the closest point.
265
- const distances = legCoords.map(coords => coords.distanceTo(stepCoords));
266
- const idStepCoordsInLeg = distances.indexOf(Math.min(...distances));
267
- if (idStepCoordsInLeg < 0) {
268
- throw new Error('Osrm Parser: Cannot find step coords in leg coordinates');
269
- }
270
-
271
- stepsBuilder.addStepInfo({
272
- coords: legCoords[idStepCoordsInLeg],
273
- name,
274
- distance,
275
- duration
276
- });
277
- })
278
-
279
- return new Leg({
280
- transitMode,
281
- duration: jsonLeg.duration,
282
- coords: legCoords,
283
- start: {
284
- coords: startCoords
285
- },
286
- end: {
287
- coords: endCoords
288
- },
289
- steps: stepsBuilder.build()
290
- });
291
- });
292
-
293
- return new Itinerary({
294
- duration: jsonItinerary.duration,
295
- origin,
296
- destination,
297
- legs
298
- });
299
- });
300
- }
301
- }
302
-
303
- export default new OsrmRemoteRouter();
@@ -1,103 +0,0 @@
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
-
10
- import OtpRemoteRouter from './OtpRemoteRouter.js';
11
- import { verifyStepsCoherence } from '../../model/Itinerary.spec.js';
12
- import { areTransitAndTravelModeConsistent } from '../../model/TransitMode.js';
13
-
14
-
15
- const { expect } = chai;
16
- chai.use(chaiAlmost(0.1));
17
-
18
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
19
- const assetsPath = path.resolve(__dirname, '../../../assets');
20
-
21
- describe('OtpRouter - createRouterResponseFromJson', () => {
22
-
23
- it('Itineraries - 1', () => {
24
-
25
- const filePath = path.resolve(assetsPath, 'itinerary-grenoble-otp-1.json');
26
- const fileString = fs.readFileSync(filePath, 'utf8');
27
- const json = JSON.parse(fileString);
28
-
29
- const itineraries = OtpRemoteRouter.parseResponse(json);
30
- itineraries.forEach(verifyStepsCoherence);
31
-
32
- expect(itineraries.length).equal(2);
33
-
34
- const itinerary1 = itineraries[0];
35
- expect(itinerary1.origin.equals(new Coordinates(45.187291, 5.723455))).true;
36
- expect(itinerary1.destination.equals(new Coordinates(45.163729, 5.74085))).true;
37
- expect(itinerary1.coords.length).equal(162);
38
- expect(itinerary1.duration).equal(1206);
39
- expect(itinerary1.startTime).equal(1614607210000);
40
- expect(itinerary1.endTime).equal(1614608416000);
41
- expect(itinerary1.legs.length).equal(3);
42
- expect(itinerary1.transitMode).equal('BUS');
43
- expect(areTransitAndTravelModeConsistent(itinerary1.transitMode, 'TRANSIT')).is.true;
44
-
45
- const itinerary1leg1 = itinerary1.legs[0];
46
- expect(itinerary1leg1.startTime).equal(1614607210000);
47
- expect(itinerary1leg1.endTime).equal(1614607499000);
48
- expect(itinerary1leg1.distance).almost.equal(260.14);
49
- expect(itinerary1leg1.transitMode).equal('WALK');
50
- expect(itinerary1leg1.transportInfo).is.null;
51
- expect(itinerary1leg1.start.name).equal('Origin');
52
- expect(itinerary1leg1.start.coords.equals(new Coordinates(45.187291, 5.723455))).true;
53
- expect(itinerary1leg1.end.name).equal('Grenoble, Victor Hugo');
54
- expect(itinerary1leg1.end.coords.equals(new Coordinates(45.1887, 5.72533))).true;
55
-
56
- const itinerary1leg2 = itinerary1.legs[1];
57
- expect(itinerary1leg2.transitMode).equal('BUS');
58
- expect(itinerary1leg2.transportInfo).is.not.null;
59
- expect(itinerary1leg2.transportInfo?.name).equal('C4');
60
- expect(itinerary1leg2.transportInfo?.routeColor).equal('F3D000');
61
- expect(itinerary1leg2.transportInfo?.routeTextColor).equal('000000');
62
- expect(itinerary1leg2.transportInfo?.directionName).equal('Eybens, Le Verderet');
63
-
64
- });
65
-
66
-
67
- it('Itineraries - 2', () => {
68
-
69
- const filePath = path.resolve(assetsPath, 'itinerary-grenoble-otp-2.json');
70
- const fileString = fs.readFileSync(filePath, 'utf8');
71
- const json = JSON.parse(fileString);
72
-
73
- const itineraries = OtpRemoteRouter.parseResponse(json);
74
- itineraries.forEach(verifyStepsCoherence);
75
-
76
- expect(itineraries.length).equal(2);
77
-
78
- const itinerary1 = itineraries[0];
79
- expect(itinerary1.origin.equals(new Coordinates(45.192514856662456, 5.731452541397871))).true;
80
- expect(itinerary1.destination.equals(new Coordinates(45.18544, 5.73123))).true;
81
- expect(itinerary1.legs.length).equal(5);
82
-
83
- expect(itinerary1.transitMode).equal('TRAM');
84
- expect(areTransitAndTravelModeConsistent(itinerary1.transitMode, 'TRANSIT')).is.true;
85
-
86
- expect(itinerary1.legs[0].transitMode).equal('WALK');
87
-
88
- expect(itinerary1.legs[1].transitMode).equal('TRAM');
89
- expect(itinerary1.legs[1].transportInfo).is.not.null;
90
-
91
- expect(itinerary1.legs[2].transitMode).equal('WALK');
92
-
93
- expect(itinerary1.legs[3].transitMode).equal('TRAM');
94
- expect(itinerary1.legs[3].transportInfo).is.not.null;
95
-
96
- expect(itinerary1.legs[4].transitMode).equal('WALK');
97
-
98
- expect(itinerary1.steps[0].firstStep).is.true;
99
- expect(itinerary1.steps[itinerary1.steps.length - 1].lastStep).is.true;
100
- });
101
-
102
-
103
- });
@@ -1,223 +0,0 @@
1
- import Polyline from '@mapbox/polyline';
2
-
3
- import { Coordinates } from '@wemap/geo';
4
- import Logger from '@wemap/logger';
5
-
6
- import Itinerary from '../../model/Itinerary.js';
7
- import Leg, { type TransportInfo } from '../../model/Leg.js';
8
- import StepsBuilder from '../../model/StepsBuilder.js';
9
- import RemoteRouter from '../RemoteRouter.js';
10
- import { type TravelMode } from '../../model/TravelMode.js';
11
- import { type RouterRequest } from '../../model/RouterRequest.js';
12
- import { RemoteRoutingError } from '../../RoutingError.js';
13
-
14
- type OtpCoordinates = { lat: number, lon: number };
15
- type FromTo = OtpCoordinates & { name: string };
16
- type FromToPT = FromTo & { stopId: string, stopCode: string };
17
-
18
- type CommonLeg = {
19
- startTime: number,
20
- endTime: number,
21
- legGeometry: {
22
- points: string,
23
- length: number
24
- },
25
- duration: number,
26
- };
27
-
28
- type LegWalk = CommonLeg & {
29
- mode: 'WALK',
30
- from: FromTo,
31
- to: FromTo,
32
- steps: (OtpCoordinates & {
33
- distance: number,
34
- streetName: string
35
- })[]
36
- }
37
-
38
- type LegPT = CommonLeg & {
39
- mode: 'BUS' | 'TRAM',
40
- from: FromToPT,
41
- to: FromToPT,
42
- intermediateStops: FromToPT,
43
- routeShortName: 'string',
44
- routeColor?: 'string',
45
- routeTextColor?: 'string',
46
- headsign: 'string'
47
- }
48
-
49
- type OtpJson = {
50
- plan: {
51
- from: FromTo,
52
- to: FromTo,
53
- itineraries: {
54
- duration: number,
55
- startTime: number,
56
- endTime: number,
57
- walkDistance: number,
58
- legs: (LegWalk | LegPT)[]
59
- }[]
60
- }
61
- }
62
-
63
- function isLegPT(leg: LegPT | LegWalk): leg is LegPT {
64
- return leg.mode === 'BUS' || leg.mode === 'TRAM';
65
- }
66
-
67
- function jsonToCoordinates(json: OtpCoordinates) {
68
- return new Coordinates(json.lat, json.lon);
69
- }
70
-
71
-
72
- /**
73
- * Input mode correspondance
74
- */
75
- const inputModeCorrespondance = new Map<TravelMode, string>();
76
- inputModeCorrespondance.set('CAR', 'CAR');
77
- inputModeCorrespondance.set('WALK', 'WALK');
78
- inputModeCorrespondance.set('BIKE', 'BICYCLE');
79
- inputModeCorrespondance.set('TRANSIT', 'WALK,TRANSIT');
80
-
81
- /**
82
- * Singleton.
83
- */
84
- class OtpRemoteRouter extends RemoteRouter {
85
-
86
- get rname() { return 'otp' as const; }
87
-
88
- async getItineraries(endpointUrl: string, routerRequest: RouterRequest) {
89
- const url = this.getURL(endpointUrl, routerRequest);
90
- const res = await (fetch(url).catch(() => {
91
- throw RemoteRoutingError.unreachableServer(this.rname, url);
92
- }));
93
-
94
- const jsonResponse = await res.json().catch(() => {
95
- throw RemoteRoutingError.responseNotParsing(this.rname, url);
96
- });
97
- return this.parseResponse(jsonResponse);
98
- }
99
-
100
- getURL(endpointUrl: string, routerRequest: RouterRequest) {
101
- const { origin, destination, waypoints, travelMode } = routerRequest;
102
-
103
- const otpMode = inputModeCorrespondance.get(travelMode);
104
- if (!otpMode) {
105
- throw RemoteRoutingError.travelModeUnimplemented(this.rname, travelMode);
106
- }
107
-
108
- if ((waypoints || []).length > 0) {
109
- Logger.warn(`${this.rname} router uses only the first 2 waypoints (asked ${waypoints?.length})`);
110
- }
111
-
112
- const fromPlace = `fromPlace=${origin.latitude},${origin.longitude}`;
113
- const toPlace = `toPlace=${destination.latitude},${destination.longitude}`;
114
- const queryMode = `mode=${otpMode}`;
115
-
116
- const url = new URL(endpointUrl);
117
- let { search } = url;
118
- search = (search ? `${search}&` : '?') + `${fromPlace}&${toPlace}&${queryMode}`;
119
-
120
- return `${url.origin}${url.pathname}${search}`;
121
- }
122
-
123
-
124
- /**
125
- * Generate multi itineraries from OTP JSON
126
- */
127
- parseResponse(json: OtpJson) {
128
-
129
- const { plan: jsonPlan } = json;
130
- if (!jsonPlan) {
131
- throw RemoteRoutingError.notFound(this.rname);
132
- }
133
-
134
- const itineraries = [];
135
-
136
- const itinerariesOrigin = jsonToCoordinates(jsonPlan.from);
137
- const itinerariesDestination = jsonToCoordinates(jsonPlan.to);
138
-
139
- for (const jsonItinerary of jsonPlan.itineraries) {
140
-
141
- const legs: Leg[] = [];
142
-
143
- for (const jsonLeg of jsonItinerary.legs) {
144
-
145
- const startCoordinates = jsonToCoordinates(jsonLeg.from);
146
- const endCoordinates = jsonToCoordinates(jsonLeg.to);
147
-
148
- const legCoords = Polyline.decode(jsonLeg.legGeometry.points)
149
- .map(([lat, lon]) => new Coordinates(lat, lon));
150
-
151
- let transportInfo: TransportInfo | undefined;
152
- const stepsBuilder = new StepsBuilder().setStart(startCoordinates).setEnd(endCoordinates).setPathCoords(legCoords);
153
-
154
- if (isLegPT(jsonLeg)) {
155
-
156
- transportInfo = {
157
- name: jsonLeg.routeShortName,
158
- routeColor: jsonLeg.routeColor,
159
- routeTextColor: jsonLeg.routeTextColor,
160
- directionName: jsonLeg.headsign
161
- };
162
-
163
- stepsBuilder.addStepInfo({
164
- coords: legCoords[0],
165
- name: jsonLeg.headsign
166
- });
167
-
168
- } else {
169
-
170
- jsonLeg.steps.forEach(jsonStep => {
171
- // OTP step does not have the same coordinates than a point in legCoords.
172
- // That is why we look for the closest point.
173
- const distances = legCoords.map(coords => coords.distanceTo(jsonToCoordinates(jsonStep)));
174
- const idStepCoordsInLeg = distances.indexOf(Math.min(...distances));
175
- if (idStepCoordsInLeg < 0) {
176
- throw new Error('OTP Parser: Cannot find closest step');
177
- }
178
-
179
- stepsBuilder.addStepInfo({
180
- coords: legCoords[idStepCoordsInLeg],
181
- name: jsonStep.streetName
182
- });
183
- })
184
- }
185
-
186
-
187
- const leg = new Leg({
188
- transitMode: jsonLeg.mode,
189
- duration: jsonLeg.duration,
190
- startTime: jsonLeg.startTime,
191
- endTime: jsonLeg.endTime,
192
- start: {
193
- name: jsonLeg.from.name,
194
- coords: jsonToCoordinates(jsonLeg.from)
195
- },
196
- end: {
197
- name: jsonLeg.to.name,
198
- coords: jsonToCoordinates(jsonLeg.to)
199
- },
200
- coords: legCoords,
201
- transportInfo,
202
- steps: stepsBuilder.build()
203
- });
204
-
205
- legs.push(leg);
206
-
207
- }
208
- const itinerary = new Itinerary({
209
- duration: jsonItinerary.duration,
210
- startTime: jsonItinerary.startTime,
211
- endTime: jsonItinerary.endTime,
212
- origin: itinerariesOrigin,
213
- destination: itinerariesDestination,
214
- legs
215
- });
216
- itineraries.push(itinerary);
217
- }
218
-
219
- return itineraries;
220
- }
221
- }
222
-
223
- export default new OtpRemoteRouter();