#include "afni.h" #ifndef ALLOW_PLUGINS # error "Plugins not properly set up -- see machdep.h" #endif #define DSETN_VERSION "Version 1.1 " /*********************************************************************** Plugin to provide extra datasets' timeseries in place of first ************************************************************************/ /*---------------------------------------------------------------------- * history: * * 1.1 October 28, 2002 - rickr * - register for RECEIVE_DSETCHANGE messages * - update global dset list from g_id list (upon message reception) *---------------------------------------------------------------------- */ char * DSETN_main ( PLUGIN_interface *) ; void DSETN_func ( MRI_IMAGE * ) ; void DSETN_dset_recv( int why, int np, int * ijk, void * aux ) ; static int set_global_dsets_from_ids( void ); #undef USE_WHERE static char helpstring[] = " Purpose: Control the 'Dataset#N' 1D timeseries function\n" "\n" " Dataset = a 3D+time dataset from which to extract data\n" " Color = color to overlay in AFNI graph window\n" "\n" " Usage:\n" " 1) Choose in this plugin the 3D+time datasets you want to graph,\n" " and their overlay colors. Then press 'Set+Keep'.\n" " 2) In an AFNI graph window, choose 'Tran 1D' to be 'Dataset#N'.\n" " This will cause the time series chosen here to replace the\n" " time series of the dataset being graphed.\n" " 3) Optionally, you can set 'Double Plot' to 'Overlay' in the\n" " AFNI graph window - this will then also show the time series\n" " from the current AFNI graph window.\n" "\n" " Note that changes in this plugin interface are not communicated\n" " to AFNI itself until you press one of the 'Set' buttons.\n" #ifdef USE_WHERE "\n" " Justify = Left means to put timeseries data at start of output array\n" " Right means to put timeseries data at end of output array\n" "\n" " Fill = Extend means to copy the last value\n" " Zero means to fill with zeros\n" "\n" " Justify and Fill are only used when the number of points in the input\n" " dataset doesn't match the number of points in the timeseries being replaced.\n" " Let M = length of dataset, N = length of timeseries,\n" " ts[] = timeseries array, ds[] = dataset array.\n" "\n" " Case: M < N (too little data to fill timeseries)\n" " Left: ts[i] = ds[i] i=0..M-1 Data goes to left\n" " = ds[M-1] i=M..N-1 if Extend edge of timeseries\n" " = 0.0 i=M..N-1 if Zero\n" " Right: ts[i] = ds[0] i=0..J-1 if Extend (with J=N-M) Data goes to right\n" " = 0.0 i=0..J-1 if Zero edge of timeseries\n" " = ds[i-J] i=J..N-1\n" " Case: M > N (too much data for timeseries)\n" " Left: ts[i] = ds[i] i=0..N-1 Left data to ts[]\n" " Right: ts[i] = ds[i+J] i=0..N-1 (with J=M-N) Right data to ts[]\n" #endif "\n" " -- RWCox - 29 Mar 2002\n" ; #define NMAX 9 /* max number of time series */ static THD_3dim_dataset *dset[NMAX] ; static MCW_idcode g_id[NMAX] ; /* for re-establishing dset values */ static int ovc [NMAX] ; static int g_dset_recv = -1 ; /* for AFNI messaging */ static int g_valid_data = 0 ; /* is the data usable */ #ifdef USE_WHERE static int justify = 0 ; static int fill = 0 ; #endif /*********************************************************************** Set up the interface to the user ************************************************************************/ static char *lr[2] = { "Left" , "Right" } ; static char *ez[2] = { "Extend" , "Zero" } ; static PLUGIN_interface *plint=NULL ; static void DSETN_func_init(void) /* 21 Jul 2003 */ { PLUG_startup_plugin_CB( NULL , (XtPointer)plint , NULL ) ; } DEFINE_PLUGIN_PROTOTYPE PLUGIN_interface * PLUGIN_init( int ncall ) { int id ; ENTRY("PLUGIN_init:Dataset#N") ; if( ncall > 0 ) RETURN( NULL ); /* only one interface */ AFNI_register_nD_function ( 1 , "Dataset#N" , (generic_func *)DSETN_func , NEEDS_DSET_INDEX|PROCESS_MRI_IMAGE ) ; AFNI_register_nD_func_init( 1 , (generic_func *) DSETN_func_init ) ; /* 21 Jul 2003 */ plint = PLUTO_new_interface( "Dataset#N", "Controls 1D function Dataset#N", helpstring, PLUGIN_CALL_VIA_MENU, DSETN_main ) ; PLUTO_add_hint( plint , "Controls 1D function Dataset#N" ) ; PLUTO_set_sequence( plint , "A:funcs:dataset#N" ) ; PLUTO_set_runlabels( plint , "Set+Keep" , "Set+Close" ) ; /* 04 Nov 2003 */ for( id=0 ; id < NMAX ; id++ ){ PLUTO_add_option( plint , "Input" , "Input" , FALSE ) ; PLUTO_add_dataset(plint , "Dataset" , ANAT_ALL_MASK , FUNC_ALL_MASK , DIMEN_4D_MASK | BRICK_ALLREAL_MASK ) ; PLUTO_add_overlaycolor( plint , "Color" ) ; } #ifdef USE_WHERE PLUTO_add_option( plint , "Where" , "Where" , FALSE ) ; PLUTO_add_string( plint, "Justify", 2, lr, justify ) ; PLUTO_add_option( plint , "How" , "How" , FALSE ) ; PLUTO_add_string( plint, "Fill", 2, ez, fill ) ; #endif /* init the global lists */ for ( id=0 ; id < NMAX ; id++ ){ dset[id] = NULL; ZERO_IDCODE(g_id[id]); } RETURN( plint ) ; } /*************************************************************************** Main routine for this plugin (will be called from AFNI). ****************************************************************************/ char * DSETN_main( PLUGIN_interface * plint ) { MCW_idcode *idc ; char *str , *tag ; int id=0 ; ENTRY( "DSETN_main" ) ; if( plint == NULL ) RETURN("***********************\n" "DSETN_main: NULL input\n" "***********************") ; for( id=0 ; id < NMAX ; id++ ){ /* 18 Mar 2004: renullification */ dset[id] = NULL ; ZERO_IDCODE(g_id[id]); } id = 0 ; while( (tag=PLUTO_get_optiontag(plint)) != NULL ){ /* Input */ if( strcmp(tag,"Input") == 0 ){ idc = PLUTO_get_idcode(plint) ; dset[id] = PLUTO_find_dset(idc) ; if ( ! ISVALID_DSET( dset[id] ) ) RETURN("******************************\n" "DSETN_main: bad input dataset\n" "******************************") ; g_id[id] = *idc ; ovc [id] = PLUTO_get_overlaycolor(plint) ; id++ ; continue ; } #ifdef USE_WHERE /* Where */ if( strcmp(tag,"Where") == 0 ){ str = PLUTO_get_string(plint) ; justify = (strcmp(str,lr[0]) != 0) ; continue ; } /* How */ if( strcmp(tag,"How") == 0 ){ str = PLUTO_get_string(plint) ; fill = (strcmp(str,ez[0]) != 0) ; continue ; } #endif } if ( id <= 0 ) /* no data - nothing to do */ RETURN( NULL ) ; g_valid_data = 1 ; /* valid data, woohooo! */ if ( g_dset_recv < 0 ) g_dset_recv = AFNI_receive_init( plint->im3d, RECEIVE_DSETCHANGE_MASK, DSETN_dset_recv, plint , "DSETN_dset_recv" ) ; if ( g_dset_recv < 0 ) RETURN("*************************************\n" "DSETN_main: failed AFNI_receive_init\n" "*************************************") ; PLUTO_force_redisplay() ; RETURN( NULL ); } /*----------------------------------------------------------------------------*/ void DSETN_dset_recv( int why, int np, int * ijk, void * aux ) { PLUGIN_interface * plint = (PLUGIN_interface *)aux; ENTRY( "DSETN_dset_recv" ); switch ( why ) { default: { fprintf( stderr, "warning: DSETN_dset_recv() called with invalid " "why code, %d\n", why ); EXRETURN; } case RECEIVE_ALTERATION: /* may take effect before DSETCHANGE */ case RECEIVE_DSETCHANGE: { /* start by noting the number of valid data sets */ int num_valid = set_global_dsets_from_ids( ); if ( g_valid_data != 1 || num_valid <= 0 ) { /* shut the plugin down - "he's only _mostly_ dead" */ g_valid_data = 0; AFNI_receive_control( plint->im3d, g_dset_recv, EVERYTHING_SHUTDOWN, NULL ); g_dset_recv = -1; PLUTO_popup_worker( plint, "Warning: plugin 'Dataset#N'\n" "has lost its dataset links.\n" "To plot 1-D overlays, please\n" "re-run the plugin.", MCW_USER_KILL | MCW_TIMER_KILL ) ; } } } EXRETURN; } /*----------------------------------------------------------------------------*/ void DSETN_func( MRI_IMAGE *qim ) { int id , ny , nxtop=0 , ijk , ii ; MRI_IMARR *tar ; MRI_IMAGE *tsim , *zim ; float *tsar , *dar ; int ovi[NMAX] ; char str[16+4*NMAX] ; ENTRY( "DSETN_func" ); if ( g_valid_data != 1 ) EXRETURN ; /* nothing to do */ INIT_IMARR(tar) ; ijk = AFNI_needs_dset_ijk() ; /* voxel index from AFNI */ for( id=0 ; id < NMAX ; id++ ){ if( ISVALID_DSET(dset[id]) ){ tsim = THD_extract_series( ijk,dset[id], 0 ) ; /* get data */ if( tsim == NULL ) continue ; ovi[IMARR_COUNT(tar)] = ovc[id] ; ADDTO_IMARR(tar,tsim) ; nxtop = MAX(nxtop,tsim->nx) ; } } ny = IMARR_COUNT(tar) ; if( ny == 0 || nxtop < 2 ){ DESTROY_IMARR(tar); EXRETURN; } /* no data */ if( ny == 1 ){ /* one dataset */ tsim = IMARR_SUBIM(tar,0); FREE_IMARR(tar); mri_move_guts(qim,tsim); sprintf(str,"color: %d",ovi[0]) ; mri_add_name(str,qim) ; EXRETURN; } /* multiple datasets */ tsim = mri_new( nxtop , ny , MRI_float ) ; tsar = MRI_FLOAT_PTR(tsim) ; strcpy(str,"color:") ; for( id=0 ; id < ny ; id++ ){ zim = IMARR_SUBIM(tar,id) ; dar = MRI_FLOAT_PTR(zim) ; memcpy( tsar , dar , sizeof(float)*zim->nx) ; if( zim->nx < nxtop ){ /* 18 Mar 2004: fill with infinity */ for( ii=zim->nx ; ii < nxtop ; ii++ ) tsar[ii] = WAY_BIG ; } tsar += nxtop ; sprintf(str+strlen(str)," %d",ovi[id]) ; } DESTROY_IMARR(tar) ; mri_move_guts(qim,tsim) ; mri_add_name(str,qim) ; EXRETURN; } static int set_global_dsets_from_ids( void ) { THD_3dim_dataset * dptr; int idcount, num_valid = 0; ENTRY( "set_global_dsets_from_ids" ); for ( idcount = 0; idcount < NMAX; idcount++ ) { if ( ! ISZERO_IDCODE( g_id[idcount] ) ) { dptr = PLUTO_find_dset( &g_id[idcount] ); if ( ! ISVALID_DSET( dptr ) ) { dptr = NULL; ZERO_IDCODE( g_id[idcount] ); /* lost dataset */ } else /* a good one */ num_valid++; } else /* just being safe */ dptr = NULL; dset[idcount] = dptr; } RETURN( num_valid ); }