feat: switch to obvious-a-star and support concatenations
This commit is contained in:
parent
6c4923bf54
commit
f43fdb52f3
|
@ -6,10 +6,6 @@
|
||||||
<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 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$/PublicProperty.js" beforeDir="false" afterPath="$PROJECT_DIR$/PublicProperty.js" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/api/click.js" beforeDir="false" afterPath="$PROJECT_DIR$/api/click.js" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/tools/PathBench.js" beforeDir="false" afterPath="$PROJECT_DIR$/tools/PathBench.js" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/tools/ShortestPath.js" beforeDir="false" afterPath="$PROJECT_DIR$/tools/ShortestPath.js" afterDir="false" />
|
|
||||||
</list>
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
|
@ -92,7 +88,7 @@
|
||||||
<workItem from="1702448962541" duration="5620000" />
|
<workItem from="1702448962541" duration="5620000" />
|
||||||
<workItem from="1703419885970" duration="13073000" />
|
<workItem from="1703419885970" duration="13073000" />
|
||||||
<workItem from="1703582457934" duration="210000" />
|
<workItem from="1703582457934" duration="210000" />
|
||||||
<workItem from="1703642799206" duration="20649000" />
|
<workItem from="1703642799206" duration="22143000" />
|
||||||
</task>
|
</task>
|
||||||
<servers />
|
<servers />
|
||||||
</component>
|
</component>
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
// no dependencies
|
// no dependencies
|
||||||
|
|
||||||
export const __DEBUG__ = 1;
|
export const __DEBUG__ = 1;
|
||||||
export const __APP_VERSION__ = 'v0.2.0a';
|
export const __APP_VERSION__ = 'v0.3.0a';
|
||||||
|
|
||||||
export const __APP_INTRO__ = `
|
export const __APP_INTRO__ = `
|
||||||
<b>Algorithm improvement.</b><br>
|
<b>Algorithm improvement.</b><br>
|
||||||
We are introducing a new pre-processing method called Obvious in this version.<br>
|
Our new routing solution is based on the Obvious A-Star algorithm now, with 2~10x faster speed in calculations.<br>
|
||||||
|
<b>Support concatenating paths.</b><br>
|
||||||
|
You can add points sequentially on the map.<br>
|
||||||
`;
|
`;
|
|
@ -1,9 +1,9 @@
|
||||||
import {dijkstra, haversine_distance, obvious_dijkstra} from "../tools/ShortestPath";
|
import {dijkstra, haversine_distance, obvious_dijkstra, obvious_a_star} from "../tools/ShortestPath";
|
||||||
import {sill, sill_unwrap, noexcept} from "../tools/Debug";
|
import {sill, sill_unwrap, noexcept} from "../tools/Debug";
|
||||||
import {get_row} from "../tools/Misc";
|
import {get_row} from "../tools/Misc";
|
||||||
import benchmark from "../tools/PathBench";
|
import benchmark from "../tools/PathBench";
|
||||||
|
|
||||||
const __spa = obvious_dijkstra;
|
const __spa = obvious_a_star;
|
||||||
|
|
||||||
function find_nearest_node_id(nodes, point) {
|
function find_nearest_node_id(nodes, point) {
|
||||||
const [lat, lon] = point;
|
const [lat, lon] = point;
|
||||||
|
|
10
src/UMap.js
10
src/UMap.js
|
@ -39,7 +39,7 @@ class Markers extends Component {
|
||||||
markers: [...prev.markers, [lat, lng]],
|
markers: [...prev.markers, [lat, lng]],
|
||||||
candMarkers: prev.candMarkers,
|
candMarkers: prev.candMarkers,
|
||||||
candEmpty: prev.candEmpty,
|
candEmpty: prev.candEmpty,
|
||||||
polylines: [], // automatically clear polylines when marker changes
|
polylines: prev.polylines,
|
||||||
}));
|
}));
|
||||||
this.getFocus();
|
this.getFocus();
|
||||||
}
|
}
|
||||||
|
@ -89,12 +89,12 @@ class Markers extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
flushPolylines(pl) {
|
flushPolylines(pl, clear=true) {
|
||||||
this.setState((prev) => ({
|
this.setState((prev) => ({
|
||||||
markers: prev.markers,
|
markers: prev.markers,
|
||||||
candMarkers: prev.candMarkers,
|
candMarkers: prev.candMarkers,
|
||||||
candEmpty: prev.candEmpty,
|
candEmpty: prev.candEmpty,
|
||||||
polylines: pl,
|
polylines: clear ? pl : [...pl, ...prev.polylines], // mind the ordering
|
||||||
}));
|
}));
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,7 @@ function MapClickHandler({mks,focusUpdater,locator,locker}) {
|
||||||
const {lat,lng}=e.latlng;
|
const {lat,lng}=e.latlng;
|
||||||
console.info(`Clicking on ${lat} ${lng}`);
|
console.info(`Clicking on ${lat} ${lng}`);
|
||||||
mks.current.addMarker(lat, lng);
|
mks.current.addMarker(lat, lng);
|
||||||
post('POST', 'click', mks.current.state.markers).then((response) => {
|
post('POST', 'click', mks.current.state.markers.slice(-2)).then((response) => {
|
||||||
// TODO: real functionality
|
// TODO: real functionality
|
||||||
const pl = JSON.parse(response.multipolyline);
|
const pl = JSON.parse(response.multipolyline);
|
||||||
// DEBUG
|
// DEBUG
|
||||||
|
@ -115,7 +115,7 @@ function MapClickHandler({mks,focusUpdater,locator,locker}) {
|
||||||
// mks.current.addCandMarker(lat,lon);
|
// mks.current.addCandMarker(lat,lon);
|
||||||
// });
|
// });
|
||||||
sill(`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, false);
|
||||||
focusUpdater([lat,lng]);
|
focusUpdater([lat,lng]);
|
||||||
locator([lat,lng]);
|
locator([lat,lng]);
|
||||||
locker(true);
|
locker(true);
|
||||||
|
|
|
@ -5,15 +5,25 @@ import {get_row} from "./Misc";
|
||||||
export default function benchmark(nodes, clean_nodes, ways, location, ch_dict, ch_dict_bench, count, aff, actual_start_node_id, actual_end_node_id) {
|
export default function benchmark(nodes, clean_nodes, ways, location, ch_dict, ch_dict_bench, count, aff, actual_start_node_id, actual_end_node_id) {
|
||||||
sill(`==========PathBench==========`);
|
sill(`==========PathBench==========`);
|
||||||
let start_time, end_time;
|
let start_time, end_time;
|
||||||
let res;
|
let res, _;
|
||||||
//benchmark Obvious-Dijkstra
|
//benchmark Obvious-Dijkstra
|
||||||
start_time = performance.now();
|
start_time = performance.now();
|
||||||
res = SP.obvious_dijkstra(clean_nodes, ways, location, ch_dict, count, aff, actual_start_node_id, actual_end_node_id);
|
res = SP.obvious_dijkstra(clean_nodes, ways, location, ch_dict, count, aff, actual_start_node_id, actual_end_node_id);
|
||||||
end_time = performance.now();
|
end_time = performance.now();
|
||||||
sill(`Obvious-Dijkstra run-time: ${end_time - start_time} ms`);
|
sill(`Obvious-Dijkstra run-time: ${end_time - start_time} ms`);
|
||||||
|
// benchmark Obvious-A-Star
|
||||||
|
start_time = performance.now();
|
||||||
|
res = SP.obvious_a_star(clean_nodes, ways, location, ch_dict, count, aff, actual_start_node_id, actual_end_node_id);
|
||||||
|
end_time = performance.now();
|
||||||
|
sill(`Obvious-A-Star run-time: ${end_time - start_time} ms`);
|
||||||
|
// benchmark Obvious-Adaptive-A-Star
|
||||||
|
start_time = performance.now();
|
||||||
|
_ = SP.obvious_a_star(clean_nodes, ways, location, ch_dict, count, aff, actual_start_node_id, actual_end_node_id, true);
|
||||||
|
end_time = performance.now();
|
||||||
|
sill(`Obvious-Adaptive-A-Star run-time: ${end_time - start_time} ms`);
|
||||||
// benchmark Dijkstra
|
// benchmark Dijkstra
|
||||||
start_time = performance.now();
|
start_time = performance.now();
|
||||||
const _ = SP.dijkstra(nodes, ways, location, ch_dict_bench, count, aff, actual_start_node_id, actual_end_node_id);
|
res = SP.dijkstra(nodes, ways, location, ch_dict_bench, count, aff, actual_start_node_id, actual_end_node_id);
|
||||||
end_time = performance.now();
|
end_time = performance.now();
|
||||||
sill(`Dijkstra run-time: ${end_time - start_time} ms`);
|
sill(`Dijkstra run-time: ${end_time - start_time} ms`);
|
||||||
sill(`==============================`);
|
sill(`==============================`);
|
||||||
|
|
|
@ -64,7 +64,7 @@ function __dijkstra(nodes, ways, loc, ch, count, aff, u, p) {
|
||||||
while (fa[curr]) {
|
while (fa[curr]) {
|
||||||
curr = fa[curr].toString();
|
curr = fa[curr].toString();
|
||||||
if (vis.has(curr)) {
|
if (vis.has(curr)) {
|
||||||
sill(`Cycle at ${curr}`);
|
// sill(`Cycle at ${curr}`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
vis.add(curr);
|
vis.add(curr);
|
||||||
|
@ -125,7 +125,98 @@ function __obvious_dijkstra(nodes, ways, loc, ch, count, aff, u, p) {
|
||||||
const prev = curr;
|
const prev = curr;
|
||||||
curr = fa[curr];
|
curr = fa[curr];
|
||||||
if (vis.has(curr)) {
|
if (vis.has(curr)) {
|
||||||
sill(`Cycle at ${curr}`);
|
// sill(`Cycle at ${curr}`);
|
||||||
|
// sill(res);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
vis.set(curr,true);
|
||||||
|
|
||||||
|
// res.push(curr);
|
||||||
|
const way_id = find_common(aff[prev], aff[curr]);
|
||||||
|
const way = ways[way_id];
|
||||||
|
if(!way) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const p_oc = loc[prev][way_id];
|
||||||
|
const c_oc = loc[curr][way_id];
|
||||||
|
if (p_oc < c_oc) {
|
||||||
|
for (let _p = p_oc + 1; _p <= c_oc; ++_p) {
|
||||||
|
res.push(way[_p]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (let _p = p_oc - 1; _p >= c_oc; --_p) {
|
||||||
|
res.push(way[_p]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// sill("finished Obvious Dijkstra.");
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use A-star algorithm with Obvious optimization to find the shortest path.
|
||||||
|
* @param nodes node index list
|
||||||
|
* @param ways node list for each way
|
||||||
|
* @param loc relative location in the way
|
||||||
|
* @param ch adjacent table
|
||||||
|
* @param count determine isolated nodes
|
||||||
|
* @param aff affiliation of isolated nodes
|
||||||
|
* @param u start node id
|
||||||
|
* @param p destination node id
|
||||||
|
* @param adaptive if the coefficient is hard-coded
|
||||||
|
*/
|
||||||
|
function __obvious_a_star(nodes, ways, loc, ch, count, aff, u, p, adaptive = false) {
|
||||||
|
// sill(`node count: ${Object.keys(nodes).length}`);
|
||||||
|
const default_coefficient = 1.1;
|
||||||
|
const linear = (y) => y;
|
||||||
|
const curve = (y) => 0.8 * y * y;
|
||||||
|
const inversed_sigmoid = (y) => Math.log(y/(1.0-y));
|
||||||
|
const heuristic = (current_distance, node_id) => {
|
||||||
|
const estimate = haversine_distance(nodes[node_id], nodes[p]);
|
||||||
|
const coef = (!adaptive) ? default_coefficient : (
|
||||||
|
default_coefficient * curve(current_distance / (current_distance + estimate))
|
||||||
|
);
|
||||||
|
return coef * estimate;
|
||||||
|
};
|
||||||
|
const dis = {};
|
||||||
|
const fa = {};
|
||||||
|
const vis = new Map();
|
||||||
|
const pq = new MinPriorityQueue();
|
||||||
|
dis[u] = 0;
|
||||||
|
pq.push([0, 0, u]);
|
||||||
|
while (!pq.isEmpty()) {
|
||||||
|
const [_, d, v] = pq.pop();
|
||||||
|
if (vis.has(v) || !ch[v]) {
|
||||||
|
// sill(!ch[v]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (v === p) {
|
||||||
|
// sill('break');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// sill('loop');
|
||||||
|
vis.set(v,true);
|
||||||
|
const t = ch[v].length;
|
||||||
|
for (let j = 0; j < t; ++j) {
|
||||||
|
const [c, w] = ch[v][j];
|
||||||
|
if (!nodes[c]) continue;
|
||||||
|
// sill(w);
|
||||||
|
if ((!dis[c] || d + w < dis[c])) {
|
||||||
|
dis[c] = d + w;
|
||||||
|
pq.push([dis[c] + heuristic(dis[c], c), dis[c], c]);
|
||||||
|
fa[c] = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// sill_unwrap(fa);
|
||||||
|
let curr = p;
|
||||||
|
const res = [p];
|
||||||
|
vis.clear();
|
||||||
|
while (fa[curr]) {
|
||||||
|
const prev = curr;
|
||||||
|
curr = fa[curr];
|
||||||
|
if (vis.has(curr)) {
|
||||||
|
// sill(`Cycle at ${curr}`);
|
||||||
// sill(res);
|
// sill(res);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -155,4 +246,5 @@ function __obvious_dijkstra(nodes, ways, loc, ch, count, aff, u, p) {
|
||||||
|
|
||||||
export const haversine_distance = noexcept(__haversine_distance);
|
export const haversine_distance = noexcept(__haversine_distance);
|
||||||
export const dijkstra = noexcept(__dijkstra);
|
export const dijkstra = noexcept(__dijkstra);
|
||||||
export const obvious_dijkstra = noexcept(__obvious_dijkstra);
|
export const obvious_dijkstra = noexcept(__obvious_dijkstra);
|
||||||
|
export const obvious_a_star = noexcept(__obvious_a_star);
|
Loading…
Reference in New Issue