Skip to content

Commit

Permalink
Make a cost function by LTS, which is really what we want in most cas…
Browse files Browse the repository at this point in the history
…es so far
  • Loading branch information
dabreegster committed Nov 6, 2023
1 parent de701af commit 8717d73
Show file tree
Hide file tree
Showing 10 changed files with 126 additions and 52 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions od2net/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ pub enum CostFunction {
Distance,
/// Heavily penalize main roads
AvoidMainRoads,
/// Multiply distance by a factor for each LTS classification
ByLTS {
lts1: f64,
lts2: f64,
lts3: f64,
lts4: f64,
// TODO Incorporate nearby_amenities. Maybe a list of ranges and then a multiplier?
},
/// Multiply distance by a factor based on the OSM highway tag. If the type isn't present, it
/// won't be allowed at all.
OsmHighwayType(HashMap<String, f64>),
Expand Down
2 changes: 1 addition & 1 deletion od2net/src/network/create_from_osm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ fn scrape_elements(
greenspace_polygons.push(polygon);
}

// TODO Improve filtering
// Include everything here, and let LTS::NotAllowed later filter some out
if tags.has("highway") {
ways.insert(
way.id(),
Expand Down
22 changes: 22 additions & 0 deletions od2net/src/plugins/cost.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ pub fn calculate_batch(cost: &CostFunction, input_batch: Vec<&Edge>) -> Vec<Opti
.into_iter()
.map(|e| osm_highway_type(e, weights))
.collect(),
CostFunction::ByLTS {
lts1,
lts2,
lts3,
lts4,
} => input_batch
.into_iter()
.map(|e| by_lts(e, *lts1, *lts2, *lts3, *lts4))
.collect(),
CostFunction::ExternalCommand(command) => external_command(command, input_batch).unwrap(),
}
}
Expand Down Expand Up @@ -57,6 +66,19 @@ fn osm_highway_type(edge: &Edge, weights: &HashMap<String, f64>) -> Option<usize
Some((weight * edge.length_meters).round() as usize)
}

fn by_lts(edge: &Edge, lts1: f64, lts2: f64, lts3: f64, lts4: f64) -> Option<usize> {
let weight = match edge.lts {
LTS::NotAllowed => {
return None;
}
LTS::LTS1 => lts1,
LTS::LTS2 => lts2,
LTS::LTS3 => lts3,
LTS::LTS4 => lts4,
};
Some((weight * edge.length_meters).round() as usize)
}

