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