00001 #ifndef MATRIXUTIL_HEADER_
00002 #define MATRIXUTIL_HEADER_
00003
00005 struct Block {
00006 short x0, y0, xend, yend;
00007
00008 int width() const { return xend-x0; }
00009 int height() const { return yend-y0; }
00010 int size() const { return width()*height(); }
00011
00012 bool contains(short x,short y) const
00013 { return x0<=x && x<xend && y0<=y && y<yend; }
00014
00015 Block() {}
00016 Block(short x0_,short y0_,short xend_,short yend_)
00017 : x0(x0_), y0(y0_), xend(xend_), yend(yend_) {}
00018 };
00019
00021
00024 template<class T,class I=PtrInt> struct MatrixSlice {
00025 typedef MatrixSlice<const T,I> Const;
00026
00027 T *start;
00028 I colSkip;
00029
00031 MatrixSlice(): start(0) {}
00032
00034 static MatrixSlice makeRaw(T *start,I colSkip) {
00035 MatrixSlice result;
00036 result.start= start;
00037 result.colSkip= colSkip;
00038 return result;
00039 }
00040
00042 operator Const() const {
00043 Const result;
00044 result.start= start;
00045 result.colSkip= colSkip;
00046 return result;
00047 }
00048
00050 T* operator[](I column) {
00051 ASSERT( isValid() );
00052 return start+column*colSkip;
00053 }
00055 const T* operator[](I column) const {
00056 return constCast(*this)[column];
00057 }
00058
00061 void allocate( I width, I height, T *memory=0 ) {
00062 ASSERT( width>0 && height>0 );
00063 free();
00064 start= memory ? memory : new T[width*height];
00065 colSkip= height;
00066 }
00068 void free() {
00069 delete[] start;
00070 start= 0;
00071 }
00073 bool isValid() const {
00074 return start;
00075 }
00076
00078 void fillSubMatrix(const Block &block,T value) {
00079 ASSERT( isValid() );
00080
00081 T *begin= start+block.y0+colSkip*block.x0
00082 , *end= start+block.y0+colSkip*block.xend;
00083
00084 for (T *it= begin; it!=end; it+= colSkip)
00085 std::fill( it, it+block.height(), value );
00086 }
00090 MatrixSlice& shiftMatrix(I x0,I y0) {
00091 ASSERT( isValid() );
00092 start+= x0*colSkip+y0;
00093 return *this;
00094 }
00096 void getPosition(const T *elem,int &x,int &y) const {
00097 ASSERT( isValid() );
00098 PtrInt diff= elem-start;
00099 if (diff>=0) {
00100 x= diff/colSkip;
00101 y= diff%colSkip;
00102 } else {
00103 x= -((-diff-1)/colSkip) -1;
00104 y= colSkip - (-diff-1)%colSkip -1;
00105 }
00106 }
00107 };
00108
00109
00113 template<class T,class I=PtrInt> struct MatrixSummer {
00114 typedef T Result;
00115
00116 MatrixSlice<T,I> sums;
00117
00119 bool isValid() const { return sums.isValid(); }
00121 void free() { sums.free(); };
00122
00124 Result getSum(I x0,I y0,I xend,I yend) const {
00125 ASSERT( sums.isValid() );
00126 return sums[xend][yend] -(sums[x0][yend]+sums[xend][y0]) +sums[x0][y0];
00127 }
00129 Result getSum(const Block &b) const
00130 { return getSum( b.x0, b.y0, b.xend, b.yend ); }
00131
00134 template<class Input> void fill(Input inp,I width,I height) {
00135 if ( !sums.isValid() )
00136 sums.allocate(width+1,height+1);
00137
00138
00139 for (I i=0; i<=width; ++i)
00140 sums[i][0]= 0;
00141 for (I j=1; j<=height; ++j)
00142 sums[0][j]= 0;
00143
00144 for (I i=1; i<=width; ++i)
00145 for (I j=1; j<=height; ++j)
00146 sums[i][j]= sums[i][j-1] + Result(inp[i-1][j-1]);
00147
00148 for (I i=2; i<=width; ++i)
00149 for (I j=1; j<=height; ++j)
00150 sums[i][j]+= sums[i-1][j];
00151 }
00152 };
00153
00155 template<class Num> struct DoubleNum {
00156 Num value, square;
00157
00158 DoubleNum()
00159 { DEBUG_ONLY( value= square= std::numeric_limits<Num>::quiet_NaN(); ) }
00160
00161 DoubleNum(Num val)
00162 : value(val), square(sqr(val)) {}
00163
00164 DoubleNum(const DoubleNum &other)
00165 : value(other.value), square(other.square) {}
00166
00167 void unpack(Num &val,Num &sq) const { val= value; sq= square; }
00168
00169 DoubleNum& operator+=(const DoubleNum &other) {
00170 value+= other.value;
00171 square+= other.square;
00172 return *this;
00173 }
00174 DoubleNum& operator-=(const DoubleNum &other) {
00175 value-= other.value;
00176 square-= other.square;
00177 return *this;
00178 }
00179 friend DoubleNum operator+(const DoubleNum &a,const DoubleNum &b)
00180 { return DoubleNum(a)+= b; }
00181 friend DoubleNum operator-(const DoubleNum &a,const DoubleNum &b)
00182 { return DoubleNum(a)-= b; }
00183 };
00184
00185
00187 template< class SumT, class PixT, class I=PtrInt >
00188 struct SummedMatrix {
00189 typedef DoubleNum<SumT> BSumRes;
00190 typedef MatrixSummer<BSumRes,I> BSummer;
00191
00192 I width
00193 , height;
00194 MatrixSlice<PixT> pixels;
00195 BSummer summer;
00196 bool sumsValid;
00197
00199 void setSize( I width_, I height_ ) {
00200 free();
00201 width= width_;
00202 height= height_;
00203 pixels.allocate(width,height);
00204 }
00206 void free(bool freePixels=true) {
00207 if (freePixels)
00208 pixels.free();
00209 else
00210 pixels.start= 0;
00211 summer.free();
00212 sumsValid= false;
00213 }
00214
00216 void summers_makeValid() const {
00217 ASSERT(pixels.isValid());
00218 if (!sumsValid) {
00219 constCast(summer).fill(pixels,width,height);
00220 constCast(sumsValid)= true;
00221 }
00222 }
00224 void summers_invalidate()
00225 { sumsValid= false; }
00227 BSumRes getSums(const Block &block) const
00228 { return getSums( block.x0, block.y0, block.xend, block.yend ); }
00230 BSumRes getSums( I x0, I y0, I xend, I yend ) const {
00231 ASSERT( sumsValid && x0>=0 && y0>=0 && xend>x0 && yend>y0
00232 && xend<=width && yend<=height );
00233 return summer.getSum(x0,y0,xend,yend);
00234 }
00236 SumT getValueSum( I x0, I y0, I xend, I yend ) const {
00237
00238 return getSums(x0,y0,xend,yend).value;
00239 }
00240 };
00241
00242
00243
00246 namespace MatrixWalkers {
00247
00251 template < class Checked, class Unchecked, class Operator >
00252 Operator walkOperate( Checked checked, Unchecked unchecked, Operator oper ) {
00253
00254 ASSERT( checked.outerCond() );
00255 do {
00256
00257 checked.innerInit();
00258 unchecked.innerInit();
00259
00260 ASSERT( checked.innerCond() );
00261 do {
00262
00263 oper( checked.get(), unchecked.get() );
00264 checked.innerStep();
00265 unchecked.innerStep();
00266 } while ( checked.innerCond() );
00267
00268
00269 oper.innerEnd();
00270 checked.outerStep();
00271 unchecked.outerStep();
00272
00273 } while ( checked.outerCond() );
00274
00275 return oper;
00276 }
00277
00278
00280 template<class T,class I> struct RotBase {
00281 public:
00282 typedef MatrixSlice<T,I> TMatrix;
00283 protected:
00284 TMatrix current;
00285 T *lastStart;
00286
00287 public:
00288 RotBase( TMatrix matrix, int x0, int y0 )
00289 : current( matrix.shiftMatrix(x0,y0) ), lastStart(current.start) {
00290 DEBUG_ONLY( current.start= 0; )
00291 ASSERT( matrix.isValid() );
00292 }
00293
00294 void innerInit() { current.start= lastStart; }
00295 T& get() { return *current.start; }
00296 };
00297
00298 #define ROTBASE_INHERIT \
00299 typedef typename RotBase<T,I>::TMatrix TMatrix; \
00300 using RotBase<T,I>::current; \
00301 using RotBase<T,I>::lastStart;
00302
00304 template<class T,class I=PtrInt> struct Rotation_0: public RotBase<T,I> { ROTBASE_INHERIT
00305 Rotation_0( TMatrix matrix, const Block &block )
00306 : RotBase<T,I>( matrix, block.x0, block.y0 ) {}
00307
00308 explicit Rotation_0( TMatrix matrix, I x0=0, I y0=0 )
00309 : RotBase<T,I>( matrix, x0, y0 ) {}
00310
00311 void outerStep() { lastStart+= current.colSkip; }
00312 void innerStep() { ++current.start; }
00313 };
00314
00316 template<class T,class I> struct Rotation_1_T: public RotBase<T,I> { ROTBASE_INHERIT
00317 Rotation_1_T( TMatrix matrix, const Block &block )
00318 : RotBase<T,I>( matrix, block.xend-1, block.y0 ) {}
00319
00320 void outerStep() { lastStart-= current.colSkip; }
00321 void innerStep() { ++current.start; }
00322 };
00323
00325 template<class T,class I> struct Rotation_2: public RotBase<T,I> { ROTBASE_INHERIT
00326 Rotation_2( TMatrix matrix, const Block &block )
00327 : RotBase<T,I>( matrix, block.xend-1, block.yend-1 ) {}
00328
00329 void outerStep() { lastStart-= current.colSkip; }
00330 void innerStep() { --current.start; }
00331 };
00332
00334 template<class T,class I> struct Rotation_3_T: public RotBase<T,I> { ROTBASE_INHERIT
00335 Rotation_3_T( TMatrix matrix, const Block &block )
00336 : RotBase<T,I>( matrix, block.x0, block.yend-1 ) {}
00337
00338 void outerStep() { lastStart+= current.colSkip; }
00339 void innerStep() { --current.start; }
00340 };
00341
00343 template<class T,class I> struct Rotation_0_T: public RotBase<T,I> { ROTBASE_INHERIT
00344 Rotation_0_T( TMatrix matrix, const Block &block )
00345 : RotBase<T,I>( matrix, block.x0, block.y0 ) {}
00346
00347 explicit Rotation_0_T( TMatrix matrix, I x0=0, I y0=0 )
00348 : RotBase<T,I>( matrix, x0, y0 ) {}
00349
00350 void outerStep() { ++lastStart; }
00351 void innerStep() { current.start+= current.colSkip; }
00352 };
00353
00355 template<class T,class I> struct Rotation_1: public RotBase<T,I> { ROTBASE_INHERIT
00356 Rotation_1( TMatrix matrix, const Block &block )
00357 : RotBase<T,I>( matrix, block.xend-1, block.y0 ) {}
00358
00359 void outerStep() { ++lastStart; }
00360 void innerStep() { current.start-= current.colSkip; }
00361 };
00362
00364 template<class T,class I> struct Rotation_2_T: public RotBase<T,I> { ROTBASE_INHERIT
00365 Rotation_2_T( TMatrix matrix, const Block &block )
00366 : RotBase<T,I>( matrix, block.xend-1, block.yend-1 ) {}
00367
00368 void outerStep() { --lastStart; }
00369 void innerStep() { current.start-= current.colSkip; }
00370 };
00371
00373 template<class T,class I> struct Rotation_3: public RotBase<T,I> { ROTBASE_INHERIT
00374 Rotation_3( TMatrix matrix, const Block &block )
00375 : RotBase<T,I>( matrix, block.x0, block.yend-1 ) {}
00376
00377 void outerStep() { --lastStart; }
00378 void innerStep() { current.start+= current.colSkip; }
00379 };
00380
00381
00384 template<class Check,class U,class Operator>
00385 inline Operator walkOperateCheckRotate( Check checked, Operator oper
00386 , MatrixSlice<U> pixels2, const Block &block2, char rotation) {
00387 typedef PtrInt I;
00388 switch (rotation) {
00389 case 0: return walkOperate( checked, Rotation_0 <U,I>(pixels2,block2) , oper );
00390 case 1: return walkOperate( checked, Rotation_0_T<U,I>(pixels2,block2) , oper );
00391 case 2: return walkOperate( checked, Rotation_1 <U,I>(pixels2,block2) , oper );
00392 case 3: return walkOperate( checked, Rotation_1_T<U,I>(pixels2,block2) , oper );
00393 case 4: return walkOperate( checked, Rotation_2 <U,I>(pixels2,block2) , oper );
00394 case 5: return walkOperate( checked, Rotation_2_T<U,I>(pixels2,block2) , oper );
00395 case 6: return walkOperate( checked, Rotation_3 <U,I>(pixels2,block2) , oper );
00396 case 7: return walkOperate( checked, Rotation_3_T<U,I>(pixels2,block2) , oper );
00397 default: ASSERT(false); return oper;
00398 }
00399 }
00400
00401
00403 struct Rotation {
00405 static void check(int DEBUG_ONLY(r)) {
00406 ASSERT( 0<=r && r<8 );
00407 }
00409 static int invert(int r) {
00410 check(r);
00411 return (4-r/2)%4 *2 +r%2;
00412 }
00414 static int compose(int r1,int r2) {
00415 check(r1); check(r2);
00416 if (r2%2)
00417 r1= invert(r1);
00418 return (r1/2 + r2/2) %4 *2+ ( (r1%2)^(r2%2) );
00419 }
00420 };
00421
00423 template<class T,class I=PtrInt> struct Checked: public Rotation_0<T,I> {
00424 typedef MatrixSlice<T,I> TMatrix;
00425 typedef Rotation_0<T,I> Base;
00426 using Base::current;
00427 using Base::lastStart;
00428
00429 T *colEnd
00430 , *colsEndStart;
00431
00433 Checked( TMatrix pixels, const Block &block )
00434 : Base( pixels, block ), colEnd( pixels.start+pixels.colSkip*block.x0+block.yend )
00435 , colsEndStart( pixels.start+pixels.colSkip*block.xend+block.y0 ) {
00436 ASSERT( block.xend>block.x0 && block.yend>block.y0 );
00437 }
00438
00439 bool outerCond() {
00440 ASSERT(lastStart<=colsEndStart);
00441 return lastStart!=colsEndStart;
00442 }
00443 void outerStep() {
00444 colEnd+= current.colSkip;
00445 Base::outerStep();
00446 }
00447 bool innerCond() {
00448 ASSERT(current.start<=colEnd);
00449 return current.start!=colEnd;
00450 }
00451 };
00452
00454 template<class T,class U> struct CheckedImage {
00455 typedef T QImage;
00456 typedef U QRgb;
00457 protected:
00458 QImage &img;
00459 int lineIndex
00460 , width
00461 , height;
00462 QRgb *line
00463 , *lineEnd;
00464
00465 public:
00467 CheckedImage(QImage &image)
00468 : img(image), lineIndex(0), width(image.width()), height(image.height())
00469 { DEBUG_ONLY(line=lineEnd=0;) }
00470
00471 bool outerCond() { return lineIndex<height; }
00472 void outerStep() { ++lineIndex; }
00473
00474 void innerInit() { line= (QRgb*)img.scanLine(lineIndex); lineEnd= line+width; }
00475 bool innerCond() { return line!=lineEnd; }
00476 void innerStep() { ++line; }
00477
00478 QRgb& get() { return *line; }
00479 };
00480
00481
00483 struct OperatorBase {
00484 void innerEnd() {}
00485 };
00486
00488 template<class TOut,class TIn> struct RDSummer: public OperatorBase {
00489 TOut totalSum, lineSum;
00490
00491 RDSummer()
00492 : totalSum(0), lineSum(0) {}
00493 void operator()(const TIn &num1,const TIn& num2)
00494 { lineSum+= TOut(num1) * TOut(num2); }
00495 void innerEnd()
00496 { totalSum+= lineSum; lineSum= 0; }
00497 TOut result()
00498 { ASSERT(!lineSum); return totalSum; }
00499 };
00500
00502 template<class T> struct AddMulCopy: public OperatorBase {
00503 const T toAdd, toMul;
00504
00505 AddMulCopy(T add,T mul)
00506 : toAdd(add), toMul(mul) {}
00507
00508 template<class R1,class R2> void operator()(R1 &res,R2 f) const
00509 { res= (f+toAdd)*toMul; }
00510 };
00511
00514 template<class T> struct MulAddCopyChecked: public OperatorBase {
00515 const T toMul, toAdd, min, max;
00516
00517 MulAddCopyChecked(T mul,T add,T minVal,T maxVal)
00518 : toMul(mul), toAdd(add), min(minVal), max(maxVal) {}
00519
00520 template<class R1,class R2> void operator()(R1 &res,R2 f) const
00521 { res= checkBoundsFunc( min, f*toMul+toAdd, max ); }
00522 };
00523 }
00524
00525 #endif // MATRIXUTIL_HEADER_