| 1 | /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
 | 
|---|
| 2 |  * Qwt Widget Library
 | 
|---|
| 3 |  * Copyright (C) 1997   Josef Wilgen
 | 
|---|
| 4 |  * Copyright (C) 2002   Uwe Rathmann
 | 
|---|
| 5 |  *
 | 
|---|
| 6 |  * This library is free software; you can redistribute it and/or
 | 
|---|
| 7 |  * modify it under the terms of the Qwt License, Version 1.0
 | 
|---|
| 8 |  *****************************************************************************/
 | 
|---|
| 9 | 
 | 
|---|
| 10 | #include "qwt_scale_engine.h"
 | 
|---|
| 11 | #include "qwt_math.h"
 | 
|---|
| 12 | #include "qwt_scale_map.h"
 | 
|---|
| 13 | #include <qalgorithms.h>
 | 
|---|
| 14 | #include <qmath.h>
 | 
|---|
| 15 | 
 | 
|---|
| 16 | #if QT_VERSION < 0x040601
 | 
|---|
| 17 | #define qFabs(x) ::fabs(x)
 | 
|---|
| 18 | #define qExp(x) ::exp(x)
 | 
|---|
| 19 | #endif
 | 
|---|
| 20 | 
 | 
|---|
| 21 | static const double _eps = 1.0e-6;
 | 
|---|
| 22 | 
 | 
|---|
| 23 | /*!
 | 
|---|
| 24 |   Ceil a value, relative to an interval
 | 
|---|
| 25 | 
 | 
|---|
| 26 |   \param value Value to ceil
 | 
|---|
| 27 |   \param intervalSize Interval size
 | 
|---|
| 28 | 
 | 
|---|
| 29 |   \sa floorEps()
 | 
|---|
| 30 | */
 | 
|---|
| 31 | double QwtScaleArithmetic::ceilEps( double value,
 | 
|---|
| 32 |     double intervalSize )
 | 
|---|
| 33 | {
 | 
|---|
| 34 |     const double eps = _eps * intervalSize;
 | 
|---|
| 35 | 
 | 
|---|
| 36 |     value = ( value - eps ) / intervalSize;
 | 
|---|
| 37 |     return qwtCeilF( value ) * intervalSize;
 | 
|---|
| 38 | }
 | 
|---|
| 39 | 
 | 
|---|
| 40 | /*!
 | 
|---|
| 41 |   Floor a value, relative to an interval
 | 
|---|
| 42 | 
 | 
|---|
| 43 |   \param value Value to floor
 | 
|---|
| 44 |   \param intervalSize Interval size
 | 
|---|
| 45 | 
 | 
|---|
| 46 |   \sa floorEps()
 | 
|---|
| 47 | */
 | 
|---|
| 48 | double QwtScaleArithmetic::floorEps( double value, double intervalSize )
 | 
|---|
| 49 | {
 | 
|---|
| 50 |     const double eps = _eps * intervalSize;
 | 
|---|
| 51 | 
 | 
|---|
| 52 |     value = ( value + eps ) / intervalSize;
 | 
|---|
| 53 |     return qwtFloorF( value ) * intervalSize;
 | 
|---|
| 54 | }
 | 
|---|
| 55 | 
 | 
|---|
| 56 | /*!
 | 
|---|
| 57 |   \brief Divide an interval into steps
 | 
|---|
| 58 | 
 | 
|---|
| 59 |   \f$stepSize = (intervalSize - intervalSize * 10e^{-6}) / numSteps\f$
 | 
|---|
| 60 | 
 | 
|---|
| 61 |   \param intervalSize Interval size
 | 
|---|
| 62 |   \param numSteps Number of steps
 | 
|---|
| 63 |   \return Step size
 | 
|---|
| 64 | */
 | 
|---|
| 65 | double QwtScaleArithmetic::divideEps( double intervalSize, double numSteps )
 | 
|---|
| 66 | {
 | 
|---|
| 67 |     if ( numSteps == 0.0 || intervalSize == 0.0 )
 | 
|---|
| 68 |         return 0.0;
 | 
|---|
| 69 | 
 | 
|---|
| 70 |     return ( intervalSize - ( _eps * intervalSize ) ) / numSteps;
 | 
|---|
| 71 | }
 | 
|---|
| 72 | 
 | 
|---|
| 73 | /*!
 | 
|---|
| 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 )
 | 
|---|
| 82 |         return 0.0;
 | 
|---|
| 83 | 
 | 
|---|
| 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 )
 | 
|---|
| 110 |         return 0.0;
 | 
|---|
| 111 | 
 | 
|---|
| 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 );
 | 
|---|
| 127 | }
 | 
|---|
| 128 | 
 | 
|---|
| 129 | class QwtScaleEngine::PrivateData
 | 
|---|
| 130 | {
 | 
|---|
| 131 | public:
 | 
|---|
| 132 |     PrivateData():
 | 
|---|
| 133 |         attributes( QwtScaleEngine::NoAttribute ),
 | 
|---|
| 134 |         lowerMargin( 0.0 ),
 | 
|---|
| 135 |         upperMargin( 0.0 ),
 | 
|---|
| 136 |         referenceValue( 0.0 )
 | 
|---|
| 137 |     {
 | 
|---|
| 138 |     }
 | 
|---|
| 139 | 
 | 
|---|
| 140 |     QwtScaleEngine::Attributes attributes;       // scale attributes
 | 
|---|
| 141 | 
 | 
|---|
| 142 |     double lowerMargin;      // margins
 | 
|---|
| 143 |     double upperMargin;
 | 
|---|
| 144 | 
 | 
|---|
| 145 |     double referenceValue; // reference value
 | 
|---|
| 146 | 
 | 
|---|
| 147 | };
 | 
|---|
| 148 | 
 | 
|---|
| 149 | //! Constructor
 | 
|---|
| 150 | QwtScaleEngine::QwtScaleEngine()
 | 
|---|
| 151 | {
 | 
|---|
| 152 |     d_data = new PrivateData;
 | 
|---|
| 153 | }
 | 
|---|
| 154 | 
 | 
|---|
| 155 | 
 | 
|---|
| 156 | //! Destructor
 | 
|---|
| 157 | QwtScaleEngine::~QwtScaleEngine ()
 | 
|---|
| 158 | {
 | 
|---|
| 159 |     delete d_data;
 | 
|---|
| 160 | }
 | 
|---|
| 161 | 
 | 
|---|
| 162 | /*!
 | 
|---|
| 163 |     \return the margin at the lower end of the scale
 | 
|---|
| 164 |     The default margin is 0.
 | 
|---|
| 165 | 
 | 
|---|
| 166 |     \sa setMargins()
 | 
|---|
| 167 | */
 | 
