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