Writing - added references to source files.
[fic.git] / matrixUtil.h
blob16dd825ad71e0f607c0ee15a411cbc855a9dec63
1 #ifndef MATRIXUTIL_HEADER_
2 #define MATRIXUTIL_HEADER_
4 /** A simple structure representing a rectangle */
5 struct Block {
6 short x0, y0, xend, yend;
8 int width() const { return xend-x0; }
9 int height() const { return yend-y0; }
10 int size() const { return width()*height(); }
12 bool contains(short x,short y) const
13 { return x0<=x && x<xend && y0<=y && y<yend; }
15 Block() {}
16 Block(short x0_,short y0_,short xend_,short yend_)
17 : x0(x0_), y0(y0_), xend(xend_), yend(yend_) {}
20 //// Matrix templates
22 /** A simple generic template for matrices of fixed size, uses shallow copying
23 * and manual memory management */
24 template<class T,class I=PtrInt> struct MatrixSlice {
25 typedef MatrixSlice<const T,I> Const; ///< the class is convertible to Const type
27 T *start; ///< pointer to the top-left pixel
28 I colSkip; ///< how many pixels to skip to get in the next column
30 /** Initializes an empty slice */
31 MatrixSlice(): start(0) {}
33 /** Creates an instance with pre-filled member fields */
34 static MatrixSlice makeRaw(T *start,I colSkip) {
35 MatrixSlice result;
36 result.start= start;
37 result.colSkip= colSkip;
38 return result;
41 /** Converts to a matrix of constant objects (shallow copy) */
42 operator Const() const {
43 Const result;
44 result.start= start;
45 result.colSkip= colSkip;
46 return result;
49 /** Indexing operator - returns pointer to a column */
50 T* operator[](I column) {
51 ASSERT( isValid() );
52 return start+column*colSkip;
54 /** Const version of indexing operator - doesn't allow to change the elements */
55 const T* operator[](I column) const {
56 return constCast(*this)[column];
59 /** Reallocates the matrix for a new size. If \p memory parameter is given,
60 * it is used for storage (the user is responsible that the matrix fits in it, etc.) */
61 void allocate( I width, I height, T *memory=0 ) {
62 ASSERT( width>0 && height>0 );
63 free();
64 start= memory ? memory : new T[width*height];
65 colSkip= height;
67 /** Releases the memory */
68 void free() {
69 delete[] start;
70 start= 0;
72 /** Returns whether the matrix is allocated (and thus usable for indexing) */
73 bool isValid() const {
74 return start;
77 /** Fills a submatrix of a valid matrix with a value */
78 void fillSubMatrix(const Block &block,T value) {
79 ASSERT( isValid() );
80 // compute begin and end column starts
81 T *begin= start+block.y0+colSkip*block.x0
82 , *end= start+block.y0+colSkip*block.xend;
83 // fill the columns
84 for (T *it= begin; it!=end; it+= colSkip)
85 std::fill( it, it+block.height(), value );
87 /** Shifts the indexing of this matrix - dangerous.
88 * After calling this, only addressing or more shifts can be done (not checked).
89 * Also shifts out of the allocated matrix aren't detected */
90 MatrixSlice& shiftMatrix(I x0,I y0) {
91 ASSERT( isValid() );
92 start+= x0*colSkip+y0;
93 return *this;
95 /** Computes relative position of a pointer in the matrix (always 0 <= \p y < #colSkip) */
96 void getPosition(const T *elem,int &x,int &y) const {
97 ASSERT( isValid() );
98 PtrInt diff= elem-start;
99 if (diff>=0) {
100 x= diff/colSkip;
101 y= diff%colSkip;
102 } else {
103 x= -((-diff-1)/colSkip) -1;
104 y= colSkip - (-diff-1)%colSkip -1;
107 }; // MatrixSlice class template
110 /** MatrixSummer objects store partial sums of a matrix, allowing quick computation
111 * of sum of any rectangle in the matrix. It's parametrized by "type of the result",
112 * "type of the input" and "indexing type" (defaults to Int). Uses shallow copying. */
113 template<class T,class I=PtrInt> struct MatrixSummer {
114 typedef T Result;
116 MatrixSlice<T,I> sums; ///< Internal matrix containing precomputed partial sums
118 /** Returns whether the object is filled with data */
119 bool isValid() const { return sums.isValid(); }
120 /** Clears the object */
121 void free() { sums.free(); };
123 /** Computes the sum of a rectangle (in constant time) */
124 Result getSum(I x0,I y0,I xend,I yend) const {
125 ASSERT( sums.isValid() );
126 return sums[xend][yend] -(sums[x0][yend]+sums[xend][y0]) +sums[x0][y0];
128 /** A shortcut to get the sum of a block */
129 Result getSum(const Block &b) const
130 { return getSum( b.x0, b.y0, b.xend, b.yend ); }
132 /** Prepares object to make sums for a matrix. If the summer has already been
133 * used before, the method assumes it was for a matrix of the same size */
134 template<class Input> void fill(Input inp,I width,I height) {
135 if ( !sums.isValid() )
136 sums.allocate(width+1,height+1);
138 // fill the edges with zeroes
139 for (I i=0; i<=width; ++i)
140 sums[i][0]= 0;
141 for (I j=1; j<=height; ++j)
142 sums[0][j]= 0;
143 // acummulate in the y-growing direction
144 for (I i=1; i<=width; ++i)
145 for (I j=1; j<=height; ++j)
146 sums[i][j]= sums[i][j-1] + Result(inp[i-1][j-1]);
147 // acummulate in the x-growing direction
148 for (I i=2; i<=width; ++i)
149 for (I j=1; j<=height; ++j)
150 sums[i][j]+= sums[i-1][j];
152 }; // MatrixSummer class template
154 /** Helper structure for computing with value and squared sums at once */
155 template<class Num> struct DoubleNum {
156 Num value, square;
158 DoubleNum()
159 { DEBUG_ONLY( value= square= std::numeric_limits<Num>::quiet_NaN(); ) }
161 DoubleNum(Num val)
162 : value(val), square(sqr(val)) {}
164 DoubleNum(const DoubleNum &other)
165 : value(other.value), square(other.square) {}
167 void unpack(Num &val,Num &sq) const { val= value; sq= square; }
169 DoubleNum& operator+=(const DoubleNum &other) {
170 value+= other.value;
171 square+= other.square;
172 return *this;
174 DoubleNum& operator-=(const DoubleNum &other) {
175 value-= other.value;
176 square-= other.square;
177 return *this;
179 friend DoubleNum operator+(const DoubleNum &a,const DoubleNum &b)
180 { return DoubleNum(a)+= b; }
181 friend DoubleNum operator-(const DoubleNum &a,const DoubleNum &b)
182 { return DoubleNum(a)-= b; }
183 }; // DoubleNum template struct
186 /** Structure for a block of pixels - also contains summers and dimensions */
187 template< class SumT, class PixT, class I=PtrInt >
188 struct SummedMatrix {
189 typedef DoubleNum<SumT> BSumRes;
190 typedef MatrixSummer<BSumRes,I> BSummer;
192 I width /// The width of ::pixels
193 , height; ///< The height of ::pixels
194 MatrixSlice<PixT> pixels; ///< The matrix of pixels
195 BSummer summer; ///< Summer for values and squares of ::pixels
196 bool sumsValid; ///< Indicates whether the summer values are valid
198 /** Sets the size of ::pixels, optionally allocates memory */
199 void setSize( I width_, I height_ ) {
200 free();
201 width= width_;
202 height= height_;
203 pixels.allocate(width,height);
205 /** Frees the memory */
206 void free(bool freePixels=true) {
207 if (freePixels)
208 pixels.free();
209 else
210 pixels.start= 0;
211 summer.free();
212 sumsValid= false;
215 /** Just validates both summers (if needed) */
216 void summers_makeValid() const {
217 ASSERT(pixels.isValid());
218 if (!sumsValid) {
219 constCast(summer).fill(pixels,width,height);
220 constCast(sumsValid)= true;
223 /** Justs invalidates both summers (to be called after changes in the pixel-matrix) */
224 void summers_invalidate()
225 { sumsValid= false; }
226 /** A shortcut for getting sums of a block */
227 BSumRes getSums(const Block &block) const
228 { return getSums( block.x0, block.y0, block.xend, block.yend ); }
229 /** Gets both sums of a nonempty rectangle in ::pixels, the summer isn't validated */
230 BSumRes getSums( I x0, I y0, I xend, I yend ) const {
231 ASSERT( sumsValid && x0>=0 && y0>=0 && xend>x0 && yend>y0
232 && xend<=width && yend<=height );
233 return summer.getSum(x0,y0,xend,yend);
235 /** Gets only the sum of values (not the sum of squares) */
236 SumT getValueSum( I x0, I y0, I xend, I yend ) const {
237 /// \todo quicker version
238 return getSums(x0,y0,xend,yend).value;
240 }; // SummedPixels template struct
244 /** Contains various iterators for matrices (see Matrix)
245 * to be used in walkOperate() and walkOperateCheckRotate() */
246 namespace MatrixWalkers {
248 /** Iterates two matrix iterators and performs an action.
249 * The loop is controled by the first iterator (\p checked)
250 * and on every corresponding pair (a,b) \p oper(a,b) is invoked. Returns \p oper. */
251 template < class Checked, class Unchecked, class Operator >
252 Operator walkOperate( Checked checked, Unchecked unchecked, Operator oper ) {
253 // outer cycle start - to be always run at least once
254 ASSERT( checked.outerCond() );
255 do {
256 // inner initialization
257 checked.innerInit();
258 unchecked.innerInit();
259 // inner cycle start - to be always run at least once
260 ASSERT( checked.innerCond() );
261 do {
262 // perform the operation and do the inner step for both iterators
263 oper( checked.get(), unchecked.get() );
264 checked.innerStep();
265 unchecked.innerStep();
266 } while ( checked.innerCond() );
268 // signal the end of inner cycle to the operator and do the outer step for both iterators
269 oper.innerEnd();
270 checked.outerStep();
271 unchecked.outerStep();
273 } while ( checked.outerCond() );
275 return oper;
279 /** Base structure for walkers */
280 template<class T,class I> struct RotBase {
281 public:
282 typedef MatrixSlice<T,I> TMatrix;
283 protected:
284 TMatrix current; ///< matrix starting on the current element
285 T *lastStart; ///< the place of the last enter of the inner loop
287 public:
288 RotBase( TMatrix matrix, int x0, int y0 )
289 : current( matrix.shiftMatrix(x0,y0) ), lastStart(current.start) {
290 DEBUG_ONLY( current.start= 0; )
291 ASSERT( matrix.isValid() );
294 void innerInit() { current.start= lastStart; }
295 T& get() { return *current.start; }
296 }; // RotBase class template
298 #define ROTBASE_INHERIT \
299 typedef typename RotBase<T,I>::TMatrix TMatrix; \
300 using RotBase<T,I>::current; \
301 using RotBase<T,I>::lastStart;
303 /** No rotation: x->, y-> */
304 template<class T,class I=PtrInt> struct Rotation_0: public RotBase<T,I> { ROTBASE_INHERIT
305 Rotation_0( TMatrix matrix, const Block &block )
306 : RotBase<T,I>( matrix, block.x0, block.y0 ) {}
308 explicit Rotation_0( TMatrix matrix, I x0=0, I y0=0 )
309 : RotBase<T,I>( matrix, x0, y0 ) {}
311 void outerStep() { lastStart+= current.colSkip; }
312 void innerStep() { ++current.start; }
315 /** Rotated 90deg\. cw\., transposed: x<-, y-> */
316 template<class T,class I> struct Rotation_1_T: public RotBase<T,I> { ROTBASE_INHERIT
317 Rotation_1_T( TMatrix matrix, const Block &block )
318 : RotBase<T,I>( matrix, block.xend-1, block.y0 ) {}
320 void outerStep() { lastStart-= current.colSkip; }
321 void innerStep() { ++current.start; }
324 /** Rotated 180deg\. cw\.: x<-, y<- */
325 template<class T,class I> struct Rotation_2: public RotBase<T,I> { ROTBASE_INHERIT
326 Rotation_2( TMatrix matrix, const Block &block )
327 : RotBase<T,I>( matrix, block.xend-1, block.yend-1 ) {}
329 void outerStep() { lastStart-= current.colSkip; }
330 void innerStep() { --current.start; }
333 /** Rotated 270deg\. cw\., transposed: x->, y<- */
334 template<class T,class I> struct Rotation_3_T: public RotBase<T,I> { ROTBASE_INHERIT
335 Rotation_3_T( TMatrix matrix, const Block &block )
336 : RotBase<T,I>( matrix, block.x0, block.yend-1 ) {}
338 void outerStep() { lastStart+= current.colSkip; }
339 void innerStep() { --current.start; }
342 /** No rotation, transposed: y->, x-> */
343 template<class T,class I> struct Rotation_0_T: public RotBase<T,I> { ROTBASE_INHERIT
344 Rotation_0_T( TMatrix matrix, const Block &block )
345 : RotBase<T,I>( matrix, block.x0, block.y0 ) {}
347 explicit Rotation_0_T( TMatrix matrix, I x0=0, I y0=0 )
348 : RotBase<T,I>( matrix, x0, y0 ) {}
350 void outerStep() { ++lastStart; }
351 void innerStep() { current.start+= current.colSkip; }
354 /** Rotated 90deg\. cw\.: y->, x<- */
355 template<class T,class I> struct Rotation_1: public RotBase<T,I> { ROTBASE_INHERIT
356 Rotation_1( TMatrix matrix, const Block &block )
357 : RotBase<T,I>( matrix, block.xend-1, block.y0 ) {}
359 void outerStep() { ++lastStart; }
360 void innerStep() { current.start-= current.colSkip; }
363 /** Rotated 180deg\. cw\., transposed: y<-, x<- */
364 template<class T,class I> struct Rotation_2_T: public RotBase<T,I> { ROTBASE_INHERIT
365 Rotation_2_T( TMatrix matrix, const Block &block )
366 : RotBase<T,I>( matrix, block.xend-1, block.yend-1 ) {}
368 void outerStep() { --lastStart; }
369 void innerStep() { current.start-= current.colSkip; }
372 /** Rotated 270deg\. cw\.: y<-, x-> */
373 template<class T,class I> struct Rotation_3: public RotBase<T,I> { ROTBASE_INHERIT
374 Rotation_3( TMatrix matrix, const Block &block )
375 : RotBase<T,I>( matrix, block.x0, block.yend-1 ) {}
377 void outerStep() { --lastStart; }
378 void innerStep() { current.start+= current.colSkip; }
382 /** A flavour of walkOperate() choosing the right Rotation_* iterator
383 * based on \p rotation and constructing it from \p pixels2 and \p block2 */
384 template<class Check,class U,class Operator>
385 inline Operator walkOperateCheckRotate( Check checked, Operator oper
386 , MatrixSlice<U> pixels2, const Block &block2, char rotation) {
387 typedef PtrInt I;
388 switch (rotation) {
389 case 0: return walkOperate( checked, Rotation_0 <U,I>(pixels2,block2) , oper );
390 case 1: return walkOperate( checked, Rotation_0_T<U,I>(pixels2,block2) , oper );
391 case 2: return walkOperate( checked, Rotation_1 <U,I>(pixels2,block2) , oper );
392 case 3: return walkOperate( checked, Rotation_1_T<U,I>(pixels2,block2) , oper );
393 case 4: return walkOperate( checked, Rotation_2 <U,I>(pixels2,block2) , oper );
394 case 5: return walkOperate( checked, Rotation_2_T<U,I>(pixels2,block2) , oper );
395 case 6: return walkOperate( checked, Rotation_3 <U,I>(pixels2,block2) , oper );
396 case 7: return walkOperate( checked, Rotation_3_T<U,I>(pixels2,block2) , oper );
397 default: ASSERT(false); return oper;
402 /** Performs manipulations with rotation codes 0-7 (dihedral group of order eight) */
403 struct Rotation {
404 /** Asserts the parameter is within 0-7 */
405 static void check(int DEBUG_ONLY(r)) {
406 ASSERT( 0<=r && r<8 );
408 /** Returns inverted rotation (the one that takes this one back to identity) */
409 static int invert(int r) {
410 check(r);
411 return (4-r/2)%4 *2 +r%2;
413 /** Computes rotation equal to projecting at first with \p r1 and the result with \p r2 */
414 static int compose(int r1,int r2) {
415 check(r1); check(r2);
416 if (r2%2)
417 r1= invert(r1);
418 return (r1/2 + r2/2) %4 *2+ ( (r1%2)^(r2%2) );
420 }; // Rotation struct
422 /** Checked_ iterator for a rectangle in a matrix, no rotation */
423 template<class T,class I=PtrInt> struct Checked: public Rotation_0<T,I> {
424 typedef MatrixSlice<T,I> TMatrix;
425 typedef Rotation_0<T,I> Base;
426 using Base::current;
427 using Base::lastStart;
429 T *colEnd /// the end of the current column
430 , *colsEndStart; ///< the start of the end column
432 /** Initializes a new iterator for a \p block of \p pixels */
433 Checked( TMatrix pixels, const Block &block )
434 : Base( pixels, block ), colEnd( pixels.start+pixels.colSkip*block.x0+block.yend )
435 , colsEndStart( pixels.start+pixels.colSkip*block.xend+block.y0 ) {
436 ASSERT( block.xend>block.x0 && block.yend>block.y0 );
439 bool outerCond() {
440 ASSERT(lastStart<=colsEndStart);
441 return lastStart!=colsEndStart;
443 void outerStep() {
444 colEnd+= current.colSkip;
445 Base::outerStep();
447 bool innerCond() {
448 ASSERT(current.start<=colEnd);
449 return current.start!=colEnd;
451 }; // Checked class template
453 /** Checked_ iterator for a whole QImage; no rotation, but always transposed */
454 template<class T,class U> struct CheckedImage {
455 typedef T QImage;
456 typedef U QRgb;
457 protected:
458 QImage &img; ///< reference to the image
459 int lineIndex /// index of the current line
460 , width /// the width of the image
461 , height; ///< the height of the image
462 QRgb *line /// pointer to the current pixel
463 , *lineEnd; ///< pointer to the end of the line
465 public:
466 /** Initializes a new iterator for an instance of QImage (Qt class) */
467 CheckedImage(QImage &image)
468 : img(image), lineIndex(0), width(image.width()), height(image.height())
469 { DEBUG_ONLY(line=lineEnd=0;) }
471 bool outerCond() { return lineIndex<height; }
472 void outerStep() { ++lineIndex; }
474 void innerInit() { line= (QRgb*)img.scanLine(lineIndex); lineEnd= line+width; }
475 bool innerCond() { return line!=lineEnd; }
476 void innerStep() { ++line; }
478 QRgb& get() { return *line; }
479 }; // CheckedImage class template
482 /** A convenience base type for operators to use with walkOperate() */
483 struct OperatorBase {
484 void innerEnd() {}
487 /** An operator computing the sum of products */
488 template<class TOut,class TIn> struct RDSummer: public OperatorBase {
489 TOut totalSum, lineSum;
491 RDSummer()
492 : totalSum(0), lineSum(0) {}
493 void operator()(const TIn &num1,const TIn& num2)
494 { lineSum+= TOut(num1) * TOut(num2); }
495 void innerEnd()
496 { totalSum+= lineSum; lineSum= 0; }
497 TOut result() ///< returns the result
498 { ASSERT(!lineSum); return totalSum; }
501 /** An operator performing a= (b+::toAdd)*::toMul */
502 template<class T> struct AddMulCopy: public OperatorBase {
503 const T toAdd, toMul;
505 AddMulCopy(T add,T mul)
506 : toAdd(add), toMul(mul) {}
508 template<class R1,class R2> void operator()(R1 &res,R2 f) const
509 { res= (f+toAdd)*toMul; }
512 /** An operator performing a= b*::toMul+::toAdd
513 * and moving the result into [::min,::max] bounds */
514 template<class T> struct MulAddCopyChecked: public OperatorBase {
515 const T toMul, toAdd, min, max;
517 MulAddCopyChecked(T mul,T add,T minVal,T maxVal)
518 : toMul(mul), toAdd(add), min(minVal), max(maxVal) {}
520 template<class R1,class R2> void operator()(R1 &res,R2 f) const
521 { res= checkBoundsFunc( min, f*toMul+toAdd, max ); }
523 } // MatrixWalkers namespace
525 #endif // MATRIXUTIL_HEADER_