Skip to content

Commit 679fdec

Browse files
committed
Refactor to use more of osm2graph
1 parent ed90709 commit 679fdec

File tree

2 files changed

+69
-88
lines changed

2 files changed

+69
-88
lines changed

backend/Cargo.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/src/create.rs

+68-87
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ use std::collections::{BTreeMap, BTreeSet, HashMap};
22

33
use anyhow::Result;
44
use geo::{Coord, LineInterpolatePoint, LineString, Polygon};
5-
use osm_reader::{Element, NodeID};
5+
use osm_reader::{NodeID, OsmID, RelationID, WayID};
66
use petgraph::graphmap::UnGraphMap;
77
use rstar::{primitives::GeomWithData, RTree};
88
use utils::{
9-
osm2graph::{EdgeID, Graph},
9+
osm2graph::{EdgeID, Graph, OsmReader},
1010
Tags,
1111
};
1212

@@ -15,94 +15,75 @@ use crate::{
1515
Router,
1616
};
1717

18-
pub fn create_from_osm(
19-
input_bytes: &[u8],
20-
boundary_wgs84: Polygon,
21-
study_area_name: Option<String>,
22-
) -> Result<MapModel> {
23-
info!("Parsing {} bytes of OSM data", input_bytes.len());
24-
// This doesn't use osm2graph's helper, because it needs to scrape more things from OSM
25-
let mut node_mapping = HashMap::new();
26-
let mut highways = Vec::new();
27-
let mut bus_routes_on_roads = HashMap::new();
28-
let mut railways = Vec::new();
29-
let mut waterways = Vec::new();
30-
let mut barrier_nodes: BTreeSet<NodeID> = BTreeSet::new();
31-
osm_reader::parse(input_bytes, |elem| match elem {
32-
Element::Node {
33-
id, lon, lat, tags, ..
34-
} => {
35-
let pt = Coord { x: lon, y: lat };
36-
node_mapping.insert(id, pt);
37-
38-
// Tuning these by hand for a few known areas.
39-
// https://wiki.openstreetmap.org/wiki/Key:barrier is proper reference.
40-
if let Some(kind) = tags.get("barrier") {
41-
// Bristol has many gates that don't seem as relevant
42-
if kind != "gate" {
43-
barrier_nodes.insert(id);
44-
}
18+
#[derive(Default)]
19+
struct Osm {
20+
bus_routes_on_roads: HashMap<WayID, Vec<String>>,
21+
railways: Vec<LineString>,
22+
waterways: Vec<LineString>,
23+
barrier_nodes: BTreeSet<NodeID>,
24+
}
25+
26+
impl OsmReader for Osm {
27+
fn node(&mut self, id: NodeID, _: Coord, tags: Tags) {
28+
// Tuning these by hand for a few known areas.
29+
// https://wiki.openstreetmap.org/wiki/Key:barrier is proper reference.
30+
if let Some(kind) = tags.get("barrier") {
31+
// Bristol has many gates that don't seem as relevant
32+
if kind != "gate" {
33+
self.barrier_nodes.insert(id);
4534
}
4635
}
47-
Element::Way {
48-
id,
49-
mut node_ids,
50-
tags,
51-
..
52-
} => {
53-
let tags = tags.into();
54-
if is_road(&tags) {
55-
// TODO This sometimes happens from Overpass?
56-
let num = node_ids.len();
57-
node_ids.retain(|n| node_mapping.contains_key(n));
58-
if node_ids.len() != num {
59-
warn!("{id} refers to nodes outside the imported area");
60-
}
61-
if node_ids.len() >= 2 {
62-
highways.push(utils::osm2graph::Way { id, node_ids, tags });
63-
}
64-
} else if tags.has("railway") && (!tags.has("layer") || tags.is("layer", "0")) {
65-
node_ids.retain(|n| node_mapping.contains_key(n));
66-
if node_ids.len() >= 2 {
67-
railways.push(LineString(
68-
node_ids.into_iter().map(|n| node_mapping[&n]).collect(),
69-
));
70-
}
71-
} else if tags.is_any("natural", vec!["water", "coastline"])
72-
|| tags.is("waterway", "dock")
73-
{
74-
// If the entire area is inside the study area, the LineString will be closed. If
75-
// it intersects the study area, then it might not be.
76-
node_ids.retain(|n| node_mapping.contains_key(n));
77-
if node_ids.len() >= 2 {
78-
waterways.push(LineString(
79-
node_ids.into_iter().map(|n| node_mapping[&n]).collect(),
80-
));
81-
}
82-
}
36+
}
37+
38+
fn way(
39+
&mut self,
40+
_: WayID,
41+
node_ids: &Vec<NodeID>,
42+
node_mapping: &HashMap<NodeID, Coord>,
43+
tags: &Tags,
44+
) {
45+
if node_ids.len() < 2 {
46+
return;
47+
}
48+
if tags.has("railway") && (!tags.has("layer") || tags.is("layer", "0")) {
49+
self.railways.push(LineString(
50+
node_ids.into_iter().map(|n| node_mapping[&n]).collect(),
51+
));
52+
} else if tags.is_any("natural", vec!["water", "coastline"]) || tags.is("waterway", "dock")
53+
{
54+
// If the entire area is inside the study area, the LineString will be closed. If
55+
// it intersects the study area, then it might not be.
56+
self.waterways.push(LineString(
57+
node_ids.into_iter().map(|n| node_mapping[&n]).collect(),
58+
));
8359
}
84-
Element::Relation { tags, members, .. } => {
85-
let tags: Tags = tags.into();
86-
if tags.is("type", "route") && tags.is("route", "bus") {
87-
if let Some(name) = tags.get("name") {
88-
for (role, member) in members {
89-
if let osm_reader::OsmID::Way(w) = member {
90-
if role.is_empty() {
91-
bus_routes_on_roads
92-
.entry(w)
93-
.or_insert_with(Vec::new)
94-
.push(name.to_string());
95-
}
60+
}
61+
62+
fn relation(&mut self, _: RelationID, members: &Vec<(String, OsmID)>, tags: &Tags) {
63+
if tags.is("type", "route") && tags.is("route", "bus") {
64+
if let Some(name) = tags.get("name") {
65+
for (role, member) in members {
66+
if let OsmID::Way(w) = member {
67+
if role.is_empty() {
68+
self.bus_routes_on_roads
69+
.entry(*w)
70+
.or_insert_with(Vec::new)
71+
.push(name.to_string());
9672
}
9773
}
9874
}
9975
}
10076
}
101-
Element::Bounds { .. } => {}
102-
})?;
77+
}
78+
}
10379

104-
info!("Splitting {} ways into edges", highways.len());
105-
let mut graph = Graph::from_scraped_osm(node_mapping, highways);
80+
pub fn create_from_osm(
81+
input_bytes: &[u8],
82+
boundary_wgs84: Polygon,
83+
study_area_name: Option<String>,
84+
) -> Result<MapModel> {
85+
let mut osm = Osm::default();
86+
let mut graph = Graph::new(input_bytes, is_road, &mut osm)?;
10687
remove_disconnected_components(&mut graph);
10788
graph.compact_ids();
10889

@@ -135,10 +116,10 @@ pub fn create_from_osm(
135116
})
136117
.collect();
137118

138-
for ls in &mut railways {
119+
for ls in &mut osm.railways {
139120
graph.mercator.to_mercator_in_place(ls);
140121
}
141-
for ls in &mut waterways {
122+
for ls in &mut osm.waterways {
142123
graph.mercator.to_mercator_in_place(ls);
143124
}
144125

@@ -166,15 +147,15 @@ pub fn create_from_osm(
166147
let mut map = MapModel {
167148
roads,
168149
intersections,
169-
bus_routes_on_roads,
150+
bus_routes_on_roads: osm.bus_routes_on_roads,
170151
mercator: graph.mercator,
171152
boundary_wgs84,
172153
study_area_name,
173154
closest_road,
174155
closest_intersection,
175156

176-
railways,
177-
waterways,
157+
railways: osm.railways,
158+
waterways: osm.waterways,
178159

179160
router_before: None,
180161
router_after: None,
@@ -196,7 +177,7 @@ pub fn create_from_osm(
196177
// TODO Batch some or all of these initial edits?
197178

198179
// Apply barriers on any surviving edges. RoadID and osm2graph::EdgeID are the same.
199-
for node in barrier_nodes {
180+
for node in osm.barrier_nodes {
200181
// If there's no surviving edge, then it was a barrier on something we don't consider a
201182
// road or on a road that was removed
202183
let Some(edge) = graph.node_to_edge.get(&node) else {

0 commit comments

Comments
 (0)