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 
9 /***** This program makes a "duplicate" of a dataset, which is
10        nothing more than something that is warped from the parent
11        with the identity warp.
12 
13        Why is this useful?  Because you can then overwrite this
14        warped-on-demand dataset in AFNI.
15 
16        RWCox, June 1995
17 *****/
18 
19 static char DUP_session[THD_MAX_NAME]  = "./" ;
20 static char DUP_prefix[THD_MAX_PREFIX] = "dup" ;
21 static char DUP_label[THD_MAX_LABEL]   = "\0" ;
22 static char DUP_dname[THD_MAX_NAME]    = "\0" ;
23 
24 static int anatomy_type  = ILLEGAL_TYPE ;
25 static int function_type = ILLEGAL_TYPE ;
26 static int dataset_type  = ILLEGAL_TYPE ;
27 
28 THD_3dim_dataset * duplicate_dataset( THD_3dim_dataset * parent ) ;
29 
main(int argc,char * argv[])30 int main( int argc , char * argv[] )
31 {
32    int nopt , ii ;
33    THD_3dim_dataset * dset_in , * dset_out ;
34 
35    /** check for help **/
36 
37    if( argc < 2 || strncmp(argv[1],"-help",3) == 0 ){
38       printf(
39        "Usage: dsetdup [options] dataset\n"
40        " 'Duplicates' a dataset by making a warp-on-demand copy.\n"
41        " Applications:\n"
42        "   - allows AFNI to resample a dataset to a new grid without\n"
43        "       destroying an existing data .BRIK\n"
44        "   - change a functional dataset to anatomical, or vice-versa\n"
45        "\n"
46        "OPTIONS:\n"
47        "  -type             = convert to the given 'type', which must be\n"
48        "                       chosen from the same list as in to3d\n"
49        "  -session dirname  = write output into given directory (default=./)\n"
50        "  -prefix  pname    = use 'pname' for the output directory prefix\n"
51        "                       (default=dup)\n"
52        "  -label   string   = use 'string' for the label in the output\n"
53        "                       dataset (default = pname)\n"
54        "  -dname   name     = will make 3D dataset's name = 'name'\n"
55        "\n"
56        "N.B.: Even if the new dataset is anatomical, it will not contain\n"
57        "      any markers, duplicated from the original, or otherwise.\n"
58      ) ;
59      exit(0) ;
60    }
61 
62    /** scan command line options **/
63 
64 #define DUPERR(str) \
65    do{ fprintf(stderr,"ERROR: %s\n",(str)) ; exit(1) ; } while(1)
66 
67    nopt = 1 ;
68    while( nopt < argc && argv[nopt][0] == '-' ){
69 
70       /*** the following code is borrowed from to3d ***/
71 
72       /* -type from the anatomy prefixes */
73 
74       for( ii=FIRST_ANAT_TYPE ; ii <= LAST_ANAT_TYPE ; ii++ )
75          if( strncmp( &(argv[nopt][1]) ,
76                       ANAT_prefixstr[ii] , THD_MAX_PREFIX ) == 0 ) break ;
77 
78       if( ii <= LAST_ANAT_TYPE ){
79          anatomy_type = ii ;
80          dataset_type = HEAD_ANAT_TYPE ;
81          nopt++ ; continue ;
82       }
83 
84       /* -type from the function prefixes */
85 
86       for( ii=FIRST_FUNC_TYPE ; ii <= LAST_FUNC_TYPE ; ii++ )
87          if( strncmp( &(argv[nopt][1]) ,
88                       FUNC_prefixstr[ii] , THD_MAX_PREFIX ) == 0 ) break ;
89 
90       if( ii <= LAST_FUNC_TYPE ){
91          function_type = ii ;
92          dataset_type  = HEAD_FUNC_TYPE ;
93          nopt++ ; continue ;
94       }
95 
96       /**** -session dirname ****/
97 
98       if( strncmp(argv[nopt],"-session",6) == 0 ){
99          nopt++ ;
100          if( nopt >= argc ) DUPERR("need argument after -session!") ;
101          MCW_strncpy( DUP_session , argv[nopt++] , THD_MAX_NAME ) ;
102          continue ;
103       }
104 
105       /**** -prefix prefix ****/
106 
107       if( strncmp(argv[nopt],"-prefix",6) == 0 ){
108          nopt++ ;
109          if( nopt >= argc ) DUPERR("need argument after -prefix!") ;
110          MCW_strncpy( DUP_prefix , argv[nopt++] , THD_MAX_PREFIX ) ;
111          continue ;
112       }
113 
114       /**** -label string ****/
115 
116       if( strncmp(argv[nopt],"-label",6) == 0 ){
117          nopt++ ;
118          if( nopt >= argc ) DUPERR("need argument after -label!") ;
119          MCW_strncpy( DUP_label , argv[nopt++] , THD_MAX_LABEL ) ;
120          continue ;
121       }
122 
123       /**** -dname string ****/
124 
125       if( strncmp(argv[nopt],"-dname",6) == 0 ){
126          nopt++ ;
127          if( nopt >= argc ) DUPERR("need argument after -dname!") ;
128          MCW_strncpy( DUP_dname , argv[nopt++] , THD_MAX_NAME ) ;
129          continue ;
130       }
131 
132       /**** unknown switch ****/
133 
134       fprintf(stderr,"*** unrecognized option %s\n",argv[nopt]) ;
135       exit(1) ;
136    }  /* end of loop over options */
137 
138    if( strlen(DUP_label) == 0 ){
139       MCW_strncpy(DUP_label,DUP_prefix,THD_MAX_LABEL) ;
140    }
141 
142    if( nopt >= argc ) DUPERR("no dataset name given!") ;
143 
144    /*** read input dataset ***/
145 
146    dset_in = THD_open_one_dataset( argv[nopt] ) ;
147    if( ! ISVALID_3DIM_DATASET(dset_in) ) DUPERR("cannot read dataset!\n") ;
148 
149    /*** copy header info ***/
150 
151    dset_out = duplicate_dataset( dset_in ) ;
152    if( ! ISVALID_3DIM_DATASET(dset_out) ) DUPERR("cannot make duplicate!\n") ;
153 
154    /*** rewrite some strings ***/
155 
156    strcpy( dset_out->label1 , DUP_label ) ;
157    if( strlen(DUP_dname) > 0 ) strcpy( dset_out->self_name , DUP_dname ) ;
158 
159    /*** change of type? ***/
160 
161    if( dataset_type >= FIRST_3DIM_TYPE && dataset_type <= LAST_3DIM_TYPE ){
162 
163       int isfunc , new_nvals ;
164 
165       isfunc    = ISFUNCTYPE(dataset_type) ;
166       new_nvals = (isfunc) ? FUNC_nvals[function_type]
167                            : ANAT_nvals[anatomy_type]  ;
168 
169       if( new_nvals > dset_in->dblk->nvals ){
170          fprintf(stderr,
171                  "ERROR: new dataset type has %d values per voxel, but old has %d!\n"
172                  "       ==> cannot make duplicate!\n" ,
173                  new_nvals , dset_in->dblk->nvals ) ;
174          exit(1) ;
175 
176       } else if( new_nvals < dset_in->dblk->nvals ){
177          fprintf(stderr,
178                  "WARNING: new dataset type has %d values per voxel, but old has %d!\n"
179                  "         ==> new dataset will not access all data in old!\n",
180                  new_nvals , dset_in->dblk->nvals ) ;
181       }
182 
183       dset_out->type      = dataset_type ;
184       dset_out->func_type = ISANAT(dset_out) ? (anatomy_type)
185                                              : (function_type) ;
186    }
187 
188    /*** done! ***/
189 
190    THD_write_3dim_dataset( DUP_session , DUP_prefix , dset_out , False ) ;
191 
192    exit(0) ;
193 }
194 
195 /*---------------------------------------------------------------------
196    Adapted from AFNI_follower_dataset:
197      Make a warped dataset whose grid corresponds to the parent and
198      whose warp is just the identity warp.
199 -----------------------------------------------------------------------*/
200 
duplicate_dataset(THD_3dim_dataset * parent)201 THD_3dim_dataset * duplicate_dataset( THD_3dim_dataset * parent )
202 {
203    THD_3dim_dataset * new_dset ;
204    int ii ;
205 
206    /* sanity checks */
207 
208    if( ! ISVALID_3DIM_DATASET(parent) ) return NULL ;
209 
210    /* make new dataset, copying appropriate fields from its various parents */
211 
212    new_dset = myXtNew( THD_3dim_dataset ) ; INIT_KILL( new_dset->kl ) ;
213 
214    new_dset->type      = parent->type ;
215    new_dset->func_type = parent->func_type ;
216    new_dset->view_type = parent->view_type ;
217    new_dset->Label_Dtable = NULL;                  /* ZSS Feb 26 2010 */
218 
219    new_dset->anat_parent         = NULL ;   /* no anat parent */
220    new_dset->anat_parent_name[0] = '\0' ;
221 
222    new_dset->warp_parent =  parent ;        /* yes warp parent */
223    MCW_strncpy( new_dset->warp_parent_name , parent->self_name , THD_MAX_NAME ) ;
224 
225    /* make the actual warp from the warp_parent to this dataset */
226 
227    new_dset->vox_warp       = myXtNew( THD_warp ) ;
228    new_dset->vox_warp->type = ILLEGAL_TYPE ;        /* created when needed */
229    new_dset->warp           = myXtNew( THD_warp ) ;
230    *(new_dset->warp)        = IDENTITY_WARP ;
231 
232    /* make up some names for this new dataset */
233 
234    MCW_strncpy( new_dset->self_name  , parent->self_name , THD_MAX_NAME-5 ) ;
235    ii = strlen( new_dset->self_name ) ;
236    MCW_strncpy( &(new_dset->self_name[ii]) , "%duplicate" , THD_MAX_NAME-ii ) ;
237 
238    MCW_strncpy( new_dset->label1 , parent->label1 , THD_MAX_LABEL ) ;
239    MCW_strncpy( new_dset->label2 , parent->label2 , THD_MAX_LABEL ) ;
240 
241    /* set the axes for this new dataset
242       (same as parent, since that's the meaning of this routine) */
243 
244    new_dset->daxes         = myXtNew( THD_dataxes ) ;  /* copy data axes of */
245    *(new_dset->daxes)      = *(parent->daxes) ;      /* parent */
246    new_dset->daxes->parent = (XtPointer) new_dset ;  /* reset parent */
247 
248    new_dset->wod_daxes     = myXtNew( THD_dataxes ) ;  /* warp-on-demand */
249    *(new_dset->wod_daxes)  = *(new_dset->daxes) ;
250    new_dset->wod_flag      = True ;
251 
252    /* create a datablock and diskptr, in case the data is ever
253       filled into memory (instead of wod) and written to disk */
254 
255    new_dset->dblk = myXtNew( THD_datablock ) ; INIT_KILL( new_dset->dblk->kl ) ;
256 
257    new_dset->dblk->type        = DATABLOCK_TYPE ;
258    new_dset->dblk->nvals       = parent->dblk->nvals ;
259    new_dset->dblk->brick       = NULL ;
260    new_dset->dblk->malloc_type = DATABLOCK_MEM_UNDEFINED ;
261    new_dset->dblk->total_bytes = 0 ;
262    new_dset->dblk->brick_bytes = NULL ;
263    new_dset->dblk->natr        = new_dset->dblk->natr_alloc  = 0 ;
264    new_dset->dblk->atr         = NULL ;
265    new_dset->dblk->parent      = (XtPointer) new_dset ;
266 
267    DBLK_unlock(new_dset->dblk) ;
268 
269    new_dset->dblk->diskptr               = myXtNew( THD_diskptr ) ;
270    new_dset->dblk->diskptr->type         = DISKPTR_TYPE ;
271    new_dset->dblk->diskptr->nvals        = parent->dblk->nvals ;
272    new_dset->dblk->diskptr->rank         = 3 ;
273    new_dset->dblk->diskptr->storage_mode = STORAGE_UNDEFINED ;
274    new_dset->dblk->diskptr->byte_order   = THD_get_write_order() ;  /* 25 April 1998 */
275    new_dset->dblk->diskptr->dimsizes[0]  = new_dset->daxes->nxx ;
276    new_dset->dblk->diskptr->dimsizes[1]  = new_dset->daxes->nyy ;
277    new_dset->dblk->diskptr->dimsizes[2]  = new_dset->daxes->nzz ;
278 
279    /* create the names for storage on disk (if ever)
280       -- note we put it in the same directory as the parent */
281 
282    THD_init_diskptr_names( new_dset->dblk->diskptr ,
283                            parent->dblk->diskptr->directory_name , NULL ,
284                            parent->dblk->diskptr->prefix ,
285                            new_dset->view_type , True ) ;
286 
287    ADDTO_KILL( new_dset->dblk->kl , new_dset->dblk->diskptr ) ;
288 
289    /* oh yeah, set the new_dset kill list,
290       copy statistics if available, and NULL out any unused stuff */
291 
292    ADDTO_KILL( new_dset->kl , new_dset->warp ) ;
293    ADDTO_KILL( new_dset->kl , new_dset->vox_warp ) ;
294    ADDTO_KILL( new_dset->kl , new_dset->daxes ) ;
295    ADDTO_KILL( new_dset->kl , new_dset->wod_daxes ) ;
296    ADDTO_KILL( new_dset->kl , new_dset->dblk ) ;
297 
298    new_dset->self_warp = NULL ;  /* 26 Aug 2002 */
299 
300    if( parent->stats != NULL ){
301       new_dset->stats         = myXtNew( THD_statistics ) ;  /* copy statistics */
302       *(new_dset->stats)      = *(parent->stats) ;         /* of parent */
303       new_dset->stats->parent = (XtPointer) new_dset ;
304       ADDTO_KILL( new_dset->kl , new_dset->stats ) ;
305    } else {
306       new_dset->stats = NULL ;
307    }
308 
309    new_dset->markers     = NULL ;  /* no markers */
310    new_dset->death_mark  = 0 ;     /* don't kill me! */
311    new_dset->tcat_list   = 0 ;
312    new_dset->tcat_num    = 0 ;
313    new_dset->tcat_len    = NULL ;
314 
315    return(new_dset) ;
316 }
317