ISIS Core Library 0.7.2 (api 3.0.0)

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

Go to the documentation of this file.
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