]> git.street.me.uk Git - andy/viking.git/blame - src/vikmapslayer.c
Remove USGS
[andy/viking.git] / src / vikmapslayer.c
CommitLineData
50a14534
EB
1/*
2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3 *
4 * Copyright (C) 2005, Evan Battaglia <viking@greentorch.org>
5 * UTM multi-zone stuff by Kit Transue <notlostyet@didactek.com>
6 *
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.
11 *
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.
16 *
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
20 *
21 */
22
23#define MAX_SHRINKFACTOR 8.0000001 /* zoom 1 viewing 8-tiles */
24#define MIN_SHRINKFACTOR 0.0312499 /* zoom 32 viewing 1-tiles */
25
26#include <gtk/gtk.h>
27#include <gdk-pixbuf/gdk-pixdata.h>
28#include <stdio.h>
29#include <string.h>
30#include <math.h>
31#include "globals.h"
32#include "coords.h"
33#include "vikcoord.h"
34#include "viktreeview.h"
35#include "vikviewport.h"
36#include "viklayer.h"
37#include "vikmapslayer.h"
38#include "vikmapslayer_pixmap.h"
39
40#include <unistd.h>
41#include <sys/stat.h>
42#include <sys/types.h>
43
44#include "mapcache.h"
45/* only for dialog.h -- ugh */
46#include "vikwaypoint.h"
47#include "dialog.h"
48
49#include "vikstatus.h"
50#include "background.h"
51
52#include "vikaggregatelayer.h"
53#include "viklayerspanel.h"
54
55#include "mapcoord.h"
56#include "terraserver.h"
57#include "googlemaps.h"
58#include "google.h"
59#include "khmaps.h"
60#include "expedia.h"
50a14534
EB
61
62typedef struct {
63 guint8 uniq_id;
64 guint16 tilesize_x;
65 guint16 tilesize_y;
66 guint drawmode;
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;
72
73
74/****** MAP TYPES ******/
75
76static const VikMapsLayer_MapType __map_types[] = {
77
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 },
50a14534
EB
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 },
87};
88
89#define NUM_MAP_TYPES (sizeof(__map_types)/sizeof(__map_types[0]))
90
91/******** MAPZOOMS *********/
92
93static 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" };
94static 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 };
95static 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 };
96
6bca81f6 97static 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" };
dbd03ad5 98static guint params_maptypes_ids[] = { 2, 1, 4, 5, 9, 8, 7, 10, 11 };
50a14534
EB
99#define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0]))
100
101/**************************/
102
103
104static VikMapsLayer *maps_layer_copy ( VikMapsLayer *vml, VikViewport *vvp );
105static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp );
106static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id );
107static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp );
108static VikMapsLayer *maps_layer_new ( VikViewport *vvp );
109static void maps_layer_free ( VikMapsLayer *vml );
110static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
111static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
112static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir );
113static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload );
114static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp );
115
116
117static VikLayerParamScale params_scales[] = {
118 /* min, max, step, digits (decimal places) */
119 { 0, 255, 3, 0 }, /* alpha */
120};
121
122VikLayerParam 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 },
128};
129
130enum { PARAM_MAPTYPE=0, PARAM_CACHE_DIR, PARAM_ALPHA, PARAM_AUTODOWNLOAD, PARAM_MAPZOOM, NUM_PARAMS };
131
132static VikToolInterface maps_tools[] = {
133 { "Maps Download", (VikToolInterfaceFunc) maps_layer_download_click, (VikToolInterfaceFunc) maps_layer_download_release },
134};
135
136VikLayerInterface vik_maps_layer_interface = {
137 "Map",
138 &mapslayer_pixbuf,
139
140 maps_tools,
141 sizeof(maps_tools) / sizeof(maps_tools[0]),
142
143 maps_layer_params,
144 NUM_PARAMS,
145 NULL,
146 0,
147
148 (VikLayerFuncCreate) maps_layer_new,
149 (VikLayerFuncRealize) NULL,
150 (VikLayerFuncPostRead) NULL,
151 (VikLayerFuncFree) maps_layer_free,
152
153 (VikLayerFuncProperties) NULL,
154 (VikLayerFuncDraw) maps_layer_draw,
155 (VikLayerFuncChangeCoordMode) NULL,
156
157 (VikLayerFuncAddMenuItems) maps_layer_add_menu_items,
158 (VikLayerFuncSublayerAddMenuItems) NULL,
159
160 (VikLayerFuncSublayerRenameRequest) NULL,
161 (VikLayerFuncSublayerToggleVisible) NULL,
162
163 (VikLayerFuncCopy) maps_layer_copy,
164
165 (VikLayerFuncSetParam) maps_layer_set_param,
166 (VikLayerFuncGetParam) maps_layer_get_param,
167
168 (VikLayerFuncReadFileData) NULL,
169 (VikLayerFuncWriteFileData) NULL,
170
171 (VikLayerFuncCopyItem) NULL,
172 (VikLayerFuncPasteItem) NULL,
173 (VikLayerFuncFreeCopiedItem) NULL,
70a23263 174 (VikLayerFuncDragDropRequest) NULL,
50a14534
EB
175};
176
177struct _VikMapsLayer {
178 VikLayer vl;
179 guint maptype;
180 gchar *cache_dir;
181 guint8 alpha;
182 guint mapzoom_id;
183 gdouble xmapzoom, ymapzoom;
184
185 gboolean autodownload;
186
187 gint dl_tool_x, dl_tool_y;
188
189 GtkMenu *dl_right_click_menu;
190 VikCoord redownload_ul, redownload_br; /* right click menu only */
191 VikViewport *redownload_vvp;
192};
193
194enum { REDOWNLOAD_NONE = 0, REDOWNLOAD_BAD, REDOWNLOAD_ALL };
195
196
197/****************************************/
198/******** CACHE DIR STUFF ***************/
199/****************************************/
200
201#ifdef WINDOWS
202#define MAPS_CACHE_DIR "C:\\VIKING-MAPS\\"
203#define DIRSTRUCTURE "%st%ds%dz%d\\%d\\%d"
204#else /* POSIX */
205
206#include <stdlib.h>
207
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"
211
212static gchar *maps_layer_default_dir ()
213{
214 static gchar defaultdir[512];
215 static gboolean already_run = 0;
216 if ( ! already_run )
217 {
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 );
224 } else {
225 gchar *home = getenv("HOME");
226 if ( home && strlen(home) < 497 )
227 {
228 strcpy ( defaultdir, home );
229 strcat ( defaultdir, "/.viking-maps/" );
230 }
231 else
232 {
233 strcpy ( defaultdir, ".viking-maps/" );
234 }
235 }
236 already_run = 1;
237 }
238 return defaultdir;
239}
240
241#endif
242
243static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
244{
245 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && access ( vml->cache_dir, F_OK ) != 0 )
246 {
247#ifdef WINDOWS
248 mkdir ( vml->cache_dir );
249#else
250 mkdir ( vml->cache_dir, 0777 );
251#endif
252 }
253}
254
255static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
256{
257 guint len;
258 g_assert ( vml != NULL);
259 if ( vml->cache_dir )
260 g_free ( vml->cache_dir );
261
262 if ( dir == NULL || dir[0] == '\0' )
263 vml->cache_dir = g_strdup ( MAPS_CACHE_DIR );
264 else
265 {
266 len = strlen(dir);
267 if ( dir[len-1] != VIKING_FILE_SEP )
268 {
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';
273 }
274 else
275 vml->cache_dir = g_strdup ( dir );
276 }
277 maps_layer_mkdir_if_default_dir ( vml );
278}
279
280/****************************************/
281/******** GOBJECT STUFF *****************/
282/****************************************/
283
284GType vik_maps_layer_get_type ()
285{
286 static GType vml_type = 0;
287
288 if (!vml_type)
289 {
290 static const GTypeInfo vml_info =
291 {
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),
299 0,
300 NULL /* instance init */
301 };
302 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
303 }
304
305 return vml_type;
306}
307
308/****************************************/
309/************** PARAMETERS **************/
310/****************************************/
311
312static guint map_index_to_uniq_id (guint8 index)
313{
314 g_assert ( index < NUM_MAP_TYPES );
315 return __map_types[index].uniq_id;
316}
317
318static guint map_uniq_id_to_index ( guint uniq_id )
319{
320 gint i;
321 for ( i = 0; i < NUM_MAP_TYPES; i++ )
322 if ( __map_types[i].uniq_id == uniq_id )
323 return i;
324 return NUM_MAP_TYPES; /* no such thing */
325}
326
327static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp )
328{
329 switch ( id )
330 {
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;
336 break;
337 }
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;
345 }
346 return TRUE;
347}
348
349static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id )
350{
351 VikLayerParamData rv;
352 switch ( id )
353 {
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;
359 }
360 return rv;
361}
362
363/****************************************/
364/****** CREATING, COPYING, FREEING ******/
365/****************************************/
366
367static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
368{
369 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
370 vik_layer_init ( VIK_LAYER(vml), VIK_LAYER_MAPS );
371 vml->maptype = 0;
372 vml->alpha = 255;
373 vml->mapzoom_id = 0;
374 vml->dl_tool_x = vml->dl_tool_y = -1;
375 maps_layer_set_cache_dir ( vml, NULL );
376 vml->autodownload = FALSE;
377
378 vml->dl_right_click_menu = NULL;
379
380 return vml;
381}
382
383static void maps_layer_free ( VikMapsLayer *vml )
384{
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) );
389}
390
391static VikMapsLayer *maps_layer_copy ( VikMapsLayer *vml, VikViewport *vvp )
392{
393 VikMapsLayer *rv = maps_layer_new ( vvp );
394 *rv = *vml;
395 rv->cache_dir = g_strdup(rv->cache_dir);
396 VIK_LAYER(rv)->name = NULL;
397 return rv;
398}
399
400/*********************/
401/****** DRAWING ******/
402/*********************/
403
404static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
405{
406 guchar *pixels;
407 gint width, height, iii, jjj;
408
409 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
410 {
411 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
412 g_object_unref(G_OBJECT(pixbuf));
413 pixbuf = tmp;
414 }
415
416 pixels = gdk_pixbuf_get_pixels(pixbuf);
417 width = gdk_pixbuf_get_width(pixbuf);
418 height = gdk_pixbuf_get_height(pixbuf);
419
420 /* r,g,b,a,r,g,b,a.... */
421 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
422 {
423 pixels += 3;
424 *pixels++ = alpha;
425 }
426 return pixbuf;
427}
428
429static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
430{
431 GdkPixbuf *tmp;
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) );
435 return tmp;
436}
437
438static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
439{
440 GdkPixbuf *pixbuf;
441
442 /* get the thing */
443 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
444 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
445
446 if ( ! pixbuf ) {
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) {
451 {
452 GError *gx = NULL;
453 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
454
455 if (gx)
456 {
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 );
459
460 g_error_free ( gx );
461 if ( pixbuf )
462 g_object_unref ( G_OBJECT(pixbuf) );
463 pixbuf = NULL;
464 } else {
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 );
469
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 );
473 }
474 }
475 }
476 }
477 return pixbuf;
478}
479
480static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
481{
482 MapCoord ulm, brm;
483 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
484 gdouble yzoom = vik_viewport_get_ympp ( vvp );
485 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
486
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;
494 } else {
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 );
496 }
497 }
498
499 /* coord -> ID */
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 ) ) {
502
503 /* loop & draw */
504 gint x, y;
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;
508
509 VikCoord coord;
510 gint xx, yy, width, height;
511 GdkPixbuf *pixbuf;
512
513 guint max_path_len = strlen(vml->cache_dir) + 40;
514 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
515
516 if ( vml->autodownload )
517 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
518
519 if ( __map_types[vml->maptype].tilesize_x == 0 ) {
520 for ( x = xmin; x <= xmax; x++ ) {
521 for ( y = ymin; y <= ymax; y++ ) {
522 ulm.x = x;
523 ulm.y = y;
524 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
525 if ( pixbuf ) {
526 width = gdk_pixbuf_get_width ( pixbuf );
527 height = gdk_pixbuf_get_height ( pixbuf );
528
529 __map_types[vml->maptype].mapcoord_to_center_coord ( &ulm, &coord );
530 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
531 xx -= (width/2);
532 yy -= (height/2);
533
534 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
535 }
536 }
537 }
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);
550
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);
558
559 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
560 yy = base_yy;
561 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
562 ulm.x = x;
563 ulm.y = y;
564 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
565 if ( pixbuf )
566 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
567
568 yy += tilesize_y;
569 }
570 xx += tilesize_x;
571 }
572 }
573
574 g_free ( path_buf );
575 }
576}
577
578static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
579{
580 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
581 {
582 VikCoord ul, br;
583
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 );
593 }
594 }
595 else {
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 );
598
599 maps_layer_draw_section ( vml, vvp, &ul, &br );
600 }
601 }
602}
603
604/*************************/
605/****** DOWNLOADING ******/
606/*************************/
607
608/* pass along data to thread, exists even if layer is deleted. */
609typedef struct {
610 gchar *cache_dir;
611 gchar *filename_buf;
612 gint x0, y0, xf, yf;
613 MapCoord mapcoord;
614 gint maptype;
615 gint maxlen;
616 gint mapstoget;
617 gint redownload;
618} MapDownloadInfo;
619
620static void mdi_free ( MapDownloadInfo *mdi )
621{
622 g_free ( mdi->cache_dir );
623 g_free ( mdi->filename_buf );
624 g_free ( mdi );
625}
626
627static void map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
628{
629 guint donemaps = 0;
630 gint x, y;
631 for ( x = mdi->x0; x <= mdi->xf; x++ )
632 {
633 for ( y = mdi->y0; y <= mdi->yf; y++ )
634 {
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 );
638
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 )
642 {
643 /* see if this one is bad or what */
644 GError *gx = NULL;
645 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
646 if (gx || (!pixbuf))
647 remove ( mdi->filename_buf );
648 if ( pixbuf )
649 g_object_unref ( pixbuf );
650 if ( gx )
651 g_error_free ( gx );
652 }
653
654 if ( access ( mdi->filename_buf, F_OK ) != 0 )
655 {
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 */
1fe49af0
EB
659
660 if ( mdi->redownload !=- REDOWNLOAD_NONE )
661 a_mapcache_remove_all_shrinkfactors ( x, y, mdi->mapcoord.z, mdi->maptype, mdi->mapcoord.scale );
662
663
50a14534
EB
664 donemaps++;
665 a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
666 }
667 }
668 }
669}
670
671static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
672{
673 if ( mdi->mapcoord.x || mdi->mapcoord.y )
674 {
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)
679 {
680 remove ( mdi->filename_buf );
681 }
682 }
683}
684
685static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
686{
687 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
688 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
689 MapCoord ulm, brm;
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 ) )
692 {
693 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
694 gint a, b;
695
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;
701
702 mdi->mapcoord = ulm;
703
704 mdi->redownload = redownload;
705
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);
710
711 mdi->mapstoget = 0;
712
713 if ( mdi->redownload ) {
714 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
715 } else {
716 /* calculate how many we need */
717 for ( a = mdi->x0; a <= mdi->xf; a++ )
718 {
719 for ( b = mdi->y0; b <= mdi->yf; b++ )
720 {
721 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
722 vml->cache_dir, __map_types[vml->maptype].uniq_id, ulm.scale,
723 ulm.z, a, b );
724 if ( access ( mdi->filename_buf, F_OK ) != 0)
725 mdi->mapstoget++;
726 }
727 }
728 }
729
730 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
731
732 if ( mdi->mapstoget )
733 {
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" );
735
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,
743 mdi->mapstoget );
744 g_free ( tmp );
745 }
746 else
747 mdi_free ( mdi );
748 }
749}
750
751static void maps_layer_redownload_bad ( VikMapsLayer *vml )
752{
753 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
754}
755static void maps_layer_redownload_all ( VikMapsLayer *vml )
756{
757 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
758}
759
760static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
761{
762
763 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
764 {
765 if ( event->button == 1 )
766 {
767 VikCoord ul, br;
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;
772 return TRUE;
773 }
774 else
775 {
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) );
778
779 vml->redownload_vvp = vvp;
780
781 vml->dl_tool_x = vml->dl_tool_y = -1;
782
783 if ( ! vml->dl_right_click_menu ) {
784 GtkWidget *item;
785 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
786
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 );
790
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 );
794 }
795
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) );
798 }
799 }
800 return FALSE;
801}
802
803static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
804{
805 MapCoord tmp;
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 ),
810 &tmp ) ) {
811 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
812 return TRUE;
813 }
814 return FALSE;
815
816
817#if 0
818 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
819 {
820 VikCoord coord;
821 MapCoord mapcoord;
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 ),
826 &mapcoord ) ) {
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 );
830
831 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
832 g_free ( filename_buf );
833 vik_layer_emit_update ( VIK_LAYER(vml) );
834 return TRUE;
835 }
836 }
837 return FALSE;
838#endif
839}
840
841static void maps_layer_download_onscreen_maps ( gpointer vml_vvp[2] )
842{
843 VikMapsLayer *vml = vml_vvp[0];
844 VikViewport *vvp = vml_vvp[1];
845
846 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
847 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
848
849 VikCoord ul, br;
850 MapCoord ulm, brm;
851
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 );
854
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 );
859 else
860 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), "Wrong drawmode / zoom level for this map." );
861
862}
863
864static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
865{
866 static gpointer pass_along[2];
867 GtkWidget *item;
868 pass_along[0] = vml;
869 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
870
871 item = gtk_menu_item_new();
872 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
873 gtk_widget_show ( item );
874
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 );
879}