more polyline work... get rid of Warn<>. extremely spammy and hasn't

been helpful in ages.
This commit is contained in:
Dustin Carlino 2020-07-11 15:17:16 -07:00
parent f8b8c501ae
commit 07ed1fec95
35 changed files with 113 additions and 358 deletions

View File

@ -2,7 +2,6 @@ mod cli;
mod clone;
mod collections;
mod io;
mod logs;
mod random;
mod time;
@ -19,7 +18,6 @@ pub use crate::io::{
serialize_multimap, serialize_usize, serialized_size_bytes, slurp_file, to_json, write_binary,
write_json, FileWithProgress,
};
pub use crate::logs::Warn;
pub use crate::random::{fork_rng, WeightedUsizeChoice};
pub use crate::time::{
elapsed_seconds, prettyprint_usize, start_profiler, stop_profiler, MeasureMemory, Profiler,

View File

@ -1,81 +0,0 @@
use crate::Timer;
//
// - If it doesn't make sense to plumb Timer to a library call, return Warn<T>.
// - If there's no Timer, plumb the Warn<T>.
// - If a Timer is available and there's a Warn<T>, use get() or with_context().
// - If a Timer is available and something goes wrong, directly call warn().
// - DO NOT prefer plumbing the Warn<T> and accumulating context. It's usually too tedious. Check
// out DrawIntersection for an example.
pub struct Warn<T> {
value: T,
warnings: Vec<String>,
}
impl<T> Warn<T> {
pub fn ok(value: T) -> Warn<T> {
Warn {
value,
warnings: Vec::new(),
}
}
pub fn warn(value: T, warning: String) -> Warn<T> {
Warn {
value,
warnings: vec![warning],
}
}
pub fn warnings(value: T, warnings: Vec<String>) -> Warn<T> {
Warn { value, warnings }
}
pub fn unwrap(self) -> T {
if !self.warnings.is_empty() {
println!("{} warnings:", self.warnings.len());
for line in self.warnings {
println!("{}", line);
}
}
self.value
}
pub fn expect(self, context: String) -> T {
if !self.warnings.is_empty() {
println!("{} warnings ({}):", self.warnings.len(), context);
for line in self.warnings {
println!("{}", line);
}
}
self.value
}
pub fn get(self, timer: &mut Timer) -> T {
// TODO Context from the current Timer phase, caller
for line in self.warnings {
timer.warn(line);
}
self.value
}
pub fn with_context(self, timer: &mut Timer, context: String) -> T {
for line in self.warnings {
timer.warn(format!("{}: {}", context, line));
}
self.value
}
pub fn map<O, F: Fn(T) -> O>(self, f: F) -> Warn<O> {
Warn {
value: f(self.value),
warnings: self.warnings,
}
}
}
impl Warn<()> {
pub fn empty_warnings(warnings: Vec<String>) -> Warn<()> {
Warn::warnings((), warnings)
}
}

View File

@ -136,7 +136,6 @@ fn use_parking_hints(map: &mut RawMap, path: String, timer: &mut Timer) {
map.config
.driving_side
.right_shift(center.clone(), DIRECTED_ROAD_THICKNESS)
.get(timer)
.points(),
);
closest.add(
@ -144,7 +143,6 @@ fn use_parking_hints(map: &mut RawMap, path: String, timer: &mut Timer) {
map.config
.driving_side
.left_shift(center, DIRECTED_ROAD_THICKNESS)
.get(timer)
.points(),
);
}

View File

@ -133,10 +133,7 @@ impl<'a> GfxCtx<'a> {
pub fn draw_arrow(&mut self, color: Color, thickness: Distance, line: &Line) {
self.draw_polygon(
color,
&line
.to_polyline()
.make_arrow(thickness, ArrowCap::Triangle)
.unwrap(),
&line.to_polyline().make_arrow(thickness, ArrowCap::Triangle),
);
}

View File

@ -163,8 +163,7 @@ impl State for BlockMap {
pl.make_arrow(
Distance::meters(15.0) * pct,
ArrowCap::Triangle,
)
.unwrap(),
),
);
}
} else {

View File

@ -239,13 +239,11 @@ impl ParkingMapper {
batch.push(
Color::GREEN,
map.right_shift(r.center_pts.clone(), r.get_half_width(map))
.unwrap()
.make_polygons(thickness),
);
batch.push(
Color::BLUE,
map.left_shift(r.center_pts.clone(), r.get_half_width(map))
.unwrap()
.make_polygons(thickness),
);
}

View File

@ -81,8 +81,7 @@ impl State for ClusterTrafficSignalEditor {
app.cs.selected,
g.group
.geom
.make_arrow(BIG_ARROW_THICKNESS, ArrowCap::Triangle)
.unwrap(),
.make_arrow(BIG_ARROW_THICKNESS, ArrowCap::Triangle),
);
} else {
batch.push(app.cs.signal_turn_block_bg, g.block.clone());

View File

@ -488,7 +488,6 @@ pub fn apply_map_edits(ctx: &mut EventCtx, app: &mut App, edits: MapEdits) {
&app.primary.map,
&app.cs,
ctx.prerender,
&mut timer,
);
}

View File

