Skip to content

Commit

Permalink
Output the network and start a page to display different edge cost-re…
Browse files Browse the repository at this point in the history
…lated things
  • Loading branch information
dabreegster committed Nov 3, 2023
1 parent ecba8a4 commit 15857f3
Show file tree
Hide file tree
Showing 7 changed files with 187 additions and 47 deletions.
86 changes: 43 additions & 43 deletions od2net/src/network/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,36 +17,9 @@ impl Edge {
id: usize,
output_osm_tags: bool,
) -> Feature {
let geometry = Geometry::new(Value::LineString(
self.geometry.iter().map(|pt| pt.to_degrees_vec()).collect(),
));
let mut properties = JsonObject::new();
if output_osm_tags {
let mut tags = JsonObject::new();
for (key, value) in self.tags.inner() {
tags.insert(key.to_string(), JsonValue::from(value.to_string()));
}
properties.insert("osm_tags".to_string(), tags.into());
}
properties.insert("node1".to_string(), JsonValue::from(node1));
properties.insert("node2".to_string(), JsonValue::from(node2));
properties.insert("way".to_string(), JsonValue::from(self.way_id));
properties.insert("count".to_string(), JsonValue::from(count));
if let Some(cost) = self.cost {
properties.insert("cost".to_string(), serde_json::to_value(cost).unwrap());
}
properties.insert("lts".to_string(), serde_json::to_value(self.lts).unwrap());
properties.insert(
"nearby_amenities".to_string(),
serde_json::to_value(self.nearby_amenities).unwrap(),
);
Feature {
bbox: None,
geometry: Some(geometry),
id: Some(Id::Number(id.into())),
properties: Some(properties),
foreign_members: None,
}
let mut feature = self.to_base_geojson(id, node1, node2, output_osm_tags);
feature.set_property("count", count);
feature
}

