From 9a3fd90cfcef7304fdc85879a4d44ba234203a7a Mon Sep 17 00:00:00 2001 From: Dustin Carlino Date: Mon, 18 Dec 2023 12:35:58 +0900 Subject: [PATCH] Clip the network to the boundary Wires up e2e, exposing a problem with the route snapper geometry --- backend/src/lib.rs | 17 ++++++++++++- backend/src/neighbourhood.rs | 40 +++++++++++++++++++++++++++++++ web/src/App.svelte | 4 ++-- web/src/NeighbourhoodLayer.svelte | 30 +++++++++++++++++++++-- 4 files changed, 86 insertions(+), 5 deletions(-) create mode 100644 backend/src/neighbourhood.rs diff --git a/backend/src/lib.rs b/backend/src/lib.rs index c4fcce1..e735723 100644 --- a/backend/src/lib.rs +++ b/backend/src/lib.rs @@ -1,14 +1,17 @@ #[macro_use] +extern crate anyhow; +#[macro_use] extern crate log; use std::fmt; use std::sync::Once; -use geo::{LineString, Point}; +use geo::{LineString, Point, Polygon}; use geojson::{Feature, GeoJson, Geometry}; use wasm_bindgen::prelude::*; mod mercator; +mod neighbourhood; mod scrape; mod tags; @@ -111,6 +114,18 @@ impl MapModel { bytes } + /// Takes boundary GJ polygon, returns GJ with more details + #[wasm_bindgen(js_name = analyzeNeighbourhood)] + pub fn analyze_neighbourhood(&self, input: JsValue) -> Result { + let boundary_gj: Feature = serde_wasm_bindgen::from_value(input)?; + let mut boundary_geo: Polygon = boundary_gj.try_into().map_err(err_to_js)?; + self.mercator.to_mercator_in_place(&mut boundary_geo); + + let neighbourhood = + neighbourhood::Neighbourhood::new(self, boundary_geo).map_err(err_to_js)?; + Ok(serde_json::to_string(&neighbourhood.to_gj(self)).map_err(err_to_js)?) + } + fn find_edge(&self, i1: IntersectionID, i2: IntersectionID) -> &Road { // TODO Store lookup table for r in &self.intersections[i1.0].roads { diff --git a/backend/src/neighbourhood.rs b/backend/src/neighbourhood.rs new file mode 100644 index 0000000..709ef2a --- /dev/null +++ b/backend/src/neighbourhood.rs @@ -0,0 +1,40 @@ +use std::collections::HashSet; + +use anyhow::Result; +use geo::{Contains, Polygon}; +use geojson::GeoJson; + +use crate::{MapModel, RoadID}; + +pub struct Neighbourhood { + interior_roads: HashSet, +} + +impl Neighbourhood { + pub fn new(map: &MapModel, boundary: Polygon) -> Result { + let mut interior_roads = HashSet::new(); + for r in &map.roads { + if boundary.contains(&r.linestring) { + interior_roads.insert(r.id); + } + } + + if interior_roads.is_empty() { + bail!("No roads inside the boundary"); + } + + Ok(Self { interior_roads }) + } + + pub fn to_gj(&self, map: &MapModel) -> GeoJson { + let mut features = Vec::new(); + + for r in &self.interior_roads { + let mut f = map.roads[r.0].to_gj(&map.mercator); + f.set_property("kind", "interior_road"); + features.push(f); + } + + GeoJson::from(features) + } +} diff --git a/web/src/App.svelte b/web/src/App.svelte index 9086ede..ceaa947 100644 --- a/web/src/App.svelte +++ b/web/src/App.svelte @@ -82,7 +82,7 @@ {/if}
- {#if mode.mode == "network"} + {#if mode.mode == "network" && model} {:else if mode.mode == "set-boundary"}

Draw the boundary...

@@ -104,7 +104,7 @@ {:else if mode.mode == "set-boundary"} {:else if mode.mode == "neighbourhood"} - + {/if} {/if} diff --git a/web/src/NeighbourhoodLayer.svelte b/web/src/NeighbourhoodLayer.svelte index 2165f5a..d514af2 100644 --- a/web/src/NeighbourhoodLayer.svelte +++ b/web/src/NeighbourhoodLayer.svelte @@ -1,15 +1,41 @@ + + + window.open(e.detail.features[0].properties.way, "_blank")} + hoverCursor="pointer" + > + + + + +