@ -318,15 +318,13 @@ impl State for TrafficSignalEditor {
green.alpha(0.5),
signal.turn_groups[&g.id]
.geom
.make_arrow(BIG_ARROW_THICKNESS, ArrowCap::Triangle)
.unwrap(),
.make_arrow(BIG_ARROW_THICKNESS, ArrowCap::Triangle),
);
batch.extend(
green,
signal.turn_groups[&g.id]
.geom
.make_arrow_outline(BIG_ARROW_THICKNESS, Distance::meters(0.1))
.unwrap(),
.make_arrow_outline(BIG_ARROW_THICKNESS, Distance::meters(0.1)),
);
green
}
@ -366,15 +364,13 @@ impl State for TrafficSignalEditor {
red.alpha(0.5),
signal.turn_groups[&g.id]
.geom
.make_arrow(BIG_ARROW_THICKNESS, ArrowCap::Triangle)
.unwrap(),
.make_arrow(BIG_ARROW_THICKNESS, ArrowCap::Triangle),
);
batch.extend(
red,
signal.turn_groups[&g.id]
.geom
.make_arrow_outline(BIG_ARROW_THICKNESS, Distance::meters(0.1))
.unwrap(),
.make_arrow_outline(BIG_ARROW_THICKNESS, Distance::meters(0.1)),
);
red
}

View File

@ -153,8 +153,7 @@ pub fn current_demand(
let percent = (demand as f64) / (total_demand as f64);
batch.push(
Color::hex("#A3A3A3"),
pl.make_arrow(percent * Distance::meters(3.0), ArrowCap::Triangle)
.unwrap(),
pl.make_arrow(percent * Distance::meters(3.0), ArrowCap::Triangle),
);
txt_batch.append(
Text::from(Line(prettyprint_usize(demand)).fg(Color::RED))

View File

@ -349,9 +349,7 @@ fn make_timeline(
if let Ok(pl) =
PolyLine::new(vec![Pt2D::from_gps(loc.gps, map.get_gps_bounds()), center])
{
let arrow = pl
.make_arrow(Distance::meters(5.0), ArrowCap::Triangle)
.unwrap();
let arrow = pl.make_arrow(Distance::meters(5.0), ArrowCap::Triangle);
details.unzoomed.push(Color::GREEN, arrow.clone());
details.zoomed.push(Color::GREEN, arrow.clone());
}
@ -396,9 +394,7 @@ fn make_timeline(
if let Ok(pl) =
PolyLine::new(vec![center, Pt2D::from_gps(loc.gps, map.get_gps_bounds())])
{
let arrow = pl
.make_arrow(Distance::meters(5.0), ArrowCap::Triangle)
.unwrap();
let arrow = pl.make_arrow(Distance::meters(5.0), ArrowCap::Triangle);
details.unzoomed.push(Color::GREEN, arrow.clone());
details.zoomed.push(Color::GREEN, arrow.clone());
}

View File

@ -84,8 +84,7 @@ impl Elevation {
pt.project_away(arrow_len / 2.0, angle.opposite()),
pt.project_away(arrow_len / 2.0, angle),
])
.make_arrow(thickness, ArrowCap::Triangle)
.unwrap(),
.make_arrow(thickness, ArrowCap::Triangle),
);
dist += btwn;
}

View File

@ -90,8 +90,7 @@ impl DrawBike {
body_pos.project_away(body_radius / 2.0, angle.opposite()),
body_pos.project_away(body_radius / 2.0, angle),
])
.make_arrow(Distance::meters(0.15), ArrowCap::Triangle)
.unwrap(),
.make_arrow(Distance::meters(0.15), ArrowCap::Triangle),
);
}

View File

@ -24,8 +24,8 @@ impl DrawCar {
// Wheels
for side in vec![
input.body.shift_right(CAR_WIDTH / 2.0).unwrap(),
input.body.shift_left(CAR_WIDTH / 2.0).unwrap(),
input.body.shift_right(CAR_WIDTH / 2.0),
input.body.shift_left(CAR_WIDTH / 2.0),
] {
let len = side.length();
if len <= Distance::meters(2.0) {
@ -93,8 +93,7 @@ impl DrawCar {
pos.project_away(arrow_len / 2.0, angle.rotate_degs(90.0)),
pos.project_away(arrow_len / 2.0, angle.rotate_degs(-90.0)),
])
.make_arrow(arrow_thickness, ArrowCap::Triangle)
.unwrap(),
.make_arrow(arrow_thickness, ArrowCap::Triangle),
);
}
TurnType::Right => {
@ -109,8 +108,7 @@ impl DrawCar {
pos.project_away(arrow_len / 2.0, angle.rotate_degs(-90.0)),
pos.project_away(arrow_len / 2.0, angle.rotate_degs(90.0)),
])
.make_arrow(arrow_thickness, ArrowCap::Triangle)
.unwrap(),
.make_arrow(arrow_thickness, ArrowCap::Triangle),
);
}
TurnType::Straight | TurnType::LaneChangeLeft | TurnType::LaneChangeRight => {}

View File

