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, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation );
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[] = {
135 { { "DEMDownload", "vik-icon-DEM Download", N_("_DEM Download"), NULL, N_("DEM Download"), 0 },
136 (VikToolConstructorFunc) dem_layer_download_create, NULL, NULL, NULL,
137 (VikToolMouseFunc) dem_layer_download_click, NULL, (VikToolMouseFunc) dem_layer_download_release,
138 (VikToolKeyFunc) NULL,
140 GDK_CURSOR_IS_PIXMAP, &cursor_demdl_pixbuf, NULL },
145 The first entry is blue for a default 'sea' colour,
146 however the value used by the corresponding gc can be configured as part of the DEM layer properties.
147 The other colours, shaded from brown to white are used to give an indication of height.
149 static gchar *dem_height_colors[] = {
151 "#9b793c", "#9c7d40", "#9d8144", "#9e8549", "#9f894d", "#a08d51", "#a29156", "#a3955a", "#a4995e", "#a69d63",
152 "#a89f65", "#aaa267", "#ada569", "#afa76b", "#b1aa6d", "#b4ad6f", "#b6b071", "#b9b373", "#bcb676", "#beb978",
153 "#c0bc7a", "#c2c07d", "#c4c37f", "#c6c681", "#c8ca84", "#cacd86", "#ccd188", "#cfd58b", "#c2ce84", "#b5c87e",
154 "#a9c278", "#9cbb71", "#8fb56b", "#83af65", "#76a95e", "#6aa358", "#5e9d52", "#63a055", "#69a458", "#6fa85c",
155 "#74ac5f", "#7ab063", "#80b467", "#86b86a", "#8cbc6e", "#92c072", "#94c175", "#97c278", "#9ac47c", "#9cc57f",
156 "#9fc682", "#a2c886", "#a4c989", "#a7cb8d", "#aacd91", "#afce99", "#b5d0a1", "#bbd2aa", "#c0d3b2", "#c6d5ba",
157 "#ccd7c3", "#d1d9cb", "#d7dbd4", "#DDDDDD", "#e0e0e0", "#e4e4e4", "#e8e8e8", "#ebebeb", "#efefef", "#f3f3f3",
158 "#f7f7f7", "#fbfbfb", "#ffffff"
161 static const guint DEM_N_HEIGHT_COLORS = sizeof(dem_height_colors)/sizeof(dem_height_colors[0]);
164 "#9b793c", "#9e8549", "#a29156", "#a69d63", "#ada569", "#b4ad6f", "#bcb676", "#c2c07d", "#c8ca84", "#cfd58b",
165 "#a9c278", "#83af65", "#5e9d52", "#6fa85c", "#80b467", "#92c072", "#9ac47c", "#a2c886", "#aacd91", "#bbd2aa",
166 "#ccd7c3", "#DDDDDD", "#e8e8e8", "#f3f3f3", "#FFFFFF"
170 static gchar *dem_gradient_colors[] = {
172 "#000000", "#000011", "#000022", "#000033", "#000044", "#00004c", "#000055", "#00005d", "#000066", "#00006e",
173 "#000077", "#00007f", "#000088", "#000090", "#000099", "#0000a1", "#0000aa", "#0000b2", "#0000bb", "#0000c3",
174 "#0000cc", "#0000d4", "#0000dd", "#0000e5", "#0000ee", "#0000f6", "#0000ff", "#0008f7", "#0011ee", "#0019e6",
175 "#0022dd", "#002ad5", "#0033cc", "#003bc4", "#0044bb", "#004cb3", "#0055aa", "#005da2", "#006699", "#006e91",
176 "#007788", "#007f80", "#008877", "#00906f", "#009966", "#00a15e", "#00aa55", "#00b24d", "#00bb44", "#00c33c",
177 "#00cc33", "#00d42b", "#00dd22", "#00e51a", "#00ee11", "#00f609", "#00ff00", "#08f700", "#11ee00", "#19e600",
178 "#22dd00", "#2ad500", "#33cc00", "#3bc400", "#44bb00", "#4cb300", "#55aa00", "#5da200", "#669900", "#6e9100",
179 "#778800", "#7f8000", "#887700", "#906f00", "#996600", "#a15e00", "#aa5500", "#b24d00", "#bb4400", "#c33c00",
180 "#cc3300", "#d42b00", "#dd2200", "#e51a00", "#ee1100", "#f60900", "#ff0000",
184 static const guint DEM_N_GRADIENT_COLORS = sizeof(dem_gradient_colors)/sizeof(dem_gradient_colors[0]);
187 VikLayerInterface vik_dem_layer_interface = {
194 sizeof(dem_tools) / sizeof(dem_tools[0]),
203 (VikLayerFuncCreate) dem_layer_create,
204 (VikLayerFuncRealize) NULL,
205 (VikLayerFuncPostRead) dem_layer_post_read,
206 (VikLayerFuncFree) dem_layer_free,
208 (VikLayerFuncProperties) NULL,
209 (VikLayerFuncDraw) dem_layer_draw,
210 (VikLayerFuncChangeCoordMode) NULL,
212 (VikLayerFuncGetTimestamp) NULL,
214 (VikLayerFuncSetMenuItemsSelection) NULL,
215 (VikLayerFuncGetMenuItemsSelection) NULL,
217 (VikLayerFuncAddMenuItems) NULL,
218 (VikLayerFuncSublayerAddMenuItems) NULL,
220 (VikLayerFuncSublayerRenameRequest) NULL,
221 (VikLayerFuncSublayerToggleVisible) NULL,
222 (VikLayerFuncSublayerTooltip) NULL,
223 (VikLayerFuncLayerTooltip) dem_layer_tooltip,
224 (VikLayerFuncLayerSelected) NULL,
226 (VikLayerFuncMarshall) dem_layer_marshall,
227 (VikLayerFuncUnmarshall) dem_layer_unmarshall,
229 (VikLayerFuncSetParam) dem_layer_set_param,
230 (VikLayerFuncGetParam) dem_layer_get_param,
231 (VikLayerFuncChangeParam) NULL,
233 (VikLayerFuncReadFileData) NULL,
234 (VikLayerFuncWriteFileData) NULL,
236 (VikLayerFuncDeleteItem) NULL,
237 (VikLayerFuncCutItem) NULL,
238 (VikLayerFuncCopyItem) NULL,
239 (VikLayerFuncPasteItem) NULL,
240 (VikLayerFuncFreeCopiedItem) NULL,
241 (VikLayerFuncDragDropRequest) NULL,
243 (VikLayerFuncSelectClick) NULL,
244 (VikLayerFuncSelectMove) NULL,
245 (VikLayerFuncSelectRelease) NULL,
246 (VikLayerFuncSelectedViewportMenu) NULL,
249 struct _VikDEMLayer {
260 // right click menu only stuff - similar to mapslayer
261 GtkMenu *right_click_menu;
264 // NB Only performed once per program run
265 static void vik_dem_class_init ( VikDEMLayerClass *klass )
267 // Note if suppling your own base URL - the site must still follow the Continent directory layout
268 if ( ! a_settings_get_string ( VIK_SETTINGS_SRTM_HTTP_BASE_URL, &base_url ) ) {
269 // Otherwise use the default
270 base_url = g_strdup ( SRTM_HTTP_BASE_URL );
274 GType vik_dem_layer_get_type ()
276 static GType vdl_type = 0;
280 static const GTypeInfo vdl_info =
282 sizeof (VikDEMLayerClass),
283 NULL, /* base_init */
284 NULL, /* base_finalize */
285 (GClassInitFunc) vik_dem_class_init, /* class init */
286 NULL, /* class_finalize */
287 NULL, /* class_data */
288 sizeof (VikDEMLayer),
290 NULL /* instance init */
292 vdl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikDEMLayer", &vdl_info, 0 );
298 static const gchar* dem_layer_tooltip( VikDEMLayer *vdl )
300 static gchar tmp_buf[100];
301 g_snprintf (tmp_buf, sizeof(tmp_buf), _("Number of files: %d"), g_list_length (vdl->files));
305 static void dem_layer_marshall( VikDEMLayer *vdl, guint8 **data, gint *len )
307 vik_layer_marshall_params ( VIK_LAYER(vdl), data, len );
310 static VikDEMLayer *dem_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
312 VikDEMLayer *rv = dem_layer_new ( vvp );
315 /* TODO: share GCS between layers */
316 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ ) {
318 rv->gcs[i] = vik_viewport_new_gc_from_color ( vvp, &(rv->color), UNUSED_LINE_THICKNESS );
320 rv->gcs[i] = vik_viewport_new_gc ( vvp, dem_height_colors[i], UNUSED_LINE_THICKNESS );
322 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
323 rv->gcsgradient[i] = vik_viewport_new_gc ( vvp, dem_gradient_colors[i], UNUSED_LINE_THICKNESS );
325 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
329 /* Structure for DEM data used in background thread */
332 } dem_load_thread_data;
335 * Function for starting the DEM file loading as a background thread
337 static int dem_layer_load_list_thread ( dem_load_thread_data *dltd, gpointer threaddata )
339 int result = 0; // Default to good
341 if ( a_dems_load_list ( &(dltd->vdl->files), threaddata ) ) {
346 // ATM as each file is processed the screen is not updated (no mechanism exposed to a_dems_load_list)
347 // Thus force draw only at the end, as loading is complete/aborted
348 // Test is helpful to prevent Gtk-CRITICAL warnings if the program is exitted whilst loading
349 if ( IS_VIK_LAYER(dltd->vdl) )
350 vik_layer_emit_update ( VIK_LAYER(dltd->vdl) ); // NB update requested from background thread
355 static void dem_layer_thread_data_free ( dem_load_thread_data *data )
361 static void dem_layer_thread_cancel ( dem_load_thread_data *data )
364 // Instead of freeing the list, leave it as partially processed
365 // Thus we can see/use what was done
369 * Process the list of DEM files and convert each one to a relative path
371 static GList *dem_layer_convert_to_relative_filenaming ( GList *files )
373 gchar *cwd = g_get_current_dir();
377 GList *relfiles = NULL;
380 gchar *file = g_strdup ( file_GetRelativeFilename ( cwd, files->data ) );
381 relfiles = g_list_prepend ( relfiles, file );
388 // Replacing current list, so delete old values first.
391 g_free ( iter->data );
394 g_list_free ( files );
402 gboolean dem_layer_set_param ( VikDEMLayer *vdl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
406 case PARAM_COLOR: vdl->color = data.c; gdk_gc_set_rgb_fg_color ( vdl->gcs[0], &(vdl->color) ); break;
407 case PARAM_SOURCE: vdl->source = data.u; break;
408 case PARAM_TYPE: vdl->type = data.u; break;
410 /* Convert to store internally
411 NB file operation always in internal units (metres) */
412 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
413 vdl->min_elev = VIK_FEET_TO_METERS(data.d);
415 vdl->min_elev = data.d;
418 /* Convert to store internally
419 NB file operation always in internal units (metres) */
420 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
421 vdl->max_elev = VIK_FEET_TO_METERS(data.d);
423 vdl->max_elev = data.d;
427 // Clear out old settings - if any commonalities with new settings they will have to be read again
428 a_dems_list_free ( vdl->files );
429 // Set file list so any other intermediate screen drawing updates will show currently loaded DEMs by the working thread
430 vdl->files = data.sl;
431 // No need for thread if no files
434 dem_load_thread_data *dltd = g_malloc ( sizeof(dem_load_thread_data) );
436 dltd->vdl->files = data.sl;
438 a_background_thread ( BACKGROUND_POOL_LOCAL,
439 VIK_GTK_WINDOW_FROM_WIDGET(vp),
441 (vik_thr_func) dem_layer_load_list_thread,
443 (vik_thr_free_func) dem_layer_thread_data_free,
444 (vik_thr_free_func) dem_layer_thread_cancel,
445 g_list_length ( data.sl ) ); // Number of DEM files
454 static VikLayerParamData dem_layer_get_param ( VikDEMLayer *vdl, guint16 id, gboolean is_file_operation )
456 VikLayerParamData rv;
461 if ( is_file_operation )
462 // Save in relative format if necessary
463 if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE )
464 rv.sl = dem_layer_convert_to_relative_filenaming ( rv.sl );
466 case PARAM_SOURCE: rv.u = vdl->source; break;
467 case PARAM_TYPE: rv.u = vdl->type; break;
468 case PARAM_COLOR: rv.c = vdl->color; break;
470 /* Convert for display in desired units
471 NB file operation always in internal units (metres) */
472 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
473 rv.d = VIK_METERS_TO_FEET(vdl->min_elev);
475 rv.d = vdl->min_elev;
478 /* Convert for display in desired units
479 NB file operation always in internal units (metres) */
480 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
481 rv.d = VIK_METERS_TO_FEET(vdl->max_elev);
483 rv.d = vdl->max_elev;
490 static void dem_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file )
492 /* nothing ATM, but keep in case it's needed the future */
495 static VikDEMLayer *dem_layer_new ( VikViewport *vvp )
497 VikDEMLayer *vdl = VIK_DEM_LAYER ( g_object_new ( VIK_DEM_LAYER_TYPE, NULL ) );
499 vik_layer_set_type ( VIK_LAYER(vdl), VIK_LAYER_DEM );
503 vdl->gcs = g_malloc(sizeof(GdkGC *)*DEM_N_HEIGHT_COLORS);
504 vdl->gcsgradient = g_malloc(sizeof(GdkGC *)*DEM_N_GRADIENT_COLORS);
505 /* make new gcs only if we need it (copy layer -> use old) */
507 // Ensure the base GC is available so the default colour can be applied
508 if ( vvp ) vdl->gcs[0] = vik_viewport_new_gc ( vvp, "#0000FF", 1 );
510 vik_layer_set_defaults ( VIK_LAYER(vdl), vvp );
516 static inline guint16 get_height_difference(gint16 elev, gint16 new_elev)
518 if(new_elev == VIK_DEM_INVALID_ELEVATION)
521 return abs(new_elev - elev);
525 static void vik_dem_layer_draw_dem ( VikDEMLayer *vdl, VikViewport *vp, VikDEM *dem )
527 VikDEMColumn *column, *prevcolumn, *nextcolumn;
529 struct LatLon dem_northeast, dem_southwest;
530 gdouble max_lat, max_lon, min_lat, min_lon;
532 /**** Check if viewport and DEM data overlap ****/
534 /* get min, max lat/lon of viewport */
535 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
537 /* get min, max lat/lon of DEM data */
538 if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
539 dem_northeast.lat = dem->max_north / 3600.0;
540 dem_northeast.lon = dem->max_east / 3600.0;
541 dem_southwest.lat = dem->min_north / 3600.0;
542 dem_southwest.lon = dem->min_east / 3600.0;
543 } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
544 struct UTM dem_northeast_utm, dem_southwest_utm;
545 dem_northeast_utm.northing = dem->max_north;
546 dem_northeast_utm.easting = dem->max_east;
547 dem_southwest_utm.northing = dem->min_north;
548 dem_southwest_utm.easting = dem->min_east;
549 dem_northeast_utm.zone = dem_southwest_utm.zone = dem->utm_zone;
550 dem_northeast_utm.letter = dem_southwest_utm.letter = dem->utm_letter;
552 a_coords_utm_to_latlon(&dem_northeast_utm, &dem_northeast);
553 a_coords_utm_to_latlon(&dem_southwest_utm, &dem_southwest);
555 // Unknown horiz_units - this shouldn't normally happen
556 // Thus can't work out positions to use
560 if ( (max_lat > dem_northeast.lat && min_lat > dem_northeast.lat) ||
561 (max_lat < dem_southwest.lat && min_lat < dem_southwest.lat) )
563 else if ( (max_lon > dem_northeast.lon && min_lon > dem_northeast.lon) ||
564 (max_lon < dem_southwest.lon && min_lon < dem_southwest.lon) )
566 /* else they overlap */
568 /**** End Overlap Check ****/
569 /* boxes to show where we have DEM instead of actually drawing the DEM.
570 * useful if we want to see what areas we have coverage for (if we want
571 * to get elevation data for a track) but don't want to cover the map.
575 /* draw a box if a DEM is loaded. in future I'd like to add an option for this
576 * this is useful if we want to see what areas we have dem for but don't want to
577 * cover the map (or maybe we just need translucent DEM?) */
579 VikCoord demne, demsw;
581 vik_coord_load_from_latlon(&demne, vik_viewport_get_coord_mode(vp), &dem_northeast);
582 vik_coord_load_from_latlon(&demsw, vik_viewport_get_coord_mode(vp), &dem_southwest);
584 vik_viewport_coord_to_screen ( vp, &demne, &x1, &y1 );
585 vik_viewport_coord_to_screen ( vp, &demsw, &x2, &y2 );
587 if ( x1 > vik_viewport_get_width(vp) ) x1=vik_viewport_get_width(vp);
588 if ( y2 > vik_viewport_get_height(vp) ) y2=vik_viewport_get_height(vp);
589 if ( x2 < 0 ) x2 = 0;
590 if ( y1 < 0 ) y1 = 0;
591 vik_viewport_draw_rectangle ( vp, gtk_widget_get_style(GTK_WIDGET(vp))->black_gc,
592 FALSE, x2, y1, x1-x2, y2-y1 );
597 if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
598 VikCoord tmp; /* TODO: don't use coord_load_from_latlon, especially if in latlon drawing mode */
600 gdouble max_lat_as, max_lon_as, min_lat_as, min_lon_as;
601 gdouble start_lat_as, end_lat_as, start_lon_as, end_lon_as;
603 gdouble start_lat, end_lat, start_lon, end_lon;
605 struct LatLon counter;
607 guint x, y, start_x, start_y;
611 guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 80 ); /* todo: smarter calculation. */
613 gdouble nscale_deg = dem->north_scale / ((gdouble) 3600);
614 gdouble escale_deg = dem->east_scale / ((gdouble) 3600);
616 max_lat_as = max_lat * 3600;
617 min_lat_as = min_lat * 3600;
618 max_lon_as = max_lon * 3600;
619 min_lon_as = min_lon * 3600;
621 start_lat_as = MAX(min_lat_as, dem->min_north);
622 end_lat_as = MIN(max_lat_as, dem->max_north);
623 start_lon_as = MAX(min_lon_as, dem->min_east);
624 end_lon_as = MIN(max_lon_as, dem->max_east);
626 start_lat = floor(start_lat_as / dem->north_scale) * nscale_deg;
627 end_lat = ceil (end_lat_as / dem->north_scale) * nscale_deg;
628 start_lon = floor(start_lon_as / dem->east_scale) * escale_deg;
629 end_lon = ceil (end_lon_as / dem->east_scale) * escale_deg;
631 vik_dem_east_north_to_xy ( dem, start_lon_as, start_lat_as, &start_x, &start_y );
632 guint gradient_skip_factor = 1;
633 if(vdl->type == DEM_TYPE_GRADIENT)
634 gradient_skip_factor = skip_factor;
636 /* verify sane elev interval */
637 if ( vdl->max_elev <= vdl->min_elev )
638 vdl->max_elev = vdl->min_elev + 1;
640 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 ) {
641 // NOTE: ( counter.lon <= end_lon + ESCALE_DEG*SKIP_FACTOR ) is neccessary so in high zoom modes,
642 // the leftmost column does also get drawn, if the center point is out of viewport.
643 if ( x < dem->n_columns ) {
644 column = g_ptr_array_index ( dem->columns, x );
645 // get previous and next column. catch out-of-bound.
647 new_x -= gradient_skip_factor;
649 prevcolumn = g_ptr_array_index ( dem->columns, x+1);
651 prevcolumn = g_ptr_array_index ( dem->columns, new_x);
653 new_x += gradient_skip_factor;
654 if(new_x >= dem->n_columns)
655 nextcolumn = g_ptr_array_index ( dem->columns, x-1);
657 nextcolumn = g_ptr_array_index ( dem->columns, new_x);
659 for ( y=start_y, counter.lat = start_lat; counter.lat <= end_lat; counter.lat += nscale_deg * skip_factor, y += skip_factor ) {
660 if ( y > column->n_points )
663 elev = column->points[y];
665 // calculate bounding box for drawing
666 gint box_x, box_y, box_width, box_height;
669 box_c.lat += (nscale_deg * skip_factor)/2;
670 box_c.lon -= (escale_deg * skip_factor)/2;
671 vik_coord_load_from_latlon(&tmp, vik_viewport_get_coord_mode(vp), &box_c);
672 vik_viewport_coord_to_screen(vp, &tmp, &box_x, &box_y);
673 // catch box at borders
678 box_c.lat -= nscale_deg * skip_factor;
679 box_c.lon += escale_deg * skip_factor;
680 vik_coord_load_from_latlon(&tmp, vik_viewport_get_coord_mode(vp), &box_c);
681 vik_viewport_coord_to_screen(vp, &tmp, &box_width, &box_height);
684 // catch box at borders
685 if(box_width < 0 || box_height < 0)
686 // skip this as is out of the viewport (e.g. zoomed in so this point is way off screen)
689 gboolean below_minimum = FALSE;
690 if(vdl->type == DEM_TYPE_HEIGHT) {
691 if ( elev != VIK_DEM_INVALID_ELEVATION && elev < vdl->min_elev ) {
692 // Prevent 'elev - vdl->min_elev' from being negative so can safely use as array index
693 elev = ceil ( vdl->min_elev );
694 below_minimum = TRUE;
696 if ( elev != VIK_DEM_INVALID_ELEVATION && elev > vdl->max_elev )
697 elev = vdl->max_elev;
701 if(vdl->type == DEM_TYPE_GRADIENT) {
702 if( elev == VIK_DEM_INVALID_ELEVATION ) {
705 // calculate and sum gradient in all directions
709 // calculate gradient from height points all around the current one
710 new_y = y - gradient_skip_factor;
713 change += get_height_difference(elev, prevcolumn->points[new_y]);
714 change += get_height_difference(elev, column->points[new_y]);
715 change += get_height_difference(elev, nextcolumn->points[new_y]);
717 change += get_height_difference(elev, prevcolumn->points[y]);
718 change += get_height_difference(elev, nextcolumn->points[y]);
720 new_y = y + gradient_skip_factor;
721 if(new_y >= column->n_points)
723 change += get_height_difference(elev, prevcolumn->points[new_y]);
724 change += get_height_difference(elev, column->points[new_y]);
725 change += get_height_difference(elev, nextcolumn->points[new_y]);
727 change = change / ((skip_factor > 1) ? log(skip_factor) : 0.55); // FIXME: better calc.
729 if(change < vdl->min_elev)
730 // Prevent 'change - vdl->min_elev' from being negative so can safely use as array index
731 change = ceil ( vdl->min_elev );
733 if(change > vdl->max_elev)
734 change = vdl->max_elev;
736 // void vik_viewport_draw_rectangle ( VikViewport *vvp, GdkGC *gc, gboolean filled, gint x1, gint y1, gint x2, gint y2 );
737 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);
740 if(vdl->type == DEM_TYPE_HEIGHT) {
741 if ( elev == VIK_DEM_INVALID_ELEVATION )
742 ; /* don't draw it */
743 else if ( elev <= 0 || below_minimum )
744 /* If 'sea' colour or below the defined mininum draw in the configurable colour */
745 vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, box_x, box_y, box_width, box_height);
747 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);
754 } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
755 gdouble max_nor, max_eas, min_nor, min_eas;
756 gdouble start_nor, start_eas, end_nor, end_eas;
760 guint x, y, start_x, start_y;
762 VikCoord tmp; /* TODO: don't use coord_load_from_latlon, especially if in latlon drawing mode */
765 guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 10 ); /* todo: smarter calculation. */
767 VikCoord tleft, tright, bleft, bright;
769 vik_viewport_screen_to_coord ( vp, 0, 0, &tleft );
770 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), 0, &tright );
771 vik_viewport_screen_to_coord ( vp, 0, vik_viewport_get_height(vp), &bleft );
772 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), vik_viewport_get_height(vp), &bright );
775 vik_coord_convert(&tleft, VIK_COORD_UTM);
776 vik_coord_convert(&tright, VIK_COORD_UTM);
777 vik_coord_convert(&bleft, VIK_COORD_UTM);
778 vik_coord_convert(&bright, VIK_COORD_UTM);
780 max_nor = MAX(tleft.north_south, tright.north_south);
781 min_nor = MIN(bleft.north_south, bright.north_south);
782 max_eas = MAX(bright.east_west, tright.east_west);
783 min_eas = MIN(bleft.east_west, tleft.east_west);
785 start_nor = MAX(min_nor, dem->min_north);
786 end_nor = MIN(max_nor, dem->max_north);
787 if ( tleft.utm_zone == dem->utm_zone && bleft.utm_zone == dem->utm_zone
788 && (tleft.utm_letter >= 'N') == (dem->utm_letter >= 'N')
789 && (bleft.utm_letter >= 'N') == (dem->utm_letter >= 'N') ) /* if the utm zones/hemispheres are different, min_eas will be bogus */
790 start_eas = MAX(min_eas, dem->min_east);
792 start_eas = dem->min_east;
793 if ( tright.utm_zone == dem->utm_zone && bright.utm_zone == dem->utm_zone
794 && (tright.utm_letter >= 'N') == (dem->utm_letter >= 'N')
795 && (bright.utm_letter >= 'N') == (dem->utm_letter >= 'N') ) /* if the utm zones/hemispheres are different, min_eas will be bogus */
796 end_eas = MIN(max_eas, dem->max_east);
798 end_eas = dem->max_east;
800 start_nor = floor(start_nor / dem->north_scale) * dem->north_scale;
801 end_nor = ceil (end_nor / dem->north_scale) * dem->north_scale;
802 start_eas = floor(start_eas / dem->east_scale) * dem->east_scale;
803 end_eas = ceil (end_eas / dem->east_scale) * dem->east_scale;
805 vik_dem_east_north_to_xy ( dem, start_eas, start_nor, &start_x, &start_y );
807 /* TODO: why start_x and start_y are -1 -- rounding error from above? */
809 counter.zone = dem->utm_zone;
810 counter.letter = dem->utm_letter;
812 for ( x=start_x, counter.easting = start_eas; counter.easting <= end_eas; counter.easting += dem->east_scale * skip_factor, x += skip_factor ) {
813 if ( x > 0 && x < dem->n_columns ) {
814 column = g_ptr_array_index ( dem->columns, x );
815 for ( y=start_y, counter.northing = start_nor; counter.northing <= end_nor; counter.northing += dem->north_scale * skip_factor, y += skip_factor ) {
816 if ( y > column->n_points )
818 elev = column->points[y];
819 if ( elev != VIK_DEM_INVALID_ELEVATION && elev < vdl->min_elev )
821 if ( elev != VIK_DEM_INVALID_ELEVATION && elev > vdl->max_elev )
826 vik_coord_load_from_utm(&tmp, vik_viewport_get_coord_mode(vp), &counter);
827 vik_viewport_coord_to_screen(vp, &tmp, &a, &b);
828 if ( elev == VIK_DEM_INVALID_ELEVATION )
829 ; /* don't draw it */
830 else if ( elev <= 0 )
831 vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, a-1, b-1, 2, 2 );
833 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 );
841 /* return the continent for the specified lat, lon */
843 static const gchar *srtm_continent_dir ( gint lat, gint lon )
845 extern const char *_srtm_continent_data[];
846 static GHashTable *srtm_continent = NULL;
847 const gchar *continent;
850 if (!srtm_continent) {
853 srtm_continent = g_hash_table_new(g_str_hash, g_str_equal);
854 s = _srtm_continent_data;
855 while (*s != (gchar *)-1) {
858 g_hash_table_insert(srtm_continent, (gpointer) *s, (gpointer) continent);
864 g_snprintf(name, sizeof(name), "%c%02d%c%03d",
865 (lat >= 0) ? 'N' : 'S', ABS(lat),
866 (lon >= 0) ? 'E' : 'W', ABS(lon));
868 return(g_hash_table_lookup(srtm_continent, name));
871 static void dem_layer_draw ( VikDEMLayer *vdl, VikViewport *vp )
873 GList *dems_iter = vdl->files;
877 /* search for SRTM3 90m */
879 if ( vdl->source == DEM_SOURCE_SRTM )
880 srtm_draw_existence ( vp );
881 #ifdef VIK_CONFIG_DEM24K
882 else if ( vdl->source == DEM_SOURCE_DEM24K )
883 dem24k_draw_existence ( vp );
886 while ( dems_iter ) {
887 dem = a_dems_get ( (const char *) (dems_iter->data) );
889 vik_dem_layer_draw_dem ( vdl, vp, dem );
890 dems_iter = dems_iter->next;
894 static void dem_layer_free ( VikDEMLayer *vdl )
898 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ )
899 g_object_unref ( vdl->gcs[i] );
902 if ( vdl->gcsgradient )
903 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
904 g_object_unref ( vdl->gcsgradient[i] );
905 g_free ( vdl->gcsgradient );
907 a_dems_list_free ( vdl->files );
910 VikDEMLayer *dem_layer_create ( VikViewport *vp )
912 VikDEMLayer *vdl = dem_layer_new ( vp );
915 /* TODO: share GCS between layers */
916 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ ) {
918 vdl->gcs[i] = vik_viewport_new_gc ( vp, dem_height_colors[i], UNUSED_LINE_THICKNESS );
920 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
921 vdl->gcsgradient[i] = vik_viewport_new_gc ( vp, dem_gradient_colors[i], UNUSED_LINE_THICKNESS );
925 /**************************************************************
926 **** SOURCES & DOWNLOADING
927 **************************************************************/
933 VikDEMLayer *vdl; /* NULL if not alive */
939 /**************************************************
941 **************************************************/
943 static void srtm_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
946 const gchar *continent_dir;
948 intlat = (int)floor(p->lat);
949 intlon = (int)floor(p->lon);
950 continent_dir = srtm_continent_dir(intlat, intlon);
952 if (!continent_dir) {
954 gchar *msg = g_strdup_printf ( _("No SRTM data available for %f, %f"), p->lat, p->lon );
955 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(p->vdl), msg, VIK_STATUSBAR_INFO );
961 gchar *src_url = g_strdup_printf("%s/%s/%c%02d%c%03d.hgt.zip",
964 (intlat >= 0) ? 'N' : 'S',
966 (intlon >= 0) ? 'E' : 'W',
969 static DownloadFileOptions options = { FALSE, FALSE, NULL, 5, a_check_map_file, NULL, NULL };
970 DownloadResult_t result = a_http_download_get_url ( src_url, NULL, p->dest, &options, NULL );
972 case DOWNLOAD_PARAMETERS_ERROR:
973 case DOWNLOAD_CONTENT_ERROR:
974 case DOWNLOAD_HTTP_ERROR: {
975 gchar *msg = g_strdup_printf ( _("DEM download failure for %f, %f"), p->lat, p->lon );
976 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(p->vdl), msg, VIK_STATUSBAR_INFO );
980 case DOWNLOAD_FILE_WRITE_ERROR: {
981 gchar *msg = g_strdup_printf ( _("DEM write failure for %s"), p->dest );
982 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(p->vdl), msg, VIK_STATUSBAR_INFO );
986 case DOWNLOAD_SUCCESS:
987 case DOWNLOAD_NOT_REQUIRED:
994 static gchar *srtm_lat_lon_to_dest_fn ( gdouble lat, gdouble lon )
997 const gchar *continent_dir;
999 intlat = (int)floor(lat);
1000 intlon = (int)floor(lon);
1001 continent_dir = srtm_continent_dir(intlat, intlon);
1004 continent_dir = "nowhere";
1006 return g_strdup_printf("srtm3-%s%s%c%02d%c%03d.hgt.zip",
1009 (intlat >= 0) ? 'N' : 'S',
1011 (intlon >= 0) ? 'E' : 'W',
1016 /* TODO: generalize */
1017 static void srtm_draw_existence ( VikViewport *vp )
1019 gdouble max_lat, max_lon, min_lat, min_lon;
1020 gchar buf[strlen(MAPS_CACHE_DIR)+strlen(SRTM_CACHE_TEMPLATE)+30];
1023 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
1025 for (i = floor(min_lat); i <= floor(max_lat); i++) {
1026 for (j = floor(min_lon); j <= floor(max_lon); j++) {
1027 const gchar *continent_dir;
1028 if ((continent_dir = srtm_continent_dir(i, j)) == NULL)
1030 g_snprintf(buf, sizeof(buf), SRTM_CACHE_TEMPLATE,
1034 (i >= 0) ? 'N' : 'S',
1036 (j >= 0) ? 'E' : 'W',
1038 if ( g_file_test(buf, G_FILE_TEST_EXISTS ) == TRUE ) {
1040 gint x1, y1, x2, y2;
1043 sw.mode = VIK_COORD_LATLON;
1044 ne.north_south = i+1;
1046 ne.mode = VIK_COORD_LATLON;
1047 vik_viewport_coord_to_screen ( vp, &sw, &x1, &y1 );
1048 vik_viewport_coord_to_screen ( vp, &ne, &x2, &y2 );
1049 if ( x1 < 0 ) x1 = 0;
1050 if ( y2 < 0 ) y2 = 0;
1051 vik_viewport_draw_rectangle ( vp, gtk_widget_get_style(GTK_WIDGET(vp))->black_gc,
1052 FALSE, x1, y2, x2-x1, y1-y2 );
1059 /**************************************************
1060 * SOURCE: USGS 24K *
1061 **************************************************/
1063 #ifdef VIK_CONFIG_DEM24K
1065 static void dem24k_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
1067 /* TODO: dest dir */
1068 gchar *cmdline = g_strdup_printf("%s %.03f %.03f",
1069 DEM24K_DOWNLOAD_SCRIPT,
1072 /* FIX: don't use system, use execv or something. check for existence */
1077 static gchar *dem24k_lat_lon_to_dest_fn ( gdouble lat, gdouble lon )
1079 return g_strdup_printf("dem24k/%d/%d/%.03f,%.03f.dem",
1086 /* TODO: generalize */
1087 static void dem24k_draw_existence ( VikViewport *vp )
1089 gdouble max_lat, max_lon, min_lat, min_lon;
1090 gchar buf[strlen(MAPS_CACHE_DIR)+40];
1093 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
1095 for (i = floor(min_lat*8)/8; i <= floor(max_lat*8)/8; i+=0.125) {
1096 /* check lat dir first -- faster */
1097 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/",
1100 if ( g_file_test(buf, G_FILE_TEST_EXISTS) == FALSE )
1102 for (j = floor(min_lon*8)/8; j <= floor(max_lon*8)/8; j+=0.125) {
1103 /* check lon dir first -- faster */
1104 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/%d/",
1108 if ( g_file_test(buf, G_FILE_TEST_EXISTS) == FALSE )
1110 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/%d/%.03f,%.03f.dem",
1116 if ( g_file_test(buf, G_FILE_TEST_EXISTS ) == TRUE ) {
1118 gint x1, y1, x2, y2;
1120 sw.east_west = j-0.125;
1121 sw.mode = VIK_COORD_LATLON;
1122 ne.north_south = i+0.125;
1124 ne.mode = VIK_COORD_LATLON;
1125 vik_viewport_coord_to_screen ( vp, &sw, &x1, &y1 );
1126 vik_viewport_coord_to_screen ( vp, &ne, &x2, &y2 );
1127 if ( x1 < 0 ) x1 = 0;
1128 if ( y2 < 0 ) y2 = 0;
1129 vik_viewport_draw_rectangle ( vp, gtk_widget_get_style(GTK_WIDGET(vp))->black_gc,
1130 FALSE, x1, y2, x2-x1, y1-y2 );
1137 /**************************************************
1138 * SOURCES -- DOWNLOADING & IMPORTING TOOL *
1139 **************************************************
1142 static void weak_ref_cb ( gpointer ptr, GObject * dead_vdl )
1144 DEMDownloadParams *p = ptr;
1145 g_mutex_lock ( p->mutex );
1147 g_mutex_unlock ( p->mutex );
1150 /* Try to add file full_path.
1151 * filename will be copied.
1152 * returns FALSE if file does not exists, TRUE otherwise.
1154 static gboolean dem_layer_add_file ( VikDEMLayer *vdl, const gchar *filename )
1156 if ( g_file_test(filename, G_FILE_TEST_EXISTS) == TRUE ) {
1157 /* only load if file size is not 0 (not in progress) */
1159 (void)g_stat ( filename, &sb );
1161 gchar *duped_path = g_strdup(filename);
1162 vdl->files = g_list_prepend ( vdl->files, duped_path );
1163 a_dems_load ( duped_path );
1164 g_debug("%s: %s", __FUNCTION__, duped_path);
1171 static void dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
1173 if ( p->source == DEM_SOURCE_SRTM )
1174 srtm_dem_download_thread ( p, threaddata );
1175 #ifdef VIK_CONFIG_DEM24K
1176 else if ( p->source == DEM_SOURCE_DEM24K )
1177 dem24k_dem_download_thread ( p, threaddata );
1182 g_mutex_lock ( p->mutex );
1184 g_object_weak_unref ( G_OBJECT(p->vdl), weak_ref_cb, p );
1186 if ( dem_layer_add_file ( p->vdl, p->dest ) )
1187 vik_layer_emit_update ( VIK_LAYER(p->vdl) ); // NB update requested from background thread
1189 g_mutex_unlock ( p->mutex );
1193 static void free_dem_download_params ( DEMDownloadParams *p )
1195 vik_mutex_free ( p->mutex );
1200 static gpointer dem_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1206 * Display a simple dialog with information about the DEM file at this location
1208 static void dem_layer_file_info ( GtkWidget *widget, struct LatLon *ll )
1210 gint intlat, intlon;
1211 const gchar *continent_dir;
1213 intlat = (int)floor(ll->lat);
1214 intlon = (int)floor(ll->lon);
1215 continent_dir = srtm_continent_dir(intlat, intlon);
1217 gchar *source = NULL;
1218 if ( continent_dir )
1219 source = g_strdup_printf ( "%s/%s/%c%02d%c%03d.hgt.zip",
1222 (intlat >= 0) ? 'N' : 'S',
1224 (intlon >= 0) ? 'E' : 'W',
1227 // Probably not over any land...
1228 source = g_strdup ( _("No DEM File Available") );
1230 gchar *filename = NULL;
1231 gchar *dem_file = NULL;
1232 #ifdef VIK_CONFIG_DEM24K
1233 dem_file = dem24k_lat_lon_to_dest_fn ( ll->lat, ll->lon );
1235 dem_file = srtm_lat_lon_to_dest_fn ( ll->lat, ll->lon );
1237 gchar *message = NULL;
1239 filename = g_strdup_printf ( "%s%s", MAPS_CACHE_DIR, dem_file );
1241 if ( g_file_test ( filename, G_FILE_TEST_EXISTS ) ) {
1242 // Get some timestamp information of the file
1244 if ( g_stat ( filename, &stat_buf ) == 0 ) {
1246 strftime ( time_buf, sizeof(time_buf), "%c", gmtime((const time_t *)&stat_buf.st_mtime) );
1247 message = g_strdup_printf ( _("\nSource: %s\n\nDEM File: %s\nDEM File Timestamp: %s"), source, filename, time_buf );
1251 message = g_strdup_printf ( _("Source: %s\n\nNo DEM File!"), source );
1254 a_dialog_info_msg ( GTK_WINDOW(gtk_widget_get_toplevel(widget)), message );
1258 g_free ( dem_file );
1259 g_free ( filename );
1262 static gboolean dem_layer_download_release ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp )
1265 static struct LatLon ll;
1268 gchar *dem_file = NULL;
1270 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1271 vik_coord_to_latlon ( &coord, &ll );
1274 if ( vdl->source == DEM_SOURCE_SRTM )
1275 dem_file = srtm_lat_lon_to_dest_fn ( ll.lat, ll.lon );
1276 #ifdef VIK_CONFIG_DEM24K
1277 else if ( vdl->source == DEM_SOURCE_DEM24K )
1278 dem_file = dem24k_lat_lon_to_dest_fn ( ll.lat, ll.lon );
1284 full_path = g_strdup_printf("%s%s", MAPS_CACHE_DIR, dem_file );
1286 g_debug("%s: %s", __FUNCTION__, full_path);
1288 if ( event->button == 1 ) {
1289 // TODO: check if already in filelist
1290 if ( ! dem_layer_add_file(vdl, full_path) ) {
1291 gchar *tmp = g_strdup_printf ( _("Downloading DEM %s"), dem_file );
1292 DEMDownloadParams *p = g_malloc(sizeof(DEMDownloadParams));
1293 p->dest = g_strdup(full_path);
1297 p->mutex = vik_mutex_new();
1298 p->source = vdl->source;
1299 g_object_weak_ref(G_OBJECT(p->vdl), weak_ref_cb, p );
1301 a_background_thread ( BACKGROUND_POOL_REMOTE,
1302 VIK_GTK_WINDOW_FROM_LAYER(vdl), tmp,
1303 (vik_thr_func) dem_download_thread, p,
1304 (vik_thr_free_func) free_dem_download_params, NULL, 1 );
1309 vik_layer_emit_update ( VIK_LAYER(vdl) );
1312 if ( !vdl->right_click_menu ) {
1314 vdl->right_click_menu = GTK_MENU ( gtk_menu_new () );
1316 item = gtk_image_menu_item_new_with_mnemonic ( _("_Show DEM File Information") );
1317 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INFO, GTK_ICON_SIZE_MENU) );
1318 g_signal_connect ( G_OBJECT(item), "activate", G_CALLBACK(dem_layer_file_info), &ll );
1319 gtk_menu_shell_append (GTK_MENU_SHELL(vdl->right_click_menu), item);
1322 gtk_menu_popup ( vdl->right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1323 gtk_widget_show_all ( GTK_WIDGET(vdl->right_click_menu) );
1326 g_free ( dem_file );
1327 g_free ( full_path );
1332 static gboolean dem_layer_download_click ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp )
1334 /* choose & keep track of cache dir
1335 * download in background thread
1336 * download over area */