|---|
| 168 | double QwtScaleEngine::lowerMargin() const
 | 
|---|
| 169 | {
 | 
|---|
| 170 |     return d_data->lowerMargin;
 | 
|---|
| 171 | }
 | 
|---|
| 172 | 
 | 
|---|
| 173 | /*!
 | 
|---|
| 174 |     \return the margin at the upper end of the scale
 | 
|---|
| 175 |     The default margin is 0.
 | 
|---|
| 176 | 
 | 
|---|
| 177 |     \sa setMargins()
 | 
|---|
| 178 | */
 | 
|---|
| 179 | double QwtScaleEngine::upperMargin() const
 | 
|---|
| 180 | {
 | 
|---|
| 181 |     return d_data->upperMargin;
 | 
|---|
| 182 | }
 | 
|---|
| 183 | 
 | 
|---|
| 184 | /*!
 | 
|---|
| 185 |   \brief Specify margins at the scale's endpoints
 | 
|---|
| 186 |   \param lower minimum distance between the scale's lower boundary and the
 | 
|---|
| 187 |              smallest enclosed value
 | 
|---|
| 188 |   \param upper minimum distance between the scale's upper boundary and the
 | 
|---|
| 189 |              greatest enclosed value
 | 
|---|
| 190 | 
 | 
|---|
| 191 |   Margins can be used to leave a minimum amount of space between
 | 
|---|
| 192 |   the enclosed intervals and the boundaries of the scale.
 | 
|---|
| 193 | 
 | 
|---|
| 194 |   \warning
 | 
|---|
| 195 |   \li QwtLog10ScaleEngine measures the margins in decades.
 | 
|---|
| 196 | 
 | 
|---|
| 197 |   \sa upperMargin(), lowerMargin()
 | 
|---|
| 198 | */
 | 
|---|
| 199 | 
 | 
|---|
| 200 | void QwtScaleEngine::setMargins( double lower, double upper )
 | 
|---|
| 201 | {
 | 
|---|
| 202 |     d_data->lowerMargin = qMax( lower, 0.0 );
 | 
|---|
| 203 |     d_data->upperMargin = qMax( upper, 0.0 );
 | 
|---|
| 204 | }
 | 
|---|
| 205 | 
 | 
|---|
| 206 | /*!
 | 
|---|
| 207 |   Calculate a step size for an interval size
 | 
|---|
| 208 | 
 | 
|---|
| 209 |   \param intervalSize Interval size
 | 
|---|
| 210 |   \param numSteps Number of steps
 | 
|---|
| 211 | 
 | 
|---|
| 212 |   \return Step size
 | 
|---|
| 213 | */
 | 
|---|
| 214 | double QwtScaleEngine::divideInterval(
 | 
|---|
| 215 |     double intervalSize, int numSteps ) const
 | 
|---|
| 216 | {
 | 
|---|
| 217 |     if ( numSteps <= 0 )
 | 
|---|
| 218 |         return 0.0;
 | 
|---|
| 219 | 
 | 
|---|
| 220 |     double v = QwtScaleArithmetic::divideEps( intervalSize, numSteps );
 | 
|---|
| 221 |     return QwtScaleArithmetic::ceil125( v );
 | 
|---|
| 222 | }
 | 
|---|
| 223 | 
 | 
|---|
| 224 | /*!
 | 
|---|
| 225 |   Check if an interval "contains" a value
 | 
|---|
| 226 | 
 | 
|---|
| 227 |   \param interval Interval
 | 
|---|
| 228 |   \param value Value
 | 
|---|
| 229 | 
 | 
|---|
| 230 |   \sa QwtScaleArithmetic::compareEps()
 | 
|---|
| 231 | */
 | 
|---|
| 232 | bool QwtScaleEngine::contains(
 | 
|---|
| 233 |     const QwtInterval &interval, double value ) const
 | 
|---|
| 234 | {
 | 
|---|
| 235 |     if ( !interval.isValid() )
 | 
|---|
| 236 |         return false;
 | 
|---|
| 237 | 
 | 
|---|
| 238 |     if ( qwtFuzzyCompare( value, interval.minValue(), interval.width() ) < 0 )
 | 
|---|
| 239 |         return false;
 | 
|---|
| 240 | 
 | 
|---|
| 241 |     if ( qwtFuzzyCompare( value, interval.maxValue(), interval.width() ) > 0 )
 | 
|---|
| 242 |         return false;
 | 
|---|
| 243 | 
 | 
|---|
| 244 |     return true;
 | 
|---|
| 245 | }
 | 
|---|
| 246 | 
 | 
