experimentally try finding intersection polygon by naively intersecting thick road polygons.

This commit is contained in:
Dustin Carlino 2019-05-17 13:27:30 -07:00
parent de51b1c154
commit 4c1e9b41c1
7 changed files with 151 additions and 16 deletions

View File

@ -7,6 +7,7 @@ edition = "2018"
[dependencies]
aabb-quadtree = "0.1.0"
abstutil = { path = "../abstutil" }
clipping = "0.1.1"
counter = "0.4.3"
derive-new = "0.5.6"
ezgui = { path = "../ezgui" }

View File

@ -11,11 +11,13 @@ use crate::helpers::ID;
use crate::render::DrawOptions;
use crate::ui::{ShowLayers, ShowObject, UI};
use abstutil::Timer;
use clipping::CPolygon;
use ezgui::{
Color, EventCtx, EventLoopMode, GfxCtx, InputResult, Key, ModalMenu, ScrollingMenu, Text,
TextBox, Wizard,
};
use map_model::RoadID;
use geom::{Polygon, Pt2D};
use map_model::{IntersectionID, Map, RoadID};
use std::collections::HashSet;
pub struct DebugMode {
@ -23,6 +25,7 @@ pub struct DebugMode {
common: CommonState,
chokepoints: Option<chokepoints::ChokepointsFinder>,
show_original_roads: HashSet<RoadID>,
intersection_geom: HashSet<IntersectionID>,
connected_roads: connected_roads::ShowConnectedRoads,
objects: objects::ObjectDebugger,
hidden: HashSet<ID>,
@ -45,6 +48,7 @@ impl DebugMode {
common: CommonState::new(),
chokepoints: None,
show_original_roads: HashSet::new(),
intersection_geom: HashSet::new(),
connected_roads: connected_roads::ShowConnectedRoads::new(),
objects: objects::ObjectDebugger::new(),
hidden: HashSet::new(),
@ -67,6 +71,7 @@ impl DebugMode {
(Some(Key::Escape), "quit"),
(Some(Key::C), "show/hide chokepoints"),
(Some(Key::O), "clear original roads shown"),
(Some(Key::G), "clear intersection geometry"),
(Some(Key::H), "unhide everything"),
(Some(Key::Num1), "show/hide buildings"),
(Some(Key::Num2), "show/hide intersections"),
@ -111,6 +116,12 @@ impl DebugMode {
mode.show_original_roads.len()
));
}
if !mode.intersection_geom.is_empty() {
txt.add_line(format!(
"Showing {} attempts at intersection geometry",
mode.intersection_geom.len()
));
}
if !mode.hidden.is_empty() {
txt.add_line(format!("Hiding {} things", mode.hidden.len()));
}
@ -151,6 +162,13 @@ impl DebugMode {
mode.show_original_roads.clear();
}
}
if !mode.intersection_geom.is_empty()
&& state.ui.primary.current_selection.is_none()
{
if menu.action("clear intersection geometry") {
mode.intersection_geom.clear();
}
}
match state.ui.primary.current_selection {
Some(ID::Lane(_))
| Some(ID::Intersection(_))
@ -177,13 +195,25 @@ impl DebugMode {
if let Some(ID::Lane(l)) = state.ui.primary.current_selection {
let id = state.ui.primary.map.get_l(l).parent;
if ctx.input.contextual_action(
Key::V,
&format!("show original geometry of {:?}", id),
) {
if !mode.show_original_roads.contains(&id)
&& ctx.input.contextual_action(
Key::V,
&format!("show original geometry of {}", id),
)
{
mode.show_original_roads.insert(id);
}
}
if let Some(ID::Intersection(i)) = state.ui.primary.current_selection {
if !mode.intersection_geom.contains(&i)
&& ctx.input.contextual_action(
Key::G,
&format!("recalculate intersection geometry of {}", i),
)
{
mode.intersection_geom.insert(i);
}
}
mode.connected_roads.event(ctx, &state.ui);
mode.objects.event(ctx, &state.ui);
mode.neighborhood_summary.event(&state.ui, menu);
@ -344,6 +374,9 @@ impl DebugMode {
);
}
}
for id in &mode.intersection_geom {
recalc_intersection_geom(*id, &state.ui.primary.map, g);
}
mode.objects.draw(g, &state.ui);
mode.neighborhood_summary.draw(g);
@ -396,3 +429,73 @@ impl ShowObject for DebugMode {
&self.layers
}
}
fn recalc_intersection_geom(id: IntersectionID, map: &Map, g: &mut GfxCtx) {
let i = map.get_i(id);
let mut all_polys = Vec::new();
for r in &i.roads {
let (pl, width) = map.get_r(*r).get_thick_polyline(true).unwrap();
// This is different than pl.make_polygons(width) because of the order of the points!!!
let poly = Polygon::new(&pl.to_thick_boundary_pts(width));
g.draw_polygon(Color::RED.alpha(0.4), &poly);
all_polys.push(poly);
}
let mut all_pieces = Vec::new();
for (idx1, p1) in all_polys.iter().enumerate() {
for (idx2, p2) in all_polys.iter().enumerate() {
if idx1 != idx2 {
all_pieces.extend(intersection(p1, p2));
}
}
}
for p in &all_pieces {
g.draw_polygon(Color::BLUE.alpha(0.4), &p);
}
if false {
if let Some(final_poly) = union(&all_pieces) {
g.draw_polygon(Color::GREEN.alpha(0.4), &final_poly);
}
}
}
fn poly_to_cpoly(poly: &Polygon) -> CPolygon {
let mut pts: Vec<[f64; 2]> = poly.points().iter().map(|pt| [pt.x(), pt.y()]).collect();
if pts[0] == *pts.last().unwrap() {
pts.pop();
}
CPolygon::from_vec(&pts)
}
fn cpoly_to_poly(raw_pts: Vec<[f64; 2]>) -> Polygon {
let mut pts: Vec<Pt2D> = raw_pts
.into_iter()
.map(|pt| Pt2D::new(pt[0], pt[1]))
.collect();
if pts[0] != *pts.last().unwrap() {
pts.push(pts[0]);
}
Polygon::new(&pts)
}
fn intersection(p1: &Polygon, p2: &Polygon) -> Vec<Polygon> {
let mut cp1 = poly_to_cpoly(p1);
let mut cp2 = poly_to_cpoly(p2);
cp1.intersection(&mut cp2)
.into_iter()
.map(|pts| cpoly_to_poly(pts))
.collect()
}
fn union(polys: &Vec<Polygon>) -> Option<Polygon> {
let mut result = poly_to_cpoly(&polys[0]);
for p in polys.iter().skip(1) {
let output = result.union(&mut poly_to_cpoly(p));
if output.len() != 1 {
println!("Argh, got {} pieces from union", output.len());
return None;
}
result = CPolygon::from_vec(&output[0]);
}
Some(cpoly_to_poly(result.points()))
}

View File

@ -198,10 +198,7 @@ impl ID {
pub fn canonical_point(&self, primary: &PerMapUI) -> Option<Pt2D> {
match *self {
ID::Road(id) => primary
.map
.maybe_get_r(id)
.map(|r| r.original_center_pts.first_pt()),
ID::Road(id) => primary.map.maybe_get_r(id).map(|r| r.center_pts.first_pt()),
ID::Lane(id) => primary.map.maybe_get_l(id).map(|l| l.first_pt()),
ID::Intersection(id) => primary.map.maybe_get_i(id).map(|i| i.point),
ID::Turn(id) => primary.map.maybe_get_i(id.parent).map(|i| i.point),

View File

@ -36,7 +36,7 @@ impl Renderable for DrawRoad {
}
fn get_outline(&self, map: &Map) -> Polygon {
let (pl, width) = map.get_r(self.id).get_thick_polyline().unwrap();
let (pl, width) = map.get_r(self.id).get_thick_polyline(false).unwrap();
pl.to_thick_boundary(width, OUTLINE_THICKNESS)
.unwrap_or_else(|| map.get_r(self.id).get_thick_polygon().unwrap())
}

View File

@ -1,5 +1,6 @@
use crate::{Bounds, Distance, HashablePt2D, Pt2D};
use serde_derive::{Deserialize, Serialize};
use std::fmt;
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Polygon {
@ -120,6 +121,8 @@ impl Polygon {
}
}
// The order of these points depends on the constructor! The first and last point may or may
// not match. Polygons constructed from PolyLines will have a very weird order.
pub fn points(&self) -> &Vec<Pt2D> {
&self.points
}
@ -149,6 +152,25 @@ impl Polygon {
}
}
impl fmt::Display for Polygon {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(
f,
"Polygon with {} points and {} indices",
self.points.len(),
self.indices.len()
)?;
for (idx, pt) in self.points.iter().enumerate() {
writeln!(f, " {}: {}", idx, pt)?;
}
write!(f, "Indices: [")?;
for slice in self.indices.chunks_exact(3) {
write!(f, "({}, {}, {}), ", slice[0], slice[1], slice[2])?;
}
writeln!(f, "]")
}
}
#[derive(Clone, Debug)]
pub struct Triangle {
pub pt1: Pt2D,

View File

@ -59,6 +59,15 @@ impl PolyLine {
pl.make_polygons(thickness)
}
pub fn to_thick_boundary_pts(&self, width: Distance) -> Vec<Pt2D> {
let mut side1 = self.shift_with_sharp_angles(width / 2.0);
let mut side2 = self.shift_with_sharp_angles(-width / 2.0);
side2.reverse();
side1.extend(side2);
side1.push(side1[0]);
side1
}
pub fn to_thick_boundary(
&self,
self_width: Distance,

View File

@ -291,23 +291,26 @@ impl Road {
search.iter().find(|(_, t)| lt == *t).map(|(id, _)| *id)
}
pub fn get_thick_polyline(&self) -> Warn<(PolyLine, Distance)> {
pub fn get_thick_polyline(&self, orig_pts: bool) -> Warn<(PolyLine, Distance)> {
let width_right = (self.children_forwards.len() as f64) * LANE_THICKNESS;
let width_left = (self.children_backwards.len() as f64) * LANE_THICKNESS;
let total_width = width_right + width_left;
let pts = if orig_pts {
&self.original_center_pts
} else {
&self.center_pts
};
if width_right >= width_left {
self.center_pts
.shift_right((width_right - width_left) / 2.0)
pts.shift_right((width_right - width_left) / 2.0)
.map(|pl| (pl, total_width))
} else {
self.center_pts
.shift_left((width_left - width_right) / 2.0)
pts.shift_left((width_left - width_right) / 2.0)
.map(|pl| (pl, total_width))
}
}
pub fn get_thick_polygon(&self) -> Warn<Polygon> {
self.get_thick_polyline()
self.get_thick_polyline(false)
.map(|(pl, width)| pl.make_polygons(width))
}