refactor: debug tools and display
This commit is contained in:
parent
ed568f3572
commit
8c117633c5
|
@ -5,13 +5,13 @@
|
||||||
</component>
|
</component>
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="3c7078e7-6f30-4d92-9696-11496f9e6dff" name="Changes" comment="">
|
<list default="true" id="3c7078e7-6f30-4d92-9696-11496f9e6dff" name="Changes" comment="">
|
||||||
<change afterPath="$PROJECT_DIR$/.babelrc" afterDir="false" />
|
<change afterPath="$PROJECT_DIR$/PublicProperty.js" afterDir="false" />
|
||||||
<change afterPath="$PROJECT_DIR$/comp/ShortestPath.js" afterDir="false" />
|
<change afterPath="$PROJECT_DIR$/tools/Debug.js" afterDir="false" />
|
||||||
<change afterPath="$PROJECT_DIR$/test/test_nearest.js" afterDir="false" />
|
<change afterPath="$PROJECT_DIR$/tools/ShortestPath.js" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/api/click.js" beforeDir="false" afterPath="$PROJECT_DIR$/api/click.js" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/api/click.js" beforeDir="false" afterPath="$PROJECT_DIR$/api/click.js" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/package-lock.json" beforeDir="false" afterPath="$PROJECT_DIR$/package-lock.json" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/api/handshake.js" beforeDir="false" afterPath="$PROJECT_DIR$/api/handshake.js" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/package.json" beforeDir="false" afterPath="$PROJECT_DIR$/package.json" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/Networking.js" beforeDir="false" afterPath="$PROJECT_DIR$/src/Networking.js" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/UMap.js" beforeDir="false" afterPath="$PROJECT_DIR$/src/UMap.js" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/UMap.js" beforeDir="false" afterPath="$PROJECT_DIR$/src/UMap.js" afterDir="false" />
|
||||||
</list>
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
|
@ -40,26 +40,26 @@
|
||||||
<option name="hideEmptyMiddlePackages" value="true" />
|
<option name="hideEmptyMiddlePackages" value="true" />
|
||||||
<option name="showLibraryContents" value="true" />
|
<option name="showLibraryContents" value="true" />
|
||||||
</component>
|
</component>
|
||||||
<component name="PropertiesComponent"><![CDATA[{
|
<component name="PropertiesComponent">{
|
||||||
"keyToString": {
|
"keyToString": {
|
||||||
"Node.js.test.js.executor": "Run",
|
"Node.js.test.js.executor": "Run",
|
||||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||||
"WebServerToolWindowFactoryState": "false",
|
"WebServerToolWindowFactoryState": "false",
|
||||||
"git-widget-placeholder": "dev",
|
"git-widget-placeholder": "dev",
|
||||||
"last_opened_file_path": "/home/user/Documents/fd_data-structures/pj/frontend",
|
"last_opened_file_path": "/home/user/Documents/fd_data-structures/pj/frontend",
|
||||||
"node.js.detected.package.eslint": "true",
|
"node.js.detected.package.eslint": "true",
|
||||||
"node.js.detected.package.tslint": "true",
|
"node.js.detected.package.tslint": "true",
|
||||||
"node.js.selected.package.eslint": "(autodetect)",
|
"node.js.selected.package.eslint": "(autodetect)",
|
||||||
"node.js.selected.package.tslint": "(autodetect)",
|
"node.js.selected.package.tslint": "(autodetect)",
|
||||||
"nodejs_interpreter_path": "/home/user/.nvm/versions/node/v20.10.0/bin/node",
|
"nodejs_interpreter_path": "/home/user/.nvm/versions/node/v20.10.0/bin/node",
|
||||||
"nodejs_package_manager_path": "npm",
|
"nodejs_package_manager_path": "npm",
|
||||||
"npm.start.executor": "Run",
|
"npm.start.executor": "Run",
|
||||||
"settings.editor.selected.configurable": "editor.preferences.fonts.default",
|
"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",
|
"ts.external.directory.path": "/home/user/.local/share/JetBrains/Toolbox/apps/webstorm/plugins/javascript-impl/jsLanguageServicesImpl/external",
|
||||||
"vue.rearranger.settings.migration": "true"
|
"vue.rearranger.settings.migration": "true"
|
||||||
}
|
}
|
||||||
}]]></component>
|
}</component>
|
||||||
<component name="RunManager">
|
<component name="RunManager">
|
||||||
<configuration name="start" type="js.build_tools.npm" temporary="true" nameIsGenerated="true">
|
<configuration name="start" type="js.build_tools.npm" temporary="true" nameIsGenerated="true">
|
||||||
<package-json value="$PROJECT_DIR$/package.json" />
|
<package-json value="$PROJECT_DIR$/package.json" />
|
||||||
|
@ -93,7 +93,9 @@
|
||||||
<workItem from="1701056208994" duration="5687000" />
|
<workItem from="1701056208994" duration="5687000" />
|
||||||
<workItem from="1701847206194" duration="6179000" />
|
<workItem from="1701847206194" duration="6179000" />
|
||||||
<workItem from="1702448962541" duration="5620000" />
|
<workItem from="1702448962541" duration="5620000" />
|
||||||
<workItem from="1703419885970" duration="12662000" />
|
<workItem from="1703419885970" duration="13073000" />
|
||||||
|
<workItem from="1703582457934" duration="210000" />
|
||||||
|
<workItem from="1703642799206" duration="3401000" />
|
||||||
</task>
|
</task>
|
||||||
<servers />
|
<servers />
|
||||||
</component>
|
</component>
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
// no dependencies
|
||||||
|
|
||||||
|
export const __DEBUG__ = 1;
|
||||||
|
export const __APP_VERSION__ = 'v0.1.3a';
|
||||||
|
|
||||||
|
export const __APP_INTRO__ = `
|
||||||
|
<b>Right way to follow.</b><br>
|
||||||
|
In this update you can find a shortest route for any given start and destination.<br>
|
||||||
|
`;
|
113
api/click.js
113
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 __spa = dijkstra;
|
||||||
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) {
|
function find_nearest_node_id(nodes, point) {
|
||||||
const [lat, lon] = point;
|
const [lat, lon] = point;
|
||||||
|
@ -31,73 +17,24 @@ function find_nearest_node_id(nodes, point) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
function __spa(nodes, ch, u, p) {
|
const shortest_path = noexcept((nodes, ways, start_point, end_point) => {
|
||||||
console.log(`node count: ${Object.keys(nodes).length}`);
|
const count = {};
|
||||||
const weight_cache = {};
|
for(const way_id in ways) {
|
||||||
try {
|
sill(way_id);
|
||||||
const get_weight = (n1, n2) => {
|
const [l, n] = get_row(ways, way_id);
|
||||||
const tup = [n1, n2];
|
for(let i = 0; i < n; ++i) {
|
||||||
if (weight_cache[tup]) {
|
if(count[l[i]]) {
|
||||||
return weight_cache[[n1, n2]];
|
++count[l[i]];
|
||||||
}
|
} else {
|
||||||
// console.log("21");
|
count[l[i]] = 1;
|
||||||
// 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)}`);
|
sill(count);
|
||||||
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 = {};
|
const ch_dict = {};
|
||||||
for (const way_id in ways) {
|
for (const way_id in ways) {
|
||||||
const l = ways[way_id];
|
const [l, n] = get_row(ways, way_id);
|
||||||
const n = l.length;
|
for (let i = 0; i < n; ++i) {
|
||||||
for (let i = 1; i < n; ++i) {
|
|
||||||
if (ch_dict[l[i]]) {
|
if (ch_dict[l[i]]) {
|
||||||
ch_dict[l[i]].push(l[i - 1]);
|
ch_dict[l[i]].push(l[i - 1]);
|
||||||
} else {
|
} else {
|
||||||
|
@ -110,14 +47,14 @@ function shortest_path(nodes, ways, start_point, end_point){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// console.log(ch_dict);
|
|
||||||
const clean_nodes = {};
|
const clean_nodes = {};
|
||||||
Object.keys(nodes).forEach((node_id) => {
|
Object.keys(nodes).forEach((node_id) => {
|
||||||
if (ch_dict[node_id]) clean_nodes[node_id] = nodes[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_start_node_id = find_nearest_node_id(clean_nodes, start_point);
|
||||||
const actual_end_node_id = find_nearest_node_id(clean_nodes, end_point);
|
const actual_end_node_id = find_nearest_node_id(clean_nodes, end_point);
|
||||||
console.log("calling __spa...");
|
sill("calling __spa...");
|
||||||
const seq = __spa(clean_nodes, ch_dict, actual_start_node_id, actual_end_node_id);
|
const seq = __spa(clean_nodes, ch_dict, actual_start_node_id, actual_end_node_id);
|
||||||
const res = [end_point];
|
const res = [end_point];
|
||||||
seq.forEach((node_id) => {
|
seq.forEach((node_id) => {
|
||||||
|
@ -125,10 +62,7 @@ function shortest_path(nodes, ways, start_point, end_point){
|
||||||
});
|
});
|
||||||
res.push(start_point);
|
res.push(start_point);
|
||||||
return res;
|
return res;
|
||||||
} catch (e) {
|
});
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export default function handler(req, res) {
|
export default function handler(req, res) {
|
||||||
|
@ -137,14 +71,13 @@ export default function handler(req,res){
|
||||||
lonRange = pts.map((row) => row[1]);
|
lonRange = pts.map((row) => row[1]);
|
||||||
const minlon = Math.min(...lonRange) - 0.01, minlat = Math.min(...latRange) - 0.01,
|
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;
|
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;`;
|
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}`);
|
sill(`Requesting ${request_uri}`);
|
||||||
const fetch_debug_response = fetch(request_uri).then((response) => {
|
const fetch_debug_response = fetch(request_uri).then((response) => {
|
||||||
return response.json();
|
return response.json();
|
||||||
});
|
});
|
||||||
fetch_debug_response.then((debug_response) => {
|
fetch_debug_response.then((debug_response) => {
|
||||||
console.log(debug_response);
|
sill(debug_response);
|
||||||
let ps = {};
|
let ps = {};
|
||||||
let ws = {};
|
let ws = {};
|
||||||
debug_response.elements.forEach((it) => {
|
debug_response.elements.forEach((it) => {
|
||||||
|
@ -154,16 +87,14 @@ export default function handler(req,res){
|
||||||
ws[it.id] = it.nodes;
|
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 = shortest_path(ps, ws, pts[0], pts[pts.length - 1]);
|
||||||
// const path_found = [];
|
|
||||||
// console.log(JSON.stringify(path_found));
|
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
log: `Method: click\nArgs: ${pts}\nStatus: requested "${request_uri}", got response ${JSON.stringify(debug_response.elements)}`,
|
log: `Method: click\nArgs: ${pts}\nStatus: requested "${request_uri}", got response ${JSON.stringify(debug_response.elements)}`,
|
||||||
multipolyline: JSON.stringify(path_found),
|
multipolyline: JSON.stringify(path_found),
|
||||||
// __debug_pts: ps
|
// __debug_pts: ps
|
||||||
});
|
});
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
|
console.debug(e);
|
||||||
res.status(500);
|
res.status(500);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,4 @@
|
||||||
const __DEBUG__=1,
|
import {__APP_VERSION__, __APP_INTRO__} from "../PublicProperty";
|
||||||
__APP_VERSION__='v0.1.3a',
|
|
||||||
__APP_INTRO__=`
|
|
||||||
<b>Right way to follow.</b><br>
|
|
||||||
In this update you can find a shortest route for any given start and destination.<br>
|
|
||||||
`;
|
|
||||||
|
|
||||||
export default function handler(req,res){
|
export default function handler(req,res){
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import {sill} from "./tools/Debug";
|
||||||
|
|
||||||
export function post(type,method,args) {
|
export function post(type,method,args) {
|
||||||
let ft = async () => {
|
let ft = async () => {
|
||||||
let response;
|
let response;
|
||||||
|
@ -13,7 +15,7 @@ export function post(type,method,args) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const response_data = await response.json();
|
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 response_data;
|
||||||
};
|
};
|
||||||
return ft();
|
return ft();
|
||||||
|
|
|
@ -6,6 +6,7 @@ import {post} from './Networking';
|
||||||
import {Autocomplete, CircularProgress, Sheet} from "@mui/joy";
|
import {Autocomplete, CircularProgress, Sheet} from "@mui/joy";
|
||||||
import SimulateClick from "./SimulateClick";
|
import SimulateClick from "./SimulateClick";
|
||||||
import {NearMe} from "@mui/icons-material";
|
import {NearMe} from "@mui/icons-material";
|
||||||
|
import {sill} from "./tools/Debug";
|
||||||
|
|
||||||
const defaultZoomLevel=16;
|
const defaultZoomLevel=16;
|
||||||
const defaultLocationName = 'Apple Park';
|
const defaultLocationName = 'Apple Park';
|
||||||
|
@ -113,7 +114,7 @@ function MapClickHandler({mks,focusUpdater,locator,locker}) {
|
||||||
// response.__debug_pts.forEach(({lat,lon})=>{
|
// response.__debug_pts.forEach(({lat,lon})=>{
|
||||||
// mks.current.addCandMarker(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);
|
if (pl.length > 1) mks.current.flushPolylines(pl);
|
||||||
focusUpdater([lat,lng]);
|
focusUpdater([lat,lng]);
|
||||||
locator([lat,lng]);
|
locator([lat,lng]);
|
||||||
|
@ -215,7 +216,7 @@ export default function UMap() {
|
||||||
const [zoom,setZoom] = useState(defaultZoomLevel);
|
const [zoom,setZoom] = useState(defaultZoomLevel);
|
||||||
const sf = (a) => {
|
const sf = (a) => {
|
||||||
setFocus(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());
|
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'));
|
ft.then((response) => setNearbyName(' ' + response.name)).catch(() => setNearbyName('by'));
|
||||||
};
|
};
|
||||||
|
|
|
@ -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];
|
||||||
|
});
|
|
@ -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);
|
Loading…
Reference in New Issue