This is an automated email from the git hooks/post-receive script. sebastic pushed a commit to branch master in repository ncview.
commit 6954e14ed6ea728aead0a778cb636f6d68b12d63 Author: Bas Couwenberg <sebas...@xs4all.nl> Date: Sat Apr 18 01:40:38 2015 +0200 Imported Upstream version 2.1.2 --- src/Makefile.am | 2 +- src/{Makefile.am => Makefile.am.orig} | 0 src/Makefile.in | 2 +- src/do_buttons.c | 18 +- src/file_netcdf.c | 548 ++++++++++++++++++++++++++++------ src/interface/{x_interface.c => '} | 184 +++++++++++- src/interface/filesel.c | 12 +- src/interface/x_interface.c | 170 +++++++++-- src/ncview.c | 50 +++- src/ncview.defines.h | 10 +- src/ncview.protos.h | 4 +- src/util.c | 158 +++++++++- src/view.c | 99 +++++- x_interface.c | 0 14 files changed, 1091 insertions(+), 166 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index f27ba2f..de8ca20 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -33,5 +33,5 @@ sources = ncview.c file.c util.c do_buttons.c \ stringlist.c handle_rc_file.c AM_CPPFLAGS=-DNCVIEW_LIB_DIR=\"$(pkgdatadir)\" $(PNG_CPPFLAGS) $(UDUNITS2_CPPFLAGS) $(NETCDF_CPPFLAGS) -AM_CFLAGS=-Wall $(X_CFLAGS) +AM_CFLAGS=$(X_CFLAGS) AM_LDFLAGS=$(PNG_LDFLAGS) $(UDUNITS2_LDFLAGS) $(NETCDF_LDFLAGS) $(X_PRE_LIBS) $(X_LIBS) $(X11_LIBS) $(X_EXTRA_LIBS) $(RPATH_FLAGS) diff --git a/src/Makefile.am b/src/Makefile.am.orig similarity index 100% copy from src/Makefile.am copy to src/Makefile.am.orig diff --git a/src/Makefile.in b/src/Makefile.in index bc95987..d1efbfd 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -227,7 +227,7 @@ sources = ncview.c file.c util.c do_buttons.c \ stringlist.c handle_rc_file.c AM_CPPFLAGS = -DNCVIEW_LIB_DIR=\"$(pkgdatadir)\" $(PNG_CPPFLAGS) $(UDUNITS2_CPPFLAGS) $(NETCDF_CPPFLAGS) -AM_CFLAGS = -Wall $(X_CFLAGS) +AM_CFLAGS = $(X_CFLAGS) AM_LDFLAGS = $(PNG_LDFLAGS) $(UDUNITS2_LDFLAGS) $(NETCDF_LDFLAGS) $(X_PRE_LIBS) $(X_LIBS) $(X11_LIBS) $(X_EXTRA_LIBS) $(RPATH_FLAGS) all: all-am diff --git a/src/do_buttons.c b/src/do_buttons.c index ab7cdf6..219bf9d 100644 --- a/src/do_buttons.c +++ b/src/do_buttons.c @@ -92,7 +92,7 @@ do_rewind( int modifier ) in_timer_clear(); if( modifier == MOD_2 ) { - change_view( -10, PERCENT ); + change_view( -10, FRAMES ); in_timer_set( (XtTimerCallbackProc)do_rewind, (XtPointer)(MOD_2), delay_millisec ); } else @@ -157,7 +157,7 @@ do_fastforward( int modifier ) delay_millisec = (long)(DELAY_DELTA * options.frame_delay) + DELAY_OFFSET; if( modifier == MOD_2 ) { - if( change_view( 10, PERCENT ) == 0 ) + if( change_view( 10, FRAMES ) == 0 ) in_timer_set( (XtTimerCallbackProc)do_fastforward, (XtPointer)(MOD_2), delay_millisec ); } else @@ -229,27 +229,29 @@ do_set_maximum( int modifier ) void do_blowup( int modifier ) { + int view_var_is_valid = TRUE; + if( modifier == MOD_3 ) - view_change_blowup( -1, TRUE ); + view_change_blowup( -1, TRUE, view_var_is_valid ); else if( modifier == MOD_2 ) { /* Double the current blowup -- make image BIGGER */ if( options.blowup > 0 ) - view_change_blowup( options.blowup, TRUE ); + view_change_blowup( options.blowup, TRUE, view_var_is_valid ); else - view_change_blowup( -(options.blowup)/2, TRUE ); + view_change_blowup( -(options.blowup)/2, TRUE, view_var_is_valid ); } else if( modifier == MOD_4 ) { /* Halve the current blowup -- make image SMALLER */ if( options.blowup > 0 ) - view_change_blowup( -(options.blowup/2), TRUE ); + view_change_blowup( -(options.blowup/2), TRUE, view_var_is_valid ); else - view_change_blowup( options.blowup, TRUE ); + view_change_blowup( options.blowup, TRUE, view_var_is_valid ); } else - view_change_blowup( 1, TRUE ); + view_change_blowup( 1, TRUE, view_var_is_valid ); /* If we are shrinking magnification, then try re-saving * the frames because now there might be enough room. diff --git a/src/file_netcdf.c b/src/file_netcdf.c index 7b20ada..6c29ea4 100644 --- a/src/file_netcdf.c +++ b/src/file_netcdf.c @@ -40,6 +40,10 @@ void warn_about_char_dims(); int safe_ncdimid( int fileid, char *dim_name1 ); int netcdf_dimvar_id( int fileid, char *dim_name ); int netcdf_get_att_util( int id, int varid, char *var_name, char *att_name, int expected_len, void *value ); +int nc_inq_varid_grp( int ncid, char *varname, int *varid, int *groupid ); +void varname_no_groups( char *varname, char *varname_sans_groups ); +char *ncview_groupname( int gid ); +char *ncview_varname( int gid, int varid ); char *nc_type_to_string( nc_type type ); @@ -108,26 +112,62 @@ int netcdf_fi_recdim_id( int fileid ) err = nc_inq( fileid, &n_dims, &n_vars, &n_gatts, &rec_dim ); if( err != NC_NOERR ) { - fprintf( stderr, "netcdf_fi_list_vars: error on nc_inq, cdfid=%d\n", fileid ); + fprintf( stderr, "netcdf_fi_recdim_id: error on nc_inq, cdfid=%d\n", fileid ); exit( -1 ); } return( rec_dim ); } -/*******************************************************************************************/ -Stringlist *netcdf_fi_list_vars( int fileid ) +/******************************************************************************************* + * NOTE that netcdf returns names starting with slashes, while I do not. So, I strip + * the leading slash from returned names. + */ +void ncdf_fi_name_of_group( int ncid, char **name, int full_path ) { - int n_vars, err, i, jj, n_dims, n_var_dims, eff_ndims; - char *var_name; - Stringlist *ret_val, *dimlist; - int n_gatts, rec_dim; - size_t *size, total_size; + int ierr; + size_t nchar, dummy; + + ierr = nc_inq_grpname_len( ncid, &nchar ); /* According to docs, ALWAYS returns len of full path */ + if( ierr != NC_NOERR ) { + fprintf( stderr, "Error getting grpname length from file for ncid=%d: %s\n", + ncid, nc_strerror(ierr) ); + exit(-1); + } - ret_val = NULL; + *name = (char *)malloc( sizeof(char) * (nchar+2) ); /* add space for trailing NULL */ - err = nc_inq( fileid, &n_dims, &n_vars, &n_gatts, &rec_dim ); + if( full_path == 0 ) + ierr = nc_inq_grpname( ncid, *name ); + else + ierr = nc_inq_grpname_full( ncid, &dummy, *name ); + + /* Get rid of leading slash */ + if( (*name)[0] == '/' ) + (*name)++; + + if( ierr != NC_NOERR ) { + fprintf( stderr, "Error getting grpname from file for ncid=%d: %s\n", + ncid, nc_strerror(ierr) ); + exit(-1); + } +} + +/******************************************************************************************* + * Returns list of ONLY displayable vars in the passed group. The list of displayable vars + * is appended to ret_val, which might already have some displayable vars from different + * groups in it. + */ +void netcdf_fi_list_vars_inner( Stringlist **ret_val, int gid, char *groupname ) +{ + int n_vars, err, i, jj, kk, n_dims, n_var_dims, eff_ndims; + char *var_name, *grp_var_name; + Stringlist *dimlist; + int n_gatts, rec_dim, n_groups; + size_t *size, total_size; + + err = nc_inq( gid, &n_dims, &n_vars, &n_gatts, &rec_dim ); if( err != NC_NOERR ) { - fprintf( stderr, "netcdf_fi_list_vars: error on ncinqire, cdfid=%d\n", fileid ); + fprintf( stderr, "netcdf_fi_list_vars: error on ncinqire, cdfid=%d\n", gid ); exit( -1 ); } @@ -135,15 +175,31 @@ Stringlist *netcdf_fi_list_vars( int fileid ) * as a displayable variable. At present, we require: 1) that the * variable have at least 1 scannable dimensions. 2) It shouldn't * be a "dimension variable"; i.e., there should be no dimension - * with the same name as this variable. 3) It's total size should + * with the same name as this variable. 3) Its total size should * be > 1. */ for( i=0; i<n_vars; i++ ) { - var_name = netcdf_varindex_to_name( fileid, i ); - if( netcdf_dim_name_to_id( fileid, var_name, var_name ) == -1 ){ + var_name = netcdf_varindex_to_name( gid, i ); + + /* Prepend group name */ + grp_var_name = (char *)malloc( sizeof(char) * (strlen(var_name) + strlen(groupname) + 10) ); + grp_var_name[0] = '\0'; + if( (strlen(groupname) == 0) || ((strlen(groupname) == 1) && (groupname[0] == '/' ))) + strcpy( grp_var_name, var_name ); + else + { + strcat( grp_var_name, groupname ); + strcat( grp_var_name, "/" ); + strcat( grp_var_name, var_name ); + } + + if( options.debug ) printf( "netcdf_fi_list_vars_inner: checking to see if a displayable var: >%s<\n", + grp_var_name ); + + if( netcdf_dim_name_to_id( gid, var_name, var_name ) == -1 ){ /* then it's NOT a dimension variable */ - size = netcdf_fi_var_size( fileid, var_name ); - n_var_dims = netcdf_fi_n_dims( fileid, var_name ); + size = netcdf_fi_var_size( gid, var_name ); + n_var_dims = netcdf_fi_n_dims( gid, var_name ); total_size = 1L; eff_ndims = 0; for(jj=0; jj<n_var_dims; jj++ ) { @@ -151,45 +207,118 @@ Stringlist *netcdf_fi_list_vars( int fileid ) if( *(size+jj) > 1 ) eff_ndims++; } - dimlist = fi_scannable_dims( fileid, var_name ); - if( (total_size > 1L) && (stringlist_len( dimlist ) >= 1)) + dimlist = fi_scannable_dims( gid, var_name ); + if( (total_size > 1L) && (stringlist_len( dimlist ) >= 1)) { /* Hack to make version 1.70+ emulate older versions * that did not display 1-d vars. */ - if( ! (options.no_1d_vars && (eff_ndims == 1) )) - stringlist_add_string( &ret_val, var_name, NULL, SLTYPE_NULL ); + if( ! (options.no_1d_vars && (eff_ndims == 1) )) { + if( options.debug ) { + printf( "netcdf_fi_list_vars_inner: YES, is a displayable var: >%s< ndims=%d sizes=", + grp_var_name, n_var_dims ); + for( kk=0; kk<n_var_dims; kk++ ) + printf( "%ld ", size[kk] ); + printf( "\n" ); + } + stringlist_add_string( ret_val, grp_var_name, NULL, SLTYPE_NULL ); + } + } + else + if( options.debug ) printf( "netcdf_fi_list_vars_inner: NO, is size 1 so not displayable: >%s<\n", + grp_var_name ); + } + else + if( options.debug ) printf( "netcdf_fi_list_vars_inner: NO, is a dim so not displayable: >%s<\n", + grp_var_name ); } - - return( ret_val ); +} + +/*******************************************************************************************/ +void netcdf_fi_list_vars_v4( Stringlist **retval, int fileid ) +{ + char *groupname; + int i, *grp_id, err, n_groups, full_path; + + + /* Get name of this group + */ + full_path = 1; + ncdf_fi_name_of_group( fileid, &groupname, full_path ); + + netcdf_fi_list_vars_inner( retval, fileid, groupname ); + + /* Get number of groups in this group + */ + err = nc_inq_grps( fileid, &n_groups, NULL); + if( err != NC_NOERR ) { + fprintf( stderr, "netcdf_fi_list_vars: error on nc_inq_grps, cdfid=%d: %s\n", + fileid, nc_strerror(err) ); + exit( -1 ); + } + + /* Get group IDs + */ + grp_id = (int *)malloc( sizeof(int) * n_groups ); + err = nc_inq_grps( fileid, &n_groups, grp_id ); + for( i=0; i<n_groups; i++ ) { + netcdf_fi_list_vars_v4( retval, grp_id[i] ); + } + + free( grp_id ); + +} + +/******************************************************************************************* + * This provides the same interface for the requirements of groups introduced + * in netcdf library version 4 + */ +Stringlist *netcdf_fi_list_vars( int fileid ) +{ + Stringlist *retval = NULL; + + if( options.debug ) printf( "netcdf_fi_list_vars: entering for file %d\n", fileid ); + + netcdf_fi_list_vars_v4( &retval, fileid ); + + if( options.debug ) { + printf( "netcdf_fi_list_vars: exiting with list of DISPLAYABLE vars in this file:\n" ); + stringlist_dump( retval ); + } + + return( retval ); } /*******************************************************************************************/ Stringlist *netcdf_scannable_dims( int fileid, char *var_name ) { - int var_id, n_dims, i, err; + int var_id, n_dims, i, err, gid; char *dim_name; size_t dim_size; Stringlist *dimlist = NULL; int n_atts, dim[MAX_VAR_DIMS]; nc_type var_type; + char var_name_ng[MAX_NC_NAME]; dim_name = (char *)malloc( MAX_NC_NAME ); /* defined in netcdf.h */ - err = nc_inq_varid( fileid, var_name, &var_id ); + err = nc_inq_varid_grp( fileid, var_name, &var_id, &gid ); if( err != NC_NOERR ) { fprintf( stderr, "Error in netcdf_scannable_dims: could not find var named \"%s\" in file!\n", var_name ); exit(-1); } - err = nc_inq_var( fileid, var_id, var_name, &var_type, &n_dims, dim, &n_atts ); + + varname_no_groups( var_name, var_name_ng ); + + err = nc_inq_var( gid, var_id, var_name_ng, &var_type, &n_dims, dim, &n_atts ); if( err != NC_NOERR ) { fprintf( stderr, "netcdf_scannable_dims: Error on nc_inq_var call for var %s\n", var_name ); exit(-1); } for( i=0; i<n_dims; i++ ) { - err = nc_inq_dim( fileid, *(dim+i), dim_name, &dim_size ); + err = nc_inq_dim( gid, *(dim+i), dim_name, &dim_size ); if( err < 0 ) { fprintf( stderr, "ncview: netcdf_scannable_dims: "); fprintf( stderr, "error on nc_inq_dim call\n" ); @@ -212,20 +341,27 @@ Stringlist *netcdf_scannable_dims( int fileid, char *var_name ) return( dimlist ); } -/*******************************************************************************************/ +/******************************************************************************************* + * On input, var_name might have prepended group names of the form "group0/group1/varname" + */ int netcdf_fi_n_dims( int fileid, char *var_name ) { - int n_dims, err, varid; + int n_dims, err, varid, groupid; int n_atts, dim[MAX_VAR_DIMS]; + char var_name_nogroups[MAX_NC_NAME]; nc_type var_type; - err = nc_inq_varid( fileid, var_name, &varid ); + err = nc_inq_varid_grp( fileid, var_name, &varid, &groupid ); if( err != NC_NOERR ) { fprintf( stderr, "Error in netcdf_fi_n_dims: could not find var named \"%s\" in file!\n", var_name ); exit(-1); } - err = nc_inq_var( fileid, varid, var_name, &var_type, &n_dims, dim, &n_atts ); + + /* Strip off leading group names */ + varname_no_groups( var_name, var_name_nogroups ); + + err = nc_inq_var( groupid, varid, var_name_nogroups, &var_type, &n_dims, dim, &n_atts ); if( err != NC_NOERR ) { fprintf( stderr, "netcdf_fi_n_dims: error on nc_inq_var\n" ); fprintf( stderr, "netcdfid=%d, var_name=%s\n", @@ -249,25 +385,35 @@ size_t netcdf_dim_size( fileid, dimid ) return( ret_val ); } -/*******************************************************************************************/ +/******************************************************************************************* + * On input, var_name might have prepended group names of the form "group0/group1/varname" + */ size_t * netcdf_fi_var_size( int fileid, char *var_name ) { - int n_dims, varid, err, i; + int n_dims, varid, err, i, groupid; size_t *ret_val, dim_size; - int n_atts, dim[MAX_VAR_DIMS]; + int n_atts, dim[MAX_VAR_DIMS], debug; + char var_name_nogroups[MAX_NC_NAME]; nc_type var_type; + debug = 0; + + if( debug==1 ) printf( "netcdf_fi_var_size: entering for fileid=%d varname=>%s<\n", fileid, var_name ); + n_dims = netcdf_fi_n_dims( fileid, var_name ); ret_val = (size_t *)malloc( n_dims * sizeof(size_t) ); - err = nc_inq_varid( fileid, var_name, &varid ); + err = nc_inq_varid_grp( fileid, var_name, &varid, &groupid ); if( err != NC_NOERR ) { fprintf( stderr, "Error in netcdf_fi_var_size: could not find var named \"%s\" in file!\n", var_name ); exit(-1); } - err = nc_inq_var( fileid, varid, var_name, &var_type, &n_dims, dim, &n_atts ); + /* Strip off leading group names */ + varname_no_groups( var_name, var_name_nogroups ); + + err = nc_inq_var( groupid, varid, var_name_nogroups, &var_type, &n_dims, dim, &n_atts ); if( err != NC_NOERR ) { fprintf( stderr, "netcdf_fi_var_size: error on nc_inq_var\n" ); fprintf( stderr, "netcdfid=%d, var_name=%s\n", @@ -275,9 +421,11 @@ size_t * netcdf_fi_var_size( int fileid, char *var_name ) exit( -1 ); } + if( debug==1 ) printf( "netcdf_fi_var_size: here are dim sizes:\n" ); for( i=0; i<n_dims; i++ ) { - err = nc_inq_dimlen( fileid, *(dim+i), &dim_size ); + err = nc_inq_dimlen( groupid, *(dim+i), &dim_size ); *(ret_val+i) = dim_size; + if( debug==1 ) printf( "dim=%d size=%ld\n", i, dim_size ); } return( ret_val ); @@ -286,24 +434,27 @@ size_t * netcdf_fi_var_size( int fileid, char *var_name ) /*******************************************************************************************/ char *netcdf_dim_id_to_name( int fileid, char *var_name, int dim_id ) { - int netcdf_dim_id, netcdf_var_id; + int netcdf_dim_id, netcdf_var_id, gid; int n_dims, *dim, err, n_atts; - char *dim_name; + char *dim_name, var_name_ng[MAX_NC_NAME]; nc_type var_type; /* see notes under "netcdf_dim_name_to_id". "dim_id" is NOT * the netCDF dimension ID, it is the entry into the size array * for the passed variable. */ - err = nc_inq_varid( fileid, var_name, &netcdf_var_id ); + err = nc_inq_varid_grp( fileid, var_name, &netcdf_var_id, &gid ); if( err != NC_NOERR ) { fprintf( stderr, "Error in netcdf_dim_id_to_name: could not find var named \"%s\" in file!\n", var_name ); exit(-1); } - n_dims = fi_n_dims( fileid, var_name ); - dim = (int *)malloc( n_dims * sizeof( int )); - err = nc_inq_var( fileid, netcdf_var_id, var_name, &var_type, + + varname_no_groups( var_name, var_name_ng ); + + n_dims = fi_n_dims( gid, var_name_ng ); + dim = (int *)malloc( n_dims * sizeof( int )); + err = nc_inq_var( gid, netcdf_var_id, var_name_ng, &var_type, &n_dims, dim, &n_atts ); if( err != NC_NOERR ) { fprintf( stderr, "ncview: netcdf_dim_id_to_name: error on "); @@ -313,7 +464,7 @@ char *netcdf_dim_id_to_name( int fileid, char *var_name, int dim_id ) netcdf_dim_id = *(dim+dim_id); dim_name = (char *)malloc( MAX_NC_NAME ); /* defined in netcdf.h */ - err = nc_inq_dimname( fileid, netcdf_dim_id, dim_name ); + err = nc_inq_dimname( gid, netcdf_dim_id, dim_name ); if( err != NC_NOERR ) { fprintf( stderr, "ncview: netcdf_dim_id_to_name: error on "); fprintf( stderr, "nc_inq_dimname call. Variable=%s\n", var_name ); @@ -322,11 +473,19 @@ char *netcdf_dim_id_to_name( int fileid, char *var_name, int dim_id ) return( dim_name ); } -/*******************************************************************************************/ +/******************************************************************************************* + * On entry var_name could be something like "group0/group1/varname" + */ int netcdf_dim_name_to_id( int fileid, char *var_name, char *dim_name ) { - int netcdf_dim_id, netcdf_var_id, n_dims, *dim, err, i, n_atts; + int netcdf_dim_id, netcdf_var_id, n_dims, *dim, err, i, n_atts, gid, debug; nc_type var_type; + char var_name_ng[MAX_NC_NAME]; + + debug = 0; + + if( debug == 1 ) printf( "netcdf_dim_name_to_id: entering with fileid=%d var_name=%s dim_name=%s\n", + fileid, var_name, dim_name ); /* It is important to note that this routine does NOT return * the dimension ID of the passed dimension. That concept is @@ -338,19 +497,37 @@ int netcdf_dim_name_to_id( int fileid, char *var_name, char *dim_name ) * in the requested variable. */ - netcdf_dim_id = safe_ncdimid( fileid, dim_name ); - if( netcdf_dim_id == -1 ) - return( -1 ); - err = nc_inq_varid( fileid, var_name, &netcdf_var_id ); + err = nc_inq_varid_grp( fileid, var_name, &netcdf_var_id, &gid ); if( err != NC_NOERR ) { fprintf( stderr, "Error in netcdf_dim_name_to_id: could not find var named \"%s\" in file!\n", var_name ); exit(-1); } + if( debug == 1 ) { + printf( "netcdf_dim_name_to_id: nc_inq_varid_grp reported that var >%s< of gid=%d (%s)", + var_name, + fileid, + ncview_groupname(fileid) ); + printf( " is varid %d of gid=%d (%s), which ACTUALLY has name >%s<\n", + netcdf_var_id, + gid, + ncview_groupname(gid), + ncview_varname(gid, netcdf_var_id) ); + } + + varname_no_groups( var_name, var_name_ng ); + + if( debug == 1 ) printf( "netcdf_dim_name_to_id: group_id=%d var_name_no_groups=%s\n", + gid, var_name_ng ); + + netcdf_dim_id = safe_ncdimid( gid, dim_name ); + if( debug == 1 ) printf( "netcdf_dim_name_to_id: netcdf_dim_id=%d\n", netcdf_dim_id ); + if( netcdf_dim_id == -1 ) + return( -1 ); - n_dims = fi_n_dims( fileid, var_name ); + n_dims = fi_n_dims( gid, var_name_ng ); dim = (int *)malloc( n_dims * sizeof( int )); - err = nc_inq_var( fileid, netcdf_var_id, var_name, &var_type, + err = nc_inq_var( gid, netcdf_var_id, var_name_ng, &var_type, &n_dims, dim, &n_atts ); if( err != NC_NOERR ) { fprintf( stderr, "ncview: netcdf_dim_name_to_id: error on "); @@ -366,25 +543,39 @@ int netcdf_dim_name_to_id( int fileid, char *var_name, char *dim_name ) return( -1 ); } -/*******************************************************************************************/ +/******************************************************************************************* + * On entry var_name could be something like "group0/group1/varname" + */ void netcdf_fi_get_data( int fileid, char *var_name, size_t *start_pos, size_t *count, float *data, NetCDFOptions *aux_data ) { - int i, err, varid; + int i, err, varid, gid, debug; + char var_name_ng[MAX_NC_NAME]; size_t tot_size, n_dims; - tot_size = 1L; - n_dims = netcdf_fi_n_dims( fileid, var_name ); - for( i=0; i<n_dims; i++ ) - tot_size *= *(count+i); + debug = 0; - err = nc_inq_varid( fileid, var_name, &varid ); + if( debug==1 ) printf( "netcdf_fi_get_data: entering for fileid=%d var_name=%s\n", + fileid, var_name ); + + err = nc_inq_varid_grp( fileid, var_name, &varid, &gid ); if( err != NC_NOERR ) { fprintf( stderr, "Error in netcdf_fi_get_data: could not find var named \"%s\" in file!\n", var_name ); exit(-1); } + varname_no_groups( var_name, var_name_ng ); + + tot_size = 1L; + n_dims = netcdf_fi_n_dims( gid, var_name_ng ); + if( debug==1 ) printf( "netcdf_fi_get_data: ndims=%ld\n", n_dims ); + for( i=0; i<n_dims; i++ ) { + tot_size *= *(count+i); + if( debug==1 ) printf( "start[%d]=%ld count[%d]=%ld\n", i, start_pos[i], i, count[i] ); + } + + if( options.debug ) { fprintf( stderr, "About to call nc_get_vara_float on variable %s\n", var_name ); @@ -393,7 +584,7 @@ void netcdf_fi_get_data( int fileid, char *var_name, size_t *start_pos, fprintf( stderr, "[%d]: %ld %ld\n", i, *(start_pos+i), *(count+i) ); } - err = nc_get_vara_float( fileid, varid, start_pos, count, data ); + err = nc_get_vara_float( gid, varid, start_pos, count, data ); if( err != NC_NOERR ) { fprintf( stderr, "netcdf_fi_get_data: error on nc_get_vara_float call\n" ); fprintf( stderr, "cdfid=%d variable=%s\n", fileid, var_name ); @@ -478,6 +669,107 @@ void netcdf_fi_close( int fileid ) /* netCDF utility routines. Analogs are not required for each data file format. */ /****************************************************************************************/ +/******************************************************************************************* + * Given a varname string of format: groupname0/groupname1/groupnameN/varname + * this returns ONLY the trailing groupname + */ +void varname_no_groups( char *varname, char *varname_sans_groups ) +{ + int i, i0, i1, idx_slash[MAX_NC_NAME], nslash; + char ts[MAX_NC_NAME]; + + /* Get indices of the slashes */ + nslash = 0; + for( i=0; i<strlen(varname); i++ ) { + if( varname[i] == '/' ) { + idx_slash[nslash] = i; + nslash++; + } + } + + if( nslash == 0 ) { + strcpy( varname_sans_groups, varname ); + return; + } + + strcpy( varname_sans_groups, varname+idx_slash[nslash-1]+1 ); +} + +/******************************************************************************************* + * A version of 'nc_inq_varid' that has been enhanced to return a groupid/varid pair + * given a var name of form "groupname/varname" (NOTE: *NO* leading slash!!) + */ +int nc_inq_varid_grp( int ncid, char *varname, int *varid, int *groupid ) +{ + int ns, ig, gid, ierr, group_depth, cur_gid, debug, retval; + char groupname[MAX_NC_NAME], varname_sans_groups[MAX_NC_NAME], cur_gid_groupname[MAX_NC_NAME]; + + debug = 0; + + if( debug ) printf( "nc_inq_varid_grp: entering with ncid=%d (%s) varname=>%s<\n", + ncid, ncview_groupname(ncid), varname ); + + if( varname[0] == '/' ) { + fprintf( stderr, "Internal error, called nc_inq_varid_grp with a varname that starts with a slash: >%s<\n", + varname ); + exit(-1); + } + + ns = count_nslashes( varname ); + if( debug ) printf( "nc_inq_varid_grp: number of slashes in varname: %d\n", ns ); + + if( ns > 0 ) { + cur_gid = ncid; + group_depth = ns; + + /* Traverse to the LAST group in the chain of groups, that's where + * we should find this var. + */ + if( debug ) printf( "nc_inq_varid_grp: traversing to the LAST group of var >%s<\n", varname ); + for( ig=0; ig<group_depth; ig++ ) { + + ierr = nc_inq_grpname( cur_gid, cur_gid_groupname ); + if( debug ) printf( "nc_inq_varid_grp: traversing group, cur depth=%d cur root name=>%s<\n", + ig, cur_gid_groupname ); + + ierr = unpack_groupname( varname, ig, groupname ); /* if ig==0, returns first groupname, etc */ + + if( debug ) printf( "nc_inq_varid_grp: looking for subgroup >%s< in root group >%s<\n", + groupname, cur_gid_groupname ); + + ierr = nc_inq_ncid( cur_gid, groupname, &gid ); + if( ierr != NC_NOERR ) { + fprintf( stderr, "nc_inq_varid_grp: Error, did not find group named >%s< in base group >%s<\n", + groupname, cur_gid_groupname ); + fprintf( stderr, "nc_inq_varid_grp was called with id=%d (%s) varname=>%s<\n", ncid, cur_gid_groupname, varname ); + exit(-1); + return(-1); + } + + if( debug ) printf( "nc_inq_varid_grp: group >%s< has groupid %d\n", groupname, gid ); + + cur_gid = gid; + } + + *groupid = cur_gid; + if( debug ) printf( "nc_inq_varid_grp: should now be on the LAST group, here is groupname: >%s<\n", ncview_groupname( cur_gid )); + + varname_no_groups( varname, varname_sans_groups ); + if( debug ) printf( "nc_inq_varid_grp: calling regular nc_inq_varid with group %d (%s) and varname_sans_gruops >%s<\n", + cur_gid, ncview_groupname(cur_gid), varname_sans_groups ); + retval = nc_inq_varid( cur_gid, varname_sans_groups, varid ); + + if( debug ) printf( "nc_inq_varid_grp: final returned gid=%d (%s) varid=%d (which is a var named >%s<)\n", + *groupid, ncview_groupname(*groupid), *varid, ncview_varname( *groupid, *varid ) ); + return( retval ); + } + else + { + *groupid = ncid; + return( nc_inq_varid( ncid, varname, varid )); + } +} + /*******************************************************************************************/ /* How many dimensions does this variable have? */ @@ -642,25 +934,30 @@ char * netcdf_title( int fileid ) * As a special case, if the attribute exited, but the length of the * attribute was zero, then it returns a pointer to a char string * that is a single NULL. + * + * On input, var_name might be of the form "group0/group1/varname" + * */ char *netcdf_get_char_att( int fileid, char *var_name, char *att_name ) { - int varid, err; + int varid, err, gid; size_t name_length; nc_type type; - char *ret_val; + char *ret_val, var_name_ng[MAX_NC_NAME]; - err = nc_inq_varid( fileid, var_name, &varid ); + err = nc_inq_varid_grp( fileid, var_name, &varid, &gid ); if( err != NC_NOERR ) { fprintf( stderr, "Error in netcdf_get_char_att: could not find var named \"%s\" in file!\n", var_name ); exit(-1); } - if( netcdf_att_id( fileid, varid, att_name ) < 0 ) + varname_no_groups( var_name, var_name_ng ); + + if( netcdf_att_id( gid, varid, att_name ) < 0 ) return( NULL ); - err = nc_inq_att( fileid, varid, att_name, &type, &name_length ); + err = nc_inq_att( gid, varid, att_name, &type, &name_length ); if( (err != NC_NOERR) || (type != NC_CHAR)) return( NULL ); @@ -671,7 +968,7 @@ char *netcdf_get_char_att( int fileid, char *var_name, char *att_name ) return( ret_val ); } - err = nc_get_att_text( fileid, varid, att_name, ret_val ); + err = nc_get_att_text( gid, varid, att_name, ret_val ); if( err != NC_NOERR ) return( NULL ); @@ -946,50 +1243,54 @@ nc_type netcdf_dim_value( int fileid, char *dim_name, size_t place, return( ret_type ); } -/*******************************************************************************************/ +/******************************************************************************************* + * On entry, var_name can be something like "group0/group1/varname" + */ void netcdf_fill_aux_data( int id, char *var_name, FDBlist *fdb ) { - int err, varid, n_dims, dim[MAX_NC_DIMS], n_atts, unlimdimvar_id, recdim_id; - char dummy_var_name[ MAX_NC_NAME ], unlimdim_name[MAX_NC_NAME]; + int err, varid, n_dims, dim[MAX_NC_DIMS], n_atts, unlimdimvar_id, recdim_id, gid; + char dummy_var_name[ MAX_NC_NAME ], var_name_ng[MAX_NC_NAME], unlimdim_name[MAX_NC_NAME]; nc_type type; NetCDFOptions *netcdf; netcdf = (NetCDFOptions *)(fdb->aux_data); - err = nc_inq_varid( id, var_name, &varid ); + err = nc_inq_varid_grp( id, var_name, &varid, &gid ); if( err != NC_NOERR ) { fprintf( stderr, "Error in netcdf_fill_aux_data: could not find var named \"%s\" in file!\n", var_name ); exit(-1); } + varname_no_groups( var_name, var_name_ng ); + /* Record the recdim units in this file */ - recdim_id = netcdf_fi_recdim_id( id ); + recdim_id = netcdf_fi_recdim_id( gid ); if( recdim_id == -1 ) { fdb->recdim_units = NULL; } else { /* Get NAME of the record dimension */ - err = nc_inq_dimname( id, recdim_id, unlimdim_name ); + err = nc_inq_dimname( gid, recdim_id, unlimdim_name ); if( err != 0 ) { fprintf( stderr, "Error in netcdf_fill_aux_data: could not get recdim name\n%s\n", nc_strerror( err )); exit(-1); } /* See if there is a variable with the same name */ - err = nc_inq_varid( id, unlimdim_name, &unlimdimvar_id ); + err = nc_inq_varid( gid, unlimdim_name, &unlimdimvar_id ); if( err != 0 ) fdb->recdim_units = NULL; else { /* Get the units for the dimvar. Note: can be NULL */ - fdb->recdim_units = netcdf_var_units( id, unlimdim_name ); + fdb->recdim_units = netcdf_var_units( gid, unlimdim_name ); } } - err = nc_inq_var( id, varid, dummy_var_name, &type, &n_dims, dim, &n_atts ); + err = nc_inq_var( gid, varid, dummy_var_name, &type, &n_dims, dim, &n_atts ); if( err != NC_NOERR ) { fprintf( stderr, "netcdf_fill_aux_data: failed on nc_inq_var call!\n" ); exit(-1); @@ -999,15 +1300,15 @@ void netcdf_fill_aux_data( int id, char *var_name, FDBlist *fdb ) return; netcdf->valid_range_set = - netcdf_get_att_util( id, varid, var_name, "valid_range", 2, netcdf->valid_range ); + netcdf_get_att_util( gid, varid, var_name_ng, "valid_range", 2, netcdf->valid_range ); netcdf->valid_min_set = - netcdf_get_att_util( id, varid, var_name, "valid_min", 1, &(netcdf->valid_min) ); + netcdf_get_att_util( gid, varid, var_name_ng, "valid_min", 1, &(netcdf->valid_min) ); netcdf->valid_max_set = - netcdf_get_att_util( id, varid, var_name, "valid_max", 1, &(netcdf->valid_max) ); + netcdf_get_att_util( gid, varid, var_name_ng, "valid_max", 1, &(netcdf->valid_max) ); netcdf->add_offset_set = - netcdf_get_att_util( id, varid, var_name, "add_offset", 1, &(netcdf->add_offset) ); + netcdf_get_att_util( gid, varid, var_name_ng, "add_offset", 1, &(netcdf->add_offset) ); netcdf->scale_factor_set = - netcdf_get_att_util( id, varid, var_name, "scale_factor", 1, &(netcdf->scale_factor) ); + netcdf_get_att_util( gid, varid, var_name_ng, "scale_factor", 1, &(netcdf->scale_factor) ); /* Special case: if we have add_offset and scale_factor attributes, * then assume they apply to the valid range also. Q: is this @@ -1246,31 +1547,36 @@ int netcdf_max_option_set( NCVar *var, float *ret_max ) return( max_set ); } -/*******************************************************************************************/ +/******************************************************************************************* + * On entry var_name might be something like "group0/group1/varname" + */ void netcdf_fill_value( int file_id, char *var_name, float *v, NetCDFOptions *aux_data ) { - int err, varid, foundit; + int err, varid, foundit, gid; + char var_name_ng[MAX_NC_NAME]; if( options.debug ) fprintf( stderr, "Checking %s for a missing value...\n", var_name ); foundit = FALSE; - err = nc_inq_varid( file_id, var_name, &varid ); + err = nc_inq_varid_grp( file_id, var_name, &varid, &gid ); if( err != NC_NOERR ) { fprintf( stderr, "Error in netcdf_fill_value: could not find var named \"%s\" in file!\n", var_name ); exit(-1); } - if( netcdf_get_att_util( file_id, varid, var_name, "missing_value", 1, v ) ) { + varname_no_groups( var_name, var_name_ng ); + + if( netcdf_get_att_util( gid, varid, var_name_ng, "missing_value", 1, v ) ) { if( options.debug ) fprintf( stderr, "found a \"missing_value\" attribute=%g\n", *v ); foundit = TRUE; } - if( netcdf_get_att_util( file_id, varid, var_name, "_FillValue", 1, v ) ) { + if( netcdf_get_att_util( gid, varid, var_name_ng, "_FillValue", 1, v ) ) { if( options.debug ) fprintf( stderr, "found a \"_FillValue\" attribute=%g\n", *v ); @@ -1278,7 +1584,7 @@ void netcdf_fill_value( int file_id, char *var_name, float *v, NetCDFOptions *au } /* Is there a global missing value? */ - if( netcdf_get_att_util( file_id, NC_GLOBAL, var_name, "missing_value", 1, v ) ) { + if( netcdf_get_att_util( gid, NC_GLOBAL, var_name_ng, "missing_value", 1, v ) ) { if( options.debug ) fprintf( stderr, "found a \"missing_value\" attribute=%g\n", *v ); @@ -1345,23 +1651,53 @@ int safe_ncvarid( int fileid, char *varname ) */ int safe_ncdimid( int fileid, char *dim_name1 ) { - int n_vars, err, i, n_dims; + int n_vars, err, i, n_dims, *dimids, include_parents; char dim_name2[MAX_NC_NAME]; - int n_gatts, rec_dim; + int n_gatts, rec_dim, debug; size_t dim_size; - err = nc_inq( fileid, &n_dims, &n_vars, &n_gatts, &rec_dim ); + debug = 0; + + if( debug == 1 ) printf( "safe_ncdimid: entering with fileid=%d (group %s) dim_name=%s\n", + fileid, ncview_groupname(fileid), dim_name1 ); + + /* Find how many dims there are available, make space + * for their dimids, read them in + */ + include_parents = 1; + err = nc_inq_dimids( fileid, &n_dims, NULL, include_parents ); if( err != NC_NOERR ) { - fprintf( stderr, "ncview: safe_ncdimid: error in nc_inq call\n" ); - exit( -1 ); + fprintf( stderr, "safe_ncdimid: error on call to nc_inq_dimids (1): %s\n", + nc_strerror(err) ); + exit(-1); + } + if( debug == 1 ) printf( "safe_ncdimid: n_dims=%d\n", n_dims ); + + dimids = (int *)malloc( sizeof(int) * n_dims ); + err = nc_inq_dimids( fileid, &n_dims, dimids, include_parents ); + if( err != NC_NOERR ) { + fprintf( stderr, "safe_ncdimid: error on call to nc_inq_dimids (2): %s\n", + nc_strerror(err) ); + exit(-1); } for( i=0; i<n_dims; i++ ) { - err = nc_inq_dim( fileid, i, dim_name2, &dim_size ); - if( strcmp( dim_name1, dim_name2 ) == 0 ) - return( i ); + err = nc_inq_dim( fileid, dimids[i], dim_name2, &dim_size ); + if( err != 0 ) { + fprintf( stderr, "safe_ncdimid: Error, call to nc_inq_dim returned: %s\n", + nc_strerror( err )); + fprintf( stderr, "Called with ncid=%d dimid=%d\n", fileid, i ); + exit(-1); + } + if( debug == 1 ) printf( "safe_ncdimid: dim #%d (dimid %d) is named >%s<\n", + i, dimids[i], dim_name2 ); + if( strcmp( dim_name1, dim_name2 ) == 0 ) { + if( debug==1 ) printf( "safe_ncdimid found match in dim %d: returning that value\n", dimids[i] ); + return( dimids[i] ); + } } + if( debug==1 ) printf( "safe_ncdimid: no matches, returning -1\n" ); return( -1 ); } @@ -1631,3 +1967,29 @@ int netcdf_dimvar_bounds_id( int fileid, char *dim_name, int *nvertices ) return( bounds_dimvar_id ); } +/***************************************************************************************************** + * Returns a pointer to a static buffer with the group name; useful for debugging & info printouts + */ +char *ncview_groupname( int gid ) +{ + static char buffer[MAX_NC_NAME]; + int ierr; + size_t tlen; + + ierr = nc_inq_grpname_full( gid, &tlen, buffer ); + return( &(buffer[0]) ); +} + +/***************************************************************************************************** + * Returns a pointer to a static buffer with the var name; useful for debugging & info printouts + */ +char *ncview_varname( int gid, int varid ) +{ + static char buffer[MAX_NC_NAME]; + int ierr; + size_t tlen; + + ierr = nc_inq_varname( gid, varid, buffer ); + return( &(buffer[0]) ); +} + diff --git a/src/interface/x_interface.c b/src/interface/' similarity index 95% copy from src/interface/x_interface.c copy to src/interface/' index 5dcb0b2..7eeb35a 100644 --- a/src/interface/x_interface.c +++ b/src/interface/' @@ -192,6 +192,9 @@ static Widget print_button_widget, colorbar_form_widget, colorbar_widget, + groupsel_form_widget, + grouplist_label_widget, + *grouplist_widget, varsel_form_widget, *var_selection_widget, /* the boxes with N vars per box */ varlist_label_widget, @@ -440,6 +443,7 @@ void do_set_min_from_curdata(Widget w, XButtonEvent *e, String *p, Cardinal *n void do_set_max_from_curdata(Widget w, XButtonEvent *e, String *p, Cardinal *n ); void expose_ccontour(); void expose_colorbar(); +void x_init_widgets_groupsel( Widget parent ); void testf(Widget w, XButtonEvent *e, String *p, Cardinal *n ); @@ -1501,6 +1505,143 @@ void x_init_widgets_varsel( Widget parent ) } /*************************************************************************************************/ +void x_init_widgets_groupsel( Widget parent ) +{ + int n_groups, n_groupsel_boxes, which_box, i, state; + NCVar *var; + char widget_name[128]; + Widget w; + Pixel col2set; + Stringlist *group_list, *cursor; + + /* Get list of known groups */ + group_list = get_group_list( variables ); + + /* Arrange the groups in boxes, n_vars_per_row variables to a box */ + n_groups = n_strings_in_list( group_list ); + n_groupsel_boxes = n_groups / app_data.n_vars_per_row + 5; + group_selection_widget = (Widget *)malloc( n_groupsel_boxes*sizeof( Widget )); + + /* Make an array of widgets for the variables; indicate the end of the + * array by a NULL value. + */ + grouplist_widget = (Widget *)malloc( (n_groups+1)*sizeof(Widget)); + if( grouplist_widget == NULL ) { + fprintf( stderr, "ncview: x_init_widgets: malloc "); + fprintf( stderr, "failed on grouplist_widget initializeation\n" ); + exit( -1 ); + } + *(grouplist_widget+n_groups) = NULL; + + cursor = group_list; + which_box = 0; + while( cursor != NULL ) { + if( i == 0 ) { + /* The very first button box! */ + snprintf( widget_name, 127, "groupselbox_%1d", which_box+1 ); + *(group_selection_widget+which_box) = XtVaCreateManagedWidget( + widget_name, + boxWidgetClass, + parent, + XtNorientation, XtorientHorizontal, + XtNborderWidth, 0, + NULL); + snprintf( widget_name, 127, "grouplist_label_%1d", which_box+1 ); + grouplist_label_widget = XtVaCreateManagedWidget( + widget_name, + labelWidgetClass, + *(group_selection_widget+which_box), + XtNwidth, app_data.button_width, + XtNlabel, "Group:", + XtNborderWidth, 0, + NULL ); + which_box++; + } + else if( (i % app_data.n_vars_per_row) == 0 ) { + /* A new button box! */ + snprintf( widget_name, 127, "box_%1d", which_box+1 ); + *(var_selection_widget+which_box) = XtVaCreateManagedWidget( + widget_name, + boxWidgetClass, + parent, + XtNorientation, XtorientHorizontal, + XtNborderWidth, 0, + XtNfromVert, *(var_selection_widget + which_box - 1), + NULL); + snprintf( widget_name, 127, "varlist_label_%1d", which_box+1 ); + varlist_label_widget = XtVaCreateManagedWidget( + widget_name, + labelWidgetClass, + *(var_selection_widget+which_box), + XtNwidth, app_data.button_width, + XtNborderWidth, 0, + XtNlabel, "", + NULL ); + which_box++; + } + + snprintf( widget_name, 127, "varsel_%s", var->name ); + state = False; + if( i == 0 ) /* first variable button */ + *(varlist_widget+i) = XtVaCreateManagedWidget( + widget_name, + toggleWidgetClass, + *(var_selection_widget+which_box-1), + XtNstate, state, + XtNlabel, var->name, + XtNsensitive, True, + XtNwidth, app_data.varlabel_width, + NULL ); + else + *(varlist_widget+i) = XtVaCreateManagedWidget( + widget_name, + toggleWidgetClass, + *(var_selection_widget+which_box-1), + XtNradioGroup, *varlist_widget, + XtNstate, state, + XtNlabel, var->name, + XtNsensitive, True, + XtNwidth, app_data.varlabel_width, + NULL ); + if( (n_vars > 1) && app_data.var_colors && options.color_by_ndims ) { + switch( var->effective_dimensionality ) { + case 1: + col2set = app_data.foreground1d; + break; + case 2: + col2set = app_data.foreground2d; + break; + case 3: + col2set = app_data.foreground3d; + break; + case 4: + col2set = app_data.foreground4d; + break; + case 5: + default: + col2set = app_data.foreground5d; + break; + } + XtVaSetValues( *(varlist_widget+i), + XtNforeground, col2set, NULL ); + } + var = var->next; + } + + /* In the degenerate case of only one variable, must make it a radio + * group by itself; can't do it above, because it needs to know its + * own widget number before it can be done. + */ + if( n_vars == 1 ) + XtVaSetValues( *varlist_widget, XtNradioGroup, + *varlist_widget, NULL ); + + i = 0; + while( (w = *(varlist_widget + i++)) != NULL ) + XtAddCallback( w, XtNcallback, varlist_mod1, NULL ); +} + +/*************************************************************************************************/ void x_init_widgets_dimlabels( Widget parent ) { labels_row_widget = XtVaCreateManagedWidget( @@ -1626,12 +1767,43 @@ void x_init_widgets( Widget top ) XtAddEventHandler( colorbar_widget, ExposureMask, FALSE, (XtEventHandler)expose_colorbar, NULL ); - varsel_form_widget = XtVaCreateManagedWidget( - "varselectform", - formWidgetClass, - commandcanvas_widget, - XtNfromVert, colorbar_form_widget, - NULL); + if( options.enable_group_sel ) { + groupsel_form_widget = XtVaCreateManagedWidget( + "groupselectform", + formWidgetClass, + commandcanvas_widget, + XtNfromVert, colorbar_form_widget, + NULL); + + grouplist_label_widget = XtVaCreateManagedWidget( + "grouplist_label_widget", + labelWidgetClass, + groupsel_form_widget, + XtNwidth, app_data.button_width, + XtNlabel, "Group:", + XtNborderWidth, 0, + NULL ); + + /* the widgets that allow the user to select the group to display */ + x_init_widgets_groupsel( groupsel_form_widget ); + + /* Only diff between this and varsel_form_widget create call + * below is what widget this widget is vertically from + */ + varsel_form_widget = XtVaCreateManagedWidget( + "varselectform", + formWidgetClass, + commandcanvas_widget, + XtNfromVert, groupsel_form_widget, + NULL); + } + else + varsel_form_widget = XtVaCreateManagedWidget( + "varselectform", + formWidgetClass, + commandcanvas_widget, + XtNfromVert, colorbar_form_widget, + NULL); /* the widgets that allow the user to select the variable to display */ x_init_widgets_varsel( varsel_form_widget ); diff --git a/src/interface/filesel.c b/src/interface/filesel.c index 2236591..936bb00 100644 --- a/src/interface/filesel.c +++ b/src/interface/filesel.c @@ -227,6 +227,7 @@ fs_double_click(Widget w, XButtonEvent *e, String *p, Cardinal *n ) { XawListReturnStruct *highlited_entry; Stringlist *files_and_dirs; + int ierr; highlited_entry = XawListShowCurrent( w ); if( highlited_entry->list_index == XAW_LIST_NONE ) @@ -237,7 +238,7 @@ fs_double_click(Widget w, XButtonEvent *e, String *p, Cardinal *n ) * that we select this file. */ if( fs_is_a_directory( highlited_entry->string )) { - chdir( highlited_entry->string ); + ierr = chdir( highlited_entry->string ); fs_get_file_dir_list( &files_and_dirs ); XawListChange( fs_list_widget, stringlist_to_Xawlist( files_and_dirs ), @@ -272,7 +273,7 @@ fs_popup_callback( Widget widget, XtPointer client_data, XtPointer call_data) int file_select( char **filename, char *init_dir ) { - int retval; + int retval, ierr; Stringlist *files_and_dirs; char *tstr, orig_dir[1024]; @@ -284,12 +285,12 @@ file_select( char **filename, char *init_dir ) return(MESSAGE_CANCEL); } - chdir( init_dir ); + ierr = chdir( init_dir ); fs_get_file_dir_list( &files_and_dirs ); retval = fs_popup( files_and_dirs ); - chdir( orig_dir ); + ierr = chdir( orig_dir ); /* Get the final selected filename if not MESSAGE_CANCEL */ if( retval != MESSAGE_CANCEL ) { @@ -379,9 +380,10 @@ fs_is_a_directory( char *name ) static char * fs_cwd() { + char *s; static char buf[2048]; - getcwd( buf, 2048 ); + s = getcwd( buf, 2048 ); return( buf ); } diff --git a/src/interface/x_interface.c b/src/interface/x_interface.c index 5dcb0b2..73488f3 100644 --- a/src/interface/x_interface.c +++ b/src/interface/x_interface.c @@ -1252,15 +1252,22 @@ void x_sort_vars_by_ndims( NCVar *v, long **vl_1d, int *n_1d, long **vl_2d, int /*************************************************************************************************/ void x_init_widgets_varsel_menu_inner( Widget parent, long *varlist, int nv, char *tag, Widget *var_menu_2use, - Widget *list_of_sel_widgets ) + Widget *list_of_sel_widgets, int discard_grpname ) { char temp[1024], widget_name[1024], var_menu_name[1024]; NCVar *cursor; int i_cursor, i; - snprintf( temp, 1020, "(%d) %s vars", nv, tag ); + strcpy( temp, tag ); snprintf( var_menu_name, 1020, "var_menu_%s", tag ); + /* For some reason not clear to me, if a widget name has a period in it, the + * X windows system cannot find that widget ??? + */ + for( i=0; i<strlen(var_menu_name); i++ ) + if( var_menu_name[i] == '.' ) + var_menu_name[i] = '_'; + varsel_menu_widget = XtVaCreateManagedWidget( "varsel_menu", menuButtonWidgetClass, @@ -1282,7 +1289,10 @@ void x_init_widgets_varsel_menu_inner( Widget parent, long *varlist, int nv, cha cursor = cursor->next; i_cursor++; } - snprintf( widget_name, 1020, "%s", cursor->name ); + if( discard_grpname ) + unpack_groupname( cursor->name, -2, widget_name ); + else + snprintf( widget_name, 1020, "%s", cursor->name ); list_of_sel_widgets[i] = XtVaCreateManagedWidget( widget_name, smeBSBObjectClass, @@ -1292,6 +1302,89 @@ void x_init_widgets_varsel_menu_inner( Widget parent, long *varlist, int nv, cha } } +/*****************************************************************************************************/ +void x_init_widgets_varsel_menu_grp( Widget menu_box, Widget *varsel_menu_widget_list ) +{ + Stringlist *uniq_groups, *sl_cursor; + int discard_groupname, nvars, ngrps, *my_grp_num, i, igrp, nv_in_grp; /* Applies to each var on the global "variables" list; counting starts at zero */ + long *varlist; + NCVar *var_cursor; + Widget *var_menu_grp; + char widget_name[2048]; + + nvars = n_vars_in_list( variables ); + + varlist = (long *)malloc( sizeof(long) * nvars ); + + /* Sort vars into lists based on their group */ + uniq_groups = get_group_list( variables ); + ngrps = stringlist_len( uniq_groups ); + + /* Get group number for each var. First group in list "uniq_groups" is + * assigned ID 0, etc. + */ + my_grp_num = (int *)malloc( sizeof(int) * nvars ); + var_cursor = variables; + for( i=0; i<nvars; i++ ) { + my_grp_num[i] = -1; + sl_cursor = uniq_groups; + for( igrp=0; igrp<ngrps; igrp++ ) { + + /* Test for a var in the root group (in which case it has no slashes) matching + * the group named "/" + */ + if( (count_nslashes( var_cursor->name )==0) && (strncmp( "/", sl_cursor->string, 1)==0)) { + my_grp_num[i] = igrp; + break; + } + /* Var has at least one slash in its name */ + else if( strncmp( var_cursor->name, sl_cursor->string, strlen(sl_cursor->string) ) == 0 ) { + my_grp_num[i] = igrp; + break; + } + + sl_cursor = sl_cursor->next; + } + if( my_grp_num[i] == -1 ) { + fprintf( stderr, "x_init_widgets_varsel_menu_grp: Error, did not find group for var named >%s< in the following list of unique groups:\n", + var_cursor->name ); + stringlist_dump( uniq_groups ); + exit(-1); + } + + var_cursor = var_cursor->next; + } + + /* Now go through the groups, and make a menu selection button for + * each group that generates a pop-up menu of all vars in that group + */ + sl_cursor = uniq_groups; + for( igrp=0; igrp<ngrps; igrp++ ) { + /* The way the routine x_init_widgets_varsel_menu_inner is set up, it needs + * an array of longs that hold the entry number on the global "variables" + * list corresponding to each group + */ + nv_in_grp = 0; + for( i=0; i<nvars; i++ ) { + if( my_grp_num[i] == igrp ) { + varlist[nv_in_grp] = i; + nv_in_grp++; + } + } + var_menu_grp = (Widget *)malloc( sizeof(Widget) ); + discard_groupname = 1; + snprintf( widget_name, 2040, "%s (%d vars)", sl_cursor->string, nv_in_grp ); + if( options.debug ) printf( "x_init_widgets_varsel_menu_grp: making menu for group selection named >%s< with %d vars\n", + widget_name, nv_in_grp ); + x_init_widgets_varsel_menu_inner( menu_box, varlist, nv_in_grp, widget_name, var_menu_grp, + varsel_menu_widget_list, discard_groupname ); + + sl_cursor = sl_cursor->next; + } + + free( varlist ); +} + /************************************************************************************************* * The widget selection area can be in one of two different modes. In "menu" mode, there is one button * for all the 1D variables, one button for all the 2D variables, ..., up to one button for all the @@ -1303,9 +1396,10 @@ void x_init_widgets_varsel_menu_inner( Widget parent, long *varlist, int nv, cha */ void x_init_widgets_varsel_menu( Widget parent ) { - long *vl_1d, *vl_2d, *vl_3d, *vl_4d, *vl_other; - int n_1d, n_2d, n_3d, n_4d, n_other, n_tot; + long *vl_1d, *vl_2d, *vl_3d, *vl_4d, *vl_other; /* These have 0 if the var is NOT in the list, 1 if it is */ + int discard_groupname, nvars, n_1d, n_2d, n_3d, n_4d, n_other; Widget menu_box; + char widget_name[2048]; menu_box = XtVaCreateManagedWidget( "varsel_menu_box", @@ -1315,36 +1409,57 @@ void x_init_widgets_varsel_menu( Widget parent ) XtNborderWidth, 0, NULL); - n_tot = n_vars_in_list( variables ); + nvars = n_vars_in_list( variables ); /* Allocate our "global" array that will store each menu selection widget, so we * can later find them to set their sensitivities and otherwise manipulate them. */ - varsel_menu_widget_list = (Widget *)malloc( n_tot * sizeof(Widget) ); + varsel_menu_widget_list = (Widget *)malloc( nvars * sizeof(Widget) ); + + /* If we are doing groups, we sort based on their group membership. If we + * are not doing groups, we sort based on the variable's number of dims + */ + if( options.enable_group_sel ) + x_init_widgets_varsel_menu_grp( menu_box, varsel_menu_widget_list ); + + else + { + discard_groupname = 0; - /* Sort vars into lists based on their number of dimensions */ - x_sort_vars_by_ndims( variables, &vl_1d, &n_1d, &vl_2d, &n_2d, &vl_3d, &n_3d, - &vl_4d, &n_4d, &vl_other, &n_other ); + /* Sort vars into lists based on their number of dimensions */ + x_sort_vars_by_ndims( variables, &vl_1d, &n_1d, &vl_2d, &n_2d, &vl_3d, &n_3d, + &vl_4d, &n_4d, &vl_other, &n_other ); - if( n_1d > 0 ) - x_init_widgets_varsel_menu_inner( menu_box, vl_1d, n_1d, "1d", &var_menu_1d, - varsel_menu_widget_list ); + if( n_1d > 0 ) { + snprintf( widget_name, 2040, "(%d) 1d vars", n_1d ); + x_init_widgets_varsel_menu_inner( menu_box, vl_1d, n_1d, widget_name, &var_menu_1d, + varsel_menu_widget_list, discard_groupname ); + } - if( n_2d > 0 ) - x_init_widgets_varsel_menu_inner( menu_box, vl_2d, n_2d, "2d", &var_menu_2d, - varsel_menu_widget_list+n_1d ); + if( n_2d > 0 ) { + snprintf( widget_name, 2040, "(%d) 2d vars", n_2d ); + x_init_widgets_varsel_menu_inner( menu_box, vl_2d, n_2d, widget_name, &var_menu_2d, + varsel_menu_widget_list+n_1d, discard_groupname ); + } - if( n_3d > 0 ) - x_init_widgets_varsel_menu_inner( menu_box, vl_3d, n_3d, "3d", &var_menu_3d, - varsel_menu_widget_list+n_1d+n_2d ); + if( n_3d > 0 ) { + snprintf( widget_name, 2040, "(%d) 3d vars", n_3d ); + x_init_widgets_varsel_menu_inner( menu_box, vl_3d, n_3d, widget_name, &var_menu_3d, + varsel_menu_widget_list+n_1d+n_2d, discard_groupname ); + } - if( n_4d > 0 ) - x_init_widgets_varsel_menu_inner( menu_box, vl_4d, n_4d, "4d", &var_menu_4d, - varsel_menu_widget_list+n_1d+n_2d+n_3d ); + if( n_4d > 0 ) { + snprintf( widget_name, 2040, "(%d) 4d vars", n_4d ); + x_init_widgets_varsel_menu_inner( menu_box, vl_4d, n_4d, widget_name, &var_menu_4d, + varsel_menu_widget_list+n_1d+n_2d+n_3d, discard_groupname ); + } - if( n_other > 0 ) - x_init_widgets_varsel_menu_inner( menu_box, vl_other, n_other, "5d", &var_menu_other, - varsel_menu_widget_list+n_1d+n_2d+n_3d+n_4d ); + if( n_other > 0 ) { + snprintf( widget_name, 2040, "(%d) 5d vars", n_other ); + x_init_widgets_varsel_menu_inner( menu_box, vl_other, n_other, widget_name, &var_menu_other, + varsel_menu_widget_list+n_1d+n_2d+n_3d+n_4d, discard_groupname ); + } + } } /*************************************************************************************************/ @@ -1489,6 +1604,11 @@ void x_init_widgets_varsel_list( Widget parent ) /*************************************************************************************************/ void x_init_widgets_varsel( Widget parent ) { + if( options.enable_group_sel && (options.varsel_style != VARSEL_MENU)) { + fprintf( stderr, "Internal error in x_init_widgets_varsel: if group selection is enambled, var selection must be done via menus\n" ); + exit(-1); + } + if( options.varsel_style == VARSEL_LIST ) x_init_widgets_varsel_list( parent ); else if( options.varsel_style == VARSEL_MENU ) diff --git a/src/ncview.c b/src/ncview.c index 1f3be77..ed974e4 100644 --- a/src/ncview.c +++ b/src/ncview.c @@ -110,9 +110,22 @@ main( int argc, char **argv ) exit( -1 ); } + /* If any vars are in groups, we build the interface differently. + * I pass this information through the global "options" struct. + */ + if( any_var_in_group( variables )) { + options.enable_group_sel = TRUE; + options.varsel_style = VARSEL_MENU; + } + else + options.enable_group_sel = FALSE; + /* This initializes the colormaps, and then the X widows system */ + if( options.debug ) printf( "Initializing display interface...\n" ); initialize_display_interface(); + if( options.debug ) printf( "Initializing printing subsystem...\n" ); print_init(); + if( options.debug ) printf( "Initializing overlays...\n" ); overlay_init(); /* If there is only one variable, make it the active one */ @@ -580,9 +593,12 @@ init_cmap_from_file( char *dir_name, char *file_name ) void initialize_file_interface( Stringlist *input_files ) { - int idim, nvars, nfiles; + int i, idim, nvars, nfiles; NCVar *var; + if( options.debug ) + fprintf( stderr, "Initializing file interface...\n" ); + nfiles = stringlist_len( input_files ); while( input_files != NULL ) { @@ -590,7 +606,7 @@ initialize_file_interface( Stringlist *input_files ) input_files = input_files->next; } if( options.debug ) - fprintf( stderr, "Calculating dim min & maxes...\n" ); + fprintf( stderr, "...calculating dim min & maxes...\n" ); calc_dim_minmaxes(); /* Get the effective dimensionality of all the vars. @@ -602,12 +618,18 @@ initialize_file_interface( Stringlist *input_files ) while( var != NULL ) { nvars++; var->effective_dimensionality = 0; - for( idim=0; idim<var->n_dims; idim++ ) + for( idim=0; idim<var->n_dims; idim++ ) { if( *(var->size + idim) > 1 ) var->effective_dimensionality++; - if( options.debug ) + if( options.debug ) + fprintf( stderr, "var %s has %d dims, dim %d: >%s< len %ld\n", + var->name, var->n_dims, idim, + var->dim[idim]->name, var->dim[idim]->size ); + } + if( options.debug ) { fprintf( stderr, "variable %s had effective_dimensionality of %d\n", var->name, var->effective_dimensionality ); + } var = var->next; } @@ -619,6 +641,9 @@ initialize_file_interface( Stringlist *input_files ) if( nvars > options.listsel_max ) options.varsel_style = VARSEL_MENU; + + if( options.debug ) + fprintf( stderr, "Done initializing file interface...\n" ); } /***********************************************************************************************/ @@ -632,7 +657,9 @@ initialize_display_interface() */ x_check_legal_colormap_loaded(); + if( options.debug ) printf( "...initializing X interface\n" ); in_initialize(); + if( options.debug ) printf( "...done with initializing X interface\n" ); } /***********************************************************************************************/ @@ -679,6 +706,21 @@ create_default_colormap() } /***********************************************************************************************/ +int any_var_in_group( NCVar *var ) { + + NCVar *cursor; + + cursor = var; + while( cursor != NULL ) { + if( count_nslashes( cursor->name ) > 0 ) + return( 1 ); + cursor = cursor->next; + } + + return( 0 ); +} + +/***********************************************************************************************/ void useage() { diff --git a/src/ncview.defines.h b/src/ncview.defines.h index d117c55..70bc97a 100644 --- a/src/ncview.defines.h +++ b/src/ncview.defines.h @@ -31,8 +31,8 @@ #include <udunits2.h> #endif -#define PROGRAM_ID "Ncview 2.1.1 David W. Pierce 1 Aug 2011" -#define PROGRAM_VERSION_STRING "2.1.1" +#define PROGRAM_ID "Ncview 2.1.2 David W. Pierce 24 Oct 2012" +#define PROGRAM_VERSION_STRING "2.1.2" #define APP_RES_VERSION 1.93 #ifndef TRUE @@ -399,6 +399,10 @@ typedef struct { * are global, rather than local to * a file. */ + int user_set_blowup; /* Initializes to -99999, then saves user-specified + * value of 'blowup' for this var so it can be + * used again if we leave this var & then come back + */ int auto_set_no_range; /* '1' if we autoset a range of -1,1 based * on not having a valid range for this var */ @@ -532,6 +536,8 @@ typedef struct { int save_frames; /* If true, try to save frames in core for faster display */ float frame_delay; /* Normalied to be between 0.0 and 1.0 */ + int enable_group_sel; /* TRUE if we have some vars in groups, so interface must incl. grp selection */ + OverlayOptions *overlay; } Options; diff --git a/src/ncview.protos.h b/src/ncview.protos.h index 6fab2e0..8569552 100644 --- a/src/ncview.protos.h +++ b/src/ncview.protos.h @@ -141,6 +141,8 @@ void sl_cat ( Stringlist **dest, Stringlist **src ); void get_min_max_onestep( NCVar *var, size_t n_other, size_t tstep, float *data, float *min, float *max, int verbose ); void cache_scalar_coord_info( NCVar *vars ); +int count_nslashes ( char *s ); +Stringlist *get_group_list ( NCVar *vars ); /****************************************************************************** * in interface.c @@ -279,7 +281,7 @@ int view_draw ( int allow_saveframes_useage, int force_range_to_frame void view_change_cur_dim ( char *dim_name, int modifier ); void view_forward ( void ); void view_backward ( void ); -void view_change_blowup ( int delta, int redraw_flag ); +void view_change_blowup ( int delta, int redraw_flag, int view_var_is_valid ); void init_saveframes ( void ); void redraw_dimension_info( void ); void redraw_ccontour ( void ); diff --git a/src/util.c b/src/util.c index 5dc5488..4a6ff04 100644 --- a/src/util.c +++ b/src/util.c @@ -397,7 +397,7 @@ add_vars_to_list( Stringlist *var_list, int id, char *filename, int nfiles ) Stringlist *var; if( options.debug ) - fprintf( stderr, "adding vars to list for file %s\n", filename ); + fprintf( stderr, "add_vars_to_list: entering, adding vars to list for file %s\n", filename ); var = var_list; while( var != NULL ) { if( options.debug ) @@ -456,6 +456,7 @@ add_var_to_list( char *var_name, int file_id, char *filename, int nfiles ) new_var->global_max = 0.0; new_var->user_min = 0.0; new_var->user_max = 0.0; + new_var->user_set_blowup = -99999; new_var->auto_set_no_range = 0; new_var->have_set_range = FALSE; new_var->size = fi_var_size( file_id, var_name ); @@ -509,9 +510,9 @@ add_var_to_list( char *var_name, int file_id, char *filename, int nfiles ) * Go through each variable, and if it has scalar coordinate information, * read that in from each file that the var lives in. */ - void - cache_scalar_coord_info( NCVar *vars ) - { + void +cache_scalar_coord_info( NCVar *vars ) +{ NCVar *v; FDBlist *tfile; int nfiles, ifile, nsc, isc; @@ -519,6 +520,8 @@ add_var_to_list( char *var_name, int file_id, char *filename, int nfiles ) float fval; size_t zeros[MAX_NC_DIMS], ones[MAX_NC_DIMS], n_ts, ii, i_cursor, n_ts_this_file; + if( options.debug ) printf( "cache_scalar_coord_info: entering\n" ); + /* Allocate space for the timestep_2_fdb array. This points * to the file (FDBlist) associated with EACH TIMESTEP of * the variable @@ -624,6 +627,8 @@ add_var_to_list( char *var_name, int file_id, char *filename, int nfiles ) v = v->next; } + + if( options.debug ) printf( "cache_scalar_coord_info: finished\n" ); } /****************************************************************************** @@ -1303,17 +1308,22 @@ handle_dim_mapping_2d( NCVar *v, char *coord_var_name, char *coord_att, size_t * void fill_dim_structs( NCVar *v ) { - int i, fileid; + int i, fileid, debug; NCDim *d; char *dim_name, *tmp_units; static int global_id = 0; FDBlist *cursor; + debug = 0; + + if( debug == 1 ) printf( "fill_dim_structs: entering for var %s, which has %d dims\n", v->name, v->n_dims ); + fileid = v->first_file->id; v->dim = (NCDim **)malloc( v->n_dims*sizeof( NCDim *)); for( i=0; i<v->n_dims; i++ ) { + dim_name = fi_dim_id_to_name( fileid, v->name, i ); + if( debug == 1 ) printf( "fill_dim_structs: dim %d has name %s and length %ld\n", i, dim_name, v->size[i] ); if( is_scannable( v, i ) ) { - dim_name = fi_dim_id_to_name( fileid, v->name, i ); *(v->dim + i) = (NCDim *)malloc( sizeof( NCDim )); d = *(v->dim+i); d->name = dim_name; @@ -1333,7 +1343,8 @@ fill_dim_structs( NCVar *v ) /* Indicate non-scannable dimensions by a NULL */ *(v->dim + i) = NULL; if( options.debug ) - fprintf( stderr, "adding non-scannable dim to var %s\n", v->name ); + fprintf( stderr, "adding non-scannable dim to var %s: dim name: %s size: %ld\n", + v->name, fi_dim_id_to_name( fileid, v->name, i), *(v->size+i) ); } } @@ -1360,8 +1371,10 @@ fill_dim_structs( NCVar *v ) } /****************************************************************************** - * Is this variable a "scannable" variable -- i.e., accessable by the taperecorder - * style buttons? + * Is this a "scannable" dimension -- i.e., accessable by the taperecorder + * style buttons? Is scannable if: + * > is unlimited + * > or, is size > 1 */ int is_scannable( NCVar *v, int i ) @@ -2283,3 +2296,130 @@ int determine_lat_lon( char *s_in, int *is_lat, int *is_lon ) return(1); /* error return */ } +/******************************************************************************************* + * Returns the number of forward slashes in a string + */ +int count_nslashes( char *s ) +{ + int i, nslash; + + nslash = 0; + for( i=0; i<strlen(s); i++ ) + if( s[i] == '/' ) + nslash++; + + return( nslash ); +} + +/******************************************************************************************* + * Given a list of variables, this returns a stringlist of unique group names. If ANY var + * lives in the root group, then the return list includes "/". If no var lives in the root + * group, then the list does NOT include "/". + */ +Stringlist *get_group_list( NCVar *vars ) +{ + Stringlist *retval = NULL, *tg; + NCVar *cursor; + char group_name[ MAX_NC_NAME*20 ]; /* Assume no more than 20 levels of groups */ + int i, ierr, n_so_far, foundit; + + cursor = vars; + while( cursor != NULL ) { + + ierr = unpack_groupname( cursor->name, -1, group_name ); /* -1 means get full group name */ + + /* Only add to list if not already there */ + n_so_far = stringlist_len( retval ); + tg = retval; + foundit = 0; + while( tg != NULL ) { + if( strcmp( tg->string, group_name ) == 0 ) { + foundit = 1; + break; + } + tg = tg->next; + } + if( foundit == 0 ) + ierr = stringlist_add_string( &retval, group_name, NULL, SLTYPE_NULL ); + + cursor = cursor->next; + } + + return( retval ); +} + +/******************************************************************************************* + * Given a varname string of format: groupname0/groupname1/groupnameN/varname + * + * and an integer ig: 0...N this returns groupname correspoinding to the integer ig + * (NOTE: counting starts at 0, so if ig==0 then the first group name is returned) + * + * If ig == -1, then the full groupname without the varname is returned: + * I.e., "groupname0/groupname1/groupnameN". If the var does NOT have any + * forward slashes, it lives in the root group, and "/" is returned. + * + * If ig == -2, then ONLY the varname is returned. I.e., "varname" + * + * groupname must already be allocated upon entry + * + * Returns 0 on success, -1 on error + */ +int unpack_groupname( char *varname, int ig, char *groupname ) +{ + int i, i0, i1, idx_slash[MAX_NC_NAME], nslash; + char ts[MAX_NC_NAME]; + + /* Get indices of the slashes */ + nslash = 0; + for( i=0; i<strlen(varname); i++ ) { + if( varname[i] == '/' ) { + idx_slash[nslash] = i; + nslash++; + } + } + + if( nslash == 0 ) { + if (ig == -2 ) { + /* Asked for varname only */ + strcpy( groupname, varname ); + return(0); + } + else + { + /* If no slashes in the var name, must live in root group */ + strcpy( groupname, "/" ); + return( 0 ); + } + } + + if( ig > (nslash+1) ) { + fprintf( stderr, "Error in unpack_groupname: varname: >%s< group to find (starting at 0)=%d invalid group to find (not this many groups in the varname)\n", + varname, ig ); + exit(-1); + } + + strcpy( ts, varname ); + + if( ig == -2 ) { + strcpy( groupname, ts+idx_slash[nslash-1]+1 ); + return( 0 ); + } + + if( ig == -1 ) { + ts[ idx_slash[nslash-1] ] = '\0'; + strcpy( groupname, ts ); + return( 0 ); + } + + if( ig == 0 ) + i0 = 0; + else + i0 = idx_slash[ig-1] + 1; + i1 = idx_slash[ig]; + ts[i1] = '\0'; + + strcpy( groupname, ts+i0 ); + + return( 0 ); +} + diff --git a/src/view.c b/src/view.c index 7ef0f2c..60d32f7 100644 --- a/src/view.c +++ b/src/view.c @@ -75,7 +75,7 @@ static void re_determine_scan_axes( View *new_view, NCVar *new_var, View *old_ static void set_scan_place( View *new_view, NCVar *var, View *old_view ); static void initial_set_scan_place( View *view, NCVar *var ); static void re_set_scan_place( View *new_view, NCVar *new_var, View *old_view ); -static void calculate_blowup( View *view, NCVar *var ); +static void calculate_blowup( View *view, NCVar *var, int val_to_set_to ); static void draw_file_info( NCVar *var ); static void label_dimensions( View *view ); static void show_current_dim_values( View *view ); @@ -111,8 +111,12 @@ set_scan_variable( NCVar *var ) float range_x, range_y; NCDim *xdim, *ydim, *xdim_old, *xdim_new, *ydim_old, *ydim_new; - if( options.debug ) + if( options.debug ) { fprintf( stderr, "\n\n******************************************\nentering set_scan_variable with var=%s\n", var->name ); + fprintf( stderr, "var nims:%d\n", var->n_dims ); + for( i=0; i<var->n_dims; i++ ) + fprintf( stderr, "dim=%ld size=%ld\n", i, *(var->size + i) ); + } in_set_cursor_busy(); @@ -132,6 +136,9 @@ set_scan_variable( NCVar *var ) if( options.debug ) fprintf( stderr, "...determining scan axes (NEW)\n" ); determine_scan_axes( view, var, NULL ); + if( options.debug ) + fprintf( stderr, "...axes ids: scan=%d y=%d x=%d\n", + view->scan_axis_id, view->y_axis_id, view->x_axis_id ); if( var->effective_dimensionality == 1 ) { start = (size_t *)malloc(view->variable->n_dims*sizeof(size_t)); count = (size_t *)malloc(view->variable->n_dims*sizeof(size_t)); @@ -162,7 +169,12 @@ set_scan_variable( NCVar *var ) /* How big should we initially make the picture? */ if( options.debug ) fprintf( stderr, "...calculating blowup (NEW)\n" ); - calculate_blowup( view, var ); + calculate_blowup( view, var, -99999 ); /* last val is flag meaning to do automatic calculation */ + + /* Save the blowup we are using in the var structure so we can + * return to it later if we want + */ + var->user_set_blowup = options.blowup; if( options.debug ) fprintf( stderr, "... ... new blowup=%d\n", options.blowup ); } @@ -226,7 +238,11 @@ set_scan_variable( NCVar *var ) if( options.debug ) fprintf( stderr, "...axis change, recalculating blowup; old, new X dim=%s, %s; old, new Y dim=%s, %s\n", xdim_old->name, xdim_new->name, ydim_old->name, ydim_new->name ); - calculate_blowup( new_view, var ); + calculate_blowup( new_view, var, var->user_set_blowup ); + /* Save the blowup we are using in the var structure so we can + * return to it later if we want + */ + var->user_set_blowup = options.blowup; } /* If the new var has a different shape than the old var, @@ -425,7 +441,14 @@ change_view( int delta, int interpretation ) /* Delta is in percent of total size */ size = *(view->variable->size + view->scan_axis_id); provisional_delta = (float)size * (float)delta/100.0; - delta = (int)provisional_delta; + if( (int)provisional_delta == 0 ) { + if( delta < 0 ) + delta = -1; + else + delta = 1; + } + else + delta = (int)provisional_delta; } place = *(view->var_place + view->scan_axis_id) + delta; @@ -974,9 +997,16 @@ initial_determine_scan_axes( View *view, NCVar *var ) Stringlist *dimlist; int n_dims; + if( options.debug ) fprintf( stderr, "initial_determine_scan_axes: entering for var %s\n", var->name ); + /* Get a list of all possible scannable dimensions */ dimlist = fi_scannable_dims( var->first_file->id, var->name ); + if( options.debug ) { + fprintf( stderr, "initial_determine_scan_axes: scannable dims:\n" ); + stringlist_dump( dimlist ); + } + /* For now, just pick the last two to be the Y and X axes. */ n_dims = stringlist_len( dimlist ); @@ -996,11 +1026,21 @@ initial_determine_scan_axes( View *view, NCVar *var ) var->first_file->id, var->name, dimlist->string ); + if( view->y_axis_id == -1 ) { + fprintf( stderr, "initial_determine_scan_axes: internal error: dim >%s< was indicated by routine fi_scannable_dims to be a scannable dim for var >%s<, but routine fi_dim_name_to_id did not find that dim for the var\n", + dimlist->string, var->name ); + exit(-1); + } dimlist = dimlist->next; view->x_axis_id = fi_dim_name_to_id( var->first_file->id, var->name, dimlist->string ); + if( view->x_axis_id == -1 ) { + fprintf( stderr, "initial_determine_scan_axes: internal error: dim >%s< was indicated by routine fi_scannable_dims to be a scannable dim for var >%s<, but routine fi_dim_name_to_id did not find that dim for the var\n", + dimlist->string, var->name ); + exit(-1); + } break; default: @@ -1012,6 +1052,11 @@ initial_determine_scan_axes( View *view, NCVar *var ) var->first_file->id, var->name, dimlist->string ); + if( view->scan_axis_id == -1 ) { + fprintf( stderr, "initial_determine_scan_axes: internal error: dim >%s< was indicated by routine fi_scannable_dims to be a scannable dim for var >%s<, but routine fi_dim_name_to_id did not find that dim for the var\n", + dimlist->string, var->name ); + exit(-1); + } dimlist = dimlist->next; /* Go to the second to the last entry */ @@ -1021,13 +1066,26 @@ initial_determine_scan_axes( View *view, NCVar *var ) var->first_file->id, var->name, dimlist->string ); + if( view->y_axis_id == -1 ) { + fprintf( stderr, "initial_determine_scan_axes: internal error: dim >%s< was indicated by routine fi_scannable_dims to be a scannable dim for var >%s<, but routine fi_dim_name_to_id did not find that dim for the var\n", + dimlist->string, var->name ); + exit(-1); + } dimlist = dimlist->next; view->x_axis_id = fi_dim_name_to_id( var->first_file->id, var->name, dimlist->string ); + if( view->x_axis_id == -1 ) { + fprintf( stderr, "initial_determine_scan_axes: internal error: dim >%s< was indicated by routine fi_scannable_dims to be a scannable dim for var >%s<, but routine fi_dim_name_to_id did not find that dim for the var\n", + dimlist->string, var->name ); + exit(-1); + } break; } + + if( options.debug ) fprintf( stderr, "initial_determine_scan_axes: exiting with axis_ids: scan=%d y=%d x=%d\n", + view->scan_axis_id, view->y_axis_id, view->x_axis_id ); } /******************************************************************************** @@ -1053,7 +1111,7 @@ fill_view_data( View *v ) *(count+v->x_axis_id) = *(v->variable->size + v->x_axis_id); *(count+v->y_axis_id) = *(v->variable->size + v->y_axis_id); - if( options.show_sel ) { + if( options.debug || options.show_sel ) { printf( "-var %s -start \\(", v->variable->name ); for( i=v->variable->n_dims-1; i >= 0; i-- ) { printf( "%1ld", 1 + (*(v->var_place+i)) ); @@ -1079,7 +1137,7 @@ fill_view_data( View *v ) * Alter the amount by which we are blowing up pixels */ void -view_change_blowup( int delta, int redraw_flag ) +view_change_blowup( int delta, int redraw_flag, int view_var_is_valid ) { size_t x_size, y_size, scaled_x_size, scaled_y_size; char blowup_label[32]; @@ -1112,6 +1170,10 @@ view_change_blowup( int delta, int redraw_flag ) in_set_label( LABEL_BLOWUP, blowup_label ); + if( view_var_is_valid ) { + view->variable->user_set_blowup = options.blowup; + } + free( view->pixels ); x_size = *(view->variable->size + view->x_axis_id); @@ -1824,22 +1886,37 @@ re_set_scan_place( View *new_view, NCVar *new_var, View *old_view ) } /**************************************************************************************/ +/* If 'val_to_set_to' is -99999, then the blowup is calculated automatically, + * otherwise the blowup is set to val_to_set_to + */ static void -calculate_blowup( View *view, NCVar *var ) +calculate_blowup( View *view, NCVar *var, int val_to_set_to ) { size_t x_size, y_size; float fbx, fby, f_x_size, f_y_size, f_blowup; - int ifbx; + int ifbx, view_var_is_valid; if( options.small ) return; + view_var_is_valid = 0; + + if( val_to_set_to != -99999 ) { + while( options.blowup > val_to_set_to ) { + view_change_blowup( -1, FALSE, view_var_is_valid ); + } + while( options.blowup < val_to_set_to ) { + view_change_blowup( 1, FALSE, view_var_is_valid ); + } + return; + } + /* If the picture is too small, start out by blowing it up some */ x_size = *(var->size + view->x_axis_id); y_size = *(var->size + view->y_axis_id); while( (options.blowup*x_size < options.blowup_default_size) && (options.blowup*y_size < options.blowup_default_size) ) { - view_change_blowup( 1, FALSE ); + view_change_blowup( 1, FALSE, view_var_is_valid ); } /* If picture is too big, reduce it some */ @@ -1851,7 +1928,7 @@ calculate_blowup( View *view, NCVar *var ) fbx = (fbx > fby) ? fbx : fby; if( fbx > 3 ) { ifbx = -(int)fbx; - view_change_blowup(ifbx,FALSE); + view_change_blowup(ifbx,FALSE, view_var_is_valid); } } diff --git a/x_interface.c b/x_interface.c new file mode 100644 index 0000000..e69de29 -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/ncview.git _______________________________________________ Pkg-grass-devel mailing list Pkg-grass-devel@lists.alioth.debian.org http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-grass-devel