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 }