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