adding error messages for map model queries that can fail

This commit is contained in:
Dustin Carlino 2018-10-10 10:02:46 -07:00
parent e681032866
commit 843742b708
7 changed files with 76 additions and 25 deletions

View File

@ -6,6 +6,7 @@ authors = ["Dustin Carlino <dabreegster@gmail.com>"]
[dependencies] [dependencies]
abstutil = { path = "../abstutil" } abstutil = { path = "../abstutil" }
dimensioned = { git = "https://github.com/paholg/dimensioned", rev = "0e1076ebfa5128d1ee544bdc9754c948987b6fe3", features = ["serde"] } dimensioned = { git = "https://github.com/paholg/dimensioned", rev = "0e1076ebfa5128d1ee544bdc9754c948987b6fe3", features = ["serde"] }
failure = "0.1.2"
flame = "0.2.2" flame = "0.2.2"
geo = "0.9.1" geo = "0.9.1"
geom = { path = "../geom" } geom = { path = "../geom" }

View File

@ -1,5 +1,7 @@
extern crate abstutil; extern crate abstutil;
extern crate dimensioned; extern crate dimensioned;
#[macro_use]
extern crate failure;
extern crate flame; extern crate flame;
extern crate geo; extern crate geo;
extern crate geom; extern crate geom;
@ -46,3 +48,15 @@ pub use traversable::Traversable;
pub use turn::{Turn, TurnID}; pub use turn::{Turn, TurnID};
pub const LANE_THICKNESS: f64 = 2.5; pub const LANE_THICKNESS: f64 = 2.5;
#[derive(Debug, Fail)]
#[fail(display = "{}", reason)]
pub struct MapError {
reason: String,
}
impl MapError {
pub fn new(reason: String) -> MapError {
MapError { reason }
}
}

View File

