00001
00012 #ifdef _MSC_VER
00013 #include "msdevstudio/MSconfig.h"
00014 #endif
00015
00016 #include "transforms/LogTransform.h"
00017
00018 #include "axes/AxisModelBase.h"
00019 #include "axes/AxisTick.h"
00020
00021 #include <algorithm>
00022 #include <vector>
00023
00024 #include <cmath>
00025 #include <cstdio>
00026
00027 #include <cassert>
00028
00029 #ifdef ITERATOR_MEMBER_DEFECT
00030 using namespace std;
00031 #else
00032 using std::abs;
00033 using std::log10;
00034 using std::pow;
00035 using std::transform;
00036 using std::vector;
00037 #endif
00038
00039 LogTransform::LogTransform ()
00040 : UnaryTransform ( 10 * DBL_EPSILON, DBL_MAX )
00041 {
00042 m_name = "Log";
00043 }
00044
00045 LogTransform::~LogTransform ()
00046 {
00047 }
00048
00049 LogTransform::LogTransform ( const LogTransform & lt )
00050 : UnaryTransform ( lt )
00051 {
00052 }
00053
00054 #ifdef CLONE_DEFECT
00055 TransformBase * LogTransform::clone () const
00056 #else
00057 LogTransform * LogTransform::clone () const
00058 #endif
00059 {
00060 return new LogTransform ( *this );
00061 }
00062
00063 bool
00064 LogTransform::
00065 isLinear () const
00066 {
00067 return false;
00068 }
00069
00070 void LogTransform::transform ( double & x ) const
00071 {
00072 x = x <= DBL_EPSILON ? -DBL_MAX : log10 ( x );
00073 }
00074
00075 void LogTransform::inverseTransform ( double & x ) const
00076 {
00077 x = pow ( 10.0, x );
00078 }
00079
00080 void
00081 LogTransform::
00082 transform ( std::vector < double > & x ) const
00083 {
00084
00085 vector< double >::iterator first = x.begin();
00086 for ( ; first != x.end(); ++first ) {
00087 *first = *first <= DBL_EPSILON ? -DBL_MAX : log10 ( *first );
00088 }
00089
00090
00091
00092
00093
00094
00095
00096 }
00097
00098
00099 void LogTransform::validate ( Range & range ) const
00100 {
00101 double lo = range.low ();
00102 double hi = range.high ();
00103
00104 if ( hi <= 0.0 ) hi = 1.0;
00105
00106 if ( lo <= 0.0 ) lo = range.pos();
00107
00108 range.setLow ( lo );
00109 range.setHigh ( hi );
00110 }
00111
00112
00113 const vector < AxisTick > &
00114 LogTransform::
00115 setTicks ( AxisModelBase & axis )
00116 {
00117 setTickStep( axis );
00118 setFirstTick( axis );
00119
00120 return genTicks( axis );
00121 }
00122
00123 void LogTransform::setTickStep( AxisModelBase & axis )
00124 {
00125 const Range & range = axis.getRange(true);
00126 double low = range.low();
00127 double high = range.high();
00128 double rangeMag = high / low;
00129
00130
00131 double rmag = floor( log10( rangeMag ) );
00132
00133
00134 double pmag = ceil( log10( low ) );
00135
00136
00137
00138 double tmag = floor( rmag / 3.0 );
00139
00140 double tick_step = pow( 10.0, tmag );
00141
00142 axis.setRMag( rmag );
00143 axis.setPMag( pmag );
00144 axis.setTickStep( tick_step );
00145
00146 }
00147
00148 void LogTransform::setFirstTick( AxisModelBase & axis )
00149 {
00150 const Range & range = axis.getRange(true);
00151 double low = range.low();
00152
00153
00154
00155
00156
00157 double pmag = axis.getPMag();
00158 double first_tick = pow( 10.0, pmag );
00159 double tmp = 0.0;
00160 while( ( tmp = prevStep( first_tick, axis )) >= low ) {
00161 first_tick = tmp;
00162 }
00163
00164 axis.setFirstTick( first_tick );
00165 }
00166
00171 inline double FLT_EQUAL( double x, double y )
00172 {
00173 return ( (double)abs( x - y ) <= 2.0 * ( y * FLT_EPSILON + FLT_MIN ) );
00174 }
00175
00179 const vector < AxisTick > &
00180 LogTransform::
00181 genTicks ( AxisModelBase & axis )
00182 {
00183 double ylabel;
00184
00185 int num_ticks = 0;
00186
00187 m_ticks.clear ();
00188
00189
00190 double mag;
00191
00192 char pstr[10];
00193 char labl[10];
00194
00195 double first_tick = axis.getFirstTick();
00196 double tick_step = axis.getTickStep();
00197 double scale_factor = axis.getScaleFactor();
00198 double max_ticks = axis.getMaxTicks();
00199 const Range & range = axis.getRange(true);
00200
00201 double range_low = range.low();
00202 double range_high = range.high();
00203
00204 double last_tick = first_tick;
00205 double tmp = 0.0;
00206 while ( ( tmp = nextStep( last_tick, axis ) ) <= range_high ) {
00207 last_tick = tmp;
00208 }
00209
00210
00211 bool sci_not =
00212 ( floor( log10( last_tick ) ) > 3.0 ) ||
00213 ( floor ( log10 ( first_tick ) ) ) < -3.0;
00214 if( sci_not ) {
00215 sprintf( pstr, "%%1.0fe%%d" );
00216 }
00217
00218 double value = first_tick / tick_step;
00219 bool fresh = true;
00220 while( value <= range_high || FLT_EQUAL( range_high, value ) ) {
00221 if( num_ticks >= max_ticks ) {
00222
00223
00224
00225 return m_ticks;
00226 }
00227
00228 if( !fresh ) {
00229 value = nextStep( value, axis );
00230 } else {
00231 value *= tick_step;
00232 fresh = false;
00233 }
00234
00235 if( value > range_high ) break;
00236 if( sci_not ) {
00237 mag = floor( log10( value ) );
00238 ylabel = value / pow( 10.0, mag );
00239 sprintf( pstr, "%%1.0fe%%d" );
00240 sprintf( labl, pstr, ylabel, static_cast<int>( mag ) );
00241 } else {
00242 ylabel = value;
00243 double tmp = floor( log10( value ) );
00244 if( tmp > 0.0 ) tmp = 0.0;
00245 tmp = fabs( tmp );
00246 sprintf( pstr, "%%1.%df", static_cast<int>( tmp ) );
00247 sprintf( labl, pstr, ylabel );
00248 }
00249
00250 double y = value / scale_factor;
00251 m_ticks.push_back( AxisTick ( y, labl ) );
00252
00253 num_ticks++;
00254 }
00255
00256 if ( num_ticks < 3 )
00257 {
00258
00259 m_ticks.clear();
00260
00261 double xx = (log10(range_high) - log10(range_low)) / 4;
00262 double yy = log10(range_low);
00263
00264 for(int i=1; i<4; i++)
00265 {
00266
00267 value = pow (10.0, xx * i + yy);
00268
00269 if( value > range_high ) continue;
00270
00271 double tmp = floor( log10( value ) );
00272 if( tmp > 0.0 ) tmp = 0.0;
00273 tmp = fabs( tmp );
00274 if (tmp == 0.0)
00275 {
00276 value = floor(value);
00277 }
00278
00279 sprintf( pstr, "%%1.%df", static_cast<int>( tmp ) );
00280 sprintf( labl, pstr, value);
00281
00282 double y = value / scale_factor;
00283
00284 m_ticks.push_back( AxisTick ( y, labl ) );
00285 }
00286 }
00287
00288 return m_ticks;
00289 }
00290
00291 double LogTransform::nextStep ( double current, AxisModelBase & axis )
00292 {
00293 double tick_step = axis.getTickStep();
00294 if( tick_step == 1.0 ) {
00295 int bottom = static_cast<int>( current /
00296 pow( 10.0, floor( log10( current ) ) ) );
00297
00298
00299
00300
00301
00302
00305 switch( bottom ) {
00306 case 1:
00307 current *= 2.0;
00308 break;
00309 case 2:
00310 current /= 2.0;
00311 current *= 5.0;
00312 break;
00313 case 3:
00314 current /= 4.0;
00315 current *= 5.0;
00316 break;
00317 case 4:
00318 case 5:
00319 current *= 2.0;
00320 break;
00321 default:
00322 current *= 2.0;
00323
00324 }
00325 } else {
00326 current *= tick_step;
00327 }
00328 return current;
00329 }
00330
00333 double LogTransform::prevStep ( double current, AxisModelBase & axis )
00334 {
00335 double tick_step = axis.getTickStep();
00336 if( tick_step == 1.0 ) {
00337 int base = static_cast<int>( current /
00338 pow( 10.0, floor( log10( current ) ) ) );
00339
00340
00341
00342
00343
00344
00345 switch( base ) {
00346 case 1:
00347 current /= 2.0;
00348 break;
00349 case 2:
00350 current /= 2.0;
00351 break;
00352 case 4:
00353 current /= 5.0;
00354 current *= 2.0;
00355 break;
00356 case 5:
00357 current /= 5.0;
00358 current *= 2.0;
00359 break;
00360 default:
00361 assert ( false );
00362 }
00363 } else {
00364 current /= tick_step;
00365 }
00366 return current;
00367 }
00368
00369 const Range &
00370 LogTransform::adjustValues ( AxisModelBase & axis, const Range & limit )
00371 {
00372
00373
00374
00375
00376 double mylow, myhigh;
00377
00378
00379
00380
00381
00382
00383
00384 adjustLogValues( axis );
00385 setTickStep( axis );
00386
00387 const Range & init_range = axis.getRange(false);
00388 double low = init_range.low();
00389 double high = init_range.high();
00390
00391 myhigh = mylow = pow( 10.0, axis.getPMag() );
00392
00393
00394
00395 double scale_factor = axis.getScaleFactor();
00396 while( mylow >= low * scale_factor ) {
00397 mylow = prevStep( mylow, axis );
00398 }
00399
00400
00401
00402 while( myhigh <= high * scale_factor ) {
00403 myhigh = nextStep( myhigh, axis );
00404 }
00405
00406
00407
00408 if( myhigh / mylow < 10.0 ) {
00409 mylow = prevStep( mylow, axis );
00410 }
00411
00412
00413
00414 while( myhigh / mylow < 10.0 ) {
00415 myhigh = nextStep( myhigh, axis );
00416 }
00417
00418 myhigh /= scale_factor;
00419 mylow /= scale_factor;
00420
00421 Range new_range ( mylow, myhigh, init_range.pos() );
00422
00423
00424
00425
00426 double new_width = new_range.length();
00427 double init_width = init_range.length();
00428
00429 if ( new_width > init_width * 10 ){
00430
00431 if ( low < 0 ) {
00432 low *= 1.05;
00433 }
00434 else{
00435 low *= 0.95;
00436 }
00437
00438 if ( high < 0 ){
00439 high *= 0.95;
00440 }
00441 else{
00442 high *= 1.05;
00443 }
00444
00445 Range newRange ( low, high, init_range.pos() );
00446 axis.setIntersectRange ( newRange, limit );
00447 return axis.getRange( false );
00448
00449 }
00450
00451 axis.setIntersectRange ( new_range, limit );
00452
00453 return axis.getRange( false );
00454 }
00455
00456
00457 const Range & LogTransform::adjustLogValues ( AxisModelBase & axis )
00458 {
00459 const Range & r = axis.getRange( false );
00460 double low = r.low();
00461 double high = r.high();
00462 double pos = r.pos();
00463
00464 if( low > 0.0 ) return r;
00465
00466 if( pos == high ) {
00467 double l = pos / 10.0;
00468 double h = pos * 10.0;
00469 axis.setRange ( l, h, pos );
00470
00471 return axis.getRange( false );
00472 }
00473 if( pos == DBL_MAX || pos <= 0.0 ) {
00474 axis.setRange ( 0.01, 100.0, 1.0 );
00475 return axis.getRange( false );
00476 }
00477 if ( low <= 0.0 ) axis.setRange ( 0.5 * pos, high, pos );
00478 else axis.setRange ( pos, high, pos );
00479
00480 return axis.getRange( false );
00481 }