00001
00012 #include "LinearTransform.h"
00013
00014 #include "axes/AxisModelBase.h"
00015 #include "axes/AxisTick.h"
00016
00017 #include <cmath>
00018 #include <cstdio>
00019
00020 using std::abs;
00021 using std::max;
00022 using std::vector;
00023
00028 LinearTransform::LinearTransform ()
00029 : UnaryTransform ( -DBL_MAX, DBL_MAX )
00030 {
00031 m_name = "Linear";
00032 }
00033
00034 LinearTransform::~LinearTransform ()
00035 {
00036 }
00037
00038 LinearTransform::LinearTransform ( const LinearTransform & lt )
00039 : UnaryTransform ( lt )
00040 {
00041 }
00042
00043 #ifdef CLONE_DEFECT
00044 TransformBase * LinearTransform::clone () const
00045 #else
00046 LinearTransform * LinearTransform::clone () const
00047 #endif
00048 {
00049 return new LinearTransform ( *this );
00050 }
00051
00052 bool
00053 LinearTransform::
00054 isLinear () const
00055 {
00056 return true;
00057 }
00058
00059 void LinearTransform::transform ( double & x ) const
00060 {
00061 }
00062
00063 void LinearTransform::inverseTransform ( double & x ) const
00064 {
00065 }
00066
00067 void
00068 LinearTransform::
00069 transform ( std::vector < double > & x ) const
00070 {
00071 }
00072
00073
00074 void LinearTransform::validate ( Range & range ) const
00075 {
00076
00077 }
00078
00079 const vector < AxisTick > &
00080 LinearTransform::
00081 setTicks ( AxisModelBase & axis )
00082 {
00083 setTickStep( axis );
00084 setFirstTick( axis );
00085
00086 return genTicks( axis );
00087 }
00088
00089 inline double FLT_EQUAL( double x, double y )
00090 {
00091 return ( (double)abs( x - y ) <= 2.0 * ( y * FLT_EPSILON + FLT_MIN ) );
00092 }
00093
00094 void LinearTransform::setTickStep( AxisModelBase & axis )
00095 {
00096 static float goodTicks[] = { 5.0, 4.0, 2.0, 1.0 };
00097 int tickIndex;
00098
00099 const Range & range = axis.getRange(false);
00100 double rangeLength = range.length();
00101
00102 double scale_factor = axis.getScaleFactor();
00103 rangeLength *= scale_factor;
00104 const int MIN_TICKS = 3;
00105
00106
00107 double rmag = floor( log10( rangeLength ) );
00108
00109
00110
00111
00112
00113
00114 if( rangeLength / pow( 10.0, rmag ) < MIN_TICKS ) {
00115 rmag--;
00116 }
00117
00118 axis.setRMag( rmag );
00119
00120 double scalelow = range.low() * scale_factor;
00121 double scalehigh = range.high() * scale_factor;
00122
00123
00124 double pmag = max( floor( log10( abs ( scalehigh ) ) ),
00125 floor( log10( abs ( scalelow ) ) ) );
00126
00127
00128
00129
00130 if( pow( 10.0, pmag ) == scalehigh ||
00131 pow( 10.0, pmag ) == scalelow ) pmag--;
00132
00133 axis.setPMag( pmag );
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143 double tick_step = 0;
00144 for( tickIndex = 0;
00145 rangeLength /
00146 ( tick_step = goodTicks[tickIndex] * pow( 10.0, rmag ) )
00147 < MIN_TICKS;
00148 tickIndex++ ){};
00149
00150 axis.setTickStep( tick_step );
00151 }
00152
00153
00154 void LinearTransform::setFirstTick( AxisModelBase & axis )
00155 {
00156 const Range & range = axis.getRange(true);
00157 double low = range.low();
00158 double tick_step = axis.getTickStep();
00159
00160
00161
00162
00163
00164 axis.setFirstTick( ceil( low / tick_step ) * tick_step );
00165 }
00166
00167
00170 const vector < AxisTick > &
00171 LinearTransform::
00172 genTicks( AxisModelBase & axis )
00173 {
00174 double y = 0.0, ylabel;
00175
00176 int num_ticks = 0;
00177 m_ticks.clear();
00178 double pmag = axis.getPMag();
00179 double rmag = axis.getRMag();
00180 double first_tick = axis.getFirstTick();
00181 double tick_step = axis.getTickStep();
00182 double scale_factor = axis.getScaleFactor();
00183 double max_ticks = axis.getMaxTicks();
00184
00185
00186
00187
00188
00189
00190
00191 bool use_pmag = abs ( pmag ) > 3.0;
00192
00193 axis.setUsePMag ( use_pmag );
00194
00195 char pstr[10];
00196 char labl[10];
00197
00198 int decimals = 0;
00199
00200
00201
00202
00203
00204 if ( use_pmag ) {
00205
00206
00207
00208
00209 decimals = static_cast<int>( pmag - rmag );
00210
00211
00212 if( !decimals ) decimals++;
00213
00214 } else {
00215
00216 if( rmag > 0.0 ){
00217
00218
00219
00220
00221 decimals = 0;
00222
00223 } else {
00224
00225
00226
00227
00228
00229 decimals = static_cast<int>( abs( rmag ) );
00230
00231 }
00232
00233 }
00234
00235
00236
00237 if (decimals < 0) {
00238 decimals = 0;
00239 }
00240
00241 sprintf( pstr, "%%1.%df", decimals );
00242
00243 y = first_tick;
00244 const Range & range = axis.getRange(false);
00245 double range_high = range.high();
00246 range_high *= scale_factor;
00247 range_high += 100. * DBL_EPSILON;
00248
00249
00250 while( y <= range_high ) {
00251
00252 if( num_ticks >= max_ticks ) {
00253
00254
00255
00256
00257
00258 return m_ticks;
00259
00260 }
00261
00262
00263
00264
00265 double value = floor( y / pow( 10.0, rmag ) + 0.5 ) *
00266 pow( 10.0, rmag );
00267
00268
00269
00270
00271 if ( use_pmag ) ylabel = value / pow( 10.0, pmag );
00272 else ylabel = value;
00273
00274 value /= scale_factor;
00275 sprintf( labl, pstr, ylabel );
00276 m_ticks.push_back( AxisTick ( value, labl ) );
00277
00278 num_ticks++;
00279 y += tick_step;
00280
00281 }
00282
00283 return m_ticks;
00284 }
00285
00286 const Range & LinearTransform::adjustValues ( AxisModelBase & axis,
00287 const Range & limit )
00288 {
00289
00290
00291
00292 double mylow, myhigh;
00293
00294
00295
00296 double step, magnitude;
00297
00298 const int N_NICE = 6;
00299 #ifndef __STDC__
00300 static
00301 #endif
00302 float nice[N_NICE] = { 1.0, 2.0, 2.5,
00303 4.0, 5.0, 7.5 };
00304
00305 const Range & init_range = axis.getRange ( false );
00306 double low = init_range.low ();
00307 double high = init_range.high ();
00308
00309 if ( ( high - low ) < 10.* DBL_MIN ) {
00310 if ( low > 0.0 ) low *= 0.95;
00311 else low *= 1.05;
00312
00313 if ( low == 0. ) {
00314 high = low + 1000. * FLT_EPSILON;
00315 }
00316 else {
00317 if ( high > 0.) high *= 1.05;
00318 else high *= 0.95;
00319 }
00320
00321 axis.setRange ( low, high, low );
00322 }
00323 double range_length;
00324
00325 int i;
00326
00327
00328
00329
00330 mylow = low - 0.05*(high-low);
00331 myhigh = high + 0.05*(high-low);
00332
00333 range_length = myhigh - mylow;
00334
00335
00336
00337
00338
00339 if( low >= 0.0 && range_length > ( 1.05 * high ) ) {
00340 Range range ( 0.0, range_length );
00341 axis.setIntersectRange ( range, limit );
00342 return axis.getRange( false );
00343 }
00344 if( high <= 0.0 && -range_length < ( 1.05 * low ) ) {
00345 Range range ( -range_length, 0.0 );
00346 axis.setIntersectRange ( range, limit );
00347 return axis.getRange( false );
00348 }
00349
00350
00351
00352 i = N_NICE - 1;
00353 if( myhigh != 0.0 )
00354 magnitude = ceil( log10( fabs( myhigh ) ) );
00355 else
00356 magnitude = ceil( log10( fabs( mylow ) ) );
00357
00358
00359
00360
00361 do {
00362 step = nice[i] * pow( 10.0, magnitude );
00363 mylow = floor( low / step ) * step;
00364 myhigh = mylow + 1.05 * range_length;
00365 i--;
00366 if( i < 0 ) {
00367 i = N_NICE - 1;
00368 magnitude--;
00369 }
00370 } while( myhigh < high );
00371
00372 Range range ( mylow, myhigh, init_range.pos() );
00373
00374 axis.setIntersectRange ( range, limit );
00375
00376 return axis.getRange( false );
00377 }