Changeset 8127 in ntrip for trunk/BNC/qwt/qwt_scale_engine.cpp


Ignore:
Timestamp:
May 10, 2017, 3:20:54 PM (7 years ago)
Author:
stoecker
Message:

update qwt and qwtpolar, many QT5 fixes (unfinished)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/BNC/qwt/qwt_scale_engine.cpp

    r4271 r8127  
    1313#include <qalgorithms.h>
    1414#include <qmath.h>
     15#include <float.h>
     16#include <limits>
    1517
    1618#if QT_VERSION < 0x040601
     
    1921#endif
    2022
     23static inline double qwtLog( double base, double value )
     24{
     25    return log( value ) / log( base );
     26}
     27
     28static inline QwtInterval qwtLogInterval( double base, const QwtInterval &interval )
     29{
     30    return QwtInterval( qwtLog( base, interval.minValue() ),
     31            qwtLog( base, interval.maxValue() ) );
     32}
     33
     34static inline QwtInterval qwtPowInterval( double base, const QwtInterval &interval )
     35{
     36    return QwtInterval( qPow( base, interval.minValue() ),
     37            qPow( base, interval.maxValue() ) );
     38}
     39
     40static inline long double qwtIntervalWidthL( const QwtInterval &interval )
     41{
     42    if ( !interval.isValid() )
     43        return 0.0;
     44
     45    return static_cast<long double>( interval.maxValue() )
     46        - static_cast<long double>( interval.minValue() );
     47}
     48
     49#if 1
     50
     51// this version often doesn't find the best ticks: f.e for 15: 5, 10
     52static double qwtStepSize( double intervalSize, int maxSteps, uint base )
     53{
     54    const double minStep =
     55        QwtScaleArithmetic::divideInterval( intervalSize, maxSteps, base );
     56
     57    if ( minStep != 0.0 )
     58    {
     59        // # ticks per interval
     60        const int numTicks = qCeil( qAbs( intervalSize / minStep ) ) - 1;
     61
     62        // Do the minor steps fit into the interval?
     63        if ( qwtFuzzyCompare( ( numTicks +  1 ) * qAbs( minStep ),
     64            qAbs( intervalSize ), intervalSize ) > 0 )
     65        {
     66            // The minor steps doesn't fit into the interval
     67            return 0.5 * intervalSize;
     68        }
     69    }
     70
     71    return minStep;
     72}
     73
     74#else
     75
     76static double qwtStepSize( double intervalSize, int maxSteps, uint base )
     77{
     78    if ( maxSteps <= 0 )
     79        return 0.0;
     80
     81    if ( maxSteps > 2 )
     82    {
     83        for ( int numSteps = maxSteps; numSteps > 1; numSteps-- )
     84        {
     85            const double stepSize = intervalSize / numSteps;
     86
     87            const double p = ::floor( ::log( stepSize ) / ::log( base ) );
     88            const double fraction = qPow( base, p );
     89
     90            for ( uint n = base; n > 1; n /= 2 )
     91            {
     92                if ( qFuzzyCompare( stepSize, n * fraction ) )
     93                    return stepSize;
     94
     95                if ( n == 3 && ( base % 2 ) == 0 )
     96                {
     97                    if ( qFuzzyCompare( stepSize, 2 * fraction ) )
     98                        return stepSize;
     99                }
     100            }
     101        }
     102    }
     103
     104    return intervalSize * 0.5;
     105}
     106
     107#endif
     108
    21109static const double _eps = 1.0e-6;
    22110
     
    24112  Ceil a value, relative to an interval
    25113
    26   \param value Value to ceil
     114  \param value Value to be ceiled
    27115  \param intervalSize Interval size
     116
     117  \return Rounded value
    28118
    29119  \sa floorEps()
     
    35125
    36126    value = ( value - eps ) / intervalSize;
    37     return qwtCeilF( value ) * intervalSize;
     127    return ::ceil( value ) * intervalSize;
    38128}
    39129
     
    41131  Floor a value, relative to an interval
    42132
    43   \param value Value to floor
     133  \param value Value to be floored
    44134  \param intervalSize Interval size
    45135
     136  \return Rounded value
    46137  \sa floorEps()
    47138*/
     
    51142
    52143    value = ( value + eps ) / intervalSize;
    53     return qwtFloorF( value ) * intervalSize;
     144    return ::floor( value ) * intervalSize;
    54145}
    55146
     
    72163
    73164/*!
    74   Find the smallest value out of {1,2,5}*10^n with an integer number n
    75   which is greater than or equal to x
    76 
    77   \param x Input value
    78 */
    79 double QwtScaleArithmetic::ceil125( double x )
    80 {
    81     if ( x == 0.0 )
     165  Calculate a step size for a given interval
     166
     167  \param intervalSize Interval size
     168  \param numSteps Number of steps
     169  \param base Base for the division ( usually 10 )
     170
     171  \return Calculated step size
     172 */
     173double QwtScaleArithmetic::divideInterval(
     174    double intervalSize, int numSteps, uint base )
     175{
     176    if ( numSteps <= 0 )
    82177        return 0.0;
    83178
    84     const double sign = ( x > 0 ) ? 1.0 : -1.0;
    85     const double lx = ::log10( qFabs( x ) );
    86     const double p10 = qwtFloorF( lx );
    87 
    88     double fr = qPow( 10.0, lx - p10 );
    89     if ( fr <= 1.0 )
    90         fr = 1.0;
    91     else if ( fr <= 2.0 )
    92         fr = 2.0;
    93     else if ( fr <= 5.0 )
    94         fr = 5.0;
    95     else
    96         fr = 10.0;
    97 
    98     return sign * fr * qPow( 10.0, p10 );
    99 }
    100 
    101 /*!
    102   \brief Find the largest value out of {1,2,5}*10^n with an integer number n
    103   which is smaller than or equal to x
    104 
    105   \param x Input value
    106 */
    107 double QwtScaleArithmetic::floor125( double x )
    108 {
    109     if ( x == 0.0 )
     179    const double v = QwtScaleArithmetic::divideEps( intervalSize, numSteps );
     180    if ( v == 0.0 )
    110181        return 0.0;
    111182
    112     double sign = ( x > 0 ) ? 1.0 : -1.0;
    113     const double lx = ::log10( qFabs( x ) );
    114     const double p10 = qwtFloorF( lx );
    115 
    116     double fr = qPow( 10.0, lx - p10 );
    117     if ( fr >= 10.0 )
    118         fr = 10.0;
    119     else if ( fr >= 5.0 )
    120         fr = 5.0;
    121     else if ( fr >= 2.0 )
    122         fr = 2.0;
    123     else
    124         fr = 1.0;
    125 
    126     return sign * fr * qPow( 10.0, p10 );
     183    const double lx = qwtLog( base, qFabs( v ) );
     184    const double p = ::floor( lx );
     185
     186    const double fraction = qPow( base, lx - p );
     187
     188    uint n = base;
     189    while ( ( n > 1 ) && ( fraction <= n / 2 ) )
     190        n /= 2;
     191
     192    double stepSize = n * qPow( base, p );
     193    if ( v < 0 )
     194        stepSize = -stepSize;
     195
     196    return stepSize;
    127197}
    128198
     
    134204        lowerMargin( 0.0 ),
    135205        upperMargin( 0.0 ),
    136         referenceValue( 0.0 )
    137     {
    138     }
    139 
    140     QwtScaleEngine::Attributes attributes;       // scale attributes
    141 
    142     double lowerMargin;      // margins
     206        referenceValue( 0.0 ),
     207        base( 10 ),
     208        transform( NULL )
     209    {
     210    }
     211
     212    ~PrivateData()
     213    {
     214        delete transform;
     215    }
     216
     217    QwtScaleEngine::Attributes attributes;
     218
     219    double lowerMargin;
    143220    double upperMargin;
    144221
    145     double referenceValue; // reference value
    146 
     222    double referenceValue;
     223
     224    uint base;
     225
     226    QwtTransform* transform;
    147227};
    148228
    149 //! Constructor
    150 QwtScaleEngine::QwtScaleEngine()
     229/*!
     230  Constructor
     231
     232  \param base Base of the scale engine
     233  \sa setBase()
     234 */
     235QwtScaleEngine::QwtScaleEngine( uint base )
    151236{
    152237    d_data = new PrivateData;
     238    setBase( base );
    153239}
    154240
     
    158244{
    159245    delete d_data;
     246}
     247
     248/*!
     249   Assign a transformation
     250
     251   \param transform Transformation
     252
     253   The transformation object is used as factory for clones
     254   that are returned by transformation()
     255
     256   The scale engine takes ownership of the transformation.
     257
     258   \sa QwtTransform::copy(), transformation()
     259
     260 */
     261void QwtScaleEngine::setTransformation( QwtTransform *transform )
     262{
     263    if ( transform != d_data->transform )
     264    {
     265        delete d_data->transform;
     266        d_data->transform = transform;
     267    }
     268}
     269
     270/*!
     271   Create and return a clone of the transformation
     272   of the engine. When the engine has no special transformation
     273   NULL is returned, indicating no transformation.
     274
     275   \return A clone of the transfomation
     276   \sa setTransformation()
     277 */
     278QwtTransform *QwtScaleEngine::transformation() const
     279{
     280    QwtTransform *transform = NULL;
     281    if ( d_data->transform )
     282        transform = d_data->transform->copy();
     283
     284    return transform;
    160285}
    161286
     
    193318
    194319  \warning
    195   \li QwtLog10ScaleEngine measures the margins in decades.
     320  \li QwtLogScaleEngine measures the margins in decades.
    196321
    197322  \sa upperMargin(), lowerMargin()
     
    215340    double intervalSize, int numSteps ) const
    216341{
    217     if ( numSteps <= 0 )
    218         return 0.0;
    219 
    220     double v = QwtScaleArithmetic::divideEps( intervalSize, numSteps );
    221     return QwtScaleArithmetic::ceil125( v );
     342    return QwtScaleArithmetic::divideInterval(
     343        intervalSize, numSteps, d_data->base );
    222344}
    223345
     
    228350  \param value Value
    229351
    230   \sa QwtScaleArithmetic::compareEps()
     352  \return True, when the value is inside the interval
    231353*/
    232354bool QwtScaleEngine::contains(
     
    275397
    276398/*!
    277   \brief Build an interval for a value
     399  \brief Build an interval around a value
    278400
    279401  In case of v == 0.0 the interval is [-0.5, 0.5],
    280402  otherwide it is [0.5 * v, 1.5 * v]
    281 */
    282 
    283 QwtInterval QwtScaleEngine::buildInterval( double v ) const
    284 {
    285     const double delta = ( v == 0.0 ) ? 0.5 : qAbs( 0.5 * v );
    286     return QwtInterval( v - delta, v + delta );
     403
     404  \param value Initial value
     405  \return Calculated interval
     406*/
     407
     408QwtInterval QwtScaleEngine::buildInterval( double value ) const
     409{
     410    const double delta = ( value == 0.0 ) ? 0.5 : qAbs( 0.5 * value );
     411
     412    if ( DBL_MAX - delta < value )
     413        return QwtInterval( DBL_MAX - delta, DBL_MAX );
     414
     415    if ( -DBL_MAX + delta > value )
     416        return QwtInterval( -DBL_MAX, -DBL_MAX + delta );
     417
     418    return QwtInterval( value - delta, value + delta );
    287419}
    288420
     
    304436
    305437/*!
    306   Check if a attribute is set.
     438  \return True, if attribute is enabled.
    307439
    308440  \param attribute Attribute to be tested
     
    326458
    327459/*!
    328   Return the scale attributes
     460  \return Scale attributes
    329461  \sa Attribute, setAttributes(), testAttribute()
    330462*/
     
    349481
    350482/*!
    351  \return the reference value
    352  \sa setReference(), setAttribute()
     483  \return the reference value
     484  \sa setReference(), setAttribute()
    353485*/
    354486double QwtScaleEngine::reference() const
     
    358490
    359491/*!
    360   Return a transformation, for linear scales
    361 */
    362 QwtScaleTransformation *QwtLinearScaleEngine::transformation() const
    363 {
    364     return new QwtScaleTransformation( QwtScaleTransformation::Linear );
    365 }
    366 
    367 /*!
    368     Align and divide an interval
    369 
    370    \param maxNumSteps Max. number of steps
    371    \param x1 First limit of the interval (In/Out)
    372    \param x2 Second limit of the interval (In/Out)
    373    \param stepSize Step size (Out)
    374 
    375    \sa setAttribute()
     492  Set the base of the scale engine
     493
     494  While a base of 10 is what 99.9% of all applications need
     495  certain scales might need a different base: f.e 2
     496
     497  The default setting is 10
     498
     499  \param base Base of the engine
     500
     501  \sa base()
     502 */
     503void QwtScaleEngine::setBase( uint base )
     504{
     505    d_data->base = qMax( base, 2U );
     506}
     507
     508/*!
     509  \return base Base of the scale engine
     510  \sa setBase()
     511 */
     512uint QwtScaleEngine::base() const
     513{
     514    return d_data->base;
     515}
     516
     517/*!
     518  Constructor
     519
     520  \param base Base of the scale engine
     521  \sa setBase()
     522 */
     523QwtLinearScaleEngine::QwtLinearScaleEngine( uint base ):
     524    QwtScaleEngine( base )
     525{
     526}
     527
     528//! Destructor
     529QwtLinearScaleEngine::~QwtLinearScaleEngine()
     530{
     531}
     532
     533/*!
     534  Align and divide an interval
     535
     536  \param maxNumSteps Max. number of steps
     537  \param x1 First limit of the interval (In/Out)
     538  \param x2 Second limit of the interval (In/Out)
     539  \param stepSize Step size (Out)
     540
     541  \sa setAttribute()
    376542*/
    377543void QwtLinearScaleEngine::autoScale( int maxNumSteps,
     
    393559        interval = buildInterval( interval.minValue() );
    394560
    395     stepSize = divideInterval( interval.width(), qMax( maxNumSteps, 1 ) );
     561    stepSize = QwtScaleArithmetic::divideInterval(
     562        interval.width(), qMax( maxNumSteps, 1 ), base() );
    396563
    397564    if ( !testAttribute( QwtScaleEngine::Floating ) )
     
    409576
    410577/*!
    411    \brief Calculate a scale division
     578   \brief Calculate a scale division for an interval
    412579
    413580   \param x1 First interval limit
    414581   \param x2 Second interval limit
    415    \param maxMajSteps Maximum for the number of major steps
    416    \param maxMinSteps Maximum number of minor steps
    417    \param stepSize Step size. If stepSize == 0, the scaleEngine
     582   \param maxMajorSteps Maximum for the number of major steps
     583   \param maxMinorSteps Maximum number of minor steps
     584   \param stepSize Step size. If stepSize == 0, the engine
    418585                   calculates one.
    419586
    420    \sa QwtScaleEngine::stepSize(), QwtScaleEngine::subDivide()
     587   \return Calculated scale division
    421588*/
    422589QwtScaleDiv QwtLinearScaleEngine::divideScale( double x1, double x2,
    423     int maxMajSteps, int maxMinSteps, double stepSize ) const
     590    int maxMajorSteps, int maxMinorSteps, double stepSize ) const
    424591{
    425592    QwtInterval interval = QwtInterval( x1, x2 ).normalized();
     593
     594    if ( qwtIntervalWidthL( interval ) > std::numeric_limits<double>::max() )
     595    {
     596        qWarning() << "QwtLinearScaleEngine::divideScale: overflow";
     597        return QwtScaleDiv();
     598    }
     599
    426600    if ( interval.width() <= 0 )
    427601        return QwtScaleDiv();
     
    430604    if ( stepSize == 0.0 )
    431605    {
    432         if ( maxMajSteps < 1 )
    433             maxMajSteps = 1;
    434 
    435         stepSize = divideInterval( interval.width(), maxMajSteps );
     606        if ( maxMajorSteps < 1 )
     607            maxMajorSteps = 1;
     608
     609        stepSize = QwtScaleArithmetic::divideInterval(
     610            interval.width(), maxMajorSteps, base() );
    436611    }
    437612
     
    441616    {
    442617        QList<double> ticks[QwtScaleDiv::NTickTypes];
    443         buildTicks( interval, stepSize, maxMinSteps, ticks );
     618        buildTicks( interval, stepSize, maxMinorSteps, ticks );
    444619
    445620        scaleDiv = QwtScaleDiv( interval, ticks );
     
    457632   \param interval Interval
    458633   \param stepSize Step size
    459    \param maxMinSteps Maximum number of minor steps
     634   \param maxMinorSteps Maximum number of minor steps
    460635   \param ticks Arrays to be filled with the calculated ticks
    461636
     
    463638*/
    464639void QwtLinearScaleEngine::buildTicks(
    465     const QwtInterval& interval, double stepSize, int maxMinSteps,
     640    const QwtInterval& interval, double stepSize, int maxMinorSteps,
    466641    QList<double> ticks[QwtScaleDiv::NTickTypes] ) const
    467642{
    468     const QwtInterval boundingInterval =
    469         align( interval, stepSize );
     643    const QwtInterval boundingInterval = align( interval, stepSize );
    470644
    471645    ticks[QwtScaleDiv::MajorTick] =
    472646        buildMajorTicks( boundingInterval, stepSize );
    473647
    474     if ( maxMinSteps > 0 )
    475     {
    476         buildMinorTicks( ticks[QwtScaleDiv::MajorTick], maxMinSteps, stepSize,
     648    if ( maxMinorSteps > 0 )
     649    {
     650        buildMinorTicks( ticks[QwtScaleDiv::MajorTick], maxMinorSteps, stepSize,
    477651            ticks[QwtScaleDiv::MinorTick], ticks[QwtScaleDiv::MediumTick] );
    478652    }
     
    522696
    523697   \param majorTicks Major ticks
    524    \param maxMinSteps Maximum number of minor steps
     698   \param maxMinorSteps Maximum number of minor steps
    525699   \param stepSize Step size
    526700   \param minorTicks Array to be filled with the calculated minor ticks
     
    530704void QwtLinearScaleEngine::buildMinorTicks(
    531705    const QList<double>& majorTicks,
    532     int maxMinSteps, double stepSize,
     706    int maxMinorSteps, double stepSize,
    533707    QList<double> &minorTicks,
    534708    QList<double> &mediumTicks ) const
    535709{
    536     double minStep = divideInterval( stepSize, maxMinSteps );
     710    double minStep = qwtStepSize( stepSize, maxMinorSteps, base() );
    537711    if ( minStep == 0.0 )
    538712        return;
    539713
    540714    // # ticks per interval
    541     int numTicks = qCeil( qAbs( stepSize / minStep ) ) - 1;
    542 
    543     // Do the minor steps fit into the interval?
    544     if ( qwtFuzzyCompare( ( numTicks +  1 ) * qAbs( minStep ),
    545         qAbs( stepSize ), stepSize ) > 0 )
    546     {
    547         numTicks = 1;
    548         minStep = stepSize * 0.5;
    549     }
     715    const int numTicks = qCeil( qAbs( stepSize / minStep ) ) - 1;
    550716
    551717    int medIndex = -1;
     
    588754    const QwtInterval &interval, double stepSize ) const
    589755{
    590     double x1 = QwtScaleArithmetic::floorEps( interval.minValue(), stepSize );
    591     if ( qwtFuzzyCompare( interval.minValue(), x1, stepSize ) == 0 )
    592         x1 = interval.minValue();
    593 
    594     double x2 = QwtScaleArithmetic::ceilEps( interval.maxValue(), stepSize );
    595     if ( qwtFuzzyCompare( interval.maxValue(), x2, stepSize ) == 0 )
    596         x2 = interval.maxValue();
     756    double x1 = interval.minValue();
     757    double x2 = interval.maxValue();
     758
     759    // when there is no rounding beside some effect, when
     760    // calculating with doubles, we keep the original value
     761
     762    const double eps = 0.000000000001; // since Qt 4.8: qFuzzyIsNull
     763    if ( -DBL_MAX + stepSize <= x1 )
     764    {
     765        const double x = QwtScaleArithmetic::floorEps( x1, stepSize );
     766        if ( qAbs(x) <= eps || !qFuzzyCompare( x1, x ) )
     767            x1 = x;
     768    }
     769
     770    if ( DBL_MAX - stepSize >= x2 )
     771    {
     772        const double x = QwtScaleArithmetic::ceilEps( x2, stepSize );
     773        if ( qAbs(x) <= eps || !qFuzzyCompare( x2, x ) )
     774            x2 = x;
     775    }
    597776
    598777    return QwtInterval( x1, x2 );
     
    600779
    601780/*!
    602   Return a transformation, for logarithmic (base 10) scales
    603 */
    604 QwtScaleTransformation *QwtLog10ScaleEngine::transformation() const
    605 {
    606     return new QwtScaleTransformation( QwtScaleTransformation::Log10 );
     781  Constructor
     782
     783  \param base Base of the scale engine
     784  \sa setBase()
     785 */
     786QwtLogScaleEngine::QwtLogScaleEngine( uint base ):
     787    QwtScaleEngine( base )
     788{
     789    setTransformation( new QwtLogTransform() );
     790}
     791
     792//! Destructor
     793QwtLogScaleEngine::~QwtLogScaleEngine()
     794{
    607795}
    608796
     
    617805   \sa QwtScaleEngine::setAttribute()
    618806*/
    619 void QwtLog10ScaleEngine::autoScale( int maxNumSteps,
    620                                      double &x1, double &x2, double &stepSize ) const
     807void QwtLogScaleEngine::autoScale( int maxNumSteps,
     808    double &x1, double &x2, double &stepSize ) const
    621809{
    622810    if ( x1 > x2 )
    623811        qSwap( x1, x2 );
    624812
    625     QwtInterval interval( x1 / qPow( 10.0, lowerMargin() ),
    626         x2 * qPow( 10.0, upperMargin() ) );
    627 
    628     if ( interval.maxValue() / interval.minValue() < 10.0 )
    629     {
    630         // scale width is less than one decade -> build linear scale
     813    const double logBase = base();
     814
     815    QwtInterval interval( x1 / qPow( logBase, lowerMargin() ),
     816        x2 * qPow( logBase, upperMargin() ) );
     817
     818    if ( interval.maxValue() / interval.minValue() < logBase )
     819    {
     820        // scale width is less than one step -> try to build a linear scale
    631821
    632822        QwtLinearScaleEngine linearScaler;
     
    636826
    637827        linearScaler.autoScale( maxNumSteps, x1, x2, stepSize );
    638         stepSize = ::log10( stepSize );
    639 
    640         return;
     828
     829        QwtInterval linearInterval = QwtInterval( x1, x2 ).normalized();
     830        linearInterval = linearInterval.limited( LOG_MIN, LOG_MAX );
     831
     832        if ( linearInterval.maxValue() / linearInterval.minValue() < logBase )
     833        {
     834            // the aligned scale is still less than one step
     835
     836#if 1
     837            // this code doesn't make any sense, but for compatibility
     838            // reasons we keep it until 6.2. But it will be ignored
     839            // in divideScale
     840
     841            if ( stepSize < 0.0 )
     842                stepSize = -qwtLog( logBase, qAbs( stepSize ) );
     843            else
     844                stepSize = qwtLog( logBase, stepSize );
     845#endif
     846
     847            return;
     848        }
    641849    }
    642850
     
    660868        interval = buildInterval( interval.minValue() );
    661869
    662     stepSize = divideInterval( log10( interval ).width(), qMax( maxNumSteps, 1 ) );
     870    stepSize = divideInterval( qwtLogInterval( logBase, interval ).width(),
     871        qMax( maxNumSteps, 1 ) );
    663872    if ( stepSize < 1.0 )
    664873        stepSize = 1.0;
     
    678887
    679888/*!
    680    \brief Calculate a scale division
     889   \brief Calculate a scale division for an interval
    681890
    682891   \param x1 First interval limit
    683892   \param x2 Second interval limit
    684    \param maxMajSteps Maximum for the number of major steps
    685    \param maxMinSteps Maximum number of minor steps
    686    \param stepSize Step size. If stepSize == 0, the scaleEngine
     893   \param maxMajorSteps Maximum for the number of major steps
     894   \param maxMinorSteps Maximum number of minor steps
     895   \param stepSize Step size. If stepSize == 0, the engine
    687896                   calculates one.
    688897
    689    \sa QwtScaleEngine::stepSize(), QwtLog10ScaleEngine::subDivide()
    690 */
    691 QwtScaleDiv QwtLog10ScaleEngine::divideScale( double x1, double x2,
    692     int maxMajSteps, int maxMinSteps, double stepSize ) const
     898   \return Calculated scale division
     899*/
     900QwtScaleDiv QwtLogScaleEngine::divideScale( double x1, double x2,
     901    int maxMajorSteps, int maxMinorSteps, double stepSize ) const
    693902{
    694903    QwtInterval interval = QwtInterval( x1, x2 ).normalized();
     
    698907        return QwtScaleDiv();
    699908
    700     if ( interval.maxValue() / interval.minValue() < 10.0 )
     909    const double logBase = base();
     910
     911    if ( interval.maxValue() / interval.minValue() < logBase )
    701912    {
    702913        // scale width is less than one decade -> build linear scale
     
    707918        linearScaler.setMargins( lowerMargin(), upperMargin() );
    708919
    709         if ( stepSize != 0.0 )
    710             stepSize = qPow( 10.0, stepSize );
    711 
    712920        return linearScaler.divideScale( x1, x2,
    713             maxMajSteps, maxMinSteps, stepSize );
     921            maxMajorSteps, maxMinorSteps, 0.0 );
    714922    }
    715923
     
    717925    if ( stepSize == 0.0 )
    718926    {
    719         if ( maxMajSteps < 1 )
    720             maxMajSteps = 1;
    721 
    722         stepSize = divideInterval( log10( interval ).width(), maxMajSteps );
     927        if ( maxMajorSteps < 1 )
     928            maxMajorSteps = 1;
     929
     930        stepSize = divideInterval(
     931            qwtLogInterval( logBase, interval ).width(), maxMajorSteps );
    723932        if ( stepSize < 1.0 )
    724933            stepSize = 1.0; // major step must be >= 1 decade
     
    729938    {
    730939        QList<double> ticks[QwtScaleDiv::NTickTypes];
    731         buildTicks( interval, stepSize, maxMinSteps, ticks );
     940        buildTicks( interval, stepSize, maxMinorSteps, ticks );
    732941
    733942        scaleDiv = QwtScaleDiv( interval, ticks );
     
    744953
    745954   \param interval Interval
    746    \param maxMinSteps Maximum number of minor steps
     955   \param maxMinorSteps Maximum number of minor steps
    747956   \param stepSize Step size
    748957   \param ticks Arrays to be filled with the calculated ticks
     
    750959   \sa buildMajorTicks(), buildMinorTicks
    751960*/
    752 void QwtLog10ScaleEngine::buildTicks(
    753     const QwtInterval& interval, double stepSize, int maxMinSteps,
     961void QwtLogScaleEngine::buildTicks(
     962    const QwtInterval& interval, double stepSize, int maxMinorSteps,
    754963    QList<double> ticks[QwtScaleDiv::NTickTypes] ) const
    755964{
     
    759968        buildMajorTicks( boundingInterval, stepSize );
    760969
    761     if ( maxMinSteps > 0 )
    762     {
    763         ticks[QwtScaleDiv::MinorTick] = buildMinorTicks(
    764             ticks[QwtScaleDiv::MajorTick], maxMinSteps, stepSize );
     970    if ( maxMinorSteps > 0 )
     971    {
     972        buildMinorTicks( ticks[QwtScaleDiv::MajorTick], maxMinorSteps, stepSize,
     973            ticks[QwtScaleDiv::MinorTick], ticks[QwtScaleDiv::MediumTick] );
    765974    }
    766975
     
    777986   \return Calculated ticks
    778987*/
    779 QList<double> QwtLog10ScaleEngine::buildMajorTicks(
     988QList<double> QwtLogScaleEngine::buildMajorTicks(
    780989    const QwtInterval &interval, double stepSize ) const
    781990{
    782     double width = log10( interval ).width();
     991    double width = qwtLogInterval( base(), interval ).width();
    783992
    784993    int numTicks = qRound( width / stepSize ) + 1;
     
    8061015
    8071016   \param majorTicks Major ticks
    808    \param maxMinSteps Maximum number of minor steps
     1017   \param maxMinorSteps Maximum number of minor steps
    8091018   \param stepSize Step size
    810 */
    811 QList<double> QwtLog10ScaleEngine::buildMinorTicks(
     1019   \param minorTicks Array to be filled with the calculated minor ticks
     1020   \param mediumTicks Array to be filled with the calculated medium ticks
     1021*/
     1022void QwtLogScaleEngine::buildMinorTicks(
    8121023    const QList<double> &majorTicks,
    813     int maxMinSteps, double stepSize ) const
    814 {
    815     if ( stepSize < 1.1 )          // major step width is one decade
    816     {
    817         if ( maxMinSteps < 1 )
    818             return QList<double>();
    819 
    820         int k0, kstep, kmax;
    821 
    822         if ( maxMinSteps >= 8 )
     1024    int maxMinorSteps, double stepSize,
     1025    QList<double> &minorTicks,
     1026    QList<double> &mediumTicks ) const
     1027{
     1028    const double logBase = base();
     1029
     1030    if ( stepSize < 1.1 )          // major step width is one base
     1031    {
     1032        double minStep = divideInterval( stepSize, maxMinorSteps + 1 );
     1033        if ( minStep == 0.0 )
     1034            return;
     1035       
     1036        const int numSteps = qRound( stepSize / minStep );
     1037
     1038        int mediumTickIndex = -1;
     1039        if ( ( numSteps > 2 ) && ( numSteps % 2 == 0 ) )
     1040            mediumTickIndex = numSteps / 2;
     1041
     1042        for ( int i = 0; i < majorTicks.count() - 1; i++ )
    8231043        {
    824             k0 = 2;
    825             kmax = 9;
    826             kstep = 1;
     1044            const double v = majorTicks[i];
     1045            const double s = logBase / numSteps;
     1046
     1047            if ( s >= 1.0 )
     1048            {
     1049                if ( !qFuzzyCompare( s, 1.0 ) )
     1050                    minorTicks += v * s;
     1051
     1052                for ( int j = 2; j < numSteps; j++ )
     1053                {
     1054                    minorTicks += v * j * s;
     1055                }
     1056            }
     1057            else
     1058            {
     1059                for ( int j = 1; j < numSteps; j++ )
     1060                {
     1061                    const double tick = v + j * v * ( logBase - 1 ) / numSteps;
     1062                    if ( j == mediumTickIndex )
     1063                        mediumTicks += tick;
     1064                    else
     1065                        minorTicks += tick;
     1066                }
     1067            }
    8271068        }
    828         else if ( maxMinSteps >= 4 )
     1069    }
     1070    else
     1071    {
     1072        double minStep = divideInterval( stepSize, maxMinorSteps );
     1073        if ( minStep == 0.0 )
     1074            return;
     1075
     1076        if ( minStep < 1.0 )
     1077            minStep = 1.0;
     1078
     1079        // # subticks per interval
     1080        int numTicks = qRound( stepSize / minStep ) - 1;
     1081
     1082        // Do the minor steps fit into the interval?
     1083        if ( qwtFuzzyCompare( ( numTicks +  1 ) * minStep,
     1084            stepSize, stepSize ) > 0 )
    8291085        {
    830             k0 = 2;
    831             kmax = 8;
    832             kstep = 2;
     1086            numTicks = 0;
    8331087        }
    834         else if ( maxMinSteps >= 2 )
    835         {
    836             k0 = 2;
    837             kmax = 5;
    838             kstep = 3;
    839         }
    840         else
    841         {
    842             k0 = 5;
    843             kmax = 5;
    844             kstep = 1;
    845         }
    846 
    847         QList<double> minorTicks;
     1088
     1089        if ( numTicks < 1 )
     1090            return;
     1091
     1092        int mediumTickIndex = -1;
     1093        if ( ( numTicks > 2 ) && ( numTicks % 2 ) )
     1094            mediumTickIndex = numTicks / 2;
     1095
     1096        // substep factor = base^substeps
     1097        const qreal minFactor = qMax( qPow( logBase, minStep ), qreal( logBase ) );
    8481098
    8491099        for ( int i = 0; i < majorTicks.count(); i++ )
    8501100        {
    851             const double v = majorTicks[i];
    852             for ( int k = k0; k <= kmax; k += kstep )
    853                 minorTicks += v * double( k );
    854         }
    855 
    856         return minorTicks;
    857     }
    858     else  // major step > one decade
    859     {
    860         double minStep = divideInterval( stepSize, maxMinSteps );
    861         if ( minStep == 0.0 )
    862             return QList<double>();
    863 
    864         if ( minStep < 1.0 )
    865             minStep = 1.0;
    866 
    867         // # subticks per interval
    868         int nMin = qRound( stepSize / minStep ) - 1;
    869 
    870         // Do the minor steps fit into the interval?
    871 
    872         if ( qwtFuzzyCompare( ( nMin +  1 ) * minStep,
    873             qAbs( stepSize ), stepSize ) > 0 )
    874         {
    875             nMin = 0;
    876         }
    877 
    878         if ( nMin < 1 )
    879             return QList<double>();      // no subticks
    880 
    881         // substep factor = 10^substeps
    882         const qreal minFactor = qMax( qPow( 10.0, minStep ), qreal( 10.0 ) );
    883 
    884         QList<double> minorTicks;
    885         for ( int i = 0; i < majorTicks.count(); i++ )
    886         {
    887             double val = majorTicks[i];
    888             for ( int k = 0; k < nMin; k++ )
     1101            double tick = majorTicks[i];
     1102            for ( int j = 0; j < numTicks; j++ )
    8891103            {
    890                 val *= minFactor;
    891                 minorTicks += val;
     1104                tick *= minFactor;
     1105
     1106                if ( j == mediumTickIndex )
     1107                    mediumTicks += tick;
     1108                else
     1109                    minorTicks += tick;
    8921110            }
    8931111        }
    894         return minorTicks;
    8951112    }
    8961113}
     
    9071124  \return Aligned interval
    9081125*/
    909 QwtInterval QwtLog10ScaleEngine::align(
     1126QwtInterval QwtLogScaleEngine::align(
    9101127    const QwtInterval &interval, double stepSize ) const
    9111128{
    912     const QwtInterval intv = log10( interval );
     1129    const QwtInterval intv = qwtLogInterval( base(), interval );
    9131130
    9141131    double x1 = QwtScaleArithmetic::floorEps( intv.minValue(), stepSize );
     
    9201137        x2 = interval.maxValue();
    9211138
    922     return pow10( QwtInterval( x1, x2 ) );
    923 }
    924 
    925 /*!
    926   Return the interval [log10(interval.minValue(), log10(interval.maxValue]
    927 */
    928 
    929 QwtInterval QwtLog10ScaleEngine::log10( const QwtInterval &interval ) const
    930 {
    931     return QwtInterval( ::log10( interval.minValue() ),
    932             ::log10( interval.maxValue() ) );
    933 }
    934 
    935 /*!
    936   Return the interval [pow10(interval.minValue(), pow10(interval.maxValue]
    937 */
    938 QwtInterval QwtLog10ScaleEngine::pow10( const QwtInterval &interval ) const
    939 {
    940     return QwtInterval( qPow( 10.0, interval.minValue() ),
    941             qPow( 10.0, interval.maxValue() ) );
    942 }
     1139    return qwtPowInterval( base(), QwtInterval( x1, x2 ) );
     1140}
Note: See TracChangeset for help on using the changeset viewer.