2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
4 * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #ifdef HAVE_SYS_TYPES_H
29 #include <sys/types.h>
31 #ifdef HAVE_SYS_STAT_H
38 #include <glib/gstdio.h>
39 #include <glib/gi18n.h>
41 #include "background.h"
43 #include "vikmapslayer.h"
44 #include "vikdemlayer.h"
47 #include "icons/icons.h"
49 #define MAPS_CACHE_DIR maps_layer_default_dir()
51 #define SRTM_CACHE_TEMPLATE "%ssrtm3-%s%s%c%02d%c%03d.hgt.zip"
52 #define SRTM_HTTP_SITE "dds.cr.usgs.gov"
53 #define SRTM_HTTP_URI "/srtm/version2_1/SRTM3/"
55 #ifdef VIK_CONFIG_DEM24K
56 #define DEM24K_DOWNLOAD_SCRIPT "dem24k.pl"
59 #define UNUSED_LINE_THICKNESS 3
61 static VikDEMLayer *dem_layer_new ( VikViewport *vvp );
62 static void dem_layer_draw ( VikDEMLayer *vdl, VikViewport *vp );
63 static void dem_layer_free ( VikDEMLayer *vdl );
64 static VikDEMLayer *dem_layer_create ( VikViewport *vp );
65 static const gchar* dem_layer_tooltip( VikDEMLayer *vdl );
66 static void dem_layer_marshall( VikDEMLayer *vdl, guint8 **data, gint *len );
67 static VikDEMLayer *dem_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
68 static gboolean dem_layer_set_param ( VikDEMLayer *vdl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation );
69 static VikLayerParamData dem_layer_get_param ( VikDEMLayer *vdl, guint16 id, gboolean is_file_operation );
70 static void dem_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file );
71 static void srtm_draw_existence ( VikViewport *vp );
73 #ifdef VIK_CONFIG_DEM24K
74 static void dem24k_draw_existence ( VikViewport *vp );
77 /* Upped upper limit incase units are feet */
78 static VikLayerParamScale param_scales[] = {
83 static gchar *params_source[] = {
84 "SRTM Global 90m (3 arcsec)",
85 #ifdef VIK_CONFIG_DEM24K
91 static gchar *params_type[] = {
92 N_("Absolute height"),
93 N_("Height gradient"),
97 enum { DEM_SOURCE_SRTM,
98 #ifdef VIK_CONFIG_DEM24K
103 enum { DEM_TYPE_HEIGHT = 0,
108 static VikLayerParamData color_default ( void ) {
109 VikLayerParamData data; gdk_color_parse ( "blue", &data.c ); return data;
112 static VikLayerParamData source_default ( void ) { return VIK_LPD_UINT ( DEM_SOURCE_SRTM ); }
113 static VikLayerParamData type_default ( void ) { return VIK_LPD_UINT ( DEM_TYPE_HEIGHT ); }
114 static VikLayerParamData min_elev_default ( void ) { return VIK_LPD_DOUBLE ( 0.0 ); }
115 static VikLayerParamData max_elev_default ( void ) { return VIK_LPD_DOUBLE ( 1000.0 ); }
117 static VikLayerParam dem_layer_params[] = {
118 { VIK_LAYER_DEM, "files", VIK_LAYER_PARAM_STRING_LIST, VIK_LAYER_GROUP_NONE, N_("DEM Files:"), VIK_LAYER_WIDGET_FILELIST, NULL, NULL, NULL, NULL, NULL, NULL },
119 { VIK_LAYER_DEM, "source", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Download Source:"), VIK_LAYER_WIDGET_RADIOGROUP_STATIC, params_source, NULL, NULL, source_default, NULL, NULL },
120 { VIK_LAYER_DEM, "color", VIK_LAYER_PARAM_COLOR, VIK_LAYER_GROUP_NONE, N_("Min Elev Color:"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL, color_default, NULL, NULL },
121 { VIK_LAYER_DEM, "type", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Type:"), VIK_LAYER_WIDGET_RADIOGROUP_STATIC, params_type, NULL, NULL, type_default, NULL, NULL },
122 { VIK_LAYER_DEM, "min_elev", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_GROUP_NONE, N_("Min Elev:"), VIK_LAYER_WIDGET_SPINBUTTON, param_scales + 0, NULL, NULL, min_elev_default, NULL, NULL },
123 { VIK_LAYER_DEM, "max_elev", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_GROUP_NONE, N_("Max Elev:"), VIK_LAYER_WIDGET_SPINBUTTON, param_scales + 0, NULL, NULL, max_elev_default, NULL, NULL },
127 enum { PARAM_FILES=0, PARAM_SOURCE, PARAM_COLOR, PARAM_TYPE, PARAM_MIN_ELEV, PARAM_MAX_ELEV, NUM_PARAMS };
129 static gpointer dem_layer_download_create ( VikWindow *vw, VikViewport *vvp);
130 static gboolean dem_layer_download_release ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp );
131 static gboolean dem_layer_download_click ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp );
133 static VikToolInterface dem_tools[] = {
134 { { "DEMDownload", "vik-icon-DEM Download", N_("_DEM Download"), NULL, N_("DEM Download"), 0 },
135 (VikToolConstructorFunc) dem_layer_download_create, NULL, NULL, NULL,
136 (VikToolMouseFunc) dem_layer_download_click, NULL, (VikToolMouseFunc) dem_layer_download_release,
137 (VikToolKeyFunc) NULL,
139 GDK_CURSOR_IS_PIXMAP, &cursor_demdl_pixbuf },
144 The first entry is blue for a default 'sea' colour,
145 however the value used by the corresponding gc can be configured as part of the DEM layer properties.
146 The other colours, shaded from brown to white are used to give an indication of height.
148 static gchar *dem_height_colors[] = {
150 "#9b793c", "#9c7d40", "#9d8144", "#9e8549", "#9f894d", "#a08d51", "#a29156", "#a3955a", "#a4995e", "#a69d63",
151 "#a89f65", "#aaa267", "#ada569", "#afa76b", "#b1aa6d", "#b4ad6f", "#b6b071", "#b9b373", "#bcb676", "#beb978",
152 "#c0bc7a", "#c2c07d", "#c4c37f", "#c6c681", "#c8ca84", "#cacd86", "#ccd188", "#cfd58b", "#c2ce84", "#b5c87e",
153 "#a9c278", "#9cbb71", "#8fb56b", "#83af65", "#76a95e", "#6aa358", "#5e9d52", "#63a055", "#69a458", "#6fa85c",
154 "#74ac5f", "#7ab063", "#80b467", "#86b86a", "#8cbc6e", "#92c072", "#94c175", "#97c278", "#9ac47c", "#9cc57f",
155 "#9fc682", "#a2c886", "#a4c989", "#a7cb8d", "#aacd91", "#afce99", "#b5d0a1", "#bbd2aa", "#c0d3b2", "#c6d5ba",
156 "#ccd7c3", "#d1d9cb", "#d7dbd4", "#DDDDDD", "#e0e0e0", "#e4e4e4", "#e8e8e8", "#ebebeb", "#efefef", "#f3f3f3",
157 "#f7f7f7", "#fbfbfb", "#ffffff"
160 static const guint DEM_N_HEIGHT_COLORS = sizeof(dem_height_colors)/sizeof(dem_height_colors[0]);
163 "#9b793c", "#9e8549", "#a29156", "#a69d63", "#ada569", "#b4ad6f", "#bcb676", "#c2c07d", "#c8ca84", "#cfd58b",
164 "#a9c278", "#83af65", "#5e9d52", "#6fa85c", "#80b467", "#92c072", "#9ac47c", "#a2c886", "#aacd91", "#bbd2aa",
165 "#ccd7c3", "#DDDDDD", "#e8e8e8", "#f3f3f3", "#FFFFFF"
169 static gchar *dem_gradient_colors[] = {
171 "#000000", "#000011", "#000022", "#000033", "#000044", "#00004c", "#000055", "#00005d", "#000066", "#00006e",
172 "#000077", "#00007f", "#000088", "#000090", "#000099", "#0000a1", "#0000aa", "#0000b2", "#0000bb", "#0000c3",
173 "#0000cc", "#0000d4", "#0000dd", "#0000e5", "#0000ee", "#0000f6", "#0000ff", "#0008f7", "#0011ee", "#0019e6",
174 "#0022dd", "#002ad5", "#0033cc", "#003bc4", "#0044bb", "#004cb3", "#0055aa", "#005da2", "#006699", "#006e91",
175 "#007788", "#007f80", "#008877", "#00906f", "#009966", "#00a15e", "#00aa55", "#00b24d", "#00bb44", "#00c33c",
176 "#00cc33", "#00d42b", "#00dd22", "#00e51a", "#00ee11", "#00f609", "#00ff00", "#08f700", "#11ee00", "#19e600",
177 "#22dd00", "#2ad500", "#33cc00", "#3bc400", "#44bb00", "#4cb300", "#55aa00", "#5da200", "#669900", "#6e9100",
178 "#778800", "#7f8000", "#887700", "#906f00", "#996600", "#a15e00", "#aa5500", "#b24d00", "#bb4400", "#c33c00",
179 "#cc3300", "#d42b00", "#dd2200", "#e51a00", "#ee1100", "#f60900", "#ff0000",
183 static const guint DEM_N_GRADIENT_COLORS = sizeof(dem_gradient_colors)/sizeof(dem_gradient_colors[0]);
186 VikLayerInterface vik_dem_layer_interface = {
193 sizeof(dem_tools) / sizeof(dem_tools[0]),
202 (VikLayerFuncCreate) dem_layer_create,
203 (VikLayerFuncRealize) NULL,
204 (VikLayerFuncPostRead) dem_layer_post_read,
205 (VikLayerFuncFree) dem_layer_free,
207 (VikLayerFuncProperties) NULL,
208 (VikLayerFuncDraw) dem_layer_draw,
209 (VikLayerFuncChangeCoordMode) NULL,
211 (VikLayerFuncSetMenuItemsSelection) NULL,
212 (VikLayerFuncGetMenuItemsSelection) NULL,
214 (VikLayerFuncAddMenuItems) NULL,
215 (VikLayerFuncSublayerAddMenuItems) NULL,
217 (VikLayerFuncSublayerRenameRequest) NULL,
218 (VikLayerFuncSublayerToggleVisible) NULL,
219 (VikLayerFuncSublayerTooltip) NULL,
220 (VikLayerFuncLayerTooltip) dem_layer_tooltip,
221 (VikLayerFuncLayerSelected) NULL,
223 (VikLayerFuncMarshall) dem_layer_marshall,
224 (VikLayerFuncUnmarshall) dem_layer_unmarshall,
226 (VikLayerFuncSetParam) dem_layer_set_param,
227 (VikLayerFuncGetParam) dem_layer_get_param,
228 (VikLayerFuncChangeParam) NULL,
230 (VikLayerFuncReadFileData) NULL,
231 (VikLayerFuncWriteFileData) NULL,
233 (VikLayerFuncDeleteItem) NULL,
234 (VikLayerFuncCutItem) NULL,
235 (VikLayerFuncCopyItem) NULL,
236 (VikLayerFuncPasteItem) NULL,
237 (VikLayerFuncFreeCopiedItem) NULL,
238 (VikLayerFuncDragDropRequest) NULL,
240 (VikLayerFuncSelectClick) NULL,
241 (VikLayerFuncSelectMove) NULL,
242 (VikLayerFuncSelectRelease) NULL,
243 (VikLayerFuncSelectedViewportMenu) NULL,
246 struct _VikDEMLayer {
257 // right click menu only stuff - similar to mapslayer
258 GtkMenu *right_click_menu;
261 GType vik_dem_layer_get_type ()
263 static GType vdl_type = 0;
267 static const GTypeInfo vdl_info =
269 sizeof (VikDEMLayerClass),
270 NULL, /* base_init */
271 NULL, /* base_finalize */
272 NULL, /* class init */
273 NULL, /* class_finalize */
274 NULL, /* class_data */
275 sizeof (VikDEMLayer),
277 NULL /* instance init */
279 vdl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikDEMLayer", &vdl_info, 0 );
285 static const gchar* dem_layer_tooltip( VikDEMLayer *vdl )
287 static gchar tmp_buf[100];
288 g_snprintf (tmp_buf, sizeof(tmp_buf), _("Number of files: %d"), g_list_length (vdl->files));
292 static void dem_layer_marshall( VikDEMLayer *vdl, guint8 **data, gint *len )
294 vik_layer_marshall_params ( VIK_LAYER(vdl), data, len );
297 static VikDEMLayer *dem_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
299 VikDEMLayer *rv = dem_layer_new ( vvp );
302 /* TODO: share GCS between layers */
303 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ ) {
305 rv->gcs[i] = vik_viewport_new_gc_from_color ( vvp, &(rv->color), UNUSED_LINE_THICKNESS );
307 rv->gcs[i] = vik_viewport_new_gc ( vvp, dem_height_colors[i], UNUSED_LINE_THICKNESS );
309 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
310 rv->gcsgradient[i] = vik_viewport_new_gc ( vvp, dem_gradient_colors[i], UNUSED_LINE_THICKNESS );
312 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
316 /* Structure for DEM data used in background thread */
319 } dem_load_thread_data;
322 * Function for starting the DEM file loading as a background thread
324 static int dem_layer_load_list_thread ( dem_load_thread_data *dltd, gpointer threaddata )
326 int result = 0; // Default to good
328 if ( a_dems_load_list ( &(dltd->vdl->files), threaddata ) ) {
333 // ATM as each file is processed the screen is not updated (no mechanism exposed to a_dems_load_list)
334 // Thus force draw only at the end, as loading is complete/aborted
335 //gdk_threads_enter();
336 // Test is helpful to prevent Gtk-CRITICAL warnings if the program is exitted whilst loading
337 if ( IS_VIK_LAYER(dltd->vdl) )
338 vik_layer_emit_update ( VIK_LAYER(dltd->vdl) ); // NB update from background thread
339 //gdk_threads_leave();
344 static void dem_layer_thread_data_free ( dem_load_thread_data *data )
350 static void dem_layer_thread_cancel ( dem_load_thread_data *data )
353 // Instead of freeing the list, leave it as partially processed
354 // Thus we can see/use what was done
358 * Process the list of DEM files and convert each one to a relative path
360 static GList *dem_layer_convert_to_relative_filenaming ( GList *files )
362 gchar *cwd = g_get_current_dir();
366 GList *relfiles = NULL;
369 gchar *file = g_strdup ( file_GetRelativeFilename ( cwd, files->data ) );
370 relfiles = g_list_prepend ( relfiles, file );
377 // Replacing current list, so delete old values first.
380 g_free ( iter->data );
383 g_list_free ( files );
391 gboolean dem_layer_set_param ( VikDEMLayer *vdl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
395 case PARAM_COLOR: vdl->color = data.c; gdk_gc_set_rgb_fg_color ( vdl->gcs[0], &(vdl->color) ); break;
396 case PARAM_SOURCE: vdl->source = data.u; break;
397 case PARAM_TYPE: vdl->type = data.u; break;
399 /* Convert to store internally
400 NB file operation always in internal units (metres) */
401 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
402 vdl->min_elev = VIK_FEET_TO_METERS(data.d);
404 vdl->min_elev = data.d;
407 /* Convert to store internally
408 NB file operation always in internal units (metres) */
409 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
410 vdl->max_elev = VIK_FEET_TO_METERS(data.d);
412 vdl->max_elev = data.d;
416 // Clear out old settings - if any commonalities with new settings they will have to be read again
417 a_dems_list_free ( vdl->files );
418 // Set file list so any other intermediate screen drawing updates will show currently loaded DEMs by the working thread
419 vdl->files = data.sl;
420 // No need for thread if no files
423 dem_load_thread_data *dltd = g_malloc ( sizeof(dem_load_thread_data) );
425 dltd->vdl->files = data.sl;
427 a_background_thread ( VIK_GTK_WINDOW_FROM_WIDGET(vp),
429 (vik_thr_func) dem_layer_load_list_thread,
431 (vik_thr_free_func) dem_layer_thread_data_free,
432 (vik_thr_free_func) dem_layer_thread_cancel,
433 g_list_length ( data.sl ) ); // Number of DEM files
441 static VikLayerParamData dem_layer_get_param ( VikDEMLayer *vdl, guint16 id, gboolean is_file_operation )
443 VikLayerParamData rv;
448 if ( is_file_operation )
449 // Save in relative format if necessary
450 if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE )
451 rv.sl = dem_layer_convert_to_relative_filenaming ( rv.sl );
453 case PARAM_SOURCE: rv.u = vdl->source; break;
454 case PARAM_TYPE: rv.u = vdl->type; break;
455 case PARAM_COLOR: rv.c = vdl->color; break;
457 /* Convert for display in desired units
458 NB file operation always in internal units (metres) */
459 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
460 rv.d = VIK_METERS_TO_FEET(vdl->min_elev);
462 rv.d = vdl->min_elev;
465 /* Convert for display in desired units
466 NB file operation always in internal units (metres) */
467 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
468 rv.d = VIK_METERS_TO_FEET(vdl->max_elev);
470 rv.d = vdl->max_elev;
476 static void dem_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file )
478 /* nothing ATM, but keep in case it's needed the future */
481 static VikDEMLayer *dem_layer_new ( VikViewport *vvp )
483 VikDEMLayer *vdl = VIK_DEM_LAYER ( g_object_new ( VIK_DEM_LAYER_TYPE, NULL ) );
485 vik_layer_set_type ( VIK_LAYER(vdl), VIK_LAYER_DEM );
489 vdl->gcs = g_malloc(sizeof(GdkGC *)*DEM_N_HEIGHT_COLORS);
490 vdl->gcsgradient = g_malloc(sizeof(GdkGC *)*DEM_N_GRADIENT_COLORS);
491 /* make new gcs only if we need it (copy layer -> use old) */
493 // Ensure the base GC is available so the default colour can be applied
494 if ( vvp ) vdl->gcs[0] = vik_viewport_new_gc ( vvp, "#0000FF", 1 );
496 vik_layer_set_defaults ( VIK_LAYER(vdl), vvp );
502 static inline guint16 get_height_difference(gint16 elev, gint16 new_elev)
504 if(new_elev == VIK_DEM_INVALID_ELEVATION)
507 return abs(new_elev - elev);
511 static void vik_dem_layer_draw_dem ( VikDEMLayer *vdl, VikViewport *vp, VikDEM *dem )
513 VikDEMColumn *column, *prevcolumn, *nextcolumn;
515 struct LatLon dem_northeast, dem_southwest;
516 gdouble max_lat, max_lon, min_lat, min_lon;
518 /**** Check if viewport and DEM data overlap ****/
520 /* get min, max lat/lon of viewport */
521 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
523 /* get min, max lat/lon of DEM data */
524 if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
525 dem_northeast.lat = dem->max_north / 3600.0;
526 dem_northeast.lon = dem->max_east / 3600.0;
527 dem_southwest.lat = dem->min_north / 3600.0;
528 dem_southwest.lon = dem->min_east / 3600.0;
529 } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
530 struct UTM dem_northeast_utm, dem_southwest_utm;
531 dem_northeast_utm.northing = dem->max_north;
532 dem_northeast_utm.easting = dem->max_east;
533 dem_southwest_utm.northing = dem->min_north;
534 dem_southwest_utm.easting = dem->min_east;
535 dem_northeast_utm.zone = dem_southwest_utm.zone = dem->utm_zone;
536 dem_northeast_utm.letter = dem_southwest_utm.letter = dem->utm_letter;
538 a_coords_utm_to_latlon(&dem_northeast_utm, &dem_northeast);
539 a_coords_utm_to_latlon(&dem_southwest_utm, &dem_southwest);
542 if ( (max_lat > dem_northeast.lat && min_lat > dem_northeast.lat) ||
543 (max_lat < dem_southwest.lat && min_lat < dem_southwest.lat) )
545 else if ( (max_lon > dem_northeast.lon && min_lon > dem_northeast.lon) ||
546 (max_lon < dem_southwest.lon && min_lon < dem_southwest.lon) )
548 /* else they overlap */
550 /**** End Overlap Check ****/
551 /* boxes to show where we have DEM instead of actually drawing the DEM.
552 * useful if we want to see what areas we have coverage for (if we want
553 * to get elevation data for a track) but don't want to cover the map.
557 /* draw a box if a DEM is loaded. in future I'd like to add an option for this
558 * this is useful if we want to see what areas we have dem for but don't want to
559 * cover the map (or maybe we just need translucent DEM?) */
561 VikCoord demne, demsw;
563 vik_coord_load_from_latlon(&demne, vik_viewport_get_coord_mode(vp), &dem_northeast);
564 vik_coord_load_from_latlon(&demsw, vik_viewport_get_coord_mode(vp), &dem_southwest);
566 vik_viewport_coord_to_screen ( vp, &demne, &x1, &y1 );
567 vik_viewport_coord_to_screen ( vp, &demsw, &x2, &y2 );
569 if ( x1 > vik_viewport_get_width(vp) ) x1=vik_viewport_get_width(vp);
570 if ( y2 > vik_viewport_get_height(vp) ) y2=vik_viewport_get_height(vp);
571 if ( x2 < 0 ) x2 = 0;
572 if ( y1 < 0 ) y1 = 0;
573 vik_viewport_draw_rectangle ( vp, gtk_widget_get_style(GTK_WIDGET(vp))->black_gc,
574 FALSE, x2, y1, x1-x2, y2-y1 );
579 if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
580 VikCoord tmp; /* TODO: don't use coord_load_from_latlon, especially if in latlon drawing mode */
582 gdouble max_lat_as, max_lon_as, min_lat_as, min_lon_as;
583 gdouble start_lat_as, end_lat_as, start_lon_as, end_lon_as;
585 gdouble start_lat, end_lat, start_lon, end_lon;
587 struct LatLon counter;
589 guint x, y, start_x, start_y;
593 guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 80 ); /* todo: smarter calculation. */
595 gdouble nscale_deg = dem->north_scale / ((gdouble) 3600);
596 gdouble escale_deg = dem->east_scale / ((gdouble) 3600);
598 max_lat_as = max_lat * 3600;
599 min_lat_as = min_lat * 3600;
600 max_lon_as = max_lon * 3600;
601 min_lon_as = min_lon * 3600;
603 start_lat_as = MAX(min_lat_as, dem->min_north);
604 end_lat_as = MIN(max_lat_as, dem->max_north);
605 start_lon_as = MAX(min_lon_as, dem->min_east);
606 end_lon_as = MIN(max_lon_as, dem->max_east);
608 start_lat = floor(start_lat_as / dem->north_scale) * nscale_deg;
609 end_lat = ceil (end_lat_as / dem->north_scale) * nscale_deg;
610 start_lon = floor(start_lon_as / dem->east_scale) * escale_deg;
611 end_lon = ceil (end_lon_as / dem->east_scale) * escale_deg;
613 vik_dem_east_north_to_xy ( dem, start_lon_as, start_lat_as, &start_x, &start_y );
614 guint gradient_skip_factor = 1;
615 if(vdl->type == DEM_TYPE_GRADIENT)
616 gradient_skip_factor = skip_factor;
618 /* verify sane elev interval */
619 if ( vdl->max_elev <= vdl->min_elev )
620 vdl->max_elev = vdl->min_elev + 1;
622 for ( x=start_x, counter.lon = start_lon; counter.lon <= end_lon+escale_deg*skip_factor; counter.lon += escale_deg * skip_factor, x += skip_factor ) {
623 // NOTE: ( counter.lon <= end_lon + ESCALE_DEG*SKIP_FACTOR ) is neccessary so in high zoom modes,
624 // the leftmost column does also get drawn, if the center point is out of viewport.
625 if ( x < dem->n_columns ) {
626 column = g_ptr_array_index ( dem->columns, x );
627 // get previous and next column. catch out-of-bound.
629 new_x -= gradient_skip_factor;
631 prevcolumn = g_ptr_array_index ( dem->columns, x+1);
633 prevcolumn = g_ptr_array_index ( dem->columns, new_x);
635 new_x += gradient_skip_factor;
636 if(new_x >= dem->n_columns)
637 nextcolumn = g_ptr_array_index ( dem->columns, x-1);
639 nextcolumn = g_ptr_array_index ( dem->columns, new_x);
641 for ( y=start_y, counter.lat = start_lat; counter.lat <= end_lat; counter.lat += nscale_deg * skip_factor, y += skip_factor ) {
642 if ( y > column->n_points )
645 elev = column->points[y];
647 // calculate bounding box for drawing
648 gint box_x, box_y, box_width, box_height;
651 box_c.lat += (nscale_deg * skip_factor)/2;
652 box_c.lon -= (escale_deg * skip_factor)/2;
653 vik_coord_load_from_latlon(&tmp, vik_viewport_get_coord_mode(vp), &box_c);
654 vik_viewport_coord_to_screen(vp, &tmp, &box_x, &box_y);
655 // catch box at borders
660 box_c.lat -= nscale_deg * skip_factor;
661 box_c.lon += escale_deg * skip_factor;
662 vik_coord_load_from_latlon(&tmp, vik_viewport_get_coord_mode(vp), &box_c);
663 vik_viewport_coord_to_screen(vp, &tmp, &box_width, &box_height);
666 // catch box at borders
667 if(box_width < 0 || box_height < 0)
668 continue; // skip this. this is out of our viewport anyway. FIXME: why?
670 gboolean below_minimum = FALSE;
671 if(vdl->type == DEM_TYPE_HEIGHT) {
672 if ( elev != VIK_DEM_INVALID_ELEVATION && elev < vdl->min_elev ) {
673 // Prevent 'elev - vdl->min_elev' from being negative so can safely use as array index
674 elev = ceil ( vdl->min_elev );
675 below_minimum = TRUE;
677 if ( elev != VIK_DEM_INVALID_ELEVATION && elev > vdl->max_elev )
678 elev = vdl->max_elev;
682 if(box_width < 0 || box_height < 0) // FIXME: why does this happen?
685 if(vdl->type == DEM_TYPE_GRADIENT) {
686 if( elev == VIK_DEM_INVALID_ELEVATION ) {
689 // calculate and sum gradient in all directions
693 // calculate gradient from height points all around the current one
694 new_y = y - gradient_skip_factor;
697 change += get_height_difference(elev, prevcolumn->points[new_y]);
698 change += get_height_difference(elev, column->points[new_y]);
699 change += get_height_difference(elev, nextcolumn->points[new_y]);
701 change += get_height_difference(elev, prevcolumn->points[y]);
702 change += get_height_difference(elev, nextcolumn->points[y]);
704 new_y = y + gradient_skip_factor;
705 if(new_y >= column->n_points)
707 change += get_height_difference(elev, prevcolumn->points[new_y]);
708 change += get_height_difference(elev, column->points[new_y]);
709 change += get_height_difference(elev, nextcolumn->points[new_y]);
711 change = change / ((skip_factor > 1) ? log(skip_factor) : 0.55); // FIXME: better calc.
713 if(change < vdl->min_elev)
714 // Prevent 'change - vdl->min_elev' from being negative so can safely use as array index
715 change = ceil ( vdl->min_elev );
717 if(change > vdl->max_elev)
718 change = vdl->max_elev;
720 // void vik_viewport_draw_rectangle ( VikViewport *vvp, GdkGC *gc, gboolean filled, gint x1, gint y1, gint x2, gint y2 );
721 vik_viewport_draw_rectangle(vp, vdl->gcsgradient[(gint)floor(((change - vdl->min_elev)/(vdl->max_elev - vdl->min_elev))*(DEM_N_GRADIENT_COLORS-2))+1], TRUE, box_x, box_y, box_width, box_height);
724 if(vdl->type == DEM_TYPE_HEIGHT) {
725 if ( elev == VIK_DEM_INVALID_ELEVATION )
726 ; /* don't draw it */
727 else if ( elev <= 0 || below_minimum )
728 /* If 'sea' colour or below the defined mininum draw in the configurable colour */
729 vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, box_x, box_y, box_width, box_height);
731 vik_viewport_draw_rectangle(vp, vdl->gcs[(gint)floor(((elev - vdl->min_elev)/(vdl->max_elev - vdl->min_elev))*(DEM_N_HEIGHT_COLORS-2))+1], TRUE, box_x, box_y, box_width, box_height);
738 } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
739 gdouble max_nor, max_eas, min_nor, min_eas;
740 gdouble start_nor, start_eas, end_nor, end_eas;
744 guint x, y, start_x, start_y;
746 VikCoord tmp; /* TODO: don't use coord_load_from_latlon, especially if in latlon drawing mode */
749 guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 10 ); /* todo: smarter calculation. */
751 VikCoord tleft, tright, bleft, bright;
753 vik_viewport_screen_to_coord ( vp, 0, 0, &tleft );
754 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), 0, &tright );
755 vik_viewport_screen_to_coord ( vp, 0, vik_viewport_get_height(vp), &bleft );
756 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), vik_viewport_get_height(vp), &bright );
759 vik_coord_convert(&tleft, VIK_COORD_UTM);
760 vik_coord_convert(&tright, VIK_COORD_UTM);
761 vik_coord_convert(&bleft, VIK_COORD_UTM);
762 vik_coord_convert(&bright, VIK_COORD_UTM);
764 max_nor = MAX(tleft.north_south, tright.north_south);
765 min_nor = MIN(bleft.north_south, bright.north_south);
766 max_eas = MAX(bright.east_west, tright.east_west);
767 min_eas = MIN(bleft.east_west, tleft.east_west);
769 start_nor = MAX(min_nor, dem->min_north);
770 end_nor = MIN(max_nor, dem->max_north);
771 if ( tleft.utm_zone == dem->utm_zone && bleft.utm_zone == dem->utm_zone
772 && (tleft.utm_letter >= 'N') == (dem->utm_letter >= 'N')
773 && (bleft.utm_letter >= 'N') == (dem->utm_letter >= 'N') ) /* if the utm zones/hemispheres are different, min_eas will be bogus */
774 start_eas = MAX(min_eas, dem->min_east);
776 start_eas = dem->min_east;
777 if ( tright.utm_zone == dem->utm_zone && bright.utm_zone == dem->utm_zone
778 && (tright.utm_letter >= 'N') == (dem->utm_letter >= 'N')
779 && (bright.utm_letter >= 'N') == (dem->utm_letter >= 'N') ) /* if the utm zones/hemispheres are different, min_eas will be bogus */
780 end_eas = MIN(max_eas, dem->max_east);
782 end_eas = dem->max_east;
784 start_nor = floor(start_nor / dem->north_scale) * dem->north_scale;
785 end_nor = ceil (end_nor / dem->north_scale) * dem->north_scale;
786 start_eas = floor(start_eas / dem->east_scale) * dem->east_scale;
787 end_eas = ceil (end_eas / dem->east_scale) * dem->east_scale;
789 vik_dem_east_north_to_xy ( dem, start_eas, start_nor, &start_x, &start_y );
791 /* TODO: why start_x and start_y are -1 -- rounding error from above? */
793 counter.zone = dem->utm_zone;
794 counter.letter = dem->utm_letter;
796 for ( x=start_x, counter.easting = start_eas; counter.easting <= end_eas; counter.easting += dem->east_scale * skip_factor, x += skip_factor ) {
797 if ( x > 0 && x < dem->n_columns ) {
798 column = g_ptr_array_index ( dem->columns, x );
799 for ( y=start_y, counter.northing = start_nor; counter.northing <= end_nor; counter.northing += dem->north_scale * skip_factor, y += skip_factor ) {
800 if ( y > column->n_points )
802 elev = column->points[y];
803 if ( elev != VIK_DEM_INVALID_ELEVATION && elev < vdl->min_elev )
805 if ( elev != VIK_DEM_INVALID_ELEVATION && elev > vdl->max_elev )
810 vik_coord_load_from_utm(&tmp, vik_viewport_get_coord_mode(vp), &counter);
811 vik_viewport_coord_to_screen(vp, &tmp, &a, &b);
812 if ( elev == VIK_DEM_INVALID_ELEVATION )
813 ; /* don't draw it */
814 else if ( elev <= 0 )
815 vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, a-1, b-1, 2, 2 );
817 vik_viewport_draw_rectangle(vp, vdl->gcs[(gint)floor((elev - vdl->min_elev)/(vdl->max_elev - vdl->min_elev)*(DEM_N_HEIGHT_COLORS-2))+1], TRUE, a-1, b-1, 2, 2 );
825 /* return the continent for the specified lat, lon */
827 static const gchar *srtm_continent_dir ( gint lat, gint lon )
829 extern const char *_srtm_continent_data[];
830 static GHashTable *srtm_continent = NULL;
831 const gchar *continent;
834 if (!srtm_continent) {
837 srtm_continent = g_hash_table_new(g_str_hash, g_str_equal);
838 s = _srtm_continent_data;
839 while (*s != (gchar *)-1) {
842 g_hash_table_insert(srtm_continent, (gpointer) *s, (gpointer) continent);
848 g_snprintf(name, sizeof(name), "%c%02d%c%03d",
849 (lat >= 0) ? 'N' : 'S', ABS(lat),
850 (lon >= 0) ? 'E' : 'W', ABS(lon));
852 return(g_hash_table_lookup(srtm_continent, name));
855 static void dem_layer_draw ( VikDEMLayer *vdl, VikViewport *vp )
857 GList *dems_iter = vdl->files;
861 /* search for SRTM3 90m */
863 if ( vdl->source == DEM_SOURCE_SRTM )
864 srtm_draw_existence ( vp );
865 #ifdef VIK_CONFIG_DEM24K
866 else if ( vdl->source == DEM_SOURCE_DEM24K )
867 dem24k_draw_existence ( vp );
870 while ( dems_iter ) {
871 dem = a_dems_get ( (const char *) (dems_iter->data) );
873 vik_dem_layer_draw_dem ( vdl, vp, dem );
874 dems_iter = dems_iter->next;
878 static void dem_layer_free ( VikDEMLayer *vdl )
882 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ )
883 g_object_unref ( vdl->gcs[i] );
886 if ( vdl->gcsgradient )
887 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
888 g_object_unref ( vdl->gcsgradient[i] );
889 g_free ( vdl->gcsgradient );
891 a_dems_list_free ( vdl->files );
894 VikDEMLayer *dem_layer_create ( VikViewport *vp )
896 VikDEMLayer *vdl = dem_layer_new ( vp );
899 /* TODO: share GCS between layers */
900 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ ) {
902 vdl->gcs[i] = vik_viewport_new_gc ( vp, dem_height_colors[i], UNUSED_LINE_THICKNESS );
904 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
905 vdl->gcsgradient[i] = vik_viewport_new_gc ( vp, dem_gradient_colors[i], UNUSED_LINE_THICKNESS );
909 /**************************************************************
910 **** SOURCES & DOWNLOADING
911 **************************************************************/
917 VikDEMLayer *vdl; /* NULL if not alive */
923 /**************************************************
925 **************************************************/
927 static void srtm_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
930 const gchar *continent_dir;
932 intlat = (int)floor(p->lat);
933 intlon = (int)floor(p->lon);
934 continent_dir = srtm_continent_dir(intlat, intlon);
936 if (!continent_dir) {
938 gchar *msg = g_strdup_printf ( _("No SRTM data available for %f, %f"), p->lat, p->lon );
939 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(p->vdl), msg, VIK_STATUSBAR_INFO );
945 gchar *src_fn = g_strdup_printf("%s%s/%c%02d%c%03d.hgt.zip",
948 (intlat >= 0) ? 'N' : 'S',
950 (intlon >= 0) ? 'E' : 'W',
953 static DownloadMapOptions options = { FALSE, FALSE, NULL, 0, a_check_map_file, NULL };
954 a_http_download_get_url ( SRTM_HTTP_SITE, src_fn, p->dest, &options, NULL );
958 static gchar *srtm_lat_lon_to_dest_fn ( gdouble lat, gdouble lon )
961 const gchar *continent_dir;
963 intlat = (int)floor(lat);
964 intlon = (int)floor(lon);
965 continent_dir = srtm_continent_dir(intlat, intlon);
968 continent_dir = "nowhere";
970 return g_strdup_printf("srtm3-%s%s%c%02d%c%03d.hgt.zip",
973 (intlat >= 0) ? 'N' : 'S',
975 (intlon >= 0) ? 'E' : 'W',
980 /* TODO: generalize */
981 static void srtm_draw_existence ( VikViewport *vp )
983 gdouble max_lat, max_lon, min_lat, min_lon;
984 gchar buf[strlen(MAPS_CACHE_DIR)+strlen(SRTM_CACHE_TEMPLATE)+30];
987 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
989 for (i = floor(min_lat); i <= floor(max_lat); i++) {
990 for (j = floor(min_lon); j <= floor(max_lon); j++) {
991 const gchar *continent_dir;
992 if ((continent_dir = srtm_continent_dir(i, j)) == NULL)
994 g_snprintf(buf, sizeof(buf), SRTM_CACHE_TEMPLATE,
998 (i >= 0) ? 'N' : 'S',
1000 (j >= 0) ? 'E' : 'W',
1002 if ( g_file_test(buf, G_FILE_TEST_EXISTS ) == TRUE ) {
1004 gint x1, y1, x2, y2;
1007 sw.mode = VIK_COORD_LATLON;
1008 ne.north_south = i+1;
1010 ne.mode = VIK_COORD_LATLON;
1011 vik_viewport_coord_to_screen ( vp, &sw, &x1, &y1 );
1012 vik_viewport_coord_to_screen ( vp, &ne, &x2, &y2 );
1013 if ( x1 < 0 ) x1 = 0;
1014 if ( y2 < 0 ) y2 = 0;
1015 vik_viewport_draw_rectangle ( vp, gtk_widget_get_style(GTK_WIDGET(vp))->black_gc,
1016 FALSE, x1, y2, x2-x1, y1-y2 );
1023 /**************************************************
1024 * SOURCE: USGS 24K *
1025 **************************************************/
1027 #ifdef VIK_CONFIG_DEM24K
1029 static void dem24k_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
1031 /* TODO: dest dir */
1032 gchar *cmdline = g_strdup_printf("%s %.03f %.03f",
1033 DEM24K_DOWNLOAD_SCRIPT,
1036 /* FIX: don't use system, use execv or something. check for existence */
1041 static gchar *dem24k_lat_lon_to_dest_fn ( gdouble lat, gdouble lon )
1043 return g_strdup_printf("dem24k/%d/%d/%.03f,%.03f.dem",
1050 /* TODO: generalize */
1051 static void dem24k_draw_existence ( VikViewport *vp )
1053 gdouble max_lat, max_lon, min_lat, min_lon;
1054 gchar buf[strlen(MAPS_CACHE_DIR)+40];
1057 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
1059 for (i = floor(min_lat*8)/8; i <= floor(max_lat*8)/8; i+=0.125) {
1060 /* check lat dir first -- faster */
1061 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/",
1064 if ( g_file_test(buf, G_FILE_TEST_EXISTS) == FALSE )
1066 for (j = floor(min_lon*8)/8; j <= floor(max_lon*8)/8; j+=0.125) {
1067 /* check lon dir first -- faster */
1068 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/%d/",
1072 if ( g_file_test(buf, G_FILE_TEST_EXISTS) == FALSE )
1074 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/%d/%.03f,%.03f.dem",
1080 if ( g_file_test(buf, G_FILE_TEST_EXISTS ) == TRUE ) {
1082 gint x1, y1, x2, y2;
1084 sw.east_west = j-0.125;
1085 sw.mode = VIK_COORD_LATLON;
1086 ne.north_south = i+0.125;
1088 ne.mode = VIK_COORD_LATLON;
1089 vik_viewport_coord_to_screen ( vp, &sw, &x1, &y1 );
1090 vik_viewport_coord_to_screen ( vp, &ne, &x2, &y2 );
1091 if ( x1 < 0 ) x1 = 0;
1092 if ( y2 < 0 ) y2 = 0;
1093 vik_viewport_draw_rectangle ( vp, gtk_widget_get_style(GTK_WIDGET(vp))->black_gc,
1094 FALSE, x1, y2, x2-x1, y1-y2 );
1101 /**************************************************
1102 * SOURCES -- DOWNLOADING & IMPORTING TOOL *
1103 **************************************************
1106 static void weak_ref_cb ( gpointer ptr, GObject * dead_vdl )
1108 DEMDownloadParams *p = ptr;
1109 g_mutex_lock ( p->mutex );
1111 g_mutex_unlock ( p->mutex );
1114 /* Try to add file full_path.
1115 * filename will be copied.
1116 * returns FALSE if file does not exists, TRUE otherwise.
1118 static gboolean dem_layer_add_file ( VikDEMLayer *vdl, const gchar *filename )
1120 if ( g_file_test(filename, G_FILE_TEST_EXISTS) == TRUE ) {
1121 /* only load if file size is not 0 (not in progress) */
1123 stat ( filename, &sb );
1125 gchar *duped_path = g_strdup(filename);
1126 vdl->files = g_list_prepend ( vdl->files, duped_path );
1127 a_dems_load ( duped_path );
1128 g_debug("%s: %s", __FUNCTION__, duped_path);
1135 static void dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
1137 if ( p->source == DEM_SOURCE_SRTM )
1138 srtm_dem_download_thread ( p, threaddata );
1139 #ifdef VIK_CONFIG_DEM24K
1140 else if ( p->source == DEM_SOURCE_DEM24K )
1141 dem24k_dem_download_thread ( p, threaddata );
1146 //gdk_threads_enter();
1147 g_mutex_lock ( p->mutex );
1149 g_object_weak_unref ( G_OBJECT(p->vdl), weak_ref_cb, p );
1151 if ( dem_layer_add_file ( p->vdl, p->dest ) )
1152 vik_layer_emit_update ( VIK_LAYER(p->vdl) ); // NB update from background thread
1154 g_mutex_unlock ( p->mutex );
1155 //gdk_threads_leave();
1159 static void free_dem_download_params ( DEMDownloadParams *p )
1161 g_mutex_free ( p->mutex );
1166 static gpointer dem_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1172 * Display a simple dialog with information about the DEM file at this location
1174 static void dem_layer_file_info ( GtkWidget *widget, struct LatLon *ll )
1176 gint intlat, intlon;
1177 const gchar *continent_dir;
1179 intlat = (int)floor(ll->lat);
1180 intlon = (int)floor(ll->lon);
1181 continent_dir = srtm_continent_dir(intlat, intlon);
1183 gchar *source = NULL;
1184 if ( continent_dir )
1185 source = g_strdup_printf ( "http:/%s%s/%c%02d%c%03d.hgt.zip",
1188 (intlat >= 0) ? 'N' : 'S',
1190 (intlon >= 0) ? 'E' : 'W',
1193 // Probably not over any land...
1194 source = g_strdup ( _("No DEM File Available") );
1196 gchar *filename = NULL;
1197 gchar *dem_file = NULL;
1198 #ifdef VIK_CONFIG_DEM24K
1199 dem_file = dem24k_lat_lon_to_dest_fn ( ll->lat, ll->lon );
1201 dem_file = srtm_lat_lon_to_dest_fn ( ll->lat, ll->lon );
1203 gchar *message = NULL;
1205 filename = g_strdup_printf ( "%s%s", MAPS_CACHE_DIR, dem_file );
1207 if ( g_file_test ( filename, G_FILE_TEST_EXISTS ) ) {
1208 // Get some timestamp information of the file
1209 struct stat stat_buf;
1210 if ( g_stat ( filename, &stat_buf ) == 0 ) {
1212 strftime ( time_buf, sizeof(time_buf), "%c", gmtime((const time_t *)&stat_buf.st_mtime) );
1213 message = g_strdup_printf ( _("\nSource: %s\n\nDEM File: %s\nDEM File Timestamp: %s"), source, filename, time_buf );
1217 message = g_strdup_printf ( _("Source: %s\n\nNo DEM File!"), source );
1220 a_dialog_info_msg ( GTK_WINDOW(gtk_widget_get_toplevel(widget)), message );
1224 g_free ( dem_file );
1225 g_free ( filename );
1228 static gboolean dem_layer_download_release ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp )
1231 static struct LatLon ll;
1234 gchar *dem_file = NULL;
1236 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1237 vik_coord_to_latlon ( &coord, &ll );
1240 if ( vdl->source == DEM_SOURCE_SRTM )
1241 dem_file = srtm_lat_lon_to_dest_fn ( ll.lat, ll.lon );
1242 #ifdef VIK_CONFIG_DEM24K
1243 else if ( vdl->source == DEM_SOURCE_DEM24K )
1244 dem_file = dem24k_lat_lon_to_dest_fn ( ll.lat, ll.lon );
1250 full_path = g_strdup_printf("%s%s", MAPS_CACHE_DIR, dem_file );
1252 g_debug("%s: %s", __FUNCTION__, full_path);
1254 if ( event->button == 1 ) {
1255 // TODO: check if already in filelist
1256 if ( ! dem_layer_add_file(vdl, full_path) ) {
1257 gchar *tmp = g_strdup_printf ( _("Downloading DEM %s"), dem_file );
1258 DEMDownloadParams *p = g_malloc(sizeof(DEMDownloadParams));
1259 p->dest = g_strdup(full_path);
1263 p->mutex = g_mutex_new();
1264 p->source = vdl->source;
1265 g_object_weak_ref(G_OBJECT(p->vdl), weak_ref_cb, p );
1267 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vdl), tmp,
1268 (vik_thr_func) dem_download_thread, p,
1269 (vik_thr_free_func) free_dem_download_params, NULL, 1 );
1274 vik_layer_emit_update ( VIK_LAYER(vdl) );
1277 if ( !vdl->right_click_menu ) {
1279 vdl->right_click_menu = GTK_MENU ( gtk_menu_new () );
1281 item = gtk_image_menu_item_new_with_mnemonic ( _("_Show DEM File Information") );
1282 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INFO, GTK_ICON_SIZE_MENU) );
1283 g_signal_connect ( G_OBJECT(item), "activate", G_CALLBACK(dem_layer_file_info), &ll );
1284 gtk_menu_shell_append (GTK_MENU_SHELL(vdl->right_click_menu), item);
1287 gtk_menu_popup ( vdl->right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1288 gtk_widget_show_all ( GTK_WIDGET(vdl->right_click_menu) );
1291 g_free ( dem_file );
1292 g_free ( full_path );
1297 static gboolean dem_layer_download_click ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp )
1299 /* choose & keep track of cache dir
1300 * download in background thread
1301 * download over area */