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 }

Generated on Sun Nov 21 11:12:42 2004 for Qwt User's Guide by doxygen 1.3.5