]> git.street.me.uk Git - andy/viking.git/blame_incremental - src/vikdemlayer.c
Prevent Gtk-CRITICAL **: gtk_list_store_get_path: assertion `iter->stamp == GTK_LIST_...
[andy/viking.git] / src / vikdemlayer.c
... / ...
CommitLineData
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 */
21#ifdef HAVE_CONFIG_H
22#include "config.h"
23#endif
24
25#ifdef HAVE_MATH_H
26#include <math.h>
27#endif
28#ifdef HAVE_SYS_TYPES_H
29#include <sys/types.h>
30#endif
31#ifdef HAVE_SYS_STAT_H
32#include <sys/stat.h>
33#endif
34#ifdef HAVE_STRING_H
35#include <string.h>
36#endif
37#include <stdlib.h>
38#include <glib/gi18n.h>
39
40#include "config.h"
41#include "globals.h"
42#include "coords.h"
43#include "vikcoord.h"
44#include "download.h"
45#include "background.h"
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"
53#include "vikmapslayer.h"
54#include "vikdemlayer.h"
55#include "dialog.h"
56
57#include "dem.h"
58#include "dems.h"
59
60#include "icons/icons.h"
61
62#define MAPS_CACHE_DIR maps_layer_default_dir()
63
64#define SRTM_CACHE_TEMPLATE "%ssrtm3-%s%s%c%02d%c%03d.hgt.zip"
65#define SRTM_HTTP_SITE "dds.cr.usgs.gov"
66#define SRTM_HTTP_URI "/srtm/version2_1/SRTM3/"
67
68#ifdef VIK_CONFIG_DEM24K
69#define DEM24K_DOWNLOAD_SCRIPT "dem24k.pl"
70#endif
71
72#define UNUSED_LINE_THICKNESS 3
73
74static const gchar* dem_layer_tooltip( VikDEMLayer *vdl );
75static void dem_layer_marshall( VikDEMLayer *vdl, guint8 **data, gint *len );
76static VikDEMLayer *dem_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
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 );
79static void dem_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file );
80static void srtm_draw_existence ( VikViewport *vp );
81
82#ifdef VIK_CONFIG_DEM24K
83static void dem24k_draw_existence ( VikViewport *vp );
84#endif
85
86/* Upped upper limit incase units are feet */
87static VikLayerParamScale param_scales[] = {
88 { 0, 30000, 10, 1 },
89 { 1, 30000, 10, 1 },
90};
91
92static gchar *params_source[] = {
93 "SRTM Global 90m (3 arcsec)",
94#ifdef VIK_CONFIG_DEM24K
95 "USA 10m (USGS 24k)",
96#endif
97 "None",
98 NULL
99 };
100
101static gchar *params_type[] = {
102 N_("Absolute height"),
103 N_("Height gradient"),
104 NULL
105};
106
107enum { DEM_SOURCE_SRTM,
108#ifdef VIK_CONFIG_DEM24K
109 DEM_SOURCE_DEM24K,
110#endif
111 DEM_SOURCE_NONE,
112 };
113
114enum { DEM_TYPE_HEIGHT = 0,
115 DEM_TYPE_GRADIENT,
116 DEM_TYPE_NONE,
117};
118
119static VikLayerParam dem_layer_params[] = {
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 },
122 { "color", VIK_LAYER_PARAM_COLOR, VIK_LAYER_GROUP_NONE, N_("Min Elev Color:"), VIK_LAYER_WIDGET_COLOR, 0 },
123 { "type", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Type:"), VIK_LAYER_WIDGET_RADIOGROUP_STATIC, params_type, NULL },
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 },
126};
127
128
129enum { PARAM_FILES=0, PARAM_SOURCE, PARAM_COLOR, PARAM_TYPE, PARAM_MIN_ELEV, PARAM_MAX_ELEV, NUM_PARAMS };
130
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[] = {
136 { N_("DEM Download/Import"), (VikToolConstructorFunc) dem_layer_download_create, NULL, NULL, NULL,
137 (VikToolMouseFunc) dem_layer_download_click, NULL, (VikToolMouseFunc) dem_layer_download_release,
138 (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_demdl_pixbuf },
139};
140
141
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.
146*/
147static gchar *dem_height_colors[] = {
148"#0000FF",
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"
157};
158
159static const guint DEM_N_HEIGHT_COLORS = sizeof(dem_height_colors)/sizeof(dem_height_colors[0]);
160
161/*
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"
165};
166*/
167
168static gchar *dem_gradient_colors[] = {
169"#AAAAAA",
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]);
183
184
185VikLayerInterface vik_dem_layer_interface = {
186 "DEM",
187 &vikdemlayer_pixbuf,
188
189 dem_tools,
190 sizeof(dem_tools) / sizeof(dem_tools[0]),
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,
201 (VikLayerFuncPostRead) dem_layer_post_read,
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,
216 (VikLayerFuncSublayerTooltip) NULL,
217 (VikLayerFuncLayerTooltip) dem_layer_tooltip,
218
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;
237 GdkGC **gcs;
238 GdkGC **gcsgradient;
239 GList *files;
240 gdouble min_elev;
241 gdouble max_elev;
242 GdkGC *color;
243 guint source;
244 guint type;
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
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
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{
285 VikDEMLayer *rv = vik_dem_layer_new ();
286 gint i;
287
288 /* TODO: share GCS between layers */
289 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ )
290 rv->gcs[i] = vik_viewport_new_gc ( vvp, dem_height_colors[i], UNUSED_LINE_THICKNESS );
291
292 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
293 rv->gcsgradient[i] = vik_viewport_new_gc ( vvp, dem_gradient_colors[i], UNUSED_LINE_THICKNESS );
294
295 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
296 return rv;
297}
298
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 // 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) );
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
340gboolean dem_layer_set_param ( VikDEMLayer *vdl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
341{
342 switch ( id )
343 {
344 case PARAM_COLOR: gdk_gc_set_rgb_fg_color ( vdl->gcs[0], &(data.c) ); break;
345 case PARAM_SOURCE: vdl->source = data.u; break;
346 case PARAM_TYPE: vdl->type = data.u; break;
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 )
351 vdl->min_elev = VIK_FEET_TO_METERS(data.d);
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 )
359 vdl->max_elev = VIK_FEET_TO_METERS(data.d);
360 else
361 vdl->max_elev = data.d;
362 break;
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 }
383 }
384 return TRUE;
385}
386
387static VikLayerParamData dem_layer_get_param ( VikDEMLayer *vdl, guint16 id, gboolean is_file_operation )
388{
389 VikLayerParamData rv;
390 switch ( id )
391 {
392 case PARAM_FILES: rv.sl = vdl->files; break;
393 case PARAM_SOURCE: rv.u = vdl->source; break;
394 case PARAM_TYPE: rv.u = vdl->type; break;
395 case PARAM_COLOR: vik_gc_get_fg_color ( vdl->gcs[0], &(rv.c) ); break;
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 )
400 rv.d = VIK_METERS_TO_FEET(vdl->min_elev);
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 )
408 rv.d = VIK_METERS_TO_FEET(vdl->max_elev);
409 else
410 rv.d = vdl->max_elev;
411 break;
412 }
413 return rv;
414}
415
416static void dem_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file )
417{
418 /* nothing ATM, but keep in case it's needed the future */
419}
420
421VikDEMLayer *vik_dem_layer_new ( )
422{
423 VikDEMLayer *vdl = VIK_DEM_LAYER ( g_object_new ( VIK_DEM_LAYER_TYPE, NULL ) );
424
425 vik_layer_init ( VIK_LAYER(vdl), VIK_LAYER_DEM );
426
427 vdl->files = NULL;
428
429 vdl->gcs = g_malloc(sizeof(GdkGC *)*DEM_N_HEIGHT_COLORS);
430 vdl->gcsgradient = g_malloc(sizeof(GdkGC *)*DEM_N_GRADIENT_COLORS);
431 /* make new gcs only if we need it (copy layer -> use old) */
432
433 vdl->min_elev = 0.0;
434 vdl->max_elev = 1000.0;
435 vdl->source = DEM_SOURCE_SRTM;
436 vdl->type = DEM_TYPE_HEIGHT;
437 return vdl;
438}
439
440
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
449
450static void vik_dem_layer_draw_dem ( VikDEMLayer *vdl, VikViewport *vp, VikDEM *dem )
451{
452 VikDEMColumn *column, *prevcolumn, *nextcolumn;
453
454 struct LatLon dem_northeast, dem_southwest;
455 gdouble max_lat, max_lon, min_lat, min_lon;
456
457 /**** Check if viewport and DEM data overlap ****/
458
459 /* get min, max lat/lon of viewport */
460 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
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 ****/
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 );
514 return;
515 }
516 #endif
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
532 guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 80 ); /* todo: smarter calculation. */
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 );
553 guint gradient_skip_factor = 1;
554 if(vdl->type == DEM_TYPE_GRADIENT)
555 gradient_skip_factor = skip_factor;
556
557 /* verify sane elev interval */
558 if ( vdl->max_elev <= vdl->min_elev )
559 vdl->max_elev = vdl->min_elev + 1;
560
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 ) {
565 column = g_ptr_array_index ( dem->columns, x );
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);
579
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;
583
584 elev = column->points[y];
585
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
609 gboolean below_minimum = FALSE;
610 if(vdl->type == DEM_TYPE_HEIGHT) {
611 if ( elev != VIK_DEM_INVALID_ELEVATION && elev < vdl->min_elev ) {
612 // Prevent 'elev - vdl->min_elev' from being negative so can safely use as array index
613 elev = ceil ( vdl->min_elev );
614 below_minimum = TRUE;
615 }
616 if ( elev != VIK_DEM_INVALID_ELEVATION && elev > vdl->max_elev )
617 elev = vdl->max_elev;
618 }
619
620 {
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)
653 // Prevent 'change - vdl->min_elev' from being negative so can safely use as array index
654 change = ceil ( vdl->min_elev );
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 );
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);
661 }
662 } else {
663 if(vdl->type == DEM_TYPE_HEIGHT) {
664 if ( elev == VIK_DEM_INVALID_ELEVATION )
665 ; /* don't draw it */
666 else if ( elev <= 0 || below_minimum )
667 /* If 'sea' colour or below the defined mininum draw in the configurable colour */
668 vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, box_x, box_y, box_width, box_height);
669 else
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);
671 }
672 }
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
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
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];
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
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 )
754 vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, a-1, b-1, 2, 2 );
755 else
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 );
757 }
758 } /* for y= */
759 }
760 } /* for x= */
761 }
762}
763
764/* return the continent for the specified lat, lon */
765/* TODO */
766static const gchar *srtm_continent_dir ( gint lat, gint lon )
767{
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) {
781 g_hash_table_insert(srtm_continent, (gpointer) *s, (gpointer) continent);
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));
792}
793
794void vik_dem_layer_draw ( VikDEMLayer *vdl, gpointer data )
795{
796 VikViewport *vp = (VikViewport *) data;
797 GList *dems_iter = vdl->files;
798 VikDEM *dem;
799
800
801 /* search for SRTM3 90m */
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
809
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{
820 gint i;
821 if ( vdl->color != NULL )
822 g_object_unref ( vdl->color );
823
824 if ( vdl->gcs )
825 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ )
826 g_object_unref ( vdl->gcs[i] );
827 g_free ( vdl->gcs );
828
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
834 a_dems_list_free ( vdl->files );
835}
836
837VikDEMLayer *vik_dem_layer_create ( VikViewport *vp )
838{
839 VikDEMLayer *vdl = vik_dem_layer_new ();
840 gint i;
841
842 /* TODO: share GCS between layers */
843 for ( i = 0; i < DEM_N_HEIGHT_COLORS; i++ )
844 vdl->gcs[i] = vik_viewport_new_gc ( vp, dem_height_colors[i], UNUSED_LINE_THICKNESS );
845
846 for ( i = 0; i < DEM_N_GRADIENT_COLORS; i++ )
847 vdl->gcsgradient[i] = vik_viewport_new_gc ( vp, dem_gradient_colors[i], UNUSED_LINE_THICKNESS );
848
849 return vdl;
850}
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
864
865/**************************************************
866 * SOURCE: SRTM *
867 **************************************************/
868
869static void srtm_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
870{
871 gint intlat, intlon;
872 const gchar *continent_dir;
873
874 intlat = (int)floor(p->lat);
875 intlon = (int)floor(p->lon);
876 continent_dir = srtm_continent_dir(intlat, intlon);
877
878 if (!continent_dir) {
879 g_warning(N_("No SRTM data available for %f, %f"), p->lat, p->lon);
880 return;
881 }
882
883 gchar *src_fn = g_strdup_printf("%s%s/%c%02d%c%03d.hgt.zip",
884 SRTM_HTTP_URI,
885 continent_dir,
886 (intlat >= 0) ? 'N' : 'S',
887 ABS(intlat),
888 (intlon >= 0) ? 'E' : 'W',
889 ABS(intlon) );
890
891 static DownloadMapOptions options = { FALSE, FALSE, NULL, 0, a_check_map_file };
892 a_http_download_get_url ( SRTM_HTTP_SITE, src_fn, p->dest, &options, NULL );
893 g_free ( src_fn );
894}
895
896static gchar *srtm_lat_lon_to_dest_fn ( gdouble lat, gdouble lon )
897{
898 gint intlat, intlon;
899 const gchar *continent_dir;
900
901 intlat = (int)floor(lat);
902 intlon = (int)floor(lon);
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,
911 (intlat >= 0) ? 'N' : 'S',
912 ABS(intlat),
913 (intlon >= 0) ? 'E' : 'W',
914 ABS(intlon) );
915
916}
917
918/* TODO: generalize */
919static void srtm_draw_existence ( VikViewport *vp )
920{
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++) {
929 const gchar *continent_dir;
930 if ((continent_dir = srtm_continent_dir(i, j)) == NULL)
931 continue;
932 g_snprintf(buf, sizeof(buf), SRTM_CACHE_TEMPLATE,
933 MAPS_CACHE_DIR,
934 continent_dir,
935 G_DIR_SEPARATOR_S,
936 (i >= 0) ? 'N' : 'S',
937 ABS(i),
938 (j >= 0) ? 'E' : 'W',
939 ABS(j) );
940 if ( g_file_test(buf, G_FILE_TEST_EXISTS ) == TRUE ) {
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 }
958}
959
960
961/**************************************************
962 * SOURCE: USGS 24K *
963 **************************************************/
964
965#ifdef VIK_CONFIG_DEM24K
966
967static void dem24k_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
968{
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}
977
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}
986
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;
993
994 vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
995
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 );
1001 if ( g_file_test(buf, G_FILE_TEST_EXISTS) == FALSE )
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 );
1009 if ( g_file_test(buf, G_FILE_TEST_EXISTS) == FALSE )
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 );
1017 if ( g_file_test(buf, G_FILE_TEST_EXISTS ) == TRUE ) {
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
1037
1038/**************************************************
1039 * SOURCES -- DOWNLOADING & IMPORTING TOOL *
1040 **************************************************
1041 */
1042
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}
1050
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{
1057 if ( g_file_test(full_path, G_FILE_TEST_EXISTS ) == TRUE ) {
1058 /* only load if file size is not 0 (not in progress) */
1059 struct stat sb;
1060 stat (full_path, &sb);
1061 if ( sb.st_size ) {
1062 gchar *duped_path = g_strdup(full_path);
1063 vdl->files = g_list_prepend ( vdl->files, duped_path );
1064 a_dems_load ( duped_path );
1065 g_debug("%s: %s", __FUNCTION__, duped_path);
1066 vik_layer_emit_update ( VIK_LAYER(vdl) );
1067 }
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
1116 if ( vdl->source == DEM_SOURCE_NONE )
1117 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vdl), _("No download source selected. Edit layer properties.") );
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
1135 g_debug("%s: %s", __FUNCTION__, full_path);
1136
1137 // TODO: check if already in filelist
1138
1139 if ( ! dem_layer_add_file(vdl, full_path) ) {
1140 gchar *tmp = g_strdup_printf ( _("Downloading DEM %s"), dem_file );
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 );
1153
1154 g_free ( tmp );
1155 }
1156
1157 g_free ( dem_file );
1158 g_free ( full_path );
1159
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