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