diff --git a/backend/src/fix_osm.rs b/backend/src/fix_osm.rs new file mode 100644 index 0000000..7b2efed --- /dev/null +++ b/backend/src/fix_osm.rs @@ -0,0 +1,38 @@ +use geo::Intersects; +use geojson::GeoJson; +use rstar::{RTree, RTreeObject}; + +use crate::MapModel; + +pub fn find_separate_sidewalks(map: &MapModel) -> GeoJson { + let footways = RTree::bulk_load( + map.roads + .iter() + .filter(|r| r.tags.is("highway", "footway")) + .map(|r| r.linestring.clone()) + .collect(), + ); + + let mut features = Vec::new(); + 'ROAD: for r in &map.roads { + if r.tags.is("highway", "footway") + || r.tags.is("sidewalk", "separate") + || r.tags.is("sidewalk:left", "separate") + || r.tags.is("sidewalk:right", "separate") + || r.tags.is("sidewalk:both", "separate") + { + continue; + } + + // Along this road, if we project away, do we hit a footway? + for line in crate::heatmap::make_perpendicular_offsets(&r.linestring, 25.0, 15.0) { + for footway in footways.locate_in_envelope_intersecting(&line.envelope()) { + if footway.intersects(&line) { + features.push(r.to_gj(&map.mercator)); + continue 'ROAD; + } + } + } + } + GeoJson::from(features) +} diff --git a/backend/src/heatmap.rs b/backend/src/heatmap.rs index 593e8a2..ad1e3e4 100644 --- a/backend/src/heatmap.rs +++ b/backend/src/heatmap.rs @@ -97,7 +97,7 @@ fn calculate(map: &mut MapModel, requests: Vec) -> FeatureC } // TODO canvas_geometry needs this too -fn make_perpendicular_offsets( +pub fn make_perpendicular_offsets( linestring: &LineString, walk_every_m: f64, project_away_m: f64, diff --git a/backend/src/lib.rs b/backend/src/lib.rs index ca15598..73596ad 100644 --- a/backend/src/lib.rs +++ b/backend/src/lib.rs @@ -14,6 +14,7 @@ use wasm_bindgen::prelude::*; use crate::profiles::Profile; +mod fix_osm; mod heatmap; mod profiles; mod route; @@ -174,6 +175,13 @@ impl MapModel { vec![b.min().x, b.min().y, b.max().x, b.max().y] } + #[wasm_bindgen(js_name = findSeparateSidewalks)] + pub fn find_separate_sidewalks(&self) -> Result { + let out = + serde_json::to_string(&fix_osm::find_separate_sidewalks(self)).map_err(err_to_js)?; + Ok(out) + } + fn find_edge(&self, i1: IntersectionID, i2: IntersectionID) -> &Road { // TODO Store lookup table for r in &self.intersections[i1.0].roads { diff --git a/web/src/App.svelte b/web/src/App.svelte index 742ecb7..1b43bbf 100644 --- a/web/src/App.svelte +++ b/web/src/App.svelte @@ -12,6 +12,7 @@ import DebugMode from "./DebugMode.svelte"; import RouteMode from "./RouteMode.svelte"; import ScoreMode from "./ScoreMode.svelte"; + import OsmSeparateSidewalksMode from "./OsmSeparateSidewalksMode.svelte"; import NetworkLayer from "./NetworkLayer.svelte"; import { map as mapStore, @@ -96,31 +97,33 @@
- -
- -
-
- -
+ {#if $mode.kind != "osm-separate-sidewalks"} + +
+ +
+
+ +
+ {/if} {/if}
@@ -146,7 +149,11 @@ - + {#if $mode.kind == "route"} @@ -154,6 +161,8 @@ {:else if $mode.kind == "debug"} + {:else if $mode.kind == "osm-separate-sidewalks"} + {/if} {/if} diff --git a/web/src/NavBar.svelte b/web/src/NavBar.svelte index e0e4549..f7d4a72 100644 --- a/web/src/NavBar.svelte +++ b/web/src/NavBar.svelte @@ -24,6 +24,14 @@ > +
  • + +
  • +