Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2010-2013 Jiri Techet <techet@gmail.com>
3 : : * Copyright (C) 2019 Marcus Lundblad <ml@update.uu.se>
4 : : *
5 : : * This library is free software; you can redistribute it and/or
6 : : * modify it under the terms of the GNU Lesser General Public
7 : : * License as published by the Free Software Foundation; either
8 : : * version 2.1 of the License, or (at your option) any later version.
9 : : *
10 : : * This library is distributed in the hope that it will be useful,
11 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 : : * Lesser General Public License for more details.
14 : : *
15 : : * You should have received a copy of the GNU Lesser General Public
16 : : * License along with this library; if not, write to the Free Software
17 : : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 : : */
19 : :
20 : : /**
21 : : * ShumateMapSource:
22 : : *
23 : : * The base class for all map sources. Map sources fill [class@Tile] objects
24 : : * with images from various sources: a web API, for example, or a test pattern
25 : : * generated on demand.
26 : : *
27 : : * The most common map source is [class@RasterRenderer], which fetches tiles
28 : : * using a [class@TileDownloader].
29 : : */
30 : :
31 : : #include "shumate-map-source.h"
32 : : #include "shumate-location.h"
33 : : #include "shumate-enum-types.h"
34 : :
35 : : #include <math.h>
36 : :
37 : : typedef struct {
38 : : char *id;
39 : : char *name;
40 : : char *license;
41 : : char *license_uri;
42 : : guint min_zoom_level;
43 : : guint max_zoom_level;
44 : : guint tile_size;
45 : : ShumateMapProjection projection;
46 : : } ShumateMapSourcePrivate;
47 : :
48 [ + + + - ]: 2878 : G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ShumateMapSource, shumate_map_source, G_TYPE_OBJECT);
49 : :
50 : : enum
51 : : {
52 : : PROP_ID = 1,
53 : : PROP_NAME,
54 : : PROP_LICENSE,
55 : : PROP_LICENSE_URI,
56 : : PROP_MIN_ZOOM_LEVEL,
57 : : PROP_MAX_ZOOM_LEVEL,
58 : : PROP_TILE_SIZE,
59 : : PROP_PROJECTION,
60 : : N_PROPERTIES
61 : : };
62 : :
63 : : static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
64 : :
65 : : static void
66 : 33 : shumate_map_source_finalize (GObject *object)
67 : : {
68 : 33 : ShumateMapSource *map_source = SHUMATE_MAP_SOURCE (object);
69 : 33 : ShumateMapSourcePrivate *priv = shumate_map_source_get_instance_private (map_source);
70 : :
71 [ + - ]: 33 : g_clear_pointer (&priv->id, g_free);
72 [ + + ]: 33 : g_clear_pointer (&priv->name, g_free);
73 [ + + ]: 33 : g_clear_pointer (&priv->license, g_free);
74 [ + + ]: 33 : g_clear_pointer (&priv->license_uri, g_free);
75 : :
76 : 33 : G_OBJECT_CLASS (shumate_map_source_parent_class)->finalize (object);
77 : 33 : }
78 : :
79 : : static void
80 : 0 : shumate_map_source_get_property (GObject *object,
81 : : guint prop_id,
82 : : GValue *value,
83 : : GParamSpec *pspec)
84 : : {
85 : 0 : ShumateMapSource *map_source = SHUMATE_MAP_SOURCE (object);
86 : :
87 [ # # # # : 0 : switch (prop_id)
# # # #
# ]
88 : : {
89 : 0 : case PROP_ID:
90 : 0 : g_value_set_string (value, shumate_map_source_get_id (map_source));
91 : 0 : break;
92 : :
93 : 0 : case PROP_NAME:
94 : 0 : g_value_set_string (value, shumate_map_source_get_name (map_source));
95 : 0 : break;
96 : :
97 : 0 : case PROP_LICENSE:
98 : 0 : g_value_set_string (value, shumate_map_source_get_license (map_source));
99 : 0 : break;
100 : :
101 : 0 : case PROP_LICENSE_URI:
102 : 0 : g_value_set_string (value, shumate_map_source_get_license_uri (map_source));
103 : 0 : break;
104 : :
105 : 0 : case PROP_MIN_ZOOM_LEVEL:
106 : 0 : g_value_set_uint (value, shumate_map_source_get_min_zoom_level (map_source));
107 : 0 : break;
108 : :
109 : 0 : case PROP_MAX_ZOOM_LEVEL:
110 : 0 : g_value_set_uint (value, shumate_map_source_get_max_zoom_level (map_source));
111 : 0 : break;
112 : :
113 : 0 : case PROP_TILE_SIZE:
114 : 0 : g_value_set_uint (value, shumate_map_source_get_tile_size (map_source));
115 : 0 : break;
116 : :
117 : 0 : case PROP_PROJECTION:
118 : 0 : g_value_set_enum (value, shumate_map_source_get_projection (map_source));
119 : 0 : break;
120 : :
121 : 0 : default:
122 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
123 : : }
124 : 0 : }
125 : :
126 : :
127 : : static void
128 : 264 : shumate_map_source_set_property (GObject *object,
129 : : guint prop_id,
130 : : const GValue *value,
131 : : GParamSpec *pspec)
132 : : {
133 : 264 : ShumateMapSource *map_source = SHUMATE_MAP_SOURCE (object);
134 : :
135 [ + + + + : 264 : switch (prop_id)
+ + + +
- ]
136 : : {
137 : 33 : case PROP_ID:
138 : 66 : shumate_map_source_set_id (map_source,
139 : 33 : g_value_get_string (value));
140 : 33 : break;
141 : :
142 : 33 : case PROP_NAME:
143 : 66 : shumate_map_source_set_name (map_source,
144 : 33 : g_value_get_string (value));
145 : 33 : break;
146 : :
147 : 33 : case PROP_LICENSE:
148 : 66 : shumate_map_source_set_license (map_source,
149 : 33 : g_value_get_string (value));
150 : 33 : break;
151 : :
152 : 33 : case PROP_LICENSE_URI:
153 : 66 : shumate_map_source_set_license_uri (map_source,
154 : 33 : g_value_get_string (value));
155 : 33 : break;
156 : :
157 : 33 : case PROP_MIN_ZOOM_LEVEL:
158 : 33 : shumate_map_source_set_min_zoom_level (map_source,
159 : : g_value_get_uint (value));
160 : 33 : break;
161 : :
162 : 33 : case PROP_MAX_ZOOM_LEVEL:
163 : 33 : shumate_map_source_set_max_zoom_level (map_source,
164 : : g_value_get_uint (value));
165 : 33 : break;
166 : :
167 : 33 : case PROP_TILE_SIZE:
168 : 33 : shumate_map_source_set_tile_size (map_source,
169 : : g_value_get_uint (value));
170 : 33 : break;
171 : :
172 : 33 : case PROP_PROJECTION:
173 : 66 : shumate_map_source_set_projection (map_source,
174 : 33 : g_value_get_enum (value));
175 : 33 : break;
176 : :
177 : 0 : default:
178 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
179 : : }
180 : 264 : }
181 : :
182 : : static void
183 : 10 : shumate_map_source_class_init (ShumateMapSourceClass *klass)
184 : : {
185 : 10 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
186 : :
187 : 10 : object_class->set_property = shumate_map_source_set_property;
188 : 10 : object_class->get_property = shumate_map_source_get_property;
189 : 10 : object_class->finalize = shumate_map_source_finalize;
190 : :
191 : 10 : klass->fill_tile_async = NULL;
192 : :
193 : : /**
194 : : * ShumateMapSource:id:
195 : : *
196 : : * The id of the map source
197 : : */
198 : 20 : obj_properties[PROP_ID] =
199 : 10 : g_param_spec_string ("id",
200 : : "Id",
201 : : "The id of the map source",
202 : : NULL,
203 : : G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY);
204 : :
205 : : /**
206 : : * ShumateMapSource:name:
207 : : *
208 : : * The name of the map source
209 : : */
210 : 20 : obj_properties[PROP_NAME] =
211 : 10 : g_param_spec_string ("name",
212 : : "Name",
213 : : "The name of the map source",
214 : : NULL,
215 : : G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY);
216 : :
217 : : /**
218 : : * ShumateMapSource:license:
219 : : *
220 : : * The usage license of the map source
221 : : */
222 : 20 : obj_properties[PROP_LICENSE] =
223 : 10 : g_param_spec_string ("license",
224 : : "License",
225 : : "The usage license of the map source",
226 : : NULL,
227 : : G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY);
228 : :
229 : : /**
230 : : * ShumateMapSource:license-uri:
231 : : *
232 : : * The usage license's uri for more information
233 : : */
234 : 20 : obj_properties[PROP_LICENSE_URI] =
235 : 10 : g_param_spec_string ("license-uri",
236 : : "License-uri",
237 : : "The usage license's uri for more information",
238 : : NULL,
239 : : G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY);
240 : :
241 : : /**
242 : : * ShumateMapSource:min-zoom-level:
243 : : *
244 : : * The minimum zoom level
245 : : */
246 : 20 : obj_properties[PROP_MIN_ZOOM_LEVEL] =
247 : 10 : g_param_spec_uint ("min-zoom-level",
248 : : "Minimum Zoom Level",
249 : : "The minimum zoom level",
250 : : 0, 50, 0,
251 : : G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY);
252 : :
253 : : /**
254 : : * ShumateMapSource:max-zoom-level:
255 : : *
256 : : * The maximum zoom level
257 : : */
258 : 20 : obj_properties[PROP_MAX_ZOOM_LEVEL] =
259 : 10 : g_param_spec_uint ("max-zoom-level",
260 : : "Maximum Zoom Level",
261 : : "The maximum zoom level",
262 : : 0, 50, 18,
263 : : G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY);
264 : :
265 : : /**
266 : : * ShumateMapSource:tile-size:
267 : : *
268 : : * The tile size of the map source
269 : : */
270 : 20 : obj_properties[PROP_TILE_SIZE] =
271 : 10 : g_param_spec_uint ("tile-size",
272 : : "Tile Size",
273 : : "The map size",
274 : : 0, 2048, 256,
275 : : G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY);
276 : :
277 : : /**
278 : : * ShumateMapSource:projection:
279 : : *
280 : : * The map projection of the map source
281 : : */
282 : 20 : obj_properties[PROP_PROJECTION] =
283 : 10 : g_param_spec_enum ("projection",
284 : : "Projection",
285 : : "The map projection",
286 : : SHUMATE_TYPE_MAP_PROJECTION,
287 : : SHUMATE_MAP_PROJECTION_MERCATOR,
288 : : G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY);
289 : :
290 : 10 : g_object_class_install_properties (object_class,
291 : : N_PROPERTIES,
292 : : obj_properties);
293 : 10 : }
294 : :
295 : : static double
296 : 444 : map_size (ShumateMapSource *self, double zoom_level)
297 : : {
298 : 444 : return shumate_map_source_get_column_count (self, zoom_level) * shumate_map_source_get_tile_size_at_zoom (self, zoom_level);
299 : : }
300 : :
301 : :
302 : : static void
303 : 33 : shumate_map_source_init (ShumateMapSource *map_source)
304 : : {
305 : 33 : }
306 : :
307 : : /**
308 : : * shumate_map_source_get_id:
309 : : * @map_source: a #ShumateMapSource
310 : : *
311 : : * Gets map source's id.
312 : : *
313 : : * Returns: the map source's id.
314 : : */
315 : : const char *
316 : 111 : shumate_map_source_get_id (ShumateMapSource *map_source)
317 : : {
318 : 111 : ShumateMapSourcePrivate *priv = shumate_map_source_get_instance_private (map_source);
319 : :
320 [ + - ]: 111 : g_return_val_if_fail (SHUMATE_IS_MAP_SOURCE (map_source), NULL);
321 : :
322 : 111 : return priv->id;
323 : : }
324 : :
325 : : /**
326 : : * shumate_map_source_set_id:
327 : : * @map_source: a #ShumateMapSource
328 : : * @id: an id
329 : : *
330 : : * Sets the map source's id.
331 : : */
332 : : void
333 : 33 : shumate_map_source_set_id (ShumateMapSource *map_source,
334 : : const char *id)
335 : : {
336 : 33 : ShumateMapSourcePrivate *priv = shumate_map_source_get_instance_private (map_source);
337 : :
338 [ + - ]: 33 : g_return_if_fail (SHUMATE_IS_MAP_SOURCE (map_source));
339 : :
340 [ + - ]: 33 : if (g_strcmp0 (priv->id, id) != 0)
341 : : {
342 : 33 : g_free (priv->id);
343 [ - + ]: 33 : priv->id = g_strdup (id);
344 : :
345 : 33 : g_object_notify_by_pspec (G_OBJECT (map_source), obj_properties[PROP_ID]);
346 : : }
347 : : }
348 : :
349 : : /**
350 : : * shumate_map_source_get_name:
351 : : * @map_source: a #ShumateMapSource
352 : : *
353 : : * Gets map source's name.
354 : : *
355 : : * Returns: the map source's name.
356 : : */
357 : : const char *
358 : 0 : shumate_map_source_get_name (ShumateMapSource *map_source)
359 : : {
360 : 0 : ShumateMapSourcePrivate *priv = shumate_map_source_get_instance_private (map_source);
361 : :
362 [ # # ]: 0 : g_return_val_if_fail (SHUMATE_IS_MAP_SOURCE (map_source), NULL);
363 : :
364 : 0 : return priv->name;
365 : : }
366 : :
367 : : /**
368 : : * shumate_map_source_set_name:
369 : : * @map_source: a #ShumateMapSource
370 : : * @name: a name
371 : : *
372 : : * Sets the map source's name.
373 : : */
374 : : void
375 : 33 : shumate_map_source_set_name (ShumateMapSource *map_source,
376 : : const char *name)
377 : : {
378 : 33 : ShumateMapSourcePrivate *priv = shumate_map_source_get_instance_private (map_source);
379 : :
380 [ + - ]: 33 : g_return_if_fail (SHUMATE_IS_MAP_SOURCE (map_source));
381 : :
382 [ + + ]: 33 : if (g_strcmp0 (priv->name, name) != 0)
383 : : {
384 : 27 : g_free (priv->name);
385 [ - + ]: 27 : priv->name = g_strdup (name);
386 : :
387 : 27 : g_object_notify_by_pspec (G_OBJECT (map_source), obj_properties[PROP_NAME]);
388 : : }
389 : : }
390 : :
391 : : /**
392 : : * shumate_map_source_get_license:
393 : : * @map_source: a #ShumateMapSource
394 : : *
395 : : * Gets map source's license.
396 : : *
397 : : * Returns: the map source's license.
398 : : */
399 : : const char *
400 : 0 : shumate_map_source_get_license (ShumateMapSource *map_source)
401 : : {
402 : 0 : ShumateMapSourcePrivate *priv = shumate_map_source_get_instance_private (map_source);
403 : :
404 [ # # ]: 0 : g_return_val_if_fail (SHUMATE_IS_MAP_SOURCE (map_source), NULL);
405 : :
406 : 0 : return priv->license;
407 : : }
408 : :
409 : : /**
410 : : * shumate_map_source_set_license:
411 : : * @map_source: a #ShumateMapSource
412 : : * @license: the licence
413 : : *
414 : : * Sets the map source's license.
415 : : */
416 : : void
417 : 33 : shumate_map_source_set_license (ShumateMapSource *map_source,
418 : : const char *license)
419 : : {
420 : 33 : ShumateMapSourcePrivate *priv = shumate_map_source_get_instance_private (map_source);
421 : :
422 [ + - ]: 33 : g_return_if_fail (SHUMATE_IS_MAP_SOURCE (map_source));
423 : :
424 [ + + ]: 33 : if (g_strcmp0 (priv->license, license) != 0)
425 : : {
426 : 27 : g_free (priv->license);
427 [ - + ]: 27 : priv->license = g_strdup (license);
428 : :
429 : 27 : g_object_notify_by_pspec (G_OBJECT (map_source), obj_properties[PROP_LICENSE]);
430 : : }
431 : : }
432 : :
433 : : /**
434 : : * shumate_map_source_get_license_uri:
435 : : * @map_source: a #ShumateMapSource
436 : : *
437 : : * Gets map source's license URI.
438 : : *
439 : : * Returns: the map source's license URI.
440 : : */
441 : : const char *
442 : 0 : shumate_map_source_get_license_uri (ShumateMapSource *map_source)
443 : : {
444 : 0 : ShumateMapSourcePrivate *priv = shumate_map_source_get_instance_private (map_source);
445 : :
446 [ # # ]: 0 : g_return_val_if_fail (SHUMATE_IS_MAP_SOURCE (map_source), NULL);
447 : :
448 : 0 : return priv->license_uri;
449 : : }
450 : :
451 : : /**
452 : : * shumate_map_source_set_license_uri:
453 : : * @map_source: a #ShumateMapSource
454 : : * @license_uri: the licence URI
455 : : *
456 : : * Sets the map source's license URI.
457 : : */
458 : : void
459 : 33 : shumate_map_source_set_license_uri (ShumateMapSource *map_source,
460 : : const char *license_uri)
461 : : {
462 : 33 : ShumateMapSourcePrivate *priv = shumate_map_source_get_instance_private (map_source);
463 : :
464 [ + - ]: 33 : g_return_if_fail (SHUMATE_IS_MAP_SOURCE (map_source));
465 : :
466 [ + + ]: 33 : if (g_strcmp0 (priv->license_uri, license_uri) != 0)
467 : : {
468 : 27 : g_free (priv->license_uri);
469 [ - + ]: 27 : priv->license_uri = g_strdup (license_uri);
470 : :
471 : 27 : g_object_notify_by_pspec (G_OBJECT (map_source), obj_properties[PROP_LICENSE_URI]);
472 : : }
473 : : }
474 : :
475 : : /**
476 : : * shumate_map_source_get_min_zoom_level:
477 : : * @map_source: a #ShumateMapSource
478 : : *
479 : : * Gets map source's minimum zoom level.
480 : : *
481 : : * Returns: the miminum zoom level this map source supports
482 : : */
483 : : guint
484 : 3 : shumate_map_source_get_min_zoom_level (ShumateMapSource *map_source)
485 : : {
486 : 3 : ShumateMapSourcePrivate *priv = shumate_map_source_get_instance_private (map_source);
487 : :
488 [ + - ]: 3 : g_return_val_if_fail (SHUMATE_IS_MAP_SOURCE (map_source), 0);
489 : :
490 : 3 : return priv->min_zoom_level;
491 : : }
492 : :
493 : : /**
494 : : * shumate_map_source_set_min_zoom_level:
495 : : * @map_source: a #ShumateMapSource
496 : : * @zoom_level: the minimal zoom level
497 : : *
498 : : * Sets the map source's minimal zoom level.
499 : : */
500 : : void
501 : 39 : shumate_map_source_set_min_zoom_level (ShumateMapSource *map_source,
502 : : guint zoom_level)
503 : : {
504 : 39 : ShumateMapSourcePrivate *priv = shumate_map_source_get_instance_private (map_source);
505 : :
506 [ + - ]: 39 : g_return_if_fail (SHUMATE_IS_MAP_SOURCE (map_source));
507 : :
508 [ - + ]: 39 : if (priv->min_zoom_level != zoom_level)
509 : : {
510 : 0 : priv->min_zoom_level = zoom_level;
511 : :
512 : 0 : g_object_notify_by_pspec (G_OBJECT (map_source), obj_properties[PROP_MIN_ZOOM_LEVEL]);
513 : : }
514 : : }
515 : :
516 : : /**
517 : : * shumate_map_source_get_max_zoom_level:
518 : : * @map_source: a #ShumateMapSource
519 : : *
520 : : * Gets map source's maximum zoom level.
521 : : *
522 : : * Returns: the maximum zoom level this map source supports
523 : : */
524 : : guint
525 : 114 : shumate_map_source_get_max_zoom_level (ShumateMapSource *map_source)
526 : : {
527 : 114 : ShumateMapSourcePrivate *priv = shumate_map_source_get_instance_private (map_source);
528 : :
529 [ + - ]: 114 : g_return_val_if_fail (SHUMATE_IS_MAP_SOURCE (map_source), 0);
530 : :
531 : 114 : return priv->max_zoom_level;
532 : : }
533 : :
534 : : /**
535 : : * shumate_map_source_set_max_zoom_level:
536 : : * @map_source: a #ShumateMapSource
537 : : * @zoom_level: the maximum zoom level
538 : : *
539 : : * Sets the map source's maximum zoom level.
540 : : */
541 : : void
542 : 39 : shumate_map_source_set_max_zoom_level (ShumateMapSource *map_source,
543 : : guint zoom_level)
544 : : {
545 : 39 : ShumateMapSourcePrivate *priv = shumate_map_source_get_instance_private (map_source);
546 : :
547 [ + - ]: 39 : g_return_if_fail (SHUMATE_IS_MAP_SOURCE (map_source));
548 : :
549 [ + - ]: 39 : if (priv->max_zoom_level != zoom_level)
550 : : {
551 : 39 : priv->max_zoom_level = zoom_level;
552 : :
553 : 39 : g_object_notify_by_pspec (G_OBJECT (map_source), obj_properties[PROP_MAX_ZOOM_LEVEL]);
554 : : }
555 : : }
556 : :
557 : : /**
558 : : * shumate_map_source_get_tile_size:
559 : : * @map_source: a #ShumateMapSource
560 : : *
561 : : * Gets map source's tile size.
562 : : *
563 : : * Returns: the tile's size (width and height) in pixels for this map source
564 : : */
565 : : guint
566 : 0 : shumate_map_source_get_tile_size (ShumateMapSource *map_source)
567 : : {
568 : 0 : ShumateMapSourcePrivate *priv = shumate_map_source_get_instance_private (map_source);
569 : :
570 [ # # ]: 0 : g_return_val_if_fail (SHUMATE_IS_MAP_SOURCE (map_source), 0);
571 : :
572 : 0 : return priv->tile_size;
573 : : }
574 : :
575 : : /**
576 : : * shumate_map_source_get_tile_size_at_zoom:
577 : : * @map_source: a #ShumateMapSource
578 : : * @zoom_level: a zoom level
579 : : *
580 : : * Gets the apparent size of the map tiles at the given fractional zoom level.
581 : : *
582 : : * As the map is zoomed in, a tile gets bigger and bigger until, at the next
583 : : * integer zoom level, it "splits" into four tiles at the next zoom level.
584 : : * Thus, the size increase follows an exponential curve, base 2.
585 : : *
586 : : * Returns: the tile's size (width and height) in pixels for this map source
587 : : * at this zoom level
588 : : */
589 : : double
590 : 444 : shumate_map_source_get_tile_size_at_zoom (ShumateMapSource *map_source,
591 : : double zoom_level)
592 : : {
593 : 444 : ShumateMapSourcePrivate *priv = shumate_map_source_get_instance_private (map_source);
594 : :
595 [ + - ]: 444 : g_return_val_if_fail (SHUMATE_IS_MAP_SOURCE (map_source), 0);
596 : :
597 : 444 : return priv->tile_size * pow (2.0, fmod (zoom_level, 1.0));
598 : : }
599 : :
600 : : /**
601 : : * shumate_map_source_set_tile_size:
602 : : * @map_source: a #ShumateMapSource
603 : : * @tile_size: the tile size
604 : : *
605 : : * Sets the map source's tile size.
606 : : */
607 : : void
608 : 39 : shumate_map_source_set_tile_size (ShumateMapSource *map_source,
609 : : guint tile_size)
610 : : {
611 : 39 : ShumateMapSourcePrivate *priv = shumate_map_source_get_instance_private (map_source);
612 : :
613 [ + - ]: 39 : g_return_if_fail (SHUMATE_IS_MAP_SOURCE (map_source));
614 : :
615 [ + - ]: 39 : if (priv->tile_size != tile_size)
616 : : {
617 : 39 : priv->tile_size = tile_size;
618 : :
619 : 39 : g_object_notify_by_pspec (G_OBJECT (map_source), obj_properties[PROP_TILE_SIZE]);
620 : : }
621 : : }
622 : :
623 : : /**
624 : : * shumate_map_source_get_projection:
625 : : * @map_source: a #ShumateMapSource
626 : : *
627 : : * Gets map source's projection.
628 : : *
629 : : * Returns: the map source's projection.
630 : : */
631 : : ShumateMapProjection
632 : 0 : shumate_map_source_get_projection (ShumateMapSource *map_source)
633 : : {
634 : 0 : ShumateMapSourcePrivate *priv = shumate_map_source_get_instance_private (map_source);
635 : :
636 [ # # ]: 0 : g_return_val_if_fail (SHUMATE_IS_MAP_SOURCE (map_source), SHUMATE_MAP_PROJECTION_MERCATOR);
637 : :
638 : 0 : return priv->projection;
639 : : }
640 : :
641 : : /**
642 : : * shumate_map_source_set_projection:
643 : : * @map_source: a #ShumateMapSource
644 : : * @projection: a #ShumateMapProjection
645 : : *
646 : : * Sets the map source's projection.
647 : : */
648 : : void
649 : 33 : shumate_map_source_set_projection (ShumateMapSource *map_source,
650 : : ShumateMapProjection projection)
651 : : {
652 : 33 : ShumateMapSourcePrivate *priv = shumate_map_source_get_instance_private (map_source);
653 : :
654 [ + - ]: 33 : g_return_if_fail (SHUMATE_IS_MAP_SOURCE (map_source));
655 : :
656 [ - + ]: 33 : if (priv->projection != projection)
657 : : {
658 : 0 : priv->projection = projection;
659 : :
660 : 0 : g_object_notify_by_pspec (G_OBJECT (map_source), obj_properties[PROP_PROJECTION]);
661 : : }
662 : : }
663 : :
664 : : /**
665 : : * shumate_map_source_fill_tile_async:
666 : : * @self: a #ShumateMapSource
667 : : * @tile: a #ShumateTile
668 : : * @cancellable: (nullable): a #GCancellable
669 : : * @callback: a #GAsyncReadyCallback to execute upon completion
670 : : * @user_data: closure data for @callback
671 : : *
672 : : * Asynchronous version of shumate_map_source_fill_tile().
673 : : */
674 : : void
675 : 0 : shumate_map_source_fill_tile_async (ShumateMapSource *self,
676 : : ShumateTile *tile,
677 : : GCancellable *cancellable,
678 : : GAsyncReadyCallback callback,
679 : : gpointer user_data)
680 : : {
681 [ # # ]: 0 : g_return_if_fail (SHUMATE_IS_MAP_SOURCE (self));
682 [ # # ]: 0 : g_return_if_fail (SHUMATE_IS_TILE (tile));
683 [ # # # # : 0 : g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
# # # # ]
684 : :
685 : 0 : return SHUMATE_MAP_SOURCE_GET_CLASS (self)->fill_tile_async (self, tile, cancellable, callback, user_data);
686 : : }
687 : :
688 : : /**
689 : : * shumate_map_source_fill_tile_finish:
690 : : * @self: a #ShumateMapSource
691 : : * @result: a #GAsyncResult provided to callback
692 : : * @error: a location for a #GError, or %NULL
693 : : *
694 : : * Gets the success value of a completed shumate_map_source_fill_tile_async()
695 : : * operation.
696 : : *
697 : : * Returns: %TRUE if the tile was filled with valid data, otherwise %FALSE
698 : : */
699 : : gboolean
700 : 0 : shumate_map_source_fill_tile_finish (ShumateMapSource *self,
701 : : GAsyncResult *result,
702 : : GError **error)
703 : : {
704 [ # # ]: 0 : g_return_val_if_fail (SHUMATE_IS_MAP_SOURCE (self), FALSE);
705 [ # # # # : 0 : g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
# # # # ]
706 : :
707 : 0 : return SHUMATE_MAP_SOURCE_GET_CLASS (self)->fill_tile_finish (self, result, error);
708 : : }
709 : :
710 : : /**
711 : : * shumate_map_source_get_x:
712 : : * @map_source: a #ShumateMapSource
713 : : * @zoom_level: the zoom level
714 : : * @longitude: a longitude
715 : : *
716 : : * Gets the x position on the map using this map source's projection.
717 : : * (0, 0) is located at the top left.
718 : : *
719 : : * Returns: the x position
720 : : */
721 : : double
722 : 111 : shumate_map_source_get_x (ShumateMapSource *map_source,
723 : : double zoom_level,
724 : : double longitude)
725 : : {
726 [ + - ]: 111 : g_return_val_if_fail (SHUMATE_IS_MAP_SOURCE (map_source), 0.0);
727 : :
728 [ + - + - ]: 111 : longitude = CLAMP (longitude, SHUMATE_MIN_LONGITUDE, SHUMATE_MAX_LONGITUDE);
729 : :
730 : : /* FIXME: support other projections */
731 : 111 : return ((longitude + 180.0) / 360.0) * map_size (map_source, zoom_level);
732 : : }
733 : :
734 : : /**
735 : : * shumate_map_source_get_y:
736 : : * @map_source: a #ShumateMapSource
737 : : * @zoom_level: the zoom level
738 : : * @latitude: a latitude
739 : : *
740 : : * Gets the y position on the map using this map source's projection.
741 : : * (0, 0) is located at the top left.
742 : : *
743 : : * Returns: the y position
744 : : */
745 : : double
746 : 111 : shumate_map_source_get_y (ShumateMapSource *map_source,
747 : : double zoom_level,
748 : : double latitude)
749 : : {
750 : 111 : double sin_latitude;
751 : :
752 [ + - ]: 111 : g_return_val_if_fail (SHUMATE_IS_MAP_SOURCE (map_source), 0.0);
753 : :
754 [ + - + - ]: 111 : latitude = CLAMP (latitude, SHUMATE_MIN_LATITUDE, SHUMATE_MAX_LATITUDE);
755 : : /* FIXME: support other projections */
756 : 111 : sin_latitude = sin (latitude * G_PI / 180.0);
757 : 111 : return (0.5 - log ((1.0 + sin_latitude) / (1.0 - sin_latitude)) / (4.0 * G_PI)) * map_size (map_source, zoom_level);
758 : : }
759 : :
760 : : /**
761 : : * shumate_map_source_get_longitude:
762 : : * @map_source: a #ShumateMapSource
763 : : * @zoom_level: the zoom level
764 : : * @x: a x position
765 : : *
766 : : * Gets the longitude corresponding to this x position in the map source's
767 : : * projection.
768 : : *
769 : : * Returns: the longitude
770 : : */
771 : : double
772 : 111 : shumate_map_source_get_longitude (ShumateMapSource *map_source,
773 : : double zoom_level,
774 : : double x)
775 : : {
776 : 111 : double longitude;
777 : :
778 [ + - ]: 111 : g_return_val_if_fail (SHUMATE_IS_MAP_SOURCE (map_source), 0.0);
779 : :
780 : : /* FIXME: support other projections */
781 : 111 : longitude = x / map_size (map_source, zoom_level) * 360.0 - 180.0;
782 : :
783 [ + - + - ]: 111 : return CLAMP (longitude, SHUMATE_MIN_LONGITUDE, SHUMATE_MAX_LONGITUDE);
784 : : }
785 : :
786 : : /**
787 : : * shumate_map_source_get_latitude:
788 : : * @map_source: a #ShumateMapSource
789 : : * @zoom_level: the zoom level
790 : : * @y: a y position
791 : : *
792 : : * Gets the latitude corresponding to this y position in the map source's
793 : : * projection.
794 : : *
795 : : * Returns: the latitude
796 : : */
797 : : double
798 : 111 : shumate_map_source_get_latitude (ShumateMapSource *map_source,
799 : : double zoom_level,
800 : : double y)
801 : : {
802 : 111 : double latitude, dy;
803 : :
804 [ + - ]: 111 : g_return_val_if_fail (SHUMATE_IS_MAP_SOURCE (map_source), 0.0);
805 : : /* FIXME: support other projections */
806 : 111 : dy = 0.5 - y / map_size (map_source, zoom_level);
807 : 111 : latitude = 90.0 - 360.0 / G_PI * atan (exp (-dy * 2.0 * G_PI));
808 : :
809 [ + - + - ]: 111 : return CLAMP (latitude, SHUMATE_MIN_LATITUDE, SHUMATE_MAX_LATITUDE);
810 : : }
811 : :
812 : : /**
813 : : * shumate_map_source_get_row_count:
814 : : * @map_source: a #ShumateMapSource
815 : : * @zoom_level: the zoom level
816 : : *
817 : : * Gets the number of tiles in a row at this zoom level for this map source.
818 : : *
819 : : * Returns: the number of tiles in a row
820 : : */
821 : : guint
822 : 0 : shumate_map_source_get_row_count (ShumateMapSource *map_source,
823 : : guint zoom_level)
824 : : {
825 [ # # ]: 0 : g_return_val_if_fail (SHUMATE_IS_MAP_SOURCE (map_source), 0);
826 : : /* FIXME: support other projections */
827 [ # # ]: 0 : return (zoom_level != 0) ? 2 << (zoom_level - 1) : 1;
828 : : }
829 : :
830 : : /**
831 : : * shumate_map_source_get_column_count:
832 : : * @map_source: a #ShumateMapSource
833 : : * @zoom_level: the zoom level
834 : : *
835 : : * Gets the number of tiles in a column at this zoom level for this map
836 : : * source.
837 : : *
838 : : * Returns: the number of tiles in a column
839 : : */
840 : : guint
841 : 444 : shumate_map_source_get_column_count (ShumateMapSource *map_source,
842 : : guint zoom_level)
843 : : {
844 [ + - ]: 444 : g_return_val_if_fail (SHUMATE_IS_MAP_SOURCE (map_source), 0);
845 : : /* FIXME: support other projections */
846 [ + + ]: 444 : return (zoom_level != 0) ? 2 << (zoom_level - 1) : 1;
847 : : }
848 : :
849 : : #define EARTH_RADIUS 6378137.0 /* meters, Equatorial radius */
850 : :
851 : : /**
852 : : * shumate_map_source_get_meters_per_pixel:
853 : : * @map_source: a #ShumateMapSource
854 : : * @zoom_level: the zoom level
855 : : * @latitude: a latitude
856 : : * @longitude: a longitude
857 : : *
858 : : * Gets meters per pixel at the position on the map using this map source's projection.
859 : : *
860 : : * Returns: the meters per pixel
861 : : */
862 : : double
863 : 0 : shumate_map_source_get_meters_per_pixel (ShumateMapSource *map_source,
864 : : double zoom_level,
865 : : double latitude,
866 : : G_GNUC_UNUSED double longitude)
867 : : {
868 [ # # ]: 0 : g_return_val_if_fail (SHUMATE_IS_MAP_SOURCE (map_source), 0.0);
869 : :
870 : : /*
871 : : * Width is in pixels. (1 px)
872 : : * m/px = radius_at_latitude / width_in_pixels
873 : : * k = radius of earth = 6 378.1 km
874 : : * radius_at_latitude = 2pi * k * sin (pi/2-theta)
875 : : */
876 : :
877 : : /* FIXME: support other projections */
878 : 0 : return 2.0 * G_PI * EARTH_RADIUS * sin (G_PI / 2.0 - G_PI / 180.0 * latitude) / map_size (map_source, zoom_level);
879 : : }
|