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