|---|
| 247 | /*!
 | 
|---|
| 248 |   Remove ticks from a list, that are not inside an interval
 | 
|---|
| 249 | 
 | 
|---|
| 250 |   \param ticks Tick list
 | 
|---|
| 251 |   \param interval Interval
 | 
|---|
| 252 | 
 | 
|---|
| 253 |   \return Stripped tick list
 | 
|---|
| 254 | */
 | 
|---|
| 255 | QList<double> QwtScaleEngine::strip( const QList<double>& ticks,
 | 
|---|
| 256 |     const QwtInterval &interval ) const
 | 
|---|
| 257 | {
 | 
|---|
| 258 |     if ( !interval.isValid() || ticks.count() == 0 )
 | 
|---|
| 259 |         return QList<double>();
 | 
|---|
| 260 | 
 | 
|---|
| 261 |     if ( contains( interval, ticks.first() )
 | 
|---|
| 262 |         && contains( interval, ticks.last() ) )
 | 
|---|
| 263 |     {
 | 
|---|
| 264 |         return ticks;
 | 
|---|
| 265 |     }
 | 
|---|
| 266 | 
 | 
|---|
| 267 |     QList<double> strippedTicks;
 | 
|---|
| 268 |     for ( int i = 0; i < ticks.count(); i++ )
 | 
|---|
| 269 |     {
 | 
|---|
| 270 |         if ( contains( interval, ticks[i] ) )
 | 
|---|
| 271 |             strippedTicks += ticks[i];
 | 
|---|
| 272 |     }
 | 
|---|
| 273 |     return strippedTicks;
 | 
|---|
| 274 | }
 | 
|---|
| 275 | 
 | 
|---|
| 276 | /*!
 | 
|---|
| 277 |   \brief Build an interval for a value
 | 
|---|
| 278 | 
 | 
|---|
| 279 |   In case of v == 0.0 the interval is [-0.5, 0.5],
 | 
|---|
| 280 |   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 );
 | 
|---|
| 287 | }
 | 
|---|
| 288 | 
 | 
|---|
| 289 | /*!
 | 
|---|
| 290 |   Change a scale attribute
 | 
|---|
| 291 | 
 | 
|---|
| 292 |   \param attribute Attribute to change
 | 
|---|
| 293 |   \param on On/Off
 | 
|---|
| 294 | 
 | 
|---|
| 295 |   \sa Attribute, testAttribute()
 | 
|---|
| 296 | */
 | 
|---|
| 297 | void QwtScaleEngine::setAttribute( Attribute attribute, bool on )
 | 
|---|
| 298 | {
 | 
|---|
| 299 |     if ( on )
 | 
|---|
| 300 |         d_data->attributes |= attribute;
 | 
|---|
| 301 |     else
 | 
|---|
| 302 |         d_data->attributes &= ~attribute;
 | 
|---|
| 303 | }
 | 
|---|
| 304 | 
 | 
|---|
| 305 | /*!
 | 
|---|
| 306 |   Check if a attribute is set.
 | 
|---|
| 307 | 
 | 
|---|
| 308 |   \param attribute Attribute to be tested
 | 
|---|
| 309 |   \sa Attribute, setAttribute()
 | 
|---|
| 310 | */
 | 
|---|
| 311 | bool QwtScaleEngine::testAttribute( Attribute attribute ) const
 | 
|---|
| 312 | {
 | 
|---|
| 313 |     return ( d_data->attributes & attribute );
 | 
|---|
| 314 | }
 | 
|---|
| 315 | 
 | 
|---|
| 316 | /*!
 | 
|---|
| 317 |   Change the scale attribute
 | 
|---|
| 318 | 
 | 
|---|
| 319 |   \param attributes Set scale attributes
 | 
|---|
| 320 |   \sa Attribute, attributes()
 | 
|---|
| 321 | */
 | 
|---|
| 322 | void QwtScaleEngine::setAttributes( Attributes attributes )
 | 
|---|
| 323 | {
 | 
|---|
| 324 |     d_data->attributes = attributes;
 | 
|---|
| 325 | }
 | 
|---|
| 326 | 
 | 
|---|
| 327 | /*!
 | 
|---|
| 328 |   Return the scale attributes
 | 
|---|
| 329 |   \sa Attribute, setAttributes(), testAttribute()
 | 
|---|
| 330 | */
 | 
|---|
| 331 | QwtScaleEngine::Attributes QwtScaleEngine::attributes() const
 | 
|---|
| 332 | {
 | 
|---|
| 333 |     return d_data->attributes;
 | 
|---|
| 334 | }
 | 
|---|
| 335 | 
 | 
|---|
| 336 | /*!
 | 
|---|
| 337 |   \brief Specify a reference point
 | 
|---|
| 338 |   \param r new reference value
 | 
|---|
| 339 | 
 | 
|---|
| 340 |   The reference point is needed if options IncludeReference or
 | 
|---|
| 341 |   Symmetric are active. Its default value is 0.0.
 | 
|---|
| 342 | 
 | 
|---|
| 343 |   \sa Attribute
 | 
|---|
| 344 | */
 | 
|---|
| 345 | void QwtScaleEngine::setReference( double r )
 | 
|---|
| 346 | {
 | 
|---|
| 347 |     d_data->referenceValue = r;
 | 
|---|
| 348 | }
 | 
|---|
| 349 | 
 | 
|---|
| 350 | /*!
 | 
|---|
| 351 |  \return the reference value
 | 
|---|
| 352 |  \sa setReference(), setAttribute()
 | 
|---|
| 353 | */
 | 
|---|
| 354 | double QwtScaleEngine::reference() const
 | 
|---|
| 355 | {
 | 
|---|
| 356 |     return d_data->referenceValue;
 | 
|---|
| 357 | }
 | 
|---|
| 358 | 
 | 
|---|
| 359 | /*!
 | 
|---|
| 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()
 | 
|---|
| 376 | */
 | 
