]> git.street.me.uk Git - andy/viking.git/commitdiff
Merge DEM branch
authorEvan Battaglia <gtoevan@gmx.net>
Fri, 6 Jul 2007 17:04:18 +0000 (17:04 +0000)
committerEvan Battaglia <gtoevan@gmx.net>
Fri, 6 Jul 2007 17:04:18 +0000 (17:04 +0000)
19 files changed:
ChangeLog
src/Makefile.am
src/dem.c [new file with mode: 0644]
src/dem.h [new file with mode: 0644]
src/dems.c [new file with mode: 0644]
src/dems.h [new file with mode: 0644]
src/file.c
src/main.c
src/vikcoordlayer.c
src/vikdemlayer.c [new file with mode: 0644]
src/vikdemlayer.h [new file with mode: 0644]
src/vikdemlayer_pixmap.h [new file with mode: 0644]
src/vikfilelist.c [new file with mode: 0644]
src/vikfilelist.h [new file with mode: 0644]
src/viklayer.c
src/viklayer.h
src/viktrack.c
src/viktrack.h
src/viktrwlayer.c

index 75691532e8814a115d72d656f26fc02490b5bcfc..27e41c030941bf2f7d51a46c9ca047bc3017866f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2007-07-06
+Evan Battaglia <gtoevan@gmx.net>:
+       * Merge DEM Branch
+
 2007-07-04
 Quy Tonthat <qtonthat@gmail.com>:
        * Bug fix: View Mode displayed wrong setting on start up
@@ -7,6 +11,11 @@ Quy Tonthat <qtonthat@gmail.com>:
        * Fixed bugs that caused draw_scale and draw_centermark status not being
        consistent among View menu, viewport and loaded files.
 
+2007-07-02
+Evan Battaglia <gtoevan@gmx.net>
+        * DEM Branch: Trying to fix/cleanup various DEM things
+        * DEM Branch: Support for SRTM 3 arcsecond _global_ DEM data from http://www2.jpl.nasa.gov/srtm/ 
+
 2007-07-02
 Quy Tonthat <qtonthat@gmail.com>:
        * Fixed bugs that caused crashes during GPS upload/download.
@@ -103,6 +112,10 @@ Quy Tonthat <qtonthat@gmail.com>:
        * Disable prompt for save before exit.
        * Add "Save and Exit" to File menu.
 
+2007-05-20
+Evan Battaglia <gtoevan@gmx.net>
+        * DEM Branch
+
 2007-05-20
 Quy Tonthat <qtonthat@gmail.com>:
        * Stop autodownload from running forever on map downloading errors.
index 252ec6e448883017dacf4df82d3ec98789009d84..7d35b1d1b7ed158d270fc31027ed37b6178f4153 100644 (file)
@@ -57,7 +57,12 @@ viking_SOURCES = main.c \
        datasource_google.c \
        datasource_gc.c \
        datasources.h \
-       googlesearch.c googlesearch.h
+       googlesearch.c googlesearch.h \
+       datasources.h \
+       dem.c dem.h \
+       vikdemlayer.h vikdemlayer.c \
+       vikfilelist.c vikfilelist.h \
+       dems.c dems.h
 
 if LIBCURL
 viking_SOURCES += \
