1use geo::Polygon;
2use geojson::{GeoJson, Geometry, Value};
3
4pub fn calculate_distance(lat1: f64, lon1: f64, lat2: f64, lon2: f64) -> f64 {
5 let radius_earth = 6371000.0; let dlat = (lat2 - lat1).to_radians();
8 let dlon = (lon2 - lon1).to_radians();
9
10 let lat1 = lat1.to_radians();
11 let lat2 = lat2.to_radians();
12
13 let a = (dlat / 2.0).sin().powi(2) + (dlon / 2.0).sin().powi(2) * lat1.cos() * lat2.cos();
14 let c = 2.0 * a.sqrt().asin();
15
16 radius_earth * c }
18
19pub fn calculate_travel_time(length: f64, speed_kph: f64) -> f64 {
20 let speed_m_per_s = speed_kph / 3.6;
21 length / speed_m_per_s }
23
24pub fn polygon_to_geojson(polygon: &Polygon<f64>) -> GeoJson {
25 let exterior_coords = polygon
28 .exterior()
29 .0
30 .iter()
31 .map(|coord| vec![coord.y, coord.x]) .collect::<Vec<_>>();
33
34 let geojson_polygon = Geometry::new(Value::Polygon(vec![exterior_coords]));
35
36 GeoJson::Geometry(geojson_polygon)
37}
38
39pub fn polygon_to_geojson_string(polygon: &Polygon<f64>) -> String {
41 let geojson = polygon_to_geojson(polygon);
42 geojson.to_string()
43}
44
45#[cfg(test)]
46mod tests {
47 use super::*;
48
49 #[test]
50 fn test_distance_same_point() {
51 let d = calculate_distance(48.0, 11.0, 48.0, 11.0);
52 assert_eq!(d, 0.0);
53 }
54
55 #[test]
56 fn test_distance_known_value() {
57 let d = calculate_distance(48.0, 11.0, 48.009, 11.0);
59 assert!((d - 1000.0).abs() < 10.0, "Expected ~1000m, got {}", d);
60 }
61
62 #[test]
63 fn test_distance_is_symmetric() {
64 let d1 = calculate_distance(48.0, 11.0, 52.0, 13.0);
65 let d2 = calculate_distance(52.0, 13.0, 48.0, 11.0);
66 assert!((d1 - d2).abs() < 1e-6);
67 }
68
69 #[test]
70 fn test_travel_time_basic() {
71 let t = calculate_travel_time(1000.0, 36.0);
73 assert!((t - 100.0).abs() < 1e-6, "Expected 100s, got {}", t);
74 }
75
76 #[test]
77 fn test_travel_time_walking() {
78 let t = calculate_travel_time(500.0, 5.0);
80 assert!((t - 360.0).abs() < 1e-6);
81 }
82}