mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-25 07:25:47 +03:00
introduce a proper closed polyline abstraction, sub it in
This commit is contained in:
parent
fe14e1709b
commit
3dfeae8b2c
@ -1,7 +1,7 @@
|
|||||||
use crate::helpers::{ColorScheme, ID};
|
use crate::helpers::{ColorScheme, ID};
|
||||||
use crate::render::{DrawCtx, DrawOptions, Renderable, OUTLINE_THICKNESS};
|
use crate::render::{DrawCtx, DrawOptions, Renderable, OUTLINE_THICKNESS};
|
||||||
use ezgui::{Color, GeomBatch, GfxCtx, Line, Text};
|
use ezgui::{Color, GeomBatch, GfxCtx, Line, Text};
|
||||||
use geom::{Circle, Distance, Line, PolyLine, Polygon, Pt2D};
|
use geom::{Circle, Distance, Line, Polygon, Pt2D, Ring};
|
||||||
use map_model::{Building, BuildingID, Map, LANE_THICKNESS};
|
use map_model::{Building, BuildingID, Map, LANE_THICKNESS};
|
||||||
|
|
||||||
pub struct DrawBuilding {
|
pub struct DrawBuilding {
|
||||||
@ -111,10 +111,7 @@ impl Renderable for DrawBuilding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_outline(&self, map: &Map) -> Polygon {
|
fn get_outline(&self, map: &Map) -> Polygon {
|
||||||
PolyLine::make_polygons_for_boundary(
|
Ring::new(map.get_b(self.id).polygon.points().clone()).make_polygons(OUTLINE_THICKNESS)
|
||||||
map.get_b(self.id).polygon.points().clone(),
|
|
||||||
OUTLINE_THICKNESS,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contains_pt(&self, pt: Pt2D, map: &Map) -> bool {
|
fn contains_pt(&self, pt: Pt2D, map: &Map) -> bool {
|
||||||
|
@ -3,7 +3,7 @@ use crate::render::{
|
|||||||
DrawCtx, DrawOptions, Renderable, EXTRA_SHAPE_POINT_RADIUS, EXTRA_SHAPE_THICKNESS,
|
DrawCtx, DrawOptions, Renderable, EXTRA_SHAPE_POINT_RADIUS, EXTRA_SHAPE_THICKNESS,
|
||||||
};
|
};
|
||||||
use ezgui::{Color, Drawable, GeomBatch, GfxCtx, Prerender};
|
use ezgui::{Color, Drawable, GeomBatch, GfxCtx, Prerender};
|
||||||
use geom::{Circle, FindClosest, GPSBounds, PolyLine, Polygon, Pt2D};
|
use geom::{Circle, FindClosest, GPSBounds, PolyLine, Polygon, Pt2D, Ring};
|
||||||
use kml::ExtraShape;
|
use kml::ExtraShape;
|
||||||
use map_model::{DirectedRoadID, Map, LANE_THICKNESS};
|
use map_model::{DirectedRoadID, Map, LANE_THICKNESS};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
@ -54,9 +54,9 @@ impl DrawExtraShape {
|
|||||||
} else if pts[0] == *pts.last().unwrap() {
|
} else if pts[0] == *pts.last().unwrap() {
|
||||||
// TODO Toggle between these better
|
// TODO Toggle between these better
|
||||||
//Polygon::new(&pts)
|
//Polygon::new(&pts)
|
||||||
PolyLine::make_polygons_for_boundary(pts, EXTRA_SHAPE_THICKNESS)
|
Ring::new(pts).make_polygons(EXTRA_SHAPE_THICKNESS)
|
||||||
} else {
|
} else {
|
||||||
PolyLine::make_polygons_for_boundary(pts, EXTRA_SHAPE_THICKNESS)
|
PolyLine::new(pts).make_polygons(EXTRA_SHAPE_THICKNESS)
|
||||||
};
|
};
|
||||||
let mut batch = GeomBatch::new();
|
let mut batch = GeomBatch::new();
|
||||||
batch.push(
|
batch.push(
|
||||||
|
@ -5,7 +5,7 @@ use crate::render::{
|
|||||||
};
|
};
|
||||||
use abstutil::Timer;
|
use abstutil::Timer;
|
||||||
use ezgui::{Color, Drawable, GeomBatch, GfxCtx, Prerender};
|
use ezgui::{Color, Drawable, GeomBatch, GfxCtx, Prerender};
|
||||||
use geom::{Angle, Distance, Duration, Line, PolyLine, Polygon, Pt2D, EPSILON_DIST};
|
use geom::{Angle, Distance, Duration, Line, PolyLine, Polygon, Pt2D, Ring, EPSILON_DIST};
|
||||||
use map_model::{
|
use map_model::{
|
||||||
Intersection, IntersectionID, IntersectionType, Map, Road, RoadWithStopSign, Turn, TurnID,
|
Intersection, IntersectionID, IntersectionType, Map, Road, RoadWithStopSign, Turn, TurnID,
|
||||||
TurnType, LANE_THICKNESS,
|
TurnType, LANE_THICKNESS,
|
||||||
@ -170,10 +170,7 @@ impl Renderable for DrawIntersection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_outline(&self, map: &Map) -> Polygon {
|
fn get_outline(&self, map: &Map) -> Polygon {
|
||||||
PolyLine::make_polygons_for_boundary(
|
Ring::new(map.get_i(self.id).polygon.points().clone()).make_polygons(OUTLINE_THICKNESS)
|
||||||
map.get_i(self.id).polygon.points().clone(),
|
|
||||||
OUTLINE_THICKNESS,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contains_pt(&self, pt: Pt2D, map: &Map) -> bool {
|
fn contains_pt(&self, pt: Pt2D, map: &Map) -> bool {
|
||||||
|
@ -9,6 +9,7 @@ mod line;
|
|||||||
mod polygon;
|
mod polygon;
|
||||||
mod polyline;
|
mod polyline;
|
||||||
mod pt;
|
mod pt;
|
||||||
|
mod ring;
|
||||||
mod speed;
|
mod speed;
|
||||||
|
|
||||||
pub use crate::angle::Angle;
|
pub use crate::angle::Angle;
|
||||||
@ -22,6 +23,7 @@ pub use crate::line::{InfiniteLine, Line};
|
|||||||
pub use crate::polygon::{Polygon, Triangle};
|
pub use crate::polygon::{Polygon, Triangle};
|
||||||
pub use crate::polyline::PolyLine;
|
pub use crate::polyline::PolyLine;
|
||||||
pub use crate::pt::{HashablePt2D, Pt2D};
|
pub use crate::pt::{HashablePt2D, Pt2D};
|
||||||
|
pub use crate::ring::Ring;
|
||||||
pub use crate::speed::Speed;
|
pub use crate::speed::Speed;
|
||||||
|
|
||||||
// About 0.4 inches... which is quite tiny on the scale of things. :)
|
// About 0.4 inches... which is quite tiny on the scale of things. :)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
Angle, Bounds, Distance, HashablePt2D, InfiniteLine, Line, Polygon, Pt2D, EPSILON_DIST,
|
Angle, Bounds, Distance, HashablePt2D, InfiniteLine, Line, Polygon, Pt2D, Ring, EPSILON_DIST,
|
||||||
};
|
};
|
||||||
use abstutil::Warn;
|
use abstutil::Warn;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
@ -27,7 +27,7 @@ impl PolyLine {
|
|||||||
// needs to be squished down, why, and how.
|
// needs to be squished down, why, and how.
|
||||||
if pts.windows(2).any(|pair| pair[0] == pair[1]) {
|
if pts.windows(2).any(|pair| pair[0] == pair[1]) {
|
||||||
panic!(
|
panic!(
|
||||||
"PL with total length {} and {} pts has ~dupe pts: {:?}",
|
"PL with total length {} and {} pts has ~dupe adjacent pts: {:?}",
|
||||||
length,
|
length,
|
||||||
pts.len(),
|
pts.len(),
|
||||||
pts
|
pts
|
||||||
@ -68,7 +68,7 @@ impl PolyLine {
|
|||||||
Some(result)
|
Some(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn make_polygons_for_boundary(pts: Vec<Pt2D>, thickness: Distance) -> Polygon {
|
pub(crate) fn make_polygons_for_boundary(pts: Vec<Pt2D>, thickness: Distance) -> Polygon {
|
||||||
// Points WILL repeat -- fast-path some stuff.
|
// Points WILL repeat -- fast-path some stuff.
|
||||||
let pl = PolyLine {
|
let pl = PolyLine {
|
||||||
pts,
|
pts,
|
||||||
@ -77,15 +77,6 @@ impl PolyLine {
|
|||||||
pl.make_polygons(thickness)
|
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(
|
pub fn to_thick_boundary(
|
||||||
&self,
|
&self,
|
||||||
self_width: Distance,
|
self_width: Distance,
|
||||||
@ -102,7 +93,7 @@ impl PolyLine {
|
|||||||
side1.extend(side2);
|
side1.extend(side2);
|
||||||
side1.push(side1[0]);
|
side1.push(side1[0]);
|
||||||
side1.dedup();
|
side1.dedup();
|
||||||
Some(PolyLine::make_polygons_for_boundary(side1, boundary_width))
|
Some(Ring::new(side1).make_polygons(boundary_width))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reversed(&self) -> PolyLine {
|
pub fn reversed(&self) -> PolyLine {
|
||||||
@ -534,17 +525,15 @@ impl PolyLine {
|
|||||||
let angle = slice.last_pt().angle_to(self.last_pt());
|
let angle = slice.last_pt().angle_to(self.last_pt());
|
||||||
Warn::ok(vec![
|
Warn::ok(vec![
|
||||||
p,
|
p,
|
||||||
PolyLine::make_polygons_for_boundary(
|
Ring::new(vec![
|
||||||
vec![
|
self.last_pt(),
|
||||||
self.last_pt(),
|
self.last_pt()
|
||||||
self.last_pt()
|
.project_away(head_size, angle.rotate_degs(-135.0)),
|
||||||
.project_away(head_size, angle.rotate_degs(-135.0)),
|
self.last_pt()
|
||||||
self.last_pt()
|
.project_away(head_size, angle.rotate_degs(135.0)),
|
||||||
.project_away(head_size, angle.rotate_degs(135.0)),
|
self.last_pt(),
|
||||||
self.last_pt(),
|
])
|
||||||
],
|
.make_polygons(outline_thickness),
|
||||||
outline_thickness,
|
|
||||||
),
|
|
||||||
])
|
])
|
||||||
} else {
|
} else {
|
||||||
Warn::warn(
|
Warn::warn(
|
||||||
|
54
geom/src/ring.rs
Normal file
54
geom/src/ring.rs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
use crate::{Distance, PolyLine, Polygon, Pt2D};
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
// Maybe a misnomer, but like a PolyLine, but closed.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct Ring {
|
||||||
|
// first equals last
|
||||||
|
pts: Vec<Pt2D>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ring {
|
||||||
|
pub fn new(pts: Vec<Pt2D>) -> Ring {
|
||||||
|
assert!(pts.len() >= 3);
|
||||||
|
assert_eq!(pts[0], *pts.last().unwrap());
|
||||||
|
|
||||||
|
// This checks no lines are too small. Could take the other approach and automatically
|
||||||
|
// squish down points here and make sure the final result is at least EPSILON_DIST.
|
||||||
|
// But probably better for the callers to do this -- they have better understanding of what
|
||||||
|
// needs to be squished down, why, and how.
|
||||||
|
if pts.windows(2).any(|pair| pair[0] == pair[1]) {
|
||||||
|
panic!("Ring has ~dupe adjacent pts: {:?}", pts);
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = Ring { pts };
|
||||||
|
|
||||||
|
let mut seen_pts = HashSet::new();
|
||||||
|
for pt in result.pts.iter().skip(1) {
|
||||||
|
seen_pts.insert(pt.to_hashable());
|
||||||
|
}
|
||||||
|
if seen_pts.len() != result.pts.len() - 1 {
|
||||||
|
panic!("Ring has repeat points: {}", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn make_polygons(&self, thickness: Distance) -> Polygon {
|
||||||
|
// TODO Has a weird corner. Use the polygon offset thing instead? And move the
|
||||||
|
// implementation here, ideally.
|
||||||
|
PolyLine::make_polygons_for_boundary(self.pts.clone(), thickness)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Ring {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
writeln!(f, "Ring::new(vec![")?;
|
||||||
|
for pt in &self.pts {
|
||||||
|
writeln!(f, " Pt2D::new({}, {}),", pt.x(), pt.y())?;
|
||||||
|
}
|
||||||
|
write!(f, "])")
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user