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