ISIS Core Library 0.7.2 (api 3.0.0)
|
00001 /* 00002 <one line to give the program's name and a brief idea of what it does.> 00003 Copyright (C) <year> <name of author> 00004 00005 This program is free software: you can redistribute it and/or modify 00006 it under the terms of the GNU General Public License as published by 00007 the Free Software Foundation, either version 3 of the License, or 00008 (at your option) any later version. 00009 00010 This program is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License 00016 along with this program. If not, see <http://www.gnu.org/licenses/>. 00017 00018 */ 00019 00020 #ifdef _MSC_VER 00021 #pragma warning(disable:4800 4996) 00022 #endif 00023 00024 #include "valuearray_converter.hpp" 00025 00026 #include "valuearray_base.hpp" 00027 #include "numeric_convert.hpp" 00028 #include "../CoreUtils/types.hpp" 00029 #include <boost/mpl/for_each.hpp> 00030 #include <boost/type_traits/is_arithmetic.hpp> 00031 #include <boost/mpl/and.hpp> 00032 00033 #ifdef ISIS_USE_LIBOIL 00034 #include <liboil/liboil.h> 00035 #endif 00036 00037 // @todo we need to know this for lexical_cast (toString) 00038 #include <boost/date_time/gregorian/gregorian.hpp> 00039 #include <boost/date_time/posix_time/posix_time.hpp> 00040 00042 namespace isis 00043 { 00044 namespace data 00045 { 00046 API_EXCLUDE_BEGIN 00047 namespace _internal 00048 { 00049 00050 size_t getConvertSize( const ValueArrayBase &src, const ValueArrayBase &dst ) 00051 { 00052 00053 LOG_IF( src.getLength() > dst.getLength(), Runtime, error ) << "The " << src.getLength() << " elements of src wont fit into the destination. Will only convert " << dst.getLength() << " elements."; 00054 LOG_IF( src.getLength() < dst.getLength(), Debug, info ) << "Source is shorter than destination. Will only convert " << src.getLength() << " values"; 00055 return std::min( src.getLength(), dst.getLength() ); 00056 } 00057 static bool checkScale( const scaling_pair &scaling ) 00058 { 00059 assert( !scaling.first.isEmpty() && !scaling.first.isEmpty() ); 00060 const double scale = scaling.first->as<double>(), offset = scaling.second->as<double>(); 00061 LOG_IF( scale < 1, Runtime, warning ) << "Downscaling your values by Factor " << scaling.first->as<double>() << " you might lose information."; 00062 return ( scale != 1 || offset ); 00063 } 00064 00065 template<typename SRC, typename DST> 00066 scaling_pair getScalingToColor( const util::ValueBase &min, const util::ValueBase &max, autoscaleOption scaleopt = autoscale ) 00067 { 00068 double scalMin, scalMax; 00069 00070 if( min.isFloat() || min.isInteger() )scalMin = min.as<double>(); // if min is allready a scalar 00071 else { // of not, determine the scalar min from the elements 00072 const util::color48 minCol = min.as<util::color48>(); //use the "biggest" known color type 00073 scalMin = *std::min_element( &minCol.r, &minCol.b ); // take the lowest value 00074 } 00075 00076 if( max.isFloat() || max.isInteger() )scalMax = max.as<double>(); // if max is allready a scalar 00077 else { // of not, determine the scalar min from the elements 00078 const util::color48 maxCol = max.as<util::color48>(); //use the "biggest" known color type 00079 scalMax = *std::max_element( &maxCol.r, &maxCol.b ); // take the lowest value 00080 } 00081 00082 const std::pair<double, double> scale = getNumericScaling<SRC, DST>( util::Value<double>( scalMin ), util::Value<double>( scalMax ), scaleopt ); 00083 00084 return std::make_pair( 00085 util::ValueReference( util::Value<double>( scale.first ) ), 00086 util::ValueReference( util::Value<double>( scale.second ) ) 00087 ); 00088 } 00089 template<typename SRC, typename DST> 00090 scaling_pair getScalingToComplex( const util::ValueBase &min, const util::ValueBase &max, autoscaleOption scaleopt = autoscale ) 00091 { 00092 double scalMin, scalMax; 00093 00094 if( min.isFloat() || min.isInteger() )scalMin = min.as<double>(); // if min is allready a scalar 00095 else { // of not, determine the scalar min from the elements 00096 const std::complex<double> minCpl = min.as<std::complex<double> >(); //use the "biggest" known color type 00097 scalMin = *std::min_element( &minCpl.real(), &minCpl.imag() ); // take the lowest value 00098 } 00099 00100 if( max.isFloat() || max.isInteger() )scalMax = max.as<double>(); // if max is allready a scalar 00101 else { // of not, determine the scalar min from the elements 00102 const std::complex<double> maxCpl = max.as<std::complex<double> >(); //use the "biggest" known color type 00103 scalMax = *std::max_element( &maxCpl.real(), &maxCpl.imag() ); // take the lowest value 00104 } 00105 00106 const std::pair<double, double> scale = getNumericScaling<SRC, DST>( util::Value<double>( scalMin ), util::Value<double>( scalMax ), scaleopt ); 00107 00108 return std::make_pair( 00109 util::ValueReference( util::Value<double>( scale.first ) ), 00110 util::ValueReference( util::Value<double>( scale.second ) ) 00111 ); 00112 } 00113 00115 // basic numeric conversion class 00117 struct NumConvImplBase { 00118 static scaling_pair getScaling( const util::ValueBase &/*min*/, const util::ValueBase &/*max*/, autoscaleOption /*scaleopt*/ ) { 00119 return scaling_pair( util::ValueReference( util::Value<uint8_t>( 1 ) ), util::ValueReference( util::Value<uint8_t>( 0 ) ) ); 00120 } 00121 }; 00122 // default generic conversion between numeric types 00123 template<typename SRC, typename DST, bool SAME> struct NumConvImpl: NumConvImplBase { 00124 static void convert( const SRC *src, DST *dst, const scaling_pair &scaling, size_t size ) { 00125 checkScale( scaling ); 00126 const double scale = scaling.first->as<double>(), offset = scaling.second->as<double>(); 00127 numeric_convert( src, dst, size, scale , offset ); 00128 } 00129 static scaling_pair getScaling( const util::ValueBase &min, const util::ValueBase &max, autoscaleOption scaleopt ) { 00130 const std::pair<double, double> scale = getNumericScaling<SRC, DST>( min, max, scaleopt ); 00131 return std::make_pair( 00132 util::ValueReference( util::Value<double>( scale.first ) ), 00133 util::ValueReference( util::Value<double>( scale.second ) ) 00134 ); 00135 } 00136 }; 00137 // special generic conversion between equal numeric types (maybe we can copy / scaling will be 1/0) 00138 template<typename T> struct NumConvImpl<T, T, true>: NumConvImplBase { 00139 static void convert( const T *src, T *dst, const scaling_pair &scaling, size_t size ) { 00140 if( checkScale( scaling ) ) { 00141 const double scale = scaling.first->as<double>(), offset = scaling.second->as<double>(); 00142 numeric_convert( src, dst, size, scale , offset ); 00143 } else { // if there is no scaling - we can copy 00144 numeric_copy( src, dst, size ); 00145 } 00146 } 00147 }; 00148 00149 // specialisation for bool 00150 template<typename SRC> struct NumConvImpl<SRC, bool, false>: NumConvImplBase { 00151 static void convert( const SRC *src, bool *dst, const scaling_pair &/*scaling*/, size_t size ) { 00152 while( size-- ) 00153 *( dst++ ) = ( *( src++ ) != 0 ); 00154 } 00155 }; 00156 template<typename DST> struct NumConvImpl<bool, DST, false>: NumConvImplBase { 00157 static void convert( const bool *src, DST *dst, const scaling_pair &/*scaling*/, size_t size ) { 00158 while( size-- ) 00159 *( dst++ ) = *( src++ ) ? 1 : 0 ; 00160 } 00161 }; 00162 00163 00165 // scalar to container functors 00167 template<typename S, typename D> struct copy_op_base { 00168 typedef D dst_type; 00169 typedef typename ValueArray<S>::const_iterator iter_type; 00170 iter_type s; 00171 copy_op_base( iter_type _s ): s( _s ) {} 00172 D getScal() { 00173 return round<D>( *( s++ ) ); 00174 } 00175 }; 00176 template<typename S, typename D> struct scaling_op_base : copy_op_base<S, D> { 00177 double scale, offset; 00178 scaling_op_base( typename copy_op_base<S, D>::iter_type s ): copy_op_base<S, D>( s ) {} 00179 void setScale( scaling_pair scaling ) { 00180 scale = scaling.first->as<double>(); 00181 offset = scaling.second->as<double>(); 00182 } 00183 D getScal() { 00184 return round<D>( *( copy_op_base<S, D>::s++ ) * scale + offset ); 00185 } 00186 }; 00187 00188 00190 // OK, now the converter classes 00192 00193 //default implementation of ValueArrayConverterBase::getScaling - allways returns scaling of 1/0 - should be overridden by real converters if they do use a scaling 00194 scaling_pair ValueArrayConverterBase::getScaling( const isis::util::ValueBase &min, const isis::util::ValueBase &max, autoscaleOption scaleopt ) const 00195 { 00196 return NumConvImplBase::getScaling( min, max, scaleopt ); 00197 } 00198 00199 //Define generator - this can be global because its using convert internally 00200 template<typename SRC, typename DST> class ValueArrayGenerator: public ValueArrayConverterBase 00201 { 00202 public: 00203 void create( boost::scoped_ptr<ValueArrayBase>& dst, const size_t len )const { 00204 LOG_IF( dst.get(), Debug, warning ) << "Creating into existing value " << dst->toString( true ); 00205 ValueArray<DST> *newDat = new ValueArray<DST>( ( DST * )malloc( sizeof( DST )*len ), len ); 00206 dst.reset( newDat ); 00207 } 00208 void generate( const ValueArrayBase &src, boost::scoped_ptr<ValueArrayBase>& dst, const scaling_pair &scaling )const { 00209 //Create new "stuff" in memory 00210 create( dst, src.getLength() ); 00211 assert( dst ); 00212 convert( src, *dst, scaling );//and convert into that 00213 } 00214 }; 00215 void ValueArrayConverterBase::convert( const ValueArrayBase &src, ValueArrayBase &dst, const scaling_pair &/*scaling*/ ) const 00216 { 00217 LOG( Debug, error ) << "Empty conversion was called as conversion from " << src.getTypeName() << " to " << dst.getTypeName() << " this is most likely an error."; 00218 } 00219 00220 00222 // general converter version -- does nothing and returns 1/0 as scaling 00224 template<bool SRC_NUM, bool DST_NUM, typename SRC, typename DST> class ValueArrayConverter : public ValueArrayGenerator<SRC, DST> 00225 { 00226 public: 00227 virtual ~ValueArrayConverter() {} 00228 }; 00229 00231 // trivial version -- for conversion of the same non numeric type (scaling will fail) 00233 template<typename SRC, typename DST> class ValueArrayConverter<false, false, SRC, DST> : public ValueArrayGenerator<SRC, DST> 00234 { 00235 ValueArrayConverter() { 00236 LOG( Debug, verbose_info ) << "Creating trivial copy converter for " << ValueArray<SRC>::staticName(); 00237 }; 00238 public: 00239 static boost::shared_ptr<const ValueArrayConverterBase> get() { 00240 ValueArrayConverter<false, false, SRC, DST> *ret = new ValueArrayConverter<false, false, SRC, DST>; 00241 return boost::shared_ptr<const ValueArrayConverterBase>( ret ); 00242 } 00243 void convert( const ValueArrayBase &src, ValueArrayBase &dst, const scaling_pair &scaling )const { 00244 SRC *dstPtr = &dst.castToValueArray<SRC>()[0]; 00245 const SRC *srcPtr = &src.castToValueArray<SRC>()[0]; 00246 LOG_IF( checkScale( scaling ), Runtime, error ) << "Scaling is ignored when copying data of type " << src.getTypeName() << " to " << dst.getTypeName() ; 00247 memcpy( dstPtr, srcPtr, getConvertSize( src, dst )*src.bytesPerElem() ); 00248 } 00249 virtual ~ValueArrayConverter() {} 00250 }; 00251 00252 00254 // Numeric version -- uses numeric_convert 00256 template<typename SRC, typename DST> class ValueArrayConverter<true, true, SRC, DST> : public ValueArrayGenerator<SRC, DST> 00257 { 00258 ValueArrayConverter() { 00259 LOG( Debug, verbose_info ) << "Creating numeric converter from " << ValueArray<SRC>::staticName() << " to " << ValueArray<DST>::staticName(); 00260 }; 00261 public: 00262 static boost::shared_ptr<const ValueArrayConverterBase> get() { 00263 ValueArrayConverter<true, true, SRC, DST> *ret = new ValueArrayConverter<true, true, SRC, DST>; 00264 return boost::shared_ptr<const ValueArrayConverterBase>( ret ); 00265 } 00266 void convert( const ValueArrayBase &src, ValueArrayBase &dst, const scaling_pair &scaling )const { 00267 const SRC *srcPtr = &src.castToValueArray<SRC>()[0]; 00268 DST *dstPtr = &dst.castToValueArray<DST>()[0]; 00269 NumConvImpl<SRC, DST, boost::is_same<SRC, DST>::value>::convert( srcPtr, dstPtr, scaling, getConvertSize( src, dst ) ); 00270 } 00271 scaling_pair getScaling( const util::ValueBase &min, const util::ValueBase &max, autoscaleOption scaleopt = autoscale )const { 00272 return NumConvImpl<SRC, DST, boost::is_same<SRC, DST>::value >::getScaling( min, max, scaleopt ); 00273 } 00274 virtual ~ValueArrayConverter() {} 00275 }; 00276 00278 // complex to complex version 00280 template<typename SRC, typename DST> class ValueArrayConverter<false, false, std::complex<SRC>, std::complex<DST> > : public ValueArrayGenerator<std::complex<SRC>, std::complex<DST> > 00281 { 00282 ValueArrayConverter() { 00283 LOG( Debug, verbose_info ) 00284 << "Creating complex converter from " 00285 << ValueArray<std::complex<SRC> >::staticName() << " to " << ValueArray<std::complex<DST> >::staticName(); 00286 }; 00287 public: 00288 static boost::shared_ptr<const ValueArrayConverterBase> get() { 00289 ValueArrayConverter<false, false, std::complex<SRC>, std::complex<DST> > *ret = new ValueArrayConverter<false, false, std::complex<SRC>, std::complex<DST> >; 00290 return boost::shared_ptr<const ValueArrayConverterBase>( ret ); 00291 } 00292 void convert( const ValueArrayBase &src, ValueArrayBase &dst, const scaling_pair &scaling )const { 00293 //we do an evil hack here assuming std::complex is POD - at least check if the size of std::complex is reasonable 00294 BOOST_STATIC_ASSERT( sizeof( std::complex<SRC> ) == sizeof( SRC ) * 2 ); 00295 BOOST_STATIC_ASSERT( sizeof( std::complex<DST> ) == sizeof( DST ) * 2 ); 00296 00297 const SRC *sp = &src.castToValueArray<std::complex<SRC> >().begin()->real(); 00298 DST *dp = &dst.castToValueArray<std::complex<DST> >().begin()->real(); 00299 00300 NumConvImpl<SRC, DST, boost::is_same<SRC, DST>::value>::convert( sp, dp, scaling, getConvertSize( src, dst ) * 2 ); 00301 } 00302 scaling_pair getScaling( const util::ValueBase &min, const util::ValueBase &max, autoscaleOption scaleopt = autoscale )const { 00303 return getScalingToComplex<SRC, DST>( min, max, scaleopt ); 00304 } 00305 virtual ~ValueArrayConverter() {} 00306 }; 00307 00309 // numeric to complex version 00311 template<typename SRC, typename DST> class ValueArrayConverter<true, false, SRC, std::complex<DST> > : public ValueArrayGenerator<std::complex<SRC>, std::complex<DST> > 00312 { 00313 ValueArrayConverter() { 00314 LOG( Debug, verbose_info ) 00315 << "Creating converter from scalar " 00316 << ValueArray<SRC>::staticName() << " complex to " << ValueArray<std::complex<DST> >::staticName(); 00317 }; 00318 template<typename BASE> struct num2complex: BASE { 00319 num2complex( typename BASE::iter_type s ): BASE( s ) {} 00320 std::complex<typename BASE::dst_type> operator()() { 00321 return BASE::getScal(); 00322 } 00323 }; 00324 public: 00325 static boost::shared_ptr<const ValueArrayConverterBase> get() { 00326 ValueArrayConverter<true, false, SRC, std::complex<DST> > *ret = new ValueArrayConverter<true, false, SRC, std::complex<DST> >; 00327 return boost::shared_ptr<const ValueArrayConverterBase>( ret ); 00328 } 00329 void convert( const ValueArrayBase &src, ValueArrayBase &dst, const scaling_pair &scaling )const { 00330 00331 size_t size = getConvertSize( src, dst ); 00332 typename ValueArray<SRC>::const_iterator s = src.castToValueArray<SRC>().begin(); 00333 typename ValueArray<std::complex<DST> >::iterator d = dst.castToValueArray<std::complex<DST> >().begin(); 00334 00335 if( checkScale( scaling ) ) { 00336 num2complex<scaling_op_base<SRC, DST> > op( s ); 00337 op.setScale( scaling ); 00338 std::generate_n( d, size, op ); 00339 } else { // if there is no scaling - we can copy 00340 num2complex<copy_op_base<SRC, DST> > op( s ); 00341 std::generate_n( d, size, op ); 00342 } 00343 00344 } 00345 scaling_pair getScaling( const util::ValueBase &min, const util::ValueBase &max, autoscaleOption scaleopt = autoscale )const { 00346 return getScalingToComplex<SRC, DST>( min, max, scaleopt ); 00347 } 00348 virtual ~ValueArrayConverter() {} 00349 }; 00350 00352 // color to color version - using numeric_convert on each color with a global scaling 00354 template<typename SRC, typename DST> class ValueArrayConverter<false, false, util::color<SRC>, util::color<DST> > : public ValueArrayGenerator<util::color<SRC>, util::color<DST> > 00355 { 00356 ValueArrayConverter() { 00357 LOG( Debug, verbose_info ) 00358 << "Creating color converter from " 00359 << ValueArray<util::color<SRC> >::staticName() << " to " << ValueArray<util::color<DST> >::staticName(); 00360 }; 00361 public: 00362 static boost::shared_ptr<const ValueArrayConverterBase> get() { 00363 ValueArrayConverter<false, false, util::color<SRC>, util::color<DST> > *ret = new ValueArrayConverter<false, false, util::color<SRC>, util::color<DST> >; 00364 return boost::shared_ptr<const ValueArrayConverterBase>( ret ); 00365 } 00366 void convert( const ValueArrayBase &src, ValueArrayBase &dst, const scaling_pair &scaling )const { 00367 const SRC *sp = &src.castToValueArray<util::color<SRC> >().begin()->r; 00368 DST *dp = &dst.castToValueArray<util::color<DST> >().begin()->r; 00369 NumConvImpl<SRC, DST, false>::convert( sp, dp, scaling, getConvertSize( src, dst ) * 3 ); 00370 } 00371 scaling_pair getScaling( const util::ValueBase &min, const util::ValueBase &max, autoscaleOption scaleopt = autoscale )const { 00372 return getScalingToColor<SRC, DST>( min, max, scaleopt ); 00373 } 00374 00375 virtual ~ValueArrayConverter() {} 00376 }; 00378 // numeric to color version 00380 template<typename SRC, typename DST> class ValueArrayConverter<true, false, SRC, util::color<DST> > : public ValueArrayGenerator<util::color<SRC>, util::color<DST> > 00381 { 00382 ValueArrayConverter() { 00383 LOG( Debug, verbose_info ) 00384 << "Creating converter from scalar " 00385 << ValueArray<SRC >::staticName() << " to color " << ValueArray<util::color<DST> >::staticName(); 00386 }; 00387 template<typename BASE> struct num2color: BASE { 00388 num2color( typename BASE::iter_type s ): BASE( s ) {} 00389 util::color<typename BASE::dst_type> operator()() { 00390 const typename BASE::dst_type val = BASE::getScal(); 00391 const util::color<typename BASE::dst_type> ret = {val, val, val}; 00392 return ret; 00393 } 00394 }; 00395 00396 public: 00397 static boost::shared_ptr<const ValueArrayConverterBase> get() { 00398 ValueArrayConverter<true, false, SRC, util::color<DST> > *ret = new ValueArrayConverter<true, false, SRC, util::color<DST> >; 00399 return boost::shared_ptr<const ValueArrayConverterBase>( ret ); 00400 } 00401 void convert( const ValueArrayBase &src, ValueArrayBase &dst, const scaling_pair &scaling )const { 00402 size_t size = getConvertSize( src, dst ); 00403 typename ValueArray<SRC>::const_iterator s = src.castToValueArray<SRC>().begin(); 00404 typename ValueArray<util::color<DST> >::iterator d = dst.castToValueArray<util::color<DST> >().begin(); 00405 00406 if( checkScale( scaling ) ) { 00407 num2color<scaling_op_base<SRC, DST> > op( s ); 00408 op.setScale( scaling ); 00409 std::generate_n( d, size, op ); 00410 } else { // if there is no scaling - we can copy 00411 num2color<copy_op_base<SRC, DST> > op( s ); 00412 std::generate_n( d, size, op ); 00413 } 00414 } 00415 scaling_pair getScaling( const util::ValueBase &min, const util::ValueBase &max, autoscaleOption scaleopt = autoscale )const { 00416 return getScalingToColor<SRC, DST>( min, max, scaleopt ); 00417 } 00418 00419 virtual ~ValueArrayConverter() {} 00420 }; 00421 00422 00424 //OK, thats about the foreplay. Now we get to the dirty stuff. 00426 00428 template<typename SRC> struct inner_ValueArrayConverter { 00429 std::map<int, boost::shared_ptr<const ValueArrayConverterBase> > &m_subMap; 00430 inner_ValueArrayConverter( std::map<int, boost::shared_ptr<const ValueArrayConverterBase> > &subMap ): m_subMap( subMap ) {} 00431 template<typename DST> void operator()( DST ) { //will be called by the mpl::for_each in outer_ValueArrayConverter for any DST out of "types" 00432 //create a converter based on the type traits and the types of SRC and DST 00433 boost::shared_ptr<const ValueArrayConverterBase> conv = 00434 ValueArrayConverter<boost::is_arithmetic<SRC>::value, boost::is_arithmetic<DST>::value, SRC, DST>::get(); 00435 //and insert it into the to-conversion-map of SRC 00436 m_subMap.insert( m_subMap.end(), std::make_pair( ValueArray<DST>::staticID, conv ) ); 00437 } 00438 }; 00439 00441 struct outer_ValueArrayConverter { 00442 std::map< int , std::map<int, boost::shared_ptr<const ValueArrayConverterBase> > > &m_map; 00443 outer_ValueArrayConverter( std::map< int , std::map<int, boost::shared_ptr<const ValueArrayConverterBase> > > &map ): m_map( map ) {} 00444 template<typename SRC> void operator()( SRC ) {//will be called by the mpl::for_each in ValueArrayConverterMap() for any SRC out of "types" 00445 boost::mpl::for_each<util::_internal::types>( // create a functor for from-SRC-conversion and call its ()-operator for any DST out of "types" 00446 inner_ValueArrayConverter<SRC>( m_map[ValueArray<SRC>::staticID] ) 00447 ); 00448 } 00449 }; 00450 00451 ValueArrayConverterMap::ValueArrayConverterMap() 00452 { 00453 #ifdef ISIS_USE_LIBOIL 00454 LOG( Debug, info ) << "Initializing liboil"; 00455 oil_init(); 00456 #endif // ISIS_USE_LIBOIL 00457 boost::mpl::for_each<util::_internal::types>( outer_ValueArrayConverter( *this ) ); 00458 LOG( Debug, info ) 00459 << "conversion map for " << size() << " array-types created"; 00460 } 00461 00462 } 00463 API_EXCLUDE_END 00464 } 00465 } 00467