svgui  1.9
Colour3DPlotLayer.cpp
Go to the documentation of this file.
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4  Sonic Visualiser
5  An audio file viewer and annotation editor.
6  Centre for Digital Music, Queen Mary, University of London.
7  This file copyright 2006 Chris Cannam and QMUL.
8 
9  This program is free software; you can redistribute it and/or
10  modify it under the terms of the GNU General Public License as
11  published by the Free Software Foundation; either version 2 of the
12  License, or (at your option) any later version. See the file
13  COPYING included with this distribution for more information.
14 */
15 
16 #include "Colour3DPlotLayer.h"
17 
18 #include "view/View.h"
19 #include "base/Profiler.h"
20 #include "base/LogRange.h"
21 #include "base/RangeMapper.h"
22 #include "ColourMapper.h"
23 
24 #include <QPainter>
25 #include <QImage>
26 #include <QRect>
27 #include <QTextStream>
28 
29 #include <iostream>
30 
31 #include <cassert>
32 
33 #ifndef __GNUC__
34 #include <alloca.h>
35 #endif
36 
37 //#define DEBUG_COLOUR_3D_PLOT_LAYER_PAINT 1
38 
39 
41  m_model(0),
42  m_cache(0),
43  m_peaksCache(0),
44  m_cacheValidStart(0),
45  m_cacheValidEnd(0),
46  m_colourScale(LinearScale),
47  m_colourScaleSet(false),
48  m_colourMap(0),
49  m_gain(1.0),
50  m_binScale(LinearBinScale),
51  m_normalizeColumns(false),
52  m_normalizeVisibleArea(false),
53  m_normalizeHybrid(false),
54  m_invertVertical(false),
55  m_opaque(false),
56  m_smooth(false),
57  m_peakResolution(256),
58  m_miny(0),
59  m_maxy(0)
60 {
61 
62 }
63 
65 {
66  delete m_cache;
67  delete m_peaksCache;
68 }
69 
70 void
71 Colour3DPlotLayer::setModel(const DenseThreeDimensionalModel *model)
72 {
73  if (m_model == model) return;
74  const DenseThreeDimensionalModel *oldModel = m_model;
75  m_model = model;
76  if (!m_model || !m_model->isOK()) return;
77 
79 
80  connect(m_model, SIGNAL(modelChanged()), this, SLOT(modelChanged()));
81  connect(m_model, SIGNAL(modelChangedWithin(int, int)),
82  this, SLOT(modelChangedWithin(int, int)));
83 
84  m_peakResolution = 256;
85  if (model->getResolution() > 512) {
86  m_peakResolution = 16;
87  } else if (model->getResolution() > 128) {
88  m_peakResolution = 64;
89  } else if (model->getResolution() > 2) {
90  m_peakResolution = 128;
91  }
92  cacheInvalid();
93 
94  emit modelReplaced();
95  emit sliceableModelReplaced(oldModel, model);
96 }
97 
98 void
100 {
101  delete m_cache;
102  delete m_peaksCache;
103  m_cache = 0;
104  m_peaksCache = 0;
105  m_cacheValidStart = 0;
106  m_cacheValidEnd = 0;
107 }
108 
109 void
110 Colour3DPlotLayer::cacheInvalid(int startFrame, int endFrame)
111 {
112  if (!m_cache || !m_model) return;
113 
114  int modelResolution = m_model->getResolution();
115  int start = startFrame / modelResolution;
116  int end = endFrame / modelResolution + 1;
117  if (m_cacheValidStart < end) m_cacheValidStart = end;
118  if (m_cacheValidEnd > start) m_cacheValidEnd = start;
120 }
121 
122 void
124 {
126  if (m_model) {
127  if (m_model->shouldUseLogValueScale()) {
129  } else {
130  m_colourScaleSet = true;
131  }
132  }
133  }
134  cacheInvalid();
135 }
136 
137 void
138 Colour3DPlotLayer::modelChangedWithin(int startFrame, int endFrame)
139 {
141  if (m_model && m_model->getWidth() > 50) {
142  if (m_model->shouldUseLogValueScale()) {
144  } else {
145  m_colourScaleSet = true;
146  }
147  }
148  }
149  cacheInvalid(startFrame, endFrame);
150 }
151 
152 Layer::PropertyList
154 {
155  PropertyList list;
156  list.push_back("Colour");
157  list.push_back("Colour Scale");
158  list.push_back("Normalize Columns");
159  list.push_back("Normalize Visible Area");
160  list.push_back("Gain");
161  list.push_back("Bin Scale");
162  list.push_back("Invert Vertical Scale");
163  list.push_back("Opaque");
164  list.push_back("Smooth");
165  return list;
166 }
167 
168 QString
169 Colour3DPlotLayer::getPropertyLabel(const PropertyName &name) const
170 {
171  if (name == "Colour") return tr("Colour");
172  if (name == "Colour Scale") return tr("Scale");
173  if (name == "Normalize Columns") return tr("Normalize Columns");
174  if (name == "Normalize Visible Area") return tr("Normalize Visible Area");
175  if (name == "Invert Vertical Scale") return tr("Invert Vertical Scale");
176  if (name == "Gain") return tr("Gain");
177  if (name == "Opaque") return tr("Always Opaque");
178  if (name == "Smooth") return tr("Smooth");
179  if (name == "Bin Scale") return tr("Bin Scale");
180  return "";
181 }
182 
183 QString
184 Colour3DPlotLayer::getPropertyIconName(const PropertyName &name) const
185 {
186  if (name == "Normalize Columns") return "normalise-columns";
187  if (name == "Normalize Visible Area") return "normalise";
188  if (name == "Invert Vertical Scale") return "invert-vertical";
189  if (name == "Opaque") return "opaque";
190  if (name == "Smooth") return "smooth";
191  return "";
192 }
193 
194 Layer::PropertyType
195 Colour3DPlotLayer::getPropertyType(const PropertyName &name) const
196 {
197  if (name == "Gain") return RangeProperty;
198  if (name == "Normalize Columns") return ToggleProperty;
199  if (name == "Normalize Visible Area") return ToggleProperty;
200  if (name == "Invert Vertical Scale") return ToggleProperty;
201  if (name == "Opaque") return ToggleProperty;
202  if (name == "Smooth") return ToggleProperty;
203  return ValueProperty;
204 }
205 
206 QString
207 Colour3DPlotLayer::getPropertyGroupName(const PropertyName &name) const
208 {
209  if (name == "Normalize Columns" ||
210  name == "Normalize Visible Area" ||
211  name == "Colour Scale" ||
212  name == "Gain") return tr("Scale");
213  if (name == "Bin Scale" ||
214  name == "Invert Vertical Scale") return tr("Bins");
215  if (name == "Opaque" ||
216  name == "Smooth" ||
217  name == "Colour") return tr("Colour");
218  return QString();
219 }
220 
221 int
223  int *min, int *max, int *deflt) const
224 {
225  int val = 0;
226 
227  int garbage0, garbage1, garbage2;
228  if (!min) min = &garbage0;
229  if (!max) max = &garbage1;
230  if (!deflt) deflt = &garbage2;
231 
232  if (name == "Gain") {
233 
234  *min = -50;
235  *max = 50;
236 
237  *deflt = lrintf(log10(1.f) * 20.0);;
238  if (*deflt < *min) *deflt = *min;
239  if (*deflt > *max) *deflt = *max;
240 
241  val = lrintf(log10(m_gain) * 20.0);
242  if (val < *min) val = *min;
243  if (val > *max) val = *max;
244 
245  } else if (name == "Colour Scale") {
246 
247  *min = 0;
248  *max = 3;
249  *deflt = (int)LinearScale;
250 
251  val = (int)m_colourScale;
252 
253  } else if (name == "Colour") {
254 
255  *min = 0;
256  *max = ColourMapper::getColourMapCount() - 1;
257  *deflt = 0;
258 
259  val = m_colourMap;
260 
261  } else if (name == "Normalize Columns") {
262 
263  *deflt = 0;
264  val = (m_normalizeColumns ? 1 : 0);
265 
266  } else if (name == "Normalize Visible Area") {
267 
268  *deflt = 0;
269  val = (m_normalizeVisibleArea ? 1 : 0);
270 
271  } else if (name == "Invert Vertical Scale") {
272 
273  *deflt = 0;
274  val = (m_invertVertical ? 1 : 0);
275 
276  } else if (name == "Bin Scale") {
277 
278  *min = 0;
279  *max = 1;
280  *deflt = int(LinearBinScale);
281  val = (int)m_binScale;
282 
283  } else if (name == "Opaque") {
284 
285  *deflt = 0;
286  val = (m_opaque ? 1 : 0);
287 
288  } else if (name == "Smooth") {
289 
290  *deflt = 0;
291  val = (m_smooth ? 1 : 0);
292 
293  } else {
294  val = Layer::getPropertyRangeAndValue(name, min, max, deflt);
295  }
296 
297  return val;
298 }
299 
300 QString
302  int value) const
303 {
304  if (name == "Colour") {
305  return ColourMapper::getColourMapName(value);
306  }
307  if (name == "Colour Scale") {
308  switch (value) {
309  default:
310  case 0: return tr("Linear");
311  case 1: return tr("Log");
312  case 2: return tr("+/-1");
313  case 3: return tr("Absolute");
314  }
315  }
316  if (name == "Bin Scale") {
317  switch (value) {
318  default:
319  case 0: return tr("Linear");
320  case 1: return tr("Log");
321  }
322  }
323  return tr("<unknown>");
324 }
325 
326 RangeMapper *
327 Colour3DPlotLayer::getNewPropertyRangeMapper(const PropertyName &name) const
328 {
329  if (name == "Gain") {
330  return new LinearRangeMapper(-50, 50, -25, 25, tr("dB"));
331  }
332  return 0;
333 }
334 
335 void
336 Colour3DPlotLayer::setProperty(const PropertyName &name, int value)
337 {
338  if (name == "Gain") {
339  setGain(pow(10, float(value)/20.0));
340  } else if (name == "Colour Scale") {
341  switch (value) {
342  default:
343  case 0: setColourScale(LinearScale); break;
344  case 1: setColourScale(LogScale); break;
345  case 2: setColourScale(PlusMinusOneScale); break;
346  case 3: setColourScale(AbsoluteScale); break;
347  }
348  } else if (name == "Colour") {
349  setColourMap(value);
350  } else if (name == "Normalize Columns") {
351  setNormalizeColumns(value ? true : false);
352  } else if (name == "Normalize Visible Area") {
353  setNormalizeVisibleArea(value ? true : false);
354  } else if (name == "Invert Vertical Scale") {
355  setInvertVertical(value ? true : false);
356  } else if (name == "Opaque") {
357  setOpaque(value ? true : false);
358  } else if (name == "Smooth") {
359  setSmooth(value ? true : false);
360  } else if (name == "Bin Scale") {
361  switch (value) {
362  default:
363  case 0: setBinScale(LinearBinScale); break;
364  case 1: setBinScale(LogBinScale); break;
365  }
366  }
367 }
368 
369 void
371 {
372  if (m_colourScale == scale) return;
373  m_colourScale = scale;
374  m_colourScaleSet = true;
375  cacheInvalid();
376  emit layerParametersChanged();
377 }
378 
379 void
381 {
382  if (m_colourMap == map) return;
383  m_colourMap = map;
384  cacheInvalid();
385  emit layerParametersChanged();
386 }
387 
388 void
390 {
391  if (m_gain == gain) return;
392  m_gain = gain;
393  cacheInvalid();
394  emit layerParametersChanged();
395 }
396 
397 float
399 {
400  return m_gain;
401 }
402 
403 void
405 {
406  if (m_binScale == binScale) return;
407  m_binScale = binScale;
408  cacheInvalid();
409  emit layerParametersChanged();
410 }
411 
414 {
415  return m_binScale;
416 }
417 
418 void
420 {
421  if (m_normalizeColumns == n) return;
422  m_normalizeColumns = n;
423  cacheInvalid();
424  emit layerParametersChanged();
425 }
426 
427 bool
429 {
430  return m_normalizeColumns;
431 }
432 
433 void
435 {
436  if (m_normalizeHybrid == n) return;
437  m_normalizeHybrid = n;
438  cacheInvalid();
439  emit layerParametersChanged();
440 }
441 
442 bool
444 {
445  return m_normalizeHybrid;
446 }
447 
448 void
450 {
451  if (m_normalizeVisibleArea == n) return;
453  cacheInvalid();
454  emit layerParametersChanged();
455 }
456 
457 bool
459 {
460  return m_normalizeVisibleArea;
461 }
462 
463 void
465 {
466  if (m_invertVertical == n) return;
467  m_invertVertical = n;
468  cacheInvalid();
469  emit layerParametersChanged();
470 }
471 
472 void
474 {
475  if (m_opaque == n) return;
476  m_opaque = n;
477  emit layerParametersChanged();
478 }
479 
480 void
482 {
483  if (m_smooth == n) return;
484  m_smooth = n;
485  emit layerParametersChanged();
486 }
487 
488 bool
490 {
491  return m_invertVertical;
492 }
493 
494 bool
496 {
497  return m_opaque;
498 }
499 
500 bool
502 {
503  return m_smooth;
504 }
505 
506 void
508 {
509  if (dormant) {
510 
511 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
512  cerr << "Colour3DPlotLayer::setLayerDormant(" << dormant << ")"
513  << endl;
514 #endif
515 
516  if (isLayerDormant(v)) {
517  return;
518  }
519 
520  Layer::setLayerDormant(v, true);
521 
522  cacheInvalid();
523 
524  } else {
525 
526  Layer::setLayerDormant(v, false);
527  }
528 }
529 
530 bool
532 {
534  return false;
535  }
536  if (shouldPaintDenseIn(v)) {
537  return true;
538  }
539  QPoint discard;
540  return !v->shouldIlluminateLocalFeatures(this, discard);
541 }
542 
543 bool
544 Colour3DPlotLayer::getValueExtents(float &min, float &max,
545  bool &logarithmic, QString &unit) const
546 {
547  if (!m_model) return false;
548 
549  min = 0;
550  max = m_model->getHeight();
551 
552  logarithmic = false;
553  unit = "";
554 
555  return true;
556 }
557 
558 bool
559 Colour3DPlotLayer::getDisplayExtents(float &min, float &max) const
560 {
561  if (!m_model) return false;
562 
563  min = m_miny;
564  max = m_maxy;
565  if (max <= min) {
566  min = 0;
567  max = m_model->getHeight();
568  }
569  if (min < 0) min = 0;
570  if (max > m_model->getHeight()) max = m_model->getHeight();
571 
572  return true;
573 }
574 
575 bool
577 {
578  if (!m_model) return false;
579 
580  m_miny = lrintf(min);
581  m_maxy = lrintf(max);
582 
583  emit layerParametersChanged();
584  return true;
585 }
586 
587 bool
589  float &, QString &) const
590 {
591  return false;
592 }
593 
594 int
596 {
597  if (!m_model) return 0;
598 
599  defaultStep = 0;
600  int h = m_model->getHeight();
601  return h;
602 }
603 
604 int
606 {
607  if (!m_model) return 0;
608 
609  float min, max;
610  getDisplayExtents(min, max);
611  return m_model->getHeight() - lrintf(max - min);
612 }
613 
614 void
616 {
617  if (!m_model) return;
618 
619 // SVDEBUG << "Colour3DPlotLayer::setVerticalZoomStep(" <<step <<"): before: miny = " << m_miny << ", maxy = " << m_maxy << endl;
620 
621  int dist = m_model->getHeight() - step;
622  if (dist < 1) dist = 1;
623  float centre = m_miny + (float(m_maxy) - float(m_miny)) / 2.f;
624  m_miny = lrintf(centre - float(dist)/2);
625  if (m_miny < 0) m_miny = 0;
626  m_maxy = m_miny + dist;
627  if (m_maxy > m_model->getHeight()) m_maxy = m_model->getHeight();
628 
629 // SVDEBUG << "Colour3DPlotLayer::setVerticalZoomStep(" <<step <<"): after: miny = " << m_miny << ", maxy = " << m_maxy << endl;
630 
631  emit layerParametersChanged();
632 }
633 
634 RangeMapper *
636 {
637  if (!m_model) return 0;
638 
639  return new LinearRangeMapper(0, m_model->getHeight(),
640  0, m_model->getHeight(), "");
641 }
642 
643 float
645 {
646  float y = bin;
647  if (!m_model) return y;
648  float mn = 0, mx = m_model->getHeight();
649  getDisplayExtents(mn, mx);
650  float h = v->height();
651  if (m_binScale == LinearBinScale) {
652  y = h - (((bin - mn) * h) / (mx - mn));
653  } else {
654  float logmin = mn + 1, logmax = mx + 1;
655  LogRange::mapRange(logmin, logmax);
656  y = h - (((LogRange::map(bin + 1) - logmin) * h) / (logmax - logmin));
657  }
658  return y;
659 }
660 
661 float
663 {
664  float bin = y;
665  if (!m_model) return bin;
666  float mn = 0, mx = m_model->getHeight();
667  getDisplayExtents(mn, mx);
668  float h = v->height();
669  if (m_binScale == LinearBinScale) {
670  bin = mn + ((h - y) * (mx - mn)) / h;
671  } else {
672  float logmin = mn + 1, logmax = mx + 1;
673  LogRange::mapRange(logmin, logmax);
674  bin = LogRange::unmap(logmin + ((h - y) * (logmax - logmin)) / h) - 1;
675  }
676  return bin;
677 }
678 
679 QString
681 {
682  if (!m_model) return "";
683 
684  int x = pos.x();
685  int y = pos.y();
686 
687  int modelStart = m_model->getStartFrame();
688  int modelResolution = m_model->getResolution();
689 
690  float srRatio =
691  float(v->getViewManager()->getMainModelSampleRate()) /
692  float(m_model->getSampleRate());
693 
694  int sx0 = int((v->getFrameForX(x) / srRatio - modelStart) /
695  modelResolution);
696 
697  int f0 = sx0 * modelResolution;
698  int f1 = f0 + modelResolution;
699 
700  int sh = m_model->getHeight();
701 
702  int symin = m_miny;
703  int symax = m_maxy;
704  if (symax <= symin) {
705  symin = 0;
706  symax = sh;
707  }
708  if (symin < 0) symin = 0;
709  if (symax > sh) symax = sh;
710 
711  // float binHeight = float(v->height()) / (symax - symin);
712 // int sy = int((v->height() - y) / binHeight) + symin;
713 
714  int sy = getBinForY(v, y);
715 
716  if (sy < 0 || sy >= m_model->getHeight()) {
717  return "";
718  }
719 
720  if (m_invertVertical) sy = m_model->getHeight() - sy - 1;
721 
722  float value = m_model->getValueAt(sx0, sy);
723 
724 // cerr << "bin value (" << sx0 << "," << sy << ") is " << value << endl;
725 
726  QString binName = m_model->getBinName(sy);
727  if (binName == "") binName = QString("[%1]").arg(sy + 1);
728  else binName = QString("%1 [%2]").arg(binName).arg(sy + 1);
729 
730  QString text = tr("Time:\t%1 - %2\nBin:\t%3\nValue:\t%4")
731  .arg(RealTime::frame2RealTime(f0, m_model->getSampleRate())
732  .toText(true).c_str())
733  .arg(RealTime::frame2RealTime(f1, m_model->getSampleRate())
734  .toText(true).c_str())
735  .arg(binName)
736  .arg(value);
737 
738  return text;
739 }
740 
741 int
743 {
744  int cw = 20;
745  return cw;
746 }
747 
748 int
749 Colour3DPlotLayer::getVerticalScaleWidth(View *, bool, QPainter &paint) const
750 {
751  if (!m_model) return 0;
752 
753  QString sampleText = QString("[%1]").arg(m_model->getHeight());
754  int tw = paint.fontMetrics().width(sampleText);
755  bool another = false;
756 
757  for (int i = 0; i < m_model->getHeight(); ++i) {
758  if (m_model->getBinName(i).length() > sampleText.length()) {
759  sampleText = m_model->getBinName(i);
760  another = true;
761  }
762  }
763  if (another) {
764  tw = std::max(tw, paint.fontMetrics().width(sampleText));
765  }
766 
767  return tw + 13 + getColourScaleWidth(paint);
768 }
769 
770 void
771 Colour3DPlotLayer::paintVerticalScale(View *v, bool, QPainter &paint, QRect rect) const
772 {
773  if (!m_model) return;
774 
775  int h = rect.height(), w = rect.width();
776 
777  int cw = getColourScaleWidth(paint);
778 
779  int ch = h - 20;
780  if (ch > 20 && m_cache) {
781 
782  float min = m_model->getMinimumLevel();
783  float max = m_model->getMaximumLevel();
784 
785  float mmin = min;
786  float mmax = max;
787 
788  if (m_colourScale == LogScale) {
789  LogRange::mapRange(mmin, mmax);
790  } else if (m_colourScale == PlusMinusOneScale) {
791  mmin = -1.f;
792  mmax = 1.f;
793  } else if (m_colourScale == AbsoluteScale) {
794  if (mmin < 0) {
795  if (fabsf(mmin) > fabsf(mmax)) mmax = fabsf(mmin);
796  else mmax = fabsf(mmax);
797  mmin = 0;
798  } else {
799  mmin = fabsf(mmin);
800  mmax = fabsf(mmax);
801  }
802  }
803 
804  if (max == min) max = min + 1.0;
805  if (mmax == mmin) mmax = mmin + 1.0;
806 
807  paint.setPen(v->getForeground());
808  paint.drawRect(4, 10, cw - 8, ch+1);
809 
810  for (int y = 0; y < ch; ++y) {
811  float value = ((max - min) * (ch - y - 1)) / ch + min;
812  if (m_colourScale == LogScale) {
813  value = LogRange::map(value);
814  }
815  int pixel = int(((value - mmin) * 256) / (mmax - mmin));
816  if (pixel >= 0 && pixel < 256) {
817  QRgb c = m_cache->color(pixel);
818  paint.setPen(QColor(qRed(c), qGreen(c), qBlue(c)));
819  paint.drawLine(5, 11 + y, cw - 5, 11 + y);
820  } else {
821  cerr << "WARNING: Colour3DPlotLayer::paintVerticalScale: value " << value << ", mmin " << mmin << ", mmax " << mmax << " leads to invalid pixel " << pixel << endl;
822  }
823  }
824 
825  QString minstr = QString("%1").arg(min);
826  QString maxstr = QString("%1").arg(max);
827 
828  paint.save();
829 
830  QFont font = paint.font();
831  font.setPixelSize(10);
832  paint.setFont(font);
833 
834  int msw = paint.fontMetrics().width(maxstr);
835 
836  QMatrix m;
837  m.translate(cw - 6, ch + 10);
838  m.rotate(-90);
839 
840  paint.setWorldMatrix(m);
841 
842  v->drawVisibleText(paint, 2, 0, minstr, View::OutlinedText);
843 
844  m.translate(ch - msw - 2, 0);
845  paint.setWorldMatrix(m);
846 
847  v->drawVisibleText(paint, 0, 0, maxstr, View::OutlinedText);
848 
849  paint.restore();
850  }
851 
852  paint.setPen(v->getForeground());
853 
854  int sh = m_model->getHeight();
855 
856  int symin = m_miny;
857  int symax = m_maxy;
858  if (symax <= symin) {
859  symin = 0;
860  symax = sh;
861  }
862  if (symin < 0) symin = 0;
863  if (symax > sh) symax = sh;
864 
865  paint.save();
866 
867  int py = h;
868 
869  for (int i = symin; i <= symax; ++i) {
870 
871  int y0;
872 
873  y0 = lrintf(getYForBin(v, i));
874  int h = py - y0;
875 
876  if (i > symin) {
877  if (paint.fontMetrics().height() >= h) {
878  if (h >= 8) {
879  QFont tf = paint.font();
880  tf.setPixelSize(h-2);
881  paint.setFont(tf);
882  } else {
883  continue;
884  }
885  }
886  }
887 
888  py = y0;
889 
890  if (i < symax) {
891  paint.drawLine(cw, y0, w, y0);
892  }
893 
894  if (i > symin) {
895 
896  int idx = i - 1;
897  if (m_invertVertical) idx = m_model->getHeight() - idx - 1;
898 
899  QString text = m_model->getBinName(idx);
900  if (text == "") text = QString("[%1]").arg(idx + 1);
901 
902  int ty = y0 + (h/2) - (paint.fontMetrics().height()/2) +
903  paint.fontMetrics().ascent() + 1;
904 
905  paint.drawText(cw + 5, ty, text);
906  }
907  }
908 
909  paint.restore();
910 }
911 
912 DenseThreeDimensionalModel::Column
914 {
915  Profiler profiler("Colour3DPlotLayer::getColumn");
916 
917  DenseThreeDimensionalModel::Column values = m_model->getColumn(col);
918  while (values.size() < m_model->getHeight()) values.push_back(0.f);
919  if (!m_normalizeColumns && !m_normalizeHybrid) return values;
920 
921  float colMax = 0.f, colMin = 0.f;
922  float min = 0.f, max = 0.f;
923 
924  min = m_model->getMinimumLevel();
925  max = m_model->getMaximumLevel();
926 
927  for (int y = 0; y < values.size(); ++y) {
928  if (y == 0 || values.at(y) > colMax) colMax = values.at(y);
929  if (y == 0 || values.at(y) < colMin) colMin = values.at(y);
930  }
931  if (colMin == colMax) colMax = colMin + 1;
932 
933  for (int y = 0; y < values.size(); ++y) {
934 
935  float value = values.at(y);
936  float norm = (value - colMin) / (colMax - colMin);
937  float newvalue = min + (max - min) * norm;
938 
939  if (value != newvalue) values[y] = newvalue;
940  }
941 
942  if (m_normalizeHybrid && (colMax > 0.0)) {
943  float logmax = log10(colMax);
944  for (int y = 0; y < values.size(); ++y) {
945  values[y] *= logmax;
946  }
947  }
948 
949  return values;
950 }
951 
952 void
953 Colour3DPlotLayer::fillCache(int firstBin, int lastBin) const
954 {
955  Profiler profiler("Colour3DPlotLayer::fillCache", true);
956 
957  int modelStart = m_model->getStartFrame();
958  int modelEnd = m_model->getEndFrame();
959  int modelResolution = m_model->getResolution();
960 
961  int modelStartBin = modelStart / modelResolution;
962  int modelEndBin = modelEnd / modelResolution;
963 
964 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
965  cerr << "Colour3DPlotLayer::fillCache: range " << firstBin << " -> " << lastBin << " of model range " << modelStartBin << " -> " << modelEndBin << " (model resolution " << modelResolution << ")" << endl;
966 #endif
967 
968  int cacheWidth = modelEndBin - modelStartBin + 1;
969  if (lastBin > modelEndBin) cacheWidth = lastBin - modelStartBin + 1;
970  int cacheHeight = m_model->getHeight();
971 
972  if (m_cache && m_cache->height() != cacheHeight) {
973  // height has changed: delete everything rather than resizing
974 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
975  cerr << "Colour3DPlotLayer::fillCache: Cache height has changed, recreating" << endl;
976 #endif
977  delete m_cache;
978  delete m_peaksCache;
979  m_cache = 0;
980  m_peaksCache = 0;
981  }
982 
983  if (m_cache && m_cache->width() != cacheWidth) {
984  // width has changed and we have an existing cache: resize it
985 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
986  cerr << "Colour3DPlotLayer::fillCache: Cache width has changed, resizing existing cache" << endl;
987 #endif
988  QImage *newCache =
989  new QImage(m_cache->copy(0, 0, cacheWidth, cacheHeight));
990  delete m_cache;
991  m_cache = newCache;
992  if (m_peaksCache) {
993  QImage *newPeaksCache =
994  new QImage(m_peaksCache->copy
995  (0, 0, cacheWidth / m_peakResolution + 1, cacheHeight));
996  delete m_peaksCache;
997  m_peaksCache = newPeaksCache;
998  }
999  }
1000 
1001  if (!m_cache) {
1002 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
1003  cerr << "Colour3DPlotLayer::fillCache: Have no cache, making one" << endl;
1004 #endif
1005  m_cache = new QImage
1006  (cacheWidth, cacheHeight, QImage::Format_Indexed8);
1007  m_cache->setColorCount(256);
1008  m_cache->fill(0);
1009  if (!m_normalizeVisibleArea) {
1010  m_peaksCache = new QImage
1011  (cacheWidth / m_peakResolution + 1, cacheHeight,
1012  QImage::Format_Indexed8);
1013  m_peaksCache->setColorCount(256);
1014  m_peaksCache->fill(0);
1015  } else if (m_peaksCache) {
1016  delete m_peaksCache;
1017  m_peaksCache = 0;
1018  }
1019  m_cacheValidStart = 0;
1020  m_cacheValidEnd = 0;
1021  }
1022 
1023 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
1024  cerr << "cache size = " << m_cache->width() << "x" << m_cache->height()
1025  << " peaks cache size = " << m_peaksCache->width() << "x" << m_peaksCache->height() << endl;
1026 #endif
1027 
1028  if (m_cacheValidStart <= firstBin && m_cacheValidEnd >= lastBin) {
1029 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
1030  cerr << "Cache is valid in this region already" << endl;
1031 #endif
1032  return;
1033  }
1034 
1035  int fillStart = firstBin;
1036  int fillEnd = lastBin;
1037 
1038  if (fillStart < modelStartBin) fillStart = modelStartBin;
1039  if (fillStart > modelEndBin) fillStart = modelEndBin;
1040  if (fillEnd < modelStartBin) fillEnd = modelStartBin;
1041  if (fillEnd > modelEndBin) fillEnd = modelEndBin;
1042 
1043  bool normalizeVisible = (m_normalizeVisibleArea && !m_normalizeColumns);
1044 
1045  if (!normalizeVisible && (m_cacheValidStart < m_cacheValidEnd)) {
1046 
1047  if (m_cacheValidEnd < fillStart) {
1048  fillStart = m_cacheValidEnd + 1;
1049  }
1050  if (m_cacheValidStart > fillEnd) {
1051  fillEnd = m_cacheValidStart - 1;
1052  }
1053 
1054  m_cacheValidStart = std::min(fillStart, m_cacheValidStart);
1055  m_cacheValidEnd = std::max(fillEnd, m_cacheValidEnd);
1056 
1057  } else {
1058 
1059  // when normalising the visible area, the only valid area,
1060  // ever, is the currently visible one
1061 
1062  m_cacheValidStart = fillStart;
1063  m_cacheValidEnd = fillEnd;
1064  }
1065 
1066 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
1067  cerr << "Cache size " << cacheWidth << "x" << cacheHeight << " will be valid from " << m_cacheValidStart << " to " << m_cacheValidEnd << " (fillStart = " << fillStart << ", fillEnd = " << fillEnd << ")" << endl;
1068 #endif
1069 
1070  DenseThreeDimensionalModel::Column values;
1071 
1072  float min = m_model->getMinimumLevel();
1073  float max = m_model->getMaximumLevel();
1074 
1075  if (m_colourScale == LogScale) {
1076  LogRange::mapRange(min, max);
1077  } else if (m_colourScale == PlusMinusOneScale) {
1078  min = -1.f;
1079  max = 1.f;
1080  } else if (m_colourScale == AbsoluteScale) {
1081  if (min < 0) {
1082  if (fabsf(min) > fabsf(max)) max = fabsf(min);
1083  else max = fabsf(max);
1084  min = 0;
1085  } else {
1086  min = fabsf(min);
1087  max = fabsf(max);
1088  }
1089  }
1090 
1091  if (max == min) max = min + 1.0;
1092 
1093  ColourMapper mapper(m_colourMap, 0.f, 255.f);
1094 
1095  for (int index = 0; index < 256; ++index) {
1096  QColor colour = mapper.map(index);
1097  m_cache->setColor
1098  (index, qRgb(colour.red(), colour.green(), colour.blue()));
1099  if (m_peaksCache) {
1100  m_peaksCache->setColor
1101  (index, qRgb(colour.red(), colour.green(), colour.blue()));
1102  }
1103  }
1104 
1105  float visibleMax = 0.f, visibleMin = 0.f;
1106 
1107  if (normalizeVisible) {
1108 
1109  for (int c = fillStart; c <= fillEnd; ++c) {
1110 
1111  values = getColumn(c);
1112 
1113  float colMax = 0.f, colMin = 0.f;
1114 
1115  for (int y = 0; y < cacheHeight; ++y) {
1116  if (y >= values.size()) break;
1117  if (y == 0 || values[y] > colMax) colMax = values[y];
1118  if (y == 0 || values[y] < colMin) colMin = values[y];
1119  }
1120 
1121  if (c == fillStart || colMax > visibleMax) visibleMax = colMax;
1122  if (c == fillStart || colMin < visibleMin) visibleMin = colMin;
1123  }
1124 
1125  if (m_colourScale == LogScale) {
1126  visibleMin = LogRange::map(visibleMin);
1127  visibleMax = LogRange::map(visibleMax);
1128  if (visibleMin > visibleMax) std::swap(visibleMin, visibleMax);
1129  } else if (m_colourScale == AbsoluteScale) {
1130  if (visibleMin < 0) {
1131  if (fabsf(visibleMin) > fabsf(visibleMax)) visibleMax = fabsf(visibleMin);
1132  else visibleMax = fabsf(visibleMax);
1133  visibleMin = 0;
1134  } else {
1135  visibleMin = fabsf(visibleMin);
1136  visibleMax = fabsf(visibleMax);
1137  }
1138  }
1139  }
1140 
1141  if (visibleMin == visibleMax) visibleMax = visibleMin + 1;
1142 
1143  int *peaks = 0;
1144  if (m_peaksCache) {
1145  peaks = new int[cacheHeight];
1146  for (int y = 0; y < cacheHeight; ++y) {
1147  peaks[y] = 0;
1148  }
1149  }
1150 
1151  Profiler profiler2("Colour3DPlotLayer::fillCache: filling", true);
1152 
1153  for (int c = fillStart; c <= fillEnd; ++c) {
1154 
1155  values = getColumn(c);
1156 
1157  if (c >= m_cache->width()) {
1158  cerr << "ERROR: column " << c << " >= cache width "
1159  << m_cache->width() << endl;
1160  continue;
1161  }
1162 
1163  for (int y = 0; y < cacheHeight; ++y) {
1164 
1165  float value = min;
1166  if (y < values.size()) {
1167  value = values.at(y);
1168  }
1169 
1170  value = value * m_gain;
1171 
1172  if (m_colourScale == LogScale) {
1173  value = LogRange::map(value);
1174  } else if (m_colourScale == AbsoluteScale) {
1175  value = fabsf(value);
1176  }
1177 
1178  if (normalizeVisible) {
1179  float norm = (value - visibleMin) / (visibleMax - visibleMin);
1180  value = min + (max - min) * norm;
1181  }
1182 
1183  int pixel = int(((value - min) * 256) / (max - min));
1184  if (pixel < 0) pixel = 0;
1185  if (pixel > 255) pixel = 255;
1186  if (peaks && (pixel > peaks[y])) peaks[y] = pixel;
1187 
1188  if (m_invertVertical) {
1189  m_cache->setPixel(c, cacheHeight - y - 1, pixel);
1190  } else {
1191  if (y >= m_cache->height()) {
1192  cerr << "ERROR: row " << y << " >= cache height " << m_cache->height() << endl;
1193  } else {
1194  m_cache->setPixel(c, y, pixel);
1195  }
1196  }
1197  }
1198 
1199  if (peaks) {
1200  int notch = (c % m_peakResolution);
1201  if (notch == m_peakResolution-1 || c == fillEnd) {
1202  int pc = c / m_peakResolution;
1203  if (pc >= m_peaksCache->width()) {
1204  cerr << "ERROR: peak column " << pc
1205  << " (from col " << c << ") >= peaks cache width "
1206  << m_peaksCache->width() << endl;
1207  continue;
1208  }
1209  for (int y = 0; y < cacheHeight; ++y) {
1210  if (m_invertVertical) {
1211  m_peaksCache->setPixel(pc, cacheHeight - y - 1, peaks[y]);
1212  } else {
1213  if (y >= m_peaksCache->height()) {
1214  cerr << "ERROR: row " << y
1215  << " >= peaks cache height "
1216  << m_peaksCache->height() << endl;
1217  } else {
1218  m_peaksCache->setPixel(pc, y, peaks[y]);
1219  }
1220  }
1221  }
1222  for (int y = 0; y < cacheHeight; ++y) {
1223  peaks[y] = 0;
1224  }
1225  }
1226  }
1227  }
1228 
1229  delete[] peaks;
1230 }
1231 
1232 bool
1234 {
1235  if (!m_model || !v || !(v->getViewManager())) {
1236  return false;
1237  }
1238  float srRatio =
1239  float(v->getViewManager()->getMainModelSampleRate()) /
1240  float(m_model->getSampleRate());
1241  if (m_opaque ||
1242  m_smooth ||
1243  m_model->getHeight() >= v->height() ||
1244  ((m_model->getResolution() * srRatio) / v->getZoomLevel()) < 2) {
1245  return true;
1246  }
1247  return false;
1248 }
1249 
1250 void
1251 Colour3DPlotLayer::paint(View *v, QPainter &paint, QRect rect) const
1252 {
1253 /*
1254  if (m_model) {
1255  SVDEBUG << "Colour3DPlotLayer::paint: model says shouldUseLogValueScale = " << m_model->shouldUseLogValueScale() << endl;
1256  }
1257 */
1258  Profiler profiler("Colour3DPlotLayer::paint");
1259 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
1260  cerr << "Colour3DPlotLayer::paint(): m_model is " << m_model << ", zoom level is " << v->getZoomLevel() << ", rect is (" << rect.x() << "," << rect.y() << ") " << rect.width() << "x" << rect.height() << endl;
1261 #endif
1262 
1263  int completion = 0;
1264  if (!m_model || !m_model->isOK() || !m_model->isReady(&completion)) {
1265  if (completion > 0) {
1266  paint.fillRect(0, 10, v->width() * completion / 100,
1267  10, QColor(120, 120, 120));
1268  }
1269  return;
1270  }
1271 
1272  if (m_normalizeVisibleArea && !m_normalizeColumns) rect = v->rect();
1273 
1274  int modelStart = m_model->getStartFrame();
1275  int modelEnd = m_model->getEndFrame();
1276  int modelResolution = m_model->getResolution();
1277 
1278  // The cache is from the model's start frame to the model's end
1279  // frame at the model's window increment frames per pixel. We
1280  // want to draw from our start frame + x0 * zoomLevel to our start
1281  // frame + x1 * zoomLevel at zoomLevel frames per pixel.
1282 
1283  // We have quite different paint mechanisms for rendering "large"
1284  // bins (more than one bin per pixel in both directions) and
1285  // "small". This is "large"; see paintDense below for "small".
1286 
1287  int x0 = rect.left();
1288  int x1 = rect.right() + 1;
1289 
1290  int h = v->height();
1291 
1292  float srRatio =
1293  float(v->getViewManager()->getMainModelSampleRate()) /
1294  float(m_model->getSampleRate());
1295 
1296  int sx0 = int((v->getFrameForX(x0) / srRatio - modelStart)
1297  / modelResolution);
1298  int sx1 = int((v->getFrameForX(x1) / srRatio - modelStart)
1299  / modelResolution);
1300  int sh = m_model->getHeight();
1301 
1302  int symin = m_miny;
1303  int symax = m_maxy;
1304  if (symax <= symin) {
1305  symin = 0;
1306  symax = sh;
1307  }
1308  if (symin < 0) symin = 0;
1309  if (symax > sh) symax = sh;
1310 
1311  if (sx0 > 0) --sx0;
1312  fillCache(sx0 < 0 ? 0 : sx0,
1313  sx1 < 0 ? 0 : sx1);
1314 
1315 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
1316  cerr << "Colour3DPlotLayer::paint: height = "<< m_model->getHeight() << ", modelStart = " << modelStart << ", resolution = " << modelResolution << ", model rate = " << m_model->getSampleRate() << " (zoom level = " << v->getZoomLevel() << ", srRatio = " << srRatio << ")" << endl;
1317 #endif
1318 
1319  if (shouldPaintDenseIn(v)) {
1320 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
1321  cerr << "calling paintDense" << endl;
1322 #endif
1323  paintDense(v, paint, rect);
1324  return;
1325  }
1326 
1327 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
1328  cerr << "Colour3DPlotLayer::paint: w " << x1-x0 << ", h " << h << ", sx0 " << sx0 << ", sx1 " << sx1 << ", sw " << sx1-sx0 << ", sh " << sh << endl;
1329  cerr << "Colour3DPlotLayer: sample rate is " << m_model->getSampleRate() << ", resolution " << m_model->getResolution() << endl;
1330 #endif
1331 
1332  QPoint illuminatePos;
1333  bool illuminate = v->shouldIlluminateLocalFeatures(this, illuminatePos);
1334  char labelbuf[10];
1335 
1336  for (int sx = sx0; sx <= sx1; ++sx) {
1337 
1338  int fx = sx * modelResolution;
1339 
1340  if (fx + modelResolution <= modelStart || fx > modelEnd) continue;
1341 
1342  int rx0 = v->getXForFrame(int((fx + modelStart) * srRatio));
1343  int rx1 = v->getXForFrame(int((fx + modelStart + modelResolution + 1) * srRatio));
1344 
1345  int rw = rx1 - rx0;
1346  if (rw < 1) rw = 1;
1347 
1348  bool showLabel = (rw > 10 &&
1349  paint.fontMetrics().width("0.000000") < rw - 3 &&
1350  paint.fontMetrics().height() < (h / sh));
1351 
1352  for (int sy = symin; sy < symax; ++sy) {
1353 
1354  int ry0 = getYForBin(v, sy);
1355  int ry1 = getYForBin(v, sy + 1);
1356  QRect r(rx0, ry1, rw, ry0 - ry1);
1357 
1358  QRgb pixel = qRgb(255, 255, 255);
1359  if (sx >= 0 && sx < m_cache->width() &&
1360  sy >= 0 && sy < m_cache->height()) {
1361  pixel = m_cache->pixel(sx, sy);
1362  }
1363 
1364  if (rw == 1) {
1365  paint.setPen(pixel);
1366  paint.setBrush(Qt::NoBrush);
1367  paint.drawLine(r.x(), r.y(), r.x(), r.y() + r.height() - 1);
1368  continue;
1369  }
1370 
1371  QColor pen(255, 255, 255, 80);
1372  QColor brush(pixel);
1373 
1374  if (rw > 3 && r.height() > 3) {
1375  brush.setAlpha(160);
1376  }
1377 
1378  paint.setPen(Qt::NoPen);
1379  paint.setBrush(brush);
1380 
1381  if (illuminate) {
1382  if (r.contains(illuminatePos)) {
1383  paint.setPen(v->getForeground());
1384  }
1385  }
1386 
1387 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
1388 // cerr << "rect " << r.x() << "," << r.y() << " "
1389 // << r.width() << "x" << r.height() << endl;
1390 #endif
1391 
1392  paint.drawRect(r);
1393 
1394  if (showLabel) {
1395  if (sx >= 0 && sx < m_cache->width() &&
1396  sy >= 0 && sy < m_cache->height()) {
1397  float value = m_model->getValueAt(sx, sy);
1398  sprintf(labelbuf, "%06f", value);
1399  QString text(labelbuf);
1400  paint.setPen(v->getBackground());
1401  paint.drawText(rx0 + 2,
1402  ry0 - h / sh - 1 + 2 + paint.fontMetrics().ascent(),
1403  text);
1404  }
1405  }
1406  }
1407  }
1408 }
1409 
1410 void
1411 Colour3DPlotLayer::paintDense(View *v, QPainter &paint, QRect rect) const
1412 {
1413  Profiler profiler("Colour3DPlotLayer::paintDense", true);
1414  if (!m_cache) return;
1415 
1416  float modelStart = m_model->getStartFrame();
1417  float modelResolution = m_model->getResolution();
1418 
1419  int mmsr = v->getViewManager()->getMainModelSampleRate();
1420  int msr = m_model->getSampleRate();
1421  float srRatio = float(mmsr) / float(msr);
1422 
1423  int x0 = rect.left();
1424  int x1 = rect.right() + 1;
1425 
1426  const int w = x1 - x0; // const so it can be used as array size below
1427  int h = v->height(); // we always paint full height
1428  int sh = m_model->getHeight();
1429 
1430  int symin = m_miny;
1431  int symax = m_maxy;
1432  if (symax <= symin) {
1433  symin = 0;
1434  symax = sh;
1435  }
1436  if (symin < 0) symin = 0;
1437  if (symax > sh) symax = sh;
1438 
1439  QImage img(w, h, QImage::Format_Indexed8);
1440  img.setColorTable(m_cache->colorTable());
1441 
1442  uchar *peaks = new uchar[w];
1443  memset(peaks, 0, w);
1444 
1445  int zoomLevel = v->getZoomLevel();
1446 
1447  QImage *source = m_cache;
1448 
1449 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
1450  cerr << "modelResolution " << modelResolution << ", srRatio "
1451  << srRatio << ", m_peakResolution " << m_peakResolution
1452  << ", zoomLevel " << zoomLevel << ", result "
1453  << ((modelResolution * srRatio * m_peakResolution) / zoomLevel)
1454  << endl;
1455 #endif
1456 
1457  if (m_peaksCache) {
1458  if (((modelResolution * srRatio * m_peakResolution) / zoomLevel) < 1) {
1459 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
1460  cerr << "using peaks cache" << endl;
1461 #endif
1462  source = m_peaksCache;
1463  modelResolution *= m_peakResolution;
1464  } else {
1465 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
1466  cerr << "not using peaks cache" << endl;
1467 #endif
1468  }
1469  } else {
1470 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
1471  cerr << "have no peaks cache" << endl;
1472 #endif
1473  }
1474 
1475  int sw = source->width();
1476 
1477  int xf = -1;
1478  int nxf = v->getFrameForX(x0);
1479 
1480  float epsilon = 0.000001;
1481 
1482 #ifdef __GNUC__
1483  float sxa[w * 2];
1484 #else
1485  float *sxa = (float *)alloca(w * 2 * sizeof(float));
1486 #endif
1487  for (int x = 0; x < w; ++x) {
1488 
1489  xf = nxf;
1490  nxf = xf + zoomLevel;
1491 
1492  float sx0 = (float(xf) / srRatio - modelStart) / modelResolution;
1493  float sx1 = (float(nxf) / srRatio - modelStart) / modelResolution;
1494 
1495  sxa[x*2] = sx0;
1496  sxa[x*2 + 1] = sx1;
1497  }
1498 
1499  float logmin = symin+1, logmax = symax+1;
1500  LogRange::mapRange(logmin, logmax);
1501 
1502 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT
1503  cerr << "m_smooth = " << m_smooth << ", w = " << w << ", h = " << h << endl;
1504 #endif
1505 
1506  if (m_smooth) {
1507 
1508  for (int y = 0; y < h; ++y) {
1509 
1510  float sy = getBinForY(v, y) - 0.5;
1511  int syi = int(sy + epsilon);
1512  if (syi < 0 || syi >= source->height()) continue;
1513 
1514  uchar *targetLine = img.scanLine(y);
1515  uchar *sourceLine = source->scanLine(syi);
1516  uchar *nextSource;
1517  if (syi + 1 < source->height()) {
1518  nextSource = source->scanLine(syi + 1);
1519  } else {
1520  nextSource = sourceLine;
1521  }
1522 
1523  for (int x = 0; x < w; ++x) {
1524 
1525  targetLine[x] = 0;
1526 
1527  float sx0 = sxa[x*2];
1528  if (sx0 < 0) continue;
1529  int sx0i = int(sx0 + epsilon);
1530  if (sx0i >= sw) break;
1531 
1532  float a = float(sourceLine[sx0i]);
1533  float b = a;
1534  float value;
1535 
1536  float sx1 = sxa[x*2+1];
1537  if (sx1 > sx0 + 1.f) {
1538  int sx1i = int(sx1);
1539  bool have = false;
1540  for (int sx = sx0i; sx <= sx1i; ++sx) {
1541  if (sx < 0 || sx >= sw) continue;
1542  if (!have) {
1543  a = float(sourceLine[sx]);
1544  b = float(nextSource[sx]);
1545  have = true;
1546  } else {
1547  a = std::max(a, float(sourceLine[sx]));
1548  b = std::max(b, float(nextSource[sx]));
1549  }
1550  }
1551  float yprop = sy - syi;
1552  value = (a * (1.f - yprop) + b * yprop);
1553  } else {
1554  a = float(sourceLine[sx0i]);
1555  b = float(nextSource[sx0i]);
1556  float yprop = sy - syi;
1557  value = (a * (1.f - yprop) + b * yprop);
1558  int oi = sx0i + 1;
1559  float xprop = sx0 - sx0i;
1560  xprop -= 0.5;
1561  if (xprop < 0) {
1562  oi = sx0i - 1;
1563  xprop = -xprop;
1564  }
1565  if (oi < 0 || oi >= sw) oi = sx0i;
1566  a = float(sourceLine[oi]);
1567  b = float(nextSource[oi]);
1568  value = (value * (1.f - xprop) +
1569  (a * (1.f - yprop) + b * yprop) * xprop);
1570  }
1571 
1572  int vi = lrintf(value);
1573  if (vi > 255) vi = 255;
1574  if (vi < 0) vi = 0;
1575  targetLine[x] = uchar(vi);
1576  }
1577  }
1578  } else {
1579 
1580  float sy0 = getBinForY(v, 0);
1581 
1582  int psy0i = -1, psy1i = -1;
1583 
1584  for (int y = 0; y < h; ++y) {
1585 
1586  float sy1 = sy0;
1587  sy0 = getBinForY(v, y + 1);
1588 
1589  int sy0i = int(sy0 + epsilon);
1590  int sy1i = int(sy1);
1591 
1592  uchar *targetLine = img.scanLine(y);
1593 
1594  if (sy0i == psy0i && sy1i == psy1i) {
1595  // same source scan line as just computed
1596  goto copy;
1597  }
1598 
1599  psy0i = sy0i;
1600  psy1i = sy1i;
1601 
1602  for (int x = 0; x < w; ++x) {
1603  peaks[x] = 0;
1604  }
1605 
1606  for (int sy = sy0i; sy <= sy1i; ++sy) {
1607 
1608  if (sy < 0 || sy >= source->height()) continue;
1609 
1610  uchar *sourceLine = source->scanLine(sy);
1611 
1612  for (int x = 0; x < w; ++x) {
1613 
1614  float sx1 = sxa[x*2 + 1];
1615  if (sx1 < 0) continue;
1616  int sx1i = int(sx1);
1617 
1618  float sx0 = sxa[x*2];
1619  if (sx0 < 0) continue;
1620  int sx0i = int(sx0 + epsilon);
1621  if (sx0i >= sw) break;
1622 
1623  uchar peak = 0;
1624  for (int sx = sx0i; sx <= sx1i; ++sx) {
1625  if (sx < 0 || sx >= sw) continue;
1626  if (sourceLine[sx] > peak) peak = sourceLine[sx];
1627  }
1628  peaks[x] = peak;
1629  }
1630  }
1631 
1632  copy:
1633  for (int x = 0; x < w; ++x) {
1634  targetLine[x] = peaks[x];
1635  }
1636  }
1637  }
1638 
1639  delete[] peaks;
1640 
1641  paint.drawImage(x0, 0, img);
1642 }
1643 
1644 bool
1646  int &resolution,
1647  SnapType snap) const
1648 {
1649  if (!m_model) {
1650  return Layer::snapToFeatureFrame(v, frame, resolution, snap);
1651  }
1652 
1653  resolution = m_model->getResolution();
1654  int left = (frame / resolution) * resolution;
1655  int right = left + resolution;
1656 
1657  switch (snap) {
1658  case SnapLeft: frame = left; break;
1659  case SnapRight: frame = right; break;
1660  case SnapNearest:
1661  case SnapNeighbouring:
1662  if (frame - left > right - frame) frame = right;
1663  else frame = left;
1664  break;
1665  }
1666 
1667  return true;
1668 }
1669 
1670 void
1671 Colour3DPlotLayer::toXml(QTextStream &stream,
1672  QString indent, QString extraAttributes) const
1673 {
1674  QString s = QString("scale=\"%1\" "
1675  "colourScheme=\"%2\" "
1676  "normalizeColumns=\"%3\" "
1677  "normalizeVisibleArea=\"%4\" "
1678  "minY=\"%5\" "
1679  "maxY=\"%6\" "
1680  "invertVertical=\"%7\" "
1681  "opaque=\"%8\" %9")
1682  .arg((int)m_colourScale)
1683  .arg(m_colourMap)
1684  .arg(m_normalizeColumns ? "true" : "false")
1685  .arg(m_normalizeVisibleArea ? "true" : "false")
1686  .arg(m_miny)
1687  .arg(m_maxy)
1688  .arg(m_invertVertical ? "true" : "false")
1689  .arg(m_opaque ? "true" : "false")
1690  .arg(QString("binScale=\"%1\" smooth=\"%2\" gain=\"%3\" ")
1691  .arg((int)m_binScale)
1692  .arg(m_smooth ? "true" : "false")
1693  .arg(m_gain));
1694 
1695  Layer::toXml(stream, indent, extraAttributes + " " + s);
1696 }
1697 
1698 void
1699 Colour3DPlotLayer::setProperties(const QXmlAttributes &attributes)
1700 {
1701  bool ok = false, alsoOk = false;
1702 
1703  ColourScale scale = (ColourScale)attributes.value("scale").toInt(&ok);
1704  if (ok) setColourScale(scale);
1705 
1706  int colourMap = attributes.value("colourScheme").toInt(&ok);
1707  if (ok) setColourMap(colourMap);
1708 
1709  BinScale binscale = (BinScale)attributes.value("binScale").toInt(&ok);
1710  if (ok) setBinScale(binscale);
1711 
1712  bool normalizeColumns =
1713  (attributes.value("normalizeColumns").trimmed() == "true");
1714  setNormalizeColumns(normalizeColumns);
1715 
1716  bool normalizeVisibleArea =
1717  (attributes.value("normalizeVisibleArea").trimmed() == "true");
1718  setNormalizeVisibleArea(normalizeVisibleArea);
1719 
1720  bool invertVertical =
1721  (attributes.value("invertVertical").trimmed() == "true");
1722  setInvertVertical(invertVertical);
1723 
1724  bool opaque =
1725  (attributes.value("opaque").trimmed() == "true");
1726  setOpaque(opaque);
1727 
1728  bool smooth =
1729  (attributes.value("smooth").trimmed() == "true");
1730  setSmooth(smooth);
1731 
1732  float gain = attributes.value("gain").toFloat(&ok);
1733  if (ok) setGain(gain);
1734 
1735  float min = attributes.value("minY").toFloat(&ok);
1736  float max = attributes.value("maxY").toFloat(&alsoOk);
1737  if (ok && alsoOk) setDisplayExtents(min, max);
1738 }
1739 
int getFrameForX(int x) const
Return the closest frame to the given pixel x-coordinate.
Definition: View.cpp:363
virtual int getVerticalZoomSteps(int &defaultStep) const
Get the number of vertical zoom steps available for this layer.
virtual PropertyList getProperties() const
bool getNormalizeHybrid() const
bool shouldPaintDenseIn(const View *) const
True if we have the opaque or smooth flag set, or if the cells are so small you can't see their borde...
virtual PropertyType getPropertyType(const PropertyName &) const
virtual bool snapToFeatureFrame(View *, int &, int &resolution, SnapType) const
Adjust the given frame to snap to the nearest feature, if possible.
Definition: Layer.h:183
void connectSignals(const Model *)
Definition: Layer.cpp:49
virtual bool getYScaleValue(const View *, int, float &, QString &) const
Return the value and unit at the given y coordinate in the given view.
int getMainModelSampleRate() const
The sample rate of the current main model.
Definition: ViewManager.h:183
void fillCache(int firstBin, int lastBin) const
virtual bool setDisplayExtents(float min, float max)
Set the displayed minimum and maximum values for the y axis to the given range, if supported.
virtual QColor getForeground() const
Definition: View.cpp:513
virtual void toXml(QTextStream &stream, QString indent="", QString extraAttributes="") const
Convert the layer's data (though not those of the model it refers to) into XML for file output.
Definition: Layer.cpp:592
void modelReplaced()
void setNormalizeHybrid(bool n)
Normalize each column to its maximum value, and then scale by the log of the (absolute) maximum value...
virtual ViewManager * getViewManager() const
Definition: View.h:233
float getYForBin(View *, float bin) const
Return the y coordinate at which the given bin "starts" (i.e.
int getColourScaleWidth(QPainter &) const
virtual int getPropertyRangeAndValue(const PropertyName &, int *min, int *max, int *deflt) const
void setColourMap(int map)
virtual bool getValueExtents(float &min, float &max, bool &logarithmic, QString &unit) const
Return the minimum and maximum values for the y axis of the model in this layer, as well as whether t...
virtual bool shouldIlluminateLocalFeatures(const Layer *, QPoint &) const
Definition: View.h:260
static int getColourMapCount()
ColourScale m_colourScale
void setInvertVertical(bool i)
virtual void paintVerticalScale(View *v, bool, QPainter &paint, QRect rect) const
virtual QString getPropertyGroupName(const PropertyName &) const
bool getNormalizeColumns() const
virtual void setLayerDormant(const View *v, bool dormant)
Indicate that a layer is not currently visible in the given view and is not expected to become visibl...
Definition: Layer.cpp:118
int getZoomLevel() const
Return the zoom level, i.e.
Definition: View.cpp:443
virtual void toXml(QTextStream &stream, QString indent="", QString extraAttributes="") const
Convert the layer's data (though not those of the model it refers to) into XML for file output.
void setModel(const DenseThreeDimensionalModel *model)
void modelChangedWithin(int, int)
void setGain(float gain)
Set the gain multiplier for sample values in this view.
void setNormalizeVisibleArea(bool n)
Normalize each value against the maximum in the visible region.
virtual RangeMapper * getNewPropertyRangeMapper(const PropertyName &) const
virtual int getVerticalScaleWidth(View *v, bool, QPainter &) const
virtual QString getFeatureDescription(View *v, QPoint &) const
virtual bool getDisplayExtents(float &min, float &max) const
Return the minimum and maximum values within the displayed range for the y axis, if only a subset of ...
virtual QString getPropertyLabel(const PropertyName &) const
virtual void setVerticalZoomStep(int)
Set the vertical zoom step.
void layerParametersChanged()
void setNormalizeColumns(bool n)
Normalize each column to its maximum value, independent of its neighbours.
void sliceableModelReplaced(const Model *modelToBeReplaced, const Model *replacement)
SnapType
Definition: Layer.h:157
A class for mapping intensity values onto various colour maps.
Definition: ColourMapper.h:27
QColor map(float value) const
virtual RangeMapper * getNewVerticalZoomRangeMapper() const
Create and return a range mapper for vertical zoom step values.
virtual void setProperty(const PropertyName &, int value)
virtual bool isLayerScrollable(const View *v) const
This should return true if the layer can safely be scrolled automatically by a given view (simply cop...
bool getNormalizeVisibleArea() const
virtual void setLayerDormant(const View *v, bool dormant)
Indicate that a layer is not currently visible in the given view and is not expected to become visibl...
void setBinScale(BinScale)
Specify the scale for the y axis.
const DenseThreeDimensionalModel * m_model
View is the base class of widgets that display one or more overlaid views of data against a horizonta...
Definition: View.h:50
virtual void copy(View *, Selection, Clipboard &)
Definition: Layer.h:261
void setColourScale(ColourScale)
virtual void setProperties(const QXmlAttributes &)
Set the particular properties of a layer (those specific to the subclass) from a set of XML attribute...
virtual void drawVisibleText(QPainter &p, int x, int y, QString text, TextStyle style) const
Definition: View.cpp:787
DenseThreeDimensionalModel::Column getColumn(int col) const
bool getInvertVertical() const
virtual QString getPropertyIconName(const PropertyName &) const
virtual int getCurrentVerticalZoomStep() const
Get the current vertical zoom step.
void paintDense(View *v, QPainter &paint, QRect rect) const
virtual bool snapToFeatureFrame(View *v, int &frame, int &resolution, SnapType snap) const
Adjust the given frame to snap to the nearest feature, if possible.
virtual QColor getBackground() const
Definition: View.cpp:493
virtual bool isLayerDormant(const View *v) const
Return whether the layer is dormant (i.e.
Definition: Layer.cpp:126
virtual QString getPropertyValueLabel(const PropertyName &, int value) const
float getBinForY(View *, float y) const
Return the bin number, possibly fractional, at the given y coordinate.
int getXForFrame(int frame) const
Return the pixel x-coordinate corresponding to a given sample frame (which may be negative).
Definition: View.cpp:357
virtual void paint(View *v, QPainter &paint, QRect rect) const
Paint the given rectangle of this layer onto the given view using the given painter,...
static QString getColourMapName(int n)
BinScale getBinScale() const