Mercurial > hg > svgui
diff layer/SliceLayer.cpp @ 1238:4d0ca1ab4cd0
Some work to make spectrum layers (and slice layers generally) zoomable in the frequency axis. Also fixes a number of view id mixups in SliceLayer which broke offset calculations for the x axis scale.
author | Chris Cannam |
---|---|
date | Tue, 07 Feb 2017 14:55:19 +0000 |
parents | 1a7c2ca31579 |
children | 9e1559b08f0d |
line wrap: on
line diff
--- a/layer/SliceLayer.cpp Fri Jan 27 13:19:21 2017 +0000 +++ b/layer/SliceLayer.cpp Tue Feb 07 14:55:19 2017 +0000 @@ -40,6 +40,8 @@ m_threshold(0.0), m_initialThreshold(0.0), m_gain(1.0), + m_minbin(0), + m_maxbin(0), m_currentf0(0), m_currentf1(0) { @@ -67,7 +69,11 @@ connectSignals(m_sliceableModel); + m_minbin = 0; + m_maxbin = m_sliceableModel->getHeight(); + emit modelReplaced(); + emit layerParametersChanged(); } void @@ -107,13 +113,10 @@ maxbin = 0; if (!m_sliceableModel) return ""; - int xorigin = m_xorigins[v]; - int w = v->getPaintWidth() - xorigin - 1; - + minbin = int(round(getBinForX(v, p.x()))); + maxbin = int(round(getBinForX(v, p.x() + 1))); + int mh = m_sliceableModel->getHeight(); - minbin = getBinForX(p.x() - xorigin, mh, w); - maxbin = getBinForX(p.x() - xorigin + 1, mh, w); - if (minbin >= mh) minbin = mh - 1; if (maxbin >= mh) maxbin = mh - 1; if (minbin < 0) minbin = 0; @@ -133,12 +136,15 @@ if (includeBinDescription) { + int i0 = minbin - m_minbin; + int i1 = maxbin - m_minbin; + float minvalue = 0.0; - if (minbin < int(m_values.size())) minvalue = m_values[minbin]; + if (in_range_for(m_values, i0)) minvalue = m_values[i0]; float maxvalue = minvalue; - if (maxbin < int(m_values.size())) maxvalue = m_values[maxbin]; - + if (in_range_for(m_values, i1)) maxvalue = m_values[i1]; + if (minvalue > maxvalue) std::swap(minvalue, maxvalue); QString binstr; @@ -180,10 +186,21 @@ } double -SliceLayer::getXForBin(int bin, int count, double w) const +SliceLayer::getXForBin(const LayerGeometryProvider *v, double bin) const { double x = 0; + bin -= m_minbin; + if (bin < 0) bin = 0; + + double count = m_maxbin - m_minbin; + if (count < 0) count = 0; + + int pw = v->getPaintWidth(); + int origin = m_xorigins[v->getId()]; + int w = pw - origin; + if (w < 1) w = 1; + switch (m_binScale) { case LinearBins: @@ -198,15 +215,27 @@ x = w - (w * log10(count - bin - 1)) / log10(count); break; } - - return x; + + return x + origin; } -int -SliceLayer::getBinForX(double x, int count, double w) const +double +SliceLayer::getBinForX(const LayerGeometryProvider *v, double x) const { - int bin = 0; + double bin = 0; + double count = m_maxbin - m_minbin; + if (count < 0) count = 0; + + int pw = v->getPaintWidth(); + int origin = m_xorigins[v->getId()]; + + int w = pw - origin; + if (w < 1) w = 1; + + x = x - origin; + if (x < 0) x = 0; + switch (m_binScale) { case LinearBins: @@ -222,20 +251,20 @@ break; } - return bin; + return bin + m_minbin; } double -SliceLayer::getYForValue(double value, const LayerGeometryProvider *v, double &norm) const +SliceLayer::getYForValue(const LayerGeometryProvider *v, double value, double &norm) const { norm = 0.0; - if (m_yorigins.find(v) == m_yorigins.end()) return 0; + if (m_yorigins.find(v->getId()) == m_yorigins.end()) return 0; value *= m_gain; - int yorigin = m_yorigins[v]; - int h = m_heights[v]; + int yorigin = m_yorigins[v->getId()]; + int h = m_heights[v->getId()]; double thresh = getThresholdDb(); double y = 0.0; @@ -276,14 +305,14 @@ } double -SliceLayer::getValueForY(double y, const LayerGeometryProvider *v) const +SliceLayer::getValueForY(const LayerGeometryProvider *v, double y) const { double value = 0.0; - if (m_yorigins.find(v) == m_yorigins.end()) return value; + if (m_yorigins.find(v->getId()) == m_yorigins.end()) return value; - int yorigin = m_yorigins[v]; - int h = m_heights[v]; + int yorigin = m_yorigins[v->getId()]; + int h = m_heights[v->getId()]; double thresh = getThresholdDb(); if (h <= 0) return value; @@ -341,20 +370,26 @@ int xorigin = getVerticalScaleWidth(v, true, paint) + 1; int w = v->getPaintWidth() - xorigin - 1; - m_xorigins[v] = xorigin; // for use in getFeatureDescription + m_xorigins[v->getId()] = xorigin; // for use in getFeatureDescription int yorigin = v->getPaintHeight() - 20 - paint.fontMetrics().height() - 7; int h = yorigin - paint.fontMetrics().height() - 8; - m_yorigins[v] = yorigin; // for getYForValue etc - m_heights[v] = h; + m_yorigins[v->getId()] = yorigin; // for getYForValue etc + m_heights[v->getId()] = h; if (h <= 0) return; QPainterPath path; int mh = m_sliceableModel->getHeight(); + int bin0 = 0; + if (m_maxbin > m_minbin) { + mh = m_maxbin - m_minbin; + bin0 = m_minbin; + } + int divisor = 0; m_values.clear(); @@ -388,7 +423,7 @@ for (int col = col0; col <= col1; ++col) { for (int bin = 0; bin < mh; ++bin) { - float value = m_sliceableModel->getValueAt(col, bin); + float value = m_sliceableModel->getValueAt(col, bin0 + bin); if (bin < cs) value *= curve[bin]; if (m_samplingMode == SamplePeak) { if (value > m_values[bin]) m_values[bin] = value; @@ -412,18 +447,18 @@ } } - double nx = xorigin; + double nx = getXForBin(v, bin0); ColourMapper mapper(m_colourMap, 0, 1); for (int bin = 0; bin < mh; ++bin) { double x = nx; - nx = xorigin + getXForBin(bin + 1, mh, w); + nx = getXForBin(v, bin + bin0 + 1); double value = m_values[bin]; double norm = 0.0; - double y = getYForValue(value, v, norm); + double y = getYForValue(v, value, norm); if (m_plotStyle == PlotLines) { @@ -461,60 +496,20 @@ paint.drawPath(path); } paint.restore(); -/* - QPoint discard; - - if (v->getViewManager() && v->getViewManager()->shouldShowFrameCount() && - v->shouldIlluminateLocalFeatures(this, discard)) { - - int sampleRate = m_sliceableModel->getSampleRate(); - - QString startText = QString("%1 / %2") - .arg(QString::fromStdString - (RealTime::frame2RealTime - (f0, sampleRate).toText(true))) - .arg(f0); - - QString endText = QString(" %1 / %2") - .arg(QString::fromStdString - (RealTime::frame2RealTime - (f1, sampleRate).toText(true))) - .arg(f1); - - QString durationText = QString("(%1 / %2) ") - .arg(QString::fromStdString - (RealTime::frame2RealTime - (f1 - f0 + 1, sampleRate).toText(true))) - .arg(f1 - f0 + 1); - - v->drawVisibleText - (paint, xorigin + 5, - paint.fontMetrics().ascent() + 5, - startText, PaintAssistant::OutlinedText); - - v->drawVisibleText - (paint, xorigin + 5, - paint.fontMetrics().ascent() + paint.fontMetrics().height() + 10, - endText, PaintAssistant::OutlinedText); - - v->drawVisibleText - (paint, xorigin + 5, - paint.fontMetrics().ascent() + 2*paint.fontMetrics().height() + 15, - durationText, PaintAssistant::OutlinedText); - } -*/ } int SliceLayer::getVerticalScaleWidth(LayerGeometryProvider *, bool, QPainter &paint) const { + int width; if (m_energyScale == LinearScale || m_energyScale == AbsoluteScale) { - return std::max(paint.fontMetrics().width("0.0") + 13, - paint.fontMetrics().width("x10-10")); + width = std::max(paint.fontMetrics().width("0.0") + 13, + paint.fontMetrics().width("x10-10")); } else { - return std::max(paint.fontMetrics().width(tr("0dB")), - paint.fontMetrics().width(tr("-Inf"))) + 13; + width = std::max(paint.fontMetrics().width(tr("0dB")), + paint.fontMetrics().width(tr("-Inf"))) + 13; } + return width; } void @@ -630,7 +625,7 @@ *max = 50; *deflt = 0; - cerr << "gain is " << m_gain << ", mode is " << m_samplingMode << endl; +// cerr << "gain is " << m_gain << ", mode is " << m_samplingMode << endl; val = int(lrint(log10(m_gain) * 20.0)); if (val < *min) val = *min; @@ -897,7 +892,7 @@ "binScale=\"%5\" " "gain=\"%6\" " "threshold=\"%7\" " - "normalize=\"%8\"") + "normalize=\"%8\" %9") .arg(m_colourMap) .arg(m_energyScale) .arg(m_samplingMode) @@ -905,7 +900,11 @@ .arg(m_binScale) .arg(m_gain) .arg(m_threshold) - .arg(m_normalize ? "true" : "false"); + .arg(m_normalize ? "true" : "false") + .arg(QString("minbin=\"%1\" " + "maxbin=\"%2\"") + .arg(m_minbin) + .arg(m_maxbin)); SingleColourLayer::toXml(stream, indent, extraAttributes + " " + s); } @@ -944,11 +943,105 @@ bool normalize = (attributes.value("normalize").trimmed() == "true"); setNormalize(normalize); + + bool alsoOk = false; + + float min = attributes.value("minbin").toFloat(&ok); + float max = attributes.value("maxbin").toFloat(&alsoOk); + if (ok && alsoOk) setDisplayExtents(min, max); } bool -SliceLayer::getValueExtents(double &, double &, bool &, QString &) const +SliceLayer::getValueExtents(double &min, double &max, bool &logarithmic, + QString &unit) const { - return false; + if (!m_sliceableModel) return false; + + min = 0; + max = double(m_sliceableModel->getHeight()); + + logarithmic = (m_binScale == BinScale::LogBins); + unit = ""; + + return true; } +bool +SliceLayer::getDisplayExtents(double &min, double &max) const +{ + if (!m_sliceableModel) return false; + + double hmax = double(m_sliceableModel->getHeight()); + + min = m_minbin; + max = m_maxbin; + if (max <= min) { + min = 0; + max = hmax; + } + if (min < 0) min = 0; + if (max > hmax) max = hmax; + + return true; +} + +bool +SliceLayer::setDisplayExtents(double min, double max) +{ + if (!m_sliceableModel) return false; + + m_minbin = int(lrint(min)); + m_maxbin = int(lrint(max)); + + emit layerParametersChanged(); + return true; +} + +int +SliceLayer::getVerticalZoomSteps(int &defaultStep) const +{ + if (!m_sliceableModel) return 0; + + defaultStep = 0; + int h = m_sliceableModel->getHeight(); + return h; +} + +int +SliceLayer::getCurrentVerticalZoomStep() const +{ + if (!m_sliceableModel) return 0; + + double min, max; + getDisplayExtents(min, max); + return m_sliceableModel->getHeight() - int(lrint(max - min)); +} + +void +SliceLayer::setVerticalZoomStep(int step) +{ + if (!m_sliceableModel) return; + +// SVDEBUG << "SliceLayer::setVerticalZoomStep(" <<step <<"): before: minbin = " << m_minbin << ", maxbin = " << m_maxbin << endl; + + int dist = m_sliceableModel->getHeight() - step; + if (dist < 1) dist = 1; + double centre = m_minbin + (m_maxbin - m_minbin) / 2.0; + m_minbin = int(lrint(centre - dist/2.0)); + if (m_minbin < 0) m_minbin = 0; + m_maxbin = m_minbin + dist; + if (m_maxbin > m_sliceableModel->getHeight()) m_maxbin = m_sliceableModel->getHeight(); + +// SVDEBUG << "SliceLayer::setVerticalZoomStep(" <<step <<"): after: minbin = " << m_minbin << ", maxbin = " << m_maxbin << endl; + + emit layerParametersChanged(); +} + +RangeMapper * +SliceLayer::getNewVerticalZoomRangeMapper() const +{ + if (!m_sliceableModel) return 0; + + return new LinearRangeMapper(0, m_sliceableModel->getHeight(), + 0, m_sliceableModel->getHeight(), ""); +}