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