Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions rust/bambam-gbfs/src/app/gbfs_cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,6 @@ impl GbfsOperation {

fn parse_duration(s: &str) -> Result<chrono::TimeDelta, String> {
let std_duration =
humantime::parse_duration(s).map_err(|e| format!("Invalid duration: {}", e))?;
chrono::TimeDelta::from_std(std_duration).map_err(|e| format!("TimeDelta out of range: {}", e))
humantime::parse_duration(s).map_err(|e| format!("Invalid duration: {e}"))?;
chrono::TimeDelta::from_std(std_duration).map_err(|e| format!("TimeDelta out of range: {e}"))
}
3 changes: 2 additions & 1 deletion rust/bambam-omf/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,5 @@ serde_arrow = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true }
uom = { workspace = true }
wkb = { workspace = true }
wkt = { workspace = true }
wkb = { workspace = true }
2 changes: 1 addition & 1 deletion rust/bambam-omf/src/app/cli_bbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub struct CliBoundingBox {
pub fn parse_bbox(s: &str) -> Result<CliBoundingBox, String> {
let parts: Vec<&str> = s.split(',').collect();
if parts.len() != 4 {
return Err(format!("expected format: xmin,xmax,ymin,ymax, got: {}", s));
return Err(format!("expected format: xmin,xmax,ymin,ymax, got: {s}"));
}

let xmin = parse_lon(parts[0])?;
Expand Down
2 changes: 1 addition & 1 deletion rust/bambam-omf/src/graph/connector_in_segment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ impl ConnectorInSegment {
/// identifiers to sub-segments by their segment id along with linear reference ranges.
/// see <https://docs.overturemaps.org/guides/transportation/#transportation-splitter>
pub fn new_without_connector_id(segment_id: String, linear_reference: f64) -> Self {
let connector_id = format!("{}@{}", segment_id, linear_reference);
let connector_id = format!("{segment_id}@{linear_reference}");
Self {
segment_id,
connector_id,
Expand Down
41 changes: 40 additions & 1 deletion rust/bambam-omf/src/graph/omf_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ use crate::{
};
use csv::QuoteStyle;
use flate2::{write::GzEncoder, Compression};
use geo::LineString;
use kdam::tqdm;
use rayon::prelude::*;
use routee_compass_core::model::network::{EdgeConfig, EdgeList, EdgeListId, Vertex};
use wkt::ToWkt;

pub struct OmfGraphVectorized {
pub vertices: Vec<Vertex>,
Expand All @@ -24,7 +26,7 @@ pub struct OmfGraphVectorized {

pub struct OmfEdgeList {
pub edges: EdgeList,
// pub geometries: Vec<LineString<f32>>
pub geometries: Vec<LineString<f32>>,
}

impl OmfGraphVectorized {
Expand Down Expand Up @@ -75,8 +77,10 @@ impl OmfGraphVectorized {
&vertex_lookup,
edge_list_id,
)?;
let geometries = ops::create_geometries(&segments, &segment_lookup, &splits)?;
let edge_list = OmfEdgeList {
edges: EdgeList(edges.into_boxed_slice()),
geometries,
};
edge_lists.push(edge_list);
}
Expand Down Expand Up @@ -154,6 +158,13 @@ impl OmfGraphVectorized {
QuoteStyle::Necessary,
overwrite,
);
let mut geometries_writer = create_writer(
&mode_dir,
"edges-geometries-enumerated.txt.gz",
false,
QuoteStyle::Never,
overwrite,
);

// Write Edges
let e_iter = tqdm!(
Expand Down Expand Up @@ -186,6 +197,34 @@ impl OmfGraphVectorized {
))
})?;
}

// Write geometries
let g_iter = tqdm!(
edge_list.geometries.iter(),
total = edge_list.geometries.len(),
desc = "edges",
position = 1
);
for row in g_iter {
if let Some(ref mut writer) = geometries_writer {
writer
.serialize(row.to_wkt().to_string())
.map_err(|e| {
OvertureMapsCollectionError::CsvWriteError(format!(
"Failed to write to geometry file edges-geometries-enumerated.txt.gz: {e}"
))
})?;
}
}
eprintln!();

if let Some(ref mut writer) = geometries_writer {
writer.flush().map_err(|e| {
OvertureMapsCollectionError::CsvWriteError(format!(
"Failed to flush edges-geometries-enumerated.txt.gz: {e}"
))
})?;
}
}
eprintln!();

Expand Down
58 changes: 56 additions & 2 deletions rust/bambam-omf/src/graph/segment_split.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::collections::HashMap;

use geo::{Haversine, Length, LineString};
use routee_compass_core::model::network::{Edge, EdgeId, EdgeListId, Vertex, VertexId};
use uom::si::f64::Length;

use crate::{
collection::{OvertureMapsCollectionError, TransportationSegmentRecord},
Expand Down Expand Up @@ -102,11 +102,65 @@ impl SegmentSplit {
edge_id,
src_vertex_id: VertexId(*src_id),
dst_vertex_id: VertexId(*dst_id),
distance: Length::new::<uom::si::length::meter>(distance as f64),
distance: uom::si::f64::Length::new::<uom::si::length::meter>(distance as f64),
};

Ok(edge)
}
}
}

pub fn create_geometry_from_split(
&self,
segments: &[&TransportationSegmentRecord],
segment_lookup: &HashMap<String, usize>,
) -> Result<LineString<f32>, OvertureMapsCollectionError> {
use OvertureMapsCollectionError as E;

match self {
SegmentSplit::SimpleConnectorSplit { src, dst } => {
let segment_id = &src.segment_id;
let segment_idx = segment_lookup.get(segment_id).ok_or_else(|| {
let msg = format!("missing lookup entry for segment {segment_id}");
E::InvalidSegmentConnectors(msg)
})?;
let segment = segments.get(*segment_idx).ok_or_else(|| {
let msg = format!(
"missing lookup entry for segment {segment_id} with index {segment_idx}"
);
E::InvalidSegmentConnectors(msg)
})?;

let distance_to_src = segment.get_distance_at(src.linear_reference.0)?;
let distance_to_dst = segment.get_distance_at(dst.linear_reference.0)?;
let segment_geometry = segment.get_linestring()?;

let mut out_coords = vec![];

// Add the initial point
out_coords.push(segment.get_coord_at(src.linear_reference.0)?);

// Check all points to see if we need to add them
let mut total_distance = 0.;
for line in segment_geometry.lines() {
let line_distance = Haversine.length(&line);
total_distance += line_distance;

if total_distance <= distance_to_src {
continue;
}
if total_distance >= distance_to_dst {
break;
}

out_coords.push(line.end);
}

// Add final point
out_coords.push(segment.get_coord_at(dst.linear_reference.0)?);

Ok(LineString::new(out_coords))
}
}
}
}
15 changes: 14 additions & 1 deletion rust/bambam-omf/src/graph/serialize_ops.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use geo::Coord;
use geo::{Coord, LineString};
use itertools::Itertools;
use kdam::{tqdm, Bar, BarExt};
use rayon::prelude::*;
Expand Down Expand Up @@ -178,3 +178,16 @@ pub fn create_edges(
})
.collect::<Result<Vec<Edge>, OvertureMapsCollectionError>>()
}

pub fn create_geometries(
segments: &[&TransportationSegmentRecord],
segment_lookup: &HashMap<String, usize>,
splits: &[SegmentSplit],
) -> Result<Vec<LineString<f32>>, OvertureMapsCollectionError> {
splits
.iter()
.collect_vec()
.par_iter()
.map(|split| split.create_geometry_from_split(segments, segment_lookup))
.collect::<Result<Vec<LineString<f32>>, OvertureMapsCollectionError>>()
}
Loading