h3o_cli/commands/
resolution_info.rs

1//! Expose resolution information.
2
3use anyhow::Result as AnyResult;
4use clap::{Parser, ValueEnum};
5use h3o::Resolution;
6use serde::Serialize;
7use std::fmt;
8
9/// Print cell statistics per resolution.
10#[derive(Parser, Debug)]
11pub struct Args {
12    /// h3o index.
13    #[arg(short, long)]
14    resolution: Option<Resolution>,
15
16    /// Output format.
17    #[arg(short, long, value_enum, default_value_t = Format::Text)]
18    format: Format,
19
20    /// Prettify the output (JSON only).
21    #[arg(short, long, default_value_t = false)]
22    pretty: bool,
23}
24
25#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueEnum)]
26enum Format {
27    Text,
28    Json,
29}
30
31/// Run the `indexDecode` command.
32pub fn run(args: &Args) -> AnyResult<()> {
33    if let Some(resolution) = args.resolution {
34        let info = ResolutionInfo::from(resolution);
35        match args.format {
36            Format::Text => println!("{info}"),
37            Format::Json => crate::json::print(&info, args.pretty)?,
38        }
39        return Ok(());
40    }
41
42    match args.format {
43        Format::Text => {
44            println!("╔═{c:═>10}═╦═{c:═>15}═╦═{c:═>20}═╦═{c:═>14}═╗", c = '═');
45            println!(
46                "║ {:<10} ║ {:<15} ║ {:<20} ║ {:<14} ║",
47                "Resolution", "Cell count", "Hexagon area", "Edge length"
48            );
49            println!("╠═{c:═>10}═╬═{c:═>15}═╬═{c:═>20}═╬═{c:═>14}═╣", c = '═');
50            for resolution in
51                Resolution::range(Resolution::Zero, Resolution::Fifteen)
52            {
53                let info = ResolutionInfo::from(resolution);
54                let (area, area_unit, length, length_unit) = if info.resolution
55                    < Resolution::Eight
56                {
57                    (info.hexagon_area_km2, "km2", info.edge_length_km, "km")
58                } else {
59                    (
60                        info.hexagon_area_km2 * 1e6,
61                        "m2",
62                        info.edge_length_km * 1e3,
63                        "m",
64                    )
65                };
66                println!(
67                    "║ {:>10} ║ {:>15} ║ {:16.3} {:<3} ║ {:11.3} {:<2} ║",
68                    u8::from(info.resolution),
69                    info.cell_count,
70                    area,
71                    area_unit,
72                    length,
73                    length_unit
74                );
75            }
76            println!("╚═{c:═>10}═╩═{c:═>15}═╩═{c:═>20}═╩═{c:═>14}═╝", c = '═');
77        }
78        Format::Json => {
79            let infos =
80                Resolution::range(Resolution::Zero, Resolution::Fifteen)
81                    .map(Into::into)
82                    .collect::<Vec<ResolutionInfo>>();
83            crate::json::print(&infos, args.pretty)?;
84        }
85    }
86
87    Ok(())
88}
89
90// -----------------------------------------------------------------------------
91
92#[derive(Serialize)]
93struct ResolutionInfo {
94    resolution: Resolution,
95    cell_count: u64,
96    hexagon_area_km2: f64,
97    edge_length_km: f64,
98}
99
100impl From<Resolution> for ResolutionInfo {
101    fn from(value: Resolution) -> Self {
102        Self {
103            resolution: value,
104            cell_count: value.cell_count(),
105            hexagon_area_km2: value.area_km2(),
106            edge_length_km: value.edge_length_km(),
107        }
108    }
109}
110
111impl fmt::Display for ResolutionInfo {
112    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113        writeln!(f, "resolution:   {}", self.resolution)?;
114        writeln!(f, "cell count:   {}", self.cell_count)?;
115        if self.resolution < Resolution::Eight {
116            writeln!(f, "hexagon area: {} km2", self.hexagon_area_km2)?;
117            write!(f, "edge length:  {} km", self.edge_length_km)
118        } else {
119            writeln!(f, "hexagon area: {} m2", self.hexagon_area_km2 * 1e6)?;
120            write!(f, "edge length:  {} m", self.edge_length_km * 1e3)
121        }
122    }
123}