]> git.street.me.uk Git - andy/viking.git/blame - src/vikdemlayer.c
Add a preference to control the number of recent files made available.
[andy/viking.git] / src / vikdemlayer.c
CommitLineData
ad0a8c2d
EB
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 */
4c77d5e0
GB
21#ifdef HAVE_CONFIG_H
22#include "config.h"
23#endif
8c00358d
GB
24
25#ifdef HAVE_MATH_H
ad0a8c2d 26#include <math.h>
8c00358d
GB
27#endif
28#ifdef HAVE_SYS_TYPES_H
0c1044e9 29#include <sys/types.h>
8c00358d
GB
30#endif
31#ifdef HAVE_SYS_STAT_H
0c1044e9 32#include <sys/stat.h>
8c00358d
GB
33#endif
34#ifdef HAVE_STRING_H
0c1044e9 35#include <string.h>
8c00358d 36#endif
8c721f83 37#include <stdlib.h>
13d3fc89 38#include <glib/gstdio.h>
4c77d5e0 39#include <glib/gi18n.h>
ad0a8c2d 40
0c1044e9 41#include "background.h"
a7023a1b 42#include "viking.h"
c96fce26 43#include "vikmapslayer.h"
ad0a8c2d 44#include "vikdemlayer.h"
ad0a8c2d
EB
45#include "dem.h"
46#include "dems.h"
bce3a7b0
EB
47#include "icons/icons.h"
48
8c721f83 49#define MAPS_CACHE_DIR maps_layer_default_dir()
0c1044e9 50
0e25c0d0 51#define SRTM_CACHE_TEMPLATE "%ssrtm3-%s%s%c%02d%c%03d.hgt.zip"
e6c50657 52#define SRTM_HTTP_SITE "dds.cr.usgs.gov"
f9518bc9 53#define SRTM_HTTP_URI "/srtm/version2_1/SRTM3/"
8c721f83
EB
54
55#ifdef VIK_CONFIG_DEM24K
56#define DEM24K_DOWNLOAD_SCRIPT "dem24k.pl"
57#endif
58
7e74e26b 59#define UNUSED_LINE_THICKNESS 3
0c1044e9 60
0c025cfa
RN
61static VikDEMLayer *dem_layer_new ( VikViewport *vvp );
62static void dem_layer_draw ( VikDEMLayer *vdl, VikViewport *vp );
63static void dem_layer_free ( VikDEMLayer *vdl );
64static VikDEMLayer *dem_layer_create ( VikViewport *vp );
e6c9ae37 65static const gchar* dem_layer_tooltip( VikDEMLayer *vdl );
ad0a8c2d
EB
66static void dem_layer_marshall( VikDEMLayer *vdl, guint8 **data, gint *len );
67static VikDEMLayer *dem_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
158b3642
RN
68static gboolean dem_layer_set_param ( VikDEMLayer *vdl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation );
69static VikLayerParamData dem_layer_get_param ( VikDEMLayer *vdl, guint16 id, gboolean is_file_operation );
07059501 70static void dem_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file );
8c721f83
EB
71static void srtm_draw_existence ( VikViewport *vp );
72
73#ifdef VIK_CONFIG_DEM24K
74static void dem24k_draw_existence ( VikViewport *vp );
75#endif
ad0a8c2d 76
0cabb401 77/* Upped upper limit incase units are feet */
ad0a8c2d 78static VikLayerParamScale param_scales[] = {
0cabb401
RN
79 { 0, 30000, 10, 1 },
80 { 1, 30000, 10, 1 },
ad0a8c2d
EB
81};
82
8c721f83
EB
83static gchar *params_source[] = {
84 "SRTM Global 90m (3 arcsec)",
85#ifdef VIK_CONFIG_DEM24K
86 "USA 10m (USGS 24k)",
87#endif
4235f369 88 NULL
8c721f83
EB
89 };
90
c07088dd 91static gchar *params_type[] = {
c3c75563
GB
92 N_("Absolute height"),
93 N_("Height gradient"),
c07088dd
DRP
94 NULL
95};
96
8c721f83
EB
97enum { DEM_SOURCE_SRTM,
98#ifdef VIK_CONFIG_DEM24K
99 DEM_SOURCE_DEM24K,
100#endif
8c721f83
EB
101 };
102
c07088dd
DRP
103enum { DEM_TYPE_HEIGHT = 0,
104 DEM_TYPE_GRADIENT,
105 DEM_TYPE_NONE,
106};
107
a7023a1b
RN
108static VikLayerParamData color_default ( void ) {
109 VikLayerParamData data; gdk_color_parse ( "blue", &data.c ); return data;
110}
111
112static VikLayerParamData source_default ( void ) { return VIK_LPD_UINT ( DEM_SOURCE_SRTM ); }
113static VikLayerParamData type_default ( void ) { return VIK_LPD_UINT ( DEM_TYPE_HEIGHT ); }
114static VikLayerParamData min_elev_default ( void ) { return VIK_LPD_DOUBLE ( 0.0 ); }
115static VikLayerParamData max_elev_default ( void ) { return VIK_LPD_DOUBLE ( 1000.0 ); }
116
ad0a8c2d 117static VikLayerParam dem_layer_params[] = {
a87f8fa1
RN
118 { VIK_LAYER_DEM, "files", VIK_LAYER_PARAM_STRING_LIST, VIK_LAYER_GROUP_NONE, N_("DEM Files:"), VIK_LAYER_WIDGET_FILELIST, NULL, NULL, NULL, NULL, NULL, NULL },
119 { VIK_LAYER_DEM, "source", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Download Source:"), VIK_LAYER_WIDGET_RADIOGROUP_STATIC, params_source, NULL, NULL, source_default, NULL, NULL },
120 { VIK_LAYER_DEM, "color", VIK_LAYER_PARAM_COLOR, VIK_LAYER_GROUP_NONE, N_("Min Elev Color:"), VIK_LAYER_WIDGET_COLOR, NULL, NULL, NULL, color_default, NULL, NULL },
121 { VIK_LAYER_DEM, "type", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Type:"), VIK_LAYER_WIDGET_RADIOGROUP_STATIC, params_type, NULL, NULL, type_default, NULL, NULL },
122 { VIK_LAYER_DEM, "min_elev", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_GROUP_NONE, N_("Min Elev:"), VIK_LAYER_WIDGET_SPINBUTTON, param_scales + 0, NULL, NULL, min_elev_default, NULL, NULL },
123 { VIK_LAYER_DEM, "max_elev", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_GROUP_NONE, N_("Max Elev:"), VIK_LAYER_WIDGET_SPINBUTTON, param_scales + 0, NULL, NULL, max_elev_default, NULL, NULL },
ad0a8c2d
EB
124};
125
8c721f83 126
7e74e26b 127enum { PARAM_FILES=0, PARAM_SOURCE, PARAM_COLOR, PARAM_TYPE, PARAM_MIN_ELEV, PARAM_MAX_ELEV, NUM_PARAMS };
8c721f83 128
0c1044e9
EB
129static gpointer dem_layer_download_create ( VikWindow *vw, VikViewport *vvp);
130static gboolean dem_layer_download_release ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp );
131static gboolean dem_layer_download_click ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp );
132
133static VikToolInterface dem_tools[] = {
79dce0cb
RN
134 { { "DEMDownload", "vik-icon-DEM Download", N_("_DEM Download"), NULL, N_("DEM Download"), 0 },
135 (VikToolConstructorFunc) dem_layer_download_create, NULL, NULL, NULL,
bce3a7b0 136 (VikToolMouseFunc) dem_layer_download_click, NULL, (VikToolMouseFunc) dem_layer_download_release,
ef5e8132
RN
137 (VikToolKeyFunc) NULL,
138 FALSE,
139 GDK_CURSOR_IS_PIXMAP, &cursor_demdl_pixbuf },
0c1044e9
EB
140};
141
142
7e74e26b
RN
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.
ad0a8c2d 147*/
c07088dd 148static gchar *dem_height_colors[] = {
ad0a8c2d 149"#0000FF",
c07088dd
DRP
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"
ad0a8c2d
EB
158};
159
c07088dd
DRP
160static const guint DEM_N_HEIGHT_COLORS = sizeof(dem_height_colors)/sizeof(dem_height_colors[0]);
161
ad0a8c2d 162/*
c07088dd
DRP
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"
ad0a8c2d
EB
166};
167*/
168
c07088dd 169static gchar *dem_gradient_colors[] = {
0251a183 170"#AAAAAA",
c07088dd
DRP
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
183static const guint DEM_N_GRADIENT_COLORS = sizeof(dem_gradient_colors)/sizeof(dem_gradient_colors[0]);
ad0a8c2d 184
ad0a8c2d
EB
185
186VikLayerInterface vik_dem_layer_interface = {
db386630 187 "DEM",
affcc0f2 188 N_("DEM"),
75078768 189 "<control><shift>D",
5bfafde9 190 &vikdemlayer_pixbuf,
ad0a8c2d 191
0c1044e9
EB
192 dem_tools,
193 sizeof(dem_tools) / sizeof(dem_tools[0]),
ad0a8c2d
EB
194
195 dem_layer_params,
196 NUM_PARAMS,
197 NULL,
198 0,
199
200 VIK_MENU_ITEM_ALL,
201
0c025cfa 202 (VikLayerFuncCreate) dem_layer_create,
ad0a8c2d 203 (VikLayerFuncRealize) NULL,
b112cbf5 204 (VikLayerFuncPostRead) dem_layer_post_read,
0c025cfa 205 (VikLayerFuncFree) dem_layer_free,
ad0a8c2d
EB
206
207 (VikLayerFuncProperties) NULL,
0c025cfa 208 (VikLayerFuncDraw) dem_layer_draw,
ad0a8c2d
EB
209 (VikLayerFuncChangeCoordMode) NULL,
210
211 (VikLayerFuncSetMenuItemsSelection) NULL,
212 (VikLayerFuncGetMenuItemsSelection) NULL,
213
214 (VikLayerFuncAddMenuItems) NULL,
215 (VikLayerFuncSublayerAddMenuItems) NULL,
216
217 (VikLayerFuncSublayerRenameRequest) NULL,
218 (VikLayerFuncSublayerToggleVisible) NULL,
9da7faf2 219 (VikLayerFuncSublayerTooltip) NULL,
e6c9ae37 220 (VikLayerFuncLayerTooltip) dem_layer_tooltip,
a5dcfdb7 221 (VikLayerFuncLayerSelected) NULL,
ad0a8c2d 222
ad0a8c2d
EB
223 (VikLayerFuncMarshall) dem_layer_marshall,
224 (VikLayerFuncUnmarshall) dem_layer_unmarshall,
225
226 (VikLayerFuncSetParam) dem_layer_set_param,
227 (VikLayerFuncGetParam) dem_layer_get_param,
db43cfa4 228 (VikLayerFuncChangeParam) NULL,
ad0a8c2d
EB
229
230 (VikLayerFuncReadFileData) NULL,
231 (VikLayerFuncWriteFileData) NULL,
232
233 (VikLayerFuncDeleteItem) NULL,
d5874ef9 234 (VikLayerFuncCutItem) NULL,
ad0a8c2d
EB
235 (VikLayerFuncCopyItem) NULL,
236 (VikLayerFuncPasteItem) NULL,
237 (VikLayerFuncFreeCopiedItem) NULL,
238 (VikLayerFuncDragDropRequest) NULL,
77ad64fa
RN
239
240 (VikLayerFuncSelectClick) NULL,
08f14055
RN
241 (VikLayerFuncSelectMove) NULL,
242 (VikLayerFuncSelectRelease) NULL,
e46f259a 243 (VikLayerFuncSelectedViewportMenu) NULL,
ad0a8c2d
EB
244};
245
246struct _VikDEMLayer {
247 VikLayer vl;
ad0a8c2d 248 GdkGC **gcs;
c07088dd 249 GdkGC **gcsgradient;
ad0a8c2d 250 GList *files;
415302f4 251 gdouble min_elev;
ad0a8c2d 252 gdouble max_elev;
a7023a1b 253 GdkColor color;
8c721f83 254 guint source;
c07088dd 255 guint type;
13d3fc89
RN
256
257 // right click menu only stuff - similar to mapslayer
258 GtkMenu *right_click_menu;
ad0a8c2d
EB
259};
260
261GType vik_dem_layer_get_type ()
262{
263 static GType vdl_type = 0;
264
265 if (!vdl_type)
266 {
267 static const GTypeInfo vdl_info =
268 {
269 sizeof (VikDEMLayerClass),
270 NULL, /* base_init */
271 NULL, /* base_finalize */
272 NULL, /* class init */
273 NULL, /* class_finalize */
274 NULL, /* class_data */
275 sizeof (VikDEMLayer),
276 0,
277 NULL /* instance init */
278 };
279 vdl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikDEMLayer", &vdl_info, 0 );
280 }
281
282 return vdl_type;
283}
284
e6c9ae37
RN
285static const gchar* dem_layer_tooltip( VikDEMLayer *vdl )
286{
287 static gchar tmp_buf[100];
288 g_snprintf (tmp_buf, sizeof(tmp_buf), _("Number of files: %d"), g_list_length (vdl->files));
289 return tmp_buf;
290}
291
ad0a8c2d
EB
292static void dem_layer_marshall( VikDEMLayer *vdl, guint8 **data, gint *len )
293{
294 vik_layer_marshall_params ( VIK_LAYER(vdl), data, len );
295}
296
297static VikDEMLayer *dem_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
298{
0c025cfa 299 VikDEMLayer *rv = dem_layer_new ( vvp );
fa86f1c0
EB
300 gint i;
301
302 /* TODO: share GCS between layers */
a7023a1b
RN
303 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ ) {
304 if ( i == 0 )
305 rv->gcs[i] = vik_viewport_new_gc_from_color ( vvp, &(rv->color), UNUSED_LINE_THICKNESS );
306 else
307 rv->gcs[i] = vik_viewport_new_gc ( vvp, dem_height_colors[i], UNUSED_LINE_THICKNESS );
308 }
c07088dd 309 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
7e74e26b 310 rv->gcsgradient[i] = vik_viewport_new_gc ( vvp, dem_gradient_colors[i], UNUSED_LINE_THICKNESS );
fa86f1c0 311
ad0a8c2d
EB
312 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
313 return rv;
314}
315
29392f59
RN
316/* Structure for DEM data used in background thread */
317typedef struct {
318 VikDEMLayer *vdl;
319} dem_load_thread_data;
320
321/*
322 * Function for starting the DEM file loading as a background thread
323 */
324static int dem_layer_load_list_thread ( dem_load_thread_data *dltd, gpointer threaddata )
325{
326 int result = 0; // Default to good
327 // Actual Load
328 if ( a_dems_load_list ( &(dltd->vdl->files), threaddata ) ) {
329 // Thread cancelled
330 result = -1;
331 }
332
333 // ATM as each file is processed the screen is not updated (no mechanism exposed to a_dems_load_list)
334 // Thus force draw only at the end, as loading is complete/aborted
f01eebd4 335 //gdk_threads_enter();
94595b61
RN
336 // Test is helpful to prevent Gtk-CRITICAL warnings if the program is exitted whilst loading
337 if ( IS_VIK_LAYER(dltd->vdl) )
da121f9b 338 vik_layer_emit_update ( VIK_LAYER(dltd->vdl) ); // NB update from background thread
f01eebd4 339 //gdk_threads_leave();
29392f59
RN
340
341 return result;
342}
343
344static void dem_layer_thread_data_free ( dem_load_thread_data *data )
345{
346 // Simple release
347 g_free ( data );
348}
349
350static void dem_layer_thread_cancel ( dem_load_thread_data *data )
351{
352 // Abort loading
353 // Instead of freeing the list, leave it as partially processed
354 // Thus we can see/use what was done
355}
356
88542aa9
RN
357/**
358 * Process the list of DEM files and convert each one to a relative path
359 */
360static GList *dem_layer_convert_to_relative_filenaming ( GList *files )
361{
362 gchar *cwd = g_get_current_dir();
363 if ( !cwd )
364 return files;
365
366 GList *relfiles = NULL;
367
368 while ( files ) {
369 gchar *file = g_strdup ( file_GetRelativeFilename ( cwd, files->data ) );
370 relfiles = g_list_prepend ( relfiles, file );
371 files = files->next;
372 }
373
374 g_free ( cwd );
375
376 if ( relfiles ) {
377 // Replacing current list, so delete old values first.
378 GList *iter = files;
379 while ( iter ) {
380 g_free ( iter->data );
381 iter = iter->next;
382 }
383 g_list_free ( files );
384
385 return relfiles;
386 }
387
388 return files;
389}
390
158b3642 391gboolean dem_layer_set_param ( VikDEMLayer *vdl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
ad0a8c2d
EB
392{
393 switch ( id )
394 {
a7023a1b 395 case PARAM_COLOR: vdl->color = data.c; gdk_gc_set_rgb_fg_color ( vdl->gcs[0], &(vdl->color) ); break;
8c721f83 396 case PARAM_SOURCE: vdl->source = data.u; break;
c07088dd 397 case PARAM_TYPE: vdl->type = data.u; break;
0cabb401
RN
398 case PARAM_MIN_ELEV:
399 /* Convert to store internally
400 NB file operation always in internal units (metres) */
401 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
ab1e0693 402 vdl->min_elev = VIK_FEET_TO_METERS(data.d);
0cabb401
RN
403 else
404 vdl->min_elev = data.d;
405 break;
406 case PARAM_MAX_ELEV:
407 /* Convert to store internally
408 NB file operation always in internal units (metres) */
409 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
ab1e0693 410 vdl->max_elev = VIK_FEET_TO_METERS(data.d);
0cabb401
RN
411 else
412 vdl->max_elev = data.d;
413 break;
29392f59
RN
414 case PARAM_FILES:
415 {
416 // Clear out old settings - if any commonalities with new settings they will have to be read again
417 a_dems_list_free ( vdl->files );
418 // Set file list so any other intermediate screen drawing updates will show currently loaded DEMs by the working thread
419 vdl->files = data.sl;
09c91d84
RN
420 // No need for thread if no files
421 if ( vdl->files ) {
422 // Thread Load
423 dem_load_thread_data *dltd = g_malloc ( sizeof(dem_load_thread_data) );
424 dltd->vdl = vdl;
425 dltd->vdl->files = data.sl;
426
427 a_background_thread ( VIK_GTK_WINDOW_FROM_WIDGET(vp),
428 _("DEM Loading"),
429 (vik_thr_func) dem_layer_load_list_thread,
430 dltd,
431 (vik_thr_free_func) dem_layer_thread_data_free,
432 (vik_thr_free_func) dem_layer_thread_cancel,
433 g_list_length ( data.sl ) ); // Number of DEM files
434 }
29392f59
RN
435 break;
436 }
ad0a8c2d
EB
437 }
438 return TRUE;
439}
440
158b3642 441static VikLayerParamData dem_layer_get_param ( VikDEMLayer *vdl, guint16 id, gboolean is_file_operation )
ad0a8c2d
EB
442{
443 VikLayerParamData rv;
444 switch ( id )
445 {
88542aa9
RN
446 case PARAM_FILES:
447 rv.sl = vdl->files;
448 if ( is_file_operation )
449 // Save in relative format if necessary
450 if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE )
451 rv.sl = dem_layer_convert_to_relative_filenaming ( rv.sl );
452 break;
8c721f83 453 case PARAM_SOURCE: rv.u = vdl->source; break;
c07088dd 454 case PARAM_TYPE: rv.u = vdl->type; break;
a7023a1b 455 case PARAM_COLOR: rv.c = vdl->color; break;
0cabb401
RN
456 case PARAM_MIN_ELEV:
457 /* Convert for display in desired units
458 NB file operation always in internal units (metres) */
459 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
6c20e59a 460 rv.d = VIK_METERS_TO_FEET(vdl->min_elev);
0cabb401
RN
461 else
462 rv.d = vdl->min_elev;
463 break;
464 case PARAM_MAX_ELEV:
465 /* Convert for display in desired units
466 NB file operation always in internal units (metres) */
467 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
6c20e59a 468 rv.d = VIK_METERS_TO_FEET(vdl->max_elev);
0cabb401
RN
469 else
470 rv.d = vdl->max_elev;
471 break;
ad0a8c2d
EB
472 }
473 return rv;
474}
475
07059501 476static void dem_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file )
ad0a8c2d 477{
7e74e26b 478 /* nothing ATM, but keep in case it's needed the future */
ad0a8c2d
EB
479}
480
0c025cfa 481static VikDEMLayer *dem_layer_new ( VikViewport *vvp )
ad0a8c2d
EB
482{
483 VikDEMLayer *vdl = VIK_DEM_LAYER ( g_object_new ( VIK_DEM_LAYER_TYPE, NULL ) );
fa86f1c0 484
a0c65899 485 vik_layer_set_type ( VIK_LAYER(vdl), VIK_LAYER_DEM );
ad0a8c2d
EB
486
487 vdl->files = NULL;
488
c07088dd
DRP
489 vdl->gcs = g_malloc(sizeof(GdkGC *)*DEM_N_HEIGHT_COLORS);
490 vdl->gcsgradient = g_malloc(sizeof(GdkGC *)*DEM_N_GRADIENT_COLORS);
fa86f1c0 491 /* make new gcs only if we need it (copy layer -> use old) */
ad0a8c2d 492
a7023a1b
RN
493 // Ensure the base GC is available so the default colour can be applied
494 if ( vvp ) vdl->gcs[0] = vik_viewport_new_gc ( vvp, "#0000FF", 1 );
495
496 vik_layer_set_defaults ( VIK_LAYER(vdl), vvp );
497
ad0a8c2d
EB
498 return vdl;
499}
500
501
f9518bc9
DRP
502static inline guint16 get_height_difference(gint16 elev, gint16 new_elev)
503{
504 if(new_elev == VIK_DEM_INVALID_ELEVATION)
505 return 0;
506 else
507 return abs(new_elev - elev);
508}
509
0c1044e9 510
ad0a8c2d
EB
511static void vik_dem_layer_draw_dem ( VikDEMLayer *vdl, VikViewport *vp, VikDEM *dem )
512{
f9518bc9 513 VikDEMColumn *column, *prevcolumn, *nextcolumn;
ad0a8c2d
EB
514
515 struct LatLon dem_northeast, dem_southwest;
f9518bc9 516 gdouble max_lat, max_lon, min_lat, min_lon;
ad0a8c2d 517
ad0a8c2d
EB
518 /**** Check if viewport and DEM data overlap ****/
519
520 /* get min, max lat/lon of viewport */
0c1044e9 521 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
ad0a8c2d
EB
522
523 /* get min, max lat/lon of DEM data */
524 if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
525 dem_northeast.lat = dem->max_north / 3600.0;
526 dem_northeast.lon = dem->max_east / 3600.0;
527 dem_southwest.lat = dem->min_north / 3600.0;
528 dem_southwest.lon = dem->min_east / 3600.0;
529 } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
530 struct UTM dem_northeast_utm, dem_southwest_utm;
531 dem_northeast_utm.northing = dem->max_north;
532 dem_northeast_utm.easting = dem->max_east;
533 dem_southwest_utm.northing = dem->min_north;
534 dem_southwest_utm.easting = dem->min_east;
535 dem_northeast_utm.zone = dem_southwest_utm.zone = dem->utm_zone;
536 dem_northeast_utm.letter = dem_southwest_utm.letter = dem->utm_letter;
537
538 a_coords_utm_to_latlon(&dem_northeast_utm, &dem_northeast);
539 a_coords_utm_to_latlon(&dem_southwest_utm, &dem_southwest);
540 }
541
542 if ( (max_lat > dem_northeast.lat && min_lat > dem_northeast.lat) ||
543 (max_lat < dem_southwest.lat && min_lat < dem_southwest.lat) )
544 return;
545 else if ( (max_lon > dem_northeast.lon && min_lon > dem_northeast.lon) ||
546 (max_lon < dem_southwest.lon && min_lon < dem_southwest.lon) )
547 return;
548 /* else they overlap */
549
550 /**** End Overlap Check ****/
0c1044e9
EB
551 /* boxes to show where we have DEM instead of actually drawing the DEM.
552 * useful if we want to see what areas we have coverage for (if we want
553 * to get elevation data for a track) but don't want to cover the map.
554 */
555
556 #if 0
557 /* draw a box if a DEM is loaded. in future I'd like to add an option for this
558 * this is useful if we want to see what areas we have dem for but don't want to
559 * cover the map (or maybe we just need translucent DEM?) */
560 {
561 VikCoord demne, demsw;
562 gint x1, y1, x2, y2;
563 vik_coord_load_from_latlon(&demne, vik_viewport_get_coord_mode(vp), &dem_northeast);
564 vik_coord_load_from_latlon(&demsw, vik_viewport_get_coord_mode(vp), &dem_southwest);
565
566 vik_viewport_coord_to_screen ( vp, &demne, &x1, &y1 );
567 vik_viewport_coord_to_screen ( vp, &demsw, &x2, &y2 );
568
569 if ( x1 > vik_viewport_get_width(vp) ) x1=vik_viewport_get_width(vp);
570 if ( y2 > vik_viewport_get_height(vp) ) y2=vik_viewport_get_height(vp);
571 if ( x2 < 0 ) x2 = 0;
572 if ( y1 < 0 ) y1 = 0;
ff37db21 573 vik_viewport_draw_rectangle ( vp, gtk_widget_get_style(GTK_WIDGET(vp))->black_gc,
0c1044e9 574 FALSE, x2, y1, x1-x2, y2-y1 );
0c1044e9
EB
575 return;
576 }
577 #endif
ad0a8c2d
EB
578
579 if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
580 VikCoord tmp; /* TODO: don't use coord_load_from_latlon, especially if in latlon drawing mode */
581
582 gdouble max_lat_as, max_lon_as, min_lat_as, min_lon_as;
583 gdouble start_lat_as, end_lat_as, start_lon_as, end_lon_as;
584
585 gdouble start_lat, end_lat, start_lon, end_lon;
586
587 struct LatLon counter;
588
589 guint x, y, start_x, start_y;
590
591 gint16 elev;
592
f9518bc9 593 guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 80 ); /* todo: smarter calculation. */
ad0a8c2d
EB
594
595 gdouble nscale_deg = dem->north_scale / ((gdouble) 3600);
596 gdouble escale_deg = dem->east_scale / ((gdouble) 3600);
597
598 max_lat_as = max_lat * 3600;
599 min_lat_as = min_lat * 3600;
600 max_lon_as = max_lon * 3600;
601 min_lon_as = min_lon * 3600;
602
603 start_lat_as = MAX(min_lat_as, dem->min_north);
604 end_lat_as = MIN(max_lat_as, dem->max_north);
605 start_lon_as = MAX(min_lon_as, dem->min_east);
606 end_lon_as = MIN(max_lon_as, dem->max_east);
607
608 start_lat = floor(start_lat_as / dem->north_scale) * nscale_deg;
609 end_lat = ceil (end_lat_as / dem->north_scale) * nscale_deg;
610 start_lon = floor(start_lon_as / dem->east_scale) * escale_deg;
611 end_lon = ceil (end_lon_as / dem->east_scale) * escale_deg;
612
613 vik_dem_east_north_to_xy ( dem, start_lon_as, start_lat_as, &start_x, &start_y );
f9518bc9
DRP
614 guint gradient_skip_factor = 1;
615 if(vdl->type == DEM_TYPE_GRADIENT)
616 gradient_skip_factor = skip_factor;
ad0a8c2d 617
415302f4
EB
618 /* verify sane elev interval */
619 if ( vdl->max_elev <= vdl->min_elev )
620 vdl->max_elev = vdl->min_elev + 1;
621
f9518bc9
DRP
622 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 ) {
623 // NOTE: ( counter.lon <= end_lon + ESCALE_DEG*SKIP_FACTOR ) is neccessary so in high zoom modes,
624 // the leftmost column does also get drawn, if the center point is out of viewport.
5e610fc3 625 if ( x < dem->n_columns ) {
ad0a8c2d 626 column = g_ptr_array_index ( dem->columns, x );
f9518bc9
DRP
627 // get previous and next column. catch out-of-bound.
628 gint32 new_x = x;
629 new_x -= gradient_skip_factor;
630 if(new_x < 1)
631 prevcolumn = g_ptr_array_index ( dem->columns, x+1);
632 else
633 prevcolumn = g_ptr_array_index ( dem->columns, new_x);
634 new_x = x;
635 new_x += gradient_skip_factor;
636 if(new_x >= dem->n_columns)
637 nextcolumn = g_ptr_array_index ( dem->columns, x-1);
638 else
639 nextcolumn = g_ptr_array_index ( dem->columns, new_x);
c07088dd 640
ad0a8c2d
EB
641 for ( y=start_y, counter.lat = start_lat; counter.lat <= end_lat; counter.lat += nscale_deg * skip_factor, y += skip_factor ) {
642 if ( y > column->n_points )
643 break;
f9518bc9 644
ad0a8c2d 645 elev = column->points[y];
415302f4 646
f9518bc9
DRP
647 // calculate bounding box for drawing
648 gint box_x, box_y, box_width, box_height;
649 struct LatLon box_c;
650 box_c = counter;
651 box_c.lat += (nscale_deg * skip_factor)/2;
652 box_c.lon -= (escale_deg * skip_factor)/2;
653 vik_coord_load_from_latlon(&tmp, vik_viewport_get_coord_mode(vp), &box_c);
654 vik_viewport_coord_to_screen(vp, &tmp, &box_x, &box_y);
655 // catch box at borders
656 if(box_x < 0)
657 box_x = 0;
658 if(box_y < 0)
659 box_y = 0;
660 box_c.lat -= nscale_deg * skip_factor;
661 box_c.lon += escale_deg * skip_factor;
662 vik_coord_load_from_latlon(&tmp, vik_viewport_get_coord_mode(vp), &box_c);
663 vik_viewport_coord_to_screen(vp, &tmp, &box_width, &box_height);
664 box_width -= box_x;
665 box_height -= box_y;
666 // catch box at borders
667 if(box_width < 0 || box_height < 0)
668 continue; // skip this. this is out of our viewport anyway. FIXME: why?
669
7e74e26b 670 gboolean below_minimum = FALSE;
f9518bc9 671 if(vdl->type == DEM_TYPE_HEIGHT) {
7e74e26b 672 if ( elev != VIK_DEM_INVALID_ELEVATION && elev < vdl->min_elev ) {
104f8c15
RN
673 // Prevent 'elev - vdl->min_elev' from being negative so can safely use as array index
674 elev = ceil ( vdl->min_elev );
7e74e26b
RN
675 below_minimum = TRUE;
676 }
f9518bc9 677 if ( elev != VIK_DEM_INVALID_ELEVATION && elev > vdl->max_elev )
104f8c15 678 elev = vdl->max_elev;
f9518bc9 679 }
415302f4 680
ad0a8c2d 681 {
f9518bc9
DRP
682 if(box_width < 0 || box_height < 0) // FIXME: why does this happen?
683 continue;
684
685 if(vdl->type == DEM_TYPE_GRADIENT) {
686 if( elev == VIK_DEM_INVALID_ELEVATION ) {
687 /* don't draw it */
688 } else {
689 // calculate and sum gradient in all directions
690 gint16 change = 0;
691 gint32 new_y;
692
693 // calculate gradient from height points all around the current one
694 new_y = y - gradient_skip_factor;
695 if(new_y < 0)
696 new_y = y;
697 change += get_height_difference(elev, prevcolumn->points[new_y]);
698 change += get_height_difference(elev, column->points[new_y]);
699 change += get_height_difference(elev, nextcolumn->points[new_y]);
700
701 change += get_height_difference(elev, prevcolumn->points[y]);
702 change += get_height_difference(elev, nextcolumn->points[y]);
703
704 new_y = y + gradient_skip_factor;
705 if(new_y >= column->n_points)
706 new_y = y;
707 change += get_height_difference(elev, prevcolumn->points[new_y]);
708 change += get_height_difference(elev, column->points[new_y]);
709 change += get_height_difference(elev, nextcolumn->points[new_y]);
710
711 change = change / ((skip_factor > 1) ? log(skip_factor) : 0.55); // FIXME: better calc.
712
713 if(change < vdl->min_elev)
104f8c15
RN
714 // Prevent 'change - vdl->min_elev' from being negative so can safely use as array index
715 change = ceil ( vdl->min_elev );
f9518bc9
DRP
716
717 if(change > vdl->max_elev)
718 change = vdl->max_elev;
719
720 // void vik_viewport_draw_rectangle ( VikViewport *vvp, GdkGC *gc, gboolean filled, gint x1, gint y1, gint x2, gint y2 );
104f8c15 721 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);
f9518bc9 722 }
c07088dd 723 } else {
f9518bc9
DRP
724 if(vdl->type == DEM_TYPE_HEIGHT) {
725 if ( elev == VIK_DEM_INVALID_ELEVATION )
726 ; /* don't draw it */
7e74e26b
RN
727 else if ( elev <= 0 || below_minimum )
728 /* If 'sea' colour or below the defined mininum draw in the configurable colour */
f9518bc9
DRP
729 vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, box_x, box_y, box_width, box_height);
730 else
104f8c15 731 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);
f9518bc9
DRP
732 }
733 }
ad0a8c2d
EB
734 }
735 } /* for y= */
736 }
737 } /* for x= */
738 } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
739 gdouble max_nor, max_eas, min_nor, min_eas;
740 gdouble start_nor, start_eas, end_nor, end_eas;
741
742 gint16 elev;
743
744 guint x, y, start_x, start_y;
745
746 VikCoord tmp; /* TODO: don't use coord_load_from_latlon, especially if in latlon drawing mode */
747 struct UTM counter;
748
749 guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 10 ); /* todo: smarter calculation. */
750
0c1044e9
EB
751 VikCoord tleft, tright, bleft, bright;
752
753 vik_viewport_screen_to_coord ( vp, 0, 0, &tleft );
754 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), 0, &tright );
755 vik_viewport_screen_to_coord ( vp, 0, vik_viewport_get_height(vp), &bleft );
756 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), vik_viewport_get_height(vp), &bright );
757
758
ad0a8c2d
EB
759 vik_coord_convert(&tleft, VIK_COORD_UTM);
760 vik_coord_convert(&tright, VIK_COORD_UTM);
761 vik_coord_convert(&bleft, VIK_COORD_UTM);
762 vik_coord_convert(&bright, VIK_COORD_UTM);
763
764 max_nor = MAX(tleft.north_south, tright.north_south);
765 min_nor = MIN(bleft.north_south, bright.north_south);
766 max_eas = MAX(bright.east_west, tright.east_west);
767 min_eas = MIN(bleft.east_west, tleft.east_west);
768
769 start_nor = MAX(min_nor, dem->min_north);
770 end_nor = MIN(max_nor, dem->max_north);
771 if ( tleft.utm_zone == dem->utm_zone && bleft.utm_zone == dem->utm_zone
772 && (tleft.utm_letter >= 'N') == (dem->utm_letter >= 'N')
773 && (bleft.utm_letter >= 'N') == (dem->utm_letter >= 'N') ) /* if the utm zones/hemispheres are different, min_eas will be bogus */
774 start_eas = MAX(min_eas, dem->min_east);
775 else
776 start_eas = dem->min_east;
777 if ( tright.utm_zone == dem->utm_zone && bright.utm_zone == dem->utm_zone
778 && (tright.utm_letter >= 'N') == (dem->utm_letter >= 'N')
779 && (bright.utm_letter >= 'N') == (dem->utm_letter >= 'N') ) /* if the utm zones/hemispheres are different, min_eas will be bogus */
780 end_eas = MIN(max_eas, dem->max_east);
781 else
782 end_eas = dem->max_east;
783
784 start_nor = floor(start_nor / dem->north_scale) * dem->north_scale;
785 end_nor = ceil (end_nor / dem->north_scale) * dem->north_scale;
786 start_eas = floor(start_eas / dem->east_scale) * dem->east_scale;
787 end_eas = ceil (end_eas / dem->east_scale) * dem->east_scale;
788
789 vik_dem_east_north_to_xy ( dem, start_eas, start_nor, &start_x, &start_y );
790
791 /* TODO: why start_x and start_y are -1 -- rounding error from above? */
792
793 counter.zone = dem->utm_zone;
794 counter.letter = dem->utm_letter;
795
796 for ( x=start_x, counter.easting = start_eas; counter.easting <= end_eas; counter.easting += dem->east_scale * skip_factor, x += skip_factor ) {
797 if ( x > 0 && x < dem->n_columns ) {
798 column = g_ptr_array_index ( dem->columns, x );
799 for ( y=start_y, counter.northing = start_nor; counter.northing <= end_nor; counter.northing += dem->north_scale * skip_factor, y += skip_factor ) {
800 if ( y > column->n_points )
801 continue;
802 elev = column->points[y];
415302f4
EB
803 if ( elev != VIK_DEM_INVALID_ELEVATION && elev < vdl->min_elev )
804 elev=vdl->min_elev;
805 if ( elev != VIK_DEM_INVALID_ELEVATION && elev > vdl->max_elev )
806 elev=vdl->max_elev;
807
ad0a8c2d
EB
808 {
809 gint a, b;
810 vik_coord_load_from_utm(&tmp, vik_viewport_get_coord_mode(vp), &counter);
811 vik_viewport_coord_to_screen(vp, &tmp, &a, &b);
812 if ( elev == VIK_DEM_INVALID_ELEVATION )
813 ; /* don't draw it */
814 else if ( elev <= 0 )
f9518bc9 815 vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, a-1, b-1, 2, 2 );
ad0a8c2d 816 else
f9518bc9 817 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 );
ad0a8c2d
EB
818 }
819 } /* for y= */
820 }
821 } /* for x= */
822 }
823}
824
0c1044e9
EB
825/* return the continent for the specified lat, lon */
826/* TODO */
0e25c0d0 827static const gchar *srtm_continent_dir ( gint lat, gint lon )
0c1044e9 828{
0e25c0d0
QT
829 extern const char *_srtm_continent_data[];
830 static GHashTable *srtm_continent = NULL;
831 const gchar *continent;
832 gchar name[16];
833
834 if (!srtm_continent) {
835 const gchar **s;
836
837 srtm_continent = g_hash_table_new(g_str_hash, g_str_equal);
838 s = _srtm_continent_data;
839 while (*s != (gchar *)-1) {
840 continent = *s++;
841 while (*s) {
0654760a 842 g_hash_table_insert(srtm_continent, (gpointer) *s, (gpointer) continent);
0e25c0d0
QT
843 s++;
844 }
845 s++;
846 }
847 }
848 g_snprintf(name, sizeof(name), "%c%02d%c%03d",
849 (lat >= 0) ? 'N' : 'S', ABS(lat),
850 (lon >= 0) ? 'E' : 'W', ABS(lon));
851
852 return(g_hash_table_lookup(srtm_continent, name));
0c1044e9
EB
853}
854
0c025cfa 855static void dem_layer_draw ( VikDEMLayer *vdl, VikViewport *vp )
ad0a8c2d 856{
ad0a8c2d
EB
857 GList *dems_iter = vdl->files;
858 VikDEM *dem;
0c1044e9 859
0c1044e9
EB
860
861 /* search for SRTM3 90m */
8c721f83
EB
862
863 if ( vdl->source == DEM_SOURCE_SRTM )
864 srtm_draw_existence ( vp );
865#ifdef VIK_CONFIG_DEM24K
866 else if ( vdl->source == DEM_SOURCE_DEM24K )
867 dem24k_draw_existence ( vp );
868#endif
0c1044e9 869
ad0a8c2d
EB
870 while ( dems_iter ) {
871 dem = a_dems_get ( (const char *) (dems_iter->data) );
872 if ( dem )
873 vik_dem_layer_draw_dem ( vdl, vp, dem );
874 dems_iter = dems_iter->next;
875 }
876}
877
0c025cfa 878static void dem_layer_free ( VikDEMLayer *vdl )
ad0a8c2d 879{
fa86f1c0 880 gint i;
fa86f1c0 881 if ( vdl->gcs )
c07088dd 882 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ )
fa86f1c0
EB
883 g_object_unref ( vdl->gcs[i] );
884 g_free ( vdl->gcs );
885
c07088dd
DRP
886 if ( vdl->gcsgradient )
887 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
888 g_object_unref ( vdl->gcsgradient[i] );
889 g_free ( vdl->gcsgradient );
890
ad0a8c2d
EB
891 a_dems_list_free ( vdl->files );
892}
893
0c025cfa 894VikDEMLayer *dem_layer_create ( VikViewport *vp )
ad0a8c2d 895{
0c025cfa 896 VikDEMLayer *vdl = dem_layer_new ( vp );
fa86f1c0 897 gint i;
8aff54f2
RN
898 if ( vp ) {
899 /* TODO: share GCS between layers */
a7023a1b
RN
900 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ ) {
901 if ( i > 0 )
902 vdl->gcs[i] = vik_viewport_new_gc ( vp, dem_height_colors[i], UNUSED_LINE_THICKNESS );
903 }
8aff54f2
RN
904 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
905 vdl->gcsgradient[i] = vik_viewport_new_gc ( vp, dem_gradient_colors[i], UNUSED_LINE_THICKNESS );
906 }
ad0a8c2d
EB
907 return vdl;
908}
8c721f83
EB
909/**************************************************************
910 **** SOURCES & DOWNLOADING
911 **************************************************************/
912typedef struct {
913 gchar *dest;
914 gdouble lat, lon;
915
916 GMutex *mutex;
917 VikDEMLayer *vdl; /* NULL if not alive */
918
919 guint source;
920} DEMDownloadParams;
921
ad0a8c2d 922
0c1044e9 923/**************************************************
8c721f83
EB
924 * SOURCE: SRTM *
925 **************************************************/
926
927static void srtm_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
0c1044e9 928{
8c721f83 929 gint intlat, intlon;
0e25c0d0 930 const gchar *continent_dir;
8c721f83
EB
931
932 intlat = (int)floor(p->lat);
933 intlon = (int)floor(p->lon);
0e25c0d0
QT
934 continent_dir = srtm_continent_dir(intlat, intlon);
935
936 if (!continent_dir) {
1a272ee7
RN
937 if ( p->vdl ) {
938 gchar *msg = g_strdup_printf ( _("No SRTM data available for %f, %f"), p->lat, p->lon );
939 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(p->vdl), msg, VIK_STATUSBAR_INFO );
940 g_free ( msg );
941 }
0e25c0d0
QT
942 return;
943 }
944
65a64219 945 gchar *src_fn = g_strdup_printf("%s%s/%c%02d%c%03d.hgt.zip",
e6c50657 946 SRTM_HTTP_URI,
0e25c0d0 947 continent_dir,
8c721f83
EB
948 (intlat >= 0) ? 'N' : 'S',
949 ABS(intlat),
950 (intlon >= 0) ? 'E' : 'W',
951 ABS(intlon) );
952
a3697549 953 static DownloadMapOptions options = { FALSE, FALSE, NULL, 0, a_check_map_file, NULL };
825413ba 954 a_http_download_get_url ( SRTM_HTTP_SITE, src_fn, p->dest, &options, NULL );
8c721f83 955 g_free ( src_fn );
0c1044e9
EB
956}
957
8c721f83 958static gchar *srtm_lat_lon_to_dest_fn ( gdouble lat, gdouble lon )
0c1044e9 959{
8c721f83 960 gint intlat, intlon;
0e25c0d0
QT
961 const gchar *continent_dir;
962
8c721f83
EB
963 intlat = (int)floor(lat);
964 intlon = (int)floor(lon);
0e25c0d0
QT
965 continent_dir = srtm_continent_dir(intlat, intlon);
966
967 if (!continent_dir)
968 continent_dir = "nowhere";
969
970 return g_strdup_printf("srtm3-%s%s%c%02d%c%03d.hgt.zip",
971 continent_dir,
972 G_DIR_SEPARATOR_S,
8c721f83
EB
973 (intlat >= 0) ? 'N' : 'S',
974 ABS(intlat),
975 (intlon >= 0) ? 'E' : 'W',
976 ABS(intlon) );
0c1044e9 977
0c1044e9
EB
978}
979
8c721f83
EB
980/* TODO: generalize */
981static void srtm_draw_existence ( VikViewport *vp )
0c1044e9 982{
8c721f83
EB
983 gdouble max_lat, max_lon, min_lat, min_lon;
984 gchar buf[strlen(MAPS_CACHE_DIR)+strlen(SRTM_CACHE_TEMPLATE)+30];
985 gint i, j;
986
987 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
988
989 for (i = floor(min_lat); i <= floor(max_lat); i++) {
990 for (j = floor(min_lon); j <= floor(max_lon); j++) {
0e25c0d0
QT
991 const gchar *continent_dir;
992 if ((continent_dir = srtm_continent_dir(i, j)) == NULL)
993 continue;
8c721f83
EB
994 g_snprintf(buf, sizeof(buf), SRTM_CACHE_TEMPLATE,
995 MAPS_CACHE_DIR,
0e25c0d0
QT
996 continent_dir,
997 G_DIR_SEPARATOR_S,
8c721f83
EB
998 (i >= 0) ? 'N' : 'S',
999 ABS(i),
1000 (j >= 0) ? 'E' : 'W',
1001 ABS(j) );
45acf79e 1002 if ( g_file_test(buf, G_FILE_TEST_EXISTS ) == TRUE ) {
8c721f83
EB
1003 VikCoord ne, sw;
1004 gint x1, y1, x2, y2;
1005 sw.north_south = i;
1006 sw.east_west = j;
1007 sw.mode = VIK_COORD_LATLON;
1008 ne.north_south = i+1;
1009 ne.east_west = j+1;
1010 ne.mode = VIK_COORD_LATLON;
1011 vik_viewport_coord_to_screen ( vp, &sw, &x1, &y1 );
1012 vik_viewport_coord_to_screen ( vp, &ne, &x2, &y2 );
1013 if ( x1 < 0 ) x1 = 0;
1014 if ( y2 < 0 ) y2 = 0;
ff37db21 1015 vik_viewport_draw_rectangle ( vp, gtk_widget_get_style(GTK_WIDGET(vp))->black_gc,
8c721f83
EB
1016 FALSE, x1, y2, x2-x1, y1-y2 );
1017 }
1018 }
1019 }
0c1044e9
EB
1020}
1021
8c721f83
EB
1022
1023/**************************************************
1024 * SOURCE: USGS 24K *
1025 **************************************************/
1026
1027#ifdef VIK_CONFIG_DEM24K
1028
1029static void dem24k_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
0c1044e9 1030{
8c721f83
EB
1031 /* TODO: dest dir */
1032 gchar *cmdline = g_strdup_printf("%s %.03f %.03f",
1033 DEM24K_DOWNLOAD_SCRIPT,
1034 floor(p->lat*8)/8,
1035 ceil(p->lon*8)/8 );
1036 /* FIX: don't use system, use execv or something. check for existence */
1037 system(cmdline);
d94f70cc 1038 g_free ( cmdline );
8c721f83 1039}
0c1044e9 1040
8c721f83
EB
1041static gchar *dem24k_lat_lon_to_dest_fn ( gdouble lat, gdouble lon )
1042{
1043 return g_strdup_printf("dem24k/%d/%d/%.03f,%.03f.dem",
1044 (gint) lat,
1045 (gint) lon,
1046 floor(lat*8)/8,
1047 ceil(lon*8)/8);
1048}
0c1044e9 1049
8c721f83
EB
1050/* TODO: generalize */
1051static void dem24k_draw_existence ( VikViewport *vp )
1052{
1053 gdouble max_lat, max_lon, min_lat, min_lon;
1054 gchar buf[strlen(MAPS_CACHE_DIR)+40];
1055 gdouble i, j;
0c1044e9 1056
8c721f83 1057 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
0c1044e9 1058
8c721f83
EB
1059 for (i = floor(min_lat*8)/8; i <= floor(max_lat*8)/8; i+=0.125) {
1060 /* check lat dir first -- faster */
1061 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/",
1062 MAPS_CACHE_DIR,
1063 (gint) i );
6b1a58ec 1064 if ( g_file_test(buf, G_FILE_TEST_EXISTS) == FALSE )
8c721f83
EB
1065 continue;
1066 for (j = floor(min_lon*8)/8; j <= floor(max_lon*8)/8; j+=0.125) {
1067 /* check lon dir first -- faster */
1068 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/%d/",
1069 MAPS_CACHE_DIR,
1070 (gint) i,
1071 (gint) j );
45acf79e 1072 if ( g_file_test(buf, G_FILE_TEST_EXISTS) == FALSE )
8c721f83
EB
1073 continue;
1074 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/%d/%.03f,%.03f.dem",
1075 MAPS_CACHE_DIR,
1076 (gint) i,
1077 (gint) j,
1078 floor(i*8)/8,
1079 floor(j*8)/8 );
45acf79e 1080 if ( g_file_test(buf, G_FILE_TEST_EXISTS ) == TRUE ) {
8c721f83
EB
1081 VikCoord ne, sw;
1082 gint x1, y1, x2, y2;
1083 sw.north_south = i;
1084 sw.east_west = j-0.125;
1085 sw.mode = VIK_COORD_LATLON;
1086 ne.north_south = i+0.125;
1087 ne.east_west = j;
1088 ne.mode = VIK_COORD_LATLON;
1089 vik_viewport_coord_to_screen ( vp, &sw, &x1, &y1 );
1090 vik_viewport_coord_to_screen ( vp, &ne, &x2, &y2 );
1091 if ( x1 < 0 ) x1 = 0;
1092 if ( y2 < 0 ) y2 = 0;
ff37db21 1093 vik_viewport_draw_rectangle ( vp, gtk_widget_get_style(GTK_WIDGET(vp))->black_gc,
8c721f83
EB
1094 FALSE, x1, y2, x2-x1, y1-y2 );
1095 }
1096 }
1097 }
1098}
1099#endif
0c1044e9 1100
8c721f83
EB
1101/**************************************************
1102 * SOURCES -- DOWNLOADING & IMPORTING TOOL *
1103 **************************************************
1104 */
0c1044e9 1105
8c721f83
EB
1106static void weak_ref_cb ( gpointer ptr, GObject * dead_vdl )
1107{
1108 DEMDownloadParams *p = ptr;
1109 g_mutex_lock ( p->mutex );
1110 p->vdl = NULL;
1111 g_mutex_unlock ( p->mutex );
1112}
0c1044e9 1113
8c721f83 1114/* Try to add file full_path.
88542aa9 1115 * filename will be copied.
8c721f83
EB
1116 * returns FALSE if file does not exists, TRUE otherwise.
1117 */
88542aa9 1118static gboolean dem_layer_add_file ( VikDEMLayer *vdl, const gchar *filename )
8c721f83 1119{
88542aa9 1120 if ( g_file_test(filename, G_FILE_TEST_EXISTS) == TRUE ) {
b01c3429 1121 /* only load if file size is not 0 (not in progress) */
0c1044e9 1122 struct stat sb;
88542aa9 1123 stat ( filename, &sb );
0c1044e9 1124 if ( sb.st_size ) {
88542aa9 1125 gchar *duped_path = g_strdup(filename);
8c721f83
EB
1126 vdl->files = g_list_prepend ( vdl->files, duped_path );
1127 a_dems_load ( duped_path );
b01c3429 1128 g_debug("%s: %s", __FUNCTION__, duped_path);
0c1044e9 1129 }
8c721f83
EB
1130 return TRUE;
1131 } else
1132 return FALSE;
1133}
1134
1135static void dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
1136{
1137 if ( p->source == DEM_SOURCE_SRTM )
1138 srtm_dem_download_thread ( p, threaddata );
1139#ifdef VIK_CONFIG_DEM24K
1140 else if ( p->source == DEM_SOURCE_DEM24K )
1141 dem24k_dem_download_thread ( p, threaddata );
1142#endif
062ad57c
RN
1143 else
1144 return;
8c721f83 1145
f01eebd4 1146 //gdk_threads_enter();
8c721f83
EB
1147 g_mutex_lock ( p->mutex );
1148 if ( p->vdl ) {
1149 g_object_weak_unref ( G_OBJECT(p->vdl), weak_ref_cb, p );
1150
1151 if ( dem_layer_add_file ( p->vdl, p->dest ) )
da121f9b 1152 vik_layer_emit_update ( VIK_LAYER(p->vdl) ); // NB update from background thread
8c721f83
EB
1153 }
1154 g_mutex_unlock ( p->mutex );
f01eebd4 1155 //gdk_threads_leave();
8c721f83
EB
1156}
1157
1158
1159static void free_dem_download_params ( DEMDownloadParams *p )
1160{
1161 g_mutex_free ( p->mutex );
1162 g_free ( p->dest );
1163 g_free ( p );
1164}
1165
1166static gpointer dem_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1167{
1168 return vvp;
1169}
1170
13d3fc89
RN
1171/**
1172 * Display a simple dialog with information about the DEM file at this location
1173 */
1174static void dem_layer_file_info ( GtkWidget *widget, struct LatLon *ll )
1175{
1176 gint intlat, intlon;
1177 const gchar *continent_dir;
1178
1179 intlat = (int)floor(ll->lat);
1180 intlon = (int)floor(ll->lon);
1181 continent_dir = srtm_continent_dir(intlat, intlon);
1182
1183 gchar *source = NULL;
1184 if ( continent_dir )
1185 source = g_strdup_printf ( "http:/%s%s/%c%02d%c%03d.hgt.zip",
1186 SRTM_HTTP_URI,
1187 continent_dir,
1188 (intlat >= 0) ? 'N' : 'S',
1189 ABS(intlat),
1190 (intlon >= 0) ? 'E' : 'W',
1191 ABS(intlon) );
1192 else
1193 // Probably not over any land...
1194 source = g_strdup ( _("No DEM File Available") );
1195
1196 gchar *filename = NULL;
1197 gchar *dem_file = NULL;
1198#ifdef VIK_CONFIG_DEM24K
1199 dem_file = dem24k_lat_lon_to_dest_fn ( ll->lat, ll->lon );
1200#else
1201 dem_file = srtm_lat_lon_to_dest_fn ( ll->lat, ll->lon );
1202#endif
1203 gchar *message = NULL;
1204
1205 filename = g_strdup_printf ( "%s%s", MAPS_CACHE_DIR, dem_file );
1206
1207 if ( g_file_test ( filename, G_FILE_TEST_EXISTS ) ) {
1208 // Get some timestamp information of the file
1209 struct stat stat_buf;
1210 if ( g_stat ( filename, &stat_buf ) == 0 ) {
1211 gchar time_buf[64];
1212 strftime ( time_buf, sizeof(time_buf), "%c", gmtime((const time_t *)&stat_buf.st_mtime) );
1213 message = g_strdup_printf ( _("\nSource: %s\n\nDEM File: %s\nDEM File Timestamp: %s"), source, filename, time_buf );
1214 }
1215 }
1216 else
1217 message = g_strdup_printf ( _("Source: %s\n\nNo DEM File!"), source );
1218
1219 // Show the info
1220 a_dialog_info_msg ( GTK_WINDOW(gtk_widget_get_toplevel(widget)), message );
1221
1222 g_free ( message );
1223 g_free ( source );
1224 g_free ( dem_file );
1225 g_free ( filename );
1226}
8c721f83
EB
1227
1228static gboolean dem_layer_download_release ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp )
1229{
1230 VikCoord coord;
13d3fc89 1231 static struct LatLon ll;
8c721f83
EB
1232
1233 gchar *full_path;
1234 gchar *dem_file = NULL;
1235
8c721f83
EB
1236 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1237 vik_coord_to_latlon ( &coord, &ll );
1238
1239
1240 if ( vdl->source == DEM_SOURCE_SRTM )
1241 dem_file = srtm_lat_lon_to_dest_fn ( ll.lat, ll.lon );
1242#ifdef VIK_CONFIG_DEM24K
1243 else if ( vdl->source == DEM_SOURCE_DEM24K )
1244 dem_file = dem24k_lat_lon_to_dest_fn ( ll.lat, ll.lon );
1245#endif
1246
1247 if ( ! dem_file )
1248 return TRUE;
1249
1250 full_path = g_strdup_printf("%s%s", MAPS_CACHE_DIR, dem_file );
1251
b01c3429 1252 g_debug("%s: %s", __FUNCTION__, full_path);
8c721f83 1253
13d3fc89
RN
1254 if ( event->button == 1 ) {
1255 // TODO: check if already in filelist
1256 if ( ! dem_layer_add_file(vdl, full_path) ) {
1257 gchar *tmp = g_strdup_printf ( _("Downloading DEM %s"), dem_file );
1258 DEMDownloadParams *p = g_malloc(sizeof(DEMDownloadParams));
1259 p->dest = g_strdup(full_path);
1260 p->lat = ll.lat;
1261 p->lon = ll.lon;
1262 p->vdl = vdl;
1263 p->mutex = g_mutex_new();
1264 p->source = vdl->source;
1265 g_object_weak_ref(G_OBJECT(p->vdl), weak_ref_cb, p );
1266
1267 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vdl), tmp,
1268 (vik_thr_func) dem_download_thread, p,
1269 (vik_thr_free_func) free_dem_download_params, NULL, 1 );
1270
1271 g_free ( tmp );
1272 }
1273 else
1274 vik_layer_emit_update ( VIK_LAYER(vdl) );
1275 }
1276 else {
1277 if ( !vdl->right_click_menu ) {
1278 GtkWidget *item;
1279 vdl->right_click_menu = GTK_MENU ( gtk_menu_new () );
1280
1281 item = gtk_image_menu_item_new_with_mnemonic ( _("_Show DEM File Information") );
1282 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INFO, GTK_ICON_SIZE_MENU) );
1283 g_signal_connect ( G_OBJECT(item), "activate", G_CALLBACK(dem_layer_file_info), &ll );
1284 gtk_menu_shell_append (GTK_MENU_SHELL(vdl->right_click_menu), item);
1285 }
2ca82974 1286
13d3fc89
RN
1287 gtk_menu_popup ( vdl->right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1288 gtk_widget_show_all ( GTK_WIDGET(vdl->right_click_menu) );
0c1044e9
EB
1289 }
1290
8c721f83
EB
1291 g_free ( dem_file );
1292 g_free ( full_path );
1293
0c1044e9
EB
1294 return TRUE;
1295}
1296
1297static gboolean dem_layer_download_click ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp )
1298{
1299/* choose & keep track of cache dir
1300 * download in background thread
1301 * download over area */
1302 return TRUE;
1303}
1304
1305