Subversion Repositories gelsvn

Rev

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