source: trunk/demos/boxes/vector.h@ 168

Last change on this file since 168 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 16.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the demonstration applications of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#ifndef VECTOR_H
43#define VECTOR_H
44
45#include <cassert>
46#include <cmath>
47#include <iostream>
48
49namespace gfx
50{
51
52template<class T, int n>
53struct Vector
54{
55 // Keep the Vector struct a plain old data (POD) struct by avoiding constructors
56
57 static Vector vector(T x)
58 {
59 Vector result;
60 for (int i = 0; i < n; ++i)
61 result.v[i] = x;
62 return result;
63 }
64
65 // Use only for 2D vectors
66 static Vector vector(T x, T y)
67 {
68 assert(n == 2);
69 Vector result;
70 result.v[0] = x;
71 result.v[1] = y;
72 return result;
73 }
74
75 // Use only for 3D vectors
76 static Vector vector(T x, T y, T z)
77 {
78 assert(n == 3);
79 Vector result;
80 result.v[0] = x;
81 result.v[1] = y;
82 result.v[2] = z;
83 return result;
84 }
85
86 // Use only for 4D vectors
87 static Vector vector(T x, T y, T z, T w)
88 {
89 assert(n == 4);
90 Vector result;
91 result.v[0] = x;
92 result.v[1] = y;
93 result.v[2] = z;
94 result.v[3] = w;
95 return result;
96 }
97
98 // Pass 'n' arguments to this function.
99 static Vector vector(T *v)
100 {
101 Vector result;
102 for (int i = 0; i < n; ++i)
103 result.v[i] = v[i];
104 return result;
105 }
106
107 T &operator [] (int i) {return v[i];}
108 T operator [] (int i) const {return v[i];}
109
110#define VECTOR_BINARY_OP(op, arg, rhs) \
111 Vector operator op (arg) const \
112 { \
113 Vector result; \
114 for (int i = 0; i < n; ++i) \
115 result.v[i] = v[i] op rhs; \
116 return result; \
117 }
118
119 VECTOR_BINARY_OP(+, const Vector &u, u.v[i])
120 VECTOR_BINARY_OP(-, const Vector &u, u.v[i])
121 VECTOR_BINARY_OP(*, const Vector &u, u.v[i])
122 VECTOR_BINARY_OP(/, const Vector &u, u.v[i])
123 VECTOR_BINARY_OP(+, T s, s)
124 VECTOR_BINARY_OP(-, T s, s)
125 VECTOR_BINARY_OP(*, T s, s)
126 VECTOR_BINARY_OP(/, T s, s)
127#undef VECTOR_BINARY_OP
128
129 Vector operator - () const
130 {
131 Vector result;
132 for (int i = 0; i < n; ++i)
133 result.v[i] = -v[i];
134 return result;
135 }
136
137#define VECTOR_ASSIGN_OP(op, arg, rhs) \
138 Vector &operator op (arg) \
139 { \
140 for (int i = 0; i < n; ++i) \
141 v[i] op rhs; \
142 return *this; \
143 }
144
145 VECTOR_ASSIGN_OP(+=, const Vector &u, u.v[i])
146 VECTOR_ASSIGN_OP(-=, const Vector &u, u.v[i])
147 VECTOR_ASSIGN_OP(=, T s, s)
148 VECTOR_ASSIGN_OP(*=, T s, s)
149 VECTOR_ASSIGN_OP(/=, T s, s)
150#undef VECTOR_ASSIGN_OP
151
152 static T dot(const Vector &u, const Vector &v)
153 {
154 T sum(0);
155 for (int i = 0; i < n; ++i)
156 sum += u.v[i] * v.v[i];
157 return sum;
158 }
159
160 static Vector cross(const Vector &u, const Vector &v)
161 {
162 assert(n == 3);
163 return vector(u.v[1] * v.v[2] - u.v[2] * v.v[1],
164 u.v[2] * v.v[0] - u.v[0] * v.v[2],
165 u.v[0] * v.v[1] - u.v[1] * v.v[0]);
166 }
167
168 T sqrNorm() const
169 {
170 return dot(*this, *this);
171 }
172
173 // requires floating point type T
174 void normalize()
175 {
176 T s = sqrNorm();
177 if (s != 0)
178 *this /= sqrt(s);
179 }
180
181 // requires floating point type T
182 Vector normalized() const
183 {
184 T s = sqrNorm();
185 if (s == 0)
186 return *this;
187 return *this / sqrt(s);
188 }
189
190 T *bits() {return v;}
191 const T *bits() const {return v;}
192
193 T v[n];
194};
195
196#define SCALAR_VECTOR_BINARY_OP(op) \
197template<class T, int n> \
198Vector<T, n> operator op (T s, const Vector<T, n>& u) \
199{ \
200 Vector<T, n> result; \
201 for (int i = 0; i < n; ++i) \
202 result[i] = s op u[i]; \
203 return result; \
204}
205
206SCALAR_VECTOR_BINARY_OP(+)
207SCALAR_VECTOR_BINARY_OP(-)
208SCALAR_VECTOR_BINARY_OP(*)
209SCALAR_VECTOR_BINARY_OP(/)
210#undef SCALAR_VECTOR_BINARY_OP
211
212template<class T, int n>
213std::ostream &operator << (std::ostream &os, const Vector<T, n> &v)
214{
215 assert(n > 0);
216 os << "[" << v[0];
217 for (int i = 1; i < n; ++i)
218 os << ", " << v[i];
219 os << "]";
220 return os;
221}
222
223typedef Vector<float, 2> Vector2f;
224typedef Vector<float, 3> Vector3f;
225typedef Vector<float, 4> Vector4f;
226
227template<class T, int rows, int cols>
228struct Matrix
229{
230 // Keep the Matrix struct a plain old data (POD) struct by avoiding constructors
231
232 static Matrix matrix(T x)
233 {
234 Matrix result;
235 for (int i = 0; i < rows; ++i) {
236 for (int j = 0; j < cols; ++j)
237 result.v[i][j] = x;
238 }
239 return result;
240 }
241
242 static Matrix matrix(T *m)
243 {
244 Matrix result;
245 for (int i = 0; i < rows; ++i) {
246 for (int j = 0; j < cols; ++j) {
247 result.v[i][j] = *m;
248 ++m;
249 }
250 }
251 return result;
252 }
253
254 T &operator () (int i, int j) {return v[i][j];}
255 T operator () (int i, int j) const {return v[i][j];}
256 Vector<T, cols> &operator [] (int i) {return v[i];}
257 const Vector<T, cols> &operator [] (int i) const {return v[i];}
258
259 // TODO: operators, methods
260
261 Vector<T, rows> operator * (const Vector<T, cols> &u) const
262 {
263 Vector<T, rows> result;
264 for (int i = 0; i < rows; ++i)
265 result[i] = Vector<T, cols>::dot(v[i], u);
266 return result;
267 }
268
269 template<int k>
270 Matrix<T, rows, k> operator * (const Matrix<T, cols, k> &m)
271 {
272 Matrix<T, rows, k> result;
273 for (int i = 0; i < rows; ++i)
274 result[i] = v[i] * m;
275 return result;
276 }
277
278 T* bits() {return reinterpret_cast<T *>(this);}
279 const T* bits() const {return reinterpret_cast<const T *>(this);}
280
281 // Simple Gauss elimination.
282 // TODO: Optimize and improve stability.
283 Matrix inverse(bool *ok = 0) const
284 {
285 assert(rows == cols);
286 Matrix rhs = identity();
287 Matrix lhs(*this);
288 T temp;
289 // Down
290 for (int i = 0; i < rows; ++i) {
291 // Pivoting
292 int pivot = i;
293 for (int j = i; j < rows; ++j) {
294 if (qAbs(lhs(j, i)) > lhs(pivot, i))
295 pivot = j;
296 }
297 // TODO: fuzzy compare.
298 if (lhs(pivot, i) == T(0)) {
299 if (ok)
300 *ok = false;
301 return rhs;
302 }
303 if (pivot != i) {
304 for (int j = i; j < cols; ++j) {
305 temp = lhs(pivot, j);
306 lhs(pivot, j) = lhs(i, j);
307 lhs(i, j) = temp;
308 }
309 for (int j = 0; j < cols; ++j) {
310 temp = rhs(pivot, j);
311 rhs(pivot, j) = rhs(i, j);
312 rhs(i, j) = temp;
313 }
314 }
315
316 // Normalize i-th row
317 rhs[i] /= lhs(i, i);
318 for (int j = cols - 1; j > i; --j)
319 lhs(i, j) /= lhs(i, i);
320
321 // Eliminate non-zeros in i-th column below the i-th row.
322 for (int j = i + 1; j < rows; ++j) {
323 rhs[j] -= lhs(j, i) * rhs[i];
324 for (int k = i + 1; k < cols; ++k)
325 lhs(j, k) -= lhs(j, i) * lhs(i, k);
326 }
327 }
328 // Up
329 for (int i = rows - 1; i > 0; --i) {
330 for (int j = i - 1; j >= 0; --j)
331 rhs[j] -= lhs(j, i) * rhs[i];
332 }
333 if (ok)
334 *ok = true;
335 return rhs;
336 }
337
338 Matrix<T, cols, rows> transpose() const
339 {
340 Matrix<T, cols, rows> result;
341 for (int i = 0; i < rows; ++i) {
342 for (int j = 0; j < cols; ++j)
343 result.v[j][i] = v[i][j];
344 }
345 return result;
346 }
347
348 static Matrix identity()
349 {
350 Matrix result = matrix(T(0));
351 for (int i = 0; i < rows && i < cols; ++i)
352 result.v[i][i] = T(1);
353 return result;
354 }
355
356 Vector<T, cols> v[rows];
357};
358
359template<class T, int rows, int cols>
360Vector<T, cols> operator * (const Vector<T, rows> &u, const Matrix<T, rows, cols> &m)
361{
362 Vector<T, cols> result = Vector<T, cols>::vector(T(0));
363 for (int i = 0; i < rows; ++i)
364 result += m[i] * u[i];
365 return result;
366}
367
368template<class T, int rows, int cols>
369std::ostream &operator << (std::ostream &os, const Matrix<T, rows, cols> &m)
370{
371 assert(rows > 0);
372 os << "[" << m[0];
373 for (int i = 1; i < rows; ++i)
374 os << ", " << m[i];
375 os << "]";
376 return os;
377}
378
379
380typedef Matrix<float, 2, 2> Matrix2x2f;
381typedef Matrix<float, 3, 3> Matrix3x3f;
382typedef Matrix<float, 4, 4> Matrix4x4f;
383
384template<class T>
385struct Quaternion
386{
387 // Keep the Quaternion struct a plain old data (POD) struct by avoiding constructors
388
389 static Quaternion quaternion(T s, T x, T y, T z)
390 {
391 Quaternion result;
392 result.scalar = s;
393 result.vector[0] = x;
394 result.vector[1] = y;
395 result.vector[2] = z;
396 return result;
397 }
398
399 static Quaternion quaternion(T s, const Vector<T, 3> &v)
400 {
401 Quaternion result;
402 result.scalar = s;
403 result.vector = v;
404 return result;
405 }
406
407 static Quaternion identity()
408 {
409 return quaternion(T(1), T(0), T(0), T(0));
410 }
411
412 // assumes that all the elements are packed tightly
413 T& operator [] (int i) {return reinterpret_cast<T *>(this)[i];}
414 T operator [] (int i) const {return reinterpret_cast<const T *>(this)[i];}
415
416#define QUATERNION_BINARY_OP(op, arg, rhs) \
417 Quaternion operator op (arg) const \
418 { \
419 Quaternion result; \
420 for (int i = 0; i < 4; ++i) \
421 result[i] = (*this)[i] op rhs; \
422 return result; \
423 }
424
425 QUATERNION_BINARY_OP(+, const Quaternion &q, q[i])
426 QUATERNION_BINARY_OP(-, const Quaternion &q, q[i])
427 QUATERNION_BINARY_OP(*, T s, s)
428 QUATERNION_BINARY_OP(/, T s, s)
429#undef QUATERNION_BINARY_OP
430
431 Quaternion operator - () const
432 {
433 return Quaternion(-scalar, -vector);
434 }
435
436 Quaternion operator * (const Quaternion &q) const
437 {
438 Quaternion result;
439 result.scalar = scalar * q.scalar - Vector<T, 3>::dot(vector, q.vector);
440 result.vector = scalar * q.vector + vector * q.scalar + Vector<T, 3>::cross(vector, q.vector);
441 return result;
442 }
443
444 Quaternion operator * (const Vector<T, 3> &v) const
445 {
446 Quaternion result;
447 result.scalar = -Vector<T, 3>::dot(vector, v);
448 result.vector = scalar * v + Vector<T, 3>::cross(vector, v);
449 return result;
450 }
451
452 friend Quaternion operator * (const Vector<T, 3> &v, const Quaternion &q)
453 {
454 Quaternion result;
455 result.scalar = -Vector<T, 3>::dot(v, q.vector);
456 result.vector = v * q.scalar + Vector<T, 3>::cross(v, q.vector);
457 return result;
458 }
459
460#define QUATERNION_ASSIGN_OP(op, arg, rhs) \
461 Quaternion &operator op (arg) \
462 { \
463 for (int i = 0; i < 4; ++i) \
464 (*this)[i] op rhs; \
465 return *this; \
466 }
467
468 QUATERNION_ASSIGN_OP(+=, const Quaternion &q, q[i])
469 QUATERNION_ASSIGN_OP(-=, const Quaternion &q, q[i])
470 QUATERNION_ASSIGN_OP(=, T s, s)
471 QUATERNION_ASSIGN_OP(*=, T s, s)
472 QUATERNION_ASSIGN_OP(/=, T s, s)
473#undef QUATERNION_ASSIGN_OP
474
475 Quaternion& operator *= (const Quaternion &q)
476 {
477 Quaternion result;
478 result.scalar = scalar * q.scalar - Vector<T, 3>::dot(vector, q.vector);
479 result.vector = scalar * q.vector + vector * q.scalar + Vector<T, 3>::cross(vector, q.vector);
480 return (*this = result);
481 }
482
483 Quaternion& operator *= (const Vector<T, 3> &v)
484 {
485 Quaternion result;
486 result.scalar = -Vector<T, 3>::dot(vector, v);
487 result.vector = scalar * v + Vector<T, 3>::cross(vector, v);
488 return (*this = result);
489 }
490
491 Quaternion conjugate() const
492 {
493 return quaternion(scalar, -vector);
494 }
495
496 T sqrNorm() const
497 {
498 return scalar * scalar + vector.sqrNorm();
499 }
500
501 Quaternion inverse() const
502 {
503 return conjugate() / sqrNorm();
504 }
505
506 // requires floating point type T
507 Quaternion normalized() const
508 {
509 T s = sqrNorm();
510 if (s == 0)
511 return *this;
512 return *this / sqrt(s);
513 }
514
515 void matrix(Matrix<T, 3, 3>& m) const
516 {
517 T bb = vector[0] * vector[0];
518 T cc = vector[1] * vector[1];
519 T dd = vector[2] * vector[2];
520 T diag = scalar * scalar - bb - cc - dd;
521 T ab = scalar * vector[0];
522 T ac = scalar * vector[1];
523 T ad = scalar * vector[2];
524 T bc = vector[0] * vector[1];
525 T cd = vector[1] * vector[2];
526 T bd = vector[2] * vector[0];
527 m(0, 0) = diag + 2 * bb;
528 m(0, 1) = 2 * (bc - ad);
529 m(0, 2) = 2 * (ac + bd);
530 m(1, 0) = 2 * (ad + bc);
531 m(1, 1) = diag + 2 * cc;
532 m(1, 2) = 2 * (cd - ab);
533 m(2, 0) = 2 * (bd - ac);
534 m(2, 1) = 2 * (ab + cd);
535 m(2, 2) = diag + 2 * dd;
536 }
537
538 void matrix(Matrix<T, 4, 4>& m) const
539 {
540 T bb = vector[0] * vector[0];
541 T cc = vector[1] * vector[1];
542 T dd = vector[2] * vector[2];
543 T diag = scalar * scalar - bb - cc - dd;
544 T ab = scalar * vector[0];
545 T ac = scalar * vector[1];
546 T ad = scalar * vector[2];
547 T bc = vector[0] * vector[1];
548 T cd = vector[1] * vector[2];
549 T bd = vector[2] * vector[0];
550 m(0, 0) = diag + 2 * bb;
551 m(0, 1) = 2 * (bc - ad);
552 m(0, 2) = 2 * (ac + bd);
553 m(0, 3) = 0;
554 m(1, 0) = 2 * (ad + bc);
555 m(1, 1) = diag + 2 * cc;
556 m(1, 2) = 2 * (cd - ab);
557 m(1, 3) = 0;
558 m(2, 0) = 2 * (bd - ac);
559 m(2, 1) = 2 * (ab + cd);
560 m(2, 2) = diag + 2 * dd;
561 m(2, 3) = 0;
562 m(3, 0) = 0;
563 m(3, 1) = 0;
564 m(3, 2) = 0;
565 m(3, 3) = 1;
566 }
567
568 // assumes that 'this' is normalized
569 Vector<T, 3> transform(const Vector<T, 3> &v) const
570 {
571 Matrix<T, 3, 3> m;
572 matrix(m);
573 return v * m;
574 }
575
576 // assumes that all the elements are packed tightly
577 T* bits() {return reinterpret_cast<T *>(this);}
578 const T* bits() const {return reinterpret_cast<const T *>(this);}
579
580 // requires floating point type T
581 static Quaternion rotation(T angle, const Vector<T, 3> &unitAxis)
582 {
583 T s = sin(angle / 2);
584 T c = cos(angle / 2);
585 return quaternion(c, unitAxis * s);
586 }
587
588 T scalar;
589 Vector<T, 3> vector;
590};
591
592template<class T>
593Quaternion<T> operator * (T s, const Quaternion<T>& q)
594{
595 return Quaternion<T>::quaternion(s * q.scalar, s * q.vector);
596}
597
598typedef Quaternion<float> Quaternionf;
599
600} // end namespace gfx
601
602#endif
Note: See TracBrowser for help on using the repository browser.