From 133ec037c964eb312835f854b15d9c3e99403be6 Mon Sep 17 00:00:00 2001 From: Dustin Carlino Date: Wed, 30 Jan 2019 12:43:10 -0800 Subject: [PATCH] switching to new units in map_model --- geom/src/gps.rs | 2 +- geom/src/polyline.rs | 12 ++--- geom/src/units.rs | 61 +++++++++++++++++++++++--- map_model/Cargo.toml | 1 - map_model/src/find_closest.rs | 20 ++++----- map_model/src/intersection.rs | 5 +-- map_model/src/lane.rs | 20 +++------ map_model/src/make/buildings.rs | 5 +-- map_model/src/make/bus_stops.rs | 18 +++++--- map_model/src/make/half_map.rs | 14 +++--- map_model/src/make/initial/geometry.rs | 15 +++---- map_model/src/make/initial/merge.rs | 4 +- map_model/src/make/parcels.rs | 5 +-- map_model/src/make/sidewalk_finder.rs | 5 +-- map_model/src/make/turns.rs | 7 ++- map_model/src/pathfind.rs | 44 ++++++++----------- map_model/src/raw_data.rs | 5 +-- map_model/src/road.rs | 13 +++--- map_model/src/traffic_signals.rs | 19 +++----- map_model/src/traversable.rs | 22 ++++------ 20 files changed, 150 insertions(+), 147 deletions(-) diff --git a/geom/src/gps.rs b/geom/src/gps.rs index 41561f2af9..eb18e52337 100644 --- a/geom/src/gps.rs +++ b/geom/src/gps.rs @@ -116,7 +116,7 @@ impl GPSBounds { .gps_dist_meters(LonLat::new(self.max_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)); - Pt2D::new(width.inner(), height.inner()) + Pt2D::new(width.inner_meters(), height.inner_meters()) } pub fn to_bounds(&self) -> Bounds { diff --git a/geom/src/polyline.rs b/geom/src/polyline.rs index a2abcb0ed6..2e44a9e35a 100644 --- a/geom/src/polyline.rs +++ b/geom/src/polyline.rs @@ -1,7 +1,6 @@ use crate::{ Angle, Bounds, Distance, HashablePt2D, InfiniteLine, Line, Polygon, Pt2D, EPSILON_DIST, }; -use ordered_float::NotNan; use serde_derive::{Deserialize, Serialize}; use std::collections::HashSet; use std::f64; @@ -357,13 +356,10 @@ impl PolyLine { } hits.sort_by_key(|(pt, _)| { - NotNan::new( - self.get_slice_ending_at(*pt) - .map(|pl| pl.length()) - .unwrap_or(Distance::ZERO) - .inner(), - ) - .unwrap() + self.get_slice_ending_at(*pt) + .map(|pl| pl.length()) + .unwrap_or(Distance::ZERO) + .as_ordered() }); if !hits.is_empty() { return Some(hits[0]); diff --git a/geom/src/units.rs b/geom/src/units.rs index f93610c336..d3045c1629 100644 --- a/geom/src/units.rs +++ b/geom/src/units.rs @@ -1,3 +1,4 @@ +use ordered_float::NotNan; use serde_derive::{Deserialize, Serialize}; use std::{fmt, ops}; @@ -29,8 +30,13 @@ impl Distance { } } - // TODO Only used within this crate for NotNan construction and GPS->Pt2D. - pub(crate) fn inner(self) -> f64 { + // TODO Remove by making Distance itself Ord. + pub fn as_ordered(self) -> NotNan { + NotNan::new(self.0).unwrap() + } + + // TODO Remove if possible. + pub fn inner_meters(self) -> f64 { self.0 } } @@ -70,6 +76,14 @@ impl ops::SubAssign for Distance { } } +impl ops::Mul for Distance { + type Output = Distance; + + fn mul(self, scalar: f64) -> Distance { + Distance::meters(self.0 * scalar) + } +} + impl ops::Div for Distance { type Output = f64; @@ -84,11 +98,11 @@ impl ops::Div for Distance { impl ops::Div for Distance { type Output = Distance; - fn div(self, other: f64) -> Distance { - if other == 0.0 { - panic!("Can't divide {} / {}", self, other); + fn div(self, scalar: f64) -> Distance { + if scalar == 0.0 { + panic!("Can't divide {} / {}", self, scalar); } - Distance::meters(self.0 / other) + Distance::meters(self.0 / scalar) } } @@ -104,6 +118,10 @@ impl Duration { Duration(value) } + + pub const fn const_seconds(value: f64) -> Duration { + Duration(value) + } } 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 for Duration { + type Output = Duration; + + fn mul(self, other: f64) -> Duration { + Duration::seconds(self.0 * other) + } +} + +impl ops::Div 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. #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Serialize, Deserialize)] pub struct Speed(f64); @@ -124,6 +169,10 @@ impl Speed { Speed(value) } + + pub fn miles_per_hour(value: f64) -> Speed { + Speed::meters_per_second(0.44704 * value) + } } impl fmt::Display for Speed { diff --git a/map_model/Cargo.toml b/map_model/Cargo.toml index 8c433c8cd7..d0787206d5 100644 --- a/map_model/Cargo.toml +++ b/map_model/Cargo.toml @@ -7,7 +7,6 @@ edition = "2018" [dependencies] aabb-quadtree = "0.1.0" abstutil = { path = "../abstutil" } -dimensioned = { git = "https://github.com/paholg/dimensioned", rev = "0e1076ebfa5128d1ee544bdc9754c948987b6fe3", features = ["serde"] } geo = "0.11.0" geom = { path = "../geom" } gtfs = { path = "../gtfs" } diff --git a/map_model/src/find_closest.rs b/map_model/src/find_closest.rs index 10c989e8e5..4ab24fa6c9 100644 --- a/map_model/src/find_closest.rs +++ b/map_model/src/find_closest.rs @@ -1,10 +1,8 @@ use aabb_quadtree::geom::{Point, Rect}; use aabb_quadtree::QuadTree; -use dimensioned::si; use geo; use geo::prelude::{ClosestPoint, EuclideanDistance}; -use geom::{Bounds, PolyLine, Pt2D}; -use ordered_float::NotNan; +use geom::{Bounds, Distance, PolyLine, Pt2D}; use std::collections::HashMap; // TODO Refactor and generalize all of this... @@ -33,16 +31,16 @@ where } // 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) -> 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_bbox = Rect { top_left: Point { - x: (query_pt.x() - max_dist_away.value_unsafe) as f32, - y: (query_pt.y() - 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.inner_meters()) as f32, }, bottom_right: Point { - x: (query_pt.x() + max_dist_away.value_unsafe) as f32, - y: (query_pt.y() + 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.inner_meters()) as f32, }, }; @@ -53,9 +51,9 @@ where if let geo::Closest::SinglePoint(pt) = self.geometries[&key].closest_point(&query_geom) { - let dist = pt.euclidean_distance(&query_geom); - if dist * si::M <= max_dist_away { - Some((key, pt, NotNan::new(dist).unwrap())) + let dist = Distance::meters(pt.euclidean_distance(&query_geom)); + if dist <= max_dist_away { + Some((key, pt, dist.as_ordered())) } else { None } diff --git a/map_model/src/intersection.rs b/map_model/src/intersection.rs index 201fb0012a..1c49e4d529 100644 --- a/map_model/src/intersection.rs +++ b/map_model/src/intersection.rs @@ -1,7 +1,6 @@ use crate::{raw_data, LaneID, LaneType, Map, RoadID, TurnID}; use abstutil; -use dimensioned::si; -use geom::{Polygon, Pt2D}; +use geom::{Distance, Polygon, Pt2D}; use serde_derive::{Deserialize, Serialize}; use std::collections::BTreeSet; use std::fmt; @@ -30,7 +29,7 @@ pub struct Intersection { // This needs to be in clockwise orientation, or later rendering of sidewalk corners breaks. pub polygon: Polygon, pub turns: Vec, - pub elevation: si::Meter, + pub elevation: Distance, pub intersection_type: IntersectionType, pub label: Option, diff --git a/map_model/src/lane.rs b/map_model/src/lane.rs index 6682f81782..62fe86c527 100644 --- a/map_model/src/lane.rs +++ b/map_model/src/lane.rs @@ -1,17 +1,11 @@ use crate::{BuildingID, BusStopID, IntersectionID, RoadID}; use abstutil; -use dimensioned::si; -use geom::{Angle, Line, PolyLine, Pt2D}; +use geom::{Angle, Distance, Line, PolyLine, Pt2D}; use serde_derive::{Deserialize, Serialize}; -use std; -use std::f64; use std::fmt; -pub const PARKING_SPOT_LENGTH: si::Meter = si::Meter { - // Bit longer than the longest car. - value_unsafe: 8.0, - _marker: std::marker::PhantomData, -}; +// Bit longer than the longest car. +pub const PARKING_SPOT_LENGTH: Distance = Distance::const_meters(8.0); // TODO reconsider pub usize. maybe outside world shouldnt know. #[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) -> (Pt2D, Angle) { + pub fn dist_along(&self, dist_along: Distance) -> (Pt2D, Angle) { self.lane_center_pts.dist_along(dist_along) } - pub fn safe_dist_along(&self, dist_along: si::Meter) -> Option<(Pt2D, Angle)> { + pub fn safe_dist_along(&self, dist_along: Distance) -> Option<(Pt2D, Angle)> { self.lane_center_pts.safe_dist_along(dist_along) } - pub fn dist_along_of_point(&self, pt: Pt2D) -> Option> { + pub fn dist_along_of_point(&self, pt: Pt2D) -> Option { self.lane_center_pts .dist_along_of_point(pt) .map(|(dist, _)| dist) } - pub fn length(&self) -> si::Meter { + pub fn length(&self) -> Distance { self.lane_center_pts.length() } diff --git a/map_model/src/make/buildings.rs b/map_model/src/make/buildings.rs index dd0ab24307..f204364d66 100644 --- a/map_model/src/make/buildings.rs +++ b/map_model/src/make/buildings.rs @@ -1,8 +1,7 @@ use crate::make::sidewalk_finder::find_sidewalk_points; use crate::{raw_data, Building, BuildingID, FrontPath, Lane}; use abstutil::Timer; -use dimensioned::si; -use geom::{Bounds, GPSBounds, HashablePt2D, Line, Pt2D}; +use geom::{Bounds, Distance, GPSBounds, HashablePt2D, Line, Pt2D}; use std::collections::HashSet; pub fn make_all_buildings( @@ -34,7 +33,7 @@ pub fn make_all_buildings( } // 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()); for (idx, points) in pts_per_bldg.into_iter().enumerate() { diff --git a/map_model/src/make/bus_stops.rs b/map_model/src/make/bus_stops.rs index 19cbca0c86..e06736d1ef 100644 --- a/map_model/src/make/bus_stops.rs +++ b/map_model/src/make/bus_stops.rs @@ -4,11 +4,9 @@ use crate::{ Position, }; use abstutil::Timer; -use dimensioned::si; -use geom::{Bounds, GPSBounds, HashablePt2D, Pt2D}; +use geom::{Bounds, Distance, GPSBounds, HashablePt2D, Pt2D}; use gtfs; use multimap::MultiMap; -use ordered_float::NotNan; use std::collections::{BTreeMap, HashMap, HashSet}; use std::iter; @@ -32,9 +30,15 @@ pub fn make_bus_stops( } } - let mut stops_per_sidewalk: MultiMap, HashablePt2D)> = MultiMap::new(); - for (pt, pos) in - find_sidewalk_points(bounds, bus_stop_pts, map.all_lanes(), 10.0 * si::M, timer).into_iter() + let mut stops_per_sidewalk: MultiMap = MultiMap::new(); + for (pt, pos) in find_sidewalk_points( + bounds, + bus_stop_pts, + map.all_lanes(), + Distance::meters(10.0), + timer, + ) + .into_iter() { stops_per_sidewalk.insert(pos.lane(), (pos.dist_along(), pt)); } @@ -46,7 +50,7 @@ pub fn make_bus_stops( if let Ok(driving_lane) = 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() { let stop_id = BusStopID { sidewalk: *id, idx }; point_to_stop_id.insert(*orig_pt, stop_id); diff --git a/map_model/src/make/half_map.rs b/map_model/src/make/half_map.rs index a7a57f88b1..5ff55c9ee7 100644 --- a/map_model/src/make/half_map.rs +++ b/map_model/src/make/half_map.rs @@ -4,7 +4,6 @@ use crate::{ }; use abstutil::Timer; use geom::{Bounds, GPSBounds, Polygon, Pt2D}; -use ordered_float::NotNan; use std::collections::BTreeMap; pub struct HalfMap { @@ -171,14 +170,11 @@ pub fn make_half_map( let mut bldgs = half_map.lanes[lane.0].building_paths.clone(); bldgs.push(b.id); bldgs.sort_by_key(|b| { - NotNan::new( - half_map.buildings[b.0] - .front_path - .sidewalk - .dist_along() - .value_unsafe, - ) - .unwrap() + half_map.buildings[b.0] + .front_path + .sidewalk + .dist_along() + .as_ordered() }); half_map.lanes[lane.0].building_paths = bldgs; } diff --git a/map_model/src/make/initial/geometry.rs b/map_model/src/make/initial/geometry.rs index 7cb0b52f7b..49fa096a7d 100644 --- a/map_model/src/make/initial/geometry.rs +++ b/map_model/src/make/initial/geometry.rs @@ -1,15 +1,10 @@ use crate::make::initial::{Intersection, Road}; use crate::raw_data::{StableIntersectionID, StableRoadID}; use abstutil::wraparound_get; -use dimensioned::si; -use geom::{Angle, HashablePt2D, Line, PolyLine, Pt2D}; +use geom::{Angle, Distance, HashablePt2D, Line, PolyLine, Pt2D}; use std::collections::{BTreeMap, HashMap}; -use std::marker; -const DEGENERATE_INTERSECTION_HALF_LENGTH: si::Meter = si::Meter { - value_unsafe: 5.0, - _marker: marker::PhantomData, -}; +const DEGENERATE_INTERSECTION_HALF_LENGTH: Distance = Distance::const_meters(5.0); // 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. @@ -86,7 +81,7 @@ fn generalized_trim_back( let mut shortest_center = if road_center.length() >= DEGENERATE_INTERSECTION_HALF_LENGTH { road_center .slice( - 0.0 * si::M, + Distance::ZERO, road_center.length() - DEGENERATE_INTERSECTION_HALF_LENGTH, ) .unwrap() @@ -181,7 +176,7 @@ fn generalized_trim_back( } } 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); 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 .trimmed_center_pts .slice( - 0.0 * si::M, + Distance::ZERO, r.trimmed_center_pts.length() - DEGENERATE_INTERSECTION_HALF_LENGTH * 2.0, ) .unwrap() diff --git a/map_model/src/make/initial/merge.rs b/map_model/src/make/initial/merge.rs index e0d0bf03bb..d99c20a05b 100644 --- a/map_model/src/make/initial/merge.rs +++ b/map_model/src/make/initial/merge.rs @@ -1,7 +1,7 @@ use crate::make::initial::{geometry, InitialMap}; use crate::raw_data::StableRoadID; use abstutil::note; -use dimensioned::si; +use geom::Distance; pub fn short_roads(map: &mut InitialMap) { if false { @@ -29,7 +29,7 @@ pub fn short_roads(map: &mut InitialMap) { if let Some(r) = map .roads .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); } else { diff --git a/map_model/src/make/parcels.rs b/map_model/src/make/parcels.rs index f1f3416f50..5a240a0366 100644 --- a/map_model/src/make/parcels.rs +++ b/map_model/src/make/parcels.rs @@ -1,8 +1,7 @@ use crate::make::sidewalk_finder::find_sidewalk_points; use crate::{raw_data, Lane, Parcel, ParcelID}; use abstutil::Timer; -use dimensioned::si; -use geom::{Bounds, GPSBounds, HashablePt2D, Pt2D}; +use geom::{Bounds, Distance, GPSBounds, HashablePt2D, Pt2D}; use std::collections::HashSet; 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 - 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() { if sidewalk_pts.contains_key(¢er) { diff --git a/map_model/src/make/sidewalk_finder.rs b/map_model/src/make/sidewalk_finder.rs index 0d83b1b45b..48344b61a7 100644 --- a/map_model/src/make/sidewalk_finder.rs +++ b/map_model/src/make/sidewalk_finder.rs @@ -1,7 +1,6 @@ use crate::{FindClosest, Lane, LaneID, Position}; use abstutil::Timer; -use dimensioned::si; -use geom::{Bounds, HashablePt2D}; +use geom::{Bounds, Distance, HashablePt2D}; use std::collections::{HashMap, HashSet}; // 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, pts: HashSet, lanes: &Vec, - max_dist_away: si::Meter, + max_dist_away: Distance, timer: &mut Timer, ) -> HashMap { if pts.is_empty() { diff --git a/map_model/src/make/turns.rs b/map_model/src/make/turns.rs index 7b72bb0a2d..dd22686149 100644 --- a/map_model/src/make/turns.rs +++ b/map_model/src/make/turns.rs @@ -3,8 +3,7 @@ use crate::{ TurnType, LANE_THICKNESS, }; use abstutil::wraparound_get; -use dimensioned::si; -use geom::{Line, PolyLine, Pt2D}; +use geom::{Distance, Line, PolyLine, Pt2D}; use nbez::{Bez3o, BezCurve, Point2d}; use std::collections::{BTreeSet, HashSet}; 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 let curve = Bez3o::new( to_pt(src.last_pt()), - to_pt(src_line.unbounded_dist_along(src_line.length() + 5.0 * si::M)), - to_pt(dst_line.unbounded_dist_along(dst_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() + Distance::meters(5.0))), to_pt(dst.first_pt()), ); let pieces = 5; diff --git a/map_model/src/pathfind.rs b/map_model/src/pathfind.rs index f600919935..9014f318ef 100644 --- a/map_model/src/pathfind.rs +++ b/map_model/src/pathfind.rs @@ -1,6 +1,5 @@ use crate::{BusRouteID, BusStopID, LaneID, LaneType, Map, Position, Traversable, TurnID}; -use dimensioned::si; -use geom::{PolyLine, Pt2D, EPSILON_DIST}; +use geom::{Distance, PolyLine, Pt2D, EPSILON_DIST}; use ordered_float::NotNan; use serde_derive::{Deserialize, Serialize}; use std::collections::{BinaryHeap, HashMap, VecDeque}; @@ -28,18 +27,18 @@ enum InternalPathStep { impl InternalPathStep { // TODO Should consider the last step too... RideBus then Lane probably won't cross the full // lane. - fn cost(&self, map: &Map) -> si::Meter { + fn cost(&self, map: &Map) -> Distance { match *self { InternalPathStep::Lane(l) | InternalPathStep::ContraflowLane(l) => { map.get_l(l).length() } InternalPathStep::Turn(t) => map.get_t(t).geom.length(), // Free! For now. - InternalPathStep::RideBus(_, _, _) => 0.0 * si::M, + InternalPathStep::RideBus(_, _, _) => Distance::ZERO, } } - fn heuristic(&self, goal_pt: Pt2D, map: &Map) -> si::Meter { + fn heuristic(&self, goal_pt: Pt2D, map: &Map) -> Distance { let pt = match *self { InternalPathStep::Lane(l) => map.get_l(l).last_pt(), InternalPathStep::ContraflowLane(l) => map.get_l(l).first_pt(), @@ -71,13 +70,13 @@ impl PathStep { fn slice( &self, map: &Map, - start: si::Meter, - dist_ahead: si::Meter, - ) -> Option<(PolyLine, si::Meter)> { - if dist_ahead < 0.0 * si::M { + start: Distance, + dist_ahead: Distance, + ) -> Option<(PolyLine, Distance)> { + if dist_ahead < Distance::ZERO { panic!("Negative dist_ahead?! {}", dist_ahead); } - if dist_ahead == 0.0 * si::M { + if dist_ahead == Distance::ZERO { return None; } @@ -99,12 +98,12 @@ impl PathStep { #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct Path { steps: VecDeque, - end_dist: si::Meter, + end_dist: Distance, } impl Path { // TODO pub for DrawCarInput... bleh. - pub fn new(map: &Map, steps: Vec, end_dist: si::Meter) -> Path { + pub fn new(map: &Map, steps: Vec, end_dist: Distance) -> Path { // Can disable this after trusting it. validate(map, &steps); Path { @@ -152,12 +151,7 @@ impl Path { self.steps[self.steps.len() - 1] } - pub fn trace( - &self, - map: &Map, - start_dist: si::Meter, - dist_ahead: si::Meter, - ) -> Option { + pub fn trace(&self, map: &Map, start_dist: Distance, dist_ahead: Distance) -> Option { let mut pts_so_far: Option = None; let mut dist_remaining = dist_ahead; @@ -187,7 +181,7 @@ impl Path { // Crunch through the intermediate steps, as long as we can. 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 // that understanding. 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 // seems bad. 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 let Some((new_pts, dist)) = @@ -364,7 +358,7 @@ impl Pathfinder { if pos.dist_along() != sidewalk.length() { 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)); } } @@ -393,7 +387,7 @@ impl Pathfinder { let heuristic = step.heuristic(self.goal_pt, map); 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 cost = start.dist_along(); let heuristic = step.heuristic(self.goal_pt, map); @@ -459,7 +453,7 @@ fn validate(map: &Map, steps: &Vec) { PathStep::Turn(id) => map.get_t(id).geom.first_pt(), }; let len = from.dist_to(to); - if len > 0.0 * si::M { + if len > Distance::ZERO { error!("All steps in invalid path:"); for s in steps { match s { @@ -487,6 +481,6 @@ fn validate(map: &Map, steps: &Vec) { } // Negate since BinaryHeap is a max-heap. -fn dist_to_pri_queue(dist: si::Meter) -> NotNan { - NotNan::new(-1.0 * dist.value_unsafe).unwrap() +fn dist_to_pri_queue(dist: Distance) -> NotNan { + (dist * -1.0).as_ordered() } diff --git a/map_model/src/raw_data.rs b/map_model/src/raw_data.rs index a2f9d5e769..65119d054f 100644 --- a/map_model/src/raw_data.rs +++ b/map_model/src/raw_data.rs @@ -1,7 +1,6 @@ use crate::make::get_lane_types; use crate::{AreaType, IntersectionType, RoadSpec}; -use dimensioned::si; -use geom::{GPSBounds, LonLat}; +use geom::{Distance, GPSBounds, LonLat}; use gtfs::Route; use serde_derive::{Deserialize, Serialize}; use std::collections::BTreeMap; @@ -105,7 +104,7 @@ impl Road { #[derive(PartialEq, Debug, Serialize, Deserialize)] pub struct Intersection { pub point: LonLat, - pub elevation: si::Meter, + pub elevation: Distance, // A raw Intersection can be forced into being a Border. pub intersection_type: IntersectionType, pub label: Option, diff --git a/map_model/src/road.rs b/map_model/src/road.rs index f6371e3ac0..c4f299bd95 100644 --- a/map_model/src/road.rs +++ b/map_model/src/road.rs @@ -1,7 +1,6 @@ use crate::{raw_data, IntersectionID, LaneID, LaneType}; use abstutil::Error; -use dimensioned::si; -use geom::PolyLine; +use geom::{PolyLine, Speed}; use serde_derive::{Deserialize, Serialize}; use std::collections::{BTreeMap, HashSet}; use std::fmt; @@ -89,13 +88,13 @@ impl Road { lane == self.children_backwards[0].0 } - pub fn get_speed_limit(&self) -> si::MeterPerSecond { + pub fn get_speed_limit(&self) -> Speed { // TODO Should probably cache this if let Some(limit) = self.osm_tags.get("maxspeed") { // TODO handle other units if limit.ends_with(" mph") { if let Ok(mph) = limit[0..limit.len() - 4].parse::() { - 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()) || self.osm_tags.get("highway") == Some(&"secondary".to_string()) { - // 40mph - return 17.8816 * si::MPS; + return Speed::miles_per_hour(40.0); } - // 20mph - 8.9408 * si::MPS + Speed::miles_per_hour(20.0) } pub fn get_zorder(&self) -> isize { diff --git a/map_model/src/traffic_signals.rs b/map_model/src/traffic_signals.rs index 74cd1a6f76..3e78c1f34d 100644 --- a/map_model/src/traffic_signals.rs +++ b/map_model/src/traffic_signals.rs @@ -1,14 +1,10 @@ use crate::{IntersectionID, Map, RoadID, TurnID, TurnPriority, TurnType}; use abstutil::Error; -use dimensioned::si; +use geom::Duration; use serde_derive::{Deserialize, Serialize}; -use std; use std::collections::BTreeSet; -const CYCLE_DURATION: si::Second = si::Second { - value_unsafe: 30.0, - _marker: std::marker::PhantomData, -}; +const CYCLE_DURATION: Duration = Duration::const_seconds(30.0); #[derive(Debug, Serialize, Deserialize, Clone)] pub struct ControlTrafficSignal { @@ -32,13 +28,10 @@ impl ControlTrafficSignal { self.changed } - pub fn current_cycle_and_remaining_time( - &self, - time: si::Second, - ) -> (&Cycle, si::Second) { + pub fn current_cycle_and_remaining_time(&self, time: Duration) -> (&Cycle, Duration) { let cycle_idx = (time / CYCLE_DURATION).floor() as usize; 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; (cycle, remaining_cycle_time) } @@ -307,7 +300,7 @@ pub struct Cycle { pub idx: usize, pub priority_turns: BTreeSet, pub yield_turns: BTreeSet, - pub duration: si::Second, + pub duration: Duration, } impl Cycle { @@ -379,7 +372,7 @@ impl Cycle { } } - pub fn edit_duration(&mut self, new_duration: si::Second) { + pub fn edit_duration(&mut self, new_duration: Duration) { self.duration = new_duration; } } diff --git a/map_model/src/traversable.rs b/map_model/src/traversable.rs index 400a525855..d79229bc1e 100644 --- a/map_model/src/traversable.rs +++ b/map_model/src/traversable.rs @@ -1,6 +1,5 @@ use crate::{LaneID, Map, TurnID}; -use dimensioned::si; -use geom::{Angle, PolyLine, Pt2D}; +use geom::{Angle, Distance, PolyLine, Pt2D, Speed}; use serde_derive::{Deserialize, Serialize}; use std::fmt; @@ -8,7 +7,7 @@ use std::fmt; pub struct Position { // Don't let callers construct a Position directly, so it's easy to find callers of new(). lane: LaneID, - dist_along: si::Meter, + dist_along: Distance, } impl fmt::Display for Position { @@ -18,7 +17,7 @@ impl fmt::Display for Position { } impl Position { - pub fn new(lane: LaneID, dist_along: si::Meter) -> Position { + pub fn new(lane: LaneID, dist_along: Distance) -> Position { Position { lane, dist_along } } @@ -26,7 +25,7 @@ impl Position { self.lane } - pub fn dist_along(&self) -> si::Meter { + pub fn dist_along(&self) -> Distance { self.dist_along } @@ -83,33 +82,28 @@ impl Traversable { } // TODO Just expose the PolyLine instead of all these layers of helpers - pub fn length(&self, map: &Map) -> si::Meter { + pub fn length(&self, map: &Map) -> Distance { match *self { Traversable::Lane(id) => map.get_l(id).length(), Traversable::Turn(id) => map.get_t(id).geom.length(), } } - pub fn dist_along(&self, dist: si::Meter, map: &Map) -> (Pt2D, Angle) { + pub fn dist_along(&self, dist: Distance, map: &Map) -> (Pt2D, Angle) { match *self { Traversable::Lane(id) => map.get_l(id).dist_along(dist), Traversable::Turn(id) => map.get_t(id).geom.dist_along(dist), } } - pub fn slice( - &self, - start: si::Meter, - end: si::Meter, - map: &Map, - ) -> Option<(PolyLine, si::Meter)> { + pub fn slice(&self, start: Distance, end: Distance, map: &Map) -> Option<(PolyLine, Distance)> { match *self { Traversable::Lane(id) => map.get_l(id).lane_center_pts.slice(start, end), Traversable::Turn(id) => map.get_t(id).geom.slice(start, end), } } - pub fn speed_limit(&self, map: &Map) -> si::MeterPerSecond { + pub fn speed_limit(&self, map: &Map) -> Speed { match *self { Traversable::Lane(id) => map.get_parent(id).get_speed_limit(), Traversable::Turn(id) => map.get_parent(id.dst).get_speed_limit(),