]> git.street.me.uk Git - andy/viking.git/blobdiff - src/vikdemlayer.c
Remove dependencies to gob2
[andy/viking.git] / src / vikdemlayer.c
index 54f2692553cf6010a8de4cfb8c6191d177c26e7d..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 "vikaggregatelayer.h"
 #include "viklayerspanel.h"
 #include "vikdemlayer.h"
-#include "vikdemlayer_pixmap.h"
-#include "vikmapslayer.h"
+#include "dialog.h"
 
 #include "dem.h"
 #include "dems.h"
 
+#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/North_America/"
+#define SRTM_FTP_URI  "/srtm/version2/SRTM3/"
+
+#ifdef VIK_CONFIG_DEM24K
+#define DEM24K_DOWNLOAD_SCRIPT "dem24k.pl"
+#endif
 
-#define SRTM_CACHE_DIR maps_layer_default_dir()
-#define SRTM_CACHE_PREFIX "srtm3-"
-#define SRTM_CACHE_TEMPLATE "%ssrtm3-%s%c%02d%c%03d.hgt.zip"
 
-static VikDEMLayer *dem_layer_copy ( VikDEMLayer *vdl, gpointer vp );
 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, 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[] = {
-  { "DEM Download/Import", (VikToolConstructorFunc) dem_layer_download_create, NULL, NULL, NULL,
-    (VikToolMouseFunc) dem_layer_download_click, NULL,  (VikToolMouseFunc) dem_layer_download_release },
+  { 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 },
 };
 
 
@@ -188,13 +226,12 @@ 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,
 
   dem_tools,
   sizeof(dem_tools) / sizeof(dem_tools[0]),
@@ -224,7 +261,6 @@ VikLayerInterface vik_dem_layer_interface = {
   (VikLayerFuncSublayerRenameRequest)   NULL,
   (VikLayerFuncSublayerToggleVisible)   NULL,
 
-  (VikLayerFuncCopy)                    dem_layer_copy,
   (VikLayerFuncMarshall)               dem_layer_marshall,
   (VikLayerFuncUnmarshall)             dem_layer_unmarshall,
 
@@ -246,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 ()
@@ -275,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 );
@@ -297,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;
 }
@@ -307,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;
@@ -320,7 +351,9 @@ 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;
   }
@@ -339,6 +372,7 @@ static void dem_layer_post_read ( VikLayer *vl, VikViewport *vp, gboolean from_f
 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;
@@ -346,9 +380,12 @@ 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;
@@ -420,7 +457,6 @@ static void vik_dem_layer_draw_dem ( VikDEMLayer *vdl, VikViewport *vp, VikDEM *
     if ( y1 < 0 ) y1 = 0;
     vik_viewport_draw_rectangle ( vp, GTK_WIDGET(vp)->style->black_gc, 
        FALSE, x2, y1, x1-x2, y2-y1 );
-    g_print("%d %d %d %d\n", x2, y1, x1-x2, y2-y1);
     return;
   }
   #endif
@@ -461,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 );
@@ -468,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;
 
@@ -479,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= */
       }
@@ -549,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);
@@ -559,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= */
       }
@@ -569,9 +619,32 @@ static void vik_dem_layer_draw_dem ( VikDEMLayer *vdl, VikViewport *vp, VikDEM *
 
 /* return the continent for the specified lat, lon */
 /* TODO */
-const gchar *srtm_continent_dir ( gint lat, gint lon )
+static const gchar *srtm_continent_dir ( gint lat, gint lon )
 {
-  return "North_America/";
+  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 )
@@ -580,40 +653,15 @@ void vik_dem_layer_draw ( VikDEMLayer *vdl, gpointer data )
   GList *dems_iter = vdl->files;
   VikDEM *dem;
 
-  gdouble max_lat, max_lon, min_lat, min_lon;  
-  gchar buf[strlen(SRTM_CACHE_DIR)+strlen(SRTM_CACHE_TEMPLATE)+30];
-  gint i, j;
 
   /* search for SRTM3 90m */
-  vik_viewport_get_min_max_lat_lon ( vp, &min_lat, &max_lat, &min_lon, &max_lon );
-  g_print("%f %f %f %f", 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++) {
-      g_snprintf(buf, sizeof(buf), SRTM_CACHE_TEMPLATE,
-                SRTM_CACHE_DIR,
-                srtm_continent_dir(i, j),
-               (i >= 0) ? 'N' : 'S',
-               ABS(i),
-               (j >= 0) ? 'E' : 'W',
-               ABS(j) );
-      if ( access(buf, F_OK ) == 0 ) {
-        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 );
-      }
-    }
-  }
+
+  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) );
@@ -625,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 );
 
