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

qwt_autoscl.cpp

Go to the documentation of this file.
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 
00132 void QwtAutoScale::adjust(double vmin, double vmax, int reset)
00133 { 
00134     double mxv = qwtMax(vmin,vmax);
00135     double mnv = qwtMin(vmin,vmax);
00136     
00137     if (d_reset || reset)
00138     {
00139         d_minValue = mnv;
00140         d_maxValue = mxv;
00141     }
00142     else
00143     {
00144         if (d_minValue > mnv) 
00145            d_minValue = mnv;
00146         if (d_maxValue < mxv)
00147            d_maxValue = mxv;
00148     }
00149     d_reset = 0;
00150 
00151     if (d_autoRebuild) 
00152         build();
00153 }
00154 
00158 void QwtAutoScale::build() 
00159 {
00160     if (d_reset) 
00161         return;
00162     
00163     if (d_autoScale)
00164     {
00165         if (d_scaleOpt & Logarithmic) 
00166             buildLogScale(); 
00167         else 
00168             buildLinScale();
00169     }
00170     else
00171     {
00172     double start, stop, step;
00173       if (d_scaleOpt & Inverted)
00174     {
00175       start = d_scaleMax;
00176       stop = d_scaleMin;
00177       step = -d_step;
00178     }
00179     else
00180     {
00181             start = d_scaleMin;
00182             stop = d_scaleMax;
00183             step = d_step;
00184     }
00185 
00186       d_scldiv.rebuild(start, stop, d_maxMajor, d_maxMinor,
00187           bool(d_scaleOpt & Logarithmic), step, FALSE); 
00188     }
00189 }
00190 
00191 
00195 void QwtAutoScale::buildLinScale ()
00196 {
00197     double delta;
00198     const double ticks = double (d_maxMajor);
00199 
00200     //
00201     // If in Autoscale Mode, adjust minval and maxval according to
00202     // the active scale options, and add the margins
00203     //
00204     if (!d_autoScale) 
00205         return;
00206     
00207     double minval = d_minValue;    // scale boundaries are based on the
00208     double maxval = d_maxValue;    // data.
00209 
00210     //
00211     // add / subtract margins
00212     //
00213     if (d_loMargin > 0.0)
00214        minval -= d_loMargin;
00215     if (d_hiMargin > 0.0)
00216        maxval += d_hiMargin;
00217 
00218     //
00219     //  Correct minval / maxval according to the scale options
00220     //
00221     if (d_scaleOpt & Symmetric)
00222     {
00223         delta = qwtMax(qwtAbs(d_ref - maxval), qwtAbs(d_ref - minval));
00224         maxval = d_ref + delta;
00225         minval = d_ref - delta; 
00226     }
00227     else if (d_scaleOpt & IncludeRef)
00228     {
00229         if (maxval < d_ref) 
00230            maxval = d_ref;
00231         else if (minval > d_ref) 
00232            minval = d_ref;
00233     }
00234     
00235     //
00236     // first approximation of d_scaleMin and d_scaleMax
00237     //
00238     setRange(minval, maxval);
00239     delta = d_scaleMax - d_scaleMin;
00240 
00241 
00242     // dec := maximal power of ten which fits into the interval
00243     //   [d_scaleMin,d_scaleMax]
00244     const double dec = pow (10.0, floor (log10 (delta)));
00245 
00246     //
00247     //  The following magic line calculates the step size such that
00248     //      - The number of subintervals will not exceed the maximum
00249     //        as specified by the user
00250     //      - The step size fits {1,2,5}*10^n with a natural number n  
00251     // 
00252     double step = qwtCeil125(delta * 0.999999 / dec / ticks) * dec;
00253 
00254     //
00255     //  determine he final values of scaleMin and scaleMax
00256     //
00257     if (! (d_scaleOpt & Floating) )
00258     {
00259        // adjust of d_scaleMin and d_scaleMax such that both are integer
00260        // multiples of the step size.
00261        d_scaleMin = step * floor ((d_scaleMin + MinEps * step) / step);
00262        d_scaleMax = step * ceil ((d_scaleMax - MinEps * step) / step);
00263     }
00264 
00265     if (d_scaleOpt & Inverted)
00266     {
00267         step = -step;
00268         d_scldiv.rebuild(d_scaleMax, d_scaleMin, d_maxMajor, d_maxMinor,
00269              FALSE, step, FALSE);
00270     }
00271     else
00272     {
00273         d_scldiv.rebuild(d_scaleMin, d_scaleMax, d_maxMajor, d_maxMinor,
00274              FALSE, step, TRUE);
00275     }
00276 }
00277 
00278 
00282 void QwtAutoScale::buildLogScale ()
00283 {
00284     if (!d_autoScale) 
00285         return;
00286 
00287     double minval = d_minValue; // the calculation of scale divisions 
00288     double maxval = d_maxValue; // is based on the input data.
00289 
00290     if (d_loMargin > 0.0)
00291         minval /= pow(10.0, d_loMargin);
00292     if (d_hiMargin > 0.0)
00293         maxval *= pow(10.0, d_hiMargin);
00294 
00295     if (d_scaleOpt & Symmetric)
00296     {
00297         const double delta = qwtMax(maxval / d_lref,  d_lref / minval); 
00298         maxval = d_lref * delta;
00299         minval = d_lref / delta;    
00300     }
00301     else if (d_scaleOpt & IncludeRef)
00302     {
00303         if (maxval < d_lref) 
00304             maxval = d_lref;
00305         else if (minval > d_lref) 
00306             minval = d_lref;
00307     }
00308 
00309   const double ticks = (d_maxMajor > 0) ? double(d_maxMajor) : 1;
00310 
00311     setRange(minval, maxval);
00312 
00313     // decades included in the interval
00314     const double decades = qwtAbs(log10 (d_scaleMax / d_scaleMin));
00315 
00316     // calculate step size in decades
00317 
00318     double step;
00319     if ((decades > 1.0) && (decades > ticks))
00320     {
00321     double ipart;
00322         // One interval contains more than one decade.
00323         // The number of decades in an interval is adjusted
00324         // to be a multiple of 2,3,5, or 10.
00325         double fpart = modf (log10 (ceil (decades * 0.999999 / ticks)), &ipart);
00326         if (fpart < MinEps)
00327            fpart = 1.0;
00328         else if ((fpart - LOG10_2) < MinEps)
00329            fpart = 2.0;
00330         else if ((fpart - LOG10_3) < MinEps)
00331            fpart = 3.0;
00332         else if ((fpart - LOG10_5) < MinEps)
00333            fpart = 5.0;
00334         else
00335            fpart = 10.0;
00336 
00337         step = pow (10, ipart) * fpart;
00338 
00339     }
00340     else                // The minimal step size is one decade.
00341     {
00342         step = 1.0;
00343     }
00344     
00345     if (!(d_scaleOpt & Floating))
00346     {
00347         d_scaleMin = pow (10, step * 
00348             floor ((log10(d_scaleMin) + MinEps * step) / step));
00349         d_scaleMax = pow (10, step * 
00350             ceil ((log10(d_scaleMax) - MinEps * step) / step));
00351     }
00352 
00353     if (d_scaleOpt & Inverted)
00354     {
00355         step = -step;
00356         d_scldiv.rebuild(d_scaleMax, d_scaleMin, d_maxMajor, d_maxMinor, TRUE,
00357              step, FALSE);
00358     }
00359     else
00360     {
00361         d_scldiv.rebuild(d_scaleMin, d_scaleMax, d_maxMajor, d_maxMinor,
00362              TRUE, step, TRUE);
00363     }
00364 }
00365 
00373 void QwtAutoScale::changeOptions(int opt, bool tf)
00374 {
00375     if (tf)
00376        d_scaleOpt |= opt;
00377     else
00378        d_scaleOpt &= (~opt);
00379     build();
00380 }
00381 
00382 
00395 void QwtAutoScale::reset()
00396 {
00397     d_reset = TRUE;
00398     d_scldiv.reset();
00399     d_minValue = 0;
00400     d_maxValue = 0;
00401     d_step = 0;
00402 }
00403 
00404 
00421 void QwtAutoScale::setAutoScale()
00422 {
00423     d_autoScale = TRUE;
00424     build();
00425 }
00426 
00443 void QwtAutoScale::setMargins(double mlo, double mhi)
00444 {
00445     d_loMargin = qwtMax(mlo,0.0);
00446     d_hiMargin = qwtMax(mhi,0.0);
00447     build();
00448 }
00449 
00450 
00459 void QwtAutoScale::setMaxMajor(int mx)
00460 {
00461     d_maxMajor = qwtMax(mx,1);
00462     d_maxMajor = qwtMin(mx, 10000);
00463     build();
00464 }
00465 
00471 void QwtAutoScale::setMaxMinor(int mx)
00472 {
00473     d_maxMinor = qwtMin(qwtMax(mx,0), 100);
00474     build();
00475 }
00476 
00477 
00481 void QwtAutoScale::setRange(double x1, double x2)
00482 {
00483     double minval = qwtMin(x1, x2);
00484     double maxval = qwtMax(x1, x2);
00485 
00486     if (d_scaleOpt & Logarithmic)
00487     {
00488         minval = qwtMin(qwtMax(minval, LOG_MIN), LOG_MAX);
00489         maxval = qwtMin(qwtMax(maxval,LOG_MIN), LOG_MAX);
00490     }
00491     
00492     double delta = maxval - minval;
00493     
00494     if (delta <= 0.0)       // all values are equal
00495     {               
00496         if (minval > 0)
00497         {
00498             d_scaleMin = minval * 0.5;
00499             d_scaleMax = maxval * 1.5;
00500         }
00501         else if (minval < 0)
00502         {
00503             d_scaleMin = minval * 1.5;
00504             d_scaleMax = maxval * 0.5;
00505         }
00506         else              // all values are zero
00507         {           
00508             d_scaleMin = -0.5;
00509             d_scaleMax = 0.5;
00510         }
00511 
00512         delta = d_scaleMax - d_scaleMin;
00513     }
00514     else            // the normal case
00515     {               
00516         d_scaleMin = minval;
00517         d_scaleMax = maxval;
00518     }
00519 }
00520 
00544 void QwtAutoScale::setScale(double xmin, double xmax, double step)
00545 {
00546     // turn auto-scaling off and set the
00547     // scale limits to the desired values
00548     setRange(xmin,xmax);
00549     d_autoScale = FALSE;
00550     d_step = step;
00551 
00552     build(); // rebuild the scale
00553 }
00554 
00555 
00617 void QwtAutoScale::setOptions(int opt)
00618 {
00619     d_scaleOpt = opt;
00620     build();
00621 }
00622 
00623 
00637 void QwtAutoScale::setReference(double r)
00638 {
00639     d_ref = r;
00640     
00641     if (r > LOG_MIN / 2) 
00642         d_lref = qwtMin(r, LOG_MAX / 2);
00643     else
00644        d_lref = 1.0;
00645 
00646     build();
00647 }
00648 
00653 double QwtAutoScale::reference() const 
00654 { 
00655     return d_ref; 
00656 }
00657 
00658 
00664 bool QwtAutoScale::option(int opt) const
00665 {
00666     return bool(d_scaleOpt & opt);
00667 }
00668 
00674 int QwtAutoScale::options() const 
00675 { 
00676     return d_scaleOpt; 
00677 }
00678 
00687 const QwtScaleDiv &QwtAutoScale::scaleDiv() const 
00688 { 
00689     return d_scldiv; 
00690 }
00691 
00697 void QwtAutoScale::setAutoRebuild(bool tf) 
00698 { 
00699     d_autoRebuild = tf; 
00700 }
00701 
00706 bool QwtAutoScale::autoRebuild() const
00707 {
00708     return d_autoRebuild;
00709 }

Generated on Fri Nov 7 14:11:44 2003 for Qwt Developer's Guide by doxygen 1.3.2