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