use crate::types::Coordinate;
const EARTH_RADIUS_METERS: f64 = 6371000.0;
pub fn haversine_distance(coord1: Coordinate, coord2: Coordinate) -> f64 {
let lat1 = coord1.lat().to_radians();
let lat2 = coord2.lat().to_radians();
let lon1 = coord1.lon().to_radians();
let lon2 = coord2.lon().to_radians();
let dlat = lat2 - lat1;
let dlon = lon2 - lon1;
let a = (dlat / 2.0).sin().powi(2) + lat1.cos() * lat2.cos() * (dlon / 2.0).sin().powi(2);
let c = 2.0 * a.sqrt().atan2((1.0 - a).sqrt());
EARTH_RADIUS_METERS * c
}
pub(crate) fn calculate_bbox_offsets(center: Coordinate, radius_meters: f64) -> (f64, f64) {
let lat_offset = radius_meters / 111320.0;
let lon_offset = radius_meters / (111320.0 * center.lat().to_radians().cos());
(lat_offset, lon_offset)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_haversine_distance_same_point() {
let tokyo = Coordinate::new(35.6812, 139.7671).unwrap();
let distance = haversine_distance(tokyo, tokyo);
assert!(distance.abs() < 0.01, "同一座標の距離は0に近い値");
}
#[test]
fn test_haversine_distance_tokyo_yokohama() {
let tokyo = Coordinate::new(35.6812, 139.7671).unwrap();
let yokohama = Coordinate::new(35.4437, 139.6380).unwrap();
let distance = haversine_distance(tokyo, yokohama);
assert!(distance > 27000.0 && distance < 29000.0, "距離は約28km");
}
#[test]
fn test_haversine_distance_symmetric() {
let coord1 = Coordinate::new(35.6812, 139.7671).unwrap();
let coord2 = Coordinate::new(35.4437, 139.6380).unwrap();
let dist1 = haversine_distance(coord1, coord2);
let dist2 = haversine_distance(coord2, coord1);
assert!((dist1 - dist2).abs() < 0.01, "距離計算は対称");
}
#[test]
fn test_calculate_bbox_offsets_positive() {
let tokyo = Coordinate::new(35.6812, 139.7671).unwrap();
let (lat_offset, lon_offset) = calculate_bbox_offsets(tokyo, 1000.0);
assert!(lat_offset > 0.008 && lat_offset < 0.01);
assert!(lon_offset > lat_offset);
}
#[test]
fn test_calculate_bbox_offsets_zero_radius() {
let tokyo = Coordinate::new(35.6812, 139.7671).unwrap();
let (lat_offset, lon_offset) = calculate_bbox_offsets(tokyo, 0.0);
assert_eq!(lat_offset, 0.0);
assert_eq!(lon_offset, 0.0);
}
}