1 /* ----------------------------------------------------------------------------
2 @COPYRIGHT :
3 Copyright 1993,1994,1995 David MacDonald,
4 McConnell Brain Imaging Centre,
5 Montreal Neurological Institute, McGill University.
6 Permission to use, copy, modify, and distribute this
7 software and its documentation for any purpose and without
8 fee is hereby granted, provided that the above copyright
9 notice appear in all copies. The author and McGill University
10 make no representations about the suitability of this
11 software for any purpose. It is provided "as is" without
12 express or implied warranty.
13 ---------------------------------------------------------------------------- */
14
15 #include <internal_volume_io.h>
16 #include <limits.h>
17 #include <float.h>
18
19 /* ----------------------------- MNI Header -----------------------------------
20 @NAME : create_empty_multidim_array
21 @INPUT : n_dimensions
22 data_type
23 @OUTPUT : array
24 @RETURNS :
25 @DESCRIPTION: Creates a multidimensional array, without allocating its data.
26 @METHOD :
27 @GLOBALS :
28 @CALLS :
29 @CREATED : Sep. 1, 1995 David MacDonald
30 @MODIFIED :
31 ---------------------------------------------------------------------------- */
32
create_empty_multidim_array(multidim_array * array,int n_dimensions,Data_types data_type)33 VIOAPI void create_empty_multidim_array(
34 multidim_array *array,
35 int n_dimensions,
36 Data_types data_type )
37 {
38 if( n_dimensions < 1 || n_dimensions > MAX_DIMENSIONS )
39 {
40 print_error(
41 "create_empty_multidim_array(): n_dimensions (%d) not in range 1 to %d.\n",
42 n_dimensions, MAX_DIMENSIONS );
43 }
44
45 array->n_dimensions = n_dimensions;
46 array->data_type = data_type;
47 array->data = (void *) NULL;
48 }
49
50 /* ----------------------------- MNI Header -----------------------------------
51 @NAME : get_multidim_data_type
52 @INPUT : array
53 @OUTPUT :
54 @RETURNS : data type
55 @DESCRIPTION: Returns the data type of the multidimensional array.
56 @METHOD :
57 @GLOBALS :
58 @CALLS :
59 @CREATED : Sep. 1, 1995 David MacDonald
60 @MODIFIED :
61 ---------------------------------------------------------------------------- */
62
get_multidim_data_type(multidim_array * array)63 VIOAPI Data_types get_multidim_data_type(
64 multidim_array *array )
65 {
66 return( array->data_type );
67 }
68
69 /* ----------------------------- MNI Header -----------------------------------
70 @NAME : set_multidim_data_type
71 @INPUT : array
72 data_type
73 @OUTPUT :
74 @RETURNS :
75 @DESCRIPTION: Sets the data type of the array.
76 @METHOD :
77 @GLOBALS :
78 @CALLS :
79 @CREATED : Sep. 1, 1995 David MacDonald
80 @MODIFIED :
81 ---------------------------------------------------------------------------- */
82
set_multidim_data_type(multidim_array * array,Data_types data_type)83 VIOAPI void set_multidim_data_type(
84 multidim_array *array,
85 Data_types data_type )
86 {
87 array->data_type = data_type;
88 }
89
90 /* ----------------------------------------------------------------------------
91 @NAME : get_type_size
92 @INPUT : type
93 @OUTPUT :
94 @RETURNS : size of the type
95 @DESCRIPTION: Returns the size of the given type.
96 @METHOD :
97 @GLOBALS :
98 @CALLS :
99 @CREATED : June, 1993 David MacDonald
100 @MODIFIED :
101 ---------------------------------------------------------------------------- */
102
get_type_size(Data_types type)103 VIOAPI int get_type_size(
104 Data_types type )
105 {
106 int size;
107
108 switch( type )
109 {
110 case UNSIGNED_BYTE: size = sizeof( unsigned char ); break;
111 case SIGNED_BYTE: size = sizeof( signed char ); break;
112 case UNSIGNED_SHORT: size = sizeof( unsigned short ); break;
113 case SIGNED_SHORT: size = sizeof( signed short ); break;
114 case UNSIGNED_INT: size = sizeof( unsigned int ); break;
115 case SIGNED_INT: size = sizeof( signed int ); break;
116 case FLOAT: size = sizeof( float ); break;
117 case DOUBLE: size = sizeof( double ); break;
118 }
119
120 return( size );
121 }
122
get_type_range(Data_types type,Real * min_value,Real * max_value)123 VIOAPI void get_type_range(
124 Data_types type,
125 Real *min_value,
126 Real *max_value )
127 {
128 switch( type )
129 {
130 case UNSIGNED_BYTE:
131 *min_value = 0.0;
132 *max_value = (Real) UCHAR_MAX; break;
133 case SIGNED_BYTE:
134 *min_value = (Real) SCHAR_MIN;
135 *max_value = (Real) SCHAR_MAX; break;
136 case UNSIGNED_SHORT:
137 *min_value = 0.0;
138 *max_value = (Real) USHRT_MAX; break;
139 case SIGNED_SHORT:
140 *min_value = (Real) SHRT_MIN;
141 *max_value = (Real) SHRT_MAX; break;
142 case UNSIGNED_INT:
143 *min_value = 0.0;
144 *max_value = (Real) UINT_MAX; break;
145 case SIGNED_INT:
146 *min_value = (Real) INT_MIN;
147 *max_value = (Real) INT_MAX; break;
148 case FLOAT:
149 *min_value = (Real) -FLT_MAX;
150 *max_value = (Real) FLT_MAX; break;
151 case DOUBLE:
152 *min_value = (Real) -DBL_MAX;
153 *max_value = (Real) DBL_MAX; break;
154 }
155 }
156
157 /* ----------------------------- MNI Header -----------------------------------
158 @NAME : set_multidim_sizes
159 @INPUT : array
160 sizes
161 @OUTPUT :
162 @RETURNS :
163 @DESCRIPTION: Sets the sizes of the array.
164 @METHOD :
165 @GLOBALS :
166 @CALLS :
167 @CREATED : Sep. 1, 1995 David MacDonald
168 @MODIFIED :
169 ---------------------------------------------------------------------------- */
170
set_multidim_sizes(multidim_array * array,int sizes[])171 VIOAPI void set_multidim_sizes(
172 multidim_array *array,
173 int sizes[] )
174 {
175 int dim;
176
177 for_less( dim, 0, array->n_dimensions )
178 array->sizes[dim] = sizes[dim];
179 }
180
181 /* ----------------------------- MNI Header -----------------------------------
182 @NAME : get_multidim_sizes
183 @INPUT : array
184 @OUTPUT : sizes
185 @RETURNS :
186 @DESCRIPTION: Passes back the sizes of the multidimensional array.
187 @METHOD :
188 @GLOBALS :
189 @CALLS :
190 @CREATED : Sep. 1, 1995 David MacDonald
191 @MODIFIED :
192 ---------------------------------------------------------------------------- */
193
get_multidim_sizes(multidim_array * array,int sizes[])194 VIOAPI void get_multidim_sizes(
195 multidim_array *array,
196 int sizes[] )
197 {
198 int i;
199
200 for_less( i, 0, array->n_dimensions )
201 sizes[i] = array->sizes[i];
202 }
203
204 /* ----------------------------- MNI Header -----------------------------------
205 @NAME : multidim_array_is_alloced
206 @INPUT : array
207 @OUTPUT :
208 @RETURNS : TRUE if array is allocated
209 @DESCRIPTION:
210 @METHOD :
211 @GLOBALS :
212 @CALLS :
213 @CREATED : Sep. 1, 1995 David MacDonald
214 @MODIFIED :
215 ---------------------------------------------------------------------------- */
216
multidim_array_is_alloced(multidim_array * array)217 VIOAPI BOOLEAN multidim_array_is_alloced(
218 multidim_array *array ) {
219
220 BOOLEAN status = FALSE;
221 void **p1, ***p2, ****p3, *****p4, ******p5;
222
223 if( array == NULL ) return( FALSE );
224
225 switch( array->n_dimensions ) {
226 case 1: p1 = (void **)&array->data;
227 status = ( *p1 != NULL );
228 break;
229 case 2: p2 = (void ***)&array->data;
230 if( *p2 == NULL ) break;
231 if( **p2 == NULL ) break;
232 status = TRUE;
233 break;
234 case 3: p3 = (void ****)&array->data;
235 if( *p3 == NULL ) break;
236 if( **p3 == NULL ) break;
237 if( ***p3 == NULL ) break;
238 status = TRUE;
239 break;
240 case 4: p4 = (void *****)&array->data;
241 if( *p4 == NULL ) break;
242 if( **p4 == NULL ) break;
243 if( ***p4 == NULL ) break;
244 if( ****p4 == NULL ) break;
245 status = TRUE;
246 break;
247 case 5: p5 = (void ******)&array->data;
248 if( *p5 == NULL ) break;
249 if( **p5 == NULL ) break;
250 if( ***p5 == NULL ) break;
251 if( ****p5 == NULL ) break;
252 if( *****p5 == NULL ) break;
253 status = TRUE;
254 break;
255 }
256
257 return( status );
258 }
259
260 /* ----------------------------- MNI Header -----------------------------------
261 @NAME : alloc_multidim_array
262 @INPUT : array
263 @OUTPUT :
264 @RETURNS :
265 @DESCRIPTION: Allocates the data for the multidimensional array.
266 @METHOD :
267 @GLOBALS :
268 @CALLS :
269 @CREATED : Sep. 1, 1995 David MacDonald
270 @MODIFIED :
271 ---------------------------------------------------------------------------- */
272
alloc_multidim_array(multidim_array * array)273 VIOAPI void alloc_multidim_array(
274 multidim_array *array )
275 {
276 int dim;
277 size_t type_size, sizes[5];
278 void *p1, **p2, ***p3, ****p4, *****p5;
279
280 if( multidim_array_is_alloced( array ) )
281 delete_multidim_array( array );
282
283 if( array->data_type == NO_DATA_TYPE )
284 {
285 print_error(
286 "Error: cannot allocate array data until size specified.\n" );
287 return;
288 }
289
290 for_less( dim, 0, array->n_dimensions )
291 sizes[dim] = (size_t) array->sizes[dim];
292
293 type_size = (size_t) get_type_size( array->data_type );
294
295 switch( array->n_dimensions )
296 {
297 case 1:
298 ASSIGN_PTR(p1) = alloc_memory_1d( sizes[0], type_size
299 _ALLOC_SOURCE_LINE );
300 array->data = (void *) p1;
301 break;
302 case 2:
303 ASSIGN_PTR(p2) = alloc_memory_2d( sizes[0], sizes[1], type_size
304 _ALLOC_SOURCE_LINE);
305 array->data = (void *) p2;
306 break;
307 case 3:
308 ASSIGN_PTR(p3) = alloc_memory_3d( sizes[0], sizes[1], sizes[2],
309 type_size _ALLOC_SOURCE_LINE );
310 array->data = (void *) p3;
311 break;
312 case 4:
313 ASSIGN_PTR(p4) = alloc_memory_4d( sizes[0], sizes[1],
314 sizes[2], sizes[3], type_size _ALLOC_SOURCE_LINE );
315 array->data = (void *) p4;
316 break;
317 case 5:
318 ASSIGN_PTR(p5) = alloc_memory_5d( sizes[0], sizes[1],
319 sizes[2], sizes[3], sizes[4], type_size
320 _ALLOC_SOURCE_LINE );
321 array->data = (void *) p5;
322 break;
323 }
324 }
325
326 /* ----------------------------- MNI Header -----------------------------------
327 @NAME : create_multidim_array
328 @INPUT : array
329 n_dimensions
330 sizes
331 data_type
332 @OUTPUT :
333 @RETURNS :
334 @DESCRIPTION: Creates a multidimensional array.
335 @METHOD :
336 @GLOBALS :
337 @CALLS :
338 @CREATED : Sep. 1, 1995 David MacDonald
339 @MODIFIED :
340 ---------------------------------------------------------------------------- */
341
create_multidim_array(multidim_array * array,int n_dimensions,int sizes[],Data_types data_type)342 VIOAPI void create_multidim_array(
343 multidim_array *array,
344 int n_dimensions,
345 int sizes[],
346 Data_types data_type )
347 {
348 create_empty_multidim_array( array, n_dimensions, data_type );
349 set_multidim_sizes( array, sizes );
350 alloc_multidim_array( array );
351 }
352
353 /* ----------------------------- MNI Header -----------------------------------
354 @NAME : delete_multidim_array
355 @INPUT : array
356 @OUTPUT :
357 @RETURNS :
358 @DESCRIPTION: Deletes the multidimensional array.
359 @METHOD :
360 @GLOBALS :
361 @CALLS :
362 @CREATED : Sep. 1, 1995 David MacDonald
363 @MODIFIED :
364 ---------------------------------------------------------------------------- */
365
delete_multidim_array(multidim_array * array)366 VIOAPI void delete_multidim_array(
367 multidim_array *array )
368 {
369 if( array->data == NULL )
370 {
371 print_error( "Warning: cannot free NULL multidim data.\n" );
372 return;
373 }
374
375 switch( array->n_dimensions )
376 {
377 case 1: free_memory_1d( (void **) &array->data _ALLOC_SOURCE_LINE );
378 break;
379 case 2: free_memory_2d( (void ***) &array->data _ALLOC_SOURCE_LINE );
380 break;
381 case 3: free_memory_3d( (void ****) &array->data _ALLOC_SOURCE_LINE );
382 break;
383 case 4: free_memory_4d( (void *****) &array->data _ALLOC_SOURCE_LINE );
384 break;
385 case 5: free_memory_5d( (void ******) &array->data _ALLOC_SOURCE_LINE );
386 break;
387 }
388
389 array->data = NULL;
390 }
391
392 /* ----------------------------- MNI Header -----------------------------------
393 @NAME : get_multidim_n_dimensions
394 @INPUT : array
395 @OUTPUT :
396 @RETURNS : number of dimensions
397 @DESCRIPTION: Returns the number of dimensions of the array
398 @METHOD :
399 @GLOBALS :
400 @CALLS :
401 @CREATED : June, 1993 David MacDonald
402 @MODIFIED :
403 ---------------------------------------------------------------------------- */
404
get_multidim_n_dimensions(multidim_array * array)405 VIOAPI int get_multidim_n_dimensions(
406 multidim_array *array )
407 {
408 return( array->n_dimensions );
409 }
410
411 /* ----------------------------- MNI Header -----------------------------------
412 @NAME : copy_multidim_data_reordered
413 @INPUT : type_size
414 void_dest_ptr
415 n_dest_dims
416 dest_sizes
417 void_src_ptr
418 n_src_dims
419 src_sizes
420 counts
421 to_dest_index
422 use_src_order - whether to step through arrays in the
423 reverse order of src or dest
424 @OUTPUT :
425 @RETURNS :
426 @DESCRIPTION: Copies any type of multidimensional data from the src array
427 to the destination array. to_dest_index is a lookup that
428 converts src indices to destination indices, to allow arbitrary
429 reordering of array data.
430 @METHOD :
431 @GLOBALS :
432 @CALLS :
433 @CREATED : Sep. 1, 1995 David MacDonald
434 @MODIFIED : Feb. 27, 1996 D. MacDonald - made more efficient
435 ---------------------------------------------------------------------------- */
436
copy_multidim_data_reordered(int type_size,void * void_dest_ptr,int n_dest_dims,int dest_sizes[],void * void_src_ptr,int n_src_dims,int src_sizes[],int counts[],int to_dest_index[],BOOLEAN use_src_order)437 VIOAPI void copy_multidim_data_reordered(
438 int type_size,
439 void *void_dest_ptr,
440 int n_dest_dims,
441 int dest_sizes[],
442 void *void_src_ptr,
443 int n_src_dims,
444 int src_sizes[],
445 int counts[],
446 int to_dest_index[],
447 BOOLEAN use_src_order )
448 {
449 char *src_ptr, *dest_ptr;
450 int d;
451 int dest_offsets[MAX_DIMENSIONS], src_offsets[MAX_DIMENSIONS];
452 int dest_offset0, dest_offset1, dest_offset2, dest_offset3;
453 int dest_offset4;
454 int src_offset0, src_offset1, src_offset2, src_offset3;
455 int src_offset4;
456 int dest_steps[MAX_DIMENSIONS], src_steps[MAX_DIMENSIONS];
457 int dest_index;
458 int n_transfer_dims;
459 int src_axis[MAX_DIMENSIONS], dest_axis[MAX_DIMENSIONS];
460 int transfer_counts[MAX_DIMENSIONS];
461 int v0, v1, v2, v3, v4;
462 int size0, size1, size2, size3, size4;
463 BOOLEAN full_count_used;
464
465 /*--- initialize dest */
466
467 dest_ptr = (char *) void_dest_ptr;
468 dest_steps[n_dest_dims-1] = type_size;
469 for_down( d, n_dest_dims-2, 0 )
470 dest_steps[d] = dest_steps[d+1] * dest_sizes[d+1];
471
472 /*--- initialize src */
473
474 src_ptr = (char *) void_src_ptr;
475 src_steps[n_src_dims-1] = type_size;
476 for_down( d, n_src_dims-2, 0 )
477 src_steps[d] = src_steps[d+1] * src_sizes[d+1];
478
479 n_transfer_dims = 0;
480
481 if( getenv( "VOLUME_IO_SRC_ORDER" ) )
482 use_src_order = TRUE;
483 else if( getenv( "VOLUME_IO_DEST_ORDER" ) )
484 use_src_order = FALSE;
485
486 if( use_src_order )
487 {
488 for_less( d, 0, n_src_dims )
489 {
490 dest_index = to_dest_index[d];
491 if( dest_index >= 0 )
492 {
493 src_axis[n_transfer_dims] = d;
494 dest_axis[n_transfer_dims] = dest_index;
495 src_offsets[n_transfer_dims] = src_steps[d];
496 dest_offsets[n_transfer_dims] = dest_steps[dest_index];
497 transfer_counts[n_transfer_dims] = counts[d];
498 ++n_transfer_dims;
499 }
500 }
501 }
502 else
503 {
504 for_less( dest_index, 0, n_dest_dims )
505 {
506 for_less( d, 0, n_src_dims )
507 if( to_dest_index[d] == dest_index )
508 break;
509
510 if( d < n_src_dims )
511 {
512 src_axis[n_transfer_dims] = d;
513 dest_axis[n_transfer_dims] = dest_index;
514 src_offsets[n_transfer_dims] = src_steps[d];
515 dest_offsets[n_transfer_dims] = dest_steps[dest_index];
516 transfer_counts[n_transfer_dims] = counts[d];
517 ++n_transfer_dims;
518 }
519 }
520 }
521
522 /*--- check if we can transfer more than one at once */
523
524 full_count_used = TRUE;
525
526 while( n_transfer_dims > 0 &&
527 src_axis[n_transfer_dims-1] == n_src_dims-1 &&
528 dest_axis[n_transfer_dims-1] == n_dest_dims-1 && full_count_used )
529 {
530 if( transfer_counts[n_transfer_dims-1] != src_sizes[n_src_dims-1] ||
531 transfer_counts[n_transfer_dims-1] != dest_sizes[n_dest_dims-1] )
532 {
533 full_count_used = FALSE;
534 }
535
536 type_size *= transfer_counts[n_transfer_dims-1];
537 --n_src_dims;
538 --n_dest_dims;
539 --n_transfer_dims;
540 }
541
542 for_less( d, 0, n_transfer_dims-1 )
543 {
544 src_offsets[d] -= src_offsets[d+1] * transfer_counts[d+1];
545 dest_offsets[d] -= dest_offsets[d+1] * transfer_counts[d+1];
546 }
547
548 /*--- slide the transfer dims to the last of the 5 dimensions */
549
550 for_down( d, n_transfer_dims-1, 0 )
551 {
552 src_offsets[d+MAX_DIMENSIONS-n_transfer_dims] = src_offsets[d];
553 dest_offsets[d+MAX_DIMENSIONS-n_transfer_dims] = dest_offsets[d];
554 transfer_counts[d+MAX_DIMENSIONS-n_transfer_dims] = transfer_counts[d];
555 }
556
557 for_less( d, 0, MAX_DIMENSIONS-n_transfer_dims )
558 {
559 transfer_counts[d] = 1;
560 src_offsets[d] = 0;
561 dest_offsets[d] = 0;
562 }
563
564 size0 = transfer_counts[0];
565 size1 = transfer_counts[1];
566 size2 = transfer_counts[2];
567 size3 = transfer_counts[3];
568 size4 = transfer_counts[4];
569
570 src_offset0 = src_offsets[0];
571 src_offset1 = src_offsets[1];
572 src_offset2 = src_offsets[2];
573 src_offset3 = src_offsets[3];
574 src_offset4 = src_offsets[4];
575
576 dest_offset0 = dest_offsets[0];
577 dest_offset1 = dest_offsets[1];
578 dest_offset2 = dest_offsets[2];
579 dest_offset3 = dest_offsets[3];
580 dest_offset4 = dest_offsets[4];
581
582 for_less( v0, 0, size0 )
583 {
584 for_less( v1, 0, size1 )
585 {
586 for_less( v2, 0, size2 )
587 {
588 for_less( v3, 0, size3 )
589 {
590 for_less( v4, 0, size4 )
591 {
592 (void) memcpy( dest_ptr, src_ptr, (size_t) type_size );
593 src_ptr += src_offset4;
594 dest_ptr += dest_offset4;
595 }
596 src_ptr += src_offset3;
597 dest_ptr += dest_offset3;
598 }
599 src_ptr += src_offset2;
600 dest_ptr += dest_offset2;
601 }
602 src_ptr += src_offset1;
603 dest_ptr += dest_offset1;
604 }
605 src_ptr += src_offset0;
606 dest_ptr += dest_offset0;
607 }
608 }
609
610 /* ----------------------------- MNI Header -----------------------------------
611 @NAME : copy_multidim_reordered
612 @INPUT : dest
613 dest_ind
614 src
615 src_ind
616 counts
617 to_dest_index
618 @OUTPUT :
619 @RETURNS :
620 @DESCRIPTION: Copies data from src array to dest array, with dimension
621 translation given by to_dest_index[].
622 @METHOD :
623 @GLOBALS :
624 @CALLS :
625 @CREATED : Sep. 1, 1995 David MacDonald
626 @MODIFIED :
627 ---------------------------------------------------------------------------- */
628
copy_multidim_reordered(multidim_array * dest,int dest_ind[],multidim_array * src,int src_ind[],int counts[],int to_dest_index[])629 VIOAPI void copy_multidim_reordered(
630 multidim_array *dest,
631 int dest_ind[],
632 multidim_array *src,
633 int src_ind[],
634 int counts[],
635 int to_dest_index[] )
636 {
637 int n_src_dims, n_dest_dims, type_size;
638 int src_sizes[MAX_DIMENSIONS], dest_sizes[MAX_DIMENSIONS];
639 char *dest_ptr, *src_ptr;
640 void *void_ptr;
641
642 type_size = get_type_size( get_multidim_data_type(dest) );
643
644 /*--- initialize dest */
645
646 n_dest_dims = get_multidim_n_dimensions( dest );
647 get_multidim_sizes( dest, dest_sizes );
648 GET_MULTIDIM_PTR( void_ptr, *dest, dest_ind[0], dest_ind[1], dest_ind[2],
649 dest_ind[3], dest_ind[4] );
650 ASSIGN_PTR( dest_ptr ) = void_ptr;
651
652 /*--- initialize src */
653
654 n_src_dims = get_multidim_n_dimensions( src );
655 get_multidim_sizes( src, src_sizes );
656 GET_MULTIDIM_PTR( void_ptr, *src, src_ind[0], src_ind[1], src_ind[2],
657 src_ind[3], src_ind[4] );
658 ASSIGN_PTR( src_ptr ) = void_ptr;
659
660 copy_multidim_data_reordered( type_size,
661 dest_ptr, n_dest_dims, dest_sizes,
662 src_ptr, n_src_dims, src_sizes,
663 counts, to_dest_index, TRUE );
664 }
665