home *** CD-ROM | disk | FTP | other *** search
- /*
- * TransMatrix.C - methods for general 4x3 transformation matrices.
- *
- * Copyright (C) 1992, Christoph Streit (streit@iam.unibe.ch)
- * University of Berne, Switzerland
- * Portions Copyright (C) 1990, Jonathan P. Leech
- * All rights reserved.
- *
- * This software may be freely copied, modified, and redistributed
- * provided that this copyright notice is preserved on all copies.
- *
- * You may not distribute this software, in whole or in part, as part of
- * any commercial product without the express consent of the authors.
- *
- * There is no warranty or other guarantee of fitness of this software
- * for any purpose. It is provided solely "as is".
- *
- */
-
- #include "TransMatrix.h"
-
- /*
- * Copied from lsys by Jonathan P. Leech.
- */
- void SinCos(real alpha, real& sin_a, real& cos_a)
- {
- const real tolerance = 1e-10;
-
- sin_a = sin(alpha);
- cos_a = cos(alpha);
-
- if (cos_a > 1-tolerance) {
- cos_a = 1; sin_a = 0;
- }
- else if (cos_a < -1+tolerance) {
- cos_a = -1; sin_a = 0;
- }
-
- if (sin_a > 1-tolerance) {
- cos_a = 0; sin_a = 1;
- }
- else if (sin_a < -1+tolerance) {
- cos_a = 0; sin_a = -1;
- }
- }
-
- //___________________________________________________________ TransMatrix
-
- TransMatrix::TransMatrix()
- {
- for (register int i=0; i<4; i++)
- for (register int j=0; j<3; j++)
- m[i][j] = (i == j);
- }
-
- TransMatrix::TransMatrix(const Vector& v1, const Vector& v2,
- const Vector& v3)
- {
- m[0][0] = v1[0]; m[0][1] = v1[1]; m[0][2] = v1[2];
- m[1][0] = v2[0]; m[1][1] = v2[1]; m[1][2] = v2[2];
- m[2][0] = v3[0]; m[2][1] = v3[1]; m[2][2] = v3[2];
- m[3][0] = m[3][1] = m[3][2] = 0;
- }
-
- TransMatrix::TransMatrix(const Vector&v1, const Vector& v2,
- const Vector& v3, const Vector& v4)
- {
- m[0][0] = v1[0]; m[0][1] = v1[1]; m[0][2] = v1[2];
- m[1][0] = v2[0]; m[1][1] = v2[1]; m[1][2] = v2[2];
- m[2][0] = v3[0]; m[2][1] = v3[1]; m[2][2] = v3[2];
- m[3][0] = v4[0]; m[3][1] = v4[1]; m[3][2] = v4[2];
- }
-
- TransMatrix::TransMatrix(const TransMatrix& t)
- {
- for (register int i=0; i<4; i++)
- for (register int j=0; j<3; j++)
- m[i][j] = t.m[i][j];
- }
-
- const TransMatrix& TransMatrix::operator=(const TransMatrix& t)
- {
- for (register int i=0; i<4; i++)
- for (register int j=0; j<3; j++)
- m[i][j] = t.m[i][j];
- return *this;
- }
-
- TransMatrix& TransMatrix::operator+=(const TransMatrix& t)
- {
- for (register int i=0; i<4; i++)
- for (register int j=0; j<3; j++)
- m[i][j] += t.m[i][j];
- return *this;
- }
-
- TransMatrix& TransMatrix::operator-=(const TransMatrix& t)
- {
- for (register int i=0; i<4; i++)
- for (register int j=0; j<3; j++)
- m[i][j] -= t.m[i][j];
- return *this;
- }
-
- TransMatrix& TransMatrix::operator*=(const TransMatrix& t)
- {
- TransMatrix tmp(*this);
-
- for (register int i=0; i<3; i++) {
- m[0][i] = tmp.m[0][0]*t.m[0][i] + tmp.m[0][1]*t.m[1][i] + tmp.m[0][2]*t.m[2][i];
- m[1][i] = tmp.m[1][0]*t.m[0][i] + tmp.m[1][1]*t.m[1][i] + tmp.m[1][2]*t.m[2][i];
- m[2][i] = tmp.m[2][0]*t.m[0][i] + tmp.m[2][1]*t.m[1][i] + tmp.m[2][2]*t.m[2][i];
- m[3][i] = tmp.m[3][0]*t.m[0][i] + tmp.m[3][1]*t.m[1][i] + tmp.m[3][2]*t.m[2][i] +
- t.m[3][i];
- }
-
- return *this;
- }
-
- TransMatrix TransMatrix::operator-()
- {
- TransMatrix result;
-
- for (register int i=0; i<4; i++)
- for (register int j=0; j<3; j++)
- result.m[i][j] = m[i][j];
- return result;
- }
-
- TransMatrix TransMatrix::operator+(const TransMatrix& t)
- {
- TransMatrix result;
-
- for (register int i=0; i<4; i++)
- for (register int j=0; j<3; j++)
- result.m[i][j] = m[i][j] + t.m[i][j];
- return result;
- }
-
- TransMatrix TransMatrix::operator-(const TransMatrix& t)
- {
- TransMatrix result;
-
- for (register int i=0; i<4; i++)
- for (register int j=0; j<3; j++)
- result.m[i][j] = m[i][j] - t.m[i][j];
- return result;
-
- }
-
- TransMatrix TransMatrix::operator*(const TransMatrix& t)
- {
- TransMatrix result;
-
- for (register int i=0; i<3; i++) {
- result.m[0][i] = m[0][0]*t.m[0][i] + m[0][1]*t.m[1][i] + m[0][2]*t.m[2][i];
- result.m[1][i] = m[1][0]*t.m[0][i] + m[1][1]*t.m[1][i] + m[1][2]*t.m[2][i];
- result.m[2][i] = m[2][0]*t.m[0][i] + m[2][1]*t.m[1][i] + m[2][2]*t.m[2][i];
- result.m[3][i] = m[3][0]*t.m[0][i] + m[3][1]*t.m[1][i] + m[3][2]*t.m[2][i]
- + t.m[3][i];
- }
-
- return result;
- }
-
- /*
- * Compute the inverse of a 3D affine matrix; i.e. a matrix with a dimen-
- * sionality of 4 where the right column has entries (0, 0, 0, 1).
- *
- * This procedures treats the 4 by 4 matrix as ablock matrix and calculates
- * the inverse of one submatrix for a significant performance improvement
- * over a general procedure that can invert any nonsingular matrix:
- * -- -- -- --
- * | | -1 | -1 |
- * | A 0 | | A 0 |
- * -1 | | | |
- * M = | | = | -1 |
- * | C 1 | | -C A 1 |
- * | | | |
- * -- -- -- --
- *
- * where M is a 4 by 4 matrix,
- * A is the 3 by 3 upper left submatrix of M,
- * C is the 1 by 3 lower left subnatrix of M.
- *
- * Returned value:
- * 1 matrix is nonsingular
- * 0 otherwise
- *
- * Reference GraphicsGems I and Craig Kolbs rayshade.
- */
-
- int TransMatrix::invert()
- {
- TransMatrix ttmp;
- real det;
-
- /*
- * Calculate the determinant of submatrix A (optimized version:
- * don,t just compute the determinant of A)
- */
- ttmp.m[0][0] = m[1][1]*m[2][2] - m[1][2]*m[2][1];
- ttmp.m[1][0] = m[1][0]*m[2][2] - m[1][2]*m[2][0];
- ttmp.m[2][0] = m[1][0]*m[2][1] - m[1][1]*m[2][0];
-
- ttmp.m[0][1] = m[0][1]*m[2][2] - m[0][2]*m[2][1];
- ttmp.m[1][1] = m[0][0]*m[2][2] - m[0][2]*m[2][0];
- ttmp.m[2][1] = m[0][0]*m[2][1] - m[0][1]*m[2][0];
-
- ttmp.m[0][2] = m[0][1]*m[1][2] - m[0][2]*m[1][1];
- ttmp.m[1][2] = m[0][0]*m[1][2] - m[0][2]*m[1][0];
- ttmp.m[2][2] = m[0][0]*m[1][1] - m[0][1]*m[1][0];
-
- det = m[0][0]*ttmp.m[0][0] - m[0][1]*ttmp.m[1][0] + m[0][2]*ttmp.m[2][0];
-
- /*
- * singular matrix ?
- */
- if (fabs(det) < EPSILON*EPSILON)
- return 0;
-
- det = 1/det;
-
- /*
- * inverse(A) = adj(A)/det(A)
- */
- ttmp.m[0][0] *= det;
- ttmp.m[0][2] *= det;
- ttmp.m[1][1] *= det;
- ttmp.m[2][0] *= det;
- ttmp.m[2][2] *= det;
-
- det = -det;
-
- ttmp.m[0][1] *= det;
- ttmp.m[1][0] *= det;
- ttmp.m[1][2] *= det;
- ttmp.m[2][1] *= det;
-
- ttmp.m[3][0] = -(ttmp.m[0][0]*m[3][0] + ttmp.m[1][0]*m[3][1] + ttmp.m[2][0]*m[3][2]);
- ttmp.m[3][1] = -(ttmp.m[0][1]*m[3][0] + ttmp.m[1][1]*m[3][1] + ttmp.m[2][1]*m[3][2]);
- ttmp.m[3][2] = -(ttmp.m[0][2]*m[3][0] + ttmp.m[1][2]*m[3][1] + ttmp.m[2][2]*m[3][2]);
-
- *this = ttmp;
-
- return 1;
- }
-
- /*
- * Compute general rotation matrix.
- * Adapted from Craig Kolbs rayshade.
- */
- void TransMatrix::setRotate(const Vector& v, real alpha)
- {
- real sin_a, cos_a, n1, n2, n3;
- Vector n(v.normalized());
-
- SinCos(alpha, sin_a, cos_a);
-
- n1 = n[0]; n2 = n[1]; n3 = n[2];
-
- m[0][0] = (n1*n1 + (1. - n1*n1)*cos_a);
- m[0][1] = (n1*n2*(1. - cos_a) + n3*sin_a);
- m[0][2] = (n1*n3*(1. - cos_a) - n2*sin_a);
- m[1][0] = (n1*n2*(1. - cos_a) - n3*sin_a);
- m[1][1] = (n2*n2 + (1. - n2*n2)*cos_a);
- m[1][2] = (n2*n3*(1. - cos_a) + n1*sin_a);
- m[2][0] = (n1*n3*(1. - cos_a) + n2*sin_a);
- m[2][1] = (n2*n3*(1. - cos_a) - n1*sin_a);
- m[2][2] = (n3*n3 + (1. - n3*n3)*cos_a);
- m[3][0] = m[3][1] = m[3][2] = 0;
- }
-
- TransMatrix& TransMatrix::rotate(const Vector& v, real alpha)
- {
- TransMatrix rot;
- rot.setRotate(v, alpha);
- return this->operator*=(rot);
- }
-
- TransMatrix& TransMatrix::rotate(Axis a, const real sin_a, const real cos_a)
- {
- static real m00, m01, m10, m11, m20, m21, m30, m31;
-
- switch(a) {
- case X:
- m01 = m[0][1]; m11 = m[1][1]; m21 = m[2][1]; m31 = m[3][1];
-
- m[0][1] = m01*cos_a-m[0][2]*sin_a; m[0][2] = m01*sin_a+m[0][2]*cos_a;
- m[1][1] = m11*cos_a-m[1][2]*sin_a; m[1][2] = m11*sin_a+m[1][2]*cos_a;
- m[2][1] = m21*cos_a-m[2][2]*sin_a; m[2][2] = m21*sin_a+m[2][2]*cos_a;
- m[3][1] = m31*cos_a-m[3][2]*sin_a; m[3][2] = m31*sin_a+m[3][2]*cos_a;
- break;
-
- case Y:
- m00 = m[0][0]; m10 = m[1][0]; m20 = m[2][0]; m30 = m[3][0];
-
- m[0][0] = m00*cos_a-m[0][2]*sin_a; m[0][2] = m00*sin_a+m[0][2]*cos_a;
- m[1][0] = m10*cos_a-m[1][2]*sin_a; m[1][2] = m10*sin_a+m[1][2]*cos_a;
- m[2][0] = m20*cos_a-m[2][2]*sin_a; m[2][2] = m20*sin_a+m[2][2]*cos_a;
- m[3][0] = m30*cos_a-m[3][2]*sin_a; m[3][2] = m30*sin_a+m[3][2]*cos_a;
- break;
-
- case Z:
- m00 = m[0][0]; m10 = m[1][0]; m20 = m[2][0]; m30 = m[3][0];
-
- m[0][0] = m00*cos_a-m[0][1]*sin_a; m[0][1] = m00*sin_a+m[0][1]*cos_a;
- m[1][0] = m10*cos_a-m[1][1]*sin_a; m[1][1] = m10*sin_a+m[1][1]*cos_a;
- m[2][0] = m20*cos_a-m[2][1]*sin_a; m[2][1] = m20*sin_a+m[2][1]*cos_a;
- m[3][0] = m30*cos_a-m[3][1]*sin_a; m[3][1] = m30*sin_a+m[3][1]*cos_a;
- break;
-
- default:
- Error(ERR_PANIC, "TransMatrix::rotate illegal value for axis");
- }
-
- return *this;
- }
-
- TransMatrix& TransMatrix::rotate(Axis a, const real alpha)
- {
- real sin_a, cos_a;
-
- SinCos(alpha, sin_a, cos_a);
-
- return this->rotate(a, sin_a, cos_a);
- }
-
- TransMatrix& TransMatrix::scale(const real Sx, const real Sy, const real Sz)
- {
- for (register int i=0; i<4; i++) {
- m[i][0] *= Sx;
- m[i][1] *= Sy;
- m[i][2] *= Sz;
- }
-
- return *this;
- }
-
- TransMatrix& TransMatrix::translate(const Vector& T)
- {
- m[3][0] += T[0];
- m[3][1] += T[1];
- m[3][2] += T[2];
-
- return *this;
- }
-
- Vector operator*(const Vector &v, const TransMatrix& t)
- {
- return Vector(t.m[0][0]*v[0] + t.m[1][0]*v[1] + t.m[2][0]*v[2] + t.m[3][0],
- t.m[0][1]*v[0] + t.m[1][1]*v[1] + t.m[2][1]*v[2] + t.m[3][1],
- t.m[0][2]*v[0] + t.m[1][2]*v[1] + t.m[2][2]*v[2] + t.m[3][2]);
- }
-
- ostream& operator<<(ostream &os, const TransMatrix& t)
- {
- for (register int i=0; i<4; i++) {
- os << "\t( " << t.m[i][0] << ' ' << t.m[i][1] << ' ' <<t.m[i][2] << " )\n";
- }
-
- return os;
- }
-
-
-
-