Skip to content

Commit

Permalink
Check invariants after every transformation. Use this to flush out a
Browse files Browse the repository at this point in the history
case where we need to remove orphaned intersections immediately, and
simplify the intersection geometry transform a bit. #136
  • Loading branch information
dabreegster committed Dec 26, 2022
1 parent 95f39bf commit a902134
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 22 deletions.
4 changes: 1 addition & 3 deletions osm2streets/src/geometry/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,7 @@ pub fn intersection_polygon(
roads.insert(r.id, r);
}

if roads.is_empty() {
bail!("{intersection_id} has no roads");
}
assert!(!roads.is_empty());

let results = Results {
intersection_id,
Expand Down
4 changes: 4 additions & 0 deletions osm2streets/src/transform/collapse_intersections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,8 @@ pub fn trim_deadends(streets: &mut StreetNetwork) {

// It's possible we need to do this in a fixed-point until there are no changes, but meh.
// Results look good so far.

// We may have created orphaned intersections. Clean up here.
// TODO Anywhere calling remove_road potentially causes this too
streets.intersections.retain(|_, i| !i.roads.is_empty());
}
24 changes: 8 additions & 16 deletions osm2streets/src/transform/intersection_geometry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ pub fn generate(streets: &mut StreetNetwork, timer: &mut Timer) {
streets.intersections.len(),
);
// It'd be nice to mutate in the loop, but the borrow checker won't let us
let mut remove_dangling_nodes = Vec::new();
let mut set_polygons = Vec::new();

// Set trim distances for all roads
Expand All @@ -36,19 +35,15 @@ pub fn generate(streets: &mut StreetNetwork, timer: &mut Timer) {
Err(err) => {
error!("Can't make intersection geometry for {}: {}", i.id, err);

// If we haven't removed disconnected roads, we may have dangling nodes around.
if let Some(r) = i.roads.iter().next() {
// Don't trim lines back at all
let road = &streets.roads[r];
let pt = if road.src_i == i.id {
road.center_line.first_pt()
} else {
road.center_line.last_pt()
};
set_polygons.push((i.id, Circle::new(pt, Distance::meters(3.0)).to_polygon()));
let r = i.roads[0];
// Don't trim lines back at all
let road = &streets.roads[&r];
let pt = if road.src_i == i.id {
road.center_line.first_pt()
} else {
remove_dangling_nodes.push(i.id);
}
road.center_line.last_pt()
};
set_polygons.push((i.id, Circle::new(pt, Distance::meters(3.0)).to_polygon()));
}
}
}
Expand All @@ -70,7 +65,4 @@ pub fn generate(streets: &mut StreetNetwork, timer: &mut Timer) {
for (i, polygon) in set_polygons {
streets.intersections.get_mut(&i).unwrap().polygon = polygon;
}
for i in remove_dangling_nodes {
streets.intersections.remove(&i).unwrap();
}
}
15 changes: 15 additions & 0 deletions osm2streets/src/transform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,21 @@ impl StreetNetwork {
timer.stop("simplify StreetNetwork");
}

/// Apply a sequence of transformations, but also check invariants after every step. More
/// expensive and may crash, but useful for testing.
pub fn apply_transformations_with_invariant_checks(
&mut self,
transformations: Vec<Transformation>,
timer: &mut Timer,
) {
timer.start("simplify StreetNetwork");
for transformation in transformations {
transformation.apply(self, timer);
self.check_invariants();
}
timer.stop("simplify StreetNetwork");
}

/// Apply a sequence of transformations, but also save a copy of the `StreetNetwork` before
/// each step. Some steps may also internally add debugging info.
pub fn apply_transformations_stepwise_debugging(
Expand Down
7 changes: 4 additions & 3 deletions tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ mod tests {
&mut timer,
)?;
street_network.check_invariants();
street_network
.apply_transformations(Transformation::standard_for_clipped_areas(), &mut timer);
street_network.check_invariants();
street_network.apply_transformations_with_invariant_checks(
Transformation::standard_for_clipped_areas(),
&mut timer,
);
street_network.save_to_geojson(format!("{path}/geometry.json"))?;

let road_network: RoadNetwork = street_network.into();
Expand Down

0 comments on commit a902134

Please sign in to comment.