using Warn in all of geom

This commit is contained in:
Dustin Carlino 2019-02-20 10:13:43 -08:00
parent 1848387ef0
commit c2791a6ead
23 changed files with 162 additions and 100 deletions

View File

@ -88,6 +88,13 @@ impl<T> Warn<T> {
self.value
}
pub fn map<O, F: Fn(T) -> O>(self, f: F) -> Warn<O> {
Warn {
value: f(self.value),
warnings: self.warnings,
}
}
/*pub fn get_and_append<X>(self, other: &mut Warn<X>) -> T {
other.warnings.extend(self.warnings);
self.value
@ -105,9 +112,9 @@ impl<T> Warn<T> {
}
impl Warn<()> {
pub fn empty() -> Warn<()> {
Warn::ok(())
}
/*pub fn empty_warnings(warnings: Vec<String>) -> Warn<()> {
Warn::warnings((), warnings)
}*/
/*pub fn add_warning(&mut self, line: String) {
self.warnings.push(line);

View File

@ -134,8 +134,8 @@ fn use_parking_hints(
FindClosest::new(&gps_bounds.to_bounds());
for (id, r) in &map.roads {
let pts = PolyLine::new(gps_bounds.must_convert(&r.points));
closest.add((*id, true), &pts.shift_right(LANE_THICKNESS));
closest.add((*id, false), &pts.shift_left(LANE_THICKNESS));
closest.add((*id, true), &pts.shift_right(LANE_THICKNESS).get(timer));
closest.add((*id, false), &pts.shift_left(LANE_THICKNESS).get(timer));
}
'SHAPE: for s in shapes.shapes.into_iter() {

View File

@ -278,7 +278,7 @@ fn extrude_to_boundary(boundary_polygon: &Vec<LonLat>, result: &mut Vec<LonLat>)
);
let slice1 = find_slice(boundary_polygon, closest_to_last, closest_to_first);
let mut backwards_boundary: Vec<LonLat> = boundary_polygon.iter().cloned().collect();
let mut backwards_boundary: Vec<LonLat> = boundary_polygon.to_vec();
backwards_boundary.reverse();
let slice2 = find_slice(&backwards_boundary, closest_to_last, closest_to_first);
if slice_len(&slice1) <= slice_len(&slice2) {

View File

@ -122,6 +122,7 @@ fn load_initial_map(filename: &str, canvas: &mut Canvas, prerender: &Prerender)
ID::HalfRoad(r.id, true),
r.trimmed_center_pts
.shift_right(r.fwd_width / 2.0)
.unwrap()
.make_polygons(r.fwd_width),
Color::grey(0.8),
Text::from_line(format!(
@ -137,6 +138,7 @@ fn load_initial_map(filename: &str, canvas: &mut Canvas, prerender: &Prerender)
ID::HalfRoad(r.id, false),
r.trimmed_center_pts
.shift_left(r.back_width / 2.0)
.unwrap()
.make_polygons(r.back_width),
Color::grey(0.6),
Text::from_line(format!(

View File

@ -46,6 +46,7 @@ impl NonblockingPlugin for ShowOriginalRoads {
.get_def("original road forwards", Color::RED.alpha(0.5)),
&r.original_center_pts
.shift_right(width_right / 2.0)
.unwrap()
.make_polygons(width_right),
);
}
@ -55,6 +56,7 @@ impl NonblockingPlugin for ShowOriginalRoads {
.get_def("original road backwards", Color::BLUE.alpha(0.5)),
&r.original_center_pts
.shift_left(width_left / 2.0)
.unwrap()
.make_polygons(width_left),
);
}

View File

@ -82,7 +82,7 @@ impl Interval {
let numer = t_1 * v_1 - t_3 * v_3 - x_1 + x_3;
let denom = v_1 - v_3;
Duration::seconds(numer / denom)
} else if a_1 == a_3 {
} else if (a_1 - a_3).abs() < std::f64::EPSILON {
// Sometimes exactly the same acceleration happens.
let numer = a_3 * t_1.powi(2) - a_3 * t_3.powi(2) - 2.0 * t_1 * v_1
+ 2.0 * t_3 * v_3

View File

@ -83,7 +83,7 @@ impl World {
if num_waiting > 0 {
// Short lanes exist
let start = (l.length()
- (num_waiting as f64) * (VEHICLE_LENGTH + FOLLOWING_DISTANCE))
- f64::from(num_waiting) * (VEHICLE_LENGTH + FOLLOWING_DISTANCE))
.max(Distance::ZERO);
g.draw_polygon(
WAITING,
@ -100,7 +100,7 @@ impl World {
&l.lane_center_pts
.slice(
Distance::ZERO,
(num_freeflow as f64) * (VEHICLE_LENGTH + FOLLOWING_DISTANCE),
f64::from(num_freeflow) * (VEHICLE_LENGTH + FOLLOWING_DISTANCE),
)
.unwrap()
.0
@ -179,7 +179,7 @@ impl World {
.unwrap()
.cars
.push_back(Car {
id: id,
id,
max_speed,
path: VecDeque::from(path.clone()),
state: CarState::CrossingLane(TimeInterval {
@ -198,31 +198,25 @@ impl World {
// Promote CrossingLane to Queued.
for queue in self.queues.values_mut() {
for car in queue.cars.iter_mut() {
match car.state {
CarState::CrossingLane(ref interval) => {
if time > interval.end {
car.state = CarState::Queued;
}
if let CarState::CrossingLane(ref interval) = car.state {
if time > interval.end {
car.state = CarState::Queued;
}
_ => {}
};
}
}
}
// Delete head cars that're completely done.
for queue in self.queues.values_mut() {
while !queue.is_empty() {
match queue.cars[0].state {
CarState::Queued => {
if queue.cars[0].path.len() == 1 {
queue.cars.pop_front();
// TODO Should have some brief delay to creep forwards VEHICLE_LENGTH +
// FOLLOWING_DISTANCE.
continue;
}
if let CarState::Queued = queue.cars[0].state {
if queue.cars[0].path.len() == 1 {
queue.cars.pop_front();
// TODO Should have some brief delay to creep forwards VEHICLE_LENGTH +
// FOLLOWING_DISTANCE.
continue;
}
_ => {}
};
}
break;
}
}
@ -235,12 +229,9 @@ impl World {
continue;
}
let car = &queue.cars[0];
match car.state {
CarState::Queued => {
cars_ready_to_turn.push((queue.id, car.path[1].as_turn()));
}
_ => {}
};
if let CarState::Queued = car.state {
cars_ready_to_turn.push((queue.id, car.path[1].as_turn()));
}
}
// Lane->Turn transitions

View File

@ -44,7 +44,7 @@ impl Queue {
CarState::CrossingLane(ref i) => {
let bound = last_car_back
.map(|b| b - FOLLOWING_DISTANCE)
.unwrap_or(l.length());
.unwrap_or_else(|| l.length());
(i.percent(time) * bound, FREEFLOW)
}
CarState::CrossingTurn(_) => unreachable!(),

View File

@ -171,7 +171,7 @@ impl RoadHeatmap {
Color::RED
};
// TODO Inefficient!
g.draw_polygon(color, &DrawRoad::get_thick(ctx.map.get_r(*r)));
g.draw_polygon(color, &DrawRoad::get_thick(ctx.map.get_r(*r)).unwrap());
}
}
}

View File

@ -47,7 +47,7 @@ impl DrawLane {
draw.extend(calculate_parking_lines(lane, cs));
}
LaneType::Driving | LaneType::Bus => {
draw.extend(calculate_driving_lines(lane, road, cs));
draw.extend(calculate_driving_lines(lane, road, cs, timer));
draw.extend(calculate_turn_markings(map, lane, cs, timer));
}
LaneType::Biking => {}
@ -182,7 +182,12 @@ fn calculate_parking_lines(lane: &Lane, cs: &ColorScheme) -> Vec<(Color, Polygon
result
}
fn calculate_driving_lines(lane: &Lane, parent: &Road, cs: &ColorScheme) -> Vec<(Color, Polygon)> {
fn calculate_driving_lines(
lane: &Lane,
parent: &Road,
cs: &ColorScheme,
timer: &mut Timer,
) -> Vec<(Color, Polygon)> {
// The leftmost lanes don't have dashed white lines.
if parent.dir_and_offset(lane.id).1 == 0 {
return Vec::new();
@ -191,7 +196,10 @@ fn calculate_driving_lines(lane: &Lane, parent: &Road, cs: &ColorScheme) -> Vec<
let dash_separation = Distance::meters(1.5);
let dash_len = Distance::meters(1.0);
let lane_edge_pts = lane.lane_center_pts.shift_left(LANE_THICKNESS / 2.0);
let lane_edge_pts = lane
.lane_center_pts
.shift_left(LANE_THICKNESS / 2.0)
.get(timer);
if lane_edge_pts.length() < dash_separation * 2.0 {
return Vec::new();
}

View File

@ -61,7 +61,7 @@ impl DrawMap {
let mut all_roads: Vec<Polygon> = Vec::new();
for r in map.all_roads() {
timer.next();
let (draw, poly) = DrawRoad::new(r, cs, prerender);
let (draw, poly) = DrawRoad::new(r, cs, prerender, timer);
roads.push(draw);
all_roads.push(poly);
}
@ -159,8 +159,14 @@ impl DrawMap {
// Match shapes with the nearest road + direction (true for forwards)
let mut closest: FindClosest<(RoadID, bool)> = FindClosest::new(&map.get_bounds());
for r in map.all_roads().iter() {
closest.add((r.id, true), &r.center_pts.shift_right(LANE_THICKNESS));
closest.add((r.id, false), &r.center_pts.shift_left(LANE_THICKNESS));
closest.add(
(r.id, true),
&r.center_pts.shift_right(LANE_THICKNESS).get(timer),
);
closest.add(
(r.id, false),
&r.center_pts.shift_left(LANE_THICKNESS).get(timer),
);
}
let gps_bounds = map.get_gps_bounds();

View File

@ -1,6 +1,7 @@
use crate::colors::ColorScheme;
use crate::objects::{DrawCtx, ID};
use crate::render::{RenderOptions, Renderable, BIG_ARROW_THICKNESS};
use abstutil::{Timer, Warn};
use ezgui::{Color, Drawable, GfxCtx, Prerender};
use geom::{Bounds, Polygon, Pt2D};
use map_model::{Map, Road, RoadID, LANE_THICKNESS};
@ -15,8 +16,13 @@ pub struct DrawRoad {
}
impl DrawRoad {
pub fn new(r: &Road, cs: &ColorScheme, prerender: &Prerender) -> (DrawRoad, Polygon) {
let thick = DrawRoad::get_thick(r);
pub fn new(
r: &Road,
cs: &ColorScheme,
prerender: &Prerender,
timer: &mut Timer,
) -> (DrawRoad, Polygon) {
let thick = DrawRoad::get_thick(r).get(timer);
(
DrawRoad {
id: r.id,
@ -31,7 +37,7 @@ impl DrawRoad {
)
}
pub fn get_thick(r: &Road) -> Polygon {
pub fn get_thick(r: &Road) -> Warn<Polygon> {
// TODO Should be a less tedious way to do this
let width_right = (r.children_forwards.len() as f64) * LANE_THICKNESS;
let width_left = (r.children_backwards.len() as f64) * LANE_THICKNESS;
@ -39,11 +45,11 @@ impl DrawRoad {
if width_right >= width_left {
r.center_pts
.shift_right((width_right - width_left) / 2.0)
.make_polygons(total_width)
.map(|pl| pl.make_polygons(total_width))
} else {
r.center_pts
.shift_left((width_left - width_right) / 2.0)
.make_polygons(total_width)
.map(|pl| pl.make_polygons(total_width))
}
}
}

View File

@ -1,6 +1,7 @@
use crate::{
Angle, Bounds, Distance, HashablePt2D, InfiniteLine, Line, Polygon, Pt2D, EPSILON_DIST,
};
use abstutil::Warn;
use serde_derive::{Deserialize, Serialize};
use std::collections::HashSet;
use std::fmt;
@ -242,18 +243,18 @@ impl PolyLine {
Some(PolyLine::new(self.pts[0..self.pts.len() - 1].to_vec()))
}
pub fn shift_right(&self, width: Distance) -> PolyLine {
pub fn shift_right(&self, width: Distance) -> Warn<PolyLine> {
self.shift_with_corrections(width)
}
pub fn shift_left(&self, width: Distance) -> PolyLine {
pub fn shift_left(&self, width: Distance) -> Warn<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: Distance) -> PolyLine {
fn shift_with_corrections(&self, width: Distance) -> Warn<PolyLine> {
let result = PolyLine::new(Pt2D::approx_dedupe(
self.shift_with_sharp_angles(width),
EPSILON_DIST,
@ -263,11 +264,7 @@ impl PolyLine {
} else {
result
};
// TODO The warning is very spammy. Known issue, silence for now.
if false {
check_angles(self, &fixed);
}
fixed
check_angles(self, fixed)
}
fn shift_with_sharp_angles(&self, width: Distance) -> Vec<Pt2D> {
@ -529,16 +526,18 @@ fn fix_angles(orig: &PolyLine, result: PolyLine) -> PolyLine {
PolyLine::new(pts)
}
fn check_angles(a: &PolyLine, b: &PolyLine) {
for (orig_l, shifted_l) in a.lines().iter().zip(b.lines().iter()) {
fn check_angles(orig: &PolyLine, fixed: PolyLine) -> Warn<PolyLine> {
let mut warnings = Vec::new();
for (orig_l, shifted_l) in orig.lines().iter().zip(fixed.lines().iter()) {
let orig_angle = orig_l.angle();
let shifted_angle = shifted_l.angle();
if !orig_angle.approx_eq(shifted_angle, 1.0) {
println!(
"BAD! Points changed angles from {} to {}",
warnings.push(format!(
"Points changed angles from {} to {} during polyline shifting",
orig_angle, shifted_angle
);
));
}
}
Warn::warnings(fixed, warnings)
}

View File

@ -111,7 +111,9 @@ pub fn make_half_map(
// TODO need to factor in yellow center lines (but what's the right thing to even do?
// Reverse points for British-style driving on the left
let width = LANE_THICKNESS * (0.5 + (offset as f64));
let lane_center_pts = unshifted_pts.shift_right(width);
let lane_center_pts = unshifted_pts
.shift_right(width)
.with_context(timer, format!("shift for {}", id));
half_map.lanes.push(Lane {
id,

View File

@ -41,7 +41,7 @@ pub fn fix_ramps(m: &mut InitialMap, timer: &mut Timer) {
}
for (r, i) in fixme {
if fix_ramp(m, r, i) {
if fix_ramp(m, r, i, timer) {
info!("Fixed ramp {} crossing {}", r, i);
} else {
info!("{} crosses {} strangely, but didn't change anything", r, i);
@ -75,7 +75,12 @@ fn floodfill(m: &InitialMap, start: StableIntersectionID, steps: usize) -> HashS
seen
}
fn fix_ramp(m: &mut InitialMap, ramp: StableRoadID, new_src: StableIntersectionID) -> bool {
fn fix_ramp(
m: &mut InitialMap,
ramp: StableRoadID,
new_src: StableIntersectionID,
timer: &mut Timer,
) -> bool {
// Trace backwards...
let mut delete_roads: Vec<StableRoadID> = Vec::new();
let mut delete_intersections: Vec<StableIntersectionID> = Vec::new();
@ -104,7 +109,7 @@ fn fix_ramp(m: &mut InitialMap, ramp: StableRoadID, new_src: StableIntersectionI
if let Some(last_road) = delete_roads.last() {
let mut i = m.intersections.get_mut(&last_normal_intersection).unwrap();
i.roads.remove(&last_road);
i.polygon = geometry::intersection_polygon(i, &mut m.roads);
i.polygon = geometry::intersection_polygon(i, &mut m.roads, timer);
} else {
// TODO Not really sure why, but when there's not a road in between, don't apply the fix.
return false;
@ -120,7 +125,7 @@ fn fix_ramp(m: &mut InitialMap, ramp: StableRoadID, new_src: StableIntersectionI
m.roads.get_mut(&ramp).unwrap().src_i = new_src;
let mut i = m.intersections.get_mut(&new_src).unwrap();
i.roads.insert(ramp);
i.polygon = geometry::intersection_polygon(i, &mut m.roads);
i.polygon = geometry::intersection_polygon(i, &mut m.roads, timer);
}
true
}

View File

@ -1,6 +1,6 @@
use crate::make::initial::{Intersection, Road};
use crate::raw_data::{StableIntersectionID, StableRoadID};
use abstutil::wraparound_get;
use abstutil::{wraparound_get, Timer};
use geom::{Distance, HashablePt2D, Line, PolyLine, Pt2D};
use std::collections::{BTreeMap, HashMap};
@ -11,6 +11,7 @@ const DEGENERATE_INTERSECTION_HALF_LENGTH: Distance = Distance::const_meters(5.0
pub fn intersection_polygon(
i: &Intersection,
roads: &mut BTreeMap<StableRoadID, Road>,
timer: &mut Timer,
) -> Vec<Pt2D> {
let mut road_endpts: Vec<Pt2D> = Vec::new();
@ -35,8 +36,12 @@ pub fn intersection_polygon(
panic!("Incident road {} doesn't have an endpoint at {}", id, i.id);
};
let pl_normal = line.shift_right(width_normal);
let pl_reverse = line.shift_left(width_reverse);
let pl_normal = line
.shift_right(width_normal)
.with_context(timer, format!("pl_normal {}", r.id));
let pl_reverse = line
.shift_left(width_reverse)
.with_context(timer, format!("pl_reverse {}", r.id));
(*id, line.last_line(), pl_normal, pl_reverse)
})
.collect();
@ -56,7 +61,7 @@ pub fn intersection_polygon(
let mut endpoints = if lines.len() == 1 {
deadend(roads, i.id, &lines)
} else {
generalized_trim_back(roads, i.id, &lines)
generalized_trim_back(roads, i.id, &lines, timer)
};
// Close off the polygon
@ -75,6 +80,7 @@ fn generalized_trim_back(
roads: &mut BTreeMap<StableRoadID, Road>,
i: StableIntersectionID,
lines: &Vec<(StableRoadID, Line, PolyLine, PolyLine)>,
timer: &mut Timer,
) -> Vec<Pt2D> {
let mut road_lines: Vec<(StableRoadID, PolyLine, PolyLine)> = Vec::new();
for (r, _, pl1, pl2) in lines {
@ -228,11 +234,31 @@ fn generalized_trim_back(
// Shift those final centers out again to find the main endpoints for the polygon.
if r.dst_i == i {
endpoints.push(r.trimmed_center_pts.shift_right(r.fwd_width).last_pt());
endpoints.push(r.trimmed_center_pts.shift_left(r.back_width).last_pt());
endpoints.push(
r.trimmed_center_pts
.shift_right(r.fwd_width)
.get(timer)
.last_pt(),
);
endpoints.push(
r.trimmed_center_pts
.shift_left(r.back_width)
.get(timer)
.last_pt(),
);
} else {
endpoints.push(r.trimmed_center_pts.shift_left(r.back_width).first_pt());
endpoints.push(r.trimmed_center_pts.shift_right(r.fwd_width).first_pt());
endpoints.push(
r.trimmed_center_pts
.shift_left(r.back_width)
.get(timer)
.first_pt(),
);
endpoints.push(
r.trimmed_center_pts
.shift_right(r.fwd_width)
.get(timer)
.first_pt(),
);
}
if back_pl.length() >= geom::EPSILON_DIST * 3.0

View File

@ -1,26 +1,26 @@
use crate::make::initial::{geometry, InitialMap};
use crate::raw_data::{StableIntersectionID, StableRoadID};
use abstutil::note;
use abstutil::Timer;
use geom::Distance;
use std::collections::HashSet;
pub fn short_roads(map: &mut InitialMap) {
pub fn short_roads(map: &mut InitialMap, timer: &mut Timer) {
if false {
// I228
merge(map, StableRoadID(311));
merge(map, StableRoadID(311), timer);
// I201
merge(map, StableRoadID(240));
merge(map, StableRoadID(240), timer);
// I37
merge(map, StableRoadID(91));
merge(map, StableRoadID(91), timer);
// I40
merge(map, StableRoadID(59));
merge(map, StableRoadID(59), timer);
// I25
merge(map, StableRoadID(389));
merge(map, StableRoadID(22));
merge(map, StableRoadID(389), timer);
merge(map, StableRoadID(22), timer);
}
if false {
@ -36,30 +36,34 @@ pub fn short_roads(map: &mut InitialMap) {
.values()
.find(|r| r.trimmed_center_pts.length() < Distance::meters(5.0))
{
look_at.insert(merge(map, r.id));
look_at.insert(merge(map, r.id, timer));
} else {
break;
}
}
note(format!(
timer.note(format!(
"Deleted {} tiny roads",
orig_count - map.roads.len()
));
for id in look_at {
if map.intersections.contains_key(&id) {
note(format!("Check for merged roads near {}", id));
timer.note(format!("Check for merged roads near {}", id));
}
}
}
}
// Returns the retained intersection.
fn merge(map: &mut InitialMap, merge_road: StableRoadID) -> StableIntersectionID {
fn merge(
map: &mut InitialMap,
merge_road: StableRoadID,
timer: &mut Timer,
) -> StableIntersectionID {
// Arbitrarily kill off the first intersection and keep the second one.
let (delete_i, keep_i) = {
let r = &map.roads[&merge_road];
note(format!(
timer.note(format!(
"Deleting {}, which has original length {} and trimmed length {}",
merge_road,
r.original_center_pts.length(),
@ -139,7 +143,7 @@ fn merge(map: &mut InitialMap, merge_road: StableRoadID) -> StableIntersectionID
map.save(None);
let mut i = map.intersections.get_mut(&keep_i).unwrap();
i.polygon = geometry::intersection_polygon(i, &mut map.roads);
i.polygon = geometry::intersection_polygon(i, &mut map.roads, timer);
// Show the final results of fixing this area
map.save(None);

View File

@ -144,12 +144,12 @@ impl InitialMap {
for i in m.intersections.values_mut() {
timer.next();
i.polygon = geometry::intersection_polygon(i, &mut m.roads);
i.polygon = geometry::intersection_polygon(i, &mut m.roads, timer);
}
fix_ramps::fix_ramps(&mut m, timer);
merge::short_roads(&mut m);
merge::short_roads(&mut m, timer);
m
}

View File

@ -34,14 +34,14 @@ pub fn run(g: &mut GfxCtx) {
(north_yellow, RelatedColors::new(0.0, 1.0, 0.0)),
(south_yellow, RelatedColors::new(0.0, 0.0, 1.0)),
] {
let lane1_in = yellow_line.shift_right(shift1_width);
let lane1_in = yellow_line.shift_right(shift1_width).unwrap();
draw_lane(g, &lane1_in, colors.next().unwrap());
let lane2_in = yellow_line.shift_right(shift2_width);
let lane2_in = yellow_line.shift_right(shift2_width).unwrap();
draw_lane(g, &lane2_in, colors.next().unwrap());
let lane1_out = yellow_line.reversed().shift_right(shift1_width);
let lane1_out = yellow_line.reversed().shift_right(shift1_width).unwrap();
draw_lane(g, &lane1_out, colors.next().unwrap());
let lane2_out = yellow_line.reversed().shift_right(shift2_width);
let lane2_out = yellow_line.reversed().shift_right(shift2_width).unwrap();
draw_lane(g, &lane2_out, colors.next().unwrap());
draw_polyline(g, &yellow_line, thin, YELLOW);

View File

@ -31,13 +31,13 @@ pub fn run(g: &mut GfxCtx, labels: &mut Vec<(Pt2D, String)>) {
g.draw_polygon(BLACK, &center_pts.make_polygons(width));
// TODO colored labels!
let side1 = center_pts.shift_right(width / 2.0);
let side1 = center_pts.shift_right(width / 2.0).unwrap();
//draw_polyline(g, &side1, thin, BLUE);
for (idx, pt) in side1.points().iter().enumerate() {
labels.push((*pt, format!("L{}", idx + 1)));
}
let side2 = center_pts.shift_left(width / 2.0);
let side2 = center_pts.shift_left(width / 2.0).unwrap();
//draw_polyline(g, &side2, thin, GREEN);
for (idx, pt) in side2.points().iter().enumerate() {
labels.push((*pt, format!("R{}", idx + 1)));

View File

@ -37,20 +37,20 @@ pub fn run(p3_offset: (f64, f64), g: &mut GfxCtx, labels: &mut Vec<(Pt2D, String
g.draw_polygon(BLACK, &pts.make_polygons(shift_away));
// Two lanes on one side of the road
let l1_pts = pts.shift_right(shift_away);
let l1_pts = pts.shift_right(shift_away).unwrap();
for (idx, pt) in l1_pts.points().iter().enumerate() {
labels.push((*pt, format!("l1_p{}", idx + 1)));
}
draw_polyline(g, &l1_pts, thin, GREEN);
let l2_pts = pts.shift_right(shift_away * 2.0);
let l2_pts = pts.shift_right(shift_away * 2.0).unwrap();
for (idx, pt) in l2_pts.points().iter().enumerate() {
labels.push((*pt, format!("l2_p{}", idx + 1)));
}
draw_polyline(g, &l2_pts, thin, GREEN);
// Other side
let l3_pts = pts.reversed().shift_right(shift_away);
let l3_pts = pts.reversed().shift_right(shift_away).unwrap();
for (idx, pt) in l3_pts.points().iter().enumerate() {
labels.push((*pt, format!("l3_p{}", idx + 1)));
}

View File

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

View File

@ -77,10 +77,10 @@ impl Road {
]);
if direction {
let width = LANE_THICKNESS * (self.lanes.fwd.len() as f64);
pl.shift_right(width / 2.0).make_polygons(width)
pl.shift_right(width / 2.0).unwrap().make_polygons(width)
} else {
let width = LANE_THICKNESS * (self.lanes.back.len() as f64);
pl.shift_left(width / 2.0).make_polygons(width)
pl.shift_left(width / 2.0).unwrap().make_polygons(width)
}
}
@ -93,6 +93,7 @@ impl Road {
for (idx, lt) in self.lanes.fwd.iter().enumerate() {
let polygon = base
.shift_right(LANE_THICKNESS * ((idx as f64) + 0.5))
.unwrap()
.make_polygons(LANE_THICKNESS);
g.draw_polygon(
if highlight_fwd {
@ -106,6 +107,7 @@ impl Road {
for (idx, lt) in self.lanes.back.iter().enumerate() {
let polygon = base
.shift_left(LANE_THICKNESS * ((idx as f64) + 0.5))
.unwrap()
.make_polygons(LANE_THICKNESS);
g.draw_polygon(
if highlight_back {