Subversion Repositories gelsvn

Rev

Rev 45 | Rev 89 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 bj 1
#ifndef __CGLA_ARITHMATFLOAT_H__
2
#define __CGLA_ARITHMATFLOAT_H__
3
 
4
#include <vector>
5
#include <iostream>
6
 
7
#include "CGLA.h"
8
 
9
 
12 jab 10
namespace CGLA 
11
{
2 bj 12
 
12 jab 13
  /** Basic class template for matrices.
2 bj 14
 
12 jab 15
  In this template a matrix is defined as an array of vectors. This may
16
  not in all cases be the most efficient but it has the advantage that 
17
  it is possible to use the double subscripting notation:
2 bj 18
 
12 jab 19
  T x = m[i][j]
2 bj 20
 
12 jab 21
  This template should be used through inheritance just like the 
22
  vector template */
45 jab 23
  template <class VVT, class HVT, class MT, unsigned int ROWS>
12 jab 24
    class ArithMatFloat
25
    { 
26
    public:
2 bj 27
 
12 jab 28
      /// Horizontal vector type
29
      typedef HVT HVectorType;
2 bj 30
 
12 jab 31
      /// Vertical vector type
32
      typedef VVT VVectorType;
2 bj 33
 
12 jab 34
      /// The type of a matrix element
35
      typedef typename HVT::ScalarType ScalarType;
2 bj 36
 
12 jab 37
    protected:
2 bj 38
 
12 jab 39
      /// The actual contents of the matrix.
40
      HVT data[ROWS];
2 bj 41
 
12 jab 42
    protected:
2 bj 43
 
12 jab 44
      /// Construct 0 matrix
45
      ArithMatFloat() 
46
	{
10 jab 47
#ifndef NDEBUG
43 jrf 48
	  std::fill_n(data, ROWS, HVT(CGLA_INIT_VALUE));
10 jab 49
#endif
12 jab 50
	}
2 bj 51
 
12 jab 52
      /// Construct a matrix where all entries are the same.
53
      explicit ArithMatFloat(ScalarType x)
54
	{
43 jrf 55
	  std::fill_n(data, ROWS, HVT(x));
12 jab 56
	}
2 bj 57
 
12 jab 58
      /// Construct a matrix where all rows are the same.
59
      explicit ArithMatFloat(HVT _a)
60
	{
43 jrf 61
	  std::fill_n(data, ROWS, _a);
12 jab 62
	}
2 bj 63
 
12 jab 64
      /// Construct a matrix with two rows.
65
      ArithMatFloat(HVT _a, HVT _b)
66
	{
67
	  assert(ROWS==2);
68
	  data[0] = _a;
69
	  data[1] = _b;
70
	}
2 bj 71
 
12 jab 72
      /// Construct a matrix with three rows.
73
      ArithMatFloat(HVT _a, HVT _b, HVT _c)
74
	{
75
	  assert(ROWS==3);
76
	  data[0] = _a;
77
	  data[1] = _b;
78
	  data[2] = _c;
79
	}
2 bj 80
 
12 jab 81
      /// Construct a matrix with four rows.
82
      ArithMatFloat(HVT _a, HVT _b, HVT _c, HVT _d)
83
	{
84
	  assert(ROWS==4);
85
	  data[0] = _a;
86
	  data[1] = _b;
87
	  data[2] = _c;
88
	  data[3] = _d;
89
	}
2 bj 90
 
12 jab 91
    public:
2 bj 92
 
12 jab 93
      /// Get vertical dimension of matrix 
45 jab 94
      static unsigned int get_v_dim() {return VVT::get_dim();}
2 bj 95
 
12 jab 96
      /// Get horizontal dimension of matrix
45 jab 97
      static unsigned int get_h_dim() {return HVT::get_dim();}
2 bj 98
 
99
 
12 jab 100
      /** Get const pointer to data array.
101
	  This function may be useful when interfacing with some other API 
102
	  such as OpenGL (TM). */
103
      const ScalarType* get() const 
104
	{
105
	  return data[0].get();
106
	}
2 bj 107
 
12 jab 108
      /** Get pointer to data array.
109
	  This function may be useful when interfacing with some other API 
110
	  such as OpenGL (TM). */
111
      ScalarType* get()
112
	{
113
	  return data[0].get();
114
	}
2 bj 115
 
12 jab 116
      //----------------------------------------------------------------------
117
      // index operators
118
      //----------------------------------------------------------------------
2 bj 119
 
12 jab 120
      /// Const index operator. Returns i'th row of matrix.
45 jab 121
      const HVT& operator [] ( unsigned int i ) const
12 jab 122
	{
123
	  assert(i<ROWS);
124
	  return data[i];
125
	}
2 bj 126
 
12 jab 127
      /// Non-const index operator. Returns i'th row of matrix.
45 jab 128
      HVT& operator [] ( unsigned int i ) 
12 jab 129
	{
130
	  assert(i<ROWS);
131
	  return data[i];
132
	}
2 bj 133
 
12 jab 134
      //----------------------------------------------------------------------
2 bj 135
 
12 jab 136
      /// Equality operator. 
137
      bool operator==(const MT& v) const 
138
	{
43 jrf 139
	  return std::inner_product(data, &data[ROWS], &v[0], true,
140
				    std::logical_and<bool>(), std::equal_to<HVT>());
12 jab 141
	}
2 bj 142
 
12 jab 143
      /// Inequality operator.
144
      bool operator!=(const MT& v) const 
145
	{
146
	  return !(*this==v);
147
	}
2 bj 148
 
12 jab 149
      //----------------------------------------------------------------------
2 bj 150
 
12 jab 151
      /// Multiply scalar onto matrix. All entries are multiplied by scalar.
152
      const MT operator * (ScalarType k) const
153
	{
154
	  MT v_new;
43 jrf 155
	  std::transform(data, &data[ROWS], &v_new[0], std::bind2nd(std::multiplies<HVT>(), k));
12 jab 156
	  return v_new;
157
	}
2 bj 158
 
12 jab 159
      /// Divide all entries in matrix by scalar.
160
      const MT operator / (ScalarType k) const
161
	{
162
	  MT v_new;
43 jrf 163
	  std::transform(data, &data[ROWS], &v_new[0], std::bind2nd(std::divides<HVT>(), k));
12 jab 164
	  return v_new;      
165
	}
2 bj 166
 
12 jab 167
      /// Assignment multiplication of matrix by scalar.
168
      const MT& operator *=(ScalarType k) 
169
	{
43 jrf 170
	  std::transform(data, &data[ROWS], data, std::bind2nd(std::multiplies<HVT>(), k));
12 jab 171
	  return static_cast<const MT&>(*this);
172
	}
2 bj 173
 
12 jab 174
      /// Assignment division of matrix by scalar.
175
      const MT& operator /=(ScalarType k) 
176
	{ 
43 jrf 177
	  std::transform(data, &data[ROWS], data, std::bind2nd(std::divides<HVT>(), k));
12 jab 178
	  return static_cast<const MT&>(*this);
179
	}
2 bj 180
 
12 jab 181
      //----------------------------------------------------------------------
2 bj 182
 
12 jab 183
      /// Add two matrices. 
184
      const MT operator + (const MT& m1) const
185
	{
186
	  MT v_new;
43 jrf 187
	  std::transform(data, &data[ROWS], &m1[0], &v_new[0], std::plus<HVT>());
12 jab 188
	  return v_new;
189
	}
2 bj 190
 
12 jab 191
      /// Subtract two matrices.
192
      const MT operator - (const MT& m1) const
2 bj 193
	{
12 jab 194
	  MT v_new;
43 jrf 195
	  std::transform(data, &data[ROWS], &m1[0], &v_new[0], std::minus<HVT>());
12 jab 196
	  return v_new;
2 bj 197
	}
198
 
12 jab 199
      /// Assigment addition of matrices.
200
      const MT& operator +=(const MT& v) 
2 bj 201
	{
43 jrf 202
	  std::transform(data, &data[ROWS], &v[0], data, std::plus<HVT>());
12 jab 203
	  return static_cast<const MT&>(*this);
2 bj 204
	}
205
 
12 jab 206
      /// Assigment subtraction of matrices.
207
      const MT& operator -=(const MT& v) 
2 bj 208
	{
43 jrf 209
	  std::transform(data, &data[ROWS], &v[0], data, std::minus<HVT>());
12 jab 210
	  return static_cast<const MT&>(*this);
2 bj 211
	}
212
 
12 jab 213
      //----------------------------------------------------------------------
214
 
215
      /// Negate matrix.
216
      const MT operator - () const
2 bj 217
	{
12 jab 218
	  MT v_new;
43 jrf 219
	  std::transform(data, &data[ROWS], &v_new[0], std::negate<HVT>());
12 jab 220
	  return v_new;
2 bj 221
	}
12 jab 222
    };
2 bj 223
 
12 jab 224
  /// Multiply scalar onto matrix
45 jab 225
  template <class VVT, class HVT, class MT, unsigned int ROWS>
12 jab 226
    inline const MT operator * (double k, const ArithMatFloat<VVT,HVT,MT,ROWS>& v) 
227
    {
228
      return v * k;
229
    }
230
 
231
  /// Multiply scalar onto matrix
45 jab 232
  template <class VVT, class HVT, class MT, unsigned int ROWS>
12 jab 233
    inline const MT operator * (float k, const ArithMatFloat<VVT,HVT,MT,ROWS>& v) 
234
    {
235
      return v * k;
236
    }
237
 
238
  /// Multiply scalar onto matrix
45 jab 239
  template <class VVT, class HVT, class MT, unsigned int ROWS>
12 jab 240
    inline const MT operator * (int k, const ArithMatFloat<VVT,HVT,MT,ROWS>& v) 
241
    {
242
      return v * k;
243
    }
244
 
245
  /// Multiply vector onto matrix 
45 jab 246
  template <class VVT, class HVT, class MT, unsigned int ROWS>
12 jab 247
    inline VVT operator*(const ArithMatFloat<VVT,HVT,MT,ROWS>& m,const HVT& v) 
248
    {
249
      VVT v2;
45 jab 250
      for(unsigned int i=0;i<ROWS;i++) v2[i] = dot(m[i], v);
12 jab 251
      return v2;
252
    }
253
 
254
 
2 bj 255
#ifndef WIN32
12 jab 256
  /** Multiply two arbitrary matrices. 
257
      In principle, this function could return a matrix, but in general
258
      the new matrix will be of a type that is different from either of
259
      the two matrices that are multiplied together. We do not want to 
260
      return an ArithMatFloat - so it seems best to let the return value be
261
      a reference arg.
2 bj 262
 
12 jab 263
      This template can only be instantiated if the dimensions of the
264
      matrices match -- i.e. if the multiplication can actually be
265
      carried out. This is more type safe than the win32 version below.
266
  */
2 bj 267
 
12 jab 268
  template <class VVT, class HVT, 
269
    class HV1T, class VV2T,
270
    class MT1, class MT2, class MT,
45 jab 271
    unsigned int ROWS1, unsigned int ROWS2>
12 jab 272
    inline void mul(const ArithMatFloat<VVT,HV1T,MT1,ROWS1>& m1,
273
		    const ArithMatFloat<VV2T,HVT,MT2,ROWS2>& m2,
274
		    ArithMatFloat<VVT,HVT,MT,ROWS1>& m)
275
    {
45 jab 276
      unsigned int cols = ArithMatFloat<VVT,HVT,MT,ROWS1>::get_h_dim();
277
      for(unsigned int i=0;i<ROWS1;i++)
278
	for(unsigned int j=0;j<cols;j++)
12 jab 279
	  {
280
	    m[i][j] = 0;
45 jab 281
	    for(unsigned int k=0;k<ROWS2;k++)
12 jab 282
	      m[i][j] += m1[i][k] * m2[k][j]; 
283
	  }
284
    }
2 bj 285
 
286
 
12 jab 287
  /** Transpose. See the discussion on mul if you are curious as to why
288
      I don't simply return the transpose. */
45 jab 289
  template <class VVT, class HVT, class M1T, class M2T, unsigned int ROWS, unsigned int COLS>
12 jab 290
    inline void transpose(const ArithMatFloat<VVT,HVT,M1T,ROWS>& m,
291
			  ArithMatFloat<HVT,VVT,M2T,COLS>& m_new)
292
    {
45 jab 293
      for(unsigned int i=0;i<M2T::get_v_dim();++i)
294
	for(unsigned int j=0;j<M2T::get_h_dim();++j)
12 jab 295
	  m_new[i][j] = m[j][i];
296
    }
2 bj 297
 
298
#else
299
 
12 jab 300
  //----------------- win32 -------------------------------
301
  // Visual studio is not good at deducing the args. to these template functions.
302
  // This means that you can call the two functions below with 
303
  // matrices of wrong dimension.
2 bj 304
 
12 jab 305
  template <class M1, class M2, class M>
306
    inline void mul(const M1& m1, const M2& m2, M& m)
307
    {
45 jab 308
      unsigned int cols = M::get_h_dim();
309
      unsigned int rows1 = M1::get_v_dim();
310
      unsigned int rows2 = M2::get_v_dim();
2 bj 311
 
45 jab 312
      for(unsigned int i=0;i<rows1;++i)
313
	for(unsigned int j=0;j<cols;++j)
12 jab 314
	  {
315
	    m[i][j] = 0;
45 jab 316
	    for(unsigned int k=0;k<rows2;++k)
12 jab 317
	      m[i][j] += m1[i][k] * m2[k][j];
318
	  }
319
    }
2 bj 320
 
321
 
12 jab 322
  /** Transpose. See the discussion on mul if you are curious as to why
323
      I don't simply return the transpose. */
324
  template <class M1, class M2>
325
    inline void transpose(const M1& m1, M2& m2)
326
    {
45 jab 327
      for(unsigned int i=0;i<M2::get_v_dim();++i)
328
	for(unsigned int j=0;j<M2::get_h_dim();++j)
12 jab 329
	  m2[i][j] = m1[j][i];
330
    }
2 bj 331
 
332
#endif
333
 
12 jab 334
  /** Compute the outer product of a and b: a * transpose(b). This is 
335
      a matrix with a::rows and b::columns. */
45 jab 336
  template <class VVT, class HVT, class MT, unsigned int ROWS>
12 jab 337
    void outer_product(const VVT& a, const HVT& b, 
338
		       ArithMatFloat<VVT,HVT,MT,ROWS>& m)
339
    {
45 jab 340
      unsigned int R = VVT::get_dim();
341
      unsigned int C = HVT::get_dim();
342
      for(unsigned int i=0;i<R;++i)
343
	for(unsigned int j=0;j<C;++j)
12 jab 344
	  {
345
	    m[i][j] = a[i] * b[j];
346
	  }
347
    }
2 bj 348
 
46 jrf 349
  /** Compute the outer product of a and b using an arbitrary 
350
      binary operation: op(a, transpose(b)). This is 
351
      a matrix with a::rows and b::columns. */
352
  template <class VVT, class HVT, class MT, int ROWS, class BinOp>
353
    void outer_product(const VVT& a, const HVT& b, 
354
		       ArithMatFloat<VVT,HVT,MT,ROWS>& m, BinOp op)
355
    {
356
      int R = VVT::get_dim();
357
      int C = HVT::get_dim();
358
      for(int i=0;i<R;++i)
359
	for(int j=0;j<C;++j)
360
	  {
361
	    m[i][j] = op(a[i], b[j]);
362
	  }
363
    }
364
 
12 jab 365
  /** Copy a matrix to another matrix, cell by cell.
366
      This conversion that takes a const matrix as first argument
367
      (source) and a non-const matrix as second argument
368
      (destination). The contents of the first matrix is simply copied
369
      to the second matrix. 
2 bj 370
 
12 jab 371
      However, if the first matrix is	larger than the second,
372
      the cells outside the range of the destination are simply not
373
      copied. If the destination is larger, the cells outside the 
374
      range of the source matrix are not touched.
2 bj 375
 
12 jab 376
      An obvious use of this function is to copy a 3x3 rotation matrix
377
      into a 4x4 transformation matrix.
378
  */
2 bj 379
 
12 jab 380
  template <class M1, class M2>
381
    void copy_matrix(const M1& inmat, M2& outmat)
382
    {
45 jab 383
      const unsigned int R = s_min(inmat.get_v_dim(), outmat.get_v_dim());
384
      const unsigned int C = s_min(inmat.get_h_dim(), outmat.get_h_dim());
385
      for(unsigned int i=0;i<R;++i)
386
	for(unsigned int j=0;j<C;++j)
12 jab 387
	  outmat[i][j] = inmat[i][j];
388
    }
2 bj 389
 
12 jab 390
  /** Put to operator */
45 jab 391
  template <class VVT, class HVT, class MT, unsigned int ROWS>
12 jab 392
    inline std::ostream& 
393
    operator<<(std::ostream&os, const ArithMatFloat<VVT,HVT,MT,ROWS>& m)
394
    {
395
      os << "[\n";
45 jab 396
      for(unsigned int i=0;i<ROWS;i++) os << "  " << m[i] << "\n";
12 jab 397
      os << "]\n";
398
      return os;
399
    }
2 bj 400
 
12 jab 401
  /** Get from operator */
45 jab 402
  template <class VVT, class HVT, class MT, unsigned int ROWS>
12 jab 403
    inline std::istream& operator>>(std::istream&is, 
404
				    const ArithMatFloat<VVT,HVT,MT,ROWS>& m)
405
    {
45 jab 406
      for(unsigned int i=0;i<ROWS;i++) is>>m[i];
12 jab 407
      return is;
408
    }
2 bj 409
}
410
#endif