@ -5,7 +5,6 @@ use crate::options::TrafficSignalStyle;
use crate::render::{
draw_signal_phase, DrawOptions, Renderable, CROSSWALK_LINE_THICKNESS, OUTLINE_THICKNESS,
};
use abstutil::Timer;
use ezgui::{Color, Drawable, GeomBatch, GfxCtx, Line, Prerender, RewriteColor, Text};
use geom::{Angle, ArrowCap, Distance, Line, PolyLine, Polygon, Pt2D, Time, EPSILON_DIST};
use map_model::{
@ -28,7 +27,6 @@ impl DrawIntersection {
map: &Map,
cs: &ColorScheme,
prerender: &Prerender,
timer: &mut Timer,
) -> DrawIntersection {
// Order matters... main polygon first, then sidewalk corners.
let mut default_geom = GeomBatch::new();
@ -51,10 +49,7 @@ impl DrawIntersection {
match i.intersection_type {
IntersectionType::Border => {
let r = map.get_r(*i.roads.iter().next().unwrap());
default_geom.extend(
cs.road_center_line,
calculate_border_arrows(i, r, map, timer),
);
default_geom.extend(cs.road_center_line, calculate_border_arrows(i, r, map));
}
IntersectionType::StopSign => {
for ss in map.get_stop_sign(i.id).roads.values() {
@ -201,15 +196,11 @@ pub fn calculate_corners(i: &Intersection, map: &Map) -> Vec<Polygon> {
let l1 = map.get_l(turn.id.src);
let l2 = map.get_l(turn.id.dst);
let mut pts = map
.left_shift(turn.geom.clone(), width / 2.0)
.unwrap()
.into_points();
let mut pts = map.left_shift(turn.geom.clone(), width / 2.0).into_points();
pts.push(map.left_shift_line(l2.first_line(), width / 2.0).pt1());
pts.push(map.right_shift_line(l2.first_line(), width / 2.0).pt1());
pts.extend(
map.right_shift(turn.geom.clone(), width / 2.0)
.unwrap()
.reversed()
.into_points(),
);
@ -223,12 +214,7 @@ pub fn calculate_corners(i: &Intersection, map: &Map) -> Vec<Polygon> {
corners
}
fn calculate_border_arrows(
i: &Intersection,
r: &Road,
map: &Map,
timer: &mut Timer,
) -> Vec<Polygon> {
fn calculate_border_arrows(i: &Intersection, r: &Road, map: &Map) -> Vec<Polygon> {
let mut result = Vec::new();
let mut width_fwd = Distance::ZERO;
@ -261,8 +247,7 @@ fn calculate_border_arrows(
line.unbounded_dist_along(Distance::meters(-9.5)),
line.unbounded_dist_along(Distance::meters(-0.5)),
])
.make_arrow(width / 3.0, ArrowCap::Triangle)
.with_context(timer, format!("outgoing border arrows for {}", r.id)),
.make_arrow(width / 3.0, ArrowCap::Triangle),
);
}
@ -285,8 +270,7 @@ fn calculate_border_arrows(
line.unbounded_dist_along(Distance::meters(-0.5)),
line.unbounded_dist_along(Distance::meters(-9.5)),
])
.make_arrow(width / 3.0, ArrowCap::Triangle)
.with_context(timer, format!("incoming border arrows for {}", r.id)),
.make_arrow(width / 3.0, ArrowCap::Triangle),
);
}
@ -399,14 +383,12 @@ fn make_rainbow_crosswalk(batch: &mut GeomBatch, turn: &Turn, map: &Map) -> bool
let slice = turn
.geom
.exact_slice(total_width, turn.geom.length() - total_width)
.shift_left(total_width / 2.0 - band_width / 2.0)
.unwrap();
.shift_left(total_width / 2.0 - band_width / 2.0);
for (idx, color) in colors.into_iter().enumerate() {
batch.push(
color,
slice
.shift_right(band_width * (idx as f64))
.unwrap()
.make_polygons(band_width),
);
}

View File

@ -1,7 +1,6 @@
use crate::app::App;
use crate::helpers::ID;
use crate::render::{DrawOptions, Renderable, OUTLINE_THICKNESS};
use abstutil::Timer;
use ezgui::{Drawable, GeomBatch, GfxCtx, RewriteColor};
use geom::{Angle, ArrowCap, Distance, Line, PolyLine, Polygon, Pt2D};
use map_model::{Lane, LaneID, LaneType, Map, Road, TurnType, PARKING_SPOT_LENGTH};
@ -35,7 +34,6 @@ impl DrawLane {
let road = map.get_r(lane.parent);
let mut draw = GeomBatch::new();
let mut timer = Timer::throwaway();
if !lane.is_light_rail() {
draw.push(
match lane.lane_type {
@ -64,11 +62,11 @@ impl DrawLane {
LaneType::Driving | LaneType::Bus => {
draw.extend(
app.cs.general_road_marking,
calculate_driving_lines(map, lane, road, &mut timer),
calculate_driving_lines(map, lane, road),
);
draw.extend(
app.cs.general_road_marking,
calculate_turn_markings(map, lane, &mut timer),
calculate_turn_markings(map, lane),
);
draw.extend(
app.cs.general_road_marking,
@ -81,14 +79,12 @@ impl DrawLane {
app.cs.road_center_line,
lane.lane_center_pts
.shift_right(lane.width / 2.0)
.get(&mut timer)
.make_polygons(Distance::meters(0.25)),
);
draw.push(
app.cs.road_center_line,
lane.lane_center_pts
.shift_left(lane.width / 2.0)
.get(&mut timer)
.make_polygons(Distance::meters(0.25)),
);
}
@ -99,14 +95,12 @@ impl DrawLane {
app.cs.light_rail_track,
lane.lane_center_pts
.shift_right((lane.width - track_width) / 2.5)
.get(&mut timer)
.make_polygons(track_width),
);
draw.push(
app.cs.light_rail_track,
lane.lane_center_pts
.shift_left((lane.width - track_width) / 2.5)
.get(&mut timer)
.make_polygons(track_width),
);
@ -269,20 +263,13 @@ fn calculate_parking_lines(map: &Map, lane: &Lane) -> Vec<Polygon> {
result
}
fn calculate_driving_lines(
map: &Map,
lane: &Lane,
parent: &Road,
timer: &mut Timer,
) -> Vec<Polygon> {
fn calculate_driving_lines(map: &Map, lane: &Lane, parent: &Road) -> Vec<Polygon> {
// The leftmost lanes don't have dashed lines.
let (dir, idx) = parent.dir_and_offset(lane.id);
if idx == 0 || (dir && parent.children_forwards[idx - 1].1 == LaneType::SharedLeftTurn) {
return Vec::new();
}
let lane_edge_pts = map
.left_shift(lane.lane_center_pts.clone(), lane.width / 2.0)
.get(timer);
let lane_edge_pts = map.left_shift(lane.lane_center_pts.clone(), lane.width / 2.0);
lane_edge_pts.dashed_lines(
Distance::meters(0.25),
Distance::meters(1.0),
@ -290,7 +277,7 @@ fn calculate_driving_lines(
)
}
fn calculate_turn_markings(map: &Map, lane: &Lane, timer: &mut Timer) -> Vec<Polygon> {
fn calculate_turn_markings(map: &Map, lane: &Lane) -> Vec<Polygon> {
let mut results = Vec::new();
// Are there multiple driving lanes on this side of the road?
@ -325,8 +312,7 @@ fn calculate_turn_markings(map: &Map, lane: &Lane, timer: &mut Timer) -> Vec<Pol
.last_pt()
.project_away(lane.width / 2.0, turn.angle()),
])
.make_arrow(thickness, ArrowCap::Triangle)
.with_context(timer, format!("turn_markings for {}", turn.id)),
.make_arrow(thickness, ArrowCap::Triangle),
);
}
@ -361,8 +347,7 @@ fn calculate_one_way_markings(lane: &Lane, parent: &Road) -> Vec<Polygon> {
pt.project_away(arrow_len / 2.0, angle.opposite()),
pt.project_away(arrow_len / 2.0, angle),
])
.make_arrow(thickness, ArrowCap::Triangle)
.unwrap(),
.make_arrow(thickness, ArrowCap::Triangle),
);
dist += btwn;
}

View File

@ -90,7 +90,7 @@ impl DrawMap {
timer.start_iter("make DrawIntersections", map.all_intersections().len());
for i in map.all_intersections() {
timer.next();
intersections.push(DrawIntersection::new(i, map, cs, ctx.prerender, timer));
intersections.push(DrawIntersection::new(i, map, cs, ctx.prerender));
}
timer.start("generate unzoomed intersections");

View File

@ -38,8 +38,7 @@ impl DrawPedestrian {
input.pos.project_away(radius / 2.0, angle.opposite()),
input.pos.project_away(radius / 2.0, angle),
])
.make_arrow(Distance::meters(0.15), ArrowCap::Triangle)
.unwrap(),
.make_arrow(Distance::meters(0.15), ArrowCap::Triangle),
);
}
@ -207,9 +206,9 @@ impl DrawPedCrowd {
PedCrowdLocation::Sidewalk(on, contraflow) => {
let pl_slice = on.exact_slice(input.low, input.high, map);
if contraflow {
map.left_shift(pl_slice, SIDEWALK_THICKNESS / 4.0).unwrap()
map.left_shift(pl_slice, SIDEWALK_THICKNESS / 4.0)
} else {
map.right_shift(pl_slice, SIDEWALK_THICKNESS / 4.0).unwrap()
map.right_shift(pl_slice, SIDEWALK_THICKNESS / 4.0)
}
}
PedCrowdLocation::BldgFrontPath(b) => map

View File

@ -66,8 +66,7 @@ pub fn draw_signal_phase(
app.cs.signal_protected_turn.alpha(percent)
},
pl.exact_slice(slice_start, pl.length() - slice_end)
.make_arrow(BIG_ARROW_THICKNESS, ArrowCap::Triangle)
.unwrap(),
.make_arrow(BIG_ARROW_THICKNESS, ArrowCap::Triangle),
);
} else {
let (center, angle) = crosswalk_icon(&signal.turn_groups[g].geom);
@ -132,15 +131,13 @@ pub fn draw_signal_phase(
app.cs.signal_permitted_turn.alpha(0.3),
signal.turn_groups[g]
.geom
.make_arrow(BIG_ARROW_THICKNESS * 2.0, ArrowCap::Triangle)
.unwrap(),
.make_arrow(BIG_ARROW_THICKNESS * 2.0, ArrowCap::Triangle),
);
batch.extend(
app.cs.signal_permitted_turn,
signal.turn_groups[g]
.geom
.make_arrow_outline(BIG_ARROW_THICKNESS * 2.0, BIG_ARROW_THICKNESS / 2.0)
.unwrap(),
.make_arrow_outline(BIG_ARROW_THICKNESS * 2.0, BIG_ARROW_THICKNESS / 2.0),
);
}
let mut dont_walk = BTreeSet::new();
@ -155,8 +152,7 @@ pub fn draw_signal_phase(
app.cs.signal_protected_turn,
signal.turn_groups[g]
.geom
.make_arrow(BIG_ARROW_THICKNESS * 2.0, ArrowCap::Triangle)
.unwrap(),
.make_arrow(BIG_ARROW_THICKNESS * 2.0, ArrowCap::Triangle),
);
} else {
let (center, angle) = crosswalk_icon(&signal.turn_groups[g].geom);
@ -186,15 +182,13 @@ pub fn draw_signal_phase(
app.cs.signal_permitted_turn.alpha(0.3),
signal.turn_groups[g]
.geom
.make_arrow(BIG_ARROW_THICKNESS * 2.0, ArrowCap::Triangle)
.unwrap(),
.make_arrow(BIG_ARROW_THICKNESS * 2.0, ArrowCap::Triangle),
);
batch.extend(
app.cs.signal_permitted_turn,
signal.turn_groups[g]
.geom
.make_arrow_outline(BIG_ARROW_THICKNESS * 2.0, BIG_ARROW_THICKNESS / 2.0)
.unwrap(),
.make_arrow_outline(BIG_ARROW_THICKNESS * 2.0, BIG_ARROW_THICKNESS / 2.0),
);
}
for g in &phase.protected_groups {
@ -210,8 +204,7 @@ pub fn draw_signal_phase(
app.cs.signal_protected_turn,
signal.turn_groups[g]
.geom
.make_arrow(BIG_ARROW_THICKNESS * 2.0, ArrowCap::Triangle)
.unwrap(),
.make_arrow(BIG_ARROW_THICKNESS * 2.0, ArrowCap::Triangle),
);
}
}
@ -237,19 +230,16 @@ pub fn draw_signal_phase(
batch.push(
app.cs.signal_protected_turn,
turn.geom
.make_arrow(BIG_ARROW_THICKNESS * 2.0, ArrowCap::Triangle)
.unwrap(),
.make_arrow(BIG_ARROW_THICKNESS * 2.0, ArrowCap::Triangle),
);
}
TurnPriority::Yield => {
batch.extend(
app.cs.signal_permitted_turn,
turn.geom
.make_arrow_outline(
BIG_ARROW_THICKNESS * 2.0,
BIG_ARROW_THICKNESS / 2.0,
)
.unwrap(),
turn.geom.make_arrow_outline(
BIG_ARROW_THICKNESS * 2.0,
BIG_ARROW_THICKNESS / 2.0,
),
);
}
TurnPriority::Banned => {}

View File

@ -99,7 +99,6 @@ fn make_geom(offset: f64, pl: PolyLine, width: Distance, angle: Angle) -> (Polyg
center.project_away(TURN_ICON_ARROW_LENGTH / 2.0, angle),
])
.make_arrow(Distance::meters(0.5), ArrowCap::Triangle)
.unwrap()
};
(block, arrow)

