select a path of roads

This commit is contained in:
Dustin Carlino 2020-05-09 10:34:52 -07:00
parent f3b396a7e9
commit db7c276e91
4 changed files with 98 additions and 4 deletions

1
Cargo.lock generated
View File

@ -1006,6 +1006,7 @@ dependencies = [
"kml 0.1.0",
"map_model 0.1.0",
"maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"petgraph 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -23,6 +23,7 @@ instant = "0.1.2"
kml = { path = "../kml" }
maplit = "1.0.2"
map_model = { path = "../map_model" }
petgraph = "0.5.0"
rand = "0.7.0"
rand_xorshift = "0.2.0"
serde = "1.0.98"

View File

@ -1,11 +1,14 @@
use crate::app::{App, ShowEverything};
use crate::common::CommonState;
use crate::game::{State, Transition};
use crate::helpers::ID;
use ezgui::{
hotkey, Btn, Composite, EventCtx, GfxCtx, HorizontalAlignment, Key, Line, Outcome, TextExt,
VerticalAlignment, Widget,
hotkey, Btn, Color, Composite, Drawable, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment, Key,
Line, Outcome, TextExt, VerticalAlignment, Widget,
};
use map_model::IntersectionID;
use geom::Distance;
use map_model::{IntersectionID, Map, RoadID};
use petgraph::graphmap::UnGraphMap;
use sim::DontDrawAgents;
// TODO For now, individual turns can't be manipulated. Banning turns could be useful, but I'm not
@ -13,6 +16,7 @@ use sim::DontDrawAgents;
pub struct BulkSelect {
composite: Composite,
i1: Option<IntersectionID>,
preview_path: Option<(IntersectionID, Vec<RoadID>, Drawable)>,
}
impl BulkSelect {
@ -22,7 +26,9 @@ impl BulkSelect {
composite: Composite::new(
Widget::col(vec![
Line("Edit many roads").small_heading().draw(ctx),
"Click one intersection to start".draw_text(ctx),
"Click one intersection to start"
.draw_text(ctx)
.named("instructions"),
Btn::text_fg("Quit")
.build_def(ctx, hotkey(Key::Escape))
.margin_above(10),
@ -33,6 +39,7 @@ impl BulkSelect {
.aligned(HorizontalAlignment::Center, VerticalAlignment::Top)
.build(ctx),
i1: None,
preview_path: None,
})
}
}
@ -54,6 +61,58 @@ impl State for BulkSelect {
}
}
if let Some(ID::Intersection(i)) = app.primary.current_selection {
if self.i1.is_none() && app.per_obj.left_click(ctx, "start here") {
self.i1 = Some(i);
self.composite.replace(
ctx,
"instructions",
"Click a second intersection to edit this path".draw_text(ctx),
);
}
}
if let Some(i1) = self.i1 {
if let Some(ID::Intersection(i2)) = app.primary.current_selection {
if self
.preview_path
.as_ref()
.map(|(i, _, _)| *i != i2)
.unwrap_or(true)
{
let mut batch = GeomBatch::new();
let roads = if let Some(roads) = pathfind(&app.primary.map, i1, i2) {
for r in &roads {
batch.push(
Color::RED,
app.primary
.map
.get_r(*r)
.get_thick_polygon(&app.primary.map)
.unwrap(),
);
}
roads
} else {
Vec::new()
};
self.preview_path = Some((i2, roads, ctx.upload(batch)));
}
if self
.preview_path
.as_ref()
.map(|(_, roads, _)| !roads.is_empty())
.unwrap_or(false)
&& app.per_obj.left_click(ctx, "end here")
{
println!("do it");
}
} else {
self.preview_path = None;
}
}
match self.composite.event(ctx) {
Some(Outcome::Clicked(x)) => match x.as_ref() {
"Quit" => {
@ -68,5 +127,32 @@ impl State for BulkSelect {
fn draw(&self, g: &mut GfxCtx, app: &App) {
self.composite.draw(g);
if let Some(i) = self.i1 {
g.draw_polygon(Color::GREEN, &app.primary.map.get_i(i).polygon);
}
if let Some((_, _, ref p)) = self.preview_path {
g.redraw(p);
}
CommonState::draw_osd(g, app, &None);
}
}
// Simple search along undirected roads
fn pathfind(map: &Map, i1: IntersectionID, i2: IntersectionID) -> Option<Vec<RoadID>> {
let mut graph: UnGraphMap<IntersectionID, RoadID> = UnGraphMap::new();
for r in map.all_roads() {
graph.add_edge(r.src_i, r.dst_i, r.id);
}
let (_, path) = petgraph::algo::astar(
&graph,
i1,
|i| i == i2,
|(_, _, r)| map.get_r(*r).center_pts.length(),
|_| Distance::ZERO,
)?;
Some(
path.windows(2)
.map(|pair| *graph.edge_weight(pair[0], pair[1]).unwrap())
.collect(),
)
}

View File

@ -168,3 +168,9 @@ impl std::iter::Sum for Distance {
sum
}
}
impl Default for Distance {
fn default() -> Distance {
Distance::ZERO
}
}