|---|
| 377 | void QwtLinearScaleEngine::autoScale( int maxNumSteps,
 | 
|---|
| 378 |     double &x1, double &x2, double &stepSize ) const
 | 
|---|
| 379 | {
 | 
|---|
| 380 |     QwtInterval interval( x1, x2 );
 | 
|---|
| 381 |     interval = interval.normalized();
 | 
|---|
| 382 | 
 | 
|---|
| 383 |     interval.setMinValue( interval.minValue() - lowerMargin() );
 | 
|---|
| 384 |     interval.setMaxValue( interval.maxValue() + upperMargin() );
 | 
|---|
| 385 | 
 | 
|---|
| 386 |     if ( testAttribute( QwtScaleEngine::Symmetric ) )
 | 
|---|
| 387 |         interval = interval.symmetrize( reference() );
 | 
|---|
| 388 | 
 | 
|---|
| 389 |     if ( testAttribute( QwtScaleEngine::IncludeReference ) )
 | 
|---|
| 390 |         interval = interval.extend( reference() );
 | 
|---|
| 391 | 
 | 
|---|
| 392 |     if ( interval.width() == 0.0 )
 | 
|---|
| 393 |         interval = buildInterval( interval.minValue() );
 | 
|---|
| 394 | 
 | 
|---|
| 395 |     stepSize = divideInterval( interval.width(), qMax( maxNumSteps, 1 ) );
 | 
|---|
| 396 | 
 | 
|---|
| 397 |     if ( !testAttribute( QwtScaleEngine::Floating ) )
 | 
|---|
| 398 |         interval = align( interval, stepSize );
 | 
|---|
| 399 | 
 | 
|---|
| 400 |     x1 = interval.minValue();
 | 
|---|
| 401 |     x2 = interval.maxValue();
 | 
|---|
| 402 | 
 | 
|---|
| 403 |     if ( testAttribute( QwtScaleEngine::Inverted ) )
 | 
|---|
| 404 |     {
 | 
|---|
| 405 |         qSwap( x1, x2 );
 | 
|---|
| 406 |         stepSize = -stepSize;
 | 
|---|
| 407 |     }
 | 
|---|
| 408 | }
 | 
|---|
| 409 | 
 | 
|---|
| 410 | /*!
 | 
|---|
| 411 |    \brief Calculate a scale division
 | 
|---|
| 412 | 
 | 
|---|
| 413 |    \param x1 First interval limit
 | 
|---|
| 414 |    \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
 | 
|---|
| 418 |                    calculates one.
 | 
|---|
| 419 | 
 | 
|---|
| 420 |    \sa QwtScaleEngine::stepSize(), QwtScaleEngine::subDivide()
 | 
|---|
| 421 | */
 | 
|---|
| 422 | QwtScaleDiv QwtLinearScaleEngine::divideScale( double x1, double x2,
 | 
|---|
| 423 |     int maxMajSteps, int maxMinSteps, double stepSize ) const
 | 
|---|
| 424 | {
 | 
|---|
| 425 |     QwtInterval interval = QwtInterval( x1, x2 ).normalized();
 | 
|---|
| 426 |     if ( interval.width() <= 0 )
 | 
|---|
| 427 |         return QwtScaleDiv();
 | 
|---|
| 428 | 
 | 
|---|
| 429 |     stepSize = qAbs( stepSize );
 | 
|---|
| 430 |     if ( stepSize == 0.0 )
 | 
|---|
| 431 |     {
 | 
|---|
| 432 |         if ( maxMajSteps < 1 )
 | 
|---|
| 433 |             maxMajSteps = 1;
 | 
|---|
| 434 | 
 | 
|---|
| 435 |         stepSize = divideInterval( interval.width(), maxMajSteps );
 | 
|---|
| 436 |     }
 | 
|---|
| 437 | 
 | 
|---|
| 438 |     QwtScaleDiv scaleDiv;
 | 
|---|
| 439 | 
 | 
|---|
| 440 |     if ( stepSize != 0.0 )
 | 
|---|
| 441 |     {
 | 
|---|
| 442 |         QList<double> ticks[QwtScaleDiv::NTickTypes];
 | 
|---|
| 443 |         buildTicks( interval, stepSize, maxMinSteps, ticks );
 | 
|---|
| 444 | 
 | 
|---|
| 445 |         scaleDiv = QwtScaleDiv( interval, ticks );
 | 
|---|
| 446 |     }
 | 
|---|
| 447 | 
 | 
|---|
| 448 |     if ( x1 > x2 )
 | 
|---|
| 449 |         scaleDiv.invert();
 | 
|---|
| 450 | 
 | 
|---|
| 451 |     return scaleDiv;
 | 
|---|
| 452 | }
 | 
|---|
| 453 | 
 | 
|---|
| 454 | /*!
 | 
|---|
| 455 |    \brief Calculate ticks for an interval
 | 
|---|
| 456 | 
 | 
|---|
| 457 |    \param interval Interval
 | 
|---|
| 458 |    \param stepSize Step size
 | 
|---|
| 459 |    \param maxMinSteps Maximum number of minor steps
 | 
|---|
| 460 |    \param ticks Arrays to be filled with the calculated ticks
 | 
|---|
| 461 | 
 | 
|---|
| 462 |    \sa buildMajorTicks(), buildMinorTicks
 | 
|---|
| 463 | */
 | 
|---|
| 464 | void QwtLinearScaleEngine::buildTicks(
 | 
|---|
| 465 |     const QwtInterval& interval, double stepSize, int maxMinSteps,
 | 
|---|
| 466 |     QList<double> ticks[QwtScaleDiv::NTickTypes] ) const
 | 
