2023-12-25 00:06:07 +08:00
|
|
|
import {MinPriorityQueue} from "@datastructures-js/priority-queue";
|
|
|
|
|
|
|
|
function haversine_distance(p1,p2) {
|
|
|
|
const toRadians = (degrees) => {
|
|
|
|
return degrees * Math.PI / 180;
|
|
|
|
};
|
|
|
|
const [lat1, lon1] = p1;
|
|
|
|
const [lat2, lon2] = p2;
|
|
|
|
const R = 6371;
|
|
|
|
const dLat = toRadians(lat2 - lat1);
|
|
|
|
const dLon = toRadians(lon2 - lon1);
|
|
|
|
const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
|
|
|
|
Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2)) *
|
|
|
|
Math.sin(dLon / 2) * Math.sin(dLon / 2);
|
|
|
|
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
|
|
|
if (R * c < 0) console.log("WARNING!!!");
|
|
|
|
return R * c;
|
|
|
|
}
|
|
|
|
|
|
|
|
function find_nearest_node_id(nodes, point) {
|
|
|
|
const [lat, lon] = point;
|
|
|
|
let min_distance = 1e100;
|
|
|
|
let res = 0;
|
|
|
|
for (let node_id in nodes) {
|
|
|
|
const curr_distance = haversine_distance(nodes[node_id], point);
|
|
|
|
if (curr_distance < min_distance) {
|
|
|
|
min_distance = curr_distance;
|
|
|
|
res = node_id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
function __spa(nodes, ch, u, p) {
|
|
|
|
console.log(`node count: ${Object.keys(nodes).length}`);
|
|
|
|
const weight_cache = {};
|
|
|
|
try {
|
|
|
|
const get_weight = (n1, n2) => {
|
|
|
|
const tup = [n1, n2];
|
|
|
|
if (weight_cache[tup]) {
|
|
|
|
return weight_cache[[n1, n2]];
|
|
|
|
}
|
|
|
|
// console.log("21");
|
|
|
|
// console.log(`${nodes[n1]} ${nodes[n2]}`);
|
|
|
|
weight_cache[tup] = haversine_distance(nodes[n1], nodes[n2]);
|
|
|
|
return weight_cache[tup];
|
|
|
|
};
|
|
|
|
const dis = {};
|
|
|
|
const fa = {};
|
|
|
|
const vis = new Set();
|
|
|
|
const pq = new MinPriorityQueue();
|
|
|
|
// console.log(`nodes: ${JSON.stringify(nodes)}`);
|
|
|
|
dis[u] = 0;
|
|
|
|
pq.push([0, u]);
|
|
|
|
while (!pq.isEmpty()) {
|
|
|
|
const [d, v] = pq.pop();
|
|
|
|
if (vis.has(v) || !ch[v]) continue;
|
|
|
|
vis.add(v);
|
|
|
|
const t = ch[v].length;
|
|
|
|
for (let j = 0; j < t; ++j) {
|
|
|
|
const c = ch[v][j];
|
|
|
|
if (!nodes[c]) continue;
|
|
|
|
const w = get_weight(v, c);
|
|
|
|
if (!dis[c] || d + w < dis[c]) {
|
|
|
|
dis[c] = d + w;
|
|
|
|
pq.push([dis[c], c]);
|
|
|
|
fa[c] = v;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// console.log(`fa = ${JSON.stringify(fa)}`);
|
|
|
|
let curr = p;
|
|
|
|
const res = [p];
|
|
|
|
// console.log(JSON.stringify(p));
|
|
|
|
vis.clear();
|
|
|
|
while (fa[curr]) {
|
|
|
|
// console.log(JSON.stringify(curr));
|
|
|
|
curr = fa[curr].toString();
|
|
|
|
if(vis.has(curr)) {
|
|
|
|
console.log(`Cycle at ${curr}`);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
vis.add(curr);
|
|
|
|
res.push(curr);
|
|
|
|
}
|
|
|
|
console.log("finished __spa.");
|
|
|
|
// console.log(JSON.stringify(res));
|
|
|
|
return res;
|
|
|
|
} catch (e) {
|
|
|
|
console.log(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function shortest_path(nodes, ways, start_point, end_point){
|
|
|
|
try { // console.log(`Calling shortest_path(${nodes},${ways},${start_point},${end_point})`);
|
|
|
|
const ch_dict = {};
|
|
|
|
for (const way_id in ways) {
|
|
|
|
const l = ways[way_id];
|
|
|
|
const n = l.length;
|
|
|
|
for (let i = 1; i < n; ++i) {
|
|
|
|
if (ch_dict[l[i]]) {
|
|
|
|
ch_dict[l[i]].push(l[i - 1]);
|
|
|
|
} else {
|
|
|
|
ch_dict[l[i]] = [l[i - 1]];
|
|
|
|
}
|
|
|
|
if (ch_dict[l[i - 1]]) {
|
|
|
|
ch_dict[l[i - 1]].push(l[i]);
|
|
|
|
} else {
|
|
|
|
ch_dict[l[i - 1]] = [l[i]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// console.log(ch_dict);
|
|
|
|
const clean_nodes = {};
|
|
|
|
Object.keys(nodes).forEach((node_id) => {
|
|
|
|
if (ch_dict[node_id]) clean_nodes[node_id] = nodes[node_id];
|
|
|
|
});
|
|
|
|
const actual_start_node_id = find_nearest_node_id(clean_nodes, start_point);
|
|
|
|
const actual_end_node_id = find_nearest_node_id(clean_nodes, end_point);
|
|
|
|
console.log("calling __spa...");
|
|
|
|
const seq = __spa(clean_nodes, ch_dict, actual_start_node_id, actual_end_node_id);
|
|
|
|
const res = [end_point];
|
|
|
|
seq.forEach((node_id) => {
|
|
|
|
if (clean_nodes[node_id]) res.push(clean_nodes[node_id]);
|
|
|
|
});
|
|
|
|
res.push(start_point);
|
|
|
|
return res;
|
|
|
|
} catch (e) {
|
|
|
|
console.log(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-26 22:17:55 +08:00
|
|
|
|
|
|
|
export default function handler(req,res){
|
2023-11-27 12:21:22 +08:00
|
|
|
const pts=JSON.parse(req.body);
|
|
|
|
const latRange=pts.map((row)=>row[0]),
|
|
|
|
lonRange=pts.map((row)=>row[1]);
|
2023-12-25 00:06:07 +08:00
|
|
|
const minlon=Math.min(...lonRange) - 0.01,minlat=Math.min(...latRange) - 0.01,
|
|
|
|
maxlon=Math.max(...lonRange) + 0.01,maxlat=Math.max(...latRange) + 0.01;
|
|
|
|
// console.log(`1+1`);
|
|
|
|
const request_uri=`https://www.overpass-api.de/api/interpreter?data=[out:json];way[highway](${minlat},${minlon},${maxlat},${maxlon});(._;>;);out body;`;
|
|
|
|
console.log(`Requesting ${request_uri}`);
|
2023-11-27 12:21:22 +08:00
|
|
|
const fetch_debug_response= fetch(request_uri).then((response)=>{
|
|
|
|
return response.json();
|
2023-11-26 22:17:55 +08:00
|
|
|
});
|
2023-11-27 12:21:22 +08:00
|
|
|
fetch_debug_response.then((debug_response)=>{
|
2023-12-25 00:06:07 +08:00
|
|
|
console.log(debug_response);
|
|
|
|
let ps = {};
|
|
|
|
let ws = {};
|
|
|
|
debug_response.elements.forEach((it)=> {
|
|
|
|
if (it.type === "node") {
|
|
|
|
ps[it.id] = [it.lat,it.lon];
|
|
|
|
} else if (it.type === "way") {
|
|
|
|
ws[it.id] = it.nodes;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
// console.log(`pts[0]: ${pts[0]}`);
|
|
|
|
const path_found = shortest_path(ps,ws,pts[0],pts[pts.length - 1]);
|
|
|
|
// const path_found = [];
|
|
|
|
// console.log(JSON.stringify(path_found));
|
2023-11-27 12:21:22 +08:00
|
|
|
res.status(200).json({
|
|
|
|
log: `Method: click\nArgs: ${pts}\nStatus: requested "${request_uri}", got response ${JSON.stringify(debug_response.elements)}`,
|
2023-12-25 00:06:07 +08:00
|
|
|
multipolyline: JSON.stringify(path_found),
|
|
|
|
// __debug_pts: ps
|
2023-11-27 12:21:22 +08:00
|
|
|
});
|
|
|
|
}).catch(e=>{
|
|
|
|
res.status(500);
|
|
|
|
});
|
|
|
|
|
2023-11-26 22:17:55 +08:00
|
|
|
}
|