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