]> git.street.me.uk Git - andy/viking.git/blobdiff - src/vikdemlayer.c
Remove dependencies to gob2
[andy/viking.git] / src / vikdemlayer.c
index 9adc37bcf0cbe6f6e35ac52772cdb801e2ed207c..bfe51ab2395e025793e04940f64aeca83e17f31f 100644 (file)
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
 #include <math.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdlib.h>
+#include <glib/gi18n.h>
 
+#include "config.h"
 #include "globals.h"
 #include "coords.h"
 #include "vikcoord.h"
 #include "download.h"
+#include "background.h"
 #include "vikwaypoint.h"
 #include "viktrack.h"
 #include "vikviewport.h"
 #include "vikaggregatelayer.h"
 #include "viklayerspanel.h"
 #include "vikdemlayer.h"
-#include "vikdemlayer_pixmap.h"
+#include "dialog.h"
 
 #include "dem.h"
 #include "dems.h"
 
-static VikDEMLayer *dem_layer_copy ( VikDEMLayer *vdl, gpointer vp );
+#include "icons/icons.h"
+
+#define MAPS_CACHE_DIR maps_layer_default_dir()
+
+#define SRTM_CACHE_TEMPLATE "%ssrtm3-%s%s%c%02d%c%03d.hgt.zip"
+#define SRTM_FTP_SITE "e0srp01u.ecs.nasa.gov"
+#define SRTM_FTP_URI  "/srtm/version2/SRTM3/"
+
+#ifdef VIK_CONFIG_DEM24K
+#define DEM24K_DOWNLOAD_SCRIPT "dem24k.pl"
+#endif
+
+
 static void dem_layer_marshall( VikDEMLayer *vdl, guint8 **data, gint *len );
 static VikDEMLayer *dem_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
 static gboolean dem_layer_set_param ( VikDEMLayer *vdl, guint16 id, VikLayerParamData data, VikViewport *vp );
 static VikLayerParamData dem_layer_get_param ( VikDEMLayer *vdl, guint16 id );
 static void dem_layer_update_gc ( VikDEMLayer *vdl, VikViewport *vp, const gchar *color );
-static void dem_layer_post_read ( VikLayer *vl, VikViewport *vp );
+static void dem_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file );
+static void srtm_draw_existence ( VikViewport *vp );
+
+#ifdef VIK_CONFIG_DEM24K
+static void dem24k_draw_existence ( VikViewport *vp );
+#endif
 
 static VikLayerParamScale param_scales[] = {
+  { 1, 10000, 10, 1 },
   { 1, 10000, 10, 1 },
   { 1, 10, 1, 0 },
 };
 
