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"
58 #include "googlemaps.h"
64 /****** MAP TYPES ******/
66 static GList *__map_types = NULL;
68 #define NUM_MAP_TYPES g_list_length(__map_types)
70 /* List of label for each map type */
71 static GList *params_maptypes = NULL;
73 /* Corresponding IDS. (Cf. field uniq_id in VikMapsLayer struct) */
74 static GList *params_maptypes_ids = NULL;
76 /******** MAPZOOMS *********/
78 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 };
79 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 };
80 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 };
82 #define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0]) - 1)
84 /**************************/
87 static VikMapsLayer *maps_layer_copy ( VikMapsLayer *vml, VikViewport *vvp );
88 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len );
89 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
90 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp );
91 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id );
92 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp );
93 static VikMapsLayer *maps_layer_new ( VikViewport *vvp );
94 static void maps_layer_free ( VikMapsLayer *vml );
95 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
96 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
97 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp );
98 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir );
99 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload );
100 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp );
103 static VikLayerParamScale params_scales[] = {
104 /* min, max, step, digits (decimal places) */
105 { 0, 255, 3, 0 }, /* alpha */
108 VikLayerParam maps_layer_params[] = {
109 { "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, "Map Type:", VIK_LAYER_WIDGET_RADIOGROUP, NULL, NULL },
110 { "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, "Maps Directory (Optional):", VIK_LAYER_WIDGET_FILEENTRY },
111 { "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, "Alpha:", VIK_LAYER_WIDGET_HSCALE, params_scales },
112 { "autodownload", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, "Autodownload maps:", VIK_LAYER_WIDGET_CHECKBUTTON },
113 { "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, "Zoom Level:", VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms },
116 enum { PARAM_MAPTYPE=0, PARAM_CACHE_DIR, PARAM_ALPHA, PARAM_AUTODOWNLOAD, PARAM_MAPZOOM, NUM_PARAMS };
118 static VikToolInterface maps_tools[] = {
119 { "Maps Download", (VikToolConstructorFunc) maps_layer_download_create, NULL, NULL, NULL,
120 (VikToolMouseFunc) maps_layer_download_click, NULL, (VikToolMouseFunc) maps_layer_download_release },
123 VikLayerInterface vik_maps_layer_interface = {
128 sizeof(maps_tools) / sizeof(maps_tools[0]),
137 (VikLayerFuncCreate) maps_layer_new,
138 (VikLayerFuncRealize) NULL,
139 (VikLayerFuncPostRead) NULL,
140 (VikLayerFuncFree) maps_layer_free,
142 (VikLayerFuncProperties) NULL,
143 (VikLayerFuncDraw) maps_layer_draw,
144 (VikLayerFuncChangeCoordMode) NULL,
146 (VikLayerFuncSetMenuItemsSelection) NULL,
147 (VikLayerFuncGetMenuItemsSelection) NULL,
149 (VikLayerFuncAddMenuItems) maps_layer_add_menu_items,
150 (VikLayerFuncSublayerAddMenuItems) NULL,
152 (VikLayerFuncSublayerRenameRequest) NULL,
153 (VikLayerFuncSublayerToggleVisible) NULL,
155 (VikLayerFuncCopy) maps_layer_copy,
156 (VikLayerFuncMarshall) maps_layer_marshall,
157 (VikLayerFuncUnmarshall) maps_layer_unmarshall,
159 (VikLayerFuncSetParam) maps_layer_set_param,
160 (VikLayerFuncGetParam) maps_layer_get_param,
162 (VikLayerFuncReadFileData) NULL,
163 (VikLayerFuncWriteFileData) NULL,
165 (VikLayerFuncDeleteItem) NULL,
166 (VikLayerFuncCopyItem) NULL,
167 (VikLayerFuncPasteItem) NULL,
168 (VikLayerFuncFreeCopiedItem) NULL,
169 (VikLayerFuncDragDropRequest) NULL,
172 struct _VikMapsLayer {
178 gdouble xmapzoom, ymapzoom;
180 gboolean autodownload;
182 gint dl_tool_x, dl_tool_y;
184 GtkMenu *dl_right_click_menu;
185 VikCoord redownload_ul, redownload_br; /* right click menu only */
186 VikViewport *redownload_vvp;
189 enum { REDOWNLOAD_NONE = 0, REDOWNLOAD_BAD, REDOWNLOAD_ALL };
192 /****************************************/
193 /******** MAPS LAYER TYPES **************/
194 /****************************************/
196 void maps_layer_register_type ( const char *label, guint id, VikMapsLayer_MapType *map_type )
198 g_assert(label != NULL);
199 g_assert(map_type != NULL);
200 g_assert(id == map_type->uniq_id);
203 params_maptypes = g_list_append(params_maptypes, g_strdup(label));
206 params_maptypes_ids = g_list_append(params_maptypes_ids, (gpointer)id);
208 /* We have to clone */
209 VikMapsLayer_MapType *clone = g_memdup(map_type, sizeof(VikMapsLayer_MapType));
210 /* Register the clone in the list */
211 __map_types = g_list_append(__map_types, clone);
214 We have to ensure the mode LayerParam reference the up-to-date
218 memcpy(&maps_layer_params[0].widget_data, ¶ms_maptypes, sizeof(gpointer));
219 memcpy(&maps_layer_params[0].extra_widget_data, ¶ms_maptypes_ids, sizeof(gpointer));
221 maps_layer_params[0].widget_data = params_maptypes;
222 maps_layer_params[0].extra_widget_data = params_maptypes_ids;
225 #define MAPS_LAYER_NTH_LABEL(n) ((gchar*)g_list_nth_data(params_maptypes, (n)))
226 #define MAPS_LAYER_NTH_ID(n) ((guint)g_list_nth_data(params_maptypes_ids, (n)))
227 #define MAPS_LAYER_NTH_TYPE(n) ((VikMapsLayer_MapType*)g_list_nth_data(__map_types, (n)))
229 /****************************************/
230 /******** CACHE DIR STUFF ***************/
231 /****************************************/
234 #define MAPS_CACHE_DIR "C:\\VIKING-MAPS\\"
235 #define DIRSTRUCTURE "%st%ds%dz%d\\%d\\%d"
240 #define MAPS_CACHE_DIR maps_layer_default_dir()
241 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
242 #define DIRSTRUCTURE "%st%ds%dz%d/%d/%d"
244 static gchar *maps_layer_default_dir ()
246 static gchar defaultdir[512];
247 static gboolean already_run = 0;
250 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
251 gchar *mapdir = getenv("VIKING_MAPS");
252 if ( mapdir && strlen(mapdir) < 497 ) {
253 strcpy ( defaultdir, mapdir );
254 } else if ( access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
255 strcpy ( defaultdir, GLOBAL_MAPS_DIR );
257 gchar *home = getenv("HOME");
258 if ( home && strlen(home) < 497 )
260 strcpy ( defaultdir, home );
261 strcat ( defaultdir, "/.viking-maps/" );
265 strcpy ( defaultdir, ".viking-maps/" );
275 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
277 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && access ( vml->cache_dir, F_OK ) != 0 )
280 mkdir ( vml->cache_dir );
282 mkdir ( vml->cache_dir, 0777 );
287 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
290 g_assert ( vml != NULL);
291 if ( vml->cache_dir )
292 g_free ( vml->cache_dir );
294 if ( dir == NULL || dir[0] == '\0' )
295 vml->cache_dir = g_strdup ( MAPS_CACHE_DIR );
299 if ( dir[len-1] != VIKING_FILE_SEP )
301 vml->cache_dir = g_malloc ( len+2 );
302 strncpy ( vml->cache_dir, dir, len );
303 vml->cache_dir[len] = VIKING_FILE_SEP;
304 vml->cache_dir[len+1] = '\0';
307 vml->cache_dir = g_strdup ( dir );
309 maps_layer_mkdir_if_default_dir ( vml );
312 /****************************************/
313 /******** GOBJECT STUFF *****************/
314 /****************************************/
316 GType vik_maps_layer_get_type ()
318 static GType vml_type = 0;
322 static const GTypeInfo vml_info =
324 sizeof (VikMapsLayerClass),
325 NULL, /* base_init */
326 NULL, /* base_finalize */
327 NULL, /* class init */
328 NULL, /* class_finalize */
329 NULL, /* class_data */
330 sizeof (VikMapsLayer),
332 NULL /* instance init */
334 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
340 /****************************************/
341 /************** PARAMETERS **************/
342 /****************************************/
344 static guint map_index_to_uniq_id (guint8 index)
346 g_assert ( index < NUM_MAP_TYPES );
347 return MAPS_LAYER_NTH_TYPE(index)->uniq_id;
350 static guint map_uniq_id_to_index ( guint uniq_id )
353 for ( i = 0; i < NUM_MAP_TYPES; i++ )
354 if ( MAPS_LAYER_NTH_TYPE(i)->uniq_id == uniq_id )
356 return NUM_MAP_TYPES; /* no such thing */
359 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp )
363 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
364 case PARAM_MAPTYPE: {
365 gint maptype = map_uniq_id_to_index(data.u);
366 if ( maptype == NUM_MAP_TYPES ) g_warning("Unknown map type");
367 else vml->maptype = maptype;
370 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
371 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
372 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
373 vml->mapzoom_id = data.u;
374 vml->xmapzoom = __mapzooms_x [data.u];
375 vml->ymapzoom = __mapzooms_y [data.u];
376 }else g_warning ("Unknown Map Zoom"); break;
381 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id )
383 VikLayerParamData rv;
386 case PARAM_CACHE_DIR: rv.s = (vml->cache_dir && strcmp(vml->cache_dir, MAPS_CACHE_DIR) != 0) ? vml->cache_dir : ""; break;
387 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
388 case PARAM_ALPHA: rv.u = vml->alpha; break;
389 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
390 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
395 /****************************************/
396 /****** CREATING, COPYING, FREEING ******/
397 /****************************************/
399 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
401 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
402 vik_layer_init ( VIK_LAYER(vml), VIK_LAYER_MAPS );
406 vml->dl_tool_x = vml->dl_tool_y = -1;
407 maps_layer_set_cache_dir ( vml, NULL );
408 vml->autodownload = FALSE;
410 vml->dl_right_click_menu = NULL;
415 static void maps_layer_free ( VikMapsLayer *vml )
417 if ( vml->cache_dir )
418 g_free ( vml->cache_dir );
419 if ( vml->dl_right_click_menu )
420 gtk_object_sink ( GTK_OBJECT(vml->dl_right_click_menu) );
423 static VikMapsLayer *maps_layer_copy ( VikMapsLayer *vml, VikViewport *vvp )
425 VikMapsLayer *rv = maps_layer_new ( vvp );
427 rv->cache_dir = g_strdup(rv->cache_dir);
428 VIK_LAYER(rv)->name = NULL;
432 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
434 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
437 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
439 VikMapsLayer *rv = maps_layer_new ( vvp );
440 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
444 /*********************/
445 /****** DRAWING ******/
446 /*********************/
448 static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
451 gint width, height, iii, jjj;
453 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
455 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
456 g_object_unref(G_OBJECT(pixbuf));
460 pixels = gdk_pixbuf_get_pixels(pixbuf);
461 width = gdk_pixbuf_get_width(pixbuf);
462 height = gdk_pixbuf_get_height(pixbuf);
464 /* r,g,b,a,r,g,b,a.... */
465 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
473 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
476 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
477 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_BILINEAR);
478 g_object_unref ( G_OBJECT(pixbuf) );
482 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
487 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
488 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
491 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
492 vml->cache_dir, mode,
493 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
494 if ( access ( filename_buf, R_OK ) == 0) {
497 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
501 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
502 g_warning ( "Couldn't open image file: %s", gx->message );
506 g_object_unref ( G_OBJECT(pixbuf) );
509 if ( vml->alpha < 255 )
510 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
511 if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
512 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
514 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
515 mapcoord->z, MAPS_LAYER_NTH_TYPE(vml->maptype)->uniq_id,
516 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
524 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
527 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
528 gdouble yzoom = vik_viewport_get_ympp ( vvp );
529 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
531 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
532 xshrinkfactor = vml->xmapzoom / xzoom;
533 yshrinkfactor = vml->ymapzoom / yzoom;
534 if ( xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
535 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) {
536 xzoom = vml->xmapzoom;
537 yzoom = vml->xmapzoom;
539 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 );
544 VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
545 if ( map_type->coord_to_mapcoord ( ul, xzoom, yzoom, &ulm ) &&
546 map_type->coord_to_mapcoord ( br, xzoom, yzoom, &brm ) ) {
550 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
551 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
552 gint mode = map_type->uniq_id;
555 gint xx, yy, width, height;
558 guint max_path_len = strlen(vml->cache_dir) + 40;
559 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
561 if ( vml->autodownload )
562 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
564 if ( map_type->tilesize_x == 0 ) {
565 for ( x = xmin; x <= xmax; x++ ) {
566 for ( y = ymin; y <= ymax; y++ ) {
569 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
571 width = gdk_pixbuf_get_width ( pixbuf );
572 height = gdk_pixbuf_get_height ( pixbuf );
574 map_type->mapcoord_to_center_coord ( &ulm, &coord );
575 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
579 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
583 } else { /* tilesize is known, don't have to keep converting coords */
584 gdouble tilesize_x = map_type->tilesize_x * xshrinkfactor;
585 gdouble tilesize_y = map_type->tilesize_y * yshrinkfactor;
586 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
587 gint tilesize_x_ceil = ceil ( tilesize_x );
588 gint tilesize_y_ceil = ceil ( tilesize_y );
589 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
590 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
591 gdouble xx, yy; gint xx_tmp, yy_tmp;
592 gint base_yy, xend, yend;
593 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
594 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
596 map_type->mapcoord_to_center_coord ( &ulm, &coord );
597 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
598 xx = xx_tmp; yy = yy_tmp;
599 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
600 * eg if tile size 128, shrinkfactor 0.333 */
601 xx -= (tilesize_x/2);
602 base_yy = yy - (tilesize_y/2);
604 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
606 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
609 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
611 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
623 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
625 if ( MAPS_LAYER_NTH_TYPE(vml->maptype)->drawmode == vik_viewport_get_drawmode ( vvp ) )
629 /* get corner coords */
630 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
631 /* UTM multi-zone stuff by Kit Transue */
632 gchar leftmost_zone, rightmost_zone, i;
633 leftmost_zone = vik_viewport_leftmost_zone( vvp );
634 rightmost_zone = vik_viewport_rightmost_zone( vvp );
635 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
636 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
637 maps_layer_draw_section ( vml, vvp, &ul, &br );
641 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
642 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
644 maps_layer_draw_section ( vml, vvp, &ul, &br );
649 /*************************/
650 /****** DOWNLOADING ******/
651 /*************************/
653 /* pass along data to thread, exists even if layer is deleted. */
665 gboolean map_layer_alive;
669 static void mdi_free ( MapDownloadInfo *mdi )
671 g_mutex_free(mdi->mutex);
672 g_free ( mdi->cache_dir );
673 g_free ( mdi->filename_buf );
677 static GWeakNotify weak_ref_cb(MapDownloadInfo *mdi, GObject * dead_vml)
679 g_mutex_lock(mdi->mutex);
680 mdi->map_layer_alive = FALSE;
681 g_mutex_unlock(mdi->mutex);
684 static void map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
688 for ( x = mdi->x0; x <= mdi->xf; x++ )
690 for ( y = mdi->y0; y <= mdi->yf; y++ )
692 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
693 mdi->cache_dir, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id,
694 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
696 if ( mdi->redownload == REDOWNLOAD_ALL)
697 remove ( mdi->filename_buf );
698 else if ( mdi->redownload == REDOWNLOAD_BAD && access ( mdi->filename_buf, F_OK ) == 0 )
700 /* see if this one is bad or what */
702 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
704 remove ( mdi->filename_buf );
706 g_object_unref ( pixbuf );
711 if ( access ( mdi->filename_buf, F_OK ) != 0 )
713 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
714 MAPS_LAYER_NTH_TYPE(mdi->maptype)->download ( &(mdi->mapcoord), mdi->filename_buf );
716 g_mutex_lock(mdi->mutex);
717 if (mdi->map_layer_alive) {
718 /* TODO: check if it's on visible area */
719 vik_layer_emit_update ( VIK_LAYER(mdi->vml) );
721 g_mutex_unlock(mdi->mutex);
723 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
725 if ( mdi->redownload !=- REDOWNLOAD_NONE )
726 a_mapcache_remove_all_shrinkfactors ( x, y, mdi->mapcoord.z, mdi->maptype, mdi->mapcoord.scale );
730 if (donemaps == mdi->mapstoget) {
731 g_mutex_lock(mdi->mutex);
732 if (mdi->map_layer_alive)
733 g_object_weak_unref(VIK_LAYER(mdi->vml), weak_ref_cb, mdi);
734 g_mutex_unlock(mdi->mutex);
736 a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
742 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
744 if ( mdi->mapcoord.x || mdi->mapcoord.y )
746 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
747 mdi->cache_dir, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id,
748 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
749 if ( access ( mdi->filename_buf, F_OK ) == 0)
751 remove ( mdi->filename_buf );
756 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
758 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
759 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
761 VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
762 if ( map_type->coord_to_mapcoord ( ul, xzoom, yzoom, &ulm )
763 && map_type->coord_to_mapcoord ( br, xzoom, yzoom, &brm ) )
765 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
770 mdi->map_layer_alive = TRUE;
771 mdi->mutex = g_mutex_new();
773 /* cache_dir and buffer for dest filename */
774 mdi->cache_dir = g_strdup ( vml->cache_dir );
775 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
776 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
777 mdi->maptype = vml->maptype;
781 mdi->redownload = redownload;
783 mdi->x0 = MIN(ulm.x, brm.x);
784 mdi->xf = MAX(ulm.x, brm.x);
785 mdi->y0 = MIN(ulm.y, brm.y);
786 mdi->yf = MAX(ulm.y, brm.y);
790 if ( mdi->redownload ) {
791 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
793 /* calculate how many we need */
794 for ( a = mdi->x0; a <= mdi->xf; a++ )
796 for ( b = mdi->y0; b <= mdi->yf; b++ )
798 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
799 vml->cache_dir, map_type->uniq_id, ulm.scale,
801 if ( access ( mdi->filename_buf, F_OK ) != 0)
807 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
809 if ( mdi->mapstoget )
811 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" );
813 g_object_weak_ref(VIK_LAYER(mdi->vml), weak_ref_cb, mdi);
814 /* launch the thread */
815 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
816 tmp, /* description string */
817 (vik_thr_func) map_download_thread, /* function to call within thread */
818 mdi, /* pass along data */
819 (vik_thr_free_func) mdi_free, /* function to free pass along data */
820 (vik_thr_free_func) mdi_cancel_cleanup,
829 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
831 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
833 static void maps_layer_redownload_all ( VikMapsLayer *vml )
835 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
838 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
840 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
842 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
844 if ( event->button == 1 )
847 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 );
848 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 );
849 start_download_thread ( vml, vvp, &ul, &br, REDOWNLOAD_NONE );
850 vml->dl_tool_x = vml->dl_tool_y = -1;
855 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) );
856 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) );
858 vml->redownload_vvp = vvp;
860 vml->dl_tool_x = vml->dl_tool_y = -1;
862 if ( ! vml->dl_right_click_menu ) {
864 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
866 item = gtk_menu_item_new_with_label ( "Redownload bad map(s)" );
867 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
868 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
870 item = gtk_menu_item_new_with_label ( "Redownload all map(s)" );
871 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
872 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
875 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
876 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
882 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
887 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
890 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
892 VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
893 if ( map_type->drawmode == vik_viewport_get_drawmode ( vvp ) &&
894 map_type->coord_to_mapcoord ( vik_viewport_get_center ( vvp ),
895 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
896 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
898 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
905 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
909 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
910 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
911 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
912 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
914 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
915 vml->cache_dir, __map_types[vml->maptype].uniq_id,
916 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
918 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
919 g_free ( filename_buf );
920 vik_layer_emit_update ( VIK_LAYER(vml) );
928 static void maps_layer_download_onscreen_maps ( gpointer vml_vvp[2] )
930 VikMapsLayer *vml = vml_vvp[0];
931 VikViewport *vvp = vml_vvp[1];
933 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
934 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
939 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
940 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
942 VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
943 if ( map_type->drawmode == vik_viewport_get_drawmode ( vvp ) &&
944 map_type->coord_to_mapcoord ( &ul, xzoom, yzoom, &ulm ) &&
945 map_type->coord_to_mapcoord ( &br, xzoom, yzoom, &brm ) )
946 start_download_thread ( vml, vvp, &ul, &br, REDOWNLOAD_NONE );
948 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), "Wrong drawmode / zoom level for this map." );
952 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
954 static gpointer pass_along[2];
957 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
959 item = gtk_menu_item_new();
960 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
961 gtk_widget_show ( item );
963 item = gtk_menu_item_new_with_label ( "Download Onscreen Maps" );
964 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_onscreen_maps), pass_along );
965 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
966 gtk_widget_show ( item );