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