1 #include "mrilib.h"
2 #include "thd.h"
3 #include "niml.h"
4 
5 /*---------------------------------------------------------------------*/
6 /*! Write all the attributes for a datablock into a set of NIML data
7     elements, stored in a NIML group element.
8 -----------------------------------------------------------------------*/
9 
THD_nimlize_dsetatr(THD_3dim_dataset * dset)10 NI_group * THD_nimlize_dsetatr( THD_3dim_dataset *dset )
11 {
12    THD_datablock *blk ;
13    ATR_any *atr_any ;
14    NI_element *nel ;
15    int ia ;
16    NI_group *ngr = NULL ;   /* will be output */
17 
18 ENTRY("THD_nimlize_dsetatr") ;
19 
20    /*--- sanity checks ---*/
21 
22    if( !ISVALID_DSET(dset) ) RETURN(ngr) ;
23    blk = dset->dblk ;
24    if( blk == NULL )         RETURN(ngr) ;
25 
26    THD_set_dataset_attributes( dset ) ;
27    if( blk->natr == 0 || blk->atr == NULL ) RETURN(ngr) ;
28 
29    /* create empty output group */
30 
31    ngr = NI_new_group_element() ;
32 
33    NI_rename_group( ngr , "AFNI_dataset" ) ;
34 
35    NI_set_attribute( ngr , "self_idcode" , dset->idcode.str ) ;
36 
37    /* make a data element for each attribute ... */
38 
39    for( ia=0 ; ia < blk->natr ; ia++ ){
40 
41      atr_any = &(blk->atr[ia]) ;
42      if( atr_any == NULL ) continue ;   /* bad attribute */
43 
44      switch( atr_any->type ){
45 
46        /* numeric types are easy: a single column vector with the numbers */
47 
48        case ATR_FLOAT_TYPE:{
49          ATR_float *atr_flo = (ATR_float *)atr_any ;
50 
51          nel = NI_new_data_element( "AFNI_atr" , atr_flo->nfl ) ;
52          nel->outmode = NI_TEXT_MODE ;
53          NI_set_attribute( nel , "atr_name" , atr_flo->name ) ;
54          NI_add_column( nel , NI_FLOAT , atr_flo->fl ) ;
55          NI_add_to_group( ngr , nel ) ;
56        }
57        break ;
58 
59        case ATR_INT_TYPE:{
60          ATR_int *atr_int = (ATR_int *)atr_any ;
61 
62          nel = NI_new_data_element( "AFNI_atr" , atr_int->nin ) ;
63          nel->outmode = NI_TEXT_MODE ;
64          NI_set_attribute( nel , "atr_name" , atr_int->name ) ;
65          NI_add_column( nel , NI_INT , atr_int->in ) ;
66          NI_add_to_group( ngr , nel ) ;
67        }
68        break ;
69 
70        /* 02 Jun 2005: If string to save is too long, break it into pieces.
71                        Will have to be reassembled on input into one string. */
72 
73 #undef  SZMAX
74 #define SZMAX 1000
75        case ATR_STRING_TYPE:{
76          ATR_string *atr_str = (ATR_string *)atr_any ;
77          int nnn , nstr , istr , ibot,itop ;
78          char **sar ;
79 
80          nnn  = atr_str->nch ; if( nnn <= 0 ) break ;
81          nstr = ((nnn-1)/SZMAX) + 1 ;
82          sar  = (char **)malloc(sizeof(char *)*nstr) ;
83          for( istr=0 ; istr < nstr ; istr++ ){
84            ibot = istr*SZMAX ;
85            itop = ibot+SZMAX ; if( itop > atr_str->nch ) itop = atr_str->nch ;
86            nnn  = itop-ibot ;
87            sar[istr] = (char *)calloc(1,nnn+1) ;
88            memcpy( sar[istr] , atr_str->ch+ibot , nnn ) ;
89            THD_zblock( nnn , sar[istr] ) ;
90            sar[istr][nnn] = '\0' ;
91          }
92          if( nnn > 1 && sar[nstr-1][nnn-1] == ZBLOCK )
93            sar[nstr-1][nnn-1] = '\0' ;
94 
95          nel = NI_new_data_element( "AFNI_atr" , nstr ) ;
96          nel->outmode = NI_TEXT_MODE ;
97          NI_set_attribute( nel , "atr_name" , atr_str->name ) ;
98 
99          NI_add_column( nel , NI_STRING , sar ) ;
100          NI_add_to_group( ngr , nel ) ;
101 
102          for( istr=0 ; istr < nstr ; istr++ ) free((void *)sar[istr]) ;
103          free((void *)sar) ;
104        }
105        break ;
106 
107      } /* end of switch on atr type */
108 
109    } /* end of loop over all atr's */
110 
111    /*--- done ---*/
112 
113    RETURN(ngr) ;
114 }
115 
116 /*---------------------------------------------------------------------*/
117 /*! Given a NIML group element, read AFNI attribute elements from it
118     and load these into a datablock.
119 -----------------------------------------------------------------------*/
120 
THD_dblkatr_from_niml(NI_group * ngr,THD_datablock * blk)121 void THD_dblkatr_from_niml( NI_group *ngr , THD_datablock *blk )
122 {
123    int         ip  ;
124    char       *rhs ;
125 
126 ENTRY("THD_dblkatr_from_niml") ;
127 
128    if( ngr                  == NULL          ||
129        NI_element_type(ngr) != NI_GROUP_TYPE ||
130        blk                  == NULL            ) EXRETURN ;
131 
132    /*-- loop over parts and extract data from any '<AFNI_atr ...>' elements --*/
133 
134    for( ip=0 ; ip < ngr->part_num ; ip++ ){
135      switch( ngr->part_typ[ip] ){
136 
137        /*-- a sub-group ==> recursion! --*/
138 
139        case NI_GROUP_TYPE:
140          THD_dblkatr_from_niml( (NI_group *)ngr->part[ip] , blk ) ;
141        break ;
142 
143        /*- data ==> see if is marked as an AFNI_atr and has exactly 1 column
144                     if so, then extract that column and load into datablock  -*/
145 
146        case NI_ELEMENT_TYPE:{ /* data ==> see if is an AFNI attribute */
147          NI_element *nel = (NI_element *)ngr->part[ip] ;
148          char       *rhs = NI_get_attribute( nel , "atr_name" ) ;
149          if( rhs == NULL )
150                      rhs = NI_get_attribute( nel , "AFNI_name" ) ;
151          if( strcasecmp(nel->name,"AFNI_atr") == 0 &&    /* AFNI attribute?   */
152              nel->vec_num == 1                     &&    /* with some data?   */
153              nel->vec_len >  0                     &&    /* that is nonempty? */
154              nel->vec     != NULL                  &&    /* and has data? */
155              nel->vec[0]  != NULL                  &&
156              rhs != NULL                           &&    /* and has a name?   */
157             *rhs != '\0'                              ){ /* a nonempty name?  */
158 
159            STATUS(rhs) ;
160 
161            switch( nel->vec_typ[0] ){ /* 3 different data types of attributes */
162 
163              /* float attribute: copy 1st column of numbers into AFNI */
164 
165              case NI_FLOAT:
166                THD_set_float_atr( blk , rhs ,
167                                   nel->vec_len , (float *)nel->vec[0] ) ;
168              break ;
169 
170              /* int attribute: ditto */
171 
172              case NI_INT:
173                THD_set_int_atr( blk , rhs ,
174                                 nel->vec_len , (int *)nel->vec[0] ) ;
175              break ;
176 
177              /* 02 Jun 2005: if have more than one String here,
178                              must reassemble them into a single array */
179 
180              case NI_STRING:{
181                if (nel->vec) { /* to be expected */
182                   char **sar = (char **)nel->vec[0] , *str ;
183                   int nch , nstr=nel->vec_len , istr , lll=0 ;
184                   for( istr=0 ; istr < nstr ; istr++)
185                      if (sar[istr]) lll += strlen(sar[istr]); /* ZSS Nov 2012 */
186                   str = malloc(lll+4) ; *str = '\0' ;
187 
188                /* for( istr=0 ; istr < nstr ; istr++ ) strcat(str,sar[istr]); */
189 
190                   /* The loop of strcat() is very slow in the case of a long
191                      history element, O(n^2), so replace with something linear.
192                      Javier complained that afni took forever to start.  One
193                      NIfTI dset with 8 MB history took ~8 seconds in loop.
194                                                         31 Jul 2012 [rickr] */
195                   {  char * cp, * sp = str; int slen;
196                      for( istr=0; istr < nstr; istr++ ) {
197                         if (sar[istr]) {  /* ZSS Nov 2012 */
198                            cp = sar[istr];
199                            slen = strlen(cp);
200                            memcpy(sp, cp, slen*sizeof(char));
201                            sp += slen;
202                         }
203                      }
204                      *sp = '\0';
205                   }
206 
207                   nch = strlen(str) ;
208                   THD_unzblock( nch+1 , str ) ;  /* re-insert NULs */
209                   THD_set_char_atr( blk , rhs , nch+1 , str ) ;
210                   free(str) ;
211                }
212              }
213              break ;
214            }
215          }
216        }
217        break ;
218      }
219    } /* end of loop over pieces-parts */
220 
221    /* 01 Jun 2005: special case:
222       reset the IDCODE_STRING attribute if the group element so indicates
223       (thereby overriding the AFNI_atr element of that name, if was present) */
224 
225                      rhs = NI_get_attribute(ngr,"self_idcode") ;
226    if( rhs == NULL ) rhs = NI_get_attribute(ngr,"AFNI_idcode") ;
227    if( rhs != NULL && *rhs != '\0' ){
228      STATUS("reset idcode") ;
229      THD_set_string_atr( blk , ATRNAME_IDSTRING , rhs ) ;
230    }
231 
232    EXRETURN ;
233 }
234 
235 /*-----------------------------------------------------------------------*/
236 /*! Make an AFNI dataset from a NIML group element.
237     - The element should contain enough '<AFNI_atr ...>' elements
238       to define the dataset header.
239     - It may also contain '<VOLUME_DATA ...>' elements that contain
240       data for the sub-bricks.  This, however, is optional.
241     - If the element contains a 'self_prefix' or 'AFNI_prefix' attribute,
242       then the RHS of that will become the dataset's prefix name.
243     - If the element contains a 'self_idcode' or 'AFNI_idcode' attribute,
244       then the RHS of that will become the dataset's idcode, overriding the
245       value that may be stored in the similar '<AFNI_atr ...>' element.
246     - If this element can't easily be re-loaded (e.g., came from a
247       socket), then the dataset should be super-locked into memory,
248       so it won't be purged!
249     - If nodata!=0 on input, then any actual sub-brick data elements in
250       the group element will not be loaded.  You'll have to call
251       THD_add_bricks() to do that later, if desired.
252 -------------------------------------------------------------------------*/
253 
THD_niml_to_dataset(NI_group * ngr,int nodata)254 THD_3dim_dataset * THD_niml_to_dataset( NI_group *ngr , int nodata )
255 {
256    THD_3dim_dataset *dset ;
257    THD_datablock *blk ;
258    char *rhs ;
259    int ii ;
260 
261 ENTRY("THD_niml_to_dataset") ;
262 
263    if( ngr                  == NULL          ||
264        NI_element_type(ngr) != NI_GROUP_TYPE   ) RETURN(NULL) ;
265 
266    /* create the shell of a dataset's datablock and populate it's attributes */
267 
268    blk = EDIT_empty_datablock() ;
269 
270    THD_dblkatr_from_niml( ngr , blk ) ;  /* load attributes from NIML */
271 
272    /* build the datablock from the loaded attributes */
273 
274    ii = THD_datablock_from_atr( blk , NULL , NULL ) ;
275    if( ii == 0 ){                               /* bad attributes */
276      THD_delete_datablock( blk ) ; RETURN(NULL) ;
277    }
278 
279    /* build the dataset from the datablock */
280 
281    THD_allow_empty_dataset(1) ;
282    dset = THD_3dim_from_block( blk ) ;
283    THD_allow_empty_dataset(0) ;
284    if( dset == NULL ){ THD_delete_datablock( blk ); RETURN(NULL); }
285 
286    DSET_mallocize(dset) ;   /* just to be sure */
287 
288    /* change the name of the dataset? */
289 
290    rhs = NI_get_attribute( ngr , "self_prefix" ) ;
291    if( rhs == NULL )
292      rhs = NI_get_attribute( ngr , "AFNI_prefix" ) ;  /* for the 'old' way */
293    if( rhs != NULL )
294      EDIT_dset_items( dset , ADN_prefix,rhs , ADN_none ) ;
295 
296    /* change the idcode of the dataset? */
297 
298    rhs = NI_get_attribute( ngr , "self_idcode" ) ;
299    if( rhs == NULL )
300      rhs = NI_get_attribute( ngr , "AFNI_idcode" ) ;  /* for the 'old' way */
301    if( rhs != NULL )
302      NI_strncpy( dset->idcode.str , rhs , MCW_IDSIZE ) ;
303 
304    /* now scan the group element for data elements that fill sub-bricks */
305 
306    if( !nodata ){
307      (void)THD_add_bricks( dset , ngr, NULL ) ;
308      THD_update_statistics( dset ) ;
309    }
310 
311    /* 18 Mar 2005: if the header orders, zero fill any undefined bricks */
312 
313    rhs = NI_get_attribute( ngr , "AFNI_zerofill" ) ;
314    if( rhs != NULL && toupper(rhs[0]) == 'Y' ) THD_zerofill_dataset(dset);
315 
316    RETURN(dset) ;
317 }
318 
319 /*---------------------------------------------------------------------------*/
320 /*! Scan the NIML data or group element for sub-bricks to add to the given
321     dataset.
322      - Return value is number sub-bricks found (0 == something bad).
323      - Note that the '<VOLUME_DATA ...>' elements don't have to contain
324        the right amount of data for a sub-brick.  If there is too little,
325        the remaining voxels will be 0; if too much, the excess data is
326        ignored.
327      - Each column of data creates or replaces one sub-brick.
328      - At the present time, the only datatypes allowed are:
329          byte, short, float, complex (float pairs), and rgb (byte triples).
330        Columns of other types will be ignored.
331      - If a '<VOLUME_DATA ...>' element contains an 'index' attribute, then:
332        - index >= 0 indicates which sub-brick the 1st column of the element
333          goes into; subsequent columns go into successive sub-bricks, and
334          any data already present in these sub-bricks will be over-written.
335        - To indicate that the data is to be appended to the dataset, making
336          new sub-bricks, just set index to a very large positive value
337          (e.g., 9999999).
338        - If 'index' is missing or negative, then the data columns will go
339          into the first empty sub-bricks that are found; if none are found,
340          new sub-bricks will be appended to the dataset.
341      - If a '<VOLUME_DATA ...>' element contains a 'scale_factor' attribute,
342        and the numerical value of factor is positive, this value is used to
343        set the scale factor for all sub-bricks loaded from the element.
344        Otherwise, any scale factor previously set will remain in effect.
345      - Elements that are not named 'VOLUME_DATA' will be ignored here.
346      - hdset is used to provide header attributes for sub-bricks that
347        would be added from '<VOLUME_DATA ...>'   ZSS, Jan 2011
348 *//*-------------------------------------------------------------------------*/
349 
THD_add_bricks(THD_3dim_dataset * dset,void * nini,THD_3dim_dataset * hdset)350 int THD_add_bricks( THD_3dim_dataset *dset , void *nini,
351                     THD_3dim_dataset *hdset )
352 {
353    int nbr=0 , tt=NI_element_type(nini) ;
354    NI_element *nel ;
355    int nxyz , ii=-2, jj , nbar , vlen , kk , bb=-2;
356    void *bar ;
357    char *str ;
358    float fac ;
359 
360 ENTRY("THD_add_bricks") ;
361 
362    if( !ISVALID_DSET(dset) || tt < 0 || nini == NULL ) RETURN(0) ;
363 
364    /*-- if have a group element, do the parts by recursion --*/
365 
366    if( tt == NI_GROUP_TYPE ){
367      NI_group *ngr = (NI_group *)nini ;
368      int ip ;
369      for( ip=0 ; ip < ngr->part_num ; ip++ )  /* loop over parts */
370        nbr += THD_add_bricks( dset , ngr->part[ip], hdset ) ;
371      RETURN(nbr) ;
372    }
373 
374    /*-- if here, have a single data element --*/
375 
376    nel = (NI_element *)nini ;
377 
378    /*- check element name to see if it's what we want -*/
379 
380    if( strcasecmp(nel->name,"VOLUME_DATA_SPARSE") == 0 ){ /* 31 Jan 2008:     */
381      ii = THD_add_sparse_bricks( dset , nel ) ;           /* sparsely defined */
382      RETURN(ii) ;                                         /* array(s) of data */
383    }
384 
385    /*- otherwise, fully defined 3D array(s) of data -*/
386 
387    if( strcasecmp(nel->name,"VOLUME_DATA") != 0 ) RETURN(0) ;
388 
389    nxyz = DSET_NVOX(dset) ;   /* number of voxels in a sub-brick */
390    vlen = nel->vec_len ;      /* number of values in a column of data */
391    if( vlen > nxyz ) vlen = nxyz ;
392 
393    if( nel->vec_num < 1 || vlen < 1 ) RETURN(0) ;  /* no data at all? */
394 
395    /*- find index of sub-brick, if present -*/
396 
397    kk  = -1 ;                                 /* flag for overwrite */
398                      str = NI_get_attribute( nel , "AFNI_index" ) ;
399    if( str == NULL ) str = NI_get_attribute( nel , "index"      ) ;
400    if( str != NULL && isdigit(*str) )
401      kk = (int)strtol( str , NULL , 10 ) ;
402 
403    /*- and scale factor, if present -*/
404 
405    fac = 0.0 ;
406                      str = NI_get_attribute( nel , "scale_factor" ) ;
407    if( str == NULL ) str = NI_get_attribute( nel , "AFNI_factor"  ) ;
408    if( str != NULL && isnumeric(*str) )
409      fac = (float)strtod( str , NULL ) ;
410 
411    if(PRINT_TRACING){
412      char str[256] ;
413      sprintf(str,"kk=%d vlen=%d nxyz=%d fac=%f\n",kk,vlen,nxyz,fac);
414      STATUS(str);
415    }
416 
417    /*- loop over columns and enter them into the dataset -*/
418 
419    for( jj=0 ; jj < nel->vec_num ; jj++ ){
420 
421      if( !AFNI_GOOD_DTYPE(nel->vec_typ[jj]) ) continue ; /* skip this */
422 
423      /* create a volume array to hold this data */
424 
425      nbar = mri_datum_size(nel->vec_typ[jj]) ;   /* size of one value */
426      bar = calloc( nbar , nxyz ) ;             /* will be zero filled */
427      if( bar == NULL ) RETURN(nbr) ;               /* malloc failure! */
428 
429      /* copy data from element into this volume */
430 
431      memcpy( bar , nel->vec[jj] , vlen*nbar ) ;
432 
433      /* find a place (bb) to put this volume in the dataset */
434 
435      if( kk < 0 ){  /* scan for an empty sub-brick */
436        for( ii=0 ; ii < DSET_NVALS(dset) ; ii++ )
437          if( DSET_ARRAY(dset,ii) == NULL ) break ;
438        if( ii == DSET_NVALS(dset) ) kk = ii ;  /* all full */
439        bb = ii ;                               /* put here */
440      } else if( kk > DSET_NVALS(dset) ){
441        bb = DSET_NVALS(dset) ;                 /* at end */
442      } else {
443        bb = kk ;                               /* exactly here */
444      }
445 
446      if( bb < DSET_NVALS(dset) ){   /* replace existing data */
447        EDIT_substitute_brick( dset , bb , nel->vec_typ[jj] , bar ) ;
448 
449      } else {                       /* append new sub-brick */
450        bb = DSET_NVALS(dset) ;
451        if (dset->dblk->malloc_type != DATABLOCK_MEM_MALLOC) {
452          DSET_mallocize(dset); DSET_load(dset);
453        }
454        EDIT_add_brick( dset , nel->vec_typ[jj] , 0.0 , bar ) ;
455      }
456      if (hdset) { /* copy some attributes ZSS, Jan 2011 */
457       if (DSET_BRICK_LABEL(hdset,jj)) {
458          EDIT_BRICK_LABEL( dset, bb, DSET_BRICK_LABEL(hdset,jj));
459       }
460      }
461      nbr++ ;   /* 1 more sub-brick! */
462           if( fac >  0.0 ) EDIT_BRICK_FACTOR(dset,bb,fac) ;
463      else if( fac <= 0.0 ) EDIT_BRICK_FACTOR(dset,bb,0.0) ;
464 
465      DSET_CRUSH_BSTAT(dset,bb) ;
466 
467      if( kk >= 0 ) kk++ ;  /* move to next sub-brick */
468    }
469 
470    RETURN(nbr) ;
471 }
472 
473 /*---------------------------------------------------------------------------*/
474 /*! Like THD_add_bricks(), but with a single element of type
475     <VOLUME_DATA_SPARSE ...>
476 *//*-------------------------------------------------------------------------*/
477 
THD_add_sparse_bricks(THD_3dim_dataset * dset,NI_element * nel)478 int THD_add_sparse_bricks( THD_3dim_dataset *dset , NI_element *nel )
479 {
480    int nbr=0 ;
481    int nxyz , ii , jj , nbar , vlen , kk , bb ;
482    void *bar ;
483    char *str ;
484    float fac ;
485    int *id , do_zzz=1 , nd=1 ;
486    int nx,ny,nz,nxy , pp,qq,rr , otyp,ityp ;
487 
488 ENTRY("THD_add_sparse_bricks") ;
489 
490    if( !ISVALID_DSET(dset) || nel == NULL || nel->type != NI_ELEMENT_TYPE ){
491      ERROR_message("bad data on entry to THD_add_sparse_bricks()") ;
492      RETURN(0) ;
493    }
494 
495    /*--- check element name to see if it's what we want ---*/
496 
497    if( strcasecmp(nel->name,"VOLUME_DATA_SPARSE") != 0 ) RETURN(0) ;
498 
499    vlen = nel->vec_len ;      /* number of values in a column of data */
500 
501    nx = DSET_NX(dset) ;
502    ny = DSET_NY(dset) ; nxy  = nx*ny ;
503    nz = DSET_NZ(dset) ; nxyz = nxy*nz;
504 
505    /*----- check if have at least 2 columns and 1 row! -----*/
506 
507    if( nel->vec_num < 2 || vlen < 1 ){
508      ERROR_message("inadequate data in <VOLUME_DATA_SPARSE...> header") ;
509      RETURN(0) ;
510    }
511 
512    /*----- determine if we have xyz coords or index coords -----*/
513 
514    if( nel->vec_num > 3            && nel->vec_typ[0] == NI_FLOAT &&
515        nel->vec_typ[1] == NI_FLOAT && nel->vec_typ[2] == NI_FLOAT ){ /*- xyz -*/
516 
517      float *xdd , *ydd , *zdd ;
518      THD_fvec3 xyz ; THD_ivec3 ijk ;
519 
520      nd  = 3 ; /* indicating we use the first 3 columns for index compuation */
521      id  = (int *)malloc(sizeof(int)*vlen) ;       /* indexes computed below */
522      xdd = (float *)nel->vec[0] ;                       /* DICOM coordinates */
523      ydd = (float *)nel->vec[1] ;
524      zdd = (float *)nel->vec[2] ;
525 
526      for( ii=0 ; ii < vlen ; ii++ ){
527        LOAD_FVEC3( xyz , xdd[ii],ydd[ii],zdd[ii] ) ;      /* get coords  */
528        xyz = THD_dicomm_to_3dmm( dset , xyz ) ;           /* to dset xyz */
529        ijk = THD_3dmm_to_3dind_warn( dset , xyz , &jj ) ; /* to 3D index */
530        if( jj == 0 ){
531          UNLOAD_IVEC3( ijk , pp,qq,rr ) ;            /* if good, make 1D */
532          id[ii] = pp + qq*nx + rr*nxy ;
533        } else {
534          id[ii] = -1 ;          /* not good ==> means to skip this puppy */
535        }
536      }
537 
538    } else {  /*------- index coords -------*/
539 
540      if( nel->vec_num > 3          && nel->vec_typ[0] == NI_INT &&
541          nel->vec_typ[1] == NI_INT && nel->vec_typ[2] == NI_INT ){  /* 3 ints */
542 
543        nd = 3 ;
544 
545      } else if( nel->vec_typ[0] == NI_INT ){                        /* 1 int */
546 
547        nd = 1 ;
548 
549      } else {                                                       /* bad */
550        ERROR_message("invalid coordinate column types in <VOLUME_DATA_SPARSE...> header");
551        RETURN(0) ;
552      }
553 
554      /* get or create index into dataset from these int columns */
555 
556      switch( nd ){
557        case 1: id = (int *)nel->vec[0] ; break ;  /* just assign */
558 
559        case 3:{                                   /* must create index array */
560          int *idd, *jdd , *kdd ;
561          idd = (int *)nel->vec[0] ;
562          jdd = (int *)nel->vec[1] ;
563          kdd = (int *)nel->vec[2] ;
564          id  = (int *)malloc(sizeof(int)*vlen) ;
565          for( ii=0 ; ii < vlen ; ii++ ){
566            pp = idd[ii] ; if( pp < 0 || pp >= nx ){ id[ii] = -1; continue; }
567            qq = jdd[ii] ; if( qq < 0 || qq >= ny ){ id[ii] = -1; continue; }
568            rr = kdd[ii] ; if( rr < 0 || rr >= nz ){ id[ii] = -1; continue; }
569            id[ii] = pp + qq*nx + rr*nxy ;
570          }
571        }
572        break ;
573      }
574    }
575 
576    /*- find index of sub-brick, if present -*/
577 
578    kk  = -1 ;                                 /* flag for overwrite */
579                      str = NI_get_attribute( nel , "AFNI_index" ) ;
580    if( str == NULL ) str = NI_get_attribute( nel , "index"      ) ;
581    if( str != NULL && isdigit(*str) )
582      kk = (int)strtol( str , NULL , 10 ) ;
583 
584    /*- and scale factor, if present -*/
585 
586    fac = 0.0 ;
587                      str = NI_get_attribute( nel , "scale_factor" ) ;
588    if( str == NULL ) str = NI_get_attribute( nel , "AFNI_factor"  ) ;
589    if( str != NULL && isnumeric(*str) )
590      fac = (float)strtod( str , NULL ) ;
591 
592    /* check if doing infill or if we should set brick to all zero first */
593    /* THIS IS IGNORED AT PRESENT! */
594 
595 #if 0
596                      str = NI_get_attribute("infill") ;
597    if( str == NULL ) str = NI_get_attribute("fillin") ;
598    if( str != NULL && toupper(str[0]) == 'Y' ) do_zzz = 0 ;
599 #endif
600 
601    if(PRINT_TRACING){
602      char str[256] ;
603      sprintf(str,"kk=%d vlen=%d nxyz=%d fac=%f do_zzz=%d\n",kk,vlen,nxyz,fac,do_zzz);
604      STATUS(str);
605    }
606 
607    /*- loop over columns and enter them into the dataset -*/
608 
609    for( jj=nd ; jj < nel->vec_num ; jj++ ){
610 
611      ityp = nel->vec_typ[jj] ;
612           if( AFNI_GOOD_DTYPE(ityp) ) otyp = ityp ;
613      else if( ityp == NI_INT        ) otyp = NI_FLOAT ;
614      else                             continue ; /* skip this */
615 
616      /* create a volume array to hold this data */
617 
618      nbar = mri_datum_size(otyp) ;   /* size of one value */
619      bar = calloc( nbar , nxyz ) ;   /* will be zero filled */
620      if( bar == NULL ) break ;       /* malloc failure! */
621 
622      /* load data from element into this volume */
623 
624      switch( ityp ){
625        default: free((void *)bar) ; continue ;  /* should never happen */
626 
627        case MRI_int:{                         /* special case: convert int */
628          float *qar = (float *)bar ;          /* to float since AFNI */
629          int   *car = (int *)  nel->vec[jj] ; /* doesn't have int datasets */
630          for( ii=0 ; ii < vlen ; ii++ ){
631            if( id[ii] >= 0 && id[ii] < nxyz ) qar[id[ii]] = car[ii] ;
632          }
633        }
634        break ;
635 
636        case MRI_short:{
637          short *qar = (short *)bar ;
638          short *car = (short *)nel->vec[jj] ;
639          for( ii=0 ; ii < vlen ; ii++ ){
640            if( id[ii] >= 0 && id[ii] < nxyz ) qar[id[ii]] = car[ii] ;
641          }
642        }
643        break ;
644 
645        case MRI_float:{
646          float *qar = (float *)bar ;
647          float *car = (float *)nel->vec[jj] ;
648          for( ii=0 ; ii < vlen ; ii++ ){
649            if( id[ii] >= 0 && id[ii] < nxyz ) qar[id[ii]] = car[ii] ;
650          }
651        }
652        break ;
653 
654        case MRI_byte:{
655          byte *qar = (byte *)bar ;
656          byte *car = (byte *)nel->vec[jj] ;
657          for( ii=0 ; ii < vlen ; ii++ ){
658            if( id[ii] >= 0 && id[ii] < nxyz ) qar[id[ii]] = car[ii] ;
659          }
660        }
661        break ;
662 
663        case MRI_complex:{
664          complex *qar = (complex *)bar ;
665          complex *car = (complex *)nel->vec[jj] ;
666          for( ii=0 ; ii < vlen ; ii++ ){
667            if( id[ii] >= 0 && id[ii] < nxyz ) qar[id[ii]] = car[ii] ;
668          }
669        }
670        break ;
671 
672        case MRI_rgb:{
673          rgbyte *qar = (rgbyte *)bar ;
674          rgbyte *car = (rgbyte *)nel->vec[jj] ;
675          for( ii=0 ; ii < vlen ; ii++ ){
676            if( id[ii] >= 0 && id[ii] < nxyz ) qar[id[ii]] = car[ii] ;
677          }
678        }
679        break ;
680      }
681 
682      /* find a place (bb) to put this volume in the dataset */
683 
684      if( kk < 0 ){  /* scan for an empty sub-brick */
685        for( ii=0 ; ii < DSET_NVALS(dset) ; ii++ )
686          if( DSET_ARRAY(dset,ii) == NULL ) break ;
687        if( ii == DSET_NVALS(dset) ) kk = ii ;  /* all full */
688        bb = ii ;                               /* put here */
689      } else if( kk > DSET_NVALS(dset) ){
690        bb = DSET_NVALS(dset) ;                 /* at end */
691      } else {
692        bb = kk ;                               /* exactly here */
693      }
694 
695      if( bb < DSET_NVALS(dset) ){   /* replace existing data */
696        EDIT_substitute_brick( dset , bb , nel->vec_typ[jj] , bar ) ;
697 
698      } else {                       /* append new sub-brick */
699        bb = DSET_NVALS(dset) ;
700        EDIT_add_brick( dset , nel->vec_typ[jj] , 0.0 , bar ) ;
701      }
702      nbr++ ;   /* 1 more sub-brick! */
703 
704           if( fac >  0.0 ) EDIT_BRICK_FACTOR(dset,bb,fac) ;
705      else if( fac <= 0.0 ) EDIT_BRICK_FACTOR(dset,bb,0.0) ;
706 
707      DSET_CRUSH_BSTAT(dset,bb) ;
708 
709      if( kk >= 0 ) kk++ ;  /* move to next sub-brick */
710    }
711 
712    if( nd == 3 ) free((void *)id) ;  /* toss the trashola */
713    RETURN(nbr) ;
714 }
715 
716 /*---------------------------------------------------------------------------*/
717 /*! Put a dataset sub-brick into a '<VOLUME_DATA ...>' element.
718     - Returns NULL if the input is stupid.
719 -----------------------------------------------------------------------------*/
720 
THD_subbrick_to_niml(THD_3dim_dataset * dset,int ival,int flags)721 NI_element * THD_subbrick_to_niml( THD_3dim_dataset *dset, int ival, int flags )
722 {
723    NI_element *nel ;
724    char rhs[64] ;
725    void *bar ;
726    int  ityp , nxyz , nbar ;
727 
728 ENTRY("THD_subbrick_to_niml") ;
729 
730    if( !ISVALID_DSET(dset) ||
731        ival < 0            || ival >= DSET_NVALS(dset) ) RETURN(NULL) ;
732 
733    bar  = DSET_ARRAY(dset,ival) ; if( bar == NULL ) RETURN(NULL) ;
734 
735    ityp = DSET_BRICK_TYPE(dset,ival) ;  /* type of data in bar */
736    nbar = mri_datum_size(ityp) ;        /* size of one value */
737    nxyz = DSET_NVOX(dset) ;             /* number of voxels */
738 
739    nel = NI_new_data_element( "VOLUME_DATA" , nxyz ) ;
740    NI_set_attribute( nel , "domain_parent_idcode" , dset->idcode.str ) ;
741    NI_add_column( nel , ityp , bar ) ;
742    nel->outmode = NI_BINARY_MODE ;  /* write this in binary mode */
743 
744    /*-- add any special attributes desired by the caller --*/
745 
746    if( (flags & SBFLAG_INDEX) ){
747      sprintf(rhs,"%d",ival) ;
748      NI_set_attribute( nel , "index" , rhs ) ;
749    }
750 
751    if( (flags & SBFLAG_FACTOR) ){
752      float fac = DSET_BRICK_FACTOR(dset,ival) ;
753      if( fac > 0.0 ){
754        sprintf(rhs,"%f",fac) ;
755        NI_set_attribute( nel , "scale_factor" , rhs ) ;
756      }
757    }
758 
759    RETURN(nel) ;
760 }
761 
762 /*---------------------------------------------------------------------------*/
763 /*! Put an entire dataset into a single NI group element.
764 -----------------------------------------------------------------------------*/
765 
THD_dataset_to_niml(THD_3dim_dataset * dset)766 NI_group * THD_dataset_to_niml( THD_3dim_dataset *dset )
767 {
768    NI_element *nel ;
769    NI_group *ngr ;
770    int iv ;
771 
772 ENTRY("THD_dataset_to_niml") ;
773 
774    /* put AFNI dataset attributes into a group */
775 
776    ngr = THD_nimlize_dsetatr( dset ) ;
777    if( ngr == NULL ) RETURN(NULL) ;
778 
779    NI_rename_group( ngr , "AFNI_dataset" ) ;
780 
781    /* now add a data element for each sub-brick */
782 
783    STATUS("adding sub-bricks") ;
784    for( iv=0 ; iv < DSET_NVALS(dset) ; iv++ ){
785      nel = THD_subbrick_to_niml( dset , iv , 0 ) ;
786      if( nel != NULL ) NI_add_to_group( ngr , nel ) ;
787    }
788 
789    RETURN(ngr) ;
790 }
791 
792 /*---------------------------------------------------------------------------*/
793 /*! Put an MRI_IMAGE into a NIML data element.
794 -----------------------------------------------------------------------------*/
795 
mri_to_niml(MRI_IMAGE * im)796 NI_element * mri_to_niml( MRI_IMAGE *im )
797 {
798    NI_element *nel ;
799    void *vpt ;
800    char rhs[256] ;
801 
802 ENTRY("mri_to_niml") ;
803 
804    vpt = mri_data_pointer(im) ;
805    if( vpt == NULL ) RETURN(NULL) ;
806 
807    nel = NI_new_data_element( "MRI_IMAGE" , im->nvox ) ;
808 
809    /* put in some attributes about the MRI_IMAGE struct */
810 
811    sprintf( rhs , "%d,%d,%d,%d,%d,%d,%d" ,
812             im->nx , im->ny , im->nz , im->nt , im->nu , im->nv , im->nw ) ;
813    NI_set_attribute( nel , "mri_dimen" , rhs ) ;
814 
815    if( im->dx != 0.0 || im->dy != 0.0 || im->dz != 0.0 ||
816        im->dt != 0.0 || im->du != 0.0 || im->dv != 0.0 || im->dw != 0.0 ){
817 
818      sprintf( rhs , "%f,%f,%f,%f,%f,%f,%f" ,
819               im->dx , im->dy , im->dz , im->dt , im->du , im->dv , im->dw ) ;
820      NI_set_attribute( nel , "mri_dxyz" , rhs ) ;
821    }
822 
823    if( im->xo != 0.0 || im->yo != 0.0 || im->zo != 0.0 ||
824        im->to != 0.0 || im->uo != 0.0 || im->vo != 0.0 || im->wo != 0.0 ){
825 
826      sprintf( rhs , "%f,%f,%f,%f,%f,%f,%f" ,
827               im->xo , im->yo , im->zo , im->to , im->uo , im->vo , im->wo ) ;
828      NI_set_attribute( nel , "mri_xyzo" , rhs ) ;
829    }
830 
831    if( im->name != NULL && im->name[0] != '\0' )
832      NI_set_attribute( nel , "mri_name" , im->name ) ;
833 
834    /* put in the data */
835     NI_add_column( nel , im->kind , vpt ) ;
836 
837    RETURN(nel) ;
838 }
839 
840 /*---------------------------------------------------------------------------*/
841 /*! Convert a NIML element to an MRI_IMAGE.
842 -----------------------------------------------------------------------------*/
843 
niml_to_mri(NI_element * nel)844 MRI_IMAGE * niml_to_mri( NI_element *nel )
845 {
846    char *rhs ;
847    int   nx=1,ny=1,nz=1,nt=1,nu=1,nv=1,nw=1 ;
848    MRI_IMAGE *im ;
849    void *vpt ;
850    int  nvox ;
851 
852 ENTRY("niml_to_mri") ;
853 
854    if( NI_element_type(nel)          != NI_ELEMENT_TYPE ||
855        strcmp(nel->name,"MRI_IMAGE") != 0               ||
856        nel->vec_num                  != 1               ||
857        nel->vec_len                  <= 0                 ) RETURN(NULL) ;
858 
859    rhs = NI_get_attribute( nel , "mri_dimen" ) ;
860    if( rhs == NULL ) RETURN(NULL) ;
861    sscanf( rhs , "%d,%d,%d,%d,%d,%d,%d" ,
862            &nx , &ny , &nz , &nt , &nu , &nv , &nw ) ;
863    if( nx < 1 ) nx = 1 ;
864    if( ny < 1 ) ny = 1 ;
865    if( nz < 1 ) nz = 1 ;
866    if( nt < 1 ) nt = 1 ;
867    if( nu < 1 ) nu = 1 ;
868    if( nv < 1 ) nv = 1 ;
869    if( nw < 1 ) nw = 1 ;
870 
871    im = mri_new_7D_generic( nx,ny,nz,nt,nu,nv,nw ,
872                             nel->vec_typ[0] , 1   ) ;
873    if( im == NULL ) RETURN(NULL) ;
874 
875    vpt = mri_data_pointer(im) ;
876    nvox = im->nvox ; if( nvox > nel->vec_len ) nvox = nel->vec_len ;
877    memcpy( vpt , nel->vec[0] , im->pixel_size * nvox ) ;
878 
879    rhs = NI_get_attribute( nel , "mri_dxyz" ) ;
880    if( rhs != NULL )
881      sscanf( rhs , "%f,%f,%f,%f,%f,%f,%f" ,
882              &(im->dx), &(im->dy), &(im->dz),
883              &(im->dt), &(im->du), &(im->dv), &(im->dw) ) ;
884 
885    rhs = NI_get_attribute( nel , "mri_xyzo" ) ;
886    if( rhs != NULL )
887      sscanf( rhs , "%f,%f,%f,%f,%f,%f,%f" ,
888              &(im->xo), &(im->yo), &(im->zo),
889              &(im->to), &(im->uo), &(im->vo), &(im->wo) ) ;
890 
891    rhs = NI_get_attribute( nel , "mri_name" ) ;
892    if( rhs != NULL ) mri_add_name( rhs , im ) ;
893 
894    RETURN(im) ;
895 }
896 
897 /*---------------------------------------------------------------------------*/
898 
AFNI_obj_to_dataset(NI_objcontainer * dc)899 int AFNI_obj_to_dataset( NI_objcontainer *dc )
900 {
901    THD_3dim_dataset *dset ;
902 
903    if( dc == NULL || strcmp(dc->self_name,"AFNI_dataset") != 0 ) return 0 ;
904 
905    dset = THD_niml_to_dataset( (NI_group *)dc->self_data , 0 ) ;
906    if( dset == NULL ) return 0 ;
907 
908    NI_free_element( dc->self_data ) ;
909    dc->self_data = (void *)dset ;
910    return 1 ;
911 }
912 
913 /*---------------------------------------------------------------------------*/
914 
AFNI_dataset_to_obj(NI_objcontainer * dc)915 int AFNI_dataset_to_obj( NI_objcontainer *dc )
916 {
917    NI_group *ngr ;
918    THD_3dim_dataset *dset ;
919 
920    if( dc == NULL || strcmp(dc->type_name,"AFNI_dataset") != 0 ) return 0 ;
921 
922    dset = (THD_3dim_dataset *)dc->self_data ;
923    if( !ISVALID_DSET(dset) ) return 0 ;
924 
925    ngr = THD_dataset_to_niml( dset ) ;
926    if( ngr == NULL ) return 0 ;
927 
928    dc->self_data = (void *)ngr ;
929    return 1 ;
930 }
931