cartodata 6.0.1
volumebase_d.h
Go to the documentation of this file.
1/* This software and supporting documentation are distributed by
2 * Institut Federatif de Recherche 49
3 * CEA/NeuroSpin, Batiment 145,
4 * 91191 Gif-sur-Yvette cedex
5 * France
6 *
7 * This software is governed by the CeCILL-B license under
8 * French law and abiding by the rules of distribution of free software.
9 * You can use, modify and/or redistribute the software under the
10 * terms of the CeCILL-B license as circulated by CEA, CNRS
11 * and INRIA at the following URL "http://www.cecill.info".
12 *
13 * As a counterpart to the access to the source code and rights to copy,
14 * modify and redistribute granted by the license, users are provided only
15 * with a limited warranty and the software's author, the holder of the
16 * economic rights, and the successive licensors have only limited
17 * liability.
18 *
19 * In this respect, the user's attention is drawn to the risks associated
20 * with loading, using, modifying and/or developing or reproducing the
21 * software by the user in light of its specific status of free software,
22 * that may mean that it is complicated to manipulate, and that also
23 * therefore means that it is reserved for developers and experienced
24 * professionals having in-depth computer knowledge. Users are therefore
25 * encouraged to load and test the software's suitability as regards their
26 * requirements in conditions enabling the security of their systems and/or
27 * data to be ensured and, more generally, to use and operate it in the
28 * same conditions as regards security.
29 *
30 * The fact that you are presently reading this means that you have had
31 * knowledge of the CeCILL-B license and that you accept its terms.
32 */
33
34#ifndef CARTODATA_VOLUME_VOLUMEBASE_D_H
35#define CARTODATA_VOLUME_VOLUMEBASE_D_H
36
37//--- cartodata --------------------------------------------------------------
44//--- cartobase --------------------------------------------------------------
45#include <cartobase/type/limits.h>
46#include <cartobase/type/string_conversion.h>
47#include <cartobase/object/object.h>
48#include <cartobase/object/property.h>
49#include <cartobase/object/propertyfilter.h>
50#include <cartobase/containers/nditerator.h>
51#include <cartobase/uuid/uuid.h>
52//--- soma-io ----------------------------------------------------------------
54//--- std --------------------------------------------------------------------
55#include <cstdlib>
56#include <algorithm>
57#include <stdexcept>
58#include <string>
59#include <stdio.h>
60//----------------------------------------------------------------------------
61
62namespace carto
63{
64//============================================================================
65// CONSTRUCTORS
66//============================================================================
67
68 /***************************************************************************
69 * Default Constructor
70 **************************************************************************/
71 template < typename T >
72 Volume< T >::Volume( int sizeX, int sizeY, int sizeZ, int sizeT,
73 const AllocatorContext& allocatorContext,
74 bool allocated )
75 : VolumeProxy< T >( sizeX, sizeY, sizeZ, sizeT ),
77 _start( &_items[0] ),
78 _pos( 4, 0 )
79 {
80 this->header().addBuiltinProperty( "referential", _referential.uuid() );
81 allocate( -1, -1, -1, -1, allocated, allocatorContext );
82 }
83
84 template < typename T >
86 const AllocatorContext& allocatorContext,
87 bool allocated ):
88 VolumeProxy< T >( size[0] > 0 ? size[0] : 1,
89 size[1] > 0 ? size[1] : 1,
90 size[2] > 0 ? size[2] : 1,
91 size[3] > 0 ? size[3] : 1 ),
93 _start( &_items[0] ),
94 _pos( 4, 0 )
95 {
96 this->header().addBuiltinProperty( "referential", _referential.uuid() );
97 allocate( -1, -1, -1, -1, allocated, allocatorContext );
98 }
99
100 /***************************************************************************
101 * Constructor with border
102 **************************************************************************/
103
104 template < typename T >
105 void Volume< T >::constructBorders( const Position & bordersize,
106 const AllocatorContext& allocatorContext,
107 bool allocated )
108 {
109 bool has_border = false;
110 if( !bordersize.empty() )
111 {
112 size_t i, n = bordersize.size();
113 for( i=0; !has_border && i<n; ++i )
114 if( bordersize[i] != 0 )
115 has_border = true;
116 }
117
118 if( has_border )
119 {
120 size_t i, n = VolumeProxy<T>::_size.size();
121 size_t bsize = sizeof(T);
122 std::vector<int> large_size( n );
123 for( i=0; i<n; ++i )
124 {
125 large_size[i] = VolumeProxy<T>::_size[i];
126 if( i < bordersize.size() )
127 large_size[i] += bordersize[i] * 2;
128 bsize *= VolumeProxy<T>::_size[i];
129 }
130 _refvol.reset( new Volume<T>( large_size,
131 allocatorContext, allocated ) );
132
133 allocate( -1, -1, -1, -1, true,
134 _refvol->allocatorContext().isAllocated()
135 ? AllocatorContext( AllocatorStrategy::NotOwner,
136 rc_ptr<DataSource>( new BufferDataSource
137 ( (char *) &(*_refvol)( bordersize ),
138 bsize ) ) )
140 if( _refvol->allocatorContext().isAllocated() )
141 {
142 // fix offsets
143 blitz::TinyVector<int, Volume<T>::DIM_MAX> dims;
144 int i, n=VolumeProxy<T>::_size.size();
145 for(i=0; i<n; ++i )
146 dims[i] = VolumeProxy<T>::_size[i];
147 for( ; i<Volume<T>::DIM_MAX; ++i )
148 dims[i] = 1;
149 _blitz.reference
150 ( blitz::Array<T,8>
151 ( _start,
152 dims,
153 _refvol->_blitz.stride(),
154 blitz::GeneralArrayStorage<8>
155 ( blitz::shape( 0, 1, 2, 3, 4, 5, 6, 7 ), true ) ) );
156 }
157 }
158 else // no border
160 allocate( -1, -1, -1, -1, allocated, allocatorContext );
161 }
162 }
163
164 template < typename T >
165 Volume< T >::Volume( int sizeX, int sizeY, int sizeZ, int sizeT,
166 const Position4Di & bordersize,
167 const AllocatorContext& allocatorContext,
168 bool allocated )
169 : VolumeProxy< T >( sizeX, sizeY, sizeZ, sizeT ),
170 _items( 0U, AllocatorContext( AllocatorStrategy::NotOwner,
171 DataSource::none() ) ),
173 _pos( bordersize.toVector() )
174 {
175 this->header().addBuiltinProperty( "referential", _referential.uuid() );
176 constructBorders( bordersize.toVector(), allocatorContext, allocated );
177 }
178
179 template < typename T >
181 const Position4Di & bordersize,
182 const AllocatorContext& allocatorContext,
183 bool allocated ):
184 VolumeProxy< T >( size[0] > 0 ? size[0] : 1,
185 size[1] > 0 ? size[1] : 1,
186 size[2] > 0 ? size[2] : 1,
187 size[3] > 0 ? size[3] : 1 ),
188 _items( 0U, AllocatorContext( AllocatorStrategy::NotOwner,
189 DataSource::none() ) ),
190 _start( &_items[0] ),
191 _pos( bordersize.toVector() )
192 {
193 this->header().addBuiltinProperty( "referential", _referential.uuid() );
194 constructBorders( bordersize.toVector(), allocatorContext, allocated );
195 }
197 template < typename T >
198 Volume< T >::Volume( int sizeX, int sizeY, int sizeZ,
199 int sizeT, int bordersize,
200 const AllocatorContext& allocatorContext,
201 bool allocated )
202 : VolumeProxy< T >( sizeX, sizeY, sizeZ, sizeT ),
203 _items( 0U, AllocatorContext( AllocatorStrategy::NotOwner,
204 DataSource::none() ) ),
205 _start( &_items[0] ),
206 _pos( 4, 0 )
207 {
208 this->header().addBuiltinProperty( "referential", _referential.uuid() );
209 _pos[0] = bordersize;
210 _pos[1] = bordersize;
211 _pos[2] = bordersize;
214 Position4Di( bordersize, bordersize, bordersize, 0 ).toVector(),
215 allocatorContext, allocated );
216 }
217
218 template < typename T >
220 int bordersize,
221 const AllocatorContext& allocatorContext,
222 bool allocated ):
223 VolumeProxy< T >( size[0] > 0 ? size[0] : 1,
224 size[1] > 0 ? size[1] : 1,
225 size[2] > 0 ? size[2] : 1,
226 size[3] > 0 ? size[3] : 1 ),
227 _items( 0U, AllocatorContext( AllocatorStrategy::NotOwner,
228 DataSource::none() ) ),
229 _start( &_items[0] ),
230 _pos( 4, 0 )
232 this->header().addBuiltinProperty( "referential", _referential.uuid() );
233 _pos[0] = bordersize;
234 _pos[1] = bordersize;
235 _pos[2] = bordersize;
237 Position4Di( bordersize, bordersize, bordersize, 0 ).toVector(),
238 allocatorContext, allocated );
239 }
240
241
242 template < typename T >
243 Volume< T >::Volume( const std::vector<int> & size,
244 const AllocatorContext& allocatorContext,
245 bool allocated ):
246 VolumeProxy< T >( size ),
248 _start( &_items[0] ),
249 _pos( 4, 0 )
250 {
251 this->header().addBuiltinProperty( "referential", _referential.uuid() );
252 allocate( std::vector<int>( 1, -1 ), allocated, allocatorContext );
253 }
255
256 template < typename T >
257 Volume< T >::Volume( const std::vector<int> & size,
258 const std::vector<int> & bordersize,
259 const AllocatorContext& allocatorContext,
260 bool allocated ):
261 VolumeProxy< T >( size ),
262 _items( 0U, AllocatorContext( AllocatorStrategy::NotOwner,
263 DataSource::none() ) ),
264 _start( &_items[0] ),
265 _pos( bordersize )
266 {
267 this->header().addBuiltinProperty( "referential", _referential.uuid() );
268 while( _pos.size() < 4 )
269 _pos.push_back( 0 );
270 constructBorders( bordersize, allocatorContext, allocated );
271 }
273 /***************************************************************************
274 * Buffer Constructor
275 **************************************************************************/
276 template < typename T >
277 Volume< T >::Volume( int sizeX, int sizeY, int sizeZ, int sizeT, T* buffer,
278 const std::vector<long> *strides )
279 : VolumeProxy< T >( sizeX, sizeY, sizeZ, sizeT ),
280 _items( sizeX * sizeY * sizeZ * sizeT, buffer ),
281 _start( &_items[0] ),
282 _pos( 4, 0 )
284 this->header().addBuiltinProperty( "referential", _referential.uuid() );
285 allocate( -1, -1, -1, -1, true, allocatorContext(), strides );
287
288
289 template < typename T >
290 Volume< T >::Volume( const Position4Di & size, T* buffer,
291 const std::vector<long> *strides ):
292 VolumeProxy< T >( size[0] > 0 ? size[0] : 1,
293 size[1] > 0 ? size[1] : 1,
294 size[2] > 0 ? size[2] : 1,
295 size[3] > 0 ? size[3] : 1 ),
296 _items( (long)(size[0] > 0 ? size[0] : 1) *
297 (long)(size[1] > 0 ? size[1] : 1) *
298 (long)(size[2] > 0 ? size[2] : 1) *
299 (long)(size[3] > 0 ? size[3] : 1), buffer ),
300 _pos( 4, 0 )
301 {
302 this->header().addBuiltinProperty( "referential", _referential.uuid() );
303 allocate( -1, -1, -1, -1, true, allocatorContext(), strides );
304 }
305
306
307 template < typename T >
308 Volume< T >::Volume( const std::vector<int> & size, T* buffer,
309 const std::vector<long> *strides ):
310 VolumeProxy< T >( size ),
311 _items( (long) Position4Di::size_num_elements( size ), buffer ),
312 _pos( 4, 0 )
313 {
314 this->header().addBuiltinProperty( "referential", _referential.uuid() );
315 allocate( std::vector<int>( 1, -1 ), true, allocatorContext(), strides );
316 }
317
318 namespace
319 {
320
321 template <typename T>
322 void _updateHeaderFromParent( Volume<T> *vol, bool transToParent )
323 {
324 rc_ptr<Volume<T> > parent = vol->refVolume();
325 if( !parent )
326 return; // no parent: nothing to do.
327
328 /* copy voxel_size from underlying volume, if any.
329 This should probably be more general, but cannot be applied to all
330 header properties (size, transformations...).
331 WARNING: Moreover here we do not guarantee to keep both voxel_size
332 unique: we point to the same vector of values for now, but it can be
333 replaced (thus, duplicated) by a setProperty().
334 We could use a addBuiltinProperty(), but then the voxel size has to be
335 stored in a fixed location somewhere.
336 */
337 try
338 {
339 carto::Object vs = parent->header().getProperty( "voxel_size" );
340 size_t n = vol->getSize().size();
341 if( vs->size() > n )
342 {
343 // drop additional sizes
344 size_t i;
345 std::vector<carto::Object> vs2( n );
346 for( i=0; i<n; ++i )
347 vs2[i] = vs->getArrayItem( i );
348 vol->header().setProperty( "voxel_size", vs2 );
350 else
351 vol->header().setProperty( "voxel_size", vs );
352 }
353 catch( ... )
354 {
355 // never mind.
356 }
358 std::vector<std::string> refs;
359 std::vector<std::vector<float> > trans;
360
361 // handle transformation to parent ref
362 std::vector<float> vs = vol->getVoxelSize();
363 while( vs.size() < 3 )
364 vs.push_back( 1.f );
365 typename Volume<T>::Position pos = vol->posInRefVolume();
366 std::vector<float> trv( 16, 0.f );
367 trv[0] = 1.f;
368 trv[5] = 1.f;
369 trv[10] = 1.f;
370 trv[15] = 1.f;
371 trv[3] = pos[0] * vs[0];
372 trv[7] = pos[1] * vs[1];
373 trv[11] = pos[2] * vs[2];
374 AffineTransformationBase tr( trv );
375
376 if( transToParent )
377 {
378 std::string ref = parent->referential().uuid();
379 refs.push_back( ref );
380 trans.push_back( trv );
381 }
382
383 try
384 {
385 carto::Object tl = parent->header().getProperty( "transformations" );
386 trans.reserve( tl->size() + 1 );
387 carto::Object it;
388 for( it = tl->objectIterator(); it->isValid(); it->next() )
389 {
390 AffineTransformationBase tn( it->currentValue() );
391 tn *= tr;
392 trans.push_back( tn.toVector() );
393 }
394 carto::Object rl = parent->header().getProperty( "referentials" );
395 refs.reserve( rl->size() + 1 );
396 for( it = rl->objectIterator(); it->isValid(); it->next() )
397 refs.push_back( it->currentValue()->getString() );
398 }
399 catch( ... )
400 {
401 }
402 vol->header().setProperty( "referentials", refs );
403 vol->header().setProperty( "transformations", trans );
404 try
406 carto::Object s2mo = parent->header().getProperty(
407 "storage_to_memory" );
408 AffineTransformationBase s2m( s2mo );
409 // fix shifts of s2m
410 std::vector<int> p = vol->getSize();
411 --p[0];
412 --p[1];
413 --p[2];
414 std::vector<int> tp = s2m.transform( p );
415 std::vector<int> t0 = s2m.transform( std::vector<int>( 3, 0 ) );
416 tp[0] -= t0[0];
417 tp[1] -= t0[1];
418 tp[2] -= t0[2];
419 if( tp[0] < 0 )
420 s2m.matrix()( 0, 3 ) = -tp[0];
421 if( tp[1] < 0 )
422 s2m.matrix()( 0, 3 ) = -tp[1];
423 if( tp[2] < 0 )
424 s2m.matrix()( 0, 3 ) = -tp[2];
425 vol->header().setProperty( "storage_to_memory", s2m.toVector() );
426 }
427 catch( ... )
428 {
429 }
430 }
431
432 }
433
434
435 /***************************************************************************
436 * View Constructor
437 **************************************************************************/
438 template<typename T> inline
440 const Position4Di & pos, const Position4Di & size,
441 const AllocatorContext & allocContext,
442 bool transToParent )
443 : VolumeProxy<T>( size[0] >= 0 ? size[0] :
444 other->allocatorContext().isAllocated() ? other->getSizeX() : 1,
445 size[1] >= 0 ? size[1] :
446 other->allocatorContext().isAllocated() ? other->getSizeY() : 1,
447 size[2] >= 0 ? size[2] :
448 other->allocatorContext().isAllocated() ? other->getSizeZ() : 1,
449 size[3] >= 0 ? size[3] :
450 other->allocatorContext().isAllocated() ? other->getSizeT() : 1 ),
451 _items( 0U, allocContext ),
452 _refvol( other ),
453 _pos( pos.toVector() ),
455 {
456 this->header().addBuiltinProperty( "referential", _referential.uuid() );
457 // use a unique referential UUID, but keep orientation information
458 UUID uuid;
459 uuid.generate();
460 _referential.setUuid( uuid.toString() );
461
462 if( other->allocatorContext().isAllocated() )
463 {
464 size_t bsize = sizeof(T);
465 std::vector<int> osize = other->getSize();
466 int i, n = osize.size();
467 for( i=0; i<n; ++i )
468 bsize *= osize[i];
469
470 allocate( -1, -1, -1, -1, true,
471 AllocatorContext( AllocatorStrategy::NotOwner,
472 rc_ptr<DataSource>( new BufferDataSource
473 ( (char *) &other->_items[0],
474 bsize ) ) ) );
475 // fix offsets
476 blitz::TinyVector<int, Volume<T>::DIM_MAX> dims;
477 n = VolumeProxy<T>::_size.size();
478 for( i=0; i<n; ++i )
479 dims[i] = VolumeProxy<T>::_size[i];
480 for( ; i<Volume<T>::DIM_MAX; ++i )
481 dims[i] = 1;
482 _start = &(*other)( pos.toVector() );
483 _blitz.reference
484 ( blitz::Array<T,Volume<T>::DIM_MAX>
485 ( _start,
486 dims,
487 other->_blitz.stride(),
488 blitz::GeneralArrayStorage<Volume<T>::DIM_MAX>
489 ( blitz::shape( 0, 1, 2, 3, 4, 5, 6, 7 ), true ) ) );
490 }
491 else
492 allocate( -1, -1, -1, -1, true, allocContext );
493
494 _updateHeaderFromParent( this, transToParent );
495 }
496
497
498 template<typename T> inline
500 const Position & pos, const Position & size,
501 const AllocatorContext & allocContext,
502 bool transToParent )
503 : VolumeProxy<T>( Position4Di::fixed_size( size ) ),
504 _items( 0U, allocContext ),
505 _refvol( other ),
506 _pos( Position4Di::fixed_position( pos ) ),
507 _referential( other->referential() )
508 {
509 this->header().addBuiltinProperty( "referential", _referential.uuid() );
510 // use a unique referential UUID, but keep orientation information
511 UUID uuid;
512 uuid.generate();
513 _referential.setUuid( uuid.toString() );
514
515 if( other->allocatorContext().isAllocated() )
516 {
517 size_t bsize = sizeof(T);
518 std::vector<int> osize = other->getSize();
519 int i, n = osize.size();
520 for( i=0; i<n; ++i )
521 bsize *= osize[i];
522
523// std::cout << "use block start: " << (char *) ( &_items[0] + (&(*other)( pos ) - other->_start ) ) << std::endl;
524
525 allocate( -1, -1, -1, -1, true,
526 AllocatorContext( AllocatorStrategy::NotOwner,
527 rc_ptr<DataSource>( new BufferDataSource
528 ( (char *) &other->_items[0],
529 bsize ) ) ) );
530
531 // fix offsets
532 blitz::TinyVector<int, Volume<T>::DIM_MAX> dims;
533 n = VolumeProxy<T>::_size.size();
534 for(i=0; i<n; ++i )
535 dims[i] = VolumeProxy<T>::_size[i];
536 for( ; i<Volume<T>::DIM_MAX; ++i )
537 dims[i] = 1;
538 _start = &(*other)( pos );
539 _blitz.reference
540 ( blitz::Array<T,Volume<T>::DIM_MAX>
541 ( _start,
542 dims,
543 other->_blitz.stride(),
544 blitz::GeneralArrayStorage<Volume<T>::DIM_MAX>
545 ( blitz::shape( 0, 1, 2, 3, 4, 5, 6, 7 ), true ) ) );
546 }
547 else
548 allocate( -1, -1, -1, -1, true, allocContext );
549
550 _updateHeaderFromParent( this, transToParent );
551 }
552
553
554 // view + buffer (only for IO)
555
556 template < typename T >
558 const Position & size, T* buffer,
559 const std::vector<long> & strides )
560 : VolumeProxy<T>( size ),
561 _items( (long) Position4Di::size_num_elements( size ), buffer ),
562 _refvol( other ),
563 _pos( pos ),
564 _referential( other->referential() )
565 {
566 this->header().addBuiltinProperty( "referential", _referential.uuid() );
567 // use a unique referential UUID, but keep orientation information
568 UUID uuid;
569 uuid.generate();
570 _referential.setUuid( uuid.toString() );
571
572 allocate( -1, -1, -1, -1, true, allocatorContext(), &strides );
574
575
576 /***************************************************************************
577 * Copy Constructor
578 **************************************************************************/
579 template < typename T >
581 : RCObject(),
582 VolumeProxy< T >( other ),
583 _items( other._items ),
584 _start( &_items[0] + ( other._start - &other._items[0] ) ),
585
586 // TODO: test blitz ownership / strides
587 // _blitz = other.blitz;
588 _blitz( _start,
589 other._blitz.shape(),
590 other._blitz.stride(),
591 blitz::GeneralArrayStorage<8>
592 ( blitz::shape( 0, 1, 2, 3, 4, 5, 6, 7 ), true ) ),
593 _refvol( other.refVolume().get() ?
594 new Volume<T>( *other.refVolume() ) : 0 ),
595 _pos( other.posInRefVolume() ),
596 _referential( other.referential() )
597 {
598 this->header().addBuiltinProperty( "referential", _referential.uuid() );
599 if( _refvol.get() ) // view case: the underlying volume is copied.
600 {
601 Position4Di pos = other.posInRefVolume();
602 std::vector<int> oldSize(1, -1);
603 allocate( oldSize, true, _refvol->allocatorContext().isAllocated()
604 ? AllocatorContext( AllocatorStrategy::NotOwner,
605 rc_ptr<DataSource>( new BufferDataSource
606 ( (char *) &(*_refvol)( pos[0], pos[1], pos[2], pos[3] ),
610 * sizeof(T) ) ) )
611 : AllocatorContext( other.allocatorContext() ) );
612 if( _refvol->allocatorContext().isAllocated() )
613 {
614 // fix offsets
615 blitz::TinyVector<int, Volume<T>::DIM_MAX> dims;
616 int i, n=VolumeProxy<T>::_size.size();
617 for( i=0; i<n; ++i )
618 dims[i] = VolumeProxy<T>::_size[i];
619 for( ; i<Volume<T>::DIM_MAX; ++i )
620 dims[i] = 1;
621 _blitz.reference
622 ( blitz::Array<T,Volume<T>::DIM_MAX>
623 ( _start,
624 dims,
625 other._blitz.stride(),
626 blitz::GeneralArrayStorage<Volume<T>::DIM_MAX>
627 ( blitz::shape( 0, 1, 2, 3, 5, 6, 7, 8 ), true ) ) );
628 }
629 }
630 }
631
632 template < typename T >
634 {
635 }
636
637//============================================================================
638// M E T H O D S
639//============================================================================
640
641 template < typename T > inline
642 const AllocatorContext& Volume<T>::allocatorContext() const
643 {
644 return _items.allocatorContext();
645 }
646
647 template <typename T> inline
649 {
650 return _refvol;
651 }
652
653 template <typename T> inline
655 {
656 return _pos;
657 }
658
659 template <typename T>
660 inline
662 int l = 0;
663 rc_ptr<Volume<T> > v(const_cast<Volume<T> *>(this));
664 while (!v.isNull()) {
665 l++;
666 v = v->refVolume();
667 }
668 return l;
669 }
670
671 template <typename T>
672 inline
673 int Volume<T>::refLevel(const int level) const {
674 int c = getLevelsCount();
675 int l = level;
676 if (l < 0) {
677 l = c + l;
678 }
679
680 if ((l < 0) && (l >= c)) {
681 throw std::out_of_range("level " + carto::toString(level)
682 + " is out range (" + carto::toString(-c)
683 + ", " + carto::toString(c-1) + ")");
684 }
685
686 return l;
687 }
688
689 template <typename T>
690 inline
692 int l = refLevel(level);
693 int c = 0;
694 rc_ptr<Volume<T> > v(const_cast<Volume<T> *>(this));
695
696 while ((c < l) && (!v.isNull())) {
697 v = v->refVolume();
698 c++;
699 }
700
701 return v;
702 }
703
704 template <typename T>
705 inline
707 const int level) const {
708 int l = refLevel(level);
709 size_t s = this->getSize().size();
710 typename Volume<T>::Position offset(s, 0);
711 int c = 0;
712 rc_ptr<Volume<T> > v(const_cast<Volume<T> *>(this));
713 while ((c < l) && (!v.isNull())) {
714 const Position & pos = v->posInRefVolume();
715
716 for (size_t i = 0; i < s; ++i)
717 offset[i] += pos[i];
718
719 v = v->refVolume();
720 c++;
721 }
722
723 return offset;
724 }
725
726 template <typename T> inline
728 {
729
730 if ( !allocatorContext().isAllocated()
731 || (allocatorContext().accessMode() == AllocatorStrategy::NotOwner) )
732 {
733
734 // Free old buffer
735 _items.free();
736
737 if (_refvol.get())
738 {
739 // Recreate items buffer that reference volume
740 // using correct sizes and position
741 if( _refvol->allocatorContext().isAllocated() )
742 {
743 size_t size = sizeof(T);
744 int i, n = VolumeProxy<T>::_size.size();
745 for( i=0; i<n; ++i )
746 size *= VolumeProxy<T>::_size[i];
747 _items.allocate(
748 0U,
749 AllocatorContext( AllocatorStrategy::NotOwner,
750 rc_ptr<DataSource>( new BufferDataSource
751 ( (char *) &(*(_refvol))( _pos ),
752 size ) ) ) );
753 }
754 else
755 _items.allocate( 0U, allocatorContext() );
756 _start = &_items[0];
757
758 if ( _refvol->allocatorContext().isAllocated() )
759 {
760 // fix offsets
761 blitz::TinyVector<int, Volume<T>::DIM_MAX> dims;
762 int i, n=VolumeProxy<T>::_size.size();
763 for( i=0; i<n; ++i )
764 dims[i] = VolumeProxy<T>::_size[i];
765 for( ; i<Volume<T>::DIM_MAX; ++i )
766 dims[i] = 1;
767 _blitz.reference
768 ( blitz::Array<T,Volume<T>::DIM_MAX>
769 ( _start,
770 dims,
771 _refvol->_blitz.stride(),
772 blitz::GeneralArrayStorage<Volume<T>::DIM_MAX>
773 ( blitz::shape( 0, 1, 2, 3, 4, 5, 6, 7 ), true ) ) );
774 }
775
776 /* copy voxel_size from underlying volume, if any.
777 This should probably be more general, but cannot be applied to all
778 header properties (size, transformations...).
779 WARNING: Moreover here we do not guarantee to keep both voxel_size
780 unique: we point to the same vector of values for now, but it can be
781 replaced (thus, duplicated) by a setProperty().
782 We could use a addBuiltinProperty(), but then the voxel size has to be
783 stored in a fixed location somewhere.
784 */
785 try
786 {
787 carto::Object vs = _refvol->header().getProperty( "voxel_size" );
788 this->header().setProperty( "voxel_size", vs );
789 }
790 catch( ... )
791 {
792 // never mind.
793 }
794 }
795 }
796 }
797
798 template <typename T> inline
800 {
801 if ( pos != _pos )
802 {
803 _pos = pos.toVector();
805 }
806 }
807
808
809 template <typename T> inline
811 if (pos != _pos)
812 {
813 _pos = pos;
814 while( _pos.size() < 4 )
815 _pos.push_back( 0 );
817 }
818 }
819
820 template <typename T> inline
821 void Volume<T>::setRefVolume( const rc_ptr<Volume<T> > & refvol) {
822 if (refvol.get() != _refvol.get()) {
823 _refvol = refvol;
825 }
826 }
827
828 template <typename T> inline
829 std::vector<int> Volume<T>::getBorders() const
830 {
831 std::vector<int> borders( VolumeProxy<T>::_size.size() * 2, 0 );
832 if( _refvol.get() && _refvol->allocatorContext().isAllocated() )
833 {
834 int i, n = VolumeProxy<T>::_size.size();
835 for( i=0; i<n; ++i )
836 borders[i*2 + 1] = _refvol->_size[i] - VolumeProxy<T>::_size[i];
837 for( i=0, n=_pos.size(); i<n; ++i )
838 {
839 borders[i*2] = _pos[i];
840 borders[i*2+1] -= _pos[i];
841 }
842 }
843
844 return borders;
845 }
846
847 template <typename T> inline
848 std::vector<long> Volume<T>::getStrides() const
849 {
850
851 const blitz::TinyVector<BlitzStridesType, Volume<T>::DIM_MAX>& bstrides = _blitz.stride();
852 int d, n = VolumeProxy<T>::_size.size();
853 std::vector<long> strides( n );
854 for (d = 0; d < n; ++d)
855 strides[d] = bstrides[d];
856
857 return strides;
858 }
859
860 template < typename T >
862 {
863 if( &other == this )
864 return *this;
865
866 bool b = Headered::signalsBlocked();
867 if( !b )
869 this->VolumeProxy< T >::operator=( other );
870 // copy buffer, preserving allocator
871 _items.copy( other._items, other.allocatorContext() );
872 _start = &_items[0] + ( other._start - &other._items[0] );
873
874 // TODO: test blitz ownership / strides
875 // _blitz.reference( other.blitz );
876 blitz::TinyVector<long, Volume<T>::DIM_MAX> dims;
877 int i, n = VolumeProxy<T>::_size.size();
878 for( i=0; i<n; ++i )
879 dims[i] = VolumeProxy<T>::_size[i];
880 for( ; i<Volume<T>::DIM_MAX; ++i )
881 dims[i] = 1;
882 _blitz.reference
883 ( blitz::Array<T,Volume<T>::DIM_MAX>
884 ( _start,
885 dims,
886 other._blitz.stride(),
887 blitz::GeneralArrayStorage<Volume<T>::DIM_MAX>
888 ( blitz::shape( 0, 1, 2, 3, 4, 5, 6, 7 ), true ) ) );
889 _refvol = other._refvol;
890 _pos = other._pos;
892
893 initialize();
894
895 if( !b )
896 Headered::blockSignals( false );
897
898 return *this;
899
900 }
901
902 template <typename T>
904 const std::vector<int> & pos )
905 {
906 std::vector<int> size = this->getSize();
907 std::vector<int> osize = source.getSize();
908 int i;
909
910 for( i=0; i<size.size() && i<osize.size(); ++i )
911 {
912 int ip = 0;
913 if( pos.size() > i )
914 ip = pos[i];
915 size[i] = std::min( size[i] - ip, osize[i] );
916 }
917 for( ; i<size.size(); ++i )
918 size[i] = 1;
919
920 line_NDIterator<T> it( &at( pos ), size, this->getStrides() );
921 const_line_NDIterator<T> oit( &source.at( 0 ), size, source.getStrides() );
922 T *p, *pn;
923 const T *op;
924
925 for( ; !it.ended(); ++it, ++oit )
926 {
927 p = &*it;
928 op = &*oit;
929 for( pn=p + it.line_length(); p!=pn;
930 it.inc_line_ptr( p ), oit.inc_line_ptr( op ) )
931 *p = *op;
932 }
933 }
934
935 template <typename T>
937 const std::vector<int> & pos )
938 {
939 copySubVolume( *source, pos );
940 }
941
942 template < typename T >
944 {
945
946 return _blitz.begin();
947
948 }
949
950
951 template < typename T >
953 {
954
955 return _blitz.end();
956
957 }
958
959
960 template < typename T >
962 {
963
964 return _blitz.begin();
965
966 }
967
968
969 template < typename T >
971 {
972
973 return _blitz.end();
974
975 }
976
977
978 template < typename T >
980 {
981
982 // initializing headered stuff
983 this->Headered::initialize();
984
985 // creating size filter
986 std::set< std::string > sizePropertyNames;
987 sizePropertyNames.insert( "sizeX" );
988 sizePropertyNames.insert( "sizeY" );
989 sizePropertyNames.insert( "sizeZ" );
990 sizePropertyNames.insert( "sizeT" );
991 sizePropertyNames.insert( "volume_dimension" );
993 sizeRcPropertyFilter( new PropertyFilter( "size", sizePropertyNames ) );
994
995 // adding size filter to headered and connecting signal to slot
996 Headered::addPropertyFilter( sizeRcPropertyFilter );
997 Headered::connect( sizeRcPropertyFilter->getName(),
998 ::sigc::mem_fun( *this, &Volume< T >::slotSizeChanged ) );
999
1000 }
1001
1002
1003 template < typename T >
1004 void Volume< T >::allocate( int oldSizeX,
1005 int oldSizeY,
1006 int oldSizeZ,
1007 int oldSizeT,
1008 bool allocate,
1009 const AllocatorContext& ac,
1010 const std::vector<long> *strides )
1011 {
1012 std::vector<int> oldSize(4);
1013 oldSize[0] = oldSizeX;
1014 oldSize[1] = oldSizeY;
1015 oldSize[2] = oldSizeZ;
1016 oldSize[3] = oldSizeT;
1017 Volume< T >::allocate( oldSize, allocate, ac, strides );
1018 }
1019
1020
1021 template < typename T >
1022 void Volume< T >::allocate( const std::vector<int> & oldSize,
1023 bool allocate,
1024 const AllocatorContext& ac,
1025 const std::vector<long> *nstrides )
1026 {
1027 std::vector<long long int> strides(Volume<T>::DIM_MAX, 0);
1028 int i = 0, n = oldSize.size(), nn = VolumeProxy<T>::_size.size();
1029
1030 unsigned long long int stride_max = 0;
1031 unsigned long long int total_len = 0;
1032 unsigned long long absstride = 0;
1033 unsigned long long int offset = 0;
1034
1035 if( nstrides )
1036 {
1037 for( ; i<std::min(nstrides->size(), size_t(nn)); ++i )
1038 {
1039 strides[i] = (*nstrides)[i];
1040 absstride = std::abs( strides[i] );
1041 if( absstride > stride_max )
1042 stride_max = absstride;
1043 if( absstride * VolumeProxy<T>::_size[i] > total_len )
1044 total_len = absstride * VolumeProxy<T>::_size[i];
1045 if( strides[i] < 0 )
1046 offset += absstride * ( VolumeProxy<T>::_size[i] - 1 );
1047 }
1048 }
1049
1050 for( ; i<nn; ++i )
1051 {
1052 strides[i] = ( i == 0 ? 1 : VolumeProxy<T>::_size[i-1] * stride_max );
1053 if( strides[i] > stride_max )
1054 stride_max = strides[i];
1055 if( strides[i] * VolumeProxy<T>::_size[i] > total_len )
1056 total_len = strides[i] * VolumeProxy<T>::_size[i];
1057 }
1058 for( ; i<Volume<T>::DIM_MAX; ++i )
1059 strides[i] = ( i == nn ? VolumeProxy<T>::_size[i-1] * stride_max
1060 : strides[i-1] );
1061
1062 if ( total_len * sizeof(T) >
1063 (unsigned long long int) std::numeric_limits< size_t >::max() )
1064 {
1065
1066 throw std::runtime_error
1067 ( std::string( "attempt to allocate a volume which size is greater "
1068 "than allowed by the system (" )
1069 + toString( std::numeric_limits< size_t >::max() ) + " bytes)" );
1070
1071 }
1072
1073 bool no_old = true;
1074 for( i=0; i<n; ++i )
1075 if( oldSize[i] != -1 )
1076 {
1077 no_old = false;
1078 break;
1079 }
1080
1081 if ( !allocate // why !allocate ?
1082 || !_items.allocatorContext().isAllocated()
1083 || no_old )
1084 {
1085 // allocating memory space
1086 _items.free();
1087 if( allocate )
1088 {
1089 _items.allocate( ( size_t ) total_len, ac );
1090 }
1091 }
1092 else if ( oldSize != VolumeProxy<T>::_size
1093 || &ac != &_items.allocatorContext() )
1094 {
1095
1096 // allocating a new memory space
1097 AllocatedVector<T> newItems( ( size_t ) total_len, ac );
1098
1099 std::vector<int> minSize = VolumeProxy<T>::_size;
1100 for( i=0; i<std::min(n, nn); ++i )
1101 if( oldSize[i] < minSize[i] )
1102 minSize[i] = oldSize[i];
1103
1104 // preserving data
1105 int x, y, z, t;
1106 if( newItems.allocatorContext().allocatorType()
1107 != AllocatorStrategy::ReadOnlyMap )
1108 for ( t = 0; t < minSize[3]; t++ )
1109 {
1110
1111 for ( z = 0; z < minSize[2]; z++ )
1112 {
1113
1114 for ( y = 0; y < minSize[1]; y++ )
1115 {
1116
1117 for ( x = 0; x < minSize[0]; x++ )
1118 {
1119 // TODO: handle former strides with oldSize
1120 newItems[ x * strides[0] +
1121 y * strides[1] +
1122 z * ( size_t ) strides[2] +
1123 t * ( size_t ) strides[3] ] =
1124 _items[ x +
1125 y * oldSize[0] +
1126 z * ( size_t ) oldSize[0]
1127 * ( size_t ) oldSize[1] +
1128 t * ( size_t ) oldSize[0] *
1129 ( size_t ) oldSize[1]
1130 * ( size_t ) oldSize[2] ];
1131
1132 }
1133
1134 }
1135
1136 }
1137
1138 }
1139
1140 // copying new data to old one
1141 _items = newItems;
1142
1143 }
1144
1145 blitz::TinyVector<BlitzStridesType, Volume<T>::DIM_MAX> bstrides;
1146 if( nstrides )
1147 {
1148 for( i=0; i<nn; ++i )
1149 bstrides[i] = strides[i];
1150 int n;
1151 for( ; i<Volume<T>::DIM_MAX; ++i )
1152 {
1153 if( i < nn )
1154 n = VolumeProxy<T>::_size[i];
1155 else
1156 n = 1;
1157 bstrides[i] = ( i == 0 ? n : n * stride_max );
1158 if( strides[i] > stride_max )
1159 stride_max = bstrides[i];
1160 }
1161 }
1162
1163 if( allocate )
1164 {
1165 _start = &_items[0] + offset;
1166
1167 // TODO: test blitz ownership / strides
1168 /*
1169 std::cout << "alloc blitz: " << VolumeProxy<T>::_size[0] << ", "
1170 << VolumeProxy<T>::_size[1] << ", "
1171 << VolumeProxy<T>::_size[2] << ", "
1172 << VolumeProxy<T>::_size[3] << std::endl;
1173 */
1174 blitz::TinyVector<int, Volume<T>::DIM_MAX> dims;
1175 for( i=0; i<nn; ++i )
1176 dims[i] = VolumeProxy<T>::_size[i];
1177 for( ; i<Volume<T>::DIM_MAX; ++i )
1178 dims[i] = 1;
1179 if( nstrides)
1180 _blitz.reference( blitz::Array<T,Volume<T>::DIM_MAX>
1181 ( _start,
1182 dims,
1183 bstrides,
1184 blitz::GeneralArrayStorage<Volume<T>::DIM_MAX>
1185 ( blitz::shape( 0, 1, 2, 3, 4, 5, 6, 7 ),
1186 true ) ) );
1187 else
1188 _blitz.reference( blitz::Array<T,Volume<T>::DIM_MAX>
1189 ( _start,
1190 dims,
1191 blitz::GeneralArrayStorage<Volume<T>::DIM_MAX>
1192 ( blitz::shape( 0, 1, 2, 3, 4, 5, 6, 7 ),
1193 true ) ) );
1194 /*
1195 std::cout << &_items[0] << " / " << &_blitz( 0 ) << std::endl;
1196 std::cout << blitz::shape( VolumeProxy<T>::_size[0],
1197 VolumeProxy<T>::_size[1],
1198 VolumeProxy<T>::_size[2],
1199 VolumeProxy<T>::_size[3}] ) << std::endl;
1200 std::cout << "blitz data: " << _blitz.data() << std::endl;
1201 std::cout << "blitz ordering: " << _blitz.ordering() << std::endl;
1202 std::cout << "blitz numEl: " << _blitz.numElements() << std::endl;
1203 std::cout << "blitz strides: " << _blitz.stride() << std::endl;
1204 */
1205 }
1206 else
1207 {
1208 _start = (T*)( 0 ) + offset;
1209 blitz::TinyVector<int, Volume<T>::DIM_MAX> dims;
1210 for( i=0; i<nn; ++i )
1211 dims[i] = VolumeProxy<T>::_size[i];
1212 for( ; i<Volume<T>::DIM_MAX; ++i )
1213 dims[i] = 1;
1214 if( nstrides )
1215 // TODO: test blitz ownership
1216 _blitz.reference( blitz::Array<T,Volume<T>::DIM_MAX>
1217 ( 0,
1218 dims,
1219 bstrides,
1220 blitz::GeneralArrayStorage<Volume<T>::DIM_MAX>
1221 ( blitz::shape( 0, 1, 2, 3, 4, 5, 6, 7 ), true ) ) );
1222 else
1223 // TODO: test blitz ownership / strides
1224 _blitz.reference( blitz::Array<T,Volume<T>::DIM_MAX>
1225 ( 0,
1226 dims,
1227 blitz::GeneralArrayStorage<Volume<T>::DIM_MAX>
1228 ( blitz::shape( 0, 1, 2, 3, 4, 5, 6, 7 ), true ) ) );
1229 }
1230 _referential.ensureOrder( VolumeProxy<T>::_size.size() );
1231
1232 }
1233
1234
1235 template < typename T >
1237 {
1238 if( !allocatorContext().isAllocated() )
1239 {
1240 std::vector<long> strides = getStrides();
1242 &strides );
1243 }
1244 }
1245
1246
1247 template < typename T >
1248 void Volume< T >::slotSizeChanged( const PropertyFilter& propertyFilter )
1249 {
1250
1251 /* std::cout << "Volume< " << DataTypeCode<T>::name()
1252 << " >::slotSizeChanged"
1253 << std::endl; */
1254
1255 std::vector<int> oldSize = VolumeProxy<T>::_size;
1256
1257 if ( propertyFilter.hasOldValue( "sizeX" ) )
1258 {
1259
1260 oldSize[0] =
1261 propertyFilter.getOldValue( "sizeX" )->GenericObject::value< int >();
1262
1263 }
1264 if ( propertyFilter.hasOldValue( "sizeY" ) )
1265 {
1266
1267 oldSize[1] =
1268 propertyFilter.getOldValue( "sizeY" )->GenericObject::value< int >();
1269
1270 }
1271 if ( propertyFilter.hasOldValue( "sizeZ" ) )
1272 {
1273
1274 oldSize[2] =
1275 propertyFilter.getOldValue( "sizeZ" )->GenericObject::value< int >();
1276
1277 }
1278 if ( propertyFilter.hasOldValue( "sizeT" ) )
1279 {
1280
1281 oldSize[3] =
1282 propertyFilter.getOldValue( "sizeT" )->GenericObject::value< int >();
1283
1284 }
1285 /*
1286 std::cout << "old size: " << oldSize[0] << ", " << oldSize[1] << ", "
1287 << oldSize[2] << ", " << oldSize[3] << std::endl;
1288 std::cout << "new size: " << VolumeProxy<T>::_size[0] << ", "
1289 << VolumeProxy<T>::_size[1] << ", "
1290 << VolumeProxy<T>::_size[2] << ", " << VolumeProxy<T>::_size[3]
1291 << std::endl;
1292 */
1293 allocate( oldSize,
1294 _items.allocatorContext().isAllocated(), allocatorContext() );
1295
1296 }
1297
1298
1299 template < typename T >
1301 int sizeY,
1302 int sizeZ,
1303 int sizeT,
1304 bool keepcontents,
1305 const AllocatorContext & ac,
1306 bool alloc,
1307 const std::vector<long> *strides )
1308 {
1309 int oldx = VolumeProxy<T>::_size[0];
1310 int oldy = VolumeProxy<T>::_size[1];
1311 int oldz = VolumeProxy<T>::_size[2];
1312 int oldt = VolumeProxy<T>::_size[3];
1313 VolumeProxy<T>::_size.resize( 4 );
1314 VolumeProxy<T>::_size[0] = sizeX;
1315 VolumeProxy<T>::_size[1] = sizeY;
1316 VolumeProxy<T>::_size[2] = sizeZ;
1317 VolumeProxy<T>::_size[3] = sizeT;
1318 if( keepcontents || ( sizeX == oldx && sizeY == oldy && sizeZ == oldz
1319 && sizeT == oldt ) )
1320 allocate( oldx, oldy, oldz, oldt, alloc, ac, strides );
1321 else
1322 allocate( std::vector<int>(1, -1), alloc, ac, strides );
1323 // emit a signal ?
1324 }
1325
1326 template < typename T >
1328 bool keepcontents,
1329 const AllocatorContext & ac,
1330 bool alloc,
1331 const std::vector<long> *strides )
1332 {
1333 return reallocate( size[0] > 0 ? size[0] : 1,
1334 size[1] > 0 ? size[1] : 1,
1335 size[2] > 0 ? size[2] : 1,
1336 size[3] > 0 ? size[3] : 1,
1337 keepcontents, ac, alloc, strides );
1338 }
1339
1340 template < typename T >
1341 void Volume< T >::reallocate( const std::vector<int> & size,
1342 bool keepcontents,
1343 const AllocatorContext & ac,
1344 bool alloc,
1345 const std::vector<long> *strides )
1346 {
1347 std::vector<int> old = VolumeProxy<T>::_size;
1348
1349 VolumeProxy<T>::_size = size;
1350 while( VolumeProxy<T>::_size.size() < 4 )
1351 VolumeProxy<T>::_size.push_back( 1 );
1352
1361
1362 if( keepcontents || size == old )
1363 allocate( old, alloc, ac, strides );
1364 else
1365 allocate( std::vector<int>(1, -1), alloc, ac, strides );
1366 // emit a signal ?
1367 }
1368
1369
1370 template < typename T >
1371 void Volume< T >::allocateBorders( int bsx, int bsy, int bsz )
1372 {
1373 std::vector<int> border( 3 );
1374 border[0] = bsx;
1375 border[1] = ( bsy < 0 ? bsx : bsy );
1376 border[2] = ( bsz < 0 ? bsx : bsz );
1377
1378 allocateBorders( border );
1379 }
1380
1381
1382 template < typename T >
1383 void Volume< T >::allocateBorders( const std::vector<int> & border )
1384 {
1385 Volume<T> vol_copy = this->copy();
1386
1387 bool has_border = false;
1388 if( !border.empty() )
1389 {
1390 size_t i, n = border.size();
1391 for( i=0; !has_border && i<n; ++i )
1392 if( border[i] != 0 )
1393 has_border = true;
1394 }
1395 // constructBorders will not erase _refvol since it is normally used
1396 // only in constructors.
1397 if( !has_border )
1398 _refvol.reset( 0 );
1399
1400 constructBorders( border, carto::AllocatorContext(), true );
1401 _pos = border;
1402 if( _pos.size() < 4 )
1403 _pos.resize( 4, 0 );
1404
1405 this->copySubVolume( vol_copy );
1406 }
1407
1408
1409 template < typename T >
1410 void Volume< T >::flipToOrientation( const std::string & orient )
1411 {
1412 if( _referential.orientationVector( orient, _referential.order() )
1413 == _referential.axesOrientation() )
1414 // already in the same orientation
1415 return;
1416
1417 blitz::TinyVector<int, Volume<T>::DIM_MAX> dims = _blitz.shape();
1418 blitz::TinyVector<BlitzStridesType, Volume<T>::DIM_MAX>
1419 strides = _blitz.stride();
1420
1421 int i, n = this->getSize().size();
1422 std::vector<float>transl( n, 0.f );
1423
1424 for( i=0; i<n; ++i )
1425 transl[i] = dims[i] - 1;
1427 = referential().toOrientation( orient, transl );
1429 = dynamic_cast<soma::AffineTransformationBase &>( *flipt );
1430 std::unique_ptr<AffineTransformationBase> iflip = flip.inverse();
1431 blitz::TinyVector<BlitzStridesType, Volume<T>::DIM_MAX>
1432 new_strides = strides;
1433 long long offset = 0, old_offset = _start - &_items[0];
1434 long old_stride;
1435 for( i=0; i<n; ++i )
1436 {
1437 std::vector<int> p( n, 0 );
1438 p[i] = 1;
1439 std::vector<int> p1 = iflip->transformVector( p );
1440 new_strides[i] = &at( p1 ) - &at( 0 );
1441 }
1442 std::vector<int> vdims( dims.begin(), dims.end() );
1443 std::vector<int> new_dims = flip.transformVector( vdims );
1444 for( i=0; i<n; ++i )
1445 new_dims[i] = std::abs( new_dims[i] );
1446 blitz::TinyVector<int, Volume<T>::DIM_MAX> new_bdims = dims;
1447 for( i=0; i<n; ++i )
1448 new_bdims[i] = new_dims[i];
1449 for( i=0; i<n; ++i )
1450 {
1451 if( new_strides[i] < 0 )
1452 offset += -new_strides[i] * ( new_dims[i] - 1 );
1453 if( strides[i] < 0 )
1454 old_offset += strides[i] * ( dims[i] - 1 );
1455 }
1456
1457 Object reor_hdr = reorientedHeader( orient );
1458
1459 this->blockSignals( true );
1460
1461 this->header().copyProperties( reor_hdr );
1462
1463 _start = &_items[0] + offset + old_offset;
1464 _blitz.reference(
1465 blitz::Array<T,Volume<T>::DIM_MAX>(
1466 _start,
1467 new_bdims,
1468 new_strides,
1469 blitz::GeneralArrayStorage<Volume<T>::DIM_MAX>
1470 ( blitz::shape( 0, 1, 2, 3, 5, 6, 7, 8 ), true ) ) );
1471 this->blockSignals( false );
1472
1473 // update referential info, generate a new ID
1474 _referential.setOrientation( orient );
1475 if( _referential.isLpiOriented() ) // initial LPI orientation
1476 _referential.setUuid( _referential.lpiReferentialUuid() );
1477 else
1478 {
1479 UUID uuid;
1480 uuid.generate();
1481 _referential.setUuid( uuid.toString() );
1482 }
1483 }
1484
1485
1486 template < typename T >
1488 const std::string & orient, const std::string & force_memory_layout )
1489 {
1490 // calculate strides and dims for asked memory layout
1491 std::vector<int> dims = this->getSize();
1492 int i, n = dims.size();
1493 std::vector<float>transl( n, 0.f );
1494 for( i=0; i<n; ++i )
1495 transl[i] = dims[i] - 1;
1496
1498 = referential().toOrientation( force_memory_layout, transl );
1500 = dynamic_cast<soma::AffineTransformationBase &>( *flipt );
1501
1502 bool change_layout = false;
1503 std::vector<int> new_dims = flip.transformVector( dims );
1504 for( i=0; i<n; ++i )
1505 new_dims[i] = std::abs( new_dims[i] );
1506
1507 long cstride = 1;
1508
1509 std::unique_ptr<AffineTransformationBase> iflip = flip.inverse();
1510 for( i=0; i<n; ++i )
1511 {
1512 std::vector<int> p0( n, 0 );
1513 p0[i] = 1;
1514 p0 = iflip->transformVector( p0 );
1515 long st = &this->at( p0 ) - &this->at( 0 );
1516 if( st != cstride )
1517 {
1518 change_layout = true;
1519 break;
1520 }
1521 cstride *= new_dims[i];
1522 }
1523
1524 if( change_layout )
1525 {
1526
1527 // allocate a new Volume before copying it into this
1528 VolumeRef<T> copy( new_dims );
1529 copy->copyHeaderFrom( this->header() );
1530 copy->referential().setOrientation( force_memory_layout );
1531 copy->referential().setLpiReferential(
1532 this->referential().lpiReferentialUuid() );
1533
1534 // copy data in the new layout
1535 line_NDIterator<T> it( &this->at( 0 ), this->getSize(),
1536 this->getStrides(), true );
1537 T* p, *pp, *dp;
1538 long dstride = 0;
1539 std::vector<int> pos;
1540 std::vector<int> p0;
1541 pos = flip.transform( it.position() );
1542 dp = &copy->at( pos );
1543 p0 = std::vector<int>( n, 0 );
1544 p0[it.line_direction()] = 1;
1545 pos = flip.transform( p0 );
1546 dstride = &copy->at( pos ) - dp;
1547
1548 for( ; !it.ended(); ++it )
1549 {
1550 p = &*it;
1551 pos = flip.transform( it.position() );
1552 dp = &copy->at( pos );
1553
1554 for( pp=p + it.line_length(); p!=pp;
1555 it.inc_line_ptr( p ), dp += dstride )
1556 *dp = *p;
1557 }
1558
1559 // copy back data to this
1560 *this = *copy;
1561 }
1562
1563 // then flip strides to the wanted orientation
1564 this->flipToOrientation( orient );
1565 }
1566
1567
1568 template <typename T>
1569 Object Volume<T>::reorientedHeader( const std::string & orient ) const
1570 {
1571 Object rhdr = Object::value( PropertySet() );
1572 const PropertySet & hdr = this->header();
1573
1574 rhdr->copyProperties( Object::reference( hdr ) );
1575
1576 std::vector<int> dims = this->getSize();
1577 size_t i, n = dims.size();
1578 std::vector<float>transl( n, 0.f );
1579
1580 for( i=0; i<n; ++i )
1581 transl[i] = dims[i] - 1;
1583 = referential().toOrientation( orient, transl );
1585 = dynamic_cast<soma::AffineTransformationBase &>( *flipt );
1586 std::unique_ptr<AffineTransformationBase> iflip = flip.inverse();
1587
1588 dims = flip.transformVector( dims );
1589 for( i=0, n=dims.size(); i<n; ++i )
1590 dims[i] = std::abs( dims[i] );
1591 rhdr->setProperty( "volume_dimension", dims );
1592 if( rhdr->hasProperty( "sizeX" ) )
1593 rhdr->removeProperty( "sizeX" );
1594 if( rhdr->hasProperty( "sizeY" ) )
1595 rhdr->removeProperty( "sizeY" );
1596 if( rhdr->hasProperty( "sizeZ" ) )
1597 rhdr->removeProperty( "sizeZ" );
1598 if( rhdr->hasProperty( "sizeT" ) )
1599 rhdr->removeProperty( "sizeT" );
1600
1601 std::vector<float> vs = this->getVoxelSize();
1602 std::vector<float> rvs = flip.transformVector( vs );
1603 for( i=0, n=rvs.size(); i<n; ++i )
1604 rvs[i] = std::abs( rvs[i] );
1605 rhdr->setProperty( "voxel_size", rvs );
1606
1607 bool is3d = this->referential().is3DOriented( orient );
1608
1609 if( hdr.hasProperty( "transformations" ) )
1610 {
1611 AffineTransformationBase mvs( dims.size() );
1612 AffineTransformationBase rmvs( dims.size() );
1613 for( i=0, n=vs.size(); i<n; ++i )
1614 {
1615 mvs.matrix()(i, i) = vs[i];
1616 rmvs.matrix()(i, i) = 1.f / rvs[i];
1617 }
1618 // affine in mm
1619 AffineTransformationBase iflipmm = mvs * *iflip * rmvs;
1620
1621 std::vector<std::vector<float> > rtrans;
1622 Object transs = hdr.getProperty( "transformations" );
1623 rtrans.reserve( transs->size() );
1624 Object tit = transs->objectIterator();
1625 for(; tit->isValid(); tit->next() )
1626 {
1627 AffineTransformationBase trans( tit->currentValue() );
1628 trans.extendOrder( flip.order() );
1629 // TODO extend both to max order( flip, trans )
1630 // then handle non-3D transforms in header
1631 trans = trans * iflipmm;
1632 if( is3d )
1633 trans.squeezeOrder( 3, true, false );
1634 rtrans.push_back( trans.toVector() );
1635 }
1636 rhdr->setProperty( "transformations", rtrans );
1637 }
1638
1639 if( hdr.hasProperty( "storage_to_memory" ) )
1640 {
1641 AffineTransformationBase
1642 s2m( hdr.getProperty( "storage_to_memory" ) );
1643 s2m.extendOrder( flip.order() );
1644 s2m = flip * s2m;
1645 if( is3d )
1646 s2m.squeezeOrder( 3, true, false );
1647 rhdr->setProperty( "storage_to_memory", s2m.toVector() );
1648 }
1649
1650 if( rhdr->hasProperty( "referential" ) )
1651 {
1652 if( orient == "LPI" ) // initial LPI orientation
1653 rhdr->setProperty( "referential", _referential.lpiReferentialUuid() );
1654 else
1655 rhdr->removeProperty( "referential" );
1656 }
1657
1658 return rhdr;
1659 }
1660
1661
1662 template <typename T>
1663 std::vector<int> Volume<T>::memoryLayoutOrientation() const
1664 {
1665 std::vector<long> strides = this->getStrides();
1666 size_t i, j, n = strides.size();
1667 std::multimap<std::pair<long, bool>, size_t> ordered_strides;
1668 std::vector<int> orient( n, 0 );
1669 std::vector<int> dims = this->getSize();
1670
1671 for( i=0; i<n; ++i )
1672 {
1673 bool several = ( dims[i] > 1 );
1674 ordered_strides.insert(
1675 std::make_pair( std::make_pair( std::abs( strides[i] ), several),
1676 i ) );
1677 }
1678
1679 std::vector<int> aorient = this->referential().axesOrientation();
1680 std::multimap<std::pair<long, bool>, size_t>::const_iterator
1681 im, em = ordered_strides.end();
1682
1683 for( im=ordered_strides.begin(), i=0; im!=em; ++im, ++i )
1684 {
1685 j = ( ( aorient[ im->second ] - 1 ) / 2 ) * 2 + 1;
1686 bool neg = ( aorient[ im->second ] - 1 ) % 2;
1687 if( strides[ im->second] < 0 )
1688 neg = !neg;
1689 if( neg )
1690 ++j;
1691 orient[i] = j;
1692 }
1693
1694 return orient;
1695 }
1696
1697
1698 template <typename T>
1700 {
1701 try
1702 {
1703 Object s2mo = this->header().getProperty( "storage_to_memory" );
1705 std::unique_ptr<AffineTransformationBase> m2s = s2m.inverse();
1706 return this->referential().orientationFromTransform( *m2s );
1707 }
1708 catch( ... )
1709 {
1710 }
1711
1712 std::vector<int> orient( this->getSize().size(), 0 );
1713 return orient;
1714 }
1715
1716
1717//============================================================================
1718// U T I L I T I E S
1719//============================================================================
1720
1721 template <typename T>
1722 Volume<T>* Creator<Volume<T> >::create( Object header,
1723 const AllocatorContext & context,
1724 Object options )
1725 {
1726 std::vector<int> dims( 4, 1 );
1727 bool unalloc = false;
1728 if( !header->getProperty( "volume_dimension", dims ) )
1729 {
1730 header->getProperty( "sizeX", dims[0] );
1731 header->getProperty( "sizeY", dims[1] );
1732 header->getProperty( "sizeZ", dims[2] );
1733 header->getProperty( "sizeT", dims[3] );
1734 }
1735
1736 unsigned n = dims.size();
1737
1738 try
1739 {
1740 Object uao = options->getProperty( "unallocated" );
1741 unalloc = bool( uao->getScalar() );
1742 }
1743 catch( ... )
1744 {
1745 }
1746
1747 std::string orient;
1748 try
1749 {
1750 Object oo = options->getProperty( "orientation" );
1751 orient = oo->getString();
1752 }
1753 catch( ... )
1754 {
1755 }
1756
1758 new soma::AffineTransformationBase( dims.size() ) );
1759 std::vector<int> tdims = dims;
1760
1761 if( !orient.empty() )
1762 {
1763 // dims and borders are given in LPI orientation
1764
1765 Referential ref( dims.size() );
1766 if( orient == "storage" )
1767 {
1768 try
1769 {
1770 // std::cout << "request storage orientation\n";
1771 Object s2mo = header->getProperty( "storage_to_memory" );
1773 // volume will be in storage orientation,
1774 // and ortr will get from LPI orientation to storage one
1776 ortr.reset(
1777 dynamic_cast<soma::AffineTransformationBase *>( t.get() ) );
1778 // determine storage orientation
1779 orient = ref.orientationStr( ref.orientationFromTransform( *ortr ) );
1780 // std::cout << "orient: " << orient << std::endl;
1781 }
1782 catch( ... )
1783 {
1784 }
1785 }
1786 else
1787 {
1788 // ref.setOrientation( orient );
1790 = ref.toOrientation( orient, soma::Transformation::vsub( dims, 1 ) );
1791 ortr.reset(
1792 dynamic_cast<soma::AffineTransformationBase *>( t.get() ) );
1793 }
1794 tdims = ortr->transformVector( dims );
1795 for( unsigned i=0; i<n; ++i )
1796 tdims[i] = std::abs( tdims[i] );
1797 // tdims are in memory orientation
1798 orient = ref.orientationStr( orient );
1799 if( orient == ref.orientationStr( "LPI" ) )
1800 {
1801 // orient is LPI: no need to transform things
1802 orient.clear();
1803 }
1804 }
1805
1806 std::vector<int> borders( 3, 0 );
1807 try {
1808 borders[0] = (int) rint( options->getProperty( "border" )->getScalar() );
1809 borders[1] = borders[0];
1810 borders[2] = borders[0];
1811 } catch( ... ) {}
1812 try {
1813 borders[0] = (int) rint( options->getProperty( "bx" )->getScalar() );
1814 } catch( ... ) {}
1815 try {
1816 borders[1] = (int) rint( options->getProperty( "by" )->getScalar() );
1817 } catch( ... ) {}
1818 try {
1819 borders[2] = (int) rint( options->getProperty( "bz" )->getScalar() );
1820 } catch( ... ) {}
1821
1822 Volume<T> *obj;
1823 if( borders[0] != 0 || borders[1] != 0 || borders[2] != 0 )
1824 {
1825 std::vector<int> big_dims = dims;
1826 big_dims[0] += borders[0] * 2;
1827 big_dims[1] += borders[1] * 2;
1828 big_dims[2] += borders[2] * 2;
1829
1830 big_dims = ortr->transformVector( big_dims );
1831 for( unsigned i=0; i<big_dims.size(); ++i )
1832 big_dims[i] = std::abs( big_dims[i] );
1833 borders = ortr->transformVector( borders );
1834 for( unsigned i=0; i<borders.size(); ++i )
1835 borders[i] = std::abs( borders[i] );
1836
1837 obj = new Volume<T>( big_dims, context, !unalloc );
1838 if( !orient.empty() )
1839 obj->referential().setOrientation( orient );
1840 obj = new Volume<T>( rc_ptr<Volume<T> >( obj ), borders, tdims, context );
1841 }
1842 else
1843 obj = new Volume<T>( tdims, context, !unalloc );
1844
1845 if( !orient.empty() )
1846 {
1847 obj->referential().setOrientation( orient );
1848// // copy header to a temp, unallocated volume
1849// Volume<T> tvol( dims, AllocatorContext( &NullAllocator::singleton() ) );
1850// tvol.header().copyProperties( header );
1851// // then get a properly reoriented header
1852// header = tvol.reorientedHeader( orient );
1853// std::cout << "reoriented header\n";
1854
1855 // set strides orientation to default LPI
1856 obj->flipToOrientation( "LPI" );
1857 }
1858
1859 obj->blockSignals( true );
1860 try
1861 {
1862 obj->copyHeaderFrom( header, false );
1863 }
1864 catch( std::exception & )
1865 {
1866 // not beautiful, but don't crash for that
1867 }
1868 // restore original sizes : temporary too...
1869 obj->blockSignals( false );
1870
1871 return obj;
1872 }
1873
1874 template <typename T>
1875 void Creator<Volume<T> >::setup( Volume<T> & obj, Object header,
1876 const AllocatorContext & context,
1877 Object options )
1878 {
1879 std::vector<int> dims( 4, 1 );
1880 bool unalloc = false, partial = false, keep_allocation = false;
1881 try
1882 {
1883 carto::Object p = options->getProperty( "partial_reading" );
1884 partial = bool( p->getScalar() );
1885 }
1886 catch( ... ) {}
1887 if( !partial )
1888 {
1889 if( !header->getProperty( "volume_dimension", dims ) )
1890 {
1891 header->getProperty( "sizeX", dims[0] );
1892 header->getProperty( "sizeY", dims[1] );
1893 header->getProperty( "sizeZ", dims[2] );
1894 header->getProperty( "sizeT", dims[3] );
1895 }
1896 try
1897 {
1898 carto::Object p = options->getProperty( "unallocated" );
1899 unalloc = bool( p->getScalar() );
1900 }
1901 catch( ... ) {}
1902 try
1903 {
1904 carto::Object p = options->getProperty( "keep_allocation" );
1905 keep_allocation = bool( p->getScalar() );
1906 }
1907 catch( ... ) {}
1908 if( !keep_allocation || !obj.allocatorContext().isAllocated()
1909 || obj.allocatorContext().allocatorType()
1910 != AllocatorStrategy::Unallocated )
1911 obj.reallocate( dims, false, context, !unalloc );
1912 }
1913 else
1914 {
1915 const_cast<AllocatorContext &>( obj.allocatorContext() ).setDataSource
1916 ( context.dataSource() );
1917 // preserve dimensions
1918 dims = obj.getSize();
1919 }
1920 obj.blockSignals( true );
1921 obj.header().copyProperties( header );
1922 if( partial )
1923 {
1924 // restore dimensions
1925 PropertySet & ps = obj.header();
1926 ps.setProperty( "volume_dimension", dims );
1927 ps.setProperty( "sizeX", dims[0] );
1928 ps.setProperty( "sizeY", dims[1] );
1929 ps.setProperty( "sizeZ", dims[2] );
1930 ps.setProperty( "sizeT", dims[3] );
1931 }
1932 obj.blockSignals( false );
1933 }
1934
1935} // namespace carto
1936
1937#endif // CARTODATA_VOLUME_VOLUMEBASE_D_H
static void setup(Volume< T > &, Object, const AllocatorContext &, Object)
static Volume< T > * create(Object, const AllocatorContext &, Object)
virtual void copyProperties(Object source)
const PropertySet & header() const
void blockSignals(bool)
bool signalsBlocked() const
std::string uuid()
bool connect(const std::string &propertyFilterName, const PropertyFilter::Slot &slot)
void addPropertyFilter(const rc_ptr< PropertyFilter > &propertyFilter)
virtual void initialize()
const std::vector< int > & position() const
Object reference(Object &value)
static Object value()
Object getOldValue(const std::string &propertyName) const
bool hasOldValue(const std::string &propertyName) const
void setProperty(const std::string &, const T &)
virtual bool hasProperty(const std::string &) const
void addBuiltinProperty(const std::string &, T &)
bool getProperty(const std::string &, T &) const
void changeBuiltinProperty(const std::string &, T &)
Referential holds information about coordinates system and axes.
Definition referential.h:78
void setOrientation(const std::string &orient, bool allow_resize=false)
set a new orientation for the referential.
VolumeProxy(int sizeX=1, int sizeY=1, int sizeZ=1, int sizeT=1)
int getSizeY() const
VolumeProxy< T > & operator=(const VolumeProxy< T > &other)
std::vector< float > getVoxelSize() const
get the voxel size from the header, with 4 values defaulting to 1.mm if not present
virtual void copyHeaderFrom(const PropertySet &other, bool stopOnError=true)
copy properties from other to this, avoiding forbidden properties like size.
int getSizeX() const
Definition volumeproxy.h:91
std::vector< int > getSize() const
get the 4 dimensions in a vector
std::vector< int > _size
Definition volumeproxy.h:84
int getSizeZ() const
int getSizeT() const
Convenient handle for a Volume - this is normally the entry point for all volumes handling.
Definition volumeref.h:60
Position4Di(int x=0, int y=0, int z=0, int t=0)
Definition volumebase.h:602
const std::vector< int > & toVector() const
Definition volumebase.h:642
N-D Volume main class.
Definition volumebase.h:120
iterator begin()
Iterators returned here are the most "basic" (and fastest) iterators: they go from the first voxel li...
std::vector< int > _pos
Definition volumebase.h:591
std::vector< int > Position
Definition volumebase.h:130
const Referential & referential() const
const AllocatorContext & allocatorContext() const
returns volume's AllocatorContext
rc_ptr< Volume< T > > _refvol
Definition volumebase.h:590
void setPosInRefVolume(const Position4Di &pos)
Set position in parent volume.
Volume< T > & operator=(const Volume< T > &other)
blitz::Array< T, Volume< T >::DIM_MAX >::const_iterator const_iterator
Definition volumebase.h:143
Referential _referential
Definition volumebase.h:592
virtual void initialize()
Initializes header info.
Object reorientedHeader(const std::string &orient) const
used by flipToOrientation(), reorient header information
Volume(int sizeX=1, int sizeY=1, int sizeZ=1, int sizeT=1, const AllocatorContext &allocatorContext=AllocatorContext(), bool allocated=true)
Volume construction and allocation.
const Position & posInRefVolume() const
Get position in parent volume.
void constructBorders(const Position &bordersize, const AllocatorContext &allocatorContext, bool allocated)
void allocate()
This function is only useful in the particular context of an unallocated Volume, when the constructor...
void setRefVolume(const rc_ptr< Volume< T > > &refvol)
Set parent volume.
iterator end()
Volume< T > copy() const
Create a volume of same dimension and copy the data.
virtual ~Volume()
blitz::Array< T, Volume< T >::DIM_MAX >::iterator iterator
Definition volumebase.h:142
Position posInRefVolumeAtLevel(const int level) const
Get position relatively to parent volume at specified level.
rc_ptr< Volume< T > > refVolume() const
Get parent volume.
void copySubVolume(const Volume< T > &source, const std::vector< int > &pos=std::vector< int >())
Copy voxels values from another volume.
std::vector< int > getBorders() const
Get borders for the volume.
int refLevel(const int level) const
Transform a level index to a valid level index in the volume hierarchy.
std::vector< int > storageLayoutOrientation() const
determine the storage (disk) layout orientation.
std::vector< long > getStrides() const
Get strides for the volume.
rc_ptr< Volume< T > > refVolumeAtLevel(const int level) const
Get parent volume at a specified level in volume hierarchy.
const T & at(long x, long y=0, long z=0, long t=0) const
int getLevelsCount() const
Get levels count in volume hierarchy from the current volume to the topmost volume.
void slotSizeChanged(const PropertyFilter &propertyFilter)
virtual void reallocate(int sizeX=1, int sizeY=1, int sizeZ=1, int sizeT=1, bool keepcontents=false, const AllocatorContext &allocatorContext=AllocatorContext(), bool allocate=true, const std::vector< long > *strides=0)
allows resizing and changing allocator
void allocateBorders(int bsx, int bsy=-1, int bsz=-1)
reallocate the volume with given borders, keep (copy) the contents.
blitz::Array< T, Volume< T >::DIM_MAX > _blitz
Definition volumebase.h:589
void flipToOrientation(const std::string &orient)
Flip the volume to a given orientation.
std::vector< int > memoryLayoutOrientation() const
determine the memory layout orientation from strides and current indices orientation.
void updateItemsBuffer()
AllocatedVector< T > _items
Definition volumebase.h:586
void inc_line_ptr(const T *&p) const
bool isNull() const
std::ptrdiff_t line_length() const
void inc_line_ptr(T *&p) const
void reset(T *p=NULL)
T * get() const
std::unique_ptr< Transformation > getInverse() const CARTO_OVERRIDE
virtual void squeezeOrder(unsigned n, bool check=true, bool notify_fail=true)
virtual std::vector< double > transform(const std::vector< double > &pos) const
std::unique_ptr< AffineTransformationBase > inverse() const
virtual std::vector< double > transformVector(const std::vector< double > &pos) const
static std::vector< T > vsub(const std::vector< T > &v1, const std::vector< T > &v2)
std::string toString(const T &object)
Volume< T > copy(const Volume< T > &src)
Performs a copy of the data (not only a reference copy) Only the data inside the view is copied.
Definition volumeutil.h:994
Object none()
static _Tp max()