ISIS Core Library 0.7.2 (api 3.0.0)

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

Go to the documentation of this file.
00001 /*
00002     Copyright (C) 2010  reimer@cbs.mpg.de
00003 
00004     This program is free software: you can redistribute it and/or modify
00005     it under the terms of the GNU General Public License as published by
00006     the Free Software Foundation, either version 3 of the License, or
00007     (at your option) any later version.
00008 
00009     This program is distributed in the hope that it will be useful,
00010     but WITHOUT ANY WARRANTY; without even the implied warranty of
00011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012     GNU General Public License for more details.
00013 
00014     You should have received a copy of the GNU General Public License
00015     along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016 
00017 */
00018 
00019 #ifdef _MSC_VER
00020 #pragma warning(disable:4996)
00021 #endif
00022 
00023 #include "sortedchunklist.hpp"
00024 
00026 namespace isis
00027 {
00028 namespace data
00029 {
00030 namespace _internal
00031 {
00032 
00034 // sorting algorithm implementation
00036 SortedChunkList::scalarPropCompare::scalarPropCompare( const util::PropertyMap::KeyType &prop_name ): propertyName( prop_name ) {}
00037 
00038 bool SortedChunkList::posCompare::operator()( const util::fvector3 &posA, const util::fvector3 &posB ) const
00039 {
00040     if ( posA.lexical_less_reverse( posB ) ) { //if chunk is "under" the other - put it there
00041         LOG( Debug, verbose_info ) << "Successfully sorted chunks by in-image position (" << posA << " below " << posB << ")";
00042         return true;
00043     }
00044 
00045     return false;
00046 }
00047 bool SortedChunkList::scalarPropCompare::operator()( const isis::util::PropertyValue &a, const isis::util::PropertyValue &b ) const
00048 {
00049     const util::ValueBase &aScal = *a;
00050     const util::ValueBase &bScal = *b;
00051 
00052     if ( aScal.lt( bScal ) ) {
00053         LOG( Debug, verbose_info ) << "Successfully sorted chunks by " << propertyName << " (" << aScal.toString( false ) << " before " << bScal.toString( false ) << ")";
00054         return true;
00055     } else
00056         return false;
00057 }
00058 
00060 // Chunk operators
00062 SortedChunkList::chunkPtrOperator::~chunkPtrOperator() {}
00063 
00064 
00066 // SortedChunkList implementation
00068 
00069 // constructor
00070 SortedChunkList::SortedChunkList( util::PropertyMap::KeyType comma_separated_equal_props )
00071 {
00072     const std::list< isis::util::PropertyMap::KeyType > p_list = util::stringToList<util::PropertyMap::KeyType>( comma_separated_equal_props, ',' );
00073     equalProps.insert( equalProps.end(), p_list.begin(), p_list.end() );
00074 }
00075 
00076 
00077 // low level finding
00078 boost::shared_ptr<Chunk> SortedChunkList::secondaryFind( const util::PropertyValue &key, SortedChunkList::SecondaryMap &map )
00079 {
00080     const SecondaryMap::iterator found = map.find( key );
00081     return found != map.end() ? found->second : boost::shared_ptr<Chunk>();
00082 }
00083 SortedChunkList::SecondaryMap *SortedChunkList::primaryFind( const util::fvector3 &key )
00084 {
00085     const PrimaryMap::iterator found = chunks.find( key );
00086     return found != chunks.end() ? &found->second : NULL;
00087 }
00088 
00089 // low level insert
00090 std::pair<boost::shared_ptr<Chunk>, bool> SortedChunkList::secondaryInsert( SecondaryMap &map, const Chunk &ch )
00091 {
00092     util::PropertyMap::KeyType propName = map.key_comp().propertyName;
00093 
00094     if( ch.hasProperty( propName ) ) {
00095         //check, if there is already a chunk
00096         boost::shared_ptr<Chunk> &pos = map[ch.propertyValue( propName )];
00097         bool inserted = false;
00098 
00099         //if not. put oures there
00100         if( !pos ) {
00101             pos.reset( new Chunk( ch ) );
00102             inserted = true;
00103         }
00104 
00105         assert( pos ); // here it must have some content
00106         return std::make_pair( pos, inserted );
00107     } else {
00108         LOG( Runtime, warning ) << "Cannot insert chunk. It's lacking the property " << util::MSubject( propName ) << " which is needed for primary sorting";
00109         return std::pair<boost::shared_ptr<Chunk>, bool>( boost::shared_ptr<Chunk>(), false );
00110     }
00111 }
00112 std::pair<boost::shared_ptr<Chunk>, bool> SortedChunkList::primaryInsert( const Chunk &ch )
00113 {
00114     static const util::PropertyMap::PropPath rowVecProb( "rowVec" ), columnVecProb( "columnVec" ), sliceVecProb( "sliceVec" ), indexOriginProb( "indexOrigin" );
00115     LOG_IF( secondarySort.empty(), Debug, error ) << "There is no known secondary sorting left. Chunksort will fail.";
00116     assert( ch.isValid() );
00117     // compute the position of the chunk in the image space
00118     // we dont have this position, but we have the position in scanner-space (indexOrigin)
00119     const util::fvector3 &origin = ch.propertyValue( indexOriginProb ).castTo<util::fvector3>();
00120     // and we have the transformation matrix
00121     // [ rowVec ]
00122     // [ columnVec]
00123     // [ sliceVec]
00124     // [ 0 0 0 1 ]
00125     const util::fvector3 &rowVec = ch.propertyValue( rowVecProb ).castTo<util::fvector3>();
00126     const util::fvector3 &columnVec = ch.propertyValue( columnVecProb ).castTo<util::fvector3>();
00127     const util::fvector3 sliceVec = ch.hasProperty( sliceVecProb ) ?
00128                                     ch.propertyValue( sliceVecProb ).castTo<util::fvector3>() :
00129                                     util::fvector3(
00130                                         rowVec[1] * columnVec[2] - rowVec[2] * columnVec[1],
00131                                         rowVec[2] * columnVec[0] - rowVec[0] * columnVec[2],
00132                                         rowVec[0] * columnVec[1] - rowVec[1] * columnVec[0]
00133                                     );
00134 
00135 
00136     // this is actually not the complete transform (it lacks the scaling for the voxel size), but its enough
00137     const util::fvector3 key( origin.dot( rowVec ), origin.dot( columnVec ), origin.dot( sliceVec ) );
00138     const scalarPropCompare &secondaryComp = secondarySort.top();
00139 
00140     // get the reference of the secondary map for "key" (create and insert a new if neccessary)
00141     SecondaryMap &subMap = chunks.insert( std::make_pair( key, SecondaryMap( secondaryComp ) ) ).first->second;
00142 
00143     // run insert on that
00144     return secondaryInsert( subMap, ch ); // insert ch into the right secondary map
00145 }
00146 
00147 // high level insert
00148 bool SortedChunkList::insert( const Chunk &ch )
00149 {
00150     LOG_IF( secondarySort.empty(), Debug, error ) << "Inserting will fail without any secondary sort. Use chunks.addSecondarySort at least once.";
00151     LOG_IF( !ch.isValid(), Debug, error ) << "You're trying insert an invalid chunk. The missing properties are " << ch.getMissing();
00152     LOG_IF( !ch.isValid(), Debug, error ) << "You should definitively check the chunks validity (use the function Chunk::valid) before calling this funktion. Aborting now..";
00153     assert( ch.isValid() );
00154 
00155     if( !isEmpty() ) {
00156         // compare some attributes of the first chunk and the one which shall be inserted
00157         Chunk &first = *( chunks.begin()->second.begin()->second );
00158 
00159         if ( first.getSizeAsVector() != ch.getSizeAsVector() ) { // if they have different size - do not insert
00160             LOG( Debug, verbose_info )
00161                     << "Ignoring chunk with different size. (" << ch.getSizeAsString() << "!=" << first.getSizeAsString() << ")";
00162             return false;
00163         }
00164 
00165         BOOST_FOREACH( util::PropertyMap::PropPath & ref, equalProps ) { // check all properties which where given to the constructor of the list
00166             // if at least one of them has the property and they are not equal - do not insert
00167             if ( ( first.hasProperty( ref ) || ch.hasProperty( ref ) ) && first.propertyValue( ref ) != ch.propertyValue( ref ) ) {
00168                 LOG( Debug, verbose_info )
00169                         << "Ignoring chunk with different " << ref << ". Is " << util::MSubject( ch.propertyValue( ref ) )
00170                         << " but chunks already in the list have " << util::MSubject( first.propertyValue( ref ) );
00171                 return false;
00172             }
00173         }
00174     } else {
00175         LOG( Debug, verbose_info ) << "Inserting 1st chunk";
00176         std::stack<scalarPropCompare> backup = secondarySort;
00177 
00178         while( !ch.hasProperty( secondarySort.top().propertyName ) ) {
00179             const util::PropertyMap::KeyType temp = secondarySort.top().propertyName;
00180 
00181             if ( secondarySort.size() > 1 ) {
00182                 secondarySort.pop();
00183             } else {
00184                 LOG( Debug, warning )
00185                         << "First chunk is missing the last secondary sort-property fallback (" << util::MSubject( temp ) << "), won't insert.";
00186                 secondarySort = backup;
00187                 return false;
00188             }
00189         }
00190 
00191         LOG( Debug, info )  << "Using " << secondarySort.top().propertyName << " for secondary sorting, determined by the first chunk";
00192     }
00193 
00194     const util::PropertyMap::KeyType &prop2 = secondarySort.top().propertyName;
00195 
00196     std::pair<boost::shared_ptr<Chunk>, bool> inserted = primaryInsert( ch );
00197 
00198     LOG_IF( inserted.first && !inserted.second, Debug, verbose_info )
00199             << "Not inserting chunk because there is already a Chunk at the same position (" << ch.propertyValue( "indexOrigin" ) << ") with the equal property "
00200             << std::make_pair( prop2, ch.propertyValue( prop2 ) );
00201 
00202     LOG_IF(
00203         inserted.first && !inserted.second &&
00204         ch.hasProperty( "source" ) && inserted.first->hasProperty( "source" ) &&
00205         !( ch.propertyValue( "source" ) == inserted.first->propertyValue( "source" ) ),
00206         Debug, verbose_info )
00207             << "The conflicting chunks where " << ch.propertyValue( "source" ).toString( false ) << " and " << inserted.first->propertyValue( "source" ).toString( false );
00208 
00209     return inserted.second;
00210 }
00211 
00212 void SortedChunkList::addSecondarySort( const util::PropertyMap::KeyType &cmp )
00213 {
00214     secondarySort.push( scalarPropCompare( cmp ) );
00215 }
00216 bool SortedChunkList::isEmpty()const
00217 {
00218     return chunks.empty() || chunks.begin()->second.empty(); // if there is no subMap or nothing in the first subMap ... its empty
00219 }
00220 void SortedChunkList::clear()
00221 {
00222     chunks.clear();
00223 }
00224 bool SortedChunkList::isRectangular()
00225 {
00226     if( isEmpty() )return true;
00227 
00228     size_t images = getHorizontalSize();
00229     BOOST_FOREACH( PrimaryMap::reference outer, chunks ) {
00230         if( outer.second.size() != images )
00231             return false;
00232     }
00233     return true;
00234 }
00235 size_t SortedChunkList::getHorizontalSize()
00236 {
00237     if( isEmpty() )return 0;
00238     else return chunks.begin()->second.size();
00239 }
00240 
00241 std::vector< boost::shared_ptr< Chunk > > SortedChunkList::getLookup()
00242 {
00243     LOG_IF( !isRectangular(), Debug, error ) << "Running getLookup on an non rectangular chunk-list is not defined";
00244 
00245     if( !isEmpty() ) {
00246         PrimaryMap::iterator iP = chunks.begin();
00247         const size_t horizontal = chunks.size();
00248         const size_t vertical = iP->second.size();
00249         std::vector< boost::shared_ptr< Chunk > > ret( horizontal * vertical );
00250 
00251         for( size_t h = 0; h < horizontal; h++, iP++ ) { // outer loop iterates horizontaly (through the primary sorting)
00252             assert( iP != chunks.end() );
00253             SecondaryMap::iterator iS = iP->second.begin();
00254 
00255             for( size_t v = 0; v < vertical; v++, iS++ ) { // inner loop iterates verticaly (through the secondary sorting)
00256                 assert( iS != iP->second.end() );
00257                 ret[h + v *horizontal] = iS->second;  // insert horizontally - primary sorting is the fastest running index (read the sorting matrix horizontaly)
00258             }
00259         }
00260 
00261         return ret;
00262     } else
00263         return std::vector< boost::shared_ptr< Chunk > >();
00264 }
00265 
00266 void SortedChunkList::transform( chunkPtrOperator &op )
00267 {
00268     BOOST_FOREACH( PrimaryMap::reference outer, chunks ) {
00269         BOOST_FOREACH( SecondaryMap::reference inner, outer.second ) {
00270             inner.second = op( inner.second );
00271         }
00272     }
00273 }
00274 
00275 
00276 }
00277 }
00278 }