pub mod bbox;
pub mod coordinates;
pub mod distances;
pub mod geohash;
pub use coordinates::{
lat_lon_to_utm, lat_lon_to_xyz, utm_to_lat_lon, xyz_to_lat_lon, EARTH_RADIUS_M, WGS84_A,
WGS84_B, WGS84_E2, WGS84_F,
};
pub use distances::{bearing, destination_point, haversine_distance, vincenty_distance};
pub use geohash::{geohash_decode, geohash_encode, geohash_neighbors, GeoHash, GeoHashCenter};
pub use bbox::{point_in_polygon, polygon_area, BoundingBox};
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_full_pipeline_london() {
let lat = 51.5074_f64;
let lon = -0.1278_f64;
let (x, y, z) = lat_lon_to_xyz(lat, lon, 50.0);
let (lat2, lon2, alt2) = xyz_to_lat_lon(x, y, z);
assert!((lat2 - lat).abs() < 1e-7, "lat={lat2}");
assert!((lon2 - lon).abs() < 1e-7, "lon={lon2}");
assert!((alt2 - 50.0).abs() < 0.001, "alt={alt2}");
let (e, n, zone, north) = lat_lon_to_utm(lat, lon).expect("utm forward");
let (lat3, lon3) = utm_to_lat_lon(e, n, zone, north).expect("utm inverse");
assert!((lat3 - lat).abs() < 1e-5, "utm lat={lat3}");
assert!((lon3 - lon).abs() < 1e-5, "utm lon={lon3}");
let dist = haversine_distance(lat, lon, 48.8566, 2.3522);
assert!((dist - 343_000.0).abs() < 5_000.0, "dist={dist}");
let vd = vincenty_distance(lat, lon, 48.8566, 2.3522).expect("vincenty");
assert!((vd - dist).abs() / dist < 0.005, "vincenty diff");
let hash = geohash_encode(lat, lon, 7).expect("encode");
let (dlat, dlon) = geohash_decode(&hash).expect("decode");
assert!((dlat - lat).abs() < 0.001, "geohash lat={dlat}");
assert!((dlon - lon).abs() < 0.001, "geohash lon={dlon}");
let neighbors = geohash_neighbors(&hash).expect("neighbors");
assert_eq!(neighbors.len(), 8);
let bbox = BoundingBox::new(50.0, 53.0, -2.0, 2.0).expect("bbox");
assert!(bbox.contains(lat, lon));
assert!(!bbox.contains(48.8566, 2.3522)); }
#[test]
fn test_destination_and_bearing_inverse() {
let lat1 = 40.0;
let lon1 = -70.0;
let b = 135.0; let d = 200_000.0;
let (lat2, lon2) = destination_point(lat1, lon1, b, d);
let b2 = bearing(lat1, lon1, lat2, lon2);
assert!((b2 - b).abs() < 0.5, "bearing roundtrip: {b2} vs {b}");
let d2 = haversine_distance(lat1, lon1, lat2, lon2);
assert!((d2 - d).abs() < 500.0, "distance roundtrip: {d2} vs {d}");
}
#[test]
fn test_polygon_area_and_containment() {
let poly = [(0.0, 0.0), (0.0, 10.0), (10.0, 10.0), (10.0, 0.0)];
let area = polygon_area(&poly).expect("area");
assert!(area > 1e11 && area < 2e12, "area={area}");
assert!(point_in_polygon(5.0, 5.0, &poly));
assert!(!point_in_polygon(11.0, 5.0, &poly));
}
#[test]
fn test_geohash_neighbor_count() {
let hash = geohash_encode(35.6762, 139.6503, 5).expect("encode tokyo");
let neighbors = geohash_neighbors(&hash).expect("neighbors");
assert_eq!(neighbors.len(), 8);
for n in &neighbors {
assert!(!n.is_empty());
assert_eq!(n.len(), 5);
}
}
}