Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Elevation / gradient source #18

Open
dabreegster opened this issue Sep 4, 2023 · 24 comments
Open

Elevation / gradient source #18

dabreegster opened this issue Sep 4, 2023 · 24 comments
Milestone

Comments

@dabreegster
Copy link
Collaborator

Possible reference, https://www.liedman.net/2015/04/13/add-elevation-data-to-osrm/

@dabreegster dabreegster added this to the v2 milestone Sep 4, 2023
@dabreegster
Copy link
Collaborator Author

dabreegster commented Jan 17, 2024

The goal of this feature request is to incorporate elevation / steepness into od2net's route cost. I don't have time to tackle this directly, so I'm going to try and break down the steps and be around to help.

Many many more notes at a-b-street/abstreet#82 from an older project

@KDKasonde
Copy link
Contributor

I can have a look at this issue!

@dabreegster
Copy link
Collaborator Author

Rosa pointed to https://github.com/U-Shift/Declives-RedeViaria/blob/main/SpeedSlopeFactor/SpeedSlopeFactor.md for how to use in cost functions

@KDKasonde
Copy link
Contributor

I am looking at incorporating the steepness into the cost function now, but noticed the Edges do not directions attached (I could be wrong here). I am trying to think of a way to ensure the steepness is applied properly does anyone have any ideas?

Extra context:
My plan so far is calculate the steepness for each edge from its start node to its end node, calculate a slope_factor then multiply the cost by the slope_factor to get an elevation adjusted cost. But the multiplication is dependent on either each edge having 2 representations (node1, node2) and (node2, node1). Or the cost augmentation adjusting the slope_factor if the traversal is the reverse of the edge.

Let me know if I have missed something or become misguided!

@dabreegster
Copy link
Collaborator Author

Very good questions! Right now, od2net mostly ignores direction -- the final counts of trips crossing a road are in either direction, and cyclists can route either way on an existing one-way. #19 is open to fix these. For the second part, this will become a user's choice -- respect current one-ways or ignore them. When planning possible extensions to a cycling network, something that's one-way for all traffic right now could maybe become contraflow for cycling. There are many successful examples of this in the UK (and a paper demonstrating the safety of it).

But I don't think we need to care about any of that here yet. Edge itself does not track the direction, but it is available:

pub edges: HashMap<(NodeID, NodeID), Edge>,
because the lookup for Edge is (node1, node2). So you could add slope_factor to Edge and define it as going from node1 to node2. When you're calculating it for every edge, the two nodes in order are available -- an example is
let all_keys: Vec<(NodeID, NodeID)> = self.edges.keys().cloned().collect();
.

Then the second part would be using the slope in one direction or another during routing. Right now calculate_batch is only taking &Edge as input, so indeed we don't have enough info. We could either add node1 and node2 to the struct, or to keep the file serialization size smaller, just pass in the two nodes to this function as well. (I haven't done benchmarking to see if storing the nodes redundantly causes any issue. It's probably fine and something we could optimize later, if it's more convenient to just add the nodes.)

@KDKasonde
Copy link
Contributor

Thank you, that makes sense. I will give passing in the node1 and node2 a go then! I will most likely check in again soon!

@KDKasonde
Copy link
Contributor

anyone know where I can find tif files with elevation data? I have not been able to find any with elevation data inside!

@dabreegster
Copy link
Collaborator Author

https://play.abstreet.org/dev/data/input/shared/elevation/UK-dem-50m-4326.tif.gz
This is one covering England. The od2net example configs for York (small area), Liverpool (medium), and England 2011 census (large) should be quick ways to start plugging this in somewhere

@dabreegster
Copy link
Collaborator Author

@KDKasonde, some work requirements on my end have come up, and I might need to get this started before next week. I don't want to preempt or rush any work you've been doing though! I peeked around and found your branch, https://github.com/KDKasonde/od2net/tree/feature/dem_file_based_network_elevation, and it's looking pretty awesome! Any sense how far from a PR you are? Even if things are incomplete, I could start trying things out

@KDKasonde
Copy link
Contributor

KDKasonde commented Feb 21, 2024

