Skip to content

Commit

Permalink
Implement optional nodes on ways mode
Browse files Browse the repository at this point in the history
There is an optional feature `LocationsOnWays` available on OSM PBF files. It can be generated with [osmium add-locations-to-ways ...](https://docs.osmcode.org/osmium/latest/osmium-add-locations-to-ways.html), initially described [here](https://blog.jochentopf.com/2016-04-20-node-locations-on-ways.html), and documented at [osm wiki](https://wiki.openstreetmap.org/wiki/PBF_Format#Ways_and_Relations).

This PR implement support for this feature in the same way as `way.refs()`.

* Unit tests have been updated to test for required and optional features
* Added refs() tests
* added approx equality (could be used for all other tests too)
* created a test file structure to keep track of what file has what features
* a few helper utilities

Should `nodes()` return None if the file has no `LocationsOnWays` set?
  • Loading branch information
nyurik committed Feb 17, 2022
1 parent 6c645a1 commit 36c475e
Show file tree
Hide file tree
Showing 4 changed files with 293 additions and 37 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,6 @@ flate2 = { version = "1.0", optional = true }
inflate = "0.4"
memmap = "0.7"
rayon = "1.0"

[dev-dependencies]
assert_approx_eq = "1.1.0"
87 changes: 86 additions & 1 deletion src/elements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use dense::DenseNode;
use error::Result;
use proto::osmformat;
use proto::osmformat::PrimitiveBlock;
use std;

/// An enum with the OSM core elements: nodes, ways and relations.
#[derive(Clone, Debug)]
Expand Down Expand Up @@ -196,6 +195,19 @@ impl<'a> Way<'a> {
}
}

/// Returns an iterator over the way's nodes. Each node is a pair of lat,lng.
/// Only available on osm.pbf files with the optional LocationsOnWays feature.
pub fn nodes(&self) -> WayNodesIter<'a> {
// TODO: change to Option, return None if the file does not support LocationsOnWays feature
WayNodesIter {
block: self.block,
dlats: self.osmway.get_lat().iter(),
dlons: self.osmway.get_lon().iter(),
clat: 0,
clon: 0,
}
}

/// Returns a slice of delta coded node ids.
pub fn raw_refs(&self) -> &[i64] {
self.osmway.get_refs()
Expand Down Expand Up @@ -330,6 +342,79 @@ impl<'a> Iterator for WayRefIter<'a> {

impl<'a> ExactSizeIterator for WayRefIter<'a> {}

pub struct WayNode {
lat: i64,
lon: i64,
}

impl WayNode {
/// Returns the latitude coordinate in degrees.
pub fn lat(&self) -> f64 {
1e-9 * self.nano_lat() as f64
}

/// Returns the latitude coordinate in nanodegrees (10⁻⁹).
pub fn nano_lat(&self) -> i64 {
self.lat
}

/// Returns the latitude coordinate in decimicrodegrees (10⁻⁷).
pub fn decimicro_lat(&self) -> i32 {
(self.nano_lat() / 100) as i32
}

/// Returns the longitude coordinate in degrees.
pub fn lon(&self) -> f64 {
1e-9 * self.nano_lon() as f64
}

/// Returns the longitude in nanodegrees (10⁻⁹).
pub fn nano_lon(&self) -> i64 {
self.lon
}

/// Returns the longitude coordinate in decimicrodegrees (10⁻⁷).
pub fn decimicro_lon(&self) -> i32 {
(self.nano_lon() / 100) as i32
}
}

/// An iterator over the lat,lng of a way.
#[derive(Clone, Debug)]
pub struct WayNodesIter<'a> {
block: &'a osmformat::PrimitiveBlock,
dlats: std::slice::Iter<'a, i64>,
dlons: std::slice::Iter<'a, i64>,
clat: i64,
clon: i64,
}

impl<'a> Iterator for WayNodesIter<'a> {
type Item = WayNode;

fn next(&mut self) -> Option<Self::Item> {
match (self.dlats.next(), self.dlons.next()) {
(Some(&dlat), Some(&dlon)) => {
self.clat += dlat;
self.clon += dlon;
Some(WayNode {
lat: self.block.get_lat_offset()
+ i64::from(self.block.get_granularity()) * self.clat,
lon: self.block.get_lon_offset()
+ i64::from(self.block.get_granularity()) * self.clon,
})
}
_ => None,
}
}

fn size_hint(&self) -> (usize, Option<usize>) {
self.dlats.size_hint()
}
}

impl<'a> ExactSizeIterator for WayNodesIter<'a> {}

/// The element type of a relation member.
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum RelMemberType {
Expand Down
Binary file added tests/loc_on_ways.osm.pbf
Binary file not shown.
Loading

0 comments on commit 36c475e

Please sign in to comment.