Skip to content
qwt_scale_engine.cpp 27.5 KiB
Newer Older
pixhawk's avatar
pixhawk committed
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
 * Qwt Widget Library
 * Copyright (C) 1997   Josef Wilgen
 * Copyright (C) 2002   Uwe Rathmann
pixhawk's avatar
pixhawk committed
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the Qwt License, Version 1.0
 *****************************************************************************/

Bryant's avatar
Bryant committed
#include "qwt_scale_engine.h"
pixhawk's avatar
pixhawk committed
#include "qwt_math.h"
#include "qwt_scale_map.h"
Bryant's avatar
Bryant committed
#include <qalgorithms.h>
#include <qmath.h>
#include <float.h>
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
#if QT_VERSION < 0x040601
#define qFabs(x) ::fabs(x)
#define qExp(x) ::exp(x)
#endif
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
static inline double qwtLog( double base, double value )
{
    return log( value ) / log( base );
}

static inline QwtInterval qwtLogInterval( double base, const QwtInterval &interval )
{
    return QwtInterval( qwtLog( base, interval.minValue() ),
            qwtLog( base, interval.maxValue() ) );
}

static inline QwtInterval qwtPowInterval( double base, const QwtInterval &interval ) 
{
    return QwtInterval( qPow( base, interval.minValue() ),
            qPow( base, interval.maxValue() ) );
}
pixhawk's avatar
pixhawk committed


Bryant's avatar
Bryant committed
#if 1
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
// this version often doesn't find the best ticks: f.e for 15: 5, 10
static double qwtStepSize( double intervalSize, int maxSteps, uint base )
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    const double minStep = 
        QwtScaleArithmetic::divideInterval( intervalSize, maxSteps, base );

    if ( minStep != 0.0 )
    {
        // # ticks per interval
        const int numTicks = qCeil( qAbs( intervalSize / minStep ) ) - 1;

        // Do the minor steps fit into the interval?
        if ( qwtFuzzyCompare( ( numTicks +  1 ) * qAbs( minStep ),
            qAbs( intervalSize ), intervalSize ) > 0 )
        {
            // The minor steps doesn't fit into the interval
            return 0.5 * intervalSize;
        }
    }

    return minStep;
}
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
#else
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
static double qwtStepSize( double intervalSize, int maxSteps, uint base )
{
    if ( maxSteps <= 0 )
        return 0.0;

    if ( maxSteps > 2 )
    {
        for ( int numSteps = maxSteps; numSteps > 1; numSteps-- )
        {
            const double stepSize = intervalSize / numSteps;

            const double p = ::floor( ::log( stepSize ) / ::log( base ) );
            const double fraction = qPow( base, p );

            for ( uint n = base; n > 1; n /= 2 )
            {
                if ( qFuzzyCompare( stepSize, n * fraction ) )
                    return stepSize;

                if ( n == 3 && ( base % 2 ) == 0 )
                {
                    if ( qFuzzyCompare( stepSize, 2 * fraction ) )
                        return stepSize;
                }
            }
        }
    }
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    return intervalSize * 0.5;
pixhawk's avatar
pixhawk committed
}

Bryant's avatar
Bryant committed
#endif

static const double _eps = 1.0e-6;

pixhawk's avatar
pixhawk committed
/*!
  Ceil a value, relative to an interval

Bryant's avatar
Bryant committed
  \param value Value to be ceiled
pixhawk's avatar
pixhawk committed
  \param intervalSize Interval size
Bryant's avatar
Bryant committed
  \return Rounded value

  \sa floorEps()
pixhawk's avatar
pixhawk committed
*/
Bryant's avatar
Bryant committed
double QwtScaleArithmetic::ceilEps( double value,
    double intervalSize )
pixhawk's avatar
pixhawk committed
{
    const double eps = _eps * intervalSize;

Bryant's avatar
Bryant committed
    value = ( value - eps ) / intervalSize;
    return ::ceil( value ) * intervalSize;
pixhawk's avatar
pixhawk committed
}

/*!
  Floor a value, relative to an interval

Bryant's avatar
Bryant committed
  \param value Value to be floored
pixhawk's avatar
pixhawk committed
  \param intervalSize Interval size
Bryant's avatar
Bryant committed
  \return Rounded value
  \sa floorEps()
pixhawk's avatar
pixhawk committed
*/
Bryant's avatar
Bryant committed
double QwtScaleArithmetic::floorEps( double value, double intervalSize )
pixhawk's avatar
pixhawk committed
{
    const double eps = _eps * intervalSize;

Bryant's avatar
Bryant committed
    value = ( value + eps ) / intervalSize;
    return ::floor( value ) * intervalSize;
pixhawk's avatar
pixhawk committed
}

Bryant's avatar
Bryant committed
/*!
pixhawk's avatar
pixhawk committed
  \brief Divide an interval into steps

  \f$stepSize = (intervalSize - intervalSize * 10e^{-6}) / numSteps\f$

  \param intervalSize Interval size
  \param numSteps Number of steps
  \return Step size
*/
Bryant's avatar
Bryant committed
double QwtScaleArithmetic::divideEps( double intervalSize, double numSteps )
pixhawk's avatar
pixhawk committed
{
    if ( numSteps == 0.0 || intervalSize == 0.0 )
        return 0.0;

Bryant's avatar
Bryant committed
    return ( intervalSize - ( _eps * intervalSize ) ) / numSteps;
pixhawk's avatar
pixhawk committed

/*!
Bryant's avatar
Bryant committed
  Calculate a step size for a given interval
Bryant's avatar
Bryant committed
  \param intervalSize Interval size
  \param numSteps Number of steps
  \param base Base for the division ( usually 10 )

  \return Calculated step size
 */
double QwtScaleArithmetic::divideInterval( 
    double intervalSize, int numSteps, uint base ) 
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    if ( numSteps <= 0 )
pixhawk's avatar
pixhawk committed
        return 0.0;

Bryant's avatar
Bryant committed
    const double v = QwtScaleArithmetic::divideEps( intervalSize, numSteps );
    if ( v == 0.0 )
        return 0.0;
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    const double lx = qwtLog( base, qFabs( v ) );
    const double p = ::floor( lx );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    const double fraction = qPow( base, lx - p );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    uint n = base;
    while ( ( n > 1 ) && ( fraction <= n / 2 ) )
        n /= 2;
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    double stepSize = n * qPow( base, p );
    if ( v < 0 )
        stepSize = -stepSize;
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    return stepSize;
pixhawk's avatar
pixhawk committed
}

class QwtScaleEngine::PrivateData
{
public:
    PrivateData():
Bryant's avatar
Bryant committed
        attributes( QwtScaleEngine::NoAttribute ),
        lowerMargin( 0.0 ),
        upperMargin( 0.0 ),
        referenceValue( 0.0 ),
        base( 10 ),
        transform( NULL )
    {
Loading
Loading full blame...