Skip to content

Commit

Permalink
Trace a large block around sidewalks and crossings only
Browse files Browse the repository at this point in the history
  • Loading branch information
dabreegster committed Mar 29, 2024
1 parent 5b53137 commit 338660d
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 17 deletions.
4 changes: 2 additions & 2 deletions osm2streets-js/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,9 +251,9 @@ impl JsStreetNetwork {
}

#[wasm_bindgen(js_name = findBlock)]
pub fn find_block(&self, road: usize, left: bool) -> Result<String, JsValue> {
pub fn find_block(&self, road: usize, left: bool, sidewalks: bool) -> Result<String, JsValue> {
self.inner
.find_block(RoadID(road), left)
.find_block(RoadID(road), left, sidewalks)
.map_err(err_to_js)?
.render_polygon(&self.inner)
.map_err(err_to_js)
Expand Down
49 changes: 38 additions & 11 deletions osm2streets/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use anyhow::Result;
use geojson::Feature;
use geom::{Polygon, Ring};

use crate::{IntersectionID, LaneType, RoadID, StreetNetwork};
use crate::{Intersection, IntersectionID, LaneType, RoadID, StreetNetwork};

/// A "tight" cycle of roads and intersections, with a polygon capturing the negative space inside.
pub struct Block {
Expand Down Expand Up @@ -36,10 +36,10 @@ pub enum BlockKind {

impl StreetNetwork {
// Start at road's src_i
pub fn find_block(&self, start: RoadID, left: bool) -> Result<Block> {
// TODO ??
// TODO API is getting messy
pub fn find_block(&self, start: RoadID, left: bool, sidewalks: bool) -> Result<Block> {
let clockwise = left;
let steps = walk_around(self, start, clockwise)?;
let steps = walk_around(self, start, clockwise, sidewalks)?;
let polygon = trace_polygon(self, &steps, clockwise)?;
let kind = classify(self, &steps);

Expand All @@ -60,7 +60,7 @@ impl StreetNetwork {
if visited_roads.contains(&(*r, left)) {
continue;
}
if let Ok(block) = self.find_block(*r, left) {
if let Ok(block) = self.find_block(*r, left, false) {
// TODO Put more info in Step to avoid duplicating logic with trace_polygon
for pair in block.steps.windows(2) {
match (pair[0], pair[1]) {
Expand Down Expand Up @@ -132,7 +132,12 @@ impl Block {
}
}

fn walk_around(streets: &StreetNetwork, start_road: RoadID, clockwise: bool) -> Result<Vec<Step>> {
fn walk_around(
streets: &StreetNetwork,
start_road: RoadID,
clockwise: bool,
sidewalks: bool,
) -> Result<Vec<Step>> {
let start_i = streets.roads[&start_road].src_i;

let mut current_i = start_i;
Expand All @@ -142,26 +147,30 @@ fn walk_around(streets: &StreetNetwork, start_road: RoadID, clockwise: bool) ->

while current_i != start_i || steps.len() < 2 {
// Fail for dead-ends (for now, to avoid tracing around the entire clipped map)
if streets.intersections[&current_i].roads.len() == 1 {
if filter_roads(streets, sidewalks, &streets.intersections[&current_i]).len() == 1 {
bail!("Found a dead-end at {current_i}");
}

let next_i = &streets.intersections[&streets.roads[&current_r].other_side(current_i)];
let idx = next_i.roads.iter().position(|x| *x == current_r).unwrap();
let clockwise_roads = filter_roads(streets, sidewalks, next_i);
let idx = clockwise_roads
.iter()
.position(|x| *x == current_r)
.unwrap();
let next_idx = if clockwise {
if idx == next_i.roads.len() - 1 {
if idx == clockwise_roads.len() - 1 {
0
} else {
idx + 1
}
} else {
if idx == 0 {
next_i.roads.len() - 1
clockwise_roads.len() - 1
} else {
idx - 1
}
};
let next_r = next_i.roads[next_idx];
let next_r = clockwise_roads[next_idx];
steps.push(Step::Node(next_i.id));
steps.push(Step::Edge(next_r));
current_i = next_i.id;
Expand All @@ -171,6 +180,24 @@ fn walk_around(streets: &StreetNetwork, start_road: RoadID, clockwise: bool) ->
Ok(steps)
}

// When we're limiting to sidewalks, get rid of any roads around the intersection that aren't
// crossings or sidewalks
fn filter_roads(
streets: &StreetNetwork,
sidewalks: bool,
intersection: &Intersection,
) -> Vec<RoadID> {
let mut roads = intersection.roads.clone();
if !sidewalks {
return roads;
}
roads.retain(|r| {
let road = &streets.roads[r];
road.lane_specs_ltr.len() == 1 && road.lane_specs_ltr[0].lt.is_walkable()
});
roads
}

fn trace_polygon(streets: &StreetNetwork, steps: &Vec<Step>, clockwise: bool) -> Result<Polygon> {
let shift_dir = if clockwise { -1.0 } else { 1.0 };
let mut pts = Vec::new();
Expand Down
16 changes: 12 additions & 4 deletions web/src/street-explorer/LanePopup.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@
close();
}
function findBlock(left: boolean) {
function findBlock(left: boolean, sidewalks: boolean) {
try {
blockGj.set(JSON.parse($network!.findBlock(props.road, left)));
blockGj.set(JSON.parse($network!.findBlock(props.road, left, sidewalks)));
} catch (err) {
window.alert(err);
}
Expand Down Expand Up @@ -73,13 +73,21 @@
<button type="button" on:click={zip}>Zip side-path</button>
</div>
<div>
<button type="button" on:click={() => findBlock(true)}
<button type="button" on:click={() => findBlock(true, false)}
>Find block on left</button
>
<button type="button" on:click={() => findBlock(false)}
<button type="button" on:click={() => findBlock(false, false)}
>Find block on right</button
>
</div>
<div>
<button type="button" on:click={() => findBlock(true, true)}
>Trace sidewalks on left</button
>
<button type="button" on:click={() => findBlock(false, true)}
>Trace sidewalks on right</button
>
</div>

<style>
td {
Expand Down

0 comments on commit 338660d

Please sign in to comment.