|---|
| 467 | {
 | 
|---|
| 468 |     const QwtInterval boundingInterval =
 | 
|---|
| 469 |         align( interval, stepSize );
 | 
|---|
| 470 | 
 | 
|---|
| 471 |     ticks[QwtScaleDiv::MajorTick] =
 | 
|---|
| 472 |         buildMajorTicks( boundingInterval, stepSize );
 | 
|---|
| 473 | 
 | 
|---|
| 474 |     if ( maxMinSteps > 0 )
 | 
|---|
| 475 |     {
 | 
|---|
| 476 |         buildMinorTicks( ticks[QwtScaleDiv::MajorTick], maxMinSteps, stepSize,
 | 
|---|
| 477 |             ticks[QwtScaleDiv::MinorTick], ticks[QwtScaleDiv::MediumTick] );
 | 
|---|
| 478 |     }
 | 
|---|
| 479 | 
 | 
|---|
| 480 |     for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ )
 | 
|---|
| 481 |     {
 | 
|---|
| 482 |         ticks[i] = strip( ticks[i], interval );
 | 
|---|
| 483 | 
 | 
|---|
| 484 |         // ticks very close to 0.0 are
 | 
|---|
| 485 |         // explicitely set to 0.0
 | 
|---|
| 486 | 
 | 
|---|
| 487 |         for ( int j = 0; j < ticks[i].count(); j++ )
 | 
|---|
| 488 |         {
 | 
|---|
| 489 |             if ( qwtFuzzyCompare( ticks[i][j], 0.0, stepSize ) == 0 )
 | 
|---|
| 490 |                 ticks[i][j] = 0.0;
 | 
|---|
| 491 |         }
 | 
|---|
| 492 |     }
 | 
|---|
| 493 | }
 | 
|---|
| 494 | 
 | 
|---|
| 495 | /*!
 | 
|---|
| 496 |    \brief Calculate major ticks for an interval
 | 
|---|
| 497 | 
 | 
|---|
| 498 |    \param interval Interval
 | 
|---|
| 499 |    \param stepSize Step size
 | 
|---|
| 500 | 
 | 
|---|
| 501 |    \return Calculated ticks
 | 
|---|
| 502 | */
 | 
|---|
| 503 | QList<double> QwtLinearScaleEngine::buildMajorTicks(
 | 
|---|
| 504 |     const QwtInterval &interval, double stepSize ) const
 | 
|---|
| 505 | {
 | 
|---|
| 506 |     int numTicks = qRound( interval.width() / stepSize ) + 1;
 | 
|---|
| 507 |     if ( numTicks > 10000 )
 | 
|---|
| 508 |         numTicks = 10000;
 | 
|---|
| 509 | 
 | 
|---|
| 510 |     QList<double> ticks;
 | 
|---|
| 511 | 
 | 
|---|
| 512 |     ticks += interval.minValue();
 | 
|---|
| 513 |     for ( int i = 1; i < numTicks - 1; i++ )
 | 
|---|
| 514 |         ticks += interval.minValue() + i * stepSize;
 | 
|---|
| 515 |     ticks += interval.maxValue();
 | 
|---|
| 516 | 
 | 
|---|
| 517 |     return ticks;
 | 
|---|
| 518 | }
 | 
|---|
| 519 | 
 | 
|---|
| 520 | /*!
 | 
|---|
| 521 |    \brief Calculate minor/medium ticks for major ticks
 | 
|---|
| 522 | 
 | 
|---|
| 523 |    \param majorTicks Major ticks
 | 
|---|
| 524 |    \param maxMinSteps Maximum number of minor steps
 | 
|---|
| 525 |    \param stepSize Step size
 | 
|---|
| 526 |    \param minorTicks Array to be filled with the calculated minor ticks
 | 
|---|
| 527 |    \param mediumTicks Array to be filled with the calculated medium ticks
 | 
|---|
| 528 | 
 | 
|---|
| 529 | */
 | 
|---|
| 530 | void QwtLinearScaleEngine::buildMinorTicks(
 | 
|---|
| 531 |     const QList<double>& majorTicks,
 | 
|---|
| 532 |     int maxMinSteps, double stepSize,
 | 
|---|
| 533 |     QList<double> &minorTicks,
 | 
|---|
| 534 |     QList<double> &mediumTicks ) const
 | 
|---|
| 535 | {
 | 
|---|
| 536 |     double minStep = divideInterval( stepSize, maxMinSteps );
 | 
|---|
| 537 |     if ( minStep == 0.0 )
 | 
|---|
| 538 |         return;
 | 
|---|
| 539 | 
 | 
|---|
| 540 |     // # 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 |     }
 | 
|---|
| 550 | 
 | 
|---|
| 551 |     int medIndex = -1;
 | 
|---|
| 552 |     if ( numTicks % 2 )
 | 
|---|
| 553 |         medIndex = numTicks / 2;
 | 
|---|
| 554 | 
 | 
|---|
| 555 |     // calculate minor ticks
 | 
|---|
| 556 | 
 | 
|---|
| 557 |     for ( int i = 0; i < majorTicks.count(); i++ )
 | 
|---|
| 558 |     {
 | 
|---|
| 559 |         double val = majorTicks[i];
 | 
|---|
| 560 |         for ( int k = 0; k < numTicks; k++ )
 | 
|---|
| 561 |         {
 | 
|---|
| 562 |             val += minStep;
 | 
|---|
| 563 | 
 | 
|---|
| 564 |             double alignedValue = val;
 | 
|---|
| 565 |             if ( qwtFuzzyCompare( val, 0.0, stepSize ) == 0 )
 | 
|---|
| 566 |                 alignedValue = 0.0;
 | 
|---|
| 567 | 
 | 
|---|
| 568 |             if ( k == medIndex )
 | 
|---|
| 569 |                 mediumTicks += alignedValue;
 | 
|---|
| 570 |             else
 | 
|---|
| 571 |                 minorTicks += alignedValue;
 | 
|---|
| 572 |         }
 | 
|---|
| 573 |     }
 | 
|---|
| 574 | }
 | 
