@wemap/osm 5.0.3 → 5.0.5
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/custom/OsmNetworkUtils.js +6 -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 +6 -36
|
@@ -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.5",
|
|
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": "8810cc32fb87c196e8350e0a0e6f6f7671fe4246"
|
|
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
|
}
|
|
@@ -8,7 +8,12 @@ import OsmWay from '../../model/OsmWay.js';
|
|
|
8
8
|
|
|
9
9
|
export const HIGHWAYS_PEDESTRIANS = ['footway', 'steps', 'pedestrian', 'living_street', 'path', 'track', 'sidewalk'];
|
|
10
10
|
|
|
11
|
-
export const DEFAULT_WAY_SELECTOR = way =>
|
|
11
|
+
export const DEFAULT_WAY_SELECTOR = way => {
|
|
12
|
+
return HIGHWAYS_PEDESTRIANS.includes(way.tags.highway)
|
|
13
|
+
|| way.tags.footway === 'sidewalk'
|
|
14
|
+
|| way.tags.public_transport === 'platform'
|
|
15
|
+
|| way.tags.railway === 'platform';
|
|
16
|
+
};
|
|
12
17
|
|
|
13
18
|
/**
|
|
14
19
|
* @param {Network<OsmElement>} network
|
|
@@ -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;
|
|
@@ -130,32 +119,12 @@ export function createRouterResponseFromJson(json) {
|
|
|
130
119
|
return acc + arr[idx - 1].distanceTo(coords);
|
|
131
120
|
}, 0);
|
|
132
121
|
|
|
133
|
-
|
|
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
|
-
}
|
|
122
|
+
leg.steps = parseJsonSteps(jsonLeg.steps, leg.coords);
|
|
140
123
|
|
|
141
|
-
leg.steps = parseJsonSteps(
|
|
142
|
-
jsonLeg.steps,
|
|
143
|
-
leg.coords,
|
|
144
|
-
previousPoint
|
|
145
|
-
);
|
|
146
|
-
// itinerary.coords.push(...leg.coords);
|
|
147
124
|
itinerary.legs.push(leg);
|
|
148
125
|
|
|
149
126
|
}
|
|
150
127
|
|
|
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
128
|
itinerary.distance = itinerary.coords.reduce((acc, coords, idx, arr) => {
|
|
160
129
|
if (idx === 0) {
|
|
161
130
|
return acc;
|
|
@@ -163,7 +132,8 @@ export function createRouterResponseFromJson(json) {
|
|
|
163
132
|
return acc + arr[idx - 1].distanceTo(coords);
|
|
164
133
|
}, 0);
|
|
165
134
|
|
|
166
|
-
|
|
135
|
+
// All legs have to be parsed before computing steps metadata
|
|
136
|
+
generateStepsMetadata(itinerary);
|
|
167
137
|
}
|
|
168
138
|
|
|
169
139
|
return routerResponse;
|