+static gchar *params_source[] = {
+       "SRTM Global 90m (3 arcsec)",
+#ifdef VIK_CONFIG_DEM24K
+       "USA 10m (USGS 24k)",
+#endif
+        "None",
+       NULL
+       };
+
+enum { DEM_SOURCE_SRTM,
+#ifdef VIK_CONFIG_DEM24K
+       DEM_SOURCE_DEM24K,
+#endif
+       DEM_SOURCE_NONE,
+     };
+
 static VikLayerParam dem_layer_params[] = {
-  { "files", VIK_LAYER_PARAM_STRING_LIST, VIK_LAYER_GROUP_NONE, "DEM Files:", VIK_LAYER_WIDGET_FILELIST },
-  { "color", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, "Color:", VIK_LAYER_WIDGET_ENTRY },
-  { "max_elev", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_GROUP_NONE, "Max Elev:", VIK_LAYER_WIDGET_SPINBUTTON, param_scales + 0 },
-  { "line_thickness", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, "Line Thickness:", VIK_LAYER_WIDGET_SPINBUTTON, param_scales + 1 },
+  { "files", VIK_LAYER_PARAM_STRING_LIST, VIK_LAYER_GROUP_NONE, N_("DEM Files:"), VIK_LAYER_WIDGET_FILELIST },
+  { "source", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Download Source:"), VIK_LAYER_WIDGET_RADIOGROUP_STATIC, params_source, NULL },
+  { "color", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Color:"), VIK_LAYER_WIDGET_ENTRY },
+  { "min_elev", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_GROUP_NONE, N_("Min Elev:"), VIK_LAYER_WIDGET_SPINBUTTON, param_scales + 0 },
+  { "max_elev", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_GROUP_NONE, N_("Max Elev:"), VIK_LAYER_WIDGET_SPINBUTTON, param_scales + 0 },
+  { "line_thickness", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Line Thickness:"), VIK_LAYER_WIDGET_SPINBUTTON, param_scales + 1 },
+};
+
+
+enum { PARAM_FILES=0, PARAM_SOURCE, PARAM_COLOR, PARAM_MIN_ELEV, PARAM_MAX_ELEV, PARAM_LINE_THICKNESS, NUM_PARAMS };
+
+static gpointer dem_layer_download_create ( VikWindow *vw, VikViewport *vvp);
+static gboolean dem_layer_download_release ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp );
+static gboolean dem_layer_download_click ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp );
+
+static VikToolInterface dem_tools[] = {
+  { N_("DEM Download/Import"), (VikToolConstructorFunc) dem_layer_download_create, NULL, NULL, NULL,
+    (VikToolMouseFunc) dem_layer_download_click, NULL,  (VikToolMouseFunc) dem_layer_download_release,
+    (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_demdl_pixbuf },
 };
 
+
 /*
 */
 
-
 static gchar *dem_colors[] = {
 "#0000FF",
 "#9b793c",
@@ -167,16 +226,15 @@ static gchar *dem_colors[] = {
 };
 */
 
-static const guint dem_n_colors = sizeof(dem_colors)/sizeof(dem_colors[0]);
+static const guint DEM_N_COLORS = sizeof(dem_colors)/sizeof(dem_colors[0]);
 
-enum { PARAM_FILES=0, PARAM_COLOR, PARAM_MAX_ELEV, PARAM_LINE_THICKNESS, NUM_PARAMS };
 
 VikLayerInterface vik_dem_layer_interface = {
   "DEM",
-  &demlayer_pixbuf,
+  &vikdemlayer_pixbuf,
 
-  NULL,
-  0,
+  dem_tools,
+  sizeof(dem_tools) / sizeof(dem_tools[0]),
 
   dem_layer_params,
   NUM_PARAMS,
@@ -203,7 +261,6 @@ VikLayerInterface vik_dem_layer_interface = {
   (VikLayerFuncSublayerRenameRequest)   NULL,
   (VikLayerFuncSublayerToggleVisible)   NULL,
 
-  (VikLayerFuncCopy)                    dem_layer_copy,
   (VikLayerFuncMarshall)               dem_layer_marshall,
   (VikLayerFuncUnmarshall)             dem_layer_unmarshall,
 
@@ -225,9 +282,11 @@ struct _VikDEMLayer {
   GdkGC *gc;
   GdkGC **gcs;
   GList *files;
+  gdouble min_elev;
   gdouble max_elev;
   guint8 line_thickness;
   gchar *color;
+  guint source;
 };
 
 GType vik_dem_layer_get_type ()
@@ -254,21 +313,6 @@ GType vik_dem_layer_get_type ()
   return vdl_type;
 }
 
-static VikDEMLayer *dem_layer_copy ( VikDEMLayer *vdl, gpointer vp )
-{
-  VikDEMLayer *rv = vik_dem_layer_new ( );
-
-
-  /* TODO -- FIX for files */
-
-  rv->color = g_strdup ( vdl->color );
-  rv->max_elev = vdl->max_elev;
-  rv->line_thickness = vdl->line_thickness;
-  rv->gc = vdl->gc;
-  g_object_ref ( rv->gc );
-  return rv;
-}
-
 static void dem_layer_marshall( VikDEMLayer *vdl, guint8 **data, gint *len )
 {
   vik_layer_marshall_params ( VIK_LAYER(vdl), data, len );
@@ -276,7 +320,13 @@ static void dem_layer_marshall( VikDEMLayer *vdl, guint8 **data, gint *len )
 
 static VikDEMLayer *dem_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
 {
-  VikDEMLayer *rv = vik_dem_layer_new ( vvp );
+  VikDEMLayer *rv = vik_dem_layer_new ();
+  gint i;
+
+  /* TODO: share GCS between layers */
+  for ( i = 0; i < DEM_N_COLORS; i++ )
+    rv->gcs[i] = vik_viewport_new_gc ( vvp, dem_colors[i], rv->line_thickness );
+
   vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
   return rv;
 }
@@ -286,6 +336,8 @@ gboolean dem_layer_set_param ( VikDEMLayer *vdl, guint16 id, VikLayerParamData d
   switch ( id )
   {
     case PARAM_COLOR: if ( vdl->color ) g_free ( vdl->color ); vdl->color = g_strdup ( data.s ); break;
+    case PARAM_SOURCE: vdl->source = data.u; break;
+    case PARAM_MIN_ELEV: vdl->min_elev = data.d; break;
     case PARAM_MAX_ELEV: vdl->max_elev = data.d; break;
     case PARAM_LINE_THICKNESS: if ( data.u >= 1 && data.u <= 15 ) vdl->line_thickness = data.u; break;
     case PARAM_FILES: a_dems_load_list ( &(data.sl) ); a_dems_list_free ( vdl->files ); vdl->files = data.sl; break;
@@ -299,14 +351,16 @@ static VikLayerParamData dem_layer_get_param ( VikDEMLayer *vdl, guint16 id )
   switch ( id )
   {
     case PARAM_FILES: rv.sl = vdl->files; break;
+    case PARAM_SOURCE: rv.u = vdl->source; break;
     case PARAM_COLOR: rv.s = vdl->color ? vdl->color : ""; break;
+    case PARAM_MIN_ELEV: rv.d = vdl->min_elev; break;
     case PARAM_MAX_ELEV: rv.d = vdl->max_elev; break;
     case PARAM_LINE_THICKNESS: rv.i = vdl->line_thickness; break;
   }
   return rv;
 }
 
-static void dem_layer_post_read ( VikLayer *vl, VikViewport *vp )
+static void dem_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_file )
 {
   VikDEMLayer *vdl = VIK_DEM_LAYER(vl);
   if ( vdl->gc )
@@ -318,6 +372,7 @@ static void dem_layer_post_read ( VikLayer *vl, VikViewport *vp )
 VikDEMLayer *vik_dem_layer_new ( )
 {
   VikDEMLayer *vdl = VIK_DEM_LAYER ( g_object_new ( VIK_DEM_LAYER_TYPE, NULL ) );
+
   vik_layer_init ( VIK_LAYER(vdl), VIK_LAYER_DEM );
 
   vdl->files = NULL;
@@ -325,41 +380,30 @@ VikDEMLayer *vik_dem_layer_new ( )
 
   vdl->gc = NULL;
 
-  vdl->gcs = g_malloc(sizeof(GdkGC *)*dem_n_colors);
+  vdl->gcs = g_malloc(sizeof(GdkGC *)*DEM_N_COLORS);
+  /* make new gcs only if we need it (copy layer -> use old) */
 
+  vdl->min_elev = 0.0;
   vdl->max_elev = 1000.0;
+  vdl->source = DEM_SOURCE_SRTM;
   vdl->line_thickness = 3;
   vdl->color = NULL;
   return vdl;
 }
 
 
+
 static void vik_dem_layer_draw_dem ( VikDEMLayer *vdl, VikViewport *vp, VikDEM *dem )
 {
-  VikCoord tleft, tright, bleft, bright;
   VikDEMColumn *column;
 
   struct LatLon dem_northeast, dem_southwest;
   gdouble max_lat, max_lon, min_lat, min_lon;  
 
-
   /**** Check if viewport and DEM data overlap ****/
 
   /* get min, max lat/lon of viewport */
-  vik_viewport_screen_to_coord ( vp, 0, 0, &tleft );
-  vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), 0, &tright );
-  vik_viewport_screen_to_coord ( vp, 0, vik_viewport_get_height(vp), &bleft );
-  vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), vik_viewport_get_height(vp), &bright );
-
-  vik_coord_convert(&tleft, VIK_COORD_LATLON);
-  vik_coord_convert(&tright, VIK_COORD_LATLON);
-  vik_coord_convert(&bleft, VIK_COORD_LATLON);
-  vik_coord_convert(&bright, VIK_COORD_LATLON);
-
-  max_lat = MAX(tleft.north_south, tright.north_south);
-  min_lat = MIN(bleft.north_south, bright.north_south);
-  max_lon = MAX(tright.east_west, bright.east_west);
-  min_lon = MIN(tleft.east_west, bleft.east_west);
+  vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
 
   /* get min, max lat/lon of DEM data */
   if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
@@ -389,6 +433,33 @@ static void vik_dem_layer_draw_dem ( VikDEMLayer *vdl, VikViewport *vp, VikDEM *
   /* else they overlap */
 
   /**** End Overlap Check ****/
+  /* boxes to show where we have DEM instead of actually drawing the DEM.
+   * useful if we want to see what areas we have coverage for (if we want
+   * to get elevation data for a track) but don't want to cover the map.
+   */
+
+  #if 0
+  /* draw a box if a DEM is loaded. in future I'd like to add an option for this
+   * this is useful if we want to see what areas we have dem for but don't want to
+   * cover the map (or maybe we just need translucent DEM?) */
+  {
+    VikCoord demne, demsw;
+    gint x1, y1, x2, y2;
+    vik_coord_load_from_latlon(&demne, vik_viewport_get_coord_mode(vp), &dem_northeast);
+    vik_coord_load_from_latlon(&demsw, vik_viewport_get_coord_mode(vp), &dem_southwest);
+
+    vik_viewport_coord_to_screen ( vp, &demne, &x1, &y1 );
+    vik_viewport_coord_to_screen ( vp, &demsw, &x2, &y2 );
+
+    if ( x1 > vik_viewport_get_width(vp) ) x1=vik_viewport_get_width(vp);
+    if ( y2 > vik_viewport_get_height(vp) ) y2=vik_viewport_get_height(vp);
+    if ( x2 < 0 ) x2 = 0;
+    if ( y1 < 0 ) y1 = 0;
+    vik_viewport_draw_rectangle ( vp, GTK_WIDGET(vp)->style->black_gc, 
+       FALSE, x2, y1, x1-x2, y2-y1 );
+    return;
+  }
+  #endif
 
   if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
     VikCoord tmp; /* TODO: don't use coord_load_from_latlon, especially if in latlon drawing mode */
@@ -426,6 +497,10 @@ static void vik_dem_layer_draw_dem ( VikDEMLayer *vdl, VikViewport *vp, VikDEM *
 
     vik_dem_east_north_to_xy ( dem, start_lon_as, start_lat_as, &start_x, &start_y );
 
+    /* verify sane elev interval */
+    if ( vdl->max_elev <= vdl->min_elev )
+      vdl->max_elev = vdl->min_elev + 1;
+
     for ( x=start_x, counter.lon = start_lon; counter.lon <= end_lon; counter.lon += escale_deg * skip_factor, x += skip_factor ) {
       if ( x > 0 && x < dem->n_columns ) {
         column = g_ptr_array_index ( dem->columns, x );
@@ -433,7 +508,13 @@ static void vik_dem_layer_draw_dem ( VikDEMLayer *vdl, VikViewport *vp, VikDEM *
           if ( y > column->n_points )
             break;
           elev = column->points[y];
-          if ( elev > vdl->max_elev ) elev=vdl->max_elev;
+
+          if ( elev != VIK_DEM_INVALID_ELEVATION && elev < vdl->min_elev )
+            elev=vdl->min_elev;
+          if ( elev != VIK_DEM_INVALID_ELEVATION && elev > vdl->max_elev )
+            elev=vdl->max_elev;
+
+
           {
             gint a, b;
 
@@ -444,7 +525,7 @@ static void vik_dem_layer_draw_dem ( VikDEMLayer *vdl, VikViewport *vp, VikDEM *
             else if ( elev <= 0 )
               vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, a-2, b-2, 4, 4 );
             else
-              vik_viewport_draw_rectangle(vp, vdl->gcs[(gint)floor(elev/vdl->max_elev*(dem_n_colors-2))+1], TRUE, a-2, b-2, 4, 4 );
+              vik_viewport_draw_rectangle(vp, vdl->gcs[(gint)floor((elev - vdl->min_elev)/(vdl->max_elev - vdl->min_elev)*(DEM_N_COLORS-2))+1], TRUE, a-2, b-2, 4, 4 );
           }
         } /* for y= */
       }
@@ -462,6 +543,14 @@ static void vik_dem_layer_draw_dem ( VikDEMLayer *vdl, VikViewport *vp, VikDEM *
 
     guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 10 ); /* todo: smarter calculation. */
 
+    VikCoord tleft, tright, bleft, bright;
+
+    vik_viewport_screen_to_coord ( vp, 0, 0, &tleft );
+    vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), 0, &tright );
+    vik_viewport_screen_to_coord ( vp, 0, vik_viewport_get_height(vp), &bleft );
+    vik_viewport_screen_to_coord ( vp, vik_viewport_get_width(vp), vik_viewport_get_height(vp), &bright );
+
+
     vik_coord_convert(&tleft, VIK_COORD_UTM);
     vik_coord_convert(&tright, VIK_COORD_UTM);
     vik_coord_convert(&bleft, VIK_COORD_UTM);
@@ -506,7 +595,11 @@ static void vik_dem_layer_draw_dem ( VikDEMLayer *vdl, VikViewport *vp, VikDEM *
           if ( y > column->n_points )
             continue;
           elev = column->points[y];
-          if ( elev > vdl->max_elev ) elev=vdl->max_elev;
+          if ( elev != VIK_DEM_INVALID_ELEVATION && elev < vdl->min_elev )
+            elev=vdl->min_elev;
+          if ( elev != VIK_DEM_INVALID_ELEVATION && elev > vdl->max_elev )
+            elev=vdl->max_elev;
+
           {
             gint a, b;
             vik_coord_load_from_utm(&tmp, vik_viewport_get_coord_mode(vp), &counter);
@@ -516,7 +609,7 @@ static void vik_dem_layer_draw_dem ( VikDEMLayer *vdl, VikViewport *vp, VikDEM *
             else if ( elev <= 0 )
               vik_viewport_draw_rectangle(vp, vdl->gcs[0], TRUE, a-2, b-2, 4, 4 );
             else
-              vik_viewport_draw_rectangle(vp, vdl->gcs[(gint)floor(elev/vdl->max_elev*(dem_n_colors-2))+1], TRUE, a-2, b-2, 4, 4 );
+              vik_viewport_draw_rectangle(vp, vdl->gcs[(gint)floor((elev - vdl->min_elev)/(vdl->max_elev - vdl->min_elev)*(DEM_N_COLORS-2))+1], TRUE, a-2, b-2, 4, 4 );
           }
         } /* for y= */
       }
@@ -524,11 +617,52 @@ static void vik_dem_layer_draw_dem ( VikDEMLayer *vdl, VikViewport *vp, VikDEM *
   }
 }
 
+/* return the continent for the specified lat, lon */
+/* TODO */
+static const gchar *srtm_continent_dir ( gint lat, gint lon )
+{
+  extern const char *_srtm_continent_data[];
+  static GHashTable *srtm_continent = NULL;
+  const gchar *continent;
+  gchar name[16];
+
+  if (!srtm_continent) {
+    const gchar **s;
+
+    srtm_continent = g_hash_table_new(g_str_hash, g_str_equal);
+    s = _srtm_continent_data;
+    while (*s != (gchar *)-1) {
+      continent = *s++;
+      while (*s) {
+        g_hash_table_insert(srtm_continent, (gpointer) *s, (gpointer) continent);
+        s++;
+      }
+      s++;
+    }
+  }
+  g_snprintf(name, sizeof(name), "%c%02d%c%03d",
+                  (lat >= 0) ? 'N' : 'S', ABS(lat),
+                 (lon >= 0) ? 'E' : 'W', ABS(lon));
+
+  return(g_hash_table_lookup(srtm_continent, name));
+}
+
 void vik_dem_layer_draw ( VikDEMLayer *vdl, gpointer data )
 {
   VikViewport *vp = (VikViewport *) data;
   GList *dems_iter = vdl->files;
   VikDEM *dem;
+
+
+  /* search for SRTM3 90m */
+
+  if ( vdl->source == DEM_SOURCE_SRTM )
+    srtm_draw_existence ( vp );
+#ifdef VIK_CONFIG_DEM24K
+  else if ( vdl->source == DEM_SOURCE_DEM24K )
+    dem24k_draw_existence ( vp );
+#endif
+
   while ( dems_iter ) {
     dem = a_dems_get ( (const char *) (dems_iter->data) );
     if ( dem )
@@ -539,19 +673,23 @@ void vik_dem_layer_draw ( VikDEMLayer *vdl, gpointer data )
 
 void vik_dem_layer_free ( VikDEMLayer *vdl )
 {
+  gint i;
   if ( vdl->gc != NULL )
     g_object_unref ( G_OBJECT(vdl->gc) );
 
   if ( vdl->color != NULL )
     g_free ( vdl->color );
 
+  if ( vdl->gcs )
+    for ( i = 0; i < DEM_N_COLORS; i++ )
+      g_object_unref ( vdl->gcs[i] );
+  g_free ( vdl->gcs );
+
   a_dems_list_free ( vdl->files );
 }
 
 static void dem_layer_update_gc ( VikDEMLayer *vdl, VikViewport *vp, const gchar *color )
 {
-  guint i;
-
   if ( vdl->color )
     g_free ( vdl->color );
 
@@ -561,16 +699,337 @@ static void dem_layer_update_gc ( VikDEMLayer *vdl, VikViewport *vp, const gchar
     g_object_unref ( G_OBJECT(vdl->gc) );
 
   vdl->gc = vik_viewport_new_gc ( vp, vdl->color, vdl->line_thickness );
-
-  for ( i = 0 ; i < dem_n_colors; i++ )
-    vdl->gcs[i] = vik_viewport_new_gc ( vp, dem_colors[i], vdl->line_thickness );
-
 }
 
 VikDEMLayer *vik_dem_layer_create ( VikViewport *vp )
 {
   VikDEMLayer *vdl = vik_dem_layer_new ();
+  gint i;
+
+  /* TODO: share GCS between layers */
+  for ( i = 0; i < DEM_N_COLORS; i++ )
+    vdl->gcs[i] = vik_viewport_new_gc ( vp, dem_colors[i], vdl->line_thickness );
+
   dem_layer_update_gc ( vdl, vp, "red" );
   return vdl;
 }
+/**************************************************************
+ **** SOURCES & DOWNLOADING
+ **************************************************************/
+typedef struct {
+  gchar *dest;
+  gdouble lat, lon;
+
+  GMutex *mutex;
+  VikDEMLayer *vdl; /* NULL if not alive */
+
+  guint source;
+} DEMDownloadParams;
+
+
+/**************************************************
+ *  SOURCE: SRTM                                  *
+ **************************************************/
+
+static void srtm_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
+{
+  gint intlat, intlon;
+  const gchar *continent_dir;
+
+  intlat = (int)floor(p->lat);
+  intlon = (int)floor(p->lon);
+  continent_dir = srtm_continent_dir(intlat, intlon);
+
+  if (!continent_dir) {
+    g_warning(N_("No SRTM data available for %f, %f"), p->lat, p->lon);
+    return;
+  }
+
+  gchar *src_fn = g_strdup_printf("%s%s%s%c%02d%c%03d.hgt.zip",
+                SRTM_FTP_URI,
+                continent_dir,
+                G_DIR_SEPARATOR_S,
+               (intlat >= 0) ? 'N' : 'S',
+               ABS(intlat),
+               (intlon >= 0) ? 'E' : 'W',
+               ABS(intlon) );
+
+  static DownloadOptions options = { NULL, 0, a_check_map_file };
+  a_ftp_download_get_url ( SRTM_FTP_SITE, src_fn, p->dest, &options );
+  g_free ( src_fn );
+}
+
+static gchar *srtm_lat_lon_to_dest_fn ( gdouble lat, gdouble lon )
+{
+  gint intlat, intlon;
+  const gchar *continent_dir;
+
+  intlat = (int)floor(lat);
+  intlon = (int)floor(lon);
+  continent_dir = srtm_continent_dir(intlat, intlon);
+
+  if (!continent_dir)
+    continent_dir = "nowhere";
+
+  return g_strdup_printf("srtm3-%s%s%c%02d%c%03d.hgt.zip",
+                continent_dir,
+                G_DIR_SEPARATOR_S,
+               (intlat >= 0) ? 'N' : 'S',
+               ABS(intlat),
+               (intlon >= 0) ? 'E' : 'W',
+               ABS(intlon) );
+
+}
+
+/* TODO: generalize */
+static void srtm_draw_existence ( VikViewport *vp )
+{
+  gdouble max_lat, max_lon, min_lat, min_lon;  
+  gchar buf[strlen(MAPS_CACHE_DIR)+strlen(SRTM_CACHE_TEMPLATE)+30];
+  gint i, j;
+
+  vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
+
+  for (i = floor(min_lat); i <= floor(max_lat); i++) {
+    for (j = floor(min_lon); j <= floor(max_lon); j++) {
+      const gchar *continent_dir;
+      if ((continent_dir = srtm_continent_dir(i, j)) == NULL)
+        continue;
+      g_snprintf(buf, sizeof(buf), SRTM_CACHE_TEMPLATE,
+                MAPS_CACHE_DIR,
+                continent_dir,
+                G_DIR_SEPARATOR_S,
+               (i >= 0) ? 'N' : 'S',
+               ABS(i),
+               (j >= 0) ? 'E' : 'W',
+               ABS(j) );
+      if ( g_file_test(buf, G_FILE_TEST_EXISTS ) == TRUE ) {
+        VikCoord ne, sw;
+        gint x1, y1, x2, y2;
+        sw.north_south = i;
+        sw.east_west = j;
+        sw.mode = VIK_COORD_LATLON;
+        ne.north_south = i+1;
+        ne.east_west = j+1;
+        ne.mode = VIK_COORD_LATLON;
+        vik_viewport_coord_to_screen ( vp, &sw, &x1, &y1 );
+        vik_viewport_coord_to_screen ( vp, &ne, &x2, &y2 );
+        if ( x1 < 0 ) x1 = 0;
+        if ( y2 < 0 ) y2 = 0;
+        vik_viewport_draw_rectangle ( vp, GTK_WIDGET(vp)->style->black_gc, 
+               FALSE, x1, y2, x2-x1, y1-y2 );
+      }
+    }
+  }
+}
+
+
+/**************************************************
+ *  SOURCE: USGS 24K                              *
+ **************************************************/
+
+#ifdef VIK_CONFIG_DEM24K
+
+static void dem24k_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
+{
+  /* TODO: dest dir */
+  gchar *cmdline = g_strdup_printf("%s %.03f %.03f",
+       DEM24K_DOWNLOAD_SCRIPT,
+       floor(p->lat*8)/8,
+       ceil(p->lon*8)/8 );
+  /* FIX: don't use system, use execv or something. check for existence */
+  system(cmdline);
+}
+
+static gchar *dem24k_lat_lon_to_dest_fn ( gdouble lat, gdouble lon )
+{
+  return g_strdup_printf("dem24k/%d/%d/%.03f,%.03f.dem",
+       (gint) lat,
+       (gint) lon,
+       floor(lat*8)/8,
+       ceil(lon*8)/8);
+}
+
+/* TODO: generalize */
+static void dem24k_draw_existence ( VikViewport *vp )
+{
+  gdouble max_lat, max_lon, min_lat, min_lon;  
+  gchar buf[strlen(MAPS_CACHE_DIR)+40];
+  gdouble i, j;
+
+  vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
+
+  for (i = floor(min_lat*8)/8; i <= floor(max_lat*8)/8; i+=0.125) {
+    /* check lat dir first -- faster */
+    g_snprintf(buf, sizeof(buf), "%sdem24k/%d/",
+        MAPS_CACHE_DIR,
+       (gint) i );
+    if ( g_file_test(buf, G_FILE_TEST_EXISTS) == FALSE )
+      continue;
+    for (j = floor(min_lon*8)/8; j <= floor(max_lon*8)/8; j+=0.125) {
+      /* check lon dir first -- faster */
+      g_snprintf(buf, sizeof(buf), "%sdem24k/%d/%d/",
+        MAPS_CACHE_DIR,
+       (gint) i,
+        (gint) j );
+      if ( g_file_test(buf, G_FILE_TEST_EXISTS) == FALSE )
+        continue;
+      g_snprintf(buf, sizeof(buf), "%sdem24k/%d/%d/%.03f,%.03f.dem",
+               MAPS_CACHE_DIR,
+               (gint) i,
+               (gint) j,
+               floor(i*8)/8,
+               floor(j*8)/8 );
+      if ( g_file_test(buf, G_FILE_TEST_EXISTS ) == TRUE ) {
+        VikCoord ne, sw;
+        gint x1, y1, x2, y2;
+        sw.north_south = i;
+        sw.east_west = j-0.125;
+        sw.mode = VIK_COORD_LATLON;
+        ne.north_south = i+0.125;
+        ne.east_west = j;
+        ne.mode = VIK_COORD_LATLON;
+        vik_viewport_coord_to_screen ( vp, &sw, &x1, &y1 );
+        vik_viewport_coord_to_screen ( vp, &ne, &x2, &y2 );
+        if ( x1 < 0 ) x1 = 0;
+        if ( y2 < 0 ) y2 = 0;
+        vik_viewport_draw_rectangle ( vp, GTK_WIDGET(vp)->style->black_gc, 
+               FALSE, x1, y2, x2-x1, y1-y2 );
+      }
+    }
+  }
+}
+#endif
+
+/**************************************************
+ *   SOURCES -- DOWNLOADING & IMPORTING TOOL      *
+ **************************************************
+ */
+
+static void weak_ref_cb ( gpointer ptr, GObject * dead_vdl )
+{
+  DEMDownloadParams *p = ptr;
+  g_mutex_lock ( p->mutex );
+  p->vdl = NULL;
+  g_mutex_unlock ( p->mutex );
+}
+
+/* Try to add file full_path.
+ * full_path will be copied.
+ * returns FALSE if file does not exists, TRUE otherwise.
+ */
+static gboolean dem_layer_add_file ( VikDEMLayer *vdl, const gchar *full_path )
+{
+  if ( g_file_test(full_path, G_FILE_TEST_EXISTS ) == TRUE ) {
+    /* only load if file size is not 0 (not in progress) */
+    struct stat sb;
+    stat (full_path, &sb);
+    if ( sb.st_size ) {
+      gchar *duped_path = g_strdup(full_path);
+      vdl->files = g_list_prepend ( vdl->files, duped_path );
+      a_dems_load ( duped_path );
+      g_debug("%s: %s", __FUNCTION__, duped_path);
+      vik_layer_emit_update ( VIK_LAYER(vdl) );
+    }
+    return TRUE;
+  } else
+    return FALSE;
+}
+
+static void dem_download_thread ( DEMDownloadParams *p, gpointer threaddata )
+{
+  if ( p->source == DEM_SOURCE_SRTM )
+    srtm_dem_download_thread ( p, threaddata );
+#ifdef VIK_CONFIG_DEM24K
+  else if ( p->source == DEM_SOURCE_DEM24K )
+    dem24k_dem_download_thread ( p, threaddata );
+#endif
+
+  gdk_threads_enter();
+  g_mutex_lock ( p->mutex );
+  if ( p->vdl ) {
+    g_object_weak_unref ( G_OBJECT(p->vdl), weak_ref_cb, p );
+
+    if ( dem_layer_add_file ( p->vdl, p->dest ) )
+      vik_layer_emit_update ( VIK_LAYER(p->vdl) );
+  }
+  g_mutex_unlock ( p->mutex );
+  gdk_threads_leave();
+}
+
+
+static void free_dem_download_params ( DEMDownloadParams *p )
+{
+  g_mutex_free ( p->mutex );
+  g_free ( p->dest );
+  g_free ( p );
+}
+
+static gpointer dem_layer_download_create ( VikWindow *vw, VikViewport *vvp)
+{
+  return vvp;
+}
+
+
+static gboolean dem_layer_download_release ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp )
+{
+  VikCoord coord;
+  struct LatLon ll;
+
+  gchar *full_path;
+  gchar *dem_file = NULL;
+
+  if ( vdl->source == DEM_SOURCE_NONE )
+    a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vdl), _("No download source selected. Edit layer properties.") );
+
+  vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
+  vik_coord_to_latlon ( &coord, &ll );
+
+  
+  if ( vdl->source == DEM_SOURCE_SRTM )
+    dem_file = srtm_lat_lon_to_dest_fn ( ll.lat, ll.lon );
+#ifdef VIK_CONFIG_DEM24K
+  else if ( vdl->source == DEM_SOURCE_DEM24K )
+    dem_file = dem24k_lat_lon_to_dest_fn ( ll.lat, ll.lon );
+#endif
+
+  if ( ! dem_file )
+    return TRUE;
+
+  full_path = g_strdup_printf("%s%s", MAPS_CACHE_DIR, dem_file );
+
+  g_debug("%s: %s", __FUNCTION__, full_path);
+
+  // TODO: check if already in filelist
+
+  if ( ! dem_layer_add_file(vdl, full_path) ) {
+    gchar *tmp = g_strdup_printf ( _("Downloading DEM %s"), dem_file );
+    DEMDownloadParams *p = g_malloc(sizeof(DEMDownloadParams));
+    p->dest = g_strdup(full_path);
+    p->lat = ll.lat;
+    p->lon = ll.lon;
+    p->vdl = vdl;
+    p->mutex = g_mutex_new();
+    p->source = vdl->source;
+    g_object_weak_ref(G_OBJECT(p->vdl), weak_ref_cb, p );
+
+    a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vdl), tmp,
+               (vik_thr_func) dem_download_thread, p,
+               (vik_thr_free_func) free_dem_download_params, NULL, 1 );
+  }
+
+  g_free ( dem_file );
+  g_free ( full_path );
+
+  return TRUE;
+}
+
+static gboolean dem_layer_download_click ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp )
+{
+/* choose & keep track of cache dir
+ * download in background thread
+ * download over area */
+  return TRUE;
+}
+