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 static void mdi_free ( MapDownloadInfo *mdi )
667 g_free ( mdi->cache_dir );
668 g_free ( mdi->filename_buf );
672 static void map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
676 for ( x = mdi->x0; x <= mdi->xf; x++ )
678 for ( y = mdi->y0; y <= mdi->yf; y++ )
680 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
681 mdi->cache_dir, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id,
682 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
684 if ( mdi->redownload == REDOWNLOAD_ALL)
685 remove ( mdi->filename_buf );
686 else if ( mdi->redownload == REDOWNLOAD_BAD && access ( mdi->filename_buf, F_OK ) == 0 )
688 /* see if this one is bad or what */
690 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
692 remove ( mdi->filename_buf );
694 g_object_unref ( pixbuf );
699 if ( access ( mdi->filename_buf, F_OK ) != 0 )
701 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
702 MAPS_LAYER_NTH_TYPE(mdi->maptype)->download ( &(mdi->mapcoord), mdi->filename_buf );
703 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
705 if ( mdi->redownload !=- REDOWNLOAD_NONE )
706 a_mapcache_remove_all_shrinkfactors ( x, y, mdi->mapcoord.z, mdi->maptype, mdi->mapcoord.scale );
710 a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
716 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
718 if ( mdi->mapcoord.x || mdi->mapcoord.y )
720 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
721 mdi->cache_dir, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id,
722 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
723 if ( access ( mdi->filename_buf, F_OK ) == 0)
725 remove ( mdi->filename_buf );
730 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
732 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
733 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
735 VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
736 if ( map_type->coord_to_mapcoord ( ul, xzoom, yzoom, &ulm )
737 && map_type->coord_to_mapcoord ( br, xzoom, yzoom, &brm ) )
739 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
742 /* cache_dir and buffer for dest filename */
743 mdi->cache_dir = g_strdup ( vml->cache_dir );
744 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
745 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
746 mdi->maptype = vml->maptype;
750 mdi->redownload = redownload;
752 mdi->x0 = MIN(ulm.x, brm.x);
753 mdi->xf = MAX(ulm.x, brm.x);
754 mdi->y0 = MIN(ulm.y, brm.y);
755 mdi->yf = MAX(ulm.y, brm.y);
759 if ( mdi->redownload ) {
760 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
762 /* calculate how many we need */
763 for ( a = mdi->x0; a <= mdi->xf; a++ )
765 for ( b = mdi->y0; b <= mdi->yf; b++ )
767 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
768 vml->cache_dir, map_type->uniq_id, ulm.scale,
770 if ( access ( mdi->filename_buf, F_OK ) != 0)
776 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
778 if ( mdi->mapstoget )
780 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" );
782 /* launch the thread */
783 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
784 tmp, /* description string */
785 (vik_thr_func) map_download_thread, /* function to call within thread */
786 mdi, /* pass along data */
787 (vik_thr_free_func) mdi_free, /* function to free pass along data */
788 (vik_thr_free_func) mdi_cancel_cleanup,
797 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
799 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
801 static void maps_layer_redownload_all ( VikMapsLayer *vml )
803 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
806 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
808 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
810 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
812 if ( event->button == 1 )
815 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 );
816 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 );
817 start_download_thread ( vml, vvp, &ul, &br, REDOWNLOAD_NONE );
818 vml->dl_tool_x = vml->dl_tool_y = -1;
823 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) );
824 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) );
826 vml->redownload_vvp = vvp;
828 vml->dl_tool_x = vml->dl_tool_y = -1;
830 if ( ! vml->dl_right_click_menu ) {
832 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
834 item = gtk_menu_item_new_with_label ( "Redownload bad map(s)" );
835 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
836 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
838 item = gtk_menu_item_new_with_label ( "Redownload all map(s)" );
839 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
840 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
843 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
844 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
850 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
855 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
858 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
860 VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
861 if ( map_type->drawmode == vik_viewport_get_drawmode ( vvp ) &&
862 map_type->coord_to_mapcoord ( vik_viewport_get_center ( vvp ),
863 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
864 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
866 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
873 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
877 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
878 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
879 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
880 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
882 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
883 vml->cache_dir, __map_types[vml->maptype].uniq_id,
884 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
886 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
887 g_free ( filename_buf );
888 vik_layer_emit_update ( VIK_LAYER(vml) );
896 static void maps_layer_download_onscreen_maps ( gpointer vml_vvp[2] )
898 VikMapsLayer *vml = vml_vvp[0];
899 VikViewport *vvp = vml_vvp[1];
901 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
902 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
907 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
908 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
910 VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
911 if ( map_type->drawmode == vik_viewport_get_drawmode ( vvp ) &&
912 map_type->coord_to_mapcoord ( &ul, xzoom, yzoom, &ulm ) &&
913 map_type->coord_to_mapcoord ( &br, xzoom, yzoom, &brm ) )
914 start_download_thread ( vml, vvp, &ul, &br, REDOWNLOAD_NONE );
916 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), "Wrong drawmode / zoom level for this map." );
920 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
922 static gpointer pass_along[2];
925 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
927 item = gtk_menu_item_new();
928 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
929 gtk_widget_show ( item );
931 item = gtk_menu_item_new_with_label ( "Download Onscreen Maps" );
932 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_onscreen_maps), pass_along );
933 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
934 gtk_widget_show ( item );