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