solverforge_maps/routing/
config.rs1use 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}