]> git.street.me.uk Git - andy/viking.git/blob - src/vikdemlayer.c
Allow attempting to open a URL in a waypoint comment or description.
[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 const gchar* dem_layer_tooltip( VikDEMLayer *vdl );
75 static void dem_layer_marshall( VikDEMLayer *vdl, guint8 **data, gint *len );
76 static VikDEMLayer *dem_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
77 static gboolean dem_layer_set_param ( VikDEMLayer *vdl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation );
78 static VikLayerParamData dem_layer_get_param ( VikDEMLayer *vdl, guint16 id, gboolean is_file_operation );
79 static void dem_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file );
80 static void srtm_draw_existence ( VikViewport *vp );
81
82 #ifdef VIK_CONFIG_DEM24K
83 static void dem24k_draw_existence ( VikViewport *vp );
84 #endif
85
86 /* Upped upper limit incase units are feet */
87 static VikLayerParamScale param_scales[] = {
88   { 0, 30000, 10, 1 },
89   { 1, 30000, 10, 1 },
90 };
91
92 static gchar *params_source[] = {
93         "SRTM Global 90m (3 arcsec)",
94 #ifdef VIK_CONFIG_DEM24K
95         "USA 10m (USGS 24k)",
96 #endif
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      };
111
112 enum { DEM_TYPE_HEIGHT = 0,
113        DEM_TYPE_GRADIENT,
114        DEM_TYPE_NONE,
115 };
116
117 static VikLayerParam dem_layer_params[] = {
118   { "files", VIK_LAYER_PARAM_STRING_LIST, VIK_LAYER_GROUP_NONE, N_("DEM Files:"), VIK_LAYER_WIDGET_FILELIST, NULL, NULL, NULL },
119   { "source", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Download Source:"), VIK_LAYER_WIDGET_RADIOGROUP_STATIC, params_source, NULL },
120   { "color", VIK_LAYER_PARAM_COLOR, VIK_LAYER_GROUP_NONE, N_("Min Elev Color:"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL  },
121   { "type", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Type:"), VIK_LAYER_WIDGET_RADIOGROUP_STATIC, params_type, NULL, NULL },
122   { "min_elev", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_GROUP_NONE, N_("Min Elev:"), VIK_LAYER_WIDGET_SPINBUTTON, &param_scales[0], NULL, NULL },
123   { "max_elev", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_GROUP_NONE, N_("Max Elev:"), VIK_LAYER_WIDGET_SPINBUTTON, &param_scales[0], NULL, NULL },
124 };
125
126
127 enum { PARAM_FILES=0, PARAM_SOURCE, PARAM_COLOR, PARAM_TYPE, PARAM_MIN_ELEV, PARAM_MAX_ELEV, NUM_PARAMS };
128
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 );
132
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,
138     FALSE,
139     GDK_CURSOR_IS_PIXMAP, &cursor_demdl_pixbuf },
140 };
141
142
143 /* HEIGHT COLORS
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.
147 */
148 static gchar *dem_height_colors[] = {
149 "#0000FF",
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"
158 };
159
160 static const guint DEM_N_HEIGHT_COLORS = sizeof(dem_height_colors)/sizeof(dem_height_colors[0]);
161
162 /*
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"
166 };
167 */
168
169 static gchar *dem_gradient_colors[] = {
170 "#AAAAAA",
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",
180 "#FFFFFF"
181 };
182
183 static const guint DEM_N_GRADIENT_COLORS = sizeof(dem_gradient_colors)/sizeof(dem_gradient_colors[0]);
184
185
186 VikLayerInterface vik_dem_layer_interface = {
187   "DEM",
188   N_("DEM"),
189   "<control><shift>D",
190   &vikdemlayer_pixbuf,
191
192   dem_tools,
193   sizeof(dem_tools) / sizeof(dem_tools[0]),
194
195   dem_layer_params,
196   NUM_PARAMS,
197   NULL,
198   0,
199
200   VIK_MENU_ITEM_ALL,
201
202   (VikLayerFuncCreate)                  vik_dem_layer_create,
203   (VikLayerFuncRealize)                 NULL,
204   (VikLayerFuncPostRead)                dem_layer_post_read,
205   (VikLayerFuncFree)                    vik_dem_layer_free,
206
207   (VikLayerFuncProperties)              NULL,
208   (VikLayerFuncDraw)                    vik_dem_layer_draw,
209   (VikLayerFuncChangeCoordMode)         NULL,
210
211   (VikLayerFuncSetMenuItemsSelection)   NULL,
212   (VikLayerFuncGetMenuItemsSelection)   NULL,
213
214   (VikLayerFuncAddMenuItems)            NULL,
215   (VikLayerFuncSublayerAddMenuItems)    NULL,
216
217   (VikLayerFuncSublayerRenameRequest)   NULL,
218   (VikLayerFuncSublayerToggleVisible)   NULL,
219   (VikLayerFuncSublayerTooltip)         NULL,
220   (VikLayerFuncLayerTooltip)            dem_layer_tooltip,
221   (VikLayerFuncLayerSelected)           NULL,
222
223   (VikLayerFuncMarshall)                dem_layer_marshall,
224   (VikLayerFuncUnmarshall)              dem_layer_unmarshall,
225
226   (VikLayerFuncSetParam)                dem_layer_set_param,
227   (VikLayerFuncGetParam)                dem_layer_get_param,
228
229   (VikLayerFuncReadFileData)            NULL,
230   (VikLayerFuncWriteFileData)           NULL,
231
232   (VikLayerFuncDeleteItem)              NULL,
233   (VikLayerFuncCutItem)                 NULL,
234   (VikLayerFuncCopyItem)                NULL,
235   (VikLayerFuncPasteItem)               NULL,
236   (VikLayerFuncFreeCopiedItem)          NULL,
237   (VikLayerFuncDragDropRequest)         NULL,
238
239   (VikLayerFuncSelectClick)             NULL,
240   (VikLayerFuncSelectMove)              NULL,
241   (VikLayerFuncSelectRelease)           NULL,
242   (VikLayerFuncSelectedViewportMenu)    NULL,
243 };
244
245 struct _VikDEMLayer {
246   VikLayer vl;
247   GdkGC **gcs;
248   GdkGC **gcsgradient;
249   GList *files;
250   gdouble min_elev;
251   gdouble max_elev;
252   GdkGC *color;
253   guint source;
254   guint type;
255 };
256
257 GType vik_dem_layer_get_type ()
258 {
259   static GType vdl_type = 0;
260
261   if (!vdl_type)
262   {
263     static const GTypeInfo vdl_info =
264     {
265       sizeof (VikDEMLayerClass),
266       NULL, /* base_init */
267       NULL, /* base_finalize */
268       NULL, /* class init */
269       NULL, /* class_finalize */
270       NULL, /* class_data */
271       sizeof (VikDEMLayer),
272       0,
273       NULL /* instance init */
274     };
275     vdl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikDEMLayer", &vdl_info, 0 );
276   }
277
278   return vdl_type;
279 }
280
281 static const gchar* dem_layer_tooltip( VikDEMLayer *vdl )
282 {
283   static gchar tmp_buf[100];
284   g_snprintf (tmp_buf, sizeof(tmp_buf), _("Number of files: %d"), g_list_length (vdl->files));
285   return tmp_buf;
286 }
287
288 static void dem_layer_marshall( VikDEMLayer *vdl, guint8 **data, gint *len )
289 {
290   vik_layer_marshall_params ( VIK_LAYER(vdl), data, len );
291 }
292
293 static VikDEMLayer *dem_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
294 {
295   VikDEMLayer *rv = vik_dem_layer_new ();
296   gint i;
297
298   /* TODO: share GCS between layers */
299   for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ )
300     rv->gcs[i] = vik_viewport_new_gc ( vvp, dem_height_colors[i], UNUSED_LINE_THICKNESS );
301
302   for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
303     rv->gcsgradient[i] = vik_viewport_new_gc ( vvp, dem_gradient_colors[i], UNUSED_LINE_THICKNESS );
304
305   vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
306   return rv;
307 }
308
309 /* Structure for DEM data used in background thread */
310 typedef struct {
311   VikDEMLayer *vdl;
312 } dem_load_thread_data;
313
314 /*
315  * Function for starting the DEM file loading as a background thread
316  */
317 static int dem_layer_load_list_thread ( dem_load_thread_data *dltd, gpointer threaddata )
318 {
319   int result = 0; // Default to good
320   // Actual Load
321   if ( a_dems_load_list ( &(dltd->vdl->files), threaddata ) ) {
322     // Thread cancelled
323     result = -1;
324   }
325
326   // ATM as each file is processed the screen is not updated (no mechanism exposed to a_dems_load_list)
327   // Thus force draw only at the end, as loading is complete/aborted
328   //gdk_threads_enter();
329   // Test is helpful to prevent Gtk-CRITICAL warnings if the program is exitted whilst loading
330   if ( IS_VIK_LAYER(dltd->vdl) )
331     vik_layer_emit_update ( VIK_LAYER(dltd->vdl), TRUE ); // Yes update from background thread
332   //gdk_threads_leave();
333
334   return result;
335 }
336
337 static void dem_layer_thread_data_free ( dem_load_thread_data *data )
338 {
339   // Simple release
340   g_free ( data );
341 }
342
343 static void dem_layer_thread_cancel ( dem_load_thread_data *data )
344 {
345   // Abort loading
346   // Instead of freeing the list, leave it as partially processed
347   // Thus we can see/use what was done
348 }
349
350 gboolean dem_layer_set_param ( VikDEMLayer *vdl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
351 {
352   switch ( id )
353   {
354     case PARAM_COLOR: gdk_gc_set_rgb_fg_color ( vdl->gcs[0], &(data.c) ); break;
355     case PARAM_SOURCE: vdl->source = data.u; break;
356     case PARAM_TYPE: vdl->type = data.u; break;
357     case PARAM_MIN_ELEV:
358       /* Convert to store internally
359          NB file operation always in internal units (metres) */
360       if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
361         vdl->min_elev = VIK_FEET_TO_METERS(data.d);
362       else
363         vdl->min_elev = data.d;
364       break;
365     case PARAM_MAX_ELEV:
366       /* Convert to store internally
367          NB file operation always in internal units (metres) */
368       if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
369         vdl->max_elev = VIK_FEET_TO_METERS(data.d);
370       else
371         vdl->max_elev = data.d;
372       break;
373     case PARAM_FILES:
374     {
375       // Clear out old settings - if any commonalities with new settings they will have to be read again
376       a_dems_list_free ( vdl->files );
377       // Set file list so any other intermediate screen drawing updates will show currently loaded DEMs by the working thread
378       vdl->files = data.sl;
379       // Thread Load
380       dem_load_thread_data *dltd = g_malloc ( sizeof(dem_load_thread_data) );
381       dltd->vdl = vdl;
382       dltd->vdl->files = data.sl;
383
384       a_background_thread ( VIK_GTK_WINDOW_FROM_WIDGET(vp),
385                             _("DEM Loading"),
386                             (vik_thr_func) dem_layer_load_list_thread,
387                             dltd,
388                             (vik_thr_free_func) dem_layer_thread_data_free,
389                             (vik_thr_free_func) dem_layer_thread_cancel,
390                             g_list_length ( data.sl ) ); // Number of DEM files
391       break;
392     }
393   }
394   return TRUE;
395 }
396
397 static VikLayerParamData dem_layer_get_param ( VikDEMLayer *vdl, guint16 id, gboolean is_file_operation )
398 {
399   VikLayerParamData rv;
400   switch ( id )
401   {
402     case PARAM_FILES: rv.sl = vdl->files; break;
403     case PARAM_SOURCE: rv.u = vdl->source; break;
404     case PARAM_TYPE: rv.u = vdl->type; break;
405     case PARAM_COLOR: vik_gc_get_fg_color ( vdl->gcs[0], &(rv.c) ); break;
406     case PARAM_MIN_ELEV:
407       /* Convert for display in desired units
408          NB file operation always in internal units (metres) */
409       if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
410         rv.d = VIK_METERS_TO_FEET(vdl->min_elev);
411       else
412         rv.d = vdl->min_elev;
413       break;
414     case PARAM_MAX_ELEV:
415       /* Convert for display in desired units
416          NB file operation always in internal units (metres) */
417       if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
418         rv.d = VIK_METERS_TO_FEET(vdl->max_elev);
419       else
420         rv.d = vdl->max_elev;
421       break;
422   }
423   return rv;
424 }
425
426 static void dem_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file )
427 {
428   /* nothing ATM, but keep in case it's needed the future */
429 }
430
431 VikDEMLayer *vik_dem_layer_new ( )
432 {
433   VikDEMLayer *vdl = VIK_DEM_LAYER ( g_object_new ( VIK_DEM_LAYER_TYPE, NULL ) );
434
435   vik_layer_set_type ( VIK_LAYER(vdl), VIK_LAYER_DEM );
436
437   vdl->files = NULL;
438
439   vdl->gcs = g_malloc(sizeof(GdkGC *)*DEM_N_HEIGHT_COLORS);
440   vdl->gcsgradient = g_malloc(sizeof(GdkGC *)*DEM_N_GRADIENT_COLORS);
441   /* make new gcs only if we need it (copy layer -> use old) */
442
443   vdl->min_elev = 0.0;
444   vdl->max_elev = 1000.0;
445   vdl->source = DEM_SOURCE_SRTM;
446   vdl->type = DEM_TYPE_HEIGHT;
447   return vdl;
448 }
449
450
451 static inline guint16 get_height_difference(gint16 elev, gint16 new_elev)
452 {
453   if(new_elev == VIK_DEM_INVALID_ELEVATION)
454     return 0;
455   else
456     return abs(new_elev - elev);
457 }
458
459
460 static void vik_dem_layer_draw_dem ( VikDEMLayer *vdl, VikViewport *vp, VikDEM *dem )
461 {
462   VikDEMColumn *column, *prevcolumn, *nextcolumn;
463
464   struct LatLon dem_northeast, dem_southwest;
465   gdouble max_lat, max_lon, min_lat, min_lon;
466
467   /**** Check if viewport and DEM data overlap ****/
468
469   /* get min, max lat/lon of viewport */
470   vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
471
472   /* get min, max lat/lon of DEM data */
473   if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
474     dem_northeast.lat = dem->max_north / 3600.0;
475     dem_northeast.lon = dem->max_east / 3600.0;
476     dem_southwest.lat = dem->min_north / 3600.0;
477     dem_southwest.lon = dem->min_east / 3600.0;
478   } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
479     struct UTM dem_northeast_utm, dem_southwest_utm;
480     dem_northeast_utm.northing = dem->max_north;
481     dem_northeast_utm.easting = dem->max_east;
482     dem_southwest_utm.northing = dem->min_north;
483     dem_southwest_utm.easting = dem->min_east;
484     dem_northeast_utm.zone = dem_southwest_utm.zone = dem->utm_zone;
485     dem_northeast_utm.letter = dem_southwest_utm.letter = dem->utm_letter;
486
487     a_coords_utm_to_latlon(&dem_northeast_utm, &dem_northeast);
488     a_coords_utm_to_latlon(&dem_southwest_utm, &dem_southwest);
489   }
490
491   if ( (max_lat > dem_northeast.lat && min_lat > dem_northeast.lat) ||
492        (max_lat < dem_southwest.lat && min_lat < dem_southwest.lat) )
493     return;
494   else if ( (max_lon > dem_northeast.lon && min_lon > dem_northeast.lon) ||
495             (max_lon < dem_southwest.lon && min_lon < dem_southwest.lon) )
496     return;
497   /* else they overlap */
498
499   /**** End Overlap Check ****/
500   /* boxes to show where we have DEM instead of actually drawing the DEM.
501    * useful if we want to see what areas we have coverage for (if we want
502    * to get elevation data for a track) but don't want to cover the map.
503    */
504
505   #if 0
506   /* draw a box if a DEM is loaded. in future I'd like to add an option for this
507    * this is useful if we want to see what areas we have dem for but don't want to
508    * cover the map (or maybe we just need translucent DEM?) */
509   {
510     VikCoord demne, demsw;
511     gint x1, y1, x2, y2;
512     vik_coord_load_from_latlon(&demne, vik_viewport_get_coord_mode(vp), &dem_northeast);
513     vik_coord_load_from_latlon(&demsw, vik_viewport_get_coord_mode(vp), &dem_southwest);
514
515     vik_viewport_coord_to_screen ( vp, &demne, &x1, &y1 );
516     vik_viewport_coord_to_screen ( vp, &demsw, &x2, &y2 );
517
518     if ( x1 > vik_viewport_get_width(vp) ) x1=vik_viewport_get_width(vp);
519     if ( y2 > vik_viewport_get_height(vp) ) y2=vik_viewport_get_height(vp);
520     if ( x2 < 0 ) x2 = 0;
521     if ( y1 < 0 ) y1 = 0;
522     vik_viewport_draw_rectangle ( vp, GTK_WIDGET(vp)->style->black_gc, 
523         FALSE, x2, y1, x1-x2, y2-y1 );
524     return;
525   }
526   #endif
527
528   if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
529     VikCoord tmp; /* TODO: don't use coord_load_from_latlon, especially if in latlon drawing mode */
530
531     gdouble max_lat_as, max_lon_as, min_lat_as, min_lon_as;  
532     gdouble start_lat_as, end_lat_as, start_lon_as, end_lon_as;
533
534     gdouble start_lat, end_lat, start_lon, end_lon;
535
536     struct LatLon counter;
537
538     guint x, y, start_x, start_y;
539
540     gint16 elev;
541
542     guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 80 ); /* todo: smarter calculation. */
543
544     gdouble nscale_deg = dem->north_scale / ((gdouble) 3600);
545     gdouble escale_deg = dem->east_scale / ((gdouble) 3600);
546
547     max_lat_as = max_lat * 3600;
548     min_lat_as = min_lat * 3600;
549     max_lon_as = max_lon * 3600;
550     min_lon_as = min_lon * 3600;
551
552     start_lat_as = MAX(min_lat_as, dem->min_north);
553     end_lat_as   = MIN(max_lat_as, dem->max_north);
554     start_lon_as = MAX(min_lon_as, dem->min_east);
555     end_lon_as   = MIN(max_lon_as, dem->max_east);
556
557     start_lat = floor(start_lat_as / dem->north_scale) * nscale_deg;
558     end_lat   = ceil (end_lat_as / dem->north_scale) * nscale_deg;
559     start_lon = floor(start_lon_as / dem->east_scale) * escale_deg;
560     end_lon   = ceil (end_lon_as / dem->east_scale) * escale_deg;
561
562     vik_dem_east_north_to_xy ( dem, start_lon_as, start_lat_as, &start_x, &start_y );
563     guint gradient_skip_factor = 1;
564     if(vdl->type == DEM_TYPE_GRADIENT)
565             gradient_skip_factor = skip_factor;
566
567     /* verify sane elev interval */
568     if ( vdl->max_elev <= vdl->min_elev )
569       vdl->max_elev = vdl->min_elev + 1;
570
571     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 ) {
572       // NOTE: ( counter.lon <= end_lon + ESCALE_DEG*SKIP_FACTOR ) is neccessary so in high zoom modes,
573       // the leftmost column does also get drawn, if the center point is out of viewport.
574       if ( x >= 0 && x < dem->n_columns ) {
575         column = g_ptr_array_index ( dem->columns, x );
576         // get previous and next column. catch out-of-bound.
577         gint32 new_x = x;
578         new_x -= gradient_skip_factor;
579         if(new_x < 1)
580           prevcolumn = g_ptr_array_index ( dem->columns, x+1);
581         else
582           prevcolumn = g_ptr_array_index ( dem->columns, new_x);
583         new_x = x;
584         new_x += gradient_skip_factor;
585         if(new_x >= dem->n_columns)
586           nextcolumn = g_ptr_array_index ( dem->columns, x-1);
587         else
588           nextcolumn = g_ptr_array_index ( dem->columns, new_x);
589
590         for ( y=start_y, counter.lat = start_lat; counter.lat <= end_lat; counter.lat += nscale_deg * skip_factor, y += skip_factor ) {
591           if ( y > column->n_points )
592             break;
593
594           elev = column->points[y];
595
596           // calculate bounding box for drawing
597           gint box_x, box_y, box_width, box_height;
598           struct LatLon box_c;
599           box_c = counter;
600           box_c.lat += (nscale_deg * skip_factor)/2;
601           box_c.lon -= (escale_deg * skip_factor)/2;
602           vik_coord_load_from_latlon(&tmp, vik_viewport_get_coord_mode(vp), &box_c);
603           vik_viewport_coord_to_screen(vp, &tmp, &box_x, &box_y);
604           // catch box at borders
605           if(box_x < 0)
606                   box_x = 0;
607           if(box_y < 0)
608                   box_y = 0;
609           box_c.lat -= nscale_deg * skip_factor;
610           box_c.lon += escale_deg * skip_factor;
611           vik_coord_load_from_latlon(&tmp, vik_viewport_get_coord_mode(vp), &box_c);
612           vik_viewport_coord_to_screen(vp, &tmp, &box_width, &box_height);
613           box_width -= box_x;
614           box_height -= box_y;
615           // catch box at borders
616           if(box_width < 0 || box_height < 0)
617                   continue; // skip this. this is out of our viewport anyway. FIXME: why?
618
619           gboolean below_minimum = FALSE;
620           if(vdl->type == DEM_TYPE_HEIGHT) {
621             if ( elev != VIK_DEM_INVALID_ELEVATION && elev < vdl->min_elev ) {
622               // Prevent 'elev - vdl->min_elev' from being negative so can safely use as array index
623               elev = ceil ( vdl->min_elev );
624               below_minimum = TRUE;
625             }
626             if ( elev != VIK_DEM_INVALID_ELEVATION && elev > vdl->max_elev )
627               elev = vdl->max_elev;
628           }
629
630           {
631             if(box_width < 0 || box_height < 0) // FIXME: why does this happen?
632               continue;
633
634             if(vdl->type == DEM_TYPE_GRADIENT) {
635               if( elev == VIK_DEM_INVALID_ELEVATION ) {
636                 /* don't draw it */
637               } else {
638                 // calculate and sum gradient in all directions
639                 gint16 change = 0;
640                 gint32 new_y;
641
642                 // calculate gradient from height points all around the current one
643                 new_y = y - gradient_skip_factor;
644                 if(new_y < 0)
645                         new_y = y;
646                 change += get_height_difference(elev, prevcolumn->points[new_y]);
647                 change += get_height_difference(elev, column->points[new_y]);
648                 change += get_height_difference(elev, nextcolumn->points[new_y]);
649
650                 change += get_height_difference(elev, prevcolumn->points[y]);
651                 change += get_height_difference(elev, nextcolumn->points[y]);
652
653                 new_y = y + gradient_skip_factor;
654                 if(new_y >= column->n_points)
655                         new_y = y;
656                 change += get_height_difference(elev, prevcolumn->points[new_y]);
657                 change += get_height_difference(elev, column->points[new_y]);
658                 change += get_height_difference(elev, nextcolumn->points[new_y]);
659
660                 change = change / ((skip_factor > 1) ? log(skip_factor) : 0.55); // FIXME: better calc.
661
662                 if(change < vdl->min_elev)
663                   // Prevent 'change - vdl->min_elev' from being negative so can safely use as array index
664                   change = ceil ( vdl->min_elev );
665
666                 if(change > vdl->max_elev)
667                   change = vdl->max_elev;
668
669                 // void vik_viewport_draw_rectangle ( VikViewport *vvp, GdkGC *gc, gboolean filled, gint x1, gint y1, gint x2, gint y2 );
670                 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);
671               }
672             } else {
673               if(vdl->type == DEM_TYPE_HEIGHT) {
674                 if ( elev == VIK_DEM_INVALID_ELEVATION )
675                   ; /* don't draw it */
676                 else if ( elev <= 0 || below_minimum )
677                   /* If 'sea' colour or below the defined mininum draw in the configurable colour */
678                   vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, box_x, box_y, box_width, box_height);
679                 else
680                   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);
681               }
682             }
683           }
684         } /* for y= */
685       }
686     } /* for x= */
687   } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
688     gdouble max_nor, max_eas, min_nor, min_eas;
689     gdouble start_nor, start_eas, end_nor, end_eas;
690
691     gint16 elev;
692
693     guint x, y, start_x, start_y;
694
695     VikCoord tmp; /* TODO: don't use coord_load_from_latlon, especially if in latlon drawing mode */
696     struct UTM counter;
697
698     guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 10 ); /* todo: smarter calculation. */
699
700     VikCoord tleft, tright, bleft, bright;
701
702     vik_viewport_screen_to_coord ( vp, 0, 0, &tleft );
703     vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), 0, &tright );
704     vik_viewport_screen_to_coord ( vp, 0, vik_viewport_get_height(vp), &bleft );
705     vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), vik_viewport_get_height(vp), &bright );
706
707
708     vik_coord_convert(&tleft, VIK_COORD_UTM);
709     vik_coord_convert(&tright, VIK_COORD_UTM);
710     vik_coord_convert(&bleft, VIK_COORD_UTM);
711     vik_coord_convert(&bright, VIK_COORD_UTM);
712
713     max_nor = MAX(tleft.north_south, tright.north_south);
714     min_nor = MIN(bleft.north_south, bright.north_south);
715     max_eas = MAX(bright.east_west, tright.east_west);
716     min_eas = MIN(bleft.east_west, tleft.east_west);
717
718     start_nor = MAX(min_nor, dem->min_north);
719     end_nor   = MIN(max_nor, dem->max_north);
720     if ( tleft.utm_zone == dem->utm_zone && bleft.utm_zone == dem->utm_zone
721          && (tleft.utm_letter >= 'N') == (dem->utm_letter >= 'N')
722          && (bleft.utm_letter >= 'N') == (dem->utm_letter >= 'N') ) /* if the utm zones/hemispheres are different, min_eas will be bogus */
723       start_eas = MAX(min_eas, dem->min_east);
724     else
725       start_eas = dem->min_east;
726     if ( tright.utm_zone == dem->utm_zone && bright.utm_zone == dem->utm_zone
727          && (tright.utm_letter >= 'N') == (dem->utm_letter >= 'N')
728          && (bright.utm_letter >= 'N') == (dem->utm_letter >= 'N') ) /* if the utm zones/hemispheres are different, min_eas will be bogus */
729       end_eas = MIN(max_eas, dem->max_east);
730     else
731       end_eas = dem->max_east;
732
733     start_nor = floor(start_nor / dem->north_scale) * dem->north_scale;
734     end_nor   = ceil (end_nor / dem->north_scale) * dem->north_scale;
735     start_eas = floor(start_eas / dem->east_scale) * dem->east_scale;
736     end_eas   = ceil (end_eas / dem->east_scale) * dem->east_scale;
737
738     vik_dem_east_north_to_xy ( dem, start_eas, start_nor, &start_x, &start_y );
739
740     /* TODO: why start_x and start_y are -1 -- rounding error from above? */
741
742     counter.zone = dem->utm_zone;
743     counter.letter = dem->utm_letter;
744
745     for ( x=start_x, counter.easting = start_eas; counter.easting <= end_eas; counter.easting += dem->east_scale * skip_factor, x += skip_factor ) {
746       if ( x > 0 && x < dem->n_columns ) {
747         column = g_ptr_array_index ( dem->columns, x );
748         for ( y=start_y, counter.northing = start_nor; counter.northing <= end_nor; counter.northing += dem->north_scale * skip_factor, y += skip_factor ) {
749           if ( y > column->n_points )
750             continue;
751           elev = column->points[y];
752           if ( elev != VIK_DEM_INVALID_ELEVATION && elev < vdl->min_elev )
753             elev=vdl->min_elev;
754           if ( elev != VIK_DEM_INVALID_ELEVATION && elev > vdl->max_elev )
755             elev=vdl->max_elev;
756
757           {
758             gint a, b;
759             vik_coord_load_from_utm(&tmp, vik_viewport_get_coord_mode(vp), &counter);
760                     vik_viewport_coord_to_screen(vp, &tmp, &a, &b);
761             if ( elev == VIK_DEM_INVALID_ELEVATION )
762               ; /* don't draw it */
763             else if ( elev <= 0 )
764               vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, a-1, b-1, 2, 2 );
765             else
766               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 );
767           }
768         } /* for y= */
769       }
770     } /* for x= */
771   }
772 }
773
774 /* return the continent for the specified lat, lon */
775 /* TODO */
776 static const gchar *srtm_continent_dir ( gint lat, gint lon )
777 {
778   extern const char *_srtm_continent_data[];
779   static GHashTable *srtm_continent = NULL;
780   const gchar *continent;
781   gchar name[16];
782
783   if (!srtm_continent) {
784     const gchar **s;
785
786     srtm_continent = g_hash_table_new(g_str_hash, g_str_equal);
787     s = _srtm_continent_data;
788     while (*s != (gchar *)-1) {
789       continent = *s++;
790       while (*s) {
791         g_hash_table_insert(srtm_continent, (gpointer) *s, (gpointer) continent);
792         s++;
793       }
794       s++;
795     }
796   }
797   g_snprintf(name, sizeof(name), "%c%02d%c%03d",
798                   (lat >= 0) ? 'N' : 'S', ABS(lat),
799                   (lon >= 0) ? 'E' : 'W', ABS(lon));
800
801   return(g_hash_table_lookup(srtm_continent, name));
802 }
803
804 void vik_dem_layer_draw ( VikDEMLayer *vdl, gpointer data )
805 {
806   VikViewport *vp = (VikViewport *) data;
807   GList *dems_iter = vdl->files;
808   VikDEM *dem;
809
810
811   /* search for SRTM3 90m */
812
813   if ( vdl->source == DEM_SOURCE_SRTM )
814     srtm_draw_existence ( vp );
815 #ifdef VIK_CONFIG_DEM24K
816   else if ( vdl->source == DEM_SOURCE_DEM24K )
817     dem24k_draw_existence ( vp );
818 #endif
819
820   while ( dems_iter ) {
821     dem = a_dems_get ( (const char *) (dems_iter->data) );
822     if ( dem )
823       vik_dem_layer_draw_dem ( vdl, vp, dem );
824     dems_iter = dems_iter->next;
825   }
826 }
827
828 void vik_dem_layer_free ( VikDEMLayer *vdl )
829 {
830   gint i;
831   if ( vdl->color != NULL )
832     g_object_unref ( vdl->color );
833
834   if ( vdl->gcs )
835     for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ )
836       g_object_unref ( vdl->gcs[i] );
837   g_free ( vdl->gcs );
838
839   if ( vdl->gcsgradient )
840     for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
841       g_object_unref ( vdl->gcsgradient[i] );
842   g_free ( vdl->gcsgradient );
843
844   a_dems_list_free ( vdl->files );
845 }
846
847 VikDEMLayer *vik_dem_layer_create ( VikViewport *vp )
848 {
849   VikDEMLayer *vdl = vik_dem_layer_new ();
850   gint i;
851
852   /* TODO: share GCS between layers */
853   for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ )
854     vdl->gcs[i] = vik_viewport_new_gc ( vp, dem_height_colors[i], UNUSED_LINE_THICKNESS );
855
856   for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
857     vdl->gcsgradient[i] = vik_viewport_new_gc ( vp, dem_gradient_colors[i], UNUSED_LINE_THICKNESS );
858
859   return vdl;
860 }
861 /**************************************************************
862  **** SOURCES & DOWNLOADING
863  **************************************************************/
864 typedef struct {
865   gchar *dest;
866   gdouble lat, lon;
867
868   GMutex *mutex;
869   VikDEMLayer *vdl; /* NULL if not alive */
870
871   guint source;
872 } DEMDownloadParams;
873
874
875 /**************************************************
876  *  SOURCE: SRTM                                  *
877  **************************************************/
878
879 static void srtm_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
880 {
881   gint intlat, intlon;
882   const gchar *continent_dir;
883
884   intlat = (int)floor(p->lat);
885   intlon = (int)floor(p->lon);
886   continent_dir = srtm_continent_dir(intlat, intlon);
887
888   if (!continent_dir) {
889     g_warning(N_("No SRTM data available for %f, %f"), p->lat, p->lon);
890     return;
891   }
892
893   gchar *src_fn = g_strdup_printf("%s%s/%c%02d%c%03d.hgt.zip",
894                 SRTM_HTTP_URI,
895                 continent_dir,
896                 (intlat >= 0) ? 'N' : 'S',
897                 ABS(intlat),
898                 (intlon >= 0) ? 'E' : 'W',
899                 ABS(intlon) );
900
901   static DownloadMapOptions options = { FALSE, FALSE, NULL, 0, a_check_map_file };
902   a_http_download_get_url ( SRTM_HTTP_SITE, src_fn, p->dest, &options, NULL );
903   g_free ( src_fn );
904 }
905
906 static gchar *srtm_lat_lon_to_dest_fn ( gdouble lat, gdouble lon )
907 {
908   gint intlat, intlon;
909   const gchar *continent_dir;
910
911   intlat = (int)floor(lat);
912   intlon = (int)floor(lon);
913   continent_dir = srtm_continent_dir(intlat, intlon);
914
915   if (!continent_dir)
916     continent_dir = "nowhere";
917
918   return g_strdup_printf("srtm3-%s%s%c%02d%c%03d.hgt.zip",
919                 continent_dir,
920                 G_DIR_SEPARATOR_S,
921                 (intlat >= 0) ? 'N' : 'S',
922                 ABS(intlat),
923                 (intlon >= 0) ? 'E' : 'W',
924                 ABS(intlon) );
925
926 }
927
928 /* TODO: generalize */
929 static void srtm_draw_existence ( VikViewport *vp )
930 {
931   gdouble max_lat, max_lon, min_lat, min_lon;  
932   gchar buf[strlen(MAPS_CACHE_DIR)+strlen(SRTM_CACHE_TEMPLATE)+30];
933   gint i, j;
934
935   vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
936
937   for (i = floor(min_lat); i <= floor(max_lat); i++) {
938     for (j = floor(min_lon); j <= floor(max_lon); j++) {
939       const gchar *continent_dir;
940       if ((continent_dir = srtm_continent_dir(i, j)) == NULL)
941         continue;
942       g_snprintf(buf, sizeof(buf), SRTM_CACHE_TEMPLATE,
943                 MAPS_CACHE_DIR,
944                 continent_dir,
945                 G_DIR_SEPARATOR_S,
946                 (i >= 0) ? 'N' : 'S',
947                 ABS(i),
948                 (j >= 0) ? 'E' : 'W',
949                 ABS(j) );
950       if ( g_file_test(buf, G_FILE_TEST_EXISTS ) == TRUE ) {
951         VikCoord ne, sw;
952         gint x1, y1, x2, y2;
953         sw.north_south = i;
954         sw.east_west = j;
955         sw.mode = VIK_COORD_LATLON;
956         ne.north_south = i+1;
957         ne.east_west = j+1;
958         ne.mode = VIK_COORD_LATLON;
959         vik_viewport_coord_to_screen ( vp, &sw, &x1, &y1 );
960         vik_viewport_coord_to_screen ( vp, &ne, &x2, &y2 );
961         if ( x1 < 0 ) x1 = 0;
962         if ( y2 < 0 ) y2 = 0;
963         vik_viewport_draw_rectangle ( vp, GTK_WIDGET(vp)->style->black_gc, 
964                 FALSE, x1, y2, x2-x1, y1-y2 );
965       }
966     }
967   }
968 }
969
970
971 /**************************************************
972  *  SOURCE: USGS 24K                              *
973  **************************************************/
974
975 #ifdef VIK_CONFIG_DEM24K
976
977 static void dem24k_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
978 {
979   /* TODO: dest dir */
980   gchar *cmdline = g_strdup_printf("%s %.03f %.03f",
981         DEM24K_DOWNLOAD_SCRIPT,
982         floor(p->lat*8)/8,
983         ceil(p->lon*8)/8 );
984   /* FIX: don't use system, use execv or something. check for existence */
985   system(cmdline);
986   g_free ( cmdline );
987 }
988
989 static gchar *dem24k_lat_lon_to_dest_fn ( gdouble lat, gdouble lon )
990 {
991   return g_strdup_printf("dem24k/%d/%d/%.03f,%.03f.dem",
992         (gint) lat,
993         (gint) lon,
994         floor(lat*8)/8,
995         ceil(lon*8)/8);
996 }
997
998 /* TODO: generalize */
999 static void dem24k_draw_existence ( VikViewport *vp )
1000 {
1001   gdouble max_lat, max_lon, min_lat, min_lon;  
1002   gchar buf[strlen(MAPS_CACHE_DIR)+40];
1003   gdouble i, j;
1004
1005   vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
1006
1007   for (i = floor(min_lat*8)/8; i <= floor(max_lat*8)/8; i+=0.125) {
1008     /* check lat dir first -- faster */
1009     g_snprintf(buf, sizeof(buf), "%sdem24k/%d/",
1010         MAPS_CACHE_DIR,
1011         (gint) i );
1012     if ( g_file_test(buf, G_FILE_TEST_EXISTS) == FALSE )
1013       continue;
1014     for (j = floor(min_lon*8)/8; j <= floor(max_lon*8)/8; j+=0.125) {
1015       /* check lon dir first -- faster */
1016       g_snprintf(buf, sizeof(buf), "%sdem24k/%d/%d/",
1017         MAPS_CACHE_DIR,
1018         (gint) i,
1019         (gint) j );
1020       if ( g_file_test(buf, G_FILE_TEST_EXISTS) == FALSE )
1021         continue;
1022       g_snprintf(buf, sizeof(buf), "%sdem24k/%d/%d/%.03f,%.03f.dem",
1023                 MAPS_CACHE_DIR,
1024                 (gint) i,
1025                 (gint) j,
1026                 floor(i*8)/8,
1027                 floor(j*8)/8 );
1028       if ( g_file_test(buf, G_FILE_TEST_EXISTS ) == TRUE ) {
1029         VikCoord ne, sw;
1030         gint x1, y1, x2, y2;
1031         sw.north_south = i;
1032         sw.east_west = j-0.125;
1033         sw.mode = VIK_COORD_LATLON;
1034         ne.north_south = i+0.125;
1035         ne.east_west = j;
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(vp)->style->black_gc, 
1042                 FALSE, x1, y2, x2-x1, y1-y2 );
1043       }
1044     }
1045   }
1046 }
1047 #endif
1048
1049 /**************************************************
1050  *   SOURCES -- DOWNLOADING & IMPORTING TOOL      *
1051  **************************************************
1052  */
1053
1054 static void weak_ref_cb ( gpointer ptr, GObject * dead_vdl )
1055 {
1056   DEMDownloadParams *p = ptr;
1057   g_mutex_lock ( p->mutex );
1058   p->vdl = NULL;
1059   g_mutex_unlock ( p->mutex );
1060 }
1061
1062 /* Try to add file full_path.
1063  * full_path will be copied.
1064  * returns FALSE if file does not exists, TRUE otherwise.
1065  */
1066 static gboolean dem_layer_add_file ( VikDEMLayer *vdl, const gchar *full_path )
1067 {
1068   if ( g_file_test(full_path, G_FILE_TEST_EXISTS ) == TRUE ) {
1069     /* only load if file size is not 0 (not in progress) */
1070     struct stat sb;
1071     stat (full_path, &sb);
1072     if ( sb.st_size ) {
1073       gchar *duped_path = g_strdup(full_path);
1074       vdl->files = g_list_prepend ( vdl->files, duped_path );
1075       a_dems_load ( duped_path );
1076       g_debug("%s: %s", __FUNCTION__, duped_path);
1077     }
1078     return TRUE;
1079   } else
1080     return FALSE;
1081 }
1082
1083 static void dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
1084 {
1085   if ( p->source == DEM_SOURCE_SRTM )
1086     srtm_dem_download_thread ( p, threaddata );
1087 #ifdef VIK_CONFIG_DEM24K
1088   else if ( p->source == DEM_SOURCE_DEM24K )
1089     dem24k_dem_download_thread ( p, threaddata );
1090 #endif
1091   else
1092     return;
1093
1094   //gdk_threads_enter();
1095   g_mutex_lock ( p->mutex );
1096   if ( p->vdl ) {
1097     g_object_weak_unref ( G_OBJECT(p->vdl), weak_ref_cb, p );
1098
1099     if ( dem_layer_add_file ( p->vdl, p->dest ) )
1100       vik_layer_emit_update ( VIK_LAYER(p->vdl), TRUE ); // Yes update from background thread
1101   }
1102   g_mutex_unlock ( p->mutex );
1103   //gdk_threads_leave();
1104 }
1105
1106
1107 static void free_dem_download_params ( DEMDownloadParams *p )
1108 {
1109   g_mutex_free ( p->mutex );
1110   g_free ( p->dest );
1111   g_free ( p );
1112 }
1113
1114 static gpointer dem_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1115 {
1116   return vvp;
1117 }
1118
1119
1120 static gboolean dem_layer_download_release ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp )
1121 {
1122   VikCoord coord;
1123   struct LatLon ll;
1124
1125   gchar *full_path;
1126   gchar *dem_file = NULL;
1127
1128   vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1129   vik_coord_to_latlon ( &coord, &ll );
1130
1131   
1132   if ( vdl->source == DEM_SOURCE_SRTM )
1133     dem_file = srtm_lat_lon_to_dest_fn ( ll.lat, ll.lon );
1134 #ifdef VIK_CONFIG_DEM24K
1135   else if ( vdl->source == DEM_SOURCE_DEM24K )
1136     dem_file = dem24k_lat_lon_to_dest_fn ( ll.lat, ll.lon );
1137 #endif
1138
1139   if ( ! dem_file )
1140     return TRUE;
1141
1142   full_path = g_strdup_printf("%s%s", MAPS_CACHE_DIR, dem_file );
1143
1144   g_debug("%s: %s", __FUNCTION__, full_path);
1145
1146   // TODO: check if already in filelist
1147
1148   if ( ! dem_layer_add_file(vdl, full_path) ) {
1149     gchar *tmp = g_strdup_printf ( _("Downloading DEM %s"), dem_file );
1150     DEMDownloadParams *p = g_malloc(sizeof(DEMDownloadParams));
1151     p->dest = g_strdup(full_path);
1152     p->lat = ll.lat;
1153     p->lon = ll.lon;
1154     p->vdl = vdl;
1155     p->mutex = g_mutex_new();
1156     p->source = vdl->source;
1157     g_object_weak_ref(G_OBJECT(p->vdl), weak_ref_cb, p );
1158
1159     a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vdl), tmp,
1160                 (vik_thr_func) dem_download_thread, p,
1161                 (vik_thr_free_func) free_dem_download_params, NULL, 1 );
1162
1163     g_free ( tmp );
1164   }
1165   else
1166     vik_layer_emit_update ( VIK_LAYER(vdl), FALSE );
1167
1168   g_free ( dem_file );
1169   g_free ( full_path );
1170
1171   return TRUE;
1172 }
1173
1174 static gboolean dem_layer_download_click ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp )
1175 {
1176 /* choose & keep track of cache dir
1177  * download in background thread
1178  * download over area */
1179   return TRUE;
1180 }
1181
1182