123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395 |
- /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
- * Qwt Widget Library
- * Copyright (C) 1997 Josef Wilgen
- * Copyright (C) 2002 Uwe Rathmann
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the Qwt License, Version 1.0
- *****************************************************************************/
- #include "qwt_double_range.h"
- #include "qwt_math.h"
- #if QT_VERSION < 0x040601
- #define qFabs(x) ::fabs(x)
- #endif
- static double MinRelStep = 1.0e-10;
- static double DefaultRelStep = 1.0e-2;
- static double MinEps = 1.0e-10;
- /*!
- The range is initialized to [0.0, 100.0], the
- step size to 1.0, and the value to 0.0.
- */
- QwtDoubleRange::QwtDoubleRange():
- d_minValue( 0.0 ),
- d_maxValue( 0.0 ),
- d_step( 1.0 ),
- d_pageSize( 1 ),
- d_isValid( false ),
- d_value( 0.0 ),
- d_exactValue( 0.0 ),
- d_exactPrevValue( 0.0 ),
- d_prevValue( 0.0 ),
- d_periodic( false )
- {
- }
- //! Destroys the QwtDoubleRange
- QwtDoubleRange::~QwtDoubleRange()
- {
- }
- //! Set the value to be valid/invalid
- void QwtDoubleRange::setValid( bool isValid )
- {
- if ( isValid != d_isValid )
- {
- d_isValid = isValid;
- valueChange();
- }
- }
- //! Indicates if the value is valid
- bool QwtDoubleRange::isValid() const
- {
- return d_isValid;
- }
- /*!
- \brief No docs
- Description
- \param x ???
- \param align
- \todo Documentation
- */
- void QwtDoubleRange::setNewValue( double x, bool align )
- {
- double vmin, vmax;
- d_prevValue = d_value;
- vmin = qMin( d_minValue, d_maxValue );
- vmax = qMax( d_minValue, d_maxValue );
- //
- // Range check
- //
- if ( x < vmin )
- {
- if ( ( d_periodic ) && ( vmin != vmax ) )
- d_value = x + qCeil( ( vmin - x ) / ( vmax - vmin ) )
- * ( vmax - vmin );
- else
- d_value = vmin;
- }
- else if ( x > vmax )
- {
- if ( ( d_periodic ) && ( vmin != vmax ) )
- d_value = x - qCeil( ( x - vmax ) / ( vmax - vmin ) )
- * ( vmax - vmin );
- else
- d_value = vmax;
- }
- else
- d_value = x;
- d_exactPrevValue = d_exactValue;
- d_exactValue = d_value;
- // align to grid
- if ( align )
- {
- if ( d_step != 0.0 )
- {
- d_value = d_minValue +
- qRound( ( d_value - d_minValue ) / d_step ) * d_step;
- }
- else
- d_value = d_minValue;
- // correct rounding error at the border
- if ( qFabs( d_value - d_maxValue ) < MinEps * qAbs( d_step ) )
- d_value = d_maxValue;
- // correct rounding error if value = 0
- if ( qFabs( d_value ) < MinEps * qAbs( d_step ) )
- d_value = 0.0;
- }
- if ( !d_isValid || d_prevValue != d_value )
- {
- d_isValid = true;
- valueChange();
- }
- }
- /*!
- \brief Adjust the value to the closest point in the step raster.
- \param x value
- \warning The value is clipped when it lies outside the range.
- When the range is QwtDoubleRange::periodic, it will
- be mapped to a point in the interval such that
- \verbatim new value := x + n * (max. value - min. value)\endverbatim
- with an integer number n.
- */
- void QwtDoubleRange::fitValue( double x )
- {
- setNewValue( x, true );
- }
- /*!
- \brief Set a new value without adjusting to the step raster
- \param x new value
- \warning The value is clipped when it lies outside the range.
- When the range is QwtDoubleRange::periodic, it will
- be mapped to a point in the interval such that
- \verbatim new value := x + n * (max. value - min. value)\endverbatim
- with an integer number n.
- */
- void QwtDoubleRange::setValue( double x )
- {
- setNewValue( x, false );
- }
- /*!
- \brief Specify range and step size
- \param vmin lower boundary of the interval
- \param vmax higher boundary of the interval
- \param vstep step width
- \param pageSize page size in steps
- \warning
- \li A change of the range changes the value if it lies outside the
- new range. The current value
- will *not* be adjusted to the new step raster.
- \li vmax < vmin is allowed.
- \li If the step size is left out or set to zero, it will be
- set to 1/100 of the interval length.
- \li If the step size has an absurd value, it will be corrected
- to a better one.
- */
- void QwtDoubleRange::setRange( double vmin, double vmax, double vstep, int pageSize )
- {
- bool rchg = ( ( d_maxValue != vmax ) || ( d_minValue != vmin ) );
- if ( rchg )
- {
- d_minValue = vmin;
- d_maxValue = vmax;
- }
- //
- // look if the step width has an acceptable
- // value or otherwise change it.
- //
- setStep( vstep );
- //
- // limit page size
- //
- d_pageSize = qwtLim( pageSize, 0,
- int( qAbs( ( d_maxValue - d_minValue ) / d_step ) ) );
- // If the value lies out of the range, it
- // will be changed. Note that it will not be adjusted to
- // the new step width.
- setNewValue( d_value, false );
- // call notifier after the step width has been
- // adjusted.
- if ( rchg )
- rangeChange();
- }
- /*!
- \brief Change the step raster
- \param vstep new step width
- \warning The value will \e not be adjusted to the new step raster.
- */
- void QwtDoubleRange::setStep( double vstep )
- {
- double intv = d_maxValue - d_minValue;
- double newStep;
- if ( vstep == 0.0 )
- newStep = intv * DefaultRelStep;
- else
- {
- if ( ( intv > 0.0 && vstep < 0.0 ) || ( intv < 0.0 && vstep > 0.0 ) )
- newStep = -vstep;
- else
- newStep = vstep;
- if ( qFabs( newStep ) < qFabs( MinRelStep * intv ) )
- newStep = MinRelStep * intv;
- }
- if ( newStep != d_step )
- {
- d_step = newStep;
- stepChange();
- }
- }
- /*!
- \brief Make the range periodic
- When the range is periodic, the value will be set to a point
- inside the interval such that
- \verbatim point = value + n * width \endverbatim
- if the user tries to set a new value which is outside the range.
- If the range is nonperiodic (the default), values outside the
- range will be clipped.
- \param tf true for a periodic range
- */
- void QwtDoubleRange::setPeriodic( bool tf )
- {
- d_periodic = tf;
- }
- /*!
- \brief Increment the value by a specified number of steps
- \param nSteps Number of steps to increment
- \warning As a result of this operation, the new value will always be
- adjusted to the step raster.
- */
- void QwtDoubleRange::incValue( int nSteps )
- {
- if ( isValid() )
- setNewValue( d_value + double( nSteps ) * d_step, true );
- }
- /*!
- \brief Increment the value by a specified number of pages
- \param nPages Number of pages to increment.
- A negative number decrements the value.
- \warning The Page size is specified in the constructor.
- */
- void QwtDoubleRange::incPages( int nPages )
- {
- if ( isValid() )
- setNewValue( d_value + double( nPages ) * double( d_pageSize ) * d_step, true );
- }
- /*!
- \brief Notify a change of value
- This virtual function is called whenever the value changes.
- The default implementation does nothing.
- */
- void QwtDoubleRange::valueChange()
- {
- }
- /*!
- \brief Notify a change of the range
- This virtual function is called whenever the range changes.
- The default implementation does nothing.
- */
- void QwtDoubleRange::rangeChange()
- {
- }
- /*!
- \brief Notify a change of the step size
- This virtual function is called whenever the step size changes.
- The default implementation does nothing.
- */
- void QwtDoubleRange::stepChange()
- {
- }
- /*!
- \return the step size
- \sa setStep(), setRange()
- */
- double QwtDoubleRange::step() const
- {
- return qAbs( d_step );
- }
- /*!
- \brief Returns the value of the second border of the range
- maxValue returns the value which has been specified
- as the second parameter in QwtDoubleRange::setRange.
- \sa setRange()
- */
- double QwtDoubleRange::maxValue() const
- {
- return d_maxValue;
- }
- /*!
- \brief Returns the value at the first border of the range
- minValue returns the value which has been specified
- as the first parameter in setRange().
- \sa setRange()
- */
- double QwtDoubleRange::minValue() const
- {
- return d_minValue;
- }
- /*!
- \brief Returns true if the range is periodic
- \sa setPeriodic()
- */
- bool QwtDoubleRange::periodic() const
- {
- return d_periodic;
- }
- //! Returns the page size in steps.
- int QwtDoubleRange::pageSize() const
- {
- return d_pageSize;
- }
- //! Returns the current value.
- double QwtDoubleRange::value() const
- {
- return d_value;
- }
- /*!
- \brief Returns the exact value
- The exact value is the value which QwtDoubleRange::value would return
- if the value were not adjusted to the step raster. It differs from
- the current value only if QwtDoubleRange::fitValue or
- QwtDoubleRange::incValue have been used before. This function
- is intended for internal use in derived classes.
- */
- double QwtDoubleRange::exactValue() const
- {
- return d_exactValue;
- }
- //! Returns the exact previous value
- double QwtDoubleRange::exactPrevValue() const
- {
- return d_exactPrevValue;
- }
- //! Returns the previous value
- double QwtDoubleRange::prevValue() const
- {
- return d_prevValue;
- }
|