pub fn to_geojson_for_detailed_output(
Expand All @@ -55,27 +28,39 @@ impl Edge {
node2: i64,
geometry_forwards: bool,
) -> Feature {
let mut pts = self
.geometry
.iter()
.map(|pt| pt.to_degrees_vec())
.collect::<Vec<_>>();
let mut feature = self.to_base_geojson(0, node1, node2, true);
feature.id = None;
if !geometry_forwards {
pts.reverse();
if let Some(ref mut geometry) = feature.geometry {
if let Value::LineString(ref mut pts) = geometry.value {
pts.reverse();
}
}
}
let geometry = Geometry::new(Value::LineString(pts));
feature
}

fn to_base_geojson(&self, id: usize, node1: i64, node2: i64, output_osm_tags: bool) -> Feature {
let geometry = Geometry::new(Value::LineString(
self.geometry.iter().map(|pt| pt.to_degrees_vec()).collect(),
));
let mut properties = JsonObject::new();
let mut tags = JsonObject::new();
for (key, value) in self.tags.inner() {
tags.insert(key.to_string(), JsonValue::from(value.to_string()));
if output_osm_tags {
let mut tags = JsonObject::new();
for (key, value) in self.tags.inner() {
tags.insert(key.to_string(), JsonValue::from(value.to_string()));
}
properties.insert("osm_tags".to_string(), tags.into());
}
properties.insert("osm_tags".to_string(), tags.into());
properties.insert("way".to_string(), JsonValue::from(self.way_id));
properties.insert("node1".to_string(), JsonValue::from(node1));
properties.insert("node2".to_string(), JsonValue::from(node2));
properties.insert("way".to_string(), JsonValue::from(self.way_id));
if let Some(cost) = self.cost {
properties.insert("cost".to_string(), serde_json::to_value(cost).unwrap());
properties.insert(
"length".to_string(),
serde_json::to_value(self.length_meters).unwrap(),
);
}
properties.insert("lts".to_string(), serde_json::to_value(self.lts).unwrap());
properties.insert(
Expand All @@ -85,7 +70,7 @@ impl Edge {
Feature {
bbox: None,
geometry: Some(geometry),
id: None,
id: Some(Id::Number(id.into())),
properties: Some(properties),
foreign_members: None,
}
Expand Down Expand Up @@ -180,4 +165,19 @@ impl Network {
);
Ok(())
}

/// Output debug info per edge, without any counts
pub fn to_debug_geojson(&self) -> Result<String> {
let mut gj_bytes = Vec::new();
{
let mut writer = FeatureWriter::from_writer(BufWriter::new(&mut gj_bytes));
let mut id_counter = 0;
for ((node1, node2), edge) in &self.edges {
id_counter += 1;
writer.write_feature(&edge.to_base_geojson(id_counter, *node1, *node2, true))?;
}
writer.finish()?;
}
Ok(String::from_utf8(gj_bytes)?)
}
}
18 changes: 18 additions & 0 deletions viewer/edge_cost.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>od2net edge cost mode</title>
</head>
<body>
<div id="app"></div>
<script type="module">
import EdgeCostApp from "./src/EdgeCostApp.svelte";

new EdgeCostApp({
target: document.getElementById("app"),
});
</script>
</body>
</html>
4 changes: 3 additions & 1 deletion viewer/src/CostFunction.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@
<ul>
{#each osmHighwayWeights.entries() as [key, value] (key)}
<li>
<label>{key}<input type="number" min="1.0" step="0.1" bind:value /></label>
<label
>{key}<input type="number" min="1.0" step="0.1" bind:value /></label
>
</li>
{/each}
</ul>
Expand Down
103 changes: 103 additions & 0 deletions viewer/src/EdgeCostApp.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<script lang="ts">
import initLts from "lts";
import type { Map as MapType } from "maplibre-gl";
import { onMount } from "svelte";
import {
GeoJSON,
hoverStateFilter,
LineLayer,
MapLibre,
Popup,
} from "svelte-maplibre";
import init, { JsNetwork } from "wasm-od2net";
import { colors } from "./common";
import Layout from "./Layout.svelte";
import PropertiesTable from "./PropertiesTable.svelte";
onMount(async () => {
await init();
await initLts();
});
let map: MapType;
let network: JsNetwork | undefined;
let gj = {
type: "FeatureCollection",
features: [],
};
let fileInput: HTMLInputElement;
async function fileLoaded(e: Event) {
try {
let buffer = await fileInput.files![0].arrayBuffer();
network = new JsNetwork(new Uint8Array(buffer));
let bbox = network.getBounds();
map.fitBounds(
[
[bbox[0], bbox[1]],
[bbox[2], bbox[3]],
],
{ padding: 20, animate: false }
);
gj = JSON.parse(network.debugNetwork());
} catch (err) {
window.alert(`Problem loading network file: ${err}`);
}
}
function openOSM(feature) {
let id = feature.properties.way;
window.open(`http://openstreetmap.org/way/${id}`, "_blank");
}
</script>

<Layout>
<div slot="left">
<h1>od2net edge cost explorer</h1>
<label>
Open a <i>.bin</i> network file
<input bind:this={fileInput} on:change={fileLoaded} type="file" />
</label>
</div>
<div slot="main" style="position:relative; width: 100%; height: 100vh;">
<MapLibre
style="https://api.maptiler.com/maps/dataviz/style.json?key=MZEJTanw3WpxRvt7qDfo"
standardControls
hash
bind:map
>
<GeoJSON data={gj}>
<LineLayer
manageHoverState
hoverCursor="pointer"
paint={{
"line-width": 3.0,
// TODO Bucket whatever thing we're looking at
"line-color": [
// Colors from https://github.com/BikeOttawa/maps.bikeottawa.ca-frontend/blob/master/lts/index.html
"match",
["get", "lts"],
1,
colors.lts1,
2,
colors.lts2,
3,
colors.lts3,
4,
colors.lts4,
colors.lts_unknown,
],
"line-opacity": hoverStateFilter(1.0, 0.5),
}}
beforeId="Road labels"
on:click={(e) => openOSM(e.detail.features[0])}
>
<Popup openOn="hover" let:features>
<PropertiesTable properties={features[0].properties} />
</Popup>
</LineLayer>
</GeoJSON>
</MapLibre>
</div>
</Layout>
15 changes: 12 additions & 3 deletions viewer/src/PropertiesTable.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,18 @@
}
</script>

<div><b>Count: {properties.count.toFixed(2)}</b></div>
<div><b>LTS: {properties.lts}</b></div>
<div><b>Nearby amenities: {properties.nearby_amenities}</b></div>
{#if properties.count}
<div>Count: <b>{properties.count.toFixed(2)}</b></div>
{/if}
{#if properties.cost}
<div>
Cost: {properties.cost} (<b
>{(properties.cost / properties.length).toFixed(2)}</b
>x the length)
</div>
{/if}
<div>Nearby amenities: <b>{properties.nearby_amenities}</b></div>
<div>LTS: <b>{properties.lts}</b></div>
<ul>
{#each ltsMessages as msg}
<li>{msg}</li>
Expand Down
1 change: 1 addition & 0 deletions viewer/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export default defineConfig({
input: {
main: resolve(__dirname, "index.html"),
x2: resolve(__dirname, "interactive.html"),
x3: resolve(__dirname, "edge_cost.html"),
},
},
},
Expand Down
7 changes: 7 additions & 0 deletions wasm-od2net/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ impl JsNetwork {
})
}

/// Takes Input, returns GeoJSON
#[wasm_bindgen()]
pub fn recalculate(&mut self, input: JsValue) -> Result<String, JsValue> {
let input: Input = serde_wasm_bindgen::from_value(input)?;
Expand Down Expand Up @@ -146,6 +147,12 @@ impl JsNetwork {
bounds
}

/// Returns GeoJSON with details per edge that can be used to explore cost functions
#[wasm_bindgen(js_name = debugNetwork)]
pub fn debug_network(&self) -> Result<String, JsValue> {
self.network.to_debug_geojson().map_err(err_to_js)
}

// TODO Start simple. From every node to one destination
fn make_requests(&self, x2: f64, y2: f64, max_requests: usize) -> Vec<Request> {
let mut requests = Vec::new();
Expand Down

0 comments on commit 15857f3

Please sign in to comment.