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, NULL },
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
442 static VikLayerParamData dem_layer_get_param ( VikDEMLayer *vdl, guint16 id, gboolean is_file_operation )
444 VikLayerParamData rv;
449 if ( is_file_operation )
450 // Save in relative format if necessary
451 if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE )
452 rv.sl = dem_layer_convert_to_relative_filenaming ( rv.sl );
454 case PARAM_SOURCE: rv.u = vdl->source; break;
455 case PARAM_TYPE: rv.u = vdl->type; break;
456 case PARAM_COLOR: rv.c = vdl->color; break;
458 /* Convert for display in desired units
459 NB file operation always in internal units (metres) */
460 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
461 rv.d = VIK_METERS_TO_FEET(vdl->min_elev);
463 rv.d = vdl->min_elev;
466 /* Convert for display in desired units
467 NB file operation always in internal units (metres) */
468 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
469 rv.d = VIK_METERS_TO_FEET(vdl->max_elev);
471 rv.d = vdl->max_elev;
478 static void dem_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file )
480 /* nothing ATM, but keep in case it's needed the future */
483 static VikDEMLayer *dem_layer_new ( VikViewport *vvp )
485 VikDEMLayer *vdl = VIK_DEM_LAYER ( g_object_new ( VIK_DEM_LAYER_TYPE, NULL ) );
487 vik_layer_set_type ( VIK_LAYER(vdl), VIK_LAYER_DEM );
491 vdl->gcs = g_malloc(sizeof(GdkGC *)*DEM_N_HEIGHT_COLORS);
492 vdl->gcsgradient = g_malloc(sizeof(GdkGC *)*DEM_N_GRADIENT_COLORS);
493 /* make new gcs only if we need it (copy layer -> use old) */
495 // Ensure the base GC is available so the default colour can be applied
496 if ( vvp ) vdl->gcs[0] = vik_viewport_new_gc ( vvp, "#0000FF", 1 );
498 vik_layer_set_defaults ( VIK_LAYER(vdl), vvp );
504 static inline guint16 get_height_difference(gint16 elev, gint16 new_elev)
506 if(new_elev == VIK_DEM_INVALID_ELEVATION)
509 return abs(new_elev - elev);
513 static void vik_dem_layer_draw_dem ( VikDEMLayer *vdl, VikViewport *vp, VikDEM *dem )
515 VikDEMColumn *column, *prevcolumn, *nextcolumn;
517 struct LatLon dem_northeast, dem_southwest;
518 gdouble max_lat, max_lon, min_lat, min_lon;
520 /**** Check if viewport and DEM data overlap ****/
522 /* get min, max lat/lon of viewport */
523 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
525 /* get min, max lat/lon of DEM data */
526 if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
527 dem_northeast.lat = dem->max_north / 3600.0;
528 dem_northeast.lon = dem->max_east / 3600.0;
529 dem_southwest.lat = dem->min_north / 3600.0;
530 dem_southwest.lon = dem->min_east / 3600.0;
531 } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
532 struct UTM dem_northeast_utm, dem_southwest_utm;
533 dem_northeast_utm.northing = dem->max_north;
534 dem_northeast_utm.easting = dem->max_east;
535 dem_southwest_utm.northing = dem->min_north;
536 dem_southwest_utm.easting = dem->min_east;
537 dem_northeast_utm.zone = dem_southwest_utm.zone = dem->utm_zone;
538 dem_northeast_utm.letter = dem_southwest_utm.letter = dem->utm_letter;
540 a_coords_utm_to_latlon(&dem_northeast_utm, &dem_northeast);
541 a_coords_utm_to_latlon(&dem_southwest_utm, &dem_southwest);
544 if ( (max_lat > dem_northeast.lat && min_lat > dem_northeast.lat) ||
545 (max_lat < dem_southwest.lat && min_lat < dem_southwest.lat) )
547 else if ( (max_lon > dem_northeast.lon && min_lon > dem_northeast.lon) ||
548 (max_lon < dem_southwest.lon && min_lon < dem_southwest.lon) )
550 /* else they overlap */
552 /**** End Overlap Check ****/
553 /* boxes to show where we have DEM instead of actually drawing the DEM.
554 * useful if we want to see what areas we have coverage for (if we want
555 * to get elevation data for a track) but don't want to cover the map.
559 /* draw a box if a DEM is loaded. in future I'd like to add an option for this
560 * this is useful if we want to see what areas we have dem for but don't want to
561 * cover the map (or maybe we just need translucent DEM?) */
563 VikCoord demne, demsw;
565 vik_coord_load_from_latlon(&demne, vik_viewport_get_coord_mode(vp), &dem_northeast);
566 vik_coord_load_from_latlon(&demsw, vik_viewport_get_coord_mode(vp), &dem_southwest);
568 vik_viewport_coord_to_screen ( vp, &demne, &x1, &y1 );
569 vik_viewport_coord_to_screen ( vp, &demsw, &x2, &y2 );
571 if ( x1 > vik_viewport_get_width(vp) ) x1=vik_viewport_get_width(vp);
572 if ( y2 > vik_viewport_get_height(vp) ) y2=vik_viewport_get_height(vp);
573 if ( x2 < 0 ) x2 = 0;
574 if ( y1 < 0 ) y1 = 0;
575 vik_viewport_draw_rectangle ( vp, gtk_widget_get_style(GTK_WIDGET(vp))->black_gc,
576 FALSE, x2, y1, x1-x2, y2-y1 );
581 if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
582 VikCoord tmp; /* TODO: don't use coord_load_from_latlon, especially if in latlon drawing mode */
584 gdouble max_lat_as, max_lon_as, min_lat_as, min_lon_as;
585 gdouble start_lat_as, end_lat_as, start_lon_as, end_lon_as;
587 gdouble start_lat, end_lat, start_lon, end_lon;
589 struct LatLon counter;
591 guint x, y, start_x, start_y;
595 guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 80 ); /* todo: smarter calculation. */
597 gdouble nscale_deg = dem->north_scale / ((gdouble) 3600);
598 gdouble escale_deg = dem->east_scale / ((gdouble) 3600);
600 max_lat_as = max_lat * 3600;
601 min_lat_as = min_lat * 3600;
602 max_lon_as = max_lon * 3600;
603 min_lon_as = min_lon * 3600;
605 start_lat_as = MAX(min_lat_as, dem->min_north);
606 end_lat_as = MIN(max_lat_as, dem->max_north);
607 start_lon_as = MAX(min_lon_as, dem->min_east);
608 end_lon_as = MIN(max_lon_as, dem->max_east);
610 start_lat = floor(start_lat_as / dem->north_scale) * nscale_deg;
611 end_lat = ceil (end_lat_as / dem->north_scale) * nscale_deg;
612 start_lon = floor(start_lon_as / dem->east_scale) * escale_deg;
613 end_lon = ceil (end_lon_as / dem->east_scale) * escale_deg;
615 vik_dem_east_north_to_xy ( dem, start_lon_as, start_lat_as, &start_x, &start_y );
616 guint gradient_skip_factor = 1;
617 if(vdl->type == DEM_TYPE_GRADIENT)
618 gradient_skip_factor = skip_factor;
620 /* verify sane elev interval */
621 if ( vdl->max_elev <= vdl->min_elev )
622 vdl->max_elev = vdl->min_elev + 1;
624 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 ) {
625 // NOTE: ( counter.lon <= end_lon + ESCALE_DEG*SKIP_FACTOR ) is neccessary so in high zoom modes,
626 // the leftmost column does also get drawn, if the center point is out of viewport.
627 if ( x < dem->n_columns ) {
628 column = g_ptr_array_index ( dem->columns, x );
629 // get previous and next column. catch out-of-bound.
631 new_x -= gradient_skip_factor;
633 prevcolumn = g_ptr_array_index ( dem->columns, x+1);
635 prevcolumn = g_ptr_array_index ( dem->columns, new_x);
637 new_x += gradient_skip_factor;
638 if(new_x >= dem->n_columns)
639 nextcolumn = g_ptr_array_index ( dem->columns, x-1);
641 nextcolumn = g_ptr_array_index ( dem->columns, new_x);
643 for ( y=start_y, counter.lat = start_lat; counter.lat <= end_lat; counter.lat += nscale_deg * skip_factor, y += skip_factor ) {
644 if ( y > column->n_points )
647 elev = column->points[y];
649 // calculate bounding box for drawing
650 gint box_x, box_y, box_width, box_height;
653 box_c.lat += (nscale_deg * skip_factor)/2;
654 box_c.lon -= (escale_deg * skip_factor)/2;
655 vik_coord_load_from_latlon(&tmp, vik_viewport_get_coord_mode(vp), &box_c);
656 vik_viewport_coord_to_screen(vp, &tmp, &box_x, &box_y);
657 // catch box at borders
662 box_c.lat -= nscale_deg * skip_factor;
663 box_c.lon += escale_deg * skip_factor;
664 vik_coord_load_from_latlon(&tmp, vik_viewport_get_coord_mode(vp), &box_c);
665 vik_viewport_coord_to_screen(vp, &tmp, &box_width, &box_height);
668 // catch box at borders
669 if(box_width < 0 || box_height < 0)
670 continue; // skip this. this is out of our viewport anyway. FIXME: why?
672 gboolean below_minimum = FALSE;
673 if(vdl->type == DEM_TYPE_HEIGHT) {
674 if ( elev != VIK_DEM_INVALID_ELEVATION && elev < vdl->min_elev ) {
675 // Prevent 'elev - vdl->min_elev' from being negative so can safely use as array index
676 elev = ceil ( vdl->min_elev );
677 below_minimum = TRUE;
679 if ( elev != VIK_DEM_INVALID_ELEVATION && elev > vdl->max_elev )
680 elev = vdl->max_elev;
684 if(box_width < 0 || box_height < 0) // FIXME: why does this happen?
687 if(vdl->type == DEM_TYPE_GRADIENT) {
688 if( elev == VIK_DEM_INVALID_ELEVATION ) {
691 // calculate and sum gradient in all directions
695 // calculate gradient from height points all around the current one
696 new_y = y - gradient_skip_factor;
699 change += get_height_difference(elev, prevcolumn->points[new_y]);
700 change += get_height_difference(elev, column->points[new_y]);
701 change += get_height_difference(elev, nextcolumn->points[new_y]);
703 change += get_height_difference(elev, prevcolumn->points[y]);
704 change += get_height_difference(elev, nextcolumn->points[y]);
706 new_y = y + gradient_skip_factor;
707 if(new_y >= column->n_points)
709 change += get_height_difference(elev, prevcolumn->points[new_y]);
710 change += get_height_difference(elev, column->points[new_y]);
711 change += get_height_difference(elev, nextcolumn->points[new_y]);
713 change = change / ((skip_factor > 1) ? log(skip_factor) : 0.55); // FIXME: better calc.
715 if(change < vdl->min_elev)
716 // Prevent 'change - vdl->min_elev' from being negative so can safely use as array index
717 change = ceil ( vdl->min_elev );
719 if(change > vdl->max_elev)
720 change = vdl->max_elev;
722 // void vik_viewport_draw_rectangle ( VikViewport *vvp, GdkGC *gc, gboolean filled, gint x1, gint y1, gint x2, gint y2 );
723 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);
726 if(vdl->type == DEM_TYPE_HEIGHT) {
727 if ( elev == VIK_DEM_INVALID_ELEVATION )
728 ; /* don't draw it */
729 else if ( elev <= 0 || below_minimum )
730 /* If 'sea' colour or below the defined mininum draw in the configurable colour */
731 vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, box_x, box_y, box_width, box_height);
733 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);
740 } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
741 gdouble max_nor, max_eas, min_nor, min_eas;
742 gdouble start_nor, start_eas, end_nor, end_eas;
746 guint x, y, start_x, start_y;
748 VikCoord tmp; /* TODO: don't use coord_load_from_latlon, especially if in latlon drawing mode */
751 guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 10 ); /* todo: smarter calculation. */
753 VikCoord tleft, tright, bleft, bright;
755 vik_viewport_screen_to_coord ( vp, 0, 0, &tleft );
756 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), 0, &tright );
757 vik_viewport_screen_to_coord ( vp, 0, vik_viewport_get_height(vp), &bleft );
758 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), vik_viewport_get_height(vp), &bright );
761 vik_coord_convert(&tleft, VIK_COORD_UTM);
762 vik_coord_convert(&tright, VIK_COORD_UTM);
763 vik_coord_convert(&bleft, VIK_COORD_UTM);
764 vik_coord_convert(&bright, VIK_COORD_UTM);
766 max_nor = MAX(tleft.north_south, tright.north_south);
767 min_nor = MIN(bleft.north_south, bright.north_south);
768 max_eas = MAX(bright.east_west, tright.east_west);
769 min_eas = MIN(bleft.east_west, tleft.east_west);
771 start_nor = MAX(min_nor, dem->min_north);
772 end_nor = MIN(max_nor, dem->max_north);
773 if ( tleft.utm_zone == dem->utm_zone && bleft.utm_zone == dem->utm_zone
774 && (tleft.utm_letter >= 'N') == (dem->utm_letter >= 'N')
775 && (bleft.utm_letter >= 'N') == (dem->utm_letter >= 'N') ) /* if the utm zones/hemispheres are different, min_eas will be bogus */
776 start_eas = MAX(min_eas, dem->min_east);
778 start_eas = dem->min_east;
779 if ( tright.utm_zone == dem->utm_zone && bright.utm_zone == dem->utm_zone
780 && (tright.utm_letter >= 'N') == (dem->utm_letter >= 'N')
781 && (bright.utm_letter >= 'N') == (dem->utm_letter >= 'N') ) /* if the utm zones/hemispheres are different, min_eas will be bogus */
782 end_eas = MIN(max_eas, dem->max_east);
784 end_eas = dem->max_east;
786 start_nor = floor(start_nor / dem->north_scale) * dem->north_scale;
787 end_nor = ceil (end_nor / dem->north_scale) * dem->north_scale;
788 start_eas = floor(start_eas / dem->east_scale) * dem->east_scale;
789 end_eas = ceil (end_eas / dem->east_scale) * dem->east_scale;
791 vik_dem_east_north_to_xy ( dem, start_eas, start_nor, &start_x, &start_y );
793 /* TODO: why start_x and start_y are -1 -- rounding error from above? */
795 counter.zone = dem->utm_zone;
796 counter.letter = dem->utm_letter;
798 for ( x=start_x, counter.easting = start_eas; counter.easting <= end_eas; counter.easting += dem->east_scale * skip_factor, x += skip_factor ) {
799 if ( x > 0 && x < dem->n_columns ) {
800 column = g_ptr_array_index ( dem->columns, x );
801 for ( y=start_y, counter.northing = start_nor; counter.northing <= end_nor; counter.northing += dem->north_scale * skip_factor, y += skip_factor ) {
802 if ( y > column->n_points )
804 elev = column->points[y];
805 if ( elev != VIK_DEM_INVALID_ELEVATION && elev < vdl->min_elev )
807 if ( elev != VIK_DEM_INVALID_ELEVATION && elev > vdl->max_elev )
812 vik_coord_load_from_utm(&tmp, vik_viewport_get_coord_mode(vp), &counter);
813 vik_viewport_coord_to_screen(vp, &tmp, &a, &b);
814 if ( elev == VIK_DEM_INVALID_ELEVATION )
815 ; /* don't draw it */
816 else if ( elev <= 0 )
817 vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, a-1, b-1, 2, 2 );
819 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 );
827 /* return the continent for the specified lat, lon */
829 static const gchar *srtm_continent_dir ( gint lat, gint lon )
831 extern const char *_srtm_continent_data[];
832 static GHashTable *srtm_continent = NULL;
833 const gchar *continent;
836 if (!srtm_continent) {
839 srtm_continent = g_hash_table_new(g_str_hash, g_str_equal);
840 s = _srtm_continent_data;
841 while (*s != (gchar *)-1) {
844 g_hash_table_insert(srtm_continent, (gpointer) *s, (gpointer) continent);
850 g_snprintf(name, sizeof(name), "%c%02d%c%03d",
851 (lat >= 0) ? 'N' : 'S', ABS(lat),
852 (lon >= 0) ? 'E' : 'W', ABS(lon));
854 return(g_hash_table_lookup(srtm_continent, name));
857 static void dem_layer_draw ( VikDEMLayer *vdl, VikViewport *vp )
859 GList *dems_iter = vdl->files;
863 /* search for SRTM3 90m */
865 if ( vdl->source == DEM_SOURCE_SRTM )
866 srtm_draw_existence ( vp );
867 #ifdef VIK_CONFIG_DEM24K
868 else if ( vdl->source == DEM_SOURCE_DEM24K )
869 dem24k_draw_existence ( vp );
872 while ( dems_iter ) {
873 dem = a_dems_get ( (const char *) (dems_iter->data) );
875 vik_dem_layer_draw_dem ( vdl, vp, dem );
876 dems_iter = dems_iter->next;
880 static void dem_layer_free ( VikDEMLayer *vdl )
884 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ )
885 g_object_unref ( vdl->gcs[i] );
888 if ( vdl->gcsgradient )
889 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
890 g_object_unref ( vdl->gcsgradient[i] );
891 g_free ( vdl->gcsgradient );
893 a_dems_list_free ( vdl->files );
896 VikDEMLayer *dem_layer_create ( VikViewport *vp )
898 VikDEMLayer *vdl = dem_layer_new ( vp );
901 /* TODO: share GCS between layers */
902 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ ) {
904 vdl->gcs[i] = vik_viewport_new_gc ( vp, dem_height_colors[i], UNUSED_LINE_THICKNESS );
906 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
907 vdl->gcsgradient[i] = vik_viewport_new_gc ( vp, dem_gradient_colors[i], UNUSED_LINE_THICKNESS );
911 /**************************************************************
912 **** SOURCES & DOWNLOADING
913 **************************************************************/
919 VikDEMLayer *vdl; /* NULL if not alive */
925 /**************************************************
927 **************************************************/
929 static void srtm_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
932 const gchar *continent_dir;
934 intlat = (int)floor(p->lat);
935 intlon = (int)floor(p->lon);
936 continent_dir = srtm_continent_dir(intlat, intlon);
938 if (!continent_dir) {
940 gchar *msg = g_strdup_printf ( _("No SRTM data available for %f, %f"), p->lat, p->lon );
941 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(p->vdl), msg, VIK_STATUSBAR_INFO );
947 gchar *src_fn = g_strdup_printf("%s%s/%c%02d%c%03d.hgt.zip",
950 (intlat >= 0) ? 'N' : 'S',
952 (intlon >= 0) ? 'E' : 'W',
955 static DownloadMapOptions options = { FALSE, FALSE, NULL, 0, a_check_map_file, NULL, NULL };
956 DownloadResult_t result = a_http_download_get_url ( SRTM_HTTP_SITE, src_fn, p->dest, &options, NULL );
958 case DOWNLOAD_CONTENT_ERROR:
959 case DOWNLOAD_HTTP_ERROR: {
960 gchar *msg = g_strdup_printf ( _("DEM download failure for %f, %f"), p->lat, p->lon );
961 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(p->vdl), msg, VIK_STATUSBAR_INFO );
965 case DOWNLOAD_FILE_WRITE_ERROR: {
966 gchar *msg = g_strdup_printf ( _("DEM write failure for %s"), p->dest );
967 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(p->vdl), msg, VIK_STATUSBAR_INFO );
971 case DOWNLOAD_SUCCESS:
972 case DOWNLOAD_NOT_REQUIRED:
979 static gchar *srtm_lat_lon_to_dest_fn ( gdouble lat, gdouble lon )
982 const gchar *continent_dir;
984 intlat = (int)floor(lat);
985 intlon = (int)floor(lon);
986 continent_dir = srtm_continent_dir(intlat, intlon);
989 continent_dir = "nowhere";
991 return g_strdup_printf("srtm3-%s%s%c%02d%c%03d.hgt.zip",
994 (intlat >= 0) ? 'N' : 'S',
996 (intlon >= 0) ? 'E' : 'W',
1001 /* TODO: generalize */
1002 static void srtm_draw_existence ( VikViewport *vp )
1004 gdouble max_lat, max_lon, min_lat, min_lon;
1005 gchar buf[strlen(MAPS_CACHE_DIR)+strlen(SRTM_CACHE_TEMPLATE)+30];
1008 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
1010 for (i = floor(min_lat); i <= floor(max_lat); i++) {
1011 for (j = floor(min_lon); j <= floor(max_lon); j++) {
1012 const gchar *continent_dir;
1013 if ((continent_dir = srtm_continent_dir(i, j)) == NULL)
1015 g_snprintf(buf, sizeof(buf), SRTM_CACHE_TEMPLATE,
1019 (i >= 0) ? 'N' : 'S',
1021 (j >= 0) ? 'E' : 'W',
1023 if ( g_file_test(buf, G_FILE_TEST_EXISTS ) == TRUE ) {
1025 gint x1, y1, x2, y2;
1028 sw.mode = VIK_COORD_LATLON;
1029 ne.north_south = i+1;
1031 ne.mode = VIK_COORD_LATLON;
1032 vik_viewport_coord_to_screen ( vp, &sw, &x1, &y1 );
1033 vik_viewport_coord_to_screen ( vp, &ne, &x2, &y2 );
1034 if ( x1 < 0 ) x1 = 0;
1035 if ( y2 < 0 ) y2 = 0;
1036 vik_viewport_draw_rectangle ( vp, gtk_widget_get_style(GTK_WIDGET(vp))->black_gc,
1037 FALSE, x1, y2, x2-x1, y1-y2 );
1044 /**************************************************
1045 * SOURCE: USGS 24K *
1046 **************************************************/
1048 #ifdef VIK_CONFIG_DEM24K
1050 static void dem24k_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
1052 /* TODO: dest dir */
1053 gchar *cmdline = g_strdup_printf("%s %.03f %.03f",
1054 DEM24K_DOWNLOAD_SCRIPT,
1057 /* FIX: don't use system, use execv or something. check for existence */
1062 static gchar *dem24k_lat_lon_to_dest_fn ( gdouble lat, gdouble lon )
1064 return g_strdup_printf("dem24k/%d/%d/%.03f,%.03f.dem",
1071 /* TODO: generalize */
1072 static void dem24k_draw_existence ( VikViewport *vp )
1074 gdouble max_lat, max_lon, min_lat, min_lon;
1075 gchar buf[strlen(MAPS_CACHE_DIR)+40];
1078 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
1080 for (i = floor(min_lat*8)/8; i <= floor(max_lat*8)/8; i+=0.125) {
1081 /* check lat dir first -- faster */
1082 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/",
1085 if ( g_file_test(buf, G_FILE_TEST_EXISTS) == FALSE )
1087 for (j = floor(min_lon*8)/8; j <= floor(max_lon*8)/8; j+=0.125) {
1088 /* check lon dir first -- faster */
1089 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/%d/",
1093 if ( g_file_test(buf, G_FILE_TEST_EXISTS) == FALSE )
1095 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/%d/%.03f,%.03f.dem",
1101 if ( g_file_test(buf, G_FILE_TEST_EXISTS ) == TRUE ) {
1103 gint x1, y1, x2, y2;
1105 sw.east_west = j-0.125;
1106 sw.mode = VIK_COORD_LATLON;
1107 ne.north_south = i+0.125;
1109 ne.mode = VIK_COORD_LATLON;
1110 vik_viewport_coord_to_screen ( vp, &sw, &x1, &y1 );
1111 vik_viewport_coord_to_screen ( vp, &ne, &x2, &y2 );
1112 if ( x1 < 0 ) x1 = 0;
1113 if ( y2 < 0 ) y2 = 0;
1114 vik_viewport_draw_rectangle ( vp, gtk_widget_get_style(GTK_WIDGET(vp))->black_gc,
1115 FALSE, x1, y2, x2-x1, y1-y2 );
1122 /**************************************************
1123 * SOURCES -- DOWNLOADING & IMPORTING TOOL *
1124 **************************************************
1127 static void weak_ref_cb ( gpointer ptr, GObject * dead_vdl )
1129 DEMDownloadParams *p = ptr;
1130 g_mutex_lock ( p->mutex );
1132 g_mutex_unlock ( p->mutex );
1135 /* Try to add file full_path.
1136 * filename will be copied.
1137 * returns FALSE if file does not exists, TRUE otherwise.
1139 static gboolean dem_layer_add_file ( VikDEMLayer *vdl, const gchar *filename )
1141 if ( g_file_test(filename, G_FILE_TEST_EXISTS) == TRUE ) {
1142 /* only load if file size is not 0 (not in progress) */
1144 stat ( filename, &sb );
1146 gchar *duped_path = g_strdup(filename);
1147 vdl->files = g_list_prepend ( vdl->files, duped_path );
1148 a_dems_load ( duped_path );
1149 g_debug("%s: %s", __FUNCTION__, duped_path);
1156 static void dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
1158 if ( p->source == DEM_SOURCE_SRTM )
1159 srtm_dem_download_thread ( p, threaddata );
1160 #ifdef VIK_CONFIG_DEM24K
1161 else if ( p->source == DEM_SOURCE_DEM24K )
1162 dem24k_dem_download_thread ( p, threaddata );
1167 //gdk_threads_enter();
1168 g_mutex_lock ( p->mutex );
1170 g_object_weak_unref ( G_OBJECT(p->vdl), weak_ref_cb, p );
1172 if ( dem_layer_add_file ( p->vdl, p->dest ) )
1173 vik_layer_emit_update ( VIK_LAYER(p->vdl) ); // NB update from background thread
1175 g_mutex_unlock ( p->mutex );
1176 //gdk_threads_leave();
1180 static void free_dem_download_params ( DEMDownloadParams *p )
1182 vik_mutex_free ( p->mutex );
1187 static gpointer dem_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1193 * Display a simple dialog with information about the DEM file at this location
1195 static void dem_layer_file_info ( GtkWidget *widget, struct LatLon *ll )
1197 gint intlat, intlon;
1198 const gchar *continent_dir;
1200 intlat = (int)floor(ll->lat);
1201 intlon = (int)floor(ll->lon);
1202 continent_dir = srtm_continent_dir(intlat, intlon);
1204 gchar *source = NULL;
1205 if ( continent_dir )
1206 source = g_strdup_printf ( "http://%s%s%s/%c%02d%c%03d.hgt.zip",
1210 (intlat >= 0) ? 'N' : 'S',
1212 (intlon >= 0) ? 'E' : 'W',
1215 // Probably not over any land...
1216 source = g_strdup ( _("No DEM File Available") );
1218 gchar *filename = NULL;
1219 gchar *dem_file = NULL;
1220 #ifdef VIK_CONFIG_DEM24K
1221 dem_file = dem24k_lat_lon_to_dest_fn ( ll->lat, ll->lon );
1223 dem_file = srtm_lat_lon_to_dest_fn ( ll->lat, ll->lon );
1225 gchar *message = NULL;
1227 filename = g_strdup_printf ( "%s%s", MAPS_CACHE_DIR, dem_file );
1229 if ( g_file_test ( filename, G_FILE_TEST_EXISTS ) ) {
1230 // Get some timestamp information of the file
1231 struct stat stat_buf;
1232 if ( g_stat ( filename, &stat_buf ) == 0 ) {
1234 strftime ( time_buf, sizeof(time_buf), "%c", gmtime((const time_t *)&stat_buf.st_mtime) );
1235 message = g_strdup_printf ( _("\nSource: %s\n\nDEM File: %s\nDEM File Timestamp: %s"), source, filename, time_buf );
1239 message = g_strdup_printf ( _("Source: %s\n\nNo DEM File!"), source );
1242 a_dialog_info_msg ( GTK_WINDOW(gtk_widget_get_toplevel(widget)), message );
1246 g_free ( dem_file );
1247 g_free ( filename );
1250 static gboolean dem_layer_download_release ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp )
1253 static struct LatLon ll;
1256 gchar *dem_file = NULL;
1258 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1259 vik_coord_to_latlon ( &coord, &ll );
1262 if ( vdl->source == DEM_SOURCE_SRTM )
1263 dem_file = srtm_lat_lon_to_dest_fn ( ll.lat, ll.lon );
1264 #ifdef VIK_CONFIG_DEM24K
1265 else if ( vdl->source == DEM_SOURCE_DEM24K )
1266 dem_file = dem24k_lat_lon_to_dest_fn ( ll.lat, ll.lon );
1272 full_path = g_strdup_printf("%s%s", MAPS_CACHE_DIR, dem_file );
1274 g_debug("%s: %s", __FUNCTION__, full_path);
1276 if ( event->button == 1 ) {
1277 // TODO: check if already in filelist
1278 if ( ! dem_layer_add_file(vdl, full_path) ) {
1279 gchar *tmp = g_strdup_printf ( _("Downloading DEM %s"), dem_file );
1280 DEMDownloadParams *p = g_malloc(sizeof(DEMDownloadParams));
1281 p->dest = g_strdup(full_path);
1285 p->mutex = vik_mutex_new();
1286 p->source = vdl->source;
1287 g_object_weak_ref(G_OBJECT(p->vdl), weak_ref_cb, p );
1289 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vdl), tmp,
1290 (vik_thr_func) dem_download_thread, p,
1291 (vik_thr_free_func) free_dem_download_params, NULL, 1 );
1296 vik_layer_emit_update ( VIK_LAYER(vdl) );
1299 if ( !vdl->right_click_menu ) {
1301 vdl->right_click_menu = GTK_MENU ( gtk_menu_new () );
1303 item = gtk_image_menu_item_new_with_mnemonic ( _("_Show DEM File Information") );
1304 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INFO, GTK_ICON_SIZE_MENU) );
1305 g_signal_connect ( G_OBJECT(item), "activate", G_CALLBACK(dem_layer_file_info), &ll );
1306 gtk_menu_shell_append (GTK_MENU_SHELL(vdl->right_click_menu), item);
1309 gtk_menu_popup ( vdl->right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1310 gtk_widget_show_all ( GTK_WIDGET(vdl->right_click_menu) );
1313 g_free ( dem_file );
1314 g_free ( full_path );
1319 static gboolean dem_layer_download_click ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp )
1321 /* choose & keep track of cache dir
1322 * download in background thread
1323 * download over area */