Skip to content

Commit

Permalink
Special-case geometry for degenerate intersections. #136
Browse files Browse the repository at this point in the history
  • Loading branch information
dabreegster committed Dec 7, 2022
1 parent 844740c commit da8a221
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 12 deletions.
3 changes: 3 additions & 0 deletions osm2streets/src/geometry/algorithm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ pub fn intersection_polygon(

if road_lines.len() == 1 {
return super::terminus::terminus(results, roads.into_values().next().unwrap());
} else if road_lines.len() == 2 {
let mut iter = roads.into_values();
return super::degenerate::degenerate(results, iter.next().unwrap(), iter.next().unwrap());
}

if !trim_roads_for_merging.is_empty() {
Expand Down
53 changes: 53 additions & 0 deletions osm2streets/src/geometry/degenerate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use anyhow::Result;
use geom::{Distance, Ring};

use super::Results;
use crate::InputRoad;

/// For intersections between exactly 2 roads, just trim back a bit.
pub(crate) fn degenerate(
mut results: Results,
road1: InputRoad,
road2: InputRoad,
) -> Result<Results> {
// Make the intersection shape roughly square, relative to the thinner road
let intersection_half_len = Distance::meters(1.0);
let min_road_len = 2.0 * intersection_half_len;

// Make both roads point at the intersection, to simplify logic below
let mut center1 = road1.center_line_pointed_at(results.intersection_id);
let mut center2 = road2.center_line_pointed_at(results.intersection_id);

// If either road is too short, just fail outright. What else should we do?
// TODO Also, if we haven't trimmed the other side yet, we don't have the full picture
if center1.length() < min_road_len || center2.length() < min_road_len {
bail!("Road is too short to trim for a degenerate intersection");
}

// Trim each.
center1 = center1.exact_slice(Distance::ZERO, center1.length() - intersection_half_len);
center2 = center2.exact_slice(Distance::ZERO, center2.length() - intersection_half_len);

// Make the square polygon
let mut endpts = vec![
center1.shift_left(road1.half_width())?.last_pt(),
center2.shift_right(road2.half_width())?.last_pt(),
center2.shift_left(road2.half_width())?.last_pt(),
center1.shift_right(road1.half_width())?.last_pt(),
];
endpts.push(endpts[0]);

results.intersection_polygon = Ring::deduping_new(endpts)?.into_polygon();

// Fix orientation if needed
if road1.src_i == results.intersection_id {
center1 = center1.reversed();
}
if road2.src_i == results.intersection_id {
center2 = center2.reversed();
}

results.trimmed_center_pts.insert(road1.id, center1);
results.trimmed_center_pts.insert(road2.id, center2);
Ok(results)
}
10 changes: 10 additions & 0 deletions osm2streets/src/geometry/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
//! I wrote a novella about this: <https://a-b-street.github.io/docs/tech/map/geometry/index.html>
mod algorithm;
mod degenerate;
mod on_off_ramp;
mod terminus;

Expand Down Expand Up @@ -38,6 +39,15 @@ impl InputRoad {
pub fn half_width(&self) -> Distance {
self.total_width / 2.0
}

pub fn center_line_pointed_at(&self, i: IntersectionID) -> PolyLine {
if self.dst_i == i {
self.center_line.clone()
} else {
assert_eq!(self.src_i, i);
self.center_line.reversed()
}
}
}

#[derive(Clone)]
Expand Down
7 changes: 1 addition & 6 deletions osm2streets/src/geometry/on_off_ramp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,11 @@ pub(crate) fn on_off_ramp(
// TODO Use this abstraction for all the code here?
for r in road_lines {
let road = &roads[&r.id];
let center = if road.dst_i == results.intersection_id {
road.center_line.clone()
} else {
road.center_line.reversed()
};
pieces.push(Piece {
id: road.id,
dst_i: road.dst_i,
left: r.back_pl,
center,
center: road.center_line_pointed_at(results.intersection_id),
right: r.fwd_pl,
});
}
Expand Down
8 changes: 2 additions & 6 deletions osm2streets/src/geometry/terminus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,8 @@ use crate::InputRoad;

/// For dead-ends and map edges, just use a piece of the road as the intersection.
pub(crate) fn terminus(mut results: Results, road: InputRoad) -> Result<Results> {
// Point at the intersection so we can be simple below
let mut center = if road.dst_i == results.intersection_id {
road.center_line.clone()
} else {
road.center_line.reversed()
};
// Point at the intersection, to simplify logic below
let mut center = road.center_line_pointed_at(results.intersection_id);

// Make the intersection roughly square
let intersection_len = road.total_width;
Expand Down
2 changes: 2 additions & 0 deletions osm2streets/src/intersection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ pub struct Intersection {
/// StreetNetwork; roads and intersections get merged and deleted.
pub point: Pt2D,
/// This will be a placeholder until `Transformation::GenerateIntersectionGeometry` runs.
///
/// TODO Consistently make this clockwise.
pub polygon: Polygon,
pub kind: IntersectionKind,
pub control: IntersectionControl,
Expand Down

0 comments on commit da8a221

Please sign in to comment.