00001
00002
00003
00004
00005
00006
00007
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
00220
00221
00222 if (!d_autoScale)
00223 return;
00224
00225 double minval = d_minValue;
00226 double maxval = d_maxValue;
00227
00228
00229
00230
00231 if (d_loMargin > 0.0)
00232 minval -= d_loMargin;
00233 if (d_hiMargin > 0.0)
00234 maxval += d_hiMargin;
00235
00236
00237
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
00255
00256 setRange(minval, maxval);
00257 delta = d_scaleMax - d_scaleMin;
00258
00259
00260
00261
00262 const double dec = pow (10.0, floor (log10 (delta)));
00263
00264
00265
00266
00267
00268
00269
00270 double step = qwtCeil125(delta * 0.999999 / dec / ticks) * dec;
00271
00272
00273
00274
00275 if (! (d_scaleOpt & Floating) )
00276 {
00277
00278
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;
00306 double maxval = d_maxValue;
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
00332 const double decades = qwtAbs(log10 (d_scaleMax / d_scaleMin));
00333
00334
00335
00336 double step;
00337 if ((decades > 1.0) && (decades > ticks))
00338 {
00339 double ipart;
00340
00341
00342
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
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)
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
00536 {
00537 d_scaleMin = -0.5;
00538 d_scaleMax = 0.5;
00539 }
00540
00541 delta = d_scaleMax - d_scaleMin;
00542 }
00543 else
00544 {
00545 d_scaleMin = minval;
00546 d_scaleMax = maxval;
00547 }
00548 }
00549
00576 void QwtAutoScale::setScale(double xmin, double xmax, double step)
00577 {
00578
00579
00580 setRange(xmin,xmax);
00581 d_autoScale = FALSE;
00582 d_step = step;
00583
00584 build();
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 }