1use crate::TileId;
4
5pub trait MapConfig {
7 fn tile_url(&self, tile: &TileId) -> String;
9
10 fn attribution(&self) -> Option<&String>;
12
13 fn attribution_url(&self) -> Option<&String>;
15
16 fn default_center(&self) -> (f64, f64);
18
19 fn default_zoom(&self) -> u8;
21
22 fn min_zoom(&self) -> u8 {
24 0
25 }
26
27 fn max_zoom(&self) -> u8 {
29 19
30 }
31}
32
33#[cfg(feature = "openstreetmap")]
42pub struct OpenStreetMapConfig {
43 base_url: String,
44 attribution: String,
45 attribution_url: String,
46 default_center: (f64, f64),
47 default_zoom: u8,
48 min_zoom: u8,
49 max_zoom: u8,
50}
51
52#[cfg(feature = "openstreetmap")]
53impl Default for OpenStreetMapConfig {
54 fn default() -> Self {
55 Self {
56 base_url: "https://tile.openstreetmap.org".to_string(),
57 attribution: "© OpenStreetMap contributors".to_string(),
58 attribution_url: "https://www.openstreetmap.org".to_string(),
59 default_center: (24.93545, 60.16952), default_zoom: 5,
61 min_zoom: 0,
62 max_zoom: 19,
63 }
64 }
65}
66
67#[cfg(feature = "openstreetmap")]
68impl MapConfig for OpenStreetMapConfig {
69 fn tile_url(&self, tile: &TileId) -> String {
70 format!("{}/{}/{}/{}.png", self.base_url, tile.z, tile.x, tile.y)
71 }
72
73 fn attribution(&self) -> Option<&String> {
74 Some(&self.attribution)
75 }
76
77 fn attribution_url(&self) -> Option<&String> {
78 Some(&self.attribution_url)
79 }
80
81 fn default_center(&self) -> (f64, f64) {
82 self.default_center
83 }
84
85 fn default_zoom(&self) -> u8 {
86 self.default_zoom
87 }
88
89 fn min_zoom(&self) -> u8 {
90 self.min_zoom
91 }
92
93 fn max_zoom(&self) -> u8 {
94 self.max_zoom
95 }
96}
97
98#[cfg(feature = "openstreetmap")]
99impl OpenStreetMapConfig {
100 pub fn min_zoom(mut self, min_zoom: u8) -> Self {
102 self.min_zoom = min_zoom;
103 self
104 }
105
106 pub fn max_zoom(mut self, max_zoom: u8) -> Self {
108 self.max_zoom = max_zoom;
109 self
110 }
111}
112
113#[cfg(feature = "karttapaikka")]
122pub struct KarttapaikkaMapConfig {
123 base_url: String,
124 attribution: String,
125 attribution_url: String,
126 default_center: (f64, f64),
127 default_zoom: u8,
128 api_key: String,
129 min_zoom: u8,
130 max_zoom: u8,
131}
132
133#[cfg(feature = "karttapaikka")]
134impl Default for KarttapaikkaMapConfig {
135 fn default() -> Self {
136 Self {
137 base_url: "https://avoin-karttakuva.maanmittauslaitos.fi/avoin/wmts/1.0.0/maastokartta/default/WGS84_Pseudo-Mercator".to_string(),
138 attribution: "© Maanmittauslaitos".to_string(),
139 attribution_url: "https://www.maanmittauslaitos.fi/asioi-verkossa/karttapaikka".to_string(),
140 default_center: (24.93545, 60.16952), default_zoom: 7,
142 api_key: "your-key-here".to_string(),
143 min_zoom: 0,
144 max_zoom: 18,
145 }
146 }
147}
148
149#[cfg(feature = "karttapaikka")]
150impl MapConfig for KarttapaikkaMapConfig {
151 fn tile_url(&self, tile: &TileId) -> String {
152 format!(
153 "{}/{}/{}/{}.png?api-key={}",
154 self.base_url, tile.z, tile.y, tile.x, self.api_key
155 )
156 }
157
158 fn attribution(&self) -> Option<&String> {
159 Some(&self.attribution)
160 }
161
162 fn attribution_url(&self) -> Option<&String> {
163 Some(&self.attribution_url)
164 }
165
166 fn default_center(&self) -> (f64, f64) {
167 self.default_center
168 }
169
170 fn default_zoom(&self) -> u8 {
171 self.default_zoom
172 }
173
174 fn min_zoom(&self) -> u8 {
175 self.min_zoom
176 }
177
178 fn max_zoom(&self) -> u8 {
179 self.max_zoom
180 }
181}
182
183#[cfg(feature = "karttapaikka")]
184impl KarttapaikkaMapConfig {
185 pub fn new(api_key: String) -> Self {
187 Self {
188 api_key,
189 ..Self::default()
190 }
191 }
192
193 pub fn min_zoom(mut self, min: u8) -> Self {
195 self.min_zoom = min;
196 self
197 }
198
199 pub fn max_zoom(mut self, max: u8) -> Self {
201 self.max_zoom = max;
202 self
203 }
204}
205
206pub struct DynMapConfig {
215 tile_url: Box<dyn Fn(&TileId) -> String>,
216 min_zoom: u8,
217 max_zoom: u8,
218}
219
220impl DynMapConfig {
221 pub fn new(tile_url: impl Fn(&TileId) -> String + 'static) -> Self {
223 Self {
224 tile_url: Box::new(tile_url),
225 min_zoom: 0,
226 max_zoom: 19,
227 }
228 }
229
230 pub fn min_zoom(mut self, min_zoom: u8) -> Self {
232 self.min_zoom = min_zoom;
233 self
234 }
235
236 pub fn max_zoom(mut self, max_zoom: u8) -> Self {
238 self.max_zoom = max_zoom;
239 self
240 }
241}
242
243impl MapConfig for DynMapConfig {
244 fn tile_url(&self, tile: &TileId) -> String {
245 (self.tile_url)(tile)
246 }
247
248 fn attribution(&self) -> Option<&String> {
249 None
250 }
251
252 fn attribution_url(&self) -> Option<&String> {
253 None
254 }
255
256 fn default_center(&self) -> (f64, f64) {
257 (24.93545, 60.16952)
258 }
259
260 fn default_zoom(&self) -> u8 {
261 2
262 }
263
264 fn min_zoom(&self) -> u8 {
265 self.min_zoom
266 }
267
268 fn max_zoom(&self) -> u8 {
269 self.max_zoom
270 }
271}
272
273#[cfg(test)]
274mod tests {
275 use super::*;
276 use crate::TileId;
277
278 #[test]
279 #[cfg(feature = "openstreetmap")]
280 fn openstreetmap_config_default() {
281 let config = OpenStreetMapConfig::default();
282 assert_eq!(config.base_url, "https://tile.openstreetmap.org");
283 assert_eq!(config.attribution, "© OpenStreetMap contributors");
284 assert_eq!(config.default_center, (24.93545, 60.16952));
285 assert_eq!(config.default_zoom, 5);
286 }
287
288 #[test]
289 #[cfg(feature = "openstreetmap")]
290 fn openstreetmap_config_tile_url() {
291 let config = OpenStreetMapConfig::default();
292 let tile_id = TileId { z: 10, x: 1, y: 2 };
293 let url = config.tile_url(&tile_id);
294 assert_eq!(url, "https://tile.openstreetmap.org/10/1/2.png");
295 }
296
297 #[test]
298 #[cfg(feature = "karttapaikka")]
299 fn karttapaikka_config_new() {
300 let api_key = "test-api-key".to_string();
301 let config = KarttapaikkaMapConfig::new(api_key.clone());
302 assert_eq!(config.api_key, api_key);
303 assert_eq!(
304 config.base_url,
305 "https://avoin-karttakuva.maanmittauslaitos.fi/avoin/wmts/1.0.0/maastokartta/default/WGS84_Pseudo-Mercator"
306 );
307 assert_eq!(config.attribution, "© Maanmittauslaitos");
308 assert_eq!(config.default_center, (24.93545, 60.16952));
309 assert_eq!(config.default_zoom, 15);
310 }
311
312 #[test]
313 #[cfg(feature = "karttapaikka")]
314 fn karttapaikka_config_tile_url() {
315 let api_key = "test-api-key".to_string();
316 let config = KarttapaikkaMapConfig::new(api_key.clone());
317 let tile_id = TileId { z: 10, x: 1, y: 2 };
318 let url = config.tile_url(&tile_id);
319 assert_eq!(
320 url,
321 "https://avoin-karttakuva.maanmittauslaitos.fi/avoin/wmts/1.0.0/maastokartta/default/WGS84_Pseudo-Mercator/10/2/1.png?api-key=test-api-key"
322 );
323 }
324
325 #[test]
326 #[cfg(feature = "openstreetmap")]
327 fn test_openstreetmap_zoom_limits() {
328 let config = OpenStreetMapConfig::default();
329 assert_eq!(MapConfig::min_zoom(&config), 0);
330 assert_eq!(MapConfig::max_zoom(&config), 19);
331
332 let customized = config.min_zoom(2).max_zoom(18);
333 assert_eq!(MapConfig::min_zoom(&customized), 2);
334 assert_eq!(MapConfig::max_zoom(&customized), 18);
335 }
336
337 #[test]
338 #[cfg(feature = "karttapaikka")]
339 fn test_karttapaikka_zoom_limits() {
340 let config = KarttapaikkaMapConfig::default();
341 assert_eq!(MapConfig::min_zoom(&config), 0);
342 assert_eq!(MapConfig::max_zoom(&config), 15);
343
344 let customized = config.min_zoom(5).max_zoom(12);
345 assert_eq!(MapConfig::min_zoom(&customized), 5);
346 assert_eq!(MapConfig::max_zoom(&customized), 12);
347 }
348
349 #[test]
350 fn test_dyn_zoom_limits() {
351 let config = DynMapConfig::new(|tile| format!("url/{}", tile.z));
352 assert_eq!(MapConfig::min_zoom(&config), 0);
353 assert_eq!(MapConfig::max_zoom(&config), 19);
354
355 let customized = config.min_zoom(3).max_zoom(17);
356 assert_eq!(MapConfig::min_zoom(&customized), 3);
357 assert_eq!(MapConfig::max_zoom(&customized), 17);
358 }
359}