use crate::coords::face_ijk::{_face_ijk_pent_to_cell_boundary, _face_ijk_to_cell_boundary, _face_ijk_to_geo};
use crate::h3_index::inspection::{is_pentagon, is_valid_cell};
use crate::h3_index::{_h3_to_face_ijk, get_resolution};
use crate::types::{CellBoundary, FaceIJK, H3Error, H3Index, LatLng};
pub fn cell_to_lat_lng(cell: H3Index) -> Result<LatLng, H3Error> {
if !is_valid_cell(cell) {
return Err(H3Error::CellInvalid);
}
let mut fijk = FaceIJK::default();
_h3_to_face_ijk(cell, &mut fijk)?;
let mut geo = LatLng::default();
_face_ijk_to_geo(&fijk, get_resolution(cell), &mut geo);
Ok(geo)
}
pub fn cell_to_boundary(cell: H3Index) -> Result<CellBoundary, H3Error> {
if !is_valid_cell(cell) {
return Err(H3Error::CellInvalid);
}
let mut fijk = FaceIJK::default();
_h3_to_face_ijk(cell, &mut fijk)?;
let mut boundary = CellBoundary::default();
let res = get_resolution(cell);
if is_pentagon(cell) {
_face_ijk_pent_to_cell_boundary(&fijk, res, 0, crate::constants::NUM_PENT_VERTS as i32, &mut boundary);
} else {
_face_ijk_to_cell_boundary(&fijk, res, 0, crate::constants::NUM_HEX_VERTS as i32, &mut boundary);
}
Ok(boundary)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::constants::MAX_CELL_BNDRY_VERTS;
use crate::h3_index::inspection::is_valid_cell;
use crate::indexing::to_h3::lat_lng_to_cell; use crate::latlng::_set_geo_degs;
use crate::types::{H3_NULL};
#[test]
fn test_cell_to_lat_lng_invalid_input() {
assert_eq!(cell_to_lat_lng(H3_NULL), Err(H3Error::CellInvalid));
let mut invalid_h = H3Index(0x85283473fffffff); crate::h3_index::set_mode(&mut invalid_h, crate::constants::H3_DIRECTEDEDGE_MODE as u8);
assert_eq!(cell_to_lat_lng(invalid_h), Err(H3Error::CellInvalid));
}
#[test]
fn test_cell_to_boundary_invalid_input() {
assert_eq!(cell_to_boundary(H3_NULL).map_err(|e| e), Err(H3Error::CellInvalid));
let mut invalid_h = H3Index(0x85283473fffffff); crate::h3_index::set_mode(&mut invalid_h, crate::constants::H3_DIRECTEDEDGE_MODE as u8);
assert_eq!(cell_to_boundary(invalid_h).map_err(|e| e), Err(H3Error::CellInvalid));
}
#[test]
fn test_cell_to_lat_lng_and_boundary_roundtrip() {
let mut geo_orig = LatLng::default();
_set_geo_degs(&mut geo_orig, 37.779, -122.419);
for res in 0..=10 {
let cell = lat_lng_to_cell(&geo_orig, res).unwrap();
assert!(is_valid_cell(cell));
let center_geo = cell_to_lat_lng(cell).unwrap();
let cell_from_center = lat_lng_to_cell(¢er_geo, res).unwrap();
assert_eq!(
cell_from_center, cell,
"Center of cell should re-index to itself at res {}",
res
);
let boundary = cell_to_boundary(cell).unwrap();
if crate::h3_index::inspection::is_pentagon(cell) {
assert!(
boundary.num_verts >= 5 && boundary.num_verts <= MAX_CELL_BNDRY_VERTS,
"Pentagon boundary has between 5 and {} verts, got {} at res {}",
MAX_CELL_BNDRY_VERTS,
boundary.num_verts,
res
);
} else {
assert!(
boundary.num_verts >= 6 && boundary.num_verts <= MAX_CELL_BNDRY_VERTS,
"Hexagon boundary has between 6 and {} verts, got {} at res {}",
MAX_CELL_BNDRY_VERTS,
boundary.num_verts,
res
);
}
for i in 0..boundary.num_verts {
assert!(
boundary.verts[i].lat.is_finite() && boundary.verts[i].lng.is_finite(),
"Boundary vertex {} is not finite for cell {:x} res {}",
i,
cell.0,
res
);
assert!(
boundary.verts[i].lat.abs() <= crate::constants::M_PI_2 + crate::constants::EPSILON_RAD,
"Boundary vertex {} lat out of range for cell {:x} res {}",
i,
cell.0,
res
);
}
}
}
}