mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-27 00:12:55 +03:00
oops, gigantic change trying to handle bad lane geometry
- debug points and triangles of lanes - disabled fixes for polylines with points that change angles by 180 and can be fixed by swapping them - organize intersection polygon code in different methods for the degenerate cases - try something new for degenerate-two's... fix road centers, then calculate intersection corners. it fixed a few spots!
This commit is contained in:
parent
7579cd9f7e
commit
aae021f478
@ -1,26 +1,70 @@
|
||||
use crate::objects::{Ctx, ID};
|
||||
use crate::plugins::{Plugin, PluginCtx};
|
||||
use ezgui::{GfxCtx, Key, Text};
|
||||
use geom::Pt2D;
|
||||
use geom::{Pt2D, Triangle};
|
||||
|
||||
enum Item {
|
||||
Point(Pt2D),
|
||||
Triangle(Triangle),
|
||||
}
|
||||
|
||||
pub struct DebugPolygon {
|
||||
pts: Vec<Pt2D>,
|
||||
current_pt: usize,
|
||||
items: Vec<Item>,
|
||||
current: usize,
|
||||
}
|
||||
|
||||
impl DebugPolygon {
|
||||
pub fn new(ctx: &mut PluginCtx) -> Option<DebugPolygon> {
|
||||
if let Some(ID::Intersection(id)) = ctx.primary.current_selection {
|
||||
match ctx.primary.current_selection {
|
||||
Some(ID::Intersection(id)) => {
|
||||
if ctx
|
||||
.input
|
||||
.contextual_action(Key::X, "debug intersection geometry")
|
||||
{
|
||||
return Some(DebugPolygon {
|
||||
pts: ctx.primary.map.get_i(id).polygon.clone(),
|
||||
current_pt: 0,
|
||||
items: ctx
|
||||
.primary
|
||||
.map
|
||||
.get_i(id)
|
||||
.polygon
|
||||
.iter()
|
||||
.map(|pt| Item::Point(*pt))
|
||||
.collect(),
|
||||
current: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
Some(ID::Lane(id)) => {
|
||||
if ctx.input.contextual_action(Key::X, "debug lane geometry") {
|
||||
return Some(DebugPolygon {
|
||||
items: ctx
|
||||
.primary
|
||||
.map
|
||||
.get_l(id)
|
||||
.lane_center_pts
|
||||
.points()
|
||||
.iter()
|
||||
.map(|pt| Item::Point(*pt))
|
||||
.collect(),
|
||||
current: 0,
|
||||
});
|
||||
} else if ctx.input.contextual_action(Key::F2, "debug lane triangles") {
|
||||
return Some(DebugPolygon {
|
||||
items: ctx
|
||||
.primary
|
||||
.draw_map
|
||||
.get_l(id)
|
||||
.polygon
|
||||
.triangles
|
||||
.iter()
|
||||
.map(|tri| Item::Triangle(tri.clone()))
|
||||
.collect(),
|
||||
current: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
@ -30,19 +74,26 @@ impl Plugin for DebugPolygon {
|
||||
ctx.input.set_mode("Polygon Debugger", &ctx.canvas);
|
||||
if ctx.input.modal_action("quit") {
|
||||
return false;
|
||||
} else if self.current_pt != self.pts.len() - 1 && ctx.input.modal_action("next point") {
|
||||
self.current_pt += 1;
|
||||
} else if self.current_pt != 0 && ctx.input.modal_action("prev point") {
|
||||
self.current_pt -= 1;
|
||||
} else if self.current != self.items.len() - 1 && ctx.input.modal_action("next item") {
|
||||
self.current += 1;
|
||||
} else if self.current != 0 && ctx.input.modal_action("prev item") {
|
||||
self.current -= 1;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn draw(&self, g: &mut GfxCtx, ctx: &Ctx) {
|
||||
ctx.canvas.draw_text_at(
|
||||
g,
|
||||
Text::from_line(format!("{}", self.current_pt)),
|
||||
self.pts[self.current_pt],
|
||||
);
|
||||
match self.items[self.current] {
|
||||
Item::Point(pt) => {
|
||||
ctx.canvas
|
||||
.draw_text_at(g, Text::from_line(format!("{}", self.current)), pt);
|
||||
}
|
||||
Item::Triangle(ref tri) => {
|
||||
for pt in &[tri.pt1, tri.pt2, tri.pt3] {
|
||||
ctx.canvas
|
||||
.draw_text_at(g, Text::from_line(format!("{}", self.current)), *pt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -174,8 +174,8 @@ impl<S: UIState> GUI<RenderingHints> for UI<S> {
|
||||
"Polygon Debugger",
|
||||
vec![
|
||||
(Key::Enter, "quit"),
|
||||
(Key::Dot, "next point"),
|
||||
(Key::Comma, "prev point"),
|
||||
(Key::Dot, "next item"),
|
||||
(Key::Comma, "prev item"),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
@ -153,6 +153,17 @@ pub enum Key {
|
||||
UpArrow,
|
||||
DownArrow,
|
||||
F1,
|
||||
F2,
|
||||
F3,
|
||||
F4,
|
||||
F5,
|
||||
F6,
|
||||
F7,
|
||||
F8,
|
||||
F9,
|
||||
F10,
|
||||
F11,
|
||||
F12,
|
||||
}
|
||||
|
||||
impl Key {
|
||||
@ -212,7 +223,18 @@ impl Key {
|
||||
| Key::RightArrow
|
||||
| Key::UpArrow
|
||||
| Key::DownArrow
|
||||
| Key::F1 => None,
|
||||
| Key::F1
|
||||
| Key::F2
|
||||
| Key::F3
|
||||
| Key::F4
|
||||
| Key::F5
|
||||
| Key::F6
|
||||
| Key::F7
|
||||
| Key::F8
|
||||
| Key::F9
|
||||
| Key::F10
|
||||
| Key::F11
|
||||
| Key::F12 => None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -230,6 +252,17 @@ impl Key {
|
||||
Key::UpArrow => "↑".to_string(),
|
||||
Key::DownArrow => "↓".to_string(),
|
||||
Key::F1 => "F1".to_string(),
|
||||
Key::F2 => "F2".to_string(),
|
||||
Key::F3 => "F3".to_string(),
|
||||
Key::F4 => "F4".to_string(),
|
||||
Key::F5 => "F5".to_string(),
|
||||
Key::F6 => "F6".to_string(),
|
||||
Key::F7 => "F7".to_string(),
|
||||
Key::F8 => "F8".to_string(),
|
||||
Key::F9 => "F9".to_string(),
|
||||
Key::F10 => "F10".to_string(),
|
||||
Key::F11 => "F11".to_string(),
|
||||
Key::F12 => "F12".to_string(),
|
||||
// These have to_char, but override here
|
||||
Key::Space => "Space".to_string(),
|
||||
_ => self.to_char(false).unwrap().to_string(),
|
||||
@ -298,6 +331,17 @@ impl Key {
|
||||
pi::Key::Up => Key::UpArrow,
|
||||
pi::Key::Down => Key::DownArrow,
|
||||
pi::Key::F1 => Key::F1,
|
||||
pi::Key::F2 => Key::F2,
|
||||
pi::Key::F3 => Key::F3,
|
||||
pi::Key::F4 => Key::F4,
|
||||
pi::Key::F5 => Key::F5,
|
||||
pi::Key::F6 => Key::F6,
|
||||
pi::Key::F7 => Key::F7,
|
||||
pi::Key::F8 => Key::F8,
|
||||
pi::Key::F9 => Key::F9,
|
||||
pi::Key::F10 => Key::F10,
|
||||
pi::Key::F11 => Key::F11,
|
||||
pi::Key::F12 => Key::F12,
|
||||
_ => {
|
||||
println!("Unknown piston key {:?}", key);
|
||||
return None;
|
||||
|
@ -36,6 +36,8 @@ impl Angle {
|
||||
self.normalized_radians().to_degrees()
|
||||
}
|
||||
|
||||
// Logically this returns [-180, 180], but keep in mind when we print this angle, it'll
|
||||
// normalize to be [0, 360].
|
||||
pub fn shortest_rotation_towards(self, other: Angle) -> Angle {
|
||||
// https://math.stackexchange.com/questions/110080/shortest-way-to-achieve-target-angle
|
||||
Angle::new_degs(
|
||||
|
@ -217,14 +217,19 @@ impl PolyLine {
|
||||
// Things to remember about shifting polylines: the length before and after probably don't
|
||||
// match up.
|
||||
pub fn shift_right(&self, width: f64) -> Option<PolyLine> {
|
||||
let result = self.shift_blindly_right(width);
|
||||
// TODO check if any non-adjacent line segments intersect
|
||||
Some(result)
|
||||
/*let mut result = self.shift_blindly_right(width);
|
||||
fix_angles(self, &mut result);
|
||||
check_angles(self, &result);
|
||||
Some(result)*/
|
||||
Some(self.shift_blindly_right(width))
|
||||
}
|
||||
|
||||
pub fn shift_left(&self, width: f64) -> Option<PolyLine> {
|
||||
let result = self.shift_blindly_left(width);
|
||||
Some(result)
|
||||
/*let mut result = self.shift_blindly_left(width);
|
||||
fix_angles(self, &mut result);
|
||||
check_angles(self, &result);
|
||||
Some(result)*/
|
||||
Some(self.shift_blindly_left(width))
|
||||
}
|
||||
|
||||
// Doesn't massage sharp twists into more points. For polygon rendering.
|
||||
@ -450,3 +455,40 @@ impl fmt::Display for PolyLine {
|
||||
result.push(first_pt);
|
||||
result.iter().map(|pair| [pair.0, pair.1]).collect()
|
||||
}*/
|
||||
|
||||
fn fix_angles(orig: &PolyLine, result: &mut PolyLine) {
|
||||
// Check that the angles roughly match up between the original and shifted line
|
||||
for (idx, (orig_l, shifted_l)) in orig.lines().iter().zip(result.lines().iter()).enumerate() {
|
||||
let orig_angle = orig_l.angle();
|
||||
let shifted_angle = shifted_l.angle();
|
||||
|
||||
let rot = orig_angle.shortest_rotation_towards(shifted_angle);
|
||||
if rot.normalized_degrees() > 10.0 && rot.normalized_degrees() < 359.0 {
|
||||
// When this happens, the rotation is usually right around 180 -- so try swapping
|
||||
// the points!
|
||||
/*println!(
|
||||
"Points changed angles from {} to {} (rot {})",
|
||||
orig_angle, shifted_angle, rot
|
||||
);*/
|
||||
result.pts.swap(idx, idx + 1);
|
||||
// TODO recalculate length, to be safe
|
||||
// Start the fixing over. Make sure we won't infinite loop...
|
||||
//return fix_angles(orig, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_angles(a: &PolyLine, b: &PolyLine) {
|
||||
for (orig_l, shifted_l) in a.lines().iter().zip(b.lines().iter()) {
|
||||
let orig_angle = orig_l.angle();
|
||||
let shifted_angle = shifted_l.angle();
|
||||
|
||||
let rot = orig_angle.shortest_rotation_towards(shifted_angle);
|
||||
if rot.normalized_degrees() > 10.0 && rot.normalized_degrees() < 359.0 {
|
||||
println!(
|
||||
"BAD! Points changed angles from {} to {} (rot {})",
|
||||
orig_angle, shifted_angle, rot
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ pub fn make_half_map(
|
||||
panic!("{:?} is orphaned!", i);
|
||||
}
|
||||
|
||||
i.polygon = make::intersections::initial_intersection_polygon(i, &mut m.roads);
|
||||
i.polygon = make::intersections::intersection_polygon(i, &mut m.roads);
|
||||
}
|
||||
|
||||
timer.start_iter("make lane geometry", m.lanes.len());
|
||||
|
@ -12,7 +12,7 @@ const DEGENERATE_INTERSECTION_HALF_LENGTH: si::Meter<f64> = si::Meter {
|
||||
|
||||
// The polygon should exist entirely within the thick bands around all original roads -- it just
|
||||
// carves up part of that space, doesn't reach past it.
|
||||
pub fn initial_intersection_polygon(i: &Intersection, roads: &mut Vec<Road>) -> Vec<Pt2D> {
|
||||
pub fn intersection_polygon(i: &Intersection, roads: &mut Vec<Road>) -> Vec<Pt2D> {
|
||||
// Turn all of the incident roads into two PolyLines (the "forwards" and "backwards" borders of
|
||||
// the road, if the roads were oriented to both be incoming to the intersection), both ending
|
||||
// at the intersection (which may be different points for merged intersections!), and the angle
|
||||
@ -45,10 +45,31 @@ pub fn initial_intersection_polygon(i: &Intersection, roads: &mut Vec<Road>) ->
|
||||
// we have to look at all the endpoints and sort by angle from the center of the points?
|
||||
lines.sort_by_key(|(_, angle, _, _)| angle.normalized_degrees() as i64);
|
||||
|
||||
// Special cases for degenerate intersections.
|
||||
let mut endpoints: Vec<Pt2D> = Vec::new();
|
||||
if lines.len() == 1 {
|
||||
// Dead-ends!
|
||||
let mut endpoints = if lines.len() == 1 {
|
||||
deadend(roads, i.id, &lines)
|
||||
} else if lines.len() == 2 {
|
||||
degenerate_twoway(roads, i.id, &lines)
|
||||
} else if let Some(pts) = make_new_polygon(roads, i.id, &lines) {
|
||||
pts
|
||||
} else {
|
||||
/*note(format!(
|
||||
"couldnt make new for {} with {} roads",
|
||||
i.id,
|
||||
lines.len()
|
||||
));*/
|
||||
make_old_polygon(i.id, &lines)
|
||||
};
|
||||
|
||||
// Close off the polygon
|
||||
endpoints.push(endpoints[0]);
|
||||
endpoints
|
||||
}
|
||||
|
||||
fn deadend(
|
||||
roads: &mut Vec<Road>,
|
||||
i: IntersectionID,
|
||||
lines: &Vec<(RoadID, Angle, PolyLine, PolyLine)>,
|
||||
) -> Vec<Pt2D> {
|
||||
let (id, _, pl_a, pl_b) = &lines[0];
|
||||
let pt1 = pl_a
|
||||
.reversed()
|
||||
@ -59,15 +80,8 @@ pub fn initial_intersection_polygon(i: &Intersection, roads: &mut Vec<Road>) ->
|
||||
.safe_dist_along(DEGENERATE_INTERSECTION_HALF_LENGTH * 2.0)
|
||||
.map(|(pt, _)| pt);
|
||||
if pt1.is_some() && pt2.is_some() {
|
||||
endpoints.extend(vec![
|
||||
pt1.unwrap(),
|
||||
pt2.unwrap(),
|
||||
pl_b.last_pt(),
|
||||
pl_a.last_pt(),
|
||||
]);
|
||||
|
||||
let mut r = &mut roads[id.0];
|
||||
if r.src_i == i.id {
|
||||
if r.src_i == i {
|
||||
r.center_pts = r
|
||||
.center_pts
|
||||
.slice(
|
||||
@ -84,47 +98,51 @@ pub fn initial_intersection_polygon(i: &Intersection, roads: &mut Vec<Road>) ->
|
||||
)
|
||||
.0;
|
||||
}
|
||||
|
||||
vec![pt1.unwrap(), pt2.unwrap(), pl_b.last_pt(), pl_a.last_pt()]
|
||||
} else {
|
||||
error!("{} is a dead-end for {}, which is too short to make degenerate intersection geometry", i.id, id);
|
||||
endpoints.extend(vec![pl_a.last_pt(), pl_b.last_pt()]);
|
||||
error!(
|
||||
"{} is a dead-end for {}, which is too short to make degenerate intersection geometry",
|
||||
i, id
|
||||
);
|
||||
vec![pl_a.last_pt(), pl_b.last_pt()]
|
||||
}
|
||||
} else if lines.len() == 2 {
|
||||
}
|
||||
|
||||
fn degenerate_twoway(
|
||||
roads: &mut Vec<Road>,
|
||||
i: IntersectionID,
|
||||
lines: &Vec<(RoadID, Angle, PolyLine, PolyLine)>,
|
||||
) -> Vec<Pt2D> {
|
||||
let (id1, _, pl1_a, pl1_b) = &lines[0];
|
||||
let (id2, _, pl2_a, pl2_b) = &lines[1];
|
||||
if pl1_a.length() >= DEGENERATE_INTERSECTION_HALF_LENGTH
|
||||
&& pl1_b.length() >= DEGENERATE_INTERSECTION_HALF_LENGTH
|
||||
&& pl2_a.length() >= DEGENERATE_INTERSECTION_HALF_LENGTH
|
||||
&& pl2_b.length() >= DEGENERATE_INTERSECTION_HALF_LENGTH
|
||||
{
|
||||
// We could also add in the last points of each line, but this doesn't actually look
|
||||
// great when widths of the two oads are different.
|
||||
endpoints.extend(vec![
|
||||
pl1_a
|
||||
.reversed()
|
||||
.dist_along(DEGENERATE_INTERSECTION_HALF_LENGTH)
|
||||
.0,
|
||||
pl1_b
|
||||
.reversed()
|
||||
.dist_along(DEGENERATE_INTERSECTION_HALF_LENGTH)
|
||||
.0,
|
||||
pl2_a
|
||||
.reversed()
|
||||
.dist_along(DEGENERATE_INTERSECTION_HALF_LENGTH)
|
||||
.0,
|
||||
pl2_b
|
||||
.reversed()
|
||||
.dist_along(DEGENERATE_INTERSECTION_HALF_LENGTH)
|
||||
.0,
|
||||
]);
|
||||
endpoints.dedup();
|
||||
|
||||
if roads[id1.0].center_pts.length() >= DEGENERATE_INTERSECTION_HALF_LENGTH
|
||||
&& roads[id2.0].center_pts.length() >= DEGENERATE_INTERSECTION_HALF_LENGTH
|
||||
{
|
||||
// Why fix center pts and then re-shift out, instead of use the pl1_a and friends? because
|
||||
// dist_along on shifted polylines is NOT equivalent.
|
||||
let mut endpoints = Vec::new();
|
||||
for road_id in &[id1, id2] {
|
||||
let mut r = &mut roads[road_id.0];
|
||||
if r.src_i == i.id {
|
||||
if r.src_i == i {
|
||||
r.center_pts = r
|
||||
.center_pts
|
||||
.slice(DEGENERATE_INTERSECTION_HALF_LENGTH, r.center_pts.length())
|
||||
.0;
|
||||
|
||||
endpoints.push(
|
||||
r.center_pts
|
||||
.shift_left(LANE_THICKNESS * (r.children_backwards.len() as f64))
|
||||
.unwrap()
|
||||
.first_pt(),
|
||||
);
|
||||
endpoints.push(
|
||||
r.center_pts
|
||||
.shift_right(LANE_THICKNESS * (r.children_forwards.len() as f64))
|
||||
.unwrap()
|
||||
.first_pt(),
|
||||
);
|
||||
} else {
|
||||
r.center_pts = r
|
||||
.center_pts
|
||||
@ -133,84 +151,30 @@ pub fn initial_intersection_polygon(i: &Intersection, roads: &mut Vec<Road>) ->
|
||||
r.center_pts.length() - DEGENERATE_INTERSECTION_HALF_LENGTH,
|
||||
)
|
||||
.0;
|
||||
endpoints.push(
|
||||
r.center_pts
|
||||
.shift_right(LANE_THICKNESS * (r.children_forwards.len() as f64))
|
||||
.unwrap()
|
||||
.last_pt(),
|
||||
);
|
||||
endpoints.push(
|
||||
r.center_pts
|
||||
.shift_left(LANE_THICKNESS * (r.children_backwards.len() as f64))
|
||||
.unwrap()
|
||||
.last_pt(),
|
||||
);
|
||||
}
|
||||
}
|
||||
endpoints
|
||||
} else {
|
||||
error!("{} has only {} and {}, some of which are too short to make degenerate intersection geometry", i.id, id1, id2);
|
||||
endpoints.extend(vec![
|
||||
error!("{} has only {} and {}, some of which are too short to make degenerate intersection geometry", i, id1, id2);
|
||||
vec![
|
||||
pl1_a.last_pt(),
|
||||
pl1_b.last_pt(),
|
||||
pl2_a.last_pt(),
|
||||
pl2_b.last_pt(),
|
||||
]);
|
||||
]
|
||||
}
|
||||
} else {
|
||||
if let Some(pts) = make_new_polygon(roads, i.id, &lines) {
|
||||
endpoints.extend(pts);
|
||||
} else {
|
||||
/*note(format!(
|
||||
"couldnt make new for {} with {} roads",
|
||||
i.id,
|
||||
lines.len()
|
||||
));*/
|
||||
|
||||
// Look at adjacent pairs of these polylines...
|
||||
for idx1 in 0..lines.len() as isize {
|
||||
let idx2 = idx1 + 1;
|
||||
|
||||
let (id1, _, _, pl1) = wraparound_get(&lines, idx1);
|
||||
let (id2, _, pl2, _) = wraparound_get(&lines, idx2);
|
||||
|
||||
// If the two lines are too close in angle, they'll either not hit or even if they do, it
|
||||
// won't be right.
|
||||
let angle_diff = (pl1.last_line().angle().opposite().normalized_degrees()
|
||||
- pl2.last_line().angle().normalized_degrees())
|
||||
.abs();
|
||||
|
||||
// TODO A tuning challenge. :)
|
||||
if angle_diff > 15.0 {
|
||||
// The easy case!
|
||||
if let Some((hit, _)) = pl1.intersection(&pl2) {
|
||||
endpoints.push(hit);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let mut ok = true;
|
||||
|
||||
// Use the next adjacent road, doing line to line segment intersection instead.
|
||||
let inf_line1 = wraparound_get(&lines, idx1 - 1).3.last_line();
|
||||
if let Some(hit) = pl1.intersection_infinite_line(inf_line1) {
|
||||
endpoints.push(hit);
|
||||
} else {
|
||||
endpoints.push(pl1.last_pt());
|
||||
ok = false;
|
||||
}
|
||||
|
||||
let inf_line2 = wraparound_get(&lines, idx2 + 1).2.last_line();
|
||||
if let Some(hit) = pl2.intersection_infinite_line(inf_line2) {
|
||||
endpoints.push(hit);
|
||||
} else {
|
||||
endpoints.push(pl2.last_pt());
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if !ok {
|
||||
warn!(
|
||||
"No hit btwn {} and {}, for {} with {} incident roads",
|
||||
id1,
|
||||
id2,
|
||||
i.id,
|
||||
lines.len()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close off the polygon
|
||||
endpoints.push(endpoints[0]);
|
||||
endpoints
|
||||
}
|
||||
|
||||
fn make_new_polygon(
|
||||
@ -337,6 +301,65 @@ fn make_new_polygon(
|
||||
Some(approx_dedupe(endpoints))
|
||||
}
|
||||
|
||||
fn make_old_polygon(
|
||||
i: IntersectionID,
|
||||
lines: &Vec<(RoadID, Angle, PolyLine, PolyLine)>,
|
||||
) -> Vec<Pt2D> {
|
||||
let mut endpoints = Vec::new();
|
||||
// Look at adjacent pairs of these polylines...
|
||||
for idx1 in 0..lines.len() as isize {
|
||||
let idx2 = idx1 + 1;
|
||||
|
||||
let (id1, _, _, pl1) = wraparound_get(&lines, idx1);
|
||||
let (id2, _, pl2, _) = wraparound_get(&lines, idx2);
|
||||
|
||||
// If the two lines are too close in angle, they'll either not hit or even if they do, it
|
||||
// won't be right.
|
||||
let angle_diff = (pl1.last_line().angle().opposite().normalized_degrees()
|
||||
- pl2.last_line().angle().normalized_degrees())
|
||||
.abs();
|
||||
|
||||
// TODO A tuning challenge. :)
|
||||
if angle_diff > 15.0 {
|
||||
// The easy case!
|
||||
if let Some((hit, _)) = pl1.intersection(&pl2) {
|
||||
endpoints.push(hit);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let mut ok = true;
|
||||
|
||||
// Use the next adjacent road, doing line to line segment intersection instead.
|
||||
let inf_line1 = wraparound_get(&lines, idx1 - 1).3.last_line();
|
||||
if let Some(hit) = pl1.intersection_infinite_line(inf_line1) {
|
||||
endpoints.push(hit);
|
||||
} else {
|
||||
endpoints.push(pl1.last_pt());
|
||||
ok = false;
|
||||
}
|
||||
|
||||
let inf_line2 = wraparound_get(&lines, idx2 + 1).2.last_line();
|
||||
if let Some(hit) = pl2.intersection_infinite_line(inf_line2) {
|
||||
endpoints.push(hit);
|
||||
} else {
|
||||
endpoints.push(pl2.last_pt());
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if !ok {
|
||||
warn!(
|
||||
"No hit btwn {} and {}, for {} with {} incident roads",
|
||||
id1,
|
||||
id2,
|
||||
i,
|
||||
lines.len()
|
||||
);
|
||||
}
|
||||
}
|
||||
endpoints
|
||||
}
|
||||
|
||||
// Temporary until Pt2D has proper resolution.
|
||||
fn approx_dedupe(pts: Vec<Pt2D>) -> Vec<Pt2D> {
|
||||
let mut result: Vec<Pt2D> = Vec::new();
|
||||
|
Loading…
Reference in New Issue
Block a user