Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members | Related Pages

# qwt_autoscl.cpp

    00001 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
    00002  * Qwt Widget Library
    00003  * Copyright (C) 1997   Josef Wilgen
    00004  * Copyright (C) 2002   Uwe Rathmann
    00005  *
    00006  * This library is free software; you can redistribute it and/or
    00007  * modify it under the terms of the Qwt License, Version 1.0
    00008  *****************************************************************************/
    00009
    00010 #include "qwt_math.h"
    00011 #include "qwt_autoscl.h"
    00012
    00013
    00014 static const double MinEps=1.0e-10;
    00015
    00017 QwtAutoScale::QwtAutoScale ()
    00018 {
    00019     d_autoScale = TRUE;
    00020     d_scaleOpt = None;
    00021
    00022     d_minValue = 0.0;
    00023     d_maxValue = 0.0;
    00024     d_scaleMin = 0.0;
    00025     d_scaleMax = 0.0;
    00026     d_loMargin = 0.0;
    00027     d_hiMargin = 0.0;
    00028     d_step = 0.0;
    00029     d_maxMajor = 8;
    00030     d_maxMinor = 5;
    00031     d_reset = 1;
    00032     d_autoRebuild = TRUE;
    00033 }
    00034
    00035
    00037 QwtAutoScale::~QwtAutoScale ()
    00038 {
    00039 }
    00040
    00045 bool QwtAutoScale::autoScale() const
    00046 {
    00047     return d_autoScale;
    00048 }
    00049
    00054 double QwtAutoScale::loMargin() const
    00055 {
    00056     return d_loMargin;
    00057 }
    00058
    00063 double QwtAutoScale::hiMargin() const
    00064 {
    00065     return d_hiMargin;
    00066 }
    00067
    00072 int QwtAutoScale::maxMajor() const
    00073 {
    00074     return d_maxMajor;
    00075 }
    00076
    00081 int QwtAutoScale::maxMinor() const
    00082 {
    00083     return d_maxMinor;
    00084 }
    00085
    00086
    00100 void QwtAutoScale::adjust(double *x, int num, int reset)
    00101 {
    00102     if (d_reset || reset)
    00103        d_minValue = d_maxValue = x[0];
    00104
    00105     for (int i = 0; i < num; i++)
    00106     {
    00107         if (x[i] > d_maxValue)
    00108            d_maxValue = x[i];
    00109         if (x[i] < d_minValue)
    00110            d_minValue = x[i];
    00111     }
    00112     d_reset = 0;
    00113
    00114     if (d_autoRebuild)
    00115         build();
    00116 }
    00117
    00118
    00131 void QwtAutoScale::adjust(const QwtArray<double> &x, int reset)
    00132 {
    00133     adjust(x.data(), x.size(), reset);
    00134 }
    00135
    00136
    00150 void QwtAutoScale::adjust(double vmin, double vmax, int reset)
    00151 {
    00152     double mxv = qwtMax(vmin,vmax);
    00153     double mnv = qwtMin(vmin,vmax);
    00154
    00155     if (d_reset || reset)
    00156     {
    00157         d_minValue = mnv;
    00158         d_maxValue = mxv;
    00159     }
    00160     else
    00161     {
    00162         if (d_minValue > mnv)
    00163            d_minValue = mnv;
    00164         if (d_maxValue < mxv)
    00165            d_maxValue = mxv;
    00166     }
    00167     d_reset = 0;
    00168
    00169     if (d_autoRebuild)
    00170         build();
    00171 }
    00172
    00176 void QwtAutoScale::build()
    00177 {
    00178     if (d_reset)
    00179         return;
    00180
    00181     if (d_autoScale)
    00182     {
    00183         if (d_scaleOpt & Logarithmic)
    00184             buildLogScale();
    00185         else
    00186             buildLinScale();
    00187     }
    00188     else
    00189     {
    00190         double start, stop, step;
    00191         if (d_scaleOpt & Inverted)
    00192         {
    00193             start = d_scaleMax;
    00194             stop = d_scaleMin;
    00195             step = -d_step;
    00196         }
    00197         else
    00198         {
    00199             start = d_scaleMin;
    00200             stop = d_scaleMax;
    00201             step = d_step;
    00202         }
    00203
    00204         d_scldiv.rebuild(start, stop, d_maxMajor, d_maxMinor,
    00205             bool(d_scaleOpt & Logarithmic), step, FALSE);
    00206     }
    00207 }
    00208
    00209
    00213 void QwtAutoScale::buildLinScale ()
    00214 {
    00215     double delta;
    00216     const double ticks = double (d_maxMajor);
    00217
    00218     //
    00219     // If in Autoscale Mode, adjust minval and maxval according to
    00220     // the active scale options, and add the margins
    00221     //
    00222     if (!d_autoScale)
    00223         return;
    00224
    00225     double minval = d_minValue;    // scale boundaries are based on the
    00226     double maxval = d_maxValue;    // data.
    00227
    00228     //
    00229     // add / subtract margins
    00230     //
    00231     if (d_loMargin > 0.0)
    00232        minval -= d_loMargin;
    00233     if (d_hiMargin > 0.0)
    00234        maxval += d_hiMargin;
    00235
    00236     //
    00237     //  Correct minval / maxval according to the scale options
    00238     //
    00239     if (d_scaleOpt & Symmetric)
    00240     {
    00241         delta = qwtMax(qwtAbs(d_ref - maxval), qwtAbs(d_ref - minval));
    00242         maxval = d_ref + delta;
    00243         minval = d_ref - delta;
    00244     }
    00245     else if (d_scaleOpt & IncludeRef)
    00246     {
    00247         if (maxval < d_ref)
    00248            maxval = d_ref;
    00249         else if (minval > d_ref)
    00250            minval = d_ref;
    00251     }
    00252
    00253     //
    00254     // first approximation of d_scaleMin and d_scaleMax
    00255     //
    00256     setRange(minval, maxval);
    00257     delta = d_scaleMax - d_scaleMin;
    00258
    00259
    00260     // dec := maximal power of ten which fits into the interval
    00261     //   [d_scaleMin,d_scaleMax]
    00262     const double dec = pow (10.0, floor (log10 (delta)));
    00263
    00264     //
    00265     //  The following magic line calculates the step size such that
    00266     //      - The number of subintervals will not exceed the maximum
    00267     //        as specified by the user
    00268     //      - The step size fits {1,2,5}*10^n with a natural number n
    00269     //
    00270     double step = qwtCeil125(delta * 0.999999 / dec / ticks) * dec;
    00271
    00272     //
    00273     //  determine he final values of scaleMin and scaleMax
    00274     //
    00275     if (! (d_scaleOpt & Floating) )
    00276     {
    00277        // adjust of d_scaleMin and d_scaleMax such that both are integer
    00278        // multiples of the step size.
    00279        d_scaleMin = step * floor ((d_scaleMin + MinEps * step) / step);
    00280        d_scaleMax = step * ceil ((d_scaleMax - MinEps * step) / step);
    00281     }
    00282
    00283     if (d_scaleOpt & Inverted)
    00284     {
    00285         step = -step;
    00286         d_scldiv.rebuild(d_scaleMax, d_scaleMin, d_maxMajor, d_maxMinor,
    00287              FALSE, step, FALSE);
    00288     }
    00289     else
    00290     {
    00291         d_scldiv.rebuild(d_scaleMin, d_scaleMax, d_maxMajor, d_maxMinor,
    00292              FALSE, step, TRUE);
    00293     }
    00294 }
    00295
    00296
    00300 void QwtAutoScale::buildLogScale ()
    00301 {
    00302     if (!d_autoScale)
    00303         return;
    00304
    00305     double minval = d_minValue; // the calculation of scale divisions
    00306     double maxval = d_maxValue; // is based on the input data.
    00307
    00308     if (d_loMargin > 0.0)
    00309         minval /= pow(10.0, d_loMargin);
    00310     if (d_hiMargin > 0.0)
    00311         maxval *= pow(10.0, d_hiMargin);
    00312
    00313     if (d_scaleOpt & Symmetric)
    00314     {
    00315         const double delta = qwtMax(maxval / d_lref,  d_lref / minval);
    00316         maxval = d_lref * delta;
    00317         minval = d_lref / delta;
    00318     }
    00319     else if (d_scaleOpt & IncludeRef)
    00320     {
    00321         if (maxval < d_lref)
    00322             maxval = d_lref;
    00323         else if (minval > d_lref)
    00324             minval = d_lref;
    00325     }
    00326
    00327     const double ticks = (d_maxMajor > 0) ? double(d_maxMajor) : 1;
    00328
    00329     setRange(minval, maxval);
    00330
    00331     // decades included in the interval
    00332     const double decades = qwtAbs(log10 (d_scaleMax / d_scaleMin));
    00333
    00334     // calculate step size in decades
    00335
    00336     double step;
    00337     if ((decades > 1.0) && (decades > ticks))
    00338     {
    00339         double ipart;
    00340         // One interval contains more than one decade.
    00341         // The number of decades in an interval is adjusted
    00342         // to be a multiple of 2,3,5, or 10.
    00343         double fpart = modf (log10 (ceil (decades * 0.999999 / ticks)), &ipart);
    00344         if (fpart < MinEps)
    00345            fpart = 1.0;
    00346         else if ((fpart - LOG10_2) < MinEps)
    00347            fpart = 2.0;
    00348         else if ((fpart - LOG10_3) < MinEps)
    00349            fpart = 3.0;
    00350         else if ((fpart - LOG10_5) < MinEps)
    00351            fpart = 5.0;
    00352         else
    00353            fpart = 10.0;
    00354
    00355         step = pow (10.0, ipart) * fpart;
    00356
    00357     }
    00358     else                // The minimal step size is one decade.
    00359     {
    00360         step = 1.0;
    00361     }
    00362
    00363     if (!(d_scaleOpt & Floating))
    00364     {
    00365         d_scaleMin = pow (10.0, step *
    00366             floor ((log10(d_scaleMin) + MinEps * step) / step));
    00367         d_scaleMax = pow (10.0, step *
    00368             ceil ((log10(d_scaleMax) - MinEps * step) / step));
    00369     }
    00370
    00371     if (d_scaleOpt & Inverted)
    00372     {
    00373         step = -step;
    00374         d_scldiv.rebuild(d_scaleMax, d_scaleMin, d_maxMajor, d_maxMinor, TRUE,
    00375              step, FALSE);
    00376     }
    00377     else
    00378     {
    00379         d_scldiv.rebuild(d_scaleMin, d_scaleMax, d_maxMajor, d_maxMinor,
    00380              TRUE, step, TRUE);
    00381     }
    00382 }
    00383
    00391 void QwtAutoScale::changeOptions(int opt, bool tf)
    00392 {
    00393     if (tf)
    00394        d_scaleOpt |= opt;
    00395     else
    00396        d_scaleOpt &= (~opt);
    00397     build();
    00398 }
    00399
    00400
    00413 void QwtAutoScale::reset()
    00414 {
    00415     d_reset = TRUE;
    00416     d_scldiv.reset();
    00417     d_minValue = 0;
    00418     d_maxValue = 0;
    00419     d_step = 0;
    00420 }
    00421
    00422
    00439 void QwtAutoScale::setAutoScale()
    00440 {
    00441     d_autoScale = TRUE;
    00442     build();
    00443 }
    00444
    00461 void QwtAutoScale::setMargins(double mlo, double mhi)
    00462 {
    00463     d_loMargin = qwtMax(mlo,0.0);
    00464     d_hiMargin = qwtMax(mhi,0.0);
    00465     build();
    00466 }
    00467
    00468
    00477 void QwtAutoScale::setMaxMajor(int mx)
    00478 {
    00479     d_maxMajor = qwtMax(mx,1);
    00480     d_maxMajor = qwtMin(mx, 10000);
    00481     build();
    00482 }
    00483
    00489 void QwtAutoScale::setMaxMinor(int mx)
    00490 {
    00491     d_maxMinor = qwtMin(qwtMax(mx,0), 100);
    00492     build();
    00493 }
    00494
    00495
    00510 void QwtAutoScale::setRange(double x1, double x2)
    00511 {
    00512     double minval = qwtMin(x1, x2);
    00513     double maxval = qwtMax(x1, x2);
    00514
    00515     if (d_scaleOpt & Logarithmic)
    00516     {
    00517         minval = qwtMin(qwtMax(minval, LOG_MIN), LOG_MAX);
    00518         maxval = qwtMin(qwtMax(maxval, LOG_MIN), LOG_MAX);
    00519     }
    00520
    00521     double delta = maxval - minval;
    00522
    00523     if (delta <= 0.0)       // all values are equal
    00524     {
    00525         if (minval > 0)
    00526         {
    00527             d_scaleMin = minval * 0.5;
    00528             d_scaleMax = maxval * 1.5;
    00529         }
    00530         else if (minval < 0)
    00531         {
    00532             d_scaleMin = minval * 1.5;
    00533             d_scaleMax = maxval * 0.5;
    00534         }
    00535         else              // all values are zero
    00536         {
    00537             d_scaleMin = -0.5;
    00538             d_scaleMax = 0.5;
    00539         }
    00540
    00541         delta = d_scaleMax - d_scaleMin;
    00542     }
    00543     else            // the normal case
    00544     {
    00545         d_scaleMin = minval;
    00546         d_scaleMax = maxval;
    00547     }
    00548 }
    00549
    00576 void QwtAutoScale::setScale(double xmin, double xmax, double step)
    00577 {
    00578     // turn auto-scaling off and set the
    00579     // scale limits to the desired values
    00580     setRange(xmin,xmax);
    00581     d_autoScale = FALSE;
    00582     d_step = step;
    00583
    00584     build(); // rebuild the scale
    00585 }
    00586
    00587
    00649 void QwtAutoScale::setOptions(int opt)
    00650 {
    00651     d_scaleOpt = opt;
    00652     build();
    00653 }
    00654
    00655
    00670 void QwtAutoScale::setReference(double r)
    00671 {
    00672     d_ref = r;
    00673
    00674     if (r > LOG_MIN / 2)
    00675         d_lref = qwtMin(r, LOG_MAX / 2);
    00676     else
    00677        d_lref = 1.0;
    00678
    00679     build();
    00680 }
    00681
    00686 double QwtAutoScale::reference() const
    00687 {
    00688     return d_ref;
    00689 }
    00690
    00691
    00697 bool QwtAutoScale::option(int opt) const
    00698 {
    00699     return bool(d_scaleOpt & opt);
    00700 }
    00701
    00707 int QwtAutoScale::options() const
    00708 {
    00709     return d_scaleOpt;
    00710 }
    00711
    00720 const QwtScaleDiv &QwtAutoScale::scaleDiv() const
    00721 {
    00722     return d_scldiv;
    00723 }
    00724
    00730 void QwtAutoScale::setAutoRebuild(bool tf)
    00731 {
    00732     d_autoRebuild = tf;
    00733 }
    00734
    00739 bool QwtAutoScale::autoRebuild() const
    00740 {
    00741     return d_autoRebuild;
    00742 }