ISIS Core Library 0.7.2 (api 3.0.0)

/scr/tee1/isis/lib/Core/DataStorage/numeric_convert.hpp

Go to the documentation of this file.
00001 #ifndef NUMERIC_CONVERT_HPP
00002 #define NUMERIC_CONVERT_HPP
00003 
00004 #include <limits>
00005 #include <assert.h>
00006 #include <boost/mpl/bool.hpp>
00007 #include <boost/type_traits/is_arithmetic.hpp>
00008 #include "common.hpp"
00009 #include "valuearray.hpp"
00010 
00011 
00012 namespace isis
00013 {
00014 namespace data
00015 {
00016 enum autoscaleOption;
00017 API_EXCLUDE_BEGIN
00019 namespace _internal
00020 {
00021 
00022 template<typename T> T round_impl( double x, boost::mpl::bool_<true> )
00023 {
00024     const double ret( x < 0 ? x - 0.5 : x + 0.5 );
00025     return static_cast<T>( ret );
00026 }
00027 template<typename T> T round_impl( double x, boost::mpl::bool_<false> )
00028 {
00029     return static_cast<T>( x ); //@todo find a proper way to round from double to floating point (with range check !!)
00030 }
00031 template<typename T> T round( double x )
00032 {
00033     BOOST_MPL_ASSERT( ( boost::is_arithmetic<T> ) );
00034     return round_impl<T>( x, boost::mpl::bool_<std::numeric_limits<T>::is_integer>() ); //we do use overloading intead of (forbidden) partial specialization
00035 }
00036 
00037 template<typename SRC, typename DST> void numeric_convert_impl( const SRC *src, DST *dst, size_t count, double scale, double offset )
00038 {
00039     LOG( Runtime, info )
00040             << "using generic scaling convert " << ValueArray<SRC>::staticName() << "=>" << ValueArray<DST>::staticName()
00041             << " with scale/offset " << std::fixed << scale << "/" << offset;
00042 
00043     for ( size_t i = 0; i < count; i++ ) {
00044         dst[i] = round<DST>( src[i] * scale + offset );
00045     }
00046 }
00047 
00048 template<typename SRC, typename DST> void numeric_convert_impl( const SRC *src, DST *dst, size_t count )
00049 {
00050     LOG( Runtime, info ) << "using generic convert " << ValueArray<SRC>::staticName() << " => " << ValueArray<DST>::staticName() << " without scaling";
00051 
00052     for ( size_t i = 0; i < count; i++ )
00053         dst[i] = round<DST>( src[i] );
00054 }
00055 template<typename SRC, typename DST> void numeric_convert_impl( const std::complex<SRC> *src, std::complex<DST> *dst, size_t count, double /*scale*/, double /*offset*/ )
00056 {
00057     LOG( Debug, error ) << "complex conversion with scaling is not yet supportet";
00058     numeric_convert_impl( src, dst, count );
00059 }
00060 
00061 template<typename T> void numeric_copy_impl( const T *src, T *dst, size_t count )
00062 {
00063     LOG( Runtime, info )    << "using memcpy-copy of " << ValueArray<T>::staticName() << " without scaling";
00064     memcpy( dst, src, count * sizeof( T ) );
00065 }
00066 template<typename T> void numeric_copy_impl( const T *src, T *dst, size_t count, double scale, double offset )
00067 {
00068     LOG( Runtime, info )    << "using generic scaling copy of " << ValueArray<T>::staticName() << " with scale/offset " << std::fixed << scale << "/" << offset;
00069 
00070     for ( size_t i = 0; i < count; i++ )
00071         dst[i] = src[i] * scale + offset;
00072 }
00073 
00074 #ifdef ISIS_USE_LIBOIL
00075 #define DECL_CONVERT(SRC_TYPE,DST_TYPE)        template<> void numeric_convert_impl<SRC_TYPE,DST_TYPE>( const SRC_TYPE *src, DST_TYPE *dst, size_t count )
00076 #define DECL_SCALED_CONVERT(SRC_TYPE,DST_TYPE) template<> void numeric_convert_impl<SRC_TYPE,DST_TYPE>( const SRC_TYPE *src, DST_TYPE *dst, size_t count, double scale, double offset )
00077 // storage class for explicit specilisations is not allowed (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#605)
00078 
00079 //>>s32
00080 DECL_CONVERT( float, int32_t );
00081 DECL_CONVERT( double, int32_t );
00082 DECL_CONVERT( uint32_t, int32_t );
00083 DECL_CONVERT( int16_t, int32_t );
00084 DECL_CONVERT( uint16_t, int32_t );
00085 DECL_CONVERT( int8_t, int32_t );
00086 DECL_CONVERT( uint8_t, int32_t );
00087 
00088 //>>u32
00089 //DECL_CONVERT(float,uint32_t); conversion to u32 is broken (https://bugs.freedesktop.org/show_bug.cgi?ID=16524)
00090 //DECL_CONVERT(double,uint32_t);
00091 DECL_CONVERT( int32_t, uint32_t );
00092 //DECL_CONVERT(int16_t,uint32_t); ** Not available in liboil - but should be imho
00093 DECL_CONVERT( uint16_t, uint32_t );
00094 //DECL_CONVERT(int8_t,uint32_t); ** Not available in liboil - but should be imho
00095 DECL_CONVERT( uint8_t, uint32_t );
00096 
00097 //>>s16
00098 DECL_CONVERT( float, int16_t );
00099 DECL_CONVERT( double, int16_t );
00100 DECL_CONVERT( int32_t, int16_t );
00101 DECL_CONVERT( uint32_t, int16_t );
00102 DECL_CONVERT( uint16_t, int16_t );
00103 DECL_CONVERT( int8_t, int16_t );
00104 DECL_CONVERT( uint8_t, int16_t );
00105 
00106 //>>u16
00107 DECL_CONVERT( float, uint16_t );
00108 DECL_CONVERT( double, uint16_t );
00109 DECL_CONVERT( int32_t, uint16_t );
00110 DECL_CONVERT( uint32_t, uint16_t );
00111 DECL_CONVERT( int16_t, uint16_t );
00112 //DECL_CONVERT(int8_t,uint16_t); ** Not available in liboil - but should be imho
00113 DECL_CONVERT( uint8_t, uint16_t );
00114 
00115 //>>s8
00116 DECL_CONVERT( float, int8_t );
00117 DECL_CONVERT( double, int8_t );
00118 DECL_CONVERT( int32_t, int8_t );
00119 DECL_CONVERT( uint32_t, int8_t );
00120 DECL_CONVERT( int16_t, int8_t );
00121 DECL_CONVERT( uint16_t, int8_t );
00122 DECL_CONVERT( uint8_t, int8_t );
00123 
00124 //>>u8
00125 DECL_CONVERT( float, uint8_t );
00126 DECL_CONVERT( double, uint8_t );
00127 DECL_CONVERT( int32_t, uint8_t );
00128 DECL_CONVERT( uint32_t, uint8_t );
00129 DECL_CONVERT( int16_t, uint8_t );
00130 DECL_CONVERT( uint16_t, uint8_t );
00131 DECL_CONVERT( int8_t, uint8_t );
00132 
00133 //>>f32
00134 DECL_CONVERT( double, float );
00135 DECL_CONVERT( int32_t, float );
00136 DECL_CONVERT( uint32_t, float );
00137 DECL_CONVERT( int16_t, float );
00138 DECL_CONVERT( uint16_t, float );
00139 DECL_CONVERT( int8_t, float );
00140 DECL_CONVERT( uint8_t, float );
00141 
00142 //>>f64
00143 DECL_CONVERT( float, double );
00144 DECL_CONVERT( int32_t, double );
00145 DECL_CONVERT( uint32_t, double );
00146 DECL_CONVERT( int16_t, double );
00147 DECL_CONVERT( uint16_t, double );
00148 DECL_CONVERT( int8_t, double );
00149 DECL_CONVERT( uint8_t, double );
00150 
00151 //scale>>s32
00152 DECL_SCALED_CONVERT( float, int32_t );
00153 DECL_SCALED_CONVERT( double, int32_t );
00154 
00155 //scale>>u32
00156 //DECL_SCALED_CONVERT(float,uint32_t); conversion to u32 is broken (https://bugs.freedesktop.org/show_bug.cgi?ID=16524)
00157 //DECL_SCALED_CONVERT(double,uint32_t);
00158 
00159 //scale>>s16
00160 DECL_SCALED_CONVERT( float, int16_t );
00161 DECL_SCALED_CONVERT( double, int16_t );
00162 
00163 //scale>>u16
00164 DECL_SCALED_CONVERT( float, uint16_t );
00165 DECL_SCALED_CONVERT( double, uint16_t );
00166 
00167 //scale>>s8
00168 DECL_SCALED_CONVERT( float, int8_t );
00169 DECL_SCALED_CONVERT( double, int8_t );
00170 
00171 //scale>>u8
00172 DECL_SCALED_CONVERT( float, uint8_t );
00173 DECL_SCALED_CONVERT( double, uint8_t );
00174 
00175 //scale>>f32
00176 DECL_SCALED_CONVERT( int32_t, float );
00177 DECL_SCALED_CONVERT( uint32_t, float );
00178 DECL_SCALED_CONVERT( int16_t, float );
00179 DECL_SCALED_CONVERT( uint16_t, float );
00180 DECL_SCALED_CONVERT( int8_t, float );
00181 DECL_SCALED_CONVERT( uint8_t, float );
00182 
00183 //scale>>f64
00184 DECL_SCALED_CONVERT( int32_t, double );
00185 DECL_SCALED_CONVERT( uint32_t, double );
00186 DECL_SCALED_CONVERT( int16_t, double );
00187 DECL_SCALED_CONVERT( uint16_t, double );
00188 DECL_SCALED_CONVERT( int8_t, double );
00189 DECL_SCALED_CONVERT( uint8_t, double );
00190 
00191 #undef DECL_CONVERT
00192 #undef DECL_SCALED_CONVERT
00193 #endif //ISIS_USE_LIBOIL
00194 
00195 }
00197 API_EXCLUDE_END
00215 template<typename SRC, typename DST> std::pair<double, double>
00216 getNumericScaling( const util::ValueBase &min, const util::ValueBase &max, autoscaleOption scaleopt = autoscale )
00217 {
00218     double scale = 1.0;
00219     double offset = 0.0;
00220     bool doScale = ( scaleopt != noscale && std::numeric_limits<DST>::is_integer ); //only do scale if scaleopt!=noscale and the target is an integer (scaling into float is useless)
00221 
00222     if ( scaleopt == autoscale && std::numeric_limits<SRC>::is_integer ) {
00223         LOG( Debug, verbose_info ) << "Won't upscale, because the source datatype is discrete (" << util::Value<SRC>::staticName() << ")";
00224         scaleopt = noupscale; //dont scale up if SRC is an integer
00225     }
00226 
00227     if ( doScale ) {
00228         const DST domain_min = std::numeric_limits<DST>::min();//negative value domain of this dst [min .. -1]
00229         const DST domain_max = std::numeric_limits<DST>::max();//positive value domain of this dst [0 .. max]
00230         double minval, maxval;
00231         minval = min.as<double>();
00232         maxval = max.as<double>();
00233         assert( minval <= maxval );
00234         LOG( Debug, info ) << "src Range:" << minval << "=>" << maxval;
00235         LOG( Debug, info ) << "dst Domain:" << static_cast<double>( domain_min ) << "=>" << static_cast<double>( domain_max );
00236         assert( domain_min < domain_max );//we also should assume this
00237 
00238         //set offset for src
00239         //if all src is completly on positive domain, or if there is no negative domain use minval
00240         //else if src is completly on negative dmain, or if there is no positive domain use maxval
00241         //elsewise leave it at 0 and scale both sides
00242         if ( minval > 0 || !domain_min ) {
00243             //          if ( ( maxval - domain_max ) > 0 ) // if the values completely fit into the domain we dont have to offset them
00244             offset = -minval;
00245         } else if ( ( 0 - maxval ) > 0 || !domain_max ) {
00246             //          if ( ( domain_min - minval ) > 0  ) // if the values completely fit into the domain we dont have to offset them
00247             offset = -maxval;
00248         }
00249 
00250         //calculate range of values which will be on postive/negative domain when offset is applied
00251         const double range_max = maxval + offset; //allways >=0
00252         const double range_min = minval + offset; //allways <=0
00253         //set scaling factor to fit src-range into dst domain
00254         //some compilers dont make x/0 = inf, so we use std::numeric_limits<double>::max() instead, in this case
00255         const double scale_max =
00256             range_max != 0 ? domain_max / range_max :
00257             std::numeric_limits<double>::max();
00258         const double scale_min =
00259             range_min != 0 ? domain_min / range_min :
00260             std::numeric_limits<double>::max();
00261         scale = std::min( scale_max ? scale_max : std::numeric_limits<double>::max(), scale_min ? scale_min : std::numeric_limits<double>::max() );//get the smaller scaling factor which is not zero so the bigger range will fit into his domain
00262 
00263         if ( scaleopt == noupscale && scale > 1 ) {
00264             LOG( Runtime, info ) << "upscale not given, clamping scale " << scale << " to 1";
00265             scale = 1;
00266         }
00267 
00268         if( scale == 1 ) {
00269             if( ( minval - domain_min ) > 0 && ( domain_max - maxval ) > 0 )
00270                 offset = 0; // if the source does fit into the domain, and we do not scale - we wont need an offset
00271         } else
00272             offset *= scale;//calc offset for dst
00273     }
00274 
00275     return std::make_pair( scale, offset );
00276 }
00277 
00294 template<typename SRC, typename DST> void numeric_convert( const SRC *src, DST *dst, size_t size, const double scale, const double offset )
00295 {
00296     if ( ( scale != 1. || offset ) )
00297         _internal::numeric_convert_impl( src, dst, size, scale, offset );
00298     else
00299         _internal::numeric_convert_impl( src, dst, size );
00300 }
00301 template<typename T> void numeric_copy( const T *src, T *dst, size_t size )
00302 {
00303     _internal::numeric_copy_impl<T>( src, dst, size );
00304 }
00305 
00306 }
00307 }
00308 
00309 
00310 #endif // NUMERIC_CONVERT_HPP