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>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #define MAX_SHRINKFACTOR 8.0000001 /* zoom 1 viewing 8-tiles */
24 #define MIN_SHRINKFACTOR 0.0312499 /* zoom 32 viewing 1-tiles */
27 #include <gdk-pixbuf/gdk-pixdata.h>
34 #include "viktreeview.h"
35 #include "vikviewport.h"
37 #include "vikmapslayer.h"
38 #include "vikmapslayer_pixmap.h"
42 #include <sys/types.h>
45 /* only for dialog.h -- ugh */
46 #include "vikwaypoint.h"
49 #include "vikstatus.h"
50 #include "background.h"
52 #include "vikaggregatelayer.h"
53 #include "viklayerspanel.h"
56 #include "terraserver.h"
57 #include "googlemaps.h"
67 gboolean (*coord_to_mapcoord) ( const VikCoord *src, gdouble xzoom, gdouble yzoom, MapCoord *dest );
68 void (*mapcoord_to_center_coord) ( MapCoord *src, VikCoord *dest );
69 void (*download) ( MapCoord *src, const gchar *dest_fn );
70 /* TODO: constant size (yay!) */
71 } VikMapsLayer_MapType;
74 /****** MAP TYPES ******/
76 static const VikMapsLayer_MapType __map_types[] = {
78 { 2, 200, 200, VIK_VIEWPORT_DRAWMODE_UTM, terraserver_topo_coord_to_mapcoord, terraserver_mapcoord_to_center_coord, terraserver_topo_download },
79 { 1, 200, 200, VIK_VIEWPORT_DRAWMODE_UTM, terraserver_aerial_coord_to_mapcoord, terraserver_mapcoord_to_center_coord, terraserver_aerial_download },
80 { 4, 200, 200, VIK_VIEWPORT_DRAWMODE_UTM, terraserver_urban_coord_to_mapcoord, terraserver_mapcoord_to_center_coord, terraserver_urban_download },
81 { 5, 0, 0, VIK_VIEWPORT_DRAWMODE_EXPEDIA, expedia_coord_to_mapcoord, expedia_mapcoord_to_center_coord, expedia_download },
82 { 9, 128, 128, VIK_VIEWPORT_DRAWMODE_GOOGLE, googlemaps_coord_to_mapcoord, googlemaps_mapcoord_to_center_coord, googlemaps_download },
83 { 8, 256, 256, VIK_VIEWPORT_DRAWMODE_KH, khmaps_coord_to_mapcoord, khmaps_mapcoord_to_center_coord, khmaps_download },
84 { 7, 256, 256, VIK_VIEWPORT_DRAWMODE_MERCATOR, google_coord_to_mapcoord, google_mapcoord_to_center_coord, google_download },
85 { 10, 256, 256, VIK_VIEWPORT_DRAWMODE_MERCATOR, google_coord_to_mapcoord, google_mapcoord_to_center_coord, google_trans_download },
86 { 11, 256, 256, VIK_VIEWPORT_DRAWMODE_MERCATOR, google_coord_to_mapcoord, google_mapcoord_to_center_coord, google_kh_download },
89 #define NUM_MAP_TYPES (sizeof(__map_types)/sizeof(__map_types[0]))
91 /******** MAPZOOMS *********/
93 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" };
94 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 };
95 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 };
97 static gchar *params_maptypes[] = { "Terraserver Topos", "Terraserver Aerials", "Terraserver Urban Areas", "Expedia (Street Maps)", "Google Maps (Street)", "KH Maps", "New (Mercator) Google", "Transparent Google", "New (Mercator) KH" };
98 static guint params_maptypes_ids[] = { 2, 1, 4, 5, 9, 8, 7, 10, 11 };
99 #define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0]))
101 /**************************/
104 static VikMapsLayer *maps_layer_copy ( VikMapsLayer *vml, VikViewport *vvp );
105 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp );
106 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id );
107 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp );
108 static VikMapsLayer *maps_layer_new ( VikViewport *vvp );
109 static void maps_layer_free ( VikMapsLayer *vml );
110 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
111 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
112 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir );
113 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload );
114 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp );
117 static VikLayerParamScale params_scales[] = {
118 /* min, max, step, digits (decimal places) */
119 { 0, 255, 3, 0 }, /* alpha */
122 VikLayerParam maps_layer_params[] = {
123 { "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, "Map Type:", VIK_LAYER_WIDGET_RADIOGROUP, params_maptypes, params_maptypes_ids },
124 { "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, "Maps Directory (Optional):", VIK_LAYER_WIDGET_FILEENTRY },
125 { "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, "Alpha:", VIK_LAYER_WIDGET_HSCALE, params_scales },
126 { "autodownload", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, "Autodownload maps:", VIK_LAYER_WIDGET_CHECKBUTTON },
127 { "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, "Zoom Level:", VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms },
130 enum { PARAM_MAPTYPE=0, PARAM_CACHE_DIR, PARAM_ALPHA, PARAM_AUTODOWNLOAD, PARAM_MAPZOOM, NUM_PARAMS };
132 static VikToolInterface maps_tools[] = {
133 { "Maps Download", (VikToolInterfaceFunc) maps_layer_download_click, (VikToolInterfaceFunc) maps_layer_download_release },
136 VikLayerInterface vik_maps_layer_interface = {
141 sizeof(maps_tools) / sizeof(maps_tools[0]),
148 (VikLayerFuncCreate) maps_layer_new,
149 (VikLayerFuncRealize) NULL,
150 (VikLayerFuncPostRead) NULL,
151 (VikLayerFuncFree) maps_layer_free,
153 (VikLayerFuncProperties) NULL,
154 (VikLayerFuncDraw) maps_layer_draw,
155 (VikLayerFuncChangeCoordMode) NULL,
157 (VikLayerFuncAddMenuItems) maps_layer_add_menu_items,
158 (VikLayerFuncSublayerAddMenuItems) NULL,
160 (VikLayerFuncSublayerRenameRequest) NULL,
161 (VikLayerFuncSublayerToggleVisible) NULL,
163 (VikLayerFuncCopy) maps_layer_copy,
165 (VikLayerFuncSetParam) maps_layer_set_param,
166 (VikLayerFuncGetParam) maps_layer_get_param,
168 (VikLayerFuncReadFileData) NULL,
169 (VikLayerFuncWriteFileData) NULL,
171 (VikLayerFuncCopyItem) NULL,
172 (VikLayerFuncPasteItem) NULL,
173 (VikLayerFuncFreeCopiedItem) NULL,
174 (VikLayerFuncDragDropRequest) NULL,
177 struct _VikMapsLayer {
183 gdouble xmapzoom, ymapzoom;
185 gboolean autodownload;
187 gint dl_tool_x, dl_tool_y;
189 GtkMenu *dl_right_click_menu;
190 VikCoord redownload_ul, redownload_br; /* right click menu only */
191 VikViewport *redownload_vvp;
194 enum { REDOWNLOAD_NONE = 0, REDOWNLOAD_BAD, REDOWNLOAD_ALL };
197 /****************************************/
198 /******** CACHE DIR STUFF ***************/
199 /****************************************/
202 #define MAPS_CACHE_DIR "C:\\VIKING-MAPS\\"
203 #define DIRSTRUCTURE "%st%ds%dz%d\\%d\\%d"
208 #define MAPS_CACHE_DIR maps_layer_default_dir()
209 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
210 #define DIRSTRUCTURE "%st%ds%dz%d/%d/%d"
212 static gchar *maps_layer_default_dir ()
214 static gchar defaultdir[512];
215 static gboolean already_run = 0;
218 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
219 gchar *mapdir = getenv("VIKING_MAPS");
220 if ( mapdir && strlen(mapdir) < 497 ) {
221 strcpy ( defaultdir, mapdir );
222 } else if ( access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
223 strcpy ( defaultdir, GLOBAL_MAPS_DIR );
225 gchar *home = getenv("HOME");
226 if ( home && strlen(home) < 497 )
228 strcpy ( defaultdir, home );
229 strcat ( defaultdir, "/.viking-maps/" );
233 strcpy ( defaultdir, ".viking-maps/" );
243 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
245 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && access ( vml->cache_dir, F_OK ) != 0 )
248 mkdir ( vml->cache_dir );
250 mkdir ( vml->cache_dir, 0777 );
255 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
258 g_assert ( vml != NULL);
259 if ( vml->cache_dir )
260 g_free ( vml->cache_dir );
262 if ( dir == NULL || dir[0] == '\0' )
263 vml->cache_dir = g_strdup ( MAPS_CACHE_DIR );
267 if ( dir[len-1] != VIKING_FILE_SEP )
269 vml->cache_dir = g_malloc ( len+2 );
270 strncpy ( vml->cache_dir, dir, len );
271 vml->cache_dir[len] = VIKING_FILE_SEP;
272 vml->cache_dir[len+1] = '\0';
275 vml->cache_dir = g_strdup ( dir );
277 maps_layer_mkdir_if_default_dir ( vml );
280 /****************************************/
281 /******** GOBJECT STUFF *****************/
282 /****************************************/
284 GType vik_maps_layer_get_type ()
286 static GType vml_type = 0;
290 static const GTypeInfo vml_info =
292 sizeof (VikMapsLayerClass),
293 NULL, /* base_init */
294 NULL, /* base_finalize */
295 NULL, /* class init */
296 NULL, /* class_finalize */
297 NULL, /* class_data */
298 sizeof (VikMapsLayer),
300 NULL /* instance init */
302 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
308 /****************************************/
309 /************** PARAMETERS **************/
310 /****************************************/
312 static guint map_index_to_uniq_id (guint8 index)
314 g_assert ( index < NUM_MAP_TYPES );
315 return __map_types[index].uniq_id;
318 static guint map_uniq_id_to_index ( guint uniq_id )
321 for ( i = 0; i < NUM_MAP_TYPES; i++ )
322 if ( __map_types[i].uniq_id == uniq_id )
324 return NUM_MAP_TYPES; /* no such thing */
327 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp )
331 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
332 case PARAM_MAPTYPE: {
333 gint maptype = map_uniq_id_to_index(data.u);
334 if ( maptype == NUM_MAP_TYPES ) g_warning("Unknown map type");
335 else vml->maptype = maptype;
338 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
339 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
340 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
341 vml->mapzoom_id = data.u;
342 vml->xmapzoom = __mapzooms_x [data.u];
343 vml->ymapzoom = __mapzooms_y [data.u];
344 }else g_warning ("Unknown Map Zoom"); break;
349 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id )
351 VikLayerParamData rv;
354 case PARAM_CACHE_DIR: rv.s = (vml->cache_dir && strcmp(vml->cache_dir, MAPS_CACHE_DIR) != 0) ? vml->cache_dir : ""; break;
355 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
356 case PARAM_ALPHA: rv.u = vml->alpha; break;
357 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
358 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
363 /****************************************/
364 /****** CREATING, COPYING, FREEING ******/
365 /****************************************/
367 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
369 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
370 vik_layer_init ( VIK_LAYER(vml), VIK_LAYER_MAPS );
374 vml->dl_tool_x = vml->dl_tool_y = -1;
375 maps_layer_set_cache_dir ( vml, NULL );
376 vml->autodownload = FALSE;
378 vml->dl_right_click_menu = NULL;
383 static void maps_layer_free ( VikMapsLayer *vml )
385 if ( vml->cache_dir )
386 g_free ( vml->cache_dir );
387 if ( vml->dl_right_click_menu )
388 gtk_object_sink ( GTK_OBJECT(vml->dl_right_click_menu) );
391 static VikMapsLayer *maps_layer_copy ( VikMapsLayer *vml, VikViewport *vvp )
393 VikMapsLayer *rv = maps_layer_new ( vvp );
395 rv->cache_dir = g_strdup(rv->cache_dir);
396 VIK_LAYER(rv)->name = NULL;
400 /*********************/
401 /****** DRAWING ******/
402 /*********************/
404 static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
407 gint width, height, iii, jjj;
409 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
411 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
412 g_object_unref(G_OBJECT(pixbuf));
416 pixels = gdk_pixbuf_get_pixels(pixbuf);
417 width = gdk_pixbuf_get_width(pixbuf);
418 height = gdk_pixbuf_get_height(pixbuf);
420 /* r,g,b,a,r,g,b,a.... */
421 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
429 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
432 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
433 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_BILINEAR);
434 g_object_unref ( G_OBJECT(pixbuf) );
438 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
443 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
444 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
447 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
448 vml->cache_dir, mode,
449 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
450 if ( access ( filename_buf, R_OK ) == 0) {
453 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
457 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
458 g_warning ( "Couldn't open image file: %s", gx->message );
462 g_object_unref ( G_OBJECT(pixbuf) );
465 if ( vml->alpha < 255 )
466 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
467 if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
468 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
470 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
471 mapcoord->z, __map_types[vml->maptype].uniq_id,
472 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
480 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
483 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
484 gdouble yzoom = vik_viewport_get_ympp ( vvp );
485 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
487 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
488 xshrinkfactor = vml->xmapzoom / xzoom;
489 yshrinkfactor = vml->ymapzoom / yzoom;
490 if ( xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
491 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) {
492 xzoom = vml->xmapzoom;
493 yzoom = vml->xmapzoom;
495 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 );
500 if ( __map_types[vml->maptype].coord_to_mapcoord ( ul, xzoom, yzoom, &ulm ) &&
501 __map_types[vml->maptype].coord_to_mapcoord ( br, xzoom, yzoom, &brm ) ) {
505 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
506 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
507 gint mode = __map_types[vml->maptype].uniq_id;
510 gint xx, yy, width, height;
513 guint max_path_len = strlen(vml->cache_dir) + 40;
514 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
516 if ( vml->autodownload )
517 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
519 if ( __map_types[vml->maptype].tilesize_x == 0 ) {
520 for ( x = xmin; x <= xmax; x++ ) {
521 for ( y = ymin; y <= ymax; y++ ) {
524 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
526 width = gdk_pixbuf_get_width ( pixbuf );
527 height = gdk_pixbuf_get_height ( pixbuf );
529 __map_types[vml->maptype].mapcoord_to_center_coord ( &ulm, &coord );
530 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
534 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
538 } else { /* tilesize is known, don't have to keep converting coords */
539 gdouble tilesize_x = __map_types[vml->maptype].tilesize_x * xshrinkfactor;
540 gdouble tilesize_y = __map_types[vml->maptype].tilesize_y * yshrinkfactor;
541 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
542 gint tilesize_x_ceil = ceil ( tilesize_x );
543 gint tilesize_y_ceil = ceil ( tilesize_y );
544 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
545 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
546 gdouble xx, yy; gint xx_tmp, yy_tmp;
547 gint base_yy, xend, yend;
548 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
549 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
551 __map_types[vml->maptype].mapcoord_to_center_coord ( &ulm, &coord );
552 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
553 xx = xx_tmp; yy = yy_tmp;
554 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
555 * eg if tile size 128, shrinkfactor 0.333 */
556 xx -= (tilesize_x/2);
557 base_yy = yy - (tilesize_y/2);
559 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
561 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
564 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
566 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
578 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
580 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
584 /* get corner coords */
585 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
586 /* UTM multi-zone stuff by Kit Transue */
587 gchar leftmost_zone, rightmost_zone, i;
588 leftmost_zone = vik_viewport_leftmost_zone( vvp );
589 rightmost_zone = vik_viewport_rightmost_zone( vvp );
590 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
591 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
592 maps_layer_draw_section ( vml, vvp, &ul, &br );
596 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
597 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
599 maps_layer_draw_section ( vml, vvp, &ul, &br );
604 /*************************/
605 /****** DOWNLOADING ******/
606 /*************************/
608 /* pass along data to thread, exists even if layer is deleted. */
620 static void mdi_free ( MapDownloadInfo *mdi )
622 g_free ( mdi->cache_dir );
623 g_free ( mdi->filename_buf );
627 static void map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
631 for ( x = mdi->x0; x <= mdi->xf; x++ )
633 for ( y = mdi->y0; y <= mdi->yf; y++ )
635 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
636 mdi->cache_dir, __map_types[mdi->maptype].uniq_id,
637 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
639 if ( mdi->redownload == REDOWNLOAD_ALL)
640 remove ( mdi->filename_buf );
641 else if ( mdi->redownload == REDOWNLOAD_BAD && access ( mdi->filename_buf, F_OK ) == 0 )
643 /* see if this one is bad or what */
645 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
647 remove ( mdi->filename_buf );
649 g_object_unref ( pixbuf );
654 if ( access ( mdi->filename_buf, F_OK ) != 0 )
656 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
657 __map_types[mdi->maptype].download ( &(mdi->mapcoord), mdi->filename_buf );
658 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
660 if ( mdi->redownload !=- REDOWNLOAD_NONE )
661 a_mapcache_remove_all_shrinkfactors ( x, y, mdi->mapcoord.z, mdi->maptype, mdi->mapcoord.scale );
665 a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
671 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
673 if ( mdi->mapcoord.x || mdi->mapcoord.y )
675 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
676 mdi->cache_dir, __map_types[mdi->maptype].uniq_id,
677 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
678 if ( access ( mdi->filename_buf, F_OK ) == 0)
680 remove ( mdi->filename_buf );
685 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
687 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
688 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
690 if ( __map_types[vml->maptype].coord_to_mapcoord ( ul, xzoom, yzoom, &ulm )
691 && __map_types[vml->maptype].coord_to_mapcoord ( br, xzoom, yzoom, &brm ) )
693 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
696 /* cache_dir and buffer for dest filename */
697 mdi->cache_dir = g_strdup ( vml->cache_dir );
698 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
699 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
700 mdi->maptype = vml->maptype;
704 mdi->redownload = redownload;
706 mdi->x0 = MIN(ulm.x, brm.x);
707 mdi->xf = MAX(ulm.x, brm.x);
708 mdi->y0 = MIN(ulm.y, brm.y);
709 mdi->yf = MAX(ulm.y, brm.y);
713 if ( mdi->redownload ) {
714 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
716 /* calculate how many we need */
717 for ( a = mdi->x0; a <= mdi->xf; a++ )
719 for ( b = mdi->y0; b <= mdi->yf; b++ )
721 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
722 vml->cache_dir, __map_types[vml->maptype].uniq_id, ulm.scale,
724 if ( access ( mdi->filename_buf, F_OK ) != 0)
730 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
732 if ( mdi->mapstoget )
734 gchar *tmp = g_strdup_printf ( "%s %s%d %s %s...", redownload ? "Redownloading" : "Downloading", redownload == REDOWNLOAD_BAD ? "up to " : "", mdi->mapstoget, params_maptypes[vml->maptype], (mdi->mapstoget == 1) ? "map" : "maps" );
736 /* launch the thread */
737 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
738 tmp, /* description string */
739 (vik_thr_func) map_download_thread, /* function to call within thread */
740 mdi, /* pass along data */
741 (vik_thr_free_func) mdi_free, /* function to free pass along data */
742 (vik_thr_free_func) mdi_cancel_cleanup,
751 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
753 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
755 static void maps_layer_redownload_all ( VikMapsLayer *vml )
757 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
760 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
763 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
765 if ( event->button == 1 )
768 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 );
769 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 );
770 start_download_thread ( vml, vvp, &ul, &br, REDOWNLOAD_NONE );
771 vml->dl_tool_x = vml->dl_tool_y = -1;
776 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) );
777 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) );
779 vml->redownload_vvp = vvp;
781 vml->dl_tool_x = vml->dl_tool_y = -1;
783 if ( ! vml->dl_right_click_menu ) {
785 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
787 item = gtk_menu_item_new_with_label ( "Redownload bad map(s)" );
788 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
789 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
791 item = gtk_menu_item_new_with_label ( "Redownload all map(s)" );
792 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
793 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
796 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
797 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
803 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
806 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) &&
807 __map_types[vml->maptype].coord_to_mapcoord ( vik_viewport_get_center ( vvp ),
808 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
809 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
811 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
818 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
822 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
823 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
824 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
825 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
827 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
828 vml->cache_dir, __map_types[vml->maptype].uniq_id,
829 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
831 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
832 g_free ( filename_buf );
833 vik_layer_emit_update ( VIK_LAYER(vml) );
841 static void maps_layer_download_onscreen_maps ( gpointer vml_vvp[2] )
843 VikMapsLayer *vml = vml_vvp[0];
844 VikViewport *vvp = vml_vvp[1];
846 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
847 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
852 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
853 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
855 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) &&
856 __map_types[vml->maptype].coord_to_mapcoord ( &ul, xzoom, yzoom, &ulm ) &&
857 __map_types[vml->maptype].coord_to_mapcoord ( &br, xzoom, yzoom, &brm ) )
858 start_download_thread ( vml, vvp, &ul, &br, REDOWNLOAD_NONE );
860 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), "Wrong drawmode / zoom level for this map." );
864 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
866 static gpointer pass_along[2];
869 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
871 item = gtk_menu_item_new();
872 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
873 gtk_widget_show ( item );
875 item = gtk_menu_item_new_with_label ( "Download Onscreen Maps" );
876 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_onscreen_maps), pass_along );
877 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
878 gtk_widget_show ( item );