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