@@ -647,95 +699,328 @@ 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;
+
 
 /**************************************************
- *   SOURCES -- DOWNLOADING & IMPORTING -- TOOL   *
+ *  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 gpointer dem_layer_download_create ( VikWindow *vw, VikViewport *vvp)
+
+static void weak_ref_cb ( gpointer ptr, GObject * dead_vdl )
 {
-  return vvp;
+  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 create_dem_download_thread ( gpointer *pass_along, gpointer threaddata )
+
+static void free_dem_download_params ( DEMDownloadParams *p )
 {
-  gchar *name_buf = pass_along[0];
-  gint lat = (gint) pass_along[1];
-  gint lon = (gint) pass_along[2];
-
-  gchar *full_uri = g_strdup_printf("%s%s%s", SRTM_FTP_URI, srtm_continent_dir(lat,lon), name_buf);
-  gchar *full_dest_fn = g_strdup_printf("%s%s%s%s", SRTM_CACHE_DIR, SRTM_CACHE_PREFIX, srtm_continent_dir(lat, lon), name_buf );
-  DownloadOptions options = { NULL, 0 };
-  a_ftp_download_get_url ( SRTM_FTP_SITE, full_uri, full_dest_fn, &options );
+  g_mutex_free ( p->mutex );
+  g_free ( p->dest );
+  g_free ( p );
 }
 
-static void free_dem_download_pass_along ( gpointer *pass_along )
+static gpointer dem_layer_download_create ( VikWindow *vw, VikViewport *vvp)
 {
-  g_free ( pass_along[0] ); /* name_buf */
-  g_free ( pass_along );
+  return vvp;
 }
 
+
 static gboolean dem_layer_download_release ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp )
 {
   VikCoord coord;
   struct LatLon ll;
 
-  gint intlat, intlon;
+  gchar *full_path;
+  gchar *dem_file = NULL;
 
-  gchar *dem_path;
-  gchar name_buf[22];
+  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 );
-  intlat = (int)floor(ll.lat);
-  intlon = (int)floor(ll.lon);
 
-  g_snprintf(name_buf, sizeof(name_buf), "%c%02d%c%03d.hgt.zip",
-               (intlat >= 0) ? 'N' : 'S',
-               ABS(intlat),
-               (intlon >= 0) ? 'E' : 'W',
-               ABS(intlon) );
-  dem_path = g_strdup_printf("%s%s",
-               "/home/tobias/.viking-maps/srtm3-North_America/",
-               name_buf );
-
-  g_warning(dem_path);
-
-  // check if already in filelist
-
-  if ( access(dem_path, F_OK ) == 0 ) {
-    /* only load if file size is not 0 (not in progress */
-    struct stat sb;
-    stat (dem_path, &sb);
-    if ( sb.st_size ) {
-      vdl->files = g_list_prepend ( vdl->files, dem_path );
-      a_dems_load ( dem_path );
-      g_warning(dem_path);
-    }
-    vik_layer_emit_update ( VIK_LAYER(vdl) );
-  } else {
-      gchar *tmp = g_strdup_printf ( "Downloading SRTM DEM %s ", name_buf );
-      gpointer *pass_along = g_malloc ( sizeof(gpointer) * 3 );
-      pass_along[0] = g_strdup(name_buf);
-      pass_along[1] = (gpointer) intlat;
-      pass_along[2] = (gpointer) intlat;
-      a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vdl), tmp,
-               (vik_thr_func) create_dem_download_thread, pass_along,
-               (vik_thr_free_func) free_dem_download_pass_along, NULL, 1 );
+  
+  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;
 }