]> git.street.me.uk Git - andy/viking.git/blob - src/vikdemlayer.c
Merge remote branch 'jocelyn/etag'
[andy/viking.git] / src / vikdemlayer.c
1 /*
2  * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3  *
4  * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
5  *
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.
10  *
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.
15  *
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
19  *
20  */
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #ifdef HAVE_MATH_H
26 #include <math.h>
27 #endif
28 #ifdef HAVE_SYS_TYPES_H
29 #include <sys/types.h>
30 #endif
31 #ifdef HAVE_SYS_STAT_H
32 #include <sys/stat.h>
33 #endif
34 #ifdef HAVE_STRING_H
35 #include <string.h>
36 #endif
37 #include <stdlib.h>
38 #include <glib/gi18n.h>
39
40 #include "config.h"
41 #include "globals.h"
42 #include "coords.h"
43 #include "vikcoord.h"
44 #include "download.h"
45 #include "background.h"
46 #include "vikwaypoint.h"
47 #include "viktrack.h"
48 #include "vikviewport.h"
49 #include "viktreeview.h"
50 #include "viklayer.h"
51 #include "vikaggregatelayer.h"
52 #include "viklayerspanel.h"
53 #include "vikmapslayer.h"
54 #include "vikdemlayer.h"
55 #include "dialog.h"
56
57 #include "dem.h"
58 #include "dems.h"
59
60 #include "icons/icons.h"
61
62 #define MAPS_CACHE_DIR maps_layer_default_dir()
63
64 #define SRTM_CACHE_TEMPLATE "%ssrtm3-%s%s%c%02d%c%03d.hgt.zip"
65 #define SRTM_HTTP_SITE "dds.cr.usgs.gov"
66 #define SRTM_HTTP_URI  "/srtm/version2_1/SRTM3/"
67
68 #ifdef VIK_CONFIG_DEM24K
69 #define DEM24K_DOWNLOAD_SCRIPT "dem24k.pl"
70 #endif
71
72 #define UNUSED_LINE_THICKNESS 3
73
74 static void dem_layer_marshall( VikDEMLayer *vdl, guint8 **data, gint *len );
75 static VikDEMLayer *dem_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
76 static gboolean dem_layer_set_param ( VikDEMLayer *vdl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation );
77 static VikLayerParamData dem_layer_get_param ( VikDEMLayer *vdl, guint16 id, gboolean is_file_operation );
78 static void dem_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file );
79 static void srtm_draw_existence ( VikViewport *vp );
80
81 #ifdef VIK_CONFIG_DEM24K
82 static void dem24k_draw_existence ( VikViewport *vp );
83 #endif
84
85 /* Upped upper limit incase units are feet */
86 static VikLayerParamScale param_scales[] = {
87   { 0, 30000, 10, 1 },
88   { 1, 30000, 10, 1 },
89 };
90
91 static gchar *params_source[] = {
92         "SRTM Global 90m (3 arcsec)",
93 #ifdef VIK_CONFIG_DEM24K
94         "USA 10m (USGS 24k)",
95 #endif
96         "None",
97         NULL
98         };
99
100 static gchar *params_type[] = {
101         N_("Absolute height"),
102         N_("Height gradient"),
103         NULL
104 };
105
106 enum { DEM_SOURCE_SRTM,
107 #ifdef VIK_CONFIG_DEM24K
108        DEM_SOURCE_DEM24K,
109 #endif
110        DEM_SOURCE_NONE,
111      };
112
113 enum { DEM_TYPE_HEIGHT = 0,
114        DEM_TYPE_GRADIENT,
115        DEM_TYPE_NONE,
116 };
117
118 static VikLayerParam dem_layer_params[] = {
119   { "files", VIK_LAYER_PARAM_STRING_LIST, VIK_LAYER_GROUP_NONE, N_("DEM Files:"), VIK_LAYER_WIDGET_FILELIST },
120   { "source", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Download Source:"), VIK_LAYER_WIDGET_RADIOGROUP_STATIC, params_source, NULL },
121   { "color", VIK_LAYER_PARAM_COLOR, VIK_LAYER_GROUP_NONE, N_("Min Elev Color:"), VIK_LAYER_WIDGET_COLOR, 0 },
122   { "type", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Type:"), VIK_LAYER_WIDGET_RADIOGROUP_STATIC, params_type, NULL },
123   { "min_elev", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_GROUP_NONE, N_("Min Elev:"), VIK_LAYER_WIDGET_SPINBUTTON, param_scales + 0 },
124   { "max_elev", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_GROUP_NONE, N_("Max Elev:"), VIK_LAYER_WIDGET_SPINBUTTON, param_scales + 0 },
125 };
126
127
128 enum { PARAM_FILES=0, PARAM_SOURCE, PARAM_COLOR, PARAM_TYPE, PARAM_MIN_ELEV, PARAM_MAX_ELEV, NUM_PARAMS };
129
130 static gpointer dem_layer_download_create ( VikWindow *vw, VikViewport *vvp);
131 static gboolean dem_layer_download_release ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp );
132 static gboolean dem_layer_download_click ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp );
133
134 static VikToolInterface dem_tools[] = {
135   { N_("DEM Download/Import"), (VikToolConstructorFunc) dem_layer_download_create, NULL, NULL, NULL,
136     (VikToolMouseFunc) dem_layer_download_click, NULL,  (VikToolMouseFunc) dem_layer_download_release,
137     (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_demdl_pixbuf },
138 };
139
140
141 /* HEIGHT COLORS
142    The first entry is blue for a default 'sea' colour,
143    however the value used by the corresponding gc can be configured as part of the DEM layer properties.
144    The other colours, shaded from brown to white are used to give an indication of height.
145 */
146 static gchar *dem_height_colors[] = {
147 "#0000FF",
148 "#9b793c", "#9c7d40", "#9d8144", "#9e8549", "#9f894d", "#a08d51", "#a29156", "#a3955a", "#a4995e", "#a69d63",
149 "#a89f65", "#aaa267", "#ada569", "#afa76b", "#b1aa6d", "#b4ad6f", "#b6b071", "#b9b373", "#bcb676", "#beb978",
150 "#c0bc7a", "#c2c07d", "#c4c37f", "#c6c681", "#c8ca84", "#cacd86", "#ccd188", "#cfd58b", "#c2ce84", "#b5c87e",
151 "#a9c278", "#9cbb71", "#8fb56b", "#83af65", "#76a95e", "#6aa358", "#5e9d52", "#63a055", "#69a458", "#6fa85c",
152 "#74ac5f", "#7ab063", "#80b467", "#86b86a", "#8cbc6e", "#92c072", "#94c175", "#97c278", "#9ac47c", "#9cc57f",
153 "#9fc682", "#a2c886", "#a4c989", "#a7cb8d", "#aacd91", "#afce99", "#b5d0a1", "#bbd2aa", "#c0d3b2", "#c6d5ba",
154 "#ccd7c3", "#d1d9cb", "#d7dbd4", "#DDDDDD", "#e0e0e0", "#e4e4e4", "#e8e8e8", "#ebebeb", "#efefef", "#f3f3f3",
155 "#f7f7f7", "#fbfbfb", "#ffffff"
156 };
157
158 static const guint DEM_N_HEIGHT_COLORS = sizeof(dem_height_colors)/sizeof(dem_height_colors[0]);
159
160 /*
161 "#9b793c", "#9e8549", "#a29156", "#a69d63", "#ada569", "#b4ad6f", "#bcb676", "#c2c07d", "#c8ca84", "#cfd58b",
162 "#a9c278", "#83af65", "#5e9d52", "#6fa85c", "#80b467", "#92c072", "#9ac47c", "#a2c886", "#aacd91", "#bbd2aa",
163 "#ccd7c3", "#DDDDDD", "#e8e8e8", "#f3f3f3", "#FFFFFF"
164 };
165 */
166
167 static gchar *dem_gradient_colors[] = {
168 "#AAAAAA"
169 "#000000", "#000011", "#000022", "#000033", "#000044", "#00004c", "#000055", "#00005d", "#000066", "#00006e",
170 "#000077", "#00007f", "#000088", "#000090", "#000099", "#0000a1", "#0000aa", "#0000b2", "#0000bb", "#0000c3",
171 "#0000cc", "#0000d4", "#0000dd", "#0000e5", "#0000ee", "#0000f6", "#0000ff", "#0008f7", "#0011ee", "#0019e6",
172 "#0022dd", "#002ad5", "#0033cc", "#003bc4", "#0044bb", "#004cb3", "#0055aa", "#005da2", "#006699", "#006e91",
173 "#007788", "#007f80", "#008877", "#00906f", "#009966", "#00a15e", "#00aa55", "#00b24d", "#00bb44", "#00c33c",
174 "#00cc33", "#00d42b", "#00dd22", "#00e51a", "#00ee11", "#00f609", "#00ff00", "#08f700", "#11ee00", "#19e600",
175 "#22dd00", "#2ad500", "#33cc00", "#3bc400", "#44bb00", "#4cb300", "#55aa00", "#5da200", "#669900", "#6e9100",
176 "#778800", "#7f8000", "#887700", "#906f00", "#996600", "#a15e00", "#aa5500", "#b24d00", "#bb4400", "#c33c00",
177 "#cc3300", "#d42b00", "#dd2200", "#e51a00", "#ee1100", "#f60900", "#ff0000",
178 "#FFFFFF"
179 };
180
181 static const guint DEM_N_GRADIENT_COLORS = sizeof(dem_gradient_colors)/sizeof(dem_gradient_colors[0]);
182
183
184 VikLayerInterface vik_dem_layer_interface = {
185   "DEM",
186   &vikdemlayer_pixbuf,
187
188   dem_tools,
189   sizeof(dem_tools) / sizeof(dem_tools[0]),
190
191   dem_layer_params,
192   NUM_PARAMS,
193   NULL,
194   0,
195
196   VIK_MENU_ITEM_ALL,
197
198   (VikLayerFuncCreate)                  vik_dem_layer_create,
199   (VikLayerFuncRealize)                 NULL,
200   (VikLayerFuncPostRead)                dem_layer_post_read,
201   (VikLayerFuncFree)                    vik_dem_layer_free,
202
203   (VikLayerFuncProperties)              NULL,
204   (VikLayerFuncDraw)                    vik_dem_layer_draw,
205   (VikLayerFuncChangeCoordMode)         NULL,
206
207   (VikLayerFuncSetMenuItemsSelection)   NULL,
208   (VikLayerFuncGetMenuItemsSelection)   NULL,
209
210   (VikLayerFuncAddMenuItems)            NULL,
211   (VikLayerFuncSublayerAddMenuItems)    NULL,
212
213   (VikLayerFuncSublayerRenameRequest)   NULL,
214   (VikLayerFuncSublayerToggleVisible)   NULL,
215
216   (VikLayerFuncMarshall)                dem_layer_marshall,
217   (VikLayerFuncUnmarshall)              dem_layer_unmarshall,
218
219   (VikLayerFuncSetParam)                dem_layer_set_param,
220   (VikLayerFuncGetParam)                dem_layer_get_param,
221
222   (VikLayerFuncReadFileData)            NULL,
223   (VikLayerFuncWriteFileData)           NULL,
224
225   (VikLayerFuncDeleteItem)              NULL,
226   (VikLayerFuncCopyItem)                NULL,
227   (VikLayerFuncPasteItem)               NULL,
228   (VikLayerFuncFreeCopiedItem)          NULL,
229   (VikLayerFuncDragDropRequest)         NULL,
230 };
231
232 struct _VikDEMLayer {
233   VikLayer vl;
234   GdkGC **gcs;
235   GdkGC **gcsgradient;
236   GList *files;
237   gdouble min_elev;
238   gdouble max_elev;
239   GdkGC *color;
240   guint source;
241   guint type;
242 };
243
244 GType vik_dem_layer_get_type ()
245 {
246   static GType vdl_type = 0;
247
248   if (!vdl_type)
249   {
250     static const GTypeInfo vdl_info =
251     {
252       sizeof (VikDEMLayerClass),
253       NULL, /* base_init */
254       NULL, /* base_finalize */
255       NULL, /* class init */
256       NULL, /* class_finalize */
257       NULL, /* class_data */
258       sizeof (VikDEMLayer),
259       0,
260       NULL /* instance init */
261     };
262     vdl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikDEMLayer", &vdl_info, 0 );
263   }
264
265   return vdl_type;
266 }
267
268 static void dem_layer_marshall( VikDEMLayer *vdl, guint8 **data, gint *len )
269 {
270   vik_layer_marshall_params ( VIK_LAYER(vdl), data, len );
271 }
272
273 static VikDEMLayer *dem_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
274 {
275   VikDEMLayer *rv = vik_dem_layer_new ();
276   gint i;
277
278   /* TODO: share GCS between layers */
279   for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ )
280     rv->gcs[i] = vik_viewport_new_gc ( vvp, dem_height_colors[i], UNUSED_LINE_THICKNESS );
281
282   for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
283     rv->gcsgradient[i] = vik_viewport_new_gc ( vvp, dem_gradient_colors[i], UNUSED_LINE_THICKNESS );
284
285   vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
286   return rv;
287 }
288
289 gboolean dem_layer_set_param ( VikDEMLayer *vdl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
290 {
291   switch ( id )
292   {
293     case PARAM_COLOR: gdk_gc_set_rgb_fg_color ( vdl->gcs[0], &(data.c) ); break;
294     case PARAM_SOURCE: vdl->source = data.u; break;
295     case PARAM_TYPE: vdl->type = data.u; break;
296     case PARAM_MIN_ELEV:
297       /* Convert to store internally
298          NB file operation always in internal units (metres) */
299       if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
300         vdl->min_elev = VIK_FEET_TO_METERS(data.d);
301       else
302         vdl->min_elev = data.d;
303       break;
304     case PARAM_MAX_ELEV:
305       /* Convert to store internally
306          NB file operation always in internal units (metres) */
307       if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
308         vdl->max_elev = VIK_FEET_TO_METERS(data.d);
309       else
310         vdl->max_elev = data.d;
311       break;
312     case PARAM_FILES: a_dems_load_list ( &(data.sl) ); a_dems_list_free ( vdl->files ); vdl->files = data.sl; break;
313   }
314   return TRUE;
315 }
316
317 static VikLayerParamData dem_layer_get_param ( VikDEMLayer *vdl, guint16 id, gboolean is_file_operation )
318 {
319   VikLayerParamData rv;
320   switch ( id )
321   {
322     case PARAM_FILES: rv.sl = vdl->files; break;
323     case PARAM_SOURCE: rv.u = vdl->source; break;
324     case PARAM_TYPE: rv.u = vdl->type; break;
325     case PARAM_COLOR: vik_gc_get_fg_color ( vdl->gcs[0], &(rv.c) ); break;
326     case PARAM_MIN_ELEV:
327       /* Convert for display in desired units
328          NB file operation always in internal units (metres) */
329       if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
330         rv.d = VIK_METERS_TO_FEET(vdl->min_elev);
331       else
332         rv.d = vdl->min_elev;
333       break;
334     case PARAM_MAX_ELEV:
335       /* Convert for display in desired units
336          NB file operation always in internal units (metres) */
337       if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
338         rv.d = VIK_METERS_TO_FEET(vdl->max_elev);
339       else
340         rv.d = vdl->max_elev;
341       break;
342   }
343   return rv;
344 }
345
346 static void dem_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file )
347 {
348   /* nothing ATM, but keep in case it's needed the future */
349 }
350
351 VikDEMLayer *vik_dem_layer_new ( )
352 {
353   VikDEMLayer *vdl = VIK_DEM_LAYER ( g_object_new ( VIK_DEM_LAYER_TYPE, NULL ) );
354
355   vik_layer_init ( VIK_LAYER(vdl), VIK_LAYER_DEM );
356
357   vdl->files = NULL;
358
359   vdl->gcs = g_malloc(sizeof(GdkGC *)*DEM_N_HEIGHT_COLORS);
360   vdl->gcsgradient = g_malloc(sizeof(GdkGC *)*DEM_N_GRADIENT_COLORS);
361   /* make new gcs only if we need it (copy layer -> use old) */
362
363   vdl->min_elev = 0.0;
364   vdl->max_elev = 1000.0;
365   vdl->source = DEM_SOURCE_SRTM;
366   vdl->type = DEM_TYPE_HEIGHT;
367   return vdl;
368 }
369
370
371 static inline guint16 get_height_difference(gint16 elev, gint16 new_elev)
372 {
373   if(new_elev == VIK_DEM_INVALID_ELEVATION)
374     return 0;
375   else
376     return abs(new_elev - elev);
377 }
378
379
380 static void vik_dem_layer_draw_dem ( VikDEMLayer *vdl, VikViewport *vp, VikDEM *dem )
381 {
382   VikDEMColumn *column, *prevcolumn, *nextcolumn;
383
384   struct LatLon dem_northeast, dem_southwest;
385   gdouble max_lat, max_lon, min_lat, min_lon;
386
387   /**** Check if viewport and DEM data overlap ****/
388
389   /* get min, max lat/lon of viewport */
390   vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
391
392   /* get min, max lat/lon of DEM data */
393   if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
394     dem_northeast.lat = dem->max_north / 3600.0;
395     dem_northeast.lon = dem->max_east / 3600.0;
396     dem_southwest.lat = dem->min_north / 3600.0;
397     dem_southwest.lon = dem->min_east / 3600.0;
398   } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
399     struct UTM dem_northeast_utm, dem_southwest_utm;
400     dem_northeast_utm.northing = dem->max_north;
401     dem_northeast_utm.easting = dem->max_east;
402     dem_southwest_utm.northing = dem->min_north;
403     dem_southwest_utm.easting = dem->min_east;
404     dem_northeast_utm.zone = dem_southwest_utm.zone = dem->utm_zone;
405     dem_northeast_utm.letter = dem_southwest_utm.letter = dem->utm_letter;
406
407     a_coords_utm_to_latlon(&dem_northeast_utm, &dem_northeast);
408     a_coords_utm_to_latlon(&dem_southwest_utm, &dem_southwest);
409   }
410
411   if ( (max_lat > dem_northeast.lat && min_lat > dem_northeast.lat) ||
412        (max_lat < dem_southwest.lat && min_lat < dem_southwest.lat) )
413     return;
414   else if ( (max_lon > dem_northeast.lon && min_lon > dem_northeast.lon) ||
415             (max_lon < dem_southwest.lon && min_lon < dem_southwest.lon) )
416     return;
417   /* else they overlap */
418
419   /**** End Overlap Check ****/
420   /* boxes to show where we have DEM instead of actually drawing the DEM.
421    * useful if we want to see what areas we have coverage for (if we want
422    * to get elevation data for a track) but don't want to cover the map.
423    */
424
425   #if 0
426   /* draw a box if a DEM is loaded. in future I'd like to add an option for this
427    * this is useful if we want to see what areas we have dem for but don't want to
428    * cover the map (or maybe we just need translucent DEM?) */
429   {
430     VikCoord demne, demsw;
431     gint x1, y1, x2, y2;
432     vik_coord_load_from_latlon(&demne, vik_viewport_get_coord_mode(vp), &dem_northeast);
433     vik_coord_load_from_latlon(&demsw, vik_viewport_get_coord_mode(vp), &dem_southwest);
434
435     vik_viewport_coord_to_screen ( vp, &demne, &x1, &y1 );
436     vik_viewport_coord_to_screen ( vp, &demsw, &x2, &y2 );
437
438     if ( x1 > vik_viewport_get_width(vp) ) x1=vik_viewport_get_width(vp);
439     if ( y2 > vik_viewport_get_height(vp) ) y2=vik_viewport_get_height(vp);
440     if ( x2 < 0 ) x2 = 0;
441     if ( y1 < 0 ) y1 = 0;
442     vik_viewport_draw_rectangle ( vp, GTK_WIDGET(vp)->style->black_gc, 
443         FALSE, x2, y1, x1-x2, y2-y1 );
444     return;
445   }
446   #endif
447
448   if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
449     VikCoord tmp; /* TODO: don't use coord_load_from_latlon, especially if in latlon drawing mode */
450
451     gdouble max_lat_as, max_lon_as, min_lat_as, min_lon_as;  
452     gdouble start_lat_as, end_lat_as, start_lon_as, end_lon_as;
453
454     gdouble start_lat, end_lat, start_lon, end_lon;
455
456     struct LatLon counter;
457
458     guint x, y, start_x, start_y;
459
460     gint16 elev;
461
462     guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 80 ); /* todo: smarter calculation. */
463
464     gdouble nscale_deg = dem->north_scale / ((gdouble) 3600);
465     gdouble escale_deg = dem->east_scale / ((gdouble) 3600);
466
467     max_lat_as = max_lat * 3600;
468     min_lat_as = min_lat * 3600;
469     max_lon_as = max_lon * 3600;
470     min_lon_as = min_lon * 3600;
471
472     start_lat_as = MAX(min_lat_as, dem->min_north);
473     end_lat_as   = MIN(max_lat_as, dem->max_north);
474     start_lon_as = MAX(min_lon_as, dem->min_east);
475     end_lon_as   = MIN(max_lon_as, dem->max_east);
476
477     start_lat = floor(start_lat_as / dem->north_scale) * nscale_deg;
478     end_lat   = ceil (end_lat_as / dem->north_scale) * nscale_deg;
479     start_lon = floor(start_lon_as / dem->east_scale) * escale_deg;
480     end_lon   = ceil (end_lon_as / dem->east_scale) * escale_deg;
481
482     vik_dem_east_north_to_xy ( dem, start_lon_as, start_lat_as, &start_x, &start_y );
483     guint gradient_skip_factor = 1;
484     if(vdl->type == DEM_TYPE_GRADIENT)
485             gradient_skip_factor = skip_factor;
486
487     /* verify sane elev interval */
488     if ( vdl->max_elev <= vdl->min_elev )
489       vdl->max_elev = vdl->min_elev + 1;
490
491     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 ) {
492       // NOTE: ( counter.lon <= end_lon + ESCALE_DEG*SKIP_FACTOR ) is neccessary so in high zoom modes,
493       // the leftmost column does also get drawn, if the center point is out of viewport.
494       if ( x >= 0 && x < dem->n_columns ) {
495         column = g_ptr_array_index ( dem->columns, x );
496         // get previous and next column. catch out-of-bound.
497         gint32 new_x = x;
498         new_x -= gradient_skip_factor;
499         if(new_x < 1)
500           prevcolumn = g_ptr_array_index ( dem->columns, x+1);
501         else
502           prevcolumn = g_ptr_array_index ( dem->columns, new_x);
503         new_x = x;
504         new_x += gradient_skip_factor;
505         if(new_x >= dem->n_columns)
506           nextcolumn = g_ptr_array_index ( dem->columns, x-1);
507         else
508           nextcolumn = g_ptr_array_index ( dem->columns, new_x);
509
510         for ( y=start_y, counter.lat = start_lat; counter.lat <= end_lat; counter.lat += nscale_deg * skip_factor, y += skip_factor ) {
511           if ( y > column->n_points )
512             break;
513
514           elev = column->points[y];
515
516           // calculate bounding box for drawing
517           gint box_x, box_y, box_width, box_height;
518           struct LatLon box_c;
519           box_c = counter;
520           box_c.lat += (nscale_deg * skip_factor)/2;
521           box_c.lon -= (escale_deg * skip_factor)/2;
522           vik_coord_load_from_latlon(&tmp, vik_viewport_get_coord_mode(vp), &box_c);
523           vik_viewport_coord_to_screen(vp, &tmp, &box_x, &box_y);
524           // catch box at borders
525           if(box_x < 0)
526                   box_x = 0;
527           if(box_y < 0)
528                   box_y = 0;
529           box_c.lat -= nscale_deg * skip_factor;
530           box_c.lon += escale_deg * skip_factor;
531           vik_coord_load_from_latlon(&tmp, vik_viewport_get_coord_mode(vp), &box_c);
532           vik_viewport_coord_to_screen(vp, &tmp, &box_width, &box_height);
533           box_width -= box_x;
534           box_height -= box_y;
535           // catch box at borders
536           if(box_width < 0 || box_height < 0)
537                   continue; // skip this. this is out of our viewport anyway. FIXME: why?
538
539           gboolean below_minimum = FALSE;
540           if(vdl->type == DEM_TYPE_HEIGHT) {
541             if ( elev != VIK_DEM_INVALID_ELEVATION && elev < vdl->min_elev ) {
542               // Prevent 'elev - vdl->min_elev' from being negative so can safely use as array index
543               elev = ceil ( vdl->min_elev );
544               below_minimum = TRUE;
545             }
546             if ( elev != VIK_DEM_INVALID_ELEVATION && elev > vdl->max_elev )
547               elev = vdl->max_elev;
548           }
549
550           {
551             if(box_width < 0 || box_height < 0) // FIXME: why does this happen?
552               continue;
553
554             if(vdl->type == DEM_TYPE_GRADIENT) {
555               if( elev == VIK_DEM_INVALID_ELEVATION ) {
556                 /* don't draw it */
557               } else {
558                 // calculate and sum gradient in all directions
559                 gint16 change = 0;
560                 gint32 new_y;
561
562                 // calculate gradient from height points all around the current one
563                 new_y = y - gradient_skip_factor;
564                 if(new_y < 0)
565                         new_y = y;
566                 change += get_height_difference(elev, prevcolumn->points[new_y]);
567                 change += get_height_difference(elev, column->points[new_y]);
568                 change += get_height_difference(elev, nextcolumn->points[new_y]);
569
570                 change += get_height_difference(elev, prevcolumn->points[y]);
571                 change += get_height_difference(elev, nextcolumn->points[y]);
572
573                 new_y = y + gradient_skip_factor;
574                 if(new_y >= column->n_points)
575                         new_y = y;
576                 change += get_height_difference(elev, prevcolumn->points[new_y]);
577                 change += get_height_difference(elev, column->points[new_y]);
578                 change += get_height_difference(elev, nextcolumn->points[new_y]);
579
580                 change = change / ((skip_factor > 1) ? log(skip_factor) : 0.55); // FIXME: better calc.
581
582                 if(change < vdl->min_elev)
583                   // Prevent 'change - vdl->min_elev' from being negative so can safely use as array index
584                   change = ceil ( vdl->min_elev );
585
586                 if(change > vdl->max_elev)
587                   change = vdl->max_elev;
588
589                 // void vik_viewport_draw_rectangle ( VikViewport *vvp, GdkGC *gc, gboolean filled, gint x1, gint y1, gint x2, gint y2 );
590                 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);
591               }
592             } else {
593               if(vdl->type == DEM_TYPE_HEIGHT) {
594                 if ( elev == VIK_DEM_INVALID_ELEVATION )
595                   ; /* don't draw it */
596                 else if ( elev <= 0 || below_minimum )
597                   /* If 'sea' colour or below the defined mininum draw in the configurable colour */
598                   vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, box_x, box_y, box_width, box_height);
599                 else
600                   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);
601               }
602             }
603           }
604         } /* for y= */
605       }
606     } /* for x= */
607   } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
608     gdouble max_nor, max_eas, min_nor, min_eas;
609     gdouble start_nor, start_eas, end_nor, end_eas;
610
611     gint16 elev;
612
613     guint x, y, start_x, start_y;
614
615     VikCoord tmp; /* TODO: don't use coord_load_from_latlon, especially if in latlon drawing mode */
616     struct UTM counter;
617
618     guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 10 ); /* todo: smarter calculation. */
619
620     VikCoord tleft, tright, bleft, bright;
621
622     vik_viewport_screen_to_coord ( vp, 0, 0, &tleft );
623     vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), 0, &tright );
624     vik_viewport_screen_to_coord ( vp, 0, vik_viewport_get_height(vp), &bleft );
625     vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), vik_viewport_get_height(vp), &bright );
626
627
628     vik_coord_convert(&tleft, VIK_COORD_UTM);
629     vik_coord_convert(&tright, VIK_COORD_UTM);
630     vik_coord_convert(&bleft, VIK_COORD_UTM);
631     vik_coord_convert(&bright, VIK_COORD_UTM);
632
633     max_nor = MAX(tleft.north_south, tright.north_south);
634     min_nor = MIN(bleft.north_south, bright.north_south);
635     max_eas = MAX(bright.east_west, tright.east_west);
636     min_eas = MIN(bleft.east_west, tleft.east_west);
637
638     start_nor = MAX(min_nor, dem->min_north);
639     end_nor   = MIN(max_nor, dem->max_north);
640     if ( tleft.utm_zone == dem->utm_zone && bleft.utm_zone == dem->utm_zone
641          && (tleft.utm_letter >= 'N') == (dem->utm_letter >= 'N')
642          && (bleft.utm_letter >= 'N') == (dem->utm_letter >= 'N') ) /* if the utm zones/hemispheres are different, min_eas will be bogus */
643       start_eas = MAX(min_eas, dem->min_east);
644     else
645       start_eas = dem->min_east;
646     if ( tright.utm_zone == dem->utm_zone && bright.utm_zone == dem->utm_zone
647          && (tright.utm_letter >= 'N') == (dem->utm_letter >= 'N')
648          && (bright.utm_letter >= 'N') == (dem->utm_letter >= 'N') ) /* if the utm zones/hemispheres are different, min_eas will be bogus */
649       end_eas = MIN(max_eas, dem->max_east);
650     else
651       end_eas = dem->max_east;
652
653     start_nor = floor(start_nor / dem->north_scale) * dem->north_scale;
654     end_nor   = ceil (end_nor / dem->north_scale) * dem->north_scale;
655     start_eas = floor(start_eas / dem->east_scale) * dem->east_scale;
656     end_eas   = ceil (end_eas / dem->east_scale) * dem->east_scale;
657
658     vik_dem_east_north_to_xy ( dem, start_eas, start_nor, &start_x, &start_y );
659
660     /* TODO: why start_x and start_y are -1 -- rounding error from above? */
661
662     counter.zone = dem->utm_zone;
663     counter.letter = dem->utm_letter;
664
665     for ( x=start_x, counter.easting = start_eas; counter.easting <= end_eas; counter.easting += dem->east_scale * skip_factor, x += skip_factor ) {
666       if ( x > 0 && x < dem->n_columns ) {
667         column = g_ptr_array_index ( dem->columns, x );
668         for ( y=start_y, counter.northing = start_nor; counter.northing <= end_nor; counter.northing += dem->north_scale * skip_factor, y += skip_factor ) {
669           if ( y > column->n_points )
670             continue;
671           elev = column->points[y];
672           if ( elev != VIK_DEM_INVALID_ELEVATION && elev < vdl->min_elev )
673             elev=vdl->min_elev;
674           if ( elev != VIK_DEM_INVALID_ELEVATION && elev > vdl->max_elev )
675             elev=vdl->max_elev;
676
677           {
678             gint a, b;
679             vik_coord_load_from_utm(&tmp, vik_viewport_get_coord_mode(vp), &counter);
680                     vik_viewport_coord_to_screen(vp, &tmp, &a, &b);
681             if ( elev == VIK_DEM_INVALID_ELEVATION )
682               ; /* don't draw it */
683             else if ( elev <= 0 )
684               vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, a-1, b-1, 2, 2 );
685             else
686               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 );
687           }
688         } /* for y= */
689       }
690     } /* for x= */
691   }
692 }
693
694 /* return the continent for the specified lat, lon */
695 /* TODO */
696 static const gchar *srtm_continent_dir ( gint lat, gint lon )
697 {
698   extern const char *_srtm_continent_data[];
699   static GHashTable *srtm_continent = NULL;
700   const gchar *continent;
701   gchar name[16];
702
703   if (!srtm_continent) {
704     const gchar **s;
705
706     srtm_continent = g_hash_table_new(g_str_hash, g_str_equal);
707     s = _srtm_continent_data;
708     while (*s != (gchar *)-1) {
709       continent = *s++;
710       while (*s) {
711         g_hash_table_insert(srtm_continent, (gpointer) *s, (gpointer) continent);
712         s++;
713       }
714       s++;
715     }
716   }
717   g_snprintf(name, sizeof(name), "%c%02d%c%03d",
718                   (lat >= 0) ? 'N' : 'S', ABS(lat),
719                   (lon >= 0) ? 'E' : 'W', ABS(lon));
720
721   return(g_hash_table_lookup(srtm_continent, name));
722 }
723
724 void vik_dem_layer_draw ( VikDEMLayer *vdl, gpointer data )
725 {
726   VikViewport *vp = (VikViewport *) data;
727   GList *dems_iter = vdl->files;
728   VikDEM *dem;
729
730
731   /* search for SRTM3 90m */
732
733   if ( vdl->source == DEM_SOURCE_SRTM )
734     srtm_draw_existence ( vp );
735 #ifdef VIK_CONFIG_DEM24K
736   else if ( vdl->source == DEM_SOURCE_DEM24K )
737     dem24k_draw_existence ( vp );
738 #endif
739
740   while ( dems_iter ) {
741     dem = a_dems_get ( (const char *) (dems_iter->data) );
742     if ( dem )
743       vik_dem_layer_draw_dem ( vdl, vp, dem );
744     dems_iter = dems_iter->next;
745   }
746 }
747
748 void vik_dem_layer_free ( VikDEMLayer *vdl )
749 {
750   gint i;
751   if ( vdl->color != NULL )
752     g_object_unref ( vdl->color );
753
754   if ( vdl->gcs )
755     for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ )
756       g_object_unref ( vdl->gcs[i] );
757   g_free ( vdl->gcs );
758
759   if ( vdl->gcsgradient )
760     for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
761       g_object_unref ( vdl->gcsgradient[i] );
762   g_free ( vdl->gcsgradient );
763
764   a_dems_list_free ( vdl->files );
765 }
766
767 VikDEMLayer *vik_dem_layer_create ( VikViewport *vp )
768 {
769   VikDEMLayer *vdl = vik_dem_layer_new ();
770   gint i;
771
772   /* TODO: share GCS between layers */
773   for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ )
774     vdl->gcs[i] = vik_viewport_new_gc ( vp, dem_height_colors[i], UNUSED_LINE_THICKNESS );
775
776   for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
777     vdl->gcsgradient[i] = vik_viewport_new_gc ( vp, dem_gradient_colors[i], UNUSED_LINE_THICKNESS );
778
779   return vdl;
780 }
781 /**************************************************************
782  **** SOURCES & DOWNLOADING
783  **************************************************************/
784 typedef struct {
785   gchar *dest;
786   gdouble lat, lon;
787
788   GMutex *mutex;
789   VikDEMLayer *vdl; /* NULL if not alive */
790
791   guint source;
792 } DEMDownloadParams;
793
794
795 /**************************************************
796  *  SOURCE: SRTM                                  *
797  **************************************************/
798
799 static void srtm_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
800 {
801   gint intlat, intlon;
802   const gchar *continent_dir;
803
804   intlat = (int)floor(p->lat);
805   intlon = (int)floor(p->lon);
806   continent_dir = srtm_continent_dir(intlat, intlon);
807
808   if (!continent_dir) {
809     g_warning(N_("No SRTM data available for %f, %f"), p->lat, p->lon);
810     return;
811   }
812
813   gchar *src_fn = g_strdup_printf("%s%s/%c%02d%c%03d.hgt.zip",
814                 SRTM_HTTP_URI,
815                 continent_dir,
816                 (intlat >= 0) ? 'N' : 'S',
817                 ABS(intlat),
818                 (intlon >= 0) ? 'E' : 'W',
819                 ABS(intlon) );
820
821   static DownloadMapOptions options = { FALSE, FALSE, NULL, 0, a_check_map_file };
822   a_http_download_get_url ( SRTM_HTTP_SITE, src_fn, p->dest, &options, NULL );
823   g_free ( src_fn );
824 }
825
826 static gchar *srtm_lat_lon_to_dest_fn ( gdouble lat, gdouble lon )
827 {
828   gint intlat, intlon;
829   const gchar *continent_dir;
830
831   intlat = (int)floor(lat);
832   intlon = (int)floor(lon);
833   continent_dir = srtm_continent_dir(intlat, intlon);
834
835   if (!continent_dir)
836     continent_dir = "nowhere";
837
838   return g_strdup_printf("srtm3-%s%s%c%02d%c%03d.hgt.zip",
839                 continent_dir,
840                 G_DIR_SEPARATOR_S,
841                 (intlat >= 0) ? 'N' : 'S',
842                 ABS(intlat),
843                 (intlon >= 0) ? 'E' : 'W',
844                 ABS(intlon) );
845
846 }
847
848 /* TODO: generalize */
849 static void srtm_draw_existence ( VikViewport *vp )
850 {
851   gdouble max_lat, max_lon, min_lat, min_lon;  
852   gchar buf[strlen(MAPS_CACHE_DIR)+strlen(SRTM_CACHE_TEMPLATE)+30];
853   gint i, j;
854
855   vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
856
857   for (i = floor(min_lat); i <= floor(max_lat); i++) {
858     for (j = floor(min_lon); j <= floor(max_lon); j++) {
859       const gchar *continent_dir;
860       if ((continent_dir = srtm_continent_dir(i, j)) == NULL)
861         continue;
862       g_snprintf(buf, sizeof(buf), SRTM_CACHE_TEMPLATE,
863                 MAPS_CACHE_DIR,
864                 continent_dir,
865                 G_DIR_SEPARATOR_S,
866                 (i >= 0) ? 'N' : 'S',
867                 ABS(i),
868                 (j >= 0) ? 'E' : 'W',
869                 ABS(j) );
870       if ( g_file_test(buf, G_FILE_TEST_EXISTS ) == TRUE ) {
871         VikCoord ne, sw;
872         gint x1, y1, x2, y2;
873         sw.north_south = i;
874         sw.east_west = j;
875         sw.mode = VIK_COORD_LATLON;
876         ne.north_south = i+1;
877         ne.east_west = j+1;
878         ne.mode = VIK_COORD_LATLON;
879         vik_viewport_coord_to_screen ( vp, &sw, &x1, &y1 );
880         vik_viewport_coord_to_screen ( vp, &ne, &x2, &y2 );
881         if ( x1 < 0 ) x1 = 0;
882         if ( y2 < 0 ) y2 = 0;
883         vik_viewport_draw_rectangle ( vp, GTK_WIDGET(vp)->style->black_gc, 
884                 FALSE, x1, y2, x2-x1, y1-y2 );
885       }
886     }
887   }
888 }
889
890
891 /**************************************************
892  *  SOURCE: USGS 24K                              *
893  **************************************************/
894
895 #ifdef VIK_CONFIG_DEM24K
896
897 static void dem24k_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
898 {
899   /* TODO: dest dir */
900   gchar *cmdline = g_strdup_printf("%s %.03f %.03f",
901         DEM24K_DOWNLOAD_SCRIPT,
902         floor(p->lat*8)/8,
903         ceil(p->lon*8)/8 );
904   /* FIX: don't use system, use execv or something. check for existence */
905   system(cmdline);
906 }
907
908 static gchar *dem24k_lat_lon_to_dest_fn ( gdouble lat, gdouble lon )
909 {
910   return g_strdup_printf("dem24k/%d/%d/%.03f,%.03f.dem",
911         (gint) lat,
912         (gint) lon,
913         floor(lat*8)/8,
914         ceil(lon*8)/8);
915 }
916
917 /* TODO: generalize */
918 static void dem24k_draw_existence ( VikViewport *vp )
919 {
920   gdouble max_lat, max_lon, min_lat, min_lon;  
921   gchar buf[strlen(MAPS_CACHE_DIR)+40];
922   gdouble i, j;
923
924   vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
925
926   for (i = floor(min_lat*8)/8; i <= floor(max_lat*8)/8; i+=0.125) {
927     /* check lat dir first -- faster */
928     g_snprintf(buf, sizeof(buf), "%sdem24k/%d/",
929         MAPS_CACHE_DIR,
930         (gint) i );
931     if ( g_file_test(buf, G_FILE_TEST_EXISTS) == FALSE )
932       continue;
933     for (j = floor(min_lon*8)/8; j <= floor(max_lon*8)/8; j+=0.125) {
934       /* check lon dir first -- faster */
935       g_snprintf(buf, sizeof(buf), "%sdem24k/%d/%d/",
936         MAPS_CACHE_DIR,
937         (gint) i,
938         (gint) j );
939       if ( g_file_test(buf, G_FILE_TEST_EXISTS) == FALSE )
940         continue;
941       g_snprintf(buf, sizeof(buf), "%sdem24k/%d/%d/%.03f,%.03f.dem",
942                 MAPS_CACHE_DIR,
943                 (gint) i,
944                 (gint) j,
945                 floor(i*8)/8,
946                 floor(j*8)/8 );
947       if ( g_file_test(buf, G_FILE_TEST_EXISTS ) == TRUE ) {
948         VikCoord ne, sw;
949         gint x1, y1, x2, y2;
950         sw.north_south = i;
951         sw.east_west = j-0.125;
952         sw.mode = VIK_COORD_LATLON;
953         ne.north_south = i+0.125;
954         ne.east_west = j;
955         ne.mode = VIK_COORD_LATLON;
956         vik_viewport_coord_to_screen ( vp, &sw, &x1, &y1 );
957         vik_viewport_coord_to_screen ( vp, &ne, &x2, &y2 );
958         if ( x1 < 0 ) x1 = 0;
959         if ( y2 < 0 ) y2 = 0;
960         vik_viewport_draw_rectangle ( vp, GTK_WIDGET(vp)->style->black_gc, 
961                 FALSE, x1, y2, x2-x1, y1-y2 );
962       }
963     }
964   }
965 }
966 #endif
967
968 /**************************************************
969  *   SOURCES -- DOWNLOADING & IMPORTING TOOL      *
970  **************************************************
971  */
972
973 static void weak_ref_cb ( gpointer ptr, GObject * dead_vdl )
974 {
975   DEMDownloadParams *p = ptr;
976   g_mutex_lock ( p->mutex );
977   p->vdl = NULL;
978   g_mutex_unlock ( p->mutex );
979 }
980
981 /* Try to add file full_path.
982  * full_path will be copied.
983  * returns FALSE if file does not exists, TRUE otherwise.
984  */
985 static gboolean dem_layer_add_file ( VikDEMLayer *vdl, const gchar *full_path )
986 {
987   if ( g_file_test(full_path, G_FILE_TEST_EXISTS ) == TRUE ) {
988     /* only load if file size is not 0 (not in progress) */
989     struct stat sb;
990     stat (full_path, &sb);
991     if ( sb.st_size ) {
992       gchar *duped_path = g_strdup(full_path);
993       vdl->files = g_list_prepend ( vdl->files, duped_path );
994       a_dems_load ( duped_path );
995       g_debug("%s: %s", __FUNCTION__, duped_path);
996       vik_layer_emit_update ( VIK_LAYER(vdl) );
997     }
998     return TRUE;
999   } else
1000     return FALSE;
1001 }
1002
1003 static void dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
1004 {
1005   if ( p->source == DEM_SOURCE_SRTM )
1006     srtm_dem_download_thread ( p, threaddata );
1007 #ifdef VIK_CONFIG_DEM24K
1008   else if ( p->source == DEM_SOURCE_DEM24K )
1009     dem24k_dem_download_thread ( p, threaddata );
1010 #endif
1011
1012   gdk_threads_enter();
1013   g_mutex_lock ( p->mutex );
1014   if ( p->vdl ) {
1015     g_object_weak_unref ( G_OBJECT(p->vdl), weak_ref_cb, p );
1016
1017     if ( dem_layer_add_file ( p->vdl, p->dest ) )
1018       vik_layer_emit_update ( VIK_LAYER(p->vdl) );
1019   }
1020   g_mutex_unlock ( p->mutex );
1021   gdk_threads_leave();
1022 }
1023
1024
1025 static void free_dem_download_params ( DEMDownloadParams *p )
1026 {
1027   g_mutex_free ( p->mutex );
1028   g_free ( p->dest );
1029   g_free ( p );
1030 }
1031
1032 static gpointer dem_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1033 {
1034   return vvp;
1035 }
1036
1037
1038 static gboolean dem_layer_download_release ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp )
1039 {
1040   VikCoord coord;
1041   struct LatLon ll;
1042
1043   gchar *full_path;
1044   gchar *dem_file = NULL;
1045
1046   if ( vdl->source == DEM_SOURCE_NONE )
1047     a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vdl), _("No download source selected. Edit layer properties.") );
1048
1049   vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1050   vik_coord_to_latlon ( &coord, &ll );
1051
1052   
1053   if ( vdl->source == DEM_SOURCE_SRTM )
1054     dem_file = srtm_lat_lon_to_dest_fn ( ll.lat, ll.lon );
1055 #ifdef VIK_CONFIG_DEM24K
1056   else if ( vdl->source == DEM_SOURCE_DEM24K )
1057     dem_file = dem24k_lat_lon_to_dest_fn ( ll.lat, ll.lon );
1058 #endif
1059
1060   if ( ! dem_file )
1061     return TRUE;
1062
1063   full_path = g_strdup_printf("%s%s", MAPS_CACHE_DIR, dem_file );
1064
1065   g_debug("%s: %s", __FUNCTION__, full_path);
1066
1067   // TODO: check if already in filelist
1068
1069   if ( ! dem_layer_add_file(vdl, full_path) ) {
1070     gchar *tmp = g_strdup_printf ( _("Downloading DEM %s"), dem_file );
1071     DEMDownloadParams *p = g_malloc(sizeof(DEMDownloadParams));
1072     p->dest = g_strdup(full_path);
1073     p->lat = ll.lat;
1074     p->lon = ll.lon;
1075     p->vdl = vdl;
1076     p->mutex = g_mutex_new();
1077     p->source = vdl->source;
1078     g_object_weak_ref(G_OBJECT(p->vdl), weak_ref_cb, p );
1079
1080     a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vdl), tmp,
1081                 (vik_thr_func) dem_download_thread, p,
1082                 (vik_thr_free_func) free_dem_download_params, NULL, 1 );
1083
1084     g_free ( tmp );
1085   }
1086
1087   g_free ( dem_file );
1088   g_free ( full_path );
1089
1090   return TRUE;
1091 }
1092
1093 static gboolean dem_layer_download_click ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp )
1094 {
1095 /* choose & keep track of cache dir
1096  * download in background thread
1097  * download over area */
1098   return TRUE;
1099 }
1100
1101