mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-25 15:33:44 +03:00
experimentally try finding intersection polygon by naively intersecting thick road polygons.
This commit is contained in:
parent
de51b1c154
commit
4c1e9b41c1
@ -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" }
|
||||
|
@ -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()))
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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())
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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))
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user