Skip to content

Commit

Permalink
Switch to fast_paths for shortcuts. 9s to 50ms, as usual :)
Browse files Browse the repository at this point in the history
  • Loading branch information
dabreegster committed Dec 20, 2023
1 parent 3e7c64e commit d705d7a
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 45 deletions.
46 changes: 17 additions & 29 deletions backend/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ crate-type = ["cdylib", "rlib"]
anyhow = "1.0.75"
console_error_panic_hook = "0.1.6"
console_log = "1.0.0"
fast_paths = { git = "https://github.com/easbar/fast_paths" }
geo = "0.27.0"
geojson = { git = "https://github.com/georust/geojson", features = ["geo-types"] }
log = "0.4.20"
Expand All @@ -22,5 +23,4 @@ serde-wasm-bindgen = "0.6.0"
wasm-bindgen = "0.2.87"
web-sys = { version = "0.3.64", features = ["console"] }
bincode = "1.3.3"
petgraph = "0.6.4"
contour = "0.12.0"
4 changes: 3 additions & 1 deletion backend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use std::sync::Once;

use geo::{EuclideanLength, LineString, Point, Polygon};
use geojson::{Feature, GeoJson, Geometry};
use serde::Serialize;
use wasm_bindgen::prelude::*;

use self::cells::Cell;
Expand All @@ -18,6 +19,7 @@ use self::shortcuts::Shortcuts;
mod cells;
mod mercator;
mod neighbourhood;
mod node_map;
mod render_cells;
mod scrape;
mod shortcuts;
Expand Down Expand Up @@ -45,7 +47,7 @@ impl MapModel {

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct RoadID(pub usize);
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub struct IntersectionID(pub usize);

impl fmt::Display for RoadID {
Expand Down
72 changes: 72 additions & 0 deletions backend/src/node_map.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
//! Some helpers for working with fast_paths, adapted from A/B Street
use std::collections::BTreeMap;
use std::fmt::Debug;

use fast_paths::NodeId;
use serde::{Deserialize, Deserializer, Serialize};

/// A bidirectional mapping between fast_paths NodeId and some custom ID type.
#[derive(Clone, Serialize)]
pub struct NodeMap<T: Copy + Ord + Debug + Serialize> {
// These two fields are redundant and large, so don't serialize the bigger one, to cut down
// file size.
#[serde(skip_serializing)]
node_to_id: BTreeMap<T, NodeId>,
id_to_node: Vec<T>,
}

impl<T: Copy + Ord + Debug + Serialize> NodeMap<T> {
pub fn new() -> NodeMap<T> {
NodeMap {
node_to_id: BTreeMap::new(),
id_to_node: Vec::new(),
}
}

pub fn get_or_insert(&mut self, node: T) -> NodeId {
if let Some(id) = self.node_to_id.get(&node) {
return *id;
}
let id = self.id_to_node.len();
self.node_to_id.insert(node, id);
self.id_to_node.push(node);
id
}

pub fn get(&self, node: T) -> Option<NodeId> {
self.node_to_id.get(&node).cloned()
}

pub fn translate_id(&self, id: usize) -> T {
self.id_to_node[id]
}
}

// A serialized NodeMap has this form in JSON. Use this to deserialize.
#[derive(Deserialize)]
struct InnerNodeMap<T: Copy + Ord + Debug> {
#[allow(dead_code)]
id_to_node: Vec<T>,
}

#[allow(dead_code)]
pub fn deserialize_nodemap<
'de,
D: Deserializer<'de>,
T: Deserialize<'de> + Copy + Ord + Debug + Serialize,
>(
d: D,
) -> Result<NodeMap<T>, D::Error> {
let inner = <InnerNodeMap<T>>::deserialize(d)?;
let id_to_node = inner.id_to_node;
let mut node_to_id = BTreeMap::new();
for (id, node) in id_to_node.iter().enumerate() {
node_to_id.insert(*node, id);
}

Ok(NodeMap {
node_to_id,
id_to_node,
})
}
35 changes: 21 additions & 14 deletions backend/src/shortcuts.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::collections::HashMap;

use petgraph::graphmap::DiGraphMap;
use fast_paths::InputGraph;

use crate::node_map::NodeMap;
use crate::{MapModel, Neighbourhood, RoadID};

pub struct Shortcuts {
Expand All @@ -10,27 +11,33 @@ pub struct Shortcuts {

impl Shortcuts {
pub fn new(map: &MapModel, neighbourhood: &Neighbourhood) -> Self {
let mut graph = DiGraphMap::new();
let mut input_graph = InputGraph::new();
let mut node_map = NodeMap::new();

for r in &neighbourhood.interior_roads {
let road = map.get_r(*r);
graph.add_edge(road.src_i, road.dst_i, (road.id, road.length()));
let i1 = node_map.get_or_insert(road.src_i);
let i2 = node_map.get_or_insert(road.dst_i);
let cost = (road.length() * 100.0) as usize;
// TODO Look at one-way for driving
graph.add_edge(road.dst_i, road.src_i, (road.id, road.length()));
input_graph.add_edge(i1, i2, cost);
input_graph.add_edge(i2, i1, cost);
}
input_graph.freeze();
let ch = fast_paths::prepare(&input_graph);
let mut path_calc = fast_paths::create_calculator(&ch);

let mut count_per_road = HashMap::new();
for start in &neighbourhood.border_intersections {
for end in &neighbourhood.border_intersections {
if let Some((_, path)) = petgraph::algo::astar(
&graph,
*start,
|i| i == *end,
|(_, _, (_, dist))| *dist,
|_| 0.0,
) {
for pair in path.windows(2) {
let (r, _) = *graph.edge_weight(pair[0], pair[1]).unwrap();
*count_per_road.entry(r).or_insert(0) += 1;
if let (Some(i1), Some(i2)) = (node_map.get(*start), node_map.get(*end)) {
if let Some(path) = path_calc.calc_path(&ch, i1, i2) {
for pair in path.get_nodes().windows(2) {
let i1 = node_map.translate_id(pair[0]);
let i2 = node_map.translate_id(pair[1]);
let road = map.find_edge(i1, i2);
*count_per_road.entry(road.id).or_insert(0) += 1;
}
}
}
}
Expand Down

0 comments on commit d705d7a

Please sign in to comment.