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