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 (VikLayerFuncGetTimestamp) NULL,
213 (VikLayerFuncSetMenuItemsSelection) NULL,
214 (VikLayerFuncGetMenuItemsSelection) NULL,
216 (VikLayerFuncAddMenuItems) NULL,
217 (VikLayerFuncSublayerAddMenuItems) NULL,
219 (VikLayerFuncSublayerRenameRequest) NULL,
220 (VikLayerFuncSublayerToggleVisible) NULL,
221 (VikLayerFuncSublayerTooltip) NULL,
222 (VikLayerFuncLayerTooltip) dem_layer_tooltip,
223 (VikLayerFuncLayerSelected) NULL,
225 (VikLayerFuncMarshall) dem_layer_marshall,
226 (VikLayerFuncUnmarshall) dem_layer_unmarshall,
228 (VikLayerFuncSetParam) dem_layer_set_param,
229 (VikLayerFuncGetParam) dem_layer_get_param,
230 (VikLayerFuncChangeParam) NULL,
232 (VikLayerFuncReadFileData) NULL,
233 (VikLayerFuncWriteFileData) NULL,
235 (VikLayerFuncDeleteItem) NULL,
236 (VikLayerFuncCutItem) NULL,
237 (VikLayerFuncCopyItem) NULL,
238 (VikLayerFuncPasteItem) NULL,
239 (VikLayerFuncFreeCopiedItem) NULL,
240 (VikLayerFuncDragDropRequest) NULL,
242 (VikLayerFuncSelectClick) NULL,
243 (VikLayerFuncSelectMove) NULL,
244 (VikLayerFuncSelectRelease) NULL,
245 (VikLayerFuncSelectedViewportMenu) NULL,
248 struct _VikDEMLayer {
259 // right click menu only stuff - similar to mapslayer
260 GtkMenu *right_click_menu;
263 GType vik_dem_layer_get_type ()
265 static GType vdl_type = 0;
269 static const GTypeInfo vdl_info =
271 sizeof (VikDEMLayerClass),
272 NULL, /* base_init */
273 NULL, /* base_finalize */
274 NULL, /* class init */
275 NULL, /* class_finalize */
276 NULL, /* class_data */
277 sizeof (VikDEMLayer),
279 NULL /* instance init */
281 vdl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikDEMLayer", &vdl_info, 0 );
287 static const gchar* dem_layer_tooltip( VikDEMLayer *vdl )
289 static gchar tmp_buf[100];
290 g_snprintf (tmp_buf, sizeof(tmp_buf), _("Number of files: %d"), g_list_length (vdl->files));
294 static void dem_layer_marshall( VikDEMLayer *vdl, guint8 **data, gint *len )
296 vik_layer_marshall_params ( VIK_LAYER(vdl), data, len );
299 static VikDEMLayer *dem_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
301 VikDEMLayer *rv = dem_layer_new ( vvp );
304 /* TODO: share GCS between layers */
305 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ ) {
307 rv->gcs[i] = vik_viewport_new_gc_from_color ( vvp, &(rv->color), UNUSED_LINE_THICKNESS );
309 rv->gcs[i] = vik_viewport_new_gc ( vvp, dem_height_colors[i], UNUSED_LINE_THICKNESS );
311 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
312 rv->gcsgradient[i] = vik_viewport_new_gc ( vvp, dem_gradient_colors[i], UNUSED_LINE_THICKNESS );
314 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
318 /* Structure for DEM data used in background thread */
321 } dem_load_thread_data;
324 * Function for starting the DEM file loading as a background thread
326 static int dem_layer_load_list_thread ( dem_load_thread_data *dltd, gpointer threaddata )
328 int result = 0; // Default to good
330 if ( a_dems_load_list ( &(dltd->vdl->files), threaddata ) ) {
335 // ATM as each file is processed the screen is not updated (no mechanism exposed to a_dems_load_list)
336 // Thus force draw only at the end, as loading is complete/aborted
337 //gdk_threads_enter();
338 // Test is helpful to prevent Gtk-CRITICAL warnings if the program is exitted whilst loading
339 if ( IS_VIK_LAYER(dltd->vdl) )
340 vik_layer_emit_update ( VIK_LAYER(dltd->vdl) ); // NB update from background thread
341 //gdk_threads_leave();
346 static void dem_layer_thread_data_free ( dem_load_thread_data *data )
352 static void dem_layer_thread_cancel ( dem_load_thread_data *data )
355 // Instead of freeing the list, leave it as partially processed
356 // Thus we can see/use what was done
360 * Process the list of DEM files and convert each one to a relative path
362 static GList *dem_layer_convert_to_relative_filenaming ( GList *files )
364 gchar *cwd = g_get_current_dir();
368 GList *relfiles = NULL;
371 gchar *file = g_strdup ( file_GetRelativeFilename ( cwd, files->data ) );
372 relfiles = g_list_prepend ( relfiles, file );
379 // Replacing current list, so delete old values first.
382 g_free ( iter->data );
385 g_list_free ( files );
393 gboolean dem_layer_set_param ( VikDEMLayer *vdl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
397 case PARAM_COLOR: vdl->color = data.c; gdk_gc_set_rgb_fg_color ( vdl->gcs[0], &(vdl->color) ); break;
398 case PARAM_SOURCE: vdl->source = data.u; break;
399 case PARAM_TYPE: vdl->type = data.u; break;
401 /* Convert to store internally
402 NB file operation always in internal units (metres) */
403 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
404 vdl->min_elev = VIK_FEET_TO_METERS(data.d);
406 vdl->min_elev = data.d;
409 /* Convert to store internally
410 NB file operation always in internal units (metres) */
411 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
412 vdl->max_elev = VIK_FEET_TO_METERS(data.d);
414 vdl->max_elev = data.d;
418 // Clear out old settings - if any commonalities with new settings they will have to be read again
419 a_dems_list_free ( vdl->files );
420 // Set file list so any other intermediate screen drawing updates will show currently loaded DEMs by the working thread
421 vdl->files = data.sl;
422 // No need for thread if no files
425 dem_load_thread_data *dltd = g_malloc ( sizeof(dem_load_thread_data) );
427 dltd->vdl->files = data.sl;
429 a_background_thread ( BACKGROUND_POOL_LOCAL,
430 VIK_GTK_WINDOW_FROM_WIDGET(vp),
432 (vik_thr_func) dem_layer_load_list_thread,
434 (vik_thr_free_func) dem_layer_thread_data_free,
435 (vik_thr_free_func) dem_layer_thread_cancel,
436 g_list_length ( data.sl ) ); // Number of DEM files
445 static VikLayerParamData dem_layer_get_param ( VikDEMLayer *vdl, guint16 id, gboolean is_file_operation )
447 VikLayerParamData rv;
452 if ( is_file_operation )
453 // Save in relative format if necessary
454 if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE )
455 rv.sl = dem_layer_convert_to_relative_filenaming ( rv.sl );
457 case PARAM_SOURCE: rv.u = vdl->source; break;
458 case PARAM_TYPE: rv.u = vdl->type; break;
459 case PARAM_COLOR: rv.c = vdl->color; break;
461 /* Convert for display in desired units
462 NB file operation always in internal units (metres) */
463 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
464 rv.d = VIK_METERS_TO_FEET(vdl->min_elev);
466 rv.d = vdl->min_elev;
469 /* Convert for display in desired units
470 NB file operation always in internal units (metres) */
471 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
472 rv.d = VIK_METERS_TO_FEET(vdl->max_elev);
474 rv.d = vdl->max_elev;
481 static void dem_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file )
483 /* nothing ATM, but keep in case it's needed the future */
486 static VikDEMLayer *dem_layer_new ( VikViewport *vvp )
488 VikDEMLayer *vdl = VIK_DEM_LAYER ( g_object_new ( VIK_DEM_LAYER_TYPE, NULL ) );
490 vik_layer_set_type ( VIK_LAYER(vdl), VIK_LAYER_DEM );
494 vdl->gcs = g_malloc(sizeof(GdkGC *)*DEM_N_HEIGHT_COLORS);
495 vdl->gcsgradient = g_malloc(sizeof(GdkGC *)*DEM_N_GRADIENT_COLORS);
496 /* make new gcs only if we need it (copy layer -> use old) */
498 // Ensure the base GC is available so the default colour can be applied
499 if ( vvp ) vdl->gcs[0] = vik_viewport_new_gc ( vvp, "#0000FF", 1 );
501 vik_layer_set_defaults ( VIK_LAYER(vdl), vvp );
507 static inline guint16 get_height_difference(gint16 elev, gint16 new_elev)
509 if(new_elev == VIK_DEM_INVALID_ELEVATION)
512 return abs(new_elev - elev);
516 static void vik_dem_layer_draw_dem ( VikDEMLayer *vdl, VikViewport *vp, VikDEM *dem )
518 VikDEMColumn *column, *prevcolumn, *nextcolumn;
520 struct LatLon dem_northeast, dem_southwest;
521 gdouble max_lat, max_lon, min_lat, min_lon;
523 /**** Check if viewport and DEM data overlap ****/
525 /* get min, max lat/lon of viewport */
526 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
528 /* get min, max lat/lon of DEM data */
529 if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
530 dem_northeast.lat = dem->max_north / 3600.0;
531 dem_northeast.lon = dem->max_east / 3600.0;
532 dem_southwest.lat = dem->min_north / 3600.0;
533 dem_southwest.lon = dem->min_east / 3600.0;
534 } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
535 struct UTM dem_northeast_utm, dem_southwest_utm;
536 dem_northeast_utm.northing = dem->max_north;
537 dem_northeast_utm.easting = dem->max_east;
538 dem_southwest_utm.northing = dem->min_north;
539 dem_southwest_utm.easting = dem->min_east;
540 dem_northeast_utm.zone = dem_southwest_utm.zone = dem->utm_zone;
541 dem_northeast_utm.letter = dem_southwest_utm.letter = dem->utm_letter;
543 a_coords_utm_to_latlon(&dem_northeast_utm, &dem_northeast);
544 a_coords_utm_to_latlon(&dem_southwest_utm, &dem_southwest);
546 // Unknown horiz_units - this shouldn't normally happen
547 // Thus can't work out positions to use
551 if ( (max_lat > dem_northeast.lat && min_lat > dem_northeast.lat) ||
552 (max_lat < dem_southwest.lat && min_lat < dem_southwest.lat) )
554 else if ( (max_lon > dem_northeast.lon && min_lon > dem_northeast.lon) ||
555 (max_lon < dem_southwest.lon && min_lon < dem_southwest.lon) )
557 /* else they overlap */
559 /**** End Overlap Check ****/
560 /* boxes to show where we have DEM instead of actually drawing the DEM.
561 * useful if we want to see what areas we have coverage for (if we want
562 * to get elevation data for a track) but don't want to cover the map.
566 /* draw a box if a DEM is loaded. in future I'd like to add an option for this
567 * this is useful if we want to see what areas we have dem for but don't want to
568 * cover the map (or maybe we just need translucent DEM?) */
570 VikCoord demne, demsw;
572 vik_coord_load_from_latlon(&demne, vik_viewport_get_coord_mode(vp), &dem_northeast);
573 vik_coord_load_from_latlon(&demsw, vik_viewport_get_coord_mode(vp), &dem_southwest);
575 vik_viewport_coord_to_screen ( vp, &demne, &x1, &y1 );
576 vik_viewport_coord_to_screen ( vp, &demsw, &x2, &y2 );
578 if ( x1 > vik_viewport_get_width(vp) ) x1=vik_viewport_get_width(vp);
579 if ( y2 > vik_viewport_get_height(vp) ) y2=vik_viewport_get_height(vp);
580 if ( x2 < 0 ) x2 = 0;
581 if ( y1 < 0 ) y1 = 0;
582 vik_viewport_draw_rectangle ( vp, gtk_widget_get_style(GTK_WIDGET(vp))->black_gc,
583 FALSE, x2, y1, x1-x2, y2-y1 );
588 if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
589 VikCoord tmp; /* TODO: don't use coord_load_from_latlon, especially if in latlon drawing mode */
591 gdouble max_lat_as, max_lon_as, min_lat_as, min_lon_as;
592 gdouble start_lat_as, end_lat_as, start_lon_as, end_lon_as;
594 gdouble start_lat, end_lat, start_lon, end_lon;
596 struct LatLon counter;
598 guint x, y, start_x, start_y;
602 guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 80 ); /* todo: smarter calculation. */
604 gdouble nscale_deg = dem->north_scale / ((gdouble) 3600);
605 gdouble escale_deg = dem->east_scale / ((gdouble) 3600);
607 max_lat_as = max_lat * 3600;
608 min_lat_as = min_lat * 3600;
609 max_lon_as = max_lon * 3600;
610 min_lon_as = min_lon * 3600;
612 start_lat_as = MAX(min_lat_as, dem->min_north);
613 end_lat_as = MIN(max_lat_as, dem->max_north);
614 start_lon_as = MAX(min_lon_as, dem->min_east);
615 end_lon_as = MIN(max_lon_as, dem->max_east);
617 start_lat = floor(start_lat_as / dem->north_scale) * nscale_deg;
618 end_lat = ceil (end_lat_as / dem->north_scale) * nscale_deg;
619 start_lon = floor(start_lon_as / dem->east_scale) * escale_deg;
620 end_lon = ceil (end_lon_as / dem->east_scale) * escale_deg;
622 vik_dem_east_north_to_xy ( dem, start_lon_as, start_lat_as, &start_x, &start_y );
623 guint gradient_skip_factor = 1;
624 if(vdl->type == DEM_TYPE_GRADIENT)
625 gradient_skip_factor = skip_factor;
627 /* verify sane elev interval */
628 if ( vdl->max_elev <= vdl->min_elev )
629 vdl->max_elev = vdl->min_elev + 1;
631 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 ) {
632 // NOTE: ( counter.lon <= end_lon + ESCALE_DEG*SKIP_FACTOR ) is neccessary so in high zoom modes,
633 // the leftmost column does also get drawn, if the center point is out of viewport.
634 if ( x < dem->n_columns ) {
635 column = g_ptr_array_index ( dem->columns, x );
636 // get previous and next column. catch out-of-bound.
638 new_x -= gradient_skip_factor;
640 prevcolumn = g_ptr_array_index ( dem->columns, x+1);
642 prevcolumn = g_ptr_array_index ( dem->columns, new_x);
644 new_x += gradient_skip_factor;
645 if(new_x >= dem->n_columns)
646 nextcolumn = g_ptr_array_index ( dem->columns, x-1);
648 nextcolumn = g_ptr_array_index ( dem->columns, new_x);
650 for ( y=start_y, counter.lat = start_lat; counter.lat <= end_lat; counter.lat += nscale_deg * skip_factor, y += skip_factor ) {
651 if ( y > column->n_points )
654 elev = column->points[y];
656 // calculate bounding box for drawing
657 gint box_x, box_y, box_width, box_height;
660 box_c.lat += (nscale_deg * skip_factor)/2;
661 box_c.lon -= (escale_deg * skip_factor)/2;
662 vik_coord_load_from_latlon(&tmp, vik_viewport_get_coord_mode(vp), &box_c);
663 vik_viewport_coord_to_screen(vp, &tmp, &box_x, &box_y);
664 // catch box at borders
669 box_c.lat -= nscale_deg * skip_factor;
670 box_c.lon += escale_deg * skip_factor;
671 vik_coord_load_from_latlon(&tmp, vik_viewport_get_coord_mode(vp), &box_c);
672 vik_viewport_coord_to_screen(vp, &tmp, &box_width, &box_height);
675 // catch box at borders
676 if(box_width < 0 || box_height < 0)
677 // skip this as is out of the viewport (e.g. zoomed in so this point is way off screen)
680 gboolean below_minimum = FALSE;
681 if(vdl->type == DEM_TYPE_HEIGHT) {
682 if ( elev != VIK_DEM_INVALID_ELEVATION && elev < vdl->min_elev ) {
683 // Prevent 'elev - vdl->min_elev' from being negative so can safely use as array index
684 elev = ceil ( vdl->min_elev );
685 below_minimum = TRUE;
687 if ( elev != VIK_DEM_INVALID_ELEVATION && elev > vdl->max_elev )
688 elev = vdl->max_elev;
692 if(vdl->type == DEM_TYPE_GRADIENT) {
693 if( elev == VIK_DEM_INVALID_ELEVATION ) {
696 // calculate and sum gradient in all directions
700 // calculate gradient from height points all around the current one
701 new_y = y - gradient_skip_factor;
704 change += get_height_difference(elev, prevcolumn->points[new_y]);
705 change += get_height_difference(elev, column->points[new_y]);
706 change += get_height_difference(elev, nextcolumn->points[new_y]);
708 change += get_height_difference(elev, prevcolumn->points[y]);
709 change += get_height_difference(elev, nextcolumn->points[y]);
711 new_y = y + gradient_skip_factor;
712 if(new_y >= column->n_points)
714 change += get_height_difference(elev, prevcolumn->points[new_y]);
715 change += get_height_difference(elev, column->points[new_y]);
716 change += get_height_difference(elev, nextcolumn->points[new_y]);
718 change = change / ((skip_factor > 1) ? log(skip_factor) : 0.55); // FIXME: better calc.
720 if(change < vdl->min_elev)
721 // Prevent 'change - vdl->min_elev' from being negative so can safely use as array index
722 change = ceil ( vdl->min_elev );
724 if(change > vdl->max_elev)
725 change = vdl->max_elev;
727 // void vik_viewport_draw_rectangle ( VikViewport *vvp, GdkGC *gc, gboolean filled, gint x1, gint y1, gint x2, gint y2 );
728 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);
731 if(vdl->type == DEM_TYPE_HEIGHT) {
732 if ( elev == VIK_DEM_INVALID_ELEVATION )
733 ; /* don't draw it */
734 else if ( elev <= 0 || below_minimum )
735 /* If 'sea' colour or below the defined mininum draw in the configurable colour */
736 vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, box_x, box_y, box_width, box_height);
738 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);
745 } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
746 gdouble max_nor, max_eas, min_nor, min_eas;
747 gdouble start_nor, start_eas, end_nor, end_eas;
751 guint x, y, start_x, start_y;
753 VikCoord tmp; /* TODO: don't use coord_load_from_latlon, especially if in latlon drawing mode */
756 guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 10 ); /* todo: smarter calculation. */
758 VikCoord tleft, tright, bleft, bright;
760 vik_viewport_screen_to_coord ( vp, 0, 0, &tleft );
761 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), 0, &tright );
762 vik_viewport_screen_to_coord ( vp, 0, vik_viewport_get_height(vp), &bleft );
763 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), vik_viewport_get_height(vp), &bright );
766 vik_coord_convert(&tleft, VIK_COORD_UTM);
767 vik_coord_convert(&tright, VIK_COORD_UTM);
768 vik_coord_convert(&bleft, VIK_COORD_UTM);
769 vik_coord_convert(&bright, VIK_COORD_UTM);
771 max_nor = MAX(tleft.north_south, tright.north_south);
772 min_nor = MIN(bleft.north_south, bright.north_south);
773 max_eas = MAX(bright.east_west, tright.east_west);
774 min_eas = MIN(bleft.east_west, tleft.east_west);
776 start_nor = MAX(min_nor, dem->min_north);
777 end_nor = MIN(max_nor, dem->max_north);
778 if ( tleft.utm_zone == dem->utm_zone && bleft.utm_zone == dem->utm_zone
779 && (tleft.utm_letter >= 'N') == (dem->utm_letter >= 'N')
780 && (bleft.utm_letter >= 'N') == (dem->utm_letter >= 'N') ) /* if the utm zones/hemispheres are different, min_eas will be bogus */
781 start_eas = MAX(min_eas, dem->min_east);
783 start_eas = dem->min_east;
784 if ( tright.utm_zone == dem->utm_zone && bright.utm_zone == dem->utm_zone
785 && (tright.utm_letter >= 'N') == (dem->utm_letter >= 'N')
786 && (bright.utm_letter >= 'N') == (dem->utm_letter >= 'N') ) /* if the utm zones/hemispheres are different, min_eas will be bogus */
787 end_eas = MIN(max_eas, dem->max_east);
789 end_eas = dem->max_east;
791 start_nor = floor(start_nor / dem->north_scale) * dem->north_scale;
792 end_nor = ceil (end_nor / dem->north_scale) * dem->north_scale;
793 start_eas = floor(start_eas / dem->east_scale) * dem->east_scale;
794 end_eas = ceil (end_eas / dem->east_scale) * dem->east_scale;
796 vik_dem_east_north_to_xy ( dem, start_eas, start_nor, &start_x, &start_y );
798 /* TODO: why start_x and start_y are -1 -- rounding error from above? */
800 counter.zone = dem->utm_zone;
801 counter.letter = dem->utm_letter;
803 for ( x=start_x, counter.easting = start_eas; counter.easting <= end_eas; counter.easting += dem->east_scale * skip_factor, x += skip_factor ) {
804 if ( x > 0 && x < dem->n_columns ) {
805 column = g_ptr_array_index ( dem->columns, x );
806 for ( y=start_y, counter.northing = start_nor; counter.northing <= end_nor; counter.northing += dem->north_scale * skip_factor, y += skip_factor ) {
807 if ( y > column->n_points )
809 elev = column->points[y];
810 if ( elev != VIK_DEM_INVALID_ELEVATION && elev < vdl->min_elev )
812 if ( elev != VIK_DEM_INVALID_ELEVATION && elev > vdl->max_elev )
817 vik_coord_load_from_utm(&tmp, vik_viewport_get_coord_mode(vp), &counter);
818 vik_viewport_coord_to_screen(vp, &tmp, &a, &b);
819 if ( elev == VIK_DEM_INVALID_ELEVATION )
820 ; /* don't draw it */
821 else if ( elev <= 0 )
822 vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, a-1, b-1, 2, 2 );
824 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 );
832 /* return the continent for the specified lat, lon */
834 static const gchar *srtm_continent_dir ( gint lat, gint lon )
836 extern const char *_srtm_continent_data[];
837 static GHashTable *srtm_continent = NULL;
838 const gchar *continent;
841 if (!srtm_continent) {
844 srtm_continent = g_hash_table_new(g_str_hash, g_str_equal);
845 s = _srtm_continent_data;
846 while (*s != (gchar *)-1) {
849 g_hash_table_insert(srtm_continent, (gpointer) *s, (gpointer) continent);
855 g_snprintf(name, sizeof(name), "%c%02d%c%03d",
856 (lat >= 0) ? 'N' : 'S', ABS(lat),
857 (lon >= 0) ? 'E' : 'W', ABS(lon));
859 return(g_hash_table_lookup(srtm_continent, name));
862 static void dem_layer_draw ( VikDEMLayer *vdl, VikViewport *vp )
864 GList *dems_iter = vdl->files;
868 /* search for SRTM3 90m */
870 if ( vdl->source == DEM_SOURCE_SRTM )
871 srtm_draw_existence ( vp );
872 #ifdef VIK_CONFIG_DEM24K
873 else if ( vdl->source == DEM_SOURCE_DEM24K )
874 dem24k_draw_existence ( vp );
877 while ( dems_iter ) {
878 dem = a_dems_get ( (const char *) (dems_iter->data) );
880 vik_dem_layer_draw_dem ( vdl, vp, dem );
881 dems_iter = dems_iter->next;
885 static void dem_layer_free ( VikDEMLayer *vdl )
889 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ )
890 g_object_unref ( vdl->gcs[i] );
893 if ( vdl->gcsgradient )
894 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
895 g_object_unref ( vdl->gcsgradient[i] );
896 g_free ( vdl->gcsgradient );
898 a_dems_list_free ( vdl->files );
901 VikDEMLayer *dem_layer_create ( VikViewport *vp )
903 VikDEMLayer *vdl = dem_layer_new ( vp );
906 /* TODO: share GCS between layers */
907 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ ) {
909 vdl->gcs[i] = vik_viewport_new_gc ( vp, dem_height_colors[i], UNUSED_LINE_THICKNESS );
911 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
912 vdl->gcsgradient[i] = vik_viewport_new_gc ( vp, dem_gradient_colors[i], UNUSED_LINE_THICKNESS );
916 /**************************************************************
917 **** SOURCES & DOWNLOADING
918 **************************************************************/
924 VikDEMLayer *vdl; /* NULL if not alive */
930 /**************************************************
932 **************************************************/
934 static void srtm_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
937 const gchar *continent_dir;
939 intlat = (int)floor(p->lat);
940 intlon = (int)floor(p->lon);
941 continent_dir = srtm_continent_dir(intlat, intlon);
943 if (!continent_dir) {
945 gchar *msg = g_strdup_printf ( _("No SRTM data available for %f, %f"), p->lat, p->lon );
946 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(p->vdl), msg, VIK_STATUSBAR_INFO );
952 gchar *src_fn = g_strdup_printf("%s%s/%c%02d%c%03d.hgt.zip",
955 (intlat >= 0) ? 'N' : 'S',
957 (intlon >= 0) ? 'E' : 'W',
960 static DownloadFileOptions options = { FALSE, FALSE, NULL, 0, a_check_map_file, NULL, NULL };
961 DownloadResult_t result = a_http_download_get_url ( SRTM_HTTP_SITE, src_fn, p->dest, &options, NULL );
963 case DOWNLOAD_CONTENT_ERROR:
964 case DOWNLOAD_HTTP_ERROR: {
965 gchar *msg = g_strdup_printf ( _("DEM download failure for %f, %f"), p->lat, p->lon );
966 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(p->vdl), msg, VIK_STATUSBAR_INFO );
970 case DOWNLOAD_FILE_WRITE_ERROR: {
971 gchar *msg = g_strdup_printf ( _("DEM write failure for %s"), p->dest );
972 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(p->vdl), msg, VIK_STATUSBAR_INFO );
976 case DOWNLOAD_SUCCESS:
977 case DOWNLOAD_NOT_REQUIRED:
984 static gchar *srtm_lat_lon_to_dest_fn ( gdouble lat, gdouble lon )
987 const gchar *continent_dir;
989 intlat = (int)floor(lat);
990 intlon = (int)floor(lon);
991 continent_dir = srtm_continent_dir(intlat, intlon);
994 continent_dir = "nowhere";
996 return g_strdup_printf("srtm3-%s%s%c%02d%c%03d.hgt.zip",
999 (intlat >= 0) ? 'N' : 'S',
1001 (intlon >= 0) ? 'E' : 'W',
1006 /* TODO: generalize */
1007 static void srtm_draw_existence ( VikViewport *vp )
1009 gdouble max_lat, max_lon, min_lat, min_lon;
1010 gchar buf[strlen(MAPS_CACHE_DIR)+strlen(SRTM_CACHE_TEMPLATE)+30];
1013 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
1015 for (i = floor(min_lat); i <= floor(max_lat); i++) {
1016 for (j = floor(min_lon); j <= floor(max_lon); j++) {
1017 const gchar *continent_dir;
1018 if ((continent_dir = srtm_continent_dir(i, j)) == NULL)
1020 g_snprintf(buf, sizeof(buf), SRTM_CACHE_TEMPLATE,
1024 (i >= 0) ? 'N' : 'S',
1026 (j >= 0) ? 'E' : 'W',
1028 if ( g_file_test(buf, G_FILE_TEST_EXISTS ) == TRUE ) {
1030 gint x1, y1, x2, y2;
1033 sw.mode = VIK_COORD_LATLON;
1034 ne.north_south = i+1;
1036 ne.mode = VIK_COORD_LATLON;
1037 vik_viewport_coord_to_screen ( vp, &sw, &x1, &y1 );
1038 vik_viewport_coord_to_screen ( vp, &ne, &x2, &y2 );
1039 if ( x1 < 0 ) x1 = 0;
1040 if ( y2 < 0 ) y2 = 0;
1041 vik_viewport_draw_rectangle ( vp, gtk_widget_get_style(GTK_WIDGET(vp))->black_gc,
1042 FALSE, x1, y2, x2-x1, y1-y2 );
1049 /**************************************************
1050 * SOURCE: USGS 24K *
1051 **************************************************/
1053 #ifdef VIK_CONFIG_DEM24K
1055 static void dem24k_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
1057 /* TODO: dest dir */
1058 gchar *cmdline = g_strdup_printf("%s %.03f %.03f",
1059 DEM24K_DOWNLOAD_SCRIPT,
1062 /* FIX: don't use system, use execv or something. check for existence */
1067 static gchar *dem24k_lat_lon_to_dest_fn ( gdouble lat, gdouble lon )
1069 return g_strdup_printf("dem24k/%d/%d/%.03f,%.03f.dem",
1076 /* TODO: generalize */
1077 static void dem24k_draw_existence ( VikViewport *vp )
1079 gdouble max_lat, max_lon, min_lat, min_lon;
1080 gchar buf[strlen(MAPS_CACHE_DIR)+40];
1083 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
1085 for (i = floor(min_lat*8)/8; i <= floor(max_lat*8)/8; i+=0.125) {
1086 /* check lat dir first -- faster */
1087 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/",
1090 if ( g_file_test(buf, G_FILE_TEST_EXISTS) == FALSE )
1092 for (j = floor(min_lon*8)/8; j <= floor(max_lon*8)/8; j+=0.125) {
1093 /* check lon dir first -- faster */
1094 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/%d/",
1098 if ( g_file_test(buf, G_FILE_TEST_EXISTS) == FALSE )
1100 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/%d/%.03f,%.03f.dem",
1106 if ( g_file_test(buf, G_FILE_TEST_EXISTS ) == TRUE ) {
1108 gint x1, y1, x2, y2;
1110 sw.east_west = j-0.125;
1111 sw.mode = VIK_COORD_LATLON;
1112 ne.north_south = i+0.125;
1114 ne.mode = VIK_COORD_LATLON;
1115 vik_viewport_coord_to_screen ( vp, &sw, &x1, &y1 );
1116 vik_viewport_coord_to_screen ( vp, &ne, &x2, &y2 );
1117 if ( x1 < 0 ) x1 = 0;
1118 if ( y2 < 0 ) y2 = 0;
1119 vik_viewport_draw_rectangle ( vp, gtk_widget_get_style(GTK_WIDGET(vp))->black_gc,
1120 FALSE, x1, y2, x2-x1, y1-y2 );
1127 /**************************************************
1128 * SOURCES -- DOWNLOADING & IMPORTING TOOL *
1129 **************************************************
1132 static void weak_ref_cb ( gpointer ptr, GObject * dead_vdl )
1134 DEMDownloadParams *p = ptr;
1135 g_mutex_lock ( p->mutex );
1137 g_mutex_unlock ( p->mutex );
1140 /* Try to add file full_path.
1141 * filename will be copied.
1142 * returns FALSE if file does not exists, TRUE otherwise.
1144 static gboolean dem_layer_add_file ( VikDEMLayer *vdl, const gchar *filename )
1146 if ( g_file_test(filename, G_FILE_TEST_EXISTS) == TRUE ) {
1147 /* only load if file size is not 0 (not in progress) */
1149 (void)stat ( filename, &sb );
1151 gchar *duped_path = g_strdup(filename);
1152 vdl->files = g_list_prepend ( vdl->files, duped_path );
1153 a_dems_load ( duped_path );
1154 g_debug("%s: %s", __FUNCTION__, duped_path);
1161 static void dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
1163 if ( p->source == DEM_SOURCE_SRTM )
1164 srtm_dem_download_thread ( p, threaddata );
1165 #ifdef VIK_CONFIG_DEM24K
1166 else if ( p->source == DEM_SOURCE_DEM24K )
1167 dem24k_dem_download_thread ( p, threaddata );
1172 //gdk_threads_enter();
1173 g_mutex_lock ( p->mutex );
1175 g_object_weak_unref ( G_OBJECT(p->vdl), weak_ref_cb, p );
1177 if ( dem_layer_add_file ( p->vdl, p->dest ) )
1178 vik_layer_emit_update ( VIK_LAYER(p->vdl) ); // NB update from background thread
1180 g_mutex_unlock ( p->mutex );
1181 //gdk_threads_leave();
1185 static void free_dem_download_params ( DEMDownloadParams *p )
1187 vik_mutex_free ( p->mutex );
1192 static gpointer dem_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1198 * Display a simple dialog with information about the DEM file at this location
1200 static void dem_layer_file_info ( GtkWidget *widget, struct LatLon *ll )
1202 gint intlat, intlon;
1203 const gchar *continent_dir;
1205 intlat = (int)floor(ll->lat);
1206 intlon = (int)floor(ll->lon);
1207 continent_dir = srtm_continent_dir(intlat, intlon);
1209 gchar *source = NULL;
1210 if ( continent_dir )
1211 source = g_strdup_printf ( "http://%s%s%s/%c%02d%c%03d.hgt.zip",
1215 (intlat >= 0) ? 'N' : 'S',
1217 (intlon >= 0) ? 'E' : 'W',
1220 // Probably not over any land...
1221 source = g_strdup ( _("No DEM File Available") );
1223 gchar *filename = NULL;
1224 gchar *dem_file = NULL;
1225 #ifdef VIK_CONFIG_DEM24K
1226 dem_file = dem24k_lat_lon_to_dest_fn ( ll->lat, ll->lon );
1228 dem_file = srtm_lat_lon_to_dest_fn ( ll->lat, ll->lon );
1230 gchar *message = NULL;
1232 filename = g_strdup_printf ( "%s%s", MAPS_CACHE_DIR, dem_file );
1234 if ( g_file_test ( filename, G_FILE_TEST_EXISTS ) ) {
1235 // Get some timestamp information of the file
1237 if ( g_stat ( filename, &stat_buf ) == 0 ) {
1239 strftime ( time_buf, sizeof(time_buf), "%c", gmtime((const time_t *)&stat_buf.st_mtime) );
1240 message = g_strdup_printf ( _("\nSource: %s\n\nDEM File: %s\nDEM File Timestamp: %s"), source, filename, time_buf );
1244 message = g_strdup_printf ( _("Source: %s\n\nNo DEM File!"), source );
1247 a_dialog_info_msg ( GTK_WINDOW(gtk_widget_get_toplevel(widget)), message );
1251 g_free ( dem_file );
1252 g_free ( filename );
1255 static gboolean dem_layer_download_release ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp )
1258 static struct LatLon ll;
1261 gchar *dem_file = NULL;
1263 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1264 vik_coord_to_latlon ( &coord, &ll );
1267 if ( vdl->source == DEM_SOURCE_SRTM )
1268 dem_file = srtm_lat_lon_to_dest_fn ( ll.lat, ll.lon );
1269 #ifdef VIK_CONFIG_DEM24K
1270 else if ( vdl->source == DEM_SOURCE_DEM24K )
1271 dem_file = dem24k_lat_lon_to_dest_fn ( ll.lat, ll.lon );
1277 full_path = g_strdup_printf("%s%s", MAPS_CACHE_DIR, dem_file );
1279 g_debug("%s: %s", __FUNCTION__, full_path);
1281 if ( event->button == 1 ) {
1282 // TODO: check if already in filelist
1283 if ( ! dem_layer_add_file(vdl, full_path) ) {
1284 gchar *tmp = g_strdup_printf ( _("Downloading DEM %s"), dem_file );
1285 DEMDownloadParams *p = g_malloc(sizeof(DEMDownloadParams));
1286 p->dest = g_strdup(full_path);
1290 p->mutex = vik_mutex_new();
1291 p->source = vdl->source;
1292 g_object_weak_ref(G_OBJECT(p->vdl), weak_ref_cb, p );
1294 a_background_thread ( BACKGROUND_POOL_REMOTE,
1295 VIK_GTK_WINDOW_FROM_LAYER(vdl), tmp,
1296 (vik_thr_func) dem_download_thread, p,
1297 (vik_thr_free_func) free_dem_download_params, NULL, 1 );
1302 vik_layer_emit_update ( VIK_LAYER(vdl) );
1305 if ( !vdl->right_click_menu ) {
1307 vdl->right_click_menu = GTK_MENU ( gtk_menu_new () );
1309 item = gtk_image_menu_item_new_with_mnemonic ( _("_Show DEM File Information") );
1310 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INFO, GTK_ICON_SIZE_MENU) );
1311 g_signal_connect ( G_OBJECT(item), "activate", G_CALLBACK(dem_layer_file_info), &ll );
1312 gtk_menu_shell_append (GTK_MENU_SHELL(vdl->right_click_menu), item);
1315 gtk_menu_popup ( vdl->right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1316 gtk_widget_show_all ( GTK_WIDGET(vdl->right_click_menu) );
1319 g_free ( dem_file );
1320 g_free ( full_path );
1325 static gboolean dem_layer_download_click ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp )
1327 /* choose & keep track of cache dir
1328 * download in background thread
1329 * download over area */