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