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"
68 gboolean (*coord_to_mapcoord
) ( const VikCoord
*src
, gdouble xzoom
, gdouble yzoom
, MapCoord
*dest
);
69 void (*mapcoord_to_center_coord
) ( MapCoord
*src
, VikCoord
*dest
);
70 void (*download
) ( MapCoord
*src
, const gchar
*dest_fn
);
71 /* TODO: constant size (yay!) */
72 } VikMapsLayer_MapType
;
75 /****** MAP TYPES ******/
77 static const VikMapsLayer_MapType __map_types
[] = {
79 { 2, 200, 200, VIK_VIEWPORT_DRAWMODE_UTM
, terraserver_topo_coord_to_mapcoord
, terraserver_mapcoord_to_center_coord
, terraserver_topo_download
},
80 { 1, 200, 200, VIK_VIEWPORT_DRAWMODE_UTM
, terraserver_aerial_coord_to_mapcoord
, terraserver_mapcoord_to_center_coord
, terraserver_aerial_download
},
81 { 4, 200, 200, VIK_VIEWPORT_DRAWMODE_UTM
, terraserver_urban_coord_to_mapcoord
, terraserver_mapcoord_to_center_coord
, terraserver_urban_download
},
82 { 5, 0, 0, VIK_VIEWPORT_DRAWMODE_EXPEDIA
, expedia_coord_to_mapcoord
, expedia_mapcoord_to_center_coord
, expedia_download
},
83 { 9, 128, 128, VIK_VIEWPORT_DRAWMODE_GOOGLE
, googlemaps_coord_to_mapcoord
, googlemaps_mapcoord_to_center_coord
, googlemaps_download
},
84 { 6, 800, 600, VIK_VIEWPORT_DRAWMODE_UTM
, usgs_coord_to_mapcoord
, usgs_mapcoord_to_center_coord
, usgs_download
},
85 { 8, 256, 256, VIK_VIEWPORT_DRAWMODE_KH
, khmaps_coord_to_mapcoord
, khmaps_mapcoord_to_center_coord
, khmaps_download
},
86 { 7, 256, 256, VIK_VIEWPORT_DRAWMODE_MERCATOR
, google_coord_to_mapcoord
, google_mapcoord_to_center_coord
, google_download
},
87 { 10, 256, 256, VIK_VIEWPORT_DRAWMODE_MERCATOR
, google_coord_to_mapcoord
, google_mapcoord_to_center_coord
, google_trans_download
},
88 { 11, 256, 256, VIK_VIEWPORT_DRAWMODE_MERCATOR
, google_coord_to_mapcoord
, google_mapcoord_to_center_coord
, google_kh_download
},
91 #define NUM_MAP_TYPES (sizeof(__map_types)/sizeof(__map_types[0]))
93 /******** MAPZOOMS *********/
95 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" };
96 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 };
97 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 };
99 static gchar
*params_maptypes
[] = { "Terraserver Topos", "Terraserver Aerials", "Terraserver Urban Areas", "Expedia (Street Maps)", "Google Maps (Street)", "USGS", "KH Maps", "New (Mercator) Google", "Transparent Google", "New (Mercator) KH" };
100 static guint params_maptypes_ids
[] = { 2, 1, 4, 5, 9, 6, 8, 7, 10, 11 };
101 #define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0]))
103 /**************************/
106 static VikMapsLayer
*maps_layer_copy ( VikMapsLayer
*vml
, 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 void maps_layer_set_cache_dir ( VikMapsLayer
*vml
, const gchar
*dir
);
115 static void start_download_thread ( VikMapsLayer
*vml
, VikViewport
*vvp
, const VikCoord
*ul
, const VikCoord
*br
, gint redownload
);
116 static void maps_layer_add_menu_items ( VikMapsLayer
*vml
, GtkMenu
*menu
, VikLayersPanel
*vlp
);
119 static VikLayerParamScale params_scales
[] = {
120 /* min, max, step, digits (decimal places) */
121 { 0, 255, 3, 0 }, /* alpha */
124 VikLayerParam maps_layer_params
[] = {
125 { "mode", VIK_LAYER_PARAM_UINT
, VIK_LAYER_GROUP_NONE
, "Map Type:", VIK_LAYER_WIDGET_RADIOGROUP
, params_maptypes
, params_maptypes_ids
},
126 { "directory", VIK_LAYER_PARAM_STRING
, VIK_LAYER_GROUP_NONE
, "Maps Directory (Optional):", VIK_LAYER_WIDGET_FILEENTRY
},
127 { "alpha", VIK_LAYER_PARAM_UINT
, VIK_LAYER_GROUP_NONE
, "Alpha:", VIK_LAYER_WIDGET_HSCALE
, params_scales
},
128 { "autodownload", VIK_LAYER_PARAM_BOOLEAN
, VIK_LAYER_GROUP_NONE
, "Autodownload maps:", VIK_LAYER_WIDGET_CHECKBUTTON
},
129 { "mapzoom", VIK_LAYER_PARAM_UINT
, VIK_LAYER_GROUP_NONE
, "Zoom Level:", VIK_LAYER_WIDGET_COMBOBOX
, params_mapzooms
},
132 enum { PARAM_MAPTYPE
=0, PARAM_CACHE_DIR
, PARAM_ALPHA
, PARAM_AUTODOWNLOAD
, PARAM_MAPZOOM
, NUM_PARAMS
};
134 static VikToolInterface maps_tools
[] = {
135 { "Maps Download", (VikToolInterfaceFunc
) maps_layer_download_click
, (VikToolInterfaceFunc
) maps_layer_download_release
},
138 VikLayerInterface vik_maps_layer_interface
= {
143 sizeof(maps_tools
) / sizeof(maps_tools
[0]),
150 (VikLayerFuncCreate
) maps_layer_new
,
151 (VikLayerFuncRealize
) NULL
,
152 (VikLayerFuncPostRead
) NULL
,
153 (VikLayerFuncFree
) maps_layer_free
,
155 (VikLayerFuncProperties
) NULL
,
156 (VikLayerFuncDraw
) maps_layer_draw
,
157 (VikLayerFuncChangeCoordMode
) NULL
,
159 (VikLayerFuncAddMenuItems
) maps_layer_add_menu_items
,
160 (VikLayerFuncSublayerAddMenuItems
) NULL
,
162 (VikLayerFuncSublayerRenameRequest
) NULL
,
163 (VikLayerFuncSublayerToggleVisible
) NULL
,
165 (VikLayerFuncCopy
) maps_layer_copy
,
167 (VikLayerFuncSetParam
) maps_layer_set_param
,
168 (VikLayerFuncGetParam
) maps_layer_get_param
,
170 (VikLayerFuncReadFileData
) NULL
,
171 (VikLayerFuncWriteFileData
) NULL
,
173 (VikLayerFuncCopyItem
) NULL
,
174 (VikLayerFuncPasteItem
) NULL
,
175 (VikLayerFuncFreeCopiedItem
) NULL
,
178 struct _VikMapsLayer
{
184 gdouble xmapzoom
, ymapzoom
;
186 gboolean autodownload
;
188 gint dl_tool_x
, dl_tool_y
;
190 GtkMenu
*dl_right_click_menu
;
191 VikCoord redownload_ul
, redownload_br
; /* right click menu only */
192 VikViewport
*redownload_vvp
;
195 enum { REDOWNLOAD_NONE
= 0, REDOWNLOAD_BAD
, REDOWNLOAD_ALL
};
198 /****************************************/
199 /******** CACHE DIR STUFF ***************/
200 /****************************************/
203 #define MAPS_CACHE_DIR "C:\\VIKING-MAPS\\"
204 #define DIRSTRUCTURE "%st%ds%dz%d\\%d\\%d"
209 #define MAPS_CACHE_DIR maps_layer_default_dir()
210 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
211 #define DIRSTRUCTURE "%st%ds%dz%d/%d/%d"
213 static gchar
*maps_layer_default_dir ()
215 static gchar defaultdir
[512];
216 static gboolean already_run
= 0;
219 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
220 gchar
*mapdir
= getenv("VIKING_MAPS");
221 if ( mapdir
&& strlen(mapdir
) < 497 ) {
222 strcpy ( defaultdir
, mapdir
);
223 } else if ( access ( GLOBAL_MAPS_DIR
, W_OK
) == 0 ) {
224 strcpy ( defaultdir
, GLOBAL_MAPS_DIR
);
226 gchar
*home
= getenv("HOME");
227 if ( home
&& strlen(home
) < 497 )
229 strcpy ( defaultdir
, home
);
230 strcat ( defaultdir
, "/.viking-maps/" );
234 strcpy ( defaultdir
, ".viking-maps/" );
244 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer
*vml
)
246 if ( vml
->cache_dir
&& strcmp ( vml
->cache_dir
, MAPS_CACHE_DIR
) == 0 && access ( vml
->cache_dir
, F_OK
) != 0 )
249 mkdir ( vml
->cache_dir
);
251 mkdir ( vml
->cache_dir
, 0777 );
256 static void maps_layer_set_cache_dir ( VikMapsLayer
*vml
, const gchar
*dir
)
259 g_assert ( vml
!= NULL
);
260 if ( vml
->cache_dir
)
261 g_free ( vml
->cache_dir
);
263 if ( dir
== NULL
|| dir
[0] == '\0' )
264 vml
->cache_dir
= g_strdup ( MAPS_CACHE_DIR
);
268 if ( dir
[len
-1] != VIKING_FILE_SEP
)
270 vml
->cache_dir
= g_malloc ( len
+2 );
271 strncpy ( vml
->cache_dir
, dir
, len
);
272 vml
->cache_dir
[len
] = VIKING_FILE_SEP
;
273 vml
->cache_dir
[len
+1] = '\0';
276 vml
->cache_dir
= g_strdup ( dir
);
278 maps_layer_mkdir_if_default_dir ( vml
);
281 /****************************************/
282 /******** GOBJECT STUFF *****************/
283 /****************************************/
285 GType
vik_maps_layer_get_type ()
287 static GType vml_type
= 0;
291 static const GTypeInfo vml_info
=
293 sizeof (VikMapsLayerClass
),
294 NULL
, /* base_init */
295 NULL
, /* base_finalize */
296 NULL
, /* class init */
297 NULL
, /* class_finalize */
298 NULL
, /* class_data */
299 sizeof (VikMapsLayer
),
301 NULL
/* instance init */
303 vml_type
= g_type_register_static ( VIK_LAYER_TYPE
, "VikMapsLayer", &vml_info
, 0 );
309 /****************************************/
310 /************** PARAMETERS **************/
311 /****************************************/
313 static guint
map_index_to_uniq_id (guint8 index
)
315 g_assert ( index
< NUM_MAP_TYPES
);
316 return __map_types
[index
].uniq_id
;
319 static guint
map_uniq_id_to_index ( guint uniq_id
)
322 for ( i
= 0; i
< NUM_MAP_TYPES
; i
++ )
323 if ( __map_types
[i
].uniq_id
== uniq_id
)
325 return NUM_MAP_TYPES
; /* no such thing */
328 static gboolean
maps_layer_set_param ( VikMapsLayer
*vml
, guint16 id
, VikLayerParamData data
, VikViewport
*vvp
)
332 case PARAM_CACHE_DIR
: maps_layer_set_cache_dir ( vml
, data
.s
); break;
333 case PARAM_MAPTYPE
: {
334 gint maptype
= map_uniq_id_to_index(data
.u
);
335 if ( maptype
== NUM_MAP_TYPES
) g_warning("Unknown map type");
336 else vml
->maptype
= maptype
;
339 case PARAM_ALPHA
: if ( data
.u
<= 255 ) vml
->alpha
= data
.u
; break;
340 case PARAM_AUTODOWNLOAD
: vml
->autodownload
= data
.b
; break;
341 case PARAM_MAPZOOM
: if ( data
.u
< NUM_MAPZOOMS
) {
342 vml
->mapzoom_id
= data
.u
;
343 vml
->xmapzoom
= __mapzooms_x
[data
.u
];
344 vml
->ymapzoom
= __mapzooms_y
[data
.u
];
345 }else g_warning ("Unknown Map Zoom"); break;
350 static VikLayerParamData
maps_layer_get_param ( VikMapsLayer
*vml
, guint16 id
)
352 VikLayerParamData rv
;
355 case PARAM_CACHE_DIR
: rv
.s
= (vml
->cache_dir
&& strcmp(vml
->cache_dir
, MAPS_CACHE_DIR
) != 0) ? vml
->cache_dir
: ""; break;
356 case PARAM_MAPTYPE
: rv
.u
= map_index_to_uniq_id ( vml
->maptype
); break;
357 case PARAM_ALPHA
: rv
.u
= vml
->alpha
; break;
358 case PARAM_AUTODOWNLOAD
: rv
.u
= vml
->autodownload
; break;
359 case PARAM_MAPZOOM
: rv
.u
= vml
->mapzoom_id
; break;
364 /****************************************/
365 /****** CREATING, COPYING, FREEING ******/
366 /****************************************/
368 static VikMapsLayer
*maps_layer_new ( VikViewport
*vvp
)
370 VikMapsLayer
*vml
= VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE
, NULL
) );
371 vik_layer_init ( VIK_LAYER(vml
), VIK_LAYER_MAPS
);
375 vml
->dl_tool_x
= vml
->dl_tool_y
= -1;
376 maps_layer_set_cache_dir ( vml
, NULL
);
377 vml
->autodownload
= FALSE
;
379 vml
->dl_right_click_menu
= NULL
;
384 static void maps_layer_free ( VikMapsLayer
*vml
)
386 if ( vml
->cache_dir
)
387 g_free ( vml
->cache_dir
);
388 if ( vml
->dl_right_click_menu
)
389 gtk_object_sink ( GTK_OBJECT(vml
->dl_right_click_menu
) );
392 static VikMapsLayer
*maps_layer_copy ( VikMapsLayer
*vml
, VikViewport
*vvp
)
394 VikMapsLayer
*rv
= maps_layer_new ( vvp
);
396 rv
->cache_dir
= g_strdup(rv
->cache_dir
);
397 VIK_LAYER(rv
)->name
= NULL
;
401 /*********************/
402 /****** DRAWING ******/
403 /*********************/
405 static GdkPixbuf
*pixbuf_set_alpha ( GdkPixbuf
*pixbuf
, guint8 alpha
)
408 gint width
, height
, iii
, jjj
;
410 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf
) )
412 GdkPixbuf
*tmp
= gdk_pixbuf_add_alpha(pixbuf
,FALSE
,0,0,0);
413 g_object_unref(G_OBJECT(pixbuf
));
417 pixels
= gdk_pixbuf_get_pixels(pixbuf
);
418 width
= gdk_pixbuf_get_width(pixbuf
);
419 height
= gdk_pixbuf_get_height(pixbuf
);
421 /* r,g,b,a,r,g,b,a.... */
422 for (iii
= 0; iii
< width
; iii
++) for (jjj
= 0; jjj
< height
; jjj
++)
430 static GdkPixbuf
*pixbuf_shrink ( GdkPixbuf
*pixbuf
, gdouble xshrinkfactor
, gdouble yshrinkfactor
)
433 guint16 width
= gdk_pixbuf_get_width(pixbuf
), height
= gdk_pixbuf_get_height(pixbuf
);
434 tmp
= gdk_pixbuf_scale_simple(pixbuf
, ceil(width
* xshrinkfactor
), ceil(height
* yshrinkfactor
), GDK_INTERP_BILINEAR
);
435 g_object_unref ( G_OBJECT(pixbuf
) );
439 static GdkPixbuf
*get_pixbuf( VikMapsLayer
*vml
, gint mode
, MapCoord
*mapcoord
, gchar
*filename_buf
, gint buf_len
, gdouble xshrinkfactor
, gdouble yshrinkfactor
)
444 pixbuf
= a_mapcache_get ( mapcoord
->x
, mapcoord
->y
, mapcoord
->z
,
445 mode
, mapcoord
->scale
, vml
->alpha
, xshrinkfactor
, yshrinkfactor
);
448 g_snprintf ( filename_buf
, buf_len
, DIRSTRUCTURE
,
449 vml
->cache_dir
, mode
,
450 mapcoord
->scale
, mapcoord
->z
, mapcoord
->x
, mapcoord
->y
);
451 if ( access ( filename_buf
, R_OK
) == 0) {
454 pixbuf
= gdk_pixbuf_new_from_file ( filename_buf
, &gx
);
458 if ( gx
->domain
!= GDK_PIXBUF_ERROR
|| gx
->code
!= GDK_PIXBUF_ERROR_CORRUPT_IMAGE
)
459 g_warning ( "Couldn't open image file: %s", gx
->message
);
463 g_object_unref ( G_OBJECT(pixbuf
) );
466 if ( vml
->alpha
< 255 )
467 pixbuf
= pixbuf_set_alpha ( pixbuf
, vml
->alpha
);
468 if ( xshrinkfactor
!= 1.0 || yshrinkfactor
!= 1.0 )
469 pixbuf
= pixbuf_shrink ( pixbuf
, xshrinkfactor
, yshrinkfactor
);
471 a_mapcache_add ( pixbuf
, mapcoord
->x
, mapcoord
->y
,
472 mapcoord
->z
, __map_types
[vml
->maptype
].uniq_id
,
473 mapcoord
->scale
, vml
->alpha
, xshrinkfactor
, yshrinkfactor
);
481 static void maps_layer_draw_section ( VikMapsLayer
*vml
, VikViewport
*vvp
, VikCoord
*ul
, VikCoord
*br
)
484 gdouble xzoom
= vik_viewport_get_xmpp ( vvp
);
485 gdouble yzoom
= vik_viewport_get_ympp ( vvp
);
486 gdouble xshrinkfactor
= 1.0, yshrinkfactor
= 1.0;
488 if ( vml
->xmapzoom
&& (vml
->xmapzoom
!= xzoom
|| vml
->ymapzoom
!= yzoom
) ) {
489 xshrinkfactor
= vml
->xmapzoom
/ xzoom
;
490 yshrinkfactor
= vml
->ymapzoom
/ yzoom
;
491 if ( xshrinkfactor
> MIN_SHRINKFACTOR
&& xshrinkfactor
< MAX_SHRINKFACTOR
&&
492 yshrinkfactor
> MIN_SHRINKFACTOR
&& yshrinkfactor
< MAX_SHRINKFACTOR
) {
493 xzoom
= vml
->xmapzoom
;
494 yzoom
= vml
->xmapzoom
;
496 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
);
501 if ( __map_types
[vml
->maptype
].coord_to_mapcoord ( ul
, xzoom
, yzoom
, &ulm
) &&
502 __map_types
[vml
->maptype
].coord_to_mapcoord ( br
, xzoom
, yzoom
, &brm
) ) {
506 gint xmin
= MIN(ulm
.x
, brm
.x
), xmax
= MAX(ulm
.x
, brm
.x
);
507 gint ymin
= MIN(ulm
.y
, brm
.y
), ymax
= MAX(ulm
.y
, brm
.y
);
508 gint mode
= __map_types
[vml
->maptype
].uniq_id
;
511 gint xx
, yy
, width
, height
;
514 guint max_path_len
= strlen(vml
->cache_dir
) + 40;
515 gchar
*path_buf
= g_malloc ( max_path_len
* sizeof(char) );
517 if ( vml
->autodownload
)
518 start_download_thread ( vml
, vvp
, ul
, br
, REDOWNLOAD_NONE
);
520 if ( __map_types
[vml
->maptype
].tilesize_x
== 0 ) {
521 for ( x
= xmin
; x
<= xmax
; x
++ ) {
522 for ( y
= ymin
; y
<= ymax
; y
++ ) {
525 pixbuf
= get_pixbuf ( vml
, mode
, &ulm
, path_buf
, max_path_len
, xshrinkfactor
, yshrinkfactor
);
527 width
= gdk_pixbuf_get_width ( pixbuf
);
528 height
= gdk_pixbuf_get_height ( pixbuf
);
530 __map_types
[vml
->maptype
].mapcoord_to_center_coord ( &ulm
, &coord
);
531 vik_viewport_coord_to_screen ( vvp
, &coord
, &xx
, &yy
);
535 vik_viewport_draw_pixbuf ( vvp
, pixbuf
, 0, 0, xx
, yy
, width
, height
);
539 } else { /* tilesize is known, don't have to keep converting coords */
540 gdouble tilesize_x
= __map_types
[vml
->maptype
].tilesize_x
* xshrinkfactor
;
541 gdouble tilesize_y
= __map_types
[vml
->maptype
].tilesize_y
* yshrinkfactor
;
542 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
543 gint tilesize_x_ceil
= ceil ( tilesize_x
);
544 gint tilesize_y_ceil
= ceil ( tilesize_y
);
545 gint8 xinc
= (ulm
.x
== xmin
) ? 1 : -1;
546 gint8 yinc
= (ulm
.y
== ymin
) ? 1 : -1;
547 gdouble xx
, yy
; gint xx_tmp
, yy_tmp
;
548 gint base_yy
, xend
, yend
;
549 xend
= (xinc
== 1) ? (xmax
+1) : (xmin
-1);
550 yend
= (yinc
== 1) ? (ymax
+1) : (ymin
-1);
552 __map_types
[vml
->maptype
].mapcoord_to_center_coord ( &ulm
, &coord
);
553 vik_viewport_coord_to_screen ( vvp
, &coord
, &xx_tmp
, &yy_tmp
);
554 xx
= xx_tmp
; yy
= yy_tmp
;
555 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
556 * eg if tile size 128, shrinkfactor 0.333 */
557 xx
-= (tilesize_x
/2);
558 base_yy
= yy
- (tilesize_y
/2);
560 for ( x
= ((xinc
== 1) ? xmin
: xmax
); x
!= xend
; x
+=xinc
) {
562 for ( y
= ((yinc
== 1) ? ymin
: ymax
); y
!= yend
; y
+=yinc
) {
565 pixbuf
= get_pixbuf ( vml
, mode
, &ulm
, path_buf
, max_path_len
, xshrinkfactor
, yshrinkfactor
);
567 vik_viewport_draw_pixbuf ( vvp
, pixbuf
, 0, 0, xx
, yy
, tilesize_x_ceil
, tilesize_y_ceil
);
579 static void maps_layer_draw ( VikMapsLayer
*vml
, VikViewport
*vvp
)
581 if ( __map_types
[vml
->maptype
].drawmode
== vik_viewport_get_drawmode ( vvp
) )
585 /* get corner coords */
586 if ( vik_viewport_get_coord_mode ( vvp
) == VIK_COORD_UTM
&& ! vik_viewport_is_one_zone ( vvp
) ) {
587 /* UTM multi-zone stuff by Kit Transue */
588 gchar leftmost_zone
, rightmost_zone
, i
;
589 leftmost_zone
= vik_viewport_leftmost_zone( vvp
);
590 rightmost_zone
= vik_viewport_rightmost_zone( vvp
);
591 for ( i
= leftmost_zone
; i
<= rightmost_zone
; ++i
) {
592 vik_viewport_corners_for_zonen ( vvp
, i
, &ul
, &br
);
593 maps_layer_draw_section ( vml
, vvp
, &ul
, &br
);
597 vik_viewport_screen_to_coord ( vvp
, 0, 0, &ul
);
598 vik_viewport_screen_to_coord ( vvp
, vik_viewport_get_width(vvp
), vik_viewport_get_height(vvp
), &br
);
600 maps_layer_draw_section ( vml
, vvp
, &ul
, &br
);
605 /*************************/
606 /****** DOWNLOADING ******/
607 /*************************/
609 /* pass along data to thread, exists even if layer is deleted. */
621 static void mdi_free ( MapDownloadInfo
*mdi
)
623 g_free ( mdi
->cache_dir
);
624 g_free ( mdi
->filename_buf
);
628 static void map_download_thread ( MapDownloadInfo
*mdi
, gpointer threaddata
)
632 for ( x
= mdi
->x0
; x
<= mdi
->xf
; x
++ )
634 for ( y
= mdi
->y0
; y
<= mdi
->yf
; y
++ )
636 g_snprintf ( mdi
->filename_buf
, mdi
->maxlen
, DIRSTRUCTURE
,
637 mdi
->cache_dir
, __map_types
[mdi
->maptype
].uniq_id
,
638 mdi
->mapcoord
.scale
, mdi
->mapcoord
.z
, x
, y
);
640 if ( mdi
->redownload
== REDOWNLOAD_ALL
)
641 remove ( mdi
->filename_buf
);
642 else if ( mdi
->redownload
== REDOWNLOAD_BAD
&& access ( mdi
->filename_buf
, F_OK
) == 0 )
644 /* see if this one is bad or what */
646 GdkPixbuf
*pixbuf
= gdk_pixbuf_new_from_file ( mdi
->filename_buf
, &gx
);
648 remove ( mdi
->filename_buf
);
650 g_object_unref ( pixbuf
);
655 if ( access ( mdi
->filename_buf
, F_OK
) != 0 )
657 mdi
->mapcoord
.x
= x
; mdi
->mapcoord
.y
= y
;
658 __map_types
[mdi
->maptype
].download ( &(mdi
->mapcoord
), mdi
->filename_buf
);
659 mdi
->mapcoord
.x
= mdi
->mapcoord
.y
= 0; /* we're temporarily between downloads */
661 if ( mdi
->redownload
!=- REDOWNLOAD_NONE
)
662 a_mapcache_remove_all_shrinkfactors ( x
, y
, mdi
->mapcoord
.z
, mdi
->maptype
, mdi
->mapcoord
.scale
);
666 a_background_thread_progress ( threaddata
, ((gdouble
)donemaps
) / mdi
->mapstoget
); /* this also calls testcancel */
672 static void mdi_cancel_cleanup ( MapDownloadInfo
*mdi
)
674 if ( mdi
->mapcoord
.x
|| mdi
->mapcoord
.y
)
676 g_snprintf ( mdi
->filename_buf
, mdi
->maxlen
, DIRSTRUCTURE
,
677 mdi
->cache_dir
, __map_types
[mdi
->maptype
].uniq_id
,
678 mdi
->mapcoord
.scale
, mdi
->mapcoord
.z
, mdi
->mapcoord
.x
, mdi
->mapcoord
.y
);
679 if ( access ( mdi
->filename_buf
, F_OK
) == 0)
681 remove ( mdi
->filename_buf
);
686 static void start_download_thread ( VikMapsLayer
*vml
, VikViewport
*vvp
, const VikCoord
*ul
, const VikCoord
*br
, gint redownload
)
688 gdouble xzoom
= vml
->xmapzoom
? vml
->xmapzoom
: vik_viewport_get_xmpp ( vvp
);
689 gdouble yzoom
= vml
->ymapzoom
? vml
->ymapzoom
: vik_viewport_get_ympp ( vvp
);
691 if ( __map_types
[vml
->maptype
].coord_to_mapcoord ( ul
, xzoom
, yzoom
, &ulm
)
692 && __map_types
[vml
->maptype
].coord_to_mapcoord ( br
, xzoom
, yzoom
, &brm
) )
694 MapDownloadInfo
*mdi
= g_malloc ( sizeof(MapDownloadInfo
) );
697 /* cache_dir and buffer for dest filename */
698 mdi
->cache_dir
= g_strdup ( vml
->cache_dir
);
699 mdi
->maxlen
= strlen ( vml
->cache_dir
) + 40;
700 mdi
->filename_buf
= g_malloc ( mdi
->maxlen
* sizeof(gchar
) );
701 mdi
->maptype
= vml
->maptype
;
705 mdi
->redownload
= redownload
;
707 mdi
->x0
= MIN(ulm
.x
, brm
.x
);
708 mdi
->xf
= MAX(ulm
.x
, brm
.x
);
709 mdi
->y0
= MIN(ulm
.y
, brm
.y
);
710 mdi
->yf
= MAX(ulm
.y
, brm
.y
);
714 if ( mdi
->redownload
) {
715 mdi
->mapstoget
= (mdi
->xf
- mdi
->x0
+ 1) * (mdi
->yf
- mdi
->y0
+ 1);
717 /* calculate how many we need */
718 for ( a
= mdi
->x0
; a
<= mdi
->xf
; a
++ )
720 for ( b
= mdi
->y0
; b
<= mdi
->yf
; b
++ )
722 g_snprintf ( mdi
->filename_buf
, mdi
->maxlen
, DIRSTRUCTURE
,
723 vml
->cache_dir
, __map_types
[vml
->maptype
].uniq_id
, ulm
.scale
,
725 if ( access ( mdi
->filename_buf
, F_OK
) != 0)
731 mdi
->mapcoord
.x
= mdi
->mapcoord
.y
= 0; /* for cleanup -- no current map */
733 if ( mdi
->mapstoget
)
735 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" );
737 /* launch the thread */
738 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml
), /* parent window */
739 tmp
, /* description string */
740 (vik_thr_func
) map_download_thread
, /* function to call within thread */
741 mdi
, /* pass along data */
742 (vik_thr_free_func
) mdi_free
, /* function to free pass along data */
743 (vik_thr_free_func
) mdi_cancel_cleanup
,
752 static void maps_layer_redownload_bad ( VikMapsLayer
*vml
)
754 start_download_thread ( vml
, vml
->redownload_vvp
, &(vml
->redownload_ul
), &(vml
->redownload_br
), REDOWNLOAD_BAD
);
756 static void maps_layer_redownload_all ( VikMapsLayer
*vml
)
758 start_download_thread ( vml
, vml
->redownload_vvp
, &(vml
->redownload_ul
), &(vml
->redownload_br
), REDOWNLOAD_ALL
);
761 static gboolean
maps_layer_download_release ( VikMapsLayer
*vml
, GdkEventButton
*event
, VikViewport
*vvp
)
764 if ( vml
->dl_tool_x
!= -1 && vml
->dl_tool_y
!= -1 )
766 if ( event
->button
== 1 )
769 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
);
770 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
);
771 start_download_thread ( vml
, vvp
, &ul
, &br
, REDOWNLOAD_NONE
);
772 vml
->dl_tool_x
= vml
->dl_tool_y
= -1;
777 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
) );
778 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
) );
780 vml
->redownload_vvp
= vvp
;
782 vml
->dl_tool_x
= vml
->dl_tool_y
= -1;
784 if ( ! vml
->dl_right_click_menu
) {
786 vml
->dl_right_click_menu
= GTK_MENU ( gtk_menu_new () );
788 item
= gtk_menu_item_new_with_label ( "Redownload bad map(s)" );
789 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(maps_layer_redownload_bad
), vml
);
790 gtk_menu_shell_append ( GTK_MENU_SHELL(vml
->dl_right_click_menu
), item
);
792 item
= gtk_menu_item_new_with_label ( "Redownload all map(s)" );
793 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(maps_layer_redownload_all
), vml
);
794 gtk_menu_shell_append ( GTK_MENU_SHELL(vml
->dl_right_click_menu
), item
);
797 gtk_menu_popup ( vml
->dl_right_click_menu
, NULL
, NULL
, NULL
, NULL
, event
->button
, event
->time
);
798 gtk_widget_show_all ( GTK_WIDGET(vml
->dl_right_click_menu
) );
804 static gboolean
maps_layer_download_click ( VikMapsLayer
*vml
, GdkEventButton
*event
, VikViewport
*vvp
)
807 if ( __map_types
[vml
->maptype
].drawmode
== vik_viewport_get_drawmode ( vvp
) &&
808 __map_types
[vml
->maptype
].coord_to_mapcoord ( vik_viewport_get_center ( vvp
),
809 vml
->xmapzoom
? vml
->xmapzoom
: vik_viewport_get_xmpp ( vvp
),
810 vml
->ymapzoom
? vml
->ymapzoom
: vik_viewport_get_ympp ( vvp
),
812 vml
->dl_tool_x
= event
->x
, vml
->dl_tool_y
= event
->y
;
819 if ( __map_types
[vml
->maptype
].drawmode
== vik_viewport_get_drawmode ( vvp
) )
823 vik_viewport_screen_to_coord ( vvp
, event
->x
, event
->y
, &coord
);
824 if ( __map_types
[vml
->maptype
].coord_to_mapcoord ( &coord
,
825 vml
->xmapzoom
? vml
->xmapzoom
: vik_viewport_get_xmpp ( vvp
),
826 vml
->ymapzoom
? vml
->ymapzoom
: vik_viewport_get_ympp ( vvp
),
828 gchar
*filename_buf
= g_strdup_printf ( DIRSTRUCTURE
,
829 vml
->cache_dir
, __map_types
[vml
->maptype
].uniq_id
,
830 mapcoord
.scale
, mapcoord
.z
, mapcoord
.x
, mapcoord
.y
);
832 __map_types
[vml
->maptype
].download ( &mapcoord
, filename_buf
);
833 g_free ( filename_buf
);
834 vik_layer_emit_update ( VIK_LAYER(vml
) );
842 static void maps_layer_download_onscreen_maps ( gpointer vml_vvp
[2] )
844 VikMapsLayer
*vml
= vml_vvp
[0];
845 VikViewport
*vvp
= vml_vvp
[1];
847 gdouble xzoom
= vml
->xmapzoom
? vml
->xmapzoom
: vik_viewport_get_xmpp ( vvp
);
848 gdouble yzoom
= vml
->ymapzoom
? vml
->ymapzoom
: vik_viewport_get_ympp ( vvp
);
853 vik_viewport_screen_to_coord ( vvp
, 0, 0, &ul
);
854 vik_viewport_screen_to_coord ( vvp
, vik_viewport_get_width(vvp
), vik_viewport_get_height(vvp
), &br
);
856 if ( __map_types
[vml
->maptype
].drawmode
== vik_viewport_get_drawmode ( vvp
) &&
857 __map_types
[vml
->maptype
].coord_to_mapcoord ( &ul
, xzoom
, yzoom
, &ulm
) &&
858 __map_types
[vml
->maptype
].coord_to_mapcoord ( &br
, xzoom
, yzoom
, &brm
) )
859 start_download_thread ( vml
, vvp
, &ul
, &br
, REDOWNLOAD_NONE
);
861 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml
), "Wrong drawmode / zoom level for this map." );
865 static void maps_layer_add_menu_items ( VikMapsLayer
*vml
, GtkMenu
*menu
, VikLayersPanel
*vlp
)
867 static gpointer pass_along
[2];
870 pass_along
[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp
) );
872 item
= gtk_menu_item_new();
873 gtk_menu_shell_append ( GTK_MENU_SHELL(menu
), item
);
874 gtk_widget_show ( item
);
876 item
= gtk_menu_item_new_with_label ( "Download Onscreen Maps" );
877 g_signal_connect_swapped ( G_OBJECT(item
), "activate", G_CALLBACK(maps_layer_download_onscreen_maps
), pass_along
);
878 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
879 gtk_widget_show ( item
);