removing geom crate, using just map model

This commit is contained in:
Dustin Carlino 2018-06-25 08:50:42 -07:00
parent 4489abd301
commit ba310cbd45
34 changed files with 153 additions and 765 deletions

View File

@ -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"]

View File

@ -5,7 +5,6 @@ authors = ["Dustin Carlino <dabreegster@gmail.com>"]
[dependencies]
dimensioned = "0.6.0"
geom = { path = "../geom" }
map_model = { path = "../map_model" }
serde = "1.0"
serde_derive = "1.0"

View File

@ -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));

View File

@ -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;
}
}

View File

@ -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<Cycle> {
fn greedy_assignment(map: &Map, intersection: IntersectionID) -> Vec<Cycle> {
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;
}
}

View File

@ -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

View File

@ -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"

View File

@ -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;

View File

@ -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));

View File

@ -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<u8>) -> SimController {
pub fn new(map: &Map, rng_seed: Option<u8>) -> 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());
}

View File

@ -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);
}
}
};

View File

@ -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<Color> {
@ -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))

View File

@ -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<Vec2d> = 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<String> {
pub fn tooltip_lines(&self, map: &Map) -> Vec<String> {
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>) -> Vec2d {
[x / len, y / len]
}
fn road_to_line_string(r: map_model::RoadID, geom_map: &GeomMap) -> geo::LineString<f64> {
let pts: Vec<geo::Point<f64>> = geom_map
.get_r(r)
fn road_to_line_string(r: map_model::RoadID, map: &Map) -> geo::LineString<f64> {
let pts: Vec<geo::Point<f64>> = 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(&center_pt)
road_to_line_string(r.id, map).closest_point(&center_pt)
{
return Some((r.id, pt));
}

View File

@ -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;

View File

@ -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<DrawRoad> = 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<TurnID, usize> = 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<DrawTurn> = 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<DrawIntersection> = map.all_intersections()
.iter()
@ -70,7 +69,7 @@ impl DrawMap {
.collect();
let buildings: Vec<DrawBuilding> = map.all_buildings()
.iter()
.map(|b| DrawBuilding::new(b, &bounds, map, geom_map))
.map(|b| DrawBuilding::new(b, &bounds, map))
.collect();
let parcels: Vec<DrawParcel> = map.all_parcels()
.iter()

View File

@ -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;

View File

@ -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;

View File

@ -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<String> {
pub fn tooltip_lines(&self, map: &map_model::Map) -> Vec<String> {
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

View File

@ -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],

View File

@ -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,

View File

@ -1,11 +0,0 @@
[package]
name = "geom"
version = "0.1.0"
authors = ["Dustin Carlino <dabreegster@gmail.com>"]
[dependencies]
aabb-quadtree = "0.1.0"
dimensioned = "0.6.0"
map_model = { path = "../map_model" }
piston2d-graphics = "*"
vecmath = "0.3.1"

View File

@ -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<f64> = 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<Vec<Vec2d>> {
let mut polygons: Vec<Vec<Vec2d>> = 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<Vec2d> {
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<f64>,
) -> Vec<Vec2d> {
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<f64> {
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<f64>) -> 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<Vec2d>]) -> 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<f64> {
// 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
}

View File

@ -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;

View File

@ -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<GeomRoad>,
pub turns: Vec<GeomTurn>,
}
impl GeomMap {
pub fn new(map: &Map) -> GeomMap {
let bounds = map.get_gps_bounds();
let mut roads: Vec<GeomRoad> = Vec::new();
for r in map.all_roads() {
roads.push(GeomRoad::new(r, &bounds));
}
let turns: Vec<GeomTurn> = 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]
}
}

View File

@ -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<Pt2D>,
}
impl GeomRoad {
pub fn new(road: &map_model::Road, bounds: &Bounds) -> GeomRoad {
let mut pts: Vec<Pt2D> = 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<f64>) -> (Pt2D, geometry::angles::Radian<f64>) {
// 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<f64> {
self.lane_center_lines
.iter()
.fold(0.0 * si::M, |so_far, l| {
so_far + geometry::euclid_dist((&l.0, &l.1))
})
}
}

View File

@ -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<f64>) -> (Pt2D, geometry::angles::Radian<f64>) {
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<f64> {
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],
])
}
}

View File

@ -5,7 +5,6 @@ authors = ["Dustin Carlino <dabreegster@gmail.com>"]
[dependencies]
control = { path = "../control" }
geom = { path = "../geom" }
map_model = { path = "../map_model" }
sim = { path = "../sim" }
structopt = "0.2"

View File

@ -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);

View File

@ -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;

View File

@ -7,7 +7,6 @@ authors = ["Dustin Carlino <dabreegster@gmail.com>"]
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"

View File

@ -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;

View File

@ -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 {

View File

@ -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<f64> {
fn length(&self, map: &Map) -> si::Meter<f64> {
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<f64>, geom_map: &GeomMap) -> (Pt2D, Radian<f64>) {
fn dist_along(&self, dist: si::Meter<f64>, map: &Map) -> (Pt2D, Radian<f64>) {
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<f64>, si::Meter<f64>) {
fn get_best_case_pos(&self, time: Tick, map: &Map) -> (Pt2D, Radian<f64>, si::Meter<f64>) {
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<DrawCar> {
fn get_draw_cars(&self, sim: &Sim, map: &Map) -> Vec<DrawCar> {
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<u8>) -> Sim {
pub fn new(map: &Map, rng_seed: Option<u8>) -> 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<DrawCar> {
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<DrawCar> {
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<DrawCar> {
self.turns[t.0].get_draw_cars(&self, geom_map)
pub fn get_draw_cars_on_turn(&self, t: TurnID, map: &Map) -> Vec<DrawCar> {
self.turns[t.0].get_draw_cars(&self, map)
}
pub fn summary(&self) -> String {

View File

@ -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 {