1 /*****************************************************************************
2    Major portions of this software are copyrighted by the Medical College
3    of Wisconsin, 1994-2000, and are released under the Gnu General Public
4    License, Version 2.  See the file README.Copyright for details.
5 ******************************************************************************/
6 
7 #include "mrilib.h"
8 #include "thd.h"
9 
10 /*---------------------------------------------------------------*/
11 static int allow_nodata = 0 ;  /* 23 Mar 2001 */
12 
THD_allow_empty_dataset(int n)13 void THD_allow_empty_dataset( int n ){ allow_nodata = n ; }
14 /*---------------------------------------------------------------*/
15 
16 /*! With this macro defined, many of the attributes will actually
17     be set in function THD_datablock_apply_atr() instead of herein.
18     This change is to allow attributes read after the dataset struct
19     is already created to be useful, for the NIfTI-ization project. */
20 
21 #define USE_APPLICATOR  /* 10 May 2005 */
22 
23 extern int Matvec_2_WarpData(ATR_float  *atr_flo, THD_affine_warp *ww, float *wdv);
24 extern int THD_WarpData_From_3dWarpDrive(THD_3dim_dataset *dset, ATR_float *atr_flt);
25 
DSET_Label_Dtable(THD_3dim_dataset * dset)26 void *DSET_Label_Dtable(THD_3dim_dataset *dset)
27 {
28    ATR_string *atr_str = NULL;
29 
30    if (!dset) return(NULL);
31    if (dset->Label_Dtable) return(dset->Label_Dtable);
32 
33    atr_str = THD_find_string_atr( dset->dblk , "VALUE_LABEL_DTABLE" ) ;
34    if (atr_str) {
35       dset->Label_Dtable = (void *)Dtable_from_nimlstring(atr_str->ch);
36    } else {
37       dset->Label_Dtable = NULL;
38    }
39 
40    return(dset->Label_Dtable);
41 }
42 /*-------------------------------------------------------------------*/
43 /*!  Given a datablock, make it into a 3D dataset if possible.
44 ---------------------------------------------------------------------*/
45 
THD_3dim_from_block(THD_datablock * blk)46 THD_3dim_dataset * THD_3dim_from_block( THD_datablock *blk )
47 {
48    THD_3dim_dataset *dset ;
49    THD_diskptr      *dkptr ;
50    THD_dataxes      *daxes ;
51 
52    RwcBoolean dset_ok = True ;
53    int iq ;
54 
55    ATR_int    *atr_int ;
56    ATR_string *atr_str ;
57    ATR_float  *atr_flo ;
58 
59 #if 0
60    int new_idcode = 0 ;   /* no longer needed */
61 #endif
62 
63 ENTRY("THD_3dim_from_block") ; /* 29 Aug 2001 */
64 
65    /* sanity check */
66 
67    if( ! ISVALID_DATABLOCK(blk) || ! ISVALID_DISKPTR(blk->diskptr) )
68       RETURN( NULL );
69 
70    /*-- initialize a new 3D dataset --*/
71 
72    dset       = myRwcNew( THD_3dim_dataset ) ;  /* uses RwcCalloc() */
73    dset->dblk = blk  ;
74    dkptr      = blk->diskptr ;
75 
76    if( PRINT_TRACING ){
77      char str[256] ;
78      sprintf(str,"rank=%d nvals=%d dim[0]=%d dim[1]=%d dim[2]=%d",
79              dkptr->rank , dkptr->nvals ,
80              dkptr->dimsizes[0] , dkptr->dimsizes[1] , dkptr->dimsizes[2] ) ;
81      STATUS(str) ;
82    }
83 
84    INIT_KILL(dset->kl) ;
85    ADDTO_KILL(dset->kl,blk) ;
86 
87    blk->parent  = (RwcPointer) dset ;
88    dset->parent = NULL ;
89 
90    daxes = dset->daxes = myRwcNew(THD_dataxes) ;
91    daxes->parent = (RwcPointer) dset ;
92 
93    dset->wod_daxes = NULL ;  /* 02 Nov 1996 */
94 
95    dset->wod_flag    = False ;  /* set special flags */
96    dset->death_mark  = 0 ;
97    dset->tcat_list   = NULL ;
98    dset->tcat_num    = 0 ;
99    dset->tcat_len    = NULL ;
100    dset->Label_Dtable = NULL;                  /* ZSS Feb 26 2010 */
101 
102    ADDTO_KILL(dset->kl,daxes) ;
103 
104    dset->stats  = NULL ;
105 #ifdef ALLOW_DATASET_VLIST
106    dset->pts    = NULL ;
107 #endif
108    dset->taxis  = NULL ;
109    dset->tagset = NULL ;   /* 23 Oct 1998 */
110 
111    /*------------------*/
112    /*-- check for 3D --*/
113    /*------------------*/
114 
115    if( dkptr->rank != 3 ) DSET_ERRN("illegal # of dimensions",dkptr->rank) ;
116 
117    /*--------------------------------------------------*/
118    /*-- find type of image from TYPESTRING attribute --*/
119    /*--------------------------------------------------*/
120 
121    atr_str = THD_find_string_atr( blk , ATRNAME_TYPESTRING ) ;
122    if( atr_str == NULL ){
123       DSET_ERR("no TYPESTRING") ;
124       dset->type = -1 ;
125    } else {
126       int type ;
127       for( type=FIRST_3DIM_TYPE ; type <= LAST_3DIM_TYPE ; type++ )
128          if( strcmp( atr_str->ch , DATASET_typestr[type] ) == 0 ) break ;
129 
130       if( type > LAST_3DIM_TYPE ) DSET_ERR("illegal TYPESTRING") ;
131       dset->type = type ;
132    }
133 
134    /*-------------------------------------------------------*/
135    /*-- find view_type and func_type from SCENE_TYPE data --*/
136    /*-------------------------------------------------------*/
137 
138    atr_int = THD_find_int_atr( blk , ATRNAME_SCENE_TYPE ) ;
139    if( atr_int == NULL ){
140       DSET_ERR("missing or illegal SCENE_TYPE") ;
141    } else {
142       dset->view_type = atr_int->in[0] ;
143       dset->func_type = atr_int->in[1] ;
144 
145       if( dset->type != atr_int->in[2] ){
146          DSET_ERR("non-matching SCENE_TYPE[2]") ;
147       }
148    }
149 
150    /*-------------------------------------------------------*/
151    /*--               find identifier codes               --*/
152    /*-------------------------------------------------------*/
153 
154 #ifndef USE_APPLICATOR
155    atr_str = THD_find_string_atr( blk , ATRNAME_IDSTRING ) ;
156    if( atr_str != NULL ){
157      MCW_strncpy( dset->idcode.str , atr_str->ch , MCW_IDSIZE ) ;
158      atr_str = THD_find_string_atr( blk , ATRNAME_IDDATE ) ;
159      if( atr_str == NULL )
160        MCW_strncpy( dset->idcode.date , "None" , MCW_IDDATE ) ;
161      else
162        MCW_strncpy( dset->idcode.date , atr_str->ch , MCW_IDDATE ) ;
163    }
164 #endif
165 
166    ZERO_IDCODE(dset->anat_parent_idcode) ;
167    ZERO_IDCODE(dset->warp_parent_idcode) ;
168 
169 #ifndef USE_APPLICATOR
170    atr_str = THD_find_string_atr( blk , ATRNAME_IDANATPAR ) ;
171    if( atr_str != NULL )
172       MCW_strncpy( dset->anat_parent_idcode.str , atr_str->ch , MCW_IDSIZE ) ;
173 
174    atr_str = THD_find_string_atr( blk , ATRNAME_IDWARPPAR ) ;
175    if( atr_str != NULL )
176       MCW_strncpy( dset->warp_parent_idcode.str , atr_str->ch , MCW_IDSIZE ) ;
177 #endif
178 
179    /*--------------------------------*/
180    /*-- get data labels (optional) --*/
181    /*--------------------------------*/
182 
183    atr_str = THD_find_string_atr( blk , ATRNAME_LABEL1 ) ;
184    if( atr_str == NULL )
185      atr_str = THD_find_string_atr( blk , ATRNAME_DATANAME ) ;
186 
187    if( atr_str != NULL ){
188      MCW_strncpy( dset->label1 , atr_str->ch , THD_MAX_LABEL ) ;
189    } else {
190      MCW_strncpy( dset->label1 , THD_DEFAULT_LABEL , THD_MAX_LABEL ) ;
191    }
192 
193    atr_str = THD_find_string_atr( blk , ATRNAME_LABEL2 ) ;
194    if( atr_str != NULL ){
195      MCW_strncpy( dset->label2 , atr_str->ch , THD_MAX_LABEL ) ;
196    } else {
197      MCW_strncpy( dset->label2 , THD_DEFAULT_LABEL , THD_MAX_LABEL ) ;
198    }
199 
200    dset->keywords = NULL ;
201 #ifndef USE_APPLICATOR
202    atr_str = THD_find_string_atr( blk , ATRNAME_KEYWORDS ) ;
203    if( atr_str != NULL )
204       dset->keywords = RwcNewString( atr_str->ch ) ;
205 #endif
206 
207    /*---------------------------------*/
208    /*-- get parent names (optional) --*/
209    /*---------------------------------*/
210 
211    dset->anat_parent_name[0] = '\0' ;
212    dset->warp_parent_name[0] = '\0' ;
213    MCW_strncpy( dset->self_name , THD_DEFAULT_LABEL , THD_MAX_NAME ) ;
214    dset->anat_parent = dset->warp_parent = NULL ;  /* must be set later */
215 
216 #ifndef USE_APPLICATOR
217    atr_str = THD_find_string_atr( blk , ATRNAME_ANATOMY_PARENT ) ;
218    if( atr_str != NULL && ISZERO_IDCODE(dset->anat_parent_idcode) ){
219      MCW_strncpy( dset->anat_parent_name , atr_str->ch , THD_MAX_NAME ) ;
220    }
221 
222    atr_str = THD_find_string_atr( blk , ATRNAME_WARP_PARENT ) ;
223    if( atr_str != NULL && ISZERO_IDCODE(dset->warp_parent_idcode) ){
224      MCW_strncpy( dset->warp_parent_name , atr_str->ch , THD_MAX_NAME ) ;
225    }
226 
227    atr_str = THD_find_string_atr( blk , ATRNAME_DATANAME ) ;
228    if( atr_str != NULL ){
229      MCW_strncpy( dset->self_name , atr_str->ch , THD_MAX_NAME ) ;
230    }
231 #endif
232 
233    /*---------------------------*/
234    /*-- find axes orientation --*/
235    /*---------------------------*/
236 
237    daxes->type = DATAXES_TYPE ;
238    daxes->nxx  = dkptr->dimsizes[0] ;
239    daxes->nyy  = dkptr->dimsizes[1] ;
240    daxes->nzz  = dkptr->dimsizes[2] ;
241 
242    atr_int = THD_find_int_atr( blk , ATRNAME_ORIENT_SPECIFIC ) ;
243    if( atr_int == NULL ){
244      DSET_ERR("illegal or missing ORIENT_SPECIFIC") ;
245    } else {
246      daxes->xxorient = atr_int->in[0] ;
247      daxes->yyorient = atr_int->in[1] ;
248      daxes->zzorient = atr_int->in[2] ;
249    }
250 
251    /*----------------------*/
252    /*-- find axes origin --*/
253    /*----------------------*/
254 
255    atr_flo = THD_find_float_atr( blk , ATRNAME_ORIGIN ) ;
256    if( atr_flo == NULL ){
257      DSET_ERR("illegal or missing ORIGIN") ;
258    } else {
259      daxes->xxorg = atr_flo->fl[0] ;
260      daxes->yyorg = atr_flo->fl[1] ;
261      daxes->zzorg = atr_flo->fl[2] ;
262    }
263 
264    /*------------------------*/
265    /*-- find axes spacings --*/
266    /*------------------------*/
267 
268    atr_flo = THD_find_float_atr( blk , ATRNAME_DELTA ) ;
269    if( atr_flo == NULL ){
270      DSET_ERR("illegal or missing DELTA") ;
271    } else {
272      daxes->xxdel = atr_flo->fl[0] ;
273      daxes->yydel = atr_flo->fl[1] ;
274      daxes->zzdel = atr_flo->fl[2] ;
275    }
276 
277    /*---------------------------------------*/
278    /*-- set bounding box for this dataset --*/
279    /*---------------------------------------*/
280 
281    THD_set_daxes_bbox( daxes ) ; /* 20 Dec 2005 */
282 
283    /*----------------------------------------------------------------*/
284    /*--  matrix that transforms to Dicom (left-posterior-superior) --*/
285    /*----------------------------------------------------------------*/
286 
287    THD_set_daxes_to_dicomm( daxes ) ; /* 20 Dec 2005 */
288 
289    /* 09 Dec 2005: set ijk_to_dicom matrix and its inverse */
290 
291    if( !ISVALID_MAT44(daxes->ijk_to_dicom) )
292      THD_daxes_to_mat44( daxes ) ;
293 
294    atr_flo = THD_find_float_atr( blk, "IJK_TO_DICOM_REAL" );
295    /* load oblique transformation matrix */
296    if(atr_flo) {
297      LOAD_MAT44(daxes->ijk_to_dicom_real, \
298          atr_flo->fl[0], atr_flo->fl[1], atr_flo->fl[2], atr_flo->fl[3], \
299          atr_flo->fl[4], atr_flo->fl[5], atr_flo->fl[6], atr_flo->fl[7], \
300          atr_flo->fl[8], atr_flo->fl[9], atr_flo->fl[10], atr_flo->fl[11]);
301    }
302    else {
303      ZERO_MAT44(daxes->ijk_to_dicom_real);    /* clear values */
304      daxes->ijk_to_dicom_real.m[3][3] = 0.0;  /* and make invalid */
305    }
306 
307    /*------------------------------------*/
308    /*-- read set of markers (optional) --*/
309    /*------------------------------------*/
310 
311    dset->markers = NULL ;
312 
313 #ifndef USE_APPLICATOR
314    atr_flo = THD_find_float_atr( blk , ATRNAME_MARKSXYZ ) ;
315 
316    if( atr_flo != NULL ){
317       dset->markers = myRwcNew( THD_marker_set ) ;  /* new set */
318       ADDTO_KILL(dset->kl , dset->markers) ;
319 
320       /*-- copy floating coordinates into marker struct --*/
321 
322       COPY_INTO_STRUCT( *(dset->markers) ,  /* actual struct */
323                         MARKS_FSTART ,      /* byte offset */
324                         float ,             /* type being copied */
325                         atr_flo->fl ,       /* start of source */
326                         MARKS_FSIZE  ) ;    /* number of floats */
327 
328       /*----- must have labels along with coordinates -----*/
329 
330       atr_str = THD_find_string_atr( blk , ATRNAME_MARKSLAB ) ;
331       if( atr_str == NULL ){
332          DSET_ERR("MARKS_XYZ present but not MARKS_LAB!") ;
333       } else {
334          int im , llen ;
335          THD_ivec3 iv ;
336          float xxdown,xxup , yydown,yyup , zzdown,zzup ;
337 
338          /*-- copy labels into marker struct --*/
339 
340          COPY_INTO_STRUCT( *(dset->markers) ,
341                            MARKS_LSTART ,
342                            char ,
343                            atr_str->ch ,
344                            MARKS_LSIZE  ) ;
345 
346          /*-- check each marker for validity:
347                 non-blank label string,
348                 all coordinates inside bounding box --*/
349 
350          /** July 1995: extend bounding box a little, maybe **/
351 
352 #ifndef EXTEND_BBOX
353          xxdown = daxes->xxmin - 0.501 * fabs(daxes->xxdel) ;
354          xxup   = daxes->xxmax + 0.501 * fabs(daxes->xxdel) ;
355          yydown = daxes->yymin - 0.501 * fabs(daxes->yydel) ;
356          yyup   = daxes->yymax + 0.501 * fabs(daxes->yydel) ;
357          zzdown = daxes->zzmin - 0.501 * fabs(daxes->zzdel) ;
358          zzup   = daxes->zzmax + 0.501 * fabs(daxes->zzdel) ;
359 #else
360          xxdown = daxes->xxmin ;
361          xxup   = daxes->xxmax ;
362          yydown = daxes->yymin ;
363          yyup   = daxes->yymax ;
364          zzdown = daxes->zzmin ;
365          zzup   = daxes->zzmax ;
366 #endif
367 
368          dset->markers->numdef = dset->markers->numset = 0 ;
369 
370          for( im=0 ; im < MARKS_MAXNUM ; im++ ){
371             llen = strlen( &(dset->markers->label[im][0]) ) ;
372             dset->markers->valid[im]   =
373                (llen > 0) &&
374                ( dset->markers->xyz[im][0] >= xxdown ) &&
375                ( dset->markers->xyz[im][0] <= xxup   ) &&
376                ( dset->markers->xyz[im][1] >= yydown ) &&
377                ( dset->markers->xyz[im][1] <= yyup   ) &&
378                ( dset->markers->xyz[im][2] >= zzdown ) &&
379                ( dset->markers->xyz[im][2] <= zzup   )    ;
380 
381             if( dset->markers->valid[im] ) (dset->markers->numset)++ ;
382 
383             if( llen > 0 ) (dset->markers->numdef)++ ;
384 
385             dset->markers->ovcolor[im] = -1 ;  /* default color */
386 
387          } /* end of loop over markers */
388       } /* end of if marker labels exist */
389 
390       /*----- should also have help for each marker -----*/
391 
392       atr_str = THD_find_string_atr( blk , ATRNAME_MARKSHELP ) ;
393       if( atr_str == NULL ){
394          int im ;
395          for( im=0 ; im < MARKS_MAXNUM ; im++ )
396             dset->markers->help[im][0] = '\0' ;  /* empty string */
397       } else {
398          COPY_INTO_STRUCT( *(dset->markers) ,
399                            MARKS_HSTART ,
400                            char ,
401                            atr_str->ch ,
402                            MARKS_HSIZE  ) ;
403       } /* end of if marker help exists */
404 
405       /*----- should also have action flags for the marker set -----*/
406 
407       atr_int = THD_find_int_atr( blk , ATRNAME_MARKSFLAG ) ;
408       if( atr_int == NULL ){
409          int im ;
410          for( im=0 ; im < MARKS_MAXFLAG ; im++ )
411             dset->markers->aflags[im] = -1 ;
412       } else {
413          COPY_INTO_STRUCT( *(dset->markers) ,
414                            MARKS_ASTART ,
415                            int ,
416                            atr_int->in ,
417                            MARKS_ASIZE  ) ;
418          dset->markers->type = dset->markers->aflags[0] ;
419       } /* end of if marker flags exist */
420 
421    } /* end of if markers exist */
422 #endif
423 
424    /*--------------------------*/
425    /*-- read warp (optional) --*/
426    /*--------------------------*/
427 
428    dset->vox_warp  = NULL ;  /* 02 Nov 1996 */
429    dset->self_warp = NULL ;  /* 26 Aug 2002 */
430    dset->warp      = NULL ;
431 
432 #ifndef USE_APPLICATOR
433    atr_int = THD_find_int_atr( blk , ATRNAME_WARP_TYPE ) ;
434    if( atr_int != NULL ){  /* no warp */
435       int wtype = atr_int->in[0] , rtype = atr_int->in[1]  ;
436 
437       dset->warp = myRwcNew( THD_warp ) ;
438       ADDTO_KILL( dset->kl , dset->warp ) ;
439 
440       atr_flo = THD_find_float_atr( blk , ATRNAME_WARP_DATA ) ;
441       if( atr_flo == NULL ){
442          DSET_ERR("illegal or missing WARP_DATA") ;
443       } else {
444          switch( wtype ){
445 
446             default: DSET_ERR("illegal WARP_TYPE warp code") ; break;
447 
448             case WARP_AFFINE_TYPE:{
449                THD_affine_warp *ww = (THD_affine_warp *) dset->warp ;
450                ww->type       = wtype ;
451                ww->resam_type = rtype ;
452                ww->warp.type  = MAPPING_LINEAR_TYPE ;
453 
454                COPY_INTO_STRUCT( ww->warp ,
455                                  MAPPING_LINEAR_FSTART ,
456                                  float ,
457                                  atr_flo->fl ,
458                                  MAPPING_LINEAR_FSIZE ) ;
459             }
460             break ;  /* end affine warp */
461 
462             case WARP_TALAIRACH_12_TYPE:{
463                THD_talairach_12_warp *ww =
464                   (THD_talairach_12_warp *) dset->warp ;
465                int iw , ioff ;
466                ww->type       = wtype ;
467                ww->resam_type = rtype ;
468                for( iw=0 ; iw < 12 ; iw++ ){
469                   ww->warp[iw].type = MAPPING_LINEAR_TYPE ;
470 
471                   ioff = iw * MAPPING_LINEAR_FSIZE ;
472 
473                   COPY_INTO_STRUCT( ww->warp[iw] ,
474                                     MAPPING_LINEAR_FSTART ,
475                                     float ,
476                                     &(atr_flo->fl[ioff]) ,
477                                     MAPPING_LINEAR_FSIZE ) ;
478 
479                }  /* end loop over 12 warps */
480             }
481             break ;  /* end talairach_12 warp */
482 
483          } /* end of switch on warp type */
484       } /* end of if on legal warp data */
485    } /* end of if on warp existing */   else { /* But perhaps there is a
486                         little something from auto talairaching ZSS, June 06 */
487       if (dset->view_type == VIEW_TALAIRACH_TYPE) { /* something to do */
488          atr_flo = THD_find_float_atr( blk , ATRNAME_WARP_DATA_3DWD_AF ) ;
489          if ( atr_flo == NULL ){
490             /* A tlrc set with no transform. No problem */
491          } else {
492             if (!THD_WarpData_From_3dWarpDrive(dset, atr_flo)) {
493                fprintf(stderr,"Error: Failed to create WarpData!\n");
494             }
495          }
496       } else {
497          /* fprintf(stderr,"Not in TLRC space, bother not.\n"); */
498       }
499    } /* the very end of if on warp existing */
500 #endif
501 
502    /*----- read statistics, if available -----*/
503 
504 #ifndef USE_APPLICATOR
505    atr_flo = THD_find_float_atr( blk , ATRNAME_BRICK_STATS ) ;  /* new style */
506 
507    if( atr_flo != NULL ){  /*** have new style statistics ***/
508       int qq ;
509       dset->stats         = myRwcNew( THD_statistics ) ;
510       dset->stats->type   = STATISTICS_TYPE ;
511       dset->stats->parent = (RwcPointer) dset ;
512       dset->stats->nbstat = blk->nvals ;
513       dset->stats->bstat  = (THD_brick_stats *)
514                                RwcMalloc( sizeof(THD_brick_stats) * blk->nvals ) ;
515       for( qq=0 ; qq < blk->nvals ; qq++ ){
516          if( 2*qq+1 < atr_flo->nfl ){
517             dset->stats->bstat[qq].min = atr_flo->fl[2*qq] ;
518             dset->stats->bstat[qq].max = atr_flo->fl[2*qq+1] ;
519          } else {
520             INVALIDATE_BSTAT( dset->stats->bstat[qq] ) ;
521          }
522       }
523       ADDTO_KILL( dset->kl , dset->stats->bstat ) ;
524       ADDTO_KILL( dset->kl , dset->stats ) ;
525 
526    } else {  /**** check for old style (version 1.03-4) statistics ****/
527 
528       atr_int = THD_find_int_atr( blk , ATRNAME_MINMAX ) ;
529 
530       if( atr_int == NULL ){  /*** no statistics at all ***/
531          dset->stats = NULL ;
532 
533       } else {                /*** have old style (integer) statistics ***/
534          int qq ;
535          dset->stats         = myRwcNew( THD_statistics ) ;
536          dset->stats->type   = STATISTICS_TYPE ;
537          dset->stats->parent = (RwcPointer) dset ;
538          dset->stats->nbstat = blk->nvals ;
539          dset->stats->bstat  = (THD_brick_stats *)
540                                   RwcMalloc( sizeof(THD_brick_stats) * blk->nvals ) ;
541          for( qq=0 ; qq < blk->nvals ; qq++ ){
542             if( 2*qq+1 < atr_int->nin ){
543                dset->stats->bstat[qq].min = (float) atr_int->in[2*qq] ;
544                dset->stats->bstat[qq].max = (float) atr_int->in[2*qq+1] ;
545             } else {
546                INVALIDATE_BSTAT( dset->stats->bstat[qq] ) ;
547             }
548          }
549          ADDTO_KILL( dset->kl , dset->stats->bstat ) ;
550          ADDTO_KILL( dset->kl , dset->stats ) ;
551       }
552    }
553 #endif
554 
555    /*--- read auxiliary statistics info, if any ---*/
556 
557    atr_flo = THD_find_float_atr( blk , ATRNAME_STAT_AUX ) ;
558 
559    if( atr_flo != NULL ){
560      INIT_STAT_AUX( dset , atr_flo->nfl , atr_flo->fl ) ;
561      iq = atr_flo->nfl ;
562    } else {
563      ZERO_STAT_AUX( dset ) ;
564      iq = 0 ;
565    }
566 
567    if( ISFUNC(dset) && FUNC_need_stat_aux[dset->func_type] > iq ){
568      DSET_ERR("function type missing auxiliary statistical data") ;
569    }
570 
571    /*--- read time-dependent information, if any ---*/
572 
573    atr_int = THD_find_int_atr  ( blk , ATRNAME_TAXIS_NUMS ) ;
574    atr_flo = THD_find_float_atr( blk , ATRNAME_TAXIS_FLOATS ) ;
575 
576    if( atr_int != NULL && atr_flo != NULL ){
577      int isfunc , nvals ;
578 
579      dset->taxis = myRwcNew( THD_timeaxis ) ;
580      ADDTO_KILL(dset->kl,dset->taxis) ;
581 
582      dset->taxis->type    = TIMEAXIS_TYPE ;
583      dset->taxis->ntt     = atr_int->in[0] ;
584      dset->taxis->nsl     = atr_int->in[1] ;
585      dset->taxis->ttorg   = atr_flo->fl[0] ;
586      dset->taxis->ttdel   = atr_flo->fl[1] ;
587      dset->taxis->ttdur   = atr_flo->fl[2] ;
588      dset->taxis->zorg_sl = atr_flo->fl[3] ;
589      dset->taxis->dz_sl   = atr_flo->fl[4] ;
590 
591      dset->taxis->units_type = atr_int->in[2] ;    /* 21 Oct 1996 */
592      if( dset->taxis->units_type < 0 )             /* assign units */
593        dset->taxis->units_type = UNITS_SEC_TYPE ;  /* to the time axis */
594 
595      if( dset->taxis->nsl > 0 ){
596        atr_flo = THD_find_float_atr( blk , ATRNAME_TAXIS_OFFSETS ) ;
597        if( atr_flo == NULL || atr_flo->nfl < dset->taxis->nsl ){
598          dset->taxis->nsl     = 0 ;
599          dset->taxis->toff_sl = NULL ;
600          dset->taxis->zorg_sl = 0.0 ;
601          dset->taxis->dz_sl   = 0.0 ;
602        } else {
603          int ii ;
604          dset->taxis->toff_sl = (float *) RwcMalloc(sizeof(float)*dset->taxis->nsl) ;
605          ADDTO_KILL(dset->kl,dset->taxis->toff_sl) ;
606          for( ii=0 ; ii < dset->taxis->nsl ; ii++ )
607            dset->taxis->toff_sl[ii] = atr_flo->fl[ii] ;
608        }
609      } else {
610        dset->taxis->nsl     = 0 ;
611        dset->taxis->toff_sl = NULL ;
612        dset->taxis->zorg_sl = 0.0 ;
613        dset->taxis->dz_sl   = 0.0 ;
614      }
615 
616      isfunc = ISFUNCTYPE(dset->type) ;
617      nvals  = (isfunc) ? FUNC_nvals[dset->func_type]
618                        : ANAT_nvals[dset->func_type]  ;
619 
620      if( nvals != 1 ){
621        WARNING_message("Illegal 3D+time dataset & func_type combination: '%s'" ,
622                        DSET_HEADNAME(dset) ) ;
623        if( dset->taxis->toff_sl != NULL ) myRwcFree(dset->taxis->toff_sl) ;
624        myRwcFree(dset->taxis) ;
625      }
626 
627      /** 15 Aug 2005: don't allow milliseconds on input any more **/
628 
629      if( !AFNI_yesenv("AFNI_ALLOW_MILLISECONDS") ){ DSET_UNMSEC(dset); }
630    }
631 
632    /*--- 23 Oct 1998: read the tagset information ---*/
633 
634 #ifndef USE_APPLICATOR
635    atr_int = THD_find_int_atr   ( blk , ATRNAME_TAGSET_NUM    ) ;
636    atr_flo = THD_find_float_atr ( blk , ATRNAME_TAGSET_FLOATS ) ;
637    atr_str = THD_find_string_atr( blk , ATRNAME_TAGSET_LABELS ) ;
638 
639    if( atr_int != NULL && atr_flo != NULL && atr_str != NULL ){
640       int nin=atr_int->nin , nfl=atr_flo->nfl , nch=atr_str->nch ;
641       int ii , ntag , nfper , jj , kk ;
642 
643       ntag  = atr_int->in[0] ;  /* number of tags */
644       nfper = atr_int->in[1] ;  /* number of floats per tag */
645 
646       if( ntag > MAX_TAG_NUM ) ntag = MAX_TAG_NUM ;
647 
648       dset->tagset = myRwcNew( THD_usertaglist ) ;  /* create tagset */
649       ADDTO_KILL( dset->kl , dset->tagset ) ;
650 
651       dset->tagset->num = ntag ;
652       strcpy( dset->tagset->label , "Bebe Rebozo" ) ;  /* not used */
653 
654       /* read out tag values; allow for chance there isn't enough data */
655 
656 #undef  TF
657 #define TF(i,j) ( ((j)<nfper && (i)*nfper+(j)<nfl) ? atr_flo->fl[(i)*nfper+(j)] : -666.0 )
658       for( ii=0 ; ii < ntag ; ii++ ){
659          dset->tagset->tag[ii].x   = TF(ii,0) ;  /* coords */
660          dset->tagset->tag[ii].y   = TF(ii,1) ;
661          dset->tagset->tag[ii].z   = TF(ii,2) ;
662          dset->tagset->tag[ii].val = TF(ii,3) ;  /* value */
663          dset->tagset->tag[ii].ti  = TF(ii,4) ;  /* time index; if < 0 ==> not set */
664          if( dset->tagset->tag[ii].ti >= 0 ){
665              dset->tagset->tag[ii].set = 1 ;
666          } else {
667              dset->tagset->tag[ii].set = 0 ; dset->tagset->tag[ii].ti = 0 ;
668          }
669       }
670 #undef TF
671 
672       /* read out tag labels; allow for empty labels */
673 
674       jj = 0 ;
675       for( ii=0 ; ii < ntag ; ii++ ){
676          if( jj < nch ){
677             kk = strlen( atr_str->ch + jj ) ;
678             if( kk > 0 ) TAG_SETLABEL( dset->tagset->tag[ii] , atr_str->ch + jj ) ;
679             else         sprintf( dset->tagset->tag[ii].label , "Tag %d" , ii+1 ) ;
680             jj += kk+1 ;
681          } else {
682             sprintf( dset->tagset->tag[ii].label , "Tag %d" , ii+1 ) ;
683          }
684       }
685    }
686 #endif
687 
688    /* 10 May 2005: new function to apply some attributes
689                    to dataset, rather than doing it here */
690 
691 #ifdef USE_APPLICATOR
692    THD_datablock_apply_atr( dset ) ;
693 #endif
694 
695    /*--- check for the following conditions:
696            if warp exists,    warp_parent_name or _idcode must exist;
697            if warp nonexists, warp_parent_name and _idcode must nonexist,
698                               AND data must exist on disk                 ---*/
699 
700    if( dset->warp != NULL ){
701      if( strlen(dset->warp_parent_name) <= 0 &&
702          ISZERO_IDCODE(dset->warp_parent_idcode) )
703        DSET_ERR("have warp but have no warp parent") ;
704 
705      dset->wod_flag = !allow_nodata && !DSET_ONDISK(dset) ;
706    } else {
707      if( strlen(dset->warp_parent_name) > 0 ||
708          !ISZERO_IDCODE(dset->warp_parent_idcode) )
709        DSET_ERR("have no warp but have warp parent") ;
710 
711      if( !allow_nodata && !DSET_ONDISK(dset) )
712        DSET_ERR("have no warp but have no data on disk as well") ;
713    }
714 
715    /* backup assignment of ID code if not assigned earlier */
716 
717    if( dset->idcode.str[0] == '\0' ) dset->idcode = MCW_new_idcode() ;
718 
719    /*--- that's all the work for now;
720          if any error was flagged, kill this dataset and return nothing ---*/
721 
722    if( dset_ok == False ){
723      fprintf(stderr,"PURGING dataset %s from memory\n",DSET_HEADNAME(dset)) ;
724      THD_delete_3dim_dataset( dset , False ) ;
725      RETURN(NULL) ;
726    }
727 
728    /*--- If we assigned a new dataset idcode, write it back to disk ---*/
729       /* (This code was for the old days, when there were datasets)
730          (hanging around that hadn't yet been assigned ID codes.  ) */
731 
732 #if 0
733    if( dset != NULL && new_idcode ){
734      fprintf(stderr,"** Writing new ID code to dataset header %s\n",
735              dset->dblk->diskptr->header_name ) ;
736      THD_write_3dim_dataset( NULL , NULL , dset , False ) ;
737    }
738 #endif
739 
740    /* Create label table struct if attribute is present in header*/
741    dset->Label_Dtable = DSET_Label_Dtable(dset);
742 
743    THD_patch_brickim(dset) ; RETURN(dset);
744 }
745