qwt_scale_engine.cpp
Go to the documentation of this file.
00001 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
00002  * Qwt Widget Library
00003  * Copyright (C) 1997   Josef Wilgen
00004  * Copyright (C) 2002   Uwe Rathmann
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the Qwt License, Version 1.0
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 // this version often doesn't find the best ticks: f.e for 15: 5, 10
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         // # ticks per interval
00052         const int numTicks = qCeil( qAbs( intervalSize / minStep ) ) - 1;
00053 
00054         // Do the minor steps fit into the interval?
00055         if ( qwtFuzzyCompare( ( numTicks +  1 ) * qAbs( minStep ),
00056             qAbs( intervalSize ), intervalSize ) > 0 )
00057         {
00058             // The minor steps doesn't fit into the interval
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         // ticks very close to 0.0 are
00651         // explicitely set to 0.0
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 
00678     ticks += interval.minValue();
00679     for ( int i = 1; i < numTicks - 1; i++ )
00680         ticks += interval.minValue() + i * stepSize;
00681     ticks += interval.maxValue();
00682 
00683     return ticks;
00684 }
00685 
00696 void QwtLinearScaleEngine::buildMinorTicks(
00697     const QList<double>& majorTicks,
00698     int maxMinorSteps, double stepSize,
00699     QList<double> &minorTicks,
00700     QList<double> &mediumTicks ) const
00701 {
00702     double minStep = qwtStepSize( stepSize, maxMinorSteps, base() );
00703     if ( minStep == 0.0 )
00704         return;
00705 
00706     // # ticks per interval
00707     const int numTicks = qCeil( qAbs( stepSize / minStep ) ) - 1;
00708 
00709     int medIndex = -1;
00710     if ( numTicks % 2 )
00711         medIndex = numTicks / 2;
00712 
00713     // calculate minor ticks
00714 
00715     for ( int i = 0; i < majorTicks.count(); i++ )
00716     {
00717         double val = majorTicks[i];
00718         for ( int k = 0; k < numTicks; k++ )
00719         {
00720             val += minStep;
00721 
00722             double alignedValue = val;
00723             if ( qwtFuzzyCompare( val, 0.0, stepSize ) == 0 )
00724                 alignedValue = 0.0;
00725 
00726             if ( k == medIndex )
00727                 mediumTicks += alignedValue;
00728             else
00729                 minorTicks += alignedValue;
00730         }
00731     }
00732 }
00733 
00745 QwtInterval QwtLinearScaleEngine::align(
00746     const QwtInterval &interval, double stepSize ) const
00747 {
00748     double x1 = interval.minValue();
00749     double x2 = interval.maxValue();
00750 
00751     // when there is no rounding beside some effect, when 
00752     // calculating with doubles, we keep the original value
00753 
00754     const double eps = 0.000000000001; // since Qt 4.8: qFuzzyIsNull
00755     if ( -DBL_MAX + stepSize <= x1 )
00756     {
00757         const double x = QwtScaleArithmetic::floorEps( x1, stepSize );
00758         if ( qAbs(x) <= eps || !qFuzzyCompare( x1, x ) )
00759             x1 = x;
00760     }
00761 
00762     if ( DBL_MAX - stepSize >= x2 )
00763     {
00764         const double x = QwtScaleArithmetic::ceilEps( x2, stepSize );
00765         if ( qAbs(x) <= eps || !qFuzzyCompare( x2, x ) )
00766             x2 = x;
00767     }
00768 
00769     return QwtInterval( x1, x2 );
00770 }
00771 
00778 QwtLogScaleEngine::QwtLogScaleEngine( uint base ):
00779     QwtScaleEngine( base )
00780 {
00781     setTransformation( new QwtLogTransform() );
00782 }
00783 
00785 QwtLogScaleEngine::~QwtLogScaleEngine()
00786 {
00787 }
00788 
00799 void QwtLogScaleEngine::autoScale( int maxNumSteps,
00800     double &x1, double &x2, double &stepSize ) const
00801 {
00802     if ( x1 > x2 )
00803         qSwap( x1, x2 );
00804 
00805     const double logBase = base();
00806 
00807     QwtInterval interval( x1 / qPow( logBase, lowerMargin() ),
00808         x2 * qPow( logBase, upperMargin() ) );
00809 
00810     if ( interval.maxValue() / interval.minValue() < logBase )
00811     {
00812         // scale width is less than one step -> try to build a linear scale
00813 
00814         QwtLinearScaleEngine linearScaler;
00815         linearScaler.setAttributes( attributes() );
00816         linearScaler.setReference( reference() );
00817         linearScaler.setMargins( lowerMargin(), upperMargin() );
00818 
00819         linearScaler.autoScale( maxNumSteps, x1, x2, stepSize );
00820 
00821         QwtInterval linearInterval = QwtInterval( x1, x2 ).normalized();
00822         linearInterval = linearInterval.limited( LOG_MIN, LOG_MAX );
00823 
00824         if ( linearInterval.maxValue() / linearInterval.minValue() < logBase )
00825         {
00826             stepSize = 0.0;
00827             return;
00828         }
00829     }
00830 
00831     double logRef = 1.0;
00832     if ( reference() > LOG_MIN / 2 )
00833         logRef = qMin( reference(), LOG_MAX / 2 );
00834 
00835     if ( testAttribute( QwtScaleEngine::Symmetric ) )
00836     {
00837         const double delta = qMax( interval.maxValue() / logRef,
00838             logRef / interval.minValue() );
00839         interval.setInterval( logRef / delta, logRef * delta );
00840     }
00841 
00842     if ( testAttribute( QwtScaleEngine::IncludeReference ) )
00843         interval = interval.extend( logRef );
00844 
00845     interval = interval.limited( LOG_MIN, LOG_MAX );
00846 
00847     if ( interval.width() == 0.0 )
00848         interval = buildInterval( interval.minValue() );
00849 
00850     stepSize = divideInterval( qwtLogInterval( logBase, interval ).width(), 
00851         qMax( maxNumSteps, 1 ) );
00852     if ( stepSize < 1.0 )
00853         stepSize = 1.0;
00854 
00855     if ( !testAttribute( QwtScaleEngine::Floating ) )
00856         interval = align( interval, stepSize );
00857 
00858     x1 = interval.minValue();
00859     x2 = interval.maxValue();
00860 
00861     if ( testAttribute( QwtScaleEngine::Inverted ) )
00862     {
00863         qSwap( x1, x2 );
00864         stepSize = -stepSize;
00865     }
00866 }
00867 
00880 QwtScaleDiv QwtLogScaleEngine::divideScale( double x1, double x2,
00881     int maxMajorSteps, int maxMinorSteps, double stepSize ) const
00882 {
00883     QwtInterval interval = QwtInterval( x1, x2 ).normalized();
00884     interval = interval.limited( LOG_MIN, LOG_MAX );
00885 
00886     if ( interval.width() <= 0 )
00887         return QwtScaleDiv();
00888 
00889     const double logBase = base();
00890 
00891     if ( interval.maxValue() / interval.minValue() < logBase )
00892     {
00893         // scale width is less than one decade -> build linear scale
00894 
00895         QwtLinearScaleEngine linearScaler;
00896         linearScaler.setAttributes( attributes() );
00897         linearScaler.setReference( reference() );
00898         linearScaler.setMargins( lowerMargin(), upperMargin() );
00899 
00900         return linearScaler.divideScale( x1, x2,
00901             maxMajorSteps, maxMinorSteps, 0.0 );
00902     }
00903 
00904     stepSize = qAbs( stepSize );
00905     if ( stepSize == 0.0 )
00906     {
00907         if ( maxMajorSteps < 1 )
00908             maxMajorSteps = 1;
00909 
00910         stepSize = divideInterval( 
00911             qwtLogInterval( logBase, interval ).width(), maxMajorSteps );
00912         if ( stepSize < 1.0 )
00913             stepSize = 1.0; // major step must be >= 1 decade
00914     }
00915 
00916     QwtScaleDiv scaleDiv;
00917     if ( stepSize != 0.0 )
00918     {
00919         QList<double> ticks[QwtScaleDiv::NTickTypes];
00920         buildTicks( interval, stepSize, maxMinorSteps, ticks );
00921 
00922         scaleDiv = QwtScaleDiv( interval, ticks );
00923     }
00924 
00925     if ( x1 > x2 )
00926         scaleDiv.invert();
00927 
00928     return scaleDiv;
00929 }
00930 
00941 void QwtLogScaleEngine::buildTicks(
00942     const QwtInterval& interval, double stepSize, int maxMinorSteps,
00943     QList<double> ticks[QwtScaleDiv::NTickTypes] ) const
00944 {
00945     const QwtInterval boundingInterval = align( interval, stepSize );
00946 
00947     ticks[QwtScaleDiv::MajorTick] =
00948         buildMajorTicks( boundingInterval, stepSize );
00949 
00950     if ( maxMinorSteps > 0 )
00951     {
00952         buildMinorTicks( ticks[QwtScaleDiv::MajorTick], maxMinorSteps, stepSize,
00953             ticks[QwtScaleDiv::MinorTick], ticks[QwtScaleDiv::MediumTick] );
00954     }
00955 
00956     for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ )
00957         ticks[i] = strip( ticks[i], interval );
00958 }
00959 
00968 QList<double> QwtLogScaleEngine::buildMajorTicks(
00969     const QwtInterval &interval, double stepSize ) const
00970 {
00971     double width = qwtLogInterval( base(), interval ).width();
00972 
00973     int numTicks = qRound( width / stepSize ) + 1;
00974     if ( numTicks > 10000 )
00975         numTicks = 10000;
00976 
00977     const double lxmin = ::log( interval.minValue() );
00978     const double lxmax = ::log( interval.maxValue() );
00979     const double lstep = ( lxmax - lxmin ) / double( numTicks - 1 );
00980 
00981     QList<double> ticks;
00982 
00983     ticks += interval.minValue();
00984 
00985     for ( int i = 1; i < numTicks - 1; i++ )
00986         ticks += qExp( lxmin + double( i ) * lstep );
00987 
00988     ticks += interval.maxValue();
00989 
00990     return ticks;
00991 }
00992 
01002 void QwtLogScaleEngine::buildMinorTicks(
01003     const QList<double> &majorTicks,
01004     int maxMinorSteps, double stepSize,
01005     QList<double> &minorTicks,
01006     QList<double> &mediumTicks ) const
01007 {
01008     const double logBase = base();
01009 
01010     if ( stepSize < 1.1 )          // major step width is one base
01011     {
01012         double minStep = divideInterval( stepSize, maxMinorSteps + 1 );
01013         if ( minStep == 0.0 )
01014             return;
01015         
01016         const int numSteps = qRound( stepSize / minStep ); 
01017 
01018         int mediumTickIndex = -1;
01019         if ( ( numSteps > 2 ) && ( numSteps % 2 == 0 ) )
01020             mediumTickIndex = numSteps / 2;
01021 
01022         for ( int i = 0; i < majorTicks.count() - 1; i++ )
01023         {
01024             const double v = majorTicks[i];
01025             const double s = logBase / numSteps;
01026 
01027             if ( s >= 1.0 )
01028             {
01029                 if ( !qFuzzyCompare( s, 1.0 ) )
01030                     minorTicks += v * s;
01031 
01032                 for ( int j = 2; j < numSteps; j++ )
01033                 {
01034                     minorTicks += v * j * s;
01035                 }
01036             }
01037             else
01038             {
01039                 for ( int j = 1; j < numSteps; j++ )
01040                 {
01041                     const double tick = v + j * v * ( logBase - 1 ) / numSteps;
01042                     if ( j == mediumTickIndex )
01043                         mediumTicks += tick;
01044                     else
01045                         minorTicks += tick;
01046                 }
01047             }
01048         }
01049     }
01050     else
01051     {
01052         double minStep = divideInterval( stepSize, maxMinorSteps );
01053         if ( minStep == 0.0 )
01054             return;
01055 
01056         if ( minStep < 1.0 )
01057             minStep = 1.0;
01058 
01059         // # subticks per interval
01060         int numTicks = qRound( stepSize / minStep ) - 1;
01061 
01062         // Do the minor steps fit into the interval?
01063         if ( qwtFuzzyCompare( ( numTicks +  1 ) * minStep,
01064             stepSize, stepSize ) > 0 )
01065         {
01066             numTicks = 0;
01067         }
01068 
01069         if ( numTicks < 1 )
01070             return; 
01071 
01072         int mediumTickIndex = -1;
01073         if ( ( numTicks > 2 ) && ( numTicks % 2 ) )
01074             mediumTickIndex = numTicks / 2;
01075 
01076         // substep factor = base^substeps
01077         const qreal minFactor = qMax( qPow( logBase, minStep ), qreal( logBase ) );
01078 
01079         for ( int i = 0; i < majorTicks.count(); i++ )
01080         {
01081             double tick = majorTicks[i];
01082             for ( int j = 0; j < numTicks; j++ )
01083             {
01084                 tick *= minFactor;
01085 
01086                 if ( j == mediumTickIndex )
01087                     mediumTicks += tick;
01088                 else
01089                     minorTicks += tick;
01090             }
01091         }
01092     }
01093 }
01094 
01106 QwtInterval QwtLogScaleEngine::align(
01107     const QwtInterval &interval, double stepSize ) const
01108 {
01109     const QwtInterval intv = qwtLogInterval( base(), interval );
01110 
01111     double x1 = QwtScaleArithmetic::floorEps( intv.minValue(), stepSize );
01112     if ( qwtFuzzyCompare( interval.minValue(), x1, stepSize ) == 0 )
01113         x1 = interval.minValue();
01114 
01115     double x2 = QwtScaleArithmetic::ceilEps( intv.maxValue(), stepSize );
01116     if ( qwtFuzzyCompare( interval.maxValue(), x2, stepSize ) == 0 )
01117         x2 = interval.maxValue();
01118 
01119     return qwtPowInterval( base(), QwtInterval( x1, x2 ) );
01120 }


plotjuggler
Author(s): Davide Faconti
autogenerated on Fri Sep 1 2017 02:41:56