View File

@ -370,8 +370,7 @@ impl GameplayState for Tutorial {
]) {
g.draw_polygon(
Color::RED,
&pl.make_arrow(Distance::meters(20.0), ArrowCap::Triangle)
.unwrap(),
&pl.make_arrow(Distance::meters(20.0), ArrowCap::Triangle),
);
}
g.unfork();

View File

@ -203,8 +203,7 @@ impl State for TurnExplorer {
color_turn_type(turn.turn_type).alpha(0.5),
&turn
.geom
.make_arrow(BIG_ARROW_THICKNESS, ArrowCap::Triangle)
.unwrap(),
.make_arrow(BIG_ARROW_THICKNESS, ArrowCap::Triangle),
);
}
} else {
@ -228,8 +227,7 @@ impl State for TurnExplorer {
CURRENT_TURN,
current
.geom
.make_arrow(BIG_ARROW_THICKNESS, ArrowCap::Triangle)
.unwrap(),
.make_arrow(BIG_ARROW_THICKNESS, ArrowCap::Triangle),
);
batch.draw(g);
}

View File

@ -160,8 +160,7 @@ impl UberTurnViewer {
Color::RED,
ic.uber_turns[idx]
.geom(&app.primary.map)
.make_arrow(BIG_ARROW_THICKNESS, ArrowCap::Triangle)
.unwrap(),
.make_arrow(BIG_ARROW_THICKNESS, ArrowCap::Triangle),
);
}

