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