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 Tue Nov 16 21:12:21 2004 for Qwt User's Guide by doxygen 1.3.8