00001
00015 #ifdef _MSC_VER
00016
00017 #include "msdevstudio/MSconfig.h"
00018 #endif //_MSC_VER
00019
00020 #include "AxisModelLog.h"
00021
00022 #include "AxisTick.h"
00023
00024 #include <algorithm>
00025
00026 #include <cassert>
00027 #include <cmath>
00028 #include <cstdio>
00029
00030 using std::abs;
00031 using std::max;
00032 using std::min;
00033 using std::string;
00034 using std::vector;
00035
00036 AxisModelLog::AxisModelLog ( AxisLoc label_loc,
00037 AxisLoc scale_loc )
00038 : AxisModelBase ( label_loc, scale_loc )
00039 {
00040 }
00041
00042 AxisModelLog::AxisModelLog ( const AxisModelBase & axis_model )
00043 : AxisModelBase ( axis_model )
00044 {
00045
00046 adjustLogValues();
00047 }
00048
00049 AxisModelLog::~AxisModelLog()
00050 {
00051 }
00052
00053
00054 AxisModelBase * AxisModelLog::clone() const
00055 {
00056 return new AxisModelLog( *this );
00057 }
00058
00059 inline double FLT_EQUAL( double x, double y )
00060 {
00061 return ( (double)fabs( x - y ) <= 2.0 * ( y * FLT_EPSILON + FLT_MIN ) );
00062 }
00063
00064 bool AxisModelLog::isLog() const
00065 {
00066 return true;
00067 }
00068
00069 void AxisModelLog::setTickStep()
00070 {
00071 const Range & range = getRange(true);
00072 double low = range.low();
00073 double high = range.high();
00074 double rangeMag = high / low;
00075
00076
00077 m_rmag = floor( log10( rangeMag ) );
00078
00079
00080 m_pmag = ceil( log10( low ) );
00081
00082
00083
00084 double m_tmag = floor( m_rmag / 3.0 );
00085
00086 m_tick_step = pow( 10.0, m_tmag );
00087 }
00088
00089 const Range &
00090 AxisModelLog::adjustValues ( const Range & limit )
00091 {
00092
00093
00094
00095
00096
00097 double mylow, myhigh;
00098
00099
00100
00101
00102
00103
00104
00105 adjustLogValues();
00106 setTickStep();
00107
00108 const Range & init_range = getRange(false);
00109 double low = init_range.low();
00110 double high = init_range.high();
00111
00112 myhigh = mylow = pow( 10.0, m_pmag );
00113
00114
00115
00116 while( mylow >= low * m_scale_factor ) {
00117 mylow = prevStep( mylow );
00118 }
00119
00120
00121
00122 while( myhigh <= high * m_scale_factor ) {
00123 myhigh = nextStep( myhigh );
00124 }
00125
00126
00127
00128 if( myhigh / mylow < 10.0 ) {
00129 mylow = prevStep( mylow );
00130 }
00131
00132
00133
00134 while( myhigh / mylow < 10.0 ) {
00135 myhigh = nextStep( myhigh );
00136 }
00137
00138 myhigh /= m_scale_factor;
00139 mylow /= m_scale_factor;
00140
00141 Range new_range ( mylow, myhigh, init_range.pos() );
00142
00143
00144
00145
00146 double new_width = new_range.length();
00147 double init_width = init_range.length();
00148
00149 if ( new_width > init_width * 10 ){
00150
00151 if ( low < 0 ) {
00152 low *= 1.05;
00153 }
00154 else{
00155 low *= 0.95;
00156 }
00157
00158 if ( high < 0 ){
00159 high *= 0.95;
00160 }
00161 else{
00162 high *= 1.05;
00163 }
00164
00165 Range newRange ( low, high, init_range.pos() );
00166 setIntersectRange ( newRange, limit );
00167 return m_range;
00168
00169 }
00170
00171 setIntersectRange ( new_range, limit );
00172 return m_range;
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184 }
00185
00186 const Range &
00187 AxisModelLog::adjustLogValues ()
00188 {
00189 const Range & r = getRange(false);
00190 double low = r.low();
00191 double high = r.high();
00192 double pos = r.pos();
00193
00194 if( low > 0.0 ) return r;
00195
00196 if( pos == high ) {
00197
00198 double l = pos / 10.0;
00199 double h = pos * 10.0;
00200 setRange ( l, h, pos );
00201
00202 return m_range;
00203 }
00204 if( pos == DBL_MAX || pos <= 0.0 ) {
00205 setRange ( 0.01, 100.0, 1.0 );
00206 return m_range;
00207 }
00208 setRange ( pos, high, pos );
00209
00210 return m_range;
00211 }
00212
00213 double AxisModelLog::nextStep ( double current )
00214 {
00215 double tick_step = getTickStep();
00216 if( tick_step == 1.0 ) {
00217 int base = static_cast<int>( current /
00218 pow( 10.0, floor( log10( current ) ) ) );
00219
00220
00221
00222
00223
00224
00227 switch( base ) {
00228 case 1:
00229 current *= 2.0;
00230 break;
00231 case 2:
00232 current /= 2.0;
00233 current *= 5.0;
00234 break;
00235 case 3:
00236 current /= 4.0;
00237 current *= 5.0;
00238 break;
00239 case 4:
00240 case 5:
00241 current *= 2.0;
00242 break;
00243 default:
00244 assert ( false );
00245 }
00246 } else {
00247 current *= tick_step;
00248 }
00249 return current;
00250 }
00251
00254 double AxisModelLog::prevStep ( double current )
00255 {
00256 double tick_step = getTickStep();
00257 if( tick_step == 1.0 ) {
00258 int base = static_cast<int>( current /
00259 pow( 10.0, floor( log10( current ) ) ) );
00260
00261
00262
00263
00264
00265
00266 switch( base ) {
00267 case 1:
00268 current /= 2.0;
00269 break;
00270 case 2:
00271 current /= 2.0;
00272 break;
00273 case 4:
00274 current /= 5.0;
00275 current *= 2.0;
00276 break;
00277 case 5:
00278 current /= 5.0;
00279 current *= 2.0;
00280 break;
00281 default:
00282 assert ( false );
00283 }
00284 } else {
00285 current /= tick_step;
00286 }
00287 return current;
00288 }
00289
00293 Range AxisModelLog::calcLow ( int parm, bool dragging )
00294 {
00295 startDragging ( dragging );
00296
00297 double low = m_start_range.low ();
00298 double high = m_start_range.high ();
00299 double k = log10 ( high / low );
00300
00301 double x = ( parm - 50 ) / 50.0;
00302
00303 double new_low = low * pow ( 10.0, k * x );
00304
00305 new_low = max ( new_low, 10.0 * DBL_EPSILON );
00306 new_low = min ( new_low, high - 100.0 * DBL_EPSILON );
00307
00308 if( abs( new_low - m_range.high() ) < 0.0001 ) return m_range;
00309
00310 return Range ( new_low, high, m_range.pos() );
00311 }
00312
00316 Range AxisModelLog::calcHigh ( int parm, bool dragging )
00317 {
00318 startDragging ( dragging );
00319
00320 double low = m_start_range.low ();
00321 double high = m_start_range.high ();
00322 double k = log10 ( high / low );
00323
00324 double multiplier = ( parm - 50 ) / 50.0;
00325
00326 double new_high = high * pow ( 10.0, k * multiplier );
00327
00328 if( abs( new_high - m_range.low() ) < 0.0001 ) return m_range;
00329
00330 return Range ( low, new_high, m_range.pos() );
00331 }