make intersection actually be a polygon now

This commit is contained in:
Dustin Carlino 2019-01-26 13:18:58 -08:00
parent dcad4a3c87
commit ab6796d56c
8 changed files with 19 additions and 229 deletions

View File

@ -12,7 +12,6 @@
- restore original road points, then redo the intersection polygon and lane center pt expansion
- organize map creation code better...
- remove halfmap now
- final Intersection.polygon can now be a Polygon!
- manually draw a picture of the weird intersection to see what would look reasonable. i think we need original road bands from deleted stuff to make decent polygons.

View File

@ -27,6 +27,7 @@ impl DebugPolygon {
.map
.get_i(id)
.polygon
.points()
.iter()
.map(|pt| Item::Point(*pt))
.collect(),

View File

@ -27,8 +27,6 @@ impl DrawIntersection {
cs: &ColorScheme,
prerender: &Prerender,
) -> DrawIntersection {
let polygon = Polygon::new(&i.polygon);
// Order matters... main polygon first, then sidewalk corners.
let mut default_geom = vec![(
match i.intersection_type {
@ -42,17 +40,17 @@ impl DrawIntersection {
cs.get_def("traffic signal intersection", Color::grey(0.4))
}
},
polygon.clone(),
i.polygon.clone(),
)];
default_geom.extend(
calculate_corners(i.id, map)
calculate_corners(i, map)
.into_iter()
.map(|p| (cs.get("sidewalk"), p)),
);
DrawIntersection {
id: i.id,
polygon,
polygon: i.polygon.clone(),
crosswalks: calculate_crosswalks(i.id, map),
intersection_type: i.intersection_type,
zorder: i.get_zorder(map),
@ -119,13 +117,13 @@ fn calculate_crosswalks(i: IntersectionID, map: &Map) -> Vec<DrawCrosswalk> {
crosswalks
}
fn calculate_corners(i: IntersectionID, map: &Map) -> Vec<Polygon> {
fn calculate_corners(i: &Intersection, map: &Map) -> Vec<Polygon> {
let mut corners = Vec::new();
for turn in &map.get_turns_in_intersection(i) {
for turn in &map.get_turns_in_intersection(i.id) {
if turn.turn_type == TurnType::SharedSidewalkCorner {
// Avoid double-rendering
if map.get_l(turn.id.src).dst_i != i {
if map.get_l(turn.id.src).dst_i != i.id {
continue;
}
@ -144,16 +142,13 @@ fn calculate_corners(i: IntersectionID, map: &Map) -> Vec<Polygon> {
let corner2 = l2.first_line().shift_right(LANE_THICKNESS / 2.0).pt1();
// Intersection polygons are constructed in clockwise order, so do corner2 to corner1.
// constructed...
if let Some(mut pts_between) = find_pts_between(&map.get_i(i).polygon, corner2, corner1)
{
if let Some(mut pts_between) = find_pts_between(&i.polygon.points(), corner2, corner1) {
//.expect("SharedSidewalkCorner couldn't find intersection points");
pts_between.push(src_line.pt2());
// If the intersection of the two lines isn't actually inside, then just exclude
// this point.
// TODO Argh, this is inefficient.
if map.get_i(i).polygon.len() >= 3
&& Polygon::new(&map.get_i(i).polygon).contains_pt(pt_maybe_in_intersection)
{
if i.polygon.contains_pt(pt_maybe_in_intersection) {
pts_between.push(pt_maybe_in_intersection);
}
pts_between.push(dst_line.pt1());
@ -281,10 +276,7 @@ pub fn draw_signal_diagram(
let padding = 5.0;
let zoom = 10.0;
let (top_left, intersection_width, intersection_height) = {
let mut b = Bounds::new();
for pt in &ctx.map.get_i(i).polygon {
b.update(*pt);
}
let b = ctx.map.get_i(i).polygon.get_bounds();
(
Pt2D::new(b.min_x, b.min_y),
b.max_x - b.min_x,

View File

@ -1,7 +1,8 @@
use crate::{Bounds, HashablePt2D, Pt2D};
use serde_derive::{Deserialize, Serialize};
use std::f64;
#[derive(Clone, Debug)]
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Polygon {
points: Vec<Pt2D>,
// Groups of three indices make up the triangles

View File

@ -1,7 +1,7 @@
use crate::{raw_data, LaneID, LaneType, Map, RoadID, TurnID};
use abstutil;
use dimensioned::si;
use geom::Pt2D;
use geom::{Polygon, Pt2D};
use serde_derive::{Deserialize, Serialize};
use std::collections::BTreeSet;
use std::fmt;
@ -27,10 +27,8 @@ pub enum IntersectionType {
pub struct Intersection {
pub id: IntersectionID,
pub point: Pt2D,
// TODO This should really be a Polygon, but it's hard to construct in the right order and
// weird to represent an Option<Polygon> during construction.
// Also, this needs to be in clockwise orientation, or later rendering breaks.
pub polygon: Vec<Pt2D>,
// This needs to be in clockwise orientation, or later rendering of sidewalk corners breaks.
pub polygon: Polygon,
pub turns: Vec<TurnID>,
pub elevation: si::Meter<f64>,

View File

@ -4,7 +4,7 @@ use crate::{
Turn, TurnID, LANE_THICKNESS,
};
use abstutil::Timer;
use geom::{GPSBounds, Pt2D};
use geom::{GPSBounds, Polygon, Pt2D};
use std::collections::BTreeMap;
pub struct HalfMap {
@ -45,8 +45,9 @@ pub fn make_half_map(
half_map.intersections.push(Intersection {
id,
point: pt,
// TODO Could actually make it a polygon here!
polygon: i.polygon.clone(),
// IMPORTANT! We're relying on the triangulation algorithm not to mess with the order
// of the points. Sidewalk corner rendering depends on it later.
polygon: Polygon::new(&i.polygon),
turns: Vec::new(),
elevation: raw_i.elevation,
// Might change later

View File

@ -1,201 +0,0 @@
use crate::make::half_map::HalfMap;
use crate::{Intersection, IntersectionID, Lane, LaneID, Road, RoadID};
use abstutil::Timer;
use dimensioned::si;
use std::collections::{BTreeSet, HashMap, HashSet};
use std::marker;
const MIN_ROAD_LENGTH: si::Meter<f64> = si::Meter {
value_unsafe: 15.0,
_marker: marker::PhantomData,
};
pub fn merge_intersections(mut m: HalfMap, timer: &mut Timer) -> HalfMap {
timer.start_iter("merge short roads", m.roads.len());
let mut merged = 0;
for i in 0..m.roads.len() {
timer.next();
// We destroy roads and shorten this list as we go. Don't break, so the timer finishes.
if i - merged >= m.roads.len() {
continue;
}
// When we delete road X, the entire list of roads shifts down, so on the next iteration,
// we want to reconsider the new X.
let r = &m.roads[i - merged];
if r.center_pts.length() < MIN_ROAD_LENGTH
&& !m.intersections[r.src_i.0].is_dead_end()
&& !m.intersections[r.dst_i.0].is_dead_end()
{
m = merge(r.id, m);
merged += 1;
}
}
info!("Merged {} short roads", merged);
m
}
fn merge(delete_r: RoadID, mut m: HalfMap) -> HalfMap {
let old_i1 = m.roads[delete_r.0].src_i;
let old_i2 = m.roads[delete_r.0].dst_i;
// Note delete_r might be a loop.
let mut delete = Deleter::new();
// Delete the road
delete.roads.insert(delete_r);
// Delete all of its children lanes
for (id, _) in &m.roads[delete_r.0].children_forwards {
delete.lanes.insert(*id);
}
for (id, _) in &m.roads[delete_r.0].children_backwards {
delete.lanes.insert(*id);
}
// Delete the two connected intersections
delete.intersections.insert(old_i1);
delete.intersections.insert(old_i2);
// Make a new intersection to replace the two old ones
// TODO Arbitrarily take point, elevation, type, label from one of the old intersections.
let new_i = IntersectionID(m.intersections.len());
m.intersections.push(Intersection {
id: new_i,
point: m.intersections[old_i1.0].point,
polygon: Vec::new(),
turns: Vec::new(),
elevation: m.intersections[old_i1.0].elevation,
intersection_type: m.intersections[old_i1.0].intersection_type,
label: m.intersections[old_i1.0].label.clone(),
stable_id: m.intersections[old_i1.0].stable_id,
incoming_lanes: Vec::new(),
outgoing_lanes: Vec::new(),
roads: BTreeSet::new(),
});
// For all of the connected roads and children lanes of the old intersections, fix up the
// references to/from the intersection
for old_i in &[old_i1, old_i2] {
for r_id in m.intersections[old_i.0].roads.clone() {
if r_id == delete_r {
continue;
}
m.intersections[new_i.0].roads.insert(r_id);
let r = &mut m.roads[r_id.0];
if r.src_i == *old_i {
// Outgoing from old_i
r.src_i = new_i;
for (l, _) in &r.children_forwards {
m.lanes[l.0].src_i = new_i;
m.intersections[new_i.0].outgoing_lanes.push(*l);
}
for (l, _) in &r.children_backwards {
m.lanes[l.0].dst_i = new_i;
m.intersections[new_i.0].incoming_lanes.push(*l);
}
}
// This isn't an else, because r might be a loop.
if r.dst_i == *old_i {
// Incoming to old_i
r.dst_i = new_i;
for (l, _) in &r.children_backwards {
m.lanes[l.0].src_i = new_i;
m.intersections[new_i.0].outgoing_lanes.push(*l);
}
for (l, _) in &r.children_forwards {
m.lanes[l.0].dst_i = new_i;
m.intersections[new_i.0].incoming_lanes.push(*l);
}
}
}
}
delete.apply(m)
}
struct Deleter {
roads: HashSet<RoadID>,
lanes: HashSet<LaneID>,
intersections: HashSet<IntersectionID>,
}
impl Deleter {
fn new() -> Deleter {
Deleter {
roads: HashSet::new(),
lanes: HashSet::new(),
intersections: HashSet::new(),
}
}
fn apply(self, mut m: HalfMap) -> HalfMap {
assert!(m.turns.is_empty());
let mut rename_roads: HashMap<RoadID, RoadID> = HashMap::new();
let mut keep_roads: Vec<Road> = Vec::new();
for r in m.roads.drain(0..) {
if self.roads.contains(&r.id) {
continue;
}
rename_roads.insert(r.id, RoadID(keep_roads.len()));
keep_roads.push(r);
}
m.roads = keep_roads;
let mut rename_lanes: HashMap<LaneID, LaneID> = HashMap::new();
let mut keep_lanes: Vec<Lane> = Vec::new();
for l in m.lanes.drain(0..) {
if self.lanes.contains(&l.id) {
continue;
}
rename_lanes.insert(l.id, LaneID(keep_lanes.len()));
keep_lanes.push(l);
}
m.lanes = keep_lanes;
let mut rename_intersections: HashMap<IntersectionID, IntersectionID> = HashMap::new();
let mut keep_intersections: Vec<Intersection> = Vec::new();
for i in m.intersections.drain(0..) {
if self.intersections.contains(&i.id) {
continue;
}
rename_intersections.insert(i.id, IntersectionID(keep_intersections.len()));
keep_intersections.push(i);
}
m.intersections = keep_intersections;
// Fix up IDs everywhere
for r in m.roads.iter_mut() {
r.id = rename_roads[&r.id];
for (l, _) in r.children_forwards.iter_mut() {
*l = rename_lanes[l];
}
for (l, _) in r.children_backwards.iter_mut() {
*l = rename_lanes[l];
}
r.src_i = rename_intersections[&r.src_i];
r.dst_i = rename_intersections[&r.dst_i];
}
for l in m.lanes.iter_mut() {
l.id = rename_lanes[&l.id];
l.parent = rename_roads[&l.parent];
l.src_i = rename_intersections[&l.src_i];
l.dst_i = rename_intersections[&l.dst_i];
}
for i in m.intersections.iter_mut() {
i.id = rename_intersections[&i.id];
assert!(i.turns.is_empty());
for l in i.incoming_lanes.iter_mut() {
*l = rename_lanes[l];
}
for l in i.outgoing_lanes.iter_mut() {
*l = rename_lanes[l];
}
i.roads = i.roads.iter().map(|r| rename_roads[r]).collect();
}
m
}
}

View File

@ -2,7 +2,6 @@ mod buildings;
mod bus_stops;
mod half_map;
mod initial;
mod merge_intersections;
mod old_merge_intersections;
mod parcels;
mod sidewalk_finder;