From ba310cbd457a87ef7328b6f9b29fd49c55048f24 Mon Sep 17 00:00:00 2001 From: Dustin Carlino Date: Mon, 25 Jun 2018 08:50:42 -0700 Subject: [PATCH] removing geom crate, using just map model --- Cargo.toml | 2 +- control/Cargo.toml | 1 - control/src/lib.rs | 6 +- control/src/stop_signs.rs | 11 +- control/src/traffic_signals.rs | 21 +- docs/lanes.md | 4 + editor/Cargo.toml | 1 - editor/src/main.rs | 1 - editor/src/plugins/selection.rs | 18 +- editor/src/plugins/sim_controls.rs | 17 +- editor/src/plugins/stop_sign_editor.rs | 18 +- editor/src/plugins/traffic_signal_editor.rs | 8 +- editor/src/render/building.rs | 30 +-- editor/src/render/intersection.rs | 2 +- editor/src/render/map.rs | 15 +- editor/src/render/mod.rs | 4 +- editor/src/render/parcel.rs | 2 +- editor/src/render/road.rs | 27 +- editor/src/render/turn.rs | 14 +- editor/src/ui.rs | 44 +--- geom/Cargo.toml | 11 - geom/src/geometry.rs | 278 -------------------- geom/src/lib.rs | 24 -- geom/src/map.rs | 39 --- geom/src/road.rs | 116 -------- geom/src/turn.rs | 66 ----- headless/Cargo.toml | 1 - headless/src/main.rs | 8 +- map_model/src/lib.rs | 3 +- sim/Cargo.toml | 1 - sim/src/lib.rs | 1 - sim/src/straw_intersections.rs | 33 ++- sim/src/straw_model.rs | 66 +++-- sim/tests/determinism.rs | 25 +- 34 files changed, 153 insertions(+), 765 deletions(-) delete mode 100644 geom/Cargo.toml delete mode 100644 geom/src/geometry.rs delete mode 100644 geom/src/lib.rs delete mode 100644 geom/src/map.rs delete mode 100644 geom/src/road.rs delete mode 100644 geom/src/turn.rs diff --git a/Cargo.toml b/Cargo.toml index 8dc839f029..2730645563 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,3 @@ [workspace] -members = ["abstutil", "control", "convert_osm", "editor", "ezgui", "geom", "headless", "kml", "map_model", "sim"] +members = ["abstutil", "control", "convert_osm", "editor", "ezgui", "headless", "kml", "map_model", "sim"] diff --git a/control/Cargo.toml b/control/Cargo.toml index 9e7e7ad2b8..6d0be171fe 100644 --- a/control/Cargo.toml +++ b/control/Cargo.toml @@ -5,7 +5,6 @@ authors = ["Dustin Carlino "] [dependencies] dimensioned = "0.6.0" -geom = { path = "../geom" } map_model = { path = "../map_model" } serde = "1.0" serde_derive = "1.0" diff --git a/control/src/lib.rs b/control/src/lib.rs index b10deb8dec..d42f6890c1 100644 --- a/control/src/lib.rs +++ b/control/src/lib.rs @@ -1,12 +1,10 @@ // Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0 extern crate dimensioned; -extern crate geom; extern crate map_model; #[macro_use] extern crate serde_derive; -use geom::GeomMap; use map_model::{IntersectionID, Map, TurnID}; use std::collections::HashMap; use stop_signs::{ControlStopSign, TurnPriority}; @@ -22,7 +20,7 @@ pub struct ControlMap { } impl ControlMap { - pub fn new(map: &Map, geom_map: &GeomMap) -> ControlMap { + pub fn new(map: &Map) -> ControlMap { let mut ctrl = ControlMap { traffic_signals: HashMap::new(), stop_signs: HashMap::new(), @@ -31,7 +29,7 @@ impl ControlMap { for i in map.all_intersections() { if i.has_traffic_signal { ctrl.traffic_signals - .insert(i.id, ControlTrafficSignal::new(map, i.id, &geom_map)); + .insert(i.id, ControlTrafficSignal::new(map, i.id)); } else { ctrl.stop_signs .insert(i.id, ControlStopSign::new(map, i.id)); diff --git a/control/src/stop_signs.rs b/control/src/stop_signs.rs index 57648ccfac..52561a90e4 100644 --- a/control/src/stop_signs.rs +++ b/control/src/stop_signs.rs @@ -2,7 +2,6 @@ use ModifiedStopSign; -use geom::GeomMap; use map_model::{IntersectionID, Map, TurnID}; use std::collections::HashMap; @@ -50,19 +49,17 @@ impl ControlStopSign { self.turns[&turn] } - pub fn set_priority(&mut self, turn: TurnID, priority: TurnPriority, geom_map: &GeomMap) { + pub fn set_priority(&mut self, turn: TurnID, priority: TurnPriority, map: &Map) { if priority == TurnPriority::Priority { - assert!(self.could_be_priority_turn(turn, geom_map)); + assert!(self.could_be_priority_turn(turn, map)); } self.turns.insert(turn, priority); self.changed = true; } - pub fn could_be_priority_turn(&self, id: TurnID, geom_map: &GeomMap) -> bool { + pub fn could_be_priority_turn(&self, id: TurnID, map: &Map) -> bool { for (t, pri) in &self.turns { - if *pri == TurnPriority::Priority - && geom_map.get_t(id).conflicts_with(geom_map.get_t(*t)) - { + if *pri == TurnPriority::Priority && map.get_t(id).conflicts_with(map.get_t(*t)) { return false; } } diff --git a/control/src/traffic_signals.rs b/control/src/traffic_signals.rs index 93ee998f7e..4f770254e6 100644 --- a/control/src/traffic_signals.rs +++ b/control/src/traffic_signals.rs @@ -4,7 +4,6 @@ use CycleState; use ModifiedTrafficSignal; use dimensioned::si; -use geom::GeomMap; use map_model::{IntersectionID, Map, TurnID}; use std; @@ -20,15 +19,11 @@ pub struct ControlTrafficSignal { } impl ControlTrafficSignal { - pub fn new( - map: &Map, - intersection: IntersectionID, - geom_map: &GeomMap, - ) -> ControlTrafficSignal { + pub fn new(map: &Map, intersection: IntersectionID) -> ControlTrafficSignal { assert!(map.get_i(intersection).has_traffic_signal); ControlTrafficSignal { intersection, - cycles: ControlTrafficSignal::greedy_assignment(map, intersection, geom_map), + cycles: ControlTrafficSignal::greedy_assignment(map, intersection), } } @@ -73,11 +68,7 @@ impl ControlTrafficSignal { (cycle, remaining_cycle_time) } - fn greedy_assignment( - map: &Map, - intersection: IntersectionID, - geom_map: &GeomMap, - ) -> Vec { + fn greedy_assignment(map: &Map, intersection: IntersectionID) -> Vec { let mut cycles = Vec::new(); // Greedily partition turns into cycles. More clever things later. @@ -93,7 +84,7 @@ impl ControlTrafficSignal { while !remaining_turns.is_empty() { let add_turn = remaining_turns .iter() - .position(|&t| !current_cycle.conflicts_with(t, geom_map)); + .position(|&t| !current_cycle.conflicts_with(t, map)); match add_turn { Some(idx) => { current_cycle.turns.push(remaining_turns[idx]); @@ -125,9 +116,9 @@ pub struct Cycle { } impl Cycle { - pub fn conflicts_with(&self, t1: TurnID, geom_map: &GeomMap) -> bool { + pub fn conflicts_with(&self, t1: TurnID, map: &Map) -> bool { for t2 in &self.turns { - if geom_map.get_t(t1).conflicts_with(geom_map.get_t(*t2)) { + if map.get_t(t1).conflicts_with(map.get_t(*t2)) { return true; } } diff --git a/docs/lanes.md b/docs/lanes.md index 6ca9c74883..6854276eff 100644 --- a/docs/lanes.md +++ b/docs/lanes.md @@ -94,6 +94,10 @@ wait slow down even more -- before any of this change, lanes on adjacent roads s - FIRST: move geom things into the Map structs directly. get rid of that crate. ---> option 1: module per object type, geometry and graph squished together - option 2: try to separate the graph/geom stuff within map model. + - CLEANUP: no more 'extern crate' in non lib + - CLEANUP: bldg front path should happen upfront, not in render + - CLEANUP: gps to screen in map upfront, dont plumb along gps pts for bldg/parcel/etc, so bounds should become private. + - THEN: express the proto -> runtime map loading as a sequence of phases - keep doing the current road trimming for the moment - later, this could be the same as the OSM conversion. just diff --git a/editor/Cargo.toml b/editor/Cargo.toml index 5294fe613e..cf00d24d3f 100644 --- a/editor/Cargo.toml +++ b/editor/Cargo.toml @@ -8,7 +8,6 @@ aabb-quadtree = "0.1.0" abstutil = { path = "../abstutil" } control = { path = "../control" } geo = "0.9.1" -geom = { path = "../geom" } ezgui = { path = "../ezgui" } map_model = { path = "../map_model" } multimap = "0.4.0" diff --git a/editor/src/main.rs b/editor/src/main.rs index 4d70600567..47b01223de 100644 --- a/editor/src/main.rs +++ b/editor/src/main.rs @@ -5,7 +5,6 @@ extern crate abstutil; extern crate control; extern crate ezgui; extern crate geo; -extern crate geom; extern crate glutin_window; extern crate graphics; extern crate map_model; diff --git a/editor/src/plugins/selection.rs b/editor/src/plugins/selection.rs index d6f9b4ca0a..0a44def442 100644 --- a/editor/src/plugins/selection.rs +++ b/editor/src/plugins/selection.rs @@ -6,7 +6,6 @@ use control::ControlMap; use ezgui::GfxCtx; use ezgui::canvas::Canvas; use ezgui::input::UserInput; -use geom; use graphics::types::Color; use map_model; use map_model::{BuildingID, IntersectionID, Map, RoadID, TurnID}; @@ -137,7 +136,6 @@ impl SelectionState { &self, map: &Map, canvas: &Canvas, - geom_map: &geom::GeomMap, draw_map: &render::DrawMap, control_map: &ControlMap, sim: &Sim, @@ -160,14 +158,14 @@ impl SelectionState { let relevant_turns = map.get_turns_from_road(id); match current_turn_index { Some(idx) => { - let turn = draw_map.get_t(relevant_turns[idx % relevant_turns.len()].id); - let geom_turn = - geom_map.get_t(relevant_turns[idx % relevant_turns.len()].id); - turn.draw_full(g, cs.get(Colors::Turn)); + let turn = map.get_t(relevant_turns[idx % relevant_turns.len()].id); + let draw_turn = + draw_map.get_t(relevant_turns[idx % relevant_turns.len()].id); + draw_turn.draw_full(g, cs.get(Colors::Turn)); for map_t in all_turns { + let t = map.get_t(map_t.id); let draw_t = draw_map.get_t(map_t.id); - let geom_t = geom_map.get_t(map_t.id); - if geom_t.conflicts_with(geom_turn) { + if t.conflicts_with(turn) { // TODO should we instead change color_t? draw_t.draw_icon(g, cs.get(Colors::ConflictingTurn), cs); } @@ -178,10 +176,10 @@ impl SelectionState { }, } // TODO tmp - draw_map.get_r(id).draw_debug(g, cs, geom_map.get_r(id)); + draw_map.get_r(id).draw_debug(g, cs, map.get_r(id)); } SelectionState::TooltipRoad(id) => { - canvas.draw_mouse_tooltip(g, &draw_map.get_r(id).tooltip_lines(map, geom_map)); + canvas.draw_mouse_tooltip(g, &draw_map.get_r(id).tooltip_lines(map)); } SelectionState::SelectedBuilding(id) => { canvas.draw_mouse_tooltip(g, &draw_map.get_b(id).tooltip_lines(map)); diff --git a/editor/src/plugins/sim_controls.rs b/editor/src/plugins/sim_controls.rs index 723de704f8..c618c6ec8d 100644 --- a/editor/src/plugins/sim_controls.rs +++ b/editor/src/plugins/sim_controls.rs @@ -3,7 +3,6 @@ use abstutil; use control::ControlMap; use ezgui::input::UserInput; -use geom::GeomMap; use map_model::Map; use piston::input::{Key, UpdateEvent}; use sim::common; @@ -22,9 +21,9 @@ pub struct SimController { } impl SimController { - pub fn new(map: &Map, geom_map: &GeomMap, rng_seed: Option) -> SimController { + pub fn new(map: &Map, rng_seed: Option) -> SimController { SimController { - sim: straw_model::Sim::new(map, geom_map, rng_seed), + sim: straw_model::Sim::new(map, rng_seed), desired_speed: 1.0, last_step: None, benchmark: None, @@ -33,13 +32,7 @@ impl SimController { } // true if the sim is running - pub fn event( - &mut self, - input: &mut UserInput, - geom_map: &GeomMap, - map: &Map, - control_map: &ControlMap, - ) -> bool { + pub fn event(&mut self, input: &mut UserInput, map: &Map, control_map: &ControlMap) -> bool { if input.unimportant_key_pressed(Key::LeftBracket, "Press [ to slow down sim") { self.desired_speed -= ADJUST_SPEED; self.desired_speed = self.desired_speed.max(0.0); @@ -65,7 +58,7 @@ impl SimController { self.last_step = Some(Instant::now()); self.benchmark = Some(self.sim.start_benchmark()); } else if input.unimportant_key_pressed(Key::M, "press M to run one step") { - self.sim.step(geom_map, map, control_map); + self.sim.step(map, control_map); } } @@ -75,7 +68,7 @@ impl SimController { let dt = tick.elapsed(); let dt_s = dt.as_secs() as f64 + f64::from(dt.subsec_nanos()) * 1e-9; if dt_s >= common::TIMESTEP.value_unsafe / self.desired_speed { - self.sim.step(geom_map, map, control_map); + self.sim.step(map, control_map); self.last_step = Some(Instant::now()); } diff --git a/editor/src/plugins/stop_sign_editor.rs b/editor/src/plugins/stop_sign_editor.rs index 41157f6473..803f6f4fcd 100644 --- a/editor/src/plugins/stop_sign_editor.rs +++ b/editor/src/plugins/stop_sign_editor.rs @@ -6,7 +6,6 @@ use colors::{ColorScheme, Colors}; use control::ControlMap; use control::stop_signs::TurnPriority; use ezgui::input::UserInput; -use geom::GeomMap; use graphics::types::Color; use map_model::IntersectionID; use map_model::{Map, Turn}; @@ -26,7 +25,6 @@ impl StopSignEditor { &mut self, input: &mut UserInput, map: &Map, - geom_map: &GeomMap, control_map: &mut ControlMap, current_selection: &SelectionState, ) -> bool { @@ -40,30 +38,30 @@ impl StopSignEditor { match sign.get_priority(id) { TurnPriority::Priority => { if input.key_pressed(Key::D2, "Press 2 to make this turn yield") { - sign.set_priority(id, TurnPriority::Yield, geom_map); + sign.set_priority(id, TurnPriority::Yield, map); } if input.key_pressed(Key::D3, "Press 3 to make this turn always stop") { - sign.set_priority(id, TurnPriority::Stop, geom_map); + sign.set_priority(id, TurnPriority::Stop, map); } } TurnPriority::Yield => { - if sign.could_be_priority_turn(id, geom_map) + if sign.could_be_priority_turn(id, map) && input.key_pressed(Key::D1, "Press 1 to let this turn go immediately") { - sign.set_priority(id, TurnPriority::Priority, geom_map); + sign.set_priority(id, TurnPriority::Priority, map); } if input.key_pressed(Key::D3, "Press 3 to make this turn always stop") { - sign.set_priority(id, TurnPriority::Stop, geom_map); + sign.set_priority(id, TurnPriority::Stop, map); } } TurnPriority::Stop => { - if sign.could_be_priority_turn(id, geom_map) + if sign.could_be_priority_turn(id, map) && input.key_pressed(Key::D1, "Press 1 to let this turn go immediately") { - sign.set_priority(id, TurnPriority::Priority, geom_map); + sign.set_priority(id, TurnPriority::Priority, map); } if input.key_pressed(Key::D2, "Press 2 to make this turn yield") { - sign.set_priority(id, TurnPriority::Yield, geom_map); + sign.set_priority(id, TurnPriority::Yield, map); } } }; diff --git a/editor/src/plugins/traffic_signal_editor.rs b/editor/src/plugins/traffic_signal_editor.rs index f0d471d92c..a745ff8e77 100644 --- a/editor/src/plugins/traffic_signal_editor.rs +++ b/editor/src/plugins/traffic_signal_editor.rs @@ -7,7 +7,6 @@ extern crate map_model; use colors::{ColorScheme, Colors}; use control::ControlMap; use ezgui::input::UserInput; -use geom::GeomMap; use graphics::types::Color; use map_model::Map; use map_model::{IntersectionID, Turn}; @@ -31,7 +30,6 @@ impl TrafficSignalEditor { &mut self, input: &mut UserInput, map: &Map, - geom_map: &GeomMap, control_map: &mut ControlMap, current_selection: &SelectionState, ) -> bool { @@ -67,7 +65,7 @@ impl TrafficSignalEditor { ) { cycle.remove(id); } - } else if !cycle.conflicts_with(id, geom_map) { + } else if !cycle.conflicts_with(id, map) { if input.key_pressed(Key::Space, "Press Space to add this turn to this cycle") { cycle.add(id); } @@ -81,7 +79,7 @@ impl TrafficSignalEditor { pub fn color_t( &self, t: &Turn, - geom_map: &GeomMap, + map: &Map, control_map: &ControlMap, cs: &ColorScheme, ) -> Option { @@ -93,7 +91,7 @@ impl TrafficSignalEditor { if cycle.contains(t.id) { Some(cs.get(Colors::SignalEditorTurnInCurrentCycle)) - } else if !cycle.conflicts_with(t.id, geom_map) { + } else if !cycle.conflicts_with(t.id, map) { Some(cs.get(Colors::SignalEditorTurnCompatibleWithCurrentCycle)) } else { Some(cs.get(Colors::SignalEditorTurnConflictsWithCurrentCycle)) diff --git a/editor/src/render/building.rs b/editor/src/render/building.rs index 3b5cdf451b..e5b0ff583a 100644 --- a/editor/src/render/building.rs +++ b/editor/src/render/building.rs @@ -6,12 +6,11 @@ extern crate map_model; use aabb_quadtree::geom::Rect; use ezgui::GfxCtx; -use geom::GeomMap; -use geom::geometry; use graphics; use graphics::math::Vec2d; use graphics::types::Color; -use map_model::{Bounds, BuildingID}; +use map_model::geometry; +use map_model::{Bounds, BuildingID, Map}; use ordered_float::NotNaN; use std::f64; @@ -25,12 +24,7 @@ pub struct DrawBuilding { } impl DrawBuilding { - pub fn new( - bldg: &map_model::Building, - bounds: &Bounds, - map: &map_model::Map, - geom_map: &GeomMap, - ) -> DrawBuilding { + pub fn new(bldg: &map_model::Building, bounds: &Bounds, map: &Map) -> DrawBuilding { let pts: Vec = bldg.points .iter() .map(|pt| { @@ -41,7 +35,7 @@ impl DrawBuilding { DrawBuilding { id: bldg.id, // TODO ideally start the path on a side of the building - front_path: find_front_path(bldg.id, center(&pts), map, geom_map), + front_path: find_front_path(bldg.id, center(&pts), map), polygon: pts, } } @@ -61,7 +55,7 @@ impl DrawBuilding { geometry::point_in_polygon(x, y, &self.polygon) } - pub fn tooltip_lines(&self, map: &map_model::Map) -> Vec { + pub fn tooltip_lines(&self, map: &Map) -> Vec { let b = map.get_b(self.id); let mut lines = vec![ format!("Building #{:?} (from OSM way {})", self.id, b.osm_way_id), @@ -86,9 +80,8 @@ fn center(pts: &Vec) -> Vec2d { [x / len, y / len] } -fn road_to_line_string(r: map_model::RoadID, geom_map: &GeomMap) -> geo::LineString { - let pts: Vec> = geom_map - .get_r(r) +fn road_to_line_string(r: map_model::RoadID, map: &Map) -> geo::LineString { + let pts: Vec> = map.get_r(r) .lane_center_lines .iter() .flat_map(|pair| { @@ -101,12 +94,7 @@ fn road_to_line_string(r: map_model::RoadID, geom_map: &GeomMap) -> geo::LineStr pts.into() } -fn find_front_path( - id: BuildingID, - bldg_center: Vec2d, - map: &map_model::Map, - geom_map: &GeomMap, -) -> Option<[f64; 4]> { +fn find_front_path(id: BuildingID, bldg_center: Vec2d, map: &Map) -> Option<[f64; 4]> { use geo::prelude::{ClosestPoint, EuclideanDistance}; if let Some(tag) = map.get_b(id) @@ -127,7 +115,7 @@ fn find_front_path( && map_model::has_osm_tag(&r.osm_tags, "name", street_name) { if let geo::Closest::SinglePoint(pt) = - road_to_line_string(r.id, geom_map).closest_point(¢er_pt) + road_to_line_string(r.id, map).closest_point(¢er_pt) { return Some((r.id, pt)); } diff --git a/editor/src/render/intersection.rs b/editor/src/render/intersection.rs index ae6f089116..8d70fda2c5 100644 --- a/editor/src/render/intersection.rs +++ b/editor/src/render/intersection.rs @@ -5,10 +5,10 @@ extern crate map_model; use aabb_quadtree::geom::Rect; use ezgui::GfxCtx; -use geom::geometry; use graphics; use graphics::math::Vec2d; use graphics::types::Color; +use map_model::geometry; use map_model::{Bounds, IntersectionID, Map}; use render::DrawRoad; use std::f64; diff --git a/editor/src/render/map.rs b/editor/src/render/map.rs index 9302d28745..4c2293eea3 100644 --- a/editor/src/render/map.rs +++ b/editor/src/render/map.rs @@ -5,8 +5,7 @@ extern crate map_model; use aabb_quadtree::QuadTree; use aabb_quadtree::geom::{Point, Rect}; -use geom::GeomMap; -use geom::geometry; +use map_model::geometry; use map_model::{Bounds, BuildingID, IntersectionID, Map, ParcelID, Pt2D, RoadID, TurnID}; use render::building::DrawBuilding; use render::intersection::DrawIntersection; @@ -31,12 +30,12 @@ pub struct DrawMap { impl DrawMap { // Also returns the center of the map in map-space - pub fn new(map: &Map, geom_map: &GeomMap) -> (DrawMap, Bounds, Pt2D) { + pub fn new(map: &Map) -> (DrawMap, Bounds, Pt2D) { let bounds = map.get_gps_bounds(); let mut roads: Vec = Vec::new(); for r in map.all_roads() { - roads.push(DrawRoad::new(r, geom_map)); + roads.push(DrawRoad::new(r)); } let mut turn_to_road_offset: HashMap = HashMap::new(); @@ -44,8 +43,8 @@ impl DrawMap { let mut turns = map.get_turns_from_road(r.id); // Sort the turn icons by angle. turns.sort_by_key(|t| { - let src_pt = geom_map.get_r(t.src).last_pt(); - let dst_pt = geom_map.get_r(t.dst).first_pt(); + let src_pt = map.get_r(t.src).last_pt(); + let dst_pt = map.get_r(t.dst).first_pt(); let mut angle = (dst_pt[1] - src_pt[1]) .atan2(dst_pt[0] - src_pt[0]) .to_degrees(); @@ -62,7 +61,7 @@ impl DrawMap { let turns: Vec = map.all_turns() .iter() - .map(|t| DrawTurn::new(geom_map, t, turn_to_road_offset[&t.id])) + .map(|t| DrawTurn::new(map, t, turn_to_road_offset[&t.id])) .collect(); let intersections: Vec = map.all_intersections() .iter() @@ -70,7 +69,7 @@ impl DrawMap { .collect(); let buildings: Vec = map.all_buildings() .iter() - .map(|b| DrawBuilding::new(b, &bounds, map, geom_map)) + .map(|b| DrawBuilding::new(b, &bounds, map)) .collect(); let parcels: Vec = map.all_parcels() .iter() diff --git a/editor/src/render/mod.rs b/editor/src/render/mod.rs index 1df8b6dfa7..4b95afba40 100644 --- a/editor/src/render/mod.rs +++ b/editor/src/render/mod.rs @@ -9,7 +9,7 @@ mod parcel; mod road; mod turn; -use geom; +use map_model::geometry; pub use render::map::DrawMap; pub use render::road::DrawRoad; pub use render::turn::DrawTurn; @@ -18,7 +18,7 @@ use std::f64; // These are all in meters const PARCEL_BOUNDARY_THICKNESS: f64 = 0.5; -const TURN_ICON_ARROW_THICKNESS: f64 = geom::BIG_ARROW_THICKNESS / 3.0; +const TURN_ICON_ARROW_THICKNESS: f64 = geometry::BIG_ARROW_THICKNESS / 3.0; const BIG_ARROW_TIP_LENGTH: f64 = 1.0; const TURN_ICON_ARROW_TIP_LENGTH: f64 = BIG_ARROW_TIP_LENGTH * 0.8; const TURN_ICON_ARROW_LENGTH: f64 = 2.0; diff --git a/editor/src/render/parcel.rs b/editor/src/render/parcel.rs index 1ba0ee4734..ff9c0623ae 100644 --- a/editor/src/render/parcel.rs +++ b/editor/src/render/parcel.rs @@ -5,10 +5,10 @@ extern crate map_model; use aabb_quadtree::geom::Rect; use ezgui::GfxCtx; -use geom::geometry; use graphics; use graphics::math::Vec2d; use graphics::types::Color; +use map_model::geometry; use map_model::{Bounds, ParcelID, Pt2D}; use render::PARCEL_BOUNDARY_THICKNESS; diff --git a/editor/src/render/road.rs b/editor/src/render/road.rs index 64c0246bc6..2f6763406a 100644 --- a/editor/src/render/road.rs +++ b/editor/src/render/road.rs @@ -6,11 +6,10 @@ extern crate map_model; use aabb_quadtree::geom::Rect; use colors::{ColorScheme, Colors}; use ezgui::GfxCtx; -use geom; -use geom::geometry; use graphics; use graphics::math::Vec2d; use graphics::types::Color; +use map_model::geometry; use map_model::{Pt2D, RoadID}; use render::PARCEL_BOUNDARY_THICKNESS; use std::f64; @@ -25,16 +24,14 @@ pub struct DrawRoad { } impl DrawRoad { - pub fn new(road: &map_model::Road, geom_map: &geom::GeomMap) -> DrawRoad { - let geom_r = geom_map.get_r(road.id); - + pub fn new(road: &map_model::Road) -> DrawRoad { let thick_line = - geometry::ThickLine::DrivingDirectionOnly(geom::LANE_THICKNESS, road.offset); + geometry::ThickLine::DrivingDirectionOnly(geometry::LANE_THICKNESS, road.offset); DrawRoad { id: road.id, - polygons: geometry::thick_multiline(&thick_line, &geom_r.pts), + polygons: geometry::thick_multiline(&thick_line, &road.pts), yellow_center_lines: if road.use_yellow_center_lines { - geom_r.pts.clone() + road.pts.clone() } else { Vec::new() }, @@ -49,8 +46,10 @@ impl DrawRoad { } pub fn draw_detail(&self, g: &mut GfxCtx, cs: &ColorScheme) { - let road_marking = - graphics::Line::new_round(cs.get(Colors::RoadOrientation), geom::BIG_ARROW_THICKNESS); + let road_marking = graphics::Line::new_round( + cs.get(Colors::RoadOrientation), + geometry::BIG_ARROW_THICKNESS, + ); for pair in self.yellow_center_lines.windows(2) { road_marking.draw( @@ -62,12 +61,12 @@ impl DrawRoad { } } - pub fn draw_debug(&self, g: &mut GfxCtx, cs: &ColorScheme, geom_r: &geom::GeomRoad) { + pub fn draw_debug(&self, g: &mut GfxCtx, cs: &ColorScheme, r: &map_model::Road) { let line = graphics::Line::new_round(cs.get(Colors::Debug), PARCEL_BOUNDARY_THICKNESS / 2.0); let circle = graphics::Ellipse::new(cs.get(Colors::BrightDebug)); - for &(pt1, pt2) in &geom_r.lane_center_lines { + for &(pt1, pt2) in &r.lane_center_lines { line.draw( [pt1.x(), pt1.y(), pt2.x(), pt2.y()], &g.ctx.draw_state, @@ -102,7 +101,7 @@ impl DrawRoad { false } - pub fn tooltip_lines(&self, map: &map_model::Map, geom_map: &geom::GeomMap) -> Vec { + pub fn tooltip_lines(&self, map: &map_model::Map) -> Vec { let r = map.get_r(self.id); let mut lines = vec![ format!( @@ -116,7 +115,7 @@ impl DrawRoad { map.get_source_intersection(self.id).elevation_meters, map.get_destination_intersection(self.id).elevation_meters, ), - format!("Road is {}m long", geom_map.get_r(self.id).length()), + format!("Road is {}m long", r.length()), ]; lines.extend(r.osm_tags.iter().cloned()); lines diff --git a/editor/src/render/turn.rs b/editor/src/render/turn.rs index 0dc41abf89..4f6942638b 100644 --- a/editor/src/render/turn.rs +++ b/editor/src/render/turn.rs @@ -6,13 +6,11 @@ extern crate map_model; use aabb_quadtree::geom::Rect; use colors::{ColorScheme, Colors}; use ezgui::GfxCtx; -use geom; -use geom::GeomMap; -use geom::geometry; use graphics; use graphics::math::Vec2d; use graphics::types::Color; use map_model::TurnID; +use map_model::geometry; use render::{BIG_ARROW_TIP_LENGTH, TURN_ICON_ARROW_LENGTH, TURN_ICON_ARROW_THICKNESS, TURN_ICON_ARROW_TIP_LENGTH}; use std::f64; @@ -28,12 +26,12 @@ pub struct DrawTurn { } impl DrawTurn { - pub fn new(geom_map: &GeomMap, turn: &map_model::Turn, offset_along_road: usize) -> DrawTurn { + pub fn new(map: &map_model::Map, turn: &map_model::Turn, offset_along_road: usize) -> DrawTurn { let offset_along_road = offset_along_road as f64; - let src_pt = geom_map.get_r(turn.src).last_pt(); - let dst_pt = geom_map.get_r(turn.dst).first_pt(); + let src_pt = map.get_r(turn.src).last_pt(); + let dst_pt = map.get_r(turn.dst).first_pt(); let slope = vecmath::vec2_normalized([dst_pt[0] - src_pt[0], dst_pt[1] - src_pt[1]]); - let last_line = geom_map.get_r(turn.src).last_line(); + let last_line = map.get_r(turn.src).last_line(); let icon_center = geometry::dist_along_line( // Start the distance from the intersection @@ -64,7 +62,7 @@ impl DrawTurn { } pub fn draw_full(&self, g: &mut GfxCtx, color: Color) { - let turn_line = graphics::Line::new_round(color, geom::BIG_ARROW_THICKNESS); + let turn_line = graphics::Line::new_round(color, geometry::BIG_ARROW_THICKNESS); turn_line.draw_arrow( [ self.src_pt[0], diff --git a/editor/src/ui.rs b/editor/src/ui.rs index 0704cdfb11..af7460f55f 100644 --- a/editor/src/ui.rs +++ b/editor/src/ui.rs @@ -14,7 +14,6 @@ use ezgui::GfxCtx; use ezgui::ToggleableLayer; use ezgui::canvas::Canvas; use ezgui::input::UserInput; -use geom; use graphics; use graphics::types::Color; use gui; @@ -44,7 +43,6 @@ const MIN_ZOOM_FOR_ROAD_MARKERS: f64 = 5.0; pub struct UI { map: map_model::Map, - geom_map: geom::GeomMap, draw_map: render::DrawMap, control_map: ControlMap, @@ -76,17 +74,15 @@ impl UI { println!("Opening {}", abst_path); let data = map_model::load_pb(abst_path).expect("Couldn't load pb"); let map = map_model::Map::new(&data); - let geom_map = geom::GeomMap::new(&map); - let (draw_map, _, center_pt) = render::DrawMap::new(&map, &geom_map); - let control_map = ControlMap::new(&map, &geom_map); + let (draw_map, _, center_pt) = render::DrawMap::new(&map); + let control_map = ControlMap::new(&map); let steepness_viz = SteepnessVisualizer::new(&map); let turn_colors = TurnColors::new(&control_map); - let sim_ctrl = SimController::new(&map, &geom_map, rng_seed); + let sim_ctrl = SimController::new(&map, rng_seed); let mut ui = UI { map, - geom_map, draw_map, control_map, steepness_viz, @@ -165,10 +161,7 @@ impl UI { Vec::new() }; for r in &roads_onscreen { - for c in &self.sim_ctrl - .sim - .get_draw_cars_on_road(r.id, &self.geom_map) - { + for c in &self.sim_ctrl.sim.get_draw_cars_on_road(r.id, &self.map) { if c.contains_pt(x, y) { return Some(ID::Car(c.id)); } @@ -186,7 +179,7 @@ impl UI { if self.show_intersections.is_enabled() { for i in &self.draw_map.get_intersections_onscreen(screen_bbox) { for t in &self.map.get_i(i.id).turns { - for c in &self.sim_ctrl.sim.get_draw_cars_on_turn(*t, &self.geom_map) { + for c in &self.sim_ctrl.sim.get_draw_cars_on_turn(*t, &self.map) { if c.contains_pt(x, y) { return Some(ID::Car(c.id)); } @@ -201,10 +194,7 @@ impl UI { if self.show_roads.is_enabled() { for r in &roads_onscreen { - for c in &self.sim_ctrl - .sim - .get_draw_cars_on_road(r.id, &self.geom_map) - { + for c in &self.sim_ctrl.sim.get_draw_cars_on_road(r.id, &self.map) { if c.contains_pt(x, y) { return Some(ID::Car(c.id)); } @@ -287,7 +277,7 @@ impl UI { .unwrap_or_else(|| { self.traffic_signal_editor .as_ref() - .and_then(|e| e.color_t(t, &self.geom_map, &self.control_map, &self.cs)) + .and_then(|e| e.color_t(t, &self.map, &self.control_map, &self.cs)) .unwrap_or_else(|| { self.turn_colors .color_t(t) @@ -344,7 +334,6 @@ impl gui::GUI for UI { if e.event( input, &self.map, - &self.geom_map, &mut self.control_map, &self.current_selection_state, ) { @@ -359,7 +348,6 @@ impl gui::GUI for UI { if e.event( input, &self.map, - &self.geom_map, &mut self.control_map, &self.current_selection_state, ) { @@ -376,10 +364,7 @@ impl gui::GUI for UI { self.current_search_state = self.current_search_state.event(input); - if !edit_mode - && self.sim_ctrl - .event(input, &self.geom_map, &self.map, &self.control_map) - { + if !edit_mode && self.sim_ctrl.event(input, &self.map, &self.control_map) { event_loop_mode = event_loop_mode.merge(animation::EventLoopMode::Animation); } @@ -510,7 +495,7 @@ impl gui::GUI for UI { r.draw_detail(g, &self.cs); } if self.debug_mode.is_enabled() { - r.draw_debug(g, &self.cs, self.geom_map.get_r(r.id)); + r.draw_debug(g, &self.cs, self.map.get_r(r.id)); } } @@ -523,20 +508,14 @@ impl gui::GUI for UI { if self.show_icons.is_enabled() { for t in &self.draw_map.get_turn_icons_onscreen(screen_bbox) { t.draw_icon(g, self.color_turn_icon(t.id), &self.cs); - for c in &self.sim_ctrl - .sim - .get_draw_cars_on_turn(t.id, &self.geom_map) - { + for c in &self.sim_ctrl.sim.get_draw_cars_on_turn(t.id, &self.map) { c.draw(g, self.color_car(c.id)); } } } for r in &roads_onscreen { - for c in &self.sim_ctrl - .sim - .get_draw_cars_on_road(r.id, &self.geom_map) - { + for c in &self.sim_ctrl.sim.get_draw_cars_on_road(r.id, &self.map) { c.draw(g, self.color_car(c.id)); } } @@ -556,7 +535,6 @@ impl gui::GUI for UI { self.current_selection_state.draw( &self.map, &self.canvas, - &self.geom_map, &self.draw_map, &self.control_map, &self.sim_ctrl.sim, diff --git a/geom/Cargo.toml b/geom/Cargo.toml deleted file mode 100644 index 765a2b974e..0000000000 --- a/geom/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "geom" -version = "0.1.0" -authors = ["Dustin Carlino "] - -[dependencies] -aabb-quadtree = "0.1.0" -dimensioned = "0.6.0" -map_model = { path = "../map_model" } -piston2d-graphics = "*" -vecmath = "0.3.1" diff --git a/geom/src/geometry.rs b/geom/src/geometry.rs deleted file mode 100644 index 14eaa38297..0000000000 --- a/geom/src/geometry.rs +++ /dev/null @@ -1,278 +0,0 @@ -// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0 - -extern crate aabb_quadtree; - -use aabb_quadtree::geom::{Point, Rect}; -use dimensioned::si; -use graphics::math::Vec2d; -use map_model::{Bounds, Pt2D}; -use std::f64; -use vecmath; - -pub mod angles { - make_units! { - ANGLES; - ONE: Unitless; - - base { - RAD: Radian, "rad"; - } - derived {} - constants {} - - fmt = true; - } - pub use self::f64consts::*; -} - -// TODO there may be existing crates that help with this stuff - -// -1 for driving on the left -const DRIVING_DIRECTION: f64 = 1.0; - -use std; -pub const EPSILON_METERS: si::Meter = si::Meter { - value_unsafe: 0.00001, - _marker: std::marker::PhantomData, -}; - -pub enum ThickLine { - // The f64's represent the full width of the thick line - // The u8 is the offset from center - DrivingDirectionOnly(f64, u8), - Centered(f64), -} - -impl ThickLine { - // Returns a scaling factor to project away from a center line, left and right side. - fn project_away_lengths(&self) -> (f64, f64) { - match *self { - ThickLine::DrivingDirectionOnly(w, raw_offset) => { - let offset = raw_offset as f64; - if DRIVING_DIRECTION == 1.0 { - (w * (offset + 1.0), w * offset) - } else { - (-1.0 * w * offset, -1.0 * w * (offset + 1.0)) - } - } - ThickLine::Centered(w) => (w / -2.0, w / 2.0), - } - } -} - -pub fn thick_multiline(style: &ThickLine, pts: &[Pt2D]) -> Vec> { - let mut polygons: Vec> = Vec::new(); - - for slice in pts.windows(3) { - let (pt1, pt2, pt3) = (&slice[0], &slice[1], &slice[2]); - let quad1 = thick_line(style, pt1, pt2); - let quad2 = thick_line(style, pt2, pt3); - // The original quad. This over-extends in some cases, especially with multiple lanes. - polygons.push(quad1.clone()); - // Add a quad to fill in the gap. Comment out to see part of the polyline problem very - // clearly. - polygons.push(vec![quad1[2], quad1[3], quad2[0], quad2[1], quad1[2]]); - } - - // We always need a quad for the last group, since there won't be a window of 3. - polygons.push(thick_line(style, &pts[pts.len() - 2], &pts[pts.len() - 1])); - - polygons -} - -pub fn thick_line(style: &ThickLine, pt1: &Pt2D, pt2: &Pt2D) -> Vec { - let x1 = pt1.x(); - let y1 = pt1.y(); - let x2 = pt2.x(); - let y2 = pt2.y(); - let angle = (y2 - y1).atan2(x2 - x1) + (f64::consts::PI / 2.0); - // Project away from (x1, y1) in both directions by some amount - let (side1_width, side2_width) = style.project_away_lengths(); - let c1 = [ - x1 + side1_width * angle.cos(), - y1 + side1_width * angle.sin(), - ]; - let c2 = [ - x1 + side2_width * angle.cos(), - y1 + side2_width * angle.sin(), - ]; - let c3 = [ - x2 + side1_width * angle.cos(), - y2 + side1_width * angle.sin(), - ]; - let c4 = [ - x2 + side2_width * angle.cos(), - y2 + side2_width * angle.sin(), - ]; - vec![c1, c2, c4, c3, c1] -} - -pub fn thick_line_from_angle( - thickness: f64, - line_length: f64, - pt: &Pt2D, - angle: angles::Radian, -) -> Vec { - let pt2 = Pt2D::new( - pt.x() + line_length * angle.value_unsafe.cos(), - pt.y() + line_length * angle.value_unsafe.sin(), - ); - thick_line(&ThickLine::Centered(thickness), &pt, &pt2) -} - -pub fn shift_line_perpendicularly_in_driving_direction( - width: f64, - pt1: &Pt2D, - pt2: &Pt2D, -) -> (Pt2D, Pt2D) { - let x1 = pt1.x(); - let y1 = pt1.y(); - let x2 = pt2.x(); - let y2 = pt2.y(); - let half_pi = f64::consts::PI / 2.0; - let angle = (y2 - y1).atan2(x2 - x1) + DRIVING_DIRECTION * half_pi; - let shifted1 = Pt2D::new(x1 + width * angle.cos(), y1 + width * angle.sin()); - let shifted2 = Pt2D::new(x2 + width * angle.cos(), y2 + width * angle.sin()); - (shifted1, shifted2) -} - -// Algorithm from https://wrf.ecse.rpi.edu//Research/Short_Notes/pnpoly.html -pub fn point_in_polygon(x: f64, y: f64, polygon: &[Vec2d]) -> bool { - // TODO fix map conversion - //assert_eq!(polygon[0], polygon[polygon.len() - 1]); - if polygon[0] != polygon[polygon.len() - 1] { - println!("WARNING: polygon {:?} isn't closed", polygon); - return false; - } - - let mut inside = false; - for (pt1, pt2) in polygon.iter().zip(polygon.iter().skip(1)) { - let x1 = pt1[0]; - let y1 = pt1[1]; - let x2 = pt2[0]; - let y2 = pt2[1]; - let intersect = ((y1 > y) != (y2 > y)) && (x < (x2 - x1) * (y - y1) / (y2 - y1) + x1); - if intersect { - inside = !inside; - } - } - inside -} - -pub fn point_in_circle(x: f64, y: f64, center: Vec2d, radius: f64) -> bool { - // avoid sqrt by squaring radius instead - (x - center[0]).powi(2) + (y - center[1]).powi(2) < radius.powi(2) -} - -/*pub fn interpolate_along_line((pt1, pt2): (&Pt2D, &Pt2D), factor_along: f64) -> Vec2d { - assert!(factor_along >= 0.0 && factor_along <= 1.0); - let x = pt1.x + factor_along * (pt2.x - pt1.x); - let y = pt1.y + factor_along * (pt2.y - pt1.y); - return [x, y]; -}*/ - -pub fn euclid_dist((pt1, pt2): (&Pt2D, &Pt2D)) -> si::Meter { - return ((pt1.x() - pt2.x()).powi(2) + (pt1.y() - pt2.y()).powi(2)).sqrt() * si::M; -} - -pub fn line_segments_intersect((pt1, pt2): (&Vec2d, &Vec2d), (pt3, pt4): (&Vec2d, &Vec2d)) -> bool { - // From http://bryceboe.com/2006/10/23/line-segment-intersection-algorithm/ - is_counter_clockwise(pt1, pt3, pt4) != is_counter_clockwise(pt2, pt3, pt4) - && is_counter_clockwise(pt1, pt2, pt3) != is_counter_clockwise(pt1, pt2, pt4) -} - -fn is_counter_clockwise(pt1: &Vec2d, pt2: &Vec2d, pt3: &Vec2d) -> bool { - (pt3[1] - pt1[1]) * (pt2[0] - pt1[0]) > (pt2[1] - pt1[1]) * (pt3[0] - pt1[0]) -} - -pub fn dist_along_line((pt1, pt2): (&Pt2D, &Pt2D), dist_along: f64) -> Vec2d { - //assert!(euclid_dist(&pt1, &pt2) <= dist_along); - let vec = vecmath::vec2_normalized([pt2.x() - pt1.x(), pt2.y() - pt1.y()]); - [pt1.x() + dist_along * vec[0], pt1.y() + dist_along * vec[1]] -} - -// TODO rm the other one -pub fn safe_dist_along_line((pt1, pt2): (&Pt2D, &Pt2D), dist_along: si::Meter) -> Vec2d { - let len = euclid_dist((pt1, pt2)); - if dist_along > len + EPSILON_METERS { - panic!("cant do {} along a line of length {}", dist_along, len); - } - - let percent = (dist_along / len).value_unsafe; - [ - pt1.x() + percent * (pt2.x() - pt1.x()), - pt1.y() + percent * (pt2.y() - pt1.y()), - ] - // TODO unit test - /* - let res_len = euclid_dist((pt1, &Pt2D::new(res[0], res[1]))); - if res_len != dist_along { - println!("whats the delta btwn {} and {}?", res_len, dist_along); - } - */} - -pub fn get_bbox_for_polygons(polygons: &[Vec]) -> Rect { - let mut b = Bounds::new(); - for poly in polygons { - for pt in poly { - b.update(pt[0], pt[1]); - } - } - Rect { - top_left: Point { - x: b.min_x as f32, - y: b.min_y as f32, - }, - bottom_right: Point { - x: b.max_x as f32, - y: b.max_y as f32, - }, - } -} - -pub fn gps_to_screen_space(gps: &Pt2D, b: &Bounds) -> Pt2D { - // If not, havoc ensues - assert!(b.contains(gps.x(), gps.y())); - - // Invert y, so that the northernmost latitude is 0. Screen drawing order, not Cartesian grid. - let base = Pt2D::new(b.min_x, b.max_y); - // Apparently the aabb_quadtree can't handle 0, so add a bit. - // TODO epsilon or epsilon - 1.0? - let dx = base.gps_dist_meters(&Pt2D::new(gps.x(), base.y())) + f64::EPSILON; - let dy = base.gps_dist_meters(&Pt2D::new(base.x(), gps.y())) + f64::EPSILON; - // By default, 1 meter is one pixel. Normal zooming can change that. If we did scaling here, - // then we'd have to update all of the other constants too. - Pt2D::new(dx, dy) -} - -pub fn circle(center_x: f64, center_y: f64, radius: f64) -> [f64; 4] { - [ - center_x - radius, - center_y - radius, - 2.0 * radius, - 2.0 * radius, - ] -} - -pub fn circle_to_bbox(c: &[f64; 4]) -> Rect { - Rect { - top_left: Point { - x: c[0] as f32, - y: c[1] as f32, - }, - bottom_right: Point { - x: (c[0] + c[2]) as f32, - y: (c[1] + c[3]) as f32, - }, - } -} - -pub fn angle(from: &Pt2D, to: &Pt2D) -> angles::Radian { - // DON'T invert y here - let mut theta = (to.y() - from.y()).atan2(to.x() - from.x()); - // Normalize for easy output - if theta < 0.0 { - theta += 2.0 * f64::consts::PI; - } - theta * angles::RAD -} diff --git a/geom/src/lib.rs b/geom/src/lib.rs deleted file mode 100644 index 2ac84cb700..0000000000 --- a/geom/src/lib.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0 - -// TODO maybe use dimensioned way more thoroughly inside this crate - -extern crate aabb_quadtree; -#[macro_use] -extern crate dimensioned; -extern crate graphics; -extern crate map_model; -extern crate vecmath; - -pub mod geometry; -mod map; -mod road; -mod turn; - -pub use geometry::angles::{Radian, RAD}; -pub use map::GeomMap; -pub use road::GeomRoad; -pub use turn::GeomTurn; - -pub const LANE_THICKNESS: f64 = 2.5; -pub const BIG_ARROW_THICKNESS: f64 = 0.5; -pub const TURN_DIST_FROM_INTERSECTION: f64 = 7.5; diff --git a/geom/src/map.rs b/geom/src/map.rs deleted file mode 100644 index c45067a00d..0000000000 --- a/geom/src/map.rs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0 - -extern crate map_model; - -use map_model::{Map, RoadID, TurnID}; -use road::GeomRoad; -use turn::GeomTurn; - -pub struct GeomMap { - pub roads: Vec, - pub turns: Vec, -} - -impl GeomMap { - pub fn new(map: &Map) -> GeomMap { - let bounds = map.get_gps_bounds(); - - let mut roads: Vec = Vec::new(); - for r in map.all_roads() { - roads.push(GeomRoad::new(r, &bounds)); - } - - let turns: Vec = map.all_turns() - .iter() - .map(|t| GeomTurn::new(&roads, t)) - .collect(); - - GeomMap { roads, turns } - } - - // The alt to these is implementing std::ops::Index, but that's way more verbose! - pub fn get_r(&self, id: RoadID) -> &GeomRoad { - &self.roads[id.0] - } - - pub fn get_t(&self, id: TurnID) -> &GeomTurn { - &self.turns[id.0] - } -} diff --git a/geom/src/road.rs b/geom/src/road.rs deleted file mode 100644 index 385ba91066..0000000000 --- a/geom/src/road.rs +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0 - -extern crate dimensioned; -extern crate map_model; - -use BIG_ARROW_THICKNESS; -use LANE_THICKNESS; -use TURN_DIST_FROM_INTERSECTION; - -use dimensioned::si; -use geometry; -use graphics::math::Vec2d; -use map_model::{Bounds, Pt2D, RoadID}; -use std::f64; - -#[derive(Debug)] -pub struct GeomRoad { - pub id: RoadID, - // TODO need to settle on a proper Line type - pub lane_center_lines: Vec<(Pt2D, Pt2D)>, - // unshifted center points. consider computing these twice or otherwise not storing them - pub pts: Vec, -} - -impl GeomRoad { - pub fn new(road: &map_model::Road, bounds: &Bounds) -> GeomRoad { - let mut pts: Vec = road.points - .iter() - .map(|pt| geometry::gps_to_screen_space(pt, bounds)) - .collect(); - // Shove the lines away from the intersection so they don't overlap. - // TODO deal with tiny roads - let num_pts = pts.len(); - let new_first_pt = - geometry::dist_along_line((&pts[0], &pts[1]), TURN_DIST_FROM_INTERSECTION); - let new_last_pt = geometry::dist_along_line( - (&pts[num_pts - 1], &pts[num_pts - 2]), - TURN_DIST_FROM_INTERSECTION, - ); - pts[0] = Pt2D::from(new_first_pt); - pts[num_pts - 1] = Pt2D::from(new_last_pt); - - let offset = road.offset as f64; - let lane_center_shift = if road.use_yellow_center_lines { - // TODO I think this is unfair to one side, right? If we hover over the yellow line, it - // shouldn't match either lane. Needs to be its own thing, or adjust the bbox. - (LANE_THICKNESS / 2.0) + (BIG_ARROW_THICKNESS / 2.0) - } else { - LANE_THICKNESS * (offset + 0.5) - }; - // TODO when drawing cars along these lines, do we have the line overlap problem? yes. - let lane_center_lines: Vec<(Pt2D, Pt2D)> = pts.windows(2) - .map(|pair| { - geometry::shift_line_perpendicularly_in_driving_direction( - lane_center_shift, - &pair[0], - &pair[1], - ) - }) - .collect(); - - GeomRoad { - lane_center_lines, - pts, - id: road.id, - } - } - - pub fn first_pt(&self) -> Vec2d { - let pt = &self.lane_center_lines[0].0; - [pt.x(), pt.y()] - } - - pub fn last_pt(&self) -> Vec2d { - let pt = &self.lane_center_lines.last().unwrap().1; - [pt.x(), pt.y()] - } - - pub fn last_line(&self) -> (Pt2D, Pt2D) { - *self.lane_center_lines.last().unwrap() - } - - pub fn dist_along(&self, dist_along: si::Meter) -> (Pt2D, geometry::angles::Radian) { - // TODO valid to do euclidean distance on screen-space points that're formed from - // Haversine? - let mut dist_left = dist_along; - for (idx, l) in self.lane_center_lines.iter().enumerate() { - let length = geometry::euclid_dist((&l.0, &l.1)); - let epsilon = if idx == self.lane_center_lines.len() - 1 { - geometry::EPSILON_METERS - } else { - 0.0 * si::M - }; - if dist_left <= length + epsilon { - let vec = geometry::safe_dist_along_line((&l.0, &l.1), dist_left); - return (Pt2D::new(vec[0], vec[1]), geometry::angle(&l.0, &l.1)); - } - dist_left -= length; - } - panic!( - "{} is longer than road {:?}'s {}. dist_left is {}", - dist_along, - self.id, - self.length(), - dist_left - ); - } - - pub fn length(&self) -> si::Meter { - self.lane_center_lines - .iter() - .fold(0.0 * si::M, |so_far, l| { - so_far + geometry::euclid_dist((&l.0, &l.1)) - }) - } -} diff --git a/geom/src/turn.rs b/geom/src/turn.rs deleted file mode 100644 index 41540e8a8f..0000000000 --- a/geom/src/turn.rs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0 - -extern crate dimensioned; -extern crate map_model; - -use dimensioned::si; -use geometry; -use graphics::math::Vec2d; -use map_model::{Pt2D, TurnID}; -use road::GeomRoad; -use std::f64; -use vecmath; - -#[derive(Debug)] -pub struct GeomTurn { - pub id: TurnID, - src_pt: Vec2d, - pub dst_pt: Vec2d, -} - -impl GeomTurn { - pub fn new(roads: &[GeomRoad], turn: &map_model::Turn) -> GeomTurn { - let src_pt = roads[turn.src.0].last_pt(); - let dst_pt = roads[turn.dst.0].first_pt(); - - GeomTurn { - id: turn.id, - src_pt, - dst_pt, - } - } - - pub fn conflicts_with(&self, other: &GeomTurn) -> bool { - if self.src_pt == other.src_pt { - return false; - } - if self.dst_pt == other.dst_pt { - return true; - } - geometry::line_segments_intersect( - (&self.src_pt, &self.dst_pt), - (&other.src_pt, &other.dst_pt), - ) - } - - // TODO share impl with GeomRoad - pub fn dist_along(&self, dist_along: si::Meter) -> (Pt2D, geometry::angles::Radian) { - let src = Pt2D::new(self.src_pt[0], self.src_pt[1]); - let dst = Pt2D::new(self.dst_pt[0], self.dst_pt[1]); - let vec = geometry::safe_dist_along_line((&src, &dst), dist_along); - (Pt2D::new(vec[0], vec[1]), geometry::angle(&src, &dst)) - } - - pub fn length(&self) -> si::Meter { - let src = Pt2D::new(self.src_pt[0], self.src_pt[1]); - let dst = Pt2D::new(self.dst_pt[0], self.dst_pt[1]); - geometry::euclid_dist((&src, &dst)) - } - - pub fn slope(&self) -> [f64; 2] { - vecmath::vec2_normalized([ - self.dst_pt[0] - self.src_pt[0], - self.dst_pt[1] - self.src_pt[1], - ]) - } -} diff --git a/headless/Cargo.toml b/headless/Cargo.toml index 9e6d140128..1fb1d70077 100644 --- a/headless/Cargo.toml +++ b/headless/Cargo.toml @@ -5,7 +5,6 @@ authors = ["Dustin Carlino "] [dependencies] control = { path = "../control" } -geom = { path = "../geom" } map_model = { path = "../map_model" } sim = { path = "../sim" } structopt = "0.2" diff --git a/headless/src/main.rs b/headless/src/main.rs index b4b88028fc..da47f138f9 100644 --- a/headless/src/main.rs +++ b/headless/src/main.rs @@ -1,7 +1,6 @@ // Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0 extern crate control; -extern crate geom; extern crate map_model; extern crate sim; #[macro_use] @@ -27,10 +26,9 @@ fn main() { println!("Opening {}", flags.abst_input); let data = map_model::load_pb(&flags.abst_input).expect("Couldn't load pb"); let map = map_model::Map::new(&data); - let geom_map = geom::GeomMap::new(&map); // TODO could load savestate - let control_map = control::ControlMap::new(&map, &geom_map); - let mut sim = sim::straw_model::Sim::new(&map, &geom_map, flags.rng_seed); + let control_map = control::ControlMap::new(&map); + let mut sim = sim::straw_model::Sim::new(&map, flags.rng_seed); // TODO need a notion of scenarios sim.spawn_many_on_empty_roads(&map, 100000); @@ -38,7 +36,7 @@ fn main() { let mut benchmark = sim.start_benchmark(); loop { counter += 1; - sim.step(&geom_map, &map, &control_map); + sim.step(&map, &control_map); if counter % 1000 == 0 { let speed = sim.measure_speed(&mut benchmark); println!("{0}, speed = {1:.2}x", sim.summary(), speed); diff --git a/map_model/src/lib.rs b/map_model/src/lib.rs index 2d23fbf65b..404695644c 100644 --- a/map_model/src/lib.rs +++ b/map_model/src/lib.rs @@ -13,7 +13,7 @@ extern crate serde_derive; extern crate vecmath; mod building; -mod geometry; +pub mod geometry; mod intersection; mod map; mod parcel; @@ -23,6 +23,7 @@ mod road; mod turn; pub use building::{Building, BuildingID}; +pub use geometry::angles::{Radian, RAD}; pub use intersection::{Intersection, IntersectionID}; pub use map::Map; use ordered_float::NotNaN; diff --git a/sim/Cargo.toml b/sim/Cargo.toml index 8ac7690cf0..ae030f6e18 100644 --- a/sim/Cargo.toml +++ b/sim/Cargo.toml @@ -7,7 +7,6 @@ authors = ["Dustin Carlino "] control = { path = "../control" } derivative = "1.0.0" dimensioned = "0.6.0" -geom = { path = "../geom" } ezgui = { path = "../ezgui" } map_model = { path = "../map_model" } multimap = "0.4.0" diff --git a/sim/src/lib.rs b/sim/src/lib.rs index 7d06b174e7..99ab557f13 100644 --- a/sim/src/lib.rs +++ b/sim/src/lib.rs @@ -5,7 +5,6 @@ extern crate control; extern crate derivative; extern crate dimensioned; extern crate ezgui; -extern crate geom; extern crate graphics; extern crate map_model; extern crate multimap; diff --git a/sim/src/straw_intersections.rs b/sim/src/straw_intersections.rs index 2e2df6a66e..bc8c3f4478 100644 --- a/sim/src/straw_intersections.rs +++ b/sim/src/straw_intersections.rs @@ -4,8 +4,7 @@ use common::{CarID, Tick, SPEED_LIMIT}; use control::ControlMap; use control::stop_signs::{ControlStopSign, TurnPriority}; use dimensioned::si; -use geom::GeomMap; -use map_model::{IntersectionID, TurnID}; +use map_model::{IntersectionID, Map, TurnID}; use std::collections::HashMap; use std; @@ -28,15 +27,15 @@ impl IntersectionPolicy { car: CarID, turn: TurnID, time: Tick, - geom_map: &GeomMap, + map: &Map, control_map: &ControlMap, ) -> bool { match *self { IntersectionPolicy::StopSignPolicy(ref mut p) => { - p.can_do_turn(car, turn, time, geom_map, control_map) + p.can_do_turn(car, turn, time, map, control_map) } IntersectionPolicy::TrafficSignalPolicy(ref mut p) => { - p.can_do_turn(car, turn, time, geom_map, control_map) + p.can_do_turn(car, turn, time, map, control_map) } } } @@ -73,27 +72,25 @@ impl StopSign { } } - fn conflicts_with_accepted(&self, turn: TurnID, geom_map: &GeomMap) -> bool { - let base_t = geom_map.get_t(turn); + fn conflicts_with_accepted(&self, turn: TurnID, map: &Map) -> bool { + let base_t = map.get_t(turn); self.accepted .values() - .find(|t| base_t.conflicts_with(geom_map.get_t(**t))) + .find(|t| base_t.conflicts_with(map.get_t(**t))) .is_some() } fn conflicts_with_waiting_with_higher_priority( &self, turn: TurnID, - geom_map: &GeomMap, + map: &Map, ss: &ControlStopSign, ) -> bool { - let base_t = geom_map.get_t(turn); + let base_t = map.get_t(turn); let base_priority = ss.get_priority(turn); self.waiting .values() - .find(|t| { - base_t.conflicts_with(geom_map.get_t(**t)) && ss.get_priority(**t) > base_priority - }) + .find(|t| base_t.conflicts_with(map.get_t(**t)) && ss.get_priority(**t) > base_priority) .is_some() } @@ -102,7 +99,7 @@ impl StopSign { car: CarID, turn: TurnID, time: Tick, - geom_map: &GeomMap, + map: &Map, control_map: &ControlMap, ) -> bool { // TODO assert turn is in this intersection @@ -115,13 +112,13 @@ impl StopSign { self.started_waiting_at.insert(car, time); } - if self.conflicts_with_accepted(turn, geom_map) { + if self.conflicts_with_accepted(turn, map) { self.waiting.insert(car, turn); return false; } let ss = &control_map.stop_signs[&self.id]; - if self.conflicts_with_waiting_with_higher_priority(turn, geom_map, ss) { + if self.conflicts_with_waiting_with_higher_priority(turn, map, ss) { self.waiting.insert(car, turn); return false; } @@ -169,7 +166,7 @@ impl TrafficSignal { car: CarID, turn: TurnID, time: Tick, - geom_map: &GeomMap, + map: &Map, control_map: &ControlMap, ) -> bool { // TODO assert turn is in this intersection @@ -185,7 +182,7 @@ impl TrafficSignal { return false; } // How long will it take the car to cross the turn? - let crossing_time = geom_map.get_t(turn).length() / SPEED_LIMIT; + let crossing_time = map.get_t(turn).length() / SPEED_LIMIT; // TODO account for TIMESTEP if crossing_time < remaining_cycle_time { diff --git a/sim/src/straw_model.rs b/sim/src/straw_model.rs index d0897e58e4..a491610067 100644 --- a/sim/src/straw_model.rs +++ b/sim/src/straw_model.rs @@ -4,10 +4,10 @@ use common::{CarID, Tick, SPEED_LIMIT}; use control::ControlMap; use dimensioned::si; use ezgui::GfxCtx; -use geom::{geometry, GeomMap, Radian}; use graphics; use graphics::math::Vec2d; -use map_model::{LaneType, Map, Pt2D, RoadID, TurnID}; +use map_model::geometry; +use map_model::{LaneType, Map, Pt2D, Radian, RoadID, TurnID}; use multimap::MultiMap; use rand::{FromEntropy, Rng, SeedableRng, XorShiftRng}; use std::collections::{BTreeMap, HashSet}; @@ -88,17 +88,17 @@ impl On { } } - fn length(&self, geom_map: &GeomMap) -> si::Meter { + fn length(&self, map: &Map) -> si::Meter { match self { - &On::Road(id) => geom_map.get_r(id).length(), - &On::Turn(id) => geom_map.get_t(id).length(), + &On::Road(id) => map.get_r(id).length(), + &On::Turn(id) => map.get_t(id).length(), } } - fn dist_along(&self, dist: si::Meter, geom_map: &GeomMap) -> (Pt2D, Radian) { + fn dist_along(&self, dist: si::Meter, map: &Map) -> (Pt2D, Radian) { match self { - &On::Road(id) => geom_map.get_r(id).dist_along(dist), - &On::Turn(id) => geom_map.get_t(id).dist_along(dist), + &On::Road(id) => map.get_r(id).dist_along(dist), + &On::Turn(id) => map.get_t(id).dist_along(dist), } } } @@ -130,13 +130,13 @@ impl Car { ] } - fn step(&self, geom_map: &GeomMap, map: &Map, time: Tick, rng: &mut XorShiftRng) -> Action { + fn step(&self, map: &Map, time: Tick, rng: &mut XorShiftRng) -> Action { if let Some(on) = self.waiting_for { return Action::Goto(on); } let dist = SPEED_LIMIT * (time - self.started_at).as_time(); - if dist < self.on.length(geom_map) { + if dist < self.on.length(map) { return Action::Continue; } @@ -158,16 +158,12 @@ impl Car { } // Returns the angle and the dist along the road/turn too - fn get_best_case_pos( - &self, - time: Tick, - geom_map: &GeomMap, - ) -> (Pt2D, Radian, si::Meter) { + fn get_best_case_pos(&self, time: Tick, map: &Map) -> (Pt2D, Radian, si::Meter) { let mut dist = SPEED_LIMIT * (time - self.started_at).as_time(); if self.waiting_for.is_some() { - dist = self.on.length(geom_map); + dist = self.on.length(map); } - let (pt, angle) = self.on.dist_along(dist, geom_map); + let (pt, angle) = self.on.dist_along(dist, map); (pt, angle, dist) } } @@ -180,11 +176,11 @@ struct SimQueue { } impl SimQueue { - fn new(id: On, geom_map: &GeomMap) -> SimQueue { + fn new(id: On, map: &Map) -> SimQueue { SimQueue { id, cars_queue: Vec::new(), - capacity: ((id.length(geom_map) / FOLLOWING_DISTANCE).floor() as usize).max(1), + capacity: ((id.length(map) / FOLLOWING_DISTANCE).floor() as usize).max(1), } } @@ -235,27 +231,27 @@ impl SimQueue { // TODO this starts cars with their front aligned with the end of the road, sticking their back // into the intersection. :( - fn get_draw_cars(&self, sim: &Sim, geom_map: &GeomMap) -> Vec { + fn get_draw_cars(&self, sim: &Sim, map: &Map) -> Vec { if self.cars_queue.is_empty() { return Vec::new(); } let mut results = Vec::new(); let (pos1, angle1, dist_along1) = - sim.cars[&self.cars_queue[0]].get_best_case_pos(sim.time, geom_map); + sim.cars[&self.cars_queue[0]].get_best_case_pos(sim.time, map); results.push(DrawCar::new(self.cars_queue[0], &pos1, angle1)); let mut dist_along_bound = dist_along1; for id in self.cars_queue.iter().skip(1) { - let (pos, angle, dist_along) = sim.cars[id].get_best_case_pos(sim.time, geom_map); + let (pos, angle, dist_along) = sim.cars[id].get_best_case_pos(sim.time, map); if dist_along_bound - FOLLOWING_DISTANCE > dist_along { results.push(DrawCar::new(*id, &pos, angle)); dist_along_bound = dist_along; } else { dist_along_bound -= FOLLOWING_DISTANCE; // If not, we violated room_at_end() and reset() didn't catch it - assert!(dist_along_bound >= 0.0 * si::M, "dist_along_bound went negative ({}) for {:?} (length {}) with queue {:?}. first car at {}", dist_along_bound, self.id, self.id.length(geom_map), self.cars_queue, dist_along1); - let (pt, angle) = self.id.dist_along(dist_along_bound, geom_map); + assert!(dist_along_bound >= 0.0 * si::M, "dist_along_bound went negative ({}) for {:?} (length {}) with queue {:?}. first car at {}", dist_along_bound, self.id, self.id.length(map), self.cars_queue, dist_along1); + let (pt, angle) = self.id.dist_along(dist_along_bound, map); results.push(DrawCar::new(*id, &pt, angle)); } } @@ -284,7 +280,7 @@ pub struct Sim { } impl Sim { - pub fn new(map: &Map, geom_map: &GeomMap, rng_seed: Option) -> Sim { + pub fn new(map: &Map, rng_seed: Option) -> Sim { let mut rng = XorShiftRng::from_entropy(); if let Some(seed) = rng_seed { rng = XorShiftRng::from_seed([seed; 16]); @@ -308,11 +304,11 @@ impl Sim { cars: BTreeMap::new(), roads: map.all_roads() .iter() - .map(|r| SimQueue::new(On::Road(r.id), geom_map)) + .map(|r| SimQueue::new(On::Road(r.id), map)) .collect(), turns: map.all_turns() .iter() - .map(|t| SimQueue::new(On::Turn(t.id), geom_map)) + .map(|t| SimQueue::new(On::Turn(t.id), map)) .collect(), time: Tick::zero(), id_counter: 0, @@ -366,7 +362,7 @@ impl Sim { println!("Spawned {}", n); } - pub fn step(&mut self, geom_map: &GeomMap, map: &Map, control_map: &ControlMap) { + pub fn step(&mut self, map: &Map, control_map: &ControlMap) { self.time.increment(); // Could be concurrent. Ask all cars for their move, reinterpreting Goto to see if there's @@ -381,7 +377,7 @@ impl Sim { for c in self.cars.values() { requested_moves.push(( c.id, - match c.step(geom_map, map, self.time, &mut self.rng) { + match c.step(map, self.time, &mut self.rng) { Action::Goto(on) => { // This is a monotonic property in conjunction with // new_car_entered_this_step. The last car won't go backwards. @@ -426,7 +422,7 @@ impl Sim { *id, t, self.time, - geom_map, + map, control_map, ); } @@ -488,11 +484,11 @@ impl Sim { self.cars[&c].waiting_for.is_none() } - pub fn get_draw_cars_on_road(&self, r: RoadID, geom_map: &GeomMap) -> Vec { - let mut cars = self.roads[r.0].get_draw_cars(&self, geom_map); + pub fn get_draw_cars_on_road(&self, r: RoadID, map: &Map) -> Vec { + let mut cars = self.roads[r.0].get_draw_cars(&self, map); for c in &mut cars { if let Some(on) = self.cars[&c.id].waiting_for { - let slope = geom_map.get_t(on.as_turn()).slope(); + let slope = map.get_t(on.as_turn()).slope(); c.turn_arrow = Some([ c.front.x() - (CAR_LENGTH / 2.0) * slope[0], c.front.y() - (CAR_LENGTH / 2.0) * slope[1], @@ -504,8 +500,8 @@ impl Sim { cars } - pub fn get_draw_cars_on_turn(&self, t: TurnID, geom_map: &GeomMap) -> Vec { - self.turns[t.0].get_draw_cars(&self, geom_map) + pub fn get_draw_cars_on_turn(&self, t: TurnID, map: &Map) -> Vec { + self.turns[t.0].get_draw_cars(&self, map) } pub fn summary(&self) -> String { diff --git a/sim/tests/determinism.rs b/sim/tests/determinism.rs index 169f15ce5f..f62ff23f78 100644 --- a/sim/tests/determinism.rs +++ b/sim/tests/determinism.rs @@ -1,5 +1,4 @@ extern crate control; -extern crate geom; extern crate map_model; extern crate sim; @@ -15,11 +14,10 @@ fn from_scratch() { // initialization and plumbing is easier let data = map_model::load_pb(input).expect("Couldn't load input"); let map = map_model::Map::new(&data); - let geom_map = geom::GeomMap::new(&map); - let control_map = control::ControlMap::new(&map, &geom_map); + let control_map = control::ControlMap::new(&map); - let mut sim1 = sim::straw_model::Sim::new(&map, &geom_map, Some(rng_seed)); - let mut sim2 = sim::straw_model::Sim::new(&map, &geom_map, Some(rng_seed)); + let mut sim1 = sim::straw_model::Sim::new(&map, Some(rng_seed)); + let mut sim2 = sim::straw_model::Sim::new(&map, Some(rng_seed)); sim1.spawn_many_on_empty_roads(&map, spawn_count); sim2.spawn_many_on_empty_roads(&map, spawn_count); @@ -31,8 +29,8 @@ fn from_scratch() { sim2.write_savestate("sim2_state.json").unwrap(); panic!("sim state differs at {}. compare sim1_state.json and sim2_state.json", sim1.time); } - sim1.step(&geom_map, &map, &control_map); - sim2.step(&geom_map, &map, &control_map); + sim1.step(&map, &control_map); + sim2.step(&map, &control_map); } } @@ -46,17 +44,16 @@ fn with_savestating() { println!("Creating two simulations"); let data = map_model::load_pb(input).expect("Couldn't load input"); let map = map_model::Map::new(&data); - let geom_map = geom::GeomMap::new(&map); - let control_map = control::ControlMap::new(&map, &geom_map); + let control_map = control::ControlMap::new(&map); - let mut sim1 = sim::straw_model::Sim::new(&map, &geom_map, Some(rng_seed)); - let mut sim2 = sim::straw_model::Sim::new(&map, &geom_map, Some(rng_seed)); + let mut sim1 = sim::straw_model::Sim::new(&map, Some(rng_seed)); + let mut sim2 = sim::straw_model::Sim::new(&map, Some(rng_seed)); sim1.spawn_many_on_empty_roads(&map, spawn_count); sim2.spawn_many_on_empty_roads(&map, spawn_count); for _ in 1..600 { - sim1.step(&geom_map, &map, &control_map); - sim2.step(&geom_map, &map, &control_map); + sim1.step(&map, &control_map); + sim2.step(&map, &control_map); } if sim1 != sim2 { @@ -68,7 +65,7 @@ fn with_savestating() { sim1.write_savestate("sim1_savestate.json").unwrap(); for _ in 1..60 { - sim1.step(&geom_map, &map, &control_map); + sim1.step(&map, &control_map); } if sim1 == sim2 {