2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
4 * Copyright (C) 2005, Evan Battaglia <viking@greentorch.org>
5 * UTM multi-zone stuff by Kit Transue <notlostyet@didactek.com>
6 * Dynamic map type by Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #define MAX_SHRINKFACTOR 8.0000001 /* zoom 1 viewing 8-tiles */
25 #define MIN_SHRINKFACTOR 0.0312499 /* zoom 32 viewing 1-tiles */
28 #include <gdk-pixbuf/gdk-pixdata.h>
35 #include "viktreeview.h"
36 #include "vikviewport.h"
38 #include "vikmapslayer.h"
39 #include "vikmapslayer_pixmap.h"
43 #include <sys/types.h>
46 /* only for dialog.h -- ugh */
47 #include "vikwaypoint.h"
50 #include "vikstatus.h"
51 #include "background.h"
53 #include "vikaggregatelayer.h"
54 #include "viklayerspanel.h"
57 #include "terraserver.h"
59 /****** MAP TYPES ******/
61 static GList *__map_types = NULL;
63 #define NUM_MAP_TYPES g_list_length(__map_types)
65 /* List of label for each map type */
66 static GList *params_maptypes = NULL;
68 /* Corresponding IDS. (Cf. field uniq_id in VikMapsLayer struct) */
69 static GList *params_maptypes_ids = NULL;
71 /******** MAPZOOMS *********/
73 static gchar *params_mapzooms[] = { "Use Viking Zoom Level", "0.25", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", "USGS 10k", "USGS 24k", "USGS 25k", "USGS 50k", "USGS 100k", "USGS 200k", "USGS 250k", NULL };
74 static gdouble __mapzooms_x[] = { 0.0, 0.25, 1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0, 512.0, 1024.0, 1.016, 2.4384, 2.54, 5.08, 10.16, 20.32, 25.4 };
75 static gdouble __mapzooms_y[] = { 0.0, 0.25, 1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0, 512.0, 1024.0, 1.016, 2.4384, 2.54, 5.08, 10.16, 20.32, 25.4 };
77 #define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0]) - 1)
79 /**************************/
82 static VikMapsLayer *maps_layer_copy ( VikMapsLayer *vml, VikViewport *vvp );
83 static void maps_layer_post_read (VikMapsLayer *vml, gpointer vp);
84 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len );
85 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
86 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp );
87 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id );
88 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp );
89 static VikMapsLayer *maps_layer_new ( VikViewport *vvp );
90 static void maps_layer_free ( VikMapsLayer *vml );
91 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
92 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
93 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp );
94 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir );
95 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload );
96 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp );
99 static VikLayerParamScale params_scales[] = {
100 /* min, max, step, digits (decimal places) */
101 { 0, 255, 3, 0 }, /* alpha */
104 VikLayerParam maps_layer_params[] = {
105 { "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, "Map Type:", VIK_LAYER_WIDGET_RADIOGROUP, NULL, NULL },
106 { "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, "Maps Directory (Optional):", VIK_LAYER_WIDGET_FILEENTRY },
107 { "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, "Alpha:", VIK_LAYER_WIDGET_HSCALE, params_scales },
108 { "autodownload", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, "Autodownload maps:", VIK_LAYER_WIDGET_CHECKBUTTON },
109 { "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, "Zoom Level:", VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms },
112 enum { PARAM_MAPTYPE=0, PARAM_CACHE_DIR, PARAM_ALPHA, PARAM_AUTODOWNLOAD, PARAM_MAPZOOM, NUM_PARAMS };
114 static VikToolInterface maps_tools[] = {
115 { "Maps Download", (VikToolConstructorFunc) maps_layer_download_create, NULL, NULL, NULL,
116 (VikToolMouseFunc) maps_layer_download_click, NULL, (VikToolMouseFunc) maps_layer_download_release },
119 VikLayerInterface vik_maps_layer_interface = {
124 sizeof(maps_tools) / sizeof(maps_tools[0]),
133 (VikLayerFuncCreate) maps_layer_new,
134 (VikLayerFuncRealize) NULL,
135 (VikLayerFuncPostRead) maps_layer_post_read,
136 (VikLayerFuncFree) maps_layer_free,
138 (VikLayerFuncProperties) NULL,
139 (VikLayerFuncDraw) maps_layer_draw,
140 (VikLayerFuncChangeCoordMode) NULL,
142 (VikLayerFuncSetMenuItemsSelection) NULL,
143 (VikLayerFuncGetMenuItemsSelection) NULL,
145 (VikLayerFuncAddMenuItems) maps_layer_add_menu_items,
146 (VikLayerFuncSublayerAddMenuItems) NULL,
148 (VikLayerFuncSublayerRenameRequest) NULL,
149 (VikLayerFuncSublayerToggleVisible) NULL,
151 (VikLayerFuncCopy) maps_layer_copy,
152 (VikLayerFuncMarshall) maps_layer_marshall,
153 (VikLayerFuncUnmarshall) maps_layer_unmarshall,
155 (VikLayerFuncSetParam) maps_layer_set_param,
156 (VikLayerFuncGetParam) maps_layer_get_param,
158 (VikLayerFuncReadFileData) NULL,
159 (VikLayerFuncWriteFileData) NULL,
161 (VikLayerFuncDeleteItem) NULL,
162 (VikLayerFuncCopyItem) NULL,
163 (VikLayerFuncPasteItem) NULL,
164 (VikLayerFuncFreeCopiedItem) NULL,
165 (VikLayerFuncDragDropRequest) NULL,
168 struct _VikMapsLayer {
174 gdouble xmapzoom, ymapzoom;
176 gboolean autodownload;
177 VikCoord *last_center;
181 gint dl_tool_x, dl_tool_y;
183 GtkMenu *dl_right_click_menu;
184 VikCoord redownload_ul, redownload_br; /* right click menu only */
185 VikViewport *redownload_vvp;
188 enum { REDOWNLOAD_NONE = 0, REDOWNLOAD_BAD, REDOWNLOAD_ALL, DOWNLOAD_OR_REFRESH };
191 /****************************************/
192 /******** MAPS LAYER TYPES **************/
193 /****************************************/
195 void maps_layer_register_type ( const char *label, guint id, VikMapsLayer_MapType *map_type )
197 g_assert(label != NULL);
198 g_assert(map_type != NULL);
199 g_assert(id == map_type->uniq_id);
202 params_maptypes = g_list_append(params_maptypes, g_strdup(label));
205 params_maptypes_ids = g_list_append(params_maptypes_ids, (gpointer)id);
207 /* We have to clone */
208 VikMapsLayer_MapType *clone = g_memdup(map_type, sizeof(VikMapsLayer_MapType));
209 /* Register the clone in the list */
210 __map_types = g_list_append(__map_types, clone);
213 We have to ensure the mode LayerParam reference the up-to-date
217 memcpy(&maps_layer_params[0].widget_data, ¶ms_maptypes, sizeof(gpointer));
218 memcpy(&maps_layer_params[0].extra_widget_data, ¶ms_maptypes_ids, sizeof(gpointer));
220 maps_layer_params[0].widget_data = params_maptypes;
221 maps_layer_params[0].extra_widget_data = params_maptypes_ids;
224 #define MAPS_LAYER_NTH_LABEL(n) ((gchar*)g_list_nth_data(params_maptypes, (n)))
225 #define MAPS_LAYER_NTH_ID(n) ((guint)g_list_nth_data(params_maptypes_ids, (n)))
226 #define MAPS_LAYER_NTH_TYPE(n) ((VikMapsLayer_MapType*)g_list_nth_data(__map_types, (n)))
228 gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
230 return(vml->maptype);
233 gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
235 return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
238 /****************************************/
239 /******** CACHE DIR STUFF ***************/
240 /****************************************/
243 #define MAPS_CACHE_DIR "C:\\VIKING-MAPS\\"
244 #define DIRSTRUCTURE "%st%ds%dz%d\\%d\\%d"
249 #define MAPS_CACHE_DIR maps_layer_default_dir()
250 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
251 #define DIRSTRUCTURE "%st%ds%dz%d/%d/%d"
253 static gchar *maps_layer_default_dir ()
255 static gchar defaultdir[512];
256 static gboolean already_run = 0;
259 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
260 gchar *mapdir = getenv("VIKING_MAPS");
261 if ( mapdir && strlen(mapdir) < 497 ) {
262 strcpy ( defaultdir, mapdir );
263 } else if ( access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
264 strcpy ( defaultdir, GLOBAL_MAPS_DIR );
266 gchar *home = getenv("HOME");
267 if ( home && strlen(home) < 497 )
269 strcpy ( defaultdir, home );
270 strcat ( defaultdir, "/.viking-maps/" );
274 strcpy ( defaultdir, ".viking-maps/" );
284 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
286 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && access ( vml->cache_dir, F_OK ) != 0 )
289 mkdir ( vml->cache_dir );
291 mkdir ( vml->cache_dir, 0777 );
296 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
299 g_assert ( vml != NULL);
300 g_free ( vml->cache_dir );
301 vml->cache_dir = NULL;
303 if ( dir == NULL || dir[0] == '\0' )
304 vml->cache_dir = g_strdup ( MAPS_CACHE_DIR );
308 if ( dir[len-1] != VIKING_FILE_SEP )
310 vml->cache_dir = g_malloc ( len+2 );
311 strncpy ( vml->cache_dir, dir, len );
312 vml->cache_dir[len] = VIKING_FILE_SEP;
313 vml->cache_dir[len+1] = '\0';
316 vml->cache_dir = g_strdup ( dir );
318 maps_layer_mkdir_if_default_dir ( vml );
321 /****************************************/
322 /******** GOBJECT STUFF *****************/
323 /****************************************/
325 GType vik_maps_layer_get_type ()
327 static GType vml_type = 0;
331 static const GTypeInfo vml_info =
333 sizeof (VikMapsLayerClass),
334 NULL, /* base_init */
335 NULL, /* base_finalize */
336 NULL, /* class init */
337 NULL, /* class_finalize */
338 NULL, /* class_data */
339 sizeof (VikMapsLayer),
341 NULL /* instance init */
343 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
349 /****************************************/
350 /************** PARAMETERS **************/
351 /****************************************/
353 static guint map_index_to_uniq_id (guint8 index)
355 g_assert ( index < NUM_MAP_TYPES );
356 return MAPS_LAYER_NTH_TYPE(index)->uniq_id;
359 static guint map_uniq_id_to_index ( guint uniq_id )
362 for ( i = 0; i < NUM_MAP_TYPES; i++ )
363 if ( MAPS_LAYER_NTH_TYPE(i)->uniq_id == uniq_id )
365 return NUM_MAP_TYPES; /* no such thing */
368 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp )
372 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
373 case PARAM_MAPTYPE: {
374 gint maptype = map_uniq_id_to_index(data.u);
375 if ( maptype == NUM_MAP_TYPES ) g_warning("Unknown map type");
376 else vml->maptype = maptype;
379 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
380 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
381 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
382 vml->mapzoom_id = data.u;
383 vml->xmapzoom = __mapzooms_x [data.u];
384 vml->ymapzoom = __mapzooms_y [data.u];
385 }else g_warning ("Unknown Map Zoom"); break;
390 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id )
392 VikLayerParamData rv;
395 case PARAM_CACHE_DIR: rv.s = (vml->cache_dir && strcmp(vml->cache_dir, MAPS_CACHE_DIR) != 0) ? vml->cache_dir : ""; break;
396 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
397 case PARAM_ALPHA: rv.u = vml->alpha; break;
398 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
399 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
404 /****************************************/
405 /****** CREATING, COPYING, FREEING ******/
406 /****************************************/
408 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
411 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
412 vik_layer_init ( VIK_LAYER(vml), VIK_LAYER_MAPS );
413 idx = map_uniq_id_to_index(7); /* 7 is id for google maps */
414 vml->maptype = (idx < NUM_MAP_TYPES) ? idx : 0;
417 vml->dl_tool_x = vml->dl_tool_y = -1;
418 maps_layer_set_cache_dir ( vml, NULL );
419 vml->autodownload = FALSE;
420 vml->last_center = NULL;
421 vml->last_xmpp = 0.0;
422 vml->last_ympp = 0.0;
424 vml->dl_right_click_menu = NULL;
429 static void maps_layer_free ( VikMapsLayer *vml )
431 g_free ( vml->cache_dir );
432 vml->cache_dir = NULL;
433 if ( vml->dl_right_click_menu )
434 gtk_object_sink ( GTK_OBJECT(vml->dl_right_click_menu) );
435 g_free(vml->last_center);
436 vml->last_center = NULL;
439 static void maps_layer_post_read (VikMapsLayer *vml, gpointer vp)
441 VikViewportDrawMode vp_drawmode;
442 VikMapsLayer_MapType *map_type = NULL;
444 vp_drawmode = vik_viewport_get_drawmode ( VIK_VIEWPORT(vp) );
445 map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
446 if (map_type->drawmode != vp_drawmode) {
447 gchar *drawmode_name = vik_viewport_get_drawmode_name (VIK_VIEWPORT(vp), map_type->drawmode);
448 gchar *msg = g_strdup_printf("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it.", drawmode_name);
449 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), msg );
454 static VikMapsLayer *maps_layer_copy ( VikMapsLayer *vml, VikViewport *vvp )
456 VikMapsLayer *rv = maps_layer_new ( vvp );
458 rv->cache_dir = g_strdup(rv->cache_dir);
459 VIK_LAYER(rv)->name = NULL;
463 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
465 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
468 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
470 VikMapsLayer *rv = maps_layer_new ( vvp );
471 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
475 /*********************/
476 /****** DRAWING ******/
477 /*********************/
479 static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
482 gint width, height, iii, jjj;
484 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
486 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
487 g_object_unref(G_OBJECT(pixbuf));
491 pixels = gdk_pixbuf_get_pixels(pixbuf);
492 width = gdk_pixbuf_get_width(pixbuf);
493 height = gdk_pixbuf_get_height(pixbuf);
495 /* r,g,b,a,r,g,b,a.... */
496 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
504 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
507 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
508 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_BILINEAR);
509 g_object_unref ( G_OBJECT(pixbuf) );
513 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
518 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
519 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
522 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
523 vml->cache_dir, mode,
524 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
525 if ( access ( filename_buf, R_OK ) == 0) {
528 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
532 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
533 g_warning ( "Couldn't open image file: %s", gx->message );
537 g_object_unref ( G_OBJECT(pixbuf) );
540 if ( vml->alpha < 255 )
541 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
542 if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
543 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
545 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
546 mapcoord->z, MAPS_LAYER_NTH_TYPE(vml->maptype)->uniq_id,
547 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
555 gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
557 const VikCoord *center = vik_viewport_get_center ( vvp );
559 if (vml->last_center == NULL) {
560 VikCoord *new_center = g_malloc(sizeof(VikCoord));
561 *new_center = *center;
562 vml->last_center = new_center;
563 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
564 vml->last_ympp = vik_viewport_get_ympp(vvp);
568 /* TODO: perhaps vik_coord_diff() */
569 if (vik_coord_equals(vml->last_center, center)
570 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
571 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
574 *(vml->last_center) = *center;
575 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
576 vml->last_ympp = vik_viewport_get_ympp(vvp);
580 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
583 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
584 gdouble yzoom = vik_viewport_get_ympp ( vvp );
585 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
587 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
588 xshrinkfactor = vml->xmapzoom / xzoom;
589 yshrinkfactor = vml->ymapzoom / yzoom;
590 if ( xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
591 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) {
592 xzoom = vml->xmapzoom;
593 yzoom = vml->xmapzoom;
595 g_warning ( "Cowardly refusing to draw tiles at a shrinkfactor more than %.3f (zoomed out) or less than %.3f (zoomed in).", 1/MIN_SHRINKFACTOR, 1/MAX_SHRINKFACTOR );
600 VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
601 if ( map_type->coord_to_mapcoord ( ul, xzoom, yzoom, &ulm ) &&
602 map_type->coord_to_mapcoord ( br, xzoom, yzoom, &brm ) ) {
606 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
607 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
608 gint mode = map_type->uniq_id;
611 gint xx, yy, width, height;
614 guint max_path_len = strlen(vml->cache_dir) + 40;
615 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
617 if ( vml->autodownload && should_start_autodownload(vml, vvp)) {
619 fputs(stderr, "DEBUG: Starting autodownload\n");
621 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
624 if ( map_type->tilesize_x == 0 ) {
625 for ( x = xmin; x <= xmax; x++ ) {
626 for ( y = ymin; y <= ymax; y++ ) {
629 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
631 width = gdk_pixbuf_get_width ( pixbuf );
632 height = gdk_pixbuf_get_height ( pixbuf );
634 map_type->mapcoord_to_center_coord ( &ulm, &coord );
635 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
639 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
643 } else { /* tilesize is known, don't have to keep converting coords */
644 gdouble tilesize_x = map_type->tilesize_x * xshrinkfactor;
645 gdouble tilesize_y = map_type->tilesize_y * yshrinkfactor;
646 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
647 gint tilesize_x_ceil = ceil ( tilesize_x );
648 gint tilesize_y_ceil = ceil ( tilesize_y );
649 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
650 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
651 gdouble xx, yy; gint xx_tmp, yy_tmp;
652 gint base_yy, xend, yend;
653 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
654 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
656 map_type->mapcoord_to_center_coord ( &ulm, &coord );
657 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
658 xx = xx_tmp; yy = yy_tmp;
659 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
660 * eg if tile size 128, shrinkfactor 0.333 */
661 xx -= (tilesize_x/2);
662 base_yy = yy - (tilesize_y/2);
664 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
666 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
669 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
671 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
683 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
685 if ( MAPS_LAYER_NTH_TYPE(vml->maptype)->drawmode == vik_viewport_get_drawmode ( vvp ) )
689 /* get corner coords */
690 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
691 /* UTM multi-zone stuff by Kit Transue */
692 gchar leftmost_zone, rightmost_zone, i;
693 leftmost_zone = vik_viewport_leftmost_zone( vvp );
694 rightmost_zone = vik_viewport_rightmost_zone( vvp );
695 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
696 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
697 maps_layer_draw_section ( vml, vvp, &ul, &br );
701 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
702 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
704 maps_layer_draw_section ( vml, vvp, &ul, &br );
709 /*************************/
710 /****** DOWNLOADING ******/
711 /*************************/
713 /* pass along data to thread, exists even if layer is deleted. */
723 gboolean refresh_display;
726 gboolean map_layer_alive;
730 static void mdi_free ( MapDownloadInfo *mdi )
732 g_mutex_free(mdi->mutex);
733 g_free ( mdi->cache_dir );
734 mdi->cache_dir = NULL;
735 g_free ( mdi->filename_buf );
736 mdi->filename_buf = NULL;
740 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
742 MapDownloadInfo *mdi = ptr;
743 g_mutex_lock(mdi->mutex);
744 mdi->map_layer_alive = FALSE;
745 g_mutex_unlock(mdi->mutex);
748 static void map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
752 for ( x = mdi->x0; x <= mdi->xf; x++ )
754 for ( y = mdi->y0; y <= mdi->yf; y++ )
756 gboolean remove_mem_cache = FALSE;
757 gboolean need_download = FALSE;
758 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
759 mdi->cache_dir, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id,
760 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
763 a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
765 if ( mdi->redownload == REDOWNLOAD_ALL)
766 remove ( mdi->filename_buf );
768 else if ( (mdi->redownload == REDOWNLOAD_BAD) && (access ( mdi->filename_buf, F_OK ) == 0) )
770 /* see if this one is bad or what */
772 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
774 remove ( mdi->filename_buf );
776 g_object_unref ( pixbuf );
781 if ( access ( mdi->filename_buf, F_OK ) != 0 )
783 need_download = TRUE;
784 if (( mdi->redownload != REDOWNLOAD_NONE ) &&
785 ( mdi->redownload != DOWNLOAD_OR_REFRESH ))
786 remove_mem_cache = TRUE;
787 } else if ( mdi->redownload == DOWNLOAD_OR_REFRESH ) {
788 remove_mem_cache = TRUE;
792 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
795 if ( MAPS_LAYER_NTH_TYPE(mdi->maptype)->download ( &(mdi->mapcoord), mdi->filename_buf ))
800 g_mutex_lock(mdi->mutex);
801 if (remove_mem_cache)
802 a_mapcache_remove_all_shrinkfactors ( x, y, mdi->mapcoord.z, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id, mdi->mapcoord.scale );
803 if (mdi->refresh_display && mdi->map_layer_alive) {
804 /* TODO: check if it's on visible area */
805 vik_layer_emit_update ( VIK_LAYER(mdi->vml) );
807 g_mutex_unlock(mdi->mutex);
809 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
813 g_mutex_lock(mdi->mutex);
814 if (mdi->map_layer_alive)
815 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
816 g_mutex_unlock(mdi->mutex);
819 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
821 if ( mdi->mapcoord.x || mdi->mapcoord.y )
823 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
824 mdi->cache_dir, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id,
825 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
826 if ( access ( mdi->filename_buf, F_OK ) == 0)
828 remove ( mdi->filename_buf );
833 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
835 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
836 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
838 VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
839 if ( map_type->coord_to_mapcoord ( ul, xzoom, yzoom, &ulm )
840 && map_type->coord_to_mapcoord ( br, xzoom, yzoom, &brm ) )
842 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
847 mdi->map_layer_alive = TRUE;
848 mdi->mutex = g_mutex_new();
849 mdi->refresh_display = TRUE;
851 /* cache_dir and buffer for dest filename */
852 mdi->cache_dir = g_strdup ( vml->cache_dir );
853 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
854 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
855 mdi->maptype = vml->maptype;
859 mdi->redownload = redownload;
861 mdi->x0 = MIN(ulm.x, brm.x);
862 mdi->xf = MAX(ulm.x, brm.x);
863 mdi->y0 = MIN(ulm.y, brm.y);
864 mdi->yf = MAX(ulm.y, brm.y);
868 if ( mdi->redownload ) {
869 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
871 /* calculate how many we need */
872 for ( a = mdi->x0; a <= mdi->xf; a++ )
874 for ( b = mdi->y0; b <= mdi->yf; b++ )
876 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
877 vml->cache_dir, map_type->uniq_id, ulm.scale,
879 if ( access ( mdi->filename_buf, F_OK ) != 0)
885 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
887 if ( mdi->mapstoget )
889 gchar *tmp = g_strdup_printf ( "%s %s%d %s %s...", redownload ? "Redownloading" : "Downloading", redownload == REDOWNLOAD_BAD ? "up to " : "", mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype), (mdi->mapstoget == 1) ? "map" : "maps" );
891 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
892 /* launch the thread */
893 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
894 tmp, /* description string */
895 (vik_thr_func) map_download_thread, /* function to call within thread */
896 mdi, /* pass along data */
897 (vik_thr_free_func) mdi_free, /* function to free pass along data */
898 (vik_thr_free_func) mdi_cancel_cleanup,
907 void maps_layer_download_section_without_redraw( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
910 VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
912 if (!map_type->coord_to_mapcoord(ul, zoom, zoom, &ulm)
913 || !map_type->coord_to_mapcoord(br, zoom, zoom, &brm)) {
914 g_warning("%s() coord_to_mapcoord() failed\n", __PRETTY_FUNCTION__);
918 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
923 mdi->map_layer_alive = TRUE;
924 mdi->mutex = g_mutex_new();
925 mdi->refresh_display = FALSE;
927 mdi->cache_dir = g_strdup ( vml->cache_dir );
928 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
929 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
930 mdi->maptype = vml->maptype;
934 mdi->redownload = REDOWNLOAD_NONE;
936 mdi->x0 = MIN(ulm.x, brm.x);
937 mdi->xf = MAX(ulm.x, brm.x);
938 mdi->y0 = MIN(ulm.y, brm.y);
939 mdi->yf = MAX(ulm.y, brm.y);
943 for (i = mdi->x0; i <= mdi->xf; i++) {
944 for (j = mdi->y0; j <= mdi->yf; j++) {
945 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
946 vml->cache_dir, map_type->uniq_id, ulm.scale,
948 if ( access ( mdi->filename_buf, F_OK ) != 0)
953 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
955 if (mdi->mapstoget) {
956 gchar *tmp = g_strdup_printf ( "%s %d %s %s...", "Downloading", mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype), (mdi->mapstoget == 1) ? "map" : "maps" );
958 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
959 /* launch the thread */
960 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
961 tmp, /* description string */
962 (vik_thr_func) map_download_thread, /* function to call within thread */
963 mdi, /* pass along data */
964 (vik_thr_free_func) mdi_free, /* function to free pass along data */
965 (vik_thr_free_func) mdi_cancel_cleanup,
973 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
975 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
977 static void maps_layer_redownload_all ( VikMapsLayer *vml )
979 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
982 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
984 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
986 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
988 if ( event->button == 1 )
991 vik_viewport_screen_to_coord ( vvp, MAX(0, MIN(event->x, vml->dl_tool_x)), MAX(0, MIN(event->y, vml->dl_tool_y)), &ul );
992 vik_viewport_screen_to_coord ( vvp, MIN(vik_viewport_get_width(vvp), MAX(event->x, vml->dl_tool_x)), MIN(vik_viewport_get_height(vvp), MAX ( event->y, vml->dl_tool_y ) ), &br );
993 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
994 vml->dl_tool_x = vml->dl_tool_y = -1;
999 vik_viewport_screen_to_coord ( vvp, MAX(0, MIN(event->x, vml->dl_tool_x)), MAX(0, MIN(event->y, vml->dl_tool_y)), &(vml->redownload_ul) );
1000 vik_viewport_screen_to_coord ( vvp, MIN(vik_viewport_get_width(vvp), MAX(event->x, vml->dl_tool_x)), MIN(vik_viewport_get_height(vvp), MAX ( event->y, vml->dl_tool_y ) ), &(vml->redownload_br) );
1002 vml->redownload_vvp = vvp;
1004 vml->dl_tool_x = vml->dl_tool_y = -1;
1006 if ( ! vml->dl_right_click_menu ) {
1008 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1010 item = gtk_menu_item_new_with_label ( "Redownload bad map(s)" );
1011 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1012 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1014 item = gtk_menu_item_new_with_label ( "Redownload all map(s)" );
1015 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1016 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1019 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1020 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1026 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1031 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1034 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1036 VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
1037 if ( map_type->drawmode == vik_viewport_get_drawmode ( vvp ) &&
1038 map_type->coord_to_mapcoord ( vik_viewport_get_center ( vvp ),
1039 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1040 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1042 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1049 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1053 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1054 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1055 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1056 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1058 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1059 vml->cache_dir, __map_types[vml->maptype].uniq_id,
1060 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1062 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1063 g_free ( filename_buf );
1064 vik_layer_emit_update ( VIK_LAYER(vml) );
1072 static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
1074 VikMapsLayer *vml = vml_vvp[0];
1075 VikViewport *vvp = vml_vvp[1];
1076 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
1078 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1079 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1084 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1085 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1087 VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
1088 if ( map_type->drawmode == vp_drawmode &&
1089 map_type->coord_to_mapcoord ( &ul, xzoom, yzoom, &ulm ) &&
1090 map_type->coord_to_mapcoord ( &br, xzoom, yzoom, &brm ) )
1091 start_download_thread ( vml, vvp, &ul, &br, redownload );
1092 else if (map_type->drawmode != vp_drawmode) {
1093 gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, map_type->drawmode);
1094 gchar *err = g_strdup_printf("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again.", drawmode_name);
1095 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1099 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), "Wrong zoom level for this map." );
1103 static void maps_layer_download_onscreen_maps ( gpointer vml_vvp[2] )
1105 download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1108 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1110 download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1113 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1115 static gpointer pass_along[2];
1117 pass_along[0] = vml;
1118 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1120 item = gtk_menu_item_new();
1121 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1122 gtk_widget_show ( item );
1124 item = gtk_menu_item_new_with_label ( "Download Onscreen Maps" );
1125 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_onscreen_maps), pass_along );
1126 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1127 gtk_widget_show ( item );
1129 item = gtk_menu_item_new_with_label ( "Refresh Onscreen Tiles" );
1130 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1131 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1132 gtk_widget_show ( item );