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