lbajardsilogic@0: lbajardsilogic@0: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ lbajardsilogic@0: lbajardsilogic@0: /* lbajardsilogic@0: Sonic Visualiser lbajardsilogic@0: An audio file viewer and annotation editor. lbajardsilogic@0: Centre for Digital Music, Queen Mary, University of London. lbajardsilogic@0: This file copyright 2006-2007 QMUL. lbajardsilogic@0: lbajardsilogic@0: This program is free software; you can redistribute it and/or lbajardsilogic@0: modify it under the terms of the GNU General Public License as lbajardsilogic@0: published by the Free Software Foundation; either version 2 of the lbajardsilogic@0: License, or (at your option) any later version. See the file lbajardsilogic@0: COPYING included with this distribution for more information. lbajardsilogic@0: */ lbajardsilogic@0: lbajardsilogic@0: #include "SliceLayer.h" lbajardsilogic@0: lbajardsilogic@0: #include "system/System.h" lbajardsilogic@0: #include "view/View.h" lbajardsilogic@0: #include "base/AudioLevel.h" lbajardsilogic@0: #include "base/RangeMapper.h" lbajardsilogic@0: #include "base/RealTime.h" lbajardsilogic@0: lbajardsilogic@0: #include "ColourMapper.h" lbajardsilogic@0: #include "PaintAssistant.h" lbajardsilogic@0: lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: lbajardsilogic@0: SliceLayer::SliceLayer() : lbajardsilogic@0: m_sliceableModel(0), lbajardsilogic@0: m_colour(Qt::darkBlue), lbajardsilogic@0: m_colourMap(0), lbajardsilogic@0: m_energyScale(dBScale), lbajardsilogic@0: m_samplingMode(SampleMean), lbajardsilogic@0: m_plotStyle(PlotSteps), lbajardsilogic@0: m_binScale(LinearBins), lbajardsilogic@0: m_normalize(false), lbajardsilogic@0: m_bias(false), lbajardsilogic@0: m_gain(1.0), lbajardsilogic@0: m_currentf0(0), lbajardsilogic@0: m_currentf1(0) lbajardsilogic@0: { lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: SliceLayer::~SliceLayer() lbajardsilogic@0: { lbajardsilogic@0: lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: SliceLayer::setSliceableModel(const Model *model) lbajardsilogic@0: { lbajardsilogic@0: const DenseThreeDimensionalModel *sliceable = lbajardsilogic@0: dynamic_cast(model); lbajardsilogic@0: lbajardsilogic@0: if (model && !sliceable) { lbajardsilogic@0: std::cerr << "WARNING: SliceLayer::setSliceableModel(" << model lbajardsilogic@0: << "): model is not a DenseThreeDimensionalModel" << std::endl; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (m_sliceableModel == sliceable) return; lbajardsilogic@0: lbajardsilogic@0: m_sliceableModel = sliceable; lbajardsilogic@0: lbajardsilogic@0: connect(m_sliceableModel, SIGNAL(modelChanged()), lbajardsilogic@0: this, SIGNAL(modelChanged())); lbajardsilogic@0: lbajardsilogic@0: connect(m_sliceableModel, SIGNAL(modelChanged(size_t, size_t)), lbajardsilogic@0: this, SIGNAL(modelChanged(size_t, size_t))); lbajardsilogic@0: lbajardsilogic@0: connect(m_sliceableModel, SIGNAL(completionChanged()), lbajardsilogic@0: this, SIGNAL(modelCompletionChanged())); lbajardsilogic@0: lbajardsilogic@0: emit modelReplaced(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: SliceLayer::sliceableModelReplaced(const Model *orig, const Model *replacement) lbajardsilogic@0: { lbajardsilogic@0: std::cerr << "SliceLayer::sliceableModelReplaced(" << orig << ", " << replacement << ")" << std::endl; lbajardsilogic@0: lbajardsilogic@0: if (orig == m_sliceableModel) { lbajardsilogic@0: setSliceableModel lbajardsilogic@0: (dynamic_cast(replacement)); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: SliceLayer::modelAboutToBeDeleted(Model *m) lbajardsilogic@0: { lbajardsilogic@0: std::cerr << "SliceLayer::modelAboutToBeDeleted(" << m << ")" << std::endl; lbajardsilogic@0: lbajardsilogic@0: if (m == m_sliceableModel) { lbajardsilogic@0: setSliceableModel(0); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QString lbajardsilogic@0: SliceLayer::getFeatureDescription(View *v, QPoint &p) const lbajardsilogic@0: { lbajardsilogic@0: int minbin, maxbin, range; lbajardsilogic@0: return getFeatureDescription(v, p, true, minbin, maxbin, range); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QString lbajardsilogic@0: SliceLayer::getFeatureDescription(View *v, QPoint &p, lbajardsilogic@0: bool includeBinDescription, lbajardsilogic@0: int &minbin, int &maxbin, int &range) const lbajardsilogic@0: { lbajardsilogic@0: minbin = 0; lbajardsilogic@0: maxbin = 0; lbajardsilogic@0: if (!m_sliceableModel) return ""; lbajardsilogic@0: lbajardsilogic@0: int xorigin = m_xorigins[v]; lbajardsilogic@0: int w = v->width() - xorigin - 1; lbajardsilogic@0: lbajardsilogic@0: int mh = m_sliceableModel->getHeight(); lbajardsilogic@0: minbin = getBinForX(p.x() - xorigin, mh, w); lbajardsilogic@0: maxbin = getBinForX(p.x() - xorigin + 1, mh, w); lbajardsilogic@0: lbajardsilogic@0: if (minbin >= mh) minbin = mh - 1; lbajardsilogic@0: if (maxbin >= mh) maxbin = mh - 1; lbajardsilogic@0: if (minbin < 0) minbin = 0; lbajardsilogic@0: if (maxbin < 0) maxbin = 0; lbajardsilogic@0: lbajardsilogic@0: int sampleRate = m_sliceableModel->getSampleRate(); lbajardsilogic@0: lbajardsilogic@0: size_t f0 = m_currentf0; lbajardsilogic@0: size_t f1 = m_currentf1; lbajardsilogic@0: lbajardsilogic@0: RealTime rt0 = RealTime::frame2RealTime(f0, sampleRate); lbajardsilogic@0: RealTime rt1 = RealTime::frame2RealTime(f1, sampleRate); lbajardsilogic@0: lbajardsilogic@0: range = f1 - f0 + 1; lbajardsilogic@0: lbajardsilogic@0: if (includeBinDescription) { lbajardsilogic@0: lbajardsilogic@0: float minvalue = 0.f; lbajardsilogic@0: if (minbin < int(m_values.size())) minvalue = m_values[minbin]; lbajardsilogic@0: lbajardsilogic@0: float maxvalue = minvalue; lbajardsilogic@0: if (maxbin < int(m_values.size())) maxvalue = m_values[maxbin]; lbajardsilogic@0: lbajardsilogic@0: if (minvalue > maxvalue) std::swap(minvalue, maxvalue); lbajardsilogic@0: lbajardsilogic@0: QString binstr; lbajardsilogic@0: if (maxbin != minbin) { lbajardsilogic@0: binstr = tr("%1 - %2").arg(minbin+1).arg(maxbin+1); lbajardsilogic@0: } else { lbajardsilogic@0: binstr = QString("%1").arg(minbin+1); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QString valuestr; lbajardsilogic@0: if (maxvalue != minvalue) { lbajardsilogic@0: valuestr = tr("%1 - %2").arg(minvalue).arg(maxvalue); lbajardsilogic@0: } else { lbajardsilogic@0: valuestr = QString("%1").arg(minvalue); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QString description = tr("Time:\t%1 - %2\nRange:\t%3 samples\nBin:\t%4\n%5 value:\t%6") lbajardsilogic@0: .arg(QString::fromStdString(rt0.toText(true))) lbajardsilogic@0: .arg(QString::fromStdString(rt1.toText(true))) lbajardsilogic@0: .arg(range) lbajardsilogic@0: .arg(binstr) lbajardsilogic@0: .arg(m_samplingMode == NearestSample ? tr("First") : lbajardsilogic@0: m_samplingMode == SampleMean ? tr("Mean") : tr("Peak")) lbajardsilogic@0: .arg(valuestr); lbajardsilogic@0: lbajardsilogic@0: return description; lbajardsilogic@0: lbajardsilogic@0: } else { lbajardsilogic@0: lbajardsilogic@0: QString description = tr("Time:\t%1 - %2\nRange:\t%3 samples") lbajardsilogic@0: .arg(QString::fromStdString(rt0.toText(true))) lbajardsilogic@0: .arg(QString::fromStdString(rt1.toText(true))) lbajardsilogic@0: .arg(range); lbajardsilogic@0: lbajardsilogic@0: return description; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: float lbajardsilogic@0: SliceLayer::getXForBin(int bin, int count, float w) const lbajardsilogic@0: { lbajardsilogic@0: float x = 0; lbajardsilogic@0: lbajardsilogic@0: switch (m_binScale) { lbajardsilogic@0: lbajardsilogic@0: case LinearBins: lbajardsilogic@0: x = (float(w) * bin) / count; lbajardsilogic@0: break; lbajardsilogic@0: lbajardsilogic@0: case LogBins: lbajardsilogic@0: x = (float(w) * log10f(bin + 1)) / log10f(count + 1); lbajardsilogic@0: break; lbajardsilogic@0: lbajardsilogic@0: case InvertedLogBins: lbajardsilogic@0: x = w - (float(w) * log10f(count - bin - 1)) / log10f(count); lbajardsilogic@0: break; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: return x; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: int lbajardsilogic@0: SliceLayer::getBinForX(float x, int count, float w) const lbajardsilogic@0: { lbajardsilogic@0: int bin = 0; lbajardsilogic@0: lbajardsilogic@0: switch (m_binScale) { lbajardsilogic@0: lbajardsilogic@0: case LinearBins: lbajardsilogic@0: bin = int((x * count) / w + 0.0001); lbajardsilogic@0: break; lbajardsilogic@0: lbajardsilogic@0: case LogBins: lbajardsilogic@0: bin = int(powf(10.f, (x * log10f(count + 1)) / w) - 1 + 0.0001); lbajardsilogic@0: break; lbajardsilogic@0: lbajardsilogic@0: case InvertedLogBins: lbajardsilogic@0: bin = count + 1 - int(powf(10.f, (log10f(count) * (w - x)) / float(w)) + 0.0001); lbajardsilogic@0: break; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: return bin; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: SliceLayer::paint(View *v, QPainter &paint, QRect rect) const lbajardsilogic@0: { lbajardsilogic@0: if (!m_sliceableModel) return; lbajardsilogic@0: lbajardsilogic@0: paint.save(); lbajardsilogic@0: paint.setRenderHint(QPainter::Antialiasing, false); lbajardsilogic@0: lbajardsilogic@0: if (v->getViewManager() && v->getViewManager()->shouldShowScaleGuides()) { lbajardsilogic@0: if (!m_scalePoints.empty()) { lbajardsilogic@0: paint.setPen(QColor(240, 240, 240)); //!!! and dark background? lbajardsilogic@0: for (size_t i = 0; i < m_scalePoints.size(); ++i) { lbajardsilogic@0: paint.drawLine(0, m_scalePoints[i], rect.width(), m_scalePoints[i]); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: paint.setPen(m_colour); lbajardsilogic@0: lbajardsilogic@0: // int w = (v->width() * 2) / 3; lbajardsilogic@0: int xorigin = getVerticalScaleWidth(v, paint) + 1; //!!! (v->width() / 2) - (w / 2); lbajardsilogic@0: int w = v->width() - xorigin - 1; lbajardsilogic@0: lbajardsilogic@0: m_xorigins[v] = xorigin; // for use in getFeatureDescription lbajardsilogic@0: lbajardsilogic@0: int yorigin = v->height() - 20 - paint.fontMetrics().height() - 7; lbajardsilogic@0: int h = yorigin - paint.fontMetrics().height() - 8; lbajardsilogic@0: if (h < 0) return; lbajardsilogic@0: lbajardsilogic@0: // int h = (v->height() * 3) / 4; lbajardsilogic@0: // int yorigin = (v->height() / 2) + (h / 2); lbajardsilogic@0: lbajardsilogic@0: QPainterPath path; lbajardsilogic@0: float thresh = -80.f; lbajardsilogic@0: lbajardsilogic@0: size_t mh = m_sliceableModel->getHeight(); lbajardsilogic@0: lbajardsilogic@0: int divisor = 0; lbajardsilogic@0: lbajardsilogic@0: m_values.clear(); lbajardsilogic@0: for (size_t bin = 0; bin < mh; ++bin) { lbajardsilogic@0: m_values.push_back(0.f); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: size_t f0 = v->getCentreFrame(); lbajardsilogic@0: int f0x = v->getXForFrame(f0); lbajardsilogic@0: f0 = v->getFrameForX(f0x); lbajardsilogic@0: size_t f1 = v->getFrameForX(f0x + 1); lbajardsilogic@0: if (f1 > f0) --f1; lbajardsilogic@0: lbajardsilogic@0: size_t col0 = f0 / m_sliceableModel->getResolution(); lbajardsilogic@0: size_t col1 = col0; lbajardsilogic@0: if (m_samplingMode != NearestSample) { lbajardsilogic@0: col1 = f1 / m_sliceableModel->getResolution(); lbajardsilogic@0: } lbajardsilogic@0: f0 = col0 * m_sliceableModel->getResolution(); lbajardsilogic@0: f1 = (col1 + 1) * m_sliceableModel->getResolution() - 1; lbajardsilogic@0: lbajardsilogic@0: m_currentf0 = f0; lbajardsilogic@0: m_currentf1 = f1; lbajardsilogic@0: lbajardsilogic@0: for (size_t col = col0; col <= col1; ++col) { lbajardsilogic@0: for (size_t bin = 0; bin < mh; ++bin) { lbajardsilogic@0: float value = m_sliceableModel->getValueAt(col, bin); lbajardsilogic@0: if (m_bias) value *= bin + 1; lbajardsilogic@0: if (m_samplingMode == SamplePeak) { lbajardsilogic@0: if (value > m_values[bin]) m_values[bin] = value; lbajardsilogic@0: } else { lbajardsilogic@0: m_values[bin] += value; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: ++divisor; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: float max = 0.f; lbajardsilogic@0: for (size_t bin = 0; bin < mh; ++bin) { lbajardsilogic@0: if (m_samplingMode == SampleMean) m_values[bin] /= divisor; lbajardsilogic@0: if (m_values[bin] > max) max = m_values[bin]; lbajardsilogic@0: } lbajardsilogic@0: if (max != 0.f && m_normalize) { lbajardsilogic@0: for (size_t bin = 0; bin < mh; ++bin) { lbajardsilogic@0: m_values[bin] /= max; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: float py = 0; lbajardsilogic@0: float nx = xorigin; lbajardsilogic@0: lbajardsilogic@0: ColourMapper mapper(m_colourMap, 0, 1); lbajardsilogic@0: lbajardsilogic@0: for (size_t bin = 0; bin < mh; ++bin) { lbajardsilogic@0: lbajardsilogic@0: float x = nx; lbajardsilogic@0: nx = xorigin + getXForBin(bin + 1, mh, w); lbajardsilogic@0: lbajardsilogic@0: float value = m_values[bin]; lbajardsilogic@0: lbajardsilogic@0: value *= m_gain; lbajardsilogic@0: float norm = 0.f; lbajardsilogic@0: float y = 0.f; lbajardsilogic@0: lbajardsilogic@0: switch (m_energyScale) { lbajardsilogic@0: lbajardsilogic@0: case dBScale: lbajardsilogic@0: { lbajardsilogic@0: float db = thresh; lbajardsilogic@0: if (value > 0.f) db = 10.f * log10f(value); lbajardsilogic@0: if (db < thresh) db = thresh; lbajardsilogic@0: norm = (db - thresh) / -thresh; lbajardsilogic@0: y = yorigin - (float(h) * norm); lbajardsilogic@0: break; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: case MeterScale: lbajardsilogic@0: y = AudioLevel::multiplier_to_preview(value, h); lbajardsilogic@0: norm = float(y) / float(h); lbajardsilogic@0: y = yorigin - y; lbajardsilogic@0: break; lbajardsilogic@0: lbajardsilogic@0: default: lbajardsilogic@0: norm = value; lbajardsilogic@0: y = yorigin - (float(h) * value); lbajardsilogic@0: break; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (m_plotStyle == PlotLines) { lbajardsilogic@0: lbajardsilogic@0: if (bin == 0) { lbajardsilogic@0: path.moveTo(x, y); lbajardsilogic@0: } else { lbajardsilogic@0: path.lineTo(x, y); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: } else if (m_plotStyle == PlotSteps) { lbajardsilogic@0: lbajardsilogic@0: if (bin == 0) { lbajardsilogic@0: path.moveTo(x, y); lbajardsilogic@0: } else { lbajardsilogic@0: path.lineTo(x, y); lbajardsilogic@0: } lbajardsilogic@0: path.lineTo(nx, y); lbajardsilogic@0: lbajardsilogic@0: } else if (m_plotStyle == PlotBlocks) { lbajardsilogic@0: lbajardsilogic@0: path.moveTo(x, yorigin); lbajardsilogic@0: path.lineTo(x, y); lbajardsilogic@0: path.lineTo(nx, y); lbajardsilogic@0: path.lineTo(nx, yorigin); lbajardsilogic@0: path.lineTo(x, yorigin); lbajardsilogic@0: lbajardsilogic@0: } else if (m_plotStyle == PlotFilledBlocks) { lbajardsilogic@0: lbajardsilogic@0: paint.fillRect(QRectF(x, y, nx - x, yorigin - y), mapper.map(norm)); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: py = y; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (m_plotStyle != PlotFilledBlocks) { lbajardsilogic@0: paint.drawPath(path); lbajardsilogic@0: } lbajardsilogic@0: paint.restore(); lbajardsilogic@0: /* lbajardsilogic@0: QPoint discard; lbajardsilogic@0: lbajardsilogic@0: if (v->getViewManager() && v->getViewManager()->shouldShowFrameCount() && lbajardsilogic@0: v->shouldIlluminateLocalFeatures(this, discard)) { lbajardsilogic@0: lbajardsilogic@0: int sampleRate = m_sliceableModel->getSampleRate(); lbajardsilogic@0: lbajardsilogic@0: QString startText = QString("%1 / %2") lbajardsilogic@0: .arg(QString::fromStdString lbajardsilogic@0: (RealTime::frame2RealTime lbajardsilogic@0: (f0, sampleRate).toText(true))) lbajardsilogic@0: .arg(f0); lbajardsilogic@0: lbajardsilogic@0: QString endText = QString(" %1 / %2") lbajardsilogic@0: .arg(QString::fromStdString lbajardsilogic@0: (RealTime::frame2RealTime lbajardsilogic@0: (f1, sampleRate).toText(true))) lbajardsilogic@0: .arg(f1); lbajardsilogic@0: lbajardsilogic@0: QString durationText = QString("(%1 / %2) ") lbajardsilogic@0: .arg(QString::fromStdString lbajardsilogic@0: (RealTime::frame2RealTime lbajardsilogic@0: (f1 - f0 + 1, sampleRate).toText(true))) lbajardsilogic@0: .arg(f1 - f0 + 1); lbajardsilogic@0: lbajardsilogic@0: v->drawVisibleText lbajardsilogic@0: (paint, xorigin + 5, lbajardsilogic@0: paint.fontMetrics().ascent() + 5, lbajardsilogic@0: startText, View::OutlinedText); lbajardsilogic@0: lbajardsilogic@0: v->drawVisibleText lbajardsilogic@0: (paint, xorigin + 5, lbajardsilogic@0: paint.fontMetrics().ascent() + paint.fontMetrics().height() + 10, lbajardsilogic@0: endText, View::OutlinedText); lbajardsilogic@0: lbajardsilogic@0: v->drawVisibleText lbajardsilogic@0: (paint, xorigin + 5, lbajardsilogic@0: paint.fontMetrics().ascent() + 2*paint.fontMetrics().height() + 15, lbajardsilogic@0: durationText, View::OutlinedText); lbajardsilogic@0: } lbajardsilogic@0: */ lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: int lbajardsilogic@0: SliceLayer::getVerticalScaleWidth(View *, QPainter &paint) const lbajardsilogic@0: { lbajardsilogic@0: if (m_energyScale == LinearScale) { lbajardsilogic@191: return MAX(paint.fontMetrics().width("0.0") + 13, lbajardsilogic@0: paint.fontMetrics().width("x10-10")); lbajardsilogic@0: } else { lbajardsilogic@191: return MAX(paint.fontMetrics().width(tr("0dB")), lbajardsilogic@0: paint.fontMetrics().width(tr("-Inf"))) + 13; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: SliceLayer::paintVerticalScale(View *v, QPainter &paint, QRect rect) const lbajardsilogic@0: { lbajardsilogic@0: float thresh = 0; lbajardsilogic@0: if (m_energyScale != LinearScale) { lbajardsilogic@0: thresh = AudioLevel::dB_to_multiplier(-80); //!!! thresh lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: // int h = (rect.height() * 3) / 4; lbajardsilogic@0: // int y = (rect.height() / 2) - (h / 2); lbajardsilogic@0: lbajardsilogic@0: int yorigin = v->height() - 20 - paint.fontMetrics().height() - 6; lbajardsilogic@0: int h = yorigin - paint.fontMetrics().height() - 8; lbajardsilogic@0: if (h < 0) return; lbajardsilogic@0: lbajardsilogic@0: QRect actual(rect.x(), rect.y() + yorigin - h, rect.width(), h); lbajardsilogic@0: lbajardsilogic@0: int mult = 1; lbajardsilogic@0: lbajardsilogic@0: PaintAssistant::paintVerticalLevelScale lbajardsilogic@0: (paint, actual, thresh, 1.0 / m_gain, lbajardsilogic@0: PaintAssistant::Scale(m_energyScale), lbajardsilogic@0: mult, lbajardsilogic@0: const_cast *>(&m_scalePoints)); lbajardsilogic@0: lbajardsilogic@0: if (mult != 1 && mult != 0) { lbajardsilogic@0: int log = lrintf(log10f(mult)); lbajardsilogic@0: QString a = tr("x10"); lbajardsilogic@0: QString b = QString("%1").arg(-log); lbajardsilogic@0: paint.drawText(3, 8 + paint.fontMetrics().ascent(), a); lbajardsilogic@0: paint.drawText(3 + paint.fontMetrics().width(a), lbajardsilogic@0: 3 + paint.fontMetrics().ascent(), b); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: Layer::PropertyList lbajardsilogic@0: SliceLayer::getProperties() const lbajardsilogic@0: { lbajardsilogic@0: PropertyList list; lbajardsilogic@0: list.push_back("Colour"); lbajardsilogic@0: list.push_back("Plot Type"); lbajardsilogic@0: // list.push_back("Sampling Mode"); lbajardsilogic@0: list.push_back("Scale"); lbajardsilogic@0: list.push_back("Normalize"); lbajardsilogic@0: list.push_back("Gain"); lbajardsilogic@0: list.push_back("Bin Scale"); lbajardsilogic@0: lbajardsilogic@0: return list; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QString lbajardsilogic@0: SliceLayer::getPropertyLabel(const PropertyName &name) const lbajardsilogic@0: { lbajardsilogic@0: if (name == "Colour") return tr("Colour"); lbajardsilogic@0: if (name == "Plot Type") return tr("Plot Type"); lbajardsilogic@0: if (name == "Energy Scale") return tr("Scale"); lbajardsilogic@0: if (name == "Normalize") return tr("Normalize"); lbajardsilogic@0: if (name == "Gain") return tr("Gain"); lbajardsilogic@0: if (name == "Sampling Mode") return tr("Sampling Mode"); lbajardsilogic@0: if (name == "Bin Scale") return tr("Plot X Scale"); lbajardsilogic@0: return ""; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: Layer::PropertyType lbajardsilogic@0: SliceLayer::getPropertyType(const PropertyName &name) const lbajardsilogic@0: { lbajardsilogic@0: if (name == "Gain") return RangeProperty; lbajardsilogic@0: if (name == "Normalize") return ToggleProperty; lbajardsilogic@0: return ValueProperty; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QString lbajardsilogic@0: SliceLayer::getPropertyGroupName(const PropertyName &name) const lbajardsilogic@0: { lbajardsilogic@0: if (name == "Scale" || lbajardsilogic@0: name == "Normalize" || lbajardsilogic@0: name == "Sampling Mode" || lbajardsilogic@0: name == "Gain") return tr("Scale"); lbajardsilogic@0: if (name == "Plot Type" || lbajardsilogic@0: name == "Bin Scale") return tr("Plot Type"); lbajardsilogic@0: return QString(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: int lbajardsilogic@0: SliceLayer::getPropertyRangeAndValue(const PropertyName &name, lbajardsilogic@0: int *min, int *max, int *deflt) const lbajardsilogic@0: { lbajardsilogic@0: int val = 0; lbajardsilogic@0: lbajardsilogic@0: int garbage0, garbage1, garbage2; lbajardsilogic@0: if (!min) min = &garbage0; lbajardsilogic@0: if (!max) max = &garbage1; lbajardsilogic@0: if (!deflt) deflt = &garbage2; lbajardsilogic@0: lbajardsilogic@0: if (name == "Gain") { lbajardsilogic@0: lbajardsilogic@0: *min = -50; lbajardsilogic@0: *max = 50; lbajardsilogic@0: *deflt = 0; lbajardsilogic@0: lbajardsilogic@0: std::cerr << "gain is " << m_gain << ", mode is " << m_samplingMode << std::endl; lbajardsilogic@0: lbajardsilogic@0: val = lrint(log10(m_gain) * 20.0); lbajardsilogic@0: if (val < *min) val = *min; lbajardsilogic@0: if (val > *max) val = *max; lbajardsilogic@0: lbajardsilogic@0: } else if (name == "Normalize") { lbajardsilogic@0: lbajardsilogic@0: val = (m_normalize ? 1 : 0); lbajardsilogic@0: *deflt = 0; lbajardsilogic@0: lbajardsilogic@0: } else if (name == "Colour") { lbajardsilogic@0: lbajardsilogic@0: if (m_plotStyle == PlotFilledBlocks) { lbajardsilogic@0: lbajardsilogic@0: *min = 0; lbajardsilogic@0: *max = ColourMapper::getColourMapCount() - 1; lbajardsilogic@0: *deflt = 0; lbajardsilogic@0: lbajardsilogic@0: val = m_colourMap; lbajardsilogic@0: lbajardsilogic@0: } else { lbajardsilogic@0: lbajardsilogic@0: *min = 0; lbajardsilogic@0: *max = 5; lbajardsilogic@0: *deflt = 0; lbajardsilogic@0: lbajardsilogic@0: if (m_colour == Qt::black) val = 0; lbajardsilogic@0: else if (m_colour == Qt::darkRed) val = 1; lbajardsilogic@0: else if (m_colour == Qt::darkBlue) val = 2; lbajardsilogic@0: else if (m_colour == Qt::darkGreen) val = 3; lbajardsilogic@0: else if (m_colour == QColor(200, 50, 255)) val = 4; lbajardsilogic@0: else if (m_colour == QColor(255, 150, 50)) val = 5; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: } else if (name == "Scale") { lbajardsilogic@0: lbajardsilogic@0: *min = 0; lbajardsilogic@0: *max = 2; lbajardsilogic@0: *deflt = (int)dBScale; lbajardsilogic@0: lbajardsilogic@0: val = (int)m_energyScale; lbajardsilogic@0: lbajardsilogic@0: } else if (name == "Sampling Mode") { lbajardsilogic@0: lbajardsilogic@0: *min = 0; lbajardsilogic@0: *max = 2; lbajardsilogic@0: *deflt = (int)SampleMean; lbajardsilogic@0: lbajardsilogic@0: val = (int)m_samplingMode; lbajardsilogic@0: lbajardsilogic@0: } else if (name == "Plot Type") { lbajardsilogic@0: lbajardsilogic@0: *min = 0; lbajardsilogic@0: *max = 3; lbajardsilogic@0: *deflt = (int)PlotSteps; lbajardsilogic@0: lbajardsilogic@0: val = (int)m_plotStyle; lbajardsilogic@0: lbajardsilogic@0: } else if (name == "Bin Scale") { lbajardsilogic@0: lbajardsilogic@0: *min = 0; lbajardsilogic@0: *max = 2; lbajardsilogic@0: *deflt = (int)LinearBins; lbajardsilogic@0: // *max = 1; // I don't think we really do want to offer inverted log lbajardsilogic@0: lbajardsilogic@0: val = (int)m_binScale; lbajardsilogic@0: lbajardsilogic@0: } else { lbajardsilogic@0: val = Layer::getPropertyRangeAndValue(name, min, max, deflt); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: return val; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QString lbajardsilogic@0: SliceLayer::getPropertyValueLabel(const PropertyName &name, lbajardsilogic@0: int value) const lbajardsilogic@0: { lbajardsilogic@0: if (name == "Colour") { lbajardsilogic@0: if (m_plotStyle == PlotFilledBlocks) { lbajardsilogic@0: return ColourMapper::getColourMapName(value); lbajardsilogic@0: } else { lbajardsilogic@0: switch (value) { lbajardsilogic@0: default: lbajardsilogic@0: case 0: return tr("Black"); lbajardsilogic@0: case 1: return tr("Red"); lbajardsilogic@0: case 2: return tr("Blue"); lbajardsilogic@0: case 3: return tr("Green"); lbajardsilogic@0: case 4: return tr("Purple"); lbajardsilogic@0: case 5: return tr("Orange"); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: if (name == "Scale") { lbajardsilogic@0: switch (value) { lbajardsilogic@0: default: lbajardsilogic@0: case 0: return tr("Linear"); lbajardsilogic@0: case 1: return tr("Meter"); lbajardsilogic@0: case 2: return tr("dB"); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: if (name == "Sampling Mode") { lbajardsilogic@0: switch (value) { lbajardsilogic@0: default: lbajardsilogic@0: case 0: return tr("Any"); lbajardsilogic@0: case 1: return tr("Mean"); lbajardsilogic@0: case 2: return tr("Peak"); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: if (name == "Plot Type") { lbajardsilogic@0: switch (value) { lbajardsilogic@0: default: lbajardsilogic@0: case 0: return tr("Lines"); lbajardsilogic@0: case 1: return tr("Steps"); lbajardsilogic@0: case 2: return tr("Blocks"); lbajardsilogic@0: case 3: return tr("Colours"); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: if (name == "Bin Scale") { lbajardsilogic@0: switch (value) { lbajardsilogic@0: default: lbajardsilogic@0: case 0: return tr("Linear Bins"); lbajardsilogic@0: case 1: return tr("Log Bins"); lbajardsilogic@0: case 2: return tr("Rev Log Bins"); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: return tr(""); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: RangeMapper * lbajardsilogic@0: SliceLayer::getNewPropertyRangeMapper(const PropertyName &name) const lbajardsilogic@0: { lbajardsilogic@0: if (name == "Gain") { lbajardsilogic@0: return new LinearRangeMapper(-50, 50, -25, 25, tr("dB")); lbajardsilogic@0: } lbajardsilogic@0: return 0; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: SliceLayer::setProperty(const PropertyName &name, int value) lbajardsilogic@0: { lbajardsilogic@0: if (name == "Gain") { lbajardsilogic@0: setGain(pow(10, float(value)/20.0)); lbajardsilogic@0: } else if (name == "Colour") { lbajardsilogic@0: if (m_plotStyle == PlotFilledBlocks) { lbajardsilogic@0: setFillColourMap(value); lbajardsilogic@0: } else { lbajardsilogic@0: switch (value) { lbajardsilogic@0: default: lbajardsilogic@0: case 0: setBaseColour(Qt::black); break; lbajardsilogic@0: case 1: setBaseColour(Qt::darkRed); break; lbajardsilogic@0: case 2: setBaseColour(Qt::darkBlue); break; lbajardsilogic@0: case 3: setBaseColour(Qt::darkGreen); break; lbajardsilogic@0: case 4: setBaseColour(QColor(200, 50, 255)); break; lbajardsilogic@0: case 5: setBaseColour(QColor(255, 150, 50)); break; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } else if (name == "Scale") { lbajardsilogic@0: switch (value) { lbajardsilogic@0: default: lbajardsilogic@0: case 0: setEnergyScale(LinearScale); break; lbajardsilogic@0: case 1: setEnergyScale(MeterScale); break; lbajardsilogic@0: case 2: setEnergyScale(dBScale); break; lbajardsilogic@0: } lbajardsilogic@0: } else if (name == "Plot Type") { lbajardsilogic@0: setPlotStyle(PlotStyle(value)); lbajardsilogic@0: } else if (name == "Sampling Mode") { lbajardsilogic@0: switch (value) { lbajardsilogic@0: default: lbajardsilogic@0: case 0: setSamplingMode(NearestSample); break; lbajardsilogic@0: case 1: setSamplingMode(SampleMean); break; lbajardsilogic@0: case 2: setSamplingMode(SamplePeak); break; lbajardsilogic@0: } lbajardsilogic@0: } else if (name == "Bin Scale") { lbajardsilogic@0: switch (value) { lbajardsilogic@0: default: lbajardsilogic@0: case 0: setBinScale(LinearBins); break; lbajardsilogic@0: case 1: setBinScale(LogBins); break; lbajardsilogic@0: case 2: setBinScale(InvertedLogBins); break; lbajardsilogic@0: } lbajardsilogic@0: } else if (name == "Normalize") { lbajardsilogic@0: setNormalize(value ? true : false); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: SliceLayer::setBaseColour(QColor colour) lbajardsilogic@0: { lbajardsilogic@0: if (m_colour == colour) return; lbajardsilogic@0: m_colour = colour; lbajardsilogic@0: emit layerParametersChanged(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: SliceLayer::setFillColourMap(int map) lbajardsilogic@0: { lbajardsilogic@0: if (m_colourMap == map) return; lbajardsilogic@0: m_colourMap = map; lbajardsilogic@0: emit layerParametersChanged(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: SliceLayer::setEnergyScale(EnergyScale scale) lbajardsilogic@0: { lbajardsilogic@0: if (m_energyScale == scale) return; lbajardsilogic@0: m_energyScale = scale; lbajardsilogic@0: emit layerParametersChanged(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: SliceLayer::setSamplingMode(SamplingMode mode) lbajardsilogic@0: { lbajardsilogic@0: if (m_samplingMode == mode) return; lbajardsilogic@0: m_samplingMode = mode; lbajardsilogic@0: emit layerParametersChanged(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: SliceLayer::setPlotStyle(PlotStyle style) lbajardsilogic@0: { lbajardsilogic@0: if (m_plotStyle == style) return; lbajardsilogic@0: bool colourTypeChanged = (style == PlotFilledBlocks || lbajardsilogic@0: m_plotStyle == PlotFilledBlocks); lbajardsilogic@0: m_plotStyle = style; lbajardsilogic@0: if (colourTypeChanged) { lbajardsilogic@0: emit layerParameterRangesChanged(); lbajardsilogic@0: } lbajardsilogic@0: emit layerParametersChanged(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: SliceLayer::setBinScale(BinScale scale) lbajardsilogic@0: { lbajardsilogic@0: if (m_binScale == scale) return; lbajardsilogic@0: m_binScale = scale; lbajardsilogic@0: emit layerParametersChanged(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: SliceLayer::setNormalize(bool n) lbajardsilogic@0: { lbajardsilogic@0: if (m_normalize == n) return; lbajardsilogic@0: m_normalize = n; lbajardsilogic@0: emit layerParametersChanged(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: SliceLayer::setGain(float gain) lbajardsilogic@0: { lbajardsilogic@0: if (m_gain == gain) return; lbajardsilogic@0: m_gain = gain; lbajardsilogic@0: emit layerParametersChanged(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QString lbajardsilogic@0: SliceLayer::toXmlString(QString indent, QString extraAttributes) const lbajardsilogic@0: { lbajardsilogic@0: QString s; lbajardsilogic@0: lbajardsilogic@0: s += QString("colour=\"%1\" " lbajardsilogic@0: "colourScheme=\"%2\" " lbajardsilogic@0: "energyScale=\"%3\" " lbajardsilogic@0: "samplingMode=\"%4\" " lbajardsilogic@0: "gain=\"%5\" " lbajardsilogic@0: "normalize=\"%6\"") lbajardsilogic@0: .arg(encodeColour(m_colour)) lbajardsilogic@0: .arg(m_colourMap) lbajardsilogic@0: .arg(m_energyScale) lbajardsilogic@0: .arg(m_samplingMode) lbajardsilogic@0: .arg(m_gain) lbajardsilogic@0: .arg(m_normalize ? "true" : "false"); lbajardsilogic@0: lbajardsilogic@0: return Layer::toXmlString(indent, extraAttributes + " " + s); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: SliceLayer::setProperties(const QXmlAttributes &attributes) lbajardsilogic@0: { lbajardsilogic@0: bool ok = false; lbajardsilogic@0: lbajardsilogic@0: QString colourSpec = attributes.value("colour"); lbajardsilogic@0: if (colourSpec != "") { lbajardsilogic@0: QColor colour(colourSpec); lbajardsilogic@0: if (colour.isValid()) { lbajardsilogic@0: setBaseColour(QColor(colourSpec)); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: EnergyScale scale = (EnergyScale) lbajardsilogic@0: attributes.value("energyScale").toInt(&ok); lbajardsilogic@0: if (ok) setEnergyScale(scale); lbajardsilogic@0: lbajardsilogic@0: SamplingMode mode = (SamplingMode) lbajardsilogic@0: attributes.value("samplingMode").toInt(&ok); lbajardsilogic@0: if (ok) setSamplingMode(mode); lbajardsilogic@0: lbajardsilogic@0: int colourMap = attributes.value("colourScheme").toInt(&ok); lbajardsilogic@0: if (ok) setFillColourMap(colourMap); lbajardsilogic@0: lbajardsilogic@0: float gain = attributes.value("gain").toFloat(&ok); lbajardsilogic@0: if (ok) setGain(gain); lbajardsilogic@0: lbajardsilogic@0: bool normalize = (attributes.value("normalize").trimmed() == "true"); lbajardsilogic@0: setNormalize(normalize); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: bool lbajardsilogic@0: SliceLayer::getValueExtents(float &, float &, bool &, QString &) const lbajardsilogic@0: { lbajardsilogic@0: return false; lbajardsilogic@0: } lbajardsilogic@0: