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