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,
229 (VikLayerFuncReadFileData) NULL,
230 (VikLayerFuncWriteFileData) NULL,
232 (VikLayerFuncDeleteItem) NULL,
233 (VikLayerFuncCutItem) NULL,
234 (VikLayerFuncCopyItem) NULL,
235 (VikLayerFuncPasteItem) NULL,
236 (VikLayerFuncFreeCopiedItem) NULL,
237 (VikLayerFuncDragDropRequest) NULL,
239 (VikLayerFuncSelectClick) NULL,
240 (VikLayerFuncSelectMove) NULL,
241 (VikLayerFuncSelectRelease) NULL,
242 (VikLayerFuncSelectedViewportMenu) NULL,
245 struct _VikDEMLayer {
256 // right click menu only stuff - similar to mapslayer
257 GtkMenu *right_click_menu;
260 GType vik_dem_layer_get_type ()
262 static GType vdl_type = 0;
266 static const GTypeInfo vdl_info =
268 sizeof (VikDEMLayerClass),
269 NULL, /* base_init */
270 NULL, /* base_finalize */
271 NULL, /* class init */
272 NULL, /* class_finalize */
273 NULL, /* class_data */
274 sizeof (VikDEMLayer),
276 NULL /* instance init */
278 vdl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikDEMLayer", &vdl_info, 0 );
284 static const gchar* dem_layer_tooltip( VikDEMLayer *vdl )
286 static gchar tmp_buf[100];
287 g_snprintf (tmp_buf, sizeof(tmp_buf), _("Number of files: %d"), g_list_length (vdl->files));
291 static void dem_layer_marshall( VikDEMLayer *vdl, guint8 **data, gint *len )
293 vik_layer_marshall_params ( VIK_LAYER(vdl), data, len );
296 static VikDEMLayer *dem_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
298 VikDEMLayer *rv = dem_layer_new ( vvp );
301 /* TODO: share GCS between layers */
302 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ ) {
304 rv->gcs[i] = vik_viewport_new_gc_from_color ( vvp, &(rv->color), UNUSED_LINE_THICKNESS );
306 rv->gcs[i] = vik_viewport_new_gc ( vvp, dem_height_colors[i], UNUSED_LINE_THICKNESS );
308 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
309 rv->gcsgradient[i] = vik_viewport_new_gc ( vvp, dem_gradient_colors[i], UNUSED_LINE_THICKNESS );
311 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
315 /* Structure for DEM data used in background thread */
318 } dem_load_thread_data;
321 * Function for starting the DEM file loading as a background thread
323 static int dem_layer_load_list_thread ( dem_load_thread_data *dltd, gpointer threaddata )
325 int result = 0; // Default to good
327 if ( a_dems_load_list ( &(dltd->vdl->files), threaddata ) ) {
332 // ATM as each file is processed the screen is not updated (no mechanism exposed to a_dems_load_list)
333 // Thus force draw only at the end, as loading is complete/aborted
334 //gdk_threads_enter();
335 // Test is helpful to prevent Gtk-CRITICAL warnings if the program is exitted whilst loading
336 if ( IS_VIK_LAYER(dltd->vdl) )
337 vik_layer_emit_update ( VIK_LAYER(dltd->vdl) ); // NB update from background thread
338 //gdk_threads_leave();
343 static void dem_layer_thread_data_free ( dem_load_thread_data *data )
349 static void dem_layer_thread_cancel ( dem_load_thread_data *data )
352 // Instead of freeing the list, leave it as partially processed
353 // Thus we can see/use what was done
357 * Process the list of DEM files and convert each one to a relative path
359 static GList *dem_layer_convert_to_relative_filenaming ( GList *files )
361 gchar *cwd = g_get_current_dir();
365 GList *relfiles = NULL;
368 gchar *file = g_strdup ( file_GetRelativeFilename ( cwd, files->data ) );
369 relfiles = g_list_prepend ( relfiles, file );
376 // Replacing current list, so delete old values first.
379 g_free ( iter->data );
382 g_list_free ( files );
390 gboolean dem_layer_set_param ( VikDEMLayer *vdl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
394 case PARAM_COLOR: vdl->color = data.c; gdk_gc_set_rgb_fg_color ( vdl->gcs[0], &(vdl->color) ); break;
395 case PARAM_SOURCE: vdl->source = data.u; break;
396 case PARAM_TYPE: vdl->type = data.u; break;
398 /* Convert to store internally
399 NB file operation always in internal units (metres) */
400 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
401 vdl->min_elev = VIK_FEET_TO_METERS(data.d);
403 vdl->min_elev = data.d;
406 /* Convert to store internally
407 NB file operation always in internal units (metres) */
408 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
409 vdl->max_elev = VIK_FEET_TO_METERS(data.d);
411 vdl->max_elev = data.d;
415 // Clear out old settings - if any commonalities with new settings they will have to be read again
416 a_dems_list_free ( vdl->files );
417 // Set file list so any other intermediate screen drawing updates will show currently loaded DEMs by the working thread
418 vdl->files = data.sl;
419 // No need for thread if no files
422 dem_load_thread_data *dltd = g_malloc ( sizeof(dem_load_thread_data) );
424 dltd->vdl->files = data.sl;
426 a_background_thread ( VIK_GTK_WINDOW_FROM_WIDGET(vp),
428 (vik_thr_func) dem_layer_load_list_thread,
430 (vik_thr_free_func) dem_layer_thread_data_free,
431 (vik_thr_free_func) dem_layer_thread_cancel,
432 g_list_length ( data.sl ) ); // Number of DEM files
440 static VikLayerParamData dem_layer_get_param ( VikDEMLayer *vdl, guint16 id, gboolean is_file_operation )
442 VikLayerParamData rv;
447 if ( is_file_operation )
448 // Save in relative format if necessary
449 if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE )
450 rv.sl = dem_layer_convert_to_relative_filenaming ( rv.sl );
452 case PARAM_SOURCE: rv.u = vdl->source; break;
453 case PARAM_TYPE: rv.u = vdl->type; break;
454 case PARAM_COLOR: rv.c = vdl->color; break;
456 /* Convert for display in desired units
457 NB file operation always in internal units (metres) */
458 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
459 rv.d = VIK_METERS_TO_FEET(vdl->min_elev);
461 rv.d = vdl->min_elev;
464 /* Convert for display in desired units
465 NB file operation always in internal units (metres) */
466 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
467 rv.d = VIK_METERS_TO_FEET(vdl->max_elev);
469 rv.d = vdl->max_elev;
475 static void dem_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file )
477 /* nothing ATM, but keep in case it's needed the future */
480 static VikDEMLayer *dem_layer_new ( VikViewport *vvp )
482 VikDEMLayer *vdl = VIK_DEM_LAYER ( g_object_new ( VIK_DEM_LAYER_TYPE, NULL ) );
484 vik_layer_set_type ( VIK_LAYER(vdl), VIK_LAYER_DEM );
488 vdl->gcs = g_malloc(sizeof(GdkGC *)*DEM_N_HEIGHT_COLORS);
489 vdl->gcsgradient = g_malloc(sizeof(GdkGC *)*DEM_N_GRADIENT_COLORS);
490 /* make new gcs only if we need it (copy layer -> use old) */
492 // Ensure the base GC is available so the default colour can be applied
493 if ( vvp ) vdl->gcs[0] = vik_viewport_new_gc ( vvp, "#0000FF", 1 );
495 vik_layer_set_defaults ( VIK_LAYER(vdl), vvp );
501 static inline guint16 get_height_difference(gint16 elev, gint16 new_elev)
503 if(new_elev == VIK_DEM_INVALID_ELEVATION)
506 return abs(new_elev - elev);
510 static void vik_dem_layer_draw_dem ( VikDEMLayer *vdl, VikViewport *vp, VikDEM *dem )
512 VikDEMColumn *column, *prevcolumn, *nextcolumn;
514 struct LatLon dem_northeast, dem_southwest;
515 gdouble max_lat, max_lon, min_lat, min_lon;
517 /**** Check if viewport and DEM data overlap ****/
519 /* get min, max lat/lon of viewport */
520 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
522 /* get min, max lat/lon of DEM data */
523 if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
524 dem_northeast.lat = dem->max_north / 3600.0;
525 dem_northeast.lon = dem->max_east / 3600.0;
526 dem_southwest.lat = dem->min_north / 3600.0;
527 dem_southwest.lon = dem->min_east / 3600.0;
528 } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
529 struct UTM dem_northeast_utm, dem_southwest_utm;
530 dem_northeast_utm.northing = dem->max_north;
531 dem_northeast_utm.easting = dem->max_east;
532 dem_southwest_utm.northing = dem->min_north;
533 dem_southwest_utm.easting = dem->min_east;
534 dem_northeast_utm.zone = dem_southwest_utm.zone = dem->utm_zone;
535 dem_northeast_utm.letter = dem_southwest_utm.letter = dem->utm_letter;
537 a_coords_utm_to_latlon(&dem_northeast_utm, &dem_northeast);
538 a_coords_utm_to_latlon(&dem_southwest_utm, &dem_southwest);
541 if ( (max_lat > dem_northeast.lat && min_lat > dem_northeast.lat) ||
542 (max_lat < dem_southwest.lat && min_lat < dem_southwest.lat) )
544 else if ( (max_lon > dem_northeast.lon && min_lon > dem_northeast.lon) ||
545 (max_lon < dem_southwest.lon && min_lon < dem_southwest.lon) )
547 /* else they overlap */
549 /**** End Overlap Check ****/
550 /* boxes to show where we have DEM instead of actually drawing the DEM.
551 * useful if we want to see what areas we have coverage for (if we want
552 * to get elevation data for a track) but don't want to cover the map.
556 /* draw a box if a DEM is loaded. in future I'd like to add an option for this
557 * this is useful if we want to see what areas we have dem for but don't want to
558 * cover the map (or maybe we just need translucent DEM?) */
560 VikCoord demne, demsw;
562 vik_coord_load_from_latlon(&demne, vik_viewport_get_coord_mode(vp), &dem_northeast);
563 vik_coord_load_from_latlon(&demsw, vik_viewport_get_coord_mode(vp), &dem_southwest);
565 vik_viewport_coord_to_screen ( vp, &demne, &x1, &y1 );
566 vik_viewport_coord_to_screen ( vp, &demsw, &x2, &y2 );
568 if ( x1 > vik_viewport_get_width(vp) ) x1=vik_viewport_get_width(vp);
569 if ( y2 > vik_viewport_get_height(vp) ) y2=vik_viewport_get_height(vp);
570 if ( x2 < 0 ) x2 = 0;
571 if ( y1 < 0 ) y1 = 0;
572 vik_viewport_draw_rectangle ( vp, gtk_widget_get_style(GTK_WIDGET(vp))->black_gc,
573 FALSE, x2, y1, x1-x2, y2-y1 );
578 if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
579 VikCoord tmp; /* TODO: don't use coord_load_from_latlon, especially if in latlon drawing mode */
581 gdouble max_lat_as, max_lon_as, min_lat_as, min_lon_as;
582 gdouble start_lat_as, end_lat_as, start_lon_as, end_lon_as;
584 gdouble start_lat, end_lat, start_lon, end_lon;
586 struct LatLon counter;
588 guint x, y, start_x, start_y;
592 guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 80 ); /* todo: smarter calculation. */
594 gdouble nscale_deg = dem->north_scale / ((gdouble) 3600);
595 gdouble escale_deg = dem->east_scale / ((gdouble) 3600);
597 max_lat_as = max_lat * 3600;
598 min_lat_as = min_lat * 3600;
599 max_lon_as = max_lon * 3600;
600 min_lon_as = min_lon * 3600;
602 start_lat_as = MAX(min_lat_as, dem->min_north);
603 end_lat_as = MIN(max_lat_as, dem->max_north);
604 start_lon_as = MAX(min_lon_as, dem->min_east);
605 end_lon_as = MIN(max_lon_as, dem->max_east);
607 start_lat = floor(start_lat_as / dem->north_scale) * nscale_deg;
608 end_lat = ceil (end_lat_as / dem->north_scale) * nscale_deg;
609 start_lon = floor(start_lon_as / dem->east_scale) * escale_deg;
610 end_lon = ceil (end_lon_as / dem->east_scale) * escale_deg;
612 vik_dem_east_north_to_xy ( dem, start_lon_as, start_lat_as, &start_x, &start_y );
613 guint gradient_skip_factor = 1;
614 if(vdl->type == DEM_TYPE_GRADIENT)
615 gradient_skip_factor = skip_factor;
617 /* verify sane elev interval */
618 if ( vdl->max_elev <= vdl->min_elev )
619 vdl->max_elev = vdl->min_elev + 1;
621 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 ) {
622 // NOTE: ( counter.lon <= end_lon + ESCALE_DEG*SKIP_FACTOR ) is neccessary so in high zoom modes,
623 // the leftmost column does also get drawn, if the center point is out of viewport.
624 if ( x < dem->n_columns ) {
625 column = g_ptr_array_index ( dem->columns, x );
626 // get previous and next column. catch out-of-bound.
628 new_x -= gradient_skip_factor;
630 prevcolumn = g_ptr_array_index ( dem->columns, x+1);
632 prevcolumn = g_ptr_array_index ( dem->columns, new_x);
634 new_x += gradient_skip_factor;
635 if(new_x >= dem->n_columns)
636 nextcolumn = g_ptr_array_index ( dem->columns, x-1);
638 nextcolumn = g_ptr_array_index ( dem->columns, new_x);
640 for ( y=start_y, counter.lat = start_lat; counter.lat <= end_lat; counter.lat += nscale_deg * skip_factor, y += skip_factor ) {
641 if ( y > column->n_points )
644 elev = column->points[y];
646 // calculate bounding box for drawing
647 gint box_x, box_y, box_width, box_height;
650 box_c.lat += (nscale_deg * skip_factor)/2;
651 box_c.lon -= (escale_deg * skip_factor)/2;
652 vik_coord_load_from_latlon(&tmp, vik_viewport_get_coord_mode(vp), &box_c);
653 vik_viewport_coord_to_screen(vp, &tmp, &box_x, &box_y);
654 // catch box at borders
659 box_c.lat -= nscale_deg * skip_factor;
660 box_c.lon += escale_deg * skip_factor;
661 vik_coord_load_from_latlon(&tmp, vik_viewport_get_coord_mode(vp), &box_c);
662 vik_viewport_coord_to_screen(vp, &tmp, &box_width, &box_height);
665 // catch box at borders
666 if(box_width < 0 || box_height < 0)
667 continue; // skip this. this is out of our viewport anyway. FIXME: why?
669 gboolean below_minimum = FALSE;
670 if(vdl->type == DEM_TYPE_HEIGHT) {
671 if ( elev != VIK_DEM_INVALID_ELEVATION && elev < vdl->min_elev ) {
672 // Prevent 'elev - vdl->min_elev' from being negative so can safely use as array index
673 elev = ceil ( vdl->min_elev );
674 below_minimum = TRUE;
676 if ( elev != VIK_DEM_INVALID_ELEVATION && elev > vdl->max_elev )
677 elev = vdl->max_elev;
681 if(box_width < 0 || box_height < 0) // FIXME: why does this happen?
684 if(vdl->type == DEM_TYPE_GRADIENT) {
685 if( elev == VIK_DEM_INVALID_ELEVATION ) {
688 // calculate and sum gradient in all directions
692 // calculate gradient from height points all around the current one
693 new_y = y - gradient_skip_factor;
696 change += get_height_difference(elev, prevcolumn->points[new_y]);
697 change += get_height_difference(elev, column->points[new_y]);
698 change += get_height_difference(elev, nextcolumn->points[new_y]);
700 change += get_height_difference(elev, prevcolumn->points[y]);
701 change += get_height_difference(elev, nextcolumn->points[y]);
703 new_y = y + gradient_skip_factor;
704 if(new_y >= column->n_points)
706 change += get_height_difference(elev, prevcolumn->points[new_y]);
707 change += get_height_difference(elev, column->points[new_y]);
708 change += get_height_difference(elev, nextcolumn->points[new_y]);
710 change = change / ((skip_factor > 1) ? log(skip_factor) : 0.55); // FIXME: better calc.
712 if(change < vdl->min_elev)
713 // Prevent 'change - vdl->min_elev' from being negative so can safely use as array index
714 change = ceil ( vdl->min_elev );
716 if(change > vdl->max_elev)
717 change = vdl->max_elev;
719 // void vik_viewport_draw_rectangle ( VikViewport *vvp, GdkGC *gc, gboolean filled, gint x1, gint y1, gint x2, gint y2 );
720 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);
723 if(vdl->type == DEM_TYPE_HEIGHT) {
724 if ( elev == VIK_DEM_INVALID_ELEVATION )
725 ; /* don't draw it */
726 else if ( elev <= 0 || below_minimum )
727 /* If 'sea' colour or below the defined mininum draw in the configurable colour */
728 vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, box_x, box_y, box_width, box_height);
730 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);
737 } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
738 gdouble max_nor, max_eas, min_nor, min_eas;
739 gdouble start_nor, start_eas, end_nor, end_eas;
743 guint x, y, start_x, start_y;
745 VikCoord tmp; /* TODO: don't use coord_load_from_latlon, especially if in latlon drawing mode */
748 guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 10 ); /* todo: smarter calculation. */
750 VikCoord tleft, tright, bleft, bright;
752 vik_viewport_screen_to_coord ( vp, 0, 0, &tleft );
753 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), 0, &tright );
754 vik_viewport_screen_to_coord ( vp, 0, vik_viewport_get_height(vp), &bleft );
755 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), vik_viewport_get_height(vp), &bright );
758 vik_coord_convert(&tleft, VIK_COORD_UTM);
759 vik_coord_convert(&tright, VIK_COORD_UTM);
760 vik_coord_convert(&bleft, VIK_COORD_UTM);
761 vik_coord_convert(&bright, VIK_COORD_UTM);
763 max_nor = MAX(tleft.north_south, tright.north_south);
764 min_nor = MIN(bleft.north_south, bright.north_south);
765 max_eas = MAX(bright.east_west, tright.east_west);
766 min_eas = MIN(bleft.east_west, tleft.east_west);
768 start_nor = MAX(min_nor, dem->min_north);
769 end_nor = MIN(max_nor, dem->max_north);
770 if ( tleft.utm_zone == dem->utm_zone && bleft.utm_zone == dem->utm_zone
771 && (tleft.utm_letter >= 'N') == (dem->utm_letter >= 'N')
772 && (bleft.utm_letter >= 'N') == (dem->utm_letter >= 'N') ) /* if the utm zones/hemispheres are different, min_eas will be bogus */
773 start_eas = MAX(min_eas, dem->min_east);
775 start_eas = dem->min_east;
776 if ( tright.utm_zone == dem->utm_zone && bright.utm_zone == dem->utm_zone
777 && (tright.utm_letter >= 'N') == (dem->utm_letter >= 'N')
778 && (bright.utm_letter >= 'N') == (dem->utm_letter >= 'N') ) /* if the utm zones/hemispheres are different, min_eas will be bogus */
779 end_eas = MIN(max_eas, dem->max_east);
781 end_eas = dem->max_east;
783 start_nor = floor(start_nor / dem->north_scale) * dem->north_scale;
784 end_nor = ceil (end_nor / dem->north_scale) * dem->north_scale;
785 start_eas = floor(start_eas / dem->east_scale) * dem->east_scale;
786 end_eas = ceil (end_eas / dem->east_scale) * dem->east_scale;
788 vik_dem_east_north_to_xy ( dem, start_eas, start_nor, &start_x, &start_y );
790 /* TODO: why start_x and start_y are -1 -- rounding error from above? */
792 counter.zone = dem->utm_zone;
793 counter.letter = dem->utm_letter;
795 for ( x=start_x, counter.easting = start_eas; counter.easting <= end_eas; counter.easting += dem->east_scale * skip_factor, x += skip_factor ) {
796 if ( x > 0 && x < dem->n_columns ) {
797 column = g_ptr_array_index ( dem->columns, x );
798 for ( y=start_y, counter.northing = start_nor; counter.northing <= end_nor; counter.northing += dem->north_scale * skip_factor, y += skip_factor ) {
799 if ( y > column->n_points )
801 elev = column->points[y];
802 if ( elev != VIK_DEM_INVALID_ELEVATION && elev < vdl->min_elev )
804 if ( elev != VIK_DEM_INVALID_ELEVATION && elev > vdl->max_elev )
809 vik_coord_load_from_utm(&tmp, vik_viewport_get_coord_mode(vp), &counter);
810 vik_viewport_coord_to_screen(vp, &tmp, &a, &b);
811 if ( elev == VIK_DEM_INVALID_ELEVATION )
812 ; /* don't draw it */
813 else if ( elev <= 0 )
814 vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, a-1, b-1, 2, 2 );
816 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 );
824 /* return the continent for the specified lat, lon */
826 static const gchar *srtm_continent_dir ( gint lat, gint lon )
828 extern const char *_srtm_continent_data[];
829 static GHashTable *srtm_continent = NULL;
830 const gchar *continent;
833 if (!srtm_continent) {
836 srtm_continent = g_hash_table_new(g_str_hash, g_str_equal);
837 s = _srtm_continent_data;
838 while (*s != (gchar *)-1) {
841 g_hash_table_insert(srtm_continent, (gpointer) *s, (gpointer) continent);
847 g_snprintf(name, sizeof(name), "%c%02d%c%03d",
848 (lat >= 0) ? 'N' : 'S', ABS(lat),
849 (lon >= 0) ? 'E' : 'W', ABS(lon));
851 return(g_hash_table_lookup(srtm_continent, name));
854 static void dem_layer_draw ( VikDEMLayer *vdl, VikViewport *vp )
856 GList *dems_iter = vdl->files;
860 /* search for SRTM3 90m */
862 if ( vdl->source == DEM_SOURCE_SRTM )
863 srtm_draw_existence ( vp );
864 #ifdef VIK_CONFIG_DEM24K
865 else if ( vdl->source == DEM_SOURCE_DEM24K )
866 dem24k_draw_existence ( vp );
869 while ( dems_iter ) {
870 dem = a_dems_get ( (const char *) (dems_iter->data) );
872 vik_dem_layer_draw_dem ( vdl, vp, dem );
873 dems_iter = dems_iter->next;
877 static void dem_layer_free ( VikDEMLayer *vdl )
881 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ )
882 g_object_unref ( vdl->gcs[i] );
885 if ( vdl->gcsgradient )
886 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
887 g_object_unref ( vdl->gcsgradient[i] );
888 g_free ( vdl->gcsgradient );
890 a_dems_list_free ( vdl->files );
893 VikDEMLayer *dem_layer_create ( VikViewport *vp )
895 VikDEMLayer *vdl = dem_layer_new ( vp );
898 /* TODO: share GCS between layers */
899 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ ) {
901 vdl->gcs[i] = vik_viewport_new_gc ( vp, dem_height_colors[i], UNUSED_LINE_THICKNESS );
903 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
904 vdl->gcsgradient[i] = vik_viewport_new_gc ( vp, dem_gradient_colors[i], UNUSED_LINE_THICKNESS );
908 /**************************************************************
909 **** SOURCES & DOWNLOADING
910 **************************************************************/
916 VikDEMLayer *vdl; /* NULL if not alive */
922 /**************************************************
924 **************************************************/
926 static void srtm_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
929 const gchar *continent_dir;
931 intlat = (int)floor(p->lat);
932 intlon = (int)floor(p->lon);
933 continent_dir = srtm_continent_dir(intlat, intlon);
935 if (!continent_dir) {
936 g_warning(N_("No SRTM data available for %f, %f"), p->lat, p->lon);
940 gchar *src_fn = g_strdup_printf("%s%s/%c%02d%c%03d.hgt.zip",
943 (intlat >= 0) ? 'N' : 'S',
945 (intlon >= 0) ? 'E' : 'W',
948 static DownloadMapOptions options = { FALSE, FALSE, NULL, 0, a_check_map_file };
949 a_http_download_get_url ( SRTM_HTTP_SITE, src_fn, p->dest, &options, NULL );
953 static gchar *srtm_lat_lon_to_dest_fn ( gdouble lat, gdouble lon )
956 const gchar *continent_dir;
958 intlat = (int)floor(lat);
959 intlon = (int)floor(lon);
960 continent_dir = srtm_continent_dir(intlat, intlon);
963 continent_dir = "nowhere";
965 return g_strdup_printf("srtm3-%s%s%c%02d%c%03d.hgt.zip",
968 (intlat >= 0) ? 'N' : 'S',
970 (intlon >= 0) ? 'E' : 'W',
975 /* TODO: generalize */
976 static void srtm_draw_existence ( VikViewport *vp )
978 gdouble max_lat, max_lon, min_lat, min_lon;
979 gchar buf[strlen(MAPS_CACHE_DIR)+strlen(SRTM_CACHE_TEMPLATE)+30];
982 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
984 for (i = floor(min_lat); i <= floor(max_lat); i++) {
985 for (j = floor(min_lon); j <= floor(max_lon); j++) {
986 const gchar *continent_dir;
987 if ((continent_dir = srtm_continent_dir(i, j)) == NULL)
989 g_snprintf(buf, sizeof(buf), SRTM_CACHE_TEMPLATE,
993 (i >= 0) ? 'N' : 'S',
995 (j >= 0) ? 'E' : 'W',
997 if ( g_file_test(buf, G_FILE_TEST_EXISTS ) == TRUE ) {
1002 sw.mode = VIK_COORD_LATLON;
1003 ne.north_south = i+1;
1005 ne.mode = VIK_COORD_LATLON;
1006 vik_viewport_coord_to_screen ( vp, &sw, &x1, &y1 );
1007 vik_viewport_coord_to_screen ( vp, &ne, &x2, &y2 );
1008 if ( x1 < 0 ) x1 = 0;
1009 if ( y2 < 0 ) y2 = 0;
1010 vik_viewport_draw_rectangle ( vp, gtk_widget_get_style(GTK_WIDGET(vp))->black_gc,
1011 FALSE, x1, y2, x2-x1, y1-y2 );
1018 /**************************************************
1019 * SOURCE: USGS 24K *
1020 **************************************************/
1022 #ifdef VIK_CONFIG_DEM24K
1024 static void dem24k_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
1026 /* TODO: dest dir */
1027 gchar *cmdline = g_strdup_printf("%s %.03f %.03f",
1028 DEM24K_DOWNLOAD_SCRIPT,
1031 /* FIX: don't use system, use execv or something. check for existence */
1036 static gchar *dem24k_lat_lon_to_dest_fn ( gdouble lat, gdouble lon )
1038 return g_strdup_printf("dem24k/%d/%d/%.03f,%.03f.dem",
1045 /* TODO: generalize */
1046 static void dem24k_draw_existence ( VikViewport *vp )
1048 gdouble max_lat, max_lon, min_lat, min_lon;
1049 gchar buf[strlen(MAPS_CACHE_DIR)+40];
1052 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
1054 for (i = floor(min_lat*8)/8; i <= floor(max_lat*8)/8; i+=0.125) {
1055 /* check lat dir first -- faster */
1056 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/",
1059 if ( g_file_test(buf, G_FILE_TEST_EXISTS) == FALSE )
1061 for (j = floor(min_lon*8)/8; j <= floor(max_lon*8)/8; j+=0.125) {
1062 /* check lon dir first -- faster */
1063 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/%d/",
1067 if ( g_file_test(buf, G_FILE_TEST_EXISTS) == FALSE )
1069 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/%d/%.03f,%.03f.dem",
1075 if ( g_file_test(buf, G_FILE_TEST_EXISTS ) == TRUE ) {
1077 gint x1, y1, x2, y2;
1079 sw.east_west = j-0.125;
1080 sw.mode = VIK_COORD_LATLON;
1081 ne.north_south = i+0.125;
1083 ne.mode = VIK_COORD_LATLON;
1084 vik_viewport_coord_to_screen ( vp, &sw, &x1, &y1 );
1085 vik_viewport_coord_to_screen ( vp, &ne, &x2, &y2 );
1086 if ( x1 < 0 ) x1 = 0;
1087 if ( y2 < 0 ) y2 = 0;
1088 vik_viewport_draw_rectangle ( vp, gtk_widget_get_style(GTK_WIDGET(vp))->black_gc,
1089 FALSE, x1, y2, x2-x1, y1-y2 );
1096 /**************************************************
1097 * SOURCES -- DOWNLOADING & IMPORTING TOOL *
1098 **************************************************
1101 static void weak_ref_cb ( gpointer ptr, GObject * dead_vdl )
1103 DEMDownloadParams *p = ptr;
1104 g_mutex_lock ( p->mutex );
1106 g_mutex_unlock ( p->mutex );
1109 /* Try to add file full_path.
1110 * filename will be copied.
1111 * returns FALSE if file does not exists, TRUE otherwise.
1113 static gboolean dem_layer_add_file ( VikDEMLayer *vdl, const gchar *filename )
1115 if ( g_file_test(filename, G_FILE_TEST_EXISTS) == TRUE ) {
1116 /* only load if file size is not 0 (not in progress) */
1118 stat ( filename, &sb );
1120 gchar *duped_path = g_strdup(filename);
1121 vdl->files = g_list_prepend ( vdl->files, duped_path );
1122 a_dems_load ( duped_path );
1123 g_debug("%s: %s", __FUNCTION__, duped_path);
1130 static void dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
1132 if ( p->source == DEM_SOURCE_SRTM )
1133 srtm_dem_download_thread ( p, threaddata );
1134 #ifdef VIK_CONFIG_DEM24K
1135 else if ( p->source == DEM_SOURCE_DEM24K )
1136 dem24k_dem_download_thread ( p, threaddata );
1141 //gdk_threads_enter();
1142 g_mutex_lock ( p->mutex );
1144 g_object_weak_unref ( G_OBJECT(p->vdl), weak_ref_cb, p );
1146 if ( dem_layer_add_file ( p->vdl, p->dest ) )
1147 vik_layer_emit_update ( VIK_LAYER(p->vdl) ); // NB update from background thread
1149 g_mutex_unlock ( p->mutex );
1150 //gdk_threads_leave();
1154 static void free_dem_download_params ( DEMDownloadParams *p )
1156 g_mutex_free ( p->mutex );
1161 static gpointer dem_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1167 * Display a simple dialog with information about the DEM file at this location
1169 static void dem_layer_file_info ( GtkWidget *widget, struct LatLon *ll )
1171 gint intlat, intlon;
1172 const gchar *continent_dir;
1174 intlat = (int)floor(ll->lat);
1175 intlon = (int)floor(ll->lon);
1176 continent_dir = srtm_continent_dir(intlat, intlon);
1178 gchar *source = NULL;
1179 if ( continent_dir )
1180 source = g_strdup_printf ( "http:/%s%s/%c%02d%c%03d.hgt.zip",
1183 (intlat >= 0) ? 'N' : 'S',
1185 (intlon >= 0) ? 'E' : 'W',
1188 // Probably not over any land...
1189 source = g_strdup ( _("No DEM File Available") );
1191 gchar *filename = NULL;
1192 gchar *dem_file = NULL;
1193 #ifdef VIK_CONFIG_DEM24K
1194 dem_file = dem24k_lat_lon_to_dest_fn ( ll->lat, ll->lon );
1196 dem_file = srtm_lat_lon_to_dest_fn ( ll->lat, ll->lon );
1198 gchar *message = NULL;
1200 filename = g_strdup_printf ( "%s%s", MAPS_CACHE_DIR, dem_file );
1202 if ( g_file_test ( filename, G_FILE_TEST_EXISTS ) ) {
1203 // Get some timestamp information of the file
1204 struct stat stat_buf;
1205 if ( g_stat ( filename, &stat_buf ) == 0 ) {
1207 strftime ( time_buf, sizeof(time_buf), "%c", gmtime((const time_t *)&stat_buf.st_mtime) );
1208 message = g_strdup_printf ( _("\nSource: %s\n\nDEM File: %s\nDEM File Timestamp: %s"), source, filename, time_buf );
1212 message = g_strdup_printf ( _("Source: %s\n\nNo DEM File!"), source );
1215 a_dialog_info_msg ( GTK_WINDOW(gtk_widget_get_toplevel(widget)), message );
1219 g_free ( dem_file );
1220 g_free ( filename );
1223 static gboolean dem_layer_download_release ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp )
1226 static struct LatLon ll;
1229 gchar *dem_file = NULL;
1231 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1232 vik_coord_to_latlon ( &coord, &ll );
1235 if ( vdl->source == DEM_SOURCE_SRTM )
1236 dem_file = srtm_lat_lon_to_dest_fn ( ll.lat, ll.lon );
1237 #ifdef VIK_CONFIG_DEM24K
1238 else if ( vdl->source == DEM_SOURCE_DEM24K )
1239 dem_file = dem24k_lat_lon_to_dest_fn ( ll.lat, ll.lon );
1245 full_path = g_strdup_printf("%s%s", MAPS_CACHE_DIR, dem_file );
1247 g_debug("%s: %s", __FUNCTION__, full_path);
1249 if ( event->button == 1 ) {
1250 // TODO: check if already in filelist
1251 if ( ! dem_layer_add_file(vdl, full_path) ) {
1252 gchar *tmp = g_strdup_printf ( _("Downloading DEM %s"), dem_file );
1253 DEMDownloadParams *p = g_malloc(sizeof(DEMDownloadParams));
1254 p->dest = g_strdup(full_path);
1258 p->mutex = g_mutex_new();
1259 p->source = vdl->source;
1260 g_object_weak_ref(G_OBJECT(p->vdl), weak_ref_cb, p );
1262 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vdl), tmp,
1263 (vik_thr_func) dem_download_thread, p,
1264 (vik_thr_free_func) free_dem_download_params, NULL, 1 );
1269 vik_layer_emit_update ( VIK_LAYER(vdl) );
1272 if ( !vdl->right_click_menu ) {
1274 vdl->right_click_menu = GTK_MENU ( gtk_menu_new () );
1276 item = gtk_image_menu_item_new_with_mnemonic ( _("_Show DEM File Information") );
1277 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INFO, GTK_ICON_SIZE_MENU) );
1278 g_signal_connect ( G_OBJECT(item), "activate", G_CALLBACK(dem_layer_file_info), &ll );
1279 gtk_menu_shell_append (GTK_MENU_SHELL(vdl->right_click_menu), item);
1282 gtk_menu_popup ( vdl->right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1283 gtk_widget_show_all ( GTK_WIDGET(vdl->right_click_menu) );
1286 g_free ( dem_file );
1287 g_free ( full_path );
1292 static gboolean dem_layer_download_click ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp )
1294 /* choose & keep track of cache dir
1295 * download in background thread
1296 * download over area */