diff --git a/src/dem.c b/src/dem.c
new file mode 100644 (file)
index 0000000..3badc4a
--- /dev/null
+++ b/src/dem.c
@@ -0,0 +1,370 @@
+#include <stdio.h>
+#include <string.h>
+#include <glib.h>
+#include <math.h>
+#include <stdlib.h>
+
+#include "dem.h"
+#include "file.h"
+
+#define DEM_BLOCK_SIZE 1024
+#define GET_COLUMN(dem,n) ((VikDEMColumn *)g_ptr_array_index( (dem)->columns, (n) ))
+
+static gboolean get_double_and_continue ( gchar **buffer, gdouble *tmp, gboolean warn )
+{
+  gchar *endptr;
+  *tmp = g_strtod(*buffer, &endptr);
+  if ( endptr == NULL|| endptr == *buffer ) {
+    if ( warn )
+      g_warning("Invalid DEM");
+    return FALSE;
+  }
+  *buffer=endptr;
+  return TRUE;
+}
+
+
+static gboolean get_int_and_continue ( gchar **buffer, gint *tmp, gboolean warn )
+{
+  gchar *endptr;
+  *tmp = strtol(*buffer, &endptr, 10);
+  if ( endptr == NULL|| endptr == *buffer ) {
+    if ( warn )
+      g_warning("Invalid DEM");
+    return FALSE;
+  }
+  *buffer=endptr;
+  return TRUE;
+}
+
+static gboolean dem_parse_header ( gchar *buffer, VikDEM *dem )
+{
+  gdouble val;
+  gint int_val;
+  guint i;
+  gchar *tmp = buffer;
+
+  /* incomplete header */
+  if ( strlen(buffer) != 1024 )
+    return FALSE;
+
+  /* fix Fortran-style exponentiation 1.0D5 -> 1.0E5 */
+  while (*tmp) {
+    if ( *tmp=='D')
+      *tmp='E';
+    tmp++;
+  }
+
+  /* skip name */
+  buffer += 149;
+
+  /* "DEM level code, pattern code, palaimetric reference system code" -- skip */
+  get_int_and_continue(&buffer, &int_val, TRUE);
+  get_int_and_continue(&buffer, &int_val, TRUE);
+  get_int_and_continue(&buffer, &int_val, TRUE);
+
+  /* zone */
+  get_int_and_continue(&buffer, &int_val, TRUE);
+  dem->utm_zone = int_val;
+  /* TODO -- southern or northern hemisphere?! */
+  dem->utm_letter = 'N';
+
+  /* skip numbers 5-19  */
+  for ( i = 0; i < 15; i++ ) {
+    if ( ! get_double_and_continue(&buffer, &val, FALSE) ) {
+      g_warning ("Invalid DEM header");
+      return FALSE;
+    }
+  }
+
+  /* number 20 -- horizontal unit code (utm/ll) */
+  get_double_and_continue(&buffer, &val, TRUE);
+  dem->horiz_units = val;
+  get_double_and_continue(&buffer, &val, TRUE);
+  dem->vert_units = val;
+
+  /* TODO: do this for real. these are only for 1:24k and 1:250k USGS */
+  if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
+    dem->east_scale = 10.0; /* meters */
+    dem->north_scale = 10.0;
+  } else {
+    dem->east_scale = 3.0; /* arcseconds */
+    dem->north_scale = 3.0;
+  }
+
+  /* skip next */
+  get_double_and_continue(&buffer, &val, TRUE);
+
+  /* now we get the four corner points. record the min and max. */
+  get_double_and_continue(&buffer, &val, TRUE);
+  dem->min_east = dem->max_east = val;
+  get_double_and_continue(&buffer, &val, TRUE);
+  dem->min_north = dem->max_north = val;
+
+  for ( i = 0; i < 3; i++ ) {
+    get_double_and_continue(&buffer, &val, TRUE);
+    if ( val < dem->min_east ) dem->min_east = val;
+    if ( val > dem->max_east ) dem->max_east = val;
+    get_double_and_continue(&buffer, &val, TRUE);
+    if ( val < dem->min_north ) dem->min_north = val;
+    if ( val > dem->max_north ) dem->max_north = val;
+  }
+
+  return TRUE;
+}
+
+static void dem_parse_block_as_cont ( gchar *buffer, VikDEM *dem, gint *cur_column, gint *cur_row )
+{
+  gint tmp;
+  while ( *cur_row < GET_COLUMN(dem, *cur_column)->n_points ) {
+    if ( get_int_and_continue(&buffer, &tmp,FALSE) )
+      GET_COLUMN(dem, *cur_column)->points[*cur_row] = (gint16) tmp;
+    else
+      return;
+    (*cur_row)++;
+  }
+  *cur_row = -1; /* expecting new column */
+}
+
+static void dem_parse_block_as_header ( gchar *buffer, VikDEM *dem, gint *cur_column, gint *cur_row )
+{
+  guint n_rows;
+  gint i;
+  gdouble east_west, south;
+  gdouble tmp;
+
+  /* 1 x n_rows 1 east_west south x x x DATA */
+
+  if ( (!get_double_and_continue(&buffer, &tmp, TRUE)) || tmp != 1 ) {
+    g_warning("Incorrect DEM Class B record: expected 1");
+    return;
+  }
+
+  /* don't need this */
+  if ( !get_double_and_continue(&buffer, &tmp, TRUE ) ) return;
+
+  /* n_rows */
+  if ( !get_double_and_continue(&buffer, &tmp, TRUE ) )
+    return;
+  n_rows = (guint) tmp;
+
+  if ( (!get_double_and_continue(&buffer, &tmp, TRUE)) || tmp != 1 ) {
+    g_warning("Incorrect DEM Class B record: expected 1");
+    return;
+  }
+  
+  if ( !get_double_and_continue(&buffer, &east_west, TRUE) )
+    return;
+  if ( !get_double_and_continue(&buffer, &south, TRUE) )
+    return;
+
+  /* next three things we don't need */
+  if ( !get_double_and_continue(&buffer, &tmp, TRUE)) return;
+  if ( !get_double_and_continue(&buffer, &tmp, TRUE)) return;
+  if ( !get_double_and_continue(&buffer, &tmp, TRUE)) return;
+
+
+  dem->n_columns ++;
+  (*cur_column) ++;
+
+  /* empty spaces for things before that were skipped */
+  (*cur_row) = (south - dem->min_north) / dem->north_scale;
+  if ( south > dem->max_north || (*cur_row) < 0 )
+    (*cur_row) = 0;
+
+  n_rows += *cur_row;
+
+  g_ptr_array_add ( dem->columns, g_malloc(sizeof(VikDEMColumn)) );
+  GET_COLUMN(dem,*cur_column)->east_west = east_west;
+  GET_COLUMN(dem,*cur_column)->south = south;
+  GET_COLUMN(dem,*cur_column)->n_points = n_rows;
+  GET_COLUMN(dem,*cur_column)->points = g_malloc(sizeof(gint16)*n_rows);
+
+  /* no information for things before that */
+  for ( i = 0; i < (*cur_row); i++ )
+    GET_COLUMN(dem,*cur_column)->points[i] = VIK_DEM_INVALID_ELEVATION;
+
+  /* now just continue */
+  dem_parse_block_as_cont ( buffer, dem, cur_column, cur_row );
+
+
+}
+
+static void dem_parse_block ( gchar *buffer, VikDEM *dem, gint *cur_column, gint *cur_row )
+{
+  /* if haven't read anything or have read all items in a columns and are expecting a new column */
+  if ( *cur_column == -1 || *cur_row == -1 ) {
+    dem_parse_block_as_header(buffer, dem, cur_column, cur_row);
+  } else {
+    dem_parse_block_as_cont(buffer, dem, cur_column, cur_row);
+  }
+}
+
+static VikDEM *vik_dem_read_srtm_hgt(FILE *f, const gchar *basename)
+{
+  gint16 elev;
+  gint i, j;
+  VikDEM *dem;
+
+
+  dem = g_malloc(sizeof(VikDEM));
+
+  dem->horiz_units = VIK_DEM_HORIZ_LL_ARCSECONDS;
+  dem->vert_units = VIK_DEM_VERT_DECIMETERS;
+  dem->east_scale = dem->north_scale = 3;
+
+  /* TODO */
+  dem->min_north = atoi(basename+1) * 3600;
+  dem->min_east = atoi(basename+4) * 3600;
+  if ( basename[0] == 'S' )
+    dem->min_north = - dem->min_north;
+  if ( basename[3] == 'W' )
+    dem->min_east = - dem->min_east;
+
+  dem->max_north = 3600 + dem->min_north;
+  dem->max_east = 3600 + dem->min_east;
+
+  dem->columns = g_ptr_array_new();
+  dem->n_columns = 0;
+
+  for ( i = 0; i < 1201; i++ ) {
+    dem->n_columns++;
+    g_ptr_array_add ( dem->columns, g_malloc(sizeof(VikDEMColumn)) );
+    GET_COLUMN(dem,i)->east_west = dem->min_east + 3*i;
+    GET_COLUMN(dem,i)->south = dem->min_north;
+    GET_COLUMN(dem,i)->n_points = 1201;
+    GET_COLUMN(dem,i)->points = g_malloc(sizeof(gint16)*1201);
+  }
+
+  for ( i = 1200; i >= 0; i-- ) {
+    for ( j = 0; j < 1201; j++ ) {
+      if ( feof(f) ) {
+        g_warning("Incorrect SRTM file: unexpected EOF");
+        g_print("%d %d\n", i, j);
+        return dem;
+      }
+      fread(&elev, sizeof(elev), 1, f);
+      gchar *x = (gchar *) &elev;
+      gchar tmp;
+      tmp=x[0];
+      x[0]=x[1];
+      x[1]=tmp;
+      GET_COLUMN(dem,j)->points[i] = elev;
+    }
+
+  }
+
+  return dem;
+}
+
+#define IS_SRTM_HGT(fn) (strlen((fn))==11 && (fn)[7]=='.' && (fn)[8]=='h' && (fn)[9]=='g' && (fn)[10]=='t' && ((fn)[0]=='N' || (fn)[0]=='S') && ((fn)[3]=='E' || (fn)[3]=='W'))
+
+VikDEM *vik_dem_new_from_file(const gchar *file)
+{
+  FILE *f;
+  VikDEM *rv;
+  gchar buffer[DEM_BLOCK_SIZE+1];
+
+  /* use to record state for dem_parse_block */
+  gint cur_column = -1;
+  gint cur_row = -1;
+  const gchar *basename = a_file_basename(file);
+
+      /* FILE IO */
+  f = fopen(file, "r");
+  if ( !f )
+    return NULL;
+
+  if ( strlen(basename)==11 && basename[7]=='.' && basename[8]=='h' && basename[9]=='g' && basename[10]=='t' &&
+       (basename[0] == 'N' || basename[0] == 'S') && (basename[3] == 'E' || basename[3] =='W'))
+    return vik_dem_read_srtm_hgt(f, basename);
+
+      /* Create Structure */
+  rv = g_malloc(sizeof(VikDEM));
+
+      /* Header */
+  buffer[fread(buffer, 1, DEM_BLOCK_SIZE, f)] = '\0';
+  if ( ! dem_parse_header ( buffer, rv ) ) {
+    g_free ( rv );
+    return NULL;
+  }
+  /* TODO: actually use header -- i.e. GET # OF COLUMNS EXPECTED */
+
+  rv->columns = g_ptr_array_new();
+  rv->n_columns = 0;
+
+      /* Column -- Data */
+  while (! feof(f) ) {
+     gchar *tmp;
+
+     /* read block */
+     buffer[fread(buffer, 1, DEM_BLOCK_SIZE, f)] = '\0';
+
+     /* Fix Fortran-style exponentiation */
+     tmp = buffer;
+     while (*tmp) {
+       if ( *tmp=='D')
+         *tmp='E';
+       tmp++;
+     }
+
+     dem_parse_block(buffer, rv, &cur_column, &cur_row);
+  }
+
+     /* TODO - class C records (right now says 'Invalid' and dies) */
+
+  fclose(f);
+
+  /* 24k scale */
+  if ( rv->horiz_units == VIK_DEM_HORIZ_UTM_METERS && rv->n_columns >= 2 )
+    rv->north_scale = rv->east_scale = GET_COLUMN(rv, 1)->east_west - GET_COLUMN(rv,0)->east_west;
+
+  /* FIXME bug in 10m DEM's */
+  if ( rv->horiz_units == VIK_DEM_HORIZ_UTM_METERS && rv->north_scale == 10 ) {
+    rv->min_east -= 100;
+    rv->min_north += 200;
+  }
+
+
+  return rv;
+}
+
+void vik_dem_free ( VikDEM *dem )
+{
+  guint i;
+  for ( i = 0; i < dem->n_columns; i++)
+    g_free ( GET_COLUMN(dem, i)->points );
+  g_ptr_array_free ( dem->columns, TRUE );
+  g_free ( dem );
+}
+
+gint16 vik_dem_get_xy ( VikDEM *dem, guint col, guint row )
+{
+  if ( col < dem->n_columns )
+    if ( row < GET_COLUMN(dem, col)->n_points )
+      return GET_COLUMN(dem, col)->points[row];
+  return VIK_DEM_INVALID_ELEVATION;
+}
+
+gint16 vik_dem_get_east_north ( VikDEM *dem, gdouble east, gdouble north )
+{
+  gint col, row;
+
+  if ( east > dem->max_east || east < dem->min_east ||
+      north > dem->max_north || north < dem->min_north )
+    return VIK_DEM_INVALID_ELEVATION;
+
+  col = (gint) floor((east - dem->min_east) / dem->east_scale);
+  row = (gint) floor((north - dem->min_north) / dem->north_scale);
+
+  return vik_dem_get_xy ( dem, col, row );
+}
+
+void vik_dem_east_north_to_xy ( VikDEM *dem, gdouble east, gdouble north, guint *col, guint *row )
+{
+  *col = (gint) floor((east - dem->min_east) / dem->east_scale);
+  *row = (gint) floor((north - dem->min_north) / dem->north_scale);
+  if ( *col < 0 ) *col = 0;
+  if ( *row < 0 ) *row = 0;
+}
+
diff --git a/src/dem.h b/src/dem.h
new file mode 100644 (file)
index 0000000..0d90f04
--- /dev/null
+++ b/src/dem.h
@@ -0,0 +1,47 @@
+#ifndef __VIKING_DEM_H
+#define __VIKING_DEM_H
+
+#define VIK_DEM_INVALID_ELEVATION -32767
+
+/* unit codes */
+#define VIK_DEM_HORIZ_UTM_METERS 2
+#define VIK_DEM_HORIZ_LL_ARCSECONDS  3
+
+#define VIK_DEM_VERT_DECIMETERS 2
+
+typedef struct {
+  guint n_columns;
+  GPtrArray *columns;
+
+  guint16 horiz_units, vert_units;
+  gdouble east_scale; /* gap between samples */
+  gdouble north_scale;
+
+  gdouble min_east, min_north, max_east, max_north;
+
+  guint8 utm_zone;
+  gchar utm_letter;
+} VikDEM;
+
+typedef struct {
+  /* east-west coordinate for ALL items in the column */
+  gdouble east_west;
+
+  /* coordinate of northern and southern boundaries */
+  gdouble south;
+//  gdouble north;
+
+  guint n_points;
+  gint16 *points;
+} VikDEMColumn;
+
+
+VikDEM *vik_dem_new_from_file(const gchar *file);
+void vik_dem_free ( VikDEM *dem );
+gint16 vik_dem_get_xy ( VikDEM *dem, guint x, guint y );
+
+gint16 vik_dem_get_east_north ( VikDEM *dem, gdouble east, gdouble north );
+
+void vik_dem_east_north_to_xy ( VikDEM *dem, gdouble east, gdouble north, guint *col, guint *row );
+
+#endif
diff --git a/src/dems.c b/src/dems.c
new file mode 100644 (file)
index 0000000..d3d8894
--- /dev/null
@@ -0,0 +1,160 @@
+#include <glib.h>
+
+#include "dems.h"
+
+typedef struct {
+  VikDEM *dem;
+  guint ref_count;
+} LoadedDEM;
+
+GHashTable *loaded_dems = NULL;
+/* filename -> DEM */
+
+static void loaded_dem_free ( LoadedDEM *ldem )
+{
+  vik_dem_free ( ldem->dem );
+  g_free ( ldem );
+}
+
+void a_dems_uninit ()
+{
+  if ( loaded_dems )
+    g_hash_table_destroy ( loaded_dems );
+}
+
+/* To load a dem. if it was already loaded, will simply
+ * reference the one already loaded and return it.
+ */
+VikDEM *a_dems_load(const gchar *filename)
+{
+  LoadedDEM *ldem;
+
+  /* dems init hash table */
+  if ( ! loaded_dems )
+    loaded_dems = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, (GDestroyNotify) loaded_dem_free );
+
+  ldem = (LoadedDEM *) g_hash_table_lookup ( loaded_dems, filename );
+  if ( ldem ) {
+    ldem->ref_count++;
+    return ldem->dem;
+  } else {
+    VikDEM *dem = vik_dem_new_from_file ( filename );
+    if ( ! dem )
+      return NULL;
+    ldem = g_malloc ( sizeof(LoadedDEM) );
+    ldem->ref_count = 1;
+    ldem->dem = dem;
+    g_hash_table_insert ( loaded_dems, g_strdup(filename), ldem );
+    return dem;
+  }
+}
+
+void a_dems_unref(const gchar *filename)
+{
+  LoadedDEM *ldem = (LoadedDEM *) g_hash_table_lookup ( loaded_dems, filename );
+  g_assert ( ldem );
+  ldem->ref_count --;
+  if ( ldem->ref_count == 0 )
+    g_hash_table_remove ( loaded_dems, filename );
+}
+
+/* to get a DEM that was already loaded.
+ * assumes that its in there already,
+ * although it could not be if earlier load failed.
+ */
+VikDEM *a_dems_get(const gchar *filename)
+{
+  LoadedDEM *ldem = g_hash_table_lookup ( loaded_dems, filename );
+  if ( ldem )
+    return ldem->dem;
+  return NULL;
+}
+
+
+/* Load a string list (GList of strings) of dems. You have to use get to at them later.
+ * When updating a list as a parameter, this should be bfore freeing the list so
+ * the same DEMs won't be loaded & unloaded.
+ * Modifies the list to remove DEMs which did not load.
+ */
+
+/* TODO: don't delete them when they don't exist.
+ * we need to warn the user, but we should keep them in the GList.
+ * we need to know that they weren't referenced though when we
+ * do the a_dems_list_free().
+ */
+void a_dems_load_list ( GList **dems )
+{
+  GList *iter = *dems;
+  while ( iter ) {
+    if ( ! a_dems_load((const gchar *) (iter->data)) ) {
+      GList *iter_temp = iter->next;
+      g_free ( iter->data );
+      (*dems) = g_list_remove_link ( (*dems), iter );
+      iter = iter_temp;
+    } else {
+      iter = iter->next;
+    }
+  }
+}
+
+/* Takes a string list (GList of strings) of dems (filenames).
+ * Unrefs all the dems (i.e. "unloads" them), then frees the
+ * strings, the frees the list.
+ */
+void a_dems_list_free ( GList *dems )
+{
+  GList *iter = dems;
+  while ( iter ) {
+    a_dems_unref ((const gchar *)iter->data);
+    g_free ( iter->data );
+    iter = iter->next;
+  }
+  g_list_free ( dems );
+}
+
+GList *a_dems_list_copy ( GList *dems )
+{
+  GList *rv = g_list_copy ( dems );
+  GList *iter = rv;
+  while ( iter ) {
+    if ( ! a_dems_load((const gchar *) (iter->data)) ) {
+      GList *iter_temp = iter->next; /* delete link, don't bother strdup'ing and free'ing string */
+      rv = g_list_remove_link ( rv, iter );
+      iter = iter_temp;
+    } else {
+      iter->data = g_strdup((gchar *)iter->data); /* copy the string too. */
+      iter = iter->next;
+    }
+  }
+  return rv;
+}
+
+gint16 a_dems_list_get_elev_by_coord ( GList *dems, const VikCoord *coord )
+{
+  static struct UTM utm_tmp;
+  static struct LatLon ll_tmp;
+  GList *iter = dems;
+  VikDEM *dem;
+  gint elev;
+
+  while ( iter ) {
+    dem = a_dems_get ( (gchar *) iter->data );
+    if ( dem ) {
+      if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
+        vik_coord_to_latlon ( coord, &ll_tmp );
+        ll_tmp.lat *= 3600;
+        ll_tmp.lon *= 3600;
+        elev = vik_dem_get_east_north(dem, ll_tmp.lon, ll_tmp.lat);
+        if ( elev != VIK_DEM_INVALID_ELEVATION )
+          return elev;
+      } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
+        vik_coord_to_utm ( coord, &utm_tmp );
+        if ( utm_tmp.zone == dem->utm_zone &&
+             (elev = vik_dem_get_east_north(dem, utm_tmp.easting, utm_tmp.northing)) != VIK_DEM_INVALID_ELEVATION )
+            return elev;
+      }
+    }
+    iter = iter->next;
+  }
+  return VIK_DEM_INVALID_ELEVATION;
+}
diff --git a/src/dems.h b/src/dems.h
new file mode 100644 (file)
index 0000000..6c9da1c
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef __VIKING_DEMS_H
+#define __VIKING_DEMS_H
+
+#include "dem.h"
+#include "vikcoord.h"
+
+void a_dems_uninit ();
+VikDEM *a_dems_load(const gchar *filename);
+void a_dems_unref(const gchar *filename);
+VikDEM *a_dems_get(const gchar *filename);
+void a_dems_load_list ( GList **dems );
+void a_dems_list_free ( GList *dems );
+GList *a_dems_list_copy ( GList *dems );
+gint16 a_dems_list_get_elev_by_coord ( GList *dems, const VikCoord *coord );
+
+#endif
+#include <glib.h>
+
index be4fb118b54d526e580822203cba76c191ddb2f6..a105b0a1bcaa9b4bc6724860c3716515acfb2ff0 100644 (file)
@@ -105,20 +105,37 @@ static void write_layer_params_and_data ( VikLayer *l, FILE *f )
     for ( i = 0; i < params_count; i++ )
     {
       data = get_param(l,i);
-      fprintf ( f, "%s=", params[i].name );
-      switch ( params[i].type )
-      {
-        case VIK_LAYER_PARAM_DOUBLE: {
-//          char buf[15]; /* locale independent */
-//          fprintf ( f, "%s\n", (char *) g_dtostr (data.d, buf, sizeof (buf)) ); break;
-            fprintf ( f, "%f\n", data.d );
-            break;
-       }
-        case VIK_LAYER_PARAM_UINT: fprintf ( f, "%d\n", data.u ); break;
-        case VIK_LAYER_PARAM_INT: fprintf ( f, "%d\n", data.i ); break;
-        case VIK_LAYER_PARAM_BOOLEAN: fprintf ( f, "%c\n", data.b ? 't' : 'f' ); break;
-        case VIK_LAYER_PARAM_STRING: fprintf ( f, "%s\n", data.s ); break;
-        case VIK_LAYER_PARAM_COLOR: fprintf ( f, "#%.2x%.2x%.2x\n", (int)(data.c.red/256),(int)(data.c.green/256),(int)(data.c.blue/256)); break;
+
+      /* string lists are handled differently. We get a GList (that shouldn't
+       * be freed) back for get_param and if it is null we shouldn't write
+       * anything at all (otherwise we'd read in a list with an empty string,
+ Â      * not an empty string list.
+       */
+      if ( params[i].type == VIK_LAYER_PARAM_STRING_LIST ) {
+        if ( data.sl ) {
+          GList *iter = (GList *)data.sl;
+          while ( iter ) {
+            fprintf ( f, "%s=", params[i].name );
+            fprintf ( f, "%s\n", (gchar *)(iter->data) );
+            iter = iter->next;
+          }
+        }
+      } else {
+        fprintf ( f, "%s=", params[i].name );
+        switch ( params[i].type )
+        {
+          case VIK_LAYER_PARAM_DOUBLE: {
+  //          char buf[15]; /* locale independent */
+  //          fprintf ( f, "%s\n", (char *) g_dtostr (data.d, buf, sizeof (buf)) ); break;
+              fprintf ( f, "%f\n", data.d );
+              break;
+         }
+          case VIK_LAYER_PARAM_UINT: fprintf ( f, "%d\n", data.u ); break;
+          case VIK_LAYER_PARAM_INT: fprintf ( f, "%d\n", data.i ); break;
+          case VIK_LAYER_PARAM_BOOLEAN: fprintf ( f, "%c\n", data.b ? 't' : 'f' ); break;
+          case VIK_LAYER_PARAM_STRING: fprintf ( f, "%s\n", data.s ); break;
+          case VIK_LAYER_PARAM_COLOR: fprintf ( f, "#%.2x%.2x%.2x\n", (int)(data.c.red/256),(int)(data.c.green/256),(int)(data.c.blue/256)); break;
+        }
       }
     }
   }
