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::render::{DrawCtx, DrawOptions, Renderable, OUTLINE_THICKNESS};
|
||||
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};
|
||||
|
||||
pub struct DrawBuilding {
|
||||
@ -111,10 +111,7 @@ impl Renderable for DrawBuilding {
|
||||
}
|
||||
|
||||
fn get_outline(&self, map: &Map) -> Polygon {
|
||||
PolyLine::make_polygons_for_boundary(
|
||||
map.get_b(self.id).polygon.points().clone(),
|
||||
OUTLINE_THICKNESS,
|
||||
)
|
||||
Ring::new(map.get_b(self.id).polygon.points().clone()).make_polygons(OUTLINE_THICKNESS)
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
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 map_model::{DirectedRoadID, Map, LANE_THICKNESS};
|
||||
use std::collections::BTreeMap;
|
||||
@ -54,9 +54,9 @@ impl DrawExtraShape {
|
||||
} else if pts[0] == *pts.last().unwrap() {
|
||||
// TODO Toggle between these better
|
||||
//Polygon::new(&pts)
|
||||
PolyLine::make_polygons_for_boundary(pts, EXTRA_SHAPE_THICKNESS)
|
||||
Ring::new(pts).make_polygons(EXTRA_SHAPE_THICKNESS)
|
||||
} else {
|
||||
PolyLine::make_polygons_for_boundary(pts, EXTRA_SHAPE_THICKNESS)
|
||||
PolyLine::new(pts).make_polygons(EXTRA_SHAPE_THICKNESS)
|
||||
};
|
||||
let mut batch = GeomBatch::new();
|
||||
batch.push(
|
||||
|
@ -5,7 +5,7 @@ use crate::render::{
|
||||
};
|
||||
use abstutil::Timer;
|
||||
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::{
|
||||
Intersection, IntersectionID, IntersectionType, Map, Road, RoadWithStopSign, Turn, TurnID,
|
||||
TurnType, LANE_THICKNESS,
|
||||
@ -170,10 +170,7 @@ impl Renderable for DrawIntersection {
|
||||
}
|
||||
|
||||
fn get_outline(&self, map: &Map) -> Polygon {
|
||||
PolyLine::make_polygons_for_boundary(
|
||||
map.get_i(self.id).polygon.points().clone(),
|
||||
OUTLINE_THICKNESS,
|
||||
)
|
||||
Ring::new(map.get_i(self.id).polygon.points().clone()).make_polygons(OUTLINE_THICKNESS)
|
||||
}
|
||||
|
||||
fn contains_pt(&self, pt: Pt2D, map: &Map) -> bool {
|
||||
|
@ -9,6 +9,7 @@ mod line;
|
||||
mod polygon;
|
||||
mod polyline;
|
||||
mod pt;
|
||||
mod ring;
|
||||
mod speed;
|
||||
|
||||
pub use crate::angle::Angle;
|
||||
@ -22,6 +23,7 @@ pub use crate::line::{InfiniteLine, Line};
|
||||
pub use crate::polygon::{Polygon, Triangle};
|
||||
pub use crate::polyline::PolyLine;
|
||||
pub use crate::pt::{HashablePt2D, Pt2D};
|
||||
pub use crate::ring::Ring;
|
||||
pub use crate::speed::Speed;
|
||||
|
||||
// About 0.4 inches... which is quite tiny on the scale of things. :)
|
||||
|
@ -1,5 +1,5 @@
|
||||
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 serde_derive::{Deserialize, Serialize};
|
||||
@ -27,7 +27,7 @@ impl PolyLine {
|
||||
// needs to be squished down, why, and how.
|
||||
if pts.windows(2).any(|pair| pair[0] == pair[1]) {
|
||||
panic!(
|
||||
"PL with total length {} and {} pts has ~dupe pts: {:?}",
|
||||
"PL with total length {} and {} pts has ~dupe adjacent pts: {:?}",
|
||||
length,
|
||||
pts.len(),
|
||||
pts
|
||||
@ -68,7 +68,7 @@ impl PolyLine {
|
||||
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.
|
||||
let pl = PolyLine {
|
||||
pts,
|
||||
@ -77,15 +77,6 @@ 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,
|
||||
@ -102,7 +93,7 @@ impl PolyLine {
|
||||
side1.extend(side2);
|
||||
side1.push(side1[0]);
|
||||
side1.dedup();
|
||||
Some(PolyLine::make_polygons_for_boundary(side1, boundary_width))
|
||||
Some(Ring::new(side1).make_polygons(boundary_width))
|
||||
}
|
||||
|
||||
pub fn reversed(&self) -> PolyLine {
|
||||
@ -534,17 +525,15 @@ impl PolyLine {
|
||||
let angle = slice.last_pt().angle_to(self.last_pt());
|
||||
Warn::ok(vec![
|
||||
p,
|
||||
PolyLine::make_polygons_for_boundary(
|
||||
vec![
|
||||
self.last_pt(),
|
||||
self.last_pt()
|
||||
.project_away(head_size, angle.rotate_degs(-135.0)),
|
||||
self.last_pt()
|
||||
.project_away(head_size, angle.rotate_degs(135.0)),
|
||||
self.last_pt(),
|
||||
],
|
||||
outline_thickness,
|
||||
),
|
||||
Ring::new(vec![
|
||||
self.last_pt(),
|
||||
self.last_pt()
|
||||
.project_away(head_size, angle.rotate_degs(-135.0)),
|
||||
self.last_pt()
|
||||
.project_away(head_size, angle.rotate_degs(135.0)),
|
||||
self.last_pt(),
|
||||
])
|
||||
.make_polygons(outline_thickness),
|
||||
])
|
||||
} else {
|
||||
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