Skip to content

Commit ed568f3

Browse files
committed
feat: shortest path (plain implementation)
1 parent 5eeb2ae commit ed568f3

File tree

10 files changed

+12043
-75
lines changed

10 files changed

+12043
-75
lines changed

.babelrc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{ "presets": ["@babel/preset-flow"] }

.idea/misc.xml

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/workspace.xml

+29-16
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/click.js

+153-5
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,167 @@
1-
import {post} from "../src/Networking";
1+
import {MinPriorityQueue} from "@datastructures-js/priority-queue";
2+
3+
function haversine_distance(p1,p2) {
4+
const toRadians = (degrees) => {
5+
return degrees * Math.PI / 180;
6+
};
7+
const [lat1, lon1] = p1;
8+
const [lat2, lon2] = p2;
9+
const R = 6371;
10+
const dLat = toRadians(lat2 - lat1);
11+
const dLon = toRadians(lon2 - lon1);
12+
const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
13+
Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2)) *
14+
Math.sin(dLon / 2) * Math.sin(dLon / 2);
15+
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
16+
if (R * c < 0) console.log("WARNING!!!");
17+
return R * c;
18+
}
19+
20+
function find_nearest_node_id(nodes, point) {
21+
const [lat, lon] = point;
22+
let min_distance = 1e100;
23+
let res = 0;
24+
for (let node_id in nodes) {
25+
const curr_distance = haversine_distance(nodes[node_id], point);
26+
if (curr_distance < min_distance) {
27+
min_distance = curr_distance;
28+
res = node_id;
29+
}
30+
}
31+
return res;
32+
}
33+
34+
function __spa(nodes, ch, u, p) {
35+
console.log(`node count: ${Object.keys(nodes).length}`);
36+
const weight_cache = {};
37+
try {
38+
const get_weight = (n1, n2) => {
39+
const tup = [n1, n2];
40+
if (weight_cache[tup]) {
41+
return weight_cache[[n1, n2]];
42+
}
43+
// console.log("21");
44+
// console.log(`${nodes[n1]} ${nodes[n2]}`);
45+
weight_cache[tup] = haversine_distance(nodes[n1], nodes[n2]);
46+
return weight_cache[tup];
47+
};
48+
const dis = {};
49+
const fa = {};
50+
const vis = new Set();
51+
const pq = new MinPriorityQueue();
52+
// console.log(`nodes: ${JSON.stringify(nodes)}`);
53+
dis[u] = 0;
54+
pq.push([0, u]);
55+
while (!pq.isEmpty()) {
56+
const [d, v] = pq.pop();
57+
if (vis.has(v) || !ch[v]) continue;
58+
vis.add(v);
59+
const t = ch[v].length;
60+
for (let j = 0; j < t; ++j) {
61+
const c = ch[v][j];
62+
if (!nodes[c]) continue;
63+
const w = get_weight(v, c);
64+
if (!dis[c] || d + w < dis[c]) {
65+
dis[c] = d + w;
66+
pq.push([dis[c], c]);
67+
fa[c] = v;
68+
}
69+
}
70+
}
71+
// console.log(`fa = ${JSON.stringify(fa)}`);
72+
let curr = p;
73+
const res = [p];
74+
// console.log(JSON.stringify(p));
75+
vis.clear();
76+
while (fa[curr]) {
77+
// console.log(JSON.stringify(curr));
78+
curr = fa[curr].toString();
79+
if(vis.has(curr)) {
80+
console.log(`Cycle at ${curr}`);
81+
break;
82+
}
83+
vis.add(curr);
84+
res.push(curr);
85+
}
86+
console.log("finished __spa.");
87+
// console.log(JSON.stringify(res));
88+
return res;
89+
} catch (e) {
90+
console.log(e);
91+
}
92+
}
93+
94+
function shortest_path(nodes, ways, start_point, end_point){
95+
try { // console.log(`Calling shortest_path(${nodes},${ways},${start_point},${end_point})`);
96+
const ch_dict = {};
97+
for (const way_id in ways) {
98+
const l = ways[way_id];
99+
const n = l.length;
100+
for (let i = 1; i < n; ++i) {
101+
if (ch_dict[l[i]]) {
102+
ch_dict[l[i]].push(l[i - 1]);
103+
} else {
104+
ch_dict[l[i]] = [l[i - 1]];
105+
}
106+
if (ch_dict[l[i - 1]]) {
107+
ch_dict[l[i - 1]].push(l[i]);
108+
} else {
109+
ch_dict[l[i - 1]] = [l[i]];
110+
}
111+
}
112+
}
113+
// console.log(ch_dict);
114+
const clean_nodes = {};
115+
Object.keys(nodes).forEach((node_id) => {
116+
if (ch_dict[node_id]) clean_nodes[node_id] = nodes[node_id];
117+
});
118+
const actual_start_node_id = find_nearest_node_id(clean_nodes, start_point);
119+
const actual_end_node_id = find_nearest_node_id(clean_nodes, end_point);
120+
console.log("calling __spa...");
121+
const seq = __spa(clean_nodes, ch_dict, actual_start_node_id, actual_end_node_id);
122+
const res = [end_point];
123+
seq.forEach((node_id) => {
124+
if (clean_nodes[node_id]) res.push(clean_nodes[node_id]);
125+
});
126+
res.push(start_point);
127+
return res;
128+
} catch (e) {
129+
console.log(e);
130+
}
131+
}
132+
2133

