Skip to content

Commit f123598

Browse files
authored
Merge pull request #74 from NREL/yep/edge-attributes
Get and serialize geometries from SegmentSplits
2 parents 7642b7e + 26d0a4d commit f123598

File tree

7 files changed

+114
-9
lines changed

7 files changed

+114
-9
lines changed

rust/bambam-gbfs/src/app/gbfs_cli.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,6 @@ impl GbfsOperation {
5050

5151
fn parse_duration(s: &str) -> Result<chrono::TimeDelta, String> {
5252
let std_duration =
53-
humantime::parse_duration(s).map_err(|e| format!("Invalid duration: {}", e))?;
54-
chrono::TimeDelta::from_std(std_duration).map_err(|e| format!("TimeDelta out of range: {}", e))
53+
humantime::parse_duration(s).map_err(|e| format!("Invalid duration: {e}"))?;
54+
chrono::TimeDelta::from_std(std_duration).map_err(|e| format!("TimeDelta out of range: {e}"))
5555
}

rust/bambam-omf/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,5 @@ serde_arrow = { workspace = true }
5252
thiserror = { workspace = true }
5353
tokio = { workspace = true }
5454
uom = { workspace = true }
55-
wkb = { workspace = true }
55+
wkt = { workspace = true }
56+
wkb = { workspace = true }

rust/bambam-omf/src/app/cli_bbox.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pub struct CliBoundingBox {
1111
pub fn parse_bbox(s: &str) -> Result<CliBoundingBox, String> {
1212
let parts: Vec<&str> = s.split(',').collect();
1313
if parts.len() != 4 {
14-
return Err(format!("expected format: xmin,xmax,ymin,ymax, got: {}", s));
14+
return Err(format!("expected format: xmin,xmax,ymin,ymax, got: {s}"));
1515
}
1616

1717
let xmin = parse_lon(parts[0])?;

rust/bambam-omf/src/graph/connector_in_segment.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ impl ConnectorInSegment {
2525
/// identifiers to sub-segments by their segment id along with linear reference ranges.
2626
/// see <https://docs.overturemaps.org/guides/transportation/#transportation-splitter>
2727
pub fn new_without_connector_id(segment_id: String, linear_reference: f64) -> Self {
28-
let connector_id = format!("{}@{}", segment_id, linear_reference);
28+
let connector_id = format!("{segment_id}@{linear_reference}");
2929
Self {
3030
segment_id,
3131
connector_id,

rust/bambam-omf/src/graph/omf_graph.rs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@ use crate::{
1010
};
1111
use csv::QuoteStyle;
1212
use flate2::{write::GzEncoder, Compression};
13+
use geo::LineString;
1314
use kdam::tqdm;
1415
use rayon::prelude::*;
1516
use routee_compass_core::model::network::{EdgeConfig, EdgeList, EdgeListId, Vertex};
17+
use wkt::ToWkt;
1618

1719
pub struct OmfGraphVectorized {
1820
pub vertices: Vec<Vertex>,
@@ -24,7 +26,7 @@ pub struct OmfGraphVectorized {
2426

2527
pub struct OmfEdgeList {
2628
pub edges: EdgeList,
27-
// pub geometries: Vec<LineString<f32>>
29+
pub geometries: Vec<LineString<f32>>,
2830
}
2931

3032
impl OmfGraphVectorized {
@@ -75,8 +77,10 @@ impl OmfGraphVectorized {
7577
&vertex_lookup,
7678
edge_list_id,
7779
)?;
80+
let geometries = ops::create_geometries(&segments, &segment_lookup, &splits)?;
7881
let edge_list = OmfEdgeList {
7982
edges: EdgeList(edges.into_boxed_slice()),
83+
geometries,
8084
};
8185
edge_lists.push(edge_list);
8286
}
@@ -154,6 +158,13 @@ impl OmfGraphVectorized {
154158
QuoteStyle::Necessary,
155159
overwrite,
156160
);
161+
let mut geometries_writer = create_writer(
162+
&mode_dir,
163+
"edges-geometries-enumerated.txt.gz",
164+
false,
165+
QuoteStyle::Never,
166+
overwrite,
167+
);
157168

158169
// Write Edges
159170
let e_iter = tqdm!(
@@ -186,6 +197,34 @@ impl OmfGraphVectorized {
186197
))
187198
})?;
188199
}
200+
201+
// Write geometries
202+
let g_iter = tqdm!(
203+
edge_list.geometries.iter(),
204+
total = edge_list.geometries.len(),
205+
desc = "geometries",
206+
position = 1
207+
);
208+
for row in g_iter {
209+
if let Some(ref mut writer) = geometries_writer {
210+
writer
211+
.serialize(row.to_wkt().to_string())
212+
.map_err(|e| {
213+
OvertureMapsCollectionError::CsvWriteError(format!(
214+
"Failed to write to geometry file edges-geometries-enumerated.txt.gz: {e}"
215+
))
216+
})?;
217+
}
218+
}
219+
eprintln!();
220+
221+
if let Some(ref mut writer) = geometries_writer {
222+
writer.flush().map_err(|e| {
223+
OvertureMapsCollectionError::CsvWriteError(format!(
224+
"Failed to flush edges-geometries-enumerated.txt.gz: {e}"
225+
))
226+
})?;
227+
}
189228
}
190229
eprintln!();
191230

rust/bambam-omf/src/graph/segment_split.rs

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::collections::HashMap;
22

3+
use geo::{Haversine, Length, LineString};
34
use routee_compass_core::model::network::{Edge, EdgeId, EdgeListId, Vertex, VertexId};
4-
use uom::si::f64::Length;
55

66
use crate::{
77
collection::{OvertureMapsCollectionError, TransportationSegmentRecord},
@@ -102,11 +102,65 @@ impl SegmentSplit {
102102
edge_id,
103103
src_vertex_id: VertexId(*src_id),
104104
dst_vertex_id: VertexId(*dst_id),
105-
distance: Length::new::<uom::si::length::meter>(distance as f64),
105+
distance: uom::si::f64::Length::new::<uom::si::length::meter>(distance as f64),
106106
};
107107

108108
Ok(edge)
109109
}
110110
}
111111
}
112+
113+
pub fn create_geometry_from_split(
114+
&self,
115+
segments: &[&TransportationSegmentRecord],
116+
segment_lookup: &HashMap<String, usize>,
117+
) -> Result<LineString<f32>, OvertureMapsCollectionError> {
118+
use OvertureMapsCollectionError as E;
119+
120+
match self {
121+
SegmentSplit::SimpleConnectorSplit { src, dst } => {
122+
let segment_id = &src.segment_id;
123+
let segment_idx = segment_lookup.get(segment_id).ok_or_else(|| {
124+
let msg = format!("missing lookup entry for segment {segment_id}");
125+
E::InvalidSegmentConnectors(msg)
126+
})?;
127+
let segment = segments.get(*segment_idx).ok_or_else(|| {
128+
let msg = format!(
129+
"missing lookup entry for segment {segment_id} with index {segment_idx}"
130+
);
131+
E::InvalidSegmentConnectors(msg)
132+
})?;
133+
134+
let distance_to_src = segment.get_distance_at(src.linear_reference.0)?;
135+
let distance_to_dst = segment.get_distance_at(dst.linear_reference.0)?;
136+
let segment_geometry = segment.get_linestring()?;
137+
138+
let mut out_coords = vec![];
139+
140+
// Add the initial point
141+
out_coords.push(segment.get_coord_at(src.linear_reference.0)?);
142+
143+
// Check all points to see if we need to add them
144+
let mut total_distance = 0.;
145+
for line in segment_geometry.lines() {
146+
let line_distance = Haversine.length(&line);
147+
total_distance += line_distance;
148+
149+
if total_distance <= distance_to_src {
150+
continue;
151+
}
152+
if total_distance >= distance_to_dst {
153+
break;
154+
}
155+
156+
out_coords.push(line.end);
157+
}
158+
159+
// Add final point
160+
out_coords.push(segment.get_coord_at(dst.linear_reference.0)?);
161+
162+
Ok(LineString::new(out_coords))
163+
}
164+
}
165+
}
112166
}

rust/bambam-omf/src/graph/serialize_ops.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use geo::Coord;
1+
use geo::{Coord, LineString};
22
use itertools::Itertools;
33
use kdam::{tqdm, Bar, BarExt};
44
use rayon::prelude::*;
@@ -178,3 +178,14 @@ pub fn create_edges(
178178
})
179179
.collect::<Result<Vec<Edge>, OvertureMapsCollectionError>>()
180180
}
181+
182+
pub fn create_geometries(
183+
segments: &[&TransportationSegmentRecord],
184+
segment_lookup: &HashMap<String, usize>,
185+
splits: &[SegmentSplit],
186+
) -> Result<Vec<LineString<f32>>, OvertureMapsCollectionError> {
187+
splits
188+
.par_iter()
189+
.map(|split| split.create_geometry_from_split(segments, segment_lookup))
190+
.collect::<Result<Vec<LineString<f32>>, OvertureMapsCollectionError>>()
191+
}

0 commit comments

Comments
 (0)