h3ron_ndarray/
resolution.rs1use geo_types::{Coord, Rect};
2
3use h3ron::{H3Cell, ToPolygon, H3_MAX_RESOLUTION, H3_MIN_RESOLUTION};
4
5use crate::{
6 error::Error,
7 sphere::{area_squaremeters_linearring, area_squaremeters_rect},
8 transform::Transform,
9 AxisOrder,
10};
11
12pub enum ResolutionSearchMode {
13 MinDiff,
16
17 SmallerThanPixel,
19}
20
21pub fn nearest_h3_resolution(
24 shape: &[usize],
25 transform: &Transform,
26 axis_order: &AxisOrder,
27 search_mode: ResolutionSearchMode,
28) -> Result<u8, Error> {
29 if shape.len() != 2 {
30 return Err(Error::UnsupportedArrayShape);
31 }
32 if shape[0] == 0 || shape[1] == 0 {
33 return Err(Error::EmptyArray);
34 }
35 let bbox_array = Rect::new(
36 transform * Coord::from((0.0_f64, 0.0_f64)),
37 transform
38 * Coord::from((
39 (shape[axis_order.x_axis()] - 1) as f64,
40 (shape[axis_order.y_axis()] - 1) as f64,
41 )),
42 );
43 let area_pixel = area_squaremeters_rect(&bbox_array)
44 / (shape[axis_order.x_axis()] * shape[axis_order.y_axis()]) as f64;
45 let center_of_array = bbox_array.center();
46
47 let mut nearest_h3_res = 0;
48 let mut area_difference = None;
49 for h3_res in H3_MIN_RESOLUTION..=H3_MAX_RESOLUTION {
50 let area_h3_index = area_squaremeters_linearring(
53 H3Cell::from_coordinate(center_of_array, h3_res)?
54 .to_polygon()?
55 .exterior(),
56 );
57
58 match search_mode {
59 ResolutionSearchMode::SmallerThanPixel => {
60 if area_h3_index <= area_pixel {
61 nearest_h3_res = h3_res;
62 break;
63 }
64 }
65
66 ResolutionSearchMode::MinDiff => {
67 let new_area_difference = if area_h3_index > area_pixel {
68 area_h3_index - area_pixel
69 } else {
70 area_pixel - area_h3_index
71 };
72 if let Some(old_area_difference) = area_difference {
73 if old_area_difference < new_area_difference {
74 nearest_h3_res = h3_res - 1;
75 break;
76 } else {
77 area_difference = Some(new_area_difference);
78 }
79 } else {
80 area_difference = Some(new_area_difference);
81 }
82 }
83 }
84 }
85
86 Ok(nearest_h3_res)
87}
88
89#[cfg(test)]
90mod tests {
91 use crate::resolution::{nearest_h3_resolution, ResolutionSearchMode};
92 use crate::transform::Transform;
93 use crate::AxisOrder;
94
95 #[test]
96 fn test_nearest_h3_resolution() {
97 let gt = Transform::from_rasterio(&[
99 0.0011965049999999992,
100 0.0,
101 8.11377,
102 0.0,
103 -0.001215135,
104 49.40792,
105 ]);
106 let h3_res1 = nearest_h3_resolution(
107 &[2000_usize, 2000_usize],
108 >,
109 &AxisOrder::YX,
110 ResolutionSearchMode::MinDiff,
111 )
112 .unwrap();
113 assert_eq!(h3_res1, 10); let h3_res2 = nearest_h3_resolution(
116 &[2000_usize, 2000_usize],
117 >,
118 &AxisOrder::YX,
119 ResolutionSearchMode::SmallerThanPixel,
120 )
121 .unwrap();
122 assert_eq!(h3_res2, 11); }
124}