mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-26 16:02:23 +03:00
make intersection actually be a polygon now
This commit is contained in:
parent
dcad4a3c87
commit
ab6796d56c
@ -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.
|
||||
|
||||
|
@ -27,6 +27,7 @@ impl DebugPolygon {
|
||||
.map
|
||||
.get_i(id)
|
||||
.polygon
|
||||
.points()
|
||||
.iter()
|
||||
.map(|pt| Item::Point(*pt))
|
||||
.collect(),
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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>,
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user