]> git.street.me.uk Git - andy/viking.git/blame - src/vikdemlayer.c
Add internal track right click menu variable.
[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,
235};
236
237struct _VikDEMLayer {
238 VikLayer vl;
ad0a8c2d 239 GdkGC **gcs;
c07088dd 240 GdkGC **gcsgradient;
ad0a8c2d 241 GList *files;
415302f4 242 gdouble min_elev;
ad0a8c2d 243 gdouble max_elev;
7e74e26b 244 GdkGC *color;
8c721f83 245 guint source;
c07088dd 246 guint type;
ad0a8c2d
EB
247};
248
249GType vik_dem_layer_get_type ()
250{
251 static GType vdl_type = 0;
252
253 if (!vdl_type)
254 {
255 static const GTypeInfo vdl_info =
256 {
257 sizeof (VikDEMLayerClass),
258 NULL, /* base_init */
259 NULL, /* base_finalize */
260 NULL, /* class init */
261 NULL, /* class_finalize */
262 NULL, /* class_data */
263 sizeof (VikDEMLayer),
264 0,
265 NULL /* instance init */
266 };
267 vdl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikDEMLayer", &vdl_info, 0 );
268 }
269
270 return vdl_type;
271}
272
e6c9ae37
RN
273static const gchar* dem_layer_tooltip( VikDEMLayer *vdl )
274{
275 static gchar tmp_buf[100];
276 g_snprintf (tmp_buf, sizeof(tmp_buf), _("Number of files: %d"), g_list_length (vdl->files));
277 return tmp_buf;
278}
279
ad0a8c2d
EB
280static void dem_layer_marshall( VikDEMLayer *vdl, guint8 **data, gint *len )
281{
282 vik_layer_marshall_params ( VIK_LAYER(vdl), data, len );
283}
284
285static VikDEMLayer *dem_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
286{
fa86f1c0
EB
287 VikDEMLayer *rv = vik_dem_layer_new ();
288 gint i;
289
290 /* TODO: share GCS between layers */
c07088dd 291 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ )
7e74e26b 292 rv->gcs[i] = vik_viewport_new_gc ( vvp, dem_height_colors[i], UNUSED_LINE_THICKNESS );
c07088dd
DRP
293
294 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
7e74e26b 295 rv->gcsgradient[i] = vik_viewport_new_gc ( vvp, dem_gradient_colors[i], UNUSED_LINE_THICKNESS );
fa86f1c0 296
ad0a8c2d
EB
297 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
298 return rv;
299}
300
29392f59
RN
301/* Structure for DEM data used in background thread */
302typedef struct {
303 VikDEMLayer *vdl;
304} dem_load_thread_data;
305
306/*
307 * Function for starting the DEM file loading as a background thread
308 */
309static int dem_layer_load_list_thread ( dem_load_thread_data *dltd, gpointer threaddata )
310{
311 int result = 0; // Default to good
312 // Actual Load
313 if ( a_dems_load_list ( &(dltd->vdl->files), threaddata ) ) {
314 // Thread cancelled
315 result = -1;
316 }
317
318 // ATM as each file is processed the screen is not updated (no mechanism exposed to a_dems_load_list)
319 // Thus force draw only at the end, as loading is complete/aborted
320 gdk_threads_enter();
94595b61
RN
321 // Test is helpful to prevent Gtk-CRITICAL warnings if the program is exitted whilst loading
322 if ( IS_VIK_LAYER(dltd->vdl) )
323 vik_layer_emit_update ( VIK_LAYER(dltd->vdl) );
29392f59
RN
324 gdk_threads_leave();
325
326 return result;
327}
328
329static void dem_layer_thread_data_free ( dem_load_thread_data *data )
330{
331 // Simple release
332 g_free ( data );
333}
334
335static void dem_layer_thread_cancel ( dem_load_thread_data *data )
336{
337 // Abort loading
338 // Instead of freeing the list, leave it as partially processed
339 // Thus we can see/use what was done
340}
341
158b3642 342gboolean dem_layer_set_param ( VikDEMLayer *vdl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
ad0a8c2d
EB
343{
344 switch ( id )
345 {
7e74e26b 346 case PARAM_COLOR: gdk_gc_set_rgb_fg_color ( vdl->gcs[0], &(data.c) ); break;
8c721f83 347 case PARAM_SOURCE: vdl->source = data.u; break;
c07088dd 348 case PARAM_TYPE: vdl->type = data.u; break;
0cabb401
RN
349 case PARAM_MIN_ELEV:
350 /* Convert to store internally
351 NB file operation always in internal units (metres) */
352 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
ab1e0693 353 vdl->min_elev = VIK_FEET_TO_METERS(data.d);
0cabb401
RN
354 else
355 vdl->min_elev = data.d;
356 break;
357 case PARAM_MAX_ELEV:
358 /* Convert to store internally
359 NB file operation always in internal units (metres) */
360 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
ab1e0693 361 vdl->max_elev = VIK_FEET_TO_METERS(data.d);
0cabb401
RN
362 else
363 vdl->max_elev = data.d;
364 break;
29392f59
RN
365 case PARAM_FILES:
366 {
367 // Clear out old settings - if any commonalities with new settings they will have to be read again
368 a_dems_list_free ( vdl->files );
369 // Set file list so any other intermediate screen drawing updates will show currently loaded DEMs by the working thread
370 vdl->files = data.sl;
371 // Thread Load
372 dem_load_thread_data *dltd = g_malloc ( sizeof(dem_load_thread_data) );
373 dltd->vdl = vdl;
374 dltd->vdl->files = data.sl;
375
376 a_background_thread ( VIK_GTK_WINDOW_FROM_WIDGET(vp),
377 _("DEM Loading"),
378 (vik_thr_func) dem_layer_load_list_thread,
379 dltd,
380 (vik_thr_free_func) dem_layer_thread_data_free,
381 (vik_thr_free_func) dem_layer_thread_cancel,
382 g_list_length ( data.sl ) ); // Number of DEM files
383 break;
384 }
ad0a8c2d
EB
385 }
386 return TRUE;
387}
388
158b3642 389static VikLayerParamData dem_layer_get_param ( VikDEMLayer *vdl, guint16 id, gboolean is_file_operation )
ad0a8c2d
EB
390{
391 VikLayerParamData rv;
392 switch ( id )
393 {
394 case PARAM_FILES: rv.sl = vdl->files; break;
8c721f83 395 case PARAM_SOURCE: rv.u = vdl->source; break;
c07088dd 396 case PARAM_TYPE: rv.u = vdl->type; break;
7e74e26b 397 case PARAM_COLOR: vik_gc_get_fg_color ( vdl->gcs[0], &(rv.c) ); break;
0cabb401
RN
398 case PARAM_MIN_ELEV:
399 /* Convert for display in desired units
400 NB file operation always in internal units (metres) */
401 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
6c20e59a 402 rv.d = VIK_METERS_TO_FEET(vdl->min_elev);
0cabb401
RN
403 else
404 rv.d = vdl->min_elev;
405 break;
406 case PARAM_MAX_ELEV:
407 /* Convert for display in desired units
408 NB file operation always in internal units (metres) */
409 if (!is_file_operation && a_vik_get_units_height () == VIK_UNITS_HEIGHT_FEET )
6c20e59a 410 rv.d = VIK_METERS_TO_FEET(vdl->max_elev);
0cabb401
RN
411 else
412 rv.d = vdl->max_elev;
413 break;
ad0a8c2d
EB
414 }
415 return rv;
416}
417
07059501 418static void dem_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file )
ad0a8c2d 419{
7e74e26b 420 /* nothing ATM, but keep in case it's needed the future */
ad0a8c2d
EB
421}
422
423VikDEMLayer *vik_dem_layer_new ( )
424{
425 VikDEMLayer *vdl = VIK_DEM_LAYER ( g_object_new ( VIK_DEM_LAYER_TYPE, NULL ) );
fa86f1c0 426
ad0a8c2d
EB
427 vik_layer_init ( VIK_LAYER(vdl), VIK_LAYER_DEM );
428
429 vdl->files = NULL;
430
c07088dd
DRP
431 vdl->gcs = g_malloc(sizeof(GdkGC *)*DEM_N_HEIGHT_COLORS);
432 vdl->gcsgradient = g_malloc(sizeof(GdkGC *)*DEM_N_GRADIENT_COLORS);
fa86f1c0 433 /* make new gcs only if we need it (copy layer -> use old) */
ad0a8c2d 434
415302f4 435 vdl->min_elev = 0.0;
ad0a8c2d 436 vdl->max_elev = 1000.0;
8c721f83 437 vdl->source = DEM_SOURCE_SRTM;
c07088dd 438 vdl->type = DEM_TYPE_HEIGHT;
ad0a8c2d
EB
439 return vdl;
440}
441
442
f9518bc9
DRP
443static inline guint16 get_height_difference(gint16 elev, gint16 new_elev)
444{
445 if(new_elev == VIK_DEM_INVALID_ELEVATION)
446 return 0;
447 else
448 return abs(new_elev - elev);
449}
450
0c1044e9 451
ad0a8c2d
EB
452static void vik_dem_layer_draw_dem ( VikDEMLayer *vdl, VikViewport *vp, VikDEM *dem )
453{
f9518bc9 454 VikDEMColumn *column, *prevcolumn, *nextcolumn;
ad0a8c2d
EB
455
456 struct LatLon dem_northeast, dem_southwest;
f9518bc9 457 gdouble max_lat, max_lon, min_lat, min_lon;
ad0a8c2d 458
ad0a8c2d
EB
459 /**** Check if viewport and DEM data overlap ****/
460
461 /* get min, max lat/lon of viewport */
0c1044e9 462 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
ad0a8c2d
EB
463
464 /* get min, max lat/lon of DEM data */
465 if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
466 dem_northeast.lat = dem->max_north / 3600.0;
467 dem_northeast.lon = dem->max_east / 3600.0;
468 dem_southwest.lat = dem->min_north / 3600.0;
469 dem_southwest.lon = dem->min_east / 3600.0;
470 } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
471 struct UTM dem_northeast_utm, dem_southwest_utm;
472 dem_northeast_utm.northing = dem->max_north;
473 dem_northeast_utm.easting = dem->max_east;
474 dem_southwest_utm.northing = dem->min_north;
475 dem_southwest_utm.easting = dem->min_east;
476 dem_northeast_utm.zone = dem_southwest_utm.zone = dem->utm_zone;
477 dem_northeast_utm.letter = dem_southwest_utm.letter = dem->utm_letter;
478
479 a_coords_utm_to_latlon(&dem_northeast_utm, &dem_northeast);
480 a_coords_utm_to_latlon(&dem_southwest_utm, &dem_southwest);
481 }
482
483 if ( (max_lat > dem_northeast.lat && min_lat > dem_northeast.lat) ||
484 (max_lat < dem_southwest.lat && min_lat < dem_southwest.lat) )
485 return;
486 else if ( (max_lon > dem_northeast.lon && min_lon > dem_northeast.lon) ||
487 (max_lon < dem_southwest.lon && min_lon < dem_southwest.lon) )
488 return;
489 /* else they overlap */
490
491 /**** End Overlap Check ****/
0c1044e9
EB
492 /* boxes to show where we have DEM instead of actually drawing the DEM.
493 * useful if we want to see what areas we have coverage for (if we want
494 * to get elevation data for a track) but don't want to cover the map.
495 */
496
497 #if 0
498 /* draw a box if a DEM is loaded. in future I'd like to add an option for this
499 * this is useful if we want to see what areas we have dem for but don't want to
500 * cover the map (or maybe we just need translucent DEM?) */
501 {
502 VikCoord demne, demsw;
503 gint x1, y1, x2, y2;
504 vik_coord_load_from_latlon(&demne, vik_viewport_get_coord_mode(vp), &dem_northeast);
505 vik_coord_load_from_latlon(&demsw, vik_viewport_get_coord_mode(vp), &dem_southwest);
506
507 vik_viewport_coord_to_screen ( vp, &demne, &x1, &y1 );
508 vik_viewport_coord_to_screen ( vp, &demsw, &x2, &y2 );
509
510 if ( x1 > vik_viewport_get_width(vp) ) x1=vik_viewport_get_width(vp);
511 if ( y2 > vik_viewport_get_height(vp) ) y2=vik_viewport_get_height(vp);
512 if ( x2 < 0 ) x2 = 0;
513 if ( y1 < 0 ) y1 = 0;
514 vik_viewport_draw_rectangle ( vp, GTK_WIDGET(vp)->style->black_gc,
515 FALSE, x2, y1, x1-x2, y2-y1 );
0c1044e9
EB
516 return;
517 }
518 #endif
ad0a8c2d
EB
519
520 if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
521 VikCoord tmp; /* TODO: don't use coord_load_from_latlon, especially if in latlon drawing mode */
522
523 gdouble max_lat_as, max_lon_as, min_lat_as, min_lon_as;
524 gdouble start_lat_as, end_lat_as, start_lon_as, end_lon_as;
525
526 gdouble start_lat, end_lat, start_lon, end_lon;
527
528 struct LatLon counter;
529
530 guint x, y, start_x, start_y;
531
532 gint16 elev;
533
f9518bc9 534 guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 80 ); /* todo: smarter calculation. */
ad0a8c2d
EB
535
536 gdouble nscale_deg = dem->north_scale / ((gdouble) 3600);
537 gdouble escale_deg = dem->east_scale / ((gdouble) 3600);
538
539 max_lat_as = max_lat * 3600;
540 min_lat_as = min_lat * 3600;
541 max_lon_as = max_lon * 3600;
542 min_lon_as = min_lon * 3600;
543
544 start_lat_as = MAX(min_lat_as, dem->min_north);
545 end_lat_as = MIN(max_lat_as, dem->max_north);
546 start_lon_as = MAX(min_lon_as, dem->min_east);
547 end_lon_as = MIN(max_lon_as, dem->max_east);
548
549 start_lat = floor(start_lat_as / dem->north_scale) * nscale_deg;
550 end_lat = ceil (end_lat_as / dem->north_scale) * nscale_deg;
551 start_lon = floor(start_lon_as / dem->east_scale) * escale_deg;
552 end_lon = ceil (end_lon_as / dem->east_scale) * escale_deg;
553
554 vik_dem_east_north_to_xy ( dem, start_lon_as, start_lat_as, &start_x, &start_y );
f9518bc9
DRP
555 guint gradient_skip_factor = 1;
556 if(vdl->type == DEM_TYPE_GRADIENT)
557 gradient_skip_factor = skip_factor;
ad0a8c2d 558
415302f4
EB
559 /* verify sane elev interval */
560 if ( vdl->max_elev <= vdl->min_elev )
561 vdl->max_elev = vdl->min_elev + 1;
562
f9518bc9
DRP
563 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 ) {
564 // NOTE: ( counter.lon <= end_lon + ESCALE_DEG*SKIP_FACTOR ) is neccessary so in high zoom modes,
565 // the leftmost column does also get drawn, if the center point is out of viewport.
566 if ( x >= 0 && x < dem->n_columns ) {
ad0a8c2d 567 column = g_ptr_array_index ( dem->columns, x );
f9518bc9
DRP
568 // get previous and next column. catch out-of-bound.
569 gint32 new_x = x;
570 new_x -= gradient_skip_factor;
571 if(new_x < 1)
572 prevcolumn = g_ptr_array_index ( dem->columns, x+1);
573 else
574 prevcolumn = g_ptr_array_index ( dem->columns, new_x);
575 new_x = x;
576 new_x += gradient_skip_factor;
577 if(new_x >= dem->n_columns)
578 nextcolumn = g_ptr_array_index ( dem->columns, x-1);
579 else
580 nextcolumn = g_ptr_array_index ( dem->columns, new_x);
c07088dd 581
ad0a8c2d
EB
582 for ( y=start_y, counter.lat = start_lat; counter.lat <= end_lat; counter.lat += nscale_deg * skip_factor, y += skip_factor ) {
583 if ( y > column->n_points )
584 break;
f9518bc9 585
ad0a8c2d 586 elev = column->points[y];
415302f4 587
f9518bc9
DRP
588 // calculate bounding box for drawing
589 gint box_x, box_y, box_width, box_height;
590 struct LatLon box_c;
591 box_c = counter;
592 box_c.lat += (nscale_deg * skip_factor)/2;
593 box_c.lon -= (escale_deg * skip_factor)/2;
594 vik_coord_load_from_latlon(&tmp, vik_viewport_get_coord_mode(vp), &box_c);
595 vik_viewport_coord_to_screen(vp, &tmp, &box_x, &box_y);
596 // catch box at borders
597 if(box_x < 0)
598 box_x = 0;
599 if(box_y < 0)
600 box_y = 0;
601 box_c.lat -= nscale_deg * skip_factor;
602 box_c.lon += escale_deg * skip_factor;
603 vik_coord_load_from_latlon(&tmp, vik_viewport_get_coord_mode(vp), &box_c);
604 vik_viewport_coord_to_screen(vp, &tmp, &box_width, &box_height);
605 box_width -= box_x;
606 box_height -= box_y;
607 // catch box at borders
608 if(box_width < 0 || box_height < 0)
609 continue; // skip this. this is out of our viewport anyway. FIXME: why?
610
7e74e26b 611 gboolean below_minimum = FALSE;
f9518bc9 612 if(vdl->type == DEM_TYPE_HEIGHT) {
7e74e26b 613 if ( elev != VIK_DEM_INVALID_ELEVATION && elev < vdl->min_elev ) {
104f8c15
RN
614 // Prevent 'elev - vdl->min_elev' from being negative so can safely use as array index
615 elev = ceil ( vdl->min_elev );
7e74e26b
RN
616 below_minimum = TRUE;
617 }
f9518bc9 618 if ( elev != VIK_DEM_INVALID_ELEVATION && elev > vdl->max_elev )
104f8c15 619 elev = vdl->max_elev;
f9518bc9 620 }
415302f4 621
ad0a8c2d 622 {
f9518bc9
DRP
623 if(box_width < 0 || box_height < 0) // FIXME: why does this happen?
624 continue;
625
626 if(vdl->type == DEM_TYPE_GRADIENT) {
627 if( elev == VIK_DEM_INVALID_ELEVATION ) {
628 /* don't draw it */
629 } else {
630 // calculate and sum gradient in all directions
631 gint16 change = 0;
632 gint32 new_y;
633
634 // calculate gradient from height points all around the current one
635 new_y = y - gradient_skip_factor;
636 if(new_y < 0)
637 new_y = y;
638 change += get_height_difference(elev, prevcolumn->points[new_y]);
639 change += get_height_difference(elev, column->points[new_y]);
640 change += get_height_difference(elev, nextcolumn->points[new_y]);
641
642 change += get_height_difference(elev, prevcolumn->points[y]);
643 change += get_height_difference(elev, nextcolumn->points[y]);
644
645 new_y = y + gradient_skip_factor;
646 if(new_y >= column->n_points)
647 new_y = y;
648 change += get_height_difference(elev, prevcolumn->points[new_y]);
649 change += get_height_difference(elev, column->points[new_y]);
650 change += get_height_difference(elev, nextcolumn->points[new_y]);
651
652 change = change / ((skip_factor > 1) ? log(skip_factor) : 0.55); // FIXME: better calc.
653
654 if(change < vdl->min_elev)
104f8c15
RN
655 // Prevent 'change - vdl->min_elev' from being negative so can safely use as array index
656 change = ceil ( vdl->min_elev );
f9518bc9
DRP
657
658 if(change > vdl->max_elev)
659 change = vdl->max_elev;
660
661 // void vik_viewport_draw_rectangle ( VikViewport *vvp, GdkGC *gc, gboolean filled, gint x1, gint y1, gint x2, gint y2 );
104f8c15 662 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 663 }
c07088dd 664 } else {
f9518bc9
DRP
665 if(vdl->type == DEM_TYPE_HEIGHT) {
666 if ( elev == VIK_DEM_INVALID_ELEVATION )
667 ; /* don't draw it */
7e74e26b
RN
668 else if ( elev <= 0 || below_minimum )
669 /* If 'sea' colour or below the defined mininum draw in the configurable colour */
f9518bc9
DRP
670 vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, box_x, box_y, box_width, box_height);
671 else
104f8c15 672 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
673 }
674 }
ad0a8c2d
EB
675 }
676 } /* for y= */
677 }
678 } /* for x= */
679 } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
680 gdouble max_nor, max_eas, min_nor, min_eas;
681 gdouble start_nor, start_eas, end_nor, end_eas;
682
683 gint16 elev;
684
685 guint x, y, start_x, start_y;
686
687 VikCoord tmp; /* TODO: don't use coord_load_from_latlon, especially if in latlon drawing mode */
688 struct UTM counter;
689
690 guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 10 ); /* todo: smarter calculation. */
691
0c1044e9
EB
692 VikCoord tleft, tright, bleft, bright;
693
694 vik_viewport_screen_to_coord ( vp, 0, 0, &tleft );
695 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), 0, &tright );
696 vik_viewport_screen_to_coord ( vp, 0, vik_viewport_get_height(vp), &bleft );
697 vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), vik_viewport_get_height(vp), &bright );
698
699
ad0a8c2d
EB
700 vik_coord_convert(&tleft, VIK_COORD_UTM);
701 vik_coord_convert(&tright, VIK_COORD_UTM);
702 vik_coord_convert(&bleft, VIK_COORD_UTM);
703 vik_coord_convert(&bright, VIK_COORD_UTM);
704
705 max_nor = MAX(tleft.north_south, tright.north_south);
706 min_nor = MIN(bleft.north_south, bright.north_south);
707 max_eas = MAX(bright.east_west, tright.east_west);
708 min_eas = MIN(bleft.east_west, tleft.east_west);
709
710 start_nor = MAX(min_nor, dem->min_north);
711 end_nor = MIN(max_nor, dem->max_north);
712 if ( tleft.utm_zone == dem->utm_zone && bleft.utm_zone == dem->utm_zone
713 && (tleft.utm_letter >= 'N') == (dem->utm_letter >= 'N')
714 && (bleft.utm_letter >= 'N') == (dem->utm_letter >= 'N') ) /* if the utm zones/hemispheres are different, min_eas will be bogus */
715 start_eas = MAX(min_eas, dem->min_east);
716 else
717 start_eas = dem->min_east;
718 if ( tright.utm_zone == dem->utm_zone && bright.utm_zone == dem->utm_zone
719 && (tright.utm_letter >= 'N') == (dem->utm_letter >= 'N')
720 && (bright.utm_letter >= 'N') == (dem->utm_letter >= 'N') ) /* if the utm zones/hemispheres are different, min_eas will be bogus */
721 end_eas = MIN(max_eas, dem->max_east);
722 else
723 end_eas = dem->max_east;
724
725 start_nor = floor(start_nor / dem->north_scale) * dem->north_scale;
726 end_nor = ceil (end_nor / dem->north_scale) * dem->north_scale;
727 start_eas = floor(start_eas / dem->east_scale) * dem->east_scale;
728 end_eas = ceil (end_eas / dem->east_scale) * dem->east_scale;
729
730 vik_dem_east_north_to_xy ( dem, start_eas, start_nor, &start_x, &start_y );
731
732 /* TODO: why start_x and start_y are -1 -- rounding error from above? */
733
734 counter.zone = dem->utm_zone;
735 counter.letter = dem->utm_letter;
736
737 for ( x=start_x, counter.easting = start_eas; counter.easting <= end_eas; counter.easting += dem->east_scale * skip_factor, x += skip_factor ) {
738 if ( x > 0 && x < dem->n_columns ) {
739 column = g_ptr_array_index ( dem->columns, x );
740 for ( y=start_y, counter.northing = start_nor; counter.northing <= end_nor; counter.northing += dem->north_scale * skip_factor, y += skip_factor ) {
741 if ( y > column->n_points )
742 continue;
743 elev = column->points[y];
415302f4
EB
744 if ( elev != VIK_DEM_INVALID_ELEVATION && elev < vdl->min_elev )
745 elev=vdl->min_elev;
746 if ( elev != VIK_DEM_INVALID_ELEVATION && elev > vdl->max_elev )
747 elev=vdl->max_elev;
748
ad0a8c2d
EB
749 {
750 gint a, b;
751 vik_coord_load_from_utm(&tmp, vik_viewport_get_coord_mode(vp), &counter);
752 vik_viewport_coord_to_screen(vp, &tmp, &a, &b);
753 if ( elev == VIK_DEM_INVALID_ELEVATION )
754 ; /* don't draw it */
755 else if ( elev <= 0 )
f9518bc9 756 vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, a-1, b-1, 2, 2 );
ad0a8c2d 757 else
f9518bc9 758 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
759 }
760 } /* for y= */
761 }
762 } /* for x= */
763 }
764}
765
0c1044e9
EB
766/* return the continent for the specified lat, lon */
767/* TODO */
0e25c0d0 768static const gchar *srtm_continent_dir ( gint lat, gint lon )
0c1044e9 769{
0e25c0d0
QT
770 extern const char *_srtm_continent_data[];
771 static GHashTable *srtm_continent = NULL;
772 const gchar *continent;
773 gchar name[16];
774
775 if (!srtm_continent) {
776 const gchar **s;
777
778 srtm_continent = g_hash_table_new(g_str_hash, g_str_equal);
779 s = _srtm_continent_data;
780 while (*s != (gchar *)-1) {
781 continent = *s++;
782 while (*s) {
0654760a 783 g_hash_table_insert(srtm_continent, (gpointer) *s, (gpointer) continent);
0e25c0d0
QT
784 s++;
785 }
786 s++;
787 }
788 }
789 g_snprintf(name, sizeof(name), "%c%02d%c%03d",
790 (lat >= 0) ? 'N' : 'S', ABS(lat),
791 (lon >= 0) ? 'E' : 'W', ABS(lon));
792
793 return(g_hash_table_lookup(srtm_continent, name));
0c1044e9
EB
794}
795
ad0a8c2d
EB
796void vik_dem_layer_draw ( VikDEMLayer *vdl, gpointer data )
797{
798 VikViewport *vp = (VikViewport *) data;
799 GList *dems_iter = vdl->files;
800 VikDEM *dem;
0c1044e9 801
0c1044e9
EB
802
803 /* search for SRTM3 90m */
8c721f83
EB
804
805 if ( vdl->source == DEM_SOURCE_SRTM )
806 srtm_draw_existence ( vp );
807#ifdef VIK_CONFIG_DEM24K
808 else if ( vdl->source == DEM_SOURCE_DEM24K )
809 dem24k_draw_existence ( vp );
810#endif
0c1044e9 811
ad0a8c2d
EB
812 while ( dems_iter ) {
813 dem = a_dems_get ( (const char *) (dems_iter->data) );
814 if ( dem )
815 vik_dem_layer_draw_dem ( vdl, vp, dem );
816 dems_iter = dems_iter->next;
817 }
818}
819
820void vik_dem_layer_free ( VikDEMLayer *vdl )
821{
fa86f1c0 822 gint i;
ad0a8c2d 823 if ( vdl->color != NULL )
7e74e26b 824 g_object_unref ( vdl->color );
ad0a8c2d 825
fa86f1c0 826 if ( vdl->gcs )
c07088dd 827 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ )
fa86f1c0
EB
828 g_object_unref ( vdl->gcs[i] );
829 g_free ( vdl->gcs );
830
c07088dd
DRP
831 if ( vdl->gcsgradient )
832 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
833 g_object_unref ( vdl->gcsgradient[i] );
834 g_free ( vdl->gcsgradient );
835
ad0a8c2d
EB
836 a_dems_list_free ( vdl->files );
837}
838
ad0a8c2d
EB
839VikDEMLayer *vik_dem_layer_create ( VikViewport *vp )
840{
841 VikDEMLayer *vdl = vik_dem_layer_new ();
fa86f1c0
EB
842 gint i;
843
844 /* TODO: share GCS between layers */
c07088dd 845 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ )
7e74e26b 846 vdl->gcs[i] = vik_viewport_new_gc ( vp, dem_height_colors[i], UNUSED_LINE_THICKNESS );
c07088dd
DRP
847
848 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
7e74e26b 849 vdl->gcsgradient[i] = vik_viewport_new_gc ( vp, dem_gradient_colors[i], UNUSED_LINE_THICKNESS );
fa86f1c0 850
ad0a8c2d
EB
851 return vdl;
852}
8c721f83
EB
853/**************************************************************
854 **** SOURCES & DOWNLOADING
855 **************************************************************/
856typedef struct {
857 gchar *dest;
858 gdouble lat, lon;
859
860 GMutex *mutex;
861 VikDEMLayer *vdl; /* NULL if not alive */
862
863 guint source;
864} DEMDownloadParams;
865
ad0a8c2d 866
0c1044e9 867/**************************************************
8c721f83
EB
868 * SOURCE: SRTM *
869 **************************************************/
870
871static void srtm_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
0c1044e9 872{
8c721f83 873 gint intlat, intlon;
0e25c0d0 874 const gchar *continent_dir;
8c721f83
EB
875
876 intlat = (int)floor(p->lat);
877 intlon = (int)floor(p->lon);
0e25c0d0
QT
878 continent_dir = srtm_continent_dir(intlat, intlon);
879
880 if (!continent_dir) {
4258f4e2 881 g_warning(N_("No SRTM data available for %f, %f"), p->lat, p->lon);
0e25c0d0
QT
882 return;
883 }
884
65a64219 885 gchar *src_fn = g_strdup_printf("%s%s/%c%02d%c%03d.hgt.zip",
e6c50657 886 SRTM_HTTP_URI,
0e25c0d0 887 continent_dir,
8c721f83
EB
888 (intlat >= 0) ? 'N' : 'S',
889 ABS(intlat),
890 (intlon >= 0) ? 'E' : 'W',
891 ABS(intlon) );
892
74fbca98 893 static DownloadMapOptions options = { FALSE, FALSE, NULL, 0, a_check_map_file };
825413ba 894 a_http_download_get_url ( SRTM_HTTP_SITE, src_fn, p->dest, &options, NULL );
8c721f83 895 g_free ( src_fn );
0c1044e9
EB
896}
897
8c721f83 898static gchar *srtm_lat_lon_to_dest_fn ( gdouble lat, gdouble lon )
0c1044e9 899{
8c721f83 900 gint intlat, intlon;
0e25c0d0
QT
901 const gchar *continent_dir;
902
8c721f83
EB
903 intlat = (int)floor(lat);
904 intlon = (int)floor(lon);
0e25c0d0
QT
905 continent_dir = srtm_continent_dir(intlat, intlon);
906
907 if (!continent_dir)
908 continent_dir = "nowhere";
909
910 return g_strdup_printf("srtm3-%s%s%c%02d%c%03d.hgt.zip",
911 continent_dir,
912 G_DIR_SEPARATOR_S,
8c721f83
EB
913 (intlat >= 0) ? 'N' : 'S',
914 ABS(intlat),
915 (intlon >= 0) ? 'E' : 'W',
916 ABS(intlon) );
0c1044e9 917
0c1044e9
EB
918}
919
8c721f83
EB
920/* TODO: generalize */
921static void srtm_draw_existence ( VikViewport *vp )
0c1044e9 922{
8c721f83
EB
923 gdouble max_lat, max_lon, min_lat, min_lon;
924 gchar buf[strlen(MAPS_CACHE_DIR)+strlen(SRTM_CACHE_TEMPLATE)+30];
925 gint i, j;
926
927 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
928
929 for (i = floor(min_lat); i <= floor(max_lat); i++) {
930 for (j = floor(min_lon); j <= floor(max_lon); j++) {
0e25c0d0
QT
931 const gchar *continent_dir;
932 if ((continent_dir = srtm_continent_dir(i, j)) == NULL)
933 continue;
8c721f83
EB
934 g_snprintf(buf, sizeof(buf), SRTM_CACHE_TEMPLATE,
935 MAPS_CACHE_DIR,
0e25c0d0
QT
936 continent_dir,
937 G_DIR_SEPARATOR_S,
8c721f83
EB
938 (i >= 0) ? 'N' : 'S',
939 ABS(i),
940 (j >= 0) ? 'E' : 'W',
941 ABS(j) );
45acf79e 942 if ( g_file_test(buf, G_FILE_TEST_EXISTS ) == TRUE ) {
8c721f83
EB
943 VikCoord ne, sw;
944 gint x1, y1, x2, y2;
945 sw.north_south = i;
946 sw.east_west = j;
947 sw.mode = VIK_COORD_LATLON;
948 ne.north_south = i+1;
949 ne.east_west = j+1;
950 ne.mode = VIK_COORD_LATLON;
951 vik_viewport_coord_to_screen ( vp, &sw, &x1, &y1 );
952 vik_viewport_coord_to_screen ( vp, &ne, &x2, &y2 );
953 if ( x1 < 0 ) x1 = 0;
954 if ( y2 < 0 ) y2 = 0;
955 vik_viewport_draw_rectangle ( vp, GTK_WIDGET(vp)->style->black_gc,
956 FALSE, x1, y2, x2-x1, y1-y2 );
957 }
958 }
959 }
0c1044e9
EB
960}
961
8c721f83
EB
962
963/**************************************************
964 * SOURCE: USGS 24K *
965 **************************************************/
966
967#ifdef VIK_CONFIG_DEM24K
968
969static void dem24k_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
0c1044e9 970{
8c721f83
EB
971 /* TODO: dest dir */
972 gchar *cmdline = g_strdup_printf("%s %.03f %.03f",
973 DEM24K_DOWNLOAD_SCRIPT,
974 floor(p->lat*8)/8,
975 ceil(p->lon*8)/8 );
976 /* FIX: don't use system, use execv or something. check for existence */
977 system(cmdline);
978}
0c1044e9 979
8c721f83
EB
980static gchar *dem24k_lat_lon_to_dest_fn ( gdouble lat, gdouble lon )
981{
982 return g_strdup_printf("dem24k/%d/%d/%.03f,%.03f.dem",
983 (gint) lat,
984 (gint) lon,
985 floor(lat*8)/8,
986 ceil(lon*8)/8);
987}
0c1044e9 988
8c721f83
EB
989/* TODO: generalize */
990static void dem24k_draw_existence ( VikViewport *vp )
991{
992 gdouble max_lat, max_lon, min_lat, min_lon;
993 gchar buf[strlen(MAPS_CACHE_DIR)+40];
994 gdouble i, j;
0c1044e9 995
8c721f83 996 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
0c1044e9 997
8c721f83
EB
998 for (i = floor(min_lat*8)/8; i <= floor(max_lat*8)/8; i+=0.125) {
999 /* check lat dir first -- faster */
1000 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/",
1001 MAPS_CACHE_DIR,
1002 (gint) i );
6b1a58ec 1003 if ( g_file_test(buf, G_FILE_TEST_EXISTS) == FALSE )
8c721f83
EB
1004 continue;
1005 for (j = floor(min_lon*8)/8; j <= floor(max_lon*8)/8; j+=0.125) {
1006 /* check lon dir first -- faster */
1007 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/%d/",
1008 MAPS_CACHE_DIR,
1009 (gint) i,
1010 (gint) j );
45acf79e 1011 if ( g_file_test(buf, G_FILE_TEST_EXISTS) == FALSE )
8c721f83
EB
1012 continue;
1013 g_snprintf(buf, sizeof(buf), "%sdem24k/%d/%d/%.03f,%.03f.dem",
1014 MAPS_CACHE_DIR,
1015 (gint) i,
1016 (gint) j,
1017 floor(i*8)/8,
1018 floor(j*8)/8 );
45acf79e 1019 if ( g_file_test(buf, G_FILE_TEST_EXISTS ) == TRUE ) {
8c721f83
EB
1020 VikCoord ne, sw;
1021 gint x1, y1, x2, y2;
1022 sw.north_south = i;
1023 sw.east_west = j-0.125;
1024 sw.mode = VIK_COORD_LATLON;
1025 ne.north_south = i+0.125;
1026 ne.east_west = j;
1027 ne.mode = VIK_COORD_LATLON;
1028 vik_viewport_coord_to_screen ( vp, &sw, &x1, &y1 );
1029 vik_viewport_coord_to_screen ( vp, &ne, &x2, &y2 );
1030 if ( x1 < 0 ) x1 = 0;
1031 if ( y2 < 0 ) y2 = 0;
1032 vik_viewport_draw_rectangle ( vp, GTK_WIDGET(vp)->style->black_gc,
1033 FALSE, x1, y2, x2-x1, y1-y2 );
1034 }
1035 }
1036 }
1037}
1038#endif
0c1044e9 1039
8c721f83
EB
1040/**************************************************
1041 * SOURCES -- DOWNLOADING & IMPORTING TOOL *
1042 **************************************************
1043 */
0c1044e9 1044
8c721f83
EB
1045static void weak_ref_cb ( gpointer ptr, GObject * dead_vdl )
1046{
1047 DEMDownloadParams *p = ptr;
1048 g_mutex_lock ( p->mutex );
1049 p->vdl = NULL;
1050 g_mutex_unlock ( p->mutex );
1051}
0c1044e9 1052
8c721f83
EB
1053/* Try to add file full_path.
1054 * full_path will be copied.
1055 * returns FALSE if file does not exists, TRUE otherwise.
1056 */
1057static gboolean dem_layer_add_file ( VikDEMLayer *vdl, const gchar *full_path )
1058{
45acf79e 1059 if ( g_file_test(full_path, G_FILE_TEST_EXISTS ) == TRUE ) {
b01c3429 1060 /* only load if file size is not 0 (not in progress) */
0c1044e9 1061 struct stat sb;
8c721f83 1062 stat (full_path, &sb);
0c1044e9 1063 if ( sb.st_size ) {
8c721f83
EB
1064 gchar *duped_path = g_strdup(full_path);
1065 vdl->files = g_list_prepend ( vdl->files, duped_path );
1066 a_dems_load ( duped_path );
b01c3429 1067 g_debug("%s: %s", __FUNCTION__, duped_path);
8c721f83 1068 vik_layer_emit_update ( VIK_LAYER(vdl) );
0c1044e9 1069 }
8c721f83
EB
1070 return TRUE;
1071 } else
1072 return FALSE;
1073}
1074
1075static void dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
1076{
1077 if ( p->source == DEM_SOURCE_SRTM )
1078 srtm_dem_download_thread ( p, threaddata );
1079#ifdef VIK_CONFIG_DEM24K
1080 else if ( p->source == DEM_SOURCE_DEM24K )
1081 dem24k_dem_download_thread ( p, threaddata );
1082#endif
1083
1084 gdk_threads_enter();
1085 g_mutex_lock ( p->mutex );
1086 if ( p->vdl ) {
1087 g_object_weak_unref ( G_OBJECT(p->vdl), weak_ref_cb, p );
1088
1089 if ( dem_layer_add_file ( p->vdl, p->dest ) )
1090 vik_layer_emit_update ( VIK_LAYER(p->vdl) );
1091 }
1092 g_mutex_unlock ( p->mutex );
1093 gdk_threads_leave();
1094}
1095
1096
1097static void free_dem_download_params ( DEMDownloadParams *p )
1098{
1099 g_mutex_free ( p->mutex );
1100 g_free ( p->dest );
1101 g_free ( p );
1102}
1103
1104static gpointer dem_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1105{
1106 return vvp;
1107}
1108
1109
1110static gboolean dem_layer_download_release ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp )
1111{
1112 VikCoord coord;
1113 struct LatLon ll;
1114
1115 gchar *full_path;
1116 gchar *dem_file = NULL;
1117
8c721f83 1118 if ( vdl->source == DEM_SOURCE_NONE )
4c77d5e0 1119 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vdl), _("No download source selected. Edit layer properties.") );
8c721f83
EB
1120
1121 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1122 vik_coord_to_latlon ( &coord, &ll );
1123
1124
1125 if ( vdl->source == DEM_SOURCE_SRTM )
1126 dem_file = srtm_lat_lon_to_dest_fn ( ll.lat, ll.lon );
1127#ifdef VIK_CONFIG_DEM24K
1128 else if ( vdl->source == DEM_SOURCE_DEM24K )
1129 dem_file = dem24k_lat_lon_to_dest_fn ( ll.lat, ll.lon );
1130#endif
1131
1132 if ( ! dem_file )
1133 return TRUE;
1134
1135 full_path = g_strdup_printf("%s%s", MAPS_CACHE_DIR, dem_file );
1136
b01c3429 1137 g_debug("%s: %s", __FUNCTION__, full_path);
8c721f83
EB
1138
1139 // TODO: check if already in filelist
1140
1141 if ( ! dem_layer_add_file(vdl, full_path) ) {
4c77d5e0 1142 gchar *tmp = g_strdup_printf ( _("Downloading DEM %s"), dem_file );
8c721f83
EB
1143 DEMDownloadParams *p = g_malloc(sizeof(DEMDownloadParams));
1144 p->dest = g_strdup(full_path);
1145 p->lat = ll.lat;
1146 p->lon = ll.lon;
1147 p->vdl = vdl;
1148 p->mutex = g_mutex_new();
1149 p->source = vdl->source;
1150 g_object_weak_ref(G_OBJECT(p->vdl), weak_ref_cb, p );
1151
1152 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vdl), tmp,
1153 (vik_thr_func) dem_download_thread, p,
1154 (vik_thr_free_func) free_dem_download_params, NULL, 1 );
2ca82974
RN
1155
1156 g_free ( tmp );
0c1044e9
EB
1157 }
1158
8c721f83
EB
1159 g_free ( dem_file );
1160 g_free ( full_path );
1161
0c1044e9
EB
1162 return TRUE;
1163}
1164
1165static gboolean dem_layer_download_click ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp )
1166{
1167/* choose & keep track of cache dir
1168 * download in background thread
1169 * download over area */
1170 return TRUE;
1171}
1172
1173