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_BASE_URL "http://dds.cr.usgs.gov/srtm/version2_1/SRTM3"
54 #ifdef VIK_CONFIG_DEM24K
55 #define DEM24K_DOWNLOAD_SCRIPT "dem24k.pl"
58 #define UNUSED_LINE_THICKNESS 3
60 static VikDEMLayer *dem_layer_new ( VikViewport *vvp );
61 static void dem_layer_draw ( VikDEMLayer *vdl, VikViewport *vp );
62 static void dem_layer_free ( VikDEMLayer *vdl );
63 static VikDEMLayer *dem_layer_create ( VikViewport *vp );
64 static const gchar* dem_layer_tooltip( VikDEMLayer *vdl );
65 static void dem_layer_marshall( VikDEMLayer *vdl, guint8 **data, gint *len );
66 static VikDEMLayer *dem_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
67 static gboolean dem_layer_set_param ( VikDEMLayer *vdl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation );
68 static VikLayerParamData dem_layer_get_param ( VikDEMLayer *vdl, guint16 id, gboolean is_file_operation );
69 static void dem_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file );
70 static void srtm_draw_existence ( VikViewport *vp );
72 #ifdef VIK_CONFIG_DEM24K
73 static void dem24k_draw_existence ( VikViewport *vp );
76 /* Upped upper limit incase units are feet */
77 static VikLayerParamScale param_scales[] = {
82 static gchar *params_source[] = {
83 "SRTM Global 90m (3 arcsec)",
84 #ifdef VIK_CONFIG_DEM24K
90 static gchar *params_type[] = {
91 N_("Absolute height"),
92 N_("Height gradient"),
96 enum { DEM_SOURCE_SRTM,
97 #ifdef VIK_CONFIG_DEM24K
102 enum { DEM_TYPE_HEIGHT = 0,
107 static VikLayerParamData color_default ( void ) {
108 VikLayerParamData data; gdk_color_parse ( "blue", &data.c ); return data;
111 static VikLayerParamData source_default ( void ) { return VIK_LPD_UINT ( DEM_SOURCE_SRTM ); }
112 static VikLayerParamData type_default ( void ) { return VIK_LPD_UINT ( DEM_TYPE_HEIGHT ); }
113 static VikLayerParamData min_elev_default ( void ) { return VIK_LPD_DOUBLE ( 0.0 ); }
114 static VikLayerParamData max_elev_default ( void ) { return VIK_LPD_DOUBLE ( 1000.0 ); }
116 static VikLayerParam dem_layer_params[] = {
117 { 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 },
118 { 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 },
119 { 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 },
120 { 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 },
121 { 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 },
122 { 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 },
126 enum { PARAM_FILES=0, PARAM_SOURCE, PARAM_COLOR, PARAM_TYPE, PARAM_MIN_ELEV, PARAM_MAX_ELEV, NUM_PARAMS };
128 static gpointer dem_layer_download_create ( VikWindow *vw, VikViewport *vvp);
129 static gboolean dem_layer_download_release ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp );
130 static gboolean dem_layer_download_click ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp );
132 static VikToolInterface dem_tools[] = {
133 { { "DEMDownload", "vik-icon-DEM Download", N_("_DEM Download"), NULL, N_("DEM Download"), 0 },
134 (VikToolConstructorFunc) dem_layer_download_create, NULL, NULL, NULL,
135 (VikToolMouseFunc) dem_layer_download_click, NULL, (VikToolMouseFunc) dem_layer_download_release,
136 (VikToolKeyFunc) NULL,
138 GDK_CURSOR_IS_PIXMAP, &cursor_demdl_pixbuf, NULL },
143 The first entry is blue for a default 'sea' colour,
144 however the value used by the corresponding gc can be configured as part of the DEM layer properties.
145 The other colours, shaded from brown to white are used to give an indication of height.
147 static gchar *dem_height_colors[] = {
149 "#9b793c", "#9c7d40", "#9d8144", "#9e8549", "#9f894d", "#a08d51", "#a29156", "#a3955a", "#a4995e", "#a69d63",
150 "#a89f65", "#aaa267", "#ada569", "#afa76b", "#b1aa6d", "#b4ad6f", "#b6b071", "#b9b373", "#bcb676", "#beb978",
151 "#c0bc7a", "#c2c07d", "#c4c37f", "#c6c681", "#c8ca84", "#cacd86", "#ccd188", "#cfd58b", "#c2ce84", "#b5c87e",
152 "#a9c278", "#9cbb71", "#8fb56b", "#83af65", "#76a95e", "#6aa358", "#5e9d52", "#63a055", "#69a458", "#6fa85c",
153 "#74ac5f", "#7ab063", "#80b467", "#86b86a", "#8cbc6e", "#92c072", "#94c175", "#97c278", "#9ac47c", "#9cc57f",
154 "#9fc682", "#a2c886", "#a4c989", "#a7cb8d", "#aacd91", "#afce99", "#b5d0a1", "#bbd2aa", "#c0d3b2", "#c6d5ba",
155 "#ccd7c3", "#d1d9cb", "#d7dbd4", "#DDDDDD", "#e0e0e0", "#e4e4e4", "#e8e8e8", "#ebebeb", "#efefef", "#f3f3f3",
156 "#f7f7f7", "#fbfbfb", "#ffffff"
159 static const guint DEM_N_HEIGHT_COLORS = sizeof(dem_height_colors)/sizeof(dem_height_colors[0]);
162 "#9b793c", "#9e8549", "#a29156", "#a69d63", "#ada569", "#b4ad6f", "#bcb676", "#c2c07d", "#c8ca84", "#cfd58b",
163 "#a9c278", "#83af65", "#5e9d52", "#6fa85c", "#80b467", "#92c072", "#9ac47c", "#a2c886", "#aacd91", "#bbd2aa",
164 "#ccd7c3", "#DDDDDD", "#e8e8e8", "#f3f3f3", "#FFFFFF"
168 static gchar *dem_gradient_colors[] = {
170 "#000000", "#000011", "#000022", "#000033", "#000044", "#00004c", "#000055", "#00005d", "#000066", "#00006e",
171 "#000077", "#00007f", "#000088", "#000090", "#000099", "#0000a1", "#0000aa", "#0000b2", "#0000bb", "#0000c3",
172 "#0000cc", "#0000d4", "#0000dd", "#0000e5", "#0000ee", "#0000f6", "#0000ff", "#0008f7", "#0011ee", "#0019e6",
173 "#0022dd", "#002ad5", "#0033cc", "#003bc4", "#0044bb", "#004cb3", "#0055aa", "#005da2", "#006699", "#006e91",
174 "#007788", "#007f80", "#008877", "#00906f", "#009966", "#00a15e", "#00aa55", "#00b24d", "#00bb44", "#00c33c",
175 "#00cc33", "#00d42b", "#00dd22", "#00e51a", "#00ee11", "#00f609", "#00ff00", "#08f700", "#11ee00", "#19e600",
176 "#22dd00", "#2ad500", "#33cc00", "#3bc400", "#44bb00", "#4cb300", "#55aa00", "#5da200", "#669900", "#6e9100",
177 "#778800", "#7f8000", "#887700", "#906f00", "#996600", "#a15e00", "#aa5500", "#b24d00", "#bb4400", "#c33c00",
178 "#cc3300", "#d42b00", "#dd2200", "#e51a00", "#ee1100", "#f60900", "#ff0000",
182 static const guint DEM_N_GRADIENT_COLORS = sizeof(dem_gradient_colors)/sizeof(dem_gradient_colors[0]);
185 VikLayerInterface vik_dem_layer_interface = {
192 sizeof(dem_tools) / sizeof(dem_tools[0]),
201 (VikLayerFuncCreate) dem_layer_create,
202 (VikLayerFuncRealize) NULL,
203 (VikLayerFuncPostRead) dem_layer_post_read,
204 (VikLayerFuncFree) dem_layer_free,
206 (VikLayerFuncProperties) NULL,
207 (VikLayerFuncDraw) dem_layer_draw,
208 (VikLayerFuncChangeCoordMode) NULL,
210 (VikLayerFuncGetTimestamp) NULL,
212 (VikLayerFuncSetMenuItemsSelection) NULL,
213 (VikLayerFuncGetMenuItemsSelection) NULL,
215 (VikLayerFuncAddMenuItems) NULL,
216 (VikLayerFuncSublayerAddMenuItems) NULL,
218 (VikLayerFuncSublayerRenameRequest) NULL,
219 (VikLayerFuncSublayerToggleVisible) NULL,
220 (VikLayerFuncSublayerTooltip) NULL,
221 (VikLayerFuncLayerTooltip) dem_layer_tooltip,
222 (VikLayerFuncLayerSelected) NULL,
224 (VikLayerFuncMarshall) dem_layer_marshall,
225 (VikLayerFuncUnmarshall) dem_layer_unmarshall,
227 (VikLayerFuncSetParam) dem_layer_set_param,
228 (VikLayerFuncGetParam) dem_layer_get_param,
229 (VikLayerFuncChangeParam) NULL,
231 (VikLayerFuncReadFileData) NULL,
232 (VikLayerFuncWriteFileData) NULL,
234 (VikLayerFuncDeleteItem) NULL,
235 (VikLayerFuncCutItem) NULL,
236 (VikLayerFuncCopyItem) NULL,
237 (VikLayerFuncPasteItem) NULL,
238 (VikLayerFuncFreeCopiedItem) NULL,
239 (VikLayerFuncDragDropRequest) NULL,
241 (VikLayerFuncSelectClick) NULL,
242 (VikLayerFuncSelectMove) NULL,
243 (VikLayerFuncSelectRelease) NULL,
244 (VikLayerFuncSelectedViewportMenu) NULL,
247 struct _VikDEMLayer {
258 // right click menu only stuff - similar to mapslayer
259 GtkMenu *right_click_menu;
262 GType vik_dem_layer_get_type ()
264 static GType vdl_type = 0;
268 static const GTypeInfo vdl_info =
270 sizeof (VikDEMLayerClass),
271 NULL, /* base_init */
272 NULL, /* base_finalize */
273 NULL, /* class init */
274 NULL, /* class_finalize */
275 NULL, /* class_data */
276 sizeof (VikDEMLayer),
278 NULL /* instance init */
280 vdl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikDEMLayer", &vdl_info, 0 );
286 static const gchar* dem_layer_tooltip( VikDEMLayer *vdl )
288 static gchar tmp_buf[100];
289 g_snprintf (tmp_buf, sizeof(tmp_buf), _("Number of files: %d"), g_list_length (vdl->files));
293 static void dem_layer_marshall( VikDEMLayer *vdl, guint8 **data, gint *len )
295 vik_layer_marshall_params ( VIK_LAYER(vdl), data, len );
298 static VikDEMLayer *dem_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
300 VikDEMLayer *rv = dem_layer_new ( vvp );
303 /* TODO: share GCS between layers */
304 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ ) {
306 rv->gcs[i] = vik_viewport_new_gc_from_color ( vvp, &(rv->color), UNUSED_LINE_THICKNESS );
308 rv->gcs[i] = vik_viewport_new_gc ( vvp, dem_height_colors[i], UNUSED_LINE_THICKNESS );
310 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
311 rv->gcsgradient[i] = vik_viewport_new_gc ( vvp, dem_gradient_colors[i], UNUSED_LINE_THICKNESS );
313 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
317 /* Structure for DEM data used in background thread */
320 } dem_load_thread_data;
323 * Function for starting the DEM file loading as a background thread
325 static int dem_layer_load_list_thread ( dem_load_thread_data *dltd, gpointer threaddata )
327 int result = 0; // Default to good
329 if ( a_dems_load_list ( &(dltd->vdl->files), threaddata ) ) {
334 // ATM as each file is processed the screen is not updated (no mechanism exposed to a_dems_load_list)
335 // Thus force draw only at the end, as loading is complete/aborted
336 //gdk_threads_enter();
337 // Test is helpful to prevent Gtk-CRITICAL warnings if the program is exitted whilst loading
338 if ( IS_VIK_LAYER(dltd->vdl) )
339 vik_layer_emit_update ( VIK_LAYER(dltd->vdl) ); // NB update from background thread
340 //gdk_threads_leave();
345 static void dem_layer_thread_data_free ( dem_load_thread_data *data )
351 static void dem_layer_thread_cancel ( dem_load_thread_data *data )
354 // Instead of freeing the list, leave it as partially processed
355 // Thus we can see/use what was done
359 * Process the list of DEM files and convert each one to a relative path
361 static GList *dem_layer_convert_to_relative_filenaming ( GList *files )
363 gchar *cwd = g_get_current_dir();
367 GList *relfiles = NULL;
370 gchar *file = g_strdup ( file_GetRelativeFilename ( cwd, files->data ) );
371 relfiles = g_list_prepend ( relfiles, file );
378 // Replacing current list, so delete old values first.
381 g_free ( iter->data );
384 g_list_free ( files );
392 gboolean dem_layer_set_param ( VikDEMLayer *vdl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
396 case PARAM_COLOR: vdl->color = data.c; gdk_gc_set_rgb_fg_color ( vdl->gcs[0], &(vdl->color) ); break;
397 case PARAM_SOURCE: vdl->source = data.u; break;
398 case PARAM_TYPE: vdl->type = data.u; break;
400 /* Convert to store internally
401 NB file operation always in internal units (metres) */
402 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
403 vdl->min_elev = VIK_FEET_TO_METERS(data.d);
405 vdl->min_elev = data.d;
408 /* Convert to store internally
409 NB file operation always in internal units (metres) */
410 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
411 vdl->max_elev = VIK_FEET_TO_METERS(data.d);
413 vdl->max_elev = data.d;
417 // Clear out old settings - if any commonalities with new settings they will have to be read again
418 a_dems_list_free ( vdl->files );
419 // Set file list so any other intermediate screen drawing updates will show currently loaded DEMs by the working thread
420 vdl->files = data.sl;
421 // No need for thread if no files
424 dem_load_thread_data *dltd = g_malloc ( sizeof(dem_load_thread_data) );
426 dltd->vdl->files = data.sl;
428 a_background_thread ( BACKGROUND_POOL_LOCAL,
429 VIK_GTK_WINDOW_FROM_WIDGET(vp),
431 (vik_thr_func) dem_layer_load_list_thread,
433 (vik_thr_free_func) dem_layer_thread_data_free,
434 (vik_thr_free_func) dem_layer_thread_cancel,
435 g_list_length ( data.sl ) ); // Number of DEM files
444 static VikLayerParamData dem_layer_get_param ( VikDEMLayer *vdl, guint16 id, gboolean is_file_operation )
446 VikLayerParamData rv;
451 if ( is_file_operation )
452 // Save in relative format if necessary
453 if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE )
454 rv.sl = dem_layer_convert_to_relative_filenaming ( rv.sl );
456 case PARAM_SOURCE: rv.u = vdl->source; break;
457 case PARAM_TYPE: rv.u = vdl->type; break;
458 case PARAM_COLOR: rv.c = vdl->color; break;
460 /* Convert for display in desired units
461 NB file operation always in internal units (metres) */
462 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
463 rv.d = VIK_METERS_TO_FEET(vdl->min_elev);
465 rv.d = vdl->min_elev;
468 /* Convert for display in desired units
469 NB file operation always in internal units (metres) */
470 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
471 rv.d = VIK_METERS_TO_FEET(vdl->max_elev);
473 rv.d = vdl->max_elev;
480 static void dem_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file )
482 /* nothing ATM, but keep in case it's needed the future */
485 static VikDEMLayer *dem_layer_new ( VikViewport *vvp )
487 VikDEMLayer *vdl = VIK_DEM_LAYER ( g_object_new ( VIK_DEM_LAYER_TYPE, NULL ) );
489 vik_layer_set_type ( VIK_LAYER(vdl), VIK_LAYER_DEM );
493 vdl->gcs = g_malloc(sizeof(GdkGC *)*DEM_N_HEIGHT_COLORS);
494 vdl->gcsgradient = g_malloc(sizeof(GdkGC *)*DEM_N_GRADIENT_COLORS);
495 /* make new gcs only if we need it (copy layer -> use old) */
497 // Ensure the base GC is available so the default colour can be applied
498 if ( vvp ) vdl->gcs[0] = vik_viewport_new_gc ( vvp, "#0000FF", 1 );
500 vik_layer_set_defaults ( VIK_LAYER(vdl), vvp );
506 static inline guint16 get_height_difference(gint16 elev, gint16 new_elev)
508 if(new_elev == VIK_DEM_INVALID_ELEVATION)
511 return abs(new_elev - elev);
515 static void vik_dem_layer_draw_dem ( VikDEMLayer *vdl, VikViewport *vp, VikDEM *dem )
517 VikDEMColumn *column, *prevcolumn, *nextcolumn;
519 struct LatLon dem_northeast, dem_southwest;
520 gdouble max_lat, max_lon, min_lat, min_lon;
522 /**** Check if viewport and DEM data overlap ****/
524 /* get min, max lat/lon of viewport */
525 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
527 /* get min, max lat/lon of DEM data */
528 if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
529 dem_northeast.lat = dem->max_north / 3600.0;
530 dem_northeast.lon = dem->max_east / 3600.0;
531 dem_southwest.lat = dem->min_north / 3600.0;
532 dem_southwest.lon = dem->min_east / 3600.0;
533 } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
534 struct UTM dem_northeast_utm, dem_southwest_utm;
535 dem_northeast_utm.northing = dem->max_north;
536 dem_northeast_utm.easting = dem->max_east;
537 dem_southwest_utm.northing = dem->min_north;
538 dem_southwest_utm.easting = dem->min_east;
539 dem_northeast_utm.zone = dem_southwest_utm.zone = dem->utm_zone;
540 dem_northeast_utm.letter = dem_southwest_utm.letter = dem->utm_letter;
542 a_coords_utm_to_latlon(&dem_northeast_utm, &dem_northeast);
543 a_coords_utm_to_latlon(&dem_southwest_utm, &dem_southwest);
545 // Unknown horiz_units - this shouldn't normally happen
546 // Thus can't work out positions to use
550 if ( (max_lat > dem_northeast.lat && min_lat > dem_northeast.lat) ||
551 (max_lat < dem_southwest.lat && min_lat < dem_southwest.lat) )
553 else if ( (max_lon > dem_northeast.lon && min_lon > dem_northeast.lon) ||
554 (max_lon < dem_southwest.lon && min_lon < dem_southwest.lon) )
556 /* else they overlap */
558 /**** End Overlap Check ****/
559 /* boxes to show where we have DEM instead of actually drawing the DEM.
560 * useful if we want to see what areas we have coverage for (if we want
561 * to get elevation data for a track) but don't want to cover the map.
565 /* draw a box if a DEM is loaded. in future I'd like to add an option for this
566 * this is useful if we want to see what areas we have dem for but don't want to
567 * cover the map (or maybe we just need translucent DEM?) */
569 VikCoord demne, demsw;
571 vik_coord_load_from_latlon(&demne, vik_viewport_get_coord_mode(vp), &dem_northeast);
572 vik_coord_load_from_latlon(&demsw, vik_viewport_get_coord_mode(vp), &dem_southwest);
574 vik_viewport_coord_to_screen ( vp, &demne, &x1, &y1 );
575 vik_viewport_coord_to_screen ( vp, &demsw, &x2, &y2 );
577 if ( x1 > vik_viewport_get_width(vp) ) x1=vik_viewport_get_width(vp);
578 if ( y2 > vik_viewport_get_height(vp) ) y2=vik_viewport_get_height(vp);
579 if ( x2 < 0 ) x2 = 0;
580 if ( y1 < 0 ) y1 = 0;
581 vik_viewport_draw_rectangle ( vp, gtk_widget_get_style(GTK_WIDGET(vp))->black_gc,
582 FALSE, x2, y1, x1-x2, y2-y1 );
587 if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
588 VikCoord tmp; /* TODO: don't use coord_load_from_latlon, especially if in latlon drawing mode */
590 gdouble max_lat_as, max_lon_as, min_lat_as, min_lon_as;
591 gdouble start_lat_as, end_lat_as, start_lon_as, end_lon_as;
593 gdouble start_lat, end_lat, start_lon, end_lon;
595 struct LatLon counter;
597 guint x, y, start_x, start_y;
601 guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 80 ); /* todo: smarter calculation. */
603 gdouble nscale_deg = dem->north_scale / ((gdouble) 3600);
604 gdouble escale_deg = dem->east_scale / ((gdouble) 3600);
606 max_lat_as = max_lat * 3600;
607 min_lat_as = min_lat * 3600;
608 max_lon_as = max_lon * 3600;
609 min_lon_as = min_lon * 3600;
611 start_lat_as = MAX(min_lat_as, dem->min_north);
612 end_lat_as = MIN(max_lat_as, dem->max_north);
613 start_lon_as = MAX(min_lon_as, dem->min_east);
614 end_lon_as = MIN(max_lon_as, dem->max_east);
616 start_lat = floor(start_lat_as / dem->north_scale) * nscale_deg;
617 end_lat = ceil (end_lat_as / dem->north_scale) * nscale_deg;
618 start_lon = floor(start_lon_as / dem->east_scale) * escale_deg;
619 end_lon = ceil (end_lon_as / dem->east_scale) * escale_deg;
621 vik_dem_east_north_to_xy ( dem, start_lon_as, start_lat_as, &start_x, &start_y );
622 guint gradient_skip_factor = 1;
623 if(vdl->type == DEM_TYPE_GRADIENT)
624 gradient_skip_factor = skip_factor;
626 /* verify sane elev interval */
627 if ( vdl->max_elev <= vdl->min_elev )
628 vdl->max_elev = vdl->min_elev + 1;
630 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 ) {
631 // NOTE: ( counter.lon <= end_lon + ESCALE_DEG*SKIP_FACTOR ) is neccessary so in high zoom modes,
632 // the leftmost column does also get drawn, if the center point is out of viewport.
633 if ( x < dem->n_columns ) {
634 column = g_ptr_array_index ( dem->columns, x );
635 // get previous and next column. catch out-of-bound.
637 new_x -= gradient_skip_factor;
639 prevcolumn = g_ptr_array_index ( dem->columns, x+1);
641 prevcolumn = g_ptr_array_index ( dem->columns, new_x);
643 new_x += gradient_skip_factor;
644 if(new_x >= dem->n_columns)
645 nextcolumn = g_ptr_array_index ( dem->columns, x-1);
647 nextcolumn = g_ptr_array_index ( dem->columns, new_x);
649 for ( y=start_y, counter.lat = start_lat; counter.lat <= end_lat; counter.lat += nscale_deg * skip_factor, y += skip_factor ) {
650 if ( y > column->n_points )
653 elev = column->points[y];
655 // calculate bounding box for drawing
656 gint box_x, box_y, box_width, box_height;
659 box_c.lat += (nscale_deg * skip_factor)/2;
660 box_c.lon -= (escale_deg * skip_factor)/2;
661 vik_coord_load_from_latlon(&tmp, vik_viewport_get_coord_mode(vp), &box_c);
662 vik_viewport_coord_to_screen(vp, &tmp, &box_x, &box_y);
663 // catch box at borders
668 box_c.lat -= nscale_deg * skip_factor;
669 box_c.lon += escale_deg * skip_factor;
670 vik_coord_load_from_latlon(&tmp, vik_viewport_get_coord_mode(vp), &box_c);
671 vik_viewport_coord_to_screen(vp, &tmp, &box_width, &box_height);
674 // catch box at borders
675 if(box_width < 0 || box_height < 0)
676 // skip this as is out of the viewport (e.g. zoomed in so this point is way off screen)
679 gboolean below_minimum = FALSE;
680 if(vdl->type == DEM_TYPE_HEIGHT) {
681 if ( elev != VIK_DEM_INVALID_ELEVATION && elev < vdl->min_elev ) {
682 // Prevent 'elev - vdl->min_elev' from being negative so can safely use as array index
683 elev = ceil ( vdl->min_elev );
684 below_minimum = TRUE;
686 if ( elev != VIK_DEM_INVALID_ELEVATION && elev > vdl->max_elev )
687 elev = vdl->max_elev;
691 if(vdl->type == DEM_TYPE_GRADIENT) {
692 if( elev == VIK_DEM_INVALID_ELEVATION ) {
695 // calculate and sum gradient in all directions
699 // calculate gradient from height points all around the current one
700 new_y = y - gradient_skip_factor;
703 change += get_height_difference(elev, prevcolumn->points[new_y]);
704 change += get_height_difference(elev, column->points[new_y]);
705 change += get_height_difference(elev, nextcolumn->points[new_y]);
707 change += get_height_difference(elev, prevcolumn->points[y]);
708 change += get_height_difference(elev, nextcolumn->points[y]);
710 new_y = y + gradient_skip_factor;
711 if(new_y >= column->n_points)
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 = change / ((skip_factor > 1) ? log(skip_factor) : 0.55); // FIXME: better calc.
719 if(change < vdl->min_elev)
720 // Prevent 'change - vdl->min_elev' from being negative so can safely use as array index
721 change = ceil ( vdl->min_elev );
723 if(change > vdl->max_elev)
724 change = vdl->max_elev;
726 // void vik_viewport_draw_rectangle ( VikViewport *vvp, GdkGC *gc, gboolean filled, gint x1, gint y1, gint x2, gint y2 );
727 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);
730 if(vdl->type == DEM_TYPE_HEIGHT) {
731 if ( elev == VIK_DEM_INVALID_ELEVATION )
732 ; /* don't draw it */
733 else if ( elev <= 0 || below_minimum )
734 /* If 'sea' colour or below the defined mininum draw in the configurable colour */
735 vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, box_x, box_y, box_width, box_height);
737 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);
744 } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
745 gdouble max_nor, max_eas, min_nor, min_eas;
746 gdouble start_nor, start_eas, end_nor, end_eas;
750 guint x, y, start_x, start_y;
752 VikCoord tmp; /* TODO: don't use coord_load_from_latlon, especially if in latlon drawing mode */
755 guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 10 ); /* todo: smarter calculation. */
757 VikCoord tleft, tright, bleft, bright;
759 vik_viewport_screen_to_coord ( vp, 0, 0, &tleft );
760 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), 0, &tright );
761 vik_viewport_screen_to_coord ( vp, 0, vik_viewport_get_height(vp), &bleft );
762 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), vik_viewport_get_height(vp), &bright );
765 vik_coord_convert(&tleft, VIK_COORD_UTM);
766 vik_coord_convert(&tright, VIK_COORD_UTM);
767 vik_coord_convert(&bleft, VIK_COORD_UTM);
768 vik_coord_convert(&bright, VIK_COORD_UTM);
770 max_nor = MAX(tleft.north_south, tright.north_south);
771 min_nor = MIN(bleft.north_south, bright.north_south);
772 max_eas = MAX(bright.east_west, tright.east_west);
773 min_eas = MIN(bleft.east_west, tleft.east_west);
775 start_nor = MAX(min_nor, dem->min_north);
776 end_nor = MIN(max_nor, dem->max_north);
777 if ( tleft.utm_zone == dem->utm_zone && bleft.utm_zone == dem->utm_zone
778 && (tleft.utm_letter >= 'N') == (dem->utm_letter >= 'N')
779 && (bleft.utm_letter >= 'N') == (dem->utm_letter >= 'N') ) /* if the utm zones/hemispheres are different, min_eas will be bogus */
780 start_eas = MAX(min_eas, dem->min_east);
782 start_eas = dem->min_east;
783 if ( tright.utm_zone == dem->utm_zone && bright.utm_zone == dem->utm_zone
784 && (tright.utm_letter >= 'N') == (dem->utm_letter >= 'N')
785 && (bright.utm_letter >= 'N') == (dem->utm_letter >= 'N') ) /* if the utm zones/hemispheres are different, min_eas will be bogus */
786 end_eas = MIN(max_eas, dem->max_east);
788 end_eas = dem->max_east;
790 start_nor = floor(start_nor / dem->north_scale) * dem->north_scale;
791 end_nor = ceil (end_nor / dem->north_scale) * dem->north_scale;
792 start_eas = floor(start_eas / dem->east_scale) * dem->east_scale;
793 end_eas = ceil (end_eas / dem->east_scale) * dem->east_scale;
795 vik_dem_east_north_to_xy ( dem, start_eas, start_nor, &start_x, &start_y );
797 /* TODO: why start_x and start_y are -1 -- rounding error from above? */
799 counter.zone = dem->utm_zone;
800 counter.letter = dem->utm_letter;
802 for ( x=start_x, counter.easting = start_eas; counter.easting <= end_eas; counter.easting += dem->east_scale * skip_factor, x += skip_factor ) {
803 if ( x > 0 && x < dem->n_columns ) {
804 column = g_ptr_array_index ( dem->columns, x );
805 for ( y=start_y, counter.northing = start_nor; counter.northing <= end_nor; counter.northing += dem->north_scale * skip_factor, y += skip_factor ) {
806 if ( y > column->n_points )
808 elev = column->points[y];
809 if ( elev != VIK_DEM_INVALID_ELEVATION && elev < vdl->min_elev )
811 if ( elev != VIK_DEM_INVALID_ELEVATION && elev > vdl->max_elev )
816 vik_coord_load_from_utm(&tmp, vik_viewport_get_coord_mode(vp), &counter);
817 vik_viewport_coord_to_screen(vp, &tmp, &a, &b);
818 if ( elev == VIK_DEM_INVALID_ELEVATION )
819 ; /* don't draw it */
820 else if ( elev <= 0 )
821 vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, a-1, b-1, 2, 2 );
823 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 );
831 /* return the continent for the specified lat, lon */
833 static const gchar *srtm_continent_dir ( gint lat, gint lon )
835 extern const char *_srtm_continent_data[];
836 static GHashTable *srtm_continent = NULL;
837 const gchar *continent;
840 if (!srtm_continent) {
843 srtm_continent = g_hash_table_new(g_str_hash, g_str_equal);
844 s = _srtm_continent_data;
845 while (*s != (gchar *)-1) {
848 g_hash_table_insert(srtm_continent, (gpointer) *s, (gpointer) continent);
854 g_snprintf(name, sizeof(name), "%c%02d%c%03d",
855 (lat >= 0) ? 'N' : 'S', ABS(lat),
856 (lon >= 0) ? 'E' : 'W', ABS(lon));
858 return(g_hash_table_lookup(srtm_continent, name));
861 static void dem_layer_draw ( VikDEMLayer *vdl, VikViewport *vp )
863 GList *dems_iter = vdl->files;
867 /* search for SRTM3 90m */
869 if ( vdl->source == DEM_SOURCE_SRTM )
870 srtm_draw_existence ( vp );
871 #ifdef VIK_CONFIG_DEM24K
872 else if ( vdl->source == DEM_SOURCE_DEM24K )
873 dem24k_draw_existence ( vp );
876 while ( dems_iter ) {
877 dem = a_dems_get ( (const char *) (dems_iter->data) );
879 vik_dem_layer_draw_dem ( vdl, vp, dem );
880 dems_iter = dems_iter->next;
884 static void dem_layer_free ( VikDEMLayer *vdl )
888 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ )
889 g_object_unref ( vdl->gcs[i] );
892 if ( vdl->gcsgradient )
893 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
894 g_object_unref ( vdl->gcsgradient[i] );
895 g_free ( vdl->gcsgradient );
897 a_dems_list_free ( vdl->files );
900 VikDEMLayer *dem_layer_create ( VikViewport *vp )
902 VikDEMLayer *vdl = dem_layer_new ( vp );
905 /* TODO: share GCS between layers */
906 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ ) {
908 vdl->gcs[i] = vik_viewport_new_gc ( vp, dem_height_colors[i], UNUSED_LINE_THICKNESS );
910 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
911 vdl->gcsgradient[i] = vik_viewport_new_gc ( vp, dem_gradient_colors[i], UNUSED_LINE_THICKNESS );
915 /**************************************************************
916 **** SOURCES & DOWNLOADING
917 **************************************************************/
923 VikDEMLayer *vdl; /* NULL if not alive */
929 /**************************************************
931 **************************************************/
933 static void srtm_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
936 const gchar *continent_dir;
938 intlat = (int)floor(p->lat);
939 intlon = (int)floor(p->lon);
940 continent_dir = srtm_continent_dir(intlat, intlon);
942 if (!continent_dir) {
944 gchar *msg = g_strdup_printf ( _("No SRTM data available for %f, %f"), p->lat, p->lon );
945 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(p->vdl), msg, VIK_STATUSBAR_INFO );
951 gchar *src_url = g_strdup_printf("%s/%s/%c%02d%c%03d.hgt.zip",
954 (intlat >= 0) ? 'N' : 'S',
956 (intlon >= 0) ? 'E' : 'W',
959 static DownloadFileOptions options = { FALSE, FALSE, NULL, 5, a_check_map_file, NULL, NULL };
960 DownloadResult_t result = a_http_download_get_url ( src_url, NULL, p->dest, &options, NULL );
962 case DOWNLOAD_PARAMETERS_ERROR:
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)g_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 ( "%s/%s/%c%02d%c%03d.hgt.zip",
1214 (intlat >= 0) ? 'N' : 'S',
1216 (intlon >= 0) ? 'E' : 'W',
1219 // Probably not over any land...
1220 source = g_strdup ( _("No DEM File Available") );
1222 gchar *filename = NULL;
1223 gchar *dem_file = NULL;
1224 #ifdef VIK_CONFIG_DEM24K
1225 dem_file = dem24k_lat_lon_to_dest_fn ( ll->lat, ll->lon );
1227 dem_file = srtm_lat_lon_to_dest_fn ( ll->lat, ll->lon );
1229 gchar *message = NULL;
1231 filename = g_strdup_printf ( "%s%s", MAPS_CACHE_DIR, dem_file );
1233 if ( g_file_test ( filename, G_FILE_TEST_EXISTS ) ) {
1234 // Get some timestamp information of the file
1236 if ( g_stat ( filename, &stat_buf ) == 0 ) {
1238 strftime ( time_buf, sizeof(time_buf), "%c", gmtime((const time_t *)&stat_buf.st_mtime) );
1239 message = g_strdup_printf ( _("\nSource: %s\n\nDEM File: %s\nDEM File Timestamp: %s"), source, filename, time_buf );
1243 message = g_strdup_printf ( _("Source: %s\n\nNo DEM File!"), source );
1246 a_dialog_info_msg ( GTK_WINDOW(gtk_widget_get_toplevel(widget)), message );
1250 g_free ( dem_file );
1251 g_free ( filename );
1254 static gboolean dem_layer_download_release ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp )
1257 static struct LatLon ll;
1260 gchar *dem_file = NULL;
1262 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1263 vik_coord_to_latlon ( &coord, &ll );
1266 if ( vdl->source == DEM_SOURCE_SRTM )
1267 dem_file = srtm_lat_lon_to_dest_fn ( ll.lat, ll.lon );
1268 #ifdef VIK_CONFIG_DEM24K
1269 else if ( vdl->source == DEM_SOURCE_DEM24K )
1270 dem_file = dem24k_lat_lon_to_dest_fn ( ll.lat, ll.lon );
1276 full_path = g_strdup_printf("%s%s", MAPS_CACHE_DIR, dem_file );
1278 g_debug("%s: %s", __FUNCTION__, full_path);
1280 if ( event->button == 1 ) {
1281 // TODO: check if already in filelist
1282 if ( ! dem_layer_add_file(vdl, full_path) ) {
1283 gchar *tmp = g_strdup_printf ( _("Downloading DEM %s"), dem_file );
1284 DEMDownloadParams *p = g_malloc(sizeof(DEMDownloadParams));
1285 p->dest = g_strdup(full_path);
1289 p->mutex = vik_mutex_new();
1290 p->source = vdl->source;
1291 g_object_weak_ref(G_OBJECT(p->vdl), weak_ref_cb, p );
1293 a_background_thread ( BACKGROUND_POOL_REMOTE,
1294 VIK_GTK_WINDOW_FROM_LAYER(vdl), tmp,
1295 (vik_thr_func) dem_download_thread, p,
1296 (vik_thr_free_func) free_dem_download_params, NULL, 1 );
1301 vik_layer_emit_update ( VIK_LAYER(vdl) );
1304 if ( !vdl->right_click_menu ) {
1306 vdl->right_click_menu = GTK_MENU ( gtk_menu_new () );
1308 item = gtk_image_menu_item_new_with_mnemonic ( _("_Show DEM File Information") );
1309 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INFO, GTK_ICON_SIZE_MENU) );
1310 g_signal_connect ( G_OBJECT(item), "activate", G_CALLBACK(dem_layer_file_info), &ll );
1311 gtk_menu_shell_append (GTK_MENU_SHELL(vdl->right_click_menu), item);
1314 gtk_menu_popup ( vdl->right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1315 gtk_widget_show_all ( GTK_WIDGET(vdl->right_click_menu) );
1318 g_free ( dem_file );
1319 g_free ( full_path );
1324 static gboolean dem_layer_download_click ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp )
1326 /* choose & keep track of cache dir
1327 * download in background thread
1328 * download over area */