View File

@ -1,7 +1,6 @@
use crate::{
Angle, Bounds, Distance, HashablePt2D, InfiniteLine, Line, Polygon, Pt2D, Ring, EPSILON_DIST,
};
use abstutil::Warn;
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
use std::error::Error;
@ -24,40 +23,6 @@ pub struct PolyLine {
}
impl PolyLine {
fn old_new(pts: Vec<Pt2D>) -> PolyLine {
assert!(pts.len() >= 2);
let length = pts.windows(2).fold(Distance::ZERO, |so_far, pair| {
so_far + pair[0].dist_to(pair[1])
});
// This checks no lines are too small. Could take the other approach and automatically
// squish down points here and make sure the final result is at least EPSILON_DIST.
// But probably better for the callers to do this -- they have better understanding of what
// needs to be squished down, why, and how.
if pts.windows(2).any(|pair| pair[0] == pair[1]) {
panic!(
"PL with total length {} and {} pts has ~dupe adjacent pts: {:?}",
length,
pts.len(),
pts
);
}
let result = PolyLine { pts, length };
// Can't have duplicates! If the polyline ever crosses back on itself, all sorts of things
// are broken.
let (_, dupes) = to_set(result.points());
if !dupes.is_empty() {
panic!(
"PolyLine has non-adjacent repeat points: {}\nRepeated points: {:?}",
result, dupes
);
}
result
}
pub fn new(pts: Vec<Pt2D>) -> Result<PolyLine, Box<dyn Error>> {
if pts.len() < 2 {
return Err(format!("Need at least two points for a PolyLine").into());
@ -370,7 +335,6 @@ impl PolyLine {
pub fn middle(&self) -> Pt2D {
// If this fails, must be some super tiny line. Just return the first point in that case.
// TODO Use Warn<Pt2D>
match self.dist_along(self.length() / 2.0) {
Ok((pt, _)) => pt,
Err(err) => {
@ -397,29 +361,31 @@ impl PolyLine {
Line::must_new(self.pts[self.pts.len() - 2], self.pts[self.pts.len() - 1])
}
///////////////////////// TODO Keep cleaning up below
pub fn shift_right(&self, width: Distance) -> Warn<PolyLine> {
pub fn shift_right(&self, width: Distance) -> PolyLine {
self.shift_with_corrections(width)
}
pub fn shift_left(&self, width: Distance) -> Warn<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: Distance) -> Warn<PolyLine> {
let mut raw = self.shift_with_sharp_angles(width, MITER_THRESHOLD);
raw.dedup();
let result = PolyLine::old_new(raw);
let fixed = if result.pts.len() == self.pts.len() {
fix_angles(self, result)
// - the number of points may not match
fn shift_with_corrections(&self, width: Distance) -> PolyLine {
let raw = self.shift_with_sharp_angles(width, MITER_THRESHOLD);
let result = match PolyLine::deduping_new(raw) {
Ok(pl) => pl,
Err(err) => panic!("shifting by {} broke {}: {}", width, self, err),
};
if result.pts.len() == self.pts.len() {
match fix_angles(self, result) {
Ok(pl) => pl,
Err(err) => panic!("shifting by {} broke {}: {}", width, self, err),
}
} else {
result
};
check_angles(self, fixed)
}
}
fn shift_with_sharp_angles(&self, width: Distance, miter_threshold: f64) -> Vec<Pt2D> {
@ -543,15 +509,13 @@ impl PolyLine {
.exact_dashed_polygons(width, dash_len, dash_separation)
}
pub fn make_arrow(&self, thickness: Distance, cap: ArrowCap) -> Warn<Polygon> {
pub fn make_arrow(&self, thickness: Distance, cap: ArrowCap) -> Polygon {
let head_size = thickness * 2.0;
let triangle_height = head_size / 2.0_f64.sqrt();
if self.length() < triangle_height + EPSILON_DIST {
return Warn::warn(
self.make_polygons(thickness),
format!("Can't make_arrow of thickness {} for {}", thickness, self),
);
// Just give up and make the thick line.
return self.make_polygons(thickness);
}
let slice = self.exact_slice(Distance::ZERO, self.length() - triangle_height);
let angle = slice.last_pt().angle_to(self.last_pt());
@ -563,16 +527,14 @@ impl PolyLine {
.project_away(head_size, angle.rotate_degs(135.0));
match cap {
ArrowCap::Triangle => {
Warn::ok(slice.make_polygons(thickness).union(Polygon::new(&vec![
self.last_pt(),
corner1,
corner2,
])))
}
ArrowCap::Lines => Warn::ok(self.make_polygons(thickness).union(
PolyLine::old_new(vec![corner1, self.last_pt(), corner2]).make_polygons(thickness),
)),
ArrowCap::Triangle => slice.make_polygons(thickness).union(Polygon::new(&vec![
self.last_pt(),
corner1,
corner2,
])),
ArrowCap::Lines => self.make_polygons(thickness).union(
PolyLine::must_new(vec![corner1, self.last_pt(), corner2]).make_polygons(thickness),
),
}
}
@ -581,24 +543,18 @@ impl PolyLine {
&self,
arrow_thickness: Distance,
outline_thickness: Distance,
) -> Warn<Vec<Polygon>> {
) -> Vec<Polygon> {
let head_size = arrow_thickness * 2.0;
let triangle_height = head_size / 2.0_f64.sqrt();
if self.length() < triangle_height {
return Warn::warn(
vec![self.make_polygons(arrow_thickness)],
format!(
"Can't make_arrow of thickness {} for {}",
arrow_thickness, self
),
);
return vec![self.make_polygons(arrow_thickness)];
}
let slice = self.exact_slice(Distance::ZERO, self.length() - triangle_height);
if let Some(p) = slice.to_thick_boundary(arrow_thickness, outline_thickness) {
let angle = slice.last_pt().angle_to(self.last_pt());
Warn::ok(vec![
vec![
p,
Ring::new(vec![
self.last_pt(),
@ -609,15 +565,9 @@ impl PolyLine {
self.last_pt(),
])
.make_polygons(outline_thickness),
])
]
} else {
Warn::warn(
vec![self.make_polygons(arrow_thickness)],
format!(
"Can't make_arrow_outline of outline_thickness {} for {}",
outline_thickness, self
),
)
vec![self.make_polygons(arrow_thickness)]
}
}
@ -641,7 +591,7 @@ impl PolyLine {
last_line.pt2(),
)
};
polygons.push(arrow_line.to_polyline().make_arrow(width, cap).unwrap());
polygons.push(arrow_line.to_polyline().make_arrow(width, cap));
polygons
}
@ -698,7 +648,7 @@ impl PolyLine {
if pts.len() == 1 {
return None;
}
Some(PolyLine::old_new(pts))
Some(PolyLine::must_new(pts))
} else {
panic!("Can't get_slice_ending_at: {} doesn't contain {}", self, pt);
}
@ -716,7 +666,7 @@ impl PolyLine {
if pt != pts[0] {
pts.insert(0, pt);
}
Some(PolyLine::old_new(pts))
Some(PolyLine::must_new(pts))
} else {
panic!(
"Can't get_slice_starting_at: {} doesn't contain {}",
@ -754,7 +704,7 @@ impl PolyLine {
impl fmt::Display for PolyLine {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "PolyLine::new(vec![")?;
writeln!(f, "PolyLine::new(vec![ // length {}", self.length)?;
for (idx, pt) in self.pts.iter().enumerate() {
write!(f, " Pt2D::new({}, {}),", pt.x(), pt.y())?;
if idx > 0 {
@ -774,7 +724,7 @@ impl fmt::Display for PolyLine {
}
}
fn fix_angles(orig: &PolyLine, result: PolyLine) -> PolyLine {
fn fix_angles(orig: &PolyLine, result: PolyLine) -> Result<PolyLine, Box<dyn Error>> {
let mut pts = result.pts.clone();
// Check that the angles roughly match up between the original and shifted line
@ -796,23 +746,7 @@ fn fix_angles(orig: &PolyLine, result: PolyLine) -> PolyLine {
}
// When we swap points, length of the entire PolyLine may change! Recalculating is vital.
PolyLine::old_new(pts)
}
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) {
warnings.push(format!(
"Points changed angles from {} to {} during polyline shifting",
orig_angle, shifted_angle
));
}
}
Warn::warnings(fixed, warnings)
PolyLine::new(pts)
}
// Also returns the duplicates.

View File

@ -516,7 +516,6 @@ impl Model {
.config
.driving_side
.right_shift(center_pts.clone(), offset + width / 2.0)
.unwrap()
.make_polygons(width),
);
offset += width;
@ -540,7 +539,6 @@ impl Model {
.config
.driving_side
.right_shift(center_pts.reversed(), offset + width / 2.0)
.unwrap()
.make_polygons(width),
);
offset += width;
@ -563,7 +561,6 @@ impl Model {
}
PolyLine::must_new(vec![self.get_r_center(id), self.get_r_center(*to)])
.make_arrow(NORMAL_LANE_THICKNESS, ArrowCap::Triangle)
.unwrap()
};
result.push(Object::new(

View File

@ -40,12 +40,8 @@ pub fn intersection_polygon(
};
road_endpts.push(pl.last_pt());
let pl_normal = driving_side
.right_shift(pl.clone(), r.half_width)
.with_context(timer, format!("pl_normal {}", r.id));
let pl_reverse = driving_side
.left_shift(pl.clone(), r.half_width)
.with_context(timer, format!("pl_reverse {}", r.id));
let pl_normal = driving_side.right_shift(pl.clone(), r.half_width);
let pl_reverse = driving_side.left_shift(pl.clone(), r.half_width);
(*id, pl.last_line(), pl_normal, pl_reverse)
})
.collect();
@ -262,26 +258,22 @@ fn generalized_trim_back(
endpoints.push(
driving_side
.right_shift(r.trimmed_center_pts.clone(), r.half_width)
.with_context(timer, format!("main polygon endpoints from {}", r.id))
.last_pt(),
);
endpoints.push(
driving_side
.left_shift(r.trimmed_center_pts.clone(), r.half_width)
.with_context(timer, format!("main polygon endpoints from {}", r.id))
.last_pt(),
);
} else {
endpoints.push(
driving_side
.left_shift(r.trimmed_center_pts.clone(), r.half_width)
.with_context(timer, format!("main polygon endpoints from {}", r.id))
.first_pt(),
);
endpoints.push(
driving_side
.right_shift(r.trimmed_center_pts.clone(), r.half_width)
.with_context(timer, format!("main polygon endpoints from {}", r.id))
.first_pt(),
);
}
@ -388,26 +380,22 @@ fn deadend(
endpts.push(
driving_side
.right_shift(r.trimmed_center_pts.clone(), r.half_width)
.with_context(timer, format!("main polygon endpoints from {}", r.id))
.last_pt(),
);
endpts.push(
driving_side
.left_shift(r.trimmed_center_pts.clone(), r.half_width)
.with_context(timer, format!("main polygon endpoints from {}", r.id))
.last_pt(),
);
} else {
endpts.push(
driving_side
.left_shift(r.trimmed_center_pts.clone(), r.half_width)
.with_context(timer, format!("main polygon endpoints from {}", r.id))
.first_pt(),
);
endpts.push(
driving_side
.right_shift(r.trimmed_center_pts.clone(), r.half_width)
.with_context(timer, format!("main polygon endpoints from {}", r.id))
.first_pt(),
);
}

View File

@ -46,13 +46,11 @@ impl Road {
// If there's a sidewalk on only one side, adjust the true center of the road.
let mut trimmed_center_pts = PolyLine::must_new(r.center_points.clone());
if sidewalk_right && !sidewalk_left {
trimmed_center_pts = driving_side
.right_shift(trimmed_center_pts, SIDEWALK_THICKNESS / 2.0)
.unwrap();
trimmed_center_pts =
driving_side.right_shift(trimmed_center_pts, SIDEWALK_THICKNESS / 2.0);
} else if sidewalk_left && !sidewalk_right {
trimmed_center_pts = driving_side
.left_shift(trimmed_center_pts, SIDEWALK_THICKNESS / 2.0)
.unwrap();
trimmed_center_pts =
driving_side.left_shift(trimmed_center_pts, SIDEWALK_THICKNESS / 2.0);
}
Road {

View File

@ -149,9 +149,7 @@ impl Map {
}
// TODO Maybe easier to use the road's "yellow center line" and shift left/right from
// there.
let road_left_pts = map
.left_shift(road.center_pts.clone(), r.half_width)
.with_context(timer, format!("shift for {}", road.id));
let road_left_pts = map.left_shift(road.center_pts.clone(), r.half_width);
let mut fwd_width_so_far = Distance::ZERO;
let mut back_width_so_far = Distance::ZERO;
@ -173,15 +171,14 @@ impl Map {
total_back_width + fwd_width_so_far + (lane.width() / 2.0),
);
fwd_width_so_far += lane.width();
pl.with_context(timer, format!("shift for {}", id))
pl
} else {
let pl = map.right_shift(
road_left_pts.clone(),
total_back_width - back_width_so_far - (lane.width() / 2.0),
);
back_width_so_far += lane.width();
pl.with_context(timer, format!("shift for {}", id))
.reversed()
pl.reversed()
};
map.lanes.push(Lane {

View File

@ -2,7 +2,7 @@ use crate::raw::{DrivingSide, RestrictionType};
use crate::{
Intersection, IntersectionID, Lane, LaneID, LaneType, Road, RoadID, Turn, TurnID, TurnType,
};
use abstutil::{wraparound_get, Timer, Warn};
use abstutil::{wraparound_get, Timer};
use geom::{Distance, Line, PolyLine, Pt2D, Ring};
use nbez::{Bez3o, BezCurve, Point2d};
use std::collections::{BTreeSet, HashMap, HashSet};
@ -19,7 +19,7 @@ pub fn make_all_turns(
assert!(!i.is_border());
let mut raw_turns: Vec<Turn> = Vec::new();
raw_turns.extend(make_vehicle_turns(i, roads, lanes, timer));
raw_turns.extend(make_vehicle_turns(i, roads, lanes));
raw_turns.extend(make_walking_turns(driving_side, i, roads, lanes, timer));
let unique_turns = ensure_unique(raw_turns);
@ -104,7 +104,6 @@ fn make_vehicle_turns(
i: &Intersection,
all_roads: &Vec<Road>,
lanes: &Vec<Lane>,
timer: &mut Timer,
) -> impl Iterator<Item = Turn> {
let sorted_roads: Vec<&Road> = i
.get_roads_sorted_by_incoming_angle(all_roads)
@ -127,8 +126,9 @@ fn make_vehicle_turns(
for lane_type in lane_types.into_iter() {
if i.roads.len() == 1 {
result
.extend(make_vehicle_turns_for_dead_end(i, all_roads, lanes, lane_type).get(timer));
result.extend(make_vehicle_turns_for_dead_end(
i, all_roads, lanes, lane_type,
));
continue;
}
@ -266,12 +266,13 @@ fn make_vehicle_turns_for_dead_end(
roads: &Vec<Road>,
lanes: &Vec<Lane>,
lane_type: LaneType,
) -> Warn<Vec<Option<Turn>>> {
) -> Vec<Option<Turn>> {
let road = &roads[i.roads.iter().next().unwrap().0];
let incoming = filter_vehicle_lanes(road.incoming_lanes(i.id), lane_type);
let outgoing = filter_vehicle_lanes(road.outgoing_lanes(i.id), lane_type);
if incoming.is_empty() || outgoing.is_empty() {
return Warn::warn(Vec::new(), format!("{} needs to be a border node!", i.id));
println!("{} needs to be a border node!", i.id);
return Vec::new();
}
let mut result = Vec::new();
@ -290,7 +291,7 @@ fn make_vehicle_turns_for_dead_end(
}
}
Warn::ok(result)
result
}
fn make_walking_turns(
@ -575,10 +576,6 @@ fn make_shared_sidewalk_corner(
pts_between.extend(
driving_side
.right_shift(PolyLine::must_new(deduped), l1.width / 2.0)
.with_context(
timer,
format!("SharedSidewalkCorner between {} and {}", l1.id, l2.id),
)
.points(),
);
}

View File

@ -5,7 +5,7 @@ use crate::{
ParkingLot, ParkingLotID, Path, PathConstraints, PathRequest, Position, Road, RoadID, Turn,
TurnGroupID, TurnID, TurnType,
};
use abstutil::{Timer, Warn};
use abstutil::Timer;
use geom::{Angle, Bounds, Distance, GPSBounds, Line, PolyLine, Polygon, Pt2D};
use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, BTreeSet, HashSet, VecDeque};
@ -628,10 +628,10 @@ impl Map {
None
}
pub fn right_shift(&self, pl: PolyLine, width: Distance) -> Warn<PolyLine> {
pub fn right_shift(&self, pl: PolyLine, width: Distance) -> PolyLine {
self.config.driving_side.right_shift(pl, width)
}
pub fn left_shift(&self, pl: PolyLine, width: Distance) -> Warn<PolyLine> {
pub fn left_shift(&self, pl: PolyLine, width: Distance) -> PolyLine {
self.config.driving_side.left_shift(pl, width)
}
pub fn right_shift_line(&self, line: Line, width: Distance) -> Line {

View File

@ -281,7 +281,6 @@ impl Road {
self.children_backwards[0].0
});
map.left_shift(lane.lane_center_pts.clone(), lane.width / 2.0)
.unwrap()
}
pub fn any_on_other_side(&self, l: LaneID, lt: LaneType) -> Option<LaneID> {

View File

@ -240,7 +240,7 @@ impl TurnGroup {
left += map.get_l(l).width;
}
let pl = map.right_shift(pl, (leftmost + rightmost) / 2.0).unwrap();
let pl = map.right_shift(pl, (leftmost + rightmost) / 2.0);
// Flip direction, so we point away from the intersection
let pl = if self.id.crosswalk
&& map.get_l(self.members[0].src).src_i == self.members[0].parent

View File

@ -319,7 +319,7 @@ impl UberTurnGroup {
left += map.get_l(l).width;
}
let pl = map.right_shift(pl, (leftmost + rightmost) / 2.0).unwrap();
let pl = map.right_shift(pl, (leftmost + rightmost) / 2.0);
// Flip direction, so we point away from the intersection
(pl.reversed(), rightmost - leftmost)
}

View File

@ -1,6 +1,6 @@
use crate::make::initial::lane_specs::get_lane_types;
use crate::{osm, AreaType, IntersectionType, MapConfig, RoadSpec};
use abstutil::{deserialize_btreemap, serialize_btreemap, Timer, Warn};
use abstutil::{deserialize_btreemap, serialize_btreemap, Timer};
use geom::{Angle, Distance, GPSBounds, Line, PolyLine, Polygon, Pt2D};
use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, BTreeSet};
@ -388,14 +388,14 @@ pub enum DrivingSide {
impl DrivingSide {
// "right" and "left" here are in terms of DrivingSide::Right, what I'm used to reasoning about
// in the USA. They invert appropriately for DrivingSide::Left.
pub fn right_shift(self, pl: PolyLine, width: Distance) -> Warn<PolyLine> {
pub fn right_shift(self, pl: PolyLine, width: Distance) -> PolyLine {
match self {
DrivingSide::Right => pl.shift_right(width),
DrivingSide::Left => pl.shift_left(width),
}
}
pub fn left_shift(self, pl: PolyLine, width: Distance) -> Warn<PolyLine> {
pub fn left_shift(self, pl: PolyLine, width: Distance) -> PolyLine {
match self {
DrivingSide::Right => pl.shift_left(width),
DrivingSide::Left => pl.shift_right(width),

View File

@ -134,7 +134,7 @@ impl Car {
} else {
-width
};
raw_body.shift_right(shift).unwrap()
raw_body.shift_right(shift)
}
_ => {
let driveway = match spot {