@@ -208,6 +225,23 @@ static void file_write ( VikAggregateLayer *top, FILE *f, gpointer vp )
 */
 }
 
+static void string_list_delete ( gpointer key, gpointer l, gpointer user_data )
+{
+  GList *iter = (GList *) iter;
+  while ( iter ) {
+    g_free ( iter->data );
+    iter = iter->next;
+  }
+  g_list_free ( (GList *) iter );
+}
+
+static void string_list_set_param (gint i, GList *list, gpointer *layer_and_vp)
+{
+  VikLayerParamData x;
+  x.sl = list;
+  vik_layer_set_param ( VIK_LAYER(layer_and_vp[0]), i, x, layer_and_vp[1] );
+}
+
 static void file_read ( VikAggregateLayer *top, FILE *f, gpointer vp )
 {
   Stack *stack;
@@ -220,6 +254,8 @@ static void file_read ( VikAggregateLayer *top, FILE *f, gpointer vp )
   VikLayerParam *params = NULL; /* for current layer, so we don't have to keep on looking up interface */
   guint8 params_count = 0;
 
+  GHashTable *string_lists = g_hash_table_new(g_direct_hash,g_direct_equal);
+
   push(&stack);
   stack->under = NULL;
   stack->data = (gpointer) top;
@@ -290,6 +326,13 @@ static void file_read ( VikAggregateLayer *top, FILE *f, gpointer vp )
           g_warning ( "Line %ld: Mismatched ~EndLayer command", line_num );
         else
         {
+          /* add any string lists we've accumulated */
+          gpointer layer_and_vp[2];
+          layer_and_vp[0] = stack->data;
+          layer_and_vp[1] = vp;
+          g_hash_table_foreach ( string_lists, (GHFunc) string_list_set_param, layer_and_vp );
+          g_hash_table_remove_all ( string_lists );
+
           if ( stack->data && stack->under->data )
           {
             if (VIK_LAYER(stack->under->data)->type == VIK_LAYER_AGGREGATE) {
@@ -377,6 +420,7 @@ static void file_read ( VikAggregateLayer *top, FILE *f, gpointer vp )
       else if ( eq_pos != -1 && stack->under )
       {
         gboolean found_match = FALSE;
+
         /* go thru layer params. if len == eq_pos && starts_with jazz, set it. */
         /* also got to check for name and visible. */
 
@@ -391,17 +435,25 @@ static void file_read ( VikAggregateLayer *top, FILE *f, gpointer vp )
           {
             VikLayerParamData x;
             line += eq_pos+1;
-            switch ( params[i].type )
-            {
-              case VIK_LAYER_PARAM_DOUBLE: x.d = strtod(line, NULL); break;
-              case VIK_LAYER_PARAM_UINT: x.u = strtoul(line, NULL, 10); break;
-              case VIK_LAYER_PARAM_INT: x.i = strtol(line, NULL, 10); break;
-              case VIK_LAYER_PARAM_BOOLEAN: x.b = TEST_BOOLEAN(line); break;
-              case VIK_LAYER_PARAM_COLOR: memset(&(x.c), 0, sizeof(x.c)); /* default: black */
+            if ( params[i].type == VIK_LAYER_PARAM_STRING_LIST ) {
+              GList *l = g_list_append ( g_hash_table_lookup ( string_lists, (gpointer) ((gint) i) ), g_strdup(line) );
+              g_hash_table_replace ( string_lists, (gpointer) ((gint)i), l );
+              /* add the value to a list, possibly making a new list.
+               * this will be passed to the layer when we read an ~EndLayer */
+            } else {
+              switch ( params[i].type )
+              {
+                case VIK_LAYER_PARAM_DOUBLE: x.d = strtod(line, NULL); break;
+                case VIK_LAYER_PARAM_UINT: x.u = strtoul(line, NULL, 10); break;
+                case VIK_LAYER_PARAM_INT: x.i = strtol(line, NULL, 10); break;
+               case VIK_LAYER_PARAM_BOOLEAN: x.b = TEST_BOOLEAN(line); break;
+                case VIK_LAYER_PARAM_COLOR: memset(&(x.c), 0, sizeof(x.c)); /* default: black */
                                           gdk_color_parse ( line, &(x.c) ); break;
-              default: x.s = line;
+                /* STRING or STRING_LIST -- if STRING_LIST, just set param to add a STRING */
+                default: x.s = line;
+              }
+              vik_layer_set_param ( VIK_LAYER(stack->data), i, x, vp );
             }
-            vik_layer_set_param ( VIK_LAYER(stack->data), i, x, vp );
             found_match = TRUE;
             break;
           }
@@ -435,6 +487,10 @@ name=this
 
   if ( ( ! VIK_LAYER(top)->visible ) && VIK_LAYER(top)->realized )
     vik_treeview_item_set_visible ( VIK_LAYER(top)->vt, &(VIK_LAYER(top)->iter), FALSE ); 
+
+  /* delete anything we've forgotten about -- should only happen when file ends before an EndLayer */
+  g_hash_table_foreach ( string_lists, string_list_delete, NULL );
+  g_hash_table_destroy ( string_lists );
 }
 
 /*
index eee55b41c370fec8bbcca51061a86ab74fbaa7d8..44e4a54384b65f9d8ed8240b795fa9a7ff5c0fb3 100644 (file)
@@ -23,6 +23,7 @@
 #include "icons/viking_icon.png_h"
 #include "mapcache.h"
 #include "background.h"
+#include "dems.h"
 #include "curl_download.h"
 
 #include <string.h>
@@ -120,6 +121,7 @@ int main( int argc, char *argv[] )
   gdk_threads_leave ();
 
   a_mapcache_uninit ();
+  a_dems_uninit ();
 
   return 0;
 }
index 50faceafcc90e665f8c7d7a9ece36a23d1b72d89..2970d456dc412170a6ad1622318a617744af24c3 100644 (file)
@@ -31,12 +31,12 @@ static VikLayerParamData coord_layer_get_param ( VikCoordLayer *vcl, guint16 id
 static void coord_layer_update_gc ( VikCoordLayer *vcl, VikViewport *vp, const gchar *color );
 static void coord_layer_post_read ( VikCoordLayer *vcl, VikViewport *vp );
 
-VikLayerParamScale param_scales[] = {
+static VikLayerParamScale param_scales[] = {
   { 0.05, 60.0, 0.25, 10 },
   { 1, 10, 1, 0 },
 };
 
-VikLayerParam coord_layer_params[] = {
+static VikLayerParam coord_layer_params[] = {
   { "color", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, "Color:", VIK_LAYER_WIDGET_ENTRY },
   { "min_inc", VIK_LAYER_PARAM_DOUBLE, VIK_LAYER_GROUP_NONE, "Minutes Width:", 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 },
diff --git a/src/vikdemlayer.c b/src/vikdemlayer.c
new file mode 100644 (file)
index 0000000..81383dd
--- /dev/null
@@ -0,0 +1,575 @@
+/*
+ * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
+ *
+ * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <math.h>
+
+#include "globals.h"
+#include "coords.h"
+#include "vikcoord.h"
+#include "download.h"
+#include "vikwaypoint.h"
+#include "viktrack.h"
+#include "vikviewport.h"
+#include "viktreeview.h"
+#include "viklayer.h"
+#include "vikaggregatelayer.h"
+#include "viklayerspanel.h"
+#include "vikdemlayer.h"
+#include "vikdemlayer_pixmap.h"
+
+#include "dem.h"
+#include "dems.h"
+
+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 ( VikDEMLayer *vdl, VikViewport *vp );
+
+static VikLayerParamScale param_scales[] = {
+  { 1, 10000, 10, 1 },
+  { 1, 10, 1, 0 },
+};
+
+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 },
+};
+
+/*
+*/
+
+
+static gchar *dem_colors[] = {
+"#0000FF",
+"#9b793c",
+"#9c7d40",
+"#9d8144",
+"#9e8549",
+"#9f894d",
+"#a08d51",
+"#a29156",
+"#a3955a",
+"#a4995e",
+"#a69d63",
+"#a89f65",
+"#aaa267",
+"#ada569",
+"#afa76b",
+"#b1aa6d",
+"#b4ad6f",
+"#b6b071",
+"#b9b373",
+"#bcb676",
+"#beb978",
+"#c0bc7a",
+"#c2c07d",
+"#c4c37f",
+"#c6c681",
+"#c8ca84",
+"#cacd86",
+"#ccd188",
+"#cfd58b",
+"#c2ce84",
+"#b5c87e",
+"#a9c278",
+"#9cbb71",
+"#8fb56b",
+"#83af65",
+"#76a95e",
+"#6aa358",
+"#5e9d52",
+"#63a055",
+"#69a458",
+"#6fa85c",
+"#74ac5f",
+"#7ab063",
+"#80b467",
+"#86b86a",
+"#8cbc6e",
+"#92c072",
+"#94c175",
+"#97c278",
+"#9ac47c",
+"#9cc57f",
+"#9fc682",
+"#a2c886",
+"#a4c989",
+"#a7cb8d",
+"#aacd91",
+"#afce99",
+"#b5d0a1",
+"#bbd2aa",
+"#c0d3b2",
+"#c6d5ba",
+"#ccd7c3",
+"#d1d9cb",
+"#d7dbd4",
+"#DDDDDD",
+"#e0e0e0",
+"#e4e4e4",
+"#e8e8e8",
+"#ebebeb",
+"#efefef",
+"#f3f3f3",
+"#f7f7f7",
+"#fbfbfb",
+"#ffffff"
+};
+
+/*
+"#9b793c",
+"#9e8549",
+"#a29156",
+"#a69d63",
+"#ada569",
+"#b4ad6f",
+"#bcb676",
+"#c2c07d",
+"#c8ca84",
+"#cfd58b",
+"#a9c278",
+"#83af65",
+"#5e9d52",
+"#6fa85c",
+"#80b467",
+"#92c072",
+"#9ac47c",
+"#a2c886",
+"#aacd91",
+"#bbd2aa",
+"#ccd7c3",
+"#DDDDDD",
+"#e8e8e8",
+"#f3f3f3",
+"#FFFFFF"
+};
+*/
+
+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,
+
+  NULL,
+  0,
+
+  dem_layer_params,
+  NUM_PARAMS,
+  NULL,
+  0,
+
+  VIK_MENU_ITEM_ALL,
+
+  (VikLayerFuncCreate)                  vik_dem_layer_create,
+  (VikLayerFuncRealize)                 NULL,
+  (VikLayerFuncPostRead)                dem_layer_post_read,
+  (VikLayerFuncFree)                    vik_dem_layer_free,
+
+  (VikLayerFuncProperties)              NULL,
+  (VikLayerFuncDraw)                    vik_dem_layer_draw,
+  (VikLayerFuncChangeCoordMode)         NULL,
+
+  (VikLayerFuncSetMenuItemsSelection)   NULL,
+  (VikLayerFuncGetMenuItemsSelection)   NULL,
+
+  (VikLayerFuncAddMenuItems)            NULL,
+  (VikLayerFuncSublayerAddMenuItems)    NULL,
+
+  (VikLayerFuncSublayerRenameRequest)   NULL,
+  (VikLayerFuncSublayerToggleVisible)   NULL,
+
+  (VikLayerFuncCopy)                    dem_layer_copy,
+  (VikLayerFuncMarshall)               dem_layer_marshall,
+  (VikLayerFuncUnmarshall)             dem_layer_unmarshall,
+
+  (VikLayerFuncSetParam)                dem_layer_set_param,
+  (VikLayerFuncGetParam)                dem_layer_get_param,
+
+  (VikLayerFuncReadFileData)            NULL,
+  (VikLayerFuncWriteFileData)           NULL,
+
+  (VikLayerFuncDeleteItem)              NULL,
+  (VikLayerFuncCopyItem)                NULL,
+  (VikLayerFuncPasteItem)               NULL,
+  (VikLayerFuncFreeCopiedItem)          NULL,
+  (VikLayerFuncDragDropRequest)                NULL,
+};
+
+struct _VikDEMLayer {
+  VikLayer vl;
+  GdkGC *gc;
+  GdkGC **gcs;
+  GList *files;
+  gdouble max_elev;
+  guint8 line_thickness;
+  gchar *color;
+};
+
+GType vik_dem_layer_get_type ()
+{
+  static GType vdl_type = 0;
+
+  if (!vdl_type)
+  {
+    static const GTypeInfo vdl_info =
+    {
+      sizeof (VikDEMLayerClass),
+      NULL, /* base_init */
+      NULL, /* base_finalize */
+      NULL, /* class init */
+      NULL, /* class_finalize */
+      NULL, /* class_data */
+      sizeof (VikDEMLayer),
+      0,
+      NULL /* instance init */
+    };
+    vdl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikDEMLayer", &vdl_info, 0 );
+  }
+
+  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 );
+}
+
+static VikDEMLayer *dem_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
+{
+  VikDEMLayer *rv = vik_dem_layer_new ( vvp );
+  vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
+  return rv;
+}
+
+gboolean dem_layer_set_param ( VikDEMLayer *vdl, guint16 id, VikLayerParamData data, VikViewport *vp )
+{
+  switch ( id )
+  {
+    case PARAM_COLOR: if ( vdl->color ) g_free ( vdl->color ); vdl->color = g_strdup ( data.s ); 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;
+  }
+  return TRUE;
+}
+
+static VikLayerParamData dem_layer_get_param ( VikDEMLayer *vdl, guint16 id )
+{
+  VikLayerParamData rv;
+  switch ( id )
+  {
+    case PARAM_FILES: rv.sl = vdl->files; break;
+    case PARAM_COLOR: rv.s = vdl->color ? vdl->color : ""; 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 ( VikDEMLayer *vdl, VikViewport *vp )
+{
+  if ( vdl->gc )
+    g_object_unref ( G_OBJECT(vdl->gc) );
+
+  vdl->gc = vik_viewport_new_gc ( vp, vdl->color, vdl->line_thickness );
+}
+
+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;
+
+
+  vdl->gc = NULL;
+
+  vdl->gcs = g_malloc(sizeof(GdkGC *)*dem_n_colors);
+
+  vdl->max_elev = 1000.0;
+  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);
+
+  /* get min, max lat/lon of DEM data */
+  if ( dem->horiz_units == VIK_DEM_HORIZ_LL_ARCSECONDS ) {
+    dem_northeast.lat = dem->max_north / 3600.0;
+    dem_northeast.lon = dem->max_east / 3600.0;
+    dem_southwest.lat = dem->min_north / 3600.0;
+    dem_southwest.lon = dem->min_east / 3600.0;
+  } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
+    struct UTM dem_northeast_utm, dem_southwest_utm;
+    dem_northeast_utm.northing = dem->max_north;
+    dem_northeast_utm.easting = dem->max_east;
+    dem_southwest_utm.northing = dem->min_north;
+    dem_southwest_utm.easting = dem->min_east;
+    dem_northeast_utm.zone = dem_southwest_utm.zone = dem->utm_zone;
+    dem_northeast_utm.letter = dem_southwest_utm.letter = dem->utm_letter;
+
+    a_coords_utm_to_latlon(&dem_northeast_utm, &dem_northeast);
+    a_coords_utm_to_latlon(&dem_southwest_utm, &dem_southwest);
+  }
+
+  if ( (max_lat > dem_northeast.lat && min_lat > dem_northeast.lat) ||
+       (max_lat < dem_southwest.lat && min_lat < dem_southwest.lat) )
+    return;
+  else if ( (max_lon > dem_northeast.lon && min_lon > dem_northeast.lon) ||
+            (max_lon < dem_southwest.lon && min_lon < dem_southwest.lon) )
+    return;
+  /* else they overlap */
+
+  /**** End Overlap Check ****/
+
+  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 */
+
+    gdouble max_lat_as, max_lon_as, min_lat_as, min_lon_as;  
+    gdouble start_lat_as, end_lat_as, start_lon_as, end_lon_as;
+
+    gdouble start_lat, end_lat, start_lon, end_lon;
+
+    struct LatLon counter;
+
+    guint x, y, start_x, start_y;
+
+    gint16 elev;
+
+    guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 40 ); /* todo: smarter calculation. */
+
+    gdouble nscale_deg = dem->north_scale / ((gdouble) 3600);
+    gdouble escale_deg = dem->east_scale / ((gdouble) 3600);
+
+    max_lat_as = max_lat * 3600;
+    min_lat_as = min_lat * 3600;
+    max_lon_as = max_lon * 3600;
+    min_lon_as = min_lon * 3600;
+
+    start_lat_as = MAX(min_lat_as, dem->min_north);
+    end_lat_as   = MIN(max_lat_as, dem->max_north);
+    start_lon_as = MAX(min_lon_as, dem->min_east);
+    end_lon_as   = MIN(max_lon_as, dem->max_east);
+
+    start_lat = floor(start_lat_as / dem->north_scale) * nscale_deg;
+    end_lat   = ceil (end_lat_as / dem->north_scale) * nscale_deg;
+    start_lon = floor(start_lon_as / dem->east_scale) * escale_deg;
+    end_lon   = ceil (end_lon_as / dem->east_scale) * escale_deg;
+
+    vik_dem_east_north_to_xy ( dem, start_lon_as, start_lat_as, &start_x, &start_y );
+
+    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 );
+        for ( y=start_y, counter.lat = start_lat; counter.lat <= end_lat; counter.lat += nscale_deg * skip_factor, y += skip_factor ) {
+          if ( y > column->n_points )
+            break;
+          elev = column->points[y];
+          if ( elev > vdl->max_elev ) elev=vdl->max_elev;
+          {
+            gint a, b;
+
+            vik_coord_load_from_latlon(&tmp, vik_viewport_get_coord_mode(vp), &counter);
+            vik_viewport_coord_to_screen(vp, &tmp, &a, &b);
+            if ( elev == VIK_DEM_INVALID_ELEVATION )
+              ; /* don't draw it */
+            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 );
+          }
+        } /* for y= */
+      }
+    } /* for x= */
+  } else if ( dem->horiz_units == VIK_DEM_HORIZ_UTM_METERS ) {
+    gdouble max_nor, max_eas, min_nor, min_eas;
+    gdouble start_nor, start_eas, end_nor, end_eas;
+
+    gint16 elev;
+
+    guint x, y, start_x, start_y;
+
+    VikCoord tmp; /* TODO: don't use coord_load_from_latlon, especially if in latlon drawing mode */
+    struct UTM counter;
+
+    guint skip_factor = ceil ( vik_viewport_get_xmpp(vp) / 10 ); /* todo: smarter calculation. */
+
+    vik_coord_convert(&tleft, VIK_COORD_UTM);
+    vik_coord_convert(&tright, VIK_COORD_UTM);
+    vik_coord_convert(&bleft, VIK_COORD_UTM);
+    vik_coord_convert(&bright, VIK_COORD_UTM);
+
+    max_nor = MAX(tleft.north_south, tright.north_south);
+    min_nor = MIN(bleft.north_south, bright.north_south);
+    max_eas = MAX(bright.east_west, tright.east_west);
+    min_eas = MIN(bleft.east_west, tleft.east_west);
+
+    start_nor = MAX(min_nor, dem->min_north);
+    end_nor   = MIN(max_nor, dem->max_north);
+    if ( tleft.utm_zone == dem->utm_zone && bleft.utm_zone == dem->utm_zone
+         && (tleft.utm_letter >= 'N') == (dem->utm_letter >= 'N')
+         && (bleft.utm_letter >= 'N') == (dem->utm_letter >= 'N') ) /* if the utm zones/hemispheres are different, min_eas will be bogus */
+      start_eas = MAX(min_eas, dem->min_east);
+    else
+      start_eas = dem->min_east;
+    if ( tright.utm_zone == dem->utm_zone && bright.utm_zone == dem->utm_zone
+         && (tright.utm_letter >= 'N') == (dem->utm_letter >= 'N')
+         && (bright.utm_letter >= 'N') == (dem->utm_letter >= 'N') ) /* if the utm zones/hemispheres are different, min_eas will be bogus */
+      end_eas = MIN(max_eas, dem->max_east);
+    else
+      end_eas = dem->max_east;
+
+    start_nor = floor(start_nor / dem->north_scale) * dem->north_scale;
+    end_nor   = ceil (end_nor / dem->north_scale) * dem->north_scale;
+    start_eas = floor(start_eas / dem->east_scale) * dem->east_scale;
+    end_eas   = ceil (end_eas / dem->east_scale) * dem->east_scale;
+
+    vik_dem_east_north_to_xy ( dem, start_eas, start_nor, &start_x, &start_y );
+
+    /* TODO: why start_x and start_y are -1 -- rounding error from above? */
+
+    counter.zone = dem->utm_zone;
+    counter.letter = dem->utm_letter;
+
+    for ( x=start_x, counter.easting = start_eas; counter.easting <= end_eas; counter.easting += dem->east_scale * skip_factor, x += skip_factor ) {
+      if ( x > 0 && x < dem->n_columns ) {
+        column = g_ptr_array_index ( dem->columns, x );
+        for ( y=start_y, counter.northing = start_nor; counter.northing <= end_nor; counter.northing += dem->north_scale * skip_factor, y += skip_factor ) {
+          if ( y > column->n_points )
+            continue;
+          elev = column->points[y];
+          if ( elev > vdl->max_elev ) elev=vdl->max_elev;
+          {
+            gint a, b;
+            vik_coord_load_from_utm(&tmp, vik_viewport_get_coord_mode(vp), &counter);
+                   vik_viewport_coord_to_screen(vp, &tmp, &a, &b);
+            if ( elev == VIK_DEM_INVALID_ELEVATION )
+              ; /* don't draw it */
+            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 );
+          }
+        } /* for y= */
+      }
+    } /* for x= */
+  }
+}
+
+void vik_dem_layer_draw ( VikDEMLayer *vdl, gpointer data )
+{
+  VikViewport *vp = (VikViewport *) data;
+  GList *dems_iter = vdl->files;
+  VikDEM *dem;
+  while ( dems_iter ) {
+    dem = a_dems_get ( (const char *) (dems_iter->data) );
+    if ( dem )
+      vik_dem_layer_draw_dem ( vdl, vp, dem );
+    dems_iter = dems_iter->next;
+  }
+}
+
+void vik_dem_layer_free ( VikDEMLayer *vdl )
+{
+  if ( vdl->gc != NULL )
+    g_object_unref ( G_OBJECT(vdl->gc) );
+
+  if ( vdl->color != NULL )
+    g_free ( vdl->color );
+
+  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 );
+
+  vdl->color = g_strdup ( color );
+
+  if ( vdl->gc )
+    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 ();
+  dem_layer_update_gc ( vdl, vp, "red" );
+  return vdl;
+}
+
diff --git a/src/vikdemlayer.h b/src/vikdemlayer.h
new file mode 100644 (file)
index 0000000..98bf811
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
+ *
+ * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _VIKING_DEMLAYER_H
+#define _VIKING_DEMLAYER_H
+
+#include "viklayer.h"
+
+#define VIK_DEM_LAYER_TYPE            (vik_dem_layer_get_type ())
+#define VIK_DEM_LAYER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIK_DEM_LAYER_TYPE, VikDEMLayer))
+#define VIK_DEM_LAYER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), VIK_DEM_LAYER_TYPE, VikDEMLayerClass))
+#define IS_VIK_DEM_LAYER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIK_DEM_LAYER_TYPE))
+#define IS_VIK_DEM_LAYER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VIK_DEM_LAYER_TYPE))
+
+typedef struct _VikDEMLayerClass VikDEMLayerClass;
+struct _VikDEMLayerClass
+{
+  VikLayerClass object_class;
+};
+
+GType vik_dem_layer_get_type ();
+
+typedef struct _VikDEMLayer VikDEMLayer;
+
+/* TODO 0.0.8: yup, everything goes. */
+
+VikDEMLayer *vik_dem_layer_new ( );
+void vik_dem_layer_draw ( VikDEMLayer *vcl, gpointer data );
+void vik_dem_layer_free ( VikDEMLayer *vcl );
+
+VikDEMLayer *vik_dem_layer_create ( VikViewport *vp );
+gboolean vik_dem_layer_properties ( VikDEMLayer *vcl, gpointer vp );
+
+
+#endif
diff --git a/src/vikdemlayer_pixmap.h b/src/vikdemlayer_pixmap.h
new file mode 100644 (file)
index 0000000..117889b
--- /dev/null
@@ -0,0 +1,20 @@
+/* GdkPixbuf RGB C-Source image dump 1-byte-run-length-encoded */
+
+static const GdkPixdata demlayer_pixbuf = {
+  0x47646b50, /* Pixbuf magic: 'GdkP' */
+  24 + 132, /* header length + pixel_data length */
+  0x2010001, /* pixdata_type */
+  48, /* rowstride */
+  16, /* width */
+  16, /* height */
+  /* pixel_data: */
+  "\233\377\377\377\1\307\353\361\217\377\377\377\202\201\322\341\215\377"
+  "\377\377\203m\306\377\214\377\377\377\205L*\340\207\377\377\377\1!\12"
+  "\203\203\377\377\377\205!\12\203\207\377\377\377\1\12T\203\202\377\377"
+  "\377\210\12T\203\204\377\377\377\203\12\203s\1\377\377\377\210\12\203"
+  "s\203\377\377\377\215\12\203\36\202\377\377\377\216)\265\33\202\377\377"
+  "\377\216Y\265\33\1\377\377\377\217\213\265\33\1\377\377\377\217\250\265"
+  "\33\220\265\226\33\220\313S\36\220\207\25\25",
+};
+
+
diff --git a/src/vikfilelist.c b/src/vikfilelist.c
new file mode 100644 (file)
index 0000000..77c2205
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
+ *
+ * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <gtk/gtk.h>
+
+#include "vikfilelist.h"
+#include "vikfileentry.h"
+
+struct _VikFileList {
+  GtkVBox parent;
+  VikFileEntry *file_entry;
+  GtkWidget *treeview;
+  GtkTreeModel *model;
+};
+
+static void file_list_add ( VikFileList *vfl )
+{
+  GtkTreeIter iter;
+  gtk_list_store_append ( GTK_LIST_STORE(vfl->model), &iter );
+  gtk_list_store_set ( GTK_LIST_STORE(vfl->model), &iter, 0, vik_file_entry_get_filename(vfl->file_entry), -1 );
+}
+
+static void file_list_del ( VikFileList *vfl )
+{
+  GtkTreeSelection *ts = gtk_tree_view_get_selection (GTK_TREE_VIEW(vfl->treeview));
+  GtkTreeIter iter;
+  if ( gtk_tree_selection_get_selected(ts, NULL, &iter) )
+    gtk_list_store_remove(GTK_LIST_STORE(vfl->model), &iter);
+}
+
+GType vik_file_list_get_type (void)
+{
+  static GType vs_type = 0;
+
+  if (!vs_type)
+  {
+    static const GTypeInfo vs_info = 
+    {
+      sizeof (VikFileListClass),
+      NULL, /* base_init */
+      NULL, /* base_finalize */
+      NULL, /* class init */
+      NULL, /* class_finalize */
+      NULL, /* class_data */
+      sizeof (VikFileList),
+      0,
+      NULL /* instance init */
+    };
+    vs_type = g_type_register_static ( GTK_TYPE_VBOX, "VikFileList", &vs_info, 0 );
+  }
+
+  return vs_type;
+}
+
+GtkWidget *vik_file_list_new ( const gchar *title )
+{
+  GtkWidget *add_btn, *del_btn;
+  GtkWidget *hbox, *scrolledwindow;
+  VikFileList *vfl = VIK_FILE_LIST ( g_object_new ( VIK_FILE_LIST_TYPE, NULL ) );
+
+  GtkTreeViewColumn *column;
+
+  vfl->model = GTK_TREE_MODEL ( gtk_list_store_new(1, G_TYPE_STRING) );
+
+  vfl->treeview = gtk_tree_view_new ( );
+  gtk_tree_view_set_model ( GTK_TREE_VIEW(vfl->treeview), vfl->model );
+  column = gtk_tree_view_column_new_with_attributes ( title, gtk_cell_renderer_text_new (), "text", 0, NULL);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (vfl->treeview), column);
+
+  gtk_widget_set_size_request ( vfl->treeview, 200, 100);
+
+  vfl->file_entry = VIK_FILE_ENTRY(vik_file_entry_new());
+  add_btn = gtk_button_new_with_label("Add");
+  del_btn = gtk_button_new_with_label("Delete");
+
+  g_signal_connect_swapped ( G_OBJECT(add_btn), "clicked", G_CALLBACK(file_list_add), vfl );
+  g_signal_connect_swapped ( G_OBJECT(del_btn), "clicked", G_CALLBACK(file_list_del), vfl );
+
+  hbox = gtk_hbox_new(FALSE, 2);
+
+  scrolledwindow = gtk_scrolled_window_new ( NULL, NULL );
+  gtk_scrolled_window_set_policy ( GTK_SCROLLED_WINDOW(scrolledwindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
+  gtk_container_add ( GTK_CONTAINER(scrolledwindow), GTK_WIDGET(vfl->treeview) );
+
+  gtk_box_pack_start ( GTK_BOX(vfl), scrolledwindow, TRUE, TRUE, 3 );
+
+
+  gtk_box_pack_start ( GTK_BOX(hbox), GTK_WIDGET(vfl->file_entry), TRUE, TRUE, 3 );
+  gtk_box_pack_start ( GTK_BOX(hbox), add_btn, TRUE, TRUE, 3 );
+  gtk_box_pack_start ( GTK_BOX(hbox), del_btn, TRUE, TRUE, 3 );
+  gtk_box_pack_start ( GTK_BOX(vfl), hbox, FALSE, FALSE, 3 );
+  gtk_widget_show_all(GTK_WIDGET(vfl));
+
+
+  return GTK_WIDGET(vfl);
+}
+
+static gboolean get_file_name(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, GList **list)
+{
+  gchar *str;
+  gtk_tree_model_get ( model, iter, 0, &str, -1 );
+  printf("%s\n\n\n", str);
+  (*list) = g_list_append((*list), g_strdup(str));
+  return FALSE;
+}
+
+GList *vik_file_list_get_files ( VikFileList *vfl )
+{
+  GList *list = NULL;
+  gtk_tree_model_foreach (vfl->model, (GtkTreeModelForeachFunc) get_file_name, &list);
+  return list;
+}
+
+void vik_file_list_set_files ( VikFileList *vfl, GList *files )
+{
+  while (files) {
+    GtkTreeIter iter;
+    gtk_list_store_append ( GTK_LIST_STORE(vfl->model), &iter );
+    gtk_list_store_set ( GTK_LIST_STORE(vfl->model), &iter, 0, files->data, -1 );
+    files = files->next;
+  }
+}
diff --git a/src/vikfilelist.h b/src/vikfilelist.h
new file mode 100644 (file)
index 0000000..3b2665e
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
+ *
+ * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _VIKING_FILELIST_H
+#define _VIKING_FILELIST_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtkvbox.h>
+
+G_BEGIN_DECLS
+
+#define VIK_FILE_LIST_TYPE            (vik_file_list_get_type ())
+#define VIK_FILE_LIST(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIK_FILE_LIST_TYPE, VikFileList))
+#define VIK_FILE_LIST_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), VIK_FILE_LIST_TYPE, VikFileListClass))
+#define IS_VIK_FILE_LIST(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIK_FILE_LIST_TYPE))
+#define IS_VIK_FILE_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VIK_FILE_LIST_TYPE))
+
+typedef struct _VikFileList VikFileList;
+typedef struct _VikFileListClass VikFileListClass;
+
+struct _VikFileListClass
+{
+  GtkVBoxClass vbox_class;
+};
+
+GType vik_file_list_get_type ();
+
+GtkWidget *vik_file_list_new ( const gchar *title );
+/* result must be freed */
+GList *vik_file_list_get_files ( VikFileList *vfl );
+void vik_file_list_set_files ( VikFileList *vfl, GList * );
+
+#endif
index aefa1822f004b629727acce07a364a18b43db0be..e802fbc1e2f1be4ee369b8764687cfeba2501ffa 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "viking.h"
 #include "vikradiogroup.h"
+#include "vikfilelist.h"
 #include <string.h>
 
 /* functions common to all layers. */
@@ -32,6 +33,7 @@ extern VikLayerInterface vik_maps_layer_interface;
 extern VikLayerInterface vik_coord_layer_interface;
 extern VikLayerInterface vik_georef_layer_interface;
 extern VikLayerInterface vik_gps_layer_interface;
+extern VikLayerInterface vik_dem_layer_interface;
 
 enum {
   VL_UPDATE_SIGNAL,
@@ -101,6 +103,7 @@ static VikLayerInterface *vik_layer_interfaces[VIK_LAYER_NUM_TYPES] = {
   &vik_georef_layer_interface,
   &vik_gps_layer_interface,
   &vik_maps_layer_interface,
+  &vik_dem_layer_interface,
 };
 
 VikLayerInterface *vik_layer_get_interface ( gint type )
@@ -422,6 +425,7 @@ static GtkWidget *properties_widget_new_widget ( VikLayerParam *param, VikLayerP
       }
       break;
     case VIK_LAYER_WIDGET_COMBOBOX:
+#ifndef GTK_2_2
       if ( param->type == VIK_LAYER_PARAM_UINT && param->widget_data )
       {
         gchar **pstr = param->widget_data;
@@ -441,6 +445,7 @@ static GtkWidget *properties_widget_new_widget ( VikLayerParam *param, VikLayerP
         gtk_combo_box_set_active ( GTK_COMBO_BOX ( rv ), data.u );
       }
       break;
+#endif
     case VIK_LAYER_WIDGET_RADIOGROUP:
       /* widget_data and extra_widget_data are GList */
       if ( param->type == VIK_LAYER_PARAM_UINT && param->widget_data )
@@ -484,6 +489,13 @@ static GtkWidget *properties_widget_new_widget ( VikLayerParam *param, VikLayerP
         vik_file_entry_set_filename ( VIK_FILE_ENTRY(rv), data.s );
       }
       break;
+    case VIK_LAYER_WIDGET_FILELIST:
+      if ( param->type == VIK_LAYER_PARAM_STRING_LIST )
+      {
+        rv = vik_file_list_new ( param->title );
+        vik_file_list_set_files ( VIK_FILE_LIST(rv), data.sl );
+      }
+      break;
     case VIK_LAYER_WIDGET_HSCALE:
       if ( (param->type == VIK_LAYER_PARAM_DOUBLE || param->type == VIK_LAYER_PARAM_UINT
            || param->type == VIK_LAYER_PARAM_INT)  && param->widget_data )
@@ -510,12 +522,14 @@ static VikLayerParamData properties_widget_get_value ( GtkWidget *widget, VikLay
       rv.b = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
       break;
     case VIK_LAYER_WIDGET_COMBOBOX:
+#ifndef GTK_2_2
       rv.i = gtk_combo_box_get_active ( GTK_COMBO_BOX(widget) );
       if ( rv.i == -1 ) rv.i = 0;
       rv.u = rv.i;
       if ( param->extra_widget_data )
         rv.u = ((guint *)param->extra_widget_data)[rv.u];
       break;
+#endif
     case VIK_LAYER_WIDGET_RADIOGROUP:
       rv.u = vik_radio_group_get_selected(VIK_RADIO_GROUP(widget));
       if ( param->extra_widget_data )
@@ -535,6 +549,9 @@ static VikLayerParamData properties_widget_get_value ( GtkWidget *widget, VikLay
     case VIK_LAYER_WIDGET_FILEENTRY:
       rv.s = vik_file_entry_get_filename ( VIK_FILE_ENTRY(widget) );
       break;
+    case VIK_LAYER_WIDGET_FILELIST:
+      rv.sl = vik_file_list_get_files ( VIK_FILE_LIST(widget) );
+      break;
     case VIK_LAYER_WIDGET_HSCALE:
       if ( param->type == VIK_LAYER_PARAM_UINT )
         rv.u = (guint32) gtk_range_get_value ( GTK_RANGE(widget) );
index f08658aec4c8fcf86f200d9c4e6f607df514bfb9..a8df0951d5dbf45b83f36b6eeecf81a9ce20ed92 100644 (file)
@@ -69,6 +69,7 @@ enum {
   VIK_LAYER_GEOREF,
   VIK_LAYER_GPS,
   VIK_LAYER_MAPS,
+  VIK_LAYER_DEM,
   VIK_LAYER_NUM_TYPES
 };
 
@@ -107,6 +108,7 @@ typedef union {
   gboolean b;
   const gchar *s;
   GdkColor c;
+  GList *sl;
 } VikLayerParamData;
 
 typedef struct {
@@ -133,6 +135,7 @@ VIK_LAYER_WIDGET_FILEENTRY,
 VIK_LAYER_WIDGET_HSCALE,
 VIK_LAYER_WIDGET_COLOR,
 VIK_LAYER_WIDGET_COMBOBOX,
+VIK_LAYER_WIDGET_FILELIST,
 };
 
 typedef struct {
@@ -150,6 +153,14 @@ VIK_LAYER_PARAM_INT,
 VIK_LAYER_PARAM_STRING,
 VIK_LAYER_PARAM_BOOLEAN,
 VIK_LAYER_PARAM_COLOR,
+
+/* NOTE: string layer works auniquely: data.sl should NOT be free'd when
+ * the internals call get_param -- i.e. it should be managed w/in the layer.
+ * The value passed by the internals into set_param should also be managed
+ * by the layer -- i.e. free'd by the layer.
+ */
+
+VIK_LAYER_PARAM_STRING_LIST,
 };
 
 /* layer interface functions */
index 5055b82edb0a2de26cab28018d55e3a0f4163c57..0b2ebc3208c49d4fbab02e6908fda954aefffdb1 100644 (file)
@@ -29,6 +29,7 @@
 #include "vikcoord.h"
 #include "viktrack.h"
 #include "globals.h"
+#include "dems.h"
 
 VikTrack *vik_track_new()
 {
@@ -748,3 +749,21 @@ VikTrack *vik_track_unmarshall (guint8 *data, guint datalen)
   }
   return new_tr;
 }
+
+void vik_track_apply_dem_data ( VikTrack *tr, GList *dems )
+{
+  GList *tp_iter;
+  gint16 elev;
+  if ( ! dems )
+    return;
+  tp_iter = tr->trackpoints;
+  while ( tp_iter ) {
+    /* TODO: of the 4 possible choices we have for choosing an elevation
+     * (trackpoint in between samples), choose the one with the least elevation change
+     * as the last */
+    elev = a_dems_list_get_elev_by_coord ( dems, &(VIK_TRACKPOINT(tp_iter->data)->coord) );
+    if ( elev != VIK_DEM_INVALID_ELEVATION )
+      VIK_TRACKPOINT(tp_iter->data)->altitude = elev;
+    tp_iter = tp_iter->next;
+  }
+}
index b74cea527a09da3527bbf63d67c41595a4281c81..60b4f9b36f1fe7d23c3907ede667ba6bd4bb97d0 100644 (file)
@@ -80,4 +80,7 @@ gboolean vik_track_get_minmax_alt ( const VikTrack *tr, gdouble *min_alt, gdoubl
 void vik_track_marshall ( VikTrack *tr, guint8 **data, guint *len);
 VikTrack *vik_track_unmarshall (guint8 *data, guint datalen);
 
+void vik_track_apply_dem_data ( VikTrack *tr, GList *dems );
+
+
 #endif
index b3d0e1d0cbc7586b76d15931d1e5114d9acf1c90..eb2219aa9c46823e24736ab348acc85ae1315c7d 100644 (file)
@@ -34,6 +34,9 @@
 #include "background.h"
 #include "gpx.h"
 #include "babel.h"
+#include "dem.h"
+#include "dems.h"
+
 
 #include <math.h>
 #include <string.h>
@@ -140,6 +143,9 @@ struct _VikTrwLayer {
 
   gboolean has_verified_thumbnails;
 
+  /* DEM files */
+  GList *dems;
+
   GtkMenu *wp_right_click_menu;
 
   /* menu */
@@ -280,8 +286,8 @@ static VikToolInterface trw_layer_tools[] = {
 
 /****** PARAMETERS ******/
 
-static gchar *params_groups[] = { "Waypoints", "Tracks", "Waypoint Images" };
-enum { GROUP_WAYPOINTS, GROUP_TRACKS, GROUP_IMAGES };
+static gchar *params_groups[] = { "Waypoints", "Tracks", "Waypoint Images", "DEM Data" };
+enum { GROUP_WAYPOINTS, GROUP_TRACKS, GROUP_IMAGES, GROUP_DEM };
 
 static gchar *params_drawmodes[] = { "Draw by Track", "Draw by Velocity", "All Tracks Black", 0 };
 static gchar *params_wpsymbols[] = { "Filled Square", "Square", "Circle", "X", 0 };
@@ -334,9 +340,17 @@ VikLayerParam trw_layer_params[] = {
   { "image_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, "Image Size (pixels):", VIK_LAYER_WIDGET_HSCALE, params_scales + 3 },
   { "image_alpha", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, "Image Alpha:", VIK_LAYER_WIDGET_HSCALE, params_scales + 4 },
   { "image_cache_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, "Image Memory Cache Size:", VIK_LAYER_WIDGET_HSCALE, params_scales + 5 },
+
+  { "dems", VIK_LAYER_PARAM_STRING_LIST, GROUP_DEM, "DEM Files:", VIK_LAYER_WIDGET_FILELIST },
 };
 
-enum { PARAM_TV, PARAM_WV, PARAM_DM, PARAM_DL, PARAM_DP, PARAM_DE, PARAM_EF, PARAM_DS, PARAM_SL, PARAM_LT, PARAM_BLT, PARAM_TBGC, PARAM_VMIN, PARAM_VMAX, PARAM_DLA, PARAM_WPC, PARAM_WPTC, PARAM_WPBC, PARAM_WPBA, PARAM_WPSYM, PARAM_WPSIZE, PARAM_WPSYMS, PARAM_DI, PARAM_IS, PARAM_IA, PARAM_ICS, NUM_PARAMS };
+enum { PARAM_TV, PARAM_WV, PARAM_DM, PARAM_DL, PARAM_DP, PARAM_DE, PARAM_EF, PARAM_DS, PARAM_SL, PARAM_LT, PARAM_BLT, PARAM_TBGC, PARAM_VMIN, PARAM_VMAX, PARAM_DLA, PARAM_WPC, PARAM_WPTC, PARAM_WPBC, PARAM_WPBA, PARAM_WPSYM, PARAM_WPSIZE, PARAM_WPSYMS, PARAM_DI, PARAM_IS, PARAM_IA, PARAM_ICS, PARAM_DEMS, NUM_PARAMS };
+
+/*** TO ADD A PARAM:
+ *** 1) Add to trw_layer_params and enumeration
+ *** 2) Handle in get_param & set_param (presumably adding on to VikTrwLayer struct)
+ *** 3) Add code to copy_layer, free, and new (try searching for ->dems)
+ ***/
 
 /****** END PARAMETERS ******/
 
@@ -582,6 +596,7 @@ static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerPara
     case PARAM_WPSYM: if ( data.u < WP_NUM_SYMBOLS ) vtl->wp_symbol = data.u; break;
     case PARAM_WPSIZE: if ( data.u > 0 && data.u <= 64 ) vtl->wp_size = data.u; break;
     case PARAM_WPSYMS: vtl->wp_draw_symbols = data.b; break;
+    case PARAM_DEMS: a_dems_load_list ( &(data.sl) ); a_dems_list_free ( vtl->dems ); vtl->dems = data.sl; break;
   }
   return TRUE;
 }
@@ -617,6 +632,7 @@ static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id )
     case PARAM_WPSYM: rv.u = vtl->wp_symbol; break;
     case PARAM_WPSIZE: rv.u = vtl->wp_size; break;
     case PARAM_WPSYMS: rv.b = vtl->wp_draw_symbols; break;
+    case PARAM_DEMS: rv.sl = vtl->dems; break;
   }
   return rv;
 }
@@ -728,6 +744,8 @@ static VikTrwLayer *trw_layer_copy ( VikTrwLayer *vtl, gpointer vp )
   g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_copy, rv->waypoints );
   g_hash_table_foreach ( vtl->tracks, (GHFunc) track_copy, rv->tracks );
 
+  rv->dems = a_dems_list_copy ( vtl->dems );
+
   return rv;
 }
 
@@ -755,6 +773,8 @@ VikTrwLayer *vik_trw_layer_new ( gint drawmode )
   rv->tracks_iters = g_hash_table_new_full ( g_str_hash, g_str_equal, NULL, g_free );
   rv->waypoints_iters = g_hash_table_new_full ( g_str_hash, g_str_equal, NULL, g_free );
 
+  rv->dems = NULL;
+
   /* TODO: constants at top */
   rv->waypoints_visible = rv->tracks_visible = TRUE;
   rv->drawmode = drawmode;
@@ -803,6 +823,8 @@ void vik_trw_layer_free ( VikTrwLayer *trwlayer )
   g_hash_table_destroy(trwlayer->waypoints);
   g_hash_table_destroy(trwlayer->tracks);
 
+  a_dems_list_free ( trwlayer->dems );
+
   /* ODC: replace with GArray */
   trw_layer_free_track_gcs ( trwlayer );
 
@@ -1980,6 +2002,16 @@ static void trw_layer_goto_track_center ( gpointer pass_along[5] )
   }
 }
 
+static void trw_layer_apply_dem_data ( gpointer pass_along[6] )
+{
+  /* TODO: check & warn if no DEM data, or no applicable DEM data. */
+  /* Also warn if overwrite old elevation data */
+  VikTrack *track = (VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] );
+
+  vik_track_apply_dem_data ( track, VIK_TRW_LAYER(pass_along[0])->dems );
+}
+
+
 static void trw_layer_goto_track_endpoint ( gpointer pass_along[6] )
 {
   GList *trps = ((VikTrack *) g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->tracks, pass_along[3] ))->trackpoints;
@@ -2438,6 +2470,11 @@ gboolean vik_trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *menu,
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_download_map_along_track_cb), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
     gtk_widget_show ( item );
+
+    item = gtk_menu_item_new_with_label ( "Apply DEM Data" );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_apply_dem_data), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
+    gtk_widget_show ( item );
   }
 
   if ( vlp && (subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINTS || subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT) )