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
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
00202
00203
00204 if (!d_autoScale)
00205 return;
00206
00207 double minval = d_minValue;
00208 double maxval = d_maxValue;
00209
00210
00211
00212
00213 if (d_loMargin > 0.0)
00214 minval -= d_loMargin;
00215 if (d_hiMargin > 0.0)
00216 maxval += d_hiMargin;
00217
00218
00219
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
00237
00238 setRange(minval, maxval);
00239 delta = d_scaleMax - d_scaleMin;
00240
00241
00242
00243
00244 const double dec = pow (10.0, floor (log10 (delta)));
00245
00246
00247
00248
00249
00250
00251
00252 double step = qwtCeil125(delta * 0.999999 / dec / ticks) * dec;
00253
00254
00255
00256
00257 if (! (d_scaleOpt & Floating) )
00258 {
00259
00260
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;
00288 double maxval = d_maxValue;
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
00314 const double decades = qwtAbs(log10 (d_scaleMax / d_scaleMin));
00315
00316
00317
00318 double step;
00319 if ((decades > 1.0) && (decades > ticks))
00320 {
00321 double ipart;
00322
00323
00324
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
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)
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
00507 {
00508 d_scaleMin = -0.5;
00509 d_scaleMax = 0.5;
00510 }
00511
00512 delta = d_scaleMax - d_scaleMin;
00513 }
00514 else
00515 {
00516 d_scaleMin = minval;
00517 d_scaleMax = maxval;
00518 }
00519 }
00520
00544 void QwtAutoScale::setScale(double xmin, double xmax, double step)
00545 {
00546
00547
00548 setRange(xmin,xmax);
00549 d_autoScale = FALSE;
00550 d_step = step;
00551
00552 build();
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 }