use crate::base32;
use crate::LEFT;
use crate::RIGHT;
use std::collections::VecDeque;
pub fn encode(latitude: f32, longitude: f32, length_geohash: u32) -> String {
if !(-90.0..=90.0).contains(&latitude) || !(-180.0..=180.0).contains(&longitude) {
panic!("input coordinates out of bound");
}
let mut lat_info = CoordInfo {
bound: [-90.0, 90.0],
coord: latitude,
};
let mut long_info = CoordInfo {
bound: [-180.0, 180.0],
coord: longitude,
};
let mut coord_queue = VecDeque::from([&mut long_info, &mut lat_info]);
let geohash_string: String = (0..length_geohash)
.into_iter()
.map(|_| get_geo_bit(&mut coord_queue))
.map(|a| base32::encode_b32(&a))
.collect();
geohash_string
}
fn get_geo_bit(coord_queue: &mut VecDeque<&mut CoordInfo>) -> u8 {
return [4_u8, 3, 2, 1, 0]
.iter()
.map(|i| cal_bit(coord_queue, *i))
.reduce(|x, y| x | y)
.unwrap();
}
fn cal_bit(coord_queue: &mut VecDeque<&mut CoordInfo>, i: u8) -> u8 {
let mut coord_info_inst = coord_queue.pop_front().unwrap();
let mid = &(coord_info_inst.bound).iter().sum::<f32>() / 2.0;
if mid <= coord_info_inst.coord {
coord_info_inst.bound[LEFT] = mid;
coord_queue.push_back(coord_info_inst);
1 << i
} else {
coord_info_inst.bound[RIGHT] = mid;
coord_queue.push_back(coord_info_inst);
0
}
}
struct CoordInfo {
bound: [f32; 2],
coord: f32,
}