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