Mercurial > hg > svgui
comparison layer/Colour3DPlotLayer.cpp @ 0:2a4f26e85b4c
initial import
author | Chris Cannam |
---|---|
date | Tue, 10 Jan 2006 16:33:16 +0000 |
parents | |
children | 37b110168acf |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:2a4f26e85b4c |
---|---|
1 /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */ | |
2 | |
3 /* | |
4 A waveform viewer and audio annotation editor. | |
5 Chris Cannam, Queen Mary University of London, 2005 | |
6 | |
7 This is experimental software. Not for distribution. | |
8 */ | |
9 | |
10 #include "Colour3DPlotLayer.h" | |
11 | |
12 #include "base/View.h" | |
13 #include "base/Profiler.h" | |
14 | |
15 #include <QPainter> | |
16 #include <QImage> | |
17 #include <QRect> | |
18 | |
19 #include <iostream> | |
20 | |
21 #include <cassert> | |
22 | |
23 | |
24 Colour3DPlotLayer::Colour3DPlotLayer(View *w) : | |
25 Layer(w), | |
26 m_model(0), | |
27 m_cache(0) | |
28 { | |
29 m_view->addLayer(this); | |
30 } | |
31 | |
32 Colour3DPlotLayer::~Colour3DPlotLayer() | |
33 { | |
34 } | |
35 | |
36 void | |
37 Colour3DPlotLayer::setModel(const DenseThreeDimensionalModel *model) | |
38 { | |
39 m_model = model; | |
40 if (!m_model || !m_model->isOK()) return; | |
41 | |
42 connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged())); | |
43 connect(m_model, SIGNAL(modelChanged(size_t, size_t)), | |
44 this, SIGNAL(modelChanged(size_t, size_t))); | |
45 | |
46 connect(m_model, SIGNAL(completionChanged()), | |
47 this, SIGNAL(modelCompletionChanged())); | |
48 | |
49 connect(m_model, SIGNAL(modelChanged()), this, SLOT(cacheInvalid())); | |
50 connect(m_model, SIGNAL(modelChanged(size_t, size_t)), | |
51 this, SLOT(cacheInvalid(size_t, size_t))); | |
52 | |
53 emit modelReplaced(); | |
54 } | |
55 | |
56 void | |
57 Colour3DPlotLayer::cacheInvalid() | |
58 { | |
59 delete m_cache; | |
60 m_cache = 0; | |
61 } | |
62 | |
63 void | |
64 Colour3DPlotLayer::cacheInvalid(size_t, size_t) | |
65 { | |
66 cacheInvalid(); | |
67 } | |
68 | |
69 void | |
70 Colour3DPlotLayer::paint(QPainter &paint, QRect rect) const | |
71 { | |
72 // Profiler profiler("Colour3DPlotLayer::paint"); | |
73 // std::cerr << "Colour3DPlotLayer::paint(): m_model is " << m_model << ", zoom level is " << m_view->getZoomLevel() << std::endl; | |
74 | |
75 //!!! This doesn't yet accommodate the fact that the model may | |
76 //have a different sample rate from an underlying model. At the | |
77 //moment our paint mechanism assumes all models have the same | |
78 //sample rate. If that isn't the case, they won't align and the | |
79 //time ruler will match whichever model was used to construct it. | |
80 //Obviously it is not going to be the case in general that models | |
81 //will have the same samplerate, so we need a pane samplerate as | |
82 //well which we trivially realign to. (We can probably require | |
83 //the waveform and spectrogram layers to display at the pane | |
84 //samplerate.) | |
85 | |
86 int completion = 0; | |
87 if (!m_model || !m_model->isOK() || !m_model->isReady(&completion)) { | |
88 if (completion > 0) { | |
89 paint.fillRect(0, 10, m_view->width() * completion / 100, | |
90 10, QColor(120, 120, 120)); | |
91 } | |
92 return; | |
93 } | |
94 | |
95 long startFrame = m_view->getStartFrame(); | |
96 int zoomLevel = m_view->getZoomLevel(); | |
97 | |
98 size_t modelStart = m_model->getStartFrame(); | |
99 size_t modelEnd = m_model->getEndFrame(); | |
100 size_t modelWindow = m_model->getWindowSize(); | |
101 | |
102 if (!m_cache) { | |
103 | |
104 m_cache = new QImage((modelEnd - modelStart) / modelWindow + 1, | |
105 m_model->getYBinCount(), | |
106 QImage::Format_Indexed8); | |
107 | |
108 m_cache->setNumColors(256); | |
109 DenseThreeDimensionalModel::BinValueSet values; | |
110 /* | |
111 for (int pixel = 0; pixel < 256; ++pixel) { | |
112 int hue = 256 - pixel; | |
113 // int hue = 220 - pixel; | |
114 // if (hue < 0) hue += 360; | |
115 QColor color = QColor::fromHsv(hue, pixel/2 + 128, pixel); | |
116 m_cache->setColor(pixel, qRgb(color.red(), color.green(), color.blue())); | |
117 } | |
118 */ | |
119 | |
120 float min = m_model->getMinimumLevel(); | |
121 float max = m_model->getMaximumLevel(); | |
122 | |
123 if (max == min) max = min + 1.0; | |
124 | |
125 // int min = lrintf(m_model->getMinimumLevel()); | |
126 // int max = lrintf(m_model->getMaximumLevel()); | |
127 for (int value = 0; value < 256; ++value) { | |
128 // int spread = ((value - min) * 256) / (max - min); | |
129 // int hue = 256 - spread; | |
130 // QColor color = QColor::fromHsv(hue, spread/2 + 128, spread); | |
131 int hue = 256 - value; | |
132 QColor color = QColor::fromHsv(hue, value/2 + 128, value); | |
133 m_cache->setColor(value, qRgba(color.red(), color.green(), color.blue(), 80)); | |
134 // std::cerr << "Colour3DPlotLayer: Index " << value << ": hue " << hue << std::endl; | |
135 } | |
136 | |
137 m_cache->fill(min); | |
138 | |
139 for (size_t f = modelStart; f <= modelEnd; f += modelWindow) { | |
140 | |
141 values.clear(); | |
142 m_model->getBinValues(f, values); | |
143 | |
144 for (size_t y = 0; y < m_model->getYBinCount(); ++y) { | |
145 | |
146 float value = min; | |
147 if (y < values.size()) value = values[y]; | |
148 | |
149 //!!! divide-by-zero! | |
150 int pixel = int(((value - min) * 256) / (max - min)); | |
151 | |
152 m_cache->setPixel(f / modelWindow, y, pixel); | |
153 } | |
154 } | |
155 } | |
156 | |
157 int x0 = rect.left(); | |
158 int x1 = rect.right() + 1; | |
159 | |
160 // int y0 = rect.top(); | |
161 // int y1 = rect.bottom(); | |
162 int w = x1 - x0; | |
163 int h = m_view->height(); | |
164 | |
165 // The cache is from the model's start frame to the model's end | |
166 // frame at the model's window increment frames per pixel. We | |
167 // want to draw from our start frame + x0 * zoomLevel to our start | |
168 // frame + x1 * zoomLevel at zoomLevel frames per pixel. | |
169 | |
170 //!!! Strictly speaking we want quite different paint mechanisms | |
171 //for models that have more than one bin per pixel in either | |
172 //direction. This one is only really appropriate for models with | |
173 //far fewer bins in both directions. | |
174 | |
175 int sx0 = ((startFrame + x0 * zoomLevel) - int(modelStart)) / | |
176 int(modelWindow); | |
177 int sx1 = ((startFrame + x1 * zoomLevel) - int(modelStart)) / | |
178 int(modelWindow); | |
179 int sw = sx1 - sx0; | |
180 int sh = m_model->getYBinCount(); | |
181 | |
182 /* | |
183 std::cerr << "Colour3DPlotLayer::paint: w " << w << ", h " << h << ", sx0 " << sx0 << ", sx1 " << sx1 << ", sw " << sw << ", sh " << sh << std::endl; | |
184 std::cerr << "Colour3DPlotLayer: sample rate is " << m_model->getSampleRate() << ", window size " << m_model->getWindowSize() << std::endl; | |
185 */ | |
186 | |
187 for (int sx = sx0 - 1; sx <= sx1; ++sx) { | |
188 | |
189 int fx = sx * int(modelWindow); | |
190 | |
191 if (fx + modelWindow < int(modelStart) || | |
192 fx > int(modelEnd)) continue; | |
193 | |
194 for (int sy = 0; sy < sh; ++sy) { | |
195 | |
196 int rx0 = ((fx + int(modelStart)) | |
197 - int(startFrame)) / zoomLevel; | |
198 int rx1 = ((fx + int(modelWindow) + int(modelStart)) | |
199 - int(startFrame)) / zoomLevel; | |
200 | |
201 int ry0 = h - (sy * h) / sh - 1; | |
202 int ry1 = h - ((sy + 1) * h) / sh - 2; | |
203 QRgb pixel = qRgb(255, 255, 255); | |
204 if (sx >= 0 && sx < m_cache->width() && | |
205 sy >= 0 && sy < m_cache->height()) { | |
206 pixel = m_cache->pixel(sx, sy); | |
207 } | |
208 | |
209 QColor pen(255, 255, 255, 80); | |
210 // QColor pen(pixel); | |
211 QColor brush(pixel); | |
212 brush.setAlpha(160); | |
213 // paint.setPen(pen); | |
214 paint.setPen(Qt::NoPen); | |
215 paint.setBrush(brush); | |
216 | |
217 int w = rx1 - rx0; | |
218 if (w < 1) w = 1; | |
219 paint.drawRect(rx0, ry0 - h / sh - 1, w, h / sh + 1); | |
220 | |
221 if (sx >= 0 && sx < m_cache->width() && | |
222 sy >= 0 && sy < m_cache->height()) { | |
223 int dv = m_cache->pixelIndex(sx, sy); | |
224 if (dv != 0 && paint.fontMetrics().height() < (h / sh)) { | |
225 QString text = QString("%1").arg(dv); | |
226 if (paint.fontMetrics().width(text) < w - 3) { | |
227 paint.setPen(Qt::white); | |
228 paint.drawText(rx0 + 2, | |
229 ry0 - h / sh - 1 + 2 + paint.fontMetrics().ascent(), | |
230 QString("%1").arg(dv)); | |
231 } | |
232 } | |
233 } | |
234 } | |
235 } | |
236 | |
237 /* | |
238 QRect targetRect(x0, 0, w, h); | |
239 QRect sourceRect(sx0, 0, sw, sh); | |
240 | |
241 QImage scaled(w, h, QImage::Format_RGB32); | |
242 | |
243 for (int x = 0; x < w; ++x) { | |
244 for (int y = 0; y < h; ++y) { | |
245 | |
246 | |
247 | |
248 int sx = sx0 + (x * sw) / w; | |
249 int sy = sh - (y * sh) / h - 1; | |
250 // std::cerr << "Colour3DPlotLayer::paint: sx " << sx << ", sy " << sy << ", cache w " << m_cache->width() << ", cache h " << m_cache->height() << std::endl; | |
251 if (sx >= 0 && sy >= 0 && | |
252 sx < m_cache->width() && sy < m_cache->height()) { | |
253 scaled.setPixel(x, y, m_cache->pixel(sx, sy)); | |
254 } else { | |
255 scaled.setPixel(x, y, qRgba(255, 255, 255, 80)); | |
256 } | |
257 } | |
258 } | |
259 | |
260 paint.drawImage(x0, 0, scaled); | |
261 */ | |
262 } | |
263 | |
264 #ifdef INCLUDE_MOCFILES | |
265 #include "Colour3DPlotLayer.moc.cpp" | |
266 #endif | |
267 | |
268 |