|---|
| 575 | 
 | 
|---|
| 576 | /*!
 | 
|---|
| 577 |   \brief Align an interval to a step size
 | 
|---|
| 578 | 
 | 
|---|
| 579 |   The limits of an interval are aligned that both are integer
 | 
|---|
| 580 |   multiples of the step size.
 | 
|---|
| 581 | 
 | 
|---|
| 582 |   \param interval Interval
 | 
|---|
| 583 |   \param stepSize Step size
 | 
|---|
| 584 | 
 | 
|---|
| 585 |   \return Aligned interval
 | 
|---|
| 586 | */
 | 
|---|
| 587 | QwtInterval QwtLinearScaleEngine::align(
 | 
|---|
| 588 |     const QwtInterval &interval, double stepSize ) const
 | 
|---|
| 589 | {
 | 
|---|
| 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();
 | 
|---|
| 597 | 
 | 
|---|
| 598 |     return QwtInterval( x1, x2 );
 | 
|---|
| 599 | }
 | 
|---|
| 600 | 
 | 
|---|
| 601 | /*!
 | 
|---|
| 602 |   Return a transformation, for logarithmic (base 10) scales
 | 
|---|
| 603 | */
 | 
|---|
| 604 | QwtScaleTransformation *QwtLog10ScaleEngine::transformation() const
 | 
|---|
| 605 | {
 | 
|---|
| 606 |     return new QwtScaleTransformation( QwtScaleTransformation::Log10 );
 | 
|---|
| 607 | }
 | 
|---|
| 608 | 
 | 
|---|
| 609 | /*!
 | 
|---|
| 610 |     Align and divide an interval
 | 
|---|
| 611 | 
 | 
|---|
| 612 |    \param maxNumSteps Max. number of steps
 | 
|---|
| 613 |    \param x1 First limit of the interval (In/Out)
 | 
|---|
| 614 |    \param x2 Second limit of the interval (In/Out)
 | 
|---|
| 615 |    \param stepSize Step size (Out)
 | 
|---|
| 616 | 
 | 
|---|
| 617 |    \sa QwtScaleEngine::setAttribute()
 | 
|---|
| 618 | */
 | 
|---|
| 619 | void QwtLog10ScaleEngine::autoScale( int maxNumSteps,
 | 
|---|
| 620 |                                      double &x1, double &x2, double &stepSize ) const
 | 
|---|
| 621 | {
 | 
|---|
| 622 |     if ( x1 > x2 )
 | 
|---|
| 623 |         qSwap( x1, x2 );
 | 
|---|
| 624 | 
 | 
|---|
| 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
 | 
|---|
| 631 | 
 | 
|---|
| 632 |         QwtLinearScaleEngine linearScaler;
 | 
|---|
| 633 |         linearScaler.setAttributes( attributes() );
 | 
|---|
| 634 |         linearScaler.setReference( reference() );
 | 
|---|
| 635 |         linearScaler.setMargins( lowerMargin(), upperMargin() );
 | 
|---|
| 636 | 
 | 
|---|
| 637 |         linearScaler.autoScale( maxNumSteps, x1, x2, stepSize );
 | 
|---|
| 638 |         stepSize = ::log10( stepSize );
 | 
|---|
| 639 | 
 | 
|---|
| 640 |         return;
 | 
|---|
| 641 |     }
 | 
|---|
| 642 | 
 | 
|---|
| 643 |     double logRef = 1.0;
 | 
|---|
| 644 |     if ( reference() > LOG_MIN / 2 )
 | 
|---|
| 645 |         logRef = qMin( reference(), LOG_MAX / 2 );
 | 
|---|
| 646 | 
 | 
|---|
| 647 |     if ( testAttribute( QwtScaleEngine::Symmetric ) )
 | 
|---|
| 648 |     {
 | 
|---|
| 649 |         const double delta = qMax( interval.maxValue() / logRef,
 | 
|---|
| 650 |             logRef / interval.minValue() );
 | 
|---|
| 651 |         interval.setInterval( logRef / delta, logRef * delta );
 | 
|---|
| 652 |     }
 | 
|---|
| 653 | 
 | 
|---|
| 654 |     if ( testAttribute( QwtScaleEngine::IncludeReference ) )
 | 
|---|
| 655 |         interval = interval.extend( logRef );
 | 
|---|
| 656 | 
 | 
|---|
| 657 |     interval = interval.limited( LOG_MIN, LOG_MAX );
 | 
|---|
| 658 | 
 | 
|---|
| 659 |     if ( interval.width() == 0.0 )
 | 
|---|
| 660 |         interval = buildInterval( interval.minValue() );
 | 
|---|
| 661 | 
 | 
|---|
| 662 |     stepSize = divideInterval( log10( interval ).width(), qMax( maxNumSteps, 1 ) );
 | 
|---|
| 663 |     if ( stepSize < 1.0 )
 | 
|---|
| 664 |         stepSize = 1.0;
 | 
|---|
| 665 | 
 | 
|---|
| 666 |     if ( !testAttribute( QwtScaleEngine::Floating ) )
 | 
|---|
| 667 |         interval = align( interval, stepSize );
 | 
|---|
| 668 | 
 | 
|---|
| 669 |     x1 = interval.minValue();
 | 
|---|
| 670 |     x2 = interval.maxValue();
 | 
|---|
| 671 | 
 | 
|---|
| 672 |     if ( testAttribute( QwtScaleEngine::Inverted ) )
 | 
