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

View File

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

View File

@ -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<f64> {
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<f64> for Distance {
type Output = Distance;
fn mul(self, scalar: f64) -> Distance {
Distance::meters(self.0 * scalar)
}
}
impl ops::Div<Distance> for Distance {
type Output = f64;
@ -84,11 +98,11 @@ impl ops::Div<Distance> for Distance {
impl ops::Div<f64> 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<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.
#[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 {

View File

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

View File

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

View File

@ -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<TurnID>,
pub elevation: si::Meter<f64>,
pub elevation: Distance,
pub intersection_type: IntersectionType,
pub label: Option<String>,

View File

@ -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<f64> = 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<f64>) -> (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<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)
}
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
.dist_along_of_point(pt)
.map(|(dist, _)| dist)
}
pub fn length(&self) -> si::Meter<f64> {
pub fn length(&self) -> Distance {
self.lane_center_pts.length()
}

View File

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

View File

@ -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<LaneID, (si::Meter<f64>, 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<LaneID, (Distance, HashablePt2D)> = 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);

View File

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

View File

@ -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<f64> = 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()

View File

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

View File

@ -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(&center) {

View File

@ -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<HashablePt2D>,
lanes: &Vec<Lane>,
max_dist_away: si::Meter<f64>,
max_dist_away: Distance,
timer: &mut Timer,
) -> HashMap<HashablePt2D, Position> {
if pts.is_empty() {

View File

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

View File

@ -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<f64> {
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<f64> {
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<f64>,
dist_ahead: si::Meter<f64>,
) -> Option<(PolyLine, si::Meter<f64>)> {
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<PathStep>,
end_dist: si::Meter<f64>,
end_dist: Distance,
}
impl Path {
// 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.
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<f64>,
dist_ahead: si::Meter<f64>,
) -> Option<Trace> {
pub fn trace(&self, map: &Map, start_dist: Distance, dist_ahead: Distance) -> Option<Trace> {
let mut pts_so_far: Option<PolyLine> = 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>) {
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<PathStep>) {
}
// Negate since BinaryHeap is a max-heap.
fn dist_to_pri_queue(dist: si::Meter<f64>) -> NotNan<f64> {
NotNan::new(-1.0 * dist.value_unsafe).unwrap()
fn dist_to_pri_queue(dist: Distance) -> NotNan<f64> {
(dist * -1.0).as_ordered()
}

View File

@ -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<f64>,
pub elevation: Distance,
// A raw Intersection can be forced into being a Border.
pub intersection_type: IntersectionType,
pub label: Option<String>,

View File

@ -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<f64> {
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::<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())
|| 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 {

View File

@ -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<f64> = 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<f64>,
) -> (&Cycle, si::Second<f64>) {
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<TurnID>,
pub yield_turns: BTreeSet<TurnID>,
pub duration: si::Second<f64>,
pub duration: Duration,
}
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;
}
}

View File

@ -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<f64>,
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<f64>) -> 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<f64> {
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<f64> {
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<f64>, 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<f64>,
end: si::Meter<f64>,
map: &Map,
) -> Option<(PolyLine, si::Meter<f64>)> {
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<f64> {
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(),