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 void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len );
106 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
107 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp );
108 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id );
109 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp );
110 static VikMapsLayer *maps_layer_new ( VikViewport *vvp );
111 static void maps_layer_free ( VikMapsLayer *vml );
112 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
113 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
114 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp );
115 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir );
116 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload );
117 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp );
120 static VikLayerParamScale params_scales[] = {
121 /* min, max, step, digits (decimal places) */
122 { 0, 255, 3, 0 }, /* alpha */
125 VikLayerParam maps_layer_params[] = {
126 { "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, "Map Type:", VIK_LAYER_WIDGET_RADIOGROUP, params_maptypes, params_maptypes_ids },
127 { "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, "Maps Directory (Optional):", VIK_LAYER_WIDGET_FILEENTRY },
128 { "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, "Alpha:", VIK_LAYER_WIDGET_HSCALE, params_scales },
129 { "autodownload", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, "Autodownload maps:", VIK_LAYER_WIDGET_CHECKBUTTON },
130 { "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, "Zoom Level:", VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms },
133 enum { PARAM_MAPTYPE=0, PARAM_CACHE_DIR, PARAM_ALPHA, PARAM_AUTODOWNLOAD, PARAM_MAPZOOM, NUM_PARAMS };
135 static VikToolInterface maps_tools[] = {
136 { "Maps Download", (VikToolConstructorFunc) maps_layer_download_create, NULL, NULL, NULL,
137 (VikToolMouseFunc) maps_layer_download_click, NULL, (VikToolMouseFunc) maps_layer_download_release },
140 VikLayerInterface vik_maps_layer_interface = {
145 sizeof(maps_tools) / sizeof(maps_tools[0]),
152 (VikLayerFuncCreate) maps_layer_new,
153 (VikLayerFuncRealize) NULL,
154 (VikLayerFuncPostRead) NULL,
155 (VikLayerFuncFree) maps_layer_free,
157 (VikLayerFuncProperties) NULL,
158 (VikLayerFuncDraw) maps_layer_draw,
159 (VikLayerFuncChangeCoordMode) NULL,
161 (VikLayerFuncAddMenuItems) maps_layer_add_menu_items,
162 (VikLayerFuncSublayerAddMenuItems) NULL,
164 (VikLayerFuncSublayerRenameRequest) NULL,
165 (VikLayerFuncSublayerToggleVisible) NULL,
167 (VikLayerFuncCopy) maps_layer_copy,
168 (VikLayerFuncMarshall) maps_layer_marshall,
169 (VikLayerFuncUnmarshall) maps_layer_unmarshall,
171 (VikLayerFuncSetParam) maps_layer_set_param,
172 (VikLayerFuncGetParam) maps_layer_get_param,
174 (VikLayerFuncReadFileData) NULL,
175 (VikLayerFuncWriteFileData) NULL,
177 (VikLayerFuncCopyItem) NULL,
178 (VikLayerFuncPasteItem) NULL,
179 (VikLayerFuncFreeCopiedItem) NULL,
180 (VikLayerFuncDragDropRequest) NULL,
183 struct _VikMapsLayer {
189 gdouble xmapzoom, ymapzoom;
191 gboolean autodownload;
193 gint dl_tool_x, dl_tool_y;
195 GtkMenu *dl_right_click_menu;
196 VikCoord redownload_ul, redownload_br; /* right click menu only */
197 VikViewport *redownload_vvp;
200 enum { REDOWNLOAD_NONE = 0, REDOWNLOAD_BAD, REDOWNLOAD_ALL };
203 /****************************************/
204 /******** CACHE DIR STUFF ***************/
205 /****************************************/
208 #define MAPS_CACHE_DIR "C:\\VIKING-MAPS\\"
209 #define DIRSTRUCTURE "%st%ds%dz%d\\%d\\%d"
214 #define MAPS_CACHE_DIR maps_layer_default_dir()
215 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
216 #define DIRSTRUCTURE "%st%ds%dz%d/%d/%d"
218 static gchar *maps_layer_default_dir ()
220 static gchar defaultdir[512];
221 static gboolean already_run = 0;
224 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
225 gchar *mapdir = getenv("VIKING_MAPS");
226 if ( mapdir && strlen(mapdir) < 497 ) {
227 strcpy ( defaultdir, mapdir );
228 } else if ( access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
229 strcpy ( defaultdir, GLOBAL_MAPS_DIR );
231 gchar *home = getenv("HOME");
232 if ( home && strlen(home) < 497 )
234 strcpy ( defaultdir, home );
235 strcat ( defaultdir, "/.viking-maps/" );
239 strcpy ( defaultdir, ".viking-maps/" );
249 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
251 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && access ( vml->cache_dir, F_OK ) != 0 )
254 mkdir ( vml->cache_dir );
256 mkdir ( vml->cache_dir, 0777 );
261 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
264 g_assert ( vml != NULL);
265 if ( vml->cache_dir )
266 g_free ( vml->cache_dir );
268 if ( dir == NULL || dir[0] == '\0' )
269 vml->cache_dir = g_strdup ( MAPS_CACHE_DIR );
273 if ( dir[len-1] != VIKING_FILE_SEP )
275 vml->cache_dir = g_malloc ( len+2 );
276 strncpy ( vml->cache_dir, dir, len );
277 vml->cache_dir[len] = VIKING_FILE_SEP;
278 vml->cache_dir[len+1] = '\0';
281 vml->cache_dir = g_strdup ( dir );
283 maps_layer_mkdir_if_default_dir ( vml );
286 /****************************************/
287 /******** GOBJECT STUFF *****************/
288 /****************************************/
290 GType vik_maps_layer_get_type ()
292 static GType vml_type = 0;
296 static const GTypeInfo vml_info =
298 sizeof (VikMapsLayerClass),
299 NULL, /* base_init */
300 NULL, /* base_finalize */
301 NULL, /* class init */
302 NULL, /* class_finalize */
303 NULL, /* class_data */
304 sizeof (VikMapsLayer),
306 NULL /* instance init */
308 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
314 /****************************************/
315 /************** PARAMETERS **************/
316 /****************************************/
318 static guint map_index_to_uniq_id (guint8 index)
320 g_assert ( index < NUM_MAP_TYPES );
321 return __map_types[index].uniq_id;
324 static guint map_uniq_id_to_index ( guint uniq_id )
327 for ( i = 0; i < NUM_MAP_TYPES; i++ )
328 if ( __map_types[i].uniq_id == uniq_id )
330 return NUM_MAP_TYPES; /* no such thing */
333 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp )
337 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
338 case PARAM_MAPTYPE: {
339 gint maptype = map_uniq_id_to_index(data.u);
340 if ( maptype == NUM_MAP_TYPES ) g_warning("Unknown map type");
341 else vml->maptype = maptype;
344 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
345 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
346 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
347 vml->mapzoom_id = data.u;
348 vml->xmapzoom = __mapzooms_x [data.u];
349 vml->ymapzoom = __mapzooms_y [data.u];
350 }else g_warning ("Unknown Map Zoom"); break;
355 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id )
357 VikLayerParamData rv;
360 case PARAM_CACHE_DIR: rv.s = (vml->cache_dir && strcmp(vml->cache_dir, MAPS_CACHE_DIR) != 0) ? vml->cache_dir : ""; break;
361 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
362 case PARAM_ALPHA: rv.u = vml->alpha; break;
363 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
364 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
369 /****************************************/
370 /****** CREATING, COPYING, FREEING ******/
371 /****************************************/
373 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
375 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
376 vik_layer_init ( VIK_LAYER(vml), VIK_LAYER_MAPS );
380 vml->dl_tool_x = vml->dl_tool_y = -1;
381 maps_layer_set_cache_dir ( vml, NULL );
382 vml->autodownload = FALSE;
384 vml->dl_right_click_menu = NULL;
389 static void maps_layer_free ( VikMapsLayer *vml )
391 if ( vml->cache_dir )
392 g_free ( vml->cache_dir );
393 if ( vml->dl_right_click_menu )
394 gtk_object_sink ( GTK_OBJECT(vml->dl_right_click_menu) );
397 static VikMapsLayer *maps_layer_copy ( VikMapsLayer *vml, VikViewport *vvp )
399 VikMapsLayer *rv = maps_layer_new ( vvp );
401 rv->cache_dir = g_strdup(rv->cache_dir);
402 VIK_LAYER(rv)->name = NULL;
406 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
408 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
411 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
413 VikMapsLayer *rv = maps_layer_new ( vvp );
414 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
418 /*********************/
419 /****** DRAWING ******/
420 /*********************/
422 static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
425 gint width, height, iii, jjj;
427 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
429 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
430 g_object_unref(G_OBJECT(pixbuf));
434 pixels = gdk_pixbuf_get_pixels(pixbuf);
435 width = gdk_pixbuf_get_width(pixbuf);
436 height = gdk_pixbuf_get_height(pixbuf);
438 /* r,g,b,a,r,g,b,a.... */
439 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
447 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
450 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
451 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_BILINEAR);
452 g_object_unref ( G_OBJECT(pixbuf) );
456 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
461 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
462 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
465 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
466 vml->cache_dir, mode,
467 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
468 if ( access ( filename_buf, R_OK ) == 0) {
471 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
475 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
476 g_warning ( "Couldn't open image file: %s", gx->message );
480 g_object_unref ( G_OBJECT(pixbuf) );
483 if ( vml->alpha < 255 )
484 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
485 if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
486 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
488 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
489 mapcoord->z, __map_types[vml->maptype].uniq_id,
490 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
498 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
501 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
502 gdouble yzoom = vik_viewport_get_ympp ( vvp );
503 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
505 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
506 xshrinkfactor = vml->xmapzoom / xzoom;
507 yshrinkfactor = vml->ymapzoom / yzoom;
508 if ( xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
509 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) {
510 xzoom = vml->xmapzoom;
511 yzoom = vml->xmapzoom;
513 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 );
518 if ( __map_types[vml->maptype].coord_to_mapcoord ( ul, xzoom, yzoom, &ulm ) &&
519 __map_types[vml->maptype].coord_to_mapcoord ( br, xzoom, yzoom, &brm ) ) {
523 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
524 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
525 gint mode = __map_types[vml->maptype].uniq_id;
528 gint xx, yy, width, height;
531 guint max_path_len = strlen(vml->cache_dir) + 40;
532 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
534 if ( vml->autodownload )
535 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
537 if ( __map_types[vml->maptype].tilesize_x == 0 ) {
538 for ( x = xmin; x <= xmax; x++ ) {
539 for ( y = ymin; y <= ymax; y++ ) {
542 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
544 width = gdk_pixbuf_get_width ( pixbuf );
545 height = gdk_pixbuf_get_height ( pixbuf );
547 __map_types[vml->maptype].mapcoord_to_center_coord ( &ulm, &coord );
548 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
552 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
556 } else { /* tilesize is known, don't have to keep converting coords */
557 gdouble tilesize_x = __map_types[vml->maptype].tilesize_x * xshrinkfactor;
558 gdouble tilesize_y = __map_types[vml->maptype].tilesize_y * yshrinkfactor;
559 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
560 gint tilesize_x_ceil = ceil ( tilesize_x );
561 gint tilesize_y_ceil = ceil ( tilesize_y );
562 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
563 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
564 gdouble xx, yy; gint xx_tmp, yy_tmp;
565 gint base_yy, xend, yend;
566 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
567 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
569 __map_types[vml->maptype].mapcoord_to_center_coord ( &ulm, &coord );
570 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
571 xx = xx_tmp; yy = yy_tmp;
572 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
573 * eg if tile size 128, shrinkfactor 0.333 */
574 xx -= (tilesize_x/2);
575 base_yy = yy - (tilesize_y/2);
577 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
579 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
582 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
584 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
596 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
598 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
602 /* get corner coords */
603 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
604 /* UTM multi-zone stuff by Kit Transue */
605 gchar leftmost_zone, rightmost_zone, i;
606 leftmost_zone = vik_viewport_leftmost_zone( vvp );
607 rightmost_zone = vik_viewport_rightmost_zone( vvp );
608 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
609 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
610 maps_layer_draw_section ( vml, vvp, &ul, &br );
614 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
615 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
617 maps_layer_draw_section ( vml, vvp, &ul, &br );
622 /*************************/
623 /****** DOWNLOADING ******/
624 /*************************/
626 /* pass along data to thread, exists even if layer is deleted. */
638 static void mdi_free ( MapDownloadInfo *mdi )
640 g_free ( mdi->cache_dir );
641 g_free ( mdi->filename_buf );
645 static void map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
649 for ( x = mdi->x0; x <= mdi->xf; x++ )
651 for ( y = mdi->y0; y <= mdi->yf; y++ )
653 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
654 mdi->cache_dir, __map_types[mdi->maptype].uniq_id,
655 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
657 if ( mdi->redownload == REDOWNLOAD_ALL)
658 remove ( mdi->filename_buf );
659 else if ( mdi->redownload == REDOWNLOAD_BAD && access ( mdi->filename_buf, F_OK ) == 0 )
661 /* see if this one is bad or what */
663 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
665 remove ( mdi->filename_buf );
667 g_object_unref ( pixbuf );
672 if ( access ( mdi->filename_buf, F_OK ) != 0 )
674 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
675 __map_types[mdi->maptype].download ( &(mdi->mapcoord), mdi->filename_buf );
676 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
678 if ( mdi->redownload !=- REDOWNLOAD_NONE )
679 a_mapcache_remove_all_shrinkfactors ( x, y, mdi->mapcoord.z, mdi->maptype, mdi->mapcoord.scale );
683 a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
689 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
691 if ( mdi->mapcoord.x || mdi->mapcoord.y )
693 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
694 mdi->cache_dir, __map_types[mdi->maptype].uniq_id,
695 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
696 if ( access ( mdi->filename_buf, F_OK ) == 0)
698 remove ( mdi->filename_buf );
703 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
705 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
706 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
708 if ( __map_types[vml->maptype].coord_to_mapcoord ( ul, xzoom, yzoom, &ulm )
709 && __map_types[vml->maptype].coord_to_mapcoord ( br, xzoom, yzoom, &brm ) )
711 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
714 /* cache_dir and buffer for dest filename */
715 mdi->cache_dir = g_strdup ( vml->cache_dir );
716 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
717 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
718 mdi->maptype = vml->maptype;
722 mdi->redownload = redownload;
724 mdi->x0 = MIN(ulm.x, brm.x);
725 mdi->xf = MAX(ulm.x, brm.x);
726 mdi->y0 = MIN(ulm.y, brm.y);
727 mdi->yf = MAX(ulm.y, brm.y);
731 if ( mdi->redownload ) {
732 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
734 /* calculate how many we need */
735 for ( a = mdi->x0; a <= mdi->xf; a++ )
737 for ( b = mdi->y0; b <= mdi->yf; b++ )
739 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
740 vml->cache_dir, __map_types[vml->maptype].uniq_id, ulm.scale,
742 if ( access ( mdi->filename_buf, F_OK ) != 0)
748 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
750 if ( mdi->mapstoget )
752 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" );
754 /* launch the thread */
755 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
756 tmp, /* description string */
757 (vik_thr_func) map_download_thread, /* function to call within thread */
758 mdi, /* pass along data */
759 (vik_thr_free_func) mdi_free, /* function to free pass along data */
760 (vik_thr_free_func) mdi_cancel_cleanup,
769 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
771 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
773 static void maps_layer_redownload_all ( VikMapsLayer *vml )
775 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
778 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
780 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
782 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
784 if ( event->button == 1 )
787 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 );
788 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 );
789 start_download_thread ( vml, vvp, &ul, &br, REDOWNLOAD_NONE );
790 vml->dl_tool_x = vml->dl_tool_y = -1;
795 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) );
796 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) );
798 vml->redownload_vvp = vvp;
800 vml->dl_tool_x = vml->dl_tool_y = -1;
802 if ( ! vml->dl_right_click_menu ) {
804 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
806 item = gtk_menu_item_new_with_label ( "Redownload bad map(s)" );
807 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
808 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
810 item = gtk_menu_item_new_with_label ( "Redownload all map(s)" );
811 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
812 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
815 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
816 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
822 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
827 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
830 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
832 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) &&
833 __map_types[vml->maptype].coord_to_mapcoord ( vik_viewport_get_center ( vvp ),
834 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
835 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
837 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
844 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
848 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
849 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
850 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
851 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
853 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
854 vml->cache_dir, __map_types[vml->maptype].uniq_id,
855 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
857 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
858 g_free ( filename_buf );
859 vik_layer_emit_update ( VIK_LAYER(vml) );
867 static void maps_layer_download_onscreen_maps ( gpointer vml_vvp[2] )
869 VikMapsLayer *vml = vml_vvp[0];
870 VikViewport *vvp = vml_vvp[1];
872 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
873 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
878 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
879 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
881 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) &&
882 __map_types[vml->maptype].coord_to_mapcoord ( &ul, xzoom, yzoom, &ulm ) &&
883 __map_types[vml->maptype].coord_to_mapcoord ( &br, xzoom, yzoom, &brm ) )
884 start_download_thread ( vml, vvp, &ul, &br, REDOWNLOAD_NONE );
886 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), "Wrong drawmode / zoom level for this map." );
890 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
892 static gpointer pass_along[2];
895 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
897 item = gtk_menu_item_new();
898 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
899 gtk_widget_show ( item );
901 item = gtk_menu_item_new_with_label ( "Download Onscreen Maps" );
902 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_onscreen_maps), pass_along );
903 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
904 gtk_widget_show ( item );