use std::os::raw::c_int;
use h3ron_h3_sys::H3Index;
use crate::{max_grid_disk_size, Error, H3Cell, Index};
pub struct GridDiskBuilder {
k_min: u32,
k_max: u32,
k_ring_indexes: Vec<H3Index>,
k_ring_distances: Vec<c_int>,
k_ring_size: usize,
current_pos: usize,
}
impl GridDiskBuilder {
pub fn create(k_min: u32, k_max: u32) -> Result<Self, Error> {
let k_ring_size = max_grid_disk_size(k_max)?;
let k_ring_indexes = vec![0; k_ring_size];
let k_ring_distances = vec![0; k_ring_size];
Ok(Self {
k_min,
k_max,
k_ring_indexes,
k_ring_distances,
k_ring_size,
current_pos: k_ring_size, })
}
#[inline(always)]
fn rewind_iterator(&mut self) {
self.current_pos = 0;
}
pub fn build_grid_disk(&mut self, cell: &H3Cell) -> Result<&mut Self, Error> {
Error::check_returncode(unsafe {
std::ptr::write_bytes(self.k_ring_indexes.as_mut_ptr(), 0, self.k_ring_size);
std::ptr::write_bytes(self.k_ring_distances.as_mut_ptr(), 0, self.k_ring_size);
h3ron_h3_sys::gridDiskDistances(
cell.h3index(),
self.k_max as c_int,
self.k_ring_indexes.as_mut_ptr(),
self.k_ring_distances.as_mut_ptr(),
)
})?;
self.rewind_iterator();
Ok(self)
}
}
impl Iterator for GridDiskBuilder {
type Item = (H3Cell, u32);
fn next(&mut self) -> Option<Self::Item> {
while self.current_pos < self.k_ring_size {
let pos = self.current_pos;
self.current_pos += 1;
let h3index = self.k_ring_indexes[pos];
let k = self.k_ring_distances[pos] as u32;
if h3index == 0 || k < self.k_min {
continue;
}
return Some((H3Cell::new(h3index), k));
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.k_ring_size - self.current_pos, None)
}
}