switching to new units in map_model

This commit is contained in:
Dustin Carlino 2019-01-30 12:43:10 -08:00
parent 976369e7e8
commit 133ec037c9
20 changed files with 150 additions and 147 deletions

View File

@ -116,7 +116,7 @@ impl GPSBounds {
.gps_dist_meters(LonLat::new(self.max_lon, self.min_lat)); .gps_dist_meters(LonLat::new(self.max_lon, self.min_lat));
let height = LonLat::new(self.min_lon, self.min_lat) let height = LonLat::new(self.min_lon, self.min_lat)
.gps_dist_meters(LonLat::new(self.min_lon, self.max_lat)); .gps_dist_meters(LonLat::new(self.min_lon, self.max_lat));
Pt2D::new(width.inner(), height.inner()) Pt2D::new(width.inner_meters(), height.inner_meters())
} }
pub fn to_bounds(&self) -> Bounds { pub fn to_bounds(&self) -> Bounds {

View File

@ -1,7 +1,6 @@
use crate::{ use crate::{
Angle, Bounds, Distance, HashablePt2D, InfiniteLine, Line, Polygon, Pt2D, EPSILON_DIST, Angle, Bounds, Distance, HashablePt2D, InfiniteLine, Line, Polygon, Pt2D, EPSILON_DIST,
}; };
use ordered_float::NotNan;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::collections::HashSet; use std::collections::HashSet;
use std::f64; use std::f64;
@ -357,13 +356,10 @@ impl PolyLine {
} }
hits.sort_by_key(|(pt, _)| { hits.sort_by_key(|(pt, _)| {
NotNan::new(
self.get_slice_ending_at(*pt) self.get_slice_ending_at(*pt)
.map(|pl| pl.length()) .map(|pl| pl.length())
.unwrap_or(Distance::ZERO) .unwrap_or(Distance::ZERO)
.inner(), .as_ordered()
)
.unwrap()
}); });
if !hits.is_empty() { if !hits.is_empty() {
return Some(hits[0]); return Some(hits[0]);

View File

@ -1,3 +1,4 @@
use ordered_float::NotNan;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::{fmt, ops}; use std::{fmt, ops};
@ -29,8 +30,13 @@ impl Distance {
} }
} }
// TODO Only used within this crate for NotNan construction and GPS->Pt2D. // TODO Remove by making Distance itself Ord.
pub(crate) fn inner(self) -> f64 { pub fn as_ordered(self) -> NotNan<f64> {
NotNan::new(self.0).unwrap()
}
// TODO Remove if possible.
pub fn inner_meters(self) -> f64 {
self.0 self.0
} }
} }
@ -70,6 +76,14 @@ impl ops::SubAssign for Distance {
} }
} }
impl ops::Mul<f64> for Distance {
type Output = Distance;
fn mul(self, scalar: f64) -> Distance {
Distance::meters(self.0 * scalar)
}
}
impl ops::Div<Distance> for Distance { impl ops::Div<Distance> for Distance {
type Output = f64; type Output = f64;
@ -84,11 +98,11 @@ impl ops::Div<Distance> for Distance {
impl ops::Div<f64> for Distance { impl ops::Div<f64> for Distance {
type Output = Distance; type Output = Distance;
fn div(self, other: f64) -> Distance { fn div(self, scalar: f64) -> Distance {
if other == 0.0 { if scalar == 0.0 {
panic!("Can't divide {} / {}", self, other); panic!("Can't divide {} / {}", self, scalar);
} }
Distance::meters(self.0 / other) Distance::meters(self.0 / scalar)
} }
} }
@ -104,6 +118,10 @@ impl Duration {
Duration(value) Duration(value)
} }
pub const fn const_seconds(value: f64) -> Duration {
Duration(value)
}
} }
impl fmt::Display for Duration { impl fmt::Display for Duration {
@ -112,6 +130,33 @@ impl fmt::Display for Duration {
} }
} }
impl ops::Sub for Duration {
type Output = Duration;
fn sub(self, other: Duration) -> Duration {
Duration::seconds(self.0 - other.0)
}
}
impl ops::Mul<f64> for Duration {
type Output = Duration;
fn mul(self, other: f64) -> Duration {
Duration::seconds(self.0 * other)
}
}
impl ops::Div<Duration> for Duration {
type Output = f64;
fn div(self, other: Duration) -> f64 {
if other.0 == 0.0 {
panic!("Can't divide {} / {}", self, other);
}
self.0 / other.0
}
}
// In meters per second. Can be negative. // In meters per second. Can be negative.
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
pub struct Speed(f64); pub struct Speed(f64);
@ -124,6 +169,10 @@ impl Speed {
Speed(value) Speed(value)
} }
pub fn miles_per_hour(value: f64) -> Speed {
Speed::meters_per_second(0.44704 * value)
}
} }
impl fmt::Display for Speed { impl fmt::Display for Speed {

View File

@ -7,7 +7,6 @@ edition = "2018"
[dependencies] [dependencies]
aabb-quadtree = "0.1.0" aabb-quadtree = "0.1.0"
abstutil = { path = "../abstutil" } abstutil = { path = "../abstutil" }
dimensioned = { git = "https://github.com/paholg/dimensioned", rev = "0e1076ebfa5128d1ee544bdc9754c948987b6fe3", features = ["serde"] }
geo = "0.11.0" geo = "0.11.0"
geom = { path = "../geom" } geom = { path = "../geom" }
gtfs = { path = "../gtfs" } gtfs = { path = "../gtfs" }

View File

@ -1,10 +1,8 @@
use aabb_quadtree::geom::{Point, Rect}; use aabb_quadtree::geom::{Point, Rect};
use aabb_quadtree::QuadTree; use aabb_quadtree::QuadTree;
use dimensioned::si;
use geo; use geo;
use geo::prelude::{ClosestPoint, EuclideanDistance}; use geo::prelude::{ClosestPoint, EuclideanDistance};
use geom::{Bounds, PolyLine, Pt2D}; use geom::{Bounds, Distance, PolyLine, Pt2D};
use ordered_float::NotNan;
use std::collections::HashMap; use std::collections::HashMap;
// TODO Refactor and generalize all of this... // TODO Refactor and generalize all of this...
@ -33,16 +31,16 @@ where
} }
// Finds the closest point on the existing geometry to the query pt. // Finds the closest point on the existing geometry to the query pt.
pub fn closest_pt(&self, query_pt: Pt2D, max_dist_away: si::Meter<f64>) -> Option<(K, Pt2D)> { pub fn closest_pt(&self, query_pt: Pt2D, max_dist_away: Distance) -> Option<(K, Pt2D)> {
let query_geom = geo::Point::new(query_pt.x(), query_pt.y()); let query_geom = geo::Point::new(query_pt.x(), query_pt.y());
let query_bbox = Rect { let query_bbox = Rect {
top_left: Point { top_left: Point {
x: (query_pt.x() - max_dist_away.value_unsafe) as f32, x: (query_pt.x() - max_dist_away.inner_meters()) as f32,
y: (query_pt.y() - max_dist_away.value_unsafe) as f32, y: (query_pt.y() - max_dist_away.inner_meters()) as f32,
}, },
bottom_right: Point { bottom_right: Point {
x: (query_pt.x() + max_dist_away.value_unsafe) as f32, x: (query_pt.x() + max_dist_away.inner_meters()) as f32,
y: (query_pt.y() + max_dist_away.value_unsafe) as f32, y: (query_pt.y() + max_dist_away.inner_meters()) as f32,
}, },
}; };
@ -53,9 +51,9 @@ where
if let geo::Closest::SinglePoint(pt) = if let geo::Closest::SinglePoint(pt) =
self.geometries[&key].closest_point(&query_geom) self.geometries[&key].closest_point(&query_geom)
{ {
let dist = pt.euclidean_distance(&query_geom); let dist = Distance::meters(pt.euclidean_distance(&query_geom));
if dist * si::M <= max_dist_away { if dist <= max_dist_away {
Some((key, pt, NotNan::new(dist).unwrap())) Some((key, pt, dist.as_ordered()))
} else { } else {
None None
} }

View File

@ -1,7 +1,6 @@
use crate::{raw_data, LaneID, LaneType, Map, RoadID, TurnID}; use crate::{raw_data, LaneID, LaneType, Map, RoadID, TurnID};
use abstutil; use abstutil;
use dimensioned::si; use geom::{Distance, Polygon, Pt2D};
use geom::{Polygon, Pt2D};
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::collections::BTreeSet; use std::collections::BTreeSet;
use std::fmt; use std::fmt;
@ -30,7 +29,7 @@ pub struct Intersection {
// This needs to be in clockwise orientation, or later rendering of sidewalk corners breaks. // This needs to be in clockwise orientation, or later rendering of sidewalk corners breaks.
pub polygon: Polygon, pub polygon: Polygon,
pub turns: Vec<TurnID>, pub turns: Vec<TurnID>,
pub elevation: si::Meter<f64>, pub elevation: Distance,
pub intersection_type: IntersectionType, pub intersection_type: IntersectionType,
pub label: Option<String>, pub label: Option<String>,

View File

@ -1,17 +1,11 @@
use crate::{BuildingID, BusStopID, IntersectionID, RoadID}; use crate::{BuildingID, BusStopID, IntersectionID, RoadID};
use abstutil; use abstutil;
use dimensioned::si; use geom::{Angle, Distance, Line, PolyLine, Pt2D};
use geom::{Angle, Line, PolyLine, Pt2D};
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std;
use std::f64;
use std::fmt; use std::fmt;
pub const PARKING_SPOT_LENGTH: si::Meter<f64> = si::Meter { // Bit longer than the longest car.
// Bit longer than the longest car. pub const PARKING_SPOT_LENGTH: Distance = Distance::const_meters(8.0);
value_unsafe: 8.0,
_marker: std::marker::PhantomData,
};
// 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)]
@ -83,21 +77,21 @@ impl Lane {
} }
} }
pub fn dist_along(&self, dist_along: si::Meter<f64>) -> (Pt2D, Angle) { pub fn dist_along(&self, dist_along: Distance) -> (Pt2D, Angle) {
self.lane_center_pts.dist_along(dist_along) self.lane_center_pts.dist_along(dist_along)
} }
pub fn safe_dist_along(&self, dist_along: si::Meter<f64>) -> Option<(Pt2D, Angle)> { pub fn safe_dist_along(&self, dist_along: Distance) -> Option<(Pt2D, Angle)> {
self.lane_center_pts.safe_dist_along(dist_along) self.lane_center_pts.safe_dist_along(dist_along)
} }
pub fn dist_along_of_point(&self, pt: Pt2D) -> Option<si::Meter<f64>> { pub fn dist_along_of_point(&self, pt: Pt2D) -> Option<Distance> {
self.lane_center_pts self.lane_center_pts
.dist_along_of_point(pt) .dist_along_of_point(pt)
.map(|(dist, _)| dist) .map(|(dist, _)| dist)
} }
pub fn length(&self) -> si::Meter<f64> { pub fn length(&self) -> Distance {
self.lane_center_pts.length() self.lane_center_pts.length()
} }

View File

@ -1,8 +1,7 @@
use crate::make::sidewalk_finder::find_sidewalk_points; use crate::make::sidewalk_finder::find_sidewalk_points;
use crate::{raw_data, Building, BuildingID, FrontPath, Lane}; use crate::{raw_data, Building, BuildingID, FrontPath, Lane};
use abstutil::Timer; use abstutil::Timer;
use dimensioned::si; use geom::{Bounds, Distance, GPSBounds, HashablePt2D, Line, Pt2D};
use geom::{Bounds, GPSBounds, HashablePt2D, Line, Pt2D};
use std::collections::HashSet; use std::collections::HashSet;
pub fn make_all_buildings( pub fn make_all_buildings(
@ -34,7 +33,7 @@ pub fn make_all_buildings(
} }
// Skip buildings that're too far away from their sidewalk // Skip buildings that're too far away from their sidewalk
let sidewalk_pts = find_sidewalk_points(bounds, query, lanes, 100.0 * si::M, timer); let sidewalk_pts = find_sidewalk_points(bounds, query, lanes, Distance::meters(100.0), timer);
timer.start_iter("create building front paths", pts_per_bldg.len()); timer.start_iter("create building front paths", pts_per_bldg.len());
for (idx, points) in pts_per_bldg.into_iter().enumerate() { for (idx, points) in pts_per_bldg.into_iter().enumerate() {

View File

@ -4,11 +4,9 @@ use crate::{
Position, Position,
}; };
use abstutil::Timer; use abstutil::Timer;
use dimensioned::si; use geom::{Bounds, Distance, GPSBounds, HashablePt2D, Pt2D};
use geom::{Bounds, GPSBounds, HashablePt2D, Pt2D};
use gtfs; use gtfs;
use multimap::MultiMap; use multimap::MultiMap;
use ordered_float::NotNan;
use std::collections::{BTreeMap, HashMap, HashSet}; use std::collections::{BTreeMap, HashMap, HashSet};
use std::iter; use std::iter;
@ -32,9 +30,15 @@ pub fn make_bus_stops(
} }
} }
let mut stops_per_sidewalk: MultiMap<LaneID, (si::Meter<f64>, HashablePt2D)> = MultiMap::new(); let mut stops_per_sidewalk: MultiMap<LaneID, (Distance, HashablePt2D)> = MultiMap::new();
for (pt, pos) in for (pt, pos) in find_sidewalk_points(
find_sidewalk_points(bounds, bus_stop_pts, map.all_lanes(), 10.0 * si::M, timer).into_iter() bounds,
bus_stop_pts,
map.all_lanes(),
Distance::meters(10.0),
timer,
)
.into_iter()
{ {
stops_per_sidewalk.insert(pos.lane(), (pos.dist_along(), pt)); stops_per_sidewalk.insert(pos.lane(), (pos.dist_along(), pt));
} }
@ -46,7 +50,7 @@ pub fn make_bus_stops(
if let Ok(driving_lane) = if let Ok(driving_lane) =
road.find_closest_lane(*id, vec![LaneType::Driving, LaneType::Bus]) road.find_closest_lane(*id, vec![LaneType::Driving, LaneType::Bus])
{ {
dists.sort_by_key(|(dist, _)| NotNan::new(dist.value_unsafe).unwrap()); dists.sort_by_key(|(dist, _)| dist.as_ordered());
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 };
point_to_stop_id.insert(*orig_pt, stop_id); point_to_stop_id.insert(*orig_pt, stop_id);

View File

@ -4,7 +4,6 @@ use crate::{
}; };
use abstutil::Timer; use abstutil::Timer;
use geom::{Bounds, GPSBounds, Polygon, Pt2D}; use geom::{Bounds, GPSBounds, Polygon, Pt2D};
use ordered_float::NotNan;
use std::collections::BTreeMap; use std::collections::BTreeMap;
pub struct HalfMap { pub struct HalfMap {
@ -171,14 +170,11 @@ pub fn make_half_map(
let mut bldgs = half_map.lanes[lane.0].building_paths.clone(); let mut bldgs = half_map.lanes[lane.0].building_paths.clone();
bldgs.push(b.id); bldgs.push(b.id);
bldgs.sort_by_key(|b| { bldgs.sort_by_key(|b| {
NotNan::new(
half_map.buildings[b.0] half_map.buildings[b.0]
.front_path .front_path
.sidewalk .sidewalk
.dist_along() .dist_along()
.value_unsafe, .as_ordered()
)
.unwrap()
}); });
half_map.lanes[lane.0].building_paths = bldgs; half_map.lanes[lane.0].building_paths = bldgs;
} }

View File

@ -1,15 +1,10 @@
use crate::make::initial::{Intersection, Road}; use crate::make::initial::{Intersection, Road};
use crate::raw_data::{StableIntersectionID, StableRoadID}; use crate::raw_data::{StableIntersectionID, StableRoadID};
use abstutil::wraparound_get; use abstutil::wraparound_get;
use dimensioned::si; use geom::{Angle, Distance, HashablePt2D, Line, PolyLine, Pt2D};
use geom::{Angle, HashablePt2D, Line, PolyLine, Pt2D};
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
use std::marker;
const DEGENERATE_INTERSECTION_HALF_LENGTH: si::Meter<f64> = si::Meter { const DEGENERATE_INTERSECTION_HALF_LENGTH: Distance = Distance::const_meters(5.0);
value_unsafe: 5.0,
_marker: marker::PhantomData,
};
// The polygon should exist entirely within the thick bands around all original roads -- it just // The polygon should exist entirely within the thick bands around all original roads -- it just
// carves up part of that space, doesn't reach past it. // carves up part of that space, doesn't reach past it.
@ -86,7 +81,7 @@ fn generalized_trim_back(
let mut shortest_center = if road_center.length() >= DEGENERATE_INTERSECTION_HALF_LENGTH { let mut shortest_center = if road_center.length() >= DEGENERATE_INTERSECTION_HALF_LENGTH {
road_center road_center
.slice( .slice(
0.0 * si::M, Distance::ZERO,
road_center.length() - DEGENERATE_INTERSECTION_HALF_LENGTH, road_center.length() - DEGENERATE_INTERSECTION_HALF_LENGTH,
) )
.unwrap() .unwrap()
@ -181,7 +176,7 @@ fn generalized_trim_back(
} }
} }
endpoints.sort_by_key(|pt| HashablePt2D::from(*pt)); endpoints.sort_by_key(|pt| HashablePt2D::from(*pt));
endpoints = Pt2D::approx_dedupe(endpoints, 1.0 * si::M); endpoints = Pt2D::approx_dedupe(endpoints, Distance::meters(1.0));
let center = Pt2D::center(&endpoints); let center = Pt2D::center(&endpoints);
endpoints.sort_by_key(|pt| Line::new(center, *pt).angle().normalized_degrees() as i64); endpoints.sort_by_key(|pt| Line::new(center, *pt).angle().normalized_degrees() as i64);
@ -217,7 +212,7 @@ fn deadend(
r.trimmed_center_pts = r r.trimmed_center_pts = r
.trimmed_center_pts .trimmed_center_pts
.slice( .slice(
0.0 * si::M, Distance::ZERO,
r.trimmed_center_pts.length() - DEGENERATE_INTERSECTION_HALF_LENGTH * 2.0, r.trimmed_center_pts.length() - DEGENERATE_INTERSECTION_HALF_LENGTH * 2.0,
) )
.unwrap() .unwrap()

View File

@ -1,7 +1,7 @@
use crate::make::initial::{geometry, InitialMap}; use crate::make::initial::{geometry, InitialMap};
use crate::raw_data::StableRoadID; use crate::raw_data::StableRoadID;
use abstutil::note; use abstutil::note;
use dimensioned::si; use geom::Distance;
pub fn short_roads(map: &mut InitialMap) { pub fn short_roads(map: &mut InitialMap) {
if false { if false {
@ -29,7 +29,7 @@ pub fn short_roads(map: &mut InitialMap) {
if let Some(r) = map if let Some(r) = map
.roads .roads
.values() .values()
.find(|r| r.trimmed_center_pts.length() < 15.0 * si::M) .find(|r| r.trimmed_center_pts.length() < Distance::meters(15.0))
{ {
merge(map, r.id); merge(map, r.id);
} else { } else {

View File

@ -1,8 +1,7 @@
use crate::make::sidewalk_finder::find_sidewalk_points; use crate::make::sidewalk_finder::find_sidewalk_points;
use crate::{raw_data, Lane, Parcel, ParcelID}; use crate::{raw_data, Lane, Parcel, ParcelID};
use abstutil::Timer; use abstutil::Timer;
use dimensioned::si; use geom::{Bounds, Distance, GPSBounds, HashablePt2D, Pt2D};
use geom::{Bounds, GPSBounds, HashablePt2D, Pt2D};
use std::collections::HashSet; use std::collections::HashSet;
pub fn make_all_parcels( pub fn make_all_parcels(
@ -32,7 +31,7 @@ pub fn make_all_parcels(
} }
// Trim parcels that are too far away from the nearest sidewalk // Trim parcels that are too far away from the nearest sidewalk
let sidewalk_pts = find_sidewalk_points(bounds, query, lanes, 100.0 * si::M, timer); let sidewalk_pts = find_sidewalk_points(bounds, query, lanes, Distance::meters(100.0), timer);
for (idx, center) in center_per_parcel.into_iter().enumerate() { for (idx, center) in center_per_parcel.into_iter().enumerate() {
if sidewalk_pts.contains_key(&center) { if sidewalk_pts.contains_key(&center) {

View File

@ -1,7 +1,6 @@
use crate::{FindClosest, Lane, LaneID, Position}; use crate::{FindClosest, Lane, LaneID, Position};
use abstutil::Timer; use abstutil::Timer;
use dimensioned::si; use geom::{Bounds, Distance, HashablePt2D};
use geom::{Bounds, HashablePt2D};
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
// If the result doesn't contain a requested point, then there was no matching sidewalk close // If the result doesn't contain a requested point, then there was no matching sidewalk close
@ -10,7 +9,7 @@ pub fn find_sidewalk_points(
bounds: &Bounds, bounds: &Bounds,
pts: HashSet<HashablePt2D>, pts: HashSet<HashablePt2D>,
lanes: &Vec<Lane>, lanes: &Vec<Lane>,
max_dist_away: si::Meter<f64>, max_dist_away: Distance,
timer: &mut Timer, timer: &mut Timer,
) -> HashMap<HashablePt2D, Position> { ) -> HashMap<HashablePt2D, Position> {
if pts.is_empty() { if pts.is_empty() {

View File

@ -3,8 +3,7 @@ use crate::{
TurnType, LANE_THICKNESS, TurnType, LANE_THICKNESS,
}; };
use abstutil::wraparound_get; use abstutil::wraparound_get;
use dimensioned::si; use geom::{Distance, Line, PolyLine, Pt2D};
use geom::{Line, PolyLine, Pt2D};
use nbez::{Bez3o, BezCurve, Point2d}; use nbez::{Bez3o, BezCurve, Point2d};
use std::collections::{BTreeSet, HashSet}; use std::collections::{BTreeSet, HashSet};
use std::iter; use std::iter;
@ -324,8 +323,8 @@ fn make_vehicle_turn(lanes: &Vec<&Lane>, i: IntersectionID, l1: LaneID, l2: Lane
// TODO Tune the 5.0 and pieces // TODO Tune the 5.0 and pieces
let curve = Bez3o::new( let curve = Bez3o::new(
to_pt(src.last_pt()), to_pt(src.last_pt()),
to_pt(src_line.unbounded_dist_along(src_line.length() + 5.0 * si::M)), to_pt(src_line.unbounded_dist_along(src_line.length() + Distance::meters(5.0))),
to_pt(dst_line.unbounded_dist_along(dst_line.length() + 5.0 * si::M)), to_pt(dst_line.unbounded_dist_along(dst_line.length() + Distance::meters(5.0))),
to_pt(dst.first_pt()), to_pt(dst.first_pt()),
); );
let pieces = 5; let pieces = 5;

View File

@ -1,6 +1,5 @@
use crate::{BusRouteID, BusStopID, LaneID, LaneType, Map, Position, Traversable, TurnID}; use crate::{BusRouteID, BusStopID, LaneID, LaneType, Map, Position, Traversable, TurnID};
use dimensioned::si; use geom::{Distance, PolyLine, Pt2D, EPSILON_DIST};
use geom::{PolyLine, Pt2D, EPSILON_DIST};
use ordered_float::NotNan; use ordered_float::NotNan;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::collections::{BinaryHeap, HashMap, VecDeque}; use std::collections::{BinaryHeap, HashMap, VecDeque};
@ -28,18 +27,18 @@ enum InternalPathStep {
impl InternalPathStep { impl InternalPathStep {
// TODO Should consider the last step too... RideBus then Lane probably won't cross the full // TODO Should consider the last step too... RideBus then Lane probably won't cross the full
// lane. // lane.
fn cost(&self, map: &Map) -> si::Meter<f64> { fn cost(&self, map: &Map) -> Distance {
match *self { match *self {
InternalPathStep::Lane(l) | InternalPathStep::ContraflowLane(l) => { InternalPathStep::Lane(l) | InternalPathStep::ContraflowLane(l) => {
map.get_l(l).length() map.get_l(l).length()
} }
InternalPathStep::Turn(t) => map.get_t(t).geom.length(), InternalPathStep::Turn(t) => map.get_t(t).geom.length(),
// Free! For now. // Free! For now.
InternalPathStep::RideBus(_, _, _) => 0.0 * si::M, InternalPathStep::RideBus(_, _, _) => Distance::ZERO,
} }
} }
fn heuristic(&self, goal_pt: Pt2D, map: &Map) -> si::Meter<f64> { fn heuristic(&self, goal_pt: Pt2D, map: &Map) -> Distance {
let pt = match *self { let pt = match *self {
InternalPathStep::Lane(l) => map.get_l(l).last_pt(), InternalPathStep::Lane(l) => map.get_l(l).last_pt(),
InternalPathStep::ContraflowLane(l) => map.get_l(l).first_pt(), InternalPathStep::ContraflowLane(l) => map.get_l(l).first_pt(),
@ -71,13 +70,13 @@ impl PathStep {
fn slice( fn slice(
&self, &self,
map: &Map, map: &Map,
start: si::Meter<f64>, start: Distance,
dist_ahead: si::Meter<f64>, dist_ahead: Distance,
) -> Option<(PolyLine, si::Meter<f64>)> { ) -> Option<(PolyLine, Distance)> {
if dist_ahead < 0.0 * si::M { if dist_ahead < Distance::ZERO {
panic!("Negative dist_ahead?! {}", dist_ahead); panic!("Negative dist_ahead?! {}", dist_ahead);
} }
if dist_ahead == 0.0 * si::M { if dist_ahead == Distance::ZERO {
return None; return None;
} }
@ -99,12 +98,12 @@ impl PathStep {
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Path { pub struct Path {
steps: VecDeque<PathStep>, steps: VecDeque<PathStep>,
end_dist: si::Meter<f64>, end_dist: Distance,
} }
impl Path { impl Path {
// TODO pub for DrawCarInput... bleh. // TODO pub for DrawCarInput... bleh.
pub fn new(map: &Map, steps: Vec<PathStep>, end_dist: si::Meter<f64>) -> Path { pub fn new(map: &Map, steps: Vec<PathStep>, end_dist: Distance) -> Path {
// Can disable this after trusting it. // Can disable this after trusting it.
validate(map, &steps); validate(map, &steps);
Path { Path {
@ -152,12 +151,7 @@ impl Path {
self.steps[self.steps.len() - 1] self.steps[self.steps.len() - 1]
} }
pub fn trace( pub fn trace(&self, map: &Map, start_dist: Distance, dist_ahead: Distance) -> Option<Trace> {
&self,
map: &Map,
start_dist: si::Meter<f64>,
dist_ahead: si::Meter<f64>,
) -> Option<Trace> {
let mut pts_so_far: Option<PolyLine> = None; let mut pts_so_far: Option<PolyLine> = None;
let mut dist_remaining = dist_ahead; let mut dist_remaining = dist_ahead;
@ -187,7 +181,7 @@ impl Path {
// Crunch through the intermediate steps, as long as we can. // Crunch through the intermediate steps, as long as we can.
for i in 1..self.steps.len() { for i in 1..self.steps.len() {
if dist_remaining <= 0.0 * si::M { if dist_remaining <= Distance::ZERO {
// We know there's at least some geometry if we made it here, so unwrap to verify // We know there's at least some geometry if we made it here, so unwrap to verify
// that understanding. // that understanding.
return Some(pts_so_far.unwrap()); return Some(pts_so_far.unwrap());
@ -209,7 +203,7 @@ impl Path {
// TODO Length of a PolyLine can slightly change when points are reversed! That // TODO Length of a PolyLine can slightly change when points are reversed! That
// seems bad. // seems bad.
PathStep::ContraflowLane(l) => map.get_l(l).lane_center_pts.reversed().length(), PathStep::ContraflowLane(l) => map.get_l(l).lane_center_pts.reversed().length(),
_ => 0.0 * si::M, _ => Distance::ZERO,
}; };
if dist_remaining - start_dist_this_step > EPSILON_DIST { if dist_remaining - start_dist_this_step > EPSILON_DIST {
if let Some((new_pts, dist)) = if let Some((new_pts, dist)) =
@ -364,7 +358,7 @@ impl Pathfinder {
if pos.dist_along() != sidewalk.length() { if pos.dist_along() != sidewalk.length() {
results.push(InternalPathStep::Lane(sidewalk.id)); results.push(InternalPathStep::Lane(sidewalk.id));
} }
if pos.dist_along() != 0.0 * si::M { if pos.dist_along() != Distance::ZERO {
results.push(InternalPathStep::ContraflowLane(sidewalk.id)); results.push(InternalPathStep::ContraflowLane(sidewalk.id));
} }
} }
@ -393,7 +387,7 @@ impl Pathfinder {
let heuristic = step.heuristic(self.goal_pt, map); let heuristic = step.heuristic(self.goal_pt, map);
queue.push((dist_to_pri_queue(cost + heuristic), step)); queue.push((dist_to_pri_queue(cost + heuristic), step));
} }
if start.dist_along() != 0.0 * si::M { if start.dist_along() != Distance::ZERO {
let step = InternalPathStep::ContraflowLane(start.lane()); let step = InternalPathStep::ContraflowLane(start.lane());
let cost = start.dist_along(); let cost = start.dist_along();
let heuristic = step.heuristic(self.goal_pt, map); let heuristic = step.heuristic(self.goal_pt, map);
@ -459,7 +453,7 @@ fn validate(map: &Map, steps: &Vec<PathStep>) {
PathStep::Turn(id) => map.get_t(id).geom.first_pt(), PathStep::Turn(id) => map.get_t(id).geom.first_pt(),
}; };
let len = from.dist_to(to); let len = from.dist_to(to);
if len > 0.0 * si::M { if len > Distance::ZERO {
error!("All steps in invalid path:"); error!("All steps in invalid path:");
for s in steps { for s in steps {
match s { match s {
@ -487,6 +481,6 @@ fn validate(map: &Map, steps: &Vec<PathStep>) {
} }
// Negate since BinaryHeap is a max-heap. // Negate since BinaryHeap is a max-heap.
fn dist_to_pri_queue(dist: si::Meter<f64>) -> NotNan<f64> { fn dist_to_pri_queue(dist: Distance) -> NotNan<f64> {
NotNan::new(-1.0 * dist.value_unsafe).unwrap() (dist * -1.0).as_ordered()
} }

View File

@ -1,7 +1,6 @@
use crate::make::get_lane_types; use crate::make::get_lane_types;
use crate::{AreaType, IntersectionType, RoadSpec}; use crate::{AreaType, IntersectionType, RoadSpec};
use dimensioned::si; use geom::{Distance, GPSBounds, LonLat};
use geom::{GPSBounds, LonLat};
use gtfs::Route; use gtfs::Route;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::collections::BTreeMap; use std::collections::BTreeMap;
@ -105,7 +104,7 @@ impl Road {
#[derive(PartialEq, Debug, Serialize, Deserialize)] #[derive(PartialEq, Debug, Serialize, Deserialize)]
pub struct Intersection { pub struct Intersection {
pub point: LonLat, pub point: LonLat,
pub elevation: si::Meter<f64>, pub elevation: Distance,
// A raw Intersection can be forced into being a Border. // A raw Intersection can be forced into being a Border.
pub intersection_type: IntersectionType, pub intersection_type: IntersectionType,
pub label: Option<String>, pub label: Option<String>,

View File

@ -1,7 +1,6 @@
use crate::{raw_data, IntersectionID, LaneID, LaneType}; use crate::{raw_data, IntersectionID, LaneID, LaneType};
use abstutil::Error; use abstutil::Error;
use dimensioned::si; use geom::{PolyLine, Speed};
use geom::PolyLine;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::collections::{BTreeMap, HashSet}; use std::collections::{BTreeMap, HashSet};
use std::fmt; use std::fmt;
@ -89,13 +88,13 @@ impl Road {
lane == self.children_backwards[0].0 lane == self.children_backwards[0].0
} }
pub fn get_speed_limit(&self) -> si::MeterPerSecond<f64> { pub fn get_speed_limit(&self) -> Speed {
// TODO Should probably cache this // TODO Should probably cache this
if let Some(limit) = self.osm_tags.get("maxspeed") { if let Some(limit) = self.osm_tags.get("maxspeed") {
// TODO handle other units // TODO handle other units
if limit.ends_with(" mph") { if limit.ends_with(" mph") {
if let Ok(mph) = limit[0..limit.len() - 4].parse::<f64>() { if let Ok(mph) = limit[0..limit.len() - 4].parse::<f64>() {
return mph * 0.44704 * si::MPS; return Speed::miles_per_hour(mph);
} }
} }
} }
@ -103,11 +102,9 @@ impl Road {
if self.osm_tags.get("highway") == Some(&"primary".to_string()) if self.osm_tags.get("highway") == Some(&"primary".to_string())
|| self.osm_tags.get("highway") == Some(&"secondary".to_string()) || self.osm_tags.get("highway") == Some(&"secondary".to_string())
{ {
// 40mph return Speed::miles_per_hour(40.0);
return 17.8816 * si::MPS;
} }
// 20mph Speed::miles_per_hour(20.0)
8.9408 * si::MPS
} }
pub fn get_zorder(&self) -> isize { pub fn get_zorder(&self) -> isize {

View File

@ -1,14 +1,10 @@
use crate::{IntersectionID, Map, RoadID, TurnID, TurnPriority, TurnType}; use crate::{IntersectionID, Map, RoadID, TurnID, TurnPriority, TurnType};
use abstutil::Error; use abstutil::Error;
use dimensioned::si; use geom::Duration;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std;
use std::collections::BTreeSet; use std::collections::BTreeSet;
const CYCLE_DURATION: si::Second<f64> = si::Second { const CYCLE_DURATION: Duration = Duration::const_seconds(30.0);
value_unsafe: 30.0,
_marker: std::marker::PhantomData,
};
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ControlTrafficSignal { pub struct ControlTrafficSignal {
@ -32,13 +28,10 @@ impl ControlTrafficSignal {
self.changed self.changed
} }
pub fn current_cycle_and_remaining_time( pub fn current_cycle_and_remaining_time(&self, time: Duration) -> (&Cycle, Duration) {
&self,
time: si::Second<f64>,
) -> (&Cycle, si::Second<f64>) {
let cycle_idx = (time / CYCLE_DURATION).floor() as usize; let cycle_idx = (time / CYCLE_DURATION).floor() as usize;
let cycle = &self.cycles[cycle_idx % self.cycles.len()]; let cycle = &self.cycles[cycle_idx % self.cycles.len()];
let next_cycle_time = (cycle_idx + 1) as f64 * CYCLE_DURATION; let next_cycle_time = CYCLE_DURATION * (cycle_idx + 1) as f64;
let remaining_cycle_time = next_cycle_time - time; let remaining_cycle_time = next_cycle_time - time;
(cycle, remaining_cycle_time) (cycle, remaining_cycle_time)
} }
@ -307,7 +300,7 @@ pub struct Cycle {
pub idx: usize, pub idx: usize,
pub priority_turns: BTreeSet<TurnID>, pub priority_turns: BTreeSet<TurnID>,
pub yield_turns: BTreeSet<TurnID>, pub yield_turns: BTreeSet<TurnID>,
pub duration: si::Second<f64>, pub duration: Duration,
} }
impl Cycle { impl Cycle {
@ -379,7 +372,7 @@ impl Cycle {
} }
} }
pub fn edit_duration(&mut self, new_duration: si::Second<f64>) { pub fn edit_duration(&mut self, new_duration: Duration) {
self.duration = new_duration; self.duration = new_duration;
} }
} }

View File

@ -1,6 +1,5 @@
use crate::{LaneID, Map, TurnID}; use crate::{LaneID, Map, TurnID};
use dimensioned::si; use geom::{Angle, Distance, PolyLine, Pt2D, Speed};
use geom::{Angle, PolyLine, Pt2D};
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::fmt; use std::fmt;
@ -8,7 +7,7 @@ use std::fmt;
pub struct Position { pub struct Position {
// Don't let callers construct a Position directly, so it's easy to find callers of new(). // Don't let callers construct a Position directly, so it's easy to find callers of new().
lane: LaneID, lane: LaneID,
dist_along: si::Meter<f64>, dist_along: Distance,
} }
impl fmt::Display for Position { impl fmt::Display for Position {
@ -18,7 +17,7 @@ impl fmt::Display for Position {
} }
impl Position { impl Position {
pub fn new(lane: LaneID, dist_along: si::Meter<f64>) -> Position { pub fn new(lane: LaneID, dist_along: Distance) -> Position {
Position { lane, dist_along } Position { lane, dist_along }
} }
@ -26,7 +25,7 @@ impl Position {
self.lane self.lane
} }
pub fn dist_along(&self) -> si::Meter<f64> { pub fn dist_along(&self) -> Distance {
self.dist_along self.dist_along
} }
@ -83,33 +82,28 @@ impl Traversable {
} }
// TODO Just expose the PolyLine instead of all these layers of helpers // TODO Just expose the PolyLine instead of all these layers of helpers
pub fn length(&self, map: &Map) -> si::Meter<f64> { pub fn length(&self, map: &Map) -> Distance {
match *self { match *self {
Traversable::Lane(id) => map.get_l(id).length(), Traversable::Lane(id) => map.get_l(id).length(),
Traversable::Turn(id) => map.get_t(id).geom.length(), Traversable::Turn(id) => map.get_t(id).geom.length(),
} }
} }
pub fn dist_along(&self, dist: si::Meter<f64>, map: &Map) -> (Pt2D, Angle) { pub fn dist_along(&self, dist: Distance, map: &Map) -> (Pt2D, Angle) {
match *self { match *self {
Traversable::Lane(id) => map.get_l(id).dist_along(dist), Traversable::Lane(id) => map.get_l(id).dist_along(dist),
Traversable::Turn(id) => map.get_t(id).geom.dist_along(dist), Traversable::Turn(id) => map.get_t(id).geom.dist_along(dist),
} }
} }
pub fn slice( pub fn slice(&self, start: Distance, end: Distance, map: &Map) -> Option<(PolyLine, Distance)> {
&self,
start: si::Meter<f64>,
end: si::Meter<f64>,
map: &Map,
) -> Option<(PolyLine, si::Meter<f64>)> {
match *self { match *self {
Traversable::Lane(id) => map.get_l(id).lane_center_pts.slice(start, end), Traversable::Lane(id) => map.get_l(id).lane_center_pts.slice(start, end),
Traversable::Turn(id) => map.get_t(id).geom.slice(start, end), Traversable::Turn(id) => map.get_t(id).geom.slice(start, end),
} }
} }
pub fn speed_limit(&self, map: &Map) -> si::MeterPerSecond<f64> { pub fn speed_limit(&self, map: &Map) -> Speed {
match *self { match *self {
Traversable::Lane(id) => map.get_parent(id).get_speed_limit(), Traversable::Lane(id) => map.get_parent(id).get_speed_limit(),
Traversable::Turn(id) => map.get_parent(id.dst).get_speed_limit(), Traversable::Turn(id) => map.get_parent(id.dst).get_speed_limit(),