the first real big change: Line::new always returns Option

This commit is contained in:
Dustin Carlino 2020-07-11 12:37:38 -07:00
parent 0dd3199f7a
commit 98c6f46c78
21 changed files with 134 additions and 120 deletions

View File

@ -112,7 +112,7 @@ pub struct LinearGradient {
impl LinearGradient {
pub(crate) fn new(lg: &usvg::LinearGradient) -> FancyColor {
let line = Line::new(Pt2D::new(lg.x1, lg.y1), Pt2D::new(lg.x2, lg.y2));
let line = Line::must_new(Pt2D::new(lg.x1, lg.y1), Pt2D::new(lg.x2, lg.y2));
let mut stops = Vec::new();
for stop in &lg.stops {
let color = Color::rgba(

View File

@ -13,7 +13,7 @@ impl Warper {
let z = ctx.canvas.cam_zoom;
Warper {
started: Instant::now(),
line: Line::maybe_new(ctx.canvas.center_to_map_pt(), pt),
line: Line::new(ctx.canvas.center_to_map_pt(), pt),
cam_zoom: (z, target_cam_zoom.unwrap_or(z)),
}
}

View File

@ -51,18 +51,24 @@ impl CompareTimes {
// Horizontal
batch.push(
Color::grey(0.5),
geom::Line::new(Pt2D::new(0.0, y), Pt2D::new(width, y)).make_polygons(thickness),
geom::Line::new(Pt2D::new(0.0, y), Pt2D::new(width, y))
.unwrap()
.make_polygons(thickness),
);
// Vertical
batch.push(
Color::grey(0.5),
geom::Line::new(Pt2D::new(x, 0.0), Pt2D::new(x, height)).make_polygons(thickness),
geom::Line::new(Pt2D::new(x, 0.0), Pt2D::new(x, height))
.unwrap()
.make_polygons(thickness),
);
}
// Draw the diagonal, since we're comparing things on the same scale
batch.push(
Color::grey(0.5),
geom::Line::new(Pt2D::new(0.0, height), Pt2D::new(width, 0.0)).make_polygons(thickness),
geom::Line::new(Pt2D::new(0.0, height), Pt2D::new(width, 0.0))
.unwrap()
.make_polygons(thickness),
);
let circle = Circle::new(Pt2D::new(0.0, 0.0), Distance::meters(4.0)).to_polygon();
@ -145,13 +151,11 @@ impl WidgetImpl for CompareTimes {
let thickness = Distance::meters(2.0);
let mut batch = GeomBatch::new();
// Horizontal
if let Some(l) = geom::Line::maybe_new(Pt2D::new(rect.x1, cursor.y), cursor.to_pt())
{
if let Some(l) = geom::Line::new(Pt2D::new(rect.x1, cursor.y), cursor.to_pt()) {
batch.push(Color::WHITE, l.make_polygons(thickness));
}
// Vertical
if let Some(l) = geom::Line::maybe_new(Pt2D::new(cursor.x, rect.y2), cursor.to_pt())
{
if let Some(l) = geom::Line::new(Pt2D::new(cursor.x, rect.y2), cursor.to_pt()) {
batch.push(Color::WHITE, l.make_polygons(thickness));
}

View File

@ -120,7 +120,7 @@ impl ColorLegend {
let width_each = width / ((n - 1) as f64);
batch.fancy_push(
FancyColor::LinearGradient(LinearGradient {
line: Line::new(Pt2D::new(0.0, 0.0), Pt2D::new(width, 0.0)),
line: Line::must_new(Pt2D::new(0.0, 0.0), Pt2D::new(width, 0.0)),
stops: scale
.0
.iter()

View File

@ -114,7 +114,7 @@ impl State for PolygonEditor {
g.draw_line(
POINT_COLOR,
POINT_RADIUS / 2.0,
&geom::Line::new(pts[0], pts[1]),
&geom::Line::must_new(pts[0], pts[1]),
);
}
if pts.len() >= 3 {

View File

@ -488,16 +488,19 @@ impl Screensaver {
fn bounce(ctx: &mut EventCtx, app: &mut App, rng: &mut XorShiftRng) -> Screensaver {
let at = ctx.canvas.center_to_map_pt();
let bounds = app.primary.map.get_bounds();
// TODO Ideally bounce off the edge of the map
let goto = Pt2D::new(
rng.gen_range(0.0, bounds.max_x),
rng.gen_range(0.0, bounds.max_y),
);
let line = loop {
let goto = Pt2D::new(
rng.gen_range(0.0, bounds.max_x),
rng.gen_range(0.0, bounds.max_y),
);
if let Some(l) = Line::new(at, goto) {
break l;
}
};
ctx.canvas.cam_zoom = 10.0;
ctx.canvas.center_on_map_pt(at);
Screensaver {
line: Line::new(at, goto),
line,
started: Instant::now(),
}
}

View File

@ -50,6 +50,7 @@ impl DrawBike {
hand_pos.project_away(body_radius, hand_angle.rotate_degs(90.0)),
hand_pos.project_away(body_radius, hand_angle.rotate_degs(-90.0)),
)
.unwrap()
.make_polygons(Distance::meters(0.1)),
);
@ -60,6 +61,7 @@ impl DrawBike {
body_pos.project_away(0.9 * body_radius, facing.rotate_degs(-30.0)),
hand_pos.project_away(0.4 * body_radius, hand_angle.rotate_degs(-90.0)),
)
.unwrap()
.make_polygons(Distance::meters(0.08)),
);
draw_default.push(
@ -68,6 +70,7 @@ impl DrawBike {
body_pos.project_away(0.9 * body_radius, facing.rotate_degs(30.0)),
hand_pos.project_away(0.4 * body_radius, hand_angle.rotate_degs(90.0)),
)
.unwrap()
.make_polygons(Distance::meters(0.08)),
);
}

View File

@ -3,7 +3,7 @@ use crate::colors::ColorScheme;
use crate::helpers::ID;
use crate::render::{DrawOptions, Renderable, OUTLINE_THICKNESS};
use ezgui::{Color, Drawable, GeomBatch, GfxCtx, Line, Prerender, Text};
use geom::{Distance, Line, Polygon, Pt2D};
use geom::{Distance, Polygon, Pt2D};
use map_model::{Building, BuildingID, Map, NORMAL_LANE_THICKNESS, SIDEWALK_THICKNESS};
use std::cell::RefCell;
@ -23,15 +23,13 @@ impl DrawBuilding {
) -> DrawBuilding {
// Trim the front path line away from the sidewalk's center line, so that it doesn't
// 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 = SIDEWALK_THICKNESS / 2.0;
if len > trim_back && len - trim_back > geom::EPSILON_DIST {
front_path_line = Line::new(
front_path_line.pt1(),
front_path_line.dist_along(len - trim_back),
);
}
let orig_line = &bldg.front_path.line;
let front_path_line = orig_line
.slice(
Distance::ZERO,
orig_line.length() - SIDEWALK_THICKNESS / 2.0,
)
.unwrap_or_else(|| orig_line.clone());
if bldg.amenities.is_empty() {
bldg_batch.push(cs.residential_building, bldg.polygon.clone());

View File

@ -49,6 +49,7 @@ impl DrawBusStop {
center.project_away(RADIUS, Angle::new_degs(90.0)),
center.project_away(1.5 * RADIUS, Angle::new_degs(90.0)),
)
.unwrap()
.make_polygons(Distance::meters(0.3)),
);

View File

@ -109,7 +109,7 @@ impl DrawIntersection {
);
let octagon = make_octagon(last_line.pt2(), Distance::meters(1.0), last_line.angle());
let pole = Line::new(
let pole = Line::must_new(
last_line
.pt2()
.project_away(Distance::meters(1.5), last_line.angle().opposite()),
@ -322,7 +322,12 @@ pub fn make_crosswalk(batch: &mut GeomBatch, turn: &Turn, map: &Map, cs: &ColorS
);
return;
}
Line::new(pts[1], pts[2])
match Line::new(pts[1], pts[2]) {
Some(l) => l,
None => {
return;
}
}
};
let available_length = line.length() - (boundary * 2.0);
@ -337,7 +342,7 @@ pub fn make_crosswalk(batch: &mut GeomBatch, turn: &Turn, map: &Map, cs: &ColorS
let pt2 = pt1.project_away(Distance::meters(1.0), turn.angle());
batch.push(
cs.general_road_marking,
perp_line(Line::new(pt1, pt2), width).make_polygons(CROSSWALK_LINE_THICKNESS),
perp_line(Line::must_new(pt1, pt2), width).make_polygons(CROSSWALK_LINE_THICKNESS),
);
// Actually every line is a double
@ -345,7 +350,7 @@ pub fn make_crosswalk(batch: &mut GeomBatch, turn: &Turn, map: &Map, cs: &ColorS
let pt4 = pt3.project_away(Distance::meters(1.0), turn.angle());
batch.push(
cs.general_road_marking,
perp_line(Line::new(pt3, pt4), width).make_polygons(CROSSWALK_LINE_THICKNESS),
perp_line(Line::must_new(pt3, pt4), width).make_polygons(CROSSWALK_LINE_THICKNESS),
);
dist_along += tile_every;
@ -409,5 +414,5 @@ fn make_rainbow_crosswalk(batch: &mut GeomBatch, turn: &Turn, map: &Map) -> bool
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)
Line::must_new(pt1, pt2)
}

View File

@ -119,7 +119,7 @@ impl DrawLane {
let pt2 = pt.project_away(Distance::meters(1.0), angle);
draw.push(
app.cs.light_rail_track,
perp_line(Line::new(pt, pt2), lane.width).make_polygons(track_width),
perp_line(Line::must_new(pt, pt2), lane.width).make_polygons(track_width),
);
dist_along += tile_every;
}
@ -214,7 +214,7 @@ impl Renderable for DrawLane {
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)
Line::must_new(pt1, pt2)
}
fn calculate_sidewalk_lines(lane: &Lane) -> Vec<Polygon> {
@ -229,8 +229,9 @@ fn calculate_sidewalk_lines(lane: &Lane) -> Vec<Polygon> {
let (pt, angle) = lane.dist_along(dist_along);
// Reuse perp_line. Project away an arbitrary amount
let pt2 = pt.project_away(Distance::meters(1.0), angle);
result
.push(perp_line(Line::new(pt, pt2), lane.width).make_polygons(Distance::meters(0.25)));
result.push(
perp_line(Line::must_new(pt, pt2), lane.width).make_polygons(Distance::meters(0.25)),
);
dist_along += tile_every;
}
@ -253,13 +254,13 @@ fn calculate_parking_lines(map: &Map, lane: &Lane) -> Vec<Polygon> {
let t_pt = pt.project_away(lane.width * 0.4, perp_angle);
// The perp leg
let p1 = t_pt.project_away(leg_length, perp_angle.opposite());
result.push(Line::new(t_pt, p1).make_polygons(Distance::meters(0.25)));
result.push(Line::must_new(t_pt, p1).make_polygons(Distance::meters(0.25)));
// Upper leg
let p2 = t_pt.project_away(leg_length, lane_angle);
result.push(Line::new(t_pt, p2).make_polygons(Distance::meters(0.25)));
result.push(Line::must_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(Line::new(t_pt, p3).make_polygons(Distance::meters(0.25)));
result.push(Line::must_new(t_pt, p3).make_polygons(Distance::meters(0.25)));
}
}

View File

@ -3,7 +3,7 @@ use crate::colors::ColorScheme;
use crate::helpers::ID;
use crate::render::{DrawOptions, Renderable, OUTLINE_THICKNESS};
use ezgui::{Drawable, GeomBatch, GfxCtx, Prerender};
use geom::{Distance, Line, PolyLine, Polygon, Pt2D};
use geom::{Distance, PolyLine, Polygon, Pt2D};
use map_model::{
Map, ParkingLot, ParkingLotID, NORMAL_LANE_THICKNESS, PARKING_LOT_SPOT_LENGTH,
SIDEWALK_THICKNESS,
@ -37,15 +37,13 @@ impl DrawParkingLot {
// Trim the front path line away from the sidewalk's center line, so that it doesn't
// overlap. For now, this cleanup is visual; it doesn't belong in the map_model layer.
let mut front_path_line = lot.sidewalk_line.clone();
let len = front_path_line.length();
let trim_back = SIDEWALK_THICKNESS / 2.0;
if len > trim_back && len - trim_back > geom::EPSILON_DIST {
front_path_line = Line::new(
front_path_line.pt1(),
front_path_line.dist_along(len - trim_back),
);
}
let orig_line = &lot.sidewalk_line;
let front_path_line = orig_line
.slice(
Distance::ZERO,
orig_line.length() - SIDEWALK_THICKNESS / 2.0,
)
.unwrap_or_else(|| orig_line.clone());
let mut batch = GeomBatch::new();
// TODO This isn't getting clipped to the parking lot boundary properly, so just stick this

View File

@ -282,7 +282,7 @@ pub fn draw_signal_phase(
// TODO Kind of a hack to know that the second point is a better center.
// Returns (center, angle)
fn crosswalk_icon(geom: &PolyLine) -> (Pt2D, Angle) {
let l = Line::new(geom.points()[1], geom.points()[2]);
let l = Line::must_new(geom.points()[1], geom.points()[2]);
(
l.safe_dist_along(Distance::meters(1.0)).unwrap_or(l.pt1()),
l.angle().shortest_rotation_towards(Angle::new_degs(90.0)),

View File

@ -8,26 +8,21 @@ use std::fmt;
pub struct Line(Pt2D, Pt2D);
impl Line {
pub fn new(pt1: Pt2D, pt2: Pt2D) -> Line {
let len = pt1.dist_to(pt2);
if len < EPSILON_DIST {
panic!("Tiny line with length {}", len);
}
Line(pt1, pt2)
}
pub fn maybe_new(pt1: Pt2D, pt2: Pt2D) -> Option<Line> {
if pt1 == pt2 {
pub fn new(pt1: Pt2D, pt2: Pt2D) -> Option<Line> {
if pt1.dist_to(pt2) < EPSILON_DIST {
return None;
}
Some(Line::new(pt1, pt2))
Some(Line(pt1, pt2))
}
// Just to be more clear at the call-site
pub fn must_new(pt1: Pt2D, pt2: Pt2D) -> Line {
Line::new(pt1, pt2).unwrap()
}
pub fn infinite(&self) -> InfiniteLine {
InfiniteLine(self.0, self.1)
}
// TODO we call these frequently here; unnecessary copies?
pub fn pt1(&self) -> Pt2D {
self.0
}
@ -173,6 +168,13 @@ impl Line {
}
}
pub fn slice(&self, from: Distance, to: Distance) -> Option<Line> {
if from < Distance::ZERO || to < Distance::ZERO || from >= to {
return None;
}
Line::new(self.safe_dist_along(from)?, self.safe_dist_along(to)?)
}
pub fn middle(&self) -> Pt2D {
self.dist_along(self.length() / 2.0)
}

View File

@ -196,7 +196,7 @@ impl PolyLine {
pub fn lines(&self) -> Vec<Line> {
self.pts
.windows(2)
.map(|pair| Line::new(pair[0], pair[1]))
.map(|pair| Line::must_new(pair[0], pair[1]))
.collect()
}
@ -348,10 +348,10 @@ impl PolyLine {
*self.pts.last().unwrap()
}
pub fn first_line(&self) -> Line {
Line::new(self.pts[0], self.pts[1])
Line::must_new(self.pts[0], self.pts[1])
}
pub fn last_line(&self) -> Line {
Line::new(self.pts[self.pts.len() - 2], self.pts[self.pts.len() - 1])
Line::must_new(self.pts[self.pts.len() - 2], self.pts[self.pts.len() - 1])
}
pub fn shift_right(&self, width: Distance) -> Warn<PolyLine> {
@ -379,7 +379,7 @@ impl PolyLine {
fn shift_with_sharp_angles(&self, width: Distance, miter_threshold: f64) -> Vec<Pt2D> {
if self.pts.len() == 2 {
let l = Line::new(self.pts[0], self.pts[1]).shift_either_direction(width);
let l = Line::must_new(self.pts[0], self.pts[1]).shift_either_direction(width);
return vec![l.pt1(), l.pt2()];
}
@ -392,8 +392,8 @@ impl PolyLine {
loop {
let pt3_raw = self.pts[pt3_idx];
let l1 = Line::new(pt1_raw, pt2_raw).shift_either_direction(width);
let l2 = Line::new(pt2_raw, pt3_raw).shift_either_direction(width);
let l1 = Line::must_new(pt1_raw, pt2_raw).shift_either_direction(width);
let l2 = Line::must_new(pt2_raw, pt3_raw).shift_either_direction(width);
if pt3_idx == 2 {
result.push(l1.pt1());
@ -591,7 +591,7 @@ impl PolyLine {
let arrow_line = if last_len <= dash_len {
last_line
} else {
Line::new(last_line.dist_along(last_len - dash_len), last_line.pt2())
Line::must_new(last_line.dist_along(last_len - dash_len), last_line.pt2())
};
polygons.push(arrow_line.to_polyline().make_arrow(width, cap).unwrap());
polygons
@ -710,7 +710,7 @@ impl fmt::Display for PolyLine {
for (idx, pt) in self.pts.iter().enumerate() {
write!(f, " Pt2D::new({}, {}),", pt.x(), pt.y())?;
if idx > 0 {
let line = Line::new(self.pts[idx - 1], *pt);
let line = Line::must_new(self.pts[idx - 1], *pt);
write!(
f,
" // {}, {} (+ {} @ {})",

View File

@ -77,7 +77,11 @@ impl Ring {
let mut hits = Vec::new();
let mut seen = HashSet::new();
for l1 in other.lines() {
for l2 in self.pts.windows(2).map(|pair| Line::new(pair[0], pair[1])) {
for l2 in self
.pts
.windows(2)
.map(|pair| Line::must_new(pair[0], pair[1]))
{
if let Some(pt) = l1.intersection(&l2) {
if !seen.contains(&pt.to_hashable()) {
hits.push(pt);

View File

@ -564,9 +564,7 @@ impl GUI for UI {
match self.state {
State::CreatingRoad(i1) => {
if let Some(cursor) = g.get_cursor_in_map_space() {
if let Some(l) =
Line::maybe_new(self.model.map.intersections[&i1].point, cursor)
{
if let Some(l) = Line::new(self.model.map.intersections[&i1].point, cursor) {
g.draw_line(Color::GREEN, Distance::meters(5.0), &l);
}
}
@ -595,14 +593,14 @@ impl GUI for UI {
}
State::CreatingTurnRestrictionPt1(from) => {
if let Some(cursor) = g.get_cursor_in_map_space() {
if let Some(l) = Line::maybe_new(self.model.get_r_center(from), cursor) {
if let Some(l) = Line::new(self.model.get_r_center(from), cursor) {
g.draw_arrow(Color::PURPLE, NORMAL_LANE_THICKNESS, &l);
}
}
}
State::CreatingTurnRestrictionPt2(from, to, ref wizard) => {
if let Some(l) =
Line::maybe_new(self.model.get_r_center(from), self.model.get_r_center(to))
Line::new(self.model.get_r_center(from), self.model.get_r_center(to))
{
g.draw_arrow(Color::PURPLE, NORMAL_LANE_THICKNESS, &l);
}

View File

@ -44,17 +44,17 @@ pub fn make_all_buildings(
for (orig_id, bldg_center) in center_per_bldg {
timer.next();
if let Some(sidewalk_pos) = sidewalk_pts.get(&bldg_center) {
let sidewalk_pt = sidewalk_pos.pt(map);
if sidewalk_pt == bldg_center.to_pt2d() {
timer.warn(format!(
"Skipping building {} because front path has 0 length",
orig_id
));
continue;
}
let b = &input[&orig_id];
let sidewalk_line =
trim_path(&b.polygon, Line::new(bldg_center.to_pt2d(), sidewalk_pt));
let sidewalk_line = match Line::new(bldg_center.to_pt2d(), sidewalk_pos.pt(map)) {
Some(l) => trim_path(&b.polygon, l),
None => {
timer.warn(format!(
"Skipping building {} because front path has 0 length",
orig_id
));
continue;
}
};
let id = BuildingID(results.len());
let mut bldg = Building {
@ -151,16 +151,16 @@ pub fn make_all_parking_lots(
timer.next();
// TODO Refactor this
if let Some(sidewalk_pos) = sidewalk_pts.get(&lot_center) {
let sidewalk_pt = sidewalk_pos.pt(map);
if sidewalk_pt == lot_center.to_pt2d() {
timer.warn(format!(
"Skipping parking lot {} because driveway has 0 length",
orig.osm_id
));
continue;
}
let sidewalk_line =
trim_path(&orig.polygon, Line::new(lot_center.to_pt2d(), sidewalk_pt));
let sidewalk_line = match Line::new(lot_center.to_pt2d(), sidewalk_pos.pt(map)) {
Some(l) => trim_path(&orig.polygon, l),
None => {
timer.warn(format!(
"Skipping parking lot {} because front path has 0 length",
orig.osm_id
));
continue;
}
};
// Can this lot have a driveway? If it's not next to a driving lane, then no.
let mut driveway: Option<(PolyLine, Position)> = None;
@ -260,9 +260,9 @@ pub fn make_all_parking_lots(
// Adjust the path to start on the building's border, not center
fn trim_path(poly: &Polygon, path: Line) -> Line {
for bldg_line in poly.points().windows(2) {
let l = Line::new(bldg_line[0], bldg_line[1]);
let l = Line::must_new(bldg_line[0], bldg_line[1]);
if let Some(hit) = l.intersection(&path) {
if let Some(l) = Line::maybe_new(hit, path.pt2()) {
if let Some(l) = Line::new(hit, path.pt2()) {
return l;
}
}
@ -296,7 +296,7 @@ fn infer_spots(lot_polygon: &Polygon, aisles: &Vec<Vec<Pt2D>>) -> Vec<(Pt2D, Ang
let (pt, angle) = pl.dist_along(start);
start += NORMAL_LANE_THICKNESS;
let theta = angle.rotate_degs(rotate);
lines.push(Line::new(
lines.push(Line::must_new(
pt.project_away(aisle_thickness / 2.0, theta),
pt.project_away(aisle_thickness / 2.0 + PARKING_LOT_SPOT_LENGTH, theta),
));
@ -307,7 +307,7 @@ fn infer_spots(lot_polygon: &Polygon, aisles: &Vec<Vec<Pt2D>>) -> Vec<(Pt2D, Ang
for pair in lines.windows(2) {
let l1 = &pair[0];
let l2 = &pair[1];
let back = Line::new(l1.pt2(), l2.pt2());
let back = Line::must_new(l1.pt2(), l2.pt2());
if l1.intersection(&l2).is_none()
&& l1.angle().approx_eq(l2.angle(), 5.0)
&& line_valid(lot_polygon, aisles, l1, &finalized_lines)

View File

@ -150,7 +150,7 @@ 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(
let perp = Line::must_new(
hit,
hit.project_away(Distance::meters(1.0), angle.rotate_degs(90.0)),
)
@ -181,9 +181,9 @@ fn generalized_trim_back(
// road.
// TODO Reduce DEGENERATE_INTERSECTION_HALF_LENGTH to play with this.
if false {
let perp = Line::new(pl1.last_pt(), other_pl1.last_pt());
let perp = Line::must_new(pl1.last_pt(), other_pl1.last_pt());
if perp.intersection(&pl2.last_line()).is_some() {
let new_perp = Line::new(
let new_perp = Line::must_new(
pl2.last_pt(),
pl2.last_pt()
.project_away(Distance::meters(1.0), perp.angle()),

View File

@ -372,7 +372,7 @@ fn make_walking_turns(
if let Some(l1) = get_sidewalk(lanes, roads[idx1].incoming_lanes(i.id)) {
// Make the crosswalk to the other side
if let Some(l2) = get_sidewalk(lanes, roads[idx1].outgoing_lanes(i.id)) {
result.extend(make_crosswalks(i.id, l1, l2));
result.extend(make_crosswalks(i.id, l1, l2).into_iter().flatten());
}
// Find the shared corner
@ -401,7 +401,7 @@ fn make_walking_turns(
) {
// Adjacent road is missing a sidewalk on the near side, but has one on the far
// side
result.extend(make_crosswalks(i.id, l1, l2));
result.extend(make_crosswalks(i.id, l1, l2).into_iter().flatten());
} else {
// We may need to add a crosswalk over this intermediate road that has no
// sidewalks at all. There might be a few in the way -- think highway onramps.
@ -411,20 +411,20 @@ fn make_walking_turns(
abstutil::wraparound_get(&roads, (idx1 as isize) + 2 * idx_offset)
.outgoing_lanes(i.id),
) {
result.extend(make_crosswalks(i.id, l1, l2));
result.extend(make_crosswalks(i.id, l1, l2).into_iter().flatten());
} else if let Some(l2) = get_sidewalk(
lanes,
abstutil::wraparound_get(&roads, (idx1 as isize) + 2 * idx_offset)
.incoming_lanes(i.id),
) {
result.extend(make_crosswalks(i.id, l1, l2));
result.extend(make_crosswalks(i.id, l1, l2).into_iter().flatten());
} else if roads.len() > 3 {
if let Some(l2) = get_sidewalk(
lanes,
abstutil::wraparound_get(&roads, (idx1 as isize) + 3 * idx_offset)
.outgoing_lanes(i.id),
) {
result.extend(make_crosswalks(i.id, l1, l2));
result.extend(make_crosswalks(i.id, l1, l2).into_iter().flatten());
}
}
}
@ -434,12 +434,9 @@ fn make_walking_turns(
result
}
fn make_crosswalks(i: IntersectionID, l1: &Lane, l2: &Lane) -> Vec<Turn> {
fn make_crosswalks(i: IntersectionID, l1: &Lane, l2: &Lane) -> Option<Vec<Turn>> {
let l1_pt = l1.endpoint(i);
let l2_pt = l2.endpoint(i);
if l1_pt == l2_pt {
return Vec::new();
}
// TODO Not sure this is always right.
let direction = if (l1.dst_i == i) == (l2.dst_i == i) {
-1.0
@ -448,10 +445,10 @@ fn make_crosswalks(i: IntersectionID, l1: &Lane, l2: &Lane) -> Vec<Turn> {
};
// Jut out a bit into the intersection, cross over, then jut back in. Assumes sidewalks are the
// same width.
let line = Line::new(l1_pt, l2_pt).shift_either_direction(direction * l1.width / 2.0);
let line = Line::new(l1_pt, l2_pt)?.shift_either_direction(direction * l1.width / 2.0);
let geom_fwds = PolyLine::deduping_new(vec![l1_pt, line.pt1(), line.pt2(), l2_pt]);
vec![
Some(vec![
Turn {
id: turn_id(i, l1.id, l2.id),
turn_type: TurnType::Crosswalk,
@ -464,7 +461,7 @@ fn make_crosswalks(i: IntersectionID, l1: &Lane, l2: &Lane) -> Vec<Turn> {
other_crosswalk_ids: vec![turn_id(i, l1.id, l2.id)].into_iter().collect(),
geom: geom_fwds.reversed(),
},
]
])
}
// Only one physical crosswalk for degenerate intersections, right in the middle.
@ -479,8 +476,8 @@ fn make_degenerate_crosswalks(
let l2_in = get_sidewalk(lanes, r2.incoming_lanes(i))?;
let l2_out = get_sidewalk(lanes, r2.outgoing_lanes(i))?;
let pt1 = Line::maybe_new(l1_in.last_pt(), l2_out.first_pt())?.percent_along(0.5);
let pt2 = Line::maybe_new(l1_out.first_pt(), l2_in.last_pt())?.percent_along(0.5);
let pt1 = Line::new(l1_in.last_pt(), l2_out.first_pt())?.percent_along(0.5);
let pt2 = Line::new(l1_out.first_pt(), l2_in.last_pt())?.percent_along(0.5);
if pt1 == pt2 {
return None;

View File

@ -81,7 +81,7 @@ impl WalkingSimState {
),
SidewalkPOI::BikeRack(driving_pos) => PedState::FinishingBiking(
params.start.clone(),
Line::new(driving_pos.pt(map), params.start.sidewalk_pos.pt(map)),
Line::must_new(driving_pos.pt(map), params.start.sidewalk_pos.pt(map)),
TimeInterval::new(now, now + TIME_TO_FINISH_BIKING),
),
_ => ped.crossing_state(params.start.sidewalk_pos.dist_along(), now, map),
@ -198,7 +198,7 @@ impl WalkingSimState {
let pt2 = driving_pos.pt(map);
ped.state = PedState::StartingToBike(
ped.goal.clone(),
Line::new(pt1, pt2),
Line::must_new(pt1, pt2),
TimeInterval::new(now, now + TIME_TO_START_BIKING),
);
scheduler.push(ped.state.get_end_time(), Command::UpdatePed(ped.id));