From ad0a8c2dc0306d5b311df4c51915e20233ba859f Mon Sep 17 00:00:00 2001 From: Evan Battaglia Date: Fri, 6 Jul 2007 17:04:18 +0000 Subject: [PATCH] Merge DEM branch --- ChangeLog | 13 + src/Makefile.am | 7 +- src/dem.c | 370 +++++++++++++++++++++++++ src/dem.h | 47 ++++ src/dems.c | 160 +++++++++++ src/dems.h | 18 ++ src/file.c | 102 +++++-- src/main.c | 2 + src/vikcoordlayer.c | 4 +- src/vikdemlayer.c | 575 +++++++++++++++++++++++++++++++++++++++ src/vikdemlayer.h | 53 ++++ src/vikdemlayer_pixmap.h | 20 ++ src/vikfilelist.c | 140 ++++++++++ src/vikfilelist.h | 52 ++++ src/viklayer.c | 17 ++ src/viklayer.h | 11 + src/viktrack.c | 19 ++ src/viktrack.h | 3 + src/viktrwlayer.c | 43 ++- 19 files changed, 1627 insertions(+), 29 deletions(-) create mode 100644 src/dem.c create mode 100644 src/dem.h create mode 100644 src/dems.c create mode 100644 src/dems.h create mode 100644 src/vikdemlayer.c create mode 100644 src/vikdemlayer.h create mode 100644 src/vikdemlayer_pixmap.h create mode 100644 src/vikfilelist.c create mode 100644 src/vikfilelist.h diff --git a/ChangeLog b/ChangeLog index 75691532..27e41c03 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2007-07-06 +Evan Battaglia : + * Merge DEM Branch + 2007-07-04 Quy Tonthat : * Bug fix: View Mode displayed wrong setting on start up @@ -7,6 +11,11 @@ Quy Tonthat : * 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 + * 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 : * Fixed bugs that caused crashes during GPS upload/download. @@ -103,6 +112,10 @@ Quy Tonthat : * Disable prompt for save before exit. * Add "Save and Exit" to File menu. +2007-05-20 +Evan Battaglia + * DEM Branch + 2007-05-20 Quy Tonthat : * Stop autodownload from running forever on map downloading errors. diff --git a/src/Makefile.am b/src/Makefile.am index 252ec6e4..7d35b1d1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 index 00000000..3badc4a0 --- /dev/null +++ b/src/dem.c @@ -0,0 +1,370 @@ +#include +#include +#include +#include +#include + +#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 index 00000000..0d90f048 --- /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 index 00000000..d3d88946 --- /dev/null +++ b/src/dems.c @@ -0,0 +1,160 @@ +#include + +#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 index 00000000..6c9da1c6 --- /dev/null +++ b/src/dems.h @@ -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 + diff --git a/src/file.c b/src/file.c index be4fb118..a105b0a1 100644 --- a/src/file.c +++ b/src/file.c @@ -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 ); } /* diff --git a/src/main.c b/src/main.c index eee55b41..44e4a543 100644 --- a/src/main.c +++ b/src/main.c @@ -23,6 +23,7 @@ #include "icons/viking_icon.png_h" #include "mapcache.h" #include "background.h" +#include "dems.h" #include "curl_download.h" #include @@ -120,6 +121,7 @@ int main( int argc, char *argv[] ) gdk_threads_leave (); a_mapcache_uninit (); + a_dems_uninit (); return 0; } diff --git a/src/vikcoordlayer.c b/src/vikcoordlayer.c index 50faceaf..2970d456 100644 --- a/src/vikcoordlayer.c +++ b/src/vikcoordlayer.c @@ -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 index 00000000..81383dd4 --- /dev/null +++ b/src/vikdemlayer.c @@ -0,0 +1,575 @@ +/* + * viking -- GPS Data and Topo Analyzer, Explorer, and Manager + * + * Copyright (C) 2003-2005, Evan Battaglia + * + * 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 + +#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 index 00000000..98bf811e --- /dev/null +++ b/src/vikdemlayer.h @@ -0,0 +1,53 @@ +/* + * viking -- GPS Data and Topo Analyzer, Explorer, and Manager + * + * Copyright (C) 2003-2005, Evan Battaglia + * + * 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 index 00000000..117889b5 --- /dev/null +++ b/src/vikdemlayer_pixmap.h @@ -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 index 00000000..77c22059 --- /dev/null +++ b/src/vikfilelist.c @@ -0,0 +1,140 @@ +/* + * viking -- GPS Data and Topo Analyzer, Explorer, and Manager + * + * Copyright (C) 2003-2005, Evan Battaglia + * + * 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 + +#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 index 00000000..3b2665e2 --- /dev/null +++ b/src/vikfilelist.h @@ -0,0 +1,52 @@ +/* + * viking -- GPS Data and Topo Analyzer, Explorer, and Manager + * + * Copyright (C) 2003-2005, Evan Battaglia + * + * 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 +#include +#include + +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 diff --git a/src/viklayer.c b/src/viklayer.c index aefa1822..e802fbc1 100644 --- a/src/viklayer.c +++ b/src/viklayer.c @@ -21,6 +21,7 @@ #include "viking.h" #include "vikradiogroup.h" +#include "vikfilelist.h" #include /* 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) ); diff --git a/src/viklayer.h b/src/viklayer.h index f08658ae..a8df0951 100644 --- a/src/viklayer.h +++ b/src/viklayer.h @@ -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 */ diff --git a/src/viktrack.c b/src/viktrack.c index 5055b82e..0b2ebc32 100644 --- a/src/viktrack.c +++ b/src/viktrack.c @@ -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; + } +} diff --git a/src/viktrack.h b/src/viktrack.h index b74cea52..60b4f9b3 100644 --- a/src/viktrack.h +++ b/src/viktrack.h @@ -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 diff --git a/src/viktrwlayer.c b/src/viktrwlayer.c index b3d0e1d0..eb2219aa 100644 --- a/src/viktrwlayer.c +++ b/src/viktrwlayer.c @@ -34,6 +34,9 @@ #include "background.h" #include "gpx.h" #include "babel.h" +#include "dem.h" +#include "dems.h" + #include #include @@ -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) ) -- 2.39.5