diff layer/Colour3DPlotLayer.cpp @ 0:2a4f26e85b4c

initial import
author Chris Cannam
date Tue, 10 Jan 2006 16:33:16 +0000
parents
children 37b110168acf
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/layer/Colour3DPlotLayer.cpp	Tue Jan 10 16:33:16 2006 +0000
@@ -0,0 +1,268 @@
+/* -*- c-basic-offset: 4 -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    A waveform viewer and audio annotation editor.
+    Chris Cannam, Queen Mary University of London, 2005
+    
+    This is experimental software.  Not for distribution.
+*/
+
+#include "Colour3DPlotLayer.h"
+
+#include "base/View.h"
+#include "base/Profiler.h"
+
+#include <QPainter>
+#include <QImage>
+#include <QRect>
+
+#include <iostream>
+
+#include <cassert>
+
+
+Colour3DPlotLayer::Colour3DPlotLayer(View *w) :
+    Layer(w),
+    m_model(0),
+    m_cache(0)
+{
+    m_view->addLayer(this);
+}
+
+Colour3DPlotLayer::~Colour3DPlotLayer()
+{
+}
+
+void
+Colour3DPlotLayer::setModel(const DenseThreeDimensionalModel *model)
+{
+    m_model = model;
+    if (!m_model || !m_model->isOK()) return;
+
+    connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged()));
+    connect(m_model, SIGNAL(modelChanged(size_t, size_t)),
+	    this, SIGNAL(modelChanged(size_t, size_t)));
+
+    connect(m_model, SIGNAL(completionChanged()),
+	    this, SIGNAL(modelCompletionChanged()));
+
+    connect(m_model, SIGNAL(modelChanged()), this, SLOT(cacheInvalid()));
+    connect(m_model, SIGNAL(modelChanged(size_t, size_t)),
+	    this, SLOT(cacheInvalid(size_t, size_t)));
+
+    emit modelReplaced();
+}
+
+void
+Colour3DPlotLayer::cacheInvalid()
+{
+    delete m_cache; 
+    m_cache = 0;
+}
+
+void
+Colour3DPlotLayer::cacheInvalid(size_t, size_t)
+{
+    cacheInvalid();
+}
+
+void
+Colour3DPlotLayer::paint(QPainter &paint, QRect rect) const
+{
+//    Profiler profiler("Colour3DPlotLayer::paint");
+//    std::cerr << "Colour3DPlotLayer::paint(): m_model is " << m_model << ", zoom level is " << m_view->getZoomLevel() << std::endl;
+
+    //!!! This doesn't yet accommodate the fact that the model may
+    //have a different sample rate from an underlying model.  At the
+    //moment our paint mechanism assumes all models have the same
+    //sample rate.  If that isn't the case, they won't align and the
+    //time ruler will match whichever model was used to construct it.
+    //Obviously it is not going to be the case in general that models
+    //will have the same samplerate, so we need a pane samplerate as
+    //well which we trivially realign to.  (We can probably require
+    //the waveform and spectrogram layers to display at the pane
+    //samplerate.)
+
+    int completion = 0;
+    if (!m_model || !m_model->isOK() || !m_model->isReady(&completion)) {
+	if (completion > 0) {
+	    paint.fillRect(0, 10, m_view->width() * completion / 100,
+			   10, QColor(120, 120, 120));
+	}
+	return;
+    }
+
+    long startFrame = m_view->getStartFrame();
+    int zoomLevel = m_view->getZoomLevel();
+
+    size_t modelStart = m_model->getStartFrame();
+    size_t modelEnd = m_model->getEndFrame();
+    size_t modelWindow = m_model->getWindowSize();
+
+    if (!m_cache) {
+
+	m_cache = new QImage((modelEnd - modelStart) / modelWindow + 1,
+			     m_model->getYBinCount(),
+			     QImage::Format_Indexed8);
+
+	m_cache->setNumColors(256);
+	DenseThreeDimensionalModel::BinValueSet values;
+/*
+	for (int pixel = 0; pixel < 256; ++pixel) {
+	    int hue = 256 - pixel;
+//	    int hue = 220 - pixel;
+//	    if (hue < 0) hue += 360;
+	    QColor color = QColor::fromHsv(hue, pixel/2 + 128, pixel);
+	    m_cache->setColor(pixel, qRgb(color.red(), color.green(), color.blue()));
+	}
+*/
+
+	float min = m_model->getMinimumLevel();
+	float max = m_model->getMaximumLevel();
+
+	if (max == min) max = min + 1.0;
+
+//	int min = lrintf(m_model->getMinimumLevel());
+//	int max = lrintf(m_model->getMaximumLevel());
+	for (int value = 0; value < 256; ++value) {
+//	    int spread = ((value - min) * 256) / (max - min);
+//	    int hue = 256 - spread;
+//	    QColor color = QColor::fromHsv(hue, spread/2 + 128, spread);
+	    int hue = 256 - value;
+	    QColor color = QColor::fromHsv(hue, value/2 + 128, value);
+	    m_cache->setColor(value, qRgba(color.red(), color.green(), color.blue(), 80));
+//	    std::cerr << "Colour3DPlotLayer: Index " << value << ": hue " << hue << std::endl;
+	}
+
+	m_cache->fill(min);
+
+	for (size_t f = modelStart; f <= modelEnd; f += modelWindow) {
+	
+	    values.clear();
+	    m_model->getBinValues(f, values);
+	    
+	    for (size_t y = 0; y < m_model->getYBinCount(); ++y) {
+
+		float value = min;
+		if (y < values.size()) value = values[y];
+
+		//!!! divide-by-zero!
+		int pixel = int(((value - min) * 256) / (max - min));
+
+		m_cache->setPixel(f / modelWindow, y, pixel);
+	    }
+	}
+    }
+
+    int x0 = rect.left();
+    int x1 = rect.right() + 1;
+
+//    int y0 = rect.top();
+//    int y1 = rect.bottom();
+    int w = x1 - x0;
+    int h = m_view->height();
+
+    // The cache is from the model's start frame to the model's end
+    // frame at the model's window increment frames per pixel.  We
+    // want to draw from our start frame + x0 * zoomLevel to our start
+    // frame + x1 * zoomLevel at zoomLevel frames per pixel.
+
+    //!!! Strictly speaking we want quite different paint mechanisms
+    //for models that have more than one bin per pixel in either
+    //direction.  This one is only really appropriate for models with
+    //far fewer bins in both directions.
+
+    int sx0 = ((startFrame + x0 * zoomLevel) - int(modelStart)) /
+	int(modelWindow);
+    int sx1 = ((startFrame + x1 * zoomLevel) - int(modelStart)) / 
+	int(modelWindow);
+    int sw = sx1 - sx0;
+    int sh = m_model->getYBinCount();
+
+/*
+    std::cerr << "Colour3DPlotLayer::paint: w " << w << ", h " << h << ", sx0 " << sx0 << ", sx1 " << sx1 << ", sw " << sw << ", sh " << sh << std::endl;
+    std::cerr << "Colour3DPlotLayer: sample rate is " << m_model->getSampleRate() << ", window size " << m_model->getWindowSize() << std::endl;
+*/
+
+    for (int sx = sx0 - 1; sx <= sx1; ++sx) {
+
+	int fx = sx * int(modelWindow);
+
+	if (fx + modelWindow < int(modelStart) ||
+	    fx > int(modelEnd)) continue;
+
+	for (int sy = 0; sy < sh; ++sy) {
+
+	    int rx0 = ((fx + int(modelStart))
+		       - int(startFrame)) / zoomLevel;
+	    int rx1 = ((fx + int(modelWindow) + int(modelStart))
+		       - int(startFrame)) / zoomLevel;
+
+	    int ry0 = h - (sy * h) / sh - 1;
+	    int ry1 = h - ((sy + 1) * h) / sh - 2;
+	    QRgb pixel = qRgb(255, 255, 255);
+	    if (sx >= 0 && sx < m_cache->width() &&
+		sy >= 0 && sy < m_cache->height()) {
+		pixel = m_cache->pixel(sx, sy);
+	    }
+
+	    QColor pen(255, 255, 255, 80);
+//	    QColor pen(pixel);
+	    QColor brush(pixel);
+	    brush.setAlpha(160);
+//	    paint.setPen(pen);
+	    paint.setPen(Qt::NoPen);
+	    paint.setBrush(brush);
+
+	    int w = rx1 - rx0;
+	    if (w < 1) w = 1;
+	    paint.drawRect(rx0, ry0 - h / sh - 1, w, h / sh + 1);
+
+	    if (sx >= 0 && sx < m_cache->width() &&
+		sy >= 0 && sy < m_cache->height()) {
+		int dv = m_cache->pixelIndex(sx, sy);
+		if (dv != 0 && paint.fontMetrics().height() < (h / sh)) {
+		    QString text = QString("%1").arg(dv);
+		    if (paint.fontMetrics().width(text) < w - 3) {
+			paint.setPen(Qt::white);
+			paint.drawText(rx0 + 2,
+				       ry0 - h / sh - 1 + 2 + paint.fontMetrics().ascent(),
+				       QString("%1").arg(dv));
+		    }
+		}
+	    }
+	}
+    }
+    
+/*
+    QRect targetRect(x0, 0, w, h);
+    QRect sourceRect(sx0, 0, sw, sh);
+
+    QImage scaled(w, h, QImage::Format_RGB32);
+
+    for (int x = 0; x < w; ++x) {
+	for (int y = 0; y < h; ++y) {
+
+	    
+
+	    int sx = sx0 + (x * sw) / w;
+	    int sy = sh - (y * sh) / h - 1;
+//	    std::cerr << "Colour3DPlotLayer::paint: sx " << sx << ", sy " << sy << ", cache w " << m_cache->width() << ", cache h " << m_cache->height() << std::endl;
+	    if (sx >= 0 && sy >= 0 &&
+		sx < m_cache->width() && sy < m_cache->height()) {
+		scaled.setPixel(x, y, m_cache->pixel(sx, sy));
+	    } else {
+		scaled.setPixel(x, y, qRgba(255, 255, 255, 80));
+	    }
+	}
+    }
+
+    paint.drawImage(x0, 0, scaled);
+*/
+}
+
+#ifdef INCLUDE_MOCFILES
+#include "Colour3DPlotLayer.moc.cpp"
+#endif
+
+