fn external_command(command: &str, input_batch: Vec<&Edge>) -> Result<Vec<Option<usize>>> {
let args: Vec<&str> = command.split(" ").collect();

Expand Down
30 changes: 29 additions & 1 deletion viewer/src/CostFunction.svelte
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
<script lang="ts">
// TODO Widget's broken, bind:value not working
import { ltsNames } from "./common";
export let cost;
// TODO Maybe not in sync with what's passed in initially
let costChoice = "Distance";
let ltsWeights = {
lts1: 1.0,
lts2: 1.0,
lts3: 1.0,
lts4: 1.0,
};
// TODO Let people add/remove choices
let osmHighwayWeights = {};
for (let key of [
Expand Down Expand Up @@ -34,6 +43,8 @@
function setCost(costChoice) {
if (costChoice == "OsmHighwayType") {
cost = { OsmHighwayType: osmHighwayWeights };
} else if (costChoice == "ByLTS") {
cost = { ByLTS: ltsWeights };
} else {
cost = costChoice;
}
Expand All @@ -47,6 +58,7 @@
<select bind:value={costChoice}>
<option value="Distance">Distance</option>
<option value="AvoidMainRoads">Avoid main roads</option>
<option value="ByLTS">Weight per LTS</option>
<option value="OsmHighwayType">Set a weight per OSM highway type</option>
</select>
</label>
Expand All @@ -67,4 +79,20 @@
</li>
{/each}
</ul>
{:else if costChoice == "ByLTS"}
<ul>
{#each ["lts1", "lts2", "lts3", "lts4"] as key}
<li>
<label
>{ltsNames[key]}<input
type="number"
min="1.0"
step="0.1"
bind:value={ltsWeights[key]}
on:change={() => (cost = cost)}
/></label
>
</li>
{/each}
</ul>
{/if}
94 changes: 51 additions & 43 deletions viewer/src/EdgeCostApp.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,13 @@
Popup,
} from "svelte-maplibre";
import init, { JsNetwork } from "wasm-od2net";
import { colorByLts, colors, colorScale, makeColorRamp } from "./common";
import {
colorByLts,
colors,
colorScale,
ltsNames,
makeColorRamp,
} from "./common";
import CostFunction from "./CostFunction.svelte";
import Header from "./Header.svelte";
import Layout from "./Layout.svelte";
Expand Down Expand Up @@ -131,49 +137,51 @@
Open a <i>.bin</i> network file or an <i>.osm.pbf</i>
<input bind:this={fileInput} on:change={fileLoaded} type="file" />
</label>
<hr />
<div>
<label>
Color edges by:
<select bind:value={colorBy}>
<option value="lts">LTS</option>
<option value="cost">Edge cost (relative to length)</option>
<option value="nearby_amenities">Nearby amenities</option>
</select>
</label>
</div>
{#if colorBy == "lts"}
<Legend
rows={[
[
`LTS 1 - suitable for children: ${percentByLength[1].toFixed(0)}%`,
colors.lts1,
],
[
`LTS 2 - low stress: ${percentByLength[2].toFixed(0)}%`,
colors.lts2,
],
[
`LTS 3 - medium stress: ${percentByLength[3].toFixed(0)}%`,
colors.lts3,
],
[
`LTS 4 - high stress: ${percentByLength[4].toFixed(0)}%`,
colors.lts4,
],
]}
/>
<p>
Note: LTS model from <a
href="https://github.com/BikeOttawa/stressmodel/blob/master/stressmodel.js"
target="_blank">BikeOttawa</a
>
</p>
{:else}
<SequentialLegend {colorScale} limits={limitsFor(colorBy)} />
{#if network}
<hr />
<div>
<label>
Color edges by:
<select bind:value={colorBy}>
<option value="lts">LTS</option>
<option value="cost">Edge cost (relative to length)</option>
<option value="nearby_amenities">Nearby amenities</option>
</select>
</label>
</div>
{#if colorBy == "lts"}
<Legend
rows={[
[
`${ltsNames.lts1}: ${percentByLength[1].toFixed(0)}%`,
colors.lts1,
],
[
`${ltsNames.lts2}: ${percentByLength[2].toFixed(0)}%`,
colors.lts2,
],
[
`${ltsNames.lts3}: ${percentByLength[3].toFixed(0)}%`,
colors.lts3,
],
[
`${ltsNames.lts4}: ${percentByLength[4].toFixed(0)}%`,
colors.lts4,
],
]}
/>
<p>
Note: LTS model from <a
href="https://github.com/BikeOttawa/stressmodel/blob/master/stressmodel.js"
target="_blank">BikeOttawa</a
>
</p>
{:else}
<SequentialLegend {colorScale} limits={limitsFor(colorBy)} />
{/if}
<hr />
<CostFunction bind:cost />
{/if}
<hr />
<CostFunction bind:cost />
</div>
<div slot="main" style="position:relative; width: 100%; height: 100vh;">
<MapLibre
Expand Down
12 changes: 5 additions & 7 deletions viewer/src/SidebarControls.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts">
import { colors } from "./common";
import { colors, ltsNames } from "./common";
import Legend from "./Legend.svelte";
import StreetView from "./StreetView.svelte";
import ToggleLayer from "./ToggleLayer.svelte";
Expand Down Expand Up @@ -57,21 +57,19 @@
<Legend
rows={[
[
`LTS 1 - suitable for children: ${total(
outputMetadata.total_meters_lts1
)}`,
`${ltsNames.lts1}: ${total(outputMetadata.total_meters_lts1)}`,
colors.lts1,
],
[
`LTS 2 - low stress: ${total(outputMetadata.total_meters_lts2)}`,
`${ltsNames.lts2}: ${total(outputMetadata.total_meters_lts2)}`,
colors.lts2,
],
[
`LTS 3 - medium stress: ${total(outputMetadata.total_meters_lts3)}`,
`${ltsNames.lts3}: ${total(outputMetadata.total_meters_lts3)}`,
colors.lts3,
],
[
`LTS 4 - high stress: ${total(outputMetadata.total_meters_lts4)}`,
`${ltsNames.lts4}: ${total(outputMetadata.total_meters_lts4)}`,
colors.lts4,
],
]}
Expand Down
7 changes: 7 additions & 0 deletions viewer/src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,10 @@ export function makeColorRamp(

// Sequential (low-to-high) color ramp from https://www.ons.gov.uk/census/maps/choropleth
export let colorScale = ["#CDE594", "#80C6A3", "#1F9EB7", "#186290", "#080C54"];

export let ltsNames = {
lts1: "LTS 1 - suitable for children",
lts2: "LTS 2 - low stress",
lts3: "LTS 3 - medium stress",
lts4: "LTS 4 - high stress",
};
1 change: 1 addition & 0 deletions wasm-od2net/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ log = "0.4.20"
od2net = { path = "../od2net" }
rstar = "0.11.0"
serde = "1.0.188"
serde_json = "1.0.105"
serde-wasm-bindgen = "0.6.0"
wasm-bindgen = "0.2.87"
web-sys = { version = "0.3.64", features = ["console"] }
1 change: 1 addition & 0 deletions wasm-od2net/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ impl JsNetwork {
#[wasm_bindgen(js_name = updateCostFunction)]
pub fn update_cost_function(&mut self, input: JsValue) -> Result<(), JsValue> {
let cost: CostFunction = serde_wasm_bindgen::from_value(input)?;
info!("Changing cost to {}", serde_json::to_string(&cost).map_err(err_to_js)?);
self.last_cost = cost;
self.network.recalculate_cost(&self.last_cost);
// Doesn't touch the CH, because this is only meant to be used in the edge cost app, which
Expand Down

0 comments on commit 8717d73

Please sign in to comment.