bool ScaleDiv::buildLogDiv(int maxMajSteps, int maxMinSteps, double majStep) { double firstTick, lastTick; double lFirst, lLast; double val, sval, minStep, minFactor; int nMaj, nMin, minSize, i, k, k0, kstep, kmax, i0; int rv = true; double width; QVector<double> buffer; // Parameter range check maxMajSteps = qwtMax(1, qwtAbs(maxMajSteps)); maxMinSteps = qwtMax(0, qwtAbs(maxMinSteps)); majStep = qwtAbs(majStep); // boundary check limRange(d_hBound, LOG_MIN, LOG_MAX); limRange(d_lBound, LOG_MIN, LOG_MAX); // reset vectors d_minMarks.resize(0); d_majMarks.resize(0); if (d_lBound == d_hBound) return true; // scale width in decades width = log10(d_hBound) - log10(d_lBound); // scale width is less than one decade -> build linear scale if (width < 1.0) { rv = buildLinDiv(maxMajSteps, maxMinSteps, 0.0); // convert step width to decades if (d_majStep > 0) d_majStep = log10(d_majStep); return rv; } // // Set up major scale divisions // if (majStep == 0.0) d_majStep = qwtCeil125(width * 0.999999 / double(maxMajSteps)); else d_majStep = majStep; // major step must be >= 1 decade d_majStep = qwtMax(d_majStep, 1.0); lFirst = ceil((log10(d_lBound) - step_eps * d_majStep) / d_majStep) * d_majStep; lLast = floor((log10(d_hBound) + step_eps * d_majStep) / d_majStep) * d_majStep; firstTick = pow(10.0, lFirst); lastTick = pow(10.0, lLast); nMaj = qwtMin(10000, int(rint(qwtAbs(lLast - lFirst) / d_majStep)) + 1); d_majMarks.resize(nMaj); qwtLogSpace(d_majMarks.data(), d_majMarks.size(), firstTick, lastTick); // // Set up minor scale divisions // if ((d_majMarks.size() < 1) || (maxMinSteps < 1)) return true; // no minor marks if (d_majStep < 1.1) // major step width is one decade { if (maxMinSteps >= 8) { k0 = 2; kmax = 9; kstep = 1; minSize = (d_majMarks.size() + 1) * 8; } else if (maxMinSteps >= 4) { k0 = 2; kmax = 8; kstep = 2; minSize = (d_majMarks.size() + 1) * 4; } else if (maxMinSteps >= 2) { k0 = 2; kmax = 5; kstep = 3; minSize = (d_majMarks.size() + 1) * 2; } else { k0 = 5; kmax = 5; kstep = 1; minSize = (d_majMarks.size() + 1); } // resize buffer to the max. possible number of minor marks buffer.resize(minSize); // Are there minor ticks below the first major tick? if (d_lBound < firstTick) i0 = -1; else i0 = 0; minSize = 0; for (i = i0; i < (int) d_majMarks.size(); i++) { if (i >= 0) val = d_majMarks[i]; else val = d_majMarks[0] / pow(10.0, d_majStep); for (k = k0; k <= kmax; k += kstep) { sval = val * double(k); if (limRange(sval, d_lBound, d_hBound, border_eps)) { buffer[minSize] = sval; minSize++; } } } // copy values into the minMarks array //d_minMarks.duplicate(buffer.data(), minSize); d_minMarks.resize(minSize); qCopy(buffer.data(), buffer.data() + minSize, d_minMarks.begin()); } else // major step > one decade { // substep width in decades, at least one decade minStep = qwtCeil125((d_majStep - step_eps * (d_majStep / double(maxMinSteps))) / double(maxMinSteps)); minStep = qwtMax(1.0, minStep); // # subticks per interval nMin = int(rint(d_majStep / minStep)) - 1; // Do the minor steps fit into the interval? if (qwtAbs(double(nMin + 1) * minStep - d_majStep) > step_eps * d_majStep) nMin = 0; if (nMin < 1) return true; // no subticks // resize buffer to max. possible number of subticks buffer.resize((d_majMarks.size() + 1) * nMin); // substep factor = 10^substeps minFactor = qwtMax(pow(10, minStep), 10.0); // Are there minor ticks below the first major tick? if (d_lBound < firstTick) i0 = -1; else i0 = 0; minSize = 0; for (i = i0; i < (int) d_majMarks.size(); i++) { if (i >= 0) val = d_majMarks[i]; else val = firstTick / pow(10.0, d_majStep); for (k = 0; k < nMin; k++) { sval = (val *= minFactor); if (limRange(sval, d_lBound, d_hBound, border_eps)) { buffer[minSize] = sval; minSize++; } } } //d_minMarks.duplicate(buffer.data(), minSize); d_minMarks.resize(minSize); qCopy(buffer.data(), buffer.data() + minSize, d_minMarks.begin()); } return rv; }
/*! \brief Build a linear scale */ void QwtAutoScale::buildLinScale () { double delta; const double ticks = double (d_maxMajor); // // If in Autoscale Mode, adjust minval and maxval according to // the active scale options, and add the margins // if (!d_autoScale) return; double minval = d_minValue; // scale boundaries are based on the double maxval = d_maxValue; // data. // // add / subtract margins // if (d_loMargin > 0.0) minval -= d_loMargin; if (d_hiMargin > 0.0) maxval += d_hiMargin; // // Correct minval / maxval according to the scale options // if (d_scaleOpt & Symmetric) { delta = qwtMax(qwtAbs(d_ref - maxval), qwtAbs(d_ref - minval)); maxval = d_ref + delta; minval = d_ref - delta; } else if (d_scaleOpt & IncludeRef) { if (maxval < d_ref) maxval = d_ref; else if (minval > d_ref) minval = d_ref; } // // first approximation of d_scaleMin and d_scaleMax // setRange(minval, maxval); delta = d_scaleMax - d_scaleMin; // dec := maximal power of ten which fits into the interval // [d_scaleMin,d_scaleMax] const double dec = pow (10.0, floor (log10 (delta))); // // The following magic line calculates the step size such that // - The number of subintervals will not exceed the maximum // as specified by the user // - The step size fits {1,2,5}*10^n with a natural number n // double step = qwtCeil125(delta * 0.999999 / dec / ticks) * dec; // // determine he final values of scaleMin and scaleMax // if (! (d_scaleOpt & Floating) ) { // adjust of d_scaleMin and d_scaleMax such that both are integer // multiples of the step size. d_scaleMin = step * floor ((d_scaleMin + MinEps * step) / step); d_scaleMax = step * ceil ((d_scaleMax - MinEps * step) / step); } if (d_scaleOpt & Inverted) { step = -step; d_scldiv.rebuild(d_scaleMax, d_scaleMin, d_maxMajor, d_maxMinor, FALSE, step, FALSE); } else { d_scldiv.rebuild(d_scaleMin, d_scaleMax, d_maxMajor, d_maxMinor, FALSE, step, TRUE); } }
bool ScaleDiv::buildLinDiv(int maxMajSteps, int maxMinSteps, double step) { int nMaj, nMin, minSize, i0, i, k; double val, mval; double firstTick, lastTick; double minStep; QVector<double> buffer; bool rv = true; // parameter range check maxMajSteps = qwtMax(1, maxMajSteps); maxMinSteps = qwtMax(0, maxMinSteps); step = qwtAbs(step); // reset vectors d_minMarks.resize(0); d_majMarks.resize(0); if (d_lBound == d_hBound) return true; // // Set up major divisions // if (step == 0.0) d_majStep = qwtCeil125(qwtAbs(d_hBound - d_lBound) * 0.999999 / double(maxMajSteps)); else d_majStep = step; if (d_majStep == 0.0) return true; firstTick = ceil((d_lBound - step_eps * d_majStep) / d_majStep) * d_majStep; lastTick = floor((d_hBound + step_eps * d_majStep) / d_majStep) * d_majStep; nMaj = qwtMin(10000, int(rint((lastTick - firstTick) / d_majStep)) + 1); d_majMarks.resize(nMaj); qwtLinSpace(d_majMarks.data(), d_majMarks.size(), firstTick, lastTick); // // Set up minor divisions // if (maxMinSteps < 1) // no minor divs return true; minStep = qwtCeil125(d_majStep / double(maxMinSteps)); if (minStep == 0.0) return true; nMin = qwtAbs(int(rint(d_majStep / minStep))) - 1; // # minor steps per interval // Do the minor steps fit into the interval? if (qwtAbs(double(nMin + 1) * minStep - d_majStep) > step_eps * d_majStep) { nMin = 1; minStep = d_majStep * 0.5; } // Are there minor ticks below the first major tick? if (d_majMarks[0] > d_lBound) i0 = -1; else i0 = 0; // resize buffer to the maximum possible number of minor ticks buffer.resize(nMin * (nMaj + 1)); // calculate minor ticks if (rv) { minSize = 0; for (i = i0; i < (int) d_majMarks.size(); i++) { if (i >= 0) val = d_majMarks[i]; else val = d_majMarks[0] - d_majStep; for (k = 0; k < nMin; k++) { mval = (val += minStep); if (limRange(mval, d_lBound, d_hBound, border_eps)) { buffer[minSize] = mval; minSize++; } } } //d_minMarks.duplicate(buffer.data(), minSize); d_minMarks.resize(minSize); qCopy(buffer.data(), buffer.data() + minSize, d_minMarks.begin()); } return rv; }