]> git.street.me.uk Git - andy/viking.git/blame - src/vikdemlayer.c
Split background threads into two pools.
[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,
63959706 139 GDK_CURSOR_IS_PIXMAP, &cursor_demdl_pixbuf, NULL },
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
c75da936
RN
427 a_background_thread ( BACKGROUND_POOL_LOCAL,
428 VIK_GTK_WINDOW_FROM_WIDGET(vp),
09c91d84
RN
429 _("DEM Loading"),
430 (vik_thr_func) dem_layer_load_list_thread,
431 dltd,
432 (vik_thr_free_func) dem_layer_thread_data_free,
433 (vik_thr_free_func) dem_layer_thread_cancel,
434 g_list_length ( data.sl ) ); // Number of DEM files
435 }
29392f59
RN
436 break;
437 }
9351abc4 438 default: break;
ad0a8c2d
EB
439 }
440 return TRUE;
441}
442
158b3642 443static VikLayerParamData dem_layer_get_param ( VikDEMLayer *vdl, guint16 id, gboolean is_file_operation )
ad0a8c2d
EB
444{
445 VikLayerParamData rv;
446 switch ( id )
447 {
88542aa9
RN
448 case PARAM_FILES:
449 rv.sl = vdl->files;
450 if ( is_file_operation )
451 // Save in relative format if necessary
452 if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE )
453 rv.sl = dem_layer_convert_to_relative_filenaming ( rv.sl );
454 break;
8c721f83 455 case PARAM_SOURCE: rv.u = vdl->source; break;
c07088dd 456 case PARAM_TYPE: rv.u = vdl->type; break;
a7023a1b 457 case PARAM_COLOR: rv.c = vdl->color; break;
0cabb401
RN
458 case PARAM_MIN_ELEV:
459 /* Convert for display in desired units
460 NB file operation always in internal units (metres) */
461 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
6c20e59a 462 rv.d = VIK_METERS_TO_FEET(vdl->min_elev);
0cabb401
RN
463 else
464 rv.d = vdl->min_elev;
465 break;
466 case PARAM_MAX_ELEV:
467 /* Convert for display in desired units
468 NB file operation always in internal units (metres) */
469 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
6c20e59a 470 rv.d = VIK_METERS_TO_FEET(vdl->max_elev);
0cabb401
RN
471 else
472 rv.d = vdl->max_elev;
473 break;
9351abc4 474 default: break;
ad0a8c2d
EB
475 }
476 return rv;
477}
478
07059501 479static void dem_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file )
ad0a8c2d 480{
7e74e26b 481 /* nothing ATM, but keep in case it's needed the future */
ad0a8c2d
EB
482}
483
0c025cfa 484static VikDEMLayer *dem_layer_new ( VikViewport *vvp )
ad0a8c2d
EB
485{
486 VikDEMLayer *vdl = VIK_DEM_LAYER ( g_object_new ( VIK_DEM_LAYER_TYPE, NULL ) );
fa86f1c0 487
a0c65899 488 vik_layer_set_type ( VIK_LAYER(vdl), VIK_LAYER_DEM );
ad0a8c2d
EB
489
490 vdl->files = NULL;
491
c07088dd
DRP
492 vdl->gcs = g_malloc(sizeof(GdkGC *)*DEM_N_HEIGHT_COLORS);
493 vdl->gcsgradient = g_malloc(sizeof(GdkGC *)*DEM_N_GRADIENT_COLORS);
fa86f1c0 494 /* make new gcs only if we need it (copy layer -> use old) */
ad0a8c2d 495
a7023a1b
RN
496 // Ensure the base GC is available so the default colour can be applied
497 if ( vvp ) vdl->gcs[0] = vik_viewport_new_gc ( vvp, "#0000FF", 1 );
498
499 vik_layer_set_defaults ( VIK_LAYER(vdl), vvp );
500
ad0a8c2d
EB
501 return vdl;
502}
503
504
f9518bc9
DRP
505static inline guint16 get_height_difference(gint16 elev, gint16 new_elev)
506{
507 if(new_elev == VIK_DEM_INVALID_ELEVATION)
508 return 0;
509 else
510 return abs(new_elev - elev);
511}
512
0c1044e9 513
ad0a8c2d
EB
514static void vik_dem_layer_draw_dem ( VikDEMLayer *vdl, VikViewport *vp, VikDEM *dem )
515{
f9518bc9 516 VikDEMColumn *column, *prevcolumn, *nextcolumn;
ad0a8c2d
EB
517
518 struct LatLon dem_northeast, dem_southwest;
f9518bc9 519 gdouble max_lat, max_lon, min_lat, min_lon;
ad0a8c2d 520
ad0a8c2d
EB
521 /**** Check if viewport and DEM data overlap ****/
522
523 /* get min, max lat/lon of viewport */
0c1044e9 524 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
ad0a8c2d
EB
525
526 /* get min, max lat/lon of DEM data */
527 if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
528 dem_northeast.lat = dem->max_north / 3600.0;
529 dem_northeast.lon = dem->max_east / 3600.0;
530 dem_southwest.lat = dem->min_north / 3600.0;
531 dem_southwest.lon = dem->min_east / 3600.0;
532 } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
533 struct UTM dem_northeast_utm, dem_southwest_utm;
534 dem_northeast_utm.northing = dem->max_north;
535 dem_northeast_utm.easting = dem->max_east;
536 dem_southwest_utm.northing = dem->min_north;
537 dem_southwest_utm.easting = dem->min_east;
538 dem_northeast_utm.zone = dem_southwest_utm.zone = dem->utm_zone;
539 dem_northeast_utm.letter = dem_southwest_utm.letter = dem->utm_letter;
540
541 a_coords_utm_to_latlon(&dem_northeast_utm, &dem_northeast);
542 a_coords_utm_to_latlon(&dem_southwest_utm, &dem_southwest);
543 }
544
545 if ( (max_lat > dem_northeast.lat && min_lat > dem_northeast.lat) ||
546 (max_lat < dem_southwest.lat && min_lat < dem_southwest.lat) )
547 return;
548 else if ( (max_lon > dem_northeast.lon && min_lon > dem_northeast.lon) ||
549 (max_lon < dem_southwest.lon && min_lon < dem_southwest.lon) )
550 return;
551 /* else they overlap */
552
553 /**** End Overlap Check ****/
0c1044e9
EB
554 /* boxes to show where we have DEM instead of actually drawing the DEM.
555 * useful if we want to see what areas we have coverage for (if we want
556 * to get elevation data for a track) but don't want to cover the map.
557 */
558
559 #if 0
560 /* draw a box if a DEM is loaded. in future I'd like to add an option for this
561 * this is useful if we want to see what areas we have dem for but don't want to
562 * cover the map (or maybe we just need translucent DEM?) */
563 {
564 VikCoord demne, demsw;
565 gint x1, y1, x2, y2;
566 vik_coord_load_from_latlon(&demne, vik_viewport_get_coord_mode(vp), &dem_northeast);
567 vik_coord_load_from_latlon(&demsw, vik_viewport_get_coord_mode(vp), &dem_southwest);
568
569 vik_viewport_coord_to_screen ( vp, &demne, &x1, &y1 );
570 vik_viewport_coord_to_screen ( vp, &demsw, &x2, &y2 );
571
572 if ( x1 > vik_viewport_get_width(vp) ) x1=vik_viewport_get_width(vp);
573 if ( y2 > vik_viewport_get_height(vp) ) y2=vik_viewport_get_height(vp);
574 if ( x2 < 0 ) x2 = 0;
575 if ( y1 < 0 ) y1 = 0;
ff37db21 576 vik_viewport_draw_rectangle ( vp, gtk_widget_get_style(GTK_WIDGET(vp))->black_gc,
0c1044e9 577 FALSE, x2, y1, x1-x2, y2-y1 );
0c1044e9
EB
578 return;
579 }
580 #endif
ad0a8c2d
EB
581
582 if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
583 VikCoord tmp; /* TODO: don't use coord_load_from_latlon, especially if in latlon drawing mode */
584
585 gdouble max_lat_as, max_lon_as, min_lat_as, min_lon_as;
586 gdouble start_lat_as, end_lat_as, start_lon_as, end_lon_as;
587
588 gdouble start_lat, end_lat, start_lon, end_lon;
589
590 struct LatLon counter;
591
592 guint x, y, start_x, start_y;
593
594 gint16 elev;
595
f9518bc9 596 guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 80 ); /* todo: smarter calculation. */
ad0a8c2d
EB
597
598 gdouble nscale_deg = dem->north_scale / ((gdouble) 3600);
599 gdouble escale_deg = dem->east_scale / ((gdouble) 3600);
600
601 max_lat_as = max_lat * 3600;
602 min_lat_as = min_lat * 3600;
603 max_lon_as = max_lon * 3600;
604 min_lon_as = min_lon * 3600;
605
606 start_lat_as = MAX(min_lat_as, dem->min_north);
607 end_lat_as = MIN(max_lat_as, dem->max_north);
608 start_lon_as = MAX(min_lon_as, dem->min_east);
609 end_lon_as = MIN(max_lon_as, dem->max_east);
610
611 start_lat = floor(start_lat_as / dem->north_scale) * nscale_deg;
612 end_lat = ceil (end_lat_as / dem->north_scale) * nscale_deg;
613 start_lon = floor(start_lon_as / dem->east_scale) * escale_deg;
614 end_lon = ceil (end_lon_as / dem->east_scale) * escale_deg;
615
616 vik_dem_east_north_to_xy ( dem, start_lon_as, start_lat_as, &start_x, &start_y );
f9518bc9
DRP
617 guint gradient_skip_factor = 1;
618 if(vdl->type == DEM_TYPE_GRADIENT)
619 gradient_skip_factor = skip_factor;
ad0a8c2d 620
415302f4
EB
621 /* verify sane elev interval */
622 if ( vdl->max_elev <= vdl->min_elev )
623 vdl->max_elev = vdl->min_elev + 1;
624
f9518bc9
DRP
625 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 ) {
626 // NOTE: ( counter.lon <= end_lon + ESCALE_DEG*SKIP_FACTOR ) is neccessary so in high zoom modes,
627 // the leftmost column does also get drawn, if the center point is out of viewport.
5e610fc3 628 if ( x < dem->n_columns ) {
ad0a8c2d 629 column = g_ptr_array_index ( dem->columns, x );
f9518bc9
DRP
630 // get previous and next column. catch out-of-bound.
631 gint32 new_x = x;
632 new_x -= gradient_skip_factor;
633 if(new_x < 1)
634 prevcolumn = g_ptr_array_index ( dem->columns, x+1);
635 else
636 prevcolumn = g_ptr_array_index ( dem->columns, new_x);
637 new_x = x;
638 new_x += gradient_skip_factor;
639 if(new_x >= dem->n_columns)
640 nextcolumn = g_ptr_array_index ( dem->columns, x-1);
641 else
642 nextcolumn = g_ptr_array_index ( dem->columns, new_x);
c07088dd 643
ad0a8c2d
EB
644 for ( y=start_y, counter.lat = start_lat; counter.lat <= end_lat; counter.lat += nscale_deg * skip_factor, y += skip_factor ) {
645 if ( y > column->n_points )
646 break;
f9518bc9 647
ad0a8c2d 648 elev = column->points[y];
415302f4 649
f9518bc9
DRP
650 // calculate bounding box for drawing
651 gint box_x, box_y, box_width, box_height;
652 struct LatLon box_c;
653 box_c = counter;
654 box_c.lat += (nscale_deg * skip_factor)/2;
655 box_c.lon -= (escale_deg * skip_factor)/2;
656 vik_coord_load_from_latlon(&tmp, vik_viewport_get_coord_mode(vp), &box_c);
657 vik_viewport_coord_to_screen(vp, &tmp, &box_x, &box_y);
658 // catch box at borders
659 if(box_x < 0)
660 box_x = 0;
661 if(box_y < 0)
662 box_y = 0;
663 box_c.lat -= nscale_deg * skip_factor;
664 box_c.lon += escale_deg * skip_factor;
665 vik_coord_load_from_latlon(&tmp, vik_viewport_get_coord_mode(vp), &box_c);
666 vik_viewport_coord_to_screen(vp, &tmp, &box_width, &box_height);
667 box_width -= box_x;
668 box_height -= box_y;
669 // catch box at borders
670 if(box_width < 0 || box_height < 0)
671 continue; // skip this. this is out of our viewport anyway. FIXME: why?
672
7e74e26b 673 gboolean below_minimum = FALSE;
f9518bc9 674 if(vdl->type == DEM_TYPE_HEIGHT) {
7e74e26b 675 if ( elev != VIK_DEM_INVALID_ELEVATION && elev < vdl->min_elev ) {
104f8c15
RN
676 // Prevent 'elev - vdl->min_elev' from being negative so can safely use as array index
677 elev = ceil ( vdl->min_elev );
7e74e26b
RN
678 below_minimum = TRUE;
679 }
f9518bc9 680 if ( elev != VIK_DEM_INVALID_ELEVATION && elev > vdl->max_elev )
104f8c15 681 elev = vdl->max_elev;
f9518bc9 682 }
415302f4 683
ad0a8c2d 684 {
f9518bc9
DRP
685 if(box_width < 0 || box_height < 0) // FIXME: why does this happen?
686 continue;
687
688 if(vdl->type == DEM_TYPE_GRADIENT) {
689 if( elev == VIK_DEM_INVALID_ELEVATION ) {
690 /* don't draw it */
691 } else {
692 // calculate and sum gradient in all directions
693 gint16 change = 0;
694 gint32 new_y;
695
696 // calculate gradient from height points all around the current one
697 new_y = y - gradient_skip_factor;
698 if(new_y < 0)
699 new_y = y;
700 change += get_height_difference(elev, prevcolumn->points[new_y]);
701 change += get_height_difference(elev, column->points[new_y]);
702 change += get_height_difference(elev, nextcolumn->points[new_y]);
703
704 change += get_height_difference(elev, prevcolumn->points[y]);
705 change += get_height_difference(elev, nextcolumn->points[y]);
706
707 new_y = y + gradient_skip_factor;
708 if(new_y >= column->n_points)
709 new_y = y;
710 change += get_height_difference(elev, prevcolumn->points[new_y]);
711 change += get_height_difference(elev, column->points[new_y]);
712 change += get_height_difference(elev, nextcolumn->points[new_y]);
713
714 change = change / ((skip_factor > 1) ? log(skip_factor) : 0.55); // FIXME: better calc.
715
716 if(change < vdl->min_elev)
104f8c15
RN
717 // Prevent 'change - vdl->min_elev' from being negative so can safely use as array index
718 change = ceil ( vdl->min_elev );
f9518bc9
DRP
719
720 if(change > vdl->max_elev)
721 change = vdl->max_elev;
722
723 // void vik_viewport_draw_rectangle ( VikViewport *vvp, GdkGC *gc, gboolean filled, gint x1, gint y1, gint x2, gint y2 );
104f8c15 724 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 725 }
c07088dd 726 } else {
f9518bc9
DRP
727 if(vdl->type == DEM_TYPE_HEIGHT) {
728 if ( elev == VIK_DEM_INVALID_ELEVATION )
729 ; /* don't draw it */
7e74e26b
RN
730 else if ( elev <= 0 || below_minimum )
731 /* If 'sea' colour or below the defined mininum draw in the configurable colour */
f9518bc9
DRP
732 vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, box_x, box_y, box_width, box_height);
733 else
104f8c15 734 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
735 }
736 }
ad0a8c2d
EB
737 }
738 } /* for y= */
739 }
740 } /* for x= */
741 } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
742 gdouble max_nor, max_eas, min_nor, min_eas;
743 gdouble start_nor, start_eas, end_nor, end_eas;
744
745 gint16 elev;
746
747 guint x, y, start_x, start_y;
748
749 VikCoord tmp; /* TODO: don't use coord_load_from_latlon, especially if in latlon drawing mode */
750 struct UTM counter;
751
752 guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 10 ); /* todo: smarter calculation. */
753
0c1044e9
EB
754 VikCoord tleft, tright, bleft, bright;
755
756 vik_viewport_screen_to_coord ( vp, 0, 0, &tleft );
757 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), 0, &tright );
758 vik_viewport_screen_to_coord ( vp, 0, vik_viewport_get_height(vp), &bleft );
759 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), vik_viewport_get_height(vp), &bright );
760
761
ad0a8c2d
EB
762 vik_coord_convert(&tleft, VIK_COORD_UTM);
763 vik_coord_convert(&tright, VIK_COORD_UTM);
764 vik_coord_convert(&bleft, VIK_COORD_UTM);
765 vik_coord_convert(&bright, VIK_COORD_UTM);
766
767 max_nor = MAX(tleft.north_south, tright.north_south);
768 min_nor = MIN(bleft.north_south, bright.north_south);
769 max_eas = MAX(bright.east_west, tright.east_west);
770 min_eas = MIN(bleft.east_west, tleft.east_west);
771
772 start_nor = MAX(min_nor, dem->min_north);
773 end_nor = MIN(max_nor, dem->max_north);
774 if ( tleft.utm_zone == dem->utm_zone && bleft.utm_zone == dem->utm_zone
775 && (tleft.utm_letter >= 'N') == (dem->utm_letter >= 'N')
776 && (bleft.utm_letter >= 'N') == (dem->utm_letter >= 'N') ) /* if the utm zones/hemispheres are different, min_eas will be bogus */
777 start_eas = MAX(min_eas, dem->min_east);
778 else
779 start_eas = dem->min_east;
780 if ( tright.utm_zone == dem->utm_zone && bright.utm_zone == dem->utm_zone
781 && (tright.utm_letter >= 'N') == (dem->utm_letter >= 'N')
782 && (bright.utm_letter >= 'N') == (dem->utm_letter >= 'N') ) /* if the utm zones/hemispheres are different, min_eas will be bogus */
783 end_eas = MIN(max_eas, dem->max_east);
784 else
785 end_eas = dem->max_east;
786
787 start_nor = floor(start_nor / dem->north_scale) * dem->north_scale;
788 end_nor = ceil (end_nor / dem->north_scale) * dem->north_scale;
789 start_eas = floor(start_eas / dem->east_scale) * dem->east_scale;
790 end_eas = ceil (end_eas / dem->east_scale) * dem->east_scale;
791
792 vik_dem_east_north_to_xy ( dem, start_eas, start_nor, &start_x, &start_y );
793
794 /* TODO: why start_x and start_y are -1 -- rounding error from above? */
795
796 counter.zone = dem->utm_zone;
797 counter.letter = dem->utm_letter;
798
799 for ( x=start_x, counter.easting = start_eas; counter.easting <= end_eas; counter.easting += dem->east_scale * skip_factor, x += skip_factor ) {
800 if ( x > 0 && x < dem->n_columns ) {
801 column = g_ptr_array_index ( dem->columns, x );
802 for ( y=start_y, counter.northing = start_nor; counter.northing <= end_nor; counter.northing += dem->north_scale * skip_factor, y += skip_factor ) {
803 if ( y > column->n_points )
804 continue;
805 elev = column->points[y];
415302f4
EB
806 if ( elev != VIK_DEM_INVALID_ELEVATION && elev < vdl->min_elev )
807 elev=vdl->min_elev;
808 if ( elev != VIK_DEM_INVALID_ELEVATION && elev > vdl->max_elev )
809 elev=vdl->max_elev;
810
ad0a8c2d
EB
811 {
812 gint a, b;
813 vik_coord_load_from_utm(&tmp, vik_viewport_get_coord_mode(vp), &counter);
814 vik_viewport_coord_to_screen(vp, &tmp, &a, &b);
815 if ( elev == VIK_DEM_INVALID_ELEVATION )
816 ; /* don't draw it */
817 else if ( elev <= 0 )
f9518bc9 818 vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, a-1, b-1, 2, 2 );
ad0a8c2d 819 else
f9518bc9 820 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
821 }
822 } /* for y= */
823 }
824 } /* for x= */
825 }
826}
827
0c1044e9
EB
828/* return the continent for the specified lat, lon */
829/* TODO */
0e25c0d0 830static const gchar *srtm_continent_dir ( gint lat, gint lon )
0c1044e9 831{
0e25c0d0
QT
832 extern const char *_srtm_continent_data[];
833 static GHashTable *srtm_continent = NULL;
834 const gchar *continent;
835 gchar name[16];
836
837 if (!srtm_continent) {
838 const gchar **s;
839
840 srtm_continent = g_hash_table_new(g_str_hash, g_str_equal);
841 s = _srtm_continent_data;
842 while (*s != (gchar *)-1) {
843 continent = *s++;
844 while (*s) {
0654760a 845 g_hash_table_insert(srtm_continent, (gpointer) *s, (gpointer) continent);
0e25c0d0
QT
846 s++;
847 }
848 s++;
849 }
850 }
851 g_snprintf(name, sizeof(name), "%c%02d%c%03d",
852 (lat >= 0) ? 'N' : 'S', ABS(lat),
853 (lon >= 0) ? 'E' : 'W', ABS(lon));
854
855 return(g_hash_table_lookup(srtm_continent, name));
0c1044e9
EB
856}
857
0c025cfa 858static void dem_layer_draw ( VikDEMLayer *vdl, VikViewport *vp )
ad0a8c2d 859{
ad0a8c2d
EB
860 GList *dems_iter = vdl->files;
861 VikDEM *dem;
0c1044e9 862
0c1044e9
EB
863
864 /* search for SRTM3 90m */
8c721f83
EB
865
866 if ( vdl->source == DEM_SOURCE_SRTM )
867 srtm_draw_existence ( vp );
868#ifdef VIK_CONFIG_DEM24K
869 else if ( vdl->source == DEM_SOURCE_DEM24K )
870 dem24k_draw_existence ( vp );
871#endif
0c1044e9 872
ad0a8c2d
EB
873 while ( dems_iter ) {
874 dem = a_dems_get ( (const char *) (dems_iter->data) );
875 if ( dem )
876 vik_dem_layer_draw_dem ( vdl, vp, dem );
877 dems_iter = dems_iter->next;
878 }
879}
880
0c025cfa 881static void dem_layer_free ( VikDEMLayer *vdl )
ad0a8c2d 882{
fa86f1c0 883 gint i;
fa86f1c0 884 if ( vdl->gcs )
c07088dd 885 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ )
fa86f1c0
EB
886 g_object_unref ( vdl->gcs[i] );
887 g_free ( vdl->gcs );
888
c07088dd
DRP
889 if ( vdl->gcsgradient )
890 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
891 g_object_unref ( vdl->gcsgradient[i] );
892 g_free ( vdl->gcsgradient );
893
ad0a8c2d
EB
894 a_dems_list_free ( vdl->files );
895}
896
0c025cfa 897VikDEMLayer *dem_layer_create ( VikViewport *vp )
ad0a8c2d 898{
0c025cfa 899 VikDEMLayer *vdl = dem_layer_new ( vp );
fa86f1c0 900 gint i;
8aff54f2
RN
901 if ( vp ) {
902 /* TODO: share GCS between layers */
a7023a1b
RN
903 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ ) {
904 if ( i > 0 )
905 vdl->gcs[i] = vik_viewport_new_gc ( vp, dem_height_colors[i], UNUSED_LINE_THICKNESS );
906 }
8aff54f2
RN
907 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
908 vdl->gcsgradient[i] = vik_viewport_new_gc ( vp, dem_gradient_colors[i], UNUSED_LINE_THICKNESS );
909 }
ad0a8c2d
EB
910 return vdl;
911}
8c721f83
EB
912/**************************************************************
913 **** SOURCES & DOWNLOADING
914 **************************************************************/
915typedef struct {
916 gchar *dest;
917 gdouble lat, lon;
918
919 GMutex *mutex;
920 VikDEMLayer *vdl; /* NULL if not alive */
921
922 guint source;
923} DEMDownloadParams;
924
ad0a8c2d 925
0c1044e9 926/**************************************************
8c721f83
EB
927 * SOURCE: SRTM *
928 **************************************************/
929
930static void srtm_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
0c1044e9 931{
8c721f83 932 gint intlat, intlon;
0e25c0d0 933 const gchar *continent_dir;
8c721f83
EB
934
935 intlat = (int)floor(p->lat);
936 intlon = (int)floor(p->lon);
0e25c0d0
QT
937 continent_dir = srtm_continent_dir(intlat, intlon);
938
939 if (!continent_dir) {
1a272ee7
RN
940 if ( p->vdl ) {
941 gchar *msg = g_strdup_printf ( _("No SRTM data available for %f, %f"), p->lat, p->lon );
942 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(p->vdl), msg, VIK_STATUSBAR_INFO );
943 g_free ( msg );
944 }
0e25c0d0
QT
945 return;
946 }
947
65a64219 948 gchar *src_fn = g_strdup_printf("%s%s/%c%02d%c%03d.hgt.zip",
e6c50657 949 SRTM_HTTP_URI,
0e25c0d0 950 continent_dir,
8c721f83
EB
951 (intlat >= 0) ? 'N' : 'S',
952 ABS(intlat),
953 (intlon >= 0) ? 'E' : 'W',
954 ABS(intlon) );
955
63959706 956 static DownloadMapOptions options = { FALSE, FALSE, NULL, 0, a_check_map_file, NULL, NULL };
4e815e90
RN
957 DownloadResult_t result = a_http_download_get_url ( SRTM_HTTP_SITE, src_fn, p->dest, &options, NULL );
958 switch ( result ) {
959 case DOWNLOAD_CONTENT_ERROR:
960 case DOWNLOAD_HTTP_ERROR: {
961 gchar *msg = g_strdup_printf ( _("DEM download failure for %f, %f"), p->lat, p->lon );
962 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(p->vdl), msg, VIK_STATUSBAR_INFO );
963 g_free ( msg );
964 break;
965 }
966 case DOWNLOAD_FILE_WRITE_ERROR: {
967 gchar *msg = g_strdup_printf ( _("DEM write failure for %s"), p->dest );
968 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(p->vdl), msg, VIK_STATUSBAR_INFO );
969 g_free ( msg );
970 break;
971 }
972 case DOWNLOAD_SUCCESS:
973 case DOWNLOAD_NOT_REQUIRED:
974 default:
975 break;
976 }
8c721f83 977 g_free ( src_fn );
0c1044e9
EB
978}
979
8c721f83 980static gchar *srtm_lat_lon_to_dest_fn ( gdouble lat, gdouble lon )
0c1044e9 981{
8c721f83 982 gint intlat, intlon;
0e25c0d0
QT
983 const gchar *continent_dir;
984
8c721f83
EB
985 intlat = (int)floor(lat);
986 intlon = (int)floor(lon);
0e25c0d0
QT
987 continent_dir = srtm_continent_dir(intlat, intlon);
988
989 if (!continent_dir)
990 continent_dir = "nowhere";
991
992 return g_strdup_printf("srtm3-%s%s%c%02d%c%03d.hgt.zip",
993 continent_dir,
994 G_DIR_SEPARATOR_S,
8c721f83
EB
995 (intlat >= 0) ? 'N' : 'S',
996 ABS(intlat),
997 (intlon >= 0) ? 'E' : 'W',
998 ABS(intlon) );
0c1044e9 999
0c1044e9
EB
1000}
1001
8c721f83
EB
1002/* TODO: generalize */
1003static void srtm_draw_existence ( VikViewport *vp )
0c1044e9 1004{
8c721f83
EB
1005 gdouble max_lat, max_lon, min_lat, min_lon;
1006 gchar buf[strlen(MAPS_CACHE_DIR)+strlen(SRTM_CACHE_TEMPLATE)+30];
1007 gint i, j;
1008
1009 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
1010
1011 for (i = floor(min_lat); i <= floor(max_lat); i++) {
1012 for (j = floor(min_lon); j <= floor(max_lon); j++) {
0e25c0d0
QT
1013 const gchar *continent_dir;
1014 if ((continent_dir = srtm_continent_dir(i, j)) == NULL)
1015 continue;
8c721f83
EB
1016 g_snprintf(buf, sizeof(buf), SRTM_CACHE_TEMPLATE,
1017 MAPS_CACHE_DIR,
0e25c0d0
QT
1018 continent_dir,
1019 G_DIR_SEPARATOR_S,
8c721f83
EB
1020 (i >= 0) ? 'N' : 'S',
1021 ABS(i),
1022 (j >= 0) ? 'E' : 'W',
1023 ABS(j) );
45acf79e 1024 if ( g_file_test(buf, G_FILE_TEST_EXISTS ) == TRUE ) {
8c721f83
EB
1025 VikCoord ne, sw;
1026 gint x1, y1, x2, y2;
1027 sw.north_south = i;
1028 sw.east_west = j;
1029 sw.mode = VIK_COORD_LATLON;
1030 ne.north_south = i+1;
1031 ne.east_west = j+1;
1032 ne.mode = VIK_COORD_LATLON;
1033 vik_viewport_coord_to_screen ( vp, &sw, &x1, &y1 );
1034 vik_viewport_coord_to_screen ( vp, &ne, &x2, &y2 );
1035 if ( x1 < 0 ) x1 = 0;
1036 if ( y2 < 0 ) y2 = 0;
ff37db21 1037 vik_viewport_draw_rectangle ( vp, gtk_widget_get_style(GTK_WIDGET(vp))->black_gc,
8c721f83
EB
1038 FALSE, x1, y2, x2-x1, y1-y2 );
1039 }
1040 }
1041 }
0c1044e9
EB
1042}
1043
8c721f83
EB
1044
1045/**************************************************
1046 * SOURCE: USGS 24K *
1047 **************************************************/
1048
1049#ifdef VIK_CONFIG_DEM24K
1050
1051static void dem24k_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
0c1044e9 1052{
8c721f83
EB
1053 /* TODO: dest dir */
1054 gchar *cmdline = g_strdup_printf("%s %.03f %.03f",
1055 DEM24K_DOWNLOAD_SCRIPT,
1056 floor(p->lat*8)/8,
1057 ceil(p->lon*8)/8 );
1058 /* FIX: don't use system, use execv or something. check for existence */
1059 system(cmdline);
d94f70cc 1060 g_free ( cmdline );
8c721f83 1061}
0c1044e9 1062
8c721f83
EB
1063static gchar *dem24k_lat_lon_to_dest_fn ( gdouble lat, gdouble lon )
1064{
1065 return g_strdup_printf("dem24k/%d/%d/%.03f,%.03f.dem",
1066 (gint) lat,
1067 (gint) lon,
1068 floor(lat*8)/8,
1069 ceil(lon*8)/8);
1070}
0c1044e9 1071
8c721f83
EB
1072/* TODO: generalize */
1073static void dem24k_draw_existence ( VikViewport *vp )
1074{
1075 gdouble max_lat, max_lon, min_lat, min_lon;
1076 gchar buf[strlen(MAPS_CACHE_DIR)+40];
1077 gdouble i, j;
0c1044e9 1078
8c721f83 1079 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
0c1044e9 1080
8c721f83
EB
1081 for (i = floor(min_lat*8)/8; i <= floor(max_lat*8)/8; i+=0.125) {
1082 /* check lat dir first -- faster */
1083 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/",
1084 MAPS_CACHE_DIR,
1085 (gint) i );
6b1a58ec 1086 if ( g_file_test(buf, G_FILE_TEST_EXISTS) == FALSE )
8c721f83
EB
1087 continue;
1088 for (j = floor(min_lon*8)/8; j <= floor(max_lon*8)/8; j+=0.125) {
1089 /* check lon dir first -- faster */
1090 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/%d/",
1091 MAPS_CACHE_DIR,
1092 (gint) i,
1093 (gint) j );
45acf79e 1094 if ( g_file_test(buf, G_FILE_TEST_EXISTS) == FALSE )
8c721f83
EB
1095 continue;
1096 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/%d/%.03f,%.03f.dem",
1097 MAPS_CACHE_DIR,
1098 (gint) i,
1099 (gint) j,
1100 floor(i*8)/8,
1101 floor(j*8)/8 );
45acf79e 1102 if ( g_file_test(buf, G_FILE_TEST_EXISTS ) == TRUE ) {
8c721f83
EB
1103 VikCoord ne, sw;
1104 gint x1, y1, x2, y2;
1105 sw.north_south = i;
1106 sw.east_west = j-0.125;
1107 sw.mode = VIK_COORD_LATLON;
1108 ne.north_south = i+0.125;
1109 ne.east_west = j;
1110 ne.mode = VIK_COORD_LATLON;
1111 vik_viewport_coord_to_screen ( vp, &sw, &x1, &y1 );
1112 vik_viewport_coord_to_screen ( vp, &ne, &x2, &y2 );
1113 if ( x1 < 0 ) x1 = 0;
1114 if ( y2 < 0 ) y2 = 0;
ff37db21 1115 vik_viewport_draw_rectangle ( vp, gtk_widget_get_style(GTK_WIDGET(vp))->black_gc,
8c721f83
EB
1116 FALSE, x1, y2, x2-x1, y1-y2 );
1117 }
1118 }
1119 }
1120}
1121#endif
0c1044e9 1122
8c721f83
EB
1123/**************************************************
1124 * SOURCES -- DOWNLOADING & IMPORTING TOOL *
1125 **************************************************
1126 */
0c1044e9 1127
8c721f83
EB
1128static void weak_ref_cb ( gpointer ptr, GObject * dead_vdl )
1129{
1130 DEMDownloadParams *p = ptr;
1131 g_mutex_lock ( p->mutex );
1132 p->vdl = NULL;
1133 g_mutex_unlock ( p->mutex );
1134}
0c1044e9 1135
8c721f83 1136/* Try to add file full_path.
88542aa9 1137 * filename will be copied.
8c721f83
EB
1138 * returns FALSE if file does not exists, TRUE otherwise.
1139 */
88542aa9 1140static gboolean dem_layer_add_file ( VikDEMLayer *vdl, const gchar *filename )
8c721f83 1141{
88542aa9 1142 if ( g_file_test(filename, G_FILE_TEST_EXISTS) == TRUE ) {
b01c3429 1143 /* only load if file size is not 0 (not in progress) */
0c1044e9 1144 struct stat sb;
88542aa9 1145 stat ( filename, &sb );
0c1044e9 1146 if ( sb.st_size ) {
88542aa9 1147 gchar *duped_path = g_strdup(filename);
8c721f83
EB
1148 vdl->files = g_list_prepend ( vdl->files, duped_path );
1149 a_dems_load ( duped_path );
b01c3429 1150 g_debug("%s: %s", __FUNCTION__, duped_path);
0c1044e9 1151 }
8c721f83
EB
1152 return TRUE;
1153 } else
1154 return FALSE;
1155}
1156
1157static void dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
1158{
1159 if ( p->source == DEM_SOURCE_SRTM )
1160 srtm_dem_download_thread ( p, threaddata );
1161#ifdef VIK_CONFIG_DEM24K
1162 else if ( p->source == DEM_SOURCE_DEM24K )
1163 dem24k_dem_download_thread ( p, threaddata );
1164#endif
062ad57c
RN
1165 else
1166 return;
8c721f83 1167
f01eebd4 1168 //gdk_threads_enter();
8c721f83
EB
1169 g_mutex_lock ( p->mutex );
1170 if ( p->vdl ) {
1171 g_object_weak_unref ( G_OBJECT(p->vdl), weak_ref_cb, p );
1172
1173 if ( dem_layer_add_file ( p->vdl, p->dest ) )
da121f9b 1174 vik_layer_emit_update ( VIK_LAYER(p->vdl) ); // NB update from background thread
8c721f83
EB
1175 }
1176 g_mutex_unlock ( p->mutex );
f01eebd4 1177 //gdk_threads_leave();
8c721f83
EB
1178}
1179
1180
1181static void free_dem_download_params ( DEMDownloadParams *p )
1182{
fc6640a9 1183 vik_mutex_free ( p->mutex );
8c721f83
EB
1184 g_free ( p->dest );
1185 g_free ( p );
1186}
1187
1188static gpointer dem_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1189{
1190 return vvp;
1191}
1192
13d3fc89
RN
1193/**
1194 * Display a simple dialog with information about the DEM file at this location
1195 */
1196static void dem_layer_file_info ( GtkWidget *widget, struct LatLon *ll )
1197{
1198 gint intlat, intlon;
1199 const gchar *continent_dir;
1200
1201 intlat = (int)floor(ll->lat);
1202 intlon = (int)floor(ll->lon);
1203 continent_dir = srtm_continent_dir(intlat, intlon);
1204
1205 gchar *source = NULL;
1206 if ( continent_dir )
a0a471d5
RN
1207 source = g_strdup_printf ( "http://%s%s%s/%c%02d%c%03d.hgt.zip",
1208 SRTM_HTTP_SITE,
13d3fc89
RN
1209 SRTM_HTTP_URI,
1210 continent_dir,
1211 (intlat >= 0) ? 'N' : 'S',
1212 ABS(intlat),
1213 (intlon >= 0) ? 'E' : 'W',
1214 ABS(intlon) );
1215 else
1216 // Probably not over any land...
1217 source = g_strdup ( _("No DEM File Available") );
1218
1219 gchar *filename = NULL;
1220 gchar *dem_file = NULL;
1221#ifdef VIK_CONFIG_DEM24K
1222 dem_file = dem24k_lat_lon_to_dest_fn ( ll->lat, ll->lon );
1223#else
1224 dem_file = srtm_lat_lon_to_dest_fn ( ll->lat, ll->lon );
1225#endif
1226 gchar *message = NULL;
1227
1228 filename = g_strdup_printf ( "%s%s", MAPS_CACHE_DIR, dem_file );
1229
1230 if ( g_file_test ( filename, G_FILE_TEST_EXISTS ) ) {
1231 // Get some timestamp information of the file
1232 struct stat stat_buf;
1233 if ( g_stat ( filename, &stat_buf ) == 0 ) {
1234 gchar time_buf[64];
1235 strftime ( time_buf, sizeof(time_buf), "%c", gmtime((const time_t *)&stat_buf.st_mtime) );
1236 message = g_strdup_printf ( _("\nSource: %s\n\nDEM File: %s\nDEM File Timestamp: %s"), source, filename, time_buf );
1237 }
1238 }
1239 else
1240 message = g_strdup_printf ( _("Source: %s\n\nNo DEM File!"), source );
1241
1242 // Show the info
1243 a_dialog_info_msg ( GTK_WINDOW(gtk_widget_get_toplevel(widget)), message );
1244
1245 g_free ( message );
1246 g_free ( source );
1247 g_free ( dem_file );
1248 g_free ( filename );
1249}
8c721f83
EB
1250
1251static gboolean dem_layer_download_release ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp )
1252{
1253 VikCoord coord;
13d3fc89 1254 static struct LatLon ll;
8c721f83
EB
1255
1256 gchar *full_path;
1257 gchar *dem_file = NULL;
1258
8c721f83
EB
1259 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1260 vik_coord_to_latlon ( &coord, &ll );
1261
1262
1263 if ( vdl->source == DEM_SOURCE_SRTM )
1264 dem_file = srtm_lat_lon_to_dest_fn ( ll.lat, ll.lon );
1265#ifdef VIK_CONFIG_DEM24K
1266 else if ( vdl->source == DEM_SOURCE_DEM24K )
1267 dem_file = dem24k_lat_lon_to_dest_fn ( ll.lat, ll.lon );
1268#endif
1269
1270 if ( ! dem_file )
1271 return TRUE;
1272
1273 full_path = g_strdup_printf("%s%s", MAPS_CACHE_DIR, dem_file );
1274
b01c3429 1275 g_debug("%s: %s", __FUNCTION__, full_path);
8c721f83 1276
13d3fc89
RN
1277 if ( event->button == 1 ) {
1278 // TODO: check if already in filelist
1279 if ( ! dem_layer_add_file(vdl, full_path) ) {
1280 gchar *tmp = g_strdup_printf ( _("Downloading DEM %s"), dem_file );
1281 DEMDownloadParams *p = g_malloc(sizeof(DEMDownloadParams));
1282 p->dest = g_strdup(full_path);
1283 p->lat = ll.lat;
1284 p->lon = ll.lon;
1285 p->vdl = vdl;
fc6640a9 1286 p->mutex = vik_mutex_new();
13d3fc89
RN
1287 p->source = vdl->source;
1288 g_object_weak_ref(G_OBJECT(p->vdl), weak_ref_cb, p );
1289
c75da936
RN
1290 a_background_thread ( BACKGROUND_POOL_REMOTE,
1291 VIK_GTK_WINDOW_FROM_LAYER(vdl), tmp,
13d3fc89
RN
1292 (vik_thr_func) dem_download_thread, p,
1293 (vik_thr_free_func) free_dem_download_params, NULL, 1 );
1294
1295 g_free ( tmp );
1296 }
1297 else
1298 vik_layer_emit_update ( VIK_LAYER(vdl) );
1299 }
1300 else {
1301 if ( !vdl->right_click_menu ) {
1302 GtkWidget *item;
1303 vdl->right_click_menu = GTK_MENU ( gtk_menu_new () );
1304
1305 item = gtk_image_menu_item_new_with_mnemonic ( _("_Show DEM File Information") );
1306 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INFO, GTK_ICON_SIZE_MENU) );
1307 g_signal_connect ( G_OBJECT(item), "activate", G_CALLBACK(dem_layer_file_info), &ll );
1308 gtk_menu_shell_append (GTK_MENU_SHELL(vdl->right_click_menu), item);
1309 }
2ca82974 1310
13d3fc89
RN
1311 gtk_menu_popup ( vdl->right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1312 gtk_widget_show_all ( GTK_WIDGET(vdl->right_click_menu) );
0c1044e9
EB
1313 }
1314
8c721f83
EB
1315 g_free ( dem_file );
1316 g_free ( full_path );
1317
0c1044e9
EB
1318 return TRUE;
1319}
1320
1321static gboolean dem_layer_download_click ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp )
1322{
1323/* choose & keep track of cache dir
1324 * download in background thread
1325 * download over area */
1326 return TRUE;
1327}
1328
1329