bambam-omf 0.3.0

OvertureMaps Foundation support for The Behavior and Advanced Mobility Big Access Model
Documentation
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct CliBoundingBox {
    pub xmin: f32,
    pub xmax: f32,
    pub ymin: f32,
    pub ymax: f32,
}

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}"));
    }

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

    let ymin = parse_lat(parts[2])?;
    let ymax = parse_lat(parts[3])?;

    let valid_lon = xmin < xmax;
    let valid_lat = ymin < ymax;

    if !valid_lon {
        Err(format!(
            "bbox: xmin must be less than xmax, but found [{xmin},{xmax}]"
        ))
    } else if !valid_lat {
        Err(format!(
            "bbox: ymin must be less than ymax, but found [{ymin},{ymax}]"
        ))
    } else {
        Ok(CliBoundingBox {
            xmin,
            xmax,
            ymin,
            ymax,
        })
    }
}

impl std::fmt::Display for CliBoundingBox {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{},{},{},{}", self.xmin, self.xmax, self.ymin, self.ymax)
    }
}

fn parse_lat(lat: &str) -> Result<f32, String> {
    parse_num(lat, -90.0, 90.0).map_err(|e| format!("invalid latitude: {e}"))
}

fn parse_lon(lat: &str) -> Result<f32, String> {
    parse_num(lat, -180.0, 180.0).map_err(|e| format!("invalid longitude: {e}"))
}

fn parse_num(s: &str, min: f32, max: f32) -> Result<f32, String> {
    let v = s
        .trim()
        .parse::<f32>()
        .map_err(|_| format!("not a number: {s}"))?;
    if v < min || max < v {
        Err(format!(
            "number '{v}' is not valid, must be in range [{min},{max}]"
        ))
    } else {
        Ok(v)
    }
}