|---|
| 673 |     {
 | 
|---|
| 674 |         qSwap( x1, x2 );
 | 
|---|
| 675 |         stepSize = -stepSize;
 | 
|---|
| 676 |     }
 | 
|---|
| 677 | }
 | 
|---|
| 678 | 
 | 
|---|
| 679 | /*!
 | 
|---|
| 680 |    \brief Calculate a scale division
 | 
|---|
| 681 | 
 | 
|---|
| 682 |    \param x1 First interval limit
 | 
|---|
| 683 |    \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
 | 
|---|
| 687 |                    calculates one.
 | 
|---|
| 688 | 
 | 
|---|
| 689 |    \sa QwtScaleEngine::stepSize(), QwtLog10ScaleEngine::subDivide()
 | 
|---|
| 690 | */
 | 
|---|
| 691 | QwtScaleDiv QwtLog10ScaleEngine::divideScale( double x1, double x2,
 | 
|---|
| 692 |     int maxMajSteps, int maxMinSteps, double stepSize ) const
 | 
|---|
| 693 | {
 | 
|---|
| 694 |     QwtInterval interval = QwtInterval( x1, x2 ).normalized();
 | 
|---|
| 695 |     interval = interval.limited( LOG_MIN, LOG_MAX );
 | 
|---|
| 696 | 
 | 
|---|
| 697 |     if ( interval.width() <= 0 )
 | 
|---|
| 698 |         return QwtScaleDiv();
 | 
|---|
| 699 | 
 | 
|---|
| 700 |     if ( interval.maxValue() / interval.minValue() < 10.0 )
 | 
|---|
| 701 |     {
 | 
|---|
| 702 |         // scale width is less than one decade -> build linear scale
 | 
|---|
| 703 | 
 | 
|---|
| 704 |         QwtLinearScaleEngine linearScaler;
 | 
|---|
| 705 |         linearScaler.setAttributes( attributes() );
 | 
|---|
| 706 |         linearScaler.setReference( reference() );
 | 
|---|
| 707 |         linearScaler.setMargins( lowerMargin(), upperMargin() );
 | 
|---|
| 708 | 
 | 
|---|
| 709 |         if ( stepSize != 0.0 )
 | 
|---|
| 710 |             stepSize = qPow( 10.0, stepSize );
 | 
|---|
| 711 | 
 | 
|---|
| 712 |         return linearScaler.divideScale( x1, x2,
 | 
|---|
| 713 |             maxMajSteps, maxMinSteps, stepSize );
 | 
|---|
| 714 |     }
 | 
|---|
| 715 | 
 | 
|---|
| 716 |     stepSize = qAbs( stepSize );
 | 
|---|
| 717 |     if ( stepSize == 0.0 )
 | 
|---|
| 718 |     {
 | 
|---|
| 719 |         if ( maxMajSteps < 1 )
 | 
|---|
| 720 |             maxMajSteps = 1;
 | 
|---|
| 721 | 
 | 
|---|
| 722 |         stepSize = divideInterval( log10( interval ).width(), maxMajSteps );
 | 
|---|
| 723 |         if ( stepSize < 1.0 )
 | 
|---|
| 724 |             stepSize = 1.0; // major step must be >= 1 decade
 | 
|---|
| 725 |     }
 | 
|---|
| 726 | 
 | 
|---|
| 727 |     QwtScaleDiv scaleDiv;
 | 
|---|
| 728 |     if ( stepSize != 0.0 )
 | 
|---|
| 729 |     {
 | 
|---|
| 730 |         QList<double> ticks[QwtScaleDiv::NTickTypes];
 | 
|---|
| 731 |         buildTicks( interval, stepSize, maxMinSteps, ticks );
 | 
|---|
| 732 | 
 | 
|---|
| 733 |         scaleDiv = QwtScaleDiv( interval, ticks );
 | 
|---|
| 734 |     }
 | 
|---|
| 735 | 
 | 
|---|
| 736 |     if ( x1 > x2 )
 | 
|---|
| 737 |         scaleDiv.invert();
 | 
|---|
| 738 | 
 | 
|---|
| 739 |     return scaleDiv;
 | 
|---|
| 740 | }
 | 
|---|
| 741 | 
 | 
|---|
| 742 | /*!
 | 
|---|
| 743 |    \brief Calculate ticks for an interval
 | 
|---|
| 744 | 
 | 
|---|
| 745 |    \param interval Interval
 | 
|---|
| 746 |    \param maxMinSteps Maximum number of minor steps
 | 
|---|
| 747 |    \param stepSize Step size
 | 
|---|
| 748 |    \param ticks Arrays to be filled with the calculated ticks
 | 
|---|
| 749 | 
 | 
|---|
| 750 |    \sa buildMajorTicks(), buildMinorTicks
 | 
|---|
| 751 | */
 | 
|---|
| 752 | void QwtLog10ScaleEngine::buildTicks(
 | 
|---|
| 753 |     const QwtInterval& interval, double stepSize, int maxMinSteps,
 | 
|---|
| 754 |     QList<double> ticks[QwtScaleDiv::NTickTypes] ) const
 | 
|---|
| 755 | {
 | 
|---|
| 756 |     const QwtInterval boundingInterval = align( interval, stepSize );
 | 
|---|
| 757 | 
 | 
|---|
| 758 |     ticks[QwtScaleDiv::MajorTick] =
 | 
|---|
| 759 |         buildMajorTicks( boundingInterval, stepSize );
 | 
|---|
| 760 | 
 | 
|---|
| 761 |     if ( maxMinSteps > 0 )
 | 
|---|
| 762 |     {
 | 
|---|
| 763 |         ticks[QwtScaleDiv::MinorTick] = buildMinorTicks(
 | 
|---|
| 764 |             ticks[QwtScaleDiv::MajorTick], maxMinSteps, stepSize );
 | 
|---|
| 765 |     }
 | 
|---|
| 766 | 
 | 
|---|
| 767 |     for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ )
 | 
