osm-geo-mapper 0.8.0

Navigate OpenStreetMap data in the terminal.
Documentation
use std::{
    collections::BTreeMap,
    fs::File,
};

use geo::prelude::ConvexHull;
use geo_types::MultiPoint;
use osmpbfreader::{
    objects::{ OsmId, OsmObj, Relation, RelationId, Way },
    OsmPbfReader,
};

pub trait HasCoordinates {
    fn get_coordinates(&self, objs: &BTreeMap<OsmId, OsmObj>) -> Vec<(f64, f64)>;
}

pub trait HasCycleCoordinates {
    fn get_coordinates(
        &self,
        objs: &BTreeMap<OsmId, OsmObj>,
        visited: &mut Vec<RelationId>,
    ) -> Vec<(f64, f64)>;
}

impl HasCoordinates for Way {
    fn get_coordinates(&self, objs: &BTreeMap<OsmId, OsmObj>) -> Vec<(f64, f64)> {
        self.nodes
            .iter()
            .filter_map(|&id| {
                let obj = objs.get(&id.into())?;
                let node = obj.node()?;
                Some((node.lon(), node.lat()))
            })
            .collect()
    }
}

impl HasCycleCoordinates for Relation {
    fn get_coordinates(
        &self,
        objs: &BTreeMap<OsmId, OsmObj>,
        visited: &mut Vec<RelationId>,
    ) -> Vec<(f64, f64)> {
        if visited.contains(&self.id) {
            return vec![];
        }
        visited.push(self.id);
        let coordinates: Vec<(f64, f64)> = self
            .refs
            .iter()
            .filter_map(|osm_ref| {
                let obj = objs.get(&osm_ref.member)?;
                let coordinates = match obj {
                    OsmObj::Node(node) => vec![(node.lon(), node.lat())],
                    OsmObj::Way(way) => way.get_coordinates(objs),
                    OsmObj::Relation(rel) => rel.get_coordinates(objs, visited),
                };
                Some(coordinates)
            })
            .flatten()
            .collect();

        let multi_points: MultiPoint<_> = coordinates.into();
        let convex_hull = multi_points.convex_hull();
        convex_hull
            .exterior()
            .points_iter()
            .map(|p| (p.lng(), p.lat()))
            .collect()
    }
}

pub fn parse_pbf_file(filename: String) -> Result<BTreeMap<OsmId, OsmObj>, osmpbfreader::Error> {
    let file = File::open(filename.as_str()).unwrap();
    let mut pbf = OsmPbfReader::new(file);
    pbf.get_objs_and_deps(|_| true)
}