start the big one: Polyline::new

This commit is contained in:
Dustin Carlino 2020-07-11 13:42:19 -07:00
parent 0593aa52d9
commit cce624edd8
31 changed files with 160 additions and 113 deletions

View File

@ -54,7 +54,7 @@ pub fn clip_map(map: &mut RawMap, timer: &mut Timer) {
// Now trim it.
let mut mut_r = map.roads.remove(&id).unwrap();
let center = PolyLine::new(mut_r.center_points.clone());
let center = PolyLine::must_new(mut_r.center_points.clone());
let border_pt = boundary_ring.all_intersections(&center)[0];
mut_r.center_points = center
.reversed()
@ -111,7 +111,7 @@ pub fn clip_map(map: &mut RawMap, timer: &mut Timer) {
// Now trim it.
let mut mut_r = map.roads.remove(&id).unwrap();
let center = PolyLine::new(mut_r.center_points.clone());
let center = PolyLine::must_new(mut_r.center_points.clone());
let border_pt = boundary_ring.all_intersections(&center.reversed())[0];
mut_r.center_points = center
.get_slice_ending_at(border_pt)

View File

@ -130,7 +130,7 @@ fn use_parking_hints(map: &mut RawMap, path: String, timer: &mut Timer) {
if r.is_light_rail() {
continue;
}
let center = PolyLine::new(r.center_points.clone());
let center = PolyLine::must_new(r.center_points.clone());
closest.add(
(*id, true),
map.config
@ -158,7 +158,7 @@ fn use_parking_hints(map: &mut RawMap, path: String, timer: &mut Timer) {
// middle of the blockface.
// TODO Long blockfaces sometimes cover two roads. Should maybe find ALL matches within
// the threshold distance?
let middle = if let Some(pl) = PolyLine::maybe_new(pts) {
let middle = if let Ok(pl) = PolyLine::new(pts) {
pl.middle()
} else {
// Weird blockface with duplicate points. Shrug.

View File

@ -564,7 +564,7 @@ fn glue_multipolygon(
polygons.push(Polygon::new(&result));
return polygons;
}
if let Some(poly) = glue_to_boundary(PolyLine::new(result.clone()), boundary) {
if let Some(poly) = glue_to_boundary(PolyLine::must_new(result.clone()), boundary) {
polygons.push(poly);
} else {
// Give up and just connect the ends directly.

View File

@ -99,7 +99,7 @@ impl<T: Yvalue<T>> LinePlot<T> {
}
batch.push(
Color::hex("#7C7C7C"),
PolyLine::new(vec![
PolyLine::must_new(vec![
Pt2D::new(0.0, (1.0 - pct) * height),
Pt2D::new(width, (1.0 - pct) * height),
])
@ -118,7 +118,7 @@ impl<T: Yvalue<T>> LinePlot<T> {
}
batch.push(
Color::hex("#7C7C7C"),
PolyLine::new(vec![
PolyLine::must_new(vec![
Pt2D::new(pct * width, 0.0),
Pt2D::new(pct * width, height),
])

View File

@ -71,7 +71,7 @@ impl ScatterPlot {
}
batch.push(
Color::hex("#7C7C7C"),
PolyLine::new(vec![
PolyLine::must_new(vec![
Pt2D::new(0.0, (1.0 - pct) * height),
Pt2D::new(width, (1.0 - pct) * height),
])
@ -90,7 +90,7 @@ impl ScatterPlot {
}
batch.push(
Color::hex("#7C7C7C"),
PolyLine::new(vec![
PolyLine::must_new(vec![
Pt2D::new(pct * width, 0.0),
Pt2D::new(pct * width, height),
])
@ -120,7 +120,7 @@ impl ScatterPlot {
let avg = (sum / (cnt as f64)).to_percent(max_y);
batch.extend(
Color::hex("#F2F2F2"),
PolyLine::new(vec![
PolyLine::must_new(vec![
Pt2D::new(0.0, (1.0 - avg) * height),
Pt2D::new(width, (1.0 - avg) * height),
])

View File

@ -153,16 +153,20 @@ impl State for BlockMap {
for (other, cnt) in others {
let pct = (cnt as f64) / max_cnt;
if arrows {
batch.push(
Color::hex("#A32015").alpha(0.7),
PolyLine::new(if from {
vec![block.shape.center(), other.shape.center()]
} else {
vec![other.shape.center(), block.shape.center()]
})
.make_arrow(Distance::meters(15.0) * pct, ArrowCap::Triangle)
.unwrap(),
);
if let Ok(pl) = PolyLine::new(if from {
vec![block.shape.center(), other.shape.center()]
} else {
vec![other.shape.center(), block.shape.center()]
}) {
batch.push(
Color::hex("#A32015").alpha(0.7),
pl.make_arrow(
Distance::meters(15.0) * pct,
ArrowCap::Triangle,
)
.unwrap(),
);
}
} else {
batch.push(Color::RED.alpha(pct as f32), other.shape.clone());
}

View File

@ -206,7 +206,17 @@ fn make_object(
//Polygon::new(&pts)
Ring::new(pts).make_polygons(THICKNESS)
} else {
PolyLine::new(pts).make_polygons(THICKNESS)
let backup = pts[0];
match PolyLine::new(pts) {
Ok(pl) => pl.make_polygons(THICKNESS),
Err(err) => {
println!(
"Object with attribs {:?} has messed up geometry: {}",
attribs, err
);
Circle::new(backup, RADIUS).to_polygon()
}
}
};
let mut osm_bldg = None;

View File

@ -581,7 +581,7 @@ fn find_divided_highways(app: &App) -> HashSet<RoadID> {
.unwrap();
for (r2, _, _) in closest.all_close_pts(middle, Distance::meters(250.0)) {
if r1.id != r2
&& PolyLine::new(vec![
&& PolyLine::must_new(vec![
middle.project_away(Distance::meters(100.0), angle.rotate_degs(90.0)),
middle.project_away(Distance::meters(100.0), angle.rotate_degs(-90.0)),
])

View File

@ -540,7 +540,7 @@ struct Lasso {
impl Lasso {
fn new(pt: Pt2D) -> Lasso {
Lasso {
pl: PolyLine::new(vec![pt, pt.offset(0.1, 0.0)]),
pl: PolyLine::must_new(vec![pt, pt.offset(0.1, 0.0)]),
}
}
@ -550,12 +550,9 @@ impl Lasso {
}
if ctx.redo_mouseover() {
if let Some(pt) = ctx.canvas.get_cursor_in_map_space() {
if pt != self.pl.last_pt() {
if let Ok(pl) = PolyLine::new(vec![self.pl.last_pt(), pt]) {
// Did we make a crossing?
if let Some((hit, _)) = self
.pl
.intersection(&PolyLine::new(vec![self.pl.last_pt(), pt]))
{
if let Some((hit, _)) = self.pl.intersection(&pl) {
if let Some(slice) = self.pl.get_slice_starting_at(hit) {
return Some(simplify(slice.into_points()));
}
@ -563,7 +560,9 @@ impl Lasso {
let mut pts = self.pl.points().clone();
pts.push(pt);
self.pl = PolyLine::new(pts);
if let Ok(new) = PolyLine::new(pts) {
self.pl = new;
}
}
}
}

View File

@ -346,12 +346,15 @@ fn make_timeline(
.insert(format!("jump to start of {}", trip), id);
if let TripEndpoint::Border(_, ref loc) = trip_start {
if let Some(loc) = loc {
let arrow =
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();
details.unzoomed.push(Color::GREEN, arrow.clone());
details.zoomed.push(Color::GREEN, arrow.clone());
details.unzoomed.push(Color::GREEN, arrow.clone());
details.zoomed.push(Color::GREEN, arrow.clone());
}
}
}
@ -390,12 +393,15 @@ fn make_timeline(
.insert(format!("jump to goal of {}", trip), id);
if let TripEndpoint::Border(_, ref loc) = trip_end {
if let Some(loc) = loc {
let arrow =
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();
details.unzoomed.push(Color::GREEN, arrow.clone());
details.zoomed.push(Color::GREEN, arrow.clone());
details.unzoomed.push(Color::GREEN, arrow.clone());
details.zoomed.push(Color::GREEN, arrow.clone());
}
}
}

View File

@ -80,7 +80,7 @@ impl Elevation {
let (pt, angle) = pl.dist_along(dist);
batch.push(
Color::BLACK,
PolyLine::new(vec![
PolyLine::must_new(vec![
pt.project_away(arrow_len / 2.0, angle.opposite()),
pt.project_away(arrow_len / 2.0, angle),
])

View File

@ -79,7 +79,7 @@ impl DrawBike {
let angle = map.get_t(t).angle();
draw_default.push(
cs.turn_arrow,
PolyLine::new(vec![
PolyLine::must_new(vec![
body_pos.project_away(body_radius / 2.0, angle.opposite()),
body_pos.project_away(body_radius / 2.0, angle),
])

View File

@ -87,7 +87,7 @@ impl DrawCar {
draw_default.push(
cs.turn_arrow,
PolyLine::new(vec![
PolyLine::must_new(vec![
pos.project_away(arrow_len / 2.0, angle.rotate_degs(90.0)),
pos.project_away(arrow_len / 2.0, angle.rotate_degs(-90.0)),
])
@ -102,7 +102,7 @@ impl DrawCar {
draw_default.push(
cs.turn_arrow,
PolyLine::new(vec![
PolyLine::must_new(vec![
pos.project_away(arrow_len / 2.0, angle.rotate_degs(-90.0)),
pos.project_away(arrow_len / 2.0, angle.rotate_degs(90.0)),
])
@ -188,7 +188,7 @@ fn thick_line_from_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)
PolyLine::must_new(vec![pt, pt2]).make_polygons(thickness)
}
fn zoomed_color_car(input: &DrawCarInput, cs: &ColorScheme) -> Color {

View File

@ -257,7 +257,7 @@ fn calculate_border_arrows(
};
result.push(
// DEGENERATE_INTERSECTION_HALF_LENGTH is 5m...
PolyLine::new(vec![
PolyLine::must_new(vec![
line.unbounded_dist_along(Distance::meters(-9.5)),
line.unbounded_dist_along(Distance::meters(-0.5)),
])
@ -281,7 +281,7 @@ fn calculate_border_arrows(
)
};
result.push(
PolyLine::new(vec![
PolyLine::must_new(vec![
line.unbounded_dist_along(Distance::meters(-0.5)),
line.unbounded_dist_along(Distance::meters(-9.5)),
])

View File

@ -317,7 +317,7 @@ fn calculate_turn_markings(map: &Map, lane: &Lane, timer: &mut Timer) -> Vec<Pol
continue;
}
results.push(
PolyLine::new(vec![
PolyLine::must_new(vec![
common_base.last_pt(),
common_base
.last_pt()
@ -355,7 +355,7 @@ fn calculate_one_way_markings(lane: &Lane, parent: &Road) -> Vec<Polygon> {
while dist + arrow_len <= len {
let (pt, angle) = lane.lane_center_pts.dist_along(dist);
results.push(
PolyLine::new(vec![
PolyLine::must_new(vec![
pt.project_away(arrow_len / 2.0, angle.opposite()),
pt.project_away(arrow_len / 2.0, angle),
])

View File

@ -68,7 +68,7 @@ impl DrawParkingLot {
batch.push(
cs.general_road_marking,
PolyLine::new(vec![
PolyLine::must_new(vec![
left.project_away(height, *angle),
left,
right,

View File

@ -34,7 +34,7 @@ impl DrawPedestrian {
let angle = map.get_t(t).angle();
draw_default.push(
cs.turn_arrow,
PolyLine::new(vec![
PolyLine::must_new(vec![
input.pos.project_away(radius / 2.0, angle.opposite()),
input.pos.project_away(radius / 2.0, angle),
])

View File

@ -83,7 +83,7 @@ impl DrawUberTurnGroup {
fn make_geom(offset: f64, pl: PolyLine, width: Distance, angle: Angle) -> (Polygon, Polygon) {
let height = TURN_ICON_ARROW_LENGTH;
// Always extend the pl first to handle short entry lanes
let extension = PolyLine::new(vec![
let extension = PolyLine::must_new(vec![
pl.last_pt(),
pl.last_pt()
.project_away(Distance::meters(500.0), pl.last_line().angle()),
@ -94,7 +94,7 @@ fn make_geom(offset: f64, pl: PolyLine, width: Distance, angle: Angle) -> (Polyg
let arrow = {
let center = slice.middle();
PolyLine::new(vec![
PolyLine::must_new(vec![
center.project_away(TURN_ICON_ARROW_LENGTH / 2.0, angle.opposite()),
center.project_away(TURN_ICON_ARROW_LENGTH / 2.0, angle),
])

View File

@ -360,19 +360,20 @@ impl GameplayState for Tutorial {
if let Some((_, _, Some(fxn))) = tut.lines() {
let pt = (fxn)(g, app);
g.fork_screenspace();
g.draw_polygon(
Color::RED,
&PolyLine::new(vec![
self.msg_panel
.as_ref()
.unwrap()
.center_of("next message")
.to_pt(),
pt,
])
.make_arrow(Distance::meters(20.0), ArrowCap::Triangle)
.unwrap(),
);
if let Ok(pl) = PolyLine::new(vec![
self.msg_panel
.as_ref()
.unwrap()
.center_of("next message")
.to_pt(),
pt,
]) {
g.draw_polygon(
Color::RED,
&pl.make_arrow(Distance::meters(20.0), ArrowCap::Triangle)
.unwrap(),
);
}
g.unfork();
}

View File

@ -36,7 +36,7 @@ impl Line {
}
pub fn to_polyline(&self) -> PolyLine {
PolyLine::new(self.points())
PolyLine::must_new(self.points())
}
pub fn make_polygons(&self, thickness: Distance) -> Polygon {

View File

@ -4,6 +4,7 @@ use crate::{
use abstutil::Warn;
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
use std::error::Error;
use std::fmt;
// TODO How to tune this?
@ -23,7 +24,7 @@ pub struct PolyLine {
}
impl PolyLine {
pub fn new(pts: Vec<Pt2D>) -> 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])
@ -57,26 +58,41 @@ impl PolyLine {
result
}
pub fn maybe_new(pts: Vec<Pt2D>) -> Option<PolyLine> {
pub fn new(pts: Vec<Pt2D>) -> Result<PolyLine, Box<dyn Error>> {
if pts.len() < 2 {
return None;
return Err(format!("Need at least two points for a PolyLine").into());
}
let length = pts.windows(2).fold(Distance::ZERO, |so_far, pair| {
so_far + pair[0].dist_to(pair[1])
});
if pts.windows(2).any(|pair| pair[0] == pair[1]) {
return None;
return Err(format!(
"PL with total length {} and {} pts has ~dupe adjacent pts",
length,
pts.len(),
)
.into());
}
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() {
return None;
return Err(format!(
"PL with total length {} and {} pts has dupe non-adjacent pts",
result.length,
result.pts.len(),
)
.into());
}
Some(result)
Ok(result)
}
pub fn must_new(pts: Vec<Pt2D>) -> PolyLine {
PolyLine::new(pts).unwrap()
}
// Doesn't check for duplicates. Use at your own risk.
@ -89,8 +105,8 @@ impl PolyLine {
PolyLine { pts, length }
}
// First dedupes adjacent points. If the result is only 1 point, will panic.
pub fn deduping_new(mut pts: Vec<Pt2D>) -> PolyLine {
// First dedupes adjacent points
pub fn deduping_new(mut pts: Vec<Pt2D>) -> Result<PolyLine, Box<dyn Error>> {
pts.dedup();
PolyLine::new(pts)
}
@ -119,14 +135,14 @@ impl PolyLine {
pub fn reversed(&self) -> PolyLine {
let mut pts = self.pts.clone();
pts.reverse();
PolyLine::new(pts)
PolyLine::must_new(pts)
}
pub fn extend(self, other: PolyLine) -> PolyLine {
self.maybe_extend(other).unwrap()
}
pub fn maybe_extend(self, other: PolyLine) -> Option<PolyLine> {
pub fn maybe_extend(self, other: PolyLine) -> Result<PolyLine, Box<dyn Error>> {
assert_eq!(*self.pts.last().unwrap(), other.pts[0]);
let mut self_pts = self.pts;
@ -167,7 +183,7 @@ impl PolyLine {
}
}
self_pts.extend(other_pts.iter().skip(1));
PolyLine::maybe_new(self_pts)
PolyLine::new(self_pts)
}
// One or both args might be empty.
@ -179,8 +195,8 @@ impl PolyLine {
return second;
}
PolyLine::new(first)
.extend(PolyLine::new(second))
PolyLine::old_new(first)
.extend(PolyLine::old_new(second))
.points()
.clone()
}
@ -244,7 +260,7 @@ impl PolyLine {
// TODO Understand what happened here.
return None;
}
return Some((PolyLine::new(result), Distance::ZERO));
return Some((PolyLine::old_new(result), Distance::ZERO));
}
// If we're in the middle, just collect the endpoint. But not if it's too close to the
@ -268,7 +284,7 @@ impl PolyLine {
return None;
}
Some((PolyLine::new(result), end - dist_so_far))
Some((PolyLine::old_new(result), end - dist_so_far))
}
// No excess leftover distance allowed.
@ -368,7 +384,7 @@ impl PolyLine {
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::new(raw);
let result = PolyLine::old_new(raw);
let fixed = if result.pts.len() == self.pts.len() {
fix_angles(self, result)
} else {
@ -526,7 +542,7 @@ impl PolyLine {
])))
}
ArrowCap::Lines => Warn::ok(self.make_polygons(thickness).union(
PolyLine::new(vec![corner1, self.last_pt(), corner2]).make_polygons(thickness),
PolyLine::old_new(vec![corner1, self.last_pt(), corner2]).make_polygons(thickness),
)),
}
}
@ -653,7 +669,7 @@ impl PolyLine {
if pts.len() == 1 {
return None;
}
Some(PolyLine::new(pts))
Some(PolyLine::old_new(pts))
} else {
panic!("Can't get_slice_ending_at: {} doesn't contain {}", self, pt);
}
@ -671,7 +687,7 @@ impl PolyLine {
if pt != pts[0] {
pts.insert(0, pt);
}
Some(PolyLine::new(pts))
Some(PolyLine::old_new(pts))
} else {
panic!(
"Can't get_slice_starting_at: {} doesn't contain {}",
@ -751,7 +767,7 @@ fn fix_angles(orig: &PolyLine, result: PolyLine) -> PolyLine {
}
// When we swap points, length of the entire PolyLine may change! Recalculating is vital.
PolyLine::new(pts)
PolyLine::old_new(pts)
}
fn check_angles(orig: &PolyLine, fixed: PolyLine) -> Warn<PolyLine> {

View File

@ -1,6 +1,7 @@
use crate::{Distance, Line, PolyLine, Polygon, Pt2D};
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
use std::error::Error;
use std::fmt;
// Maybe a misnomer, but like a PolyLine, but closed.
@ -115,7 +116,7 @@ impl Ring {
}
// Extract all PolyLines and Rings. Doesn't handle crazy double loops and stuff.
pub fn split_points(pts: &Vec<Pt2D>) -> (Vec<PolyLine>, Vec<Ring>) {
pub fn split_points(pts: &Vec<Pt2D>) -> Result<(Vec<PolyLine>, Vec<Ring>), Box<dyn Error>> {
let mut seen = HashSet::new();
let mut intersections = HashSet::new();
for pt in pts {
@ -138,12 +139,12 @@ impl Ring {
if current[0] == pt {
rings.push(Ring::new(current.drain(..).collect()));
} else {
polylines.push(PolyLine::new(current.drain(..).collect()));
polylines.push(PolyLine::new(current.drain(..).collect())?);
}
current.push(pt);
}
}
(polylines, rings)
Ok((polylines, rings))
}
}

View File

@ -216,7 +216,7 @@ impl Model {
// (MAX_CAR_LENGTH + sim::FOLLOWING_DISTANCE) from sim, but without the dependency
txt.add(Line(format!(
"Can fit ~{} cars",
(PolyLine::new(road.center_points.clone()).length()
(PolyLine::must_new(road.center_points.clone()).length()
/ (Distance::meters(6.5 + 1.0)))
.floor() as usize
)));
@ -499,7 +499,7 @@ impl Model {
r.synthetic() && r.osm_tags.get(osm::NAME) == Some(&"Streety McStreetFace".to_string());
let lanes_unknown = r.osm_tags.contains_key(osm::INFERRED_SIDEWALKS);
let spec = r.get_spec();
let center_pts = PolyLine::new(r.center_points.clone());
let center_pts = PolyLine::must_new(r.center_points.clone());
let mut obj = Object::blank(ID::Road(id));
@ -551,7 +551,7 @@ impl Model {
let polygon = if id == *to {
// TODO Ideally a hollow circle with an arrow
Circle::new(
PolyLine::new(self.map.roads[&id].center_points.clone()).middle(),
PolyLine::must_new(self.map.roads[&id].center_points.clone()).middle(),
NORMAL_LANE_THICKNESS,
)
.to_polygon()
@ -561,7 +561,7 @@ impl Model {
println!("Turn restriction to spot is missing!{}->{}", id, to);
continue;
}
PolyLine::new(vec![self.get_r_center(id), self.get_r_center(*to)])
PolyLine::must_new(vec![self.get_r_center(id), self.get_r_center(*to)])
.make_arrow(NORMAL_LANE_THICKNESS, ArrowCap::Triangle)
.unwrap()
};
@ -714,7 +714,7 @@ impl Model {
}
pub fn get_r_center(&self, id: OriginalRoad) -> Pt2D {
PolyLine::new(self.map.roads[&id].center_points.clone()).middle()
PolyLine::must_new(self.map.roads[&id].center_points.clone()).middle()
}
}

View File

@ -85,7 +85,7 @@ pub fn make_all_buildings(
if driving_pos.dist_along() > driveway_buffer
&& map.get_l(driving_lane).length() - driving_pos.dist_along() > driveway_buffer
{
let driveway_line = PolyLine::new(vec![
let driveway_line = PolyLine::must_new(vec![
sidewalk_line.pt1(),
sidewalk_line.pt2(),
driving_pos.pt(map),
@ -175,7 +175,7 @@ pub fn make_all_parking_lots(
&& map.get_l(driving_lane).length() - driving_pos.dist_along() > driveway_buffer
{
driveway = Some((
PolyLine::new(vec![
PolyLine::must_new(vec![
sidewalk_line.pt1(),
sidewalk_line.pt2(),
driving_pos.pt(map),
@ -225,7 +225,7 @@ pub fn make_all_parking_lots(
.map(|(id, _, _)| id)
.collect();
let (polylines, rings) = Ring::split_points(pts);
let (polylines, rings) = Ring::split_points(pts).unwrap();
'PL: for pl in polylines {
for id in &candidates {
let lot = &mut results[id.0];

View File

@ -44,7 +44,7 @@ impl Road {
}
// If there's a sidewalk on only one side, adjust the true center of the road.
let mut trimmed_center_pts = PolyLine::new(r.center_points.clone());
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)

View File

@ -446,7 +446,7 @@ fn make_crosswalks(i: IntersectionID, l1: &Lane, l2: &Lane) -> Option<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 geom_fwds = PolyLine::deduping_new(vec![l1_pt, line.pt1(), line.pt2(), l2_pt]);
let geom_fwds = PolyLine::deduping_new(vec![l1_pt, line.pt1(), line.pt2(), l2_pt]).ok()?;
Some(vec![
Turn {
@ -495,25 +495,29 @@ fn make_degenerate_crosswalks(
id: turn_id(i, l1_in.id, l1_out.id),
turn_type: TurnType::Crosswalk,
other_crosswalk_ids: all_ids.clone(),
geom: PolyLine::deduping_new(vec![l1_in.last_pt(), pt1, pt2, l1_out.first_pt()]),
geom: PolyLine::deduping_new(vec![l1_in.last_pt(), pt1, pt2, l1_out.first_pt()])
.ok()?,
},
Turn {
id: turn_id(i, l1_out.id, l1_in.id),
turn_type: TurnType::Crosswalk,
other_crosswalk_ids: all_ids.clone(),
geom: PolyLine::deduping_new(vec![l1_out.first_pt(), pt2, pt1, l1_in.last_pt()]),
geom: PolyLine::deduping_new(vec![l1_out.first_pt(), pt2, pt1, l1_in.last_pt()])
.ok()?,
},
Turn {
id: turn_id(i, l2_in.id, l2_out.id),
turn_type: TurnType::Crosswalk,
other_crosswalk_ids: all_ids.clone(),
geom: PolyLine::deduping_new(vec![l2_in.last_pt(), pt2, pt1, l2_out.first_pt()]),
geom: PolyLine::deduping_new(vec![l2_in.last_pt(), pt2, pt1, l2_out.first_pt()])
.ok()?,
},
Turn {
id: turn_id(i, l2_out.id, l2_in.id),
turn_type: TurnType::Crosswalk,
other_crosswalk_ids: all_ids.clone(),
geom: PolyLine::deduping_new(vec![l2_out.first_pt(), pt1, pt2, l2_in.last_pt()]),
geom: PolyLine::deduping_new(vec![l2_out.first_pt(), pt1, pt2, l2_in.last_pt()])
.ok()?,
},
]
.into_iter()
@ -531,7 +535,7 @@ fn make_shared_sidewalk_corner(
l2: &Lane,
timer: &mut Timer,
) -> PolyLine {
let baseline = PolyLine::new(vec![l1.last_pt(), l2.first_pt()]);
let baseline = PolyLine::must_new(vec![l1.last_pt(), l2.first_pt()]);
// Find all of the points on the intersection polygon between the two sidewalks. Assumes
// sidewalks are the same length.
@ -570,7 +574,7 @@ fn make_shared_sidewalk_corner(
pts_between.extend(
driving_side
.right_shift(PolyLine::new(deduped), l1.width / 2.0)
.right_shift(PolyLine::must_new(deduped), l1.width / 2.0)
.with_context(
timer,
format!("SharedSidewalkCorner between {} and {}", l1.id, l2.id),
@ -605,7 +609,7 @@ fn make_shared_sidewalk_corner(
));
return baseline;
}
let result = PolyLine::new(final_pts);
let result = PolyLine::must_new(final_pts);
if result.length() > 10.0 * baseline.length() {
timer.warn(format!(
"SharedSidewalkCorner between {} and {} explodes to {} long, so just doing straight \
@ -662,7 +666,7 @@ fn make_vehicle_turn(
}
let geom = if turn_type == TurnType::Straight {
PolyLine::new(vec![src.last_pt(), dst.first_pt()])
PolyLine::must_new(vec![src.last_pt(), dst.first_pt()])
} else {
// The control points are straight out/in from the source/destination lanes, so
// that the car exits and enters at the same angle as the road.
@ -687,7 +691,7 @@ fn make_vehicle_turn(
})
.collect();
curve.dedup();
PolyLine::new(curve)
PolyLine::must_new(curve)
};
Some(Turn {

View File

@ -305,5 +305,5 @@ fn turn_group_geom(
&polylines.iter().map(|pl| pl.points()[idx]).collect(),
));
}
PolyLine::new(pts)
PolyLine::must_new(pts)
}

View File

@ -369,11 +369,14 @@ impl Path {
self.steps[i].slice(map, start_dist_this_step, dist_remaining)
{
if pts_so_far.is_some() {
if let Some(new) = pts_so_far.unwrap().maybe_extend(new_pts) {
pts_so_far = Some(new);
} else {
println!("WARNING: Couldn't trace some path because of duplicate points");
return None;
match pts_so_far.unwrap().maybe_extend(new_pts) {
Ok(new) => {
pts_so_far = Some(new);
}
Err(err) => {
println!("WARNING: Couldn't trace some path: {}", err);
return None;
}
}
} else {
pts_so_far = Some(new_pts);

View File

@ -343,5 +343,5 @@ fn group_geom(mut polylines: Vec<PolyLine>) -> PolyLine {
&polylines.iter().map(|pl| pl.points()[idx]).collect(),
));
}
PolyLine::new(pts)
PolyLine::must_new(pts)
}

View File

@ -99,7 +99,10 @@ impl Car {
self.vehicle.id, now, front
);
}
PolyLine::new(result)
match PolyLine::new(result) {
Ok(pl) => pl,
Err(err) => panic!("Weird body for {} at {}: {}", self.vehicle.id, now, err),
}
};
let body = match self.state {

View File

@ -229,7 +229,7 @@ impl ParkingSimState {
on: Traversable::Lane(pl.driving_pos.lane()),
label: None,
body: PolyLine::new(vec![
body: PolyLine::must_new(vec![
pt.project_away(buffer, angle),
pt.project_away(map_model::PARKING_LOT_SPOT_LENGTH - buffer, angle),
]),