Branch data Line data Source code
1 : : /* shumate-viewport.c: Viewport
2 : : *
3 : : * Copyright (C) 2008 OpenedHand
4 : : * Copyright (C) 2011-2013 Jiri Techet <techet@gmail.com>
5 : : * Copyright (C) 2019 Marcus Lundblad <ml@update.uu.se>
6 : : * Copyright (C) 2020 Collabora, Ltd. (https://www.collabora.com)
7 : : * Copyright (C) 2020 Corentin Noël <corentin.noel@collabora.com>
8 : : *
9 : : * This library is free software; you can redistribute it and/or
10 : : * modify it under the terms of the GNU Lesser General Public
11 : : * License as published by the Free Software Foundation; either
12 : : * version 2 of the License, or (at your option) any later version.
13 : : *
14 : : * This library is distributed in the hope that it will be useful,
15 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 : : * Lesser General Public License for more details.
18 : : *
19 : : * You should have received a copy of the GNU Lesser General Public
20 : : * License along with this library; if not, write to the
21 : : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 : : * Boston, MA 02111-1307, USA.
23 : : *
24 : : * Written by: Chris Lord <chris@openedhand.com>
25 : : */
26 : :
27 : : #include "shumate-viewport.h"
28 : : #include "shumate-location.h"
29 : :
30 : : /**
31 : : * ShumateViewport:
32 : : *
33 : : * The object holding the coordinate, zoom-level, and rotation state of the current view.
34 : : *
35 : : * As the object implements [iface@Shumate.Location], the latitude and longitude are
36 : : * accessible via the interface methods.
37 : : */
38 : :
39 : : #define DEFAULT_MIN_ZOOM 0
40 : : #define DEFAULT_MAX_ZOOM 20
41 : :
42 : : struct _ShumateViewport
43 : : {
44 : : GObject parent_instance;
45 : :
46 : : double lon;
47 : : double lat;
48 : :
49 : : double zoom_level;
50 : : guint min_zoom_level;
51 : : guint max_zoom_level;
52 : : double rotation;
53 : :
54 : : ShumateMapSource *ref_map_source;
55 : : };
56 : :
57 : : static void shumate_viewport_shumate_location_interface_init (ShumateLocationInterface *iface);
58 : :
59 [ + + + - ]: 434 : G_DEFINE_TYPE_WITH_CODE (ShumateViewport, shumate_viewport, G_TYPE_OBJECT,
60 : : G_IMPLEMENT_INTERFACE (SHUMATE_TYPE_LOCATION, shumate_viewport_shumate_location_interface_init));
61 : :
62 : : /* Remember to update shumate_viewport_copy() when adding properties */
63 : : enum
64 : : {
65 : : PROP_ZOOM_LEVEL = 1,
66 : : PROP_MIN_ZOOM_LEVEL,
67 : : PROP_MAX_ZOOM_LEVEL,
68 : : PROP_REFERENCE_MAP_SOURCE,
69 : : PROP_ROTATION,
70 : : N_PROPERTIES,
71 : :
72 : : PROP_LONGITUDE,
73 : : PROP_LATITUDE,
74 : : };
75 : :
76 : : static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
77 : :
78 : : static double
79 : 0 : shumate_viewport_get_latitude (ShumateLocation *location)
80 : : {
81 : 0 : ShumateViewport *self = (ShumateViewport *)location;
82 : :
83 [ # # ]: 0 : g_assert (SHUMATE_IS_VIEWPORT (self));
84 : :
85 : 0 : return self->lat;
86 : : }
87 : :
88 : : static double
89 : 0 : shumate_viewport_get_longitude (ShumateLocation *location)
90 : : {
91 : 0 : ShumateViewport *self = (ShumateViewport *)location;
92 : :
93 [ # # ]: 0 : g_assert (SHUMATE_IS_VIEWPORT (self));
94 : :
95 : 0 : return self->lon;
96 : : }
97 : :
98 : : static void
99 : 0 : shumate_viewport_set_location (ShumateLocation *location,
100 : : double latitude,
101 : : double longitude)
102 : : {
103 : 0 : ShumateViewport *self = (ShumateViewport *)location;
104 : :
105 [ # # ]: 0 : g_assert (SHUMATE_IS_VIEWPORT (self));
106 : :
107 [ # # # # ]: 0 : self->lon = CLAMP (longitude, SHUMATE_MIN_LONGITUDE, SHUMATE_MAX_LONGITUDE);
108 [ # # # # ]: 0 : self->lat = CLAMP (latitude, SHUMATE_MIN_LATITUDE, SHUMATE_MAX_LATITUDE);
109 : 0 : g_object_notify (G_OBJECT (self), "longitude");
110 : 0 : g_object_notify (G_OBJECT (self), "latitude");
111 : 0 : }
112 : :
113 : : static void
114 : 0 : shumate_viewport_get_property (GObject *object,
115 : : guint prop_id,
116 : : GValue *value,
117 : : GParamSpec *pspec)
118 : : {
119 : 0 : ShumateViewport *self = SHUMATE_VIEWPORT (object);
120 : :
121 [ # # # # : 0 : switch (prop_id)
# # # # ]
122 : : {
123 : 0 : case PROP_ZOOM_LEVEL:
124 : 0 : g_value_set_double (value, self->zoom_level);
125 : 0 : break;
126 : :
127 : 0 : case PROP_MIN_ZOOM_LEVEL:
128 : 0 : g_value_set_uint (value, self->min_zoom_level);
129 : 0 : break;
130 : :
131 : 0 : case PROP_MAX_ZOOM_LEVEL:
132 : 0 : g_value_set_uint (value, self->max_zoom_level);
133 : 0 : break;
134 : :
135 : 0 : case PROP_REFERENCE_MAP_SOURCE:
136 : 0 : g_value_set_object (value, self->ref_map_source);
137 : 0 : break;
138 : :
139 : 0 : case PROP_ROTATION:
140 : 0 : g_value_set_double (value, self->rotation);
141 : 0 : break;
142 : :
143 : 0 : case PROP_LONGITUDE:
144 : 0 : g_value_set_double (value, self->lon);
145 : 0 : break;
146 : :
147 : 0 : case PROP_LATITUDE:
148 : 0 : g_value_set_double (value, self->lat);
149 : 0 : break;
150 : :
151 : 0 : default:
152 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
153 : 0 : break;
154 : : }
155 : 0 : }
156 : :
157 : : static void
158 : 0 : shumate_viewport_set_property (GObject *object,
159 : : guint prop_id,
160 : : const GValue *value,
161 : : GParamSpec *pspec)
162 : : {
163 : 0 : ShumateViewport *self = SHUMATE_VIEWPORT (object);
164 : :
165 [ # # # # : 0 : switch (prop_id)
# # # # ]
166 : : {
167 : 0 : case PROP_ZOOM_LEVEL:
168 : 0 : shumate_viewport_set_zoom_level (self, g_value_get_double (value));
169 : 0 : break;
170 : :
171 : 0 : case PROP_MIN_ZOOM_LEVEL:
172 : 0 : shumate_viewport_set_min_zoom_level (self, g_value_get_uint (value));
173 : 0 : break;
174 : :
175 : 0 : case PROP_MAX_ZOOM_LEVEL:
176 : 0 : shumate_viewport_set_max_zoom_level (self, g_value_get_uint (value));
177 : 0 : break;
178 : :
179 : 0 : case PROP_REFERENCE_MAP_SOURCE:
180 : 0 : shumate_viewport_set_reference_map_source (self, g_value_get_object (value));
181 : 0 : break;
182 : :
183 : 0 : case PROP_ROTATION:
184 : 0 : shumate_viewport_set_rotation (self, g_value_get_double (value));
185 : 0 : break;
186 : :
187 : 0 : case PROP_LONGITUDE:
188 [ # # # # ]: 0 : self->lon = CLAMP (g_value_get_double (value), SHUMATE_MIN_LONGITUDE, SHUMATE_MAX_LONGITUDE);
189 : 0 : g_object_notify (object, "longitude");
190 : 0 : break;
191 : :
192 : 0 : case PROP_LATITUDE:
193 [ # # # # ]: 0 : self->lat = CLAMP (g_value_get_double (value), SHUMATE_MIN_LATITUDE, SHUMATE_MAX_LATITUDE);
194 : 0 : g_object_notify (object, "latitude");
195 : 0 : break;
196 : :
197 : 0 : default:
198 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
199 : 0 : break;
200 : : }
201 : 0 : }
202 : :
203 : : static void
204 : 14 : shumate_viewport_dispose (GObject *object)
205 : : {
206 : 14 : ShumateViewport *self = SHUMATE_VIEWPORT (object);
207 : :
208 [ - + ]: 14 : g_clear_object (&self->ref_map_source);
209 : :
210 : 14 : G_OBJECT_CLASS (shumate_viewport_parent_class)->dispose (object);
211 : 14 : }
212 : :
213 : : static void
214 : 8 : shumate_viewport_class_init (ShumateViewportClass *klass)
215 : : {
216 : 8 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
217 : :
218 : 8 : object_class->get_property = shumate_viewport_get_property;
219 : 8 : object_class->set_property = shumate_viewport_set_property;
220 : 8 : object_class->dispose = shumate_viewport_dispose;
221 : :
222 : : /**
223 : : * ShumateViewport:zoom-level:
224 : : *
225 : : * The level of zoom of the content.
226 : : */
227 : 16 : obj_properties[PROP_ZOOM_LEVEL] =
228 : 8 : g_param_spec_double ("zoom-level",
229 : : "Zoom level",
230 : : "The level of zoom of the map",
231 : : 0, 20, 3,
232 : : G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
233 : :
234 : : /**
235 : : * ShumateViewport:min-zoom-level:
236 : : *
237 : : * The lowest allowed level of zoom of the content.
238 : : */
239 : 16 : obj_properties[PROP_MIN_ZOOM_LEVEL] =
240 : 8 : g_param_spec_uint ("min-zoom-level",
241 : : "Min zoom level",
242 : : "The lowest allowed level of zoom",
243 : : 0, 20, DEFAULT_MIN_ZOOM,
244 : : G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
245 : :
246 : : /**
247 : : * ShumateViewport:max-zoom-level:
248 : : *
249 : : * The highest allowed level of zoom of the content.
250 : : */
251 : 16 : obj_properties[PROP_MAX_ZOOM_LEVEL] =
252 : 8 : g_param_spec_uint ("max-zoom-level",
253 : : "Max zoom level",
254 : : "The highest allowed level of zoom",
255 : : 0, 20, DEFAULT_MAX_ZOOM,
256 : : G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
257 : :
258 : : /**
259 : : * ShumateViewport:reference-map-source:
260 : : *
261 : : * The reference #ShumateMapSource being displayed
262 : : */
263 : 16 : obj_properties[PROP_REFERENCE_MAP_SOURCE] =
264 : 8 : g_param_spec_object ("reference-map-source",
265 : : "Reference Map Source",
266 : : "The reference map source being displayed",
267 : : SHUMATE_TYPE_MAP_SOURCE,
268 : : G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
269 : :
270 : : /**
271 : : * ShumateViewport:rotation:
272 : : *
273 : : * The rotation of the map view, in radians clockwise from up being due north
274 : : */
275 : 16 : obj_properties[PROP_ROTATION] =
276 : 8 : g_param_spec_double ("rotation",
277 : : "Rotation",
278 : : "The rotation of the map view in radians",
279 : : 0, G_PI * 2.0, 0,
280 : : G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
281 : :
282 : 8 : g_object_class_install_properties (object_class,
283 : : N_PROPERTIES,
284 : : obj_properties);
285 : :
286 : 8 : g_object_class_override_property (object_class,
287 : : PROP_LONGITUDE,
288 : : "longitude");
289 : :
290 : 8 : g_object_class_override_property (object_class,
291 : : PROP_LATITUDE,
292 : : "latitude");
293 : 8 : }
294 : :
295 : : static void
296 : 24 : shumate_viewport_init (ShumateViewport *self)
297 : : {
298 : : /* We need to set these here, otherwise the max_zoom >= min_zoom check in
299 : : * the setter functions may fail if they're not called in the right order. */
300 : 24 : self->min_zoom_level = DEFAULT_MIN_ZOOM;
301 : 24 : self->max_zoom_level = DEFAULT_MAX_ZOOM;
302 : 24 : }
303 : :
304 : : static void
305 : 8 : shumate_viewport_shumate_location_interface_init (ShumateLocationInterface *iface)
306 : : {
307 : 8 : iface->get_latitude = shumate_viewport_get_latitude;
308 : 8 : iface->get_longitude = shumate_viewport_get_longitude;
309 : 8 : iface->set_location = shumate_viewport_set_location;
310 : 8 : }
311 : :
312 : : /**
313 : : * shumate_viewport_new:
314 : : *
315 : : * Creates a new #ShumateViewport
316 : : *
317 : : * Returns: A new #ShumateViewport
318 : : */
319 : : ShumateViewport *
320 : 24 : shumate_viewport_new (void)
321 : : {
322 : 24 : return g_object_new (SHUMATE_TYPE_VIEWPORT, NULL);
323 : : }
324 : :
325 : : /**
326 : : * shumate_viewport_set_zoom_level:
327 : : * @self: a #ShumateViewport
328 : : * @zoom_level: the zoom level
329 : : *
330 : : * Set the zoom level
331 : : */
332 : : void
333 : 42 : shumate_viewport_set_zoom_level (ShumateViewport *self,
334 : : double zoom_level)
335 : : {
336 [ + - ]: 42 : g_return_if_fail (SHUMATE_IS_VIEWPORT (self));
337 : :
338 [ + + + + ]: 42 : zoom_level = CLAMP (zoom_level, self->min_zoom_level, self->max_zoom_level);
339 : :
340 [ + + ]: 42 : if (self->zoom_level == zoom_level)
341 : : return;
342 : :
343 : 39 : self->zoom_level = zoom_level;
344 : 39 : g_object_notify_by_pspec (G_OBJECT (self), obj_properties[PROP_ZOOM_LEVEL]);
345 : : }
346 : :
347 : : /**
348 : : * shumate_viewport_get_zoom_level:
349 : : * @self: a #ShumateViewport
350 : : *
351 : : * Get the current zoom level
352 : : *
353 : : * Returns: the current zoom level
354 : : */
355 : : double
356 : 21 : shumate_viewport_get_zoom_level (ShumateViewport *self)
357 : : {
358 [ + - ]: 21 : g_return_val_if_fail (SHUMATE_IS_VIEWPORT (self), 0U);
359 : :
360 : 21 : return self->zoom_level;
361 : : }
362 : :
363 : : /**
364 : : * shumate_viewport_set_max_zoom_level:
365 : : * @self: a #ShumateViewport
366 : : * @max_zoom_level: the maximal zoom level
367 : : *
368 : : * Set the maximal zoom level
369 : : */
370 : : void
371 : 45 : shumate_viewport_set_max_zoom_level (ShumateViewport *self,
372 : : guint max_zoom_level)
373 : : {
374 [ + - ]: 45 : g_return_if_fail (SHUMATE_IS_VIEWPORT (self));
375 [ + + ]: 45 : g_return_if_fail (max_zoom_level >= self->min_zoom_level);
376 : :
377 [ + + ]: 42 : if (self->max_zoom_level == max_zoom_level)
378 : : return;
379 : :
380 : 27 : self->max_zoom_level = max_zoom_level;
381 : 27 : g_object_notify_by_pspec (G_OBJECT (self), obj_properties[PROP_MAX_ZOOM_LEVEL]);
382 : :
383 [ + + ]: 27 : if (self->zoom_level > max_zoom_level)
384 : 3 : shumate_viewport_set_zoom_level (self, max_zoom_level);
385 : : }
386 : :
387 : : /**
388 : : * shumate_viewport_get_max_zoom_level:
389 : : * @self: a #ShumateViewport
390 : : *
391 : : * Get the maximal zoom level
392 : : *
393 : : * Returns: the maximal zoom level
394 : : */
395 : : guint
396 : 12 : shumate_viewport_get_max_zoom_level (ShumateViewport *self)
397 : : {
398 [ + - ]: 12 : g_return_val_if_fail (SHUMATE_IS_VIEWPORT (self), 0U);
399 : :
400 : 12 : return self->max_zoom_level;
401 : : }
402 : :
403 : : /**
404 : : * shumate_viewport_set_min_zoom_level:
405 : : * @self: a #ShumateViewport
406 : : * @min_zoom_level: the minimal zoom level
407 : : *
408 : : * Set the minimal zoom level
409 : : */
410 : : void
411 : 42 : shumate_viewport_set_min_zoom_level (ShumateViewport *self,
412 : : guint min_zoom_level)
413 : : {
414 [ + - ]: 42 : g_return_if_fail (SHUMATE_IS_VIEWPORT (self));
415 [ + + ]: 42 : g_return_if_fail (min_zoom_level <= self->max_zoom_level);
416 : :
417 [ + + ]: 39 : if (self->min_zoom_level == min_zoom_level)
418 : : return;
419 : :
420 : 24 : self->min_zoom_level = min_zoom_level;
421 : 24 : g_object_notify_by_pspec (G_OBJECT (self), obj_properties[PROP_MIN_ZOOM_LEVEL]);
422 : :
423 [ + + ]: 24 : if (self->zoom_level < min_zoom_level)
424 : 6 : shumate_viewport_set_zoom_level (self, min_zoom_level);
425 : : }
426 : :
427 : : /**
428 : : * shumate_viewport_get_min_zoom_level:
429 : : * @self: a #ShumateViewport
430 : : *
431 : : * Get the minimal zoom level
432 : : *
433 : : * Returns: the minimal zoom level
434 : : */
435 : : guint
436 : 12 : shumate_viewport_get_min_zoom_level (ShumateViewport *self)
437 : : {
438 [ + - ]: 12 : g_return_val_if_fail (SHUMATE_IS_VIEWPORT (self), 0U);
439 : :
440 : 12 : return self->min_zoom_level;
441 : : }
442 : :
443 : : /**
444 : : * shumate_viewport_set_reference_map_source:
445 : : * @self: a #ShumateViewport
446 : : * @map_source: (nullable): a #ShumateMapSource or %NULL to set none.
447 : : *
448 : : * Set the reference map source
449 : : */
450 : : void
451 : 0 : shumate_viewport_set_reference_map_source (ShumateViewport *self,
452 : : ShumateMapSource *map_source)
453 : : {
454 [ # # ]: 0 : g_return_if_fail (SHUMATE_IS_VIEWPORT (self));
455 [ # # # # ]: 0 : g_return_if_fail (map_source == NULL || SHUMATE_IS_MAP_SOURCE (map_source));
456 : :
457 [ # # ]: 0 : if (g_set_object (&self->ref_map_source, map_source))
458 : : {
459 [ # # ]: 0 : if (map_source != NULL)
460 : : {
461 : 0 : shumate_viewport_set_max_zoom_level (self, shumate_map_source_get_max_zoom_level (map_source));
462 : 0 : shumate_viewport_set_min_zoom_level (self, shumate_map_source_get_min_zoom_level (map_source));
463 : : }
464 : :
465 : 0 : g_object_notify_by_pspec (G_OBJECT (self), obj_properties[PROP_REFERENCE_MAP_SOURCE]);
466 : : }
467 : :
468 : : }
469 : :
470 : : /**
471 : : * shumate_viewport_get_reference_map_source:
472 : : * @self: a #ShumateViewport
473 : : *
474 : : * Get the reference map source
475 : : *
476 : : * Returns: (transfer none) (nullable): the reference #ShumateMapSource or %NULL
477 : : * when none has been set.
478 : : */
479 : : ShumateMapSource *
480 : 208 : shumate_viewport_get_reference_map_source (ShumateViewport *self)
481 : : {
482 [ + - ]: 208 : g_return_val_if_fail (SHUMATE_IS_VIEWPORT (self), NULL);
483 : :
484 : 208 : return self->ref_map_source;
485 : : }
486 : :
487 : : /**
488 : : * shumate_viewport_set_rotation:
489 : : * @self: a #ShumateViewport
490 : : * @rotation: the rotation
491 : : *
492 : : * Sets the rotation
493 : : */
494 : : void
495 : 0 : shumate_viewport_set_rotation (ShumateViewport *self,
496 : : double rotation)
497 : : {
498 [ # # ]: 0 : g_return_if_fail (SHUMATE_IS_VIEWPORT (self));
499 : :
500 : 0 : rotation = fmod (rotation, G_PI * 2.0);
501 [ # # ]: 0 : if (rotation < 0)
502 : 0 : rotation += G_PI * 2.0;
503 : :
504 [ # # ]: 0 : if (self->rotation == rotation)
505 : : return;
506 : :
507 : 0 : self->rotation = rotation;
508 : 0 : g_object_notify_by_pspec (G_OBJECT (self), obj_properties[PROP_ROTATION]);
509 : : }
510 : :
511 : : /**
512 : : * shumate_viewport_get_rotation:
513 : : * @self: a #ShumateViewport
514 : : *
515 : : * Gets the current rotation
516 : : *
517 : : * Returns: the current rotation
518 : : */
519 : : double
520 : 0 : shumate_viewport_get_rotation (ShumateViewport *self)
521 : : {
522 [ # # ]: 0 : g_return_val_if_fail (SHUMATE_IS_VIEWPORT (self), 0);
523 : :
524 : 0 : return self->rotation;
525 : : }
526 : :
527 : : static void
528 : 0 : rotate_around_center (double *x, double *y, double width, double height, double angle)
529 : : {
530 : : /* Rotate (x, y) around (width / 2, height / 2) */
531 : :
532 : 0 : double old_x = *x;
533 : 0 : double old_y = *y;
534 : 0 : double center_x = width / 2.0;
535 : 0 : double center_y = height / 2.0;
536 : :
537 : 0 : *x = cos(angle) * (old_x - center_x) - sin(angle) * (old_y - center_y) + center_x;
538 : 0 : *y = sin(angle) * (old_x - center_x) + cos(angle) * (old_y - center_y) + center_y;
539 : 0 : }
540 : :
541 : : static double
542 : 0 : positive_mod (double i, double n)
543 : : {
544 : 0 : return fmod (fmod (i, n) + n, n);
545 : : }
546 : :
547 : : /**
548 : : * shumate_viewport_widget_coords_to_location:
549 : : * @self: a #ShumateViewport
550 : : * @widget: a #GtkWidget that uses @self as viewport
551 : : * @x: the x coordinate
552 : : * @y: the y coordinate
553 : : * @latitude: (out): return location for the latitude
554 : : * @longitude: (out): return location for the longitude
555 : : *
556 : : * Gets the latitude and longitude corresponding to a position on @widget.
557 : : */
558 : : void
559 : 0 : shumate_viewport_widget_coords_to_location (ShumateViewport *self,
560 : : GtkWidget *widget,
561 : : double x,
562 : : double y,
563 : : double *latitude,
564 : : double *longitude)
565 : : {
566 : 0 : double center_x, center_y;
567 : 0 : double width, height;
568 : 0 : double tile_size;
569 : 0 : double map_width, map_height;
570 : :
571 [ # # ]: 0 : g_return_if_fail (SHUMATE_IS_VIEWPORT (self));
572 [ # # # # : 0 : g_return_if_fail (GTK_IS_WIDGET (widget));
# # # # ]
573 [ # # ]: 0 : g_return_if_fail (latitude != NULL);
574 [ # # ]: 0 : g_return_if_fail (longitude != NULL);
575 : :
576 [ # # ]: 0 : if (!self->ref_map_source)
577 : : {
578 : 0 : g_critical ("A reference map source is required.");
579 : 0 : return;
580 : : }
581 : :
582 : 0 : width = gtk_widget_get_width (widget);
583 : 0 : height = gtk_widget_get_height (widget);
584 : 0 : rotate_around_center (&x, &y, width, height, -self->rotation);
585 : :
586 : 0 : tile_size = shumate_map_source_get_tile_size_at_zoom (self->ref_map_source, self->zoom_level);
587 : 0 : map_width = tile_size * shumate_map_source_get_column_count (self->ref_map_source, self->zoom_level);
588 : 0 : map_height = tile_size * shumate_map_source_get_row_count (self->ref_map_source, self->zoom_level);
589 : :
590 : 0 : center_x = shumate_map_source_get_x (self->ref_map_source, self->zoom_level, self->lon) - width/2 + x;
591 : 0 : center_y = shumate_map_source_get_y (self->ref_map_source, self->zoom_level, self->lat) - height/2 + y;
592 : :
593 : 0 : center_x = positive_mod (center_x, map_width);
594 : 0 : center_y = positive_mod (center_y, map_height);
595 : :
596 : 0 : *latitude = shumate_map_source_get_latitude (self->ref_map_source, self->zoom_level, center_y);
597 : 0 : *longitude = shumate_map_source_get_longitude (self->ref_map_source, self->zoom_level, center_x);
598 : : }
599 : :
600 : : /**
601 : : * shumate_viewport_location_to_widget_coords:
602 : : * @self: a #ShumateViewport
603 : : * @widget: a #GtkWidget that uses @self as viewport
604 : : * @latitude: the latitude
605 : : * @longitude: the longitude
606 : : * @x: (out): return value for the x coordinate
607 : : * @y: (out): return value for the y coordinate
608 : : *
609 : : * Gets the position on @widget that correspond to the given latitude and
610 : : * longitude.
611 : : */
612 : : void
613 : 0 : shumate_viewport_location_to_widget_coords (ShumateViewport *self,
614 : : GtkWidget *widget,
615 : : double latitude,
616 : : double longitude,
617 : : double *x,
618 : : double *y)
619 : : {
620 : 0 : double center_latitude, center_longitude;
621 : 0 : double width, height;
622 : :
623 [ # # ]: 0 : g_return_if_fail (SHUMATE_IS_VIEWPORT (self));
624 [ # # # # : 0 : g_return_if_fail (GTK_IS_WIDGET (widget));
# # # # ]
625 [ # # ]: 0 : g_return_if_fail (x != NULL);
626 [ # # ]: 0 : g_return_if_fail (y != NULL);
627 : :
628 [ # # ]: 0 : if (!self->ref_map_source)
629 : : {
630 : 0 : g_critical ("A reference map source is required.");
631 : 0 : return;
632 : : }
633 : :
634 : 0 : width = gtk_widget_get_width (widget);
635 : 0 : height = gtk_widget_get_height (widget);
636 : :
637 : 0 : *x = shumate_map_source_get_x (self->ref_map_source, self->zoom_level, longitude);
638 : 0 : *y = shumate_map_source_get_y (self->ref_map_source, self->zoom_level, latitude);
639 : :
640 : 0 : center_latitude = shumate_location_get_latitude (SHUMATE_LOCATION (self));
641 : 0 : center_longitude = shumate_location_get_longitude (SHUMATE_LOCATION (self));
642 : 0 : *x -= shumate_map_source_get_x (self->ref_map_source, self->zoom_level, center_longitude) - width/2;
643 : 0 : *y -= shumate_map_source_get_y (self->ref_map_source, self->zoom_level, center_latitude) - height/2;
644 : :
645 : 0 : rotate_around_center (x, y, width, height, self->rotation);
646 : : }
647 : :
648 : : /**
649 : : * shumate_viewport_copy:
650 : : * @self: a [class@Viewport]
651 : : *
652 : : * Creates a copy of the viewport.
653 : : *
654 : : * Returns: (transfer full): a [class@Viewport] with the same values as @self
655 : : */
656 : : ShumateViewport *
657 : 0 : shumate_viewport_copy (ShumateViewport *self)
658 : : {
659 [ # # ]: 0 : g_return_val_if_fail (SHUMATE_IS_VIEWPORT (self), NULL);
660 : :
661 : 0 : return g_object_new (SHUMATE_TYPE_VIEWPORT,
662 : : "latitude", self->lat,
663 : : "longitude", self->lon,
664 : : "min-zoom-level", self->min_zoom_level,
665 : : "max-zoom-level", self->max_zoom_level,
666 : : "rotation", self->rotation,
667 : : "reference-map-source", self->ref_map_source,
668 : : "zoom-level", self->zoom_level,
669 : : NULL);
670 : : }
|