mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-29 01:13:53 +03:00
start the big one: Polyline::new
This commit is contained in:
parent
0593aa52d9
commit
cce624edd8
@ -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(¢er)[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(¢er.reversed())[0];
|
||||
mut_r.center_points = center
|
||||
.get_slice_ending_at(border_pt)
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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),
|
||||
])
|
||||
|
@ -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),
|
||||
])
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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)),
|
||||
])
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
])
|
||||
|
@ -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),
|
||||
])
|
||||
|
@ -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 {
|
||||
|
@ -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)),
|
||||
])
|
||||
|
@ -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),
|
||||
])
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
])
|
||||
|
@ -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),
|
||||
])
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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> {
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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];
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -305,5 +305,5 @@ fn turn_group_geom(
|
||||
&polylines.iter().map(|pl| pl.points()[idx]).collect(),
|
||||
));
|
||||
}
|
||||
PolyLine::new(pts)
|
||||
PolyLine::must_new(pts)
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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),
|
||||
]),
|
||||
|
Loading…
Reference in New Issue
Block a user