cartodata 6.0.0
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 }
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 }
254
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() ) ),
265 _pos( bordersize )
267 this->header().addBuiltinProperty( "referential", _referential.uuid() );
268 while( _pos.size() < 4 )
269 _pos.push_back( 0 );
270 constructBorders( bordersize, allocatorContext, allocated );
271 }
272
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 )
283 {
284 this->header().addBuiltinProperty( "referential", _referential.uuid() );
285 allocate( -1, -1, -1, -1, true, allocatorContext(), strides );
286 }
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 )
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.
357
358 // handle transformation to parent ref
359 std::vector<float> vs = vol->getVoxelSize();
360 while( vs.size() < 3 )
361 vs.push_back( 1.f );
362 typename Volume<T>::Position pos = vol->posInRefVolume();
363 std::vector<float> trv( 16, 0.f );
364 trv[0] = 1.f;
365 trv[5] = 1.f;
366 trv[10] = 1.f;
367 trv[15] = 1.f;
368 trv[3] = pos[0] * vs[0];
369 trv[7] = pos[1] * vs[1];
370 trv[11] = pos[2] * vs[2];
371 AffineTransformationBase tr( trv );
372
373 std::string ref = parent->referential().uuid();
374 std::vector<std::string> refs;
375 std::vector<std::vector<float> > trans;
376 refs.push_back( ref );
377 trans.push_back( trv );
378 try
379 {
380 carto::Object tl = parent->header().getProperty( "transformations" );
381 trans.reserve( tl->size() + 1 );
382 carto::Object it;
383 for( it = tl->objectIterator(); it->isValid(); it->next() )
384 {
385 AffineTransformationBase tn( it->currentValue() );
386 tn *= tr;
387 trans.push_back( tn.toVector() );
388 }
389 carto::Object rl = parent->header().getProperty( "referentials" );
390 refs.reserve( rl->size() + 1 );
391 for( it = rl->objectIterator(); it->isValid(); it->next() )
392 refs.push_back( it->currentValue()->getString() );
393 }
394 catch( ... )
395 {
396 }
397 vol->header().setProperty( "referentials", refs );
398 vol->header().setProperty( "transformations", trans );
400
401 }
402
403
404 /***************************************************************************
405 * View Constructor
406 **************************************************************************/
407 template<typename T> inline
409 const Position4Di & pos, const Position4Di & size,
410 const AllocatorContext & allocContext )
411 : VolumeProxy<T>( size[0] >= 0 ? size[0] :
412 other->allocatorContext().isAllocated() ? other->getSizeX() : 1,
413 size[1] >= 0 ? size[1] :
414 other->allocatorContext().isAllocated() ? other->getSizeY() : 1,
415 size[2] >= 0 ? size[2] :
416 other->allocatorContext().isAllocated() ? other->getSizeZ() : 1,
417 size[3] >= 0 ? size[3] :
418 other->allocatorContext().isAllocated() ? other->getSizeT() : 1 ),
419 _items( 0U, allocContext ),
420 _refvol( other ),
421 _pos( pos.toVector() ),
422 _referential( other->referential() )
423 {
424 this->header().addBuiltinProperty( "referential", _referential.uuid() );
425 // use a unique referential UUID, but keep orientation information
426 UUID uuid;
427 uuid.generate();
428 _referential.setUuid( uuid.toString() );
430 if( other->allocatorContext().isAllocated() )
431 {
432 size_t bsize = sizeof(T);
433 std::vector<int> osize = other->getSize();
434 int i, n = osize.size();
435 for( i=0; i<n; ++i )
436 bsize *= osize[i];
438 allocate( -1, -1, -1, -1, true,
439 AllocatorContext( AllocatorStrategy::NotOwner,
440 rc_ptr<DataSource>( new BufferDataSource
441 ( (char *) &other->_items[0],
442 bsize ) ) ) );
443 // fix offsets
444 blitz::TinyVector<int, Volume<T>::DIM_MAX> dims;
445 n = VolumeProxy<T>::_size.size();
446 for( i=0; i<n; ++i )
448 for( ; i<Volume<T>::DIM_MAX; ++i )
449 dims[i] = 1;
450 _start = &(*other)( pos.toVector() );
451 _blitz.reference
452 ( blitz::Array<T,Volume<T>::DIM_MAX>
453 ( _start,
454 dims,
455 other->_blitz.stride(),
456 blitz::GeneralArrayStorage<Volume<T>::DIM_MAX>
457 ( blitz::shape( 0, 1, 2, 3, 4, 5, 6, 7 ), true ) ) );
458 }
459 else
460 allocate( -1, -1, -1, -1, true, allocContext );
461
462 _updateHeaderFromParent( this );
463 }
464
465
466 template<typename T> inline
468 const Position & pos, const Position & size,
469 const AllocatorContext & allocContext )
470 : VolumeProxy<T>( Position4Di::fixed_size( size ) ),
471 _items( 0U, allocContext ),
472 _refvol( other ),
473 _pos( Position4Di::fixed_position( pos ) ),
474 _referential( other->referential() )
475 {
476 this->header().addBuiltinProperty( "referential", _referential.uuid() );
477 // use a unique referential UUID, but keep orientation information
478 UUID uuid;
479 uuid.generate();
480 _referential.setUuid( uuid.toString() );
481
482 if( other->allocatorContext().isAllocated() )
483 {
484 size_t bsize = sizeof(T);
485 std::vector<int> osize = other->getSize();
486 int i, n = osize.size();
487 for( i=0; i<n; ++i )
488 bsize *= osize[i];
489
490// std::cout << "use block start: " << (char *) ( &_items[0] + (&(*other)( pos ) - other->_start ) ) << std::endl;
491
492 allocate( -1, -1, -1, -1, true,
493 AllocatorContext( AllocatorStrategy::NotOwner,
494 rc_ptr<DataSource>( new BufferDataSource
495 ( (char *) &other->_items[0],
496 bsize ) ) ) );
497
498 // fix offsets
499 blitz::TinyVector<int, Volume<T>::DIM_MAX> dims;
500 n = VolumeProxy<T>::_size.size();
501 for(i=0; i<n; ++i )
502 dims[i] = VolumeProxy<T>::_size[i];
503 for( ; i<Volume<T>::DIM_MAX; ++i )
504 dims[i] = 1;
505 _start = &(*other)( pos );
506 _blitz.reference
507 ( blitz::Array<T,Volume<T>::DIM_MAX>
508 ( _start,
509 dims,
510 other->_blitz.stride(),
511 blitz::GeneralArrayStorage<Volume<T>::DIM_MAX>
512 ( blitz::shape( 0, 1, 2, 3, 4, 5, 6, 7 ), true ) ) );
513 }
514 else
515 allocate( -1, -1, -1, -1, true, allocContext );
516
517 _updateHeaderFromParent( this );
518 }
519
520
521 // view + buffer (only for IO)
522
523 template < typename T >
525 const Position & size, T* buffer,
526 const std::vector<long> & strides )
527 : VolumeProxy<T>( size ),
528 _items( (long) Position4Di::size_num_elements( size ), buffer ),
529 _refvol( other ),
530 _pos( pos ),
531 _referential( other->referential() )
532 {
533 this->header().addBuiltinProperty( "referential", _referential.uuid() );
534 // use a unique referential UUID, but keep orientation information
535 UUID uuid;
536 uuid.generate();
537 _referential.setUuid( uuid.toString() );
538
539 allocate( -1, -1, -1, -1, true, allocatorContext(), &strides );
540 }
541
543 /***************************************************************************
544 * Copy Constructor
545 **************************************************************************/
546 template < typename T >
548 : RCObject(),
549 VolumeProxy< T >( other ),
550 _items( other._items ),
551 _start( &_items[0] + ( other._start - &other._items[0] ) ),
552
553 // TODO: test blitz ownership / strides
554 // _blitz = other.blitz;
555 _blitz( _start,
556 other._blitz.shape(),
557 other._blitz.stride(),
558 blitz::GeneralArrayStorage<8>
559 ( blitz::shape( 0, 1, 2, 3, 4, 5, 6, 7 ), true ) ),
560 _refvol( other.refVolume().get() ?
561 new Volume<T>( *other.refVolume() ) : 0 ),
562 _pos( other.posInRefVolume() ),
563 _referential( other.referential() )
564 {
565 this->header().addBuiltinProperty( "referential", _referential.uuid() );
566 if( _refvol.get() ) // view case: the underlying volume is copied.
568 Position4Di pos = other.posInRefVolume();
569 std::vector<int> oldSize(1, -1);
570 allocate( oldSize, true, _refvol->allocatorContext().isAllocated()
571 ? AllocatorContext( AllocatorStrategy::NotOwner,
572 rc_ptr<DataSource>( new BufferDataSource
573 ( (char *) &(*_refvol)( pos[0], pos[1], pos[2], pos[3] ),
577 * sizeof(T) ) ) )
578 : AllocatorContext( other.allocatorContext() ) );
579 if( _refvol->allocatorContext().isAllocated() )
580 {
581 // fix offsets
582 blitz::TinyVector<int, Volume<T>::DIM_MAX> dims;
583 int i, n=VolumeProxy<T>::_size.size();
584 for( i=0; i<n; ++i )
585 dims[i] = VolumeProxy<T>::_size[i];
586 for( ; i<Volume<T>::DIM_MAX; ++i )
587 dims[i] = 1;
588 _blitz.reference
589 ( blitz::Array<T,Volume<T>::DIM_MAX>
590 ( _start,
591 dims,
592 other._blitz.stride(),
593 blitz::GeneralArrayStorage<Volume<T>::DIM_MAX>
594 ( blitz::shape( 0, 1, 2, 3, 5, 6, 7, 8 ), true ) ) );
595 }
596 }
597 }
598
599 template < typename T >
601 {
602 }
603
604//============================================================================
605// M E T H O D S
606//============================================================================
607
608 template < typename T > inline
609 const AllocatorContext& Volume<T>::allocatorContext() const
610 {
611 return _items.allocatorContext();
612 }
613
614 template <typename T> inline
616 {
617 return _refvol;
618 }
619
620 template <typename T> inline
622 {
623 return _pos;
624 }
625
626 template <typename T>
627 inline
629 int l = 0;
630 rc_ptr<Volume<T> > v(const_cast<Volume<T> *>(this));
631 while (!v.isNull()) {
632 l++;
633 v = v->refVolume();
634 }
635 return l;
636 }
637
638 template <typename T>
639 inline
640 int Volume<T>::refLevel(const int level) const {
641 int c = getLevelsCount();
642 int l = level;
643 if (l < 0) {
644 l = c + l;
645 }
646
647 if ((l < 0) && (l >= c)) {
648 throw std::out_of_range("level " + carto::toString(level)
649 + " is out range (" + carto::toString(-c)
650 + ", " + carto::toString(c-1) + ")");
651 }
652
653 return l;
654 }
655
656 template <typename T>
657 inline
659 int l = refLevel(level);
660 int c = 0;
661 rc_ptr<Volume<T> > v(const_cast<Volume<T> *>(this));
662
663 while ((c < l) && (!v.isNull())) {
664 v = v->refVolume();
665 c++;
666 }
667
668 return v;
669 }
670
671 template <typename T>
672 inline
674 const int level) const {
675 int l = refLevel(level);
676 size_t s = this->getSize().size();
677 typename Volume<T>::Position offset(s, 0);
678 int c = 0;
679 rc_ptr<Volume<T> > v(const_cast<Volume<T> *>(this));
680 while ((c < l) && (!v.isNull())) {
681 const Position & pos = v->posInRefVolume();
682
683 for (size_t i = 0; i < s; ++i)
684 offset[i] += pos[i];
685
686 v = v->refVolume();
687 c++;
688 }
689
690 return offset;
691 }
692
693 template <typename T> inline
695 {
696
697 if ( !allocatorContext().isAllocated()
698 || (allocatorContext().accessMode() == AllocatorStrategy::NotOwner) )
699 {
700
701 // Free old buffer
702 _items.free();
703
704 if (_refvol.get())
705 {
706 // Recreate items buffer that reference volume
707 // using correct sizes and position
708 if( _refvol->allocatorContext().isAllocated() )
709 {
710 size_t size = sizeof(T);
711 int i, n = VolumeProxy<T>::_size.size();
712 for( i=0; i<n; ++i )
713 size *= VolumeProxy<T>::_size[i];
714 _items.allocate(
715 0U,
716 AllocatorContext( AllocatorStrategy::NotOwner,
717 rc_ptr<DataSource>( new BufferDataSource
718 ( (char *) &(*(_refvol))( _pos ),
719 size ) ) ) );
720 }
721 else
722 _items.allocate( 0U, allocatorContext() );
723 _start = &_items[0];
724
725 if ( _refvol->allocatorContext().isAllocated() )
726 {
727 // fix offsets
728 blitz::TinyVector<int, Volume<T>::DIM_MAX> dims;
729 int i, n=VolumeProxy<T>::_size.size();
730 for( i=0; i<n; ++i )
731 dims[i] = VolumeProxy<T>::_size[i];
732 for( ; i<Volume<T>::DIM_MAX; ++i )
733 dims[i] = 1;
734 _blitz.reference
735 ( blitz::Array<T,Volume<T>::DIM_MAX>
736 ( _start,
737 dims,
738 _refvol->_blitz.stride(),
739 blitz::GeneralArrayStorage<Volume<T>::DIM_MAX>
740 ( blitz::shape( 0, 1, 2, 3, 4, 5, 6, 7 ), true ) ) );
741 }
742
743 /* copy voxel_size from underlying volume, if any.
744 This should probably be more general, but cannot be applied to all
745 header properties (size, transformations...).
746 WARNING: Moreover here we do not guarantee to keep both voxel_size
747 unique: we point to the same vector of values for now, but it can be
748 replaced (thus, duplicated) by a setProperty().
749 We could use a addBuiltinProperty(), but then the voxel size has to be
750 stored in a fixed location somewhere.
751 */
752 try
753 {
754 carto::Object vs = _refvol->header().getProperty( "voxel_size" );
755 this->header().setProperty( "voxel_size", vs );
756 }
757 catch( ... )
758 {
759 // never mind.
760 }
761 }
762 }
763 }
764
765 template <typename T> inline
767 {
768 if ( pos != _pos )
769 {
770 _pos = pos.toVector();
772 }
773 }
774
775
776 template <typename T> inline
778 if (pos != _pos)
779 {
780 _pos = pos;
781 while( _pos.size() < 4 )
782 _pos.push_back( 0 );
784 }
785 }
786
787 template <typename T> inline
788 void Volume<T>::setRefVolume( const rc_ptr<Volume<T> > & refvol) {
789 if (refvol.get() != _refvol.get()) {
790 _refvol = refvol;
792 }
793 }
794
795 template <typename T> inline
796 std::vector<int> Volume<T>::getBorders() const
797 {
798 std::vector<int> borders( VolumeProxy<T>::_size.size() * 2, 0 );
799 if( _refvol.get() && _refvol->allocatorContext().isAllocated() )
800 {
801 int i, n = VolumeProxy<T>::_size.size();
802 for( i=0; i<n; ++i )
803 borders[i*2 + 1] = _refvol->_size[i] - VolumeProxy<T>::_size[i];
804 for( i=0, n=_pos.size(); i<n; ++i )
805 {
806 borders[i*2] = _pos[i];
807 borders[i*2+1] -= _pos[i];
808 }
809 }
810
811 return borders;
812 }
813
814 template <typename T> inline
815 std::vector<long> Volume<T>::getStrides() const
816 {
817
818 const blitz::TinyVector<BlitzStridesType, Volume<T>::DIM_MAX>& bstrides = _blitz.stride();
819 int d, n = VolumeProxy<T>::_size.size();
820 std::vector<long> strides( n );
821 for (d = 0; d < n; ++d)
822 strides[d] = bstrides[d];
823
824 return strides;
825 }
826
827 template < typename T >
829 {
830 if( &other == this )
831 return *this;
832
833 bool b = Headered::signalsBlocked();
834 if( !b )
836 this->VolumeProxy< T >::operator=( other );
837 // copy buffer, preserving allocator
838 _items.copy( other._items, other.allocatorContext() );
839 _start = &_items[0] + ( other._start - &other._items[0] );
840
841 // TODO: test blitz ownership / strides
842 // _blitz.reference( other.blitz );
843 blitz::TinyVector<long, Volume<T>::DIM_MAX> dims;
844 int i, n = VolumeProxy<T>::_size.size();
845 for( i=0; i<n; ++i )
846 dims[i] = VolumeProxy<T>::_size[i];
847 for( ; i<Volume<T>::DIM_MAX; ++i )
848 dims[i] = 1;
849 _blitz.reference
850 ( blitz::Array<T,Volume<T>::DIM_MAX>
851 ( _start,
852 dims,
853 other._blitz.stride(),
854 blitz::GeneralArrayStorage<Volume<T>::DIM_MAX>
855 ( blitz::shape( 0, 1, 2, 3, 4, 5, 6, 7 ), true ) ) );
856 _refvol = other._refvol;
857 _pos = other._pos;
859
860 initialize();
861
862 if( !b )
863 Headered::blockSignals( false );
864
865 return *this;
866
867 }
868
869 template <typename T>
871 const std::vector<int> & pos )
872 {
873 std::vector<int> size = this->getSize();
874 std::vector<int> osize = source.getSize();
875 int i;
876
877 for( i=0; i<size.size() && i<osize.size(); ++i )
878 {
879 int ip = 0;
880 if( pos.size() > i )
881 ip = pos[i];
882 size[i] = std::min( size[i] - ip, osize[i] );
883 }
884 for( ; i<size.size(); ++i )
885 size[i] = 1;
886
887 line_NDIterator<T> it( &at( pos ), size, this->getStrides() );
888 const_line_NDIterator<T> oit( &source.at( 0 ), size, source.getStrides() );
889 T *p, *pn;
890 const T *op;
891
892 for( ; !it.ended(); ++it, ++oit )
893 {
894 p = &*it;
895 op = &*oit;
896 for( pn=p + it.line_length(); p!=pn;
897 it.inc_line_ptr( p ), oit.inc_line_ptr( op ) )
898 *p = *op;
899 }
900 }
901
902 template <typename T>
904 const std::vector<int> & pos )
905 {
906 copySubVolume( *source, pos );
907 }
908
909 template < typename T >
911 {
912
913 return _blitz.begin();
914
915 }
916
917
918 template < typename T >
920 {
921
922 return _blitz.end();
923
924 }
925
926
927 template < typename T >
929 {
930
931 return _blitz.begin();
932
933 }
934
935
936 template < typename T >
938 {
939
940 return _blitz.end();
941
942 }
943
944
945 template < typename T >
947 {
948
949 // initializing headered stuff
950 this->Headered::initialize();
951
952 // creating size filter
953 std::set< std::string > sizePropertyNames;
954 sizePropertyNames.insert( "sizeX" );
955 sizePropertyNames.insert( "sizeY" );
956 sizePropertyNames.insert( "sizeZ" );
957 sizePropertyNames.insert( "sizeT" );
958 sizePropertyNames.insert( "volume_dimension" );
960 sizeRcPropertyFilter( new PropertyFilter( "size", sizePropertyNames ) );
961
962 // adding size filter to headered and connecting signal to slot
963 Headered::addPropertyFilter( sizeRcPropertyFilter );
964 Headered::connect( sizeRcPropertyFilter->getName(),
965 ::sigc::mem_fun( *this, &Volume< T >::slotSizeChanged ) );
966
967 }
968
969
970 template < typename T >
971 void Volume< T >::allocate( int oldSizeX,
972 int oldSizeY,
973 int oldSizeZ,
974 int oldSizeT,
975 bool allocate,
976 const AllocatorContext& ac,
977 const std::vector<long> *strides )
978 {
979 std::vector<int> oldSize(4);
980 oldSize[0] = oldSizeX;
981 oldSize[1] = oldSizeY;
982 oldSize[2] = oldSizeZ;
983 oldSize[3] = oldSizeT;
984 Volume< T >::allocate( oldSize, allocate, ac, strides );
985 }
986
987
988 template < typename T >
989 void Volume< T >::allocate( const std::vector<int> & oldSize,
990 bool allocate,
991 const AllocatorContext& ac,
992 const std::vector<long> *nstrides )
993 {
994 std::vector<long long int> strides(Volume<T>::DIM_MAX, 0);
995 int i = 0, n = oldSize.size(), nn = VolumeProxy<T>::_size.size();
996
997 unsigned long long int stride_max = 0;
998 unsigned long long int total_len = 0;
999 unsigned long long absstride = 0;
1000 unsigned long long int offset = 0;
1001
1002 if( nstrides )
1003 {
1004 for( ; i<std::min(nstrides->size(), size_t(nn)); ++i )
1005 {
1006 strides[i] = (*nstrides)[i];
1007 absstride = std::abs( strides[i] );
1008 if( absstride > stride_max )
1009 stride_max = absstride;
1010 if( absstride * VolumeProxy<T>::_size[i] > total_len )
1011 total_len = absstride * VolumeProxy<T>::_size[i];
1012 if( strides[i] < 0 )
1013 offset += absstride * ( VolumeProxy<T>::_size[i] - 1 );
1014 }
1015 }
1016
1017 for( ; i<nn; ++i )
1018 {
1019 strides[i] = ( i == 0 ? 1 : VolumeProxy<T>::_size[i-1] * stride_max );
1020 if( strides[i] > stride_max )
1021 stride_max = strides[i];
1022 if( strides[i] * VolumeProxy<T>::_size[i] > total_len )
1023 total_len = strides[i] * VolumeProxy<T>::_size[i];
1024 }
1025 for( ; i<Volume<T>::DIM_MAX; ++i )
1026 strides[i] = ( i == nn ? VolumeProxy<T>::_size[i-1] * stride_max
1027 : strides[i-1] );
1028
1029 if ( total_len * sizeof(T) >
1030 (unsigned long long int) std::numeric_limits< size_t >::max() )
1031 {
1032
1033 throw std::runtime_error
1034 ( std::string( "attempt to allocate a volume which size is greater "
1035 "than allowed by the system (" )
1036 + toString( std::numeric_limits< size_t >::max() ) + " bytes)" );
1037
1038 }
1039
1040 bool no_old = true;
1041 for( i=0; i<n; ++i )
1042 if( oldSize[i] != -1 )
1043 {
1044 no_old = false;
1045 break;
1046 }
1047
1048 if ( !allocate // why !allocate ?
1049 || !_items.allocatorContext().isAllocated()
1050 || no_old )
1051 {
1052 // allocating memory space
1053 _items.free();
1054 if( allocate )
1055 {
1056 _items.allocate( ( size_t ) total_len, ac );
1057 }
1058 }
1059 else if ( oldSize != VolumeProxy<T>::_size
1060 || &ac != &_items.allocatorContext() )
1061 {
1062
1063 // allocating a new memory space
1064 AllocatedVector<T> newItems( ( size_t ) total_len, ac );
1065
1066 std::vector<int> minSize = VolumeProxy<T>::_size;
1067 for( i=0; i<std::min(n, nn); ++i )
1068 if( oldSize[i] < minSize[i] )
1069 minSize[i] = oldSize[i];
1070
1071 // preserving data
1072 int x, y, z, t;
1073 if( newItems.allocatorContext().allocatorType()
1074 != AllocatorStrategy::ReadOnlyMap )
1075 for ( t = 0; t < minSize[3]; t++ )
1076 {
1077
1078 for ( z = 0; z < minSize[2]; z++ )
1079 {
1080
1081 for ( y = 0; y < minSize[1]; y++ )
1082 {
1083
1084 for ( x = 0; x < minSize[0]; x++ )
1085 {
1086 // TODO: handle former strides with oldSize
1087 newItems[ x * strides[0] +
1088 y * strides[1] +
1089 z * ( size_t ) strides[2] +
1090 t * ( size_t ) strides[3] ] =
1091 _items[ x +
1092 y * oldSize[0] +
1093 z * ( size_t ) oldSize[0]
1094 * ( size_t ) oldSize[1] +
1095 t * ( size_t ) oldSize[0] *
1096 ( size_t ) oldSize[1]
1097 * ( size_t ) oldSize[2] ];
1098
1099 }
1100
1101 }
1102
1103 }
1104
1105 }
1106
1107 // copying new data to old one
1108 _items = newItems;
1109
1110 }
1111
1112 blitz::TinyVector<BlitzStridesType, Volume<T>::DIM_MAX> bstrides;
1113 if( nstrides )
1114 {
1115 for( i=0; i<nn; ++i )
1116 bstrides[i] = strides[i];
1117 int n;
1118 for( ; i<Volume<T>::DIM_MAX; ++i )
1119 {
1120 if( i < nn )
1121 n = VolumeProxy<T>::_size[i];
1122 else
1123 n = 1;
1124 bstrides[i] = ( i == 0 ? n : n * stride_max );
1125 if( strides[i] > stride_max )
1126 stride_max = bstrides[i];
1127 }
1128 }
1129
1130 if( allocate )
1131 {
1132 _start = &_items[0] + offset;
1133
1134 // TODO: test blitz ownership / strides
1135 /*
1136 std::cout << "alloc blitz: " << VolumeProxy<T>::_size[0] << ", "
1137 << VolumeProxy<T>::_size[1] << ", "
1138 << VolumeProxy<T>::_size[2] << ", "
1139 << VolumeProxy<T>::_size[3] << std::endl;
1140 */
1141 blitz::TinyVector<int, Volume<T>::DIM_MAX> dims;
1142 for( i=0; i<nn; ++i )
1143 dims[i] = VolumeProxy<T>::_size[i];
1144 for( ; i<Volume<T>::DIM_MAX; ++i )
1145 dims[i] = 1;
1146 if( nstrides)
1147 _blitz.reference( blitz::Array<T,Volume<T>::DIM_MAX>
1148 ( _start,
1149 dims,
1150 bstrides,
1151 blitz::GeneralArrayStorage<Volume<T>::DIM_MAX>
1152 ( blitz::shape( 0, 1, 2, 3, 4, 5, 6, 7 ),
1153 true ) ) );
1154 else
1155 _blitz.reference( blitz::Array<T,Volume<T>::DIM_MAX>
1156 ( _start,
1157 dims,
1158 blitz::GeneralArrayStorage<Volume<T>::DIM_MAX>
1159 ( blitz::shape( 0, 1, 2, 3, 4, 5, 6, 7 ),
1160 true ) ) );
1161 /*
1162 std::cout << &_items[0] << " / " << &_blitz( 0 ) << std::endl;
1163 std::cout << blitz::shape( VolumeProxy<T>::_size[0],
1164 VolumeProxy<T>::_size[1],
1165 VolumeProxy<T>::_size[2],
1166 VolumeProxy<T>::_size[3}] ) << std::endl;
1167 std::cout << "blitz data: " << _blitz.data() << std::endl;
1168 std::cout << "blitz ordering: " << _blitz.ordering() << std::endl;
1169 std::cout << "blitz numEl: " << _blitz.numElements() << std::endl;
1170 std::cout << "blitz strides: " << _blitz.stride() << std::endl;
1171 */
1172 }
1173 else
1174 {
1175 _start = (T*)( 0 ) + offset;
1176 blitz::TinyVector<int, Volume<T>::DIM_MAX> dims;
1177 for( i=0; i<nn; ++i )
1178 dims[i] = VolumeProxy<T>::_size[i];
1179 for( ; i<Volume<T>::DIM_MAX; ++i )
1180 dims[i] = 1;
1181 if( nstrides )
1182 // TODO: test blitz ownership
1183 _blitz.reference( blitz::Array<T,Volume<T>::DIM_MAX>
1184 ( 0,
1185 dims,
1186 bstrides,
1187 blitz::GeneralArrayStorage<Volume<T>::DIM_MAX>
1188 ( blitz::shape( 0, 1, 2, 3, 4, 5, 6, 7 ), true ) ) );
1189 else
1190 // TODO: test blitz ownership / strides
1191 _blitz.reference( blitz::Array<T,Volume<T>::DIM_MAX>
1192 ( 0,
1193 dims,
1194 blitz::GeneralArrayStorage<Volume<T>::DIM_MAX>
1195 ( blitz::shape( 0, 1, 2, 3, 4, 5, 6, 7 ), true ) ) );
1196 }
1197 _referential.ensureOrder( VolumeProxy<T>::_size.size() );
1198
1199 }
1200
1201
1202 template < typename T >
1204 {
1205 if( !allocatorContext().isAllocated() )
1206 {
1207 std::vector<long> strides = getStrides();
1209 &strides );
1210 }
1211 }
1212
1213
1214 template < typename T >
1215 void Volume< T >::slotSizeChanged( const PropertyFilter& propertyFilter )
1216 {
1217
1218 /* std::cout << "Volume< " << DataTypeCode<T>::name()
1219 << " >::slotSizeChanged"
1220 << std::endl; */
1221
1222 std::vector<int> oldSize = VolumeProxy<T>::_size;
1223
1224 if ( propertyFilter.hasOldValue( "sizeX" ) )
1225 {
1226
1227 oldSize[0] =
1228 propertyFilter.getOldValue( "sizeX" )->GenericObject::value< int >();
1229
1230 }
1231 if ( propertyFilter.hasOldValue( "sizeY" ) )
1232 {
1233
1234 oldSize[1] =
1235 propertyFilter.getOldValue( "sizeY" )->GenericObject::value< int >();
1236
1237 }
1238 if ( propertyFilter.hasOldValue( "sizeZ" ) )
1239 {
1240
1241 oldSize[2] =
1242 propertyFilter.getOldValue( "sizeZ" )->GenericObject::value< int >();
1243
1244 }
1245 if ( propertyFilter.hasOldValue( "sizeT" ) )
1246 {
1247
1248 oldSize[3] =
1249 propertyFilter.getOldValue( "sizeT" )->GenericObject::value< int >();
1250
1251 }
1252 /*
1253 std::cout << "old size: " << oldSize[0] << ", " << oldSize[1] << ", "
1254 << oldSize[2] << ", " << oldSize[3] << std::endl;
1255 std::cout << "new size: " << VolumeProxy<T>::_size[0] << ", "
1256 << VolumeProxy<T>::_size[1] << ", "
1257 << VolumeProxy<T>::_size[2] << ", " << VolumeProxy<T>::_size[3]
1258 << std::endl;
1259 */
1260 allocate( oldSize,
1261 _items.allocatorContext().isAllocated(), allocatorContext() );
1262
1263 }
1264
1265
1266 template < typename T >
1268 int sizeY,
1269 int sizeZ,
1270 int sizeT,
1271 bool keepcontents,
1272 const AllocatorContext & ac,
1273 bool alloc,
1274 const std::vector<long> *strides )
1275 {
1276 int oldx = VolumeProxy<T>::_size[0];
1277 int oldy = VolumeProxy<T>::_size[1];
1278 int oldz = VolumeProxy<T>::_size[2];
1279 int oldt = VolumeProxy<T>::_size[3];
1280 VolumeProxy<T>::_size.resize( 4 );
1281 VolumeProxy<T>::_size[0] = sizeX;
1282 VolumeProxy<T>::_size[1] = sizeY;
1283 VolumeProxy<T>::_size[2] = sizeZ;
1284 VolumeProxy<T>::_size[3] = sizeT;
1285 if( keepcontents || ( sizeX == oldx && sizeY == oldy && sizeZ == oldz
1286 && sizeT == oldt ) )
1287 allocate( oldx, oldy, oldz, oldt, alloc, ac, strides );
1288 else
1289 allocate( std::vector<int>(1, -1), alloc, ac, strides );
1290 // emit a signal ?
1291 }
1292
1293 template < typename T >
1295 bool keepcontents,
1296 const AllocatorContext & ac,
1297 bool alloc,
1298 const std::vector<long> *strides )
1299 {
1300 return reallocate( size[0] > 0 ? size[0] : 1,
1301 size[1] > 0 ? size[1] : 1,
1302 size[2] > 0 ? size[2] : 1,
1303 size[3] > 0 ? size[3] : 1,
1304 keepcontents, ac, alloc, strides );
1305 }
1306
1307 template < typename T >
1308 void Volume< T >::reallocate( const std::vector<int> & size,
1309 bool keepcontents,
1310 const AllocatorContext & ac,
1311 bool alloc,
1312 const std::vector<long> *strides )
1313 {
1314 std::vector<int> old = VolumeProxy<T>::_size;
1315
1316 VolumeProxy<T>::_size = size;
1317 while( VolumeProxy<T>::_size.size() < 4 )
1318 VolumeProxy<T>::_size.push_back( 1 );
1319
1328
1329 if( keepcontents || size == old )
1330 allocate( old, alloc, ac, strides );
1331 else
1332 allocate( std::vector<int>(1, -1), alloc, ac, strides );
1333 // emit a signal ?
1334 }
1335
1336
1337 template < typename T >
1338 void Volume< T >::allocateBorders( int bsx, int bsy, int bsz )
1339 {
1340 std::vector<int> border( 3 );
1341 border[0] = bsx;
1342 border[1] = ( bsy < 0 ? bsx : bsy );
1343 border[2] = ( bsz < 0 ? bsx : bsz );
1344
1345 allocateBorders( border );
1346 }
1347
1348
1349 template < typename T >
1350 void Volume< T >::allocateBorders( const std::vector<int> & border )
1351 {
1352 Volume<T> vol_copy = this->copy();
1353
1354 bool has_border = false;
1355 if( !border.empty() )
1356 {
1357 size_t i, n = border.size();
1358 for( i=0; !has_border && i<n; ++i )
1359 if( border[i] != 0 )
1360 has_border = true;
1361 }
1362 // constructBorders will not erase _refvol since it is normally used
1363 // only in constructors.
1364 if( !has_border )
1365 _refvol.reset( 0 );
1366
1367 constructBorders( border, carto::AllocatorContext(), true );
1368 _pos = border;
1369 if( _pos.size() < 4 )
1370 _pos.resize( 4, 0 );
1371
1372 this->copySubVolume( vol_copy );
1373 }
1374
1375
1376 template < typename T >
1377 void Volume< T >::flipToOrientation( const std::string & orient )
1378 {
1379 if( _referential.orientationVector( orient, _referential.order() )
1380 == _referential.axesOrientation() )
1381 // already in the same orientation
1382 return;
1383
1384 blitz::TinyVector<int, Volume<T>::DIM_MAX> dims = _blitz.shape();
1385 blitz::TinyVector<BlitzStridesType, Volume<T>::DIM_MAX>
1386 strides = _blitz.stride();
1387
1388 int i, n = this->getSize().size();
1389 std::vector<float>transl( n, 0.f );
1390
1391 for( i=0; i<n; ++i )
1392 transl[i] = dims[i] - 1;
1394 = referential().toOrientation( orient, transl );
1396 = dynamic_cast<soma::AffineTransformationBase &>( *flipt );
1397 std::unique_ptr<AffineTransformationBase> iflip = flip.inverse();
1398 blitz::TinyVector<BlitzStridesType, Volume<T>::DIM_MAX>
1399 new_strides = strides;
1400 long long offset = 0, old_offset = _start - &_items[0];
1401 long old_stride;
1402 for( i=0; i<n; ++i )
1403 {
1404 std::vector<int> p( n, 0 );
1405 p[i] = 1;
1406 std::vector<int> p1 = iflip->transformVector( p );
1407 new_strides[i] = &at( p1 ) - &at( 0 );
1408 }
1409 std::vector<int> vdims( dims.begin(), dims.end() );
1410 std::vector<int> new_dims = flip.transformVector( vdims );
1411 for( i=0; i<n; ++i )
1412 new_dims[i] = std::abs( new_dims[i] );
1413 blitz::TinyVector<int, Volume<T>::DIM_MAX> new_bdims = dims;
1414 for( i=0; i<n; ++i )
1415 new_bdims[i] = new_dims[i];
1416 for( i=0; i<n; ++i )
1417 {
1418 if( new_strides[i] < 0 )
1419 offset += -new_strides[i] * ( new_dims[i] - 1 );
1420 if( strides[i] < 0 )
1421 old_offset += strides[i] * ( dims[i] - 1 );
1422 }
1423
1424 Object reor_hdr = reorientedHeader( orient );
1425
1426 this->blockSignals( true );
1427
1428 this->header().copyProperties( reor_hdr );
1429
1430 _start = &_items[0] + offset + old_offset;
1431 _blitz.reference(
1432 blitz::Array<T,Volume<T>::DIM_MAX>(
1433 _start,
1434 new_bdims,
1435 new_strides,
1436 blitz::GeneralArrayStorage<Volume<T>::DIM_MAX>
1437 ( blitz::shape( 0, 1, 2, 3, 5, 6, 7, 8 ), true ) ) );
1438 this->blockSignals( false );
1439
1440 // update referential info, generate a new ID
1441 _referential.setOrientation( orient );
1442 if( _referential.isLpiOriented() ) // initial LPI orientation
1443 _referential.setUuid( _referential.lpiReferentialUuid() );
1444 else
1445 {
1446 UUID uuid;
1447 uuid.generate();
1448 _referential.setUuid( uuid.toString() );
1449 }
1450 }
1451
1452
1453 template < typename T >
1455 const std::string & orient, const std::string & force_memory_layout )
1456 {
1457 // calculate strides and dims for asked memory layout
1458 std::vector<int> dims = this->getSize();
1459 int i, n = dims.size();
1460 std::vector<float>transl( n, 0.f );
1461 for( i=0; i<n; ++i )
1462 transl[i] = dims[i] - 1;
1463
1465 = referential().toOrientation( force_memory_layout, transl );
1467 = dynamic_cast<soma::AffineTransformationBase &>( *flipt );
1468
1469 bool change_layout = false;
1470 std::vector<int> new_dims = flip.transformVector( dims );
1471 for( i=0; i<n; ++i )
1472 new_dims[i] = std::abs( new_dims[i] );
1473
1474 long cstride = 1;
1475
1476 std::unique_ptr<AffineTransformationBase> iflip = flip.inverse();
1477 for( i=0; i<n; ++i )
1478 {
1479 std::vector<int> p0( n, 0 );
1480 p0[i] = 1;
1481 p0 = iflip->transformVector( p0 );
1482 long st = &this->at( p0 ) - &this->at( 0 );
1483 if( st != cstride )
1484 {
1485 change_layout = true;
1486 break;
1487 }
1488 cstride *= new_dims[i];
1489 }
1490
1491 if( change_layout )
1492 {
1493
1494 // allocate a new Volume before copying it into this
1495 VolumeRef<T> copy( new_dims );
1496 copy->copyHeaderFrom( this->header() );
1497 copy->referential().setOrientation( force_memory_layout );
1498 copy->referential().setLpiReferential(
1499 this->referential().lpiReferentialUuid() );
1500
1501 // copy data in the new layout
1502 line_NDIterator<T> it( &this->at( 0 ), this->getSize(),
1503 this->getStrides(), true );
1504 T* p, *pp, *dp;
1505 long dstride = 0;
1506 std::vector<int> pos;
1507 std::vector<int> p0;
1508 pos = flip.transform( it.position() );
1509 dp = &copy->at( pos );
1510 p0 = std::vector<int>( n, 0 );
1511 p0[it.line_direction()] = 1;
1512 pos = flip.transform( p0 );
1513 dstride = &copy->at( pos ) - dp;
1514
1515 for( ; !it.ended(); ++it )
1516 {
1517 p = &*it;
1518 pos = flip.transform( it.position() );
1519 dp = &copy->at( pos );
1520
1521 for( pp=p + it.line_length(); p!=pp;
1522 it.inc_line_ptr( p ), dp += dstride )
1523 *dp = *p;
1524 }
1525
1526 // copy back data to this
1527 *this = *copy;
1528 }
1529
1530 // then flip strides to the wanted orientation
1531 this->flipToOrientation( orient );
1532 }
1533
1534
1535 template <typename T>
1536 Object Volume<T>::reorientedHeader( const std::string & orient ) const
1537 {
1538 Object rhdr = Object::value( PropertySet() );
1539 const PropertySet & hdr = this->header();
1540
1541 rhdr->copyProperties( Object::reference( hdr ) );
1542
1543 std::vector<int> dims = this->getSize();
1544 size_t i, n = dims.size();
1545 std::vector<float>transl( n, 0.f );
1546
1547 for( i=0; i<n; ++i )
1548 transl[i] = dims[i] - 1;
1550 = referential().toOrientation( orient, transl );
1552 = dynamic_cast<soma::AffineTransformationBase &>( *flipt );
1553 std::unique_ptr<AffineTransformationBase> iflip = flip.inverse();
1554
1555 dims = flip.transformVector( dims );
1556 for( i=0, n=dims.size(); i<n; ++i )
1557 dims[i] = std::abs( dims[i] );
1558 rhdr->setProperty( "volume_dimension", dims );
1559 if( rhdr->hasProperty( "sizeX" ) )
1560 rhdr->removeProperty( "sizeX" );
1561 if( rhdr->hasProperty( "sizeY" ) )
1562 rhdr->removeProperty( "sizeY" );
1563 if( rhdr->hasProperty( "sizeZ" ) )
1564 rhdr->removeProperty( "sizeZ" );
1565 if( rhdr->hasProperty( "sizeT" ) )
1566 rhdr->removeProperty( "sizeT" );
1567
1568 std::vector<float> vs = this->getVoxelSize();
1569 std::vector<float> rvs = flip.transformVector( vs );
1570 for( i=0, n=rvs.size(); i<n; ++i )
1571 rvs[i] = std::abs( rvs[i] );
1572 rhdr->setProperty( "voxel_size", rvs );
1573
1574 bool is3d = this->referential().is3DOriented( orient );
1575
1576 if( hdr.hasProperty( "transformations" ) )
1577 {
1578 AffineTransformationBase mvs( dims.size() );
1579 AffineTransformationBase rmvs( dims.size() );
1580 for( i=0, n=vs.size(); i<n; ++i )
1581 {
1582 mvs.matrix()(i, i) = vs[i];
1583 rmvs.matrix()(i, i) = 1.f / rvs[i];
1584 }
1585 // affine in mm
1586 AffineTransformationBase iflipmm = mvs * *iflip * rmvs;
1587
1588 std::vector<std::vector<float> > rtrans;
1589 Object transs = hdr.getProperty( "transformations" );
1590 rtrans.reserve( transs->size() );
1591 Object tit = transs->objectIterator();
1592 for(; tit->isValid(); tit->next() )
1593 {
1594 AffineTransformationBase trans( tit->currentValue() );
1595 trans.extendOrder( flip.order() );
1596 // TODO extend both to max order( flip, trans )
1597 // then handle non-3D transforms in header
1598 trans = trans * iflipmm;
1599 if( is3d )
1600 trans.squeezeOrder( 3, true, false );
1601 rtrans.push_back( trans.toVector() );
1602 }
1603 rhdr->setProperty( "transformations", rtrans );
1604 }
1605
1606 if( hdr.hasProperty( "storage_to_memory" ) )
1607 {
1608 AffineTransformationBase
1609 s2m( hdr.getProperty( "storage_to_memory" ) );
1610 s2m.extendOrder( flip.order() );
1611 s2m = flip * s2m;
1612 if( is3d )
1613 s2m.squeezeOrder( 3, true, false );
1614 rhdr->setProperty( "storage_to_memory", s2m.toVector() );
1615 }
1616
1617 if( rhdr->hasProperty( "referential" ) )
1618 {
1619 if( orient == "LPI" ) // initial LPI orientation
1620 rhdr->setProperty( "referential", _referential.lpiReferentialUuid() );
1621 else
1622 rhdr->removeProperty( "referential" );
1623 }
1624
1625 return rhdr;
1626 }
1627
1628
1629 template <typename T>
1630 std::vector<int> Volume<T>::memoryLayoutOrientation() const
1631 {
1632 std::vector<long> strides = this->getStrides();
1633 size_t i, j, n = strides.size();
1634 std::multimap<std::pair<long, bool>, size_t> ordered_strides;
1635 std::vector<int> orient( n, 0 );
1636 std::vector<int> dims = this->getSize();
1637
1638 for( i=0; i<n; ++i )
1639 {
1640 bool several = ( dims[i] > 1 );
1641 ordered_strides.insert(
1642 std::make_pair( std::make_pair( std::abs( strides[i] ), several),
1643 i ) );
1644 }
1645
1646 std::vector<int> aorient = this->referential().axesOrientation();
1647 std::multimap<std::pair<long, bool>, size_t>::const_iterator
1648 im, em = ordered_strides.end();
1649
1650 for( im=ordered_strides.begin(), i=0; im!=em; ++im, ++i )
1651 {
1652 j = ( ( aorient[ im->second ] - 1 ) / 2 ) * 2 + 1;
1653 bool neg = ( aorient[ im->second ] - 1 ) % 2;
1654 if( strides[ im->second] < 0 )
1655 neg = !neg;
1656 if( neg )
1657 ++j;
1658 orient[i] = j;
1659 }
1660
1661 return orient;
1662 }
1663
1664
1665 template <typename T>
1667 {
1668 try
1669 {
1670 Object s2mo = this->header().getProperty( "storage_to_memory" );
1672 std::unique_ptr<AffineTransformationBase> m2s = s2m.inverse();
1673 return this->referential().orientationFromTransform( *m2s );
1674 }
1675 catch( ... )
1676 {
1677 }
1678
1679 std::vector<int> orient( this->getSize().size(), 0 );
1680 return orient;
1681 }
1682
1683
1684//============================================================================
1685// U T I L I T I E S
1686//============================================================================
1687
1688 template <typename T>
1689 Volume<T>* Creator<Volume<T> >::create( Object header,
1690 const AllocatorContext & context,
1691 Object options )
1692 {
1693 std::vector<int> dims( 4, 1 );
1694 bool unalloc = false;
1695 if( !header->getProperty( "volume_dimension", dims ) )
1696 {
1697 header->getProperty( "sizeX", dims[0] );
1698 header->getProperty( "sizeY", dims[1] );
1699 header->getProperty( "sizeZ", dims[2] );
1700 header->getProperty( "sizeT", dims[3] );
1701 }
1702
1703 unsigned n = dims.size();
1704
1705 try
1706 {
1707 Object uao = options->getProperty( "unallocated" );
1708 unalloc = bool( uao->getScalar() );
1709 }
1710 catch( ... )
1711 {
1712 }
1713
1714 std::string orient;
1715 try
1716 {
1717 Object oo = options->getProperty( "orientation" );
1718 orient = oo->getString();
1719 }
1720 catch( ... )
1721 {
1722 }
1723
1725 new soma::AffineTransformationBase( dims.size() ) );
1726 std::vector<int> tdims = dims;
1727
1728 if( !orient.empty() )
1729 {
1730 // dims and borders are given in LPI orientation
1731
1732 Referential ref( dims.size() );
1733 if( orient == "storage" )
1734 {
1735 try
1736 {
1737 // std::cout << "request storage orientation\n";
1738 Object s2mo = header->getProperty( "storage_to_memory" );
1740 // volume will be in storage orientation,
1741 // and ortr will get from LPI orientation to storage one
1743 ortr.reset(
1744 dynamic_cast<soma::AffineTransformationBase *>( t.get() ) );
1745 // determine storage orientation
1746 orient = ref.orientationStr( ref.orientationFromTransform( *ortr ) );
1747 // std::cout << "orient: " << orient << std::endl;
1748 }
1749 catch( ... )
1750 {
1751 }
1752 }
1753 else
1754 {
1755 // ref.setOrientation( orient );
1757 = ref.toOrientation( orient, soma::Transformation::vsub( dims, 1 ) );
1758 ortr.reset(
1759 dynamic_cast<soma::AffineTransformationBase *>( t.get() ) );
1760 }
1761 tdims = ortr->transformVector( dims );
1762 for( unsigned i=0; i<n; ++i )
1763 tdims[i] = std::abs( tdims[i] );
1764 // tdims are in memory orientation
1765 orient = ref.orientationStr( orient );
1766 if( orient == ref.orientationStr( "LPI" ) )
1767 {
1768 // orient is LPI: no need to transform things
1769 orient.clear();
1770 }
1771 }
1772
1773 std::vector<int> borders( 3, 0 );
1774 try {
1775 borders[0] = (int) rint( options->getProperty( "border" )->getScalar() );
1776 borders[1] = borders[0];
1777 borders[2] = borders[0];
1778 } catch( ... ) {}
1779 try {
1780 borders[0] = (int) rint( options->getProperty( "bx" )->getScalar() );
1781 } catch( ... ) {}
1782 try {
1783 borders[1] = (int) rint( options->getProperty( "by" )->getScalar() );
1784 } catch( ... ) {}
1785 try {
1786 borders[2] = (int) rint( options->getProperty( "bz" )->getScalar() );
1787 } catch( ... ) {}
1788
1789 Volume<T> *obj;
1790 if( borders[0] != 0 || borders[1] != 0 || borders[2] != 0 )
1791 {
1792 std::vector<int> big_dims = dims;
1793 big_dims[0] += borders[0] * 2;
1794 big_dims[1] += borders[1] * 2;
1795 big_dims[2] += borders[2] * 2;
1796
1797 big_dims = ortr->transformVector( big_dims );
1798 for( unsigned i=0; i<big_dims.size(); ++i )
1799 big_dims[i] = std::abs( big_dims[i] );
1800 borders = ortr->transformVector( borders );
1801 for( unsigned i=0; i<borders.size(); ++i )
1802 borders[i] = std::abs( borders[i] );
1803
1804 obj = new Volume<T>( big_dims, context, !unalloc );
1805 if( !orient.empty() )
1806 obj->referential().setOrientation( orient );
1807 obj = new Volume<T>( rc_ptr<Volume<T> >( obj ), borders, tdims, context );
1808 }
1809 else
1810 obj = new Volume<T>( tdims, context, !unalloc );
1811
1812 if( !orient.empty() )
1813 {
1814 obj->referential().setOrientation( orient );
1815// // copy header to a temp, unallocated volume
1816// Volume<T> tvol( dims, AllocatorContext( &NullAllocator::singleton() ) );
1817// tvol.header().copyProperties( header );
1818// // then get a properly reoriented header
1819// header = tvol.reorientedHeader( orient );
1820// std::cout << "reoriented header\n";
1821
1822 // set strides orientation to default LPI
1823 obj->flipToOrientation( "LPI" );
1824 }
1825
1826 obj->blockSignals( true );
1827 try
1828 {
1829 obj->copyHeaderFrom( header, false );
1830 }
1831 catch( std::exception & )
1832 {
1833 // not beautiful, but don't crash for that
1834 }
1835 // restore original sizes : temporary too...
1836 obj->blockSignals( false );
1837
1838 return obj;
1839 }
1840
1841 template <typename T>
1842 void Creator<Volume<T> >::setup( Volume<T> & obj, Object header,
1843 const AllocatorContext & context,
1844 Object options )
1845 {
1846 std::vector<int> dims( 4, 1 );
1847 bool unalloc = false, partial = false, keep_allocation = false;
1848 try
1849 {
1850 carto::Object p = options->getProperty( "partial_reading" );
1851 partial = bool( p->getScalar() );
1852 }
1853 catch( ... ) {}
1854 if( !partial )
1855 {
1856 if( !header->getProperty( "volume_dimension", dims ) )
1857 {
1858 header->getProperty( "sizeX", dims[0] );
1859 header->getProperty( "sizeY", dims[1] );
1860 header->getProperty( "sizeZ", dims[2] );
1861 header->getProperty( "sizeT", dims[3] );
1862 }
1863 try
1864 {
1865 carto::Object p = options->getProperty( "unallocated" );
1866 unalloc = bool( p->getScalar() );
1867 }
1868 catch( ... ) {}
1869 try
1870 {
1871 carto::Object p = options->getProperty( "keep_allocation" );
1872 keep_allocation = bool( p->getScalar() );
1873 }
1874 catch( ... ) {}
1875 if( !keep_allocation || !obj.allocatorContext().isAllocated()
1876 || obj.allocatorContext().allocatorType()
1877 != AllocatorStrategy::Unallocated )
1878 obj.reallocate( dims, false, context, !unalloc );
1879 }
1880 else
1881 {
1882 const_cast<AllocatorContext &>( obj.allocatorContext() ).setDataSource
1883 ( context.dataSource() );
1884 // preserve dimensions
1885 dims = obj.getSize();
1886 }
1887 obj.blockSignals( true );
1888 obj.header().copyProperties( header );
1889 if( partial )
1890 {
1891 // restore dimensions
1892 PropertySet & ps = obj.header();
1893 ps.setProperty( "volume_dimension", dims );
1894 ps.setProperty( "sizeX", dims[0] );
1895 ps.setProperty( "sizeY", dims[1] );
1896 ps.setProperty( "sizeZ", dims[2] );
1897 ps.setProperty( "sizeT", dims[3] );
1898 }
1899 obj.blockSignals( false );
1900 }
1901
1902} // namespace carto
1903
1904#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:596
const std::vector< int > & toVector() const
Definition volumebase.h:636
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:585
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:584
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:586
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:583
void allocate(const std::vector< int > &oldSize, bool allocate, const AllocatorContext &allocatorContext, const std::vector< long > *strides=0)
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:580
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()