00001
00002
00003
00004
00005
00006
00007
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
00139 maxMajSteps = qwtMax(1, maxMajSteps);
00140 maxMinSteps = qwtMax(0, maxMinSteps);
00141 step = qwtAbs(step);
00142
00143
00144 d_majMarks.duplicate(0,0);
00145 d_minMarks.duplicate(0,0);
00146
00147 if (d_lBound == d_hBound) return TRUE;
00148
00149
00150
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
00172
00173 if (maxMinSteps < 1)
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;
00181
00182
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
00191 if (d_majMarks[0] > d_lBound )
00192 i0 = -1;
00193 else
00194 i0 = 0;
00195
00196
00197 rv = buffer.resize(nMin * (nMaj + 1));
00198
00199
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
00245 maxMajSteps = qwtMax(1, qwtAbs(maxMajSteps));
00246 maxMinSteps = qwtMax(0, qwtAbs(maxMinSteps));
00247 majStep = qwtAbs(majStep);
00248
00249
00250 qwtLimRange(d_hBound, LOG_MIN, LOG_MAX);
00251 qwtLimRange(d_lBound, LOG_MIN, LOG_MAX);
00252
00253
00254 d_majMarks.duplicate(0,0);
00255 d_minMarks.duplicate(0,0);
00256
00257 if (d_lBound == d_hBound) return TRUE;
00258
00259
00260 width = log10(d_hBound) - log10(d_lBound);
00261
00262
00263 if (width < 1.0)
00264 {
00265 rv = buildLinDiv(maxMajSteps, maxMinSteps, 0.0);
00266
00267 if (d_majStep > 0)
00268 d_majStep = log10(d_majStep);
00269
00270 return rv;
00271 }
00272
00273
00274
00275
00276 if (majStep == 0.0)
00277 d_majStep = qwtCeil125( width * 0.999999 / double(maxMajSteps));
00278 else
00279 d_majStep = majStep;
00280
00281
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
00301
00302
00303 if ((d_majMarks.size() < 1) || (maxMinSteps < 1)) return TRUE;
00304
00305 if (d_majStep < 1.1)
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
00337 buffer.resize(minSize);
00338
00339
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
00365 d_minMarks.duplicate(buffer.data(), minSize);
00366
00367 }
00368 else
00369 {
00370
00371
00372 minStep = qwtCeil125( (d_majStep - step_eps * (d_majStep / double(maxMinSteps)))
00373 / double(maxMinSteps) );
00374 minStep = qwtMax(1.0, minStep);
00375
00376
00377 nMin = int(floor (d_majStep / minStep + 0.5)) - 1;
00378
00379
00380 if ( qwtAbs( double(nMin + 1) * minStep - d_majStep) > step_eps * d_majStep)
00381 nMin = 0;
00382
00383 if (nMin < 1) return TRUE;
00384
00385
00386 buffer.resize((d_majMarks.size() + 1) * nMin );
00387
00388
00389 minFactor = qwtMax(pow(10.0, minStep), 10.0);
00390
00391
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
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 }