@wemap/osm 5.0.4 → 5.0.6
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/itinerary-montpellier-osrm-3.json +1 -0
- package/package.json +2 -2
- package/src/routers/Itinerary.js +10 -0
- package/src/routers/Itinerary.type.spec.js +1 -0
- package/src/routers/Step.js +6 -1
- package/src/routers/Utils.js +33 -1
- package/src/routers/info/ItineraryInfoManager.js +1 -4
- package/src/routers/osrm/OsrmUtils.js +18 -27
- package/src/routers/osrm/OsrmUtils.spec.js +26 -0
- package/src/routers/otp/OtpUtils.js +15 -37
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"code":"Ok","routes":[{"geometry":{"coordinates":[[3.887244,43.605663],[3.887534,43.605579],[3.887765,43.605512],[3.887776,43.605508],[3.887849,43.605489]],"type":"LineString"},"legs":[{"steps":[{"intersections":[{"out":0,"entry":[true],"bearings":[112],"location":[3.887244,43.605663]},{"out":1,"location":[3.887534,43.605579],"bearings":[30,105,285],"entry":[true,true,false],"in":2}],"driving_side":"right","geometry":{"coordinates":[[3.887244,43.605663],[3.887534,43.605579],[3.887765,43.605512],[3.887776,43.605508],[3.887849,43.605489]],"type":"LineString"},"mode":"walking","duration":39.7,"maneuver":{"bearing_after":112,"location":[3.887244,43.605663],"bearing_before":0,"type":"depart"},"weight":39.7,"distance":52.4,"name":"Avenue du Pont Juvénal"},{"intersections":[{"in":0,"entry":[true],"bearings":[290],"location":[3.887849,43.605489]}],"driving_side":"right","geometry":{"coordinates":[[3.887849,43.605489],[3.887849,43.605489]],"type":"LineString"},"mode":"walking","duration":0,"maneuver":{"bearing_after":0,"type":"arrive","modifier":"right","bearing_before":110,"location":[3.887849,43.605489]},"weight":0,"distance":0,"name":"Avenue du Pont Juvénal"}],"distance":52.4,"duration":39.7,"summary":"Avenue du Pont Juvénal","weight":39.7}],"distance":52.4,"duration":39.7,"weight_name":"duration","weight":39.7}],"waypoints":[{"hint":"-y1UgREuVIG1AAAAbQEAAAAAAAAWAAAAtQAAAG0BAAAAAAAAFgAAAAIAAACMUDsAn16ZAoxQOwCfXpkCAAA_Eg61bn8=","name":"Avenue du Pont Juvénal","location":[3.887244,43.605663]},{"hint":"-S1UgRUuVIEtAAAALAAAAKsAAAAAAAAALQAAACwAAACrAAAAAAAAAAIAAADpUjsA8V2ZAsNSOwCjXZkCAwDfBg61bn8=","name":"Avenue du Pont Juvénal","location":[3.887849,43.605489]}]}
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"directory": "packages/osm"
|
|
12
12
|
},
|
|
13
13
|
"name": "@wemap/osm",
|
|
14
|
-
"version": "5.0.
|
|
14
|
+
"version": "5.0.6",
|
|
15
15
|
"bugs": {
|
|
16
16
|
"url": "https://github.com/wemap/wemap-modules-js/issues"
|
|
17
17
|
},
|
|
@@ -31,5 +31,5 @@
|
|
|
31
31
|
"@wemap/maths": "^5.0.0",
|
|
32
32
|
"sax": "^1.2.4"
|
|
33
33
|
},
|
|
34
|
-
"gitHead": "
|
|
34
|
+
"gitHead": "412142e60e70b1e18989c616c6c7d3b6f577ef2c"
|
|
35
35
|
}
|
package/src/routers/Itinerary.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* eslint-disable max-statements */
|
|
2
2
|
import { Coordinates, Network } from '@wemap/geo';
|
|
3
3
|
import Leg from './Leg.js';
|
|
4
|
+
import Step from './Step.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Main attributes are:
|
|
@@ -53,6 +54,15 @@ class Itinerary {
|
|
|
53
54
|
return this._coords;
|
|
54
55
|
}
|
|
55
56
|
|
|
57
|
+
set steps(_) {
|
|
58
|
+
throw new Error('Itinerary.step cannot be set. They are calculated from Itinerary.legs.');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** @type {!(Step[])} */
|
|
62
|
+
get steps() {
|
|
63
|
+
return this.legs.map(leg => leg.steps).flat();
|
|
64
|
+
}
|
|
65
|
+
|
|
56
66
|
/**
|
|
57
67
|
* @returns {Network}
|
|
58
68
|
*/
|
|
@@ -38,6 +38,7 @@ export function verifyStepData(step) {
|
|
|
38
38
|
expect(step.duration).satisfies(isNullOrNumber);
|
|
39
39
|
expect(step.name).satisfies(isNullOrString);
|
|
40
40
|
expect(step.levelChange).satisfies(isNullOrLevelChange);
|
|
41
|
+
expect(step._idCoordsInLeg).be.a('number');
|
|
41
42
|
|
|
42
43
|
expect(step.extras).satisfies(isNullOrObject);
|
|
43
44
|
if (step.extras !== null) {
|
package/src/routers/Step.js
CHANGED
|
@@ -43,6 +43,9 @@ class Step {
|
|
|
43
43
|
/** @type {?{?subwayEntrance: boolean, ?subwayEntranceRef: string}} */
|
|
44
44
|
extras = {};
|
|
45
45
|
|
|
46
|
+
/** @type {!number} */
|
|
47
|
+
_idCoordsInLeg = null;
|
|
48
|
+
|
|
46
49
|
/**
|
|
47
50
|
* @returns {object}
|
|
48
51
|
*/
|
|
@@ -53,7 +56,8 @@ class Step {
|
|
|
53
56
|
angle: this.angle,
|
|
54
57
|
previousBearing: this.previousBearing,
|
|
55
58
|
nextBearing: this.nextBearing,
|
|
56
|
-
distance: this.distance
|
|
59
|
+
distance: this.distance,
|
|
60
|
+
_idCoordsInLeg: this._idCoordsInLeg
|
|
57
61
|
};
|
|
58
62
|
if (this.firstStep) {
|
|
59
63
|
output.firstStep = true;
|
|
@@ -88,6 +92,7 @@ class Step {
|
|
|
88
92
|
step.previousBearing = json.previousBearing;
|
|
89
93
|
step.nextBearing = json.nextBearing;
|
|
90
94
|
step.distance = json.distance;
|
|
95
|
+
step._idCoordsInLeg = json._idCoordsInLeg;
|
|
91
96
|
if (json.firstStep) {
|
|
92
97
|
step.firstStep = json.firstStep;
|
|
93
98
|
}
|
package/src/routers/Utils.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
import { diffAngle } from '@wemap/maths';
|
|
2
|
+
|
|
1
3
|
import Itinerary from './Itinerary.js';
|
|
2
4
|
|
|
3
5
|
/**
|
|
4
6
|
* @param {Itinerary} itinerary
|
|
5
7
|
*/
|
|
6
|
-
export function
|
|
8
|
+
export function generateStepsMetadata(itinerary) {
|
|
9
|
+
|
|
7
10
|
let counter = 1;
|
|
11
|
+
|
|
8
12
|
itinerary.legs.forEach((leg, legId) => {
|
|
9
13
|
leg.steps.forEach((step, stepId) => {
|
|
10
14
|
|
|
@@ -17,6 +21,34 @@ export function generateStepsNumbers(itinerary) {
|
|
|
17
21
|
}
|
|
18
22
|
|
|
19
23
|
step.number = counter++;
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
/*
|
|
27
|
+
* Generate previousBearing, nextBearing and angle
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
let coordsBeforeStep;
|
|
31
|
+
if (step._idCoordsInLeg > 0) {
|
|
32
|
+
coordsBeforeStep = leg.coords[step._idCoordsInLeg - 1];
|
|
33
|
+
} else if (legId === 0) {
|
|
34
|
+
coordsBeforeStep = itinerary.from;
|
|
35
|
+
} else {
|
|
36
|
+
coordsBeforeStep = itinerary.legs[legId - 1].to.coords;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let coordsAfterStep;
|
|
40
|
+
if (step._idCoordsInLeg !== leg.coords.length - 1) {
|
|
41
|
+
coordsAfterStep = leg.coords[step._idCoordsInLeg + 1];
|
|
42
|
+
} else if (legId === itinerary.legs.length - 1) {
|
|
43
|
+
coordsAfterStep = itinerary.to;
|
|
44
|
+
} else {
|
|
45
|
+
coordsAfterStep = itinerary.legs[legId + 1].from.coords;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
step.previousBearing = coordsBeforeStep.bearingTo(step.coords);
|
|
49
|
+
step.nextBearing = step.coords.bearingTo(coordsAfterStep);
|
|
50
|
+
step.angle = diffAngle(step.previousBearing, step.nextBearing + Math.PI);
|
|
51
|
+
|
|
20
52
|
});
|
|
21
53
|
});
|
|
22
54
|
}
|
|
@@ -36,10 +36,7 @@ class ItineraryInfoManager {
|
|
|
36
36
|
set itinerary(itinerary) {
|
|
37
37
|
|
|
38
38
|
this._itinerary = itinerary;
|
|
39
|
-
this._steps = itinerary.
|
|
40
|
-
acc.push(...steps);
|
|
41
|
-
return acc;
|
|
42
|
-
}, []);
|
|
39
|
+
this._steps = itinerary.steps;
|
|
43
40
|
this._network = itinerary.toNetwork();
|
|
44
41
|
this._mapMatching = new MapMatching(this._network);
|
|
45
42
|
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
/* eslint-disable max-statements */
|
|
2
2
|
|
|
3
3
|
import { Level, Coordinates } from '@wemap/geo';
|
|
4
|
-
import {
|
|
5
|
-
rad2deg, positiveMod, diffAngle, deg2rad
|
|
6
|
-
} from '@wemap/maths';
|
|
4
|
+
import { rad2deg, positiveMod } from '@wemap/maths';
|
|
7
5
|
|
|
8
6
|
import Itinerary from '../Itinerary.js';
|
|
9
7
|
import Leg from '../Leg.js';
|
|
10
8
|
import RouterResponse from '../RouterResponse.js';
|
|
11
9
|
import Step from '../Step.js';
|
|
12
|
-
import {
|
|
10
|
+
import { generateStepsMetadata } from '../Utils.js';
|
|
13
11
|
|
|
14
12
|
/**
|
|
15
13
|
* @param {Coordinates} coordinates
|
|
@@ -151,11 +149,10 @@ export function itineraryToOsrmJson(itinerary) {
|
|
|
151
149
|
|
|
152
150
|
/**
|
|
153
151
|
* @param {object} jsonSteps
|
|
154
|
-
* @param {Coordinates}
|
|
155
|
-
* @param {Coordinates} itineraryEnd
|
|
152
|
+
* @param {Coordinates[]} legCoords
|
|
156
153
|
* @returns {Step[]}
|
|
157
154
|
*/
|
|
158
|
-
function parseJsonSteps(jsonSteps,
|
|
155
|
+
function parseJsonSteps(jsonSteps, legCoords) {
|
|
159
156
|
|
|
160
157
|
if (!jsonSteps) {
|
|
161
158
|
return [];
|
|
@@ -166,14 +163,12 @@ function parseJsonSteps(jsonSteps, itineraryStart, itineraryEnd) {
|
|
|
166
163
|
const step = new Step();
|
|
167
164
|
step.coords = jsonToCoordinates(jsonStep.maneuver.location);
|
|
168
165
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
:
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
: deg2rad(jsonStep.maneuver.bearing_after);
|
|
166
|
+
const idStepCoordsInLeg = legCoords.findIndex(coords => step.coords.equalsTo(coords));
|
|
167
|
+
if (idStepCoordsInLeg < 0) {
|
|
168
|
+
throw new Error('Osrm Parser: Cannot find step coords in leg coordinates');
|
|
169
|
+
}
|
|
170
|
+
step._idCoordsInLeg = idStepCoordsInLeg;
|
|
175
171
|
|
|
176
|
-
step.angle = diffAngle(step.previousBearing, step.nextBearing + Math.PI);
|
|
177
172
|
step.name = jsonStep.name;
|
|
178
173
|
step.levelChange = jsonStep.levelChange ? jsonStep.levelChange : null;
|
|
179
174
|
|
|
@@ -240,17 +235,11 @@ export function createRouterResponseFromJson(json, from, to, routingMode = 'walk
|
|
|
240
235
|
leg.distance = jsonLeg.distance;
|
|
241
236
|
leg.duration = jsonLeg.duration;
|
|
242
237
|
|
|
243
|
-
leg.coords = jsonLeg.steps
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
leg.coords = leg.coords.reduce((acc, val) => {
|
|
249
|
-
if (acc.length === 0 || !acc[acc.length - 1].equalsTo(val)) {
|
|
250
|
-
acc.push(val);
|
|
251
|
-
}
|
|
252
|
-
return acc;
|
|
253
|
-
}, []);
|
|
238
|
+
leg.coords = jsonLeg.steps
|
|
239
|
+
.map(step => step.geometry.coordinates.map(jsonToCoordinates))
|
|
240
|
+
.flat()
|
|
241
|
+
// Remove duplicates
|
|
242
|
+
.filter((coords, idx, arr) => idx === 0 || !arr[idx - 1].equalsTo(coords));
|
|
254
243
|
|
|
255
244
|
leg.from = {
|
|
256
245
|
name: null,
|
|
@@ -261,12 +250,14 @@ export function createRouterResponseFromJson(json, from, to, routingMode = 'walk
|
|
|
261
250
|
coords: leg.coords[leg.coords.length - 1]
|
|
262
251
|
};
|
|
263
252
|
|
|
264
|
-
leg.steps = parseJsonSteps(jsonLeg.steps,
|
|
253
|
+
leg.steps = parseJsonSteps(jsonLeg.steps, leg.coords);
|
|
265
254
|
|
|
266
255
|
itinerary.legs.push(leg);
|
|
267
256
|
}
|
|
268
257
|
|
|
269
|
-
|
|
258
|
+
// All legs have to be parsed before computing steps metadata
|
|
259
|
+
generateStepsMetadata(itinerary);
|
|
260
|
+
|
|
270
261
|
}
|
|
271
262
|
|
|
272
263
|
return routerResponse;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* eslint-disable max-statements */
|
|
2
2
|
import chai from 'chai';
|
|
3
|
+
import chaiAlmost from 'chai-almost';
|
|
3
4
|
import fs from 'fs';
|
|
4
5
|
import path from 'path';
|
|
5
6
|
import { fileURLToPath } from 'url';
|
|
@@ -21,6 +22,8 @@ import {
|
|
|
21
22
|
import { verifyRouterResponseData } from '../RouterResponse.type.spec.js';
|
|
22
23
|
|
|
23
24
|
const { expect } = chai;
|
|
25
|
+
chai.use(chaiAlmost(0.1));
|
|
26
|
+
|
|
24
27
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
25
28
|
|
|
26
29
|
|
|
@@ -427,5 +430,28 @@ describe('OsrmUtils - createRouterResponseFromJson', () => {
|
|
|
427
430
|
|
|
428
431
|
});
|
|
429
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
|
+
|
|
430
456
|
});
|
|
431
457
|
|
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
import Polyline from '@mapbox/polyline';
|
|
3
3
|
|
|
4
4
|
import { Coordinates } from '@wemap/geo';
|
|
5
|
-
import { diffAngle } from '@wemap/maths';
|
|
6
5
|
|
|
7
6
|
import Itinerary from '../Itinerary.js';
|
|
8
7
|
import Leg from '../Leg.js';
|
|
9
8
|
import RouterResponse from '../RouterResponse.js';
|
|
10
9
|
import Step from '../Step.js';
|
|
11
|
-
import {
|
|
10
|
+
import { generateStepsMetadata } from '../Utils.js';
|
|
12
11
|
|
|
13
12
|
/**
|
|
14
13
|
* @param {object} json
|
|
@@ -21,11 +20,9 @@ export function jsonToCoordinates(json) {
|
|
|
21
20
|
/**
|
|
22
21
|
* @param {object} jsonSteps
|
|
23
22
|
* @param {Coordinates[]} legCoords
|
|
24
|
-
* @param {Coordinates} itineraryStart
|
|
25
|
-
* @param {Coordinates} itineraryEnd
|
|
26
23
|
* @returns {Step[]}
|
|
27
24
|
*/
|
|
28
|
-
function parseJsonSteps(jsonSteps, legCoords
|
|
25
|
+
function parseJsonSteps(jsonSteps, legCoords) {
|
|
29
26
|
|
|
30
27
|
if (!jsonSteps) {
|
|
31
28
|
return [];
|
|
@@ -44,15 +41,7 @@ function parseJsonSteps(jsonSteps, legCoords, itineraryStart) {
|
|
|
44
41
|
throw new Error('OTP Parser: Cannot find closest step');
|
|
45
42
|
}
|
|
46
43
|
step.coords = legCoords[idStepCoordsInLeg];
|
|
47
|
-
|
|
48
|
-
step.previousBearing = idStepCoordsInLeg === 0
|
|
49
|
-
? itineraryStart.bearingTo(step.coords)
|
|
50
|
-
: legCoords[idStepCoordsInLeg - 1].bearingTo(legCoords[idStepCoordsInLeg]);
|
|
51
|
-
step.nextBearing = idStepCoordsInLeg === legCoords.length - 1
|
|
52
|
-
? 0
|
|
53
|
-
: legCoords[idStepCoordsInLeg].bearingTo(legCoords[idStepCoordsInLeg + 1]);
|
|
54
|
-
|
|
55
|
-
step.angle = diffAngle(step.previousBearing, step.nextBearing + Math.PI);
|
|
44
|
+
step._idCoordsInLeg = idStepCoordsInLeg;
|
|
56
45
|
|
|
57
46
|
step.name = jsonStep.streetName;
|
|
58
47
|
step.levelChange = null;
|
|
@@ -112,6 +101,8 @@ export function createRouterResponseFromJson(json) {
|
|
|
112
101
|
};
|
|
113
102
|
leg.coords = Polyline.decode(jsonLeg.legGeometry.points).map(([lat, lon]) => new Coordinates(lat, lon));
|
|
114
103
|
|
|
104
|
+
leg.steps = parseJsonSteps(jsonLeg.steps, leg.coords);
|
|
105
|
+
|
|
115
106
|
if (leg.mode === 'BUS' || leg.mode === 'TRAM') {
|
|
116
107
|
leg.transportInfo = {
|
|
117
108
|
name: jsonLeg.route,
|
|
@@ -119,6 +110,14 @@ export function createRouterResponseFromJson(json) {
|
|
|
119
110
|
routeTextColor: jsonLeg.routeTextColor,
|
|
120
111
|
directionName: jsonLeg.headsign
|
|
121
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];
|
|
122
121
|
}
|
|
123
122
|
|
|
124
123
|
// jsonLeg.distance is not reliable when compared to the array of leg coords.
|
|
@@ -130,32 +129,10 @@ export function createRouterResponseFromJson(json) {
|
|
|
130
129
|
return acc + arr[idx - 1].distanceTo(coords);
|
|
131
130
|
}, 0);
|
|
132
131
|
|
|
133
|
-
let previousPoint;
|
|
134
|
-
if (itinerary.legs.length === 0) {
|
|
135
|
-
previousPoint = itinerary.from;
|
|
136
|
-
} else {
|
|
137
|
-
const lastLeg = itinerary.legs[itinerary.legs.length - 1];
|
|
138
|
-
previousPoint = lastLeg.coords[lastLeg.coords.length - 1];
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
leg.steps = parseJsonSteps(
|
|
142
|
-
jsonLeg.steps,
|
|
143
|
-
leg.coords,
|
|
144
|
-
previousPoint
|
|
145
|
-
);
|
|
146
|
-
// itinerary.coords.push(...leg.coords);
|
|
147
132
|
itinerary.legs.push(leg);
|
|
148
133
|
|
|
149
134
|
}
|
|
150
135
|
|
|
151
|
-
// Remove duplicates
|
|
152
|
-
// itinerary.coords = itinerary.coords.reduce((acc, val) => {
|
|
153
|
-
// if (acc.length === 0 || !acc[acc.length - 1].equalsTo(val)) {
|
|
154
|
-
// acc.push(val);
|
|
155
|
-
// }
|
|
156
|
-
// return acc;
|
|
157
|
-
// }, []);
|
|
158
|
-
|
|
159
136
|
itinerary.distance = itinerary.coords.reduce((acc, coords, idx, arr) => {
|
|
160
137
|
if (idx === 0) {
|
|
161
138
|
return acc;
|
|
@@ -163,7 +140,8 @@ export function createRouterResponseFromJson(json) {
|
|
|
163
140
|
return acc + arr[idx - 1].distanceTo(coords);
|
|
164
141
|
}, 0);
|
|
165
142
|
|
|
166
|
-
|
|
143
|
+
// All legs have to be parsed before computing steps metadata
|
|
144
|
+
generateStepsMetadata(itinerary);
|
|
167
145
|
}
|
|
168
146
|
|
|
169
147
|
return routerResponse;
|