@ -35,7 +35,7 @@ pub fn make_bus_stops(
for (id, dists) in stops_per_sidewalk.iter_all_mut() { for (id, dists) in stops_per_sidewalk.iter_all_mut() {
let road = &roads[lanes[id.0].parent.0]; let road = &roads[lanes[id.0].parent.0];
if let Some(driving_lane) = road.find_driving_lane_from_sidewalk(*id) { if let Ok(driving_lane) = road.find_driving_lane_from_sidewalk(*id) {
dists.sort_by_key(|(dist, _)| NotNaN::new(dist.value_unsafe).unwrap()); dists.sort_by_key(|(dist, _)| NotNaN::new(dist.value_unsafe).unwrap());
for (idx, (dist_along, orig_pt)) in dists.iter().enumerate() { for (idx, (dist_along, orig_pt)) in dists.iter().enumerate() {
let stop_id = BusStopID { sidewalk: *id, idx }; let stop_id = BusStopID { sidewalk: *id, idx };

View File

@ -2,12 +2,12 @@
use abstutil; use abstutil;
use edits::RoadEdits; use edits::RoadEdits;
use failure::{Error, ResultExt};
use flame; use flame;
use geom::{Bounds, HashablePt2D, PolyLine, Pt2D}; use geom::{Bounds, HashablePt2D, PolyLine, Pt2D};
use make; use make;
use raw_data; use raw_data;
use std::collections::{BTreeMap, BTreeSet, HashMap}; use std::collections::{BTreeMap, BTreeSet, HashMap};
use std::io::Error;
use std::path; use std::path;
use { use {
Area, AreaID, Building, BuildingID, BusRoute, BusStop, BusStopID, Intersection, IntersectionID, Area, AreaID, Building, BuildingID, BusRoute, BusStop, BusStopID, Intersection, IntersectionID,
@ -379,24 +379,26 @@ impl Map {
self.bounds.clone() self.bounds.clone()
} }
pub fn get_driving_lane_from_bldg(&self, bldg: BuildingID) -> Option<LaneID> { pub fn get_driving_lane_from_bldg(&self, bldg: BuildingID) -> Result<LaneID, Error> {
let sidewalk = self.get_b(bldg).front_path.sidewalk; let sidewalk = self.get_b(bldg).front_path.sidewalk;
let road = self.get_parent(sidewalk); let road = self.get_parent(sidewalk);
let parking = road.find_parking_lane(sidewalk)?; road.find_parking_lane(sidewalk)
road.find_driving_lane(parking) .and_then(|parking| road.find_driving_lane(parking))
.context(format!("get_driving_lane_from_bldg({})", bldg))
} }
pub fn get_sidewalk_from_driving_lane(&self, driving: LaneID) -> Option<LaneID> { pub fn get_sidewalk_from_driving_lane(&self, driving: LaneID) -> Result<LaneID, Error> {
let road = self.get_parent(driving); let road = self.get_parent(driving);
// No parking lane? // No parking lane?
if let Some(l) = road.find_sidewalk(driving) { if let Ok(l) = road.find_sidewalk(driving) {
return Some(l); return Ok(l);
} }
let parking = road.find_parking_lane(driving)?; road.find_parking_lane(driving)
road.find_sidewalk(parking) .and_then(|parking| road.find_sidewalk(parking))
.context(format!("get_sidewalk_from_driving_lane({})", driving))
} }
pub fn get_driving_lane_from_parking(&self, parking: LaneID) -> Option<LaneID> { pub fn get_driving_lane_from_parking(&self, parking: LaneID) -> Result<LaneID, Error> {
self.get_parent(parking).find_driving_lane(parking) self.get_parent(parking).find_driving_lane(parking)
} }

View File

@ -1,8 +1,9 @@
use dimensioned::si; use dimensioned::si;
use failure::Error;
use geom::PolyLine; use geom::PolyLine;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::fmt; use std::fmt;
use {LaneID, LaneType}; use {LaneID, LaneType, MapError};
// TODO reconsider pub usize. maybe outside world shouldnt know. // TODO reconsider pub usize. maybe outside world shouldnt know.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
@ -82,25 +83,37 @@ impl Road {
lane == self.children_backwards[0].0 lane == self.children_backwards[0].0
} }
pub fn find_sidewalk(&self, parking_or_driving: LaneID) -> Option<LaneID> { pub fn find_sidewalk(&self, parking_or_driving: LaneID) -> Result<LaneID, Error> {
self.get_siblings(parking_or_driving) self.get_siblings(parking_or_driving)
.iter() .iter()
.find(|pair| pair.1 == LaneType::Sidewalk) .find(|pair| pair.1 == LaneType::Sidewalk)
.map(|pair| pair.0) .map(|pair| pair.0)
.ok_or_else(|| {
Error::from(MapError::new(format!(
"{} doesn't have sidewalk sibling",
parking_or_driving
)))
})
} }
pub fn find_driving_lane(&self, parking: LaneID) -> Option<LaneID> { pub fn find_driving_lane(&self, parking: LaneID) -> Result<LaneID, Error> {
//assert_eq!(l.lane_type, LaneType::Parking); //assert_eq!(l.lane_type, LaneType::Parking);
self.get_siblings(parking) self.get_siblings(parking)
.iter() .iter()
.find(|pair| pair.1 == LaneType::Driving) .find(|pair| pair.1 == LaneType::Driving)
.map(|pair| pair.0) .map(|pair| pair.0)
.ok_or_else(|| {
Error::from(MapError::new(format!(
"{} doesn't have driving lane sibling",
parking
)))
})
} }
// Handles intermediate parking and bus lanes and such // Handles intermediate parking and bus lanes and such
// Additionally handles one-ways with a sidewalk on only one side. // Additionally handles one-ways with a sidewalk on only one side.
// TODO but in reality, there probably isn't a sidewalk on the other side of the one-way. :\ // TODO but in reality, there probably isn't a sidewalk on the other side of the one-way. :\
pub fn find_driving_lane_from_sidewalk(&self, sidewalk: LaneID) -> Option<LaneID> { pub fn find_driving_lane_from_sidewalk(&self, sidewalk: LaneID) -> Result<LaneID, Error> {
let (this_side, opposite, idx) = if let Some(idx) = self let (this_side, opposite, idx) = if let Some(idx) = self
.children_forwards .children_forwards
.iter() .iter()
@ -125,25 +138,34 @@ impl Road {
.find(|(_, lt)| *lt == LaneType::Driving) .find(|(_, lt)| *lt == LaneType::Driving)
.map(|(l, _)| *l) .map(|(l, _)| *l)
{ {
return Some(l); return Ok(l);
} }
// Is the sidewalk on a one-way with the other side having a driving lane? // Is the sidewalk on a one-way with the other side having a driving lane?
if this_side.len() == 1 && opposite[0].1 == LaneType::Driving { if this_side.len() == 1 && opposite[0].1 == LaneType::Driving {
return Some(opposite[0].0); return Ok(opposite[0].0);
} }
None bail!(MapError::new(format!(
"Sidewalk {} doesn't have driving lane",
sidewalk
)));
} }
pub fn find_parking_lane(&self, driving: LaneID) -> Option<LaneID> { pub fn find_parking_lane(&self, driving: LaneID) -> Result<LaneID, Error> {
//assert_eq!(l.lane_type, LaneType::Driving); //assert_eq!(l.lane_type, LaneType::Driving);
self.get_siblings(driving) self.get_siblings(driving)
.iter() .iter()
.find(|pair| pair.1 == LaneType::Parking) .find(|pair| pair.1 == LaneType::Parking)
.map(|pair| pair.0) .map(|pair| pair.0)
.ok_or_else(|| {
Error::from(MapError::new(format!(
"{} doesn't have parking lane sibling",
driving
)))
})
} }
pub fn get_opposite_lane(&self, lane: LaneID, lane_type: LaneType) -> Option<LaneID> { pub fn get_opposite_lane(&self, lane: LaneID, lane_type: LaneType) -> Result<LaneID, Error> {
let forwards: Vec<LaneID> = self let forwards: Vec<LaneID> = self
.children_forwards .children_forwards
.iter() .iter()
@ -158,10 +180,20 @@ impl Road {
.collect(); .collect();
if let Some(idx) = forwards.iter().position(|id| *id == lane) { if let Some(idx) = forwards.iter().position(|id| *id == lane) {
return backwards.get(idx).map(|id| *id); return backwards.get(idx).map(|id| *id).ok_or_else(|| {
Error::from(MapError::new(format!(
"{} doesn't have opposite lane of type {:?}",
lane, lane_type
)))
});
} }
if let Some(idx) = backwards.iter().position(|id| *id == lane) { if let Some(idx) = backwards.iter().position(|id| *id == lane) {
return forwards.get(idx).map(|id| *id); return forwards.get(idx).map(|id| *id).ok_or_else(|| {
Error::from(MapError::new(format!(
"{} doesn't have opposite lane of type {:?}",
lane, lane_type
)))
});
} }
panic!("{} doesn't contain {}", self.id, lane); panic!("{} doesn't contain {}", self.id, lane);
} }

View File

@ -202,12 +202,13 @@ impl Sim {
let has_bldgs = map let has_bldgs = map
.get_parent(lane) .get_parent(lane)
.find_sidewalk(lane) .find_sidewalk(lane)
.and_then(|sidewalk| Some(!map.get_l(sidewalk).building_paths.is_empty())) .and_then(|sidewalk| Ok(!map.get_l(sidewalk).building_paths.is_empty()))
.unwrap_or(false); .unwrap_or(false);
if has_bldgs { if has_bldgs {
map.get_parent(lane) map.get_parent(lane)
.find_driving_lane(lane) .find_driving_lane(lane)
.and_then(|_driving_lane| Some(parked_car.car)) .and_then(|_driving_lane| Ok(parked_car.car))
.ok()
} else { } else {
None None
} }
@ -325,7 +326,7 @@ fn pick_car_goal<R: Rng + ?Sized>(rng: &mut R, map: &Map, start: LaneID) -> Lane
.iter() .iter()
.filter_map(|l| { .filter_map(|l| {
if l.id != start && l.is_driving() { if l.id != start && l.is_driving() {
if let Some(sidewalk) = map.get_sidewalk_from_driving_lane(l.id) { if let Ok(sidewalk) = map.get_sidewalk_from_driving_lane(l.id) {
if !map.get_l(sidewalk).building_paths.is_empty() { if !map.get_l(sidewalk).building_paths.is_empty() {
return Some(l.id); return Some(l.id);
} }

View File

@ -213,6 +213,7 @@ fn find_parking_spot(
) -> Option<ParkingSpot> { ) -> Option<ParkingSpot> {
map.get_parent(driving_lane) map.get_parent(driving_lane)
.find_parking_lane(driving_lane) .find_parking_lane(driving_lane)
.ok()
.and_then(|l| parking_sim.get_first_free_spot(l, dist_along)) .and_then(|l| parking_sim.get_first_free_spot(l, dist_along))
} }