osm-geo-mapper 0.8.0

Navigate OpenStreetMap data in the terminal.
Documentation
use log::warn;
use geo_types;
use std::sync::Arc;
use crate::{
    features::{ GeoTile, GeoTilesDataStructure },
    geojson_parser,
    nominatim,
    operations,
    osm_parser,
    pbf_parser,
};

#[derive(Debug, Clone)]
pub enum Location {
    Coordinates {
        latitude: f64,
        longitude: f64
    },
    Center
}

#[derive(Debug, Clone)]
pub struct OSMGeoMapper {
    pub data_structure: GeoTilesDataStructure,
    pub coordinates: geo_types::Coordinate<i32>,
    pub radius: u32
}

impl OSMGeoMapper {
    pub fn from_geojson_file_with_radius(geojson_file: String, radius: u32, location: Option<Location>) -> Result<OSMGeoMapper, Box<dyn std::error::Error>> {
        let geojson = geojson_parser::parse_geojson_file(&geojson_file);
        let data_structure = operations::process_geojson(&geojson);
        let coordinates = match location {
            Some(Location::Coordinates { latitude, longitude }) => {
                geo_types::Coordinate {
                    x: operations::to_tile_scale(longitude),
                    y: operations::to_tile_scale(latitude)
                }
            },
            Some(Location::Center) => {
                warn!("Finding center location of geojson file not supported yet");
                geo_types::Coordinate { x: 0, y: 0 }
            },
            None => {
                let (x, y) = data_structure.read().unwrap().keys().nth(0).unwrap().x_y();
                geo_types::Coordinate { x, y }
            }
        };
        Ok(OSMGeoMapper { data_structure, coordinates, radius })
    }

    pub fn from_geojson_file(geojson_file: String, location: Option<Location>) -> Result<OSMGeoMapper, Box<dyn std::error::Error>> {
        OSMGeoMapper::from_geojson_file_with_radius(geojson_file, 0, location)
    }

    pub fn from_osm_file(osm_file: String, location: Option<Location>) -> Result<OSMGeoMapper, Box<dyn std::error::Error>> {
        let osm_data = osm_parser::parse_osm_file(osm_file.to_string())?;
        let radius = 0;
        let data_structure = operations::process_osm(&osm_data);
        let coordinates = match location {
            Some(Location::Coordinates { latitude, longitude }) => {
                geo_types::Coordinate {
                    x: operations::to_tile_scale(longitude),
                    y: operations::to_tile_scale(latitude)
                }
            },
            Some(Location::Center) => {
                warn!("Finding center location of osm file not supported yet");
                geo_types::Coordinate { x: 0, y: 0 }
            },
            None => {
                let (x, y) = data_structure.read().unwrap().keys().nth(0).unwrap().x_y();
                geo_types::Coordinate { x, y }
            }
        };
        Ok(OSMGeoMapper {
            data_structure,
            coordinates,
            radius,
        })
    }

    pub fn from_pbf_file(pbf_file: String, location: Option<Location>) -> Result<OSMGeoMapper, Box<dyn std::error::Error>> {
        let pbf_data = pbf_parser::parse_pbf_file(pbf_file.to_string())?;
        let radius = 0;
        let data_structure = operations::process_pbf(&pbf_data);
        let coordinates = match location {
            Some(Location::Coordinates { latitude, longitude }) => {
                geo_types::Coordinate {
                    x: operations::to_tile_scale(longitude),
                    y: operations::to_tile_scale(latitude)
                }
            },
            Some(Location::Center) => {
                warn!("Finding center location of pbf file not supported yet");
                geo_types::Coordinate { x: 0, y: 0 }
            },
            None => {
                let (x, y) = data_structure.read().unwrap().keys().nth(0).unwrap().x_y();
                geo_types::Coordinate { x, y }
            }
        };
        Ok(OSMGeoMapper {
            data_structure,
            coordinates,
            radius,
        })
    }

    pub fn from_address(address: String, radius: Option<u32>) -> Result<OSMGeoMapper, Box<dyn std::error::Error>> {
        let (latitude, longitude) = nominatim::get_address_lat_lon(address)?;
        OSMGeoMapper::from_lat_lon(latitude, longitude, radius)
    }

    pub fn from_lat_lon(latitude: f64, longitude: f64, radius: Option<u32>) -> Result<OSMGeoMapper, Box<dyn std::error::Error>> {
        let rad = radius.unwrap_or(200);
        let radiusf = operations::from_tile_scale(rad as i32);
        let geojson_file = operations::get_geojson_file_by_lat_lon(latitude, longitude, radiusf)?;
        OSMGeoMapper::from_geojson_file_with_radius(
            geojson_file,
            rad,
            Some(
                Location::Coordinates {
                    latitude,
                    longitude
                }
            )
        )
    }

    pub fn load_more_from_lat_lon(&mut self, latitude: f64, longitude: f64, radius: Option<u32>) -> Result<(), Box<dyn std::error::Error>> {
        let radiusf = operations::from_tile_scale(radius.unwrap_or(200) as i32);
        let geojson_file = operations::get_geojson_file_by_lat_lon(latitude, longitude, radiusf)?;
        let geojson = geojson_parser::parse_geojson_file(&geojson_file.to_string());
        operations::process_geojson_with_data_structure(&geojson, self.data_structure.clone());
        Ok(())
    }

    pub fn load_more_from_address(&mut self, address: String, radius: Option<u32>) -> Result<(), Box<dyn std::error::Error>> {
        let (latitude, longitude) = nominatim::get_address_lat_lon(address)?;
        self.load_more_from_lat_lon(latitude, longitude, radius)
    }

    pub fn load_more_from_geojson_file(&mut self, geojson_file: String) -> Result<(), Box<dyn std::error::Error>> {
        let geojson = geojson_parser::parse_geojson_file(&geojson_file.to_string());
        operations::process_geojson_with_data_structure(&geojson, self.data_structure.clone());
        Ok(())
    }

    pub fn load_more_from_osm_file(&mut self, osm_file: String) -> Result<(), Box<dyn std::error::Error>> {
        let osm_data = osm_parser::parse_osm_file(osm_file.to_string())?;
        operations::process_osm_with_data_structure(&osm_data, self.data_structure.clone());
        Ok(())
    }

    pub fn load_more_from_pbf_file(&mut self, pbf_file: String) -> Result<(), Box<dyn std::error::Error>> {
        let pbf_data = pbf_parser::parse_pbf_file(pbf_file.to_string())?;
        operations::process_pbf_with_data_structure(&pbf_data, self.data_structure.clone());
        Ok(())
    }

    pub fn get(&self, lat: i32, lon: i32) -> Option<Vec<Arc<GeoTile>>> {
        let locked_data_structure = self.data_structure.read().unwrap();
        if let Some(geo_tiles) = locked_data_structure.get(&geo_types::Coordinate { x: lon, y: lat }) {
            return Some(geo_tiles.clone());
        }
        None
    }

    pub fn get_real(&self, lat: f64, lon: f64) -> Option<Vec<Arc<GeoTile>>> {
        let lat = operations::to_tile_scale(lat);
        let lon = operations::to_tile_scale(lon);
        self.get(lat, lon)
    }

    pub fn atomic_clone(&self) -> OSMGeoMapper {
        OSMGeoMapper {
            data_structure: self.data_structure.clone(),
            coordinates: self.coordinates,
            radius: self.radius,
        }
    }
}