# HG changeset patch # User Chris Cannam # Date 1243000485 0 # Node ID 78f9436195b1e2b2d151920acced0c5ddbb8d468 # Parent 7a560380b6e2f48feae1443817dde7bb11a59963 * Add smoothing option to colour 3d plot diff -r 7a560380b6e2 -r 78f9436195b1 layer/Colour3DPlotLayer.cpp --- a/layer/Colour3DPlotLayer.cpp Thu May 21 16:55:57 2009 +0000 +++ b/layer/Colour3DPlotLayer.cpp Fri May 22 13:54:45 2009 +0000 @@ -49,6 +49,7 @@ m_normalizeVisibleArea(false), m_invertVertical(false), m_opaque(false), + m_smooth(false), m_miny(0), m_maxy(0) { @@ -155,6 +156,7 @@ list.push_back("Bin Scale"); list.push_back("Invert Vertical Scale"); list.push_back("Opaque"); + list.push_back("Smooth"); return list; } @@ -168,6 +170,7 @@ if (name == "Invert Vertical Scale") return tr("Invert Vertical Scale"); if (name == "Gain") return tr("Gain"); if (name == "Opaque") return tr("Always Opaque"); + if (name == "Smooth") return tr("Smooth"); if (name == "Bin Scale") return tr("Bin Scale"); return ""; } @@ -179,6 +182,7 @@ if (name == "Normalize Visible Area") return "normalise"; if (name == "Invert Vertical Scale") return "invert-vertical"; if (name == "Opaque") return "opaque"; + if (name == "Smooth") return "smooth"; return ""; } @@ -190,6 +194,7 @@ if (name == "Normalize Visible Area") return ToggleProperty; if (name == "Invert Vertical Scale") return ToggleProperty; if (name == "Opaque") return ToggleProperty; + if (name == "Smooth") return ToggleProperty; return ValueProperty; } @@ -203,6 +208,7 @@ if (name == "Bin Scale" || name == "Invert Vertical Scale") return tr("Bins"); if (name == "Opaque" || + name == "Smooth" || name == "Colour") return tr("Colour"); return QString(); } @@ -274,6 +280,11 @@ *deflt = 0; val = (m_opaque ? 1 : 0); + } else if (name == "Smooth") { + + *deflt = 0; + val = (m_smooth ? 1 : 0); + } else { val = Layer::getPropertyRangeAndValue(name, min, max, deflt); } @@ -339,6 +350,8 @@ setInvertVertical(value ? true : false); } else if (name == "Opaque") { setOpaque(value ? true : false); + } else if (name == "Smooth") { + setSmooth(value ? true : false); } else if (name == "Bin Scale") { switch (value) { default: @@ -444,6 +457,14 @@ emit layerParametersChanged(); } +void +Colour3DPlotLayer::setSmooth(bool n) +{ + if (m_smooth == n) return; + m_smooth = n; + emit layerParametersChanged(); +} + bool Colour3DPlotLayer::getInvertVertical() const { @@ -456,6 +477,12 @@ return m_opaque; } +bool +Colour3DPlotLayer::getSmooth() const +{ + return m_smooth; +} + void Colour3DPlotLayer::setLayerDormant(const View *v, bool dormant) { @@ -1186,6 +1213,7 @@ #endif if (m_opaque || + m_smooth || int(m_model->getHeight()) >= v->height() || ((modelResolution * srRatio) / v->getZoomLevel()) < 2) { #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT @@ -1342,7 +1370,9 @@ long xf = -1; long nxf = v->getFrameForX(x0); - int sxa[w * 2]; + float epsilon = 0.000001; + + float sxa[w * 2]; for (int x = 0; x < w; ++x) { xf = nxf; @@ -1351,76 +1381,132 @@ float sx0 = (float(xf) / srRatio - modelStart) / modelResolution; float sx1 = (float(nxf) / srRatio - modelStart) / modelResolution; - int sx0i = int(sx0 + 0.001); - int sx1i = int(sx1); - - sxa[x*2] = sx0i; - sxa[x*2 + 1] = sx1i; + sxa[x*2] = sx0; + sxa[x*2 + 1] = sx1; } float logmin = symin+1, logmax = symax+1; LogRange::mapRange(logmin, logmax); - for (int y = 0; y < h; ++y) { + if (m_smooth) { + + for (int y = 0; y < h; ++y) { - float sy0, sy1; + float sy = getBinForY(v, y) - 0.5; + int syi = int(sy + epsilon); + if (syi < 0 || syi >= source->height()) continue; - sy0 = getBinForY(v, y + 1); - sy1 = getBinForY(v, y); -/* - if (m_binScale == LinearBinScale) { - sy0 = symin + (float(h - y - 1) * (symax - symin)) / h; - sy1 = symin + (float(h - y) * (symax - symin)) / h; - } else { -// float logmin = LogRange::map(symin); -// float logmax = LogRange::map(symax); - sy0 = logmin + (float(h - y - 1) * (logmax - logmin)) / h; - sy1 = logmin + (float(h - y) * (logmax - logmin)) / h; - sy0 = LogRange::unmap(sy0)-1; - sy1 = LogRange::unmap(sy1)-1; -// sy0 = pow10f(sy0); -// sy1 = pow10f(sy1); - } -*/ - int sy0i = int(sy0 + 0.001); - int sy1i = int(sy1); + uchar *targetLine = img.scanLine(y); + uchar *sourceLine = source->scanLine(syi); + uchar *nextSource; + if (syi + 1 < source->height()) { + nextSource = source->scanLine(syi + 1); + } else { + nextSource = sourceLine; + } - uchar *targetLine = img.scanLine(y); - - if (sy0i == sy1i && sy0i == psy1i) { // same scan line as just computed - goto copy; - } - - for (int x = 0; x < w; ++x) { - peaks[x] = 0; - } - - for (int sy = sy0i; sy <= sy1i; ++sy) { - - if (sy < 0 || sy >= source->height()) continue; - - uchar *sourceLine = source->scanLine(sy); - for (int x = 0; x < w; ++x) { - int sx1i = sxa[x*2 + 1]; - if (sx1i < 0) continue; + targetLine[x] = 0; - int sx0i = sxa[x*2]; + float sx0 = sxa[x*2]; + int sx0i = int(sx0 + epsilon); if (sx0i >= sw) break; + if (sx0i < 0) continue; - uchar peak = 0; - for (int sx = sx0i; sx <= sx1i; ++sx) { - if (sx < 0 || sx >= sw) continue; - if (sourceLine[sx] > peak) peak = sourceLine[sx]; + float a, b, value; + + float sx1 = sxa[x*2+1]; + if (sx1 > sx0 + 1.f) { + int sx1i = int(sx1); + bool have = false; + for (int sx = sx0i; sx <= sx1i; ++sx) { + if (sx < 0 || sx >= sw) continue; + if (!have) { + a = float(sourceLine[sx]); + b = float(nextSource[sx]); + have = true; + } else { + a = std::max(a, float(sourceLine[sx])); + b = std::max(b, float(nextSource[sx])); + } + } + float yprop = sy - syi; + value = (a * (1.f - yprop) + b * yprop); + } else { + a = float(sourceLine[sx0i]); + b = float(nextSource[sx0i]); + float yprop = sy - syi; + value = (a * (1.f - yprop) + b * yprop); + int oi = sx0i + 1; + float xprop = sx0 - sx0i; + xprop -= 0.5; + if (xprop < 0) { + oi = sx0i - 1; + xprop = -xprop; + } + if (oi < 0 || oi >= sw) oi = sx0i; + a = float(sourceLine[oi]); + b = float(nextSource[oi]); + value = (value * (1.f - xprop) + + (a * (1.f - yprop) + b * yprop) * xprop); } - peaks[x] = peak; + + int vi = lrintf(value); + if (vi > 255) vi = 255; + if (vi < 0) vi = 0; + targetLine[x] = uchar(vi); } } + } else { + + for (int y = 0; y < h; ++y) { + + float sy0, sy1; + + sy0 = getBinForY(v, y + 1); + sy1 = getBinForY(v, y); + + int sy0i = int(sy0 + epsilon); + int sy1i = int(sy1); + + uchar *targetLine = img.scanLine(y); + + if (sy0i == sy1i && sy0i == psy1i) { // same source scan line as just computed + goto copy; + } + + for (int x = 0; x < w; ++x) { + peaks[x] = 0; + } - copy: - for (int x = 0; x < w; ++x) { - targetLine[x] = peaks[x]; + for (int sy = sy0i; sy <= sy1i; ++sy) { + + if (sy < 0 || sy >= source->height()) continue; + + uchar *sourceLine = source->scanLine(sy); + + for (int x = 0; x < w; ++x) { + + int sx1i = int(sxa[x*2 + 1]); + if (sx1i < 0) continue; + + int sx0i = int(sxa[x*2] + epsilon); + if (sx0i >= sw) break; + + uchar peak = 0; + for (int sx = sx0i; sx <= sx1i; ++sx) { + if (sx < 0 || sx >= sw) continue; + if (sourceLine[sx] > peak) peak = sourceLine[sx]; + } + peaks[x] = peak; + } + } + + copy: + for (int x = 0; x < w; ++x) { + targetLine[x] = peaks[x]; + } } } @@ -1429,68 +1515,6 @@ paint.drawImage(x0, 0, img); } -void -Colour3DPlotLayer::paintSmooth(View *v, QPainter &paint, QRect rect) const -{ - Profiler profiler("Colour3DPlotLayer:paintSmooth"); - if (!m_cache) return; - - float modelStart = m_model->getStartFrame(); - float modelResolution = m_model->getResolution(); - - int mmsr = v->getViewManager()->getMainModelSampleRate(); - int msr = m_model->getSampleRate(); - float srRatio = float(mmsr) / float(msr); - - int x0 = rect.left(); - int x1 = rect.right() + 1; - - int h = v->height(); // we always paint full height - int sh = m_model->getHeight(); - - int symin = m_miny; - int symax = m_maxy; - if (symax <= symin) { - symin = 0; - symax = sh; - } - if (symin < 0) symin = 0; - if (symax > sh) symax = sh; - -// QImage img(w, h, QImage::Format_Indexed8); -// img.setColorTable(m_cache->colorTable()); - - int zoomLevel = v->getZoomLevel(); - - QImage *source = m_cache; - if (m_peaksCache && - ((modelResolution * srRatio * m_peakResolution) / zoomLevel) < 1) { - std::cerr << "using peaks cache" << std::endl; - source = m_peaksCache; - modelResolution *= m_peakResolution; - } else { - std::cerr << "not using peaks cache" << std::endl; - } - - float sx0 = (float(v->getFrameForX(x0)) / srRatio - modelStart) / modelResolution; - float sx1 = (float(v->getFrameForX(x1)) / srRatio - modelStart) / modelResolution; - int sx0i = int(sx0 + 0.001); - int sx1i = int(sx1); - - if (sx0i < 0) sx0i = 0; - if (sx0i > source->width()) sx0i = source->width(); - - int tx0 = v->getXForFrame(((sx0i * modelResolution) + modelStart) * srRatio + 0.001); - int tx1 = v->getXForFrame(((sx1i * modelResolution) + modelStart) * srRatio); - - std::cerr << "x0 " << x0 << ", x1 " << x1 << " -> sx0 " << sx0i << ", sx1 " << sx1i << " -> tx0 " << tx0 << ", tx1 " << tx1 << std::endl; - - QImage img = source->copy(sx0i, 0, sx1i - sx0i, source->height()) - .scaled(QSize(tx1 - tx0, h), - Qt::IgnoreAspectRatio, Qt::SmoothTransformation); - paint.drawImage(x0, 0, img); -} - bool Colour3DPlotLayer::snapToFeatureFrame(View *v, int &frame, size_t &resolution, @@ -1528,8 +1552,7 @@ "minY=\"%5\" " "maxY=\"%6\" " "invertVertical=\"%7\" " - "opaque=\"%8\" " - "binScale=\"%9\"") + "opaque=\"%8\" %9") .arg((int)m_colourScale) .arg(m_colourMap) .arg(m_normalizeColumns ? "true" : "false") @@ -1538,8 +1561,10 @@ .arg(m_maxy) .arg(m_invertVertical ? "true" : "false") .arg(m_opaque ? "true" : "false") - .arg((int)m_binScale); - + .arg(QString("binScale=\"%1\" smooth=\"%2\" ") + .arg((int)m_binScale) + .arg(m_smooth ? "true" : "false")); + Layer::toXml(stream, indent, extraAttributes + " " + s); } @@ -1571,7 +1596,11 @@ bool opaque = (attributes.value("opaque").trimmed() == "true"); - setNormalizeVisibleArea(opaque); + setOpaque(opaque); + + bool smooth = + (attributes.value("smooth").trimmed() == "true"); + setSmooth(smooth); float min = attributes.value("minY").toFloat(&ok); float max = attributes.value("maxY").toFloat(&alsoOk); diff -r 7a560380b6e2 -r 78f9436195b1 layer/Colour3DPlotLayer.h --- a/layer/Colour3DPlotLayer.h Thu May 21 16:55:57 2009 +0000 +++ b/layer/Colour3DPlotLayer.h Fri May 22 13:54:45 2009 +0000 @@ -128,6 +128,9 @@ void setOpaque(bool i); bool getOpaque() const; + void setSmooth(bool i); + bool getSmooth() const; + virtual bool getValueExtents(float &min, float &max, bool &logarithmic, QString &unit) const; @@ -167,6 +170,7 @@ bool m_normalizeVisibleArea; bool m_invertVertical; bool m_opaque; + bool m_smooth; size_t m_peakResolution; int m_miny; @@ -177,7 +181,6 @@ int getColourScaleWidth(QPainter &) const; void fillCache(size_t firstBin, size_t lastBin) const; void paintDense(View *v, QPainter &paint, QRect rect) const; - void paintSmooth(View *v, QPainter &paint, QRect rect) const; float getYForBin(View *, float bin) const; float getBinForY(View *, float y) const;