solverforge_maps/routing/
config.rs

1//! Configuration for road network operations.
2
3use std::path::PathBuf;
4use std::time::Duration;
5
6#[derive(Debug, Clone)]
7pub struct SpeedProfile {
8    pub motorway: f64,
9    pub trunk: f64,
10    pub primary: f64,
11    pub secondary: f64,
12    pub tertiary: f64,
13    pub residential: f64,
14    pub unclassified: f64,
15    pub service: f64,
16    pub living_street: f64,
17    pub default: f64,
18}
19
20impl Default for SpeedProfile {
21    fn default() -> Self {
22        Self {
23            motorway: 100.0,
24            trunk: 80.0,
25            primary: 60.0,
26            secondary: 50.0,
27            tertiary: 40.0,
28            residential: 30.0,
29            unclassified: 30.0,
30            service: 20.0,
31            living_street: 10.0,
32            default: 30.0,
33        }
34    }
35}
36
37impl SpeedProfile {
38    pub fn speed_mps(&self, maxspeed: Option<&str>, highway: &str) -> f64 {
39        let kmh = maxspeed
40            .and_then(|v| self.parse_maxspeed(v))
41            .unwrap_or_else(|| self.highway_speed(highway));
42        kmh * 1000.0 / 3600.0
43    }
44
45    fn highway_speed(&self, highway: &str) -> f64 {
46        match highway {
47            "motorway" | "motorway_link" => self.motorway,
48            "trunk" | "trunk_link" => self.trunk,
49            "primary" | "primary_link" => self.primary,
50            "secondary" | "secondary_link" => self.secondary,
51            "tertiary" | "tertiary_link" => self.tertiary,
52            "residential" => self.residential,
53            "unclassified" => self.unclassified,
54            "service" => self.service,
55            "living_street" => self.living_street,
56            _ => self.default,
57        }
58    }
59
60    fn parse_maxspeed(&self, value: &str) -> Option<f64> {
61        let value = value.trim();
62
63        match value.to_lowercase().as_str() {
64            "walk" => return Some(5.0),
65            "none" | "unlimited" => return None,
66            _ => {}
67        }
68
69        let (num_str, is_mph) = if let Some(s) = value.strip_suffix("mph") {
70            (s.trim(), true)
71        } else if let Some(s) = value.strip_suffix("km/h") {
72            (s.trim(), false)
73        } else if let Some(s) = value.strip_suffix("kmh") {
74            (s.trim(), false)
75        } else {
76            (value, false)
77        };
78
79        let kmh: f64 = num_str.parse().ok()?;
80        if kmh <= 0.0 || kmh > 300.0 {
81            return None;
82        }
83
84        Some(if is_mph { kmh * 1.60934 } else { kmh })
85    }
86}
87
88#[derive(Debug, Clone)]
89pub struct NetworkConfig {
90    pub overpass_url: String,
91    pub cache_dir: PathBuf,
92    pub connect_timeout: Duration,
93    pub read_timeout: Duration,
94    pub speed_profile: SpeedProfile,
95    pub highway_types: Vec<&'static str>,
96}
97
98impl Default for NetworkConfig {
99    fn default() -> Self {
100        Self {
101            overpass_url: "https://overpass-api.de/api/interpreter".to_string(),
102            cache_dir: PathBuf::from(".osm_cache"),
103            connect_timeout: Duration::from_secs(30),
104            read_timeout: Duration::from_secs(180),
105            speed_profile: SpeedProfile::default(),
106            highway_types: vec![
107                "motorway",
108                "trunk",
109                "primary",
110                "secondary",
111                "tertiary",
112                "residential",
113                "unclassified",
114                "service",
115                "living_street",
116            ],
117        }
118    }
119}
120
121impl NetworkConfig {
122    pub fn new() -> Self {
123        Self::default()
124    }
125
126    pub fn overpass_url(mut self, url: impl Into<String>) -> Self {
127        self.overpass_url = url.into();
128        self
129    }
130
131    pub fn cache_dir(mut self, path: impl Into<PathBuf>) -> Self {
132        self.cache_dir = path.into();
133        self
134    }
135
136    pub fn connect_timeout(mut self, timeout: Duration) -> Self {
137        self.connect_timeout = timeout;
138        self
139    }
140
141    pub fn read_timeout(mut self, timeout: Duration) -> Self {
142        self.read_timeout = timeout;
143        self
144    }
145
146    pub fn speed_profile(mut self, profile: SpeedProfile) -> Self {
147        self.speed_profile = profile;
148        self
149    }
150
151    pub fn highway_types(mut self, types: Vec<&'static str>) -> Self {
152        self.highway_types = types;
153        self
154    }
155
156    pub(crate) fn highway_regex(&self) -> String {
157        format!("^({})$", self.highway_types.join("|"))
158    }
159}