Decode a geohash string to its bounding box. Returns `None` if the geohash contains invalid characters or is empty.
(hash: &str)
| 100 | /// |
| 101 | /// Returns `None` if the geohash contains invalid characters or is empty. |
| 102 | pub fn geohash_decode(hash: &str) -> Option<BoundingBox> { |
| 103 | if hash.is_empty() { |
| 104 | return None; |
| 105 | } |
| 106 | |
| 107 | let mut min_lng = -180.0_f64; |
| 108 | let mut max_lng = 180.0_f64; |
| 109 | let mut min_lat = -90.0_f64; |
| 110 | let mut max_lat = 90.0_f64; |
| 111 | let mut is_lng = true; |
| 112 | |
| 113 | for byte in hash.bytes() { |
| 114 | if byte >= 128 { |
| 115 | return None; |
| 116 | } |
| 117 | let idx = DECODE_TABLE[byte as usize]; |
| 118 | if idx == 255 { |
| 119 | return None; |
| 120 | } |
| 121 | |
| 122 | // Each character encodes 5 bits, MSB first. |
| 123 | for bit in (0..5).rev() { |
| 124 | let on = (idx >> bit) & 1 == 1; |
| 125 | if is_lng { |
| 126 | let mid = (min_lng + max_lng) / 2.0; |
| 127 | if on { |
| 128 | min_lng = mid; |
| 129 | } else { |
| 130 | max_lng = mid; |
| 131 | } |
| 132 | } else { |
| 133 | let mid = (min_lat + max_lat) / 2.0; |
| 134 | if on { |
| 135 | min_lat = mid; |
| 136 | } else { |
| 137 | max_lat = mid; |
| 138 | } |
| 139 | } |
| 140 | is_lng = !is_lng; |
| 141 | } |
| 142 | } |
| 143 | |
| 144 | Some(BoundingBox::new(min_lng, min_lat, max_lng, max_lat)) |
| 145 | } |
| 146 | |
| 147 | /// Decode a geohash to its center point (longitude, latitude). |
| 148 | pub fn geohash_decode_center(hash: &str) -> Option<(f64, f64)> { |