Reimplemented things working with summed pixels, other fixes.
[fic.git] / debug.cpp
blob2ec4ed99a1e114fb64909f167f53b897261f3952
1 #include "interfaces.h"
2 #ifndef NDEBUG
4 #include "modules/root.h"
5 #include "modules/squarePixels.h"
6 #include "modules/stdEncoder.h"
7 #include "modules/quadTree.h"
8 #include "modules/stdDomains.h"
9 #include "modules/saupePredictor.h"
11 #include <QBoxLayout>
12 #include <QDialog>
13 #include <QLabel>
14 #include <QTabWidget>
15 #include <QTableWidget>
17 using namespace std;
19 int pos;
21 QWidget* MRoot::debugModule(QPixmap &pixmap,const QPoint &click) {
22 // create a new modeless dialog window
23 QDialog *dlg= new QDialog;
24 dlg->setModal(false);
25 // add a laid-out single widget created by IShapeTransformer
26 ( new QVBoxLayout(dlg) )->addWidget( moduleShape()->debugModule(pixmap,click) );
27 return dlg;
30 namespace NOSPACE {
31 struct PlaneFinder {
32 typedef const IColorTransformer::PlaneSettings CPlSet;
34 CPlSet* const plSet;
36 PlaneFinder(CPlSet *plSet2find): plSet(plSet2find) {}
37 bool operator()(const IColorTransformer::Plane &plane)
38 { return plane.settings==plSet; }
41 QWidget* MSquarePixels::debugModule(QPixmap &pixmap,const QPoint &click) {
42 ASSERT( !planeList.empty() );
43 // create a tab widget
44 QTabWidget *tabs= new QTabWidget;
45 // fill one tab for every job by three sub-tabs with the three modules
46 for (int i=0; i<(int)jobs.size(); ++i) {
47 Job &job= jobs[i];
48 if ( job.ranges->getRangeList().size() == 1 )
49 continue;
50 // find the plane which is the job from
51 PlaneList::const_iterator plane=
52 find_if( planeList.begin(), planeList.end(), PlaneFinder(job.settings) );
53 ASSERT( plane != planeList.end() );
54 // find out the position of the job in the plane
55 int xShift=-1, yShift;
56 plane->pixels.getPosition(job.pixels.start,xShift,yShift);
57 ASSERT(xShift>=0);
58 QPoint jobClick= click-QPoint(xShift,yShift);
59 if ( jobClick.x()<0 || jobClick.y()<0
60 || jobClick.x()>=job.width || jobClick.y()>=job.height )
61 continue;
62 // make children do the work
63 QTabWidget *tabs2= new QTabWidget;
64 tabs2->addTab( job.encoder->debugModule(pixmap,jobClick) , "Encoder" );
65 tabs2->addTab( job.ranges->debugModule(pixmap,jobClick), "Ranges" );
66 tabs2->addTab( job.domains->debugModule(pixmap,jobClick), "Domains" );
68 tabs->addTab( tabs2, QString("Job %1").arg(i+1) );
70 return tabs;
74 namespace NOSPACE {
75 struct RangeInfoAccumulator {
76 const ISquareDomains::PoolList *pools;
77 int rotCounts[9];
78 vector<int> poolCounts, levelCounts;
80 RangeInfoAccumulator(const ISquareDomains::PoolList &poolList)
81 : pools( &poolList ), poolCounts( pools->size(), 0 ), levelCounts( 10, 0 ) {
82 for (int i=0; i<9; ++i)
83 rotCounts[i]= 0;
86 void operator()(const ISquareRanges::RangeNode *range) {
87 const MStandardEncoder::RangeInfo &info
88 = static_cast<MStandardEncoder::RangeInfo&>( *range->encoderData );
89 // increment the counts of ranges on this rotation and level
90 ++rotCounts[info.rotation+1];
91 ++levelCounts.at(range->level);
92 // find and increment the pool of the range's domain (if exists)
93 if ( info.rotation>=0 ) {
94 int index= info.decAccel.pool - &*pools->begin() ;
95 ASSERT( index>=0 && index<(int)pools->size() );
96 ++poolCounts[index];
99 }; // RangeAccumulator struct
101 const ISquareRanges::RangeNode* findRangeOnPoint
102 ( const ISquareRanges::RangeList &ranges, const QPoint &click ) {
103 int x= click.x(), y= click.y();
104 ISquareRanges::RangeList::const_iterator it;
105 for (it=ranges.begin(); it!=ranges.end(); ++it) {
106 const Block &b= **it;
107 if ( b.x0<=x && b.y0<=y && b.xend>x && b.yend>y )
108 return *it;
110 ASSERT(false); return 0;
114 namespace NOSPACE {
115 static void addFramedImage(QLayout *layout,const QImage &image) {
116 QLabel *label= new QLabel;
117 label->setPixmap( QPixmap::fromImage(image) );
118 label->setFrameStyle( QFrame::Plain | QFrame::Box ); // to have a thin frame
119 label->setSizePolicy( QSizePolicy() ); // to have the frame exatly around the image
120 layout->addWidget(label);
122 template<class Assigner>
123 QImage imageFromMatrix(CSMatrix matrix,Block block,int rotation,Assigner assigner) {
124 QImage image(block.width(),block.height(),QImage::Format_RGB32);
126 using namespace MatrixWalkers;
127 // changing rotation because of transposed CheckedImage
128 rotation= Rotation::compose(1,rotation);
130 walkOperateCheckRotate( CheckedImage<QImage,QRgb>(image), assigner
131 , matrix, block, rotation );
133 return image;
135 struct GrayImageAssigner {
136 void operator()(QRgb &rgb,const SReal &pixel) {
137 int gray= Float2int<8,Real>::convertCheck(pixel);
138 rgb= qRgb(gray,gray,255); // not gray colour (intentionally)
140 void innerEnd() const {}
142 struct GrayImageMulAddAssigner: public GrayImageAssigner {
143 Real mul, add;
145 GrayImageMulAddAssigner(Real toMul,Real toAdd)
146 : mul(toMul), add(toAdd) {}
147 void operator()(QRgb &rgb,const SReal &pixel)
148 { GrayImageAssigner::operator()( rgb, pixel*mul+add ); }
151 QWidget* MStandardEncoder::debugModule(QPixmap &pixmap,const QPoint &click) {
152 const ISquareRanges::RangeList &ranges= planeBlock->ranges->getRangeList();
154 QWidget *widget= new QWidget;
155 QBoxLayout *layout= new QVBoxLayout(widget);
157 if ( pixmap.rect().contains(click) ) { // info about range clicked on
158 const RangeNode &range= *findRangeOnPoint( ranges, click );
159 const RangeInfo &info= static_cast<RangeInfo&>(*range.encoderData);
161 QString msg= QString("Quantized average: %1\nQuantized deviation: %2\n\n")
162 .arg(info.qrAvg) .arg(sqrt(info.qrDev2));
164 msg+= QString("Encoding SE: %1\n") .arg(info.bestSE);
166 if (info.qrDev2) {
167 int poolIndex= info.decAccel.pool - &*planeBlock->domains->getPools().begin();
168 const Block &domBlock= info.decAccel.domBlock;
169 msg+= QString("Domain pool: %1\nDomain block top-left corner coordinates:\n"
170 "\t %2 %3\n") .arg(poolIndex) .arg(domBlock.x0) .arg(domBlock.y0);
172 msg+= QString("Rotation: %1\nInversion: %2")
173 .arg((int)info.rotation) .arg(info.inverted);
174 } else
175 msg+= "Only using solid color";
177 layout->addWidget( new QLabel(msg) );
179 if (info.qrDev2) {
180 layout->addWidget( new QLabel("Domain block:") );
181 addFramedImage( layout
182 , imageFromMatrix( info.decAccel.pool->pixels, info.decAccel.domBlock
183 , 0, GrayImageAssigner() )
186 layout->addWidget( new QLabel("Domain block, transformed (encode-mode-only):") );
187 addFramedImage( layout
188 , imageFromMatrix( info.decAccel.pool->pixels, info.decAccel.domBlock
189 , info.rotation, GrayImageMulAddAssigner(info.exact.linCoeff,info.exact.constCoeff) )
193 layout->addWidget( new QLabel("Range block:") );
194 addFramedImage( layout
195 , imageFromMatrix( planeBlock->pixels, range, 0, GrayImageAssigner() )
198 } else { // provide general info
199 RangeInfoAccumulator info( planeBlock->domains->getPools() );
200 info= for_each( ranges.begin(), ranges.end(), info );
202 {// create a label with various counts info
203 QString msg= "Range count: %1\nRotation counts: %2\nDomain pool counts: %3";
204 // fill in the total range count
205 msg= msg.arg( ranges.size() );
206 // fill in the rotation counts
207 QString rots= QString::number(info.rotCounts[0]);
208 for (int i=1; i<9; ++i)
209 (rots+= ", ")+= QString::number(info.rotCounts[i]);
210 msg= msg.arg(rots);
211 // fill in the domain counts
212 QString doms= QString::number(info.rotCounts[0]);
213 vector<int>::const_iterator it;
214 for (it= info.poolCounts.begin(); it!=info.poolCounts.end(); ++it)
215 (doms+= ", ")+= QString::number(*it);
216 msg= msg.arg(doms);
217 // create the label and add it to the layout
218 layout->addWidget( new QLabel(msg) );
221 int maxLevel= 1 +log2ceil( max(planeBlock->width,planeBlock->height) );
223 QTableWidget *table= new QTableWidget( maxLevel-2, 3 );
224 table->setHorizontalHeaderLabels
225 ( QStringList() << "Level" << "Ranges" << "Domain count" );
226 for (int level=2; level<maxLevel; ++level) {
227 // the number of the level
228 table->setItem( level-2, 0, new QTableWidgetItem(QString::number(level)) );
229 // the count of the ranges on the level
230 table->setItem( level-2, 1, new QTableWidgetItem(
231 QString::number( info.levelCounts[level] )
232 ) );
233 // the maximum allowed SE for the level
234 //float maxSE= planeBlock->moduleQ2SE->rangeSE( planeBlock->quality, powers[2*level] );
235 //table->setItem( level-2, 1.5, new QTableWidgetItem(QString::number(maxSE)) );
236 // the domain count for the level
237 int domCount= levelPoolInfos[level].empty() ? -1
238 : levelPoolInfos[level].back().indexBegin;
239 table->setItem( level-2, 2, new QTableWidgetItem(
240 QString("2 ^ %1").arg( log2(domCount) )
241 ) );
243 // resize the label and add it to the layout
244 table->resizeColumnsToContents();
245 table->resizeRowsToContents();
246 layout->addWidget(table);
248 if ( modulePredictor() )
249 layout->addWidget( modulePredictor()->debugModule(pixmap,click) );
250 } // if-then-else
252 return widget;
253 } // MStandardEncoder::debugModule method
256 QWidget* MQuadTree::debugModule(QPixmap &pixmap,const QPoint &click) {
258 if ( pixmap.rect().contains(click) ) { // info about range clicked on
259 const ISquareRanges::RangeNode &range= *findRangeOnPoint( fringe, click );
261 QString msg= QString("Level: %1\nRegular: %2\n"
262 "Top-left corner: %3 %4\nWidth: %5\nHeight: %6")
263 .arg(range.level) .arg(range.isRegular())
264 .arg(range.x0) .arg(range.y0)
265 .arg(range.width()) .arg(range.height());
266 return new QLabel(msg);
268 } else { // provide general info
269 QString msg;
270 // add info about heuristic dividing (if it's allowed)
271 if ( settingsInt(HeuristicAllowed) ) {
272 msg+= "Heuristic dividing info:\n"
273 "\tBad tries (forced to divide): %1\n"
274 "\tBad divides (successful merges): %2\n"
275 "\tUnsuccessful merges: %3\n";
276 msg= msg.arg(badTries).arg(badDivides).arg(triedMerges);
278 return new QLabel(msg);
279 } // if-then-else
281 } // MQuadTree::debugModule method
284 QWidget* MStdDomains::debugModule(QPixmap &pixmap,const QPoint &click) {
286 if ( pixmap.rect().contains(click) ) { // info about range clicked on
289 } else { // provide general info
292 } // if-then-else
293 return 0;
296 QWidget* MSaupePredictor::debugModule(QPixmap &pixmap,const QPoint &click) {
297 if ( pixmap.rect().contains(click) )
298 return 0;
299 return new QLabel( QString("Predicted %1/%2 (%3%)")
300 .arg(predicted) .arg(maxpred) .arg(double(100)*predicted/(double)maxpred) );
303 #endif