00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "qwt_scale_engine.h"
00011 #include "qwt_math.h"
00012 #include "qwt_scale_map.h"
00013 #include <qalgorithms.h>
00014 #include <qmath.h>
00015 #include <float.h>
00016 #include <limits>
00017
00018 #if QT_VERSION < 0x040601
00019 #define qFabs(x) ::fabs(x)
00020 #define qExp(x) ::exp(x)
00021 #endif
00022
00023 static inline double qwtLog( double base, double value )
00024 {
00025 return log( value ) / log( base );
00026 }
00027
00028 static inline QwtInterval qwtLogInterval( double base, const QwtInterval &interval )
00029 {
00030 return QwtInterval( qwtLog( base, interval.minValue() ),
00031 qwtLog( base, interval.maxValue() ) );
00032 }
00033
00034 static inline QwtInterval qwtPowInterval( double base, const QwtInterval &interval )
00035 {
00036 return QwtInterval( qPow( base, interval.minValue() ),
00037 qPow( base, interval.maxValue() ) );
00038 }
00039
00040
00041 #if 1
00042
00043
00044 static double qwtStepSize( double intervalSize, int maxSteps, uint base )
00045 {
00046 const double minStep =
00047 QwtScaleArithmetic::divideInterval( intervalSize, maxSteps, base );
00048
00049 if ( minStep != 0.0 )
00050 {
00051
00052 const int numTicks = qCeil( qAbs( intervalSize / minStep ) ) - 1;
00053
00054
00055 if ( qwtFuzzyCompare( ( numTicks + 1 ) * qAbs( minStep ),
00056 qAbs( intervalSize ), intervalSize ) > 0 )
00057 {
00058
00059 return 0.5 * intervalSize;
00060 }
00061 }
00062
00063 return minStep;
00064 }
00065
00066 #else
00067
00068 static double qwtStepSize( double intervalSize, int maxSteps, uint base )
00069 {
00070 if ( maxSteps <= 0 )
00071 return 0.0;
00072
00073 if ( maxSteps > 2 )
00074 {
00075 for ( int numSteps = maxSteps; numSteps > 1; numSteps-- )
00076 {
00077 const double stepSize = intervalSize / numSteps;
00078
00079 const double p = ::floor( ::log( stepSize ) / ::log( base ) );
00080 const double fraction = qPow( base, p );
00081
00082 for ( uint n = base; n > 1; n /= 2 )
00083 {
00084 if ( qFuzzyCompare( stepSize, n * fraction ) )
00085 return stepSize;
00086
00087 if ( n == 3 && ( base % 2 ) == 0 )
00088 {
00089 if ( qFuzzyCompare( stepSize, 2 * fraction ) )
00090 return stepSize;
00091 }
00092 }
00093 }
00094 }
00095
00096 return intervalSize * 0.5;
00097 }
00098
00099 #endif
00100
00101 static const double _eps = 1.0e-6;
00102
00113 double QwtScaleArithmetic::ceilEps( double value,
00114 double intervalSize )
00115 {
00116 const double eps = _eps * intervalSize;
00117
00118 value = ( value - eps ) / intervalSize;
00119 return ::ceil( value ) * intervalSize;
00120 }
00121
00131 double QwtScaleArithmetic::floorEps( double value, double intervalSize )
00132 {
00133 const double eps = _eps * intervalSize;
00134
00135 value = ( value + eps ) / intervalSize;
00136 return ::floor( value ) * intervalSize;
00137 }
00138
00148 double QwtScaleArithmetic::divideEps( double intervalSize, double numSteps )
00149 {
00150 if ( numSteps == 0.0 || intervalSize == 0.0 )
00151 return 0.0;
00152
00153 return ( intervalSize - ( _eps * intervalSize ) ) / numSteps;
00154 }
00155
00165 double QwtScaleArithmetic::divideInterval(
00166 double intervalSize, int numSteps, uint base )
00167 {
00168 if ( numSteps <= 0 )
00169 return 0.0;
00170
00171 const double v = QwtScaleArithmetic::divideEps( intervalSize, numSteps );
00172 if ( v == 0.0 )
00173 return 0.0;
00174
00175 const double lx = qwtLog( base, qFabs( v ) );
00176 const double p = ::floor( lx );
00177
00178 const double fraction = qPow( base, lx - p );
00179
00180 uint n = base;
00181 while ( ( n > 1 ) && ( fraction <= n / 2 ) )
00182 n /= 2;
00183
00184 double stepSize = n * qPow( base, p );
00185 if ( v < 0 )
00186 stepSize = -stepSize;
00187
00188 return stepSize;
00189 }
00190
00191 class QwtScaleEngine::PrivateData
00192 {
00193 public:
00194 PrivateData():
00195 attributes( QwtScaleEngine::NoAttribute ),
00196 lowerMargin( 0.0 ),
00197 upperMargin( 0.0 ),
00198 referenceValue( 0.0 ),
00199 base( 10 ),
00200 transform( NULL )
00201 {
00202 }
00203
00204 ~PrivateData()
00205 {
00206 delete transform;
00207 }
00208
00209 QwtScaleEngine::Attributes attributes;
00210
00211 double lowerMargin;
00212 double upperMargin;
00213
00214 double referenceValue;
00215
00216 uint base;
00217
00218 QwtTransform* transform;
00219 };
00220
00227 QwtScaleEngine::QwtScaleEngine( uint base )
00228 {
00229 d_data = new PrivateData;
00230 setBase( base );
00231 }
00232
00233
00235 QwtScaleEngine::~QwtScaleEngine ()
00236 {
00237 delete d_data;
00238 }
00239
00253 void QwtScaleEngine::setTransformation( QwtTransform *transform )
00254 {
00255 if ( transform != d_data->transform )
00256 {
00257 delete d_data->transform;
00258 d_data->transform = transform;
00259 }
00260 }
00261
00270 QwtTransform *QwtScaleEngine::transformation() const
00271 {
00272 QwtTransform *transform = NULL;
00273 if ( d_data->transform )
00274 transform = d_data->transform->copy();
00275
00276 return transform;
00277 }
00278
00285 double QwtScaleEngine::lowerMargin() const
00286 {
00287 return d_data->lowerMargin;
00288 }
00289
00296 double QwtScaleEngine::upperMargin() const
00297 {
00298 return d_data->upperMargin;
00299 }
00300
00317 void QwtScaleEngine::setMargins( double lower, double upper )
00318 {
00319 d_data->lowerMargin = qMax( lower, 0.0 );
00320 d_data->upperMargin = qMax( upper, 0.0 );
00321 }
00322
00331 double QwtScaleEngine::divideInterval(
00332 double intervalSize, int numSteps ) const
00333 {
00334 return QwtScaleArithmetic::divideInterval(
00335 intervalSize, numSteps, d_data->base );
00336 }
00337
00346 bool QwtScaleEngine::contains(
00347 const QwtInterval &interval, double value ) const
00348 {
00349 if ( !interval.isValid() )
00350 return false;
00351
00352 if ( qwtFuzzyCompare( value, interval.minValue(), interval.width() ) < 0 )
00353 return false;
00354
00355 if ( qwtFuzzyCompare( value, interval.maxValue(), interval.width() ) > 0 )
00356 return false;
00357
00358 return true;
00359 }
00360
00369 QList<double> QwtScaleEngine::strip( const QList<double>& ticks,
00370 const QwtInterval &interval ) const
00371 {
00372 if ( !interval.isValid() || ticks.count() == 0 )
00373 return QList<double>();
00374
00375 if ( contains( interval, ticks.first() )
00376 && contains( interval, ticks.last() ) )
00377 {
00378 return ticks;
00379 }
00380
00381 QList<double> strippedTicks;
00382 for ( int i = 0; i < ticks.count(); i++ )
00383 {
00384 if ( contains( interval, ticks[i] ) )
00385 strippedTicks += ticks[i];
00386 }
00387 return strippedTicks;
00388 }
00389
00400 QwtInterval QwtScaleEngine::buildInterval( double value ) const
00401 {
00402 const double delta = ( value == 0.0 ) ? 0.5 : qAbs( 0.5 * value );
00403
00404 if ( DBL_MAX - delta < value )
00405 return QwtInterval( DBL_MAX - delta, DBL_MAX );
00406
00407 if ( -DBL_MAX + delta > value )
00408 return QwtInterval( -DBL_MAX, -DBL_MAX + delta );
00409
00410 return QwtInterval( value - delta, value + delta );
00411 }
00412
00421 void QwtScaleEngine::setAttribute( Attribute attribute, bool on )
00422 {
00423 if ( on )
00424 d_data->attributes |= attribute;
00425 else
00426 d_data->attributes &= ~attribute;
00427 }
00428
00435 bool QwtScaleEngine::testAttribute( Attribute attribute ) const
00436 {
00437 return ( d_data->attributes & attribute );
00438 }
00439
00446 void QwtScaleEngine::setAttributes( Attributes attributes )
00447 {
00448 d_data->attributes = attributes;
00449 }
00450
00455 QwtScaleEngine::Attributes QwtScaleEngine::attributes() const
00456 {
00457 return d_data->attributes;
00458 }
00459
00469 void QwtScaleEngine::setReference( double r )
00470 {
00471 d_data->referenceValue = r;
00472 }
00473
00478 double QwtScaleEngine::reference() const
00479 {
00480 return d_data->referenceValue;
00481 }
00482
00495 void QwtScaleEngine::setBase( uint base )
00496 {
00497 d_data->base = qMax( base, 2U );
00498 }
00499
00504 uint QwtScaleEngine::base() const
00505 {
00506 return d_data->base;
00507 }
00508
00515 QwtLinearScaleEngine::QwtLinearScaleEngine( uint base ):
00516 QwtScaleEngine( base )
00517 {
00518 }
00519
00521 QwtLinearScaleEngine::~QwtLinearScaleEngine()
00522 {
00523 }
00524
00535 void QwtLinearScaleEngine::autoScale( int maxNumSteps,
00536 double &x1, double &x2, double &stepSize ) const
00537 {
00538 QwtInterval interval( x1, x2 );
00539 interval = interval.normalized();
00540
00541 interval.setMinValue( interval.minValue() - lowerMargin() );
00542 interval.setMaxValue( interval.maxValue() + upperMargin() );
00543
00544 if ( testAttribute( QwtScaleEngine::Symmetric ) )
00545 interval = interval.symmetrize( reference() );
00546
00547 if ( testAttribute( QwtScaleEngine::IncludeReference ) )
00548 interval = interval.extend( reference() );
00549
00550 if ( interval.width() == 0.0 )
00551 interval = buildInterval( interval.minValue() );
00552
00553 stepSize = QwtScaleArithmetic::divideInterval(
00554 interval.width(), qMax( maxNumSteps, 1 ), base() );
00555
00556 if ( !testAttribute( QwtScaleEngine::Floating ) )
00557 interval = align( interval, stepSize );
00558
00559 x1 = interval.minValue();
00560 x2 = interval.maxValue();
00561
00562 if ( testAttribute( QwtScaleEngine::Inverted ) )
00563 {
00564 qSwap( x1, x2 );
00565 stepSize = -stepSize;
00566 }
00567 }
00568
00581 QwtScaleDiv QwtLinearScaleEngine::divideScale( double x1, double x2,
00582 int maxMajorSteps, int maxMinorSteps, double stepSize ) const
00583 {
00584 QwtInterval interval = QwtInterval( x1, x2 ).normalized();
00585
00586 if ( interval.widthL() > std::numeric_limits<double>::max() )
00587 {
00588 qWarning() << "QwtLinearScaleEngine::divideScale: overflow";
00589 return QwtScaleDiv();
00590 }
00591
00592 if ( interval.width() <= 0 )
00593 return QwtScaleDiv();
00594
00595 stepSize = qAbs( stepSize );
00596 if ( stepSize == 0.0 )
00597 {
00598 if ( maxMajorSteps < 1 )
00599 maxMajorSteps = 1;
00600
00601 stepSize = QwtScaleArithmetic::divideInterval(
00602 interval.width(), maxMajorSteps, base() );
00603 }
00604
00605 QwtScaleDiv scaleDiv;
00606
00607 if ( stepSize != 0.0 )
00608 {
00609 QList<double> ticks[QwtScaleDiv::NTickTypes];
00610 buildTicks( interval, stepSize, maxMinorSteps, ticks );
00611
00612 scaleDiv = QwtScaleDiv( interval, ticks );
00613 }
00614
00615 if ( x1 > x2 )
00616 scaleDiv.invert();
00617
00618 return scaleDiv;
00619 }
00620
00631 void QwtLinearScaleEngine::buildTicks(
00632 const QwtInterval& interval, double stepSize, int maxMinorSteps,
00633 QList<double> ticks[QwtScaleDiv::NTickTypes] ) const
00634 {
00635 const QwtInterval boundingInterval = align( interval, stepSize );
00636
00637 ticks[QwtScaleDiv::MajorTick] =
00638 buildMajorTicks( boundingInterval, stepSize );
00639
00640 if ( maxMinorSteps > 0 )
00641 {
00642 buildMinorTicks( ticks[QwtScaleDiv::MajorTick], maxMinorSteps, stepSize,
00643 ticks[QwtScaleDiv::MinorTick], ticks[QwtScaleDiv::MediumTick] );
00644 }
00645
00646 for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ )
00647 {
00648 ticks[i] = strip( ticks[i], interval );
00649
00650
00651
00652
00653 for ( int j = 0; j < ticks[i].count(); j++ )
00654 {
00655 if ( qwtFuzzyCompare( ticks[i][j], 0.0, stepSize ) == 0 )
00656 ticks[i][j] = 0.0;
00657 }
00658 }
00659 }
00660
00669 QList<double> QwtLinearScaleEngine::buildMajorTicks(
00670 const QwtInterval &interval, double stepSize ) const
00671 {
00672 int numTicks = qRound( interval.width() / stepSize ) + 1;
00673 if ( numTicks > 10000 )
00674 numTicks = 10000;
00675
00676 QList<double> ticks;
00677 #if QT_VERSION >= 0x040700
00678 ticks.reserve( numTicks );
00679 #endif
00680
00681 ticks += interval.minValue();
00682 for ( int i = 1; i < numTicks - 1; i++ )
00683 ticks += interval.minValue() + i * stepSize;
00684 ticks += interval.maxValue();
00685
00686 return ticks;
00687 }
00688
00699 void QwtLinearScaleEngine::buildMinorTicks(
00700 const QList<double>& majorTicks,
00701 int maxMinorSteps, double stepSize,
00702 QList<double> &minorTicks,
00703 QList<double> &mediumTicks ) const
00704 {
00705 double minStep = qwtStepSize( stepSize, maxMinorSteps, base() );
00706 if ( minStep == 0.0 )
00707 return;
00708
00709
00710 const int numTicks = qCeil( qAbs( stepSize / minStep ) ) - 1;
00711
00712 int medIndex = -1;
00713 if ( numTicks % 2 )
00714 medIndex = numTicks / 2;
00715
00716
00717
00718 for ( int i = 0; i < majorTicks.count(); i++ )
00719 {
00720 double val = majorTicks[i];
00721 for ( int k = 0; k < numTicks; k++ )
00722 {
00723 val += minStep;
00724
00725 double alignedValue = val;
00726 if ( qwtFuzzyCompare( val, 0.0, stepSize ) == 0 )
00727 alignedValue = 0.0;
00728
00729 if ( k == medIndex )
00730 mediumTicks += alignedValue;
00731 else
00732 minorTicks += alignedValue;
00733 }
00734 }
00735 }
00736
00748 QwtInterval QwtLinearScaleEngine::align(
00749 const QwtInterval &interval, double stepSize ) const
00750 {
00751 double x1 = interval.minValue();
00752 double x2 = interval.maxValue();
00753
00754
00755
00756
00757 const double eps = 0.000000000001;
00758 if ( -DBL_MAX + stepSize <= x1 )
00759 {
00760 const double x = QwtScaleArithmetic::floorEps( x1, stepSize );
00761 if ( qAbs(x) <= eps || !qFuzzyCompare( x1, x ) )
00762 x1 = x;
00763 }
00764
00765 if ( DBL_MAX - stepSize >= x2 )
00766 {
00767 const double x = QwtScaleArithmetic::ceilEps( x2, stepSize );
00768 if ( qAbs(x) <= eps || !qFuzzyCompare( x2, x ) )
00769 x2 = x;
00770 }
00771
00772 return QwtInterval( x1, x2 );
00773 }
00774
00781 QwtLogScaleEngine::QwtLogScaleEngine( uint base ):
00782 QwtScaleEngine( base )
00783 {
00784 setTransformation( new QwtLogTransform() );
00785 }
00786
00788 QwtLogScaleEngine::~QwtLogScaleEngine()
00789 {
00790 }
00791
00802 void QwtLogScaleEngine::autoScale( int maxNumSteps,
00803 double &x1, double &x2, double &stepSize ) const
00804 {
00805 if ( x1 > x2 )
00806 qSwap( x1, x2 );
00807
00808 const double logBase = base();
00809
00810 QwtInterval interval( x1 / qPow( logBase, lowerMargin() ),
00811 x2 * qPow( logBase, upperMargin() ) );
00812
00813 if ( interval.maxValue() / interval.minValue() < logBase )
00814 {
00815
00816
00817 QwtLinearScaleEngine linearScaler;
00818 linearScaler.setAttributes( attributes() );
00819 linearScaler.setReference( reference() );
00820 linearScaler.setMargins( lowerMargin(), upperMargin() );
00821
00822 linearScaler.autoScale( maxNumSteps, x1, x2, stepSize );
00823
00824 QwtInterval linearInterval = QwtInterval( x1, x2 ).normalized();
00825 linearInterval = linearInterval.limited( LOG_MIN, LOG_MAX );
00826
00827 if ( linearInterval.maxValue() / linearInterval.minValue() < logBase )
00828 {
00829 stepSize = 0.0;
00830 return;
00831 }
00832 }
00833
00834 double logRef = 1.0;
00835 if ( reference() > LOG_MIN / 2 )
00836 logRef = qMin( reference(), LOG_MAX / 2 );
00837
00838 if ( testAttribute( QwtScaleEngine::Symmetric ) )
00839 {
00840 const double delta = qMax( interval.maxValue() / logRef,
00841 logRef / interval.minValue() );
00842 interval.setInterval( logRef / delta, logRef * delta );
00843 }
00844
00845 if ( testAttribute( QwtScaleEngine::IncludeReference ) )
00846 interval = interval.extend( logRef );
00847
00848 interval = interval.limited( LOG_MIN, LOG_MAX );
00849
00850 if ( interval.width() == 0.0 )
00851 interval = buildInterval( interval.minValue() );
00852
00853 stepSize = divideInterval( qwtLogInterval( logBase, interval ).width(),
00854 qMax( maxNumSteps, 1 ) );
00855 if ( stepSize < 1.0 )
00856 stepSize = 1.0;
00857
00858 if ( !testAttribute( QwtScaleEngine::Floating ) )
00859 interval = align( interval, stepSize );
00860
00861 x1 = interval.minValue();
00862 x2 = interval.maxValue();
00863
00864 if ( testAttribute( QwtScaleEngine::Inverted ) )
00865 {
00866 qSwap( x1, x2 );
00867 stepSize = -stepSize;
00868 }
00869 }
00870
00883 QwtScaleDiv QwtLogScaleEngine::divideScale( double x1, double x2,
00884 int maxMajorSteps, int maxMinorSteps, double stepSize ) const
00885 {
00886 QwtInterval interval = QwtInterval( x1, x2 ).normalized();
00887 interval = interval.limited( LOG_MIN, LOG_MAX );
00888
00889 if ( interval.width() <= 0 )
00890 return QwtScaleDiv();
00891
00892 const double logBase = base();
00893
00894 if ( interval.maxValue() / interval.minValue() < logBase )
00895 {
00896
00897
00898 QwtLinearScaleEngine linearScaler;
00899 linearScaler.setAttributes( attributes() );
00900 linearScaler.setReference( reference() );
00901 linearScaler.setMargins( lowerMargin(), upperMargin() );
00902
00903 return linearScaler.divideScale( x1, x2,
00904 maxMajorSteps, maxMinorSteps, 0.0 );
00905 }
00906
00907 stepSize = qAbs( stepSize );
00908 if ( stepSize == 0.0 )
00909 {
00910 if ( maxMajorSteps < 1 )
00911 maxMajorSteps = 1;
00912
00913 stepSize = divideInterval(
00914 qwtLogInterval( logBase, interval ).width(), maxMajorSteps );
00915 if ( stepSize < 1.0 )
00916 stepSize = 1.0;
00917 }
00918
00919 QwtScaleDiv scaleDiv;
00920 if ( stepSize != 0.0 )
00921 {
00922 QList<double> ticks[QwtScaleDiv::NTickTypes];
00923 buildTicks( interval, stepSize, maxMinorSteps, ticks );
00924
00925 scaleDiv = QwtScaleDiv( interval, ticks );
00926 }
00927
00928 if ( x1 > x2 )
00929 scaleDiv.invert();
00930
00931 return scaleDiv;
00932 }
00933
00944 void QwtLogScaleEngine::buildTicks(
00945 const QwtInterval& interval, double stepSize, int maxMinorSteps,
00946 QList<double> ticks[QwtScaleDiv::NTickTypes] ) const
00947 {
00948 const QwtInterval boundingInterval = align( interval, stepSize );
00949
00950 ticks[QwtScaleDiv::MajorTick] =
00951 buildMajorTicks( boundingInterval, stepSize );
00952
00953 if ( maxMinorSteps > 0 )
00954 {
00955 buildMinorTicks( ticks[QwtScaleDiv::MajorTick], maxMinorSteps, stepSize,
00956 ticks[QwtScaleDiv::MinorTick], ticks[QwtScaleDiv::MediumTick] );
00957 }
00958
00959 for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ )
00960 ticks[i] = strip( ticks[i], interval );
00961 }
00962
00971 QList<double> QwtLogScaleEngine::buildMajorTicks(
00972 const QwtInterval &interval, double stepSize ) const
00973 {
00974 double width = qwtLogInterval( base(), interval ).width();
00975
00976 int numTicks = qRound( width / stepSize ) + 1;
00977 if ( numTicks > 10000 )
00978 numTicks = 10000;
00979
00980 const double lxmin = ::log( interval.minValue() );
00981 const double lxmax = ::log( interval.maxValue() );
00982 const double lstep = ( lxmax - lxmin ) / double( numTicks - 1 );
00983
00984 QList<double> ticks;
00985 #if QT_VERSION >= 0x040700
00986 ticks.reserve( numTicks );
00987 #endif
00988
00989 ticks += interval.minValue();
00990
00991 for ( int i = 1; i < numTicks - 1; i++ )
00992 ticks += qExp( lxmin + double( i ) * lstep );
00993
00994 ticks += interval.maxValue();
00995
00996 return ticks;
00997 }
00998
01008 void QwtLogScaleEngine::buildMinorTicks(
01009 const QList<double> &majorTicks,
01010 int maxMinorSteps, double stepSize,
01011 QList<double> &minorTicks,
01012 QList<double> &mediumTicks ) const
01013 {
01014 const double logBase = base();
01015
01016 if ( stepSize < 1.1 )
01017 {
01018 double minStep = divideInterval( stepSize, maxMinorSteps + 1 );
01019 if ( minStep == 0.0 )
01020 return;
01021
01022 const int numSteps = qRound( stepSize / minStep );
01023
01024 int mediumTickIndex = -1;
01025 if ( ( numSteps > 2 ) && ( numSteps % 2 == 0 ) )
01026 mediumTickIndex = numSteps / 2;
01027
01028 for ( int i = 0; i < majorTicks.count() - 1; i++ )
01029 {
01030 const double v = majorTicks[i];
01031 const double s = logBase / numSteps;
01032
01033 if ( s >= 1.0 )
01034 {
01035 if ( !qFuzzyCompare( s, 1.0 ) )
01036 minorTicks += v * s;
01037
01038 for ( int j = 2; j < numSteps; j++ )
01039 {
01040 minorTicks += v * j * s;
01041 }
01042 }
01043 else
01044 {
01045 for ( int j = 1; j < numSteps; j++ )
01046 {
01047 const double tick = v + j * v * ( logBase - 1 ) / numSteps;
01048 if ( j == mediumTickIndex )
01049 mediumTicks += tick;
01050 else
01051 minorTicks += tick;
01052 }
01053 }
01054 }
01055 }
01056 else
01057 {
01058 double minStep = divideInterval( stepSize, maxMinorSteps );
01059 if ( minStep == 0.0 )
01060 return;
01061
01062 if ( minStep < 1.0 )
01063 minStep = 1.0;
01064
01065
01066 int numTicks = qRound( stepSize / minStep ) - 1;
01067
01068
01069 if ( qwtFuzzyCompare( ( numTicks + 1 ) * minStep,
01070 stepSize, stepSize ) > 0 )
01071 {
01072 numTicks = 0;
01073 }
01074
01075 if ( numTicks < 1 )
01076 return;
01077
01078 int mediumTickIndex = -1;
01079 if ( ( numTicks > 2 ) && ( numTicks % 2 ) )
01080 mediumTickIndex = numTicks / 2;
01081
01082
01083 const qreal minFactor = qMax( qPow( logBase, minStep ), qreal( logBase ) );
01084
01085 for ( int i = 0; i < majorTicks.count(); i++ )
01086 {
01087 double tick = majorTicks[i];
01088 for ( int j = 0; j < numTicks; j++ )
01089 {
01090 tick *= minFactor;
01091
01092 if ( j == mediumTickIndex )
01093 mediumTicks += tick;
01094 else
01095 minorTicks += tick;
01096 }
01097 }
01098 }
01099 }
01100
01112 QwtInterval QwtLogScaleEngine::align(
01113 const QwtInterval &interval, double stepSize ) const
01114 {
01115 const QwtInterval intv = qwtLogInterval( base(), interval );
01116
01117 double x1 = QwtScaleArithmetic::floorEps( intv.minValue(), stepSize );
01118 if ( qwtFuzzyCompare( interval.minValue(), x1, stepSize ) == 0 )
01119 x1 = interval.minValue();
01120
01121 double x2 = QwtScaleArithmetic::ceilEps( intv.maxValue(), stepSize );
01122 if ( qwtFuzzyCompare( interval.maxValue(), x2, stepSize ) == 0 )
01123 x2 = interval.maxValue();
01124
01125 return qwtPowInterval( base(), QwtInterval( x1, x2 ) );
01126 }