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