comparison layer/Colour3DPlotLayer.cpp @ 461:272e58f0bf8b sv-v1.4 sv-v1.4rc1

* Knock a bit of sense into Colour3DPlotLayer's cache management
author Chris Cannam
date Mon, 08 Dec 2008 13:06:44 +0000
parents e75f15c9ea11
children 1461cfc7e446
comparison
equal deleted inserted replaced
460:5f9a257598d8 461:272e58f0bf8b
34 34
35 35
36 Colour3DPlotLayer::Colour3DPlotLayer() : 36 Colour3DPlotLayer::Colour3DPlotLayer() :
37 m_model(0), 37 m_model(0),
38 m_cache(0), 38 m_cache(0),
39 m_cacheStart(0), 39 m_cacheValidStart(0),
40 m_cacheValidEnd(0),
40 m_colourScale(LinearScale), 41 m_colourScale(LinearScale),
42 m_colourScaleSet(false),
41 m_colourMap(0), 43 m_colourMap(0),
42 m_normalizeColumns(false), 44 m_normalizeColumns(false),
43 m_normalizeVisibleArea(false), 45 m_normalizeVisibleArea(false),
44 m_invertVertical(false), 46 m_invertVertical(false),
45 m_miny(0), 47 m_miny(0),
48 50
49 } 51 }
50 52
51 Colour3DPlotLayer::~Colour3DPlotLayer() 53 Colour3DPlotLayer::~Colour3DPlotLayer()
52 { 54 {
55 delete m_cache;
53 } 56 }
54 57
55 void 58 void
56 Colour3DPlotLayer::setModel(const DenseThreeDimensionalModel *model) 59 Colour3DPlotLayer::setModel(const DenseThreeDimensionalModel *model)
57 { 60 {
60 m_model = model; 63 m_model = model;
61 if (!m_model || !m_model->isOK()) return; 64 if (!m_model || !m_model->isOK()) return;
62 65
63 connectSignals(m_model); 66 connectSignals(m_model);
64 67
65 connect(m_model, SIGNAL(modelChanged()), this, SLOT(cacheInvalid())); 68 connect(m_model, SIGNAL(modelChanged()), this, SLOT(modelChanged()));
66 connect(m_model, SIGNAL(modelChanged(size_t, size_t)), 69 connect(m_model, SIGNAL(modelChanged(size_t, size_t)),
67 this, SLOT(cacheInvalid(size_t, size_t))); 70 this, SLOT(modelChanged(size_t, size_t)));
68 71
69 emit modelReplaced(); 72 emit modelReplaced();
70 emit sliceableModelReplaced(oldModel, model); 73 emit sliceableModelReplaced(oldModel, model);
71 } 74 }
72 75
73 void 76 void
74 Colour3DPlotLayer::cacheInvalid() 77 Colour3DPlotLayer::cacheInvalid()
75 { 78 {
76 delete m_cache; 79 delete m_cache;
77 m_cache = 0; 80 m_cache = 0;
78 } 81 m_cacheValidStart = 0;
79 82 m_cacheValidEnd = 0;
80 void 83 }
81 Colour3DPlotLayer::cacheInvalid(size_t, size_t) 84
82 { 85 void
86 Colour3DPlotLayer::cacheInvalid(size_t startFrame, size_t endFrame)
87 {
88 if (!m_cache) return;
89
90 size_t modelResolution = m_model->getResolution();
91 size_t start = startFrame / modelResolution;
92 size_t end = endFrame / modelResolution + 1;
93 if (m_cacheValidStart < end) m_cacheValidStart = end;
94 if (m_cacheValidEnd > start) m_cacheValidEnd = start;
95 if (m_cacheValidStart > m_cacheValidEnd) m_cacheValidEnd = m_cacheValidStart;
96 }
97
98 void
99 Colour3DPlotLayer::modelChanged()
100 {
101 if (!m_colourScaleSet && m_colourScale == LinearScale) {
102 if (m_model) {
103 if (m_model->shouldUseLogValueScale()) {
104 setColourScale(LogScale);
105 } else {
106 m_colourScaleSet = true;
107 }
108 }
109 }
83 cacheInvalid(); 110 cacheInvalid();
111 }
112
113 void
114 Colour3DPlotLayer::modelChanged(size_t startFrame, size_t endFrame)
115 {
116 if (!m_colourScaleSet && m_colourScale == LinearScale) {
117 if (m_model && m_model->getWidth() > 50) {
118 if (m_model->shouldUseLogValueScale()) {
119 setColourScale(LogScale);
120 } else {
121 m_colourScaleSet = true;
122 }
123 }
124 }
125 cacheInvalid(startFrame, endFrame);
84 } 126 }
85 127
86 Layer::PropertyList 128 Layer::PropertyList
87 Colour3DPlotLayer::getProperties() const 129 Colour3DPlotLayer::getProperties() const
88 { 130 {
225 void 267 void
226 Colour3DPlotLayer::setColourScale(ColourScale scale) 268 Colour3DPlotLayer::setColourScale(ColourScale scale)
227 { 269 {
228 if (m_colourScale == scale) return; 270 if (m_colourScale == scale) return;
229 m_colourScale = scale; 271 m_colourScale = scale;
272 m_colourScaleSet = true;
230 cacheInvalid(); 273 cacheInvalid();
231 emit layerParametersChanged(); 274 emit layerParametersChanged();
232 } 275 }
233 276
234 void 277 void
601 Colour3DPlotLayer::getColumn(size_t col, 644 Colour3DPlotLayer::getColumn(size_t col,
602 DenseThreeDimensionalModel::Column &values) const 645 DenseThreeDimensionalModel::Column &values) const
603 { 646 {
604 m_model->getColumn(col, values); 647 m_model->getColumn(col, values);
605 648
649 if (!m_normalizeColumns) return;
650
606 float colMax = 0.f, colMin = 0.f; 651 float colMax = 0.f, colMin = 0.f;
607
608 float min = 0.f, max = 0.f; 652 float min = 0.f, max = 0.f;
609 if (m_normalizeColumns) { 653
610 min = m_model->getMinimumLevel(); 654 min = m_model->getMinimumLevel();
611 max = m_model->getMaximumLevel(); 655 max = m_model->getMaximumLevel();
612 } 656
613
614 if (m_normalizeColumns) {
615 for (size_t y = 0; y < values.size(); ++y) {
616 if (y == 0 || values[y] > colMax) colMax = values[y];
617 if (y == 0 || values[y] < colMin) colMin = values[y];
618 }
619 if (colMin == colMax) colMax = colMin + 1;
620 }
621
622 for (size_t y = 0; y < values.size(); ++y) { 657 for (size_t y = 0; y < values.size(); ++y) {
623 658 if (y == 0 || values[y] > colMax) colMax = values[y];
624 float value = min; 659 if (y == 0 || values[y] < colMin) colMin = values[y];
625 660 }
626 value = values[y]; 661 if (colMin == colMax) colMax = colMin + 1;
627 662
628 if (m_normalizeColumns) { 663 for (size_t y = 0; y < values.size(); ++y) {
629 float norm = (value - colMin) / (colMax - colMin); 664
630 value = min + (max - min) * norm; 665 float value = values[y];
631 } 666 float norm = (value - colMin) / (colMax - colMin);
667 value = min + (max - min) * norm;
632 668
633 values[y] = value; 669 values[y] = value;
634 } 670 }
635 } 671 }
636 672
641 size_t modelEnd = m_model->getEndFrame(); 677 size_t modelEnd = m_model->getEndFrame();
642 size_t modelResolution = m_model->getResolution(); 678 size_t modelResolution = m_model->getResolution();
643 679
644 // std::cerr << "Colour3DPlotLayer::fillCache: " << firstBin << " -> " << lastBin << std::endl; 680 // std::cerr << "Colour3DPlotLayer::fillCache: " << firstBin << " -> " << lastBin << std::endl;
645 681
646 if (!m_normalizeVisibleArea || m_normalizeColumns) { 682 size_t modelStartBin = modelStart / modelResolution;
647 firstBin = modelStart / modelResolution; 683 size_t modelEndBin = modelEnd / modelResolution;
648 lastBin = modelEnd / modelResolution; 684
649 } 685 size_t cacheWidth = modelEndBin - modelStartBin + 1;
650
651 size_t cacheWidth = lastBin - firstBin + 1;
652 size_t cacheHeight = m_model->getHeight(); 686 size_t cacheHeight = m_model->getHeight();
653 687
654 if (m_cache && 688 if (m_cache && (m_cache->height() != int(cacheHeight))) {
655 (m_cacheStart != firstBin || 689 delete m_cache;
656 m_cache->width() != int(cacheWidth) || 690 m_cache = 0;
657 m_cache->height() != int(cacheHeight))) { 691 }
658 692
659 delete m_cache; 693 if (m_cache && (m_cache->width() != int(cacheWidth))) {
660 m_cache = 0; 694 QImage *newCache = new QImage(m_cache->copy(0, 0, cacheWidth, cacheHeight));
661 } 695 delete m_cache;
662 696 m_cache = newCache;
663 if (m_cache) return; 697 }
664 698
665 m_cache = new QImage(cacheWidth, cacheHeight, QImage::Format_Indexed8); 699 if (!m_cache) {
666 m_cacheStart = firstBin; 700 m_cache = new QImage(cacheWidth, cacheHeight, QImage::Format_Indexed8);
667 701 m_cache->setNumColors(256);
668 // std::cerr << "Cache size " << cacheWidth << "x" << cacheHeight << " starting " << m_cacheStart << std::endl; 702 m_cacheValidStart = 0;
669 703 m_cacheValidEnd = 0;
670 m_cache->setNumColors(256); 704 }
705
706 if (m_cacheValidStart <= firstBin && m_cacheValidEnd >= lastBin) {
707 return;
708 }
709
710 size_t fillStart = firstBin;
711 size_t fillEnd = lastBin;
712
713 if (fillStart < modelStartBin) fillStart = modelStartBin;
714 if (fillStart > modelEndBin) fillStart = modelEndBin;
715 if (fillEnd < modelStartBin) fillEnd = modelStartBin;
716 if (fillEnd > modelEndBin) fillEnd = modelEndBin;
717
718 bool normalizeVisible = (m_normalizeVisibleArea && !m_normalizeColumns);
719
720 if (!normalizeVisible && (m_cacheValidStart < m_cacheValidEnd)) {
721
722 if (m_cacheValidEnd < fillStart) {
723 fillStart = m_cacheValidEnd + 1;
724 }
725 if (m_cacheValidStart > fillEnd) {
726 fillEnd = m_cacheValidStart - 1;
727 }
728
729 m_cacheValidStart = std::min(fillStart, m_cacheValidStart);
730 m_cacheValidEnd = std::max(fillEnd, m_cacheValidEnd);
731
732 } else {
733
734 // the only valid area, ever, is the currently visible one
735
736 m_cacheValidStart = fillStart;
737 m_cacheValidEnd = fillEnd;
738 }
739
740 // std::cerr << "Cache size " << cacheWidth << "x" << cacheHeight << " will be valid from " << m_cacheValidStart << " to " << m_cacheValidEnd << std::endl;
741
671 DenseThreeDimensionalModel::Column values; 742 DenseThreeDimensionalModel::Column values;
743 values.reserve(cacheHeight);
672 744
673 float min = m_model->getMinimumLevel(); 745 float min = m_model->getMinimumLevel();
674 float max = m_model->getMaximumLevel(); 746 float max = m_model->getMaximumLevel();
675 747
676 if (m_colourScale == LogScale) { 748 if (m_colourScale == LogScale) {
683 if (max == min) max = min + 1.0; 755 if (max == min) max = min + 1.0;
684 756
685 ColourMapper mapper(m_colourMap, 0.f, 255.f); 757 ColourMapper mapper(m_colourMap, 0.f, 255.f);
686 758
687 for (int index = 0; index < 256; ++index) { 759 for (int index = 0; index < 256; ++index) {
688
689 QColor colour = mapper.map(index); 760 QColor colour = mapper.map(index);
690 m_cache->setColor(index, qRgb(colour.red(), colour.green(), colour.blue())); 761 m_cache->setColor(index, qRgb(colour.red(), colour.green(), colour.blue()));
691 } 762 }
692 763
693 m_cache->fill(0); 764 // m_cache->fill(0);
694 765
695 float visibleMax = 0.f, visibleMin = 0.f; 766 float visibleMax = 0.f, visibleMin = 0.f;
696 767
697 if (m_normalizeVisibleArea && !m_normalizeColumns) { 768 if (normalizeVisible) {
698 769
699 for (size_t c = firstBin; c <= lastBin; ++c) { 770 for (size_t c = fillStart; c <= fillEnd; ++c) {
700 771
701 values.clear(); 772 values.clear();
702 getColumn(c, values); 773 getColumn(c, values);
703 774
704 float colMax = 0.f, colMin = 0.f; 775 float colMax = 0.f, colMin = 0.f;
705 776
706 for (size_t y = 0; y < m_model->getHeight(); ++y) { 777 for (size_t y = 0; y < cacheHeight; ++y) {
707 if (y >= values.size()) break; 778 if (y >= values.size()) break;
708 if (y == 0 || values[y] > colMax) colMax = values[y]; 779 if (y == 0 || values[y] > colMax) colMax = values[y];
709 if (y == 0 || values[y] < colMin) colMin = values[y]; 780 if (y == 0 || values[y] < colMin) colMin = values[y];
710 } 781 }
711 782
712 if (c == firstBin || colMax > visibleMax) visibleMax = colMax; 783 if (c == fillStart || colMax > visibleMax) visibleMax = colMax;
713 if (c == firstBin || colMin < visibleMin) visibleMin = colMin; 784 if (c == fillStart || colMin < visibleMin) visibleMin = colMin;
714 } 785 }
786
787 if (m_colourScale == LogScale) {
788 visibleMin = LogRange::map(visibleMin);
789 visibleMax = LogRange::map(visibleMax);
790 if (visibleMin > visibleMax) std::swap(visibleMin, visibleMax);
791 }
715 } 792 }
716 793
717 if (visibleMin == visibleMax) visibleMax = visibleMin + 1; 794 if (visibleMin == visibleMax) visibleMax = visibleMin + 1;
718 795
719 for (size_t c = firstBin; c <= lastBin; ++c) { 796 for (size_t c = fillStart; c <= fillEnd; ++c) {
720 797
721 values.clear(); 798 values.clear();
722 getColumn(c, values); 799 getColumn(c, values);
723 800
724 for (size_t y = 0; y < m_model->getHeight(); ++y) { 801 for (size_t y = 0; y < cacheHeight; ++y) {
725 802
726 float value = min; 803 float value = min;
727 if (y < values.size()) { 804 if (y < values.size()) {
728 value = values[y]; 805 value = values[y];
729 } 806 }
807
808 if (m_colourScale == LogScale) {
809 value = LogRange::map(value);
810 }
730 811
731 if (m_normalizeVisibleArea && !m_normalizeColumns) { 812 if (normalizeVisible) {
732 float norm = (value - visibleMin) / (visibleMax - visibleMin); 813 float norm = (value - visibleMin) / (visibleMax - visibleMin);
733 value = min + (max - min) * norm; 814 value = min + (max - min) * norm;
734 } 815 }
735 816
736 if (m_colourScale == LogScale) {
737 value = LogRange::map(value);
738 }
739
740 int pixel = int(((value - min) * 256) / (max - min)); 817 int pixel = int(((value - min) * 256) / (max - min));
741 if (pixel < 0) pixel = 0; 818 if (pixel < 0) pixel = 0;
742 if (pixel > 255) pixel = 255; 819 if (pixel > 255) pixel = 255;
743 820
744 if (m_invertVertical) { 821 if (m_invertVertical) {
745 m_cache->setPixel(c - firstBin, m_model->getHeight() - y - 1, 822 m_cache->setPixel(c, cacheHeight - y - 1, pixel);
746 pixel);
747 } else { 823 } else {
748 m_cache->setPixel(c - firstBin, y, pixel); 824 m_cache->setPixel(c, y, pixel);
749 } 825 }
750 } 826 }
751 } 827 }
752 } 828 }
753 829
838 bool illuminate = v->shouldIlluminateLocalFeatures(this, illuminatePos); 914 bool illuminate = v->shouldIlluminateLocalFeatures(this, illuminatePos);
839 char labelbuf[10]; 915 char labelbuf[10];
840 916
841 for (int sx = sx0; sx <= sx1; ++sx) { 917 for (int sx = sx0; sx <= sx1; ++sx) {
842 918
843 int scx = 0;
844 if (sx > int(m_cacheStart)) scx = sx - m_cacheStart;
845
846 int fx = sx * int(modelResolution); 919 int fx = sx * int(modelResolution);
847 920
848 if (fx + int(modelResolution) <= int(modelStart) || 921 if (fx + int(modelResolution) <= int(modelStart) ||
849 fx > int(modelEnd)) continue; 922 fx > int(modelEnd)) continue;
850 923
860 933
861 for (int sy = symin; sy < symax; ++sy) { 934 for (int sy = symin; sy < symax; ++sy) {
862 935
863 int ry0 = h - ((sy - symin) * h) / (symax - symin) - 1; 936 int ry0 = h - ((sy - symin) * h) / (symax - symin) - 1;
864 QRgb pixel = qRgb(255, 255, 255); 937 QRgb pixel = qRgb(255, 255, 255);
865 if (scx >= 0 && scx < m_cache->width() && 938 if (sx >= 0 && sx < m_cache->width() &&
866 sy >= 0 && sy < m_cache->height()) { 939 sy >= 0 && sy < m_cache->height()) {
867 pixel = m_cache->pixel(scx, sy); 940 pixel = m_cache->pixel(sx, sy);
868 } 941 }
869 942
870 QRect r(rx0, ry0 - h / (symax - symin) - 1, 943 QRect r(rx0, ry0 - h / (symax - symin) - 1,
871 rw, h / (symax - symin) + 1); 944 rw, h / (symax - symin) + 1);
872 945
899 #endif 972 #endif
900 973
901 paint.drawRect(r); 974 paint.drawRect(r);
902 975
903 if (showLabel) { 976 if (showLabel) {
904 if (scx >= 0 && scx < m_cache->width() && 977 if (sx >= 0 && sx < m_cache->width() &&
905 sy >= 0 && sy < m_cache->height()) { 978 sy >= 0 && sy < m_cache->height()) {
906 float value = m_model->getValueAt(scx, sy); 979 float value = m_model->getValueAt(sx, sy);
907 sprintf(labelbuf, "%06f", value); 980 sprintf(labelbuf, "%06f", value);
908 QString text(labelbuf); 981 QString text(labelbuf);
909 paint.setPen(v->getBackground()); 982 paint.setPen(v->getBackground());
910 paint.drawText(rx0 + 2, 983 paint.drawText(rx0 + 2,
911 ry0 - h / sh - 1 + 2 + paint.fontMetrics().ascent(), 984 ry0 - h / sh - 1 + 2 + paint.fontMetrics().ascent(),
973 float mag = 0.0, div = 0.0; 1046 float mag = 0.0, div = 0.0;
974 int max = 0; 1047 int max = 0;
975 1048
976 for (int sx = sx0i; sx <= sx1i; ++sx) { 1049 for (int sx = sx0i; sx <= sx1i; ++sx) {
977 1050
978 int scx = 0; 1051 if (sx < 0 || sx >= m_cache->width()) continue;
979 if (sx > int(m_cacheStart)) scx = sx - int(m_cacheStart);
980
981 if (scx < 0 || scx >= m_cache->width()) continue;
982 1052
983 for (int sy = sy0i; sy <= sy1i; ++sy) { 1053 for (int sy = sy0i; sy <= sy1i; ++sy) {
984 1054
985 if (sy < 0 || sy >= m_cache->height()) continue; 1055 if (sy < 0 || sy >= m_cache->height()) continue;
986 1056
988 if (sx == sx0i) prop *= (sx + 1) - sx0; 1058 if (sx == sx0i) prop *= (sx + 1) - sx0;
989 if (sx == sx1i) prop *= sx1 - sx; 1059 if (sx == sx1i) prop *= sx1 - sx;
990 if (sy == sy0i) prop *= (sy + 1) - sy0; 1060 if (sy == sy0i) prop *= (sy + 1) - sy0;
991 if (sy == sy1i) prop *= sy1 - sy; 1061 if (sy == sy1i) prop *= sy1 - sy;
992 1062
993 mag += prop * m_cache->pixelIndex(scx, sy); 1063 mag += prop * m_cache->pixelIndex(sx, sy);
994 max = std::max(max, m_cache->pixelIndex(scx, sy)); 1064 max = std::max(max, m_cache->pixelIndex(sx, sy));
995 div += prop; 1065 div += prop;
996 } 1066 }
997 } 1067 }
998 1068
999 if (div != 0) mag /= div; 1069 if (div != 0) mag /= div;