Hey sorry this definitely took longer than I thought it would😅 I think I am happy with getting the slope augmented cost, generating a network, and using the appropriate cost when doing the routing. What I am stuck on now is showing the cost (now stored as a tuple in the edge), slope and highlighting routes on the web app. Also turns out my issue tif files was me not the files! But I am just trying to figure out how to get serde to send the cost data as an Array so I can give the cost of each edge in both directions. As for when I can do this, I think I can figure out serde relatively quickly what may take longer is the optional slope highlighting!

Let me know if this was helpful I can go into more detail.

@dabreegster
Copy link
Collaborator Author

No worries at all, it's quite a hefty "starter" project. For plumbing the new per-edge data to the frontend, check out

if let Some(cost) = self.cost {
. To keep it simple, how about just a separate cost_forwards and cost_backwards property? Sending back a JSON array with 2 numbers should be possible too, but then using it over in MapLibre will be a bit funky, because array and nested object properties get squished down into a string in some of their APIs. (It's a really weird and subtle behavior that constantly messes me up.)

I'm curious what you have in mind for visualizing the steepness in the frontend. In another work project, I'm working on this too: acteng/atip#475. We could use the same ideas if they seem relevant

@dabreegster
Copy link
Collaborator Author

Also, I'm realizing the code at

let mut properties = JsonObject::new();
is pretty awkward. There's a simpler set_property API once you have a geojson::Feature. An example is https://github.com/dabreegster/ltn/blob/f5f321732d80a127534676559047dd94f7471449/backend/src/neighbourhood.rs#L133. We could make the geojson::Feature struct first with empty properties, then just call set_property and get rid of all the serde::to_value boilerplate

@KDKasonde
Copy link
Contributor

So that's why my tuples were string! Thank you I couldn't figure out why that was happening, I think I will go with what you have just said then, it makes sense and should be a quick change!

For the steepness I won't lie I have not thought about it too deeply, but my initial thoughts were similar to how the LTS is done, getting the min and max slope, mapping this to a colour range and seeing how that would work out🤔 But not much thought on showing which direction the slope is for, really.

@dabreegster
Copy link
Collaborator Author

https://maplibre.org/maplibre-gl-js/docs/API/classes/Map/#queryrenderedfeatures
"For GeoJSON sources, only string and numeric property values are supported (i.e. null, Array, and Object values are not supported)."
Before I internalized this, I think I probably burned at least 5 hours on different bugs caused by this...

And sounds good for visualization -- start simple, we can always make improvements later on

@KDKasonde
Copy link
Contributor

Thanks for that link! Also when is your cut off date so I can keep it in mind?

@dabreegster
Copy link
Collaborator Author

dabreegster commented Feb 21, 2024 via email

@KDKasonde
Copy link
Contributor

Right okay, I can PR everything except the steepness visuals if that helps?

@dabreegster
Copy link
Collaborator Author

Yep, that'll work. Thank you! And again, no need to rush on this, I can very much just clone from your branch if needed

@dabreegster
Copy link
Collaborator Author

@KDKasonde, enabling this is pretty easy: 6f31e13
I'm getting slope output, but it's hard to understand piecemeal. I'm going to adapt the steepness visualization from my other work project now

@KDKasonde
Copy link
Contributor

Which project is that? And is that because it is calculated edge by edge or they are not all calculated or something?

@KDKasonde
Copy link
Contributor

Should I leave the visualisation to you then?

@dabreegster
Copy link
Collaborator Author

It's hard to understand just because hovering over each edge and looking at the slope in the popup is tedious. The other project is https://acteng.github.io/atip/browse.html, "Other > Gradient" on the right. acteng/atip#475 is the frontend code I'm adapting now

@dabreegster
Copy link
Collaborator Author

Should I leave the visualisation to you then?

Yep, I'm sort of in a rush to get some things ready for next week. Thanks again a ton for getting this going -- a group is looking at the whole process of route network generation and analysis, and being able to influence route choice by slope makes od2net way more realistic for studying this

@KDKasonde
Copy link
Contributor

Happy to help! I just hope I have not set you guys back!

dabreegster added a commit that referenced this issue Feb 23, 2024
dabreegster added a commit that referenced this issue Feb 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants