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 #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     // # ticks per interval
00710     const int numTicks = qCeil( qAbs( stepSize / minStep ) ) - 1;
00711 
00712     int medIndex = -1;
00713     if ( numTicks % 2 )
00714         medIndex = numTicks / 2;
00715 
00716     // calculate minor ticks
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     // when there is no rounding beside some effect, when 
00755     // calculating with doubles, we keep the original value
00756 
00757     const double eps = 0.000000000001; // since Qt 4.8: qFuzzyIsNull
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         // scale width is less than one step -> try to build a linear scale
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         // scale width is less than one decade -> build linear scale
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; // major step must be >= 1 decade
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 )          // major step width is one base
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         // # subticks per interval
01066         int numTicks = qRound( stepSize / minStep ) - 1;
01067 
01068         // Do the minor steps fit into the interval?
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         // substep factor = base^substeps
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 }


plotjuggler
Author(s): Davide Faconti
autogenerated on Wed Jul 3 2019 19:28:05