1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
use ogcapi_types::tiles::{OrderedAxes, TileMatrixSet};
use std::path::PathBuf;

#[derive(thiserror::Error, Debug)]
pub enum TileMatrixSetError {
    #[error(transparent)]
    JsonError(#[from] serde_json::Error),
    #[error("{0}: {1}")]
    FileError(PathBuf, #[source] std::io::Error),
}

pub trait TileMatrixSetOps: Sized {
    fn from_json_file(json_path: &str) -> Result<Self, TileMatrixSetError>;
    fn from_json(json: &str) -> Result<Self, TileMatrixSetError>;
    /// Check if CRS has inverted AXIS (lat,lon) instead of (lon,lat).
    fn crs_axis_inverted(&self) -> bool;
}

impl TileMatrixSetOps for TileMatrixSet {
    fn from_json_file(json_path: &str) -> Result<Self, TileMatrixSetError> {
        let content = std::fs::read_to_string(json_path)
            .map_err(|e| TileMatrixSetError::FileError(json_path.into(), e))?;
        TileMatrixSet::from_json(&content)
    }
    fn from_json(json: &str) -> Result<Self, TileMatrixSetError> {
        serde_json::from_str(json).map_err(Into::into)
    }
    /// Check if CRS has inverted AXIS (lat,lon) instead of (lon,lat).
    fn crs_axis_inverted(&self) -> bool {
        if let Some(axes) = &self.ordered_axes {
            ordered_axes_inverted(axes)
        } else {
            false // TODO: Check CRS axis ordering
        }
    }
}

pub(crate) fn ordered_axes_inverted(axes: &OrderedAxes) -> bool {
    first_axes_inverted(&axes[0].to_uppercase())
}

fn first_axes_inverted(first: &str) -> bool {
    first == "Y" || first == "LAT" || first == "N"
}

#[cfg(test)]
mod test {
    use super::TileMatrixSetOps;
    use ogcapi_types::tiles::TileMatrixSet;

    #[test]
    fn parse_tms_example() {
        let tms = TileMatrixSet::from_json_file("./data/WebMercatorQuad.json").unwrap();
        println!("{}", serde_json::to_string_pretty(&tms).unwrap());
    }
}