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