ISIS Core Library 0.7.2 (api 3.0.0)
|
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 }