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