using strong Distance types in many more places

This commit is contained in:
Dustin Carlino 2019-01-30 15:10:05 -08:00
parent 3e00789960
commit 7519fdf584
35 changed files with 180 additions and 149 deletions

View File

@ -165,9 +165,7 @@ fn use_parking_hints(map: &mut raw_data::Map, shapes: ExtraShapes, gps_bounds: &
// TODO Long blockfaces sometimes cover two roads. Should maybe find ALL matches within
// the threshold distance?
let middle = PolyLine::new(pts).middle();
if let Some(((r, fwds), _)) =
closest.closest_pt(middle, Distance::meters(5.0 * LANE_THICKNESS))
{
if let Some(((r, fwds), _)) = closest.closest_pt(middle, LANE_THICKNESS * 5.0) {
let category = s.attributes.get("PARKING_CATEGORY");
let has_parking = category != Some(&"None".to_string())
&& category != Some(&"No Parking Allowed".to_string());

View File

@ -3,9 +3,6 @@
## Geometry
- try fixed pt again, for determinism purposes mostly
- go through and use less f64's... like LANE_THICKNESS, make_polygons, Circle::new, project_away
- audit inner_foo()'s
- change internal pt2d representation to int. JUST get that working first.
- clamp distances first, not points?
- note contains_pt needs to use 2 or 3 * epsilon, because of the error that may accumulate...

View File

@ -1,10 +1,10 @@
use crate::objects::Ctx;
use crate::plugins::{load_neighborhood_builder, Plugin, PluginCtx};
use ezgui::{Color, GfxCtx, Key, Wizard, WrappedWizard};
use geom::{Circle, Line, Polygon, Pt2D};
use geom::{Circle, Distance, Line, Polygon, Pt2D};
use map_model::{Map, NeighborhoodBuilder};
const POINT_RADIUS: f64 = 2.0;
const POINT_RADIUS: Distance = Distance::const_meters(2.0);
pub enum DrawNeighborhoodState {
PickNeighborhood(Wizard),

View File

@ -1,10 +1,10 @@
use crate::objects::{Ctx, ID};
use crate::render::{RenderOptions, Renderable};
use ezgui::{Color, GfxCtx};
use geom::{Bounds, Polygon, Pt2D};
use geom::{Bounds, Distance, Polygon, Pt2D};
use sim::{CarID, CarState, DrawCarInput};
const BIKE_WIDTH: f64 = 0.8;
const BIKE_WIDTH: Distance = Distance::const_meters(0.8);
pub struct DrawBike {
pub id: CarID,

View File

@ -19,7 +19,7 @@ impl DrawBuilding {
// overlap. For now, this cleanup is visual; it doesn't belong in the map_model layer.
let mut front_path_line = bldg.front_path.line.clone();
let len = front_path_line.length();
let trim_back = Distance::meters(LANE_THICKNESS / 2.0);
let trim_back = LANE_THICKNESS / 2.0;
if len > trim_back && len - trim_back > geom::EPSILON_DIST {
front_path_line = Line::new(
front_path_line.pt1(),
@ -27,7 +27,7 @@ impl DrawBuilding {
);
}
let fill_polygon = Polygon::new(&bldg.points);
let front_path = front_path_line.make_polygons(1.0);
let front_path = front_path_line.make_polygons(Distance::meters(1.0));
let default_draw = prerender.upload_borrowed(vec![
(

View File

@ -27,7 +27,7 @@ impl DrawBusStop {
.map(|(pt, _)| pt)
.unwrap_or_else(|| lane.last_pt()),
])
.make_polygons(0.8 * LANE_THICKNESS);
.make_polygons(LANE_THICKNESS * 0.8);
DrawBusStop {
id: stop.id,
polygon,

View File

@ -6,7 +6,7 @@ use map_model::{Map, TurnType};
use sim::{CarID, CarState, DrawCarInput, MIN_CAR_LENGTH};
use std;
const CAR_WIDTH: f64 = 2.0;
const CAR_WIDTH: Distance = Distance::const_meters(2.0);
pub struct DrawCar {
pub id: CarID,
@ -57,17 +57,17 @@ impl DrawCar {
.body
.dist_along(input.body.length() - Distance::meters(0.5));
let (back_blinker_pos, back_blinker_angle) = input.body.dist_along(Distance::meters(0.5));
let blinker_radius = 0.3;
let blinker_radius = Distance::meters(0.3);
let window_length_gap = 0.2;
let window_thickness = 0.3;
let window_length_gap = Distance::meters(0.2);
let window_thickness = Distance::meters(0.3);
let front_window = {
let (pos, angle) = input
.body
.dist_along(input.body.length() - Distance::meters(1.0));
thick_line_from_angle(
window_thickness,
CAR_WIDTH - 2.0 * window_length_gap,
CAR_WIDTH - window_length_gap * 2.0,
pos.project_away(
CAR_WIDTH / 2.0 - window_length_gap,
angle.rotate_degs(-90.0),
@ -79,7 +79,7 @@ impl DrawCar {
let (pos, angle) = input.body.dist_along(Distance::meters(1.0));
thick_line_from_angle(
window_thickness * 0.8,
CAR_WIDTH - 2.0 * window_length_gap,
CAR_WIDTH - window_length_gap * 2.0,
pos.project_away(
CAR_WIDTH / 2.0 - window_length_gap,
angle.rotate_degs(-90.0),
@ -95,26 +95,32 @@ impl DrawCar {
left_blinkers: Some((
Circle::new(
front_blinker_pos.project_away(
CAR_WIDTH / 2.0 - 0.5,
CAR_WIDTH / 2.0 - Distance::meters(0.5),
front_blinker_angle.rotate_degs(-90.0),
),
blinker_radius,
),
Circle::new(
back_blinker_pos
.project_away(CAR_WIDTH / 2.0 - 0.5, back_blinker_angle.rotate_degs(-90.0)),
back_blinker_pos.project_away(
CAR_WIDTH / 2.0 - Distance::meters(0.5),
back_blinker_angle.rotate_degs(-90.0),
),
blinker_radius,
),
)),
right_blinkers: Some((
Circle::new(
front_blinker_pos
.project_away(CAR_WIDTH / 2.0 - 0.5, front_blinker_angle.rotate_degs(90.0)),
front_blinker_pos.project_away(
CAR_WIDTH / 2.0 - Distance::meters(0.5),
front_blinker_angle.rotate_degs(90.0),
),
blinker_radius,
),
Circle::new(
back_blinker_pos
.project_away(CAR_WIDTH / 2.0 - 0.5, back_blinker_angle.rotate_degs(90.0)),
back_blinker_pos.project_away(
CAR_WIDTH / 2.0 - Distance::meters(0.5),
back_blinker_angle.rotate_degs(90.0),
),
blinker_radius,
),
)),
@ -216,7 +222,12 @@ impl Renderable for DrawCar {
}
}
fn thick_line_from_angle(thickness: f64, line_length: f64, pt: Pt2D, angle: Angle) -> Polygon {
fn thick_line_from_angle(
thickness: Distance,
line_length: Distance,
pt: Pt2D,
angle: Angle,
) -> Polygon {
let pt2 = pt.project_away(line_length, angle);
// Shouldn't ever fail for a single line
PolyLine::new(vec![pt, pt2]).make_polygons(thickness)

View File

@ -50,19 +50,18 @@ impl DrawExtraShape {
road: None,
})
} else {
let width = get_sidewalk_width(&s.attributes)
.unwrap_or_else(|| Distance::meters(EXTRA_SHAPE_THICKNESS));
let width = get_sidewalk_width(&s.attributes).unwrap_or(EXTRA_SHAPE_THICKNESS);
let pl = PolyLine::new(pts);
// The blockface line endpoints will be close to other roads, so match based on the
// middle of the blockface.
// TODO Long blockfaces sometimes cover two roads. Should maybe find ALL matches within
// the threshold distance?
let road = closest
.closest_pt(pl.middle(), Distance::meters(5.0 * LANE_THICKNESS))
.closest_pt(pl.middle(), LANE_THICKNESS * 5.0)
.map(|(r, _)| r);
Some(DrawExtraShape {
id,
shape: Shape::Polygon(pl.make_polygons(width.inner_meters())),
shape: Shape::Polygon(pl.make_polygons(width)),
attributes: s.attributes,
road,
})

View File

@ -224,7 +224,7 @@ fn draw_signal_cycle_with_icons(cycle: &Cycle, g: &mut GfxCtx, ctx: &Ctx) {
};
}
let radius = Distance::meters(LANE_THICKNESS / 2.0);
let radius = LANE_THICKNESS / 2.0;
// TODO Ignore right_ok...
{
@ -234,7 +234,7 @@ fn draw_signal_cycle_with_icons(cycle: &Cycle, g: &mut GfxCtx, ctx: &Ctx) {
} else {
ctx.cs.get_def("traffic light stop", Color::RED)
};
g.draw_circle(color, &Circle::new(center1, radius.inner_meters()));
g.draw_circle(color, &Circle::new(center1, radius));
}
if let Some(pri) = left_priority {
@ -248,16 +248,14 @@ fn draw_signal_cycle_with_icons(cycle: &Cycle, g: &mut GfxCtx, ctx: &Ctx) {
};
g.draw_circle(
ctx.cs.get_def("traffic light box", Color::BLACK),
&Circle::new(center2, radius.inner_meters()),
&Circle::new(center2, radius),
);
g.draw_arrow(
color,
0.1,
Distance::meters(0.1),
&Line::new(
center2
.project_away(radius.inner_meters(), lane_line.angle().rotate_degs(90.0)),
center2
.project_away(radius.inner_meters(), lane_line.angle().rotate_degs(-90.0)),
center2.project_away(radius, lane_line.angle().rotate_degs(90.0)),
center2.project_away(radius, lane_line.angle().rotate_degs(-90.0)),
),
);
}

View File

@ -81,8 +81,8 @@ impl DrawLane {
PARCEL_BOUNDARY_THICKNESS / 2.0,
&l,
);
g.draw_circle(circle_color, &Circle::new(l.pt1(), 0.4));
g.draw_circle(circle_color, &Circle::new(l.pt2(), 0.8));
g.draw_circle(circle_color, &Circle::new(l.pt1(), Distance::meters(0.4)));
g.draw_circle(circle_color, &Circle::new(l.pt2(), Distance::meters(0.8)));
}
}
}
@ -122,14 +122,14 @@ impl Renderable for DrawLane {
}
// TODO this always does it at pt1
fn perp_line(l: Line, length: f64) -> Line {
fn perp_line(l: Line, length: Distance) -> Line {
let pt1 = l.shift_right(length / 2.0).pt1();
let pt2 = l.shift_left(length / 2.0).pt1();
Line::new(pt1, pt2)
}
fn calculate_sidewalk_lines(lane: &Lane, cs: &ColorScheme) -> Vec<(Color, Polygon)> {
let tile_every = Distance::meters(LANE_THICKNESS);
let tile_every = LANE_THICKNESS;
let color = cs.get_def("sidewalk lines", Color::grey(0.7));
let length = lane.length();
@ -140,10 +140,10 @@ fn calculate_sidewalk_lines(lane: &Lane, cs: &ColorScheme) -> Vec<(Color, Polygo
while dist_along < length - tile_every {
let (pt, angle) = lane.dist_along(dist_along);
// Reuse perp_line. Project away an arbitrary amount
let pt2 = pt.project_away(1.0, angle);
let pt2 = pt.project_away(Distance::meters(1.0), angle);
result.push((
color,
perp_line(Line::new(pt, pt2), LANE_THICKNESS).make_polygons(0.25),
perp_line(Line::new(pt, pt2), LANE_THICKNESS).make_polygons(Distance::meters(0.25)),
));
dist_along += tile_every;
}
@ -153,8 +153,7 @@ fn calculate_sidewalk_lines(lane: &Lane, cs: &ColorScheme) -> Vec<(Color, Polygo
fn calculate_parking_lines(lane: &Lane, cs: &ColorScheme) -> Vec<(Color, Polygon)> {
// meters, but the dims get annoying below to remove
// TODO make Pt2D natively understand meters, projecting away by an angle
let leg_length = 1.0;
let leg_length = Distance::meters(1.0);
let color = cs.get_def("parking lines", Color::WHITE);
let mut result = Vec::new();
@ -168,13 +167,22 @@ fn calculate_parking_lines(lane: &Lane, cs: &ColorScheme) -> Vec<(Color, Polygon
let t_pt = pt.project_away(LANE_THICKNESS * 0.4, perp_angle);
// The perp leg
let p1 = t_pt.project_away(leg_length, perp_angle.opposite());
result.push((color, Line::new(t_pt, p1).make_polygons(0.25)));
result.push((
color,
Line::new(t_pt, p1).make_polygons(Distance::meters(0.25)),
));
// Upper leg
let p2 = t_pt.project_away(leg_length, lane_angle);
result.push((color, Line::new(t_pt, p2).make_polygons(0.25)));
result.push((
color,
Line::new(t_pt, p2).make_polygons(Distance::meters(0.25)),
));
// Lower leg
let p3 = t_pt.project_away(leg_length, lane_angle.opposite());
result.push((color, Line::new(t_pt, p3).make_polygons(0.25)));
result.push((
color,
Line::new(t_pt, p3).make_polygons(Distance::meters(0.25)),
));
}
}
@ -199,7 +207,7 @@ fn calculate_driving_lines(lane: &Lane, parent: &Road, cs: &ColorScheme) -> Vec<
.slice(dash_separation, lane_edge_pts.length() - dash_separation)
.unwrap()
.0
.dashed_polygons(0.25, dash_len, dash_separation);
.dashed_polygons(Distance::meters(0.25), dash_len, dash_separation);
polygons
.into_iter()
.map(|p| (cs.get_def("dashed lane line", Color::WHITE), p))
@ -220,7 +228,7 @@ fn calculate_stop_sign_line(
let (pt1, angle) = lane.safe_dist_along(lane.length() - Distance::meters(1.0))?;
// Reuse perp_line. Project away an arbitrary amount
let pt2 = pt1.project_away(1.0, angle);
let pt2 = pt1.project_away(Distance::meters(1.0), angle);
// Don't clobber the yellow line.
let line = if road.is_canonical_lane(lane.id) {
perp_line(
@ -233,7 +241,7 @@ fn calculate_stop_sign_line(
Some((
cs.get_def("stop line for lane", Color::RED),
line.make_polygons(0.45),
line.make_polygons(Distance::meters(0.45)),
))
}
@ -266,7 +274,7 @@ fn turn_markings(turn: &Turn, map: &Map, cs: &ColorScheme) -> Vec<(Color, Polygo
.slice(len - Distance::meters(7.0), len - Distance::meters(5.0))
.unwrap()
.0;
let base_polygon = common_base.make_polygons(0.1);
let base_polygon = common_base.make_polygons(Distance::meters(0.1));
let turn_line = Line::new(
common_base.last_pt(),
common_base
@ -276,6 +284,11 @@ fn turn_markings(turn: &Turn, map: &Map, cs: &ColorScheme) -> Vec<(Color, Polygo
let color = cs.get_def("turn restrictions on lane", Color::WHITE);
let mut result = vec![(color, base_polygon)];
result.extend(turn_line.make_arrow(0.05).into_iter().map(|p| (color, p)));
result.extend(
turn_line
.make_arrow(Distance::meters(0.05))
.into_iter()
.map(|p| (color, p)),
);
result
}

View File

@ -22,21 +22,20 @@ pub use crate::render::map::{DrawMap, RenderOrder};
pub use crate::render::pedestrian::DrawPedestrian;
pub use crate::render::turn::{DrawCrosswalk, DrawTurn};
use ezgui::{Color, GfxCtx};
use geom::{Bounds, Pt2D};
use geom::{Bounds, Distance, Pt2D};
use map_model::Map;
use sim::{DrawCarInput, VehicleType};
use std::f64;
// These are all in meters
const PARCEL_BOUNDARY_THICKNESS: f64 = 0.5;
const EXTRA_SHAPE_THICKNESS: f64 = 1.0;
const EXTRA_SHAPE_POINT_RADIUS: f64 = 1.0;
const PARCEL_BOUNDARY_THICKNESS: Distance = Distance::const_meters(0.5);
const EXTRA_SHAPE_THICKNESS: Distance = Distance::const_meters(1.0);
const EXTRA_SHAPE_POINT_RADIUS: Distance = Distance::const_meters(1.0);
const BIG_ARROW_THICKNESS: f64 = 0.5;
const BIG_ARROW_THICKNESS: Distance = Distance::const_meters(0.5);
const TURN_ICON_ARROW_THICKNESS: f64 = 0.15;
const TURN_ICON_ARROW_LENGTH: f64 = 2.0;
pub const CROSSWALK_LINE_THICKNESS: f64 = 0.25;
const TURN_ICON_ARROW_THICKNESS: Distance = Distance::const_meters(0.15);
const TURN_ICON_ARROW_LENGTH: Distance = Distance::const_meters(2.0);
pub const CROSSWALK_LINE_THICKNESS: Distance = Distance::const_meters(0.25);
pub const MIN_ZOOM_FOR_MARKINGS: f64 = 5.0;

View File

@ -1,11 +1,11 @@
use crate::objects::{Ctx, ID};
use crate::render::{RenderOptions, Renderable};
use ezgui::{Color, GfxCtx};
use geom::{Bounds, Circle, Line, Pt2D};
use geom::{Bounds, Circle, Distance, Line, Pt2D};
use map_model::Map;
use sim::{DrawPedestrianInput, PedestrianID};
const RADIUS: f64 = 1.0;
const RADIUS: Distance = Distance::const_meters(1.0);
pub struct DrawPedestrian {
pub id: PedestrianID,
@ -59,7 +59,7 @@ impl Renderable for DrawPedestrian {
if let Some(ref a) = self.turn_arrow {
g.draw_arrow(
ctx.cs.get_def("pedestrian turn arrow", Color::CYAN),
0.25,
Distance::meters(0.25),
a,
);
}

View File

@ -6,7 +6,6 @@ use crate::render::{
use ezgui::{Color, GfxCtx};
use geom::{Bounds, Circle, Distance, Line, Polygon, Pt2D};
use map_model::{Map, Turn, TurnID, LANE_THICKNESS};
use std::f64;
#[derive(Debug)]
pub struct DrawTurn {
@ -22,9 +21,9 @@ impl DrawTurn {
let end_line = map.get_l(turn.id.src).end_line(turn.id.parent);
// Start the distance from the intersection
let icon_center = end_line.reverse().unbounded_dist_along(Distance::meters(
(offset_along_lane + 0.5) * TURN_ICON_ARROW_LENGTH,
));
let icon_center = end_line
.reverse()
.unbounded_dist_along(TURN_ICON_ARROW_LENGTH * (offset_along_lane + 0.5));
let icon_circle = Circle::new(icon_center, TURN_ICON_ARROW_LENGTH / 2.0);
@ -43,10 +42,10 @@ impl DrawTurn {
// TODO This is hiding a real problem... some composite turns probably need to have their
// geometry simplified a bit.
if let Some(pl) = t.geom.without_last_line() {
g.draw_polygon(color, &pl.make_polygons(2.0 * BIG_ARROW_THICKNESS));
g.draw_polygon(color, &pl.make_polygons(BIG_ARROW_THICKNESS * 2.0));
}
// And a cap on the arrow
g.draw_arrow(color, 2.0 * BIG_ARROW_THICKNESS, &t.geom.last_line());
g.draw_arrow(color, BIG_ARROW_THICKNESS * 2.0, &t.geom.last_line());
}
pub fn draw_dashed(turn: &Turn, g: &mut GfxCtx, color: Color) {
@ -118,8 +117,8 @@ impl DrawCrosswalk {
// Start at least LANE_THICKNESS out to not hit sidewalk corners. Also account for
// the thickness of the crosswalk line itself. Center the lines inside these two
// boundaries.
let boundary = Distance::meters(LANE_THICKNESS + CROSSWALK_LINE_THICKNESS);
let tile_every = Distance::meters(0.6 * LANE_THICKNESS);
let boundary = LANE_THICKNESS + CROSSWALK_LINE_THICKNESS;
let tile_every = LANE_THICKNESS * 0.6;
let line = {
// The middle line in the crosswalk geometry is the main crossing line.
let pts = turn.geom.points();
@ -136,7 +135,7 @@ impl DrawCrosswalk {
for _ in 0..=num_markings {
let pt1 = line.dist_along(dist_along);
// Reuse perp_line. Project away an arbitrary amount
let pt2 = pt1.project_away(1.0, turn.angle());
let pt2 = pt1.project_away(Distance::meters(1.0), turn.angle());
draw.push(
perp_line(Line::new(pt1, pt2), LANE_THICKNESS)
.make_polygons(CROSSWALK_LINE_THICKNESS),
@ -154,7 +153,7 @@ impl DrawCrosswalk {
}
// TODO copied from DrawLane
fn perp_line(l: Line, length: f64) -> Line {
fn perp_line(l: Line, length: Distance) -> Line {
let pt1 = l.shift_right(length / 2.0).pt1();
let pt2 = l.shift_left(length / 2.0).pt1();
Line::new(pt1, pt2)

View File

@ -1,5 +1,5 @@
use crate::{Canvas, Color, ScreenPt};
use geom::{Circle, Line, Polygon, Pt2D};
use geom::{Circle, Distance, Line, Polygon, Pt2D};
use glium::{implement_vertex, uniform, Surface};
const TRIANGLES_PER_CIRCLE: usize = 60;
@ -100,11 +100,11 @@ impl<'a> GfxCtx<'a> {
// Use graphics::Line internally for now, but make it easy to switch to something else by
// picking this API now.
pub fn draw_line(&mut self, color: Color, thickness: f64, line: &Line) {
pub fn draw_line(&mut self, color: Color, thickness: Distance, line: &Line) {
self.draw_polygon(color, &line.make_polygons(thickness));
}
pub fn draw_rounded_line(&mut self, color: Color, thickness: f64, line: &Line) {
pub fn draw_rounded_line(&mut self, color: Color, thickness: Distance, line: &Line) {
self.draw_polygon_batch(vec![
(color, &line.make_polygons(thickness)),
(
@ -118,7 +118,7 @@ impl<'a> GfxCtx<'a> {
]);
}
pub fn draw_arrow(&mut self, color: Color, thickness: f64, line: &Line) {
pub fn draw_arrow(&mut self, color: Color, thickness: Distance, line: &Line) {
let polygons = line.make_arrow(thickness);
self.draw_polygon_batch(polygons.iter().map(|poly| (color, poly)).collect());
}

View File

@ -1,30 +1,30 @@
use crate::{Angle, Bounds, Polygon, Pt2D};
use crate::{Angle, Bounds, Distance, Polygon, Pt2D};
use serde_derive::{Deserialize, Serialize};
use std::fmt;
#[derive(Serialize, Deserialize, Debug)]
pub struct Circle {
pub center: Pt2D,
pub radius: f64,
pub radius: Distance,
}
impl Circle {
pub fn new(center: Pt2D, radius: f64) -> Circle {
pub fn new(center: Pt2D, radius: Distance) -> Circle {
Circle { center, radius }
}
pub fn contains_pt(&self, pt: Pt2D) -> bool {
// avoid sqrt by squaring radius instead
(pt.x() - self.center.x()).powi(2) + (pt.y() - self.center.y()).powi(2)
< self.radius.powi(2)
< self.radius.inner_meters().powi(2)
}
pub fn get_bounds(&self) -> Bounds {
Bounds {
min_x: self.center.x() - self.radius,
max_x: self.center.x() + self.radius,
min_y: self.center.y() - self.radius,
max_y: self.center.y() + self.radius,
min_x: self.center.x() - self.radius.inner_meters(),
max_x: self.center.x() + self.radius.inner_meters(),
min_y: self.center.y() - self.radius.inner_meters(),
max_y: self.center.y() + self.radius.inner_meters(),
}
}

View File

@ -36,15 +36,15 @@ impl Line {
PolyLine::new(self.points())
}
pub fn make_polygons(&self, thickness: f64) -> Polygon {
pub fn make_polygons(&self, thickness: Distance) -> Polygon {
self.to_polyline().make_polygons(thickness)
}
// TODO One polygon, please :)
pub fn make_arrow(&self, thickness: f64) -> Vec<Polygon> {
let head_size = 2.0 * thickness;
pub fn make_arrow(&self, thickness: Distance) -> Vec<Polygon> {
let head_size = thickness * 2.0;
let angle = self.angle();
let triangle_height = Distance::meters((head_size / 2.0).sqrt());
let triangle_height = (head_size / 2.0).sqrt();
vec![
Polygon::new(&vec![
//self.pt2(),
@ -107,8 +107,8 @@ impl Line {
}
}
pub fn shift_right(&self, width: f64) -> Line {
assert!(width >= 0.0);
pub fn shift_right(&self, width: Distance) -> Line {
assert!(width >= Distance::ZERO);
let angle = self.angle().rotate_degs(90.0);
Line(
self.pt1().project_away(width, angle),
@ -116,8 +116,8 @@ impl Line {
)
}
pub fn shift_left(&self, width: f64) -> Line {
assert!(width >= 0.0);
pub fn shift_left(&self, width: Distance) -> Line {
assert!(width >= Distance::ZERO);
let angle = self.angle().rotate_degs(-90.0);
Line(
self.pt1().project_away(width, angle),
@ -125,8 +125,8 @@ impl Line {
)
}
pub(crate) fn shift_either_direction(&self, width: f64) -> Line {
if width >= 0.0 {
pub(crate) fn shift_either_direction(&self, width: Distance) -> Line {
if width >= Distance::ZERO {
self.shift_right(width)
} else {
self.shift_left(-width)

View File

@ -3,7 +3,6 @@ use crate::{
};
use serde_derive::{Deserialize, Serialize};
use std::collections::HashSet;
use std::f64;
use std::fmt;
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
@ -51,7 +50,7 @@ impl PolyLine {
PolyLine { pts, length }
}
pub fn make_polygons_for_boundary(pts: Vec<Pt2D>, thickness: f64) -> Polygon {
pub fn make_polygons_for_boundary(pts: Vec<Pt2D>, thickness: Distance) -> Polygon {
// Points WILL repeat -- fast-path some stuff.
let pl = PolyLine {
pts,
@ -222,18 +221,18 @@ impl PolyLine {
Some(PolyLine::new(self.pts[0..self.pts.len() - 1].to_vec()))
}
pub fn shift_right(&self, width: f64) -> PolyLine {
pub fn shift_right(&self, width: Distance) -> PolyLine {
self.shift_with_corrections(width)
}
pub fn shift_left(&self, width: f64) -> PolyLine {
pub fn shift_left(&self, width: Distance) -> PolyLine {
self.shift_with_corrections(-width)
}
// Things to remember about shifting polylines:
// - the length before and after probably don't match up
// - the number of points will match
fn shift_with_corrections(&self, width: f64) -> PolyLine {
fn shift_with_corrections(&self, width: Distance) -> PolyLine {
let result = PolyLine::new(Pt2D::approx_dedupe(
self.shift_with_sharp_angles(width),
EPSILON_DIST,
@ -247,7 +246,7 @@ impl PolyLine {
fixed
}
fn shift_with_sharp_angles(&self, width: f64) -> Vec<Pt2D> {
fn shift_with_sharp_angles(&self, width: Distance) -> Vec<Pt2D> {
if self.pts.len() == 2 {
let l = Line::new(self.pts[0], self.pts[1]).shift_either_direction(width);
return vec![l.pt1(), l.pt2()];
@ -290,7 +289,7 @@ impl PolyLine {
result
}
pub fn make_polygons(&self, width: f64) -> Polygon {
pub fn make_polygons(&self, width: Distance) -> Polygon {
// TODO Don't use the angle corrections yet -- they seem to do weird things.
let side1 = self.shift_with_sharp_angles(width / 2.0);
let side2 = self.shift_with_sharp_angles(-width / 2.0);
@ -315,7 +314,7 @@ impl PolyLine {
pub fn dashed_polygons(
&self,
width: f64,
width: Distance,
dash_len: Distance,
dash_separation: Distance,
) -> Vec<Polygon> {

View File

@ -86,12 +86,15 @@ impl Pt2D {
// TODO better name
// TODO Meters for dist?
pub fn project_away(self, dist: f64, theta: Angle) -> Pt2D {
pub fn project_away(self, dist: Distance, theta: Angle) -> Pt2D {
// If negative, caller should use theta.opposite()
assert!(dist >= 0.0);
assert!(dist >= Distance::ZERO);
let (sin, cos) = theta.normalized_radians().sin_cos();
Pt2D::new(self.x() + dist * cos, self.y() + dist * sin)
Pt2D::new(
self.x() + dist.inner_meters() * cos,
self.y() + dist.inner_meters() * sin,
)
}
// TODO valid to do euclidean distance on world-space points that're formed from

View File

@ -35,6 +35,10 @@ impl Distance {
}
}
pub fn sqrt(self) -> Distance {
Distance::meters(self.0.sqrt())
}
// TODO Remove by making Distance itself Ord.
pub fn as_ordered(self) -> NotNan<f64> {
NotNan::new(self.0).unwrap()
@ -75,6 +79,14 @@ impl ops::Sub for Distance {
}
}
impl ops::Neg for Distance {
type Output = Distance;
fn neg(self) -> Distance {
Distance::meters(-self.0)
}
}
impl ops::SubAssign for Distance {
fn sub_assign(&mut self, other: Distance) {
*self = *self - other;

View File

@ -1,6 +1,6 @@
use aabb_quadtree::QuadTree;
use ezgui::{Color, GfxCtx};
use geom::{Bounds, Line, Polygon, Pt2D};
use geom::{Bounds, Distance, Line, Polygon, Pt2D};
use map_model::{Building, BuildingID, Map, Road, RoadID, LANE_THICKNESS};
// black
@ -12,7 +12,7 @@ const BUILDING: Color = Color::rgb_f(136.0 / 255.0, 30.0 / 255.0, 228.0 / 255.0)
// dark orange / red
const PATH: Color = Color::rgb_f(247.0 / 255.0, 95.0 / 255.0, 28.0 / 255.0);
const LINE_WIDTH: f64 = 1.0;
const LINE_WIDTH: Distance = Distance::const_meters(1.0);
pub struct DrawMap {
roads: Vec<DrawRoad>,

View File

@ -38,8 +38,9 @@ pub use crate::traffic_signals::{ControlTrafficSignal, Cycle};
pub use crate::traversable::{Position, Traversable};
pub use crate::turn::{Turn, TurnID, TurnPriority, TurnType};
use abstutil::Cloneable;
use geom::Distance;
pub const LANE_THICKNESS: f64 = 2.5;
pub const LANE_THICKNESS: Distance = Distance::const_meters(2.5);
impl Cloneable for ControlTrafficSignal {}
impl Cloneable for IntersectionID {}

View File

@ -114,8 +114,11 @@ fn generalized_trim_back(
if let Some((hit, angle)) = use_pl1.intersection(&use_pl2) {
// Find where the perpendicular hits the original road line
let perp =
Line::new(hit, hit.project_away(1.0, angle.rotate_degs(90.0))).infinite();
let perp = Line::new(
hit,
hit.project_away(Distance::meters(1.0), angle.rotate_degs(90.0)),
)
.infinite();
// How could something perpendicular to a shifted polyline never hit the original
// polyline?
let trim_to = road_center.intersection_infinite(&perp).unwrap();

View File

@ -5,7 +5,7 @@ mod merge;
use crate::raw_data::{StableIntersectionID, StableRoadID};
use crate::{raw_data, MapEdits, LANE_THICKNESS};
use abstutil::Timer;
use geom::{GPSBounds, PolyLine, Pt2D};
use geom::{Distance, GPSBounds, PolyLine, Pt2D};
use serde_derive::{Deserialize, Serialize};
use std::collections::{BTreeMap, BTreeSet};
@ -25,8 +25,8 @@ pub struct Road {
pub dst_i: StableIntersectionID,
pub original_center_pts: PolyLine,
pub trimmed_center_pts: PolyLine,
pub fwd_width: f64,
pub back_width: f64,
pub fwd_width: Distance,
pub back_width: Distance,
pub lane_specs: Vec<lane_specs::LaneSpec>,
}
@ -90,8 +90,8 @@ impl InitialMap {
);
let lane_specs = lane_specs::get_lane_specs(r, *stable_id, edits);
let mut fwd_width = 0.0;
let mut back_width = 0.0;
let mut fwd_width = Distance::ZERO;
let mut back_width = Distance::ZERO;
for l in &lane_specs {
if l.reverse_pts {
back_width += LANE_THICKNESS;

View File

@ -482,5 +482,5 @@ fn validate(map: &Map, steps: &Vec<PathStep>) {
// Negate since BinaryHeap is a max-heap.
fn dist_to_pri_queue(dist: Distance) -> NotNan<f64> {
(dist * -1.0).as_ordered()
-dist.as_ordered()
}

View File

@ -1,5 +1,5 @@
use ezgui::{Color, GfxCtx};
use geom::{Circle, PolyLine};
use geom::{Circle, Distance, PolyLine};
// TODO Don't just use ezgui constants in this crate, since we want the slight transparency by
// default.
@ -11,11 +11,11 @@ pub const BLACK: Color = Color::BLACK.alpha(0.3);
pub const SOLID_BLACK: Color = Color::BLACK.alpha(0.9);
pub const YELLOW: Color = Color::YELLOW.alpha(0.8);
pub fn draw_polyline(g: &mut GfxCtx, pl: &PolyLine, thickness: f64, color: Color) {
pub fn draw_polyline(g: &mut GfxCtx, pl: &PolyLine, thickness: Distance, color: Color) {
for l in pl.lines() {
g.draw_line(color, thickness, &l);
}
let radius = 0.5;
let radius = Distance::meters(0.5);
let pts = pl.points();
assert!(pts.len() >= 2);
for pt in pts {

View File

@ -1,13 +1,13 @@
use crate::common::{draw_polyline, SOLID_BLACK, YELLOW};
use ezgui::{Color, GfxCtx};
use geom::{PolyLine, Pt2D};
use geom::{Distance, PolyLine, Pt2D};
// Copied from map_model; no need to have to rebuild that crate
const LANE_THICKNESS: f64 = 2.5;
const LANE_THICKNESS: Distance = Distance::const_meters(2.5);
#[allow(clippy::unreadable_literal)]
pub fn run(g: &mut GfxCtx) {
let thin = 0.25;
let thin = Distance::meters(0.25);
let shift1_width = LANE_THICKNESS * 0.5;
let shift2_width = LANE_THICKNESS * 1.5;
@ -80,5 +80,5 @@ pub fn draw_lane(g: &mut GfxCtx, pl: &PolyLine, color: Color) {
g.draw_polygon(color, &pl.make_polygons(LANE_THICKNESS));
// Debug the center points
draw_polyline(g, pl, 0.25, SOLID_BLACK);
draw_polyline(g, pl, Distance::meters(0.25), SOLID_BLACK);
}

View File

@ -1,11 +1,11 @@
use crate::common::{draw_polyline, BLACK, RED};
use ezgui::GfxCtx;
use geom::{PolyLine, Pt2D};
use geom::{Distance, PolyLine, Pt2D};
#[allow(clippy::unreadable_literal)]
pub fn run(g: &mut GfxCtx, labels: &mut Vec<(Pt2D, String)>) {
let thin = 1.0;
let width = 50.0;
let thin = Distance::meters(1.0);
let width = Distance::meters(50.0);
// TODO retain this as a regression test
let center_pts = PolyLine::new(

View File

@ -7,7 +7,6 @@ mod trim_polyline;
use ezgui::{Canvas, EventLoopMode, GfxCtx, Key, Prerender, Text, UserInput, GUI};
use geom::Pt2D;
use std::f64;
use std::process;
pub struct UI {

View File

@ -1,6 +1,6 @@
use crate::common::{draw_polyline, BLACK, BLUE, GREEN, RED};
use ezgui::GfxCtx;
use geom::{PolyLine, Pt2D};
use geom::{Distance, PolyLine, Pt2D};
pub fn run(p3_offset: (f64, f64), g: &mut GfxCtx, labels: &mut Vec<(Pt2D, String)>) {
macro_rules! point {
@ -17,9 +17,9 @@ pub fn run(p3_offset: (f64, f64), g: &mut GfxCtx, labels: &mut Vec<(Pt2D, String
};
}*/
let thin = 1.0;
let thick = 5.0;
let shift_away = 50.0;
let thin = Distance::meters(1.0);
let thick = Distance::meters(5.0);
let shift_away = Distance::meters(50.0);
point!(p1, Pt2D::new(100.0, 100.0));
point!(p2, Pt2D::new(110.0, 200.0));

View File

@ -1,6 +1,6 @@
use crate::common::{draw_polyline, BLUE, GREEN, RED};
use ezgui::GfxCtx;
use geom::{Circle, PolyLine, Pt2D};
use geom::{Circle, Distance, PolyLine, Pt2D};
#[allow(clippy::unreadable_literal)]
pub fn run(g: &mut GfxCtx) {
@ -20,12 +20,12 @@ pub fn run(g: &mut GfxCtx) {
let (hit, _) = vertical_pl.intersection(&horiz_pl).unwrap();
if false {
g.draw_circle(BLUE, &Circle::new(hit, 1.0));
g.draw_circle(BLUE, &Circle::new(hit, Distance::meters(1.0)));
} else {
vertical_pl = vertical_pl.get_slice_ending_at(hit).unwrap();
horiz_pl = horiz_pl.get_slice_ending_at(hit).unwrap();
}
draw_polyline(g, &vertical_pl, 0.25, RED);
draw_polyline(g, &horiz_pl, 0.25, GREEN);
draw_polyline(g, &vertical_pl, Distance::meters(0.25), RED);
draw_polyline(g, &horiz_pl, Distance::meters(0.25), GREEN);
}

View File

@ -859,7 +859,7 @@ impl DrivingSimState {
1.0 - progress
};
// TODO we're assuming the parking lane is to the right of us!
base_body.shift_right(project_away_ratio * LANE_THICKNESS)
base_body.shift_right(LANE_THICKNESS * project_away_ratio)
} else {
base_body
};

View File

@ -142,7 +142,7 @@ impl Vehicle {
speed: Speed,
dist: Distance,
) -> Result<Acceleration, Error> {
if dist < EPSILON_DIST * -1.0 {
if dist < -EPSILON_DIST {
return Err(Error::new(format!(
"{} called accel_to_stop_in_dist({}, {}) with negative distance",
self.id, speed, dist

View File

@ -3,7 +3,7 @@ mod model;
use crate::model::{BuildingID, Direction, Model, ID};
use aabb_quadtree::QuadTree;
use ezgui::{Canvas, Color, EventLoopMode, GfxCtx, Key, Prerender, Text, UserInput, Wizard, GUI};
use geom::Line;
use geom::{Distance, Line};
use map_model::raw_data::{StableIntersectionID, StableRoadID};
use std::{env, process};
@ -210,7 +210,7 @@ impl GUI<Text> for UI {
if let Some(cursor) = self.canvas.get_cursor_in_map_space() {
g.draw_line(
Color::GREEN,
5.0,
Distance::meters(5.0),
&Line::new(self.model.get_i_center(i1), cursor),
);
}

View File

@ -8,9 +8,9 @@ use serde_derive::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::mem;
const INTERSECTION_RADIUS: f64 = 5.0;
const INTERSECTION_RADIUS: Distance = Distance::const_meters(5.0);
const BUILDING_LENGTH: f64 = 30.0;
const CENTER_LINE_THICKNESS: f64 = 0.5;
const CENTER_LINE_THICKNESS: Distance = Distance::const_meters(0.5);
const HIGHLIGHT_COLOR: Color = Color::CYAN;
@ -99,7 +99,7 @@ impl Road {
for (idx, lt) in self.lanes.fwd.iter().enumerate() {
let polygon = base
.shift_right(((idx as f64) + 0.5) * LANE_THICKNESS)
.shift_right(LANE_THICKNESS * ((idx as f64) + 0.5))
.make_polygons(LANE_THICKNESS);
g.draw_polygon(
if highlight_fwd {
@ -112,7 +112,7 @@ impl Road {
}
for (idx, lt) in self.lanes.back.iter().enumerate() {
let polygon = base
.shift_left(((idx as f64) + 0.5) * LANE_THICKNESS)
.shift_left(LANE_THICKNESS * ((idx as f64) + 0.5))
.make_polygons(LANE_THICKNESS);
g.draw_polygon(
if highlight_back {

View File

@ -80,7 +80,7 @@ fn test_accel_to_stop_in_dist(vehicle: Vehicle, orig_dist_left: Distance, orig_s
speed = new_speed;
dist_left -= dist_covered;
if dist_left < EPSILON_DIST * -1.0 {
if dist_left < -EPSILON_DIST {
println!(" Result: speed {}, dist_left {}", speed, dist_left);
panic!("We overshot too much!");
}