diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 5109b78..213e3b6 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -5,13 +5,13 @@
-
-
-
+
+
+
-
-
+
+
@@ -40,26 +40,26 @@
- {
+ "keyToString": {
+ "Node.js.test.js.executor": "Run",
+ "RunOnceActivity.OpenProjectViewOnStart": "true",
+ "RunOnceActivity.ShowReadmeOnStart": "true",
+ "WebServerToolWindowFactoryState": "false",
+ "git-widget-placeholder": "dev",
+ "last_opened_file_path": "/home/user/Documents/fd_data-structures/pj/frontend",
+ "node.js.detected.package.eslint": "true",
+ "node.js.detected.package.tslint": "true",
+ "node.js.selected.package.eslint": "(autodetect)",
+ "node.js.selected.package.tslint": "(autodetect)",
+ "nodejs_interpreter_path": "/home/user/.nvm/versions/node/v20.10.0/bin/node",
+ "nodejs_package_manager_path": "npm",
+ "npm.start.executor": "Run",
+ "settings.editor.selected.configurable": "editor.preferences.fonts.default",
+ "ts.external.directory.path": "/home/user/.local/share/JetBrains/Toolbox/apps/webstorm/plugins/javascript-impl/jsLanguageServicesImpl/external",
+ "vue.rearranger.settings.migration": "true"
}
-}]]>
+}
@@ -93,7 +93,9 @@
-
+
+
+
diff --git a/PublicProperty.js b/PublicProperty.js
new file mode 100644
index 0000000..7c26357
--- /dev/null
+++ b/PublicProperty.js
@@ -0,0 +1,9 @@
+// no dependencies
+
+export const __DEBUG__ = 1;
+export const __APP_VERSION__ = 'v0.1.3a';
+
+export const __APP_INTRO__ = `
+Right way to follow.
+In this update you can find a shortest route for any given start and destination.
+`;
\ No newline at end of file
diff --git a/api/click.js b/api/click.js
index 7651363..8877269 100644
--- a/api/click.js
+++ b/api/click.js
@@ -1,21 +1,7 @@
-import {MinPriorityQueue} from "@datastructures-js/priority-queue";
+import {dijkstra, haversine_distance} from "../tools/ShortestPath";
+import {sill, sill_unwrap, get_row, noexcept} from "../tools/Debug";
-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;
-}
+const __spa = dijkstra;
function find_nearest_node_id(nodes, point) {
const [lat, lon] = point;
@@ -31,139 +17,84 @@ function find_nearest_node_id(nodes, point) {
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;
- }
+const shortest_path = noexcept((nodes, ways, start_point, end_point) => {
+ const count = {};
+ for(const way_id in ways) {
+ sill(way_id);
+ const [l, n] = get_row(ways, way_id);
+ for(let i = 0; i < n; ++i) {
+ if(count[l[i]]) {
+ ++count[l[i]];
+ } else {
+ count[l[i]] = 1;
}
}
- // 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]];
- }
+ sill(count);
+ const ch_dict = {};
+ for (const way_id in ways) {
+ const [l, n] = get_row(ways, way_id);
+ for (let i = 0; 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);
}
-}
+ const clean_nodes = {};
+ Object.keys(nodes).forEach((node_id) => {
+ if (ch_dict[node_id]) clean_nodes[node_id] = nodes[node_id];
+ });
+ sill_unwrap(start_point);
+ 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);
+ sill("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;
+});
-export default function handler(req,res){
- const pts=JSON.parse(req.body);
- const latRange=pts.map((row)=>row[0]),
- lonRange=pts.map((row)=>row[1]);
- 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}`);
- const fetch_debug_response= fetch(request_uri).then((response)=>{
+export default function handler(req, res) {
+ const pts = JSON.parse(req.body);
+ const latRange = pts.map((row) => row[0]),
+ lonRange = pts.map((row) => row[1]);
+ 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;
+ const request_uri = `https://www.overpass-api.de/api/interpreter?data=[out:json];way[highway](${minlat},${minlon},${maxlat},${maxlon});(._;>;);out body;`;
+ sill(`Requesting ${request_uri}`);
+ const fetch_debug_response = fetch(request_uri).then((response) => {
return response.json();
});
- fetch_debug_response.then((debug_response)=>{
- console.log(debug_response);
+ fetch_debug_response.then((debug_response) => {
+ sill(debug_response);
let ps = {};
let ws = {};
- debug_response.elements.forEach((it)=> {
+ debug_response.elements.forEach((it) => {
if (it.type === "node") {
- ps[it.id] = [it.lat,it.lon];
+ 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));
+ const path_found = shortest_path(ps, ws, pts[0], pts[pts.length - 1]);
res.status(200).json({
log: `Method: click\nArgs: ${pts}\nStatus: requested "${request_uri}", got response ${JSON.stringify(debug_response.elements)}`,
multipolyline: JSON.stringify(path_found),
// __debug_pts: ps
});
- }).catch(e=>{
+ }).catch(e => {
+ console.debug(e);
res.status(500);
});
diff --git a/api/handshake.js b/api/handshake.js
index 2421e38..d0c3898 100644
--- a/api/handshake.js
+++ b/api/handshake.js
@@ -1,9 +1,4 @@
-const __DEBUG__=1,
- __APP_VERSION__='v0.1.3a',
- __APP_INTRO__=`
-Right way to follow.
-In this update you can find a shortest route for any given start and destination.
-`;
+import {__APP_VERSION__, __APP_INTRO__} from "../PublicProperty";
export default function handler(req,res){
res.status(200).json({
diff --git a/src/Networking.js b/src/Networking.js
index 9caf9b8..5df9f74 100644
--- a/src/Networking.js
+++ b/src/Networking.js
@@ -1,3 +1,5 @@
+import {sill} from "./tools/Debug";
+
export function post(type,method,args) {
let ft = async () => {
let response;
@@ -13,7 +15,7 @@ export function post(type,method,args) {
});
}
const response_data = await response.json();
- console.log(`Request "${method}" finished:\n ${response_data.log.replaceAll('\n','\n ')}`);
+ sill(`Request "${method}" finished:\n ${response_data.log.replaceAll('\n','\n ')}`);
return response_data;
};
return ft();
diff --git a/src/UMap.js b/src/UMap.js
index 42f484e..976b544 100644
--- a/src/UMap.js
+++ b/src/UMap.js
@@ -6,6 +6,7 @@ import {post} from './Networking';
import {Autocomplete, CircularProgress, Sheet} from "@mui/joy";
import SimulateClick from "./SimulateClick";
import {NearMe} from "@mui/icons-material";
+import {sill} from "./tools/Debug";
const defaultZoomLevel=16;
const defaultLocationName = 'Apple Park';
@@ -113,7 +114,7 @@ function MapClickHandler({mks,focusUpdater,locator,locker}) {
// response.__debug_pts.forEach(({lat,lon})=>{
// mks.current.addCandMarker(lat,lon);
// });
- console.log(`pl = ${JSON.stringify(pl)}`);
+ sill(`pl = ${JSON.stringify(pl)}`);
if (pl.length > 1) mks.current.flushPolylines(pl);
focusUpdater([lat,lng]);
locator([lat,lng]);
@@ -215,7 +216,7 @@ export default function UMap() {
const [zoom,setZoom] = useState(defaultZoomLevel);
const sf = (a) => {
setFocus(a);
- console.log(`triggered focus update, new focus is ${focus}`);
+ sill(`triggered focus update, new focus is ${focus}`);
const ft = fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${a[0]}&lon=${a[1]}&zoom=${zoom}&addressdetails=0`).then(response => response.json());
ft.then((response) => setNearbyName(' ' + response.name)).catch(() => setNearbyName('by'));
};
diff --git a/src/tools b/src/tools
new file mode 120000
index 0000000..4887d6e
--- /dev/null
+++ b/src/tools
@@ -0,0 +1 @@
+../tools
\ No newline at end of file
diff --git a/tools/Debug.js b/tools/Debug.js
new file mode 100644
index 0000000..665bf35
--- /dev/null
+++ b/tools/Debug.js
@@ -0,0 +1,33 @@
+// no dependencies
+import {__DEBUG__} from "../PublicProperty";
+
+export function noexcept(f) {
+ /**
+ * No exceptions.
+ * @returns {*}
+ * @private
+ */
+ function _wrap() {
+ try {
+ return f.apply(this, arguments);
+ } catch (e) {
+ console.debug(e);
+ }
+ }
+ return _wrap;
+}
+
+export const sill = noexcept((x) => {
+ if(__DEBUG__) {
+ console.log(x);
+ }
+});
+
+export const sill_unwrap = noexcept((x) => {
+ sill(JSON.stringify(x));
+});
+
+export const get_row = noexcept((a,i) => {
+ const row = a[i];
+ return [row, row.length];
+});
\ No newline at end of file
diff --git a/tools/ShortestPath.js b/tools/ShortestPath.js
new file mode 100644
index 0000000..e75d286
--- /dev/null
+++ b/tools/ShortestPath.js
@@ -0,0 +1,79 @@
+import {MinPriorityQueue} from "@datastructures-js/priority-queue";
+import {sill, noexcept} from "./Debug";
+
+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.warn("WARNING!!!");
+ return R * c;
+}
+
+
+/**
+ * Use Dijkstra algorithm to find the shortest path.
+ * @param nodes node index list
+ * @param ch adjacent table
+ * @param u start node id
+ * @param p destination node id
+ */
+function __dijkstra(nodes, ch, u, p) {
+ sill(`node count: ${Object.keys(nodes).length}`);
+ const weight_cache = {};
+ const get_weight = (n1, n2) => {
+ const tup = [n1, n2];
+ if (weight_cache[tup]) {
+ return weight_cache[[n1, 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();
+ 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;
+ }
+ }
+ }
+ let curr = p;
+ const res = [p];
+ vis.clear();
+ while (fa[curr]) {
+ curr = fa[curr].toString();
+ if (vis.has(curr)) {
+ sill(`Cycle at ${curr}`);
+ break;
+ }
+ vis.add(curr);
+ res.push(curr);
+ }
+ sill("finished Dijkstra.");
+ return res;
+}
+
+export const haversine_distance = noexcept(__haversine_distance);
+export const dijkstra = noexcept(__dijkstra);
\ No newline at end of file