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);
547 if ( (max_lat > dem_northeast.lat && min_lat > dem_northeast.lat) ||
548 (max_lat < dem_southwest.lat && min_lat < dem_southwest.lat) )
550 else if ( (max_lon > dem_northeast.lon && min_lon > dem_northeast.lon) ||
551 (max_lon < dem_southwest.lon && min_lon < dem_southwest.lon) )
553 /* else they overlap */
555 /**** End Overlap Check ****/
556 /* boxes to show where we have DEM instead of actually drawing the DEM.
557 * useful if we want to see what areas we have coverage for (if we want
558 * to get elevation data for a track) but don't want to cover the map.
562 /* draw a box if a DEM is loaded. in future I'd like to add an option for this
563 * this is useful if we want to see what areas we have dem for but don't want to
564 * cover the map (or maybe we just need translucent DEM?) */
566 VikCoord demne, demsw;
568 vik_coord_load_from_latlon(&demne, vik_viewport_get_coord_mode(vp), &dem_northeast);
569 vik_coord_load_from_latlon(&demsw, vik_viewport_get_coord_mode(vp), &dem_southwest);
571 vik_viewport_coord_to_screen ( vp, &demne, &x1, &y1 );
572 vik_viewport_coord_to_screen ( vp, &demsw, &x2, &y2 );
574 if ( x1 > vik_viewport_get_width(vp) ) x1=vik_viewport_get_width(vp);
575 if ( y2 > vik_viewport_get_height(vp) ) y2=vik_viewport_get_height(vp);
576 if ( x2 < 0 ) x2 = 0;
577 if ( y1 < 0 ) y1 = 0;
578 vik_viewport_draw_rectangle ( vp, gtk_widget_get_style(GTK_WIDGET(vp))->black_gc,
579 FALSE, x2, y1, x1-x2, y2-y1 );
584 if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
585 VikCoord tmp; /* TODO: don't use coord_load_from_latlon, especially if in latlon drawing mode */
587 gdouble max_lat_as, max_lon_as, min_lat_as, min_lon_as;
588 gdouble start_lat_as, end_lat_as, start_lon_as, end_lon_as;
590 gdouble start_lat, end_lat, start_lon, end_lon;
592 struct LatLon counter;
594 guint x, y, start_x, start_y;
598 guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 80 ); /* todo: smarter calculation. */
600 gdouble nscale_deg = dem->north_scale / ((gdouble) 3600);
601 gdouble escale_deg = dem->east_scale / ((gdouble) 3600);
603 max_lat_as = max_lat * 3600;
604 min_lat_as = min_lat * 3600;
605 max_lon_as = max_lon * 3600;
606 min_lon_as = min_lon * 3600;
608 start_lat_as = MAX(min_lat_as, dem->min_north);
609 end_lat_as = MIN(max_lat_as, dem->max_north);
610 start_lon_as = MAX(min_lon_as, dem->min_east);
611 end_lon_as = MIN(max_lon_as, dem->max_east);
613 start_lat = floor(start_lat_as / dem->north_scale) * nscale_deg;
614 end_lat = ceil (end_lat_as / dem->north_scale) * nscale_deg;
615 start_lon = floor(start_lon_as / dem->east_scale) * escale_deg;
616 end_lon = ceil (end_lon_as / dem->east_scale) * escale_deg;
618 vik_dem_east_north_to_xy ( dem, start_lon_as, start_lat_as, &start_x, &start_y );
619 guint gradient_skip_factor = 1;
620 if(vdl->type == DEM_TYPE_GRADIENT)
621 gradient_skip_factor = skip_factor;
623 /* verify sane elev interval */
624 if ( vdl->max_elev <= vdl->min_elev )
625 vdl->max_elev = vdl->min_elev + 1;
627 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 ) {
628 // NOTE: ( counter.lon <= end_lon + ESCALE_DEG*SKIP_FACTOR ) is neccessary so in high zoom modes,
629 // the leftmost column does also get drawn, if the center point is out of viewport.
630 if ( x < dem->n_columns ) {
631 column = g_ptr_array_index ( dem->columns, x );
632 // get previous and next column. catch out-of-bound.
634 new_x -= gradient_skip_factor;
636 prevcolumn = g_ptr_array_index ( dem->columns, x+1);
638 prevcolumn = g_ptr_array_index ( dem->columns, new_x);
640 new_x += gradient_skip_factor;
641 if(new_x >= dem->n_columns)
642 nextcolumn = g_ptr_array_index ( dem->columns, x-1);
644 nextcolumn = g_ptr_array_index ( dem->columns, new_x);
646 for ( y=start_y, counter.lat = start_lat; counter.lat <= end_lat; counter.lat += nscale_deg * skip_factor, y += skip_factor ) {
647 if ( y > column->n_points )
650 elev = column->points[y];
652 // calculate bounding box for drawing
653 gint box_x, box_y, box_width, box_height;
656 box_c.lat += (nscale_deg * skip_factor)/2;
657 box_c.lon -= (escale_deg * skip_factor)/2;
658 vik_coord_load_from_latlon(&tmp, vik_viewport_get_coord_mode(vp), &box_c);
659 vik_viewport_coord_to_screen(vp, &tmp, &box_x, &box_y);
660 // catch box at borders
665 box_c.lat -= nscale_deg * skip_factor;
666 box_c.lon += escale_deg * skip_factor;
667 vik_coord_load_from_latlon(&tmp, vik_viewport_get_coord_mode(vp), &box_c);
668 vik_viewport_coord_to_screen(vp, &tmp, &box_width, &box_height);
671 // catch box at borders
672 if(box_width < 0 || box_height < 0)
673 continue; // skip this. this is out of our viewport anyway. FIXME: why?
675 gboolean below_minimum = FALSE;
676 if(vdl->type == DEM_TYPE_HEIGHT) {
677 if ( elev != VIK_DEM_INVALID_ELEVATION && elev < vdl->min_elev ) {
678 // Prevent 'elev - vdl->min_elev' from being negative so can safely use as array index
679 elev = ceil ( vdl->min_elev );
680 below_minimum = TRUE;
682 if ( elev != VIK_DEM_INVALID_ELEVATION && elev > vdl->max_elev )
683 elev = vdl->max_elev;
687 if(box_width < 0 || box_height < 0) // FIXME: why does this happen?
690 if(vdl->type == DEM_TYPE_GRADIENT) {
691 if( elev == VIK_DEM_INVALID_ELEVATION ) {
694 // calculate and sum gradient in all directions
698 // calculate gradient from height points all around the current one
699 new_y = y - gradient_skip_factor;
702 change += get_height_difference(elev, prevcolumn->points[new_y]);
703 change += get_height_difference(elev, column->points[new_y]);
704 change += get_height_difference(elev, nextcolumn->points[new_y]);
706 change += get_height_difference(elev, prevcolumn->points[y]);
707 change += get_height_difference(elev, nextcolumn->points[y]);
709 new_y = y + gradient_skip_factor;
710 if(new_y >= column->n_points)
712 change += get_height_difference(elev, prevcolumn->points[new_y]);
713 change += get_height_difference(elev, column->points[new_y]);
714 change += get_height_difference(elev, nextcolumn->points[new_y]);
716 change = change / ((skip_factor > 1) ? log(skip_factor) : 0.55); // FIXME: better calc.
718 if(change < vdl->min_elev)
719 // Prevent 'change - vdl->min_elev' from being negative so can safely use as array index
720 change = ceil ( vdl->min_elev );
722 if(change > vdl->max_elev)
723 change = vdl->max_elev;
725 // void vik_viewport_draw_rectangle ( VikViewport *vvp, GdkGC *gc, gboolean filled, gint x1, gint y1, gint x2, gint y2 );
726 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);
729 if(vdl->type == DEM_TYPE_HEIGHT) {
730 if ( elev == VIK_DEM_INVALID_ELEVATION )
731 ; /* don't draw it */
732 else if ( elev <= 0 || below_minimum )
733 /* If 'sea' colour or below the defined mininum draw in the configurable colour */
734 vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, box_x, box_y, box_width, box_height);
736 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);
743 } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
744 gdouble max_nor, max_eas, min_nor, min_eas;
745 gdouble start_nor, start_eas, end_nor, end_eas;
749 guint x, y, start_x, start_y;
751 VikCoord tmp; /* TODO: don't use coord_load_from_latlon, especially if in latlon drawing mode */
754 guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 10 ); /* todo: smarter calculation. */
756 VikCoord tleft, tright, bleft, bright;
758 vik_viewport_screen_to_coord ( vp, 0, 0, &tleft );
759 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), 0, &tright );
760 vik_viewport_screen_to_coord ( vp, 0, vik_viewport_get_height(vp), &bleft );
761 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), vik_viewport_get_height(vp), &bright );
764 vik_coord_convert(&tleft, VIK_COORD_UTM);
765 vik_coord_convert(&tright, VIK_COORD_UTM);
766 vik_coord_convert(&bleft, VIK_COORD_UTM);
767 vik_coord_convert(&bright, VIK_COORD_UTM);
769 max_nor = MAX(tleft.north_south, tright.north_south);
770 min_nor = MIN(bleft.north_south, bright.north_south);
771 max_eas = MAX(bright.east_west, tright.east_west);
772 min_eas = MIN(bleft.east_west, tleft.east_west);
774 start_nor = MAX(min_nor, dem->min_north);
775 end_nor = MIN(max_nor, dem->max_north);
776 if ( tleft.utm_zone == dem->utm_zone && bleft.utm_zone == dem->utm_zone
777 && (tleft.utm_letter >= 'N') == (dem->utm_letter >= 'N')
778 && (bleft.utm_letter >= 'N') == (dem->utm_letter >= 'N') ) /* if the utm zones/hemispheres are different, min_eas will be bogus */
779 start_eas = MAX(min_eas, dem->min_east);
781 start_eas = dem->min_east;
782 if ( tright.utm_zone == dem->utm_zone && bright.utm_zone == dem->utm_zone
783 && (tright.utm_letter >= 'N') == (dem->utm_letter >= 'N')
784 && (bright.utm_letter >= 'N') == (dem->utm_letter >= 'N') ) /* if the utm zones/hemispheres are different, min_eas will be bogus */
785 end_eas = MIN(max_eas, dem->max_east);
787 end_eas = dem->max_east;
789 start_nor = floor(start_nor / dem->north_scale) * dem->north_scale;
790 end_nor = ceil (end_nor / dem->north_scale) * dem->north_scale;
791 start_eas = floor(start_eas / dem->east_scale) * dem->east_scale;
792 end_eas = ceil (end_eas / dem->east_scale) * dem->east_scale;
794 vik_dem_east_north_to_xy ( dem, start_eas, start_nor, &start_x, &start_y );
796 /* TODO: why start_x and start_y are -1 -- rounding error from above? */
798 counter.zone = dem->utm_zone;
799 counter.letter = dem->utm_letter;
801 for ( x=start_x, counter.easting = start_eas; counter.easting <= end_eas; counter.easting += dem->east_scale * skip_factor, x += skip_factor ) {
802 if ( x > 0 && x < dem->n_columns ) {
803 column = g_ptr_array_index ( dem->columns, x );
804 for ( y=start_y, counter.northing = start_nor; counter.northing <= end_nor; counter.northing += dem->north_scale * skip_factor, y += skip_factor ) {
805 if ( y > column->n_points )
807 elev = column->points[y];
808 if ( elev != VIK_DEM_INVALID_ELEVATION && elev < vdl->min_elev )
810 if ( elev != VIK_DEM_INVALID_ELEVATION && elev > vdl->max_elev )
815 vik_coord_load_from_utm(&tmp, vik_viewport_get_coord_mode(vp), &counter);
816 vik_viewport_coord_to_screen(vp, &tmp, &a, &b);
817 if ( elev == VIK_DEM_INVALID_ELEVATION )
818 ; /* don't draw it */
819 else if ( elev <= 0 )
820 vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, a-1, b-1, 2, 2 );
822 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 );
830 /* return the continent for the specified lat, lon */
832 static const gchar *srtm_continent_dir ( gint lat, gint lon )
834 extern const char *_srtm_continent_data[];
835 static GHashTable *srtm_continent = NULL;
836 const gchar *continent;
839 if (!srtm_continent) {
842 srtm_continent = g_hash_table_new(g_str_hash, g_str_equal);
843 s = _srtm_continent_data;
844 while (*s != (gchar *)-1) {
847 g_hash_table_insert(srtm_continent, (gpointer) *s, (gpointer) continent);
853 g_snprintf(name, sizeof(name), "%c%02d%c%03d",
854 (lat >= 0) ? 'N' : 'S', ABS(lat),
855 (lon >= 0) ? 'E' : 'W', ABS(lon));
857 return(g_hash_table_lookup(srtm_continent, name));
860 static void dem_layer_draw ( VikDEMLayer *vdl, VikViewport *vp )
862 GList *dems_iter = vdl->files;
866 /* search for SRTM3 90m */
868 if ( vdl->source == DEM_SOURCE_SRTM )
869 srtm_draw_existence ( vp );
870 #ifdef VIK_CONFIG_DEM24K
871 else if ( vdl->source == DEM_SOURCE_DEM24K )
872 dem24k_draw_existence ( vp );
875 while ( dems_iter ) {
876 dem = a_dems_get ( (const char *) (dems_iter->data) );
878 vik_dem_layer_draw_dem ( vdl, vp, dem );
879 dems_iter = dems_iter->next;
883 static void dem_layer_free ( VikDEMLayer *vdl )
887 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ )
888 g_object_unref ( vdl->gcs[i] );
891 if ( vdl->gcsgradient )
892 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
893 g_object_unref ( vdl->gcsgradient[i] );
894 g_free ( vdl->gcsgradient );
896 a_dems_list_free ( vdl->files );
899 VikDEMLayer *dem_layer_create ( VikViewport *vp )
901 VikDEMLayer *vdl = dem_layer_new ( vp );
904 /* TODO: share GCS between layers */
905 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ ) {
907 vdl->gcs[i] = vik_viewport_new_gc ( vp, dem_height_colors[i], UNUSED_LINE_THICKNESS );
909 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
910 vdl->gcsgradient[i] = vik_viewport_new_gc ( vp, dem_gradient_colors[i], UNUSED_LINE_THICKNESS );
914 /**************************************************************
915 **** SOURCES & DOWNLOADING
916 **************************************************************/
922 VikDEMLayer *vdl; /* NULL if not alive */
928 /**************************************************
930 **************************************************/
932 static void srtm_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
935 const gchar *continent_dir;
937 intlat = (int)floor(p->lat);
938 intlon = (int)floor(p->lon);
939 continent_dir = srtm_continent_dir(intlat, intlon);
941 if (!continent_dir) {
943 gchar *msg = g_strdup_printf ( _("No SRTM data available for %f, %f"), p->lat, p->lon );
944 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(p->vdl), msg, VIK_STATUSBAR_INFO );
950 gchar *src_fn = g_strdup_printf("%s%s/%c%02d%c%03d.hgt.zip",
953 (intlat >= 0) ? 'N' : 'S',
955 (intlon >= 0) ? 'E' : 'W',
958 static DownloadMapOptions options = { FALSE, FALSE, NULL, 0, a_check_map_file, NULL, NULL };
959 DownloadResult_t result = a_http_download_get_url ( SRTM_HTTP_SITE, src_fn, p->dest, &options, NULL );
961 case DOWNLOAD_CONTENT_ERROR:
962 case DOWNLOAD_HTTP_ERROR: {
963 gchar *msg = g_strdup_printf ( _("DEM download failure for %f, %f"), p->lat, p->lon );
964 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(p->vdl), msg, VIK_STATUSBAR_INFO );
968 case DOWNLOAD_FILE_WRITE_ERROR: {
969 gchar *msg = g_strdup_printf ( _("DEM write failure for %s"), p->dest );
970 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(p->vdl), msg, VIK_STATUSBAR_INFO );
974 case DOWNLOAD_SUCCESS:
975 case DOWNLOAD_NOT_REQUIRED:
982 static gchar *srtm_lat_lon_to_dest_fn ( gdouble lat, gdouble lon )
985 const gchar *continent_dir;
987 intlat = (int)floor(lat);
988 intlon = (int)floor(lon);
989 continent_dir = srtm_continent_dir(intlat, intlon);
992 continent_dir = "nowhere";
994 return g_strdup_printf("srtm3-%s%s%c%02d%c%03d.hgt.zip",
997 (intlat >= 0) ? 'N' : 'S',
999 (intlon >= 0) ? 'E' : 'W',
1004 /* TODO: generalize */
1005 static void srtm_draw_existence ( VikViewport *vp )
1007 gdouble max_lat, max_lon, min_lat, min_lon;
1008 gchar buf[strlen(MAPS_CACHE_DIR)+strlen(SRTM_CACHE_TEMPLATE)+30];
1011 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
1013 for (i = floor(min_lat); i <= floor(max_lat); i++) {
1014 for (j = floor(min_lon); j <= floor(max_lon); j++) {
1015 const gchar *continent_dir;
1016 if ((continent_dir = srtm_continent_dir(i, j)) == NULL)
1018 g_snprintf(buf, sizeof(buf), SRTM_CACHE_TEMPLATE,
1022 (i >= 0) ? 'N' : 'S',
1024 (j >= 0) ? 'E' : 'W',
1026 if ( g_file_test(buf, G_FILE_TEST_EXISTS ) == TRUE ) {
1028 gint x1, y1, x2, y2;
1031 sw.mode = VIK_COORD_LATLON;
1032 ne.north_south = i+1;
1034 ne.mode = VIK_COORD_LATLON;
1035 vik_viewport_coord_to_screen ( vp, &sw, &x1, &y1 );
1036 vik_viewport_coord_to_screen ( vp, &ne, &x2, &y2 );
1037 if ( x1 < 0 ) x1 = 0;
1038 if ( y2 < 0 ) y2 = 0;
1039 vik_viewport_draw_rectangle ( vp, gtk_widget_get_style(GTK_WIDGET(vp))->black_gc,
1040 FALSE, x1, y2, x2-x1, y1-y2 );
1047 /**************************************************
1048 * SOURCE: USGS 24K *
1049 **************************************************/
1051 #ifdef VIK_CONFIG_DEM24K
1053 static void dem24k_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
1055 /* TODO: dest dir */
1056 gchar *cmdline = g_strdup_printf("%s %.03f %.03f",
1057 DEM24K_DOWNLOAD_SCRIPT,
1060 /* FIX: don't use system, use execv or something. check for existence */
1065 static gchar *dem24k_lat_lon_to_dest_fn ( gdouble lat, gdouble lon )
1067 return g_strdup_printf("dem24k/%d/%d/%.03f,%.03f.dem",
1074 /* TODO: generalize */
1075 static void dem24k_draw_existence ( VikViewport *vp )
1077 gdouble max_lat, max_lon, min_lat, min_lon;
1078 gchar buf[strlen(MAPS_CACHE_DIR)+40];
1081 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
1083 for (i = floor(min_lat*8)/8; i <= floor(max_lat*8)/8; i+=0.125) {
1084 /* check lat dir first -- faster */
1085 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/",
1088 if ( g_file_test(buf, G_FILE_TEST_EXISTS) == FALSE )
1090 for (j = floor(min_lon*8)/8; j <= floor(max_lon*8)/8; j+=0.125) {
1091 /* check lon dir first -- faster */
1092 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/%d/",
1096 if ( g_file_test(buf, G_FILE_TEST_EXISTS) == FALSE )
1098 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/%d/%.03f,%.03f.dem",
1104 if ( g_file_test(buf, G_FILE_TEST_EXISTS ) == TRUE ) {
1106 gint x1, y1, x2, y2;
1108 sw.east_west = j-0.125;
1109 sw.mode = VIK_COORD_LATLON;
1110 ne.north_south = i+0.125;
1112 ne.mode = VIK_COORD_LATLON;
1113 vik_viewport_coord_to_screen ( vp, &sw, &x1, &y1 );
1114 vik_viewport_coord_to_screen ( vp, &ne, &x2, &y2 );
1115 if ( x1 < 0 ) x1 = 0;
1116 if ( y2 < 0 ) y2 = 0;
1117 vik_viewport_draw_rectangle ( vp, gtk_widget_get_style(GTK_WIDGET(vp))->black_gc,
1118 FALSE, x1, y2, x2-x1, y1-y2 );
1125 /**************************************************
1126 * SOURCES -- DOWNLOADING & IMPORTING TOOL *
1127 **************************************************
1130 static void weak_ref_cb ( gpointer ptr, GObject * dead_vdl )
1132 DEMDownloadParams *p = ptr;
1133 g_mutex_lock ( p->mutex );
1135 g_mutex_unlock ( p->mutex );
1138 /* Try to add file full_path.
1139 * filename will be copied.
1140 * returns FALSE if file does not exists, TRUE otherwise.
1142 static gboolean dem_layer_add_file ( VikDEMLayer *vdl, const gchar *filename )
1144 if ( g_file_test(filename, G_FILE_TEST_EXISTS) == TRUE ) {
1145 /* only load if file size is not 0 (not in progress) */
1147 stat ( filename, &sb );
1149 gchar *duped_path = g_strdup(filename);
1150 vdl->files = g_list_prepend ( vdl->files, duped_path );
1151 a_dems_load ( duped_path );
1152 g_debug("%s: %s", __FUNCTION__, duped_path);
1159 static void dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
1161 if ( p->source == DEM_SOURCE_SRTM )
1162 srtm_dem_download_thread ( p, threaddata );
1163 #ifdef VIK_CONFIG_DEM24K
1164 else if ( p->source == DEM_SOURCE_DEM24K )
1165 dem24k_dem_download_thread ( p, threaddata );
1170 //gdk_threads_enter();
1171 g_mutex_lock ( p->mutex );
1173 g_object_weak_unref ( G_OBJECT(p->vdl), weak_ref_cb, p );
1175 if ( dem_layer_add_file ( p->vdl, p->dest ) )
1176 vik_layer_emit_update ( VIK_LAYER(p->vdl) ); // NB update from background thread
1178 g_mutex_unlock ( p->mutex );
1179 //gdk_threads_leave();
1183 static void free_dem_download_params ( DEMDownloadParams *p )
1185 vik_mutex_free ( p->mutex );
1190 static gpointer dem_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1196 * Display a simple dialog with information about the DEM file at this location
1198 static void dem_layer_file_info ( GtkWidget *widget, struct LatLon *ll )
1200 gint intlat, intlon;
1201 const gchar *continent_dir;
1203 intlat = (int)floor(ll->lat);
1204 intlon = (int)floor(ll->lon);
1205 continent_dir = srtm_continent_dir(intlat, intlon);
1207 gchar *source = NULL;
1208 if ( continent_dir )
1209 source = g_strdup_printf ( "http://%s%s%s/%c%02d%c%03d.hgt.zip",
1213 (intlat >= 0) ? 'N' : 'S',
1215 (intlon >= 0) ? 'E' : 'W',
1218 // Probably not over any land...
1219 source = g_strdup ( _("No DEM File Available") );
1221 gchar *filename = NULL;
1222 gchar *dem_file = NULL;
1223 #ifdef VIK_CONFIG_DEM24K
1224 dem_file = dem24k_lat_lon_to_dest_fn ( ll->lat, ll->lon );
1226 dem_file = srtm_lat_lon_to_dest_fn ( ll->lat, ll->lon );
1228 gchar *message = NULL;
1230 filename = g_strdup_printf ( "%s%s", MAPS_CACHE_DIR, dem_file );
1232 if ( g_file_test ( filename, G_FILE_TEST_EXISTS ) ) {
1233 // Get some timestamp information of the file
1234 struct stat stat_buf;
1235 if ( g_stat ( filename, &stat_buf ) == 0 ) {
1237 strftime ( time_buf, sizeof(time_buf), "%c", gmtime((const time_t *)&stat_buf.st_mtime) );
1238 message = g_strdup_printf ( _("\nSource: %s\n\nDEM File: %s\nDEM File Timestamp: %s"), source, filename, time_buf );
1242 message = g_strdup_printf ( _("Source: %s\n\nNo DEM File!"), source );
1245 a_dialog_info_msg ( GTK_WINDOW(gtk_widget_get_toplevel(widget)), message );
1249 g_free ( dem_file );
1250 g_free ( filename );
1253 static gboolean dem_layer_download_release ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp )
1256 static struct LatLon ll;
1259 gchar *dem_file = NULL;
1261 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1262 vik_coord_to_latlon ( &coord, &ll );
1265 if ( vdl->source == DEM_SOURCE_SRTM )
1266 dem_file = srtm_lat_lon_to_dest_fn ( ll.lat, ll.lon );
1267 #ifdef VIK_CONFIG_DEM24K
1268 else if ( vdl->source == DEM_SOURCE_DEM24K )
1269 dem_file = dem24k_lat_lon_to_dest_fn ( ll.lat, ll.lon );
1275 full_path = g_strdup_printf("%s%s", MAPS_CACHE_DIR, dem_file );
1277 g_debug("%s: %s", __FUNCTION__, full_path);
1279 if ( event->button == 1 ) {
1280 // TODO: check if already in filelist
1281 if ( ! dem_layer_add_file(vdl, full_path) ) {
1282 gchar *tmp = g_strdup_printf ( _("Downloading DEM %s"), dem_file );
1283 DEMDownloadParams *p = g_malloc(sizeof(DEMDownloadParams));
1284 p->dest = g_strdup(full_path);
1288 p->mutex = vik_mutex_new();
1289 p->source = vdl->source;
1290 g_object_weak_ref(G_OBJECT(p->vdl), weak_ref_cb, p );
1292 a_background_thread ( BACKGROUND_POOL_REMOTE,
1293 VIK_GTK_WINDOW_FROM_LAYER(vdl), tmp,
1294 (vik_thr_func) dem_download_thread, p,
1295 (vik_thr_free_func) free_dem_download_params, NULL, 1 );
1300 vik_layer_emit_update ( VIK_LAYER(vdl) );
1303 if ( !vdl->right_click_menu ) {
1305 vdl->right_click_menu = GTK_MENU ( gtk_menu_new () );
1307 item = gtk_image_menu_item_new_with_mnemonic ( _("_Show DEM File Information") );
1308 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INFO, GTK_ICON_SIZE_MENU) );
1309 g_signal_connect ( G_OBJECT(item), "activate", G_CALLBACK(dem_layer_file_info), &ll );
1310 gtk_menu_shell_append (GTK_MENU_SHELL(vdl->right_click_menu), item);
1313 gtk_menu_popup ( vdl->right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1314 gtk_widget_show_all ( GTK_WIDGET(vdl->right_click_menu) );
1317 g_free ( dem_file );
1318 g_free ( full_path );
1323 static gboolean dem_layer_download_click ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp )
1325 /* choose & keep track of cache dir
1326 * download in background thread
1327 * download over area */