added working ALT
This commit is contained in:
parent
7d657b7222
commit
b11eef1cf7
8 changed files with 167 additions and 80 deletions
76
src/alt.rs
76
src/alt.rs
|
|
@ -12,6 +12,11 @@ pub struct Landmark {
|
||||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||||
pub struct LandmarkSet {
|
pub struct LandmarkSet {
|
||||||
pub landmarks: Vec<Landmark>,
|
pub landmarks: Vec<Landmark>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct LandmarkBestSet<'a> {
|
||||||
|
pub landmark_set: &'a LandmarkSet,
|
||||||
pub best_size: usize,
|
pub best_size: usize,
|
||||||
best_landmarks: Vec<usize>,
|
best_landmarks: Vec<usize>,
|
||||||
}
|
}
|
||||||
|
|
@ -24,7 +29,7 @@ impl Landmark {
|
||||||
};
|
};
|
||||||
landmark.node = node;
|
landmark.node = node;
|
||||||
|
|
||||||
#[derive(Eq)]
|
#[derive(Eq, PartialEq)]
|
||||||
struct DijkstraElement {
|
struct DijkstraElement {
|
||||||
index: u32,
|
index: u32,
|
||||||
cost: EdgeCost,
|
cost: EdgeCost,
|
||||||
|
|
@ -44,40 +49,23 @@ impl Landmark {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for DijkstraElement {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.cost == other.cost
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut heap = BinaryHeap::new();
|
let mut heap = BinaryHeap::new();
|
||||||
heap.push(DijkstraElement {
|
heap.push(DijkstraElement {
|
||||||
cost: 0,
|
cost: 0,
|
||||||
index: landmark.node.index,
|
index: landmark.node.index,
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut counter = 0;
|
|
||||||
|
|
||||||
while let Some(DijkstraElement { index, cost }) = heap.pop() {
|
while let Some(DijkstraElement { index, cost }) = heap.pop() {
|
||||||
// the heap does not support "update" operations, so we
|
// the heap does not support "update" operations, so we
|
||||||
// insert elements again and if they come out of the heap but have
|
// insert elements again and if they come out of the heap but have
|
||||||
// been processed earlier we simply skip them.
|
// been processed earlier we simply skip them.
|
||||||
if landmark.distances[index as usize] <= cost {
|
if cost > landmark.distances[index as usize] {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
counter += 1;
|
|
||||||
|
|
||||||
if counter % 1000 == 0 {
|
|
||||||
println!("Finished {} nodes", counter);
|
|
||||||
}
|
|
||||||
|
|
||||||
landmark.distances[index as usize] = cost;
|
landmark.distances[index as usize] = cost;
|
||||||
|
|
||||||
let edge_start = graph.edge_offsets[index as usize] as usize;
|
for edge in graph.get_edges(index as NodeId) {
|
||||||
let edge_end = graph.edge_offsets[(index + 1) as usize] as usize;
|
|
||||||
|
|
||||||
for edge in graph.edges[edge_start..edge_end].iter() {
|
|
||||||
let new_cost = cost + edge.cost;
|
let new_cost = cost + edge.cost;
|
||||||
|
|
||||||
if new_cost < landmark.distances[edge.neighbor as usize] {
|
if new_cost < landmark.distances[edge.neighbor as usize] {
|
||||||
|
|
@ -86,11 +74,11 @@ impl Landmark {
|
||||||
index: edge.neighbor,
|
index: edge.neighbor,
|
||||||
cost: new_cost,
|
cost: new_cost,
|
||||||
});
|
});
|
||||||
|
landmark.distances[edge.neighbor as usize] = new_cost;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// now the costs to all reachable nodes is calculated.
|
||||||
// now the shortest paths to all reachable nodes is calculated.
|
|
||||||
|
|
||||||
landmark
|
landmark
|
||||||
}
|
}
|
||||||
|
|
@ -103,18 +91,28 @@ impl Landmark {
|
||||||
let l_to = self.distances[to];
|
let l_to = self.distances[to];
|
||||||
let l_from = self.distances[from];
|
let l_from = self.distances[from];
|
||||||
|
|
||||||
if l_to == EdgeCost::MAX {
|
if l_to == EdgeCost::MAX || l_from == EdgeCost::MAX {
|
||||||
0
|
EdgeCost::MAX
|
||||||
} else {
|
} else {
|
||||||
l_to.saturating_sub(l_from)
|
// since we are working on an undirected graph we can
|
||||||
|
// use the distances once from and once to the landmark.
|
||||||
|
// This leads to l_to - l_from and l_from - l_to (as signed subtractions)
|
||||||
|
// which except for the sign are the same value.
|
||||||
|
// We can simply take the bigger one, which is handled
|
||||||
|
// nicely the abs() function
|
||||||
|
let distance = (l_to as i64 - l_from as i64).abs() as EdgeCost;
|
||||||
|
//println!(
|
||||||
|
// "distance from {} to {} via landmark {} is at least {}",
|
||||||
|
// from, to, self.node.index, distance
|
||||||
|
//);
|
||||||
|
distance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LandmarkSet {
|
impl LandmarkSet {
|
||||||
pub fn random_set(size: usize, best_size: usize, graph: &GridGraph) -> Self {
|
pub fn random_set(size: usize, graph: &GridGraph) -> Self {
|
||||||
let mut set = LandmarkSet::default();
|
let mut set = LandmarkSet::default();
|
||||||
set.best_size = best_size;
|
|
||||||
|
|
||||||
let nodes = graph.get_random_nodes(size);
|
let nodes = graph.get_random_nodes(size);
|
||||||
|
|
||||||
|
|
@ -125,11 +123,13 @@ impl LandmarkSet {
|
||||||
|
|
||||||
set
|
set
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LandmarkBestSet<'_> {
|
||||||
pub fn select_best(&mut self, from: NodeId, to: NodeId) {
|
pub fn select_best(&mut self, from: NodeId, to: NodeId) {
|
||||||
let mut results = vec![];
|
let mut results = vec![];
|
||||||
|
|
||||||
for (index, landmark) in self.landmarks.iter().enumerate() {
|
for (index, landmark) in self.landmark_set.landmarks.iter().enumerate() {
|
||||||
results.push((index, landmark.estimate(from, to)));
|
results.push((index, landmark.estimate(from, to)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,18 +143,28 @@ impl LandmarkSet {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn estimate(&self, from: NodeId, to: NodeId) -> EdgeCost {
|
pub fn estimate(&self, from: NodeId, to: NodeId) -> EdgeCost {
|
||||||
|
|
||||||
let mut distance = 0;
|
let mut distance = 0;
|
||||||
|
|
||||||
for index in &self.best_landmarks {
|
for index in &self.best_landmarks {
|
||||||
distance = distance.max(self.landmarks[*index].estimate(from, to));
|
let candidate = self.landmark_set.landmarks[*index].estimate(from, to);
|
||||||
};
|
|
||||||
|
|
||||||
if distance == 0 {
|
if candidate == EdgeCost::MAX {
|
||||||
distance = EdgeCost::MAX;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
distance = distance.max(candidate)
|
||||||
|
}
|
||||||
|
|
||||||
|
//println!("calculated estimate {:?} for {} to {}", distance, from, to);
|
||||||
|
|
||||||
distance
|
distance
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new<'a>(best_size: usize, landmark_set: &'a LandmarkSet) -> LandmarkBestSet<'a> {
|
||||||
|
LandmarkBestSet {
|
||||||
|
best_size,
|
||||||
|
landmark_set,
|
||||||
|
best_landmarks: Vec::new(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
59
src/astar.rs
59
src/astar.rs
|
|
@ -4,17 +4,16 @@ use crate::utils::EARTH_RADIUS;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::BinaryHeap;
|
use std::collections::BinaryHeap;
|
||||||
|
|
||||||
pub struct AStar {
|
pub struct AStar<'a> {
|
||||||
pub graph: GridGraph,
|
pub graph: &'a GridGraph,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Eq)]
|
#[derive(Eq, PartialEq)]
|
||||||
struct HeapElement {
|
struct HeapElement {
|
||||||
index: u32,
|
index: u32,
|
||||||
cost: EdgeCost, // the cost so far plus the estimated cost until we reach the
|
cost: EdgeCost, // the cost so far plus the estimated cost until we reach the
|
||||||
// destination
|
// destination
|
||||||
path_cost: EdgeCost, // the cost to reach this node from the start node
|
path_cost: EdgeCost, // the cost to reach this node from the start node
|
||||||
ancestor: Option<u32>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ord for HeapElement {
|
impl Ord for HeapElement {
|
||||||
|
|
@ -31,12 +30,6 @@ impl PartialOrd for HeapElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for HeapElement {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.cost == other.cost
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn estimate_haversine(node: &GraphNode, destination: &GraphNode) -> EdgeCost {
|
pub fn estimate_haversine(node: &GraphNode, destination: &GraphNode) -> EdgeCost {
|
||||||
// simple haversine distance
|
// simple haversine distance
|
||||||
(node.position.distance_to(&destination.position) * EARTH_RADIUS) as EdgeCost
|
(node.position.distance_to(&destination.position) * EARTH_RADIUS) as EdgeCost
|
||||||
|
|
@ -47,26 +40,27 @@ pub fn estimate_haversine(node: &GraphNode, destination: &GraphNode) -> EdgeCost
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn estimate_latitude(node: &GraphNode, destination: &GraphNode) -> EdgeCost {
|
pub fn estimate_latitude(node: &GraphNode, destination: &GraphNode) -> EdgeCost {
|
||||||
let lat_dist_a = (node.position.lat - destination.position.lat).abs();
|
let lat_dist = (node.position.lat - destination.position.lat).abs();
|
||||||
let lat_dist_b = (destination.position.lat - node.position.lat).abs();
|
|
||||||
|
|
||||||
(lat_dist_a.min(lat_dist_b) * EARTH_RADIUS) as EdgeCost
|
(lat_dist * EARTH_RADIUS) as EdgeCost
|
||||||
}
|
}
|
||||||
impl AStar {
|
impl AStar<'_> {
|
||||||
|
|
||||||
pub fn shortest_path<F>(&self, start: &GraphNode, end: &GraphNode, estimate: F) -> Option<Route>
|
pub fn shortest_path<F>(&self, start: &GraphNode, end: &GraphNode, estimate: F) -> Option<Route>
|
||||||
where F: Fn(&GraphNode, &GraphNode) -> EdgeCost {
|
where
|
||||||
|
F: Fn(&GraphNode, &GraphNode) -> EdgeCost,
|
||||||
|
{
|
||||||
let mut heap = BinaryHeap::new();
|
let mut heap = BinaryHeap::new();
|
||||||
heap.push(HeapElement {
|
heap.push(HeapElement {
|
||||||
cost: estimate(start, end),
|
cost: estimate(start, end),
|
||||||
path_cost: 0,
|
path_cost: 0,
|
||||||
index: start.index,
|
index: start.index,
|
||||||
ancestor: None,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut distance = vec![EdgeCost::MAX; self.graph.nodes.len()];
|
let mut distance = vec![EdgeCost::MAX; self.graph.nodes.len()];
|
||||||
let mut ancestor: Vec<Option<u32>> = vec![None; self.graph.nodes.len()];
|
let mut ancestor: Vec<Option<u32>> = vec![None; self.graph.nodes.len()];
|
||||||
|
|
||||||
|
distance[start.index as usize] = 0;
|
||||||
|
|
||||||
let mut popcount = 0;
|
let mut popcount = 0;
|
||||||
|
|
||||||
while let Some(HeapElement {
|
while let Some(HeapElement {
|
||||||
|
|
@ -74,37 +68,44 @@ impl AStar {
|
||||||
cost, // the cost value, no longer needed, because it is only important for the
|
cost, // the cost value, no longer needed, because it is only important for the
|
||||||
// distance estimate
|
// distance estimate
|
||||||
path_cost,
|
path_cost,
|
||||||
ancestor: prev,
|
|
||||||
}) = heap.pop()
|
}) = heap.pop()
|
||||||
{
|
{
|
||||||
|
//println!("working on node {} with cost {} and path cost {}", index, cost, path_cost);
|
||||||
|
|
||||||
|
popcount += 1;
|
||||||
|
|
||||||
// the heap does not support "update" operations, so we
|
// the heap does not support "update" operations, so we
|
||||||
// insert elements again and if they come out of the heap but have
|
// insert elements again and if they come out of the heap but have
|
||||||
// been processed earlier (which implies a shorter distance)
|
// been processed earlier (which implies a shorter distance)
|
||||||
// we simply skip them.
|
// we simply skip them.
|
||||||
if distance[index as usize] <= path_cost {
|
if path_cost > distance[index as usize] {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
popcount += 1;
|
|
||||||
|
|
||||||
distance[index as usize] = path_cost;
|
|
||||||
ancestor[index as usize] = prev;
|
|
||||||
|
|
||||||
if index == end.index {
|
if index == end.index {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for edge in self.graph.get_edges(index as usize).iter() {
|
for edge in self.graph.get_edges(index as usize).iter() {
|
||||||
|
//println!("working on edge {:?}", edge);
|
||||||
let new_cost = path_cost + edge.cost;
|
let new_cost = path_cost + edge.cost;
|
||||||
|
|
||||||
if new_cost < distance[edge.neighbor as usize] {
|
if new_cost < distance[edge.neighbor as usize] {
|
||||||
//println!("adding new element to heap");
|
//println!("adding new element to heap");
|
||||||
|
let remaining_cost = estimate(&self.graph.nodes[edge.neighbor as usize], end);
|
||||||
|
|
||||||
|
// check for unreachable nodes
|
||||||
|
if remaining_cost == EdgeCost::MAX {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
distance[edge.neighbor as usize] = new_cost;
|
||||||
|
ancestor[edge.neighbor as usize] = Some(index);
|
||||||
|
|
||||||
heap.push(HeapElement {
|
heap.push(HeapElement {
|
||||||
index: edge.neighbor,
|
index: edge.neighbor,
|
||||||
cost: new_cost + estimate(&self.graph.nodes[edge.neighbor as usize], end),
|
cost: new_cost + remaining_cost,
|
||||||
path_cost: new_cost,
|
path_cost: new_cost,
|
||||||
ancestor: Some(index),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -122,10 +123,14 @@ impl AStar {
|
||||||
|
|
||||||
let mut current = end.index;
|
let mut current = end.index;
|
||||||
while current != start.index {
|
while current != start.index {
|
||||||
route.nodes.push(self.graph.nodes[current as usize].position);
|
route
|
||||||
|
.nodes
|
||||||
|
.push(self.graph.nodes[current as usize].position);
|
||||||
current = ancestor[current as usize].unwrap();
|
current = ancestor[current as usize].unwrap();
|
||||||
}
|
}
|
||||||
route.nodes.push(self.graph.nodes[current as usize].position);
|
route
|
||||||
|
.nodes
|
||||||
|
.push(self.graph.nodes[current as usize].position);
|
||||||
|
|
||||||
route.nodes.reverse();
|
route.nodes.reverse();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use fapra_osm_2::alt::LandmarkSet;
|
use fapra_osm_2::alt::{LandmarkSet, LandmarkBestSet};
|
||||||
use fapra_osm_2::astar::{estimate_haversine, estimate_latitude, AStar};
|
use fapra_osm_2::astar::{estimate_haversine, estimate_latitude, AStar};
|
||||||
use fapra_osm_2::gridgraph::{GridGraph, NodeId};
|
use fapra_osm_2::gridgraph::{GridGraph, NodeId};
|
||||||
use fapra_osm_2::utils::RoutingQuery;
|
use fapra_osm_2::utils::RoutingQuery;
|
||||||
|
|
@ -77,10 +77,9 @@ fn main() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut landmarks: LandmarkSet = bincode::deserialize_from(BufReader::new(landmarks)).unwrap();
|
let landmarks: LandmarkSet = bincode::deserialize_from(BufReader::new(landmarks)).unwrap();
|
||||||
landmarks.best_size = 4;
|
|
||||||
|
|
||||||
let astar = AStar { graph: *graph };
|
let astar = AStar { graph: &(*graph) };
|
||||||
|
|
||||||
println!("{:?}", args);
|
println!("{:?}", args);
|
||||||
|
|
||||||
|
|
@ -93,7 +92,7 @@ fn main() {
|
||||||
let source = astar.graph.nodes[query.source];
|
let source = astar.graph.nodes[query.source];
|
||||||
let destination = astar.graph.nodes[query.destination];
|
let destination = astar.graph.nodes[query.destination];
|
||||||
|
|
||||||
let _result = astar.shortest_path(&source, &destination, estimate_latitude);
|
let _result = astar.shortest_path(&source, &destination, estimate_haversine);
|
||||||
}
|
}
|
||||||
|
|
||||||
let elapsed = start.elapsed();
|
let elapsed = start.elapsed();
|
||||||
|
|
@ -113,7 +112,7 @@ fn main() {
|
||||||
let source = astar.graph.nodes[query.source];
|
let source = astar.graph.nodes[query.source];
|
||||||
let destination = astar.graph.nodes[query.destination];
|
let destination = astar.graph.nodes[query.destination];
|
||||||
|
|
||||||
let result = astar.graph.shortest_path(&source, &destination);
|
let _result = astar.graph.shortest_path(&source, &destination);
|
||||||
|
|
||||||
//println!("{}", result.unwrap().to_geojson());
|
//println!("{}", result.unwrap().to_geojson());
|
||||||
}
|
}
|
||||||
|
|
@ -126,17 +125,20 @@ fn main() {
|
||||||
|
|
||||||
if args.alt {
|
if args.alt {
|
||||||
println!("running ALT");
|
println!("running ALT");
|
||||||
|
|
||||||
|
let mut best_landmarks = LandmarkBestSet::new(4, &landmarks);
|
||||||
// Landmarks
|
// Landmarks
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
|
|
||||||
for query in targets.iter() {
|
for query in targets.iter() {
|
||||||
|
println!("working on {:?}", query);
|
||||||
let source = astar.graph.nodes[query.source];
|
let source = astar.graph.nodes[query.source];
|
||||||
let destination = astar.graph.nodes[query.destination];
|
let destination = astar.graph.nodes[query.destination];
|
||||||
|
|
||||||
landmarks.select_best(source.index as NodeId, destination.index as NodeId);
|
best_landmarks.select_best(source.index as NodeId, destination.index as NodeId);
|
||||||
|
|
||||||
let _result = astar.shortest_path(&source, &destination, |src, dest| {
|
let _result = astar.shortest_path(&source, &destination, |src, dest| {
|
||||||
landmarks.estimate(src.index as NodeId, dest.index as NodeId)
|
best_landmarks.estimate(src.index as NodeId, dest.index as NodeId)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,14 @@
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use fapra_osm_2::gridgraph::{GridGraph, Route};
|
use fapra_osm_2::gridgraph::{GridGraph, Route, NodeId};
|
||||||
use fapra_osm_2::coordinates::{RadianCoordinate, DegreeCoordinate};
|
use fapra_osm_2::coordinates::{RadianCoordinate, DegreeCoordinate};
|
||||||
|
use fapra_osm_2::astar::{AStar, estimate_haversine};
|
||||||
|
use fapra_osm_2::alt::{LandmarkSet, LandmarkBestSet};
|
||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use std::io::BufReader;
|
||||||
|
use fapra_osm_2::utils::EARTH_RADIUS;
|
||||||
|
|
||||||
use rocket::State;
|
use rocket::State;
|
||||||
use rocket::response::status::BadRequest;
|
use rocket::response::status::BadRequest;
|
||||||
|
|
@ -21,6 +25,10 @@ struct Args {
|
||||||
/// name of the FMI file to read
|
/// name of the FMI file to read
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
filename: String,
|
filename: String,
|
||||||
|
|
||||||
|
/// the landmarks to load
|
||||||
|
#[clap(short, long)]
|
||||||
|
landmarks: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/")]
|
#[get("/")]
|
||||||
|
|
@ -47,6 +55,7 @@ fn random_route(graphwrapper: &State<GraphWrapper>) -> String {
|
||||||
struct RouteQuery<'r> {
|
struct RouteQuery<'r> {
|
||||||
r#from: &'r str,
|
r#from: &'r str,
|
||||||
r#to: &'r str,
|
r#to: &'r str,
|
||||||
|
r#algorithm: &'r str,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -54,6 +63,7 @@ struct RouteQuery<'r> {
|
||||||
pub struct RouteResponse {
|
pub struct RouteResponse {
|
||||||
success: bool,
|
success: bool,
|
||||||
route: Option<Route>,
|
route: Option<Route>,
|
||||||
|
algorithm: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/route", data = "<routequery>")]
|
#[post("/route", data = "<routequery>")]
|
||||||
|
|
@ -71,16 +81,50 @@ fn route(routequery: Form<RouteQuery<'_>>, graphwrapper: &State<GraphWrapper>) -
|
||||||
let from = graphwrapper.graph.get_nearest_node(from).unwrap();
|
let from = graphwrapper.graph.get_nearest_node(from).unwrap();
|
||||||
let to = graphwrapper.graph.get_nearest_node(to).unwrap();
|
let to = graphwrapper.graph.get_nearest_node(to).unwrap();
|
||||||
|
|
||||||
let route = graphwrapper.graph.shortest_path(from, to);
|
println!("working on route from {:?} to {:?}", from, to);
|
||||||
|
let direct_distance = from.position.distance_to(&to.position) * EARTH_RADIUS;
|
||||||
|
println!("haversine distance: {}", direct_distance);
|
||||||
|
let graph_distance = graphwrapper.graph.shortest_path(from, to).unwrap().cost;
|
||||||
|
println!("graph distance is: {}", graph_distance);
|
||||||
|
|
||||||
|
let mut algorithm = routequery.algorithm;
|
||||||
|
|
||||||
|
let route = if algorithm == "astar-haversine" {
|
||||||
|
println!("running A* with haversine distance");
|
||||||
|
let astar = AStar{graph: &graphwrapper.graph};
|
||||||
|
|
||||||
|
astar.shortest_path(from, to, estimate_haversine)
|
||||||
|
} else if algorithm == "alt" {
|
||||||
|
println!("running ALT");
|
||||||
|
|
||||||
|
let mut best_landmarks = LandmarkBestSet::new(4, &graphwrapper.landmarks);
|
||||||
|
|
||||||
|
let astar = AStar{graph: &graphwrapper.graph};
|
||||||
|
best_landmarks.select_best(from.index as usize, to.index as usize);
|
||||||
|
|
||||||
|
println!("initial estimate: {:?}", best_landmarks.estimate(from.index as NodeId, to.index as NodeId));
|
||||||
|
|
||||||
|
astar.shortest_path(from, to, |src, dest| {
|
||||||
|
best_landmarks.estimate(src.index as NodeId, dest.index as NodeId)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
println!("running dijkstra");
|
||||||
|
algorithm = "dijkstra";
|
||||||
|
graphwrapper.graph.shortest_path(from, to)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
println!("from: {:?}, to: {:?}", from, to);
|
println!("from: {:?}, to: {:?}", from, to);
|
||||||
|
|
||||||
let response = RouteResponse{success: route.is_some(), route};
|
let response = RouteResponse{success: route.is_some(), route, algorithm: algorithm.to_string()};
|
||||||
Ok(Json(response))
|
Ok(Json(response))
|
||||||
}
|
}
|
||||||
|
|
||||||
struct GraphWrapper {
|
struct GraphWrapper {
|
||||||
graph: Box<GridGraph>
|
graph: GridGraph,
|
||||||
|
landmarks: LandmarkSet,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[launch]
|
#[launch]
|
||||||
|
|
@ -106,10 +150,21 @@ fn rocket() -> _ {
|
||||||
|
|
||||||
println!("Loaded graph file");
|
println!("Loaded graph file");
|
||||||
|
|
||||||
// let graph = GridGraph::generate_regular_grid(10,10);
|
let landmarks = match File::open(args.landmarks.clone()) {
|
||||||
|
Ok(f) => f,
|
||||||
|
Err(e) => {
|
||||||
|
println!(
|
||||||
|
"Error while opening landmark file {}: {:?}",
|
||||||
|
args.landmarks, e
|
||||||
|
);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let landmarks: LandmarkSet = bincode::deserialize_from(BufReader::new(landmarks)).unwrap();
|
||||||
|
|
||||||
rocket::build()
|
rocket::build()
|
||||||
.manage(GraphWrapper{graph: graph})
|
.manage(GraphWrapper{graph: *graph, landmarks})
|
||||||
.mount("/", routes![index])
|
.mount("/", routes![index])
|
||||||
.mount("/", routes![random_route])
|
.mount("/", routes![random_route])
|
||||||
.mount("/", routes![route])
|
.mount("/", routes![route])
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let set = LandmarkSet::random_set(args.amount, 4, &grid);
|
let set = LandmarkSet::random_set(args.amount, &grid);
|
||||||
|
|
||||||
let encoded = bincode::serialize(&set).unwrap();
|
let encoded = bincode::serialize(&set).unwrap();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -291,7 +291,6 @@ impl GridGraph {
|
||||||
let mut gridgraph = Box::new(GridGraph::default());
|
let mut gridgraph = Box::new(GridGraph::default());
|
||||||
|
|
||||||
let reader = BufReader::new(file);
|
let reader = BufReader::new(file);
|
||||||
|
|
||||||
let lines = reader.lines();
|
let lines = reader.lines();
|
||||||
|
|
||||||
let mut total_node_count: u32 = 0;
|
let mut total_node_count: u32 = 0;
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,11 @@ function set_route_cost(cost) {
|
||||||
field.value = cost;
|
field.value = cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function set_algorithm_type(alg) {
|
||||||
|
let field = document.getElementById("algorithm_used");
|
||||||
|
field.value = alg;
|
||||||
|
}
|
||||||
|
|
||||||
async function get_route() {
|
async function get_route() {
|
||||||
let form = document.getElementById("queryform");
|
let form = document.getElementById("queryform");
|
||||||
data = new FormData(form);
|
data = new FormData(form);
|
||||||
|
|
@ -74,6 +79,7 @@ async function get_route() {
|
||||||
let response = await(fetch("/route", { method: "POST", body: data }));
|
let response = await(fetch("/route", { method: "POST", body: data }));
|
||||||
|
|
||||||
let result = await response.json();
|
let result = await response.json();
|
||||||
|
set_algorithm_type(result.algorithm);
|
||||||
|
|
||||||
if (result.success === true) {
|
if (result.success === true) {
|
||||||
set_route_cost(result.route.cost);
|
set_route_cost(result.route.cost);
|
||||||
|
|
|
||||||
|
|
@ -31,10 +31,20 @@
|
||||||
<input type="text" class="form-control" name="to" id="to">
|
<input type="text" class="form-control" name="to" id="to">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form group">
|
||||||
|
<label for="algorithm">Algorithm</label>
|
||||||
|
<select name="algorithm" id="algorithm" class="form-control">
|
||||||
|
<option value="dijkstra">Dijkstra</option>
|
||||||
|
<option value="astar-haversine">A* with haversine</option>
|
||||||
|
<option value="alt">ALT</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
<button class="btn btn-primary" onclick="get_route()">Submit</button>
|
<button class="btn btn-primary" onclick="get_route()">Submit</button>
|
||||||
<button class="btn btn-primary" onclick="get_random_route()">Random Route</button>
|
<button class="btn btn-primary" onclick="get_random_route()">Random Route</button>
|
||||||
<p>Route Cost: <input class="form-control " type="text" id="routecost" readonly></p>
|
<p>Route Cost: <input class="form-control " type="text" id="routecost" readonly></p>
|
||||||
|
<p>Algorithm: <input class="form-control " type="text" id="algorithm_used" readonly></p>
|
||||||
</div>
|
</div>
|
||||||
<div id="map" class="col-9"></div>
|
<div id="map" class="col-9"></div>
|
||||||
<script type="text/javascript" src="/static/js/script.js"></script>
|
<script type="text/javascript" src="/static/js/script.js"></script>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue