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()
50 #define SRTM_CACHE_TEMPLATE "%ssrtm3-%s%s%c%02d%c%03d.hgt.zip"
52 #define SRTM_HTTP_BASE_URL "https://dds.cr.usgs.gov/srtm/version2_1/SRTM3"
53 static gchar *base_url = NULL;
54 #define VIK_SETTINGS_SRTM_HTTP_BASE_URL "srtm_http_base_url"
56 #ifdef VIK_CONFIG_DEM24K
57 #define DEM24K_DOWNLOAD_SCRIPT "dem24k.pl"
60 #define UNUSED_LINE_THICKNESS 3
62 static VikDEMLayer *dem_layer_new ( VikViewport *vvp );
63 static void dem_layer_draw ( VikDEMLayer *vdl, VikViewport *vp );
64 static void dem_layer_free ( VikDEMLayer *vdl );
65 static VikDEMLayer *dem_layer_create ( VikViewport *vp );
66 static const gchar* dem_layer_tooltip( VikDEMLayer *vdl );
67 static void dem_layer_marshall( VikDEMLayer *vdl, guint8 **data, gint *len );
68 static VikDEMLayer *dem_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
69 static gboolean dem_layer_set_param ( VikDEMLayer *vdl, VikLayerSetParam *vlsp );
70 static VikLayerParamData dem_layer_get_param ( VikDEMLayer *vdl, guint16 id, gboolean is_file_operation );
71 static void dem_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file );
72 static void srtm_draw_existence ( VikViewport *vp );
74 #ifdef VIK_CONFIG_DEM24K
75 static void dem24k_draw_existence ( VikViewport *vp );
78 /* Upped upper limit incase units are feet */
79 static VikLayerParamScale param_scales[] = {
84 static gchar *params_source[] = {
85 N_("SRTM Global 90m (3 arcsec)"),
86 #ifdef VIK_CONFIG_DEM24K
92 static gchar *params_type[] = {
93 N_("Absolute height"),
94 N_("Height gradient"),
98 enum { DEM_SOURCE_SRTM,
99 #ifdef VIK_CONFIG_DEM24K
104 enum { DEM_TYPE_HEIGHT = 0,
109 static VikLayerParamData color_default ( void ) {
110 VikLayerParamData data; gdk_color_parse ( "blue", &data.c ); return data;
113 static VikLayerParamData source_default ( void ) { return VIK_LPD_UINT ( DEM_SOURCE_SRTM ); }
114 static VikLayerParamData type_default ( void ) { return VIK_LPD_UINT ( DEM_TYPE_HEIGHT ); }
115 static VikLayerParamData min_elev_default ( void ) { return VIK_LPD_DOUBLE ( 0.0 ); }
116 static VikLayerParamData max_elev_default ( void ) { return VIK_LPD_DOUBLE ( 1000.0 ); }
118 static VikLayerParam dem_layer_params[] = {
119 { 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 },
120 { 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 },
121 { 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 },
122 { 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 },
123 { 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 },
124 { 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 },
128 enum { PARAM_FILES=0, PARAM_SOURCE, PARAM_COLOR, PARAM_TYPE, PARAM_MIN_ELEV, PARAM_MAX_ELEV, NUM_PARAMS };
130 static gpointer dem_layer_download_create ( VikWindow *vw, VikViewport *vvp);
131 static gboolean dem_layer_download_release ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp );
132 static gboolean dem_layer_download_click ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp );
134 static VikToolInterface dem_tools[] = {
136 { "DEMDownload", "vik-icon-DEM Download", N_("_DEM Download"), NULL, N_("DEM Download"), 0 },
137 (VikToolConstructorFunc) dem_layer_download_create, NULL, NULL, NULL,
138 (VikToolMouseFunc) dem_layer_download_click, NULL, (VikToolMouseFunc) dem_layer_download_release,
139 (VikToolKeyFunc) NULL,
141 GDK_CURSOR_IS_PIXMAP, &cursor_demdl_pixbuf, NULL },
146 The first entry is blue for a default 'sea' colour,
147 however the value used by the corresponding gc can be configured as part of the DEM layer properties.
148 The other colours, shaded from brown to white are used to give an indication of height.
150 static gchar *dem_height_colors[] = {
152 "#9b793c", "#9c7d40", "#9d8144", "#9e8549", "#9f894d", "#a08d51", "#a29156", "#a3955a", "#a4995e", "#a69d63",
153 "#a89f65", "#aaa267", "#ada569", "#afa76b", "#b1aa6d", "#b4ad6f", "#b6b071", "#b9b373", "#bcb676", "#beb978",
154 "#c0bc7a", "#c2c07d", "#c4c37f", "#c6c681", "#c8ca84", "#cacd86", "#ccd188", "#cfd58b", "#c2ce84", "#b5c87e",
155 "#a9c278", "#9cbb71", "#8fb56b", "#83af65", "#76a95e", "#6aa358", "#5e9d52", "#63a055", "#69a458", "#6fa85c",
156 "#74ac5f", "#7ab063", "#80b467", "#86b86a", "#8cbc6e", "#92c072", "#94c175", "#97c278", "#9ac47c", "#9cc57f",
157 "#9fc682", "#a2c886", "#a4c989", "#a7cb8d", "#aacd91", "#afce99", "#b5d0a1", "#bbd2aa", "#c0d3b2", "#c6d5ba",
158 "#ccd7c3", "#d1d9cb", "#d7dbd4", "#DDDDDD", "#e0e0e0", "#e4e4e4", "#e8e8e8", "#ebebeb", "#efefef", "#f3f3f3",
159 "#f7f7f7", "#fbfbfb", "#ffffff"
162 static const guint DEM_N_HEIGHT_COLORS = sizeof(dem_height_colors)/sizeof(dem_height_colors[0]);
165 "#9b793c", "#9e8549", "#a29156", "#a69d63", "#ada569", "#b4ad6f", "#bcb676", "#c2c07d", "#c8ca84", "#cfd58b",
166 "#a9c278", "#83af65", "#5e9d52", "#6fa85c", "#80b467", "#92c072", "#9ac47c", "#a2c886", "#aacd91", "#bbd2aa",
167 "#ccd7c3", "#DDDDDD", "#e8e8e8", "#f3f3f3", "#FFFFFF"
171 static gchar *dem_gradient_colors[] = {
173 "#000000", "#000011", "#000022", "#000033", "#000044", "#00004c", "#000055", "#00005d", "#000066", "#00006e",
174 "#000077", "#00007f", "#000088", "#000090", "#000099", "#0000a1", "#0000aa", "#0000b2", "#0000bb", "#0000c3",
175 "#0000cc", "#0000d4", "#0000dd", "#0000e5", "#0000ee", "#0000f6", "#0000ff", "#0008f7", "#0011ee", "#0019e6",
176 "#0022dd", "#002ad5", "#0033cc", "#003bc4", "#0044bb", "#004cb3", "#0055aa", "#005da2", "#006699", "#006e91",
177 "#007788", "#007f80", "#008877", "#00906f", "#009966", "#00a15e", "#00aa55", "#00b24d", "#00bb44", "#00c33c",
178 "#00cc33", "#00d42b", "#00dd22", "#00e51a", "#00ee11", "#00f609", "#00ff00", "#08f700", "#11ee00", "#19e600",
179 "#22dd00", "#2ad500", "#33cc00", "#3bc400", "#44bb00", "#4cb300", "#55aa00", "#5da200", "#669900", "#6e9100",
180 "#778800", "#7f8000", "#887700", "#906f00", "#996600", "#a15e00", "#aa5500", "#b24d00", "#bb4400", "#c33c00",
181 "#cc3300", "#d42b00", "#dd2200", "#e51a00", "#ee1100", "#f60900", "#ff0000",
185 static const guint DEM_N_GRADIENT_COLORS = sizeof(dem_gradient_colors)/sizeof(dem_gradient_colors[0]);
188 VikLayerInterface vik_dem_layer_interface = {
195 sizeof(dem_tools) / sizeof(dem_tools[0]),
204 (VikLayerFuncCreate) dem_layer_create,
205 (VikLayerFuncRealize) NULL,
206 (VikLayerFuncPostRead) dem_layer_post_read,
207 (VikLayerFuncFree) dem_layer_free,
209 (VikLayerFuncProperties) NULL,
210 (VikLayerFuncDraw) dem_layer_draw,
211 (VikLayerFuncChangeCoordMode) NULL,
213 (VikLayerFuncGetTimestamp) NULL,
215 (VikLayerFuncSetMenuItemsSelection) NULL,
216 (VikLayerFuncGetMenuItemsSelection) NULL,
218 (VikLayerFuncAddMenuItems) NULL,
219 (VikLayerFuncSublayerAddMenuItems) NULL,
221 (VikLayerFuncSublayerRenameRequest) NULL,
222 (VikLayerFuncSublayerToggleVisible) NULL,
223 (VikLayerFuncSublayerTooltip) NULL,
224 (VikLayerFuncLayerTooltip) dem_layer_tooltip,
225 (VikLayerFuncLayerSelected) NULL,
227 (VikLayerFuncMarshall) dem_layer_marshall,
228 (VikLayerFuncUnmarshall) dem_layer_unmarshall,
230 (VikLayerFuncSetParam) dem_layer_set_param,
231 (VikLayerFuncGetParam) dem_layer_get_param,
232 (VikLayerFuncChangeParam) NULL,
234 (VikLayerFuncReadFileData) NULL,
235 (VikLayerFuncWriteFileData) NULL,
237 (VikLayerFuncDeleteItem) NULL,
238 (VikLayerFuncCutItem) NULL,
239 (VikLayerFuncCopyItem) NULL,
240 (VikLayerFuncPasteItem) NULL,
241 (VikLayerFuncFreeCopiedItem) NULL,
242 (VikLayerFuncDragDropRequest) NULL,
244 (VikLayerFuncSelectClick) NULL,
245 (VikLayerFuncSelectMove) NULL,
246 (VikLayerFuncSelectRelease) NULL,
247 (VikLayerFuncSelectedViewportMenu) NULL,
250 struct _VikDEMLayer {
261 // right click menu only stuff - similar to mapslayer
262 GtkMenu *right_click_menu;
265 // NB Only performed once per program run
266 static void vik_dem_class_init ( VikDEMLayerClass *klass )
268 // Note if suppling your own base URL - the site must still follow the Continent directory layout
269 if ( ! a_settings_get_string ( VIK_SETTINGS_SRTM_HTTP_BASE_URL, &base_url ) ) {
270 // Otherwise use the default
271 base_url = g_strdup ( SRTM_HTTP_BASE_URL );
275 GType vik_dem_layer_get_type ()
277 static GType vdl_type = 0;
281 static const GTypeInfo vdl_info =
283 sizeof (VikDEMLayerClass),
284 NULL, /* base_init */
285 NULL, /* base_finalize */
286 (GClassInitFunc) vik_dem_class_init, /* class init */
287 NULL, /* class_finalize */
288 NULL, /* class_data */
289 sizeof (VikDEMLayer),
291 NULL /* instance init */
293 vdl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikDEMLayer", &vdl_info, 0 );
299 static const gchar* dem_layer_tooltip( VikDEMLayer *vdl )
301 static gchar tmp_buf[100];
302 g_snprintf (tmp_buf, sizeof(tmp_buf), _("Number of files: %d"), g_list_length (vdl->files));
306 static void dem_layer_marshall( VikDEMLayer *vdl, guint8 **data, gint *len )
308 vik_layer_marshall_params ( VIK_LAYER(vdl), data, len );
311 static VikDEMLayer *dem_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
313 VikDEMLayer *rv = dem_layer_new ( vvp );
316 /* TODO: share GCS between layers */
317 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ ) {
319 rv->gcs[i] = vik_viewport_new_gc_from_color ( vvp, &(rv->color), UNUSED_LINE_THICKNESS );
321 rv->gcs[i] = vik_viewport_new_gc ( vvp, dem_height_colors[i], UNUSED_LINE_THICKNESS );
323 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
324 rv->gcsgradient[i] = vik_viewport_new_gc ( vvp, dem_gradient_colors[i], UNUSED_LINE_THICKNESS );
326 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
330 /* Structure for DEM data used in background thread */
333 } dem_load_thread_data;
336 * Function for starting the DEM file loading as a background thread
338 static int dem_layer_load_list_thread ( dem_load_thread_data *dltd, gpointer threaddata )
340 int result = 0; // Default to good
342 if ( a_dems_load_list ( &(dltd->vdl->files), threaddata ) ) {
347 // ATM as each file is processed the screen is not updated (no mechanism exposed to a_dems_load_list)
348 // Thus force draw only at the end, as loading is complete/aborted
349 // Test is helpful to prevent Gtk-CRITICAL warnings if the program is exitted whilst loading
350 if ( IS_VIK_LAYER(dltd->vdl) )
351 vik_layer_emit_update ( VIK_LAYER(dltd->vdl) ); // NB update requested from background thread
356 static void dem_layer_thread_data_free ( dem_load_thread_data *data )
362 static void dem_layer_thread_cancel ( dem_load_thread_data *data )
365 // Instead of freeing the list, leave it as partially processed
366 // Thus we can see/use what was done
370 * Process the list of DEM files and convert each one to a relative path
372 static GList *dem_layer_convert_to_relative_filenaming ( GList *files )
374 gchar *cwd = g_get_current_dir();
378 GList *relfiles = NULL;
381 gchar *file = g_strdup ( file_GetRelativeFilename ( cwd, files->data ) );
382 relfiles = g_list_prepend ( relfiles, file );
389 // Replacing current list, so delete old values first.
392 g_free ( iter->data );
395 g_list_free ( files );
403 gboolean dem_layer_set_param ( VikDEMLayer *vdl, VikLayerSetParam *vlsp )
407 case PARAM_COLOR: vdl->color = vlsp->data.c; gdk_gc_set_rgb_fg_color ( vdl->gcs[0], &(vdl->color) ); break;
408 case PARAM_SOURCE: vdl->source = vlsp->data.u; break;
409 case PARAM_TYPE: vdl->type = vlsp->data.u; break;
411 /* Convert to store internally
412 NB file operation always in internal units (metres) */
413 if (!vlsp->is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
414 vdl->min_elev = VIK_FEET_TO_METERS(vlsp->data.d);
416 vdl->min_elev = vlsp->data.d;
419 /* Convert to store internally
420 NB file operation always in internal units (metres) */
421 if (!vlsp->is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
422 vdl->max_elev = VIK_FEET_TO_METERS(vlsp->data.d);
424 vdl->max_elev = vlsp->data.d;
428 // Clear out old settings - if any commonalities with new settings they will have to be read again
429 a_dems_list_free ( vdl->files );
431 // Set file list so any other intermediate screen drawing updates will show currently loaded DEMs by the working thread
432 // Ensure resolving of any relative path names
433 util_make_absolute_filenames ( vdl->files, vlsp->dirpath );
435 // No need for thread if no files
438 dem_load_thread_data *dltd = g_malloc ( sizeof(dem_load_thread_data) );
441 a_background_thread ( BACKGROUND_POOL_LOCAL,
442 VIK_GTK_WINDOW_FROM_WIDGET(vlsp->vp),
444 (vik_thr_func) dem_layer_load_list_thread,
446 (vik_thr_free_func) dem_layer_thread_data_free,
447 (vik_thr_free_func) dem_layer_thread_cancel,
448 g_list_length ( vlsp->data.sl ) ); // Number of DEM files
457 static VikLayerParamData dem_layer_get_param ( VikDEMLayer *vdl, guint16 id, gboolean is_file_operation )
459 VikLayerParamData rv;
464 if ( is_file_operation )
465 // Save in relative format if necessary
466 if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE )
467 rv.sl = dem_layer_convert_to_relative_filenaming ( rv.sl );
469 case PARAM_SOURCE: rv.u = vdl->source; break;
470 case PARAM_TYPE: rv.u = vdl->type; break;
471 case PARAM_COLOR: rv.c = vdl->color; break;
473 /* Convert for display in desired units
474 NB file operation always in internal units (metres) */
475 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
476 rv.d = VIK_METERS_TO_FEET(vdl->min_elev);
478 rv.d = vdl->min_elev;
481 /* Convert for display in desired units
482 NB file operation always in internal units (metres) */
483 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
484 rv.d = VIK_METERS_TO_FEET(vdl->max_elev);
486 rv.d = vdl->max_elev;
493 static void dem_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file )
495 /* nothing ATM, but keep in case it's needed the future */
498 static VikDEMLayer *dem_layer_new ( VikViewport *vvp )
500 VikDEMLayer *vdl = VIK_DEM_LAYER ( g_object_new ( VIK_DEM_LAYER_TYPE, NULL ) );
502 vik_layer_set_type ( VIK_LAYER(vdl), VIK_LAYER_DEM );
506 vdl->gcs = g_malloc(sizeof(GdkGC *)*DEM_N_HEIGHT_COLORS);
507 vdl->gcsgradient = g_malloc(sizeof(GdkGC *)*DEM_N_GRADIENT_COLORS);
508 /* make new gcs only if we need it (copy layer -> use old) */
510 // Ensure the base GC is available so the default colour can be applied
511 if ( vvp ) vdl->gcs[0] = vik_viewport_new_gc ( vvp, "#0000FF", 1 );
513 vik_layer_set_defaults ( VIK_LAYER(vdl), vvp );
519 static inline guint16 get_height_difference(gint16 elev, gint16 new_elev)
521 if(new_elev == VIK_DEM_INVALID_ELEVATION)
524 return abs(new_elev - elev);
528 static void vik_dem_layer_draw_dem ( VikDEMLayer *vdl, VikViewport *vp, VikDEM *dem )
530 VikDEMColumn *column, *prevcolumn, *nextcolumn;
532 struct LatLon dem_northeast, dem_southwest;
533 gdouble max_lat, max_lon, min_lat, min_lon;
535 /**** Check if viewport and DEM data overlap ****/
537 /* get min, max lat/lon of viewport */
538 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
540 /* get min, max lat/lon of DEM data */
541 if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
542 dem_northeast.lat = dem->max_north / 3600.0;
543 dem_northeast.lon = dem->max_east / 3600.0;
544 dem_southwest.lat = dem->min_north / 3600.0;
545 dem_southwest.lon = dem->min_east / 3600.0;
546 } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
547 struct UTM dem_northeast_utm, dem_southwest_utm;
548 dem_northeast_utm.northing = dem->max_north;
549 dem_northeast_utm.easting = dem->max_east;
550 dem_southwest_utm.northing = dem->min_north;
551 dem_southwest_utm.easting = dem->min_east;
552 dem_northeast_utm.zone = dem_southwest_utm.zone = dem->utm_zone;
553 dem_northeast_utm.letter = dem_southwest_utm.letter = dem->utm_letter;
555 a_coords_utm_to_latlon(&dem_northeast_utm, &dem_northeast);
556 a_coords_utm_to_latlon(&dem_southwest_utm, &dem_southwest);
558 // Unknown horiz_units - this shouldn't normally happen
559 // Thus can't work out positions to use
563 if ( (max_lat > dem_northeast.lat && min_lat > dem_northeast.lat) ||
564 (max_lat < dem_southwest.lat && min_lat < dem_southwest.lat) )
566 else if ( (max_lon > dem_northeast.lon && min_lon > dem_northeast.lon) ||
567 (max_lon < dem_southwest.lon && min_lon < dem_southwest.lon) )
569 /* else they overlap */
571 /**** End Overlap Check ****/
572 /* boxes to show where we have DEM instead of actually drawing the DEM.
573 * useful if we want to see what areas we have coverage for (if we want
574 * to get elevation data for a track) but don't want to cover the map.
578 /* draw a box if a DEM is loaded. in future I'd like to add an option for this
579 * this is useful if we want to see what areas we have dem for but don't want to
580 * cover the map (or maybe we just need translucent DEM?) */
582 VikCoord demne, demsw;
584 vik_coord_load_from_latlon(&demne, vik_viewport_get_coord_mode(vp), &dem_northeast);
585 vik_coord_load_from_latlon(&demsw, vik_viewport_get_coord_mode(vp), &dem_southwest);
587 vik_viewport_coord_to_screen ( vp, &demne, &x1, &y1 );
588 vik_viewport_coord_to_screen ( vp, &demsw, &x2, &y2 );
590 if ( x1 > vik_viewport_get_width(vp) ) x1=vik_viewport_get_width(vp);
591 if ( y2 > vik_viewport_get_height(vp) ) y2=vik_viewport_get_height(vp);
592 if ( x2 < 0 ) x2 = 0;
593 if ( y1 < 0 ) y1 = 0;
594 vik_viewport_draw_rectangle ( vp, gtk_widget_get_style(GTK_WIDGET(vp))->black_gc,
595 FALSE, x2, y1, x1-x2, y2-y1 );
600 if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
601 VikCoord tmp; /* TODO: don't use coord_load_from_latlon, especially if in latlon drawing mode */
603 gdouble max_lat_as, max_lon_as, min_lat_as, min_lon_as;
604 gdouble start_lat_as, end_lat_as, start_lon_as, end_lon_as;
606 gdouble start_lat, end_lat, start_lon, end_lon;
608 struct LatLon counter;
610 guint x, y, start_x, start_y;
614 guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 80 ); /* todo: smarter calculation. */
616 gdouble nscale_deg = dem->north_scale / ((gdouble) 3600);
617 gdouble escale_deg = dem->east_scale / ((gdouble) 3600);
619 max_lat_as = max_lat * 3600;
620 min_lat_as = min_lat * 3600;
621 max_lon_as = max_lon * 3600;
622 min_lon_as = min_lon * 3600;
624 start_lat_as = MAX(min_lat_as, dem->min_north);
625 end_lat_as = MIN(max_lat_as, dem->max_north);
626 start_lon_as = MAX(min_lon_as, dem->min_east);
627 end_lon_as = MIN(max_lon_as, dem->max_east);
629 start_lat = floor(start_lat_as / dem->north_scale) * nscale_deg;
630 end_lat = ceil (end_lat_as / dem->north_scale) * nscale_deg;
631 start_lon = floor(start_lon_as / dem->east_scale) * escale_deg;
632 end_lon = ceil (end_lon_as / dem->east_scale) * escale_deg;
634 vik_dem_east_north_to_xy ( dem, start_lon_as, start_lat_as, &start_x, &start_y );
635 guint gradient_skip_factor = 1;
636 if(vdl->type == DEM_TYPE_GRADIENT)
637 gradient_skip_factor = skip_factor;
639 /* verify sane elev interval */
640 if ( vdl->max_elev <= vdl->min_elev )
641 vdl->max_elev = vdl->min_elev + 1;
643 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 ) {
644 // NOTE: ( counter.lon <= end_lon + ESCALE_DEG*SKIP_FACTOR ) is neccessary so in high zoom modes,
645 // the leftmost column does also get drawn, if the center point is out of viewport.
646 if ( x < dem->n_columns ) {
647 column = g_ptr_array_index ( dem->columns, x );
648 // get previous and next column. catch out-of-bound.
650 new_x -= gradient_skip_factor;
652 prevcolumn = g_ptr_array_index ( dem->columns, x+1);
654 prevcolumn = g_ptr_array_index ( dem->columns, new_x);
656 new_x += gradient_skip_factor;
657 if(new_x >= dem->n_columns)
658 nextcolumn = g_ptr_array_index ( dem->columns, x-1);
660 nextcolumn = g_ptr_array_index ( dem->columns, new_x);
662 for ( y=start_y, counter.lat = start_lat; counter.lat <= end_lat; counter.lat += nscale_deg * skip_factor, y += skip_factor ) {
663 if ( y > column->n_points )
666 elev = column->points[y];
668 // calculate bounding box for drawing
669 gint box_x, box_y, box_width, box_height;
672 box_c.lat += (nscale_deg * skip_factor)/2;
673 box_c.lon -= (escale_deg * skip_factor)/2;
674 vik_coord_load_from_latlon(&tmp, vik_viewport_get_coord_mode(vp), &box_c);
675 vik_viewport_coord_to_screen(vp, &tmp, &box_x, &box_y);
676 // catch box at borders
681 box_c.lat -= nscale_deg * skip_factor;
682 box_c.lon += escale_deg * skip_factor;
683 vik_coord_load_from_latlon(&tmp, vik_viewport_get_coord_mode(vp), &box_c);
684 vik_viewport_coord_to_screen(vp, &tmp, &box_width, &box_height);
687 // catch box at borders
688 if(box_width < 0 || box_height < 0)
689 // skip this as is out of the viewport (e.g. zoomed in so this point is way off screen)
692 gboolean below_minimum = FALSE;
693 if(vdl->type == DEM_TYPE_HEIGHT) {
694 if ( elev != VIK_DEM_INVALID_ELEVATION && elev < vdl->min_elev ) {
695 // Prevent 'elev - vdl->min_elev' from being negative so can safely use as array index
696 elev = ceil ( vdl->min_elev );
697 below_minimum = TRUE;
699 if ( elev != VIK_DEM_INVALID_ELEVATION && elev > vdl->max_elev )
700 elev = vdl->max_elev;
704 if(vdl->type == DEM_TYPE_GRADIENT) {
705 if( elev == VIK_DEM_INVALID_ELEVATION ) {
708 // calculate and sum gradient in all directions
712 // calculate gradient from height points all around the current one
713 new_y = y - gradient_skip_factor;
716 change += get_height_difference(elev, prevcolumn->points[new_y]);
717 change += get_height_difference(elev, column->points[new_y]);
718 change += get_height_difference(elev, nextcolumn->points[new_y]);
720 change += get_height_difference(elev, prevcolumn->points[y]);
721 change += get_height_difference(elev, nextcolumn->points[y]);
723 new_y = y + gradient_skip_factor;
724 if(new_y >= column->n_points)
726 change += get_height_difference(elev, prevcolumn->points[new_y]);
727 change += get_height_difference(elev, column->points[new_y]);
728 change += get_height_difference(elev, nextcolumn->points[new_y]);
730 change = change / ((skip_factor > 1) ? log(skip_factor) : 0.55); // FIXME: better calc.
732 if(change < vdl->min_elev)
733 // Prevent 'change - vdl->min_elev' from being negative so can safely use as array index
734 change = ceil ( vdl->min_elev );
736 if(change > vdl->max_elev)
737 change = vdl->max_elev;
739 // void vik_viewport_draw_rectangle ( VikViewport *vvp, GdkGC *gc, gboolean filled, gint x1, gint y1, gint x2, gint y2 );
740 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);
743 if(vdl->type == DEM_TYPE_HEIGHT) {
744 if ( elev == VIK_DEM_INVALID_ELEVATION )
745 ; /* don't draw it */
746 else if ( elev <= 0 || below_minimum )
747 /* If 'sea' colour or below the defined mininum draw in the configurable colour */
748 vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, box_x, box_y, box_width, box_height);
750 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);
757 } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
758 gdouble max_nor, max_eas, min_nor, min_eas;
759 gdouble start_nor, start_eas, end_nor, end_eas;
763 guint x, y, start_x, start_y;
765 VikCoord tmp; /* TODO: don't use coord_load_from_latlon, especially if in latlon drawing mode */
768 guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 10 ); /* todo: smarter calculation. */
770 VikCoord tleft, tright, bleft, bright;
772 vik_viewport_screen_to_coord ( vp, 0, 0, &tleft );
773 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), 0, &tright );
774 vik_viewport_screen_to_coord ( vp, 0, vik_viewport_get_height(vp), &bleft );
775 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), vik_viewport_get_height(vp), &bright );
778 vik_coord_convert(&tleft, VIK_COORD_UTM);
779 vik_coord_convert(&tright, VIK_COORD_UTM);
780 vik_coord_convert(&bleft, VIK_COORD_UTM);
781 vik_coord_convert(&bright, VIK_COORD_UTM);
783 max_nor = MAX(tleft.north_south, tright.north_south);
784 min_nor = MIN(bleft.north_south, bright.north_south);
785 max_eas = MAX(bright.east_west, tright.east_west);
786 min_eas = MIN(bleft.east_west, tleft.east_west);
788 start_nor = MAX(min_nor, dem->min_north);
789 end_nor = MIN(max_nor, dem->max_north);
790 if ( tleft.utm_zone == dem->utm_zone && bleft.utm_zone == dem->utm_zone
791 && (tleft.utm_letter >= 'N') == (dem->utm_letter >= 'N')
792 && (bleft.utm_letter >= 'N') == (dem->utm_letter >= 'N') ) /* if the utm zones/hemispheres are different, min_eas will be bogus */
793 start_eas = MAX(min_eas, dem->min_east);
795 start_eas = dem->min_east;
796 if ( tright.utm_zone == dem->utm_zone && bright.utm_zone == dem->utm_zone
797 && (tright.utm_letter >= 'N') == (dem->utm_letter >= 'N')
798 && (bright.utm_letter >= 'N') == (dem->utm_letter >= 'N') ) /* if the utm zones/hemispheres are different, min_eas will be bogus */
799 end_eas = MIN(max_eas, dem->max_east);
801 end_eas = dem->max_east;
803 start_nor = floor(start_nor / dem->north_scale) * dem->north_scale;
804 end_nor = ceil (end_nor / dem->north_scale) * dem->north_scale;
805 start_eas = floor(start_eas / dem->east_scale) * dem->east_scale;
806 end_eas = ceil (end_eas / dem->east_scale) * dem->east_scale;
808 vik_dem_east_north_to_xy ( dem, start_eas, start_nor, &start_x, &start_y );
810 /* TODO: why start_x and start_y are -1 -- rounding error from above? */
812 counter.zone = dem->utm_zone;
813 counter.letter = dem->utm_letter;
815 for ( x=start_x, counter.easting = start_eas; counter.easting <= end_eas; counter.easting += dem->east_scale * skip_factor, x += skip_factor ) {
816 if ( x > 0 && x < dem->n_columns ) {
817 column = g_ptr_array_index ( dem->columns, x );
818 for ( y=start_y, counter.northing = start_nor; counter.northing <= end_nor; counter.northing += dem->north_scale * skip_factor, y += skip_factor ) {
819 if ( y > column->n_points )
821 elev = column->points[y];
822 if ( elev != VIK_DEM_INVALID_ELEVATION && elev < vdl->min_elev )
824 if ( elev != VIK_DEM_INVALID_ELEVATION && elev > vdl->max_elev )
829 vik_coord_load_from_utm(&tmp, vik_viewport_get_coord_mode(vp), &counter);
830 vik_viewport_coord_to_screen(vp, &tmp, &a, &b);
831 if ( elev == VIK_DEM_INVALID_ELEVATION )
832 ; /* don't draw it */
833 else if ( elev <= 0 )
834 vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, a-1, b-1, 2, 2 );
836 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 );
844 /* return the continent for the specified lat, lon */
846 static const gchar *srtm_continent_dir ( gint lat, gint lon )
848 extern const char *_srtm_continent_data[];
849 static GHashTable *srtm_continent = NULL;
850 const gchar *continent;
853 if (!srtm_continent) {
856 srtm_continent = g_hash_table_new(g_str_hash, g_str_equal);
857 s = _srtm_continent_data;
858 while (*s != (gchar *)-1) {
861 g_hash_table_insert(srtm_continent, (gpointer) *s, (gpointer) continent);
867 g_snprintf(name, sizeof(name), "%c%02d%c%03d",
868 (lat >= 0) ? 'N' : 'S', ABS(lat),
869 (lon >= 0) ? 'E' : 'W', ABS(lon));
871 return(g_hash_table_lookup(srtm_continent, name));
874 static void dem_layer_draw ( VikDEMLayer *vdl, VikViewport *vp )
876 GList *dems_iter = vdl->files;
880 /* search for SRTM3 90m */
882 if ( vdl->source == DEM_SOURCE_SRTM )
883 srtm_draw_existence ( vp );
884 #ifdef VIK_CONFIG_DEM24K
885 else if ( vdl->source == DEM_SOURCE_DEM24K )
886 dem24k_draw_existence ( vp );
889 while ( dems_iter ) {
890 dem = a_dems_get ( (const char *) (dems_iter->data) );
892 vik_dem_layer_draw_dem ( vdl, vp, dem );
893 dems_iter = dems_iter->next;
897 static void dem_layer_free ( VikDEMLayer *vdl )
901 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ )
902 g_object_unref ( vdl->gcs[i] );
905 if ( vdl->gcsgradient )
906 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
907 g_object_unref ( vdl->gcsgradient[i] );
908 g_free ( vdl->gcsgradient );
910 a_dems_list_free ( vdl->files );
913 VikDEMLayer *dem_layer_create ( VikViewport *vp )
915 VikDEMLayer *vdl = dem_layer_new ( vp );
918 /* TODO: share GCS between layers */
919 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ ) {
921 vdl->gcs[i] = vik_viewport_new_gc ( vp, dem_height_colors[i], UNUSED_LINE_THICKNESS );
923 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
924 vdl->gcsgradient[i] = vik_viewport_new_gc ( vp, dem_gradient_colors[i], UNUSED_LINE_THICKNESS );
928 /**************************************************************
929 **** SOURCES & DOWNLOADING
930 **************************************************************/
936 VikDEMLayer *vdl; /* NULL if not alive */
942 /**************************************************
944 **************************************************/
946 static void srtm_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
949 const gchar *continent_dir;
951 intlat = (int)floor(p->lat);
952 intlon = (int)floor(p->lon);
953 continent_dir = srtm_continent_dir(intlat, intlon);
955 if (!continent_dir) {
957 gchar *msg = g_strdup_printf ( _("No SRTM data available for %f, %f"), p->lat, p->lon );
958 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(p->vdl), msg, VIK_STATUSBAR_INFO );
964 gchar *src_url = g_strdup_printf("%s/%s/%c%02d%c%03d.hgt.zip",
967 (intlat >= 0) ? 'N' : 'S',
969 (intlon >= 0) ? 'E' : 'W',
972 static DownloadFileOptions options = { FALSE, FALSE, NULL, 5, a_check_map_file, NULL, NULL };
973 DownloadResult_t result = a_http_download_get_url ( src_url, NULL, p->dest, &options, NULL );
975 case DOWNLOAD_PARAMETERS_ERROR:
976 case DOWNLOAD_CONTENT_ERROR:
977 case DOWNLOAD_HTTP_ERROR: {
978 gchar *msg = g_strdup_printf ( _("DEM download failure for %f, %f"), p->lat, p->lon );
979 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(p->vdl), msg, VIK_STATUSBAR_INFO );
983 case DOWNLOAD_FILE_WRITE_ERROR: {
984 gchar *msg = g_strdup_printf ( _("DEM write failure for %s"), p->dest );
985 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(p->vdl), msg, VIK_STATUSBAR_INFO );
989 case DOWNLOAD_SUCCESS:
990 case DOWNLOAD_NOT_REQUIRED:
997 static gchar *srtm_lat_lon_to_dest_fn ( gdouble lat, gdouble lon )
1000 const gchar *continent_dir;
1002 intlat = (int)floor(lat);
1003 intlon = (int)floor(lon);
1004 continent_dir = srtm_continent_dir(intlat, intlon);
1007 continent_dir = "nowhere";
1009 return g_strdup_printf("srtm3-%s%s%c%02d%c%03d.hgt.zip",
1012 (intlat >= 0) ? 'N' : 'S',
1014 (intlon >= 0) ? 'E' : 'W',
1019 /* TODO: generalize */
1020 static void srtm_draw_existence ( VikViewport *vp )
1022 gdouble max_lat, max_lon, min_lat, min_lon;
1023 gchar buf[strlen(MAPS_CACHE_DIR)+strlen(SRTM_CACHE_TEMPLATE)+30];
1026 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
1028 for (i = floor(min_lat); i <= floor(max_lat); i++) {
1029 for (j = floor(min_lon); j <= floor(max_lon); j++) {
1030 const gchar *continent_dir;
1031 if ((continent_dir = srtm_continent_dir(i, j)) == NULL)
1033 g_snprintf(buf, sizeof(buf), SRTM_CACHE_TEMPLATE,
1037 (i >= 0) ? 'N' : 'S',
1039 (j >= 0) ? 'E' : 'W',
1041 if ( g_file_test(buf, G_FILE_TEST_EXISTS ) == TRUE ) {
1043 gint x1, y1, x2, y2;
1046 sw.mode = VIK_COORD_LATLON;
1047 ne.north_south = i+1;
1049 ne.mode = VIK_COORD_LATLON;
1050 vik_viewport_coord_to_screen ( vp, &sw, &x1, &y1 );
1051 vik_viewport_coord_to_screen ( vp, &ne, &x2, &y2 );
1052 if ( x1 < 0 ) x1 = 0;
1053 if ( y2 < 0 ) y2 = 0;
1054 vik_viewport_draw_rectangle ( vp, gtk_widget_get_style(GTK_WIDGET(vp))->black_gc,
1055 FALSE, x1, y2, x2-x1, y1-y2 );
1062 /**************************************************
1063 * SOURCE: USGS 24K *
1064 **************************************************/
1066 #ifdef VIK_CONFIG_DEM24K
1068 static void dem24k_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
1070 /* TODO: dest dir */
1071 gchar *cmdline = g_strdup_printf("%s %.03f %.03f",
1072 DEM24K_DOWNLOAD_SCRIPT,
1075 /* FIX: don't use system, use execv or something. check for existence */
1080 static gchar *dem24k_lat_lon_to_dest_fn ( gdouble lat, gdouble lon )
1082 return g_strdup_printf("dem24k/%d/%d/%.03f,%.03f.dem",
1089 /* TODO: generalize */
1090 static void dem24k_draw_existence ( VikViewport *vp )
1092 gdouble max_lat, max_lon, min_lat, min_lon;
1093 gchar buf[strlen(MAPS_CACHE_DIR)+40];
1096 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
1098 for (i = floor(min_lat*8)/8; i <= floor(max_lat*8)/8; i+=0.125) {
1099 /* check lat dir first -- faster */
1100 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/",
1103 if ( g_file_test(buf, G_FILE_TEST_EXISTS) == FALSE )
1105 for (j = floor(min_lon*8)/8; j <= floor(max_lon*8)/8; j+=0.125) {
1106 /* check lon dir first -- faster */
1107 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/%d/",
1111 if ( g_file_test(buf, G_FILE_TEST_EXISTS) == FALSE )
1113 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/%d/%.03f,%.03f.dem",
1119 if ( g_file_test(buf, G_FILE_TEST_EXISTS ) == TRUE ) {
1121 gint x1, y1, x2, y2;
1123 sw.east_west = j-0.125;
1124 sw.mode = VIK_COORD_LATLON;
1125 ne.north_south = i+0.125;
1127 ne.mode = VIK_COORD_LATLON;
1128 vik_viewport_coord_to_screen ( vp, &sw, &x1, &y1 );
1129 vik_viewport_coord_to_screen ( vp, &ne, &x2, &y2 );
1130 if ( x1 < 0 ) x1 = 0;
1131 if ( y2 < 0 ) y2 = 0;
1132 vik_viewport_draw_rectangle ( vp, gtk_widget_get_style(GTK_WIDGET(vp))->black_gc,
1133 FALSE, x1, y2, x2-x1, y1-y2 );
1140 /**************************************************
1141 * SOURCES -- DOWNLOADING & IMPORTING TOOL *
1142 **************************************************
1145 static void weak_ref_cb ( gpointer ptr, GObject * dead_vdl )
1147 DEMDownloadParams *p = ptr;
1148 g_mutex_lock ( p->mutex );
1150 g_mutex_unlock ( p->mutex );
1153 /* Try to add file full_path.
1154 * filename will be copied.
1155 * returns FALSE if file does not exists, TRUE otherwise.
1157 static gboolean dem_layer_add_file ( VikDEMLayer *vdl, const gchar *filename )
1159 if ( g_file_test(filename, G_FILE_TEST_EXISTS) == TRUE ) {
1160 /* only load if file size is not 0 (not in progress) */
1162 (void)g_stat ( filename, &sb );
1164 gchar *duped_path = g_strdup(filename);
1165 vdl->files = g_list_prepend ( vdl->files, duped_path );
1166 a_dems_load ( duped_path );
1167 g_debug("%s: %s", __FUNCTION__, duped_path);
1174 static void dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
1176 if ( p->source == DEM_SOURCE_SRTM )
1177 srtm_dem_download_thread ( p, threaddata );
1178 #ifdef VIK_CONFIG_DEM24K
1179 else if ( p->source == DEM_SOURCE_DEM24K )
1180 dem24k_dem_download_thread ( p, threaddata );
1185 g_mutex_lock ( p->mutex );
1187 g_object_weak_unref ( G_OBJECT(p->vdl), weak_ref_cb, p );
1189 if ( dem_layer_add_file ( p->vdl, p->dest ) )
1190 vik_layer_emit_update ( VIK_LAYER(p->vdl) ); // NB update requested from background thread
1192 g_mutex_unlock ( p->mutex );
1196 static void free_dem_download_params ( DEMDownloadParams *p )
1198 vik_mutex_free ( p->mutex );
1203 static gpointer dem_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1209 * Display a simple dialog with information about the DEM file at this location
1211 static void dem_layer_file_info ( GtkWidget *widget, struct LatLon *ll )
1213 gint intlat, intlon;
1214 const gchar *continent_dir;
1216 intlat = (int)floor(ll->lat);
1217 intlon = (int)floor(ll->lon);
1218 continent_dir = srtm_continent_dir(intlat, intlon);
1220 gchar *source = NULL;
1221 if ( continent_dir )
1222 source = g_strdup_printf ( "%s/%s/%c%02d%c%03d.hgt.zip",
1225 (intlat >= 0) ? 'N' : 'S',
1227 (intlon >= 0) ? 'E' : 'W',
1230 // Probably not over any land...
1231 source = g_strdup ( _("No DEM File Available") );
1233 gchar *filename = NULL;
1234 gchar *dem_file = NULL;
1235 #ifdef VIK_CONFIG_DEM24K
1236 dem_file = dem24k_lat_lon_to_dest_fn ( ll->lat, ll->lon );
1238 dem_file = srtm_lat_lon_to_dest_fn ( ll->lat, ll->lon );
1240 gchar *message = NULL;
1242 filename = g_strdup_printf ( "%s%s", MAPS_CACHE_DIR, dem_file );
1244 if ( g_file_test ( filename, G_FILE_TEST_EXISTS ) ) {
1245 // Get some timestamp information of the file
1247 if ( g_stat ( filename, &stat_buf ) == 0 ) {
1249 strftime ( time_buf, sizeof(time_buf), "%c", gmtime((const time_t *)&stat_buf.st_mtime) );
1250 message = g_strdup_printf ( _("\nSource: %s\n\nDEM File: %s\nDEM File Timestamp: %s"), source, filename, time_buf );
1254 message = g_strdup_printf ( _("Source: %s\n\nNo DEM File!"), source );
1257 a_dialog_info_msg ( GTK_WINDOW(gtk_widget_get_toplevel(widget)), message );
1261 g_free ( dem_file );
1262 g_free ( filename );
1265 static gboolean dem_layer_download_release ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp )
1268 static struct LatLon ll;
1271 gchar *dem_file = NULL;
1273 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1274 vik_coord_to_latlon ( &coord, &ll );
1277 if ( vdl->source == DEM_SOURCE_SRTM )
1278 dem_file = srtm_lat_lon_to_dest_fn ( ll.lat, ll.lon );
1279 #ifdef VIK_CONFIG_DEM24K
1280 else if ( vdl->source == DEM_SOURCE_DEM24K )
1281 dem_file = dem24k_lat_lon_to_dest_fn ( ll.lat, ll.lon );
1287 full_path = g_strdup_printf("%s%s", MAPS_CACHE_DIR, dem_file );
1289 g_debug("%s: %s", __FUNCTION__, full_path);
1291 if ( event->button == 1 ) {
1292 // TODO: check if already in filelist
1293 if ( ! dem_layer_add_file(vdl, full_path) ) {
1294 gchar *tmp = g_strdup_printf ( _("Downloading DEM %s"), dem_file );
1295 DEMDownloadParams *p = g_malloc(sizeof(DEMDownloadParams));
1296 p->dest = g_strdup(full_path);
1300 p->mutex = vik_mutex_new();
1301 p->source = vdl->source;
1302 g_object_weak_ref(G_OBJECT(p->vdl), weak_ref_cb, p );
1304 a_background_thread ( BACKGROUND_POOL_REMOTE,
1305 VIK_GTK_WINDOW_FROM_LAYER(vdl), tmp,
1306 (vik_thr_func) dem_download_thread, p,
1307 (vik_thr_free_func) free_dem_download_params, NULL, 1 );
1312 vik_layer_emit_update ( VIK_LAYER(vdl) );
1315 if ( !vdl->right_click_menu ) {
1317 vdl->right_click_menu = GTK_MENU ( gtk_menu_new () );
1319 item = gtk_image_menu_item_new_with_mnemonic ( _("_Show DEM File Information") );
1320 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INFO, GTK_ICON_SIZE_MENU) );
1321 g_signal_connect ( G_OBJECT(item), "activate", G_CALLBACK(dem_layer_file_info), &ll );
1322 gtk_menu_shell_append (GTK_MENU_SHELL(vdl->right_click_menu), item);
1325 gtk_menu_popup ( vdl->right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1326 gtk_widget_show_all ( GTK_WIDGET(vdl->right_click_menu) );
1329 g_free ( dem_file );
1330 g_free ( full_path );
1335 static gboolean dem_layer_download_click ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp )
1337 /* choose & keep track of cache dir
1338 * download in background thread
1339 * download over area */