3134
export default function handler(req,res){
4135
const pts=JSON.parse(req.body);
5136
const latRange=pts.map((row)=>row[0]),
6137
lonRange=pts.map((row)=>row[1]);
7-
const minlon=Math.min(...lonRange),minlat=Math.min(...latRange),
8-
maxlon=Math.max(...lonRange),maxlat=Math.max(...latRange);
9-
const request_uri=`https://www.overpass-api.de/api/interpreter?data=[out:json];node[highway](${minlat},${minlon},${maxlat},${maxlon});out;`;
138+
const minlon=Math.min(...lonRange) - 0.01,minlat=Math.min(...latRange) - 0.01,
139+
maxlon=Math.max(...lonRange) + 0.01,maxlat=Math.max(...latRange) + 0.01;
140+
// console.log(`1+1`);
141+
const request_uri=`https://www.overpass-api.de/api/interpreter?data=[out:json];way[highway](${minlat},${minlon},${maxlat},${maxlon});(._;>;);out body;`;
142+
console.log(`Requesting ${request_uri}`);
10143
const fetch_debug_response= fetch(request_uri).then((response)=>{
11144
return response.json();
12145
});
13146
fetch_debug_response.then((debug_response)=>{
147+
console.log(debug_response);
148+
let ps = {};
149+
let ws = {};
150+
debug_response.elements.forEach((it)=> {
151+
if (it.type === "node") {
152+
ps[it.id] = [it.lat,it.lon];
153+
} else if (it.type === "way") {
154+
ws[it.id] = it.nodes;
155+
}
156+
});
157+
// console.log(`pts[0]: ${pts[0]}`);
158+
const path_found = shortest_path(ps,ws,pts[0],pts[pts.length - 1]);
159+
// const path_found = [];
160+
// console.log(JSON.stringify(path_found));
14161
res.status(200).json({
15162
log: `Method: click\nArgs: ${pts}\nStatus: requested "${request_uri}", got response ${JSON.stringify(debug_response.elements)}`,
16-
multipolyline: JSON.stringify(pts),
163+
multipolyline: JSON.stringify(path_found),
164+
// __debug_pts: ps
17165
});
18166
}).catch(e=>{
19167
res.status(500);

api/handshake.js

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
const __DEBUG__=1,
2-
__APP_VERSION__='v0.1.2a',
2+
__APP_VERSION__='v0.1.3a',
33
__APP_INTRO__=`
4-
<b>Relocating Support</b>
5-
Can't find where you are from? We now memorize the last location you visited. Tap the "Relocate" button to find your way home.<br>
6-
<b>Nearby Search</b>
7-
You can first locate a general area and schedule detailed travel plan later. Tap the magnifier/gear icon to toggle between Nearby Search mode and Global Search mode.
8-
<i>This update also includes several stability and UI improvements.</i>
4+
<b>Right way to follow.</b><br>
5+
In this update you can find a shortest route for any given start and destination.<br>
96
`;
107

118
export default function handler(req,res){

0 commit comments

Comments
 (0)