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