making small_seattle fully convert, with some less messy hacks. added it

as a test!
This commit is contained in:
Dustin Carlino 2019-02-11 15:59:36 -08:00
parent a3b03952cf
commit 6da48c28c1
6 changed files with 98 additions and 51 deletions

View File

@ -43,6 +43,10 @@ pub fn make_all_buildings(
let sidewalk_pt = lanes[sidewalk_pos.lane().0] let sidewalk_pt = lanes[sidewalk_pos.lane().0]
.dist_along(sidewalk_pos.dist_along()) .dist_along(sidewalk_pos.dist_along())
.0; .0;
if sidewalk_pt.epsilon_eq(bldg_center.into()) {
warn!("Skipping a building because front path has 0 length");
continue;
}
let line = trim_front_path(&points, Line::new(bldg_center.into(), sidewalk_pt)); let line = trim_front_path(&points, Line::new(bldg_center.into(), sidewalk_pt));
let id = BuildingID(results.len()); let id = BuildingID(results.len());

View File

@ -4,6 +4,11 @@ use abstutil::Timer;
use std::collections::{BTreeSet, HashSet}; use std::collections::{BTreeSet, HashSet};
pub fn fix_ramps(m: &mut InitialMap, timer: &mut Timer) { pub fn fix_ramps(m: &mut InitialMap, timer: &mut Timer) {
if m.roads.len() > 15_000 {
error!("Skipping fix_ramps because map is too big! TODO: Optimize me!");
return;
}
// Look for road center lines that hit an intersection polygon that isn't one of their // Look for road center lines that hit an intersection polygon that isn't one of their
// endpoints. // endpoints.
timer.start_iter( timer.start_iter(

View File

@ -139,10 +139,16 @@ fn generalized_trim_back(
// How could something perpendicular to a shifted polyline never hit the original // How could something perpendicular to a shifted polyline never hit the original
// polyline? Also, find the hit closest to the intersection -- this matters for // polyline? Also, find the hit closest to the intersection -- this matters for
// very curvy roads, like highway ramps. // very curvy roads, like highway ramps.
let trim_to = road_center.reversed().intersection_infinite(&perp).unwrap(); if let Some(trimmed) = road_center
let trimmed = road_center.get_slice_ending_at(trim_to).unwrap(); .reversed()
if trimmed.length() < shortest_center.length() { .intersection_infinite(&perp)
shortest_center = trimmed; .and_then(|trim_to| road_center.get_slice_ending_at(trim_to))
{
if trimmed.length() < shortest_center.length() {
shortest_center = trimmed;
}
} else {
warn!("{} and {} hit, but the perpendicular never hit the original center line, or the trimmed thing is empty", r1, r2);
} }
// We could also do the update for r2, but we'll just get to it later. // We could also do the update for r2, but we'll just get to it later.
@ -199,18 +205,25 @@ fn generalized_trim_back(
// Include collisions between polylines of adjacent roads, so the polygon doesn't cover area // Include collisions between polylines of adjacent roads, so the polygon doesn't cover area
// not originally covered by the thick road bands. // not originally covered by the thick road bands.
// It's apparently safe to always take the second_half here. // It's apparently safe to always take the second_half here.
if let Some((hit, _)) = fwd_pl.second_half().intersection(&adj_fwd_pl.second_half()) { if fwd_pl.length() >= geom::EPSILON_DIST * 3.0
endpoints.push(hit); && adj_fwd_pl.length() >= geom::EPSILON_DIST * 3.0
} else if r.original_endpoint(i) != roads[&adj_fwd_id].original_endpoint(i) { {
if false { if let Some((hit, _)) = fwd_pl.second_half().intersection(&adj_fwd_pl.second_half()) {
// TODO This cuts some corners nicely, but also causes lots of problems. endpoints.push(hit);
// If the original roads didn't end at the same intersection (due to intersection } else if r.original_endpoint(i) != roads[&adj_fwd_id].original_endpoint(i) {
// merging), then use infinite lines. if false {
if let Some((hit, _)) = fwd_pl.second_half().intersection(&adj_fwd_pl.second_half()) // TODO This cuts some corners nicely, but also causes lots of problems.
{ // If the original roads didn't end at the same intersection (due to intersection
endpoints.push(hit); // merging), then use infinite lines.
if let Some((hit, _)) =
fwd_pl.second_half().intersection(&adj_fwd_pl.second_half())
{
endpoints.push(hit);
}
} }
} }
} else {
warn!("Excluding collision between original polylines of {} and something, because stuff's too short", id);
} }
// Shift those final centers out again to find the main endpoints for the polygon. // Shift those final centers out again to find the main endpoints for the polygon.
@ -222,21 +235,27 @@ fn generalized_trim_back(
endpoints.push(r.trimmed_center_pts.shift_right(r.fwd_width).first_pt()); endpoints.push(r.trimmed_center_pts.shift_right(r.fwd_width).first_pt());
} }
if let Some((hit, _)) = back_pl if back_pl.length() >= geom::EPSILON_DIST * 3.0
.second_half() && adj_back_pl.length() >= geom::EPSILON_DIST * 3.0
.intersection(&adj_back_pl.second_half())
{ {
endpoints.push(hit); if let Some((hit, _)) = back_pl
} else if r.original_endpoint(i) != roads[&adj_back_id].original_endpoint(i) { .second_half()
if false { .intersection(&adj_back_pl.second_half())
if let Some(hit) = back_pl {
.last_line() endpoints.push(hit);
.infinite() } else if r.original_endpoint(i) != roads[&adj_back_id].original_endpoint(i) {
.intersection(&adj_back_pl.last_line().infinite()) if false {
{ if let Some(hit) = back_pl
endpoints.push(hit); .last_line()
.infinite()
.intersection(&adj_back_pl.last_line().infinite())
{
endpoints.push(hit);
}
} }
} }
} else {
warn!("Excluding collision between original polylines of {} and something, because stuff's too short", id);
} }
} }
// TODO Caller will close off the polygon. Does that affect our dedupe? // TODO Caller will close off the polygon. Does that affect our dedupe?

View File

@ -8,6 +8,8 @@ use nbez::{Bez3o, BezCurve, Point2d};
use std::collections::{BTreeSet, HashSet}; use std::collections::{BTreeSet, HashSet};
use std::iter; use std::iter;
// TODO Add proper warnings when the geometry is too small to handle.
pub fn make_all_turns(i: &Intersection, roads: &Vec<Road>, lanes: &Vec<Lane>) -> Vec<Turn> { pub fn make_all_turns(i: &Intersection, roads: &Vec<Road>, lanes: &Vec<Lane>) -> Vec<Turn> {
if i.intersection_type == IntersectionType::Border { if i.intersection_type == IntersectionType::Border {
return Vec::new(); return Vec::new();
@ -73,7 +75,7 @@ fn make_vehicle_turns(i: &Intersection, all_roads: &Vec<Road>, lanes: &Vec<Lane>
lane_types.remove(&LaneType::Parking); lane_types.remove(&LaneType::Parking);
lane_types.remove(&LaneType::Sidewalk); lane_types.remove(&LaneType::Sidewalk);
let mut result = Vec::new(); let mut result: Vec<Option<Turn>> = Vec::new();
for lane_type in lane_types.into_iter() { for lane_type in lane_types.into_iter() {
if i.is_dead_end() { if i.is_dead_end() {
@ -139,7 +141,7 @@ fn make_vehicle_turns(i: &Intersection, all_roads: &Vec<Road>, lanes: &Vec<Lane>
} }
} }
result result.into_iter().filter_map(|x| x).collect()
} }
fn match_up_lanes( fn match_up_lanes(
@ -147,7 +149,7 @@ fn match_up_lanes(
i: IntersectionID, i: IntersectionID,
incoming: &Vec<LaneID>, incoming: &Vec<LaneID>,
outgoing: &Vec<LaneID>, outgoing: &Vec<LaneID>,
) -> Vec<Turn> { ) -> Vec<Option<Turn>> {
let mut result = Vec::new(); let mut result = Vec::new();
if incoming.len() < outgoing.len() { if incoming.len() < outgoing.len() {
// Arbitrarily use the leftmost incoming lane to handle the excess. // Arbitrarily use the leftmost incoming lane to handle the excess.
@ -185,7 +187,7 @@ fn make_vehicle_turns_for_dead_end(
roads: &Vec<Road>, roads: &Vec<Road>,
lanes: &Vec<Lane>, lanes: &Vec<Lane>,
lane_type: LaneType, lane_type: LaneType,
) -> Vec<Turn> { ) -> Vec<Option<Turn>> {
let road = &roads[i.roads.iter().next().unwrap().0]; let road = &roads[i.roads.iter().next().unwrap().0];
let incoming = filter_vehicle_lanes(road.incoming_lanes(i.id), lane_type); let incoming = filter_vehicle_lanes(road.incoming_lanes(i.id), lane_type);
let outgoing = filter_vehicle_lanes(road.outgoing_lanes(i.id), lane_type); let outgoing = filter_vehicle_lanes(road.outgoing_lanes(i.id), lane_type);
@ -219,18 +221,22 @@ fn make_walking_turns(i: &Intersection, all_roads: &Vec<Road>, lanes: &Vec<Lane>
lanes, lanes,
wraparound_get(&roads, (idx1 as isize) - 1).outgoing_lanes(i.id), wraparound_get(&roads, (idx1 as isize) - 1).outgoing_lanes(i.id),
) { ) {
result.push(Turn { if !l1.last_pt().epsilon_eq(l2.first_pt()) {
id: turn_id(i.id, l1.id, l2.id), result.push(Turn {
turn_type: TurnType::SharedSidewalkCorner, id: turn_id(i.id, l1.id, l2.id),
geom: PolyLine::new(vec![l1.last_pt(), l2.first_pt()]), turn_type: TurnType::SharedSidewalkCorner,
lookup_idx: 0, geom: PolyLine::new(vec![l1.last_pt(), l2.first_pt()]),
}); lookup_idx: 0,
result.push(Turn { });
id: turn_id(i.id, l2.id, l1.id), }
turn_type: TurnType::SharedSidewalkCorner, if !l2.first_pt().epsilon_eq(l1.last_pt()) {
geom: PolyLine::new(vec![l2.first_pt(), l1.last_pt()]), result.push(Turn {
lookup_idx: 0, id: turn_id(i.id, l2.id, l1.id),
}); turn_type: TurnType::SharedSidewalkCorner,
geom: PolyLine::new(vec![l2.first_pt(), l1.last_pt()]),
lookup_idx: 0,
});
}
} else if roads.len() > 2 { } else if roads.len() > 2 {
// See if we need to add a crosswalk over this adjacent road. // See if we need to add a crosswalk over this adjacent road.
// TODO This is brittle; I could imagine having to cross two adjacent highway // TODO This is brittle; I could imagine having to cross two adjacent highway
@ -249,6 +255,10 @@ fn make_walking_turns(i: &Intersection, all_roads: &Vec<Road>, lanes: &Vec<Lane>
} }
fn make_crosswalks(i: IntersectionID, l1: &Lane, l2: &Lane) -> Vec<Turn> { fn make_crosswalks(i: IntersectionID, l1: &Lane, l2: &Lane) -> Vec<Turn> {
if l1.last_pt().epsilon_eq(l2.first_pt()) {
return Vec::new();
}
// Jut out a bit into the intersection, cross over, then jut back in. // Jut out a bit into the intersection, cross over, then jut back in.
let line = Line::new(l1.last_pt(), l2.first_pt()).shift_right(LANE_THICKNESS / 2.0); let line = Line::new(l1.last_pt(), l2.first_pt()).shift_right(LANE_THICKNESS / 2.0);
let geom_fwds = PolyLine::new(vec![l1.last_pt(), line.pt1(), line.pt2(), l2.first_pt()]); let geom_fwds = PolyLine::new(vec![l1.last_pt(), line.pt1(), line.pt2(), l2.first_pt()]);
@ -297,11 +307,15 @@ fn filter_lanes(lanes: &Vec<(LaneID, LaneType)>, filter: LaneType) -> Vec<LaneID
.collect() .collect()
} }
fn make_vehicle_turn(lanes: &Vec<Lane>, i: IntersectionID, l1: LaneID, l2: LaneID) -> Turn { fn make_vehicle_turn(lanes: &Vec<Lane>, i: IntersectionID, l1: LaneID, l2: LaneID) -> Option<Turn> {
let src = &lanes[l1.0]; let src = &lanes[l1.0];
let dst = &lanes[l2.0]; let dst = &lanes[l2.0];
let turn_type = TurnType::from_angles(src.last_line().angle(), dst.first_line().angle()); let turn_type = TurnType::from_angles(src.last_line().angle(), dst.first_line().angle());
if src.last_pt().epsilon_eq(dst.first_pt()) {
return None;
}
let geom = if turn_type == TurnType::Straight { let geom = if turn_type == TurnType::Straight {
PolyLine::new(vec![src.last_pt(), dst.first_pt()]) PolyLine::new(vec![src.last_pt(), dst.first_pt()])
} else { } else {
@ -332,12 +346,12 @@ fn make_vehicle_turn(lanes: &Vec<Lane>, i: IntersectionID, l1: LaneID, l2: LaneI
)) ))
}; };
Turn { Some(Turn {
id: turn_id(i, l1, l2), id: turn_id(i, l1, l2),
turn_type, turn_type,
geom, geom,
lookup_idx: 0, lookup_idx: 0,
} })
} }
fn to_pt(pt: Pt2D) -> Point2d<f64> { fn to_pt(pt: Pt2D) -> Point2d<f64> {

View File

@ -85,7 +85,12 @@ impl ControlTrafficSignal {
intersection: IntersectionID, intersection: IntersectionID,
) -> Option<ControlTrafficSignal> { ) -> Option<ControlTrafficSignal> {
if map.get_turns_in_intersection(intersection).is_empty() { if map.get_turns_in_intersection(intersection).is_empty() {
panic!("{} has no turns", intersection); error!("{} has no turns", intersection);
return Some(ControlTrafficSignal {
id: intersection,
cycles: Vec::new(),
changed: false,
});
} }
let mut cycles = Vec::new(); let mut cycles = Vec::new();

View File

@ -51,21 +51,21 @@ pub fn run(t: &mut TestRunner) {
} }
}); });
t.run_slow("bigger_maps", |_| { t.run_slow("bigger_map_loads", |_| {
map_model::Map::new( map_model::Map::new(
"../data/raw_maps/23rd.abst", "../data/raw_maps/23rd.abst",
map_model::MapEdits::new("23rd"), map_model::MapEdits::new("23rd"),
&mut abstutil::Timer::new("raw to map"), &mut abstutil::Timer::new("raw to map"),
) )
.expect("23rd broke"); .expect("23rd broke");
});
// TODO This one has lots more problems (turns with no geometry) and even when the map is t.run_slow("biggest_map_loads", |_| {
// made successfully, can't load it in the UI without OOMing. map_model::Map::new(
/*map_model::Map::new(
"../data/raw_maps/small_seattle.abst", "../data/raw_maps/small_seattle.abst",
map_model::MapEdits::new("small_seattle"), map_model::MapEdits::new("small_seattle"),
&mut abstutil::Timer::new("raw to map"), &mut abstutil::Timer::new("raw to map"),
) )
.expect("small_seattle broke");*/ .expect("small_seattle broke");
}); });
} }