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

qwt_scldiv.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_scldiv.h"
00011 #include "qwt_math.h"
00012 
00013 static const double step_eps = 1.0e-3;
00014 static const double border_eps = 1.0e-10;
00015 
00016 static bool qwtLimRange(double &val, double v1, double v2, 
00017     double eps_rel = 0.0, double eps_abs = 0.0)
00018 {
00019     bool rv = TRUE;
00020     double vmin = qwtMin(v1, v2);
00021     double vmax = qwtMax(v1, v2);
00022     double delta_min = qwtMax(qwtAbs(eps_rel * vmin), qwtAbs(eps_abs));
00023     double delta_max = qwtMax(qwtAbs(eps_rel * vmax), qwtAbs(eps_abs));
00024     
00025     if (val < vmin) 
00026     {
00027         if (val < vmin - delta_min) 
00028             rv = FALSE;
00029         val = vmin;
00030     }
00031     else if (val > vmax)
00032     {
00033         if (val > vmax + delta_max) 
00034             rv = FALSE;
00035         val = vmax;
00036     }
00037     return rv;
00038 }
00039 
00040 
00042 QwtScaleDiv::QwtScaleDiv()
00043 {
00044     d_lBound = 0.0;
00045     d_hBound = 0.0;
00046     d_majStep = 0.0;
00047     d_log = FALSE;
00048 }
00049 
00086 bool QwtScaleDiv::rebuild(double x1, double x2, 
00087     int maxMajSteps, int maxMinSteps, bool log, double step, bool ascend)
00088 {
00089   int rv;
00090 
00091   d_lBound = qwtMin(x1, x2);
00092   d_hBound = qwtMax(x1, x2);
00093   d_log = log;
00094   
00095   if (d_log)
00096       rv = buildLogDiv(maxMajSteps,maxMinSteps,step);
00097   else
00098       rv = buildLinDiv(maxMajSteps, maxMinSteps, step);
00099 
00100   if ((!ascend) && (x2 < x1))
00101   {
00102       d_lBound = x1;
00103       d_hBound = x2;
00104       qwtTwistArray(d_majMarks.data(), d_majMarks.size());
00105       qwtTwistArray(d_minMarks.data(), d_minMarks.size());
00106   }
00107 
00108   return rv;
00109 }
00110 
00129 bool QwtScaleDiv::buildLinDiv(int maxMajSteps, int maxMinSteps, double step)
00130 {
00131     int nMaj, nMin, minSize, i0,i,k;
00132     double val, mval;
00133     double firstTick, lastTick;
00134     double minStep;
00135     QwtArray<double> buffer;
00136     bool rv = TRUE;
00137 
00138     // parameter range check
00139     maxMajSteps = qwtMax(1, maxMajSteps);
00140     maxMinSteps = qwtMax(0, maxMinSteps);
00141     step = qwtAbs(step);
00142     
00143     // detach arrays
00144     d_majMarks.duplicate(0,0);
00145     d_minMarks.duplicate(0,0);
00146 
00147     if (d_lBound == d_hBound) return TRUE;
00148     
00149     //
00150     // Set up major divisions
00151     //
00152     if (step == 0.0)
00153        d_majStep = qwtCeil125(qwtAbs(d_hBound - d_lBound) * 0.999999
00154                   / double(maxMajSteps));
00155     else
00156        d_majStep = step;
00157 
00158     if (d_majStep == 0.0) return TRUE;
00159 
00160     firstTick = ceil( (d_lBound - step_eps * d_majStep) / d_majStep) * d_majStep;
00161     lastTick = floor( (d_hBound + step_eps * d_majStep) / d_majStep) * d_majStep;
00162 
00163     nMaj = qwtMin(10000, int(floor ((lastTick - firstTick) / d_majStep + 0.5)) + 1);
00164 
00165     if ((rv = d_majMarks.resize(nMaj)))
00166        qwtLinSpace(d_majMarks.data(), d_majMarks.size(), firstTick, lastTick);
00167     else
00168        return FALSE;
00169 
00170     //
00171     // Set up minor divisions
00172     //
00173     if (maxMinSteps < 1) // no minor divs
00174        return TRUE;
00175 
00176     minStep = qwtCeil125( d_majStep  /  double(maxMinSteps) );
00177 
00178     if (minStep == 0.0) return TRUE;
00179     
00180     nMin = qwtAbs(int(floor(d_majStep / minStep + 0.5))) - 1; // # minor steps per interval
00181 
00182     // Do the minor steps fit into the interval?
00183     if ( qwtAbs(double(nMin +  1) * minStep - d_majStep) 
00184         >  step_eps * d_majStep)
00185     {
00186         nMin = 1;
00187         minStep = d_majStep * 0.5;
00188     }
00189     
00190     // Are there minor ticks below the first major tick?
00191     if (d_majMarks[0] > d_lBound )
00192        i0 = -1; 
00193     else
00194        i0 = 0;
00195 
00196     // resize buffer to the maximum possible number of minor ticks
00197     rv = buffer.resize(nMin * (nMaj + 1));
00198        
00199     // calculate minor ticks
00200     if (rv)
00201     {
00202         minSize = 0;
00203         for (i = i0; i < (int)d_majMarks.size(); i++)
00204         {
00205             if (i >= 0)
00206                val = d_majMarks[i];
00207             else
00208                val = d_majMarks[0] - d_majStep;
00209 
00210             for (k=0; k< nMin; k++)
00211             {
00212                 mval = (val += minStep);
00213                 if (qwtLimRange(mval, d_lBound, d_hBound, border_eps))
00214                 {
00215                     buffer[minSize] = mval;
00216                     minSize++;
00217                 }
00218             }
00219         }
00220         d_minMarks.duplicate(buffer.data(), minSize);
00221     }
00222 
00223     return rv;
00224 }
00225 
00232 bool QwtScaleDiv::buildLogDiv(int maxMajSteps, int maxMinSteps, double majStep)
00233 {
00234     double firstTick, lastTick;
00235     double lFirst, lLast;
00236     double val, sval, minStep, minFactor;
00237     int nMaj, nMin, minSize, i, k, k0, kstep, kmax, i0;
00238     int rv = TRUE;
00239     double width;
00240     
00241     QwtArray<double> buffer;
00242     
00243 
00244     // Parameter range check
00245     maxMajSteps = qwtMax(1, qwtAbs(maxMajSteps));
00246     maxMinSteps = qwtMax(0, qwtAbs(maxMinSteps));
00247     majStep = qwtAbs(majStep);
00248 
00249     // boundary check
00250     qwtLimRange(d_hBound, LOG_MIN, LOG_MAX);
00251     qwtLimRange(d_lBound, LOG_MIN, LOG_MAX);
00252     
00253     // detach arrays
00254     d_majMarks.duplicate(0,0);
00255     d_minMarks.duplicate(0,0);
00256 
00257     if (d_lBound == d_hBound) return TRUE;
00258 
00259     // scale width in decades
00260     width = log10(d_hBound) - log10(d_lBound);
00261 
00262     // scale width is less than one decade -> build linear scale
00263     if (width < 1.0) 
00264     {
00265         rv = buildLinDiv(maxMajSteps, maxMinSteps, 0.0);
00266         // convert step width to decades
00267         if (d_majStep > 0)
00268            d_majStep = log10(d_majStep);
00269 
00270         return rv;
00271     }
00272 
00273     //
00274     //  Set up major scale divisions
00275     //
00276     if (majStep == 0.0)
00277        d_majStep = qwtCeil125( width * 0.999999 / double(maxMajSteps));
00278     else
00279        d_majStep = majStep;
00280 
00281     // major step must be >= 1 decade
00282     d_majStep = qwtMax(d_majStep, 1.0);
00283     
00284 
00285     lFirst = ceil((log10(d_lBound) - step_eps * d_majStep) / d_majStep) * d_majStep;
00286     lLast = floor((log10(d_hBound) + step_eps * d_majStep) / d_majStep) * d_majStep;
00287 
00288     firstTick = pow(10.0, lFirst);
00289     lastTick = pow(10.0, lLast);
00290     
00291     nMaj = qwtMin(10000, int(floor (qwtAbs(lLast - lFirst) / d_majStep + 0.5)) + 1);
00292 
00293     if (d_majMarks.resize(nMaj))
00294        qwtLogSpace(d_majMarks.data(), d_majMarks.size(), firstTick, lastTick);
00295     else
00296        return FALSE;
00297 
00298 
00299     //
00300     // Set up minor scale divisions
00301     //
00302 
00303     if ((d_majMarks.size() < 1) || (maxMinSteps < 1)) return TRUE; // no minor marks
00304 
00305     if (d_majStep < 1.1)            // major step width is one decade
00306     {
00307         if (maxMinSteps >= 8)
00308         {
00309             k0 = 2;
00310             kmax = 9;
00311             kstep = 1;
00312             minSize = (d_majMarks.size() + 1) * 8;
00313         }
00314         else if (maxMinSteps >= 4)
00315         {
00316             k0 = 2;
00317             kmax = 8;
00318             kstep = 2;
00319             minSize = (d_majMarks.size() + 1) * 4;
00320         }
00321         else if (maxMinSteps >= 2)
00322         {
00323             k0 = 2;
00324             kmax = 5;
00325             kstep = 3;
00326             minSize = (d_majMarks.size() + 1) * 2;
00327         }
00328         else
00329         {
00330             k0 = 5;
00331             kmax = 5;
00332             kstep = 1;
00333             minSize = (d_majMarks.size() + 1);
00334         }
00335         
00336         // resize buffer to the max. possible number of minor marks
00337         buffer.resize(minSize);
00338 
00339         // Are there minor ticks below the first major tick?
00340         if ( d_lBound < firstTick )
00341             i0 = -1;
00342         else
00343            i0 = 0;
00344         
00345         minSize = 0;
00346         for (i = i0; i< (int)d_majMarks.size(); i++)
00347         {
00348             if (i >= 0)
00349                val = d_majMarks[i];
00350             else
00351                val = d_majMarks[0] / pow(10.0, d_majStep);
00352             
00353             for (k=k0; k<= kmax; k+=kstep)
00354             {
00355             sval = val * double(k);
00356             if (qwtLimRange(sval, d_lBound, d_hBound, border_eps))
00357             {
00358                 buffer[minSize] = sval;
00359                 minSize++;
00360             }
00361             }
00362         }
00363 
00364         // copy values into the minMarks array
00365         d_minMarks.duplicate(buffer.data(), minSize);
00366 
00367     }
00368     else                // major step > one decade
00369     {
00370         
00371         // substep width in decades, at least one decade
00372         minStep = qwtCeil125( (d_majStep - step_eps * (d_majStep / double(maxMinSteps)))
00373                  /  double(maxMinSteps) );
00374         minStep = qwtMax(1.0, minStep);
00375 
00376         // # subticks per interval
00377         nMin = int(floor (d_majStep / minStep + 0.5)) - 1;
00378 
00379         // Do the minor steps fit into the interval?
00380         if ( qwtAbs( double(nMin + 1) * minStep - d_majStep)  >  step_eps * d_majStep)
00381             nMin = 0;
00382 
00383         if (nMin < 1) return TRUE;      // no subticks
00384 
00385         // resize buffer to max. possible number of subticks
00386         buffer.resize((d_majMarks.size() + 1) * nMin );
00387         
00388         // substep factor = 10^substeps
00389         minFactor = qwtMax(pow(10.0, minStep), 10.0);
00390 
00391         // Are there minor ticks below the first major tick?
00392         if ( d_lBound < firstTick )
00393             i0 = -1;
00394         else
00395            i0 = 0;
00396         
00397         minSize = 0;
00398         for (i = i0; i< (int)d_majMarks.size(); i++)
00399         {
00400             if (i >= 0)
00401                val = d_majMarks[i];
00402             else
00403                val = firstTick / pow(10.0, d_majStep);
00404             
00405             for (k=0; k< nMin; k++)
00406             {
00407                 sval = (val *= minFactor);
00408                 if (qwtLimRange(sval, d_lBound, d_hBound, border_eps))
00409                 {
00410                     buffer[minSize] = sval;
00411                     minSize++;
00412                 }
00413             }
00414         }
00415         d_minMarks.duplicate(buffer.data(), minSize);
00416     }
00417     
00418     return rv;
00419 }
00420 
00425 int QwtScaleDiv::operator==(const QwtScaleDiv &s) const
00426 {
00427     if (d_lBound != s.d_lBound) return 0;
00428     if (d_hBound != s.d_hBound) return 0;
00429     if (d_log != s.d_log) return 0;
00430     if (d_majStep != s.d_majStep) return 0;
00431     if (d_majMarks != s.d_majMarks) return 0;
00432     return (d_minMarks == s.d_minMarks);
00433 }
00434 
00439 int QwtScaleDiv::operator!=(const QwtScaleDiv &s) const
00440 {
00441     return (!(*this == s));
00442 }
00443 
00445 void QwtScaleDiv::reset()
00446 {
00447     // detach arrays
00448     d_majMarks.duplicate(0,0);
00449     d_minMarks.duplicate(0,0);
00450 
00451     d_lBound = 0.0;
00452     d_hBound = 0.0;
00453     d_majStep = 0.0;
00454     d_log = FALSE;
00455 }

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