Mercurial > hg > svgui
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; |