ISIS Core Library 0.7.2 (api 3.0.0)

/scr/tee1/isis/lib/Core/DataStorage/chunk.cpp

Go to the documentation of this file.
00001 //
00002 // C++ Implementation: chunk
00003 //
00004 // Description:
00005 //
00006 //
00007 // Author: Enrico Reimer<reimer@cbs.mpg.de>, (C) 2009
00008 //
00009 // Copyright: See COPYING file that comes with this distribution
00010 //
00011 //
00012 
00013 #ifdef _MSC_VER
00014 #pragma warning(disable:4996)
00015 #endif
00016 
00017 #include "chunk.hpp"
00018 #include <boost/foreach.hpp>
00019 #include <boost/scoped_ptr.hpp>
00020 
00021 namespace isis
00022 {
00023 namespace data
00024 {
00026 namespace _internal
00027 {
00028 
00029 ChunkBase::ChunkBase ( size_t nrOfColumns, size_t nrOfRows, size_t nrOfSlices, size_t nrOfTimesteps )
00030 {
00031     const size_t idx[] = {nrOfColumns, nrOfRows, nrOfSlices, nrOfTimesteps};
00032     init( idx );
00033     util::Singletons::get<NeededsList<Chunk>, 0>().applyTo( *this );
00034     LOG_IF( NDimensional<4>::getVolume() == 0, Debug, warning )
00035             << "Size " << nrOfTimesteps << "|" << nrOfSlices << "|" << nrOfRows << "|" << nrOfColumns << " is invalid";
00036 }
00037 
00038 ChunkBase::~ChunkBase() { }
00039 
00040 }
00042 
00043 Chunk::Chunk( const ValueArrayReference &src, size_t nrOfColumns, size_t nrOfRows, size_t nrOfSlices, size_t nrOfTimesteps, bool fakeValid ):
00044     _internal::ChunkBase( nrOfColumns, nrOfRows, nrOfSlices, nrOfTimesteps ),
00045     ValueArrayReference( src )
00046 {
00047     assert( ( *this )->getLength() == getVolume() );
00048 
00049     if( fakeValid ) {
00050         setPropertyAs( "indexOrigin", util::fvector3() );
00051         setPropertyAs( "acquisitionNumber", 0 );
00052         setPropertyAs( "voxelSize", util::fvector3( 1, 1, 1 ) );
00053         setPropertyAs( "rowVec", util::fvector3( 1, 0 ) );
00054         setPropertyAs( "columnVec", util::fvector3( 0, 1 ) );
00055         setPropertyAs( "sequenceNumber", ( uint16_t )0 );
00056     }
00057 }
00058 
00059 Chunk Chunk::cloneToNew( size_t nrOfColumns, size_t nrOfRows, size_t nrOfSlices, size_t nrOfTimesteps )const
00060 {
00061     return createByID( getTypeID(), nrOfColumns, nrOfRows, nrOfSlices, nrOfTimesteps );
00062 }
00063 
00064 Chunk Chunk::createByID ( unsigned short ID, size_t nrOfColumns, size_t nrOfRows, size_t nrOfSlices, size_t nrOfTimesteps, bool fakeValid )
00065 {
00066     util::vector4<size_t> newSize( nrOfColumns, nrOfRows, nrOfSlices, nrOfTimesteps );
00067     assert( newSize.product() );
00068     const ValueArrayReference created( ValueArrayBase::createByID( ID, newSize.product() ) );
00069     return  Chunk( created, newSize[0], newSize[1], newSize[2], newSize[3], fakeValid );
00070 }
00071 
00072 bool Chunk::convertToType( short unsigned int ID, scaling_pair scaling )
00073 {
00074     //get a converted ValueArray (will be a cheap copy if no conv was needed)
00075     ValueArrayReference newPtr = asValueArrayBase().convertByID( ID, scaling );
00076 
00077     if( newPtr.isEmpty() ) // if the reference is empty the conversion failed
00078         return false;
00079     else
00080         static_cast<ValueArrayReference &>( *this ) = newPtr; // otherwise replace my own ValueArray with the new one
00081 
00082     return true;
00083 }
00084 
00085 Chunk Chunk::copyByID( short unsigned int ID, scaling_pair scaling ) const
00086 {
00087     Chunk ret = *this; //make copy of the chunk
00088     static_cast<ValueArrayReference &>( ret ) = getValueArrayBase().copyByID( ID, scaling ); // replace its data by the copy
00089     return ret;
00090 }
00091 
00092 size_t Chunk::getBytesPerVoxel()const
00093 {
00094     return getValueArrayBase().bytesPerElem();
00095 }
00096 std::string Chunk::getTypeName()const
00097 {
00098     return getValueArrayBase().getTypeName();
00099 }
00100 unsigned short Chunk::getTypeID()const
00101 {
00102     return getValueArrayBase().getTypeID();
00103 }
00104 
00105 void Chunk::copySlice( size_t thirdDimS, size_t fourthDimS, Chunk &dst, size_t thirdDimD, size_t fourthDimD ) const
00106 {
00107     const size_t idx1[] = {0, 0, thirdDimS, fourthDimS};
00108     const size_t idx2[] = {getSizeAsVector()[0] - 1, getSizeAsVector()[1] - 1, thirdDimS, fourthDimS};
00109     const size_t idx3[] = {0, 0, thirdDimD, fourthDimD};
00110     copyRange( idx1, idx2, dst, idx3 );
00111 }
00112 
00113 void Chunk::copyRange( const size_t source_start[], const size_t source_end[], Chunk &dst, const size_t destination[] ) const
00114 {
00115     LOG_IF( ! isInRange( source_start ), Debug, error )
00116             << "Copy start " << util::vector4<size_t>( source_start )
00117             << " is out of range (" << getSizeAsString() << ") at the source chunk";
00118     LOG_IF( ! isInRange( source_end ), Debug, error )
00119             << "Copy end " << util::vector4<size_t>( source_end )
00120             << " is out of range (" << getSizeAsString() << ") at the source chunk";
00121     LOG_IF( ! dst.isInRange( destination ), Debug, error )
00122             << "Index " << util::vector4<size_t>( destination )
00123             << " is out of range (" << getSizeAsString() << ") at the destination chunk";
00124     const size_t sstart = getLinearIndex( source_start );
00125     const size_t send = getLinearIndex( source_end );
00126     const size_t dstart = dst.getLinearIndex( destination );
00127     getValueArrayBase().copyRange( sstart, send, *dst, dstart );
00128 }
00129 
00130 size_t Chunk::compareRange( const size_t source_start[], const size_t source_end[], const Chunk &dst, const size_t destination[] ) const
00131 {
00132     LOG_IF( ! isInRange( source_start ), Debug, error )
00133             << "memcmp start " << util::vector4<size_t>( source_start )
00134             << " is out of range (" << getSizeAsString() << ") at the first chunk";
00135     LOG_IF( ! isInRange( source_end ), Debug, error )
00136             << "memcmp end " << util::vector4<size_t>( source_end )
00137             << " is out of range (" << getSizeAsString() << ") at the first chunk";
00138     LOG_IF( ! dst.isInRange( destination ), Debug, error )
00139             << "Index " << util::vector4<size_t>( destination )
00140             << " is out of range (" << getSizeAsString() << ") at the second chunk";
00141     LOG( Debug, verbose_info )
00142             << "Comparing range from " << util::vector4<size_t>( source_start ) << " to " << util::vector4<size_t>( source_end )
00143             << " and " << util::vector4<size_t>( destination );
00144     const size_t sstart = getLinearIndex( source_start );
00145     const size_t send = getLinearIndex( source_end );
00146     const size_t dstart = dst.getLinearIndex( destination );
00147     return getValueArrayBase().compare( sstart, send, dst.getValueArrayBase(), dstart );
00148 }
00149 size_t Chunk::compare( const isis::data::Chunk &dst ) const
00150 {
00151     if( getSizeAsVector() == dst.getSizeAsVector() )
00152         return getValueArrayBase().compare( 0, getVolume() - 1, dst.getValueArrayBase(), 0 );
00153     else
00154         return std::max( getVolume(), dst.getVolume() );
00155 }
00156 
00157 
00158 std::pair<util::ValueReference, util::ValueReference> Chunk::getMinMax ( ) const
00159 {
00160     return getValueArrayBase().getMinMax();
00161 }
00162 
00163 scaling_pair Chunk::getScalingTo( unsigned short typeID, autoscaleOption scaleopt )const
00164 {
00165     return getValueArrayBase().getScalingTo( typeID, scaleopt );
00166 }
00167 scaling_pair Chunk::getScalingTo( unsigned short typeID, const std::pair<util::ValueReference, util::ValueReference> &minmax, autoscaleOption scaleopt )const
00168 {
00169     return getValueArrayBase().getScalingTo( typeID, minmax, scaleopt );
00170 }
00171 
00172 Chunk &Chunk::operator=( const Chunk &ref )
00173 {
00174     _internal::ChunkBase::operator=( static_cast<const _internal::ChunkBase &>( ref ) ); //copy the metadate of ref
00175     ValueArrayReference::operator=( static_cast<const ValueArrayReference &>( ref ) ); // copy the reference of ref's data
00176     return *this;
00177 }
00178 
00179 std::list<Chunk> Chunk::autoSplice ( uint32_t acquisitionNumberStride )const
00180 {
00181     if ( !isValid() ) {
00182         LOG( Runtime, error ) << "Cannot splice invalid Chunk (missing properties are " << this->getMissing() << ")";
00183         return std::list<Chunk>();
00184     }
00185 
00186     util::fvector3 offset;
00187     const util::fvector3 voxelSize = propertyValue( "voxelSize" ).castTo<util::fvector3>();
00188     util::fvector3 voxelGap;
00189 
00190     if( hasProperty( "voxelGap" ) )
00191         voxelGap = propertyValue( "voxelGap" ).castTo<util::fvector3>();
00192 
00193     const util::fvector3 distance = voxelSize + voxelGap;
00194     size_t atDim = getRelevantDims() - 1;
00195 
00196     LOG_IF( atDim < data::timeDim && distance[atDim] == 0, Runtime, error ) << "The voxel distance (voxelSize + voxelGap) at the splicing direction (" << atDim << ") is zero. This will likely cause errors in the Images structure.";
00197 
00198     switch( atDim ) { // init offset with the given direction
00199     case rowDim :
00200         offset = this->propertyValue( "rowVec" ).castTo<util::fvector3>();
00201         break;
00202     case columnDim:
00203         offset = this->propertyValue( "columnVec" ).castTo<util::fvector3>();
00204         break;
00205     case sliceDim:
00206 
00207         if( this->hasProperty( "sliceVec" ) ) {
00208             offset = this->propertyValue( "sliceVec" ).castTo<util::fvector3>();
00209         } else {
00210             const util::fvector3 &row = this->propertyValue( "rowVec" ).castTo<util::fvector3>();
00211             const util::fvector3 &column = this->propertyValue( "columnVec" ).castTo<util::fvector3>();
00212             assert( util::fuzzyEqual<float>( row.sqlen(), 1 ) );
00213             assert( util::fuzzyEqual<float>( column.sqlen(), 1 ) );
00214             offset[0] = row[1] * column[2] - row[2] * column[1];
00215             offset[1] = row[2] * column[0] - row[0] * column[2];
00216             offset[2] = row[0] * column[1] - row[1] * column[0];
00217         }
00218 
00219         break;
00220     case timeDim :
00221         LOG_IF( acquisitionNumberStride == 0, Debug, error ) << "Splicing at timeDim without acquisitionNumberStride will very likely make the next reIndex() fail";
00222     }
00223 
00224     // prepare some attributes
00225     const util::fvector3 indexOriginOffset = atDim < data::timeDim ? offset * distance[atDim] : util::fvector3();
00226 
00227     LOG( Debug, info ) << "Splicing chunk at dimenstion " << atDim + 1 << " with indexOrigin stride " << indexOriginOffset << " and acquisitionNumberStride " << acquisitionNumberStride;
00228     std::list<Chunk> ret = splice( ( dimensions )atDim ); // do low level splice - get the chunklist
00229 
00230     std::list<Chunk>::iterator it = ret.begin();
00231     it++;// skip the first one
00232 
00233     for( size_t cnt = 1; it != ret.end(); it++, cnt++ ) { // adapt some metadata in them
00234         util::fvector3 &orig = it->propertyValue( "indexOrigin" ).castTo<util::fvector3>();
00235 
00236         if( orig == ret.front().getPropertyAs<util::fvector3>( "indexOrigin" ) ) { // fix pos if its the same as for the first
00237             LOG( Debug, verbose_info ) << "Origin was " << orig << " will be moved by " << indexOriginOffset << "*"  << cnt;
00238             orig = orig + indexOriginOffset * ( float )cnt;
00239         }
00240 
00241         uint32_t &acq = it->propertyValue( "acquisitionNumber" ).castTo<uint32_t>();//@todo acquisitionTime needs to be fixed as well
00242 
00243         if( acq == ret.front().getPropertyAs<uint32_t>( "acquisitionNumber" ) ) {
00244             LOG( Debug, verbose_info ) << "acquisitionNumber was " << acq << " will be moved by " << acquisitionNumberStride << "*"  << cnt;
00245             acq += acquisitionNumberStride * cnt; //@todo this might cause trouble if we try to insert this chunks into an image
00246         }
00247     }
00248 
00249     return ret;
00250 }
00251 
00252 std::list<Chunk> Chunk::splice ( dimensions atDim )const
00253 {
00254     std::list<Chunk> ret;
00255 
00256     //@todo should be locking
00257     typedef std::vector<ValueArrayReference> ValueArrayList;
00258     const util::FixedVector<size_t, dims> wholesize = getSizeAsVector();
00259     util::FixedVector<size_t, dims> spliceSize;
00260     spliceSize.fill( 1 ); //init size of one chunk-splice to 1x1x1x1
00261     //copy the relevant dimensional sizes from wholesize (in case of sliceDim we copy only the first two elements of wholesize - making slices)
00262     spliceSize.copyFrom( &wholesize[0], &wholesize[atDim] );
00263     //get the spliced ValueArray's (the volume of the requested dims is the split-size - in case of sliceDim it is rows*columns)
00264     const ValueArrayList pointers = this->getValueArrayBase().splice( spliceSize.product() );
00265 
00266     const util::PropertyMap::KeyList lists = this->findLists();
00267     size_t list_idx = 0;
00268 
00269     //create new Chunks from this ValueArray's
00270     BOOST_FOREACH( ValueArrayList::const_reference ref, pointers ) {
00271         ret.push_back( Chunk( ref, spliceSize[0], spliceSize[1], spliceSize[2], spliceSize[3] ) ); //@todo make sure this is only one copy-operation
00272         static_cast<util::PropertyMap &>( ret.back() ) = static_cast<const util::PropertyMap &>( *this ); // copy all props into the splices
00273         BOOST_FOREACH( const util::PropertyMap::KeyType & key, lists ) { // override list-entries in the splices with their respective entries
00274             ret.back().propertyValue( key ) = this->propertyValueAt( key, list_idx );
00275         }
00276         //      std::cout << static_cast<util::PropertyMap &>( ret.back() ) << std::endl;
00277         list_idx++;
00278     }
00279     return ret;
00280 }
00281 
00282 size_t Chunk::useCount() const
00283 {
00284     return getValueArrayBase().useCount();
00285 }
00286 
00287 void Chunk::swapAlong( const dimensions dim ) const
00288 {
00289     const size_t elSize = getBytesPerVoxel();
00290     const util::vector4<size_t> whole_size = getSizeAsVector();
00291 
00292     boost::shared_ptr<uint8_t> swap_ptr = boost::shared_static_cast<uint8_t>( get()->getRawAddress() );
00293     uint8_t *swap_start = swap_ptr.get();
00294     const uint8_t *const swap_end = swap_start + whole_size.product() * elSize;
00295 
00296     size_t block_volume = whole_size.product();
00297 
00298     for( int i = data::timeDim; i >= dim; i-- ) {
00299         assert( ( block_volume % whole_size[i] ) == 0 );
00300         block_volume /= whole_size[i];
00301     }
00302 
00303     assert( block_volume );
00304     block_volume *= elSize;
00305     const size_t swap_volume = block_volume * whole_size[dim];
00306     const boost::scoped_array<uint8_t> buff( new uint8_t[ block_volume ] );
00307 
00308     //iterate over all swap-volumes
00309     for( ; swap_start < swap_end; swap_start += swap_volume ) { //outer loop
00310         // swap each block with the one at the oppsite end of the swap_volume
00311         uint8_t *a = swap_start; //first block
00312         uint8_t *b = swap_start + swap_volume - block_volume; //last block within the swap-volume
00313 
00314         for( ; a < b; a += block_volume, b -= block_volume ) { // grow a, shrink b (inner loop)
00315             memcpy( buff.get(), a, block_volume );
00316             memcpy( a, b, block_volume );
00317             memcpy( b, buff.get(), block_volume );
00318         }
00319 
00320     }
00321 }
00322 
00323 util::PropertyValue &Chunk::propertyValueAt( const util::PropertyMap::KeyType &key, size_t at )
00324 {
00325     std::vector< util::PropertyValue > &vec = propertyValueVec( key );
00326     const size_t cSize = getSizeAsVector()[getRelevantDims() - 1];
00327 
00328     if( vec.size() != cSize ) {
00329         LOG( Debug, info ) << "Resizing sub-property " << key << " to size of the chunk (" << cSize  << ")";
00330         vec.resize( cSize );
00331     }
00332 
00333     return vec.at( at );
00334 }
00335 const util::PropertyValue &Chunk::propertyValueAt( const util::PropertyMap::KeyType &key, size_t at ) const
00336 {
00337     const std::vector< util::PropertyValue > &vec = propertyValueVec( key );
00338     const size_t cSize = getSizeAsVector()[getRelevantDims() - 1];
00339     LOG_IF( vec.size() != cSize, Debug, warning ) << "Sub-property " << key << " does not have the size of the chunk (" << cSize  << ")";
00340     return vec.at( at );
00341 }
00342 
00343 Chunk::iterator Chunk::begin()
00344 {
00345     return asValueArrayBase().beginGeneric();
00346 }
00347 
00348 Chunk::iterator Chunk::end()
00349 {
00350     return asValueArrayBase().endGeneric();
00351 }
00352 Chunk::const_iterator Chunk::begin()const
00353 {
00354     return getValueArrayBase().beginGeneric();
00355 }
00356 
00357 Chunk::const_iterator Chunk::end()const
00358 {
00359     return getValueArrayBase().endGeneric();
00360 }
00361 
00362 const util::ValueReference Chunk::getVoxelValue ( size_t nrOfColumns, size_t nrOfRows, size_t nrOfSlices, size_t nrOfTimesteps ) const
00363 {
00364     const size_t idx[] = {nrOfColumns, nrOfRows, nrOfSlices, nrOfTimesteps};
00365 
00366     if ( !isInRange( idx ) ) {
00367         LOG( Debug, isis::error )
00368                 << "Index " << util::vector4<size_t>( idx ) << nrOfTimesteps
00369                 << " is out of range (" << getSizeAsString() << ")";
00370     }
00371 
00372     return begin()[getLinearIndex( idx )];
00373 }
00374 void Chunk::setVoxelValue ( const util::ValueReference &val, size_t nrOfColumns, size_t nrOfRows, size_t nrOfSlices, size_t nrOfTimesteps )
00375 {
00376     const size_t idx[] = {nrOfColumns, nrOfRows, nrOfSlices, nrOfTimesteps};
00377 
00378     if ( !isInRange( idx ) ) {
00379         LOG( Debug, isis::error )
00380                 << "Index " << util::vector4<size_t>( idx ) << nrOfTimesteps
00381                 << " is out of range (" << getSizeAsString() << ")";
00382     }
00383 
00384     begin()[getLinearIndex( idx )] = val;
00385 }
00386 
00387 
00388 }
00389 }