#include "mrilib.h" #include "thd.h" #include "niml.h" /*---------------------------------------------------------------------*/ /*! Write all the attributes for a datablock into a set of NIML data elements, stored in a NIML group element. -----------------------------------------------------------------------*/ NI_group * THD_nimlize_dsetatr( THD_3dim_dataset *dset ) { THD_datablock *blk ; ATR_any *atr_any ; NI_element *nel ; int ia ; NI_group *ngr = NULL ; /* will be output */ ENTRY("THD_nimlize_dsetatr") ; /*--- sanity checks ---*/ if( !ISVALID_DSET(dset) ) RETURN(ngr) ; blk = dset->dblk ; if( blk == NULL ) RETURN(ngr) ; THD_set_dataset_attributes( dset ) ; if( blk->natr == 0 || blk->atr == NULL ) RETURN(ngr) ; /* create empty output group */ ngr = NI_new_group_element() ; NI_rename_group( ngr , "AFNI_dataset" ) ; NI_set_attribute( ngr , "self_idcode" , dset->idcode.str ) ; /* make a data element for each attribute ... */ for( ia=0 ; ia < blk->natr ; ia++ ){ atr_any = &(blk->atr[ia]) ; if( atr_any == NULL ) continue ; /* bad attribute */ switch( atr_any->type ){ /* numeric types are easy: a single column vector with the numbers */ case ATR_FLOAT_TYPE:{ ATR_float *atr_flo = (ATR_float *)atr_any ; nel = NI_new_data_element( "AFNI_atr" , atr_flo->nfl ) ; nel->outmode = NI_TEXT_MODE ; NI_set_attribute( nel , "atr_name" , atr_flo->name ) ; NI_add_column( nel , NI_FLOAT , atr_flo->fl ) ; NI_add_to_group( ngr , nel ) ; } break ; case ATR_INT_TYPE:{ ATR_int *atr_int = (ATR_int *)atr_any ; nel = NI_new_data_element( "AFNI_atr" , atr_int->nin ) ; nel->outmode = NI_TEXT_MODE ; NI_set_attribute( nel , "atr_name" , atr_int->name ) ; NI_add_column( nel , NI_INT , atr_int->in ) ; NI_add_to_group( ngr , nel ) ; } break ; /* 02 Jun 2005: If string to save is too long, break it into pieces. Will have to be reassembled on input into one string. */ #undef SZMAX #define SZMAX 1000 case ATR_STRING_TYPE:{ ATR_string *atr_str = (ATR_string *)atr_any ; int nnn , nstr , istr , ibot,itop ; char **sar ; nnn = atr_str->nch ; if( nnn <= 0 ) break ; nstr = ((nnn-1)/SZMAX) + 1 ; sar = (char **)malloc(sizeof(char *)*nstr) ; for( istr=0 ; istr < nstr ; istr++ ){ ibot = istr*SZMAX ; itop = ibot+SZMAX ; if( itop > atr_str->nch ) itop = atr_str->nch ; nnn = itop-ibot ; sar[istr] = (char *)calloc(1,nnn+1) ; memcpy( sar[istr] , atr_str->ch+ibot , nnn ) ; THD_zblock( nnn , sar[istr] ) ; sar[istr][nnn] = '\0' ; } if( nnn > 1 && sar[nstr-1][nnn-1] == ZBLOCK ) sar[nstr-1][nnn-1] = '\0' ; nel = NI_new_data_element( "AFNI_atr" , nstr ) ; nel->outmode = NI_TEXT_MODE ; NI_set_attribute( nel , "atr_name" , atr_str->name ) ; NI_add_column( nel , NI_STRING , sar ) ; NI_add_to_group( ngr , nel ) ; for( istr=0 ; istr < nstr ; istr++ ) free((void *)sar[istr]) ; free((void *)sar) ; } break ; } /* end of switch on atr type */ } /* end of loop over all atr's */ /*--- done ---*/ RETURN(ngr) ; } /*---------------------------------------------------------------------*/ /*! Given a NIML group element, read AFNI attribute elements from it and load these into a datablock. -----------------------------------------------------------------------*/ void THD_dblkatr_from_niml( NI_group *ngr , THD_datablock *blk ) { int ip ; char *rhs ; ENTRY("THD_dblkatr_from_niml") ; if( ngr == NULL || NI_element_type(ngr) != NI_GROUP_TYPE || blk == NULL ) EXRETURN ; /*-- loop over parts and extract data from any '' elements --*/ for( ip=0 ; ip < ngr->part_num ; ip++ ){ switch( ngr->part_typ[ip] ){ /*-- a sub-group ==> recursion! --*/ case NI_GROUP_TYPE: THD_dblkatr_from_niml( (NI_group *)ngr->part[ip] , blk ) ; break ; /*- data ==> see if is marked as an AFNI_atr and has exactly 1 column if so, then extract that column and load into datablock -*/ case NI_ELEMENT_TYPE:{ /* data ==> see if is an AFNI attribute */ NI_element *nel = (NI_element *)ngr->part[ip] ; char *rhs = NI_get_attribute( nel , "atr_name" ) ; if( rhs == NULL ) rhs = NI_get_attribute( nel , "AFNI_name" ) ; if( strcasecmp(nel->name,"AFNI_atr") == 0 && /* AFNI attribute? */ nel->vec_num == 1 && /* with some data? */ nel->vec_len > 0 && /* that is nonempty? */ nel->vec != NULL && /* and has data? */ nel->vec[0] != NULL && rhs != NULL && /* and has a name? */ *rhs != '\0' ){ /* a nonempty name? */ STATUS(rhs) ; switch( nel->vec_typ[0] ){ /* 3 different data types of attributes */ /* float attribute: copy 1st column of numbers into AFNI */ case NI_FLOAT: THD_set_float_atr( blk , rhs , nel->vec_len , (float *)nel->vec[0] ) ; break ; /* int attribute: ditto */ case NI_INT: THD_set_int_atr( blk , rhs , nel->vec_len , (int *)nel->vec[0] ) ; break ; /* 02 Jun 2005: if have more than one String here, must reassemble them into a single array */ case NI_STRING:{ if (nel->vec) { /* to be expected */ char **sar = (char **)nel->vec[0] , *str ; int nch , nstr=nel->vec_len , istr , lll=0 ; for( istr=0 ; istr < nstr ; istr++) if (sar[istr]) lll += strlen(sar[istr]); /* ZSS Nov 2012 */ str = malloc(lll+4) ; *str = '\0' ; /* for( istr=0 ; istr < nstr ; istr++ ) strcat(str,sar[istr]); */ /* The loop of strcat() is very slow in the case of a long history element, O(n^2), so replace with something linear. Javier complained that afni took forever to start. One NIfTI dset with 8 MB history took ~8 seconds in loop. 31 Jul 2012 [rickr] */ { char * cp, * sp = str; int slen; for( istr=0; istr < nstr; istr++ ) { if (sar[istr]) { /* ZSS Nov 2012 */ cp = sar[istr]; slen = strlen(cp); memcpy(sp, cp, slen*sizeof(char)); sp += slen; } } *sp = '\0'; } nch = strlen(str) ; THD_unzblock( nch+1 , str ) ; /* re-insert NULs */ THD_set_char_atr( blk , rhs , nch+1 , str ) ; free(str) ; } } break ; } } } break ; } } /* end of loop over pieces-parts */ /* 01 Jun 2005: special case: reset the IDCODE_STRING attribute if the group element so indicates (thereby overriding the AFNI_atr element of that name, if was present) */ rhs = NI_get_attribute(ngr,"self_idcode") ; if( rhs == NULL ) rhs = NI_get_attribute(ngr,"AFNI_idcode") ; if( rhs != NULL && *rhs != '\0' ){ STATUS("reset idcode") ; THD_set_string_atr( blk , ATRNAME_IDSTRING , rhs ) ; } EXRETURN ; } /*-----------------------------------------------------------------------*/ /*! Make an AFNI dataset from a NIML group element. - The element should contain enough '' elements to define the dataset header. - It may also contain '' elements that contain data for the sub-bricks. This, however, is optional. - If the element contains a 'self_prefix' or 'AFNI_prefix' attribute, then the RHS of that will become the dataset's prefix name. - If the element contains a 'self_idcode' or 'AFNI_idcode' attribute, then the RHS of that will become the dataset's idcode, overriding the value that may be stored in the similar '' element. - If this element can't easily be re-loaded (e.g., came from a socket), then the dataset should be super-locked into memory, so it won't be purged! - If nodata!=0 on input, then any actual sub-brick data elements in the group element will not be loaded. You'll have to call THD_add_bricks() to do that later, if desired. -------------------------------------------------------------------------*/ THD_3dim_dataset * THD_niml_to_dataset( NI_group *ngr , int nodata ) { THD_3dim_dataset *dset ; THD_datablock *blk ; char *rhs ; int ii ; ENTRY("THD_niml_to_dataset") ; if( ngr == NULL || NI_element_type(ngr) != NI_GROUP_TYPE ) RETURN(NULL) ; /* create the shell of a dataset's datablock and populate it's attributes */ blk = EDIT_empty_datablock() ; THD_dblkatr_from_niml( ngr , blk ) ; /* load attributes from NIML */ /* build the datablock from the loaded attributes */ ii = THD_datablock_from_atr( blk , NULL , NULL ) ; if( ii == 0 ){ /* bad attributes */ THD_delete_datablock( blk ) ; RETURN(NULL) ; } /* build the dataset from the datablock */ THD_allow_empty_dataset(1) ; dset = THD_3dim_from_block( blk ) ; THD_allow_empty_dataset(0) ; if( dset == NULL ){ THD_delete_datablock( blk ); RETURN(NULL); } DSET_mallocize(dset) ; /* just to be sure */ /* change the name of the dataset? */ rhs = NI_get_attribute( ngr , "self_prefix" ) ; if( rhs == NULL ) rhs = NI_get_attribute( ngr , "AFNI_prefix" ) ; /* for the 'old' way */ if( rhs != NULL ) EDIT_dset_items( dset , ADN_prefix,rhs , ADN_none ) ; /* change the idcode of the dataset? */ rhs = NI_get_attribute( ngr , "self_idcode" ) ; if( rhs == NULL ) rhs = NI_get_attribute( ngr , "AFNI_idcode" ) ; /* for the 'old' way */ if( rhs != NULL ) NI_strncpy( dset->idcode.str , rhs , MCW_IDSIZE ) ; /* now scan the group element for data elements that fill sub-bricks */ if( !nodata ){ (void)THD_add_bricks( dset , ngr, NULL ) ; THD_update_statistics( dset ) ; } /* 18 Mar 2005: if the header orders, zero fill any undefined bricks */ rhs = NI_get_attribute( ngr , "AFNI_zerofill" ) ; if( rhs != NULL && toupper(rhs[0]) == 'Y' ) THD_zerofill_dataset(dset); RETURN(dset) ; } /*---------------------------------------------------------------------------*/ /*! Scan the NIML data or group element for sub-bricks to add to the given dataset. - Return value is number sub-bricks found (0 == something bad). - Note that the '' elements don't have to contain the right amount of data for a sub-brick. If there is too little, the remaining voxels will be 0; if too much, the excess data is ignored. - Each column of data creates or replaces one sub-brick. - At the present time, the only datatypes allowed are: byte, short, float, complex (float pairs), and rgb (byte triples). Columns of other types will be ignored. - If a '' element contains an 'index' attribute, then: - index >= 0 indicates which sub-brick the 1st column of the element goes into; subsequent columns go into successive sub-bricks, and any data already present in these sub-bricks will be over-written. - To indicate that the data is to be appended to the dataset, making new sub-bricks, just set index to a very large positive value (e.g., 9999999). - If 'index' is missing or negative, then the data columns will go into the first empty sub-bricks that are found; if none are found, new sub-bricks will be appended to the dataset. - If a '' element contains a 'scale_factor' attribute, and the numerical value of factor is positive, this value is used to set the scale factor for all sub-bricks loaded from the element. Otherwise, any scale factor previously set will remain in effect. - Elements that are not named 'VOLUME_DATA' will be ignored here. - hdset is used to provide header attributes for sub-bricks that would be added from '' ZSS, Jan 2011 *//*-------------------------------------------------------------------------*/ int THD_add_bricks( THD_3dim_dataset *dset , void *nini, THD_3dim_dataset *hdset ) { int nbr=0 , tt=NI_element_type(nini) ; NI_element *nel ; int nxyz , ii=-2, jj , nbar , vlen , kk , bb=-2; void *bar ; char *str ; float fac ; ENTRY("THD_add_bricks") ; if( !ISVALID_DSET(dset) || tt < 0 || nini == NULL ) RETURN(0) ; /*-- if have a group element, do the parts by recursion --*/ if( tt == NI_GROUP_TYPE ){ NI_group *ngr = (NI_group *)nini ; int ip ; for( ip=0 ; ip < ngr->part_num ; ip++ ) /* loop over parts */ nbr += THD_add_bricks( dset , ngr->part[ip], hdset ) ; RETURN(nbr) ; } /*-- if here, have a single data element --*/ nel = (NI_element *)nini ; /*- check element name to see if it's what we want -*/ if( strcasecmp(nel->name,"VOLUME_DATA_SPARSE") == 0 ){ /* 31 Jan 2008: */ ii = THD_add_sparse_bricks( dset , nel ) ; /* sparsely defined */ RETURN(ii) ; /* array(s) of data */ } /*- otherwise, fully defined 3D array(s) of data -*/ if( strcasecmp(nel->name,"VOLUME_DATA") != 0 ) RETURN(0) ; nxyz = DSET_NVOX(dset) ; /* number of voxels in a sub-brick */ vlen = nel->vec_len ; /* number of values in a column of data */ if( vlen > nxyz ) vlen = nxyz ; if( nel->vec_num < 1 || vlen < 1 ) RETURN(0) ; /* no data at all? */ /*- find index of sub-brick, if present -*/ kk = -1 ; /* flag for overwrite */ str = NI_get_attribute( nel , "AFNI_index" ) ; if( str == NULL ) str = NI_get_attribute( nel , "index" ) ; if( str != NULL && isdigit(*str) ) kk = (int)strtol( str , NULL , 10 ) ; /*- and scale factor, if present -*/ fac = 0.0 ; str = NI_get_attribute( nel , "scale_factor" ) ; if( str == NULL ) str = NI_get_attribute( nel , "AFNI_factor" ) ; if( str != NULL && isnumeric(*str) ) fac = (float)strtod( str , NULL ) ; if(PRINT_TRACING){ char str[256] ; sprintf(str,"kk=%d vlen=%d nxyz=%d fac=%f\n",kk,vlen,nxyz,fac); STATUS(str); } /*- loop over columns and enter them into the dataset -*/ for( jj=0 ; jj < nel->vec_num ; jj++ ){ if( !AFNI_GOOD_DTYPE(nel->vec_typ[jj]) ) continue ; /* skip this */ /* create a volume array to hold this data */ nbar = mri_datum_size(nel->vec_typ[jj]) ; /* size of one value */ bar = calloc( nbar , nxyz ) ; /* will be zero filled */ if( bar == NULL ) RETURN(nbr) ; /* malloc failure! */ /* copy data from element into this volume */ memcpy( bar , nel->vec[jj] , vlen*nbar ) ; /* find a place (bb) to put this volume in the dataset */ if( kk < 0 ){ /* scan for an empty sub-brick */ for( ii=0 ; ii < DSET_NVALS(dset) ; ii++ ) if( DSET_ARRAY(dset,ii) == NULL ) break ; if( ii == DSET_NVALS(dset) ) kk = ii ; /* all full */ bb = ii ; /* put here */ } else if( kk > DSET_NVALS(dset) ){ bb = DSET_NVALS(dset) ; /* at end */ } else { bb = kk ; /* exactly here */ } if( bb < DSET_NVALS(dset) ){ /* replace existing data */ EDIT_substitute_brick( dset , bb , nel->vec_typ[jj] , bar ) ; } else { /* append new sub-brick */ bb = DSET_NVALS(dset) ; if (dset->dblk->malloc_type != DATABLOCK_MEM_MALLOC) { DSET_mallocize(dset); DSET_load(dset); } EDIT_add_brick( dset , nel->vec_typ[jj] , 0.0 , bar ) ; } if (hdset) { /* copy some attributes ZSS, Jan 2011 */ if (DSET_BRICK_LABEL(hdset,jj)) { EDIT_BRICK_LABEL( dset, bb, DSET_BRICK_LABEL(hdset,jj)); } } nbr++ ; /* 1 more sub-brick! */ if( fac > 0.0 ) EDIT_BRICK_FACTOR(dset,bb,fac) ; else if( fac <= 0.0 ) EDIT_BRICK_FACTOR(dset,bb,0.0) ; DSET_CRUSH_BSTAT(dset,bb) ; if( kk >= 0 ) kk++ ; /* move to next sub-brick */ } RETURN(nbr) ; } /*---------------------------------------------------------------------------*/ /*! Like THD_add_bricks(), but with a single element of type *//*-------------------------------------------------------------------------*/ int THD_add_sparse_bricks( THD_3dim_dataset *dset , NI_element *nel ) { int nbr=0 ; int nxyz , ii , jj , nbar , vlen , kk , bb ; void *bar ; char *str ; float fac ; int *id , do_zzz=1 , nd=1 ; int nx,ny,nz,nxy , pp,qq,rr , otyp,ityp ; ENTRY("THD_add_sparse_bricks") ; if( !ISVALID_DSET(dset) || nel == NULL || nel->type != NI_ELEMENT_TYPE ){ ERROR_message("bad data on entry to THD_add_sparse_bricks()") ; RETURN(0) ; } /*--- check element name to see if it's what we want ---*/ if( strcasecmp(nel->name,"VOLUME_DATA_SPARSE") != 0 ) RETURN(0) ; vlen = nel->vec_len ; /* number of values in a column of data */ nx = DSET_NX(dset) ; ny = DSET_NY(dset) ; nxy = nx*ny ; nz = DSET_NZ(dset) ; nxyz = nxy*nz; /*----- check if have at least 2 columns and 1 row! -----*/ if( nel->vec_num < 2 || vlen < 1 ){ ERROR_message("inadequate data in header") ; RETURN(0) ; } /*----- determine if we have xyz coords or index coords -----*/ if( nel->vec_num > 3 && nel->vec_typ[0] == NI_FLOAT && nel->vec_typ[1] == NI_FLOAT && nel->vec_typ[2] == NI_FLOAT ){ /*- xyz -*/ float *xdd , *ydd , *zdd ; THD_fvec3 xyz ; THD_ivec3 ijk ; nd = 3 ; /* indicating we use the first 3 columns for index computation */ id = (int *)malloc(sizeof(int)*vlen) ; /* indexes computed below */ xdd = (float *)nel->vec[0] ; /* DICOM coordinates */ ydd = (float *)nel->vec[1] ; zdd = (float *)nel->vec[2] ; for( ii=0 ; ii < vlen ; ii++ ){ LOAD_FVEC3( xyz , xdd[ii],ydd[ii],zdd[ii] ) ; /* get coords */ xyz = THD_dicomm_to_3dmm( dset , xyz ) ; /* to dset xyz */ ijk = THD_3dmm_to_3dind_warn( dset , xyz , &jj ) ; /* to 3D index */ if( jj == 0 ){ UNLOAD_IVEC3( ijk , pp,qq,rr ) ; /* if good, make 1D */ id[ii] = pp + qq*nx + rr*nxy ; } else { id[ii] = -1 ; /* not good ==> means to skip this puppy */ } } } else { /*------- index coords -------*/ if( nel->vec_num > 3 && nel->vec_typ[0] == NI_INT && nel->vec_typ[1] == NI_INT && nel->vec_typ[2] == NI_INT ){ /* 3 ints */ nd = 3 ; } else if( nel->vec_typ[0] == NI_INT ){ /* 1 int */ nd = 1 ; } else { /* bad */ ERROR_message("invalid coordinate column types in header"); RETURN(0) ; } /* get or create index into dataset from these int columns */ switch( nd ){ case 1: id = (int *)nel->vec[0] ; break ; /* just assign */ case 3:{ /* must create index array */ int *idd, *jdd , *kdd ; idd = (int *)nel->vec[0] ; jdd = (int *)nel->vec[1] ; kdd = (int *)nel->vec[2] ; id = (int *)malloc(sizeof(int)*vlen) ; for( ii=0 ; ii < vlen ; ii++ ){ pp = idd[ii] ; if( pp < 0 || pp >= nx ){ id[ii] = -1; continue; } qq = jdd[ii] ; if( qq < 0 || qq >= ny ){ id[ii] = -1; continue; } rr = kdd[ii] ; if( rr < 0 || rr >= nz ){ id[ii] = -1; continue; } id[ii] = pp + qq*nx + rr*nxy ; } } break ; } } /*- find index of sub-brick, if present -*/ kk = -1 ; /* flag for overwrite */ str = NI_get_attribute( nel , "AFNI_index" ) ; if( str == NULL ) str = NI_get_attribute( nel , "index" ) ; if( str != NULL && isdigit(*str) ) kk = (int)strtol( str , NULL , 10 ) ; /*- and scale factor, if present -*/ fac = 0.0 ; str = NI_get_attribute( nel , "scale_factor" ) ; if( str == NULL ) str = NI_get_attribute( nel , "AFNI_factor" ) ; if( str != NULL && isnumeric(*str) ) fac = (float)strtod( str , NULL ) ; /* check if doing infill or if we should set brick to all zero first */ /* THIS IS IGNORED AT PRESENT! */ #if 0 str = NI_get_attribute("infill") ; if( str == NULL ) str = NI_get_attribute("fillin") ; if( str != NULL && toupper(str[0]) == 'Y' ) do_zzz = 0 ; #endif if(PRINT_TRACING){ char str[256] ; sprintf(str,"kk=%d vlen=%d nxyz=%d fac=%f do_zzz=%d\n",kk,vlen,nxyz,fac,do_zzz); STATUS(str); } /*- loop over columns and enter them into the dataset -*/ for( jj=nd ; jj < nel->vec_num ; jj++ ){ ityp = nel->vec_typ[jj] ; if( AFNI_GOOD_DTYPE(ityp) ) otyp = ityp ; else if( ityp == NI_INT ) otyp = NI_FLOAT ; else continue ; /* skip this */ /* create a volume array to hold this data */ nbar = mri_datum_size(otyp) ; /* size of one value */ bar = calloc( nbar , nxyz ) ; /* will be zero filled */ if( bar == NULL ) break ; /* malloc failure! */ /* load data from element into this volume */ switch( ityp ){ default: free((void *)bar) ; continue ; /* should never happen */ case MRI_int:{ /* special case: convert int */ float *qar = (float *)bar ; /* to float since AFNI */ int *car = (int *) nel->vec[jj] ; /* doesn't have int datasets */ for( ii=0 ; ii < vlen ; ii++ ){ if( id[ii] >= 0 && id[ii] < nxyz ) qar[id[ii]] = car[ii] ; } } break ; case MRI_short:{ short *qar = (short *)bar ; short *car = (short *)nel->vec[jj] ; for( ii=0 ; ii < vlen ; ii++ ){ if( id[ii] >= 0 && id[ii] < nxyz ) qar[id[ii]] = car[ii] ; } } break ; case MRI_float:{ float *qar = (float *)bar ; float *car = (float *)nel->vec[jj] ; for( ii=0 ; ii < vlen ; ii++ ){ if( id[ii] >= 0 && id[ii] < nxyz ) qar[id[ii]] = car[ii] ; } } break ; case MRI_byte:{ byte *qar = (byte *)bar ; byte *car = (byte *)nel->vec[jj] ; for( ii=0 ; ii < vlen ; ii++ ){ if( id[ii] >= 0 && id[ii] < nxyz ) qar[id[ii]] = car[ii] ; } } break ; case MRI_complex:{ complex *qar = (complex *)bar ; complex *car = (complex *)nel->vec[jj] ; for( ii=0 ; ii < vlen ; ii++ ){ if( id[ii] >= 0 && id[ii] < nxyz ) qar[id[ii]] = car[ii] ; } } break ; case MRI_rgb:{ rgbyte *qar = (rgbyte *)bar ; rgbyte *car = (rgbyte *)nel->vec[jj] ; for( ii=0 ; ii < vlen ; ii++ ){ if( id[ii] >= 0 && id[ii] < nxyz ) qar[id[ii]] = car[ii] ; } } break ; } /* find a place (bb) to put this volume in the dataset */ if( kk < 0 ){ /* scan for an empty sub-brick */ for( ii=0 ; ii < DSET_NVALS(dset) ; ii++ ) if( DSET_ARRAY(dset,ii) == NULL ) break ; if( ii == DSET_NVALS(dset) ) kk = ii ; /* all full */ bb = ii ; /* put here */ } else if( kk > DSET_NVALS(dset) ){ bb = DSET_NVALS(dset) ; /* at end */ } else { bb = kk ; /* exactly here */ } if( bb < DSET_NVALS(dset) ){ /* replace existing data */ EDIT_substitute_brick( dset , bb , nel->vec_typ[jj] , bar ) ; } else { /* append new sub-brick */ bb = DSET_NVALS(dset) ; EDIT_add_brick( dset , nel->vec_typ[jj] , 0.0 , bar ) ; } nbr++ ; /* 1 more sub-brick! */ if( fac > 0.0 ) EDIT_BRICK_FACTOR(dset,bb,fac) ; else if( fac <= 0.0 ) EDIT_BRICK_FACTOR(dset,bb,0.0) ; DSET_CRUSH_BSTAT(dset,bb) ; if( kk >= 0 ) kk++ ; /* move to next sub-brick */ } if( nd == 3 ) free((void *)id) ; /* toss the trashola */ RETURN(nbr) ; } /*---------------------------------------------------------------------------*/ /*! Put a dataset sub-brick into a '' element. - Returns NULL if the input is stupid. -----------------------------------------------------------------------------*/ NI_element * THD_subbrick_to_niml( THD_3dim_dataset *dset, int ival, int flags ) { NI_element *nel ; char rhs[64] ; void *bar ; int ityp , nxyz , nbar ; ENTRY("THD_subbrick_to_niml") ; if( !ISVALID_DSET(dset) || ival < 0 || ival >= DSET_NVALS(dset) ) RETURN(NULL) ; bar = DSET_ARRAY(dset,ival) ; if( bar == NULL ) RETURN(NULL) ; ityp = DSET_BRICK_TYPE(dset,ival) ; /* type of data in bar */ nbar = mri_datum_size(ityp) ; /* size of one value */ nxyz = DSET_NVOX(dset) ; /* number of voxels */ nel = NI_new_data_element( "VOLUME_DATA" , nxyz ) ; NI_set_attribute( nel , "domain_parent_idcode" , dset->idcode.str ) ; NI_add_column( nel , ityp , bar ) ; nel->outmode = NI_BINARY_MODE ; /* write this in binary mode */ /*-- add any special attributes desired by the caller --*/ if( (flags & SBFLAG_INDEX) ){ sprintf(rhs,"%d",ival) ; NI_set_attribute( nel , "index" , rhs ) ; } if( (flags & SBFLAG_FACTOR) ){ float fac = DSET_BRICK_FACTOR(dset,ival) ; if( fac > 0.0 ){ sprintf(rhs,"%f",fac) ; NI_set_attribute( nel , "scale_factor" , rhs ) ; } } RETURN(nel) ; } /*---------------------------------------------------------------------------*/ /*! Put an entire dataset into a single NI group element. -----------------------------------------------------------------------------*/ NI_group * THD_dataset_to_niml( THD_3dim_dataset *dset ) { NI_element *nel ; NI_group *ngr ; int iv ; ENTRY("THD_dataset_to_niml") ; /* put AFNI dataset attributes into a group */ ngr = THD_nimlize_dsetatr( dset ) ; if( ngr == NULL ) RETURN(NULL) ; NI_rename_group( ngr , "AFNI_dataset" ) ; /* now add a data element for each sub-brick */ STATUS("adding sub-bricks") ; for( iv=0 ; iv < DSET_NVALS(dset) ; iv++ ){ nel = THD_subbrick_to_niml( dset , iv , 0 ) ; if( nel != NULL ) NI_add_to_group( ngr , nel ) ; } RETURN(ngr) ; } /*---------------------------------------------------------------------------*/ /*! Put an MRI_IMAGE into a NIML data element. -----------------------------------------------------------------------------*/ NI_element * mri_to_niml( MRI_IMAGE *im ) { NI_element *nel ; void *vpt ; char rhs[256] ; ENTRY("mri_to_niml") ; vpt = mri_data_pointer(im) ; if( vpt == NULL ) RETURN(NULL) ; nel = NI_new_data_element( "MRI_IMAGE" , im->nvox ) ; /* put in some attributes about the MRI_IMAGE struct */ sprintf( rhs , "%d,%d,%d,%d,%d,%d,%d" , im->nx , im->ny , im->nz , im->nt , im->nu , im->nv , im->nw ) ; NI_set_attribute( nel , "mri_dimen" , rhs ) ; if( im->dx != 0.0 || im->dy != 0.0 || im->dz != 0.0 || im->dt != 0.0 || im->du != 0.0 || im->dv != 0.0 || im->dw != 0.0 ){ sprintf( rhs , "%f,%f,%f,%f,%f,%f,%f" , im->dx , im->dy , im->dz , im->dt , im->du , im->dv , im->dw ) ; NI_set_attribute( nel , "mri_dxyz" , rhs ) ; } if( im->xo != 0.0 || im->yo != 0.0 || im->zo != 0.0 || im->to != 0.0 || im->uo != 0.0 || im->vo != 0.0 || im->wo != 0.0 ){ sprintf( rhs , "%f,%f,%f,%f,%f,%f,%f" , im->xo , im->yo , im->zo , im->to , im->uo , im->vo , im->wo ) ; NI_set_attribute( nel , "mri_xyzo" , rhs ) ; } if( im->name != NULL && im->name[0] != '\0' ) NI_set_attribute( nel , "mri_name" , im->name ) ; /* put in the data */ NI_add_column( nel , im->kind , vpt ) ; RETURN(nel) ; } /*---------------------------------------------------------------------------*/ /*! Convert a NIML element to an MRI_IMAGE. -----------------------------------------------------------------------------*/ MRI_IMAGE * niml_to_mri( NI_element *nel ) { char *rhs ; int nx=1,ny=1,nz=1,nt=1,nu=1,nv=1,nw=1 ; MRI_IMAGE *im ; void *vpt ; int nvox ; ENTRY("niml_to_mri") ; if( NI_element_type(nel) != NI_ELEMENT_TYPE || strcmp(nel->name,"MRI_IMAGE") != 0 || nel->vec_num != 1 || nel->vec_len <= 0 ) RETURN(NULL) ; rhs = NI_get_attribute( nel , "mri_dimen" ) ; if( rhs == NULL ) RETURN(NULL) ; sscanf( rhs , "%d,%d,%d,%d,%d,%d,%d" , &nx , &ny , &nz , &nt , &nu , &nv , &nw ) ; if( nx < 1 ) nx = 1 ; if( ny < 1 ) ny = 1 ; if( nz < 1 ) nz = 1 ; if( nt < 1 ) nt = 1 ; if( nu < 1 ) nu = 1 ; if( nv < 1 ) nv = 1 ; if( nw < 1 ) nw = 1 ; im = mri_new_7D_generic( nx,ny,nz,nt,nu,nv,nw , nel->vec_typ[0] , 1 ) ; if( im == NULL ) RETURN(NULL) ; vpt = mri_data_pointer(im) ; nvox = im->nvox ; if( nvox > nel->vec_len ) nvox = nel->vec_len ; memcpy( vpt , nel->vec[0] , im->pixel_size * nvox ) ; rhs = NI_get_attribute( nel , "mri_dxyz" ) ; if( rhs != NULL ) sscanf( rhs , "%f,%f,%f,%f,%f,%f,%f" , &(im->dx), &(im->dy), &(im->dz), &(im->dt), &(im->du), &(im->dv), &(im->dw) ) ; rhs = NI_get_attribute( nel , "mri_xyzo" ) ; if( rhs != NULL ) sscanf( rhs , "%f,%f,%f,%f,%f,%f,%f" , &(im->xo), &(im->yo), &(im->zo), &(im->to), &(im->uo), &(im->vo), &(im->wo) ) ; rhs = NI_get_attribute( nel , "mri_name" ) ; if( rhs != NULL ) mri_add_name( rhs , im ) ; RETURN(im) ; } /*---------------------------------------------------------------------------*/ int AFNI_obj_to_dataset( NI_objcontainer *dc ) { THD_3dim_dataset *dset ; if( dc == NULL || strcmp(dc->self_name,"AFNI_dataset") != 0 ) return 0 ; dset = THD_niml_to_dataset( (NI_group *)dc->self_data , 0 ) ; if( dset == NULL ) return 0 ; NI_free_element( dc->self_data ) ; dc->self_data = (void *)dset ; return 1 ; } /*---------------------------------------------------------------------------*/ int AFNI_dataset_to_obj( NI_objcontainer *dc ) { NI_group *ngr ; THD_3dim_dataset *dset ; if( dc == NULL || strcmp(dc->type_name,"AFNI_dataset") != 0 ) return 0 ; dset = (THD_3dim_dataset *)dc->self_data ; if( !ISVALID_DSET(dset) ) return 0 ; ngr = THD_dataset_to_niml( dset ) ; if( ngr == NULL ) return 0 ; dc->self_data = (void *)ngr ; return 1 ; }