-
Notifications
You must be signed in to change notification settings - Fork 1
/
routing.js
289 lines (237 loc) · 10.6 KB
/
routing.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
"use strict";
const cm = require("./common.js");
/**
* compute a route with optional waypooints. [See more info on optional parameters](http://documentation.developer.here.com/pdf/routing_hlp/7.2.100/Routing%20API%20v7.2.100%20Developer's%20Guide.pdf)
* @alias hm:route
* @param {object} source - source as \[lat,lng\]. Can be array of \[lat,lng\] to define waypoints
* @param {object} dest - dest as \[lat,lng\]. Can be array of \[lat,lng\] to define waypoints
* @param opt {object} route options
* @param [opt.mode=fastest;car;traffic:disabled] {string} routing mode
* @param [opt.routeattributes=waypoints,summary,shape] {string} route attributes
* @param [opt.maneuverattributes=direction,action] {string} manoeuver attributes
* @returns {Promise} returns { summary: object, coords:array,route: object, body:object}. coords is array of coord, to be used with hm.polyline.
*
* @example
* ```js
* const res = await hm.route([48.8,2.3],[48.7,2.5]);
* console.log (res.summary);
*
* const res = await hm.route([[48.8,2.3],[48.9,2.7]], [49.3,2.5]);
* console.log (res.route);
*
* const res = await hm.route([48.8,2.3], [[48.9,2.7], [49.3,2.5]]);
* console.log (res.summary);
* ```
*/
function route(source, dest, opt) {
const settings = {
mode: "fastest;car;traffic:disabled",
representation: "linkPaging",
routeattributes: "waypoints,summary,shape",
maneuverattributes: "direction,action"
};
const params = cm.addCredentials(settings, opt);
// 1 seul source ou array de source ?
let id = 0;
if (Array.isArray(source[0]))
for (var i = 0; i < source.length; i++) {
let coord = source[i];
params["waypoint" + id++] = coord[0] + "," + coord[1];
}
else
params["waypoint" + id++] = source[0] + "," + source[1];
if (Array.isArray(dest[0]))
for (let i = 0; i < dest.length; i++) {
let coord = dest[i];
params["waypoint" + id++] = coord[0] + "," + coord[1];
}
else
params["waypoint" + id++] = dest[0] + "," + dest[1];
const url = cm.buildUrl("route", "api.here.com/routing/7.2/calculateroute.json");
return cm.hereRest(url, params, "post")
.then(res => {
const route = res.body.response.route[0];
const summary = route.summary;
const coords = route.shape.map((latlng => latlng.split(",")));
return { summary: summary, coords: coords, route: route, body: res.body };
});
}
/**
* compute an isoline. [See more info on optional parameters](http://documentation.developer.here.com/pdf/routing_hlp/7.2.100/Routing%20API%20v7.2.100%20Developer's%20Guide.pdf)
* @alias hm:isoline
* @param opt {object} option for isoline
* @param [opt.start] {coord} coord for starting point of isoline
* @param [opt.destination] {coord} coord for destination point of isoline
* @param [opt.rangeType="time"] {string} time or distance
* @param [opt.range] {number} range in seconds or in meters
* @param [opt.mode="fastest;car;traffic:disabled"] {String} routing mode
* @param [opt.linkattributes=sh] {String} attributes to be returned
*
* @returns {Promise} returns { poly:array, body:object }. Poly is array of coords, body is full answer
*/
function isoline(opt) {
const settings = {
start: null, // for direct isoline
destination: null, // for reverse isoline
rangeType: "time", // time or distance
range: null, // in seconds or meters
linkattributes: "sh", // to get the shape
mode: "fastest;car;traffic:disabled", //shortest;car;traffic:disabled
};
const params = cm.addCredentials(settings, opt);
if (params.start)
params.start = "geo!" + params.start[0] + "," + params.start[1];
if (params.destination)
params.destination = "geo!" + params.destination[0] + "," + params.destination[1];
if (!params.start && !params.destination) {
let e = new Error("Isoline routing : missing start or destination"); // e.message
throw (e);
}
if (!params.range) {
let e = new Error("Isoline routing : missing range"); // e.message
throw (e);
}
const url = cm.buildUrl("isoline.route", "api.here.com/routing/7.2/calculateisoline.json");
return cm.hereRest(url, params, "post")
.then(res => {
// array of lat,lng, to be transformed into array of [lat,lng]
const shape = res.body.response.isoline[0].component[0].shape;
const poly = shape.map(point => point.split(","));
return { poly: poly, body: res.body };
});
}
/**
* compute a matrix. [See more info on optional parameters](http://documentation.developer.here.com/pdf/routing_hlp/7.2.100/Routing%20API%20v7.2.100%20Developer's%20Guide.pdf)
*
* Matrix size is limited to 1x100, 100x1 or 15xN
* @alias hm:matrix
* @param source {object} source as \[lat,lng\]. Can be array of \[lat,lng\]
* @param dest {object} dest as \[lat,lng\]. Can be array of \[lat,lng\]
* @param opt {object} additional optional parameters like mode, summaryAttributes
* @param [opt.mode="fastest;car;traffic:enabled"] {string} routing mode to compute matrix
* @param [opt.summaryAttributes="tt,di"] {string} attributes in the answer
*
* @returns {Promise} { entries: object, body:object }. entries is the array of {start,stop} information. body is full json answer
* @example
* ```js
* const res = await hm.matrix({
* source:[48.8,2.3]
* dest:[[48.7,2.5],[48.1,2.0],[44.2,2.3]]
* });
* console.log (res.entries);
* ```
*/
function matrix(source, dest, opt) {
var settings = {
mode: "fastest;car;traffic:enabled",
summaryAttributes: "tt,di"
};
const params = cm.addCredentials(settings, opt);
if (!Array.isArray(source[0])) // if only one coord
source = [source];
source.forEach((coord, i) => {
params["start" + i] = coord[0] + "," + coord[1];
});
if (!Array.isArray(dest[0])) // if only one coord
dest = [dest];
dest.forEach((coord, i) => {
params["destination" + i] = coord[0] + "," + coord[1];
});
const url = cm.buildUrl("matrix.route", "api.here.com/routing/7.2/calculatematrix.json");
return cm.hereRest(url, params, "post")
.then(res => {
return { entries: res.body.response.matrixEntry, body: res.body };
});
}
/**
* Compute the detour for each waypoint provided, compared to normal route from A to B
*
* @async
* @alias hm:detour
* @param start {coord} starting point for route
* @param stop {coord} destination point of route
* @param waypoints {array} list of watypoints to test
* @returns {Promise} returns {reference: {start, stop, distance, distance2, time, time2} ,waypoints:[ {coord, distA, timeA, distB, timeB}]}
*/
async function detour(start, stop, waypoints) {
// eslint-disable-next-line no-undef
return new Promise(
async (resolve, reject) => {
//let tStart = new Date();
if (!start) return reject("missing start point");
if (!stop) return reject("missing stop point");
if (!waypoints) return reject("missing waypoints");
if (!Array.isArray) return reject("waypoints should be an array");
// initialise le resultat
let res = {
reference: {},
waypoints: []
};
// calcul les coords nonPostGres, creer l'array de coord des waypoints.
let dest = [stop]; // so we have a distance/time reference, not same as from routing 1:1
waypoints.forEach(waypoint => {
dest.push(waypoint);
res.waypoints.push(
{ coord: waypoint }
);
});
// inspect(dest, "dest from detour")
// compute start to all waypoint, 1st waypoint is stop to get a reference
let p1 = matrix(start, dest, { mode: "fastest;car;traffic:disabled" });
// compute from all waypoint to stop, 1st waypoint is start to get another reference
dest[0] = start;
let p2 = matrix(dest, stop, { mode: "fastest;car;traffic:disabled" });
// wait for both matrix to complete
// eslint-disable-next-line no-undef
const result = await Promise.all([p1, p2]);
// process first part: start => N waypoints
let entries = result[0].entries;
// first entry is start stop
let dist = entries[0].summary.distance;
let time = entries[0].summary.travelTime;
res.reference.start = start;
res.reference.stop = stop;
res.reference.distance = dist;
res.reference.time = time; // the reference sans waypoint
entries.forEach((entry, i) => {
if (i == 0) return; // skip the first which is start stop
if (entry.status == "failed") {
//console.log(entry, "error on matrixA" + i);
//console.log(start, "associated start");
//console.log(dest[i], "associated dest" + i);
return;
}
let id = entry.destinationIndex;
let dist = entry.summary.distance;
let time = entry.summary.travelTime;
res.waypoints[id - 1].distA = dist;
res.waypoints[id - 1].timeA = time;
});
// process second part: N waypoints => stop
entries = result[1].entries;
//inspect(entries[0], "matrixB0");
res.reference.distance2 = entries[0].summary.distance;
res.reference.time2 = entries[0].summary.travelTime;
entries.forEach((entry, i) => {
if (i == 0) return; // skip the first which is start stop
if (entry.status == "failed") {
//console.log(entry, "error on matrixB" + i);
//console.log(entry, "associated start" + i);
//console.log(stop, "associated stop");
return;
}
let id = entry.startIndex;
let dist = entry.summary.distance;
let time = entry.summary.travelTime;
res.waypoints[id - 1].distB = dist;
res.waypoints[id - 1].timeB = time;
});
return resolve(res);
});
}
module.exports = {
matrix: matrix,
route: route,
isoline: isoline,
detour: detour
};