@wemap/osm 0.1.1 → 0.2.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/assets/itinerary-osrm.json +1 -0
- package/package.json +3 -3
- package/src/network/OsmNetwork.js +3 -2
- package/src/network/OsmRouter.spec.js +31 -47
- package/src/osrm/OsrmUtils.js +124 -80
- package/src/osrm/OsrmUtils.spec.js +168 -0
- package/src/osrm/OsrmItinerary.js +0 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"code":"Ok","routes":[{"geometry":{"coordinates":[[3.89678,43.600032],[3.896532,43.600216],[3.896247,43.600432],[3.896188,43.600488],[3.896151,43.600523],[3.895937,43.600726],[3.895824,43.600837],[3.89566,43.601048],[3.895605,43.601131],[3.895549,43.601243],[3.895511,43.601337],[3.895492,43.601413],[3.895485,43.601506],[3.89549,43.601585],[3.895549,43.601785],[3.895413,43.60181],[3.895353,43.601826],[3.895305,43.601628],[3.8953,43.60157],[3.89532,43.60143]],"type":"LineString"},"legs":[{"steps":[{"intersections":[{"out":0,"entry":[true],"bearings":[316],"location":[3.89678,43.600032]}],"driving_side":"right","geometry":{"coordinates":[[3.89678,43.600032],[3.896532,43.600216],[3.896247,43.600432],[3.896188,43.600488],[3.896151,43.600523],[3.895937,43.600726],[3.895824,43.600837],[3.89566,43.601048],[3.895605,43.601131],[3.895549,43.601243],[3.895511,43.601337],[3.895492,43.601413],[3.895485,43.601506],[3.89549,43.601585],[3.895549,43.601785]],"type":"LineString"},"mode":"walking","duration":165.6,"maneuver":{"bearing_after":316,"type":"depart","modifier":"right","bearing_before":0,"location":[3.89678,43.600032]},"weight":165.6,"distance":230.1,"name":""},{"intersections":[{"out":2,"location":[3.895549,43.601785],"bearings":[15,195,285],"entry":[true,false,true],"in":1}],"driving_side":"right","geometry":{"coordinates":[[3.895549,43.601785],[3.895413,43.60181],[3.895353,43.601826]],"type":"LineString"},"mode":"walking","duration":11.8,"maneuver":{"bearing_after":284,"type":"turn","modifier":"left","bearing_before":11,"location":[3.895549,43.601785]},"weight":11.8,"distance":16.5,"name":""},{"intersections":[{"out":2,"location":[3.895353,43.601826],"bearings":[15,105,195,285],"entry":[true,false,true,true],"in":1}],"driving_side":"right","geometry":{"coordinates":[[3.895353,43.601826],[3.895305,43.601628],[3.8953,43.60157],[3.89532,43.60143]],"type":"LineString"},"mode":"walking","duration":32.2,"maneuver":{"bearing_after":189,"type":"turn","modifier":"left","bearing_before":286,"location":[3.895353,43.601826]},"weight":32.2,"distance":44.5,"name":""},{"intersections":[{"in":0,"entry":[true],"bearings":[354],"location":[3.89532,43.60143]}],"driving_side":"right","geometry":{"coordinates":[[3.89532,43.60143],[3.89532,43.60143]],"type":"LineString"},"mode":"walking","duration":0,"maneuver":{"bearing_after":0,"location":[3.89532,43.60143],"bearing_before":174,"type":"arrive"},"weight":0,"distance":0,"name":""}],"distance":291,"duration":209.6,"summary":"","weight":209.6}],"distance":291,"duration":209.6,"weight_name":"duration","weight":209.6}],"waypoints":[{"hint":"4dUHgOOrJ4DOAAAAnwAAAKoFAAB5AwAAzgAAAJ8AAACqBQAAeQMAAAIAAADMdTsAoEiZAjd2OwDrSJkCDQB_CA61bn8=","name":"","location":[3.89678,43.600032]},{"hint":"3vZTgejVB4AEAAAAcgAAAF8AAADQAAAABAAAAHIAAABfAAAA0AAAAAIAAAAYcDsAFk6ZAhdwOwAWTpkCAgAvFg61bn8=","name":"","location":[3.89532,43.60143]}]}
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"directory": "packages/osm"
|
|
12
12
|
},
|
|
13
13
|
"name": "@wemap/osm",
|
|
14
|
-
"version": "0.
|
|
14
|
+
"version": "0.2.0",
|
|
15
15
|
"bugs": {
|
|
16
16
|
"url": "https://github.com/wemap/wemap-utils-js/issues"
|
|
17
17
|
},
|
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
],
|
|
27
27
|
"license": "ISC",
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@wemap/geo": "^0.
|
|
29
|
+
"@wemap/geo": "^0.3.0",
|
|
30
30
|
"@wemap/logger": "^0.1.5",
|
|
31
31
|
"lodash.isnumber": "^3.0.3",
|
|
32
32
|
"sax": "^1.2.4"
|
|
33
33
|
},
|
|
34
|
-
"gitHead": "
|
|
34
|
+
"gitHead": "1175cf4c2faf2506e2fafa03f2eec7cbd632a5de"
|
|
35
35
|
}
|
|
@@ -39,8 +39,6 @@ class OsmNetwork extends Network {
|
|
|
39
39
|
edge.data = way;
|
|
40
40
|
edge.level = way.level;
|
|
41
41
|
networkModel.edges.push(edge);
|
|
42
|
-
firstNode.edges.push(edge);
|
|
43
|
-
secondNode.edges.push(edge);
|
|
44
42
|
|
|
45
43
|
firstNode = secondNode;
|
|
46
44
|
}
|
|
@@ -54,6 +52,9 @@ class OsmNetwork extends Network {
|
|
|
54
52
|
return this.nodes.find(node => node.data.id === id);
|
|
55
53
|
}
|
|
56
54
|
|
|
55
|
+
getNodeByName(name) {
|
|
56
|
+
return this.nodes.find(node => node.data.tags.name === name);
|
|
57
|
+
}
|
|
57
58
|
|
|
58
59
|
getEdgeById(id) {
|
|
59
60
|
return this.edges.find(edge => edge.data.id === id);
|
|
@@ -1,22 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
1
|
+
/* eslint-disable max-statements */
|
|
2
|
+
import { expect } from 'chai';
|
|
3
3
|
import fs from 'fs';
|
|
4
4
|
import path from 'path';
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
WGS84, Level
|
|
8
|
-
} from '@wemap/geo';
|
|
6
|
+
import { Node } from '@wemap/geo';
|
|
9
7
|
|
|
10
8
|
import OsmParser from '../model/OsmParser';
|
|
11
9
|
import OsmRouter from './OsmRouter';
|
|
12
10
|
import OsmNetwork from './OsmNetwork';
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
import {
|
|
13
|
+
itineraryStart, itineraryEnd
|
|
14
|
+
} from '../../../geo/tests/CommonTest';
|
|
17
15
|
|
|
18
16
|
|
|
19
|
-
describe('OsmRouter', () => {
|
|
17
|
+
describe('OsmRouter - Multi-level itinerary', () => {
|
|
20
18
|
|
|
21
19
|
const filePath = path.resolve(__dirname, '../../assets/bureaux-wemap-montpellier-network.osm');
|
|
22
20
|
const osmXmlString = fs.readFileSync(filePath, 'utf8');
|
|
@@ -25,60 +23,46 @@ describe('OsmRouter', () => {
|
|
|
25
23
|
const networkModel = OsmNetwork.fromOsmModel(osmModel);
|
|
26
24
|
const router = new OsmRouter(networkModel);
|
|
27
25
|
|
|
28
|
-
it('Multi-level itinerary', () => {
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
start.level = Level.fromString(2);
|
|
27
|
+
const itinerary = router.getShortestPath(itineraryStart, itineraryEnd);
|
|
32
28
|
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
const p = [];
|
|
30
|
+
it('Search for nodes', () => {
|
|
31
|
+
for (let i = 1; i <= 16; i++) {
|
|
32
|
+
p[i] = networkModel.getNodeByName('p' + i);
|
|
33
|
+
expect(p[i]).instanceOf(Node);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
it('Router return shortest path', () => {
|
|
37
38
|
|
|
38
39
|
expect(itinerary.nodes.length).equal(11);
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
expect(itinerary.nodes[4].data.tags.name).equal('p10');
|
|
44
|
-
expect(itinerary.nodes[5].data.tags.name).equal('p11');
|
|
45
|
-
expect(itinerary.nodes[6].data.tags.name).equal('p12');
|
|
46
|
-
expect(itinerary.nodes[7].data.tags.name).equal('p13');
|
|
47
|
-
expect(itinerary.nodes[8].data.tags.name).equal('p14');
|
|
48
|
-
expect(itinerary.nodes[9].data.tags.name).equal('p15');
|
|
49
|
-
expect(itinerary.nodes[10].data.tags.name).equal('p16');
|
|
50
|
-
|
|
41
|
+
for (let i = 1; i <= 10; i++) {
|
|
42
|
+
expect(itinerary.nodes[i].data).equal(p[i + 6].data);
|
|
43
|
+
}
|
|
51
44
|
|
|
52
|
-
|
|
53
|
-
* Verify if itinerary is ordered
|
|
54
|
-
*/
|
|
45
|
+
});
|
|
55
46
|
|
|
56
|
-
|
|
57
|
-
const node = itinerary.nodes[i];
|
|
47
|
+
it('Verify steps', () => {
|
|
58
48
|
|
|
59
|
-
|
|
49
|
+
const steps = itinerary.steps;
|
|
50
|
+
expect(steps.length).equal(10);
|
|
60
51
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
expect(itinerary.edges[i].node2).equal(itinerary.nodes[i + 1]);
|
|
64
|
-
}
|
|
52
|
+
expect(steps[0].nodes[1].data).equal(p[7].data);
|
|
53
|
+
expect(steps[0].nodes[2].data).equal(p[8].data);
|
|
65
54
|
|
|
55
|
+
for (let i = 2; i <= 9; i++) {
|
|
56
|
+
expect(steps[i - 1].nodes[0].data).equal(p[i + 6].data);
|
|
57
|
+
expect(steps[i - 1].nodes[1].data).equal(p[i + 7].data);
|
|
66
58
|
}
|
|
67
59
|
|
|
60
|
+
expect(steps[9].nodes[0].data).equal(p[16].data);
|
|
68
61
|
});
|
|
69
62
|
|
|
70
63
|
|
|
71
64
|
it('No route itinerary', () => {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
start.level = Level.fromString(2);
|
|
75
|
-
|
|
76
|
-
const end = new WGS84(43.6092602, 3.8842669);
|
|
77
|
-
end.level = Level.fromString(1);
|
|
78
|
-
|
|
79
|
-
const itinerary = router.getShortestPath(start, end, { useStairs: false });
|
|
80
|
-
|
|
81
|
-
expect(itinerary).is.undefined;
|
|
82
|
-
|
|
65
|
+
const itineraryWithoutStairs = router.getShortestPath(itineraryStart, itineraryEnd, { useStairs: false });
|
|
66
|
+
expect(itineraryWithoutStairs).is.undefined;
|
|
83
67
|
});
|
|
84
68
|
});
|
package/src/osrm/OsrmUtils.js
CHANGED
|
@@ -1,99 +1,87 @@
|
|
|
1
1
|
/* eslint-disable max-statements */
|
|
2
|
-
|
|
3
2
|
import {
|
|
4
|
-
|
|
3
|
+
WGS84, Itinerary, Node, Edge, Level
|
|
5
4
|
} from '@wemap/geo';
|
|
6
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
rad2deg, Utils as MathUtils
|
|
7
|
+
} from '@wemap/maths';
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
class OsrmUtils {
|
|
10
11
|
|
|
11
|
-
static
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
12
|
+
static wgs84ToJson(wgs84) {
|
|
13
|
+
const output = [wgs84.lng, wgs84.lat];
|
|
14
|
+
if (wgs84.level) {
|
|
15
|
+
output.push(wgs84.level.toString());
|
|
16
|
+
}
|
|
17
|
+
return output;
|
|
18
|
+
}
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
const
|
|
20
|
+
static jsonToWgs84(json) {
|
|
21
|
+
const output = new WGS84(json[1], json[0]);
|
|
22
|
+
if (json.length > 2) {
|
|
23
|
+
output.level = Level.fromString(json[2]);
|
|
24
|
+
}
|
|
25
|
+
return output;
|
|
26
|
+
}
|
|
19
27
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
nodeCoordsModified.level.multiplyBy(altitudeFactor);
|
|
24
|
-
}
|
|
25
|
-
coordinates.push(nodeCoordsModified.toJson(WGS84.FORMAT_LNG_LAT_STRLEVEL));
|
|
26
|
-
});
|
|
28
|
+
static nodesToJsonCoords(nodes) {
|
|
29
|
+
return nodes.map(node => OsrmUtils.wgs84ToJson(node.coords));
|
|
30
|
+
}
|
|
27
31
|
|
|
28
|
-
|
|
32
|
+
static itineraryToOsrmJson(itinerary) {
|
|
29
33
|
|
|
30
|
-
|
|
34
|
+
const itinerarySteps = itinerary.steps;
|
|
35
|
+
const osrmSteps = [];
|
|
31
36
|
|
|
32
|
-
|
|
33
|
-
|
|
37
|
+
const lastStepId = itinerarySteps.length - 1;
|
|
38
|
+
for (let i = 0; i <= lastStepId; i++) {
|
|
34
39
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
let nextEdgeTags;
|
|
40
|
+
const {
|
|
41
|
+
nodes, length, nextEdgeData, nextBearing, previousBearing, angle, node, duration
|
|
42
|
+
} = itinerarySteps[i];
|
|
39
43
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
previousBearing = 0;
|
|
43
|
-
} else {
|
|
44
|
-
node = nodes[i];
|
|
45
|
-
nodeCoords = node.coords;
|
|
46
|
-
nodeTags = node.tags;
|
|
47
|
-
}
|
|
44
|
+
const edgeData = i !== lastStepId ? nextEdgeData : itinerary.edges[lastStepId];
|
|
45
|
+
const name = edgeData && edgeData.tags ? nextEdgeData.tags.name : '';
|
|
48
46
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
} else {
|
|
52
|
-
nextNode = nodes[i + 1];
|
|
53
|
-
nextNodeCoords = nextNode.coords;
|
|
54
|
-
}
|
|
47
|
+
let type = i === 0 ? 'depart' : 'turn';
|
|
48
|
+
type = i === lastStepId ? 'arrive' : type;
|
|
55
49
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
nextEdgeTags = edge.data.tags;
|
|
59
|
-
}
|
|
50
|
+
const bearingBefore = MathUtils.positiveMod(i === 0 ? 0 : previousBearing, 2 * Math.PI);
|
|
51
|
+
const bearingAfter = MathUtils.positiveMod(i === lastStepId ? 0 : nextBearing, 2 * Math.PI);
|
|
60
52
|
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
53
|
+
const osrmStep = {
|
|
54
|
+
geometry: {
|
|
55
|
+
type: 'LineString',
|
|
56
|
+
coordinates: OsrmUtils.nodesToJsonCoords(nodes)
|
|
57
|
+
},
|
|
58
|
+
distance: length,
|
|
59
|
+
duration,
|
|
60
|
+
name,
|
|
61
|
+
maneuver: {
|
|
62
|
+
bearing_before: rad2deg(bearingBefore),
|
|
63
|
+
bearing_after: rad2deg(bearingAfter),
|
|
64
|
+
location: OsrmUtils.wgs84ToJson(node.coords),
|
|
65
|
+
type
|
|
66
|
+
},
|
|
67
|
+
wemap: {}
|
|
68
|
+
};
|
|
65
69
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
nodeCoordsModified.level.multiplyBy(altitudeFactor);
|
|
70
|
+
if (node.data && node.data.tags) {
|
|
71
|
+
osrmStep.wemap.nodeTags = node.data.tags;
|
|
69
72
|
}
|
|
70
73
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
bearing_after: bearing * 180 / Math.PI,
|
|
75
|
-
location: nodeCoordsModified.toJson(WGS84.FORMAT_LNG_LAT_STRLEVEL),
|
|
76
|
-
modifier
|
|
77
|
-
},
|
|
78
|
-
distance,
|
|
79
|
-
nodeTags,
|
|
80
|
-
nextEdgeTags
|
|
81
|
-
});
|
|
74
|
+
if (i !== lastStepId) {
|
|
75
|
+
osrmStep.wemap.nextEdgeTags = nextEdgeData.tags;
|
|
76
|
+
}
|
|
82
77
|
|
|
83
|
-
|
|
84
|
-
|
|
78
|
+
// The first modifier is not mandatory by OSRM.
|
|
79
|
+
// if (i !== 0) {
|
|
80
|
+
osrmStep.maneuver.modifier = OsrmUtils.getModifierFromAngle(angle);
|
|
81
|
+
// }
|
|
85
82
|
|
|
86
|
-
|
|
87
|
-
if (altitudeFactor !== 1 && endNodeCoordsModified.level) {
|
|
88
|
-
endNodeCoordsModified.level.multiplyBy(altitudeFactor);
|
|
83
|
+
osrmSteps.push(osrmStep);
|
|
89
84
|
}
|
|
90
|
-
steps.push({maneuver: {
|
|
91
|
-
bearing_before: previousBearing * 180 / Math.PI,
|
|
92
|
-
bearing_after: 0,
|
|
93
|
-
location: endNodeCoordsModified.toJson(WGS84.FORMAT_LNG_LAT_STRLEVEL),
|
|
94
|
-
modifier: 'arrive'
|
|
95
|
-
}});
|
|
96
|
-
|
|
97
85
|
|
|
98
86
|
return {
|
|
99
87
|
'code': 'Ok',
|
|
@@ -101,17 +89,17 @@ class OsrmUtils {
|
|
|
101
89
|
{
|
|
102
90
|
'geometry': {
|
|
103
91
|
'type': 'LineString',
|
|
104
|
-
'coordinates':
|
|
92
|
+
'coordinates': OsrmUtils.nodesToJsonCoords(itinerary.nodes)
|
|
105
93
|
},
|
|
106
94
|
'legs': [
|
|
107
95
|
{
|
|
108
|
-
'duration': itinerary.
|
|
109
|
-
'distance': length,
|
|
110
|
-
'steps':
|
|
96
|
+
'duration': itinerary.duration,
|
|
97
|
+
'distance': itinerary.length,
|
|
98
|
+
'steps': osrmSteps
|
|
111
99
|
}
|
|
112
100
|
],
|
|
113
|
-
'distance': length,
|
|
114
|
-
'duration': itinerary.
|
|
101
|
+
'distance': itinerary.length,
|
|
102
|
+
'duration': itinerary.duration,
|
|
115
103
|
'weight_name': 'routability',
|
|
116
104
|
'weight': 0
|
|
117
105
|
}
|
|
@@ -125,7 +113,10 @@ class OsrmUtils {
|
|
|
125
113
|
}
|
|
126
114
|
|
|
127
115
|
|
|
128
|
-
static getModifierFromAngle(
|
|
116
|
+
static getModifierFromAngle(_angle) {
|
|
117
|
+
|
|
118
|
+
const angle = MathUtils.positiveMod(rad2deg(_angle), 360);
|
|
119
|
+
|
|
129
120
|
if (angle > 0 && angle < 60) {
|
|
130
121
|
return 'sharp right';
|
|
131
122
|
}
|
|
@@ -149,6 +140,59 @@ class OsrmUtils {
|
|
|
149
140
|
}
|
|
150
141
|
return 'u turn';
|
|
151
142
|
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Generate Itinerary from OSRM JSON, start and end.
|
|
146
|
+
* @param {Object} json JSON file provided by OSRM.
|
|
147
|
+
* @param {Array} start Array of <lng, lat[, level]>
|
|
148
|
+
* @param {Array} end Array of <lng, lat[, level]>
|
|
149
|
+
*/
|
|
150
|
+
static createItineraryFromJson(json, start, end) {
|
|
151
|
+
const itinerary = new Itinerary();
|
|
152
|
+
|
|
153
|
+
itinerary.start = OsrmUtils.jsonToWgs84(start);
|
|
154
|
+
itinerary.end = OsrmUtils.jsonToWgs84(end);
|
|
155
|
+
|
|
156
|
+
const {
|
|
157
|
+
legs, geometry
|
|
158
|
+
} = json.routes[0];
|
|
159
|
+
const { steps } = legs[0];
|
|
160
|
+
|
|
161
|
+
let previousNode;
|
|
162
|
+
const { coordinates } = geometry;
|
|
163
|
+
for (let i = 0; i < coordinates.length; i++) {
|
|
164
|
+
const node = new Node(OsrmUtils.jsonToWgs84(coordinates[i]));
|
|
165
|
+
itinerary.nodes.push(node);
|
|
166
|
+
|
|
167
|
+
if (previousNode) {
|
|
168
|
+
const edge = new Edge(previousNode, node);
|
|
169
|
+
edge.level = Level.union(previousNode.coords.level, node.coords.level);
|
|
170
|
+
itinerary.edges.push(edge);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
previousNode = node;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
for (let i = 0; i < steps.length; i++) {
|
|
177
|
+
const step = steps[i];
|
|
178
|
+
if (step.wemap) {
|
|
179
|
+
const stepLocation = step.maneuver.location;
|
|
180
|
+
const location = OsrmUtils.jsonToWgs84(stepLocation);
|
|
181
|
+
const existingNode = itinerary.getNodeByCoords(location);
|
|
182
|
+
|
|
183
|
+
if (step.wemap.nodeTags) {
|
|
184
|
+
existingNode.data = { tags: step.wemap.nodeTags };
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (step.wemap.nextEdgeTags) {
|
|
188
|
+
const nextEdge = existingNode.edges[i === 0 ? 0 : 1];
|
|
189
|
+
nextEdge.data = { tags: step.wemap.nextEdgeTags };
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return itinerary;
|
|
195
|
+
}
|
|
152
196
|
}
|
|
153
197
|
|
|
154
198
|
export default OsrmUtils;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/* eslint-disable max-statements */
|
|
2
|
+
import { expect } from 'chai';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
|
|
6
|
+
import { Level } from '@wemap/geo';
|
|
7
|
+
|
|
8
|
+
import OsmParser from '../model/OsmParser';
|
|
9
|
+
import OsmRouter from '../network/OsmRouter';
|
|
10
|
+
import OsmNetwork from '../network/OsmNetwork';
|
|
11
|
+
import OsrmUtils from './OsrmUtils';
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
itineraryStart, itineraryEnd
|
|
15
|
+
} from '../../../geo/tests/CommonTest';
|
|
16
|
+
|
|
17
|
+
describe('OsmRouter - Multi-level itinerary', () => {
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
it('OSRM JSON to Itinerary', () => {
|
|
21
|
+
|
|
22
|
+
const filePath = path.resolve(__dirname, '../../assets/itinerary-osrm.json');
|
|
23
|
+
const fileString = fs.readFileSync(filePath, 'utf8');
|
|
24
|
+
|
|
25
|
+
const json = JSON.parse(fileString);
|
|
26
|
+
|
|
27
|
+
const start = [3.8968868999999997, 43.6001066];
|
|
28
|
+
const end = [3.895319, 43.601430];
|
|
29
|
+
|
|
30
|
+
const itinerary = OsrmUtils.createItineraryFromJson(json, start, end);
|
|
31
|
+
|
|
32
|
+
expect(json.routes[0].geometry.coordinates.length).equal(itinerary.nodes.length);
|
|
33
|
+
expect(itinerary.nodes.length).equal(itinerary.edges.length + 1);
|
|
34
|
+
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
let osrmWemapJson, wemapItinerary;
|
|
38
|
+
it('Itinerary to OSRM JSON', () => {
|
|
39
|
+
|
|
40
|
+
const filePath = path.resolve(__dirname, '../../assets/bureaux-wemap-montpellier-network.osm');
|
|
41
|
+
const osmXmlString = fs.readFileSync(filePath, 'utf8');
|
|
42
|
+
|
|
43
|
+
const osmModel = OsmParser.parseOsmXmlString(osmXmlString);
|
|
44
|
+
const networkModel = OsmNetwork.fromOsmModel(osmModel);
|
|
45
|
+
const router = new OsmRouter(networkModel);
|
|
46
|
+
|
|
47
|
+
wemapItinerary = router.getShortestPath(itineraryStart, itineraryEnd);
|
|
48
|
+
|
|
49
|
+
osrmWemapJson = OsrmUtils.itineraryToOsrmJson(wemapItinerary);
|
|
50
|
+
const itinerarySteps = wemapItinerary.steps;
|
|
51
|
+
|
|
52
|
+
const {
|
|
53
|
+
geometry, legs
|
|
54
|
+
} = osrmWemapJson.routes[0];
|
|
55
|
+
|
|
56
|
+
const p = [];
|
|
57
|
+
for (let i = 1; i <= 16; i++) {
|
|
58
|
+
p[i] = networkModel.getNodeByName('p' + i);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Verify if JSON geometry corresponds to Itinerary points
|
|
64
|
+
*/
|
|
65
|
+
const { coordinates } = geometry;
|
|
66
|
+
expect(coordinates.length).equal(11);
|
|
67
|
+
for (let i = 1; i < 11; i++) {
|
|
68
|
+
expect(p[i + 6].coords.equalsTo(OsrmUtils.jsonToWgs84(coordinates[i]))).true;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Verify location, type and modifier of each step
|
|
73
|
+
*/
|
|
74
|
+
const { steps } = legs[0];
|
|
75
|
+
for (let i = 0; i < steps.length; i++) {
|
|
76
|
+
const {
|
|
77
|
+
location, type
|
|
78
|
+
} = steps[i].maneuver;
|
|
79
|
+
expect(itinerarySteps[i].node.coords.equalsTo(OsrmUtils.jsonToWgs84(location))).true;
|
|
80
|
+
|
|
81
|
+
let expectedType;
|
|
82
|
+
switch (i) {
|
|
83
|
+
case 0:
|
|
84
|
+
expectedType = 'depart';
|
|
85
|
+
break;
|
|
86
|
+
case steps.length - 1:
|
|
87
|
+
expectedType = 'arrive';
|
|
88
|
+
break;
|
|
89
|
+
default:
|
|
90
|
+
expectedType = 'turn';
|
|
91
|
+
}
|
|
92
|
+
expect(type).equals(expectedType);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// The first modifier is not mandatory by OSRM.
|
|
96
|
+
expect(steps[0].maneuver.modifier).equals('left');
|
|
97
|
+
expect(steps[0].distance).be.closeTo(2.33, 0.01);
|
|
98
|
+
expect(steps[0].maneuver.bearing_after).be.closeTo(11.90, 0.01);
|
|
99
|
+
|
|
100
|
+
expect(steps[1].maneuver.modifier).equals('right');
|
|
101
|
+
expect(steps[1].distance).be.closeTo(1.76, 0.01);
|
|
102
|
+
expect(steps[1].maneuver.bearing_after).be.closeTo(56.90, 0.01);
|
|
103
|
+
|
|
104
|
+
expect(steps[2].maneuver.modifier).equals('left');
|
|
105
|
+
expect(steps[2].distance).be.closeTo(1.15, 0.01);
|
|
106
|
+
expect(steps[2].maneuver.bearing_after).be.closeTo(11.90, 0.01);
|
|
107
|
+
|
|
108
|
+
expect(steps[3].maneuver.modifier).equals('left');
|
|
109
|
+
expect(steps[3].distance).be.closeTo(5.95, 0.01);
|
|
110
|
+
expect(steps[3].maneuver.bearing_after).be.closeTo(281.93, 0.01);
|
|
111
|
+
|
|
112
|
+
expect(steps[4].maneuver.modifier).equals('right');
|
|
113
|
+
expect(steps[4].distance).be.closeTo(4.51, 0.01);
|
|
114
|
+
expect(steps[4].maneuver.bearing_after).be.closeTo(12.22, 0.01);
|
|
115
|
+
|
|
116
|
+
expect(steps[5].maneuver.modifier).equals('right');
|
|
117
|
+
expect(steps[5].distance).be.closeTo(1.72, 0.01);
|
|
118
|
+
expect(steps[5].maneuver.bearing_after).be.closeTo(102.22, 0.01);
|
|
119
|
+
|
|
120
|
+
expect(steps[6].maneuver.modifier).equals('right');
|
|
121
|
+
expect(steps[6].distance).be.closeTo(4.49, 0.01);
|
|
122
|
+
expect(steps[6].maneuver.bearing_after).be.closeTo(192.22, 0.01);
|
|
123
|
+
|
|
124
|
+
expect(steps[7].maneuver.modifier).equals('left');
|
|
125
|
+
expect(steps[7].distance).be.closeTo(4.23, 0.01);
|
|
126
|
+
expect(steps[7].maneuver.bearing_after).be.closeTo(102.00, 0.01);
|
|
127
|
+
|
|
128
|
+
expect(steps[8].maneuver.modifier).equals('right');
|
|
129
|
+
expect(steps[8].distance).be.closeTo(5.03, 0.01);
|
|
130
|
+
expect(steps[8].maneuver.bearing_after).be.closeTo(191.75, 0.01);
|
|
131
|
+
|
|
132
|
+
expect(steps[9].maneuver.modifier).equals('left');
|
|
133
|
+
expect(steps[9].distance).be.closeTo(0, 0.01);
|
|
134
|
+
expect(steps[9].maneuver.bearing_after).be.closeTo(0, 0.01);
|
|
135
|
+
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
it('Itinerary to OSRM JSON to Itinerary', () => {
|
|
140
|
+
|
|
141
|
+
const json = osrmWemapJson;
|
|
142
|
+
|
|
143
|
+
const start = OsrmUtils.wgs84ToJson(itineraryStart);
|
|
144
|
+
const end = OsrmUtils.wgs84ToJson(itineraryEnd);
|
|
145
|
+
|
|
146
|
+
const itinerary = OsrmUtils.createItineraryFromJson(json, start, end);
|
|
147
|
+
|
|
148
|
+
expect(itinerary.nodes.length).equal(wemapItinerary.nodes.length);
|
|
149
|
+
for (let i = 0; i < itinerary.nodes.length; i++) {
|
|
150
|
+
const itineraryNode = itinerary.nodes[i];
|
|
151
|
+
const wemapItineraryNode = wemapItinerary.nodes[i];
|
|
152
|
+
expect(itineraryNode.coords.equalsTo(wemapItineraryNode.coords)).true;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
expect(itinerary.edges.length).equal(wemapItinerary.edges.length);
|
|
156
|
+
for (let i = 0; i < itinerary.edges.length; i++) {
|
|
157
|
+
const itineraryEdge = itinerary.edges[i];
|
|
158
|
+
const wemapItineraryEdge = wemapItinerary.edges[i];
|
|
159
|
+
const firstNode = wemapItineraryEdge[wemapItinerary._edgesDirectionReversed[i] ? 'node2' : 'node1'];
|
|
160
|
+
const secondNode = wemapItineraryEdge[wemapItinerary._edgesDirectionReversed[i] ? 'node1' : 'node2'];
|
|
161
|
+
expect(itineraryEdge.node1.coords.equalsTo(firstNode.coords)).true;
|
|
162
|
+
expect(itineraryEdge.node2.coords.equalsTo(secondNode.coords)).true;
|
|
163
|
+
expect(Level.equalsTo(itineraryEdge.level, wemapItineraryEdge.level)).true;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
});
|