|---|
| 768 |         ticks[i] = strip( ticks[i], interval );
 | 
|---|
| 769 | }
 | 
|---|
| 770 | 
 | 
|---|
| 771 | /*!
 | 
|---|
| 772 |    \brief Calculate major ticks for an interval
 | 
|---|
| 773 | 
 | 
|---|
| 774 |    \param interval Interval
 | 
|---|
| 775 |    \param stepSize Step size
 | 
|---|
| 776 | 
 | 
|---|
| 777 |    \return Calculated ticks
 | 
|---|
| 778 | */
 | 
|---|
| 779 | QList<double> QwtLog10ScaleEngine::buildMajorTicks(
 | 
|---|
| 780 |     const QwtInterval &interval, double stepSize ) const
 | 
|---|
| 781 | {
 | 
|---|
| 782 |     double width = log10( interval ).width();
 | 
|---|
| 783 | 
 | 
|---|
| 784 |     int numTicks = qRound( width / stepSize ) + 1;
 | 
|---|
| 785 |     if ( numTicks > 10000 )
 | 
|---|
| 786 |         numTicks = 10000;
 | 
|---|
| 787 | 
 | 
|---|
| 788 |     const double lxmin = ::log( interval.minValue() );
 | 
|---|
| 789 |     const double lxmax = ::log( interval.maxValue() );
 | 
|---|
| 790 |     const double lstep = ( lxmax - lxmin ) / double( numTicks - 1 );
 | 
|---|
| 791 | 
 | 
|---|
| 792 |     QList<double> ticks;
 | 
|---|
| 793 | 
 | 
|---|
| 794 |     ticks += interval.minValue();
 | 
|---|
| 795 | 
 | 
|---|
| 796 |     for ( int i = 1; i < numTicks - 1; i++ )
 | 
|---|
| 797 |         ticks += qExp( lxmin + double( i ) * lstep );
 | 
|---|
| 798 | 
 | 
|---|
| 799 |     ticks += interval.maxValue();
 | 
|---|
| 800 | 
 | 
|---|
| 801 |     return ticks;
 | 
|---|
| 802 | }
 | 
|---|
| 803 | 
 | 
|---|
| 804 | /*!
 | 
|---|
| 805 |    \brief Calculate minor/medium ticks for major ticks
 | 
|---|
| 806 | 
 | 
|---|
| 807 |    \param majorTicks Major ticks
 | 
|---|
| 808 |    \param maxMinSteps Maximum number of minor steps
 | 
|---|
| 809 |    \param stepSize Step size
 | 
|---|
| 810 | */
 | 
|---|
| 811 | QList<double> QwtLog10ScaleEngine::buildMinorTicks(
 | 
|---|
| 812 |     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 )
 | 
|---|
| 823 |         {
 | 
|---|
| 824 |             k0 = 2;
 | 
|---|
| 825 |             kmax = 9;
 | 
|---|
| 826 |             kstep = 1;
 | 
|---|
| 827 |         }
 | 
|---|
| 828 |         else if ( maxMinSteps >= 4 )
 | 
|---|
| 829 |         {
 | 
|---|
| 830 |             k0 = 2;
 | 
|---|
| 831 |             kmax = 8;
 | 
|---|
| 832 |             kstep = 2;
 | 
|---|
| 833 |         }
 | 
|---|
| 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;
 | 
|---|
| 848 | 
 | 
|---|
| 849 |         for ( int i = 0; i < majorTicks.count(); i++ )
 | 
|---|
| 850 |         {
 | 
|---|
| 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++ )
 | 
|---|
| 889 |             {
 | 
|---|
| 890 |                 val *= minFactor;
 | 
|---|
| 891 |                 minorTicks += val;
 | 
|---|
| 892 |             }
 | 
|---|
| 893 |         }
 | 
|---|
| 894 |         return minorTicks;
 | 
|---|
| 895 |     }
 | 
|---|
| 896 | }
 | 
|---|
| 897 | 
 | 
|---|
| 898 | /*!
 | 
|---|
| 899 |   \brief Align an interval to a step size
 | 
|---|
| 900 | 
 | 
|---|
| 901 |   The limits of an interval are aligned that both are integer
 | 
|---|
| 902 |   multiples of the step size.
 | 
|---|
| 903 | 
 | 
|---|
| 904 |   \param interval Interval
 | 
|---|
| 905 |   \param stepSize Step size
 | 
|---|
| 906 | 
 | 
|---|
| 907 |   \return Aligned interval
 | 
|---|
| 908 | */
 | 
|---|
| 909 | QwtInterval QwtLog10ScaleEngine::align(
 | 
|---|
| 910 |     const QwtInterval &interval, double stepSize ) const
 | 
|---|
| 911 | {
 | 
|---|
| 912 |     const QwtInterval intv = log10( interval );
 | 
|---|
| 913 | 
 | 
|---|
| 914 |     double x1 = QwtScaleArithmetic::floorEps( intv.minValue(), stepSize );
 | 
|---|
| 915 |     if ( qwtFuzzyCompare( interval.minValue(), x1, stepSize ) == 0 )
 | 
|---|
| 916 |         x1 = interval.minValue();
 | 
|---|
| 917 | 
 | 
|---|
| 918 |     double x2 = QwtScaleArithmetic::ceilEps( intv.maxValue(), stepSize );
 | 
|---|
| 919 |     if ( qwtFuzzyCompare( interval.maxValue(), x2, stepSize ) == 0 )
 | 
|---|
| 920 |         x2 = interval.maxValue();
 | 
|---|
| 921 | 
 | 
|---|
| 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 | }
 | 
|---|