@wemap/osm 3.2.16 → 4.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.
@@ -1,318 +1,286 @@
1
1
  /* eslint-disable max-statements */
2
2
  import {
3
- Level, Coordinates
3
+ Level, Coordinates, Edge, Node, Itinerary, Step, Network
4
4
  } from '@wemap/geo';
5
5
  import {
6
- Edge, Node, Itinerary, Step, Network
7
- } from '@wemap/graph';
8
- import {
9
- rad2deg, Utils as MathUtils, diffAngle, deg2rad
6
+ rad2deg, positiveMod, diffAngle, deg2rad
10
7
  } from '@wemap/maths';
11
8
 
12
- import OsmNode from '../model/OsmNode.js';
13
- import OsmWay from '../model/OsmWay.js';
14
9
 
10
+ export function coordinatesToJson(coordinates) {
11
+ const output = [coordinates.lng, coordinates.lat];
12
+ if (coordinates.level) {
13
+ output.push(coordinates.level.toString());
14
+ }
15
+ return output;
16
+ }
15
17
 
16
- class OsrmUtils {
18
+ export function jsonToCoordinates(json) {
19
+ const output = new Coordinates(json[1], json[0]);
20
+ if (json.length > 2) {
21
+ output.level = Level.fromString(json[2]);
22
+ }
23
+ return output;
24
+ }
17
25
 
18
- /**
19
- * @param {Itinerary} itinerary
20
- * @returns {object}
21
- */
22
- static itineraryToOsrmJson(itinerary) {
26
+ export function nodesToJsonCoords(nodes) {
27
+ return nodes.map(node => coordinatesToJson(node.coords));
28
+ }
23
29
 
24
- const itinerarySteps = itinerary.steps;
25
- const osrmSteps = [];
26
30
 
27
- const lastStepId = itinerarySteps.length - 1;
28
- for (let i = 0; i <= lastStepId; i++) {
31
+ export function getModifierFromAngle(_angle) {
29
32
 
30
- const {
31
- nodes, length, nextEdgeData, nextBearing, previousBearing, angle, node,
32
- duration, levelChange, edges
33
- } = itinerarySteps[i];
33
+ const angle = positiveMod(rad2deg(_angle), 360);
34
34
 
35
- const edgeData = i !== lastStepId ? nextEdgeData : itinerary.edges[lastStepId];
36
- const name = edgeData && edgeData.tags ? nextEdgeData.tags.name : '';
35
+ if (angle > 0 && angle < 60) {
36
+ return 'sharp right';
37
+ }
38
+ if (angle >= 60 && angle < 140) {
39
+ return 'right';
40
+ }
41
+ if (angle >= 140 && angle < 160) {
42
+ return 'slight right';
43
+ }
44
+ if (angle >= 160 && angle <= 200) {
45
+ return 'straight';
46
+ }
47
+ if (angle > 200 && angle <= 220) {
48
+ return 'slight left';
49
+ }
50
+ if (angle > 220 && angle <= 300) {
51
+ return 'left';
52
+ }
53
+ if (angle > 300 && angle < 360) {
54
+ return 'sharp left';
55
+ }
56
+ return 'u turn';
57
+ }
37
58
 
38
- let type = i === 0 ? 'depart' : 'turn';
39
- type = i === lastStepId ? 'arrive' : type;
40
59
 
41
- const bearingBefore = MathUtils.positiveMod(i === 0 ? 0 : previousBearing, 2 * Math.PI);
42
- const bearingAfter = MathUtils.positiveMod(i === lastStepId ? 0 : nextBearing, 2 * Math.PI);
60
+ export function noRouteFoundJson(message) {
61
+ return {
62
+ 'code': 'NoRoute',
63
+ message
64
+ };
65
+ }
43
66
 
44
- const osrmStep = {
45
- geometry: {
46
- type: 'LineString',
47
- coordinates: OsrmUtils.nodesToJsonCoords(nodes)
48
- },
49
- distance: length,
50
- duration,
51
- name,
52
- maneuver: {
53
- bearing_before: rad2deg(bearingBefore),
54
- bearing_after: rad2deg(bearingAfter),
55
- location: OsrmUtils.coordinatesToJson(node.coords),
56
- type
57
- },
58
- wemap: {}
59
- };
67
+ /**
68
+ * @param {Itinerary} itinerary
69
+ * @returns {object}
70
+ */
71
+ export function itineraryToOsrmJson(itinerary) {
60
72
 
61
- if (levelChange !== null) {
62
- osrmStep.levelChange = levelChange;
63
- }
73
+ const itinerarySteps = itinerary.steps;
74
+ const osrmSteps = [];
64
75
 
65
- if (node.data && node.data.tags) {
66
- osrmStep.wemap.node = {
67
- id: node.data.id,
68
- tags: node.data.tags
69
- };
70
- }
76
+ const lastStepId = itinerarySteps.length - 1;
77
+ for (let i = 0; i <= lastStepId; i++) {
71
78
 
72
- if (i !== lastStepId && nextEdgeData) {
73
- osrmStep.wemap.nextEdgeData = {
74
- id: nextEdgeData.id,
75
- tags: nextEdgeData.tags
76
- };
77
- if (edges[0].data instanceof OsmNode) {
78
- osrmStep.wemap.nextEdgeData.type = 'node';
79
- osrmStep.wemap.nextEdgeData.coords = OsrmUtils.coordinatesToJson(edges[0].data.coords);
80
- }
81
- if (edges[0].data instanceof OsmWay) {
82
- osrmStep.wemap.nextEdgeData.type = 'way';
83
- }
84
- }
85
-
86
- // The first modifier is not mandatory by OSRM.
87
- // if (i !== 0) {
88
- osrmStep.maneuver.modifier = OsrmUtils.getModifierFromAngle(angle);
89
- // }
79
+ const {
80
+ nodes, length, nextEdge, nextBearing, previousBearing, angle, node,
81
+ duration, levelChange
82
+ } = itinerarySteps[i];
83
+
84
+ const name = (i === lastStepId ? node.name : nextEdge.name) || '';
85
+
86
+ let type = i === 0 ? 'depart' : 'turn';
87
+ type = i === lastStepId ? 'arrive' : type;
88
+
89
+ const bearingBefore = positiveMod(i === 0 ? 0 : previousBearing, 2 * Math.PI);
90
+ const bearingAfter = positiveMod(i === lastStepId ? 0 : nextBearing, 2 * Math.PI);
91
+
92
+ const osrmStep = {
93
+ geometry: {
94
+ type: 'LineString',
95
+ coordinates: nodesToJsonCoords(nodes)
96
+ },
97
+ distance: length,
98
+ duration,
99
+ name,
100
+ maneuver: {
101
+ bearing_before: rad2deg(bearingBefore),
102
+ bearing_after: rad2deg(bearingAfter),
103
+ location: coordinatesToJson(node.coords),
104
+ type
105
+ },
106
+ wemap: {}
107
+ };
90
108
 
91
- osrmSteps.push(osrmStep);
109
+ if (levelChange !== null) {
110
+ osrmStep.levelChange = levelChange;
92
111
  }
93
112
 
94
- return {
95
- 'code': 'Ok',
96
- 'routes': [
97
- {
98
- 'geometry': {
99
- 'type': 'LineString',
100
- 'coordinates': OsrmUtils.nodesToJsonCoords(itinerary.nodes)
101
- },
102
- 'legs': [
103
- {
104
- 'duration': itinerary.duration,
105
- 'distance': itinerary.length,
106
- 'steps': osrmSteps
107
- }
108
- ],
109
- 'distance': itinerary.length,
110
- 'duration': itinerary.duration,
111
- 'weight_name': 'routability',
112
- 'weight': 0
113
- }
114
- ],
115
- 'waypoints': []
116
- };
117
- }
118
-
119
- /**
120
- * Generate Itinerary from OSRM JSON, start and end.
121
- * @param {object} json JSON file provided by OSRM.
122
- * @param {Coordinates} start itinerary start
123
- * @param {Coordinates} end itinerary end
124
- */
125
- static createItineraryFromJson(json, start, end) {
126
- const itinerary = new Itinerary();
113
+ const nodeProperties = node.extractProperties();
114
+ if (Object.keys(nodeProperties).length !== 0) {
115
+ osrmStep.wemap.nodeProperties = nodeProperties;
116
+ }
127
117
 
128
- itinerary.start = start;
129
- itinerary.end = end;
118
+ if (i !== lastStepId && nextEdge) {
119
+ const nextEdgeProperties = nextEdge.extractProperties();
120
+ if (Object.keys(nextEdgeProperties).length !== 0) {
121
+ osrmStep.wemap.nextEdgeProperties = nextEdgeProperties;
122
+ }
123
+ }
130
124
 
131
- const {
132
- legs, geometry
133
- } = json.routes[0];
125
+ // The first modifier is not mandatory by OSRM.
126
+ // if (i !== 0) {
127
+ osrmStep.maneuver.modifier = getModifierFromAngle(angle);
128
+ // }
134
129
 
135
- /**
136
- * Create nodes and edges from geometry
137
- */
138
- let previousNode;
139
- const { coordinates } = geometry;
140
- for (let i = 0; i < coordinates.length; i++) {
141
- const node = new Node(OsrmUtils.jsonToCoordinates(coordinates[i]));
142
- itinerary.nodes.push(node);
130
+ osrmSteps.push(osrmStep);
131
+ }
143
132
 
144
- if (previousNode) {
145
- const edge = new Edge(previousNode, node);
146
- edge.level = Level.union(previousNode.coords.level, node.coords.level);
147
- itinerary.edges.push(edge);
133
+ return {
134
+ 'code': 'Ok',
135
+ 'routes': [
136
+ {
137
+ 'geometry': {
138
+ 'type': 'LineString',
139
+ 'coordinates': nodesToJsonCoords(itinerary.nodes)
140
+ },
141
+ 'legs': [
142
+ {
143
+ 'duration': itinerary.duration,
144
+ 'distance': itinerary.length,
145
+ 'steps': osrmSteps
146
+ }
147
+ ],
148
+ 'distance': itinerary.length,
149
+ 'duration': itinerary.duration,
150
+ 'weight_name': 'routability',
151
+ 'weight': 0
148
152
  }
153
+ ],
154
+ 'waypoints': []
155
+ };
156
+ }
149
157
 
150
- previousNode = node;
151
- }
158
+ function _parseSteps(itinerary, jsonSteps) {
152
159
 
153
- if (legs && legs[0]) {
154
- const { steps } = legs[0];
155
- OsrmUtils._parseSteps(itinerary, steps);
156
- }
160
+ itinerary._steps = [];
161
+ itinerary._nextStepsIndexes = [];
157
162
 
158
- return itinerary;
159
- }
163
+ let currentNodeIndex = 0;
160
164
 
161
- static _parseSteps(itinerary, jsonSteps) {
165
+ for (let i = 0; i < jsonSteps.length; i++) {
166
+ const jsonStep = jsonSteps[i];
162
167
 
163
- itinerary._steps = [];
164
- itinerary._nextStepsIndexes = [];
168
+ const step = new Step();
169
+ step.number = i + 1;
170
+ step.firstStep = i === 0;
171
+ step.lastStep = i === jsonSteps.length - 1;
165
172
 
166
- let currentNodeIndex = 0;
167
173
 
168
- for (let i = 0; i < jsonSteps.length; i++) {
169
- const jsonStep = jsonSteps[i];
174
+ /**
175
+ * Add nodes and edges to step
176
+ */
177
+ step.nodes = [];
178
+ step.edges = [];
170
179
 
171
- const step = new Step();
172
- step.number = i + 1;
173
- step.firstStep = i === 0;
174
- step.lastStep = i === jsonSteps.length - 1;
180
+ let previousNode;
181
+ let { coordinates } = jsonStep.geometry;
175
182
 
183
+ // The OSRM last step is twice the last node. So, remove the second.
184
+ if (step.lastStep) {
185
+ coordinates = [coordinates[0]];
186
+ }
176
187
 
177
- /**
178
- * Add nodes and edges to step
179
- */
180
- step.nodes = [];
181
- step.edges = [];
188
+ for (const coords of coordinates) {
182
189
 
183
- let previousNode;
184
- let { coordinates } = jsonStep.geometry;
190
+ const node = itinerary.nodes[currentNodeIndex];
191
+ step.nodes.push(node);
185
192
 
186
- // The OSRM last step is twice the last node. So, remove the second.
187
- if (step.lastStep) {
188
- coordinates = [coordinates[0]];
193
+ const isFirstNode = coordinates[0] === coords;
194
+ const isLastNode = coordinates[coordinates.length - 1] === coords;
195
+ if (isFirstNode) {
196
+ itinerary._nextStepsIndexes.push(i);
197
+ } else if (!isLastNode) {
198
+ itinerary._nextStepsIndexes.push(i + 1);
189
199
  }
190
200
 
191
- for (const coords of coordinates) {
192
-
193
- const node = itinerary.nodes[currentNodeIndex];
194
- step.nodes.push(node);
201
+ if (previousNode) {
202
+ const edge = Network.getEdgeByNodes(previousNode.edges, previousNode, node);
203
+ step.edges.push(edge);
204
+ }
195
205
 
196
- const isFirstNode = coordinates[0] === coords;
197
- const isLastNode = coordinates[coordinates.length - 1] === coords;
198
- if (isFirstNode) {
199
- itinerary._nextStepsIndexes.push(i);
200
- } else if (!isLastNode) {
201
- itinerary._nextStepsIndexes.push(i + 1);
202
- }
206
+ previousNode = node;
207
+ currentNodeIndex++;
208
+ }
203
209
 
204
- if (previousNode) {
205
- const edge = Network.getEdgeByNodes(previousNode.edges, previousNode, node);
206
- step.edges.push(edge);
207
- }
210
+ /**
211
+ * Add common fields
212
+ */
213
+ step.previousBearing = step.firstStep
214
+ ? itinerary.start.bearingTo(itinerary.nodes[0].coords)
215
+ : deg2rad(jsonStep.maneuver.bearing_before);
216
+ step.nextBearing = step.lastStep
217
+ ? previousNode.coords.bearingTo(itinerary.end)
218
+ : deg2rad(jsonStep.maneuver.bearing_after);
219
+ step.angle = diffAngle(step.previousBearing, step.nextBearing + Math.PI);
220
+ step.name = jsonStep.name;
221
+ step.levelChange = jsonStep.levelChange ? jsonStep.levelChange : null;
208
222
 
209
- previousNode = node;
210
- currentNodeIndex++;
223
+ /**
224
+ * Wemap fields
225
+ */
226
+ if (jsonStep.wemap) {
227
+ const firstNode = step.nodes[0];
228
+ if (jsonStep.wemap.nodeProperties && firstNode) {
229
+ firstNode.applyProperties(jsonStep.wemap.nodeProperties);
211
230
  }
212
231
 
213
- /**
214
- * Add common fields
215
- */
216
- step.previousBearing = step.firstStep
217
- ? itinerary.start.bearingTo(itinerary.nodes[0].coords)
218
- : deg2rad(jsonStep.maneuver.bearing_before);
219
- step.nextBearing = step.lastStep
220
- ? previousNode.coords.bearingTo(itinerary.end)
221
- : deg2rad(jsonStep.maneuver.bearing_after);
222
- step.angle = diffAngle(step.previousBearing, step.nextBearing + Math.PI);
223
- step.name = jsonStep.name;
224
- step.levelChange = jsonStep.levelChange ? jsonStep.levelChange : null;
225
-
226
- /**
227
- * Wemap fields
228
- */
229
- if (jsonStep.wemap) {
230
- const firstNode = step.nodes[0];
231
- if (jsonStep.wemap.node && firstNode) {
232
- const {
233
- id, tags
234
- } = jsonStep.wemap.node;
235
- firstNode.data = new OsmNode(id, step.nodes[0].coords, tags);
236
- }
237
-
238
- const firstEdge = step.edges[0];
239
- if (jsonStep.wemap.nextEdgeData && firstEdge) {
240
- const {
241
- coords, id, tags, type
242
- } = jsonStep.wemap.nextEdgeData;
243
- if (type === 'node') {
244
- firstEdge.data = new OsmNode(id, OsrmUtils.jsonToCoordinates(coords), tags);
245
- } else {
246
- // if (type === 'way')
247
- firstEdge.data = new OsmWay(id, tags);
248
- }
249
-
250
- firstEdge.data.level = firstEdge.level;
251
- }
232
+ const firstEdge = step.edges[0];
233
+ if (jsonStep.wemap.nextEdgeProperties && firstEdge) {
234
+ firstEdge.applyProperties(jsonStep.wemap.nextEdgeProperties);
252
235
  }
236
+ }
253
237
 
254
- itinerary._steps.push(step);
238
+ itinerary._steps.push(step);
255
239
 
256
- currentNodeIndex--;
257
- }
240
+ currentNodeIndex--;
258
241
  }
242
+ }
259
243
 
260
- static getModifierFromAngle(_angle) {
261
-
262
- const angle = MathUtils.positiveMod(rad2deg(_angle), 360);
244
+ /**
245
+ * Generate Itinerary from OSRM JSON, start and end.
246
+ * @param {object} json JSON file provided by OSRM.
247
+ * @param {Coordinates} start itinerary start
248
+ * @param {Coordinates} end itinerary end
249
+ */
250
+ export function createItineraryFromJson(json, start, end) {
251
+ const itinerary = new Itinerary();
263
252
 
264
- if (angle > 0 && angle < 60) {
265
- return 'sharp right';
266
- }
267
- if (angle >= 60 && angle < 140) {
268
- return 'right';
269
- }
270
- if (angle >= 140 && angle < 160) {
271
- return 'slight right';
272
- }
273
- if (angle >= 160 && angle <= 200) {
274
- return 'straight';
275
- }
276
- if (angle > 200 && angle <= 220) {
277
- return 'slight left';
278
- }
279
- if (angle > 220 && angle <= 300) {
280
- return 'left';
281
- }
282
- if (angle > 300 && angle < 360) {
283
- return 'sharp left';
284
- }
285
- return 'u turn';
286
- }
253
+ itinerary.start = start;
254
+ itinerary.end = end;
287
255
 
288
- static coordinatesToJson(coordinates) {
289
- const output = [coordinates.lng, coordinates.lat];
290
- if (coordinates.level) {
291
- output.push(coordinates.level.toString());
292
- }
293
- return output;
294
- }
256
+ const {
257
+ legs, geometry
258
+ } = json.routes[0];
295
259
 
296
- static jsonToCoordinates(json) {
297
- const output = new Coordinates(json[1], json[0]);
298
- if (json.length > 2) {
299
- output.level = Level.fromString(json[2]);
260
+ /**
261
+ * Create nodes and edges from geometry
262
+ */
263
+ let previousNode;
264
+ const { coordinates } = geometry;
265
+ for (let i = 0; i < coordinates.length; i++) {
266
+ const node = new Node(jsonToCoordinates(coordinates[i]));
267
+ itinerary.nodes.push(node);
268
+
269
+ if (previousNode) {
270
+ const edge = new Edge(previousNode, node);
271
+ edge.level = Level.union(previousNode.coords.level, node.coords.level);
272
+ itinerary.edges.push(edge);
300
273
  }
301
- return output;
302
- }
303
274
 
304
- static nodesToJsonCoords(nodes) {
305
- return nodes.map(node => OsrmUtils.coordinatesToJson(node.coords));
275
+ previousNode = node;
306
276
  }
307
277
 
308
-
309
- static noRouteFoundJson(message) {
310
- return {
311
- 'code': 'NoRoute',
312
- message
313
- };
278
+ if (legs && legs[0]) {
279
+ const { steps } = legs[0];
280
+ _parseSteps(itinerary, steps);
314
281
  }
315
282
 
283
+ return itinerary;
316
284
  }
317
285
 
318
- export default OsrmUtils;
286
+