worldsim/include/wmatrix.h

00001 /********************************************************************************
00002  *  WorldSim -- library for robot simulations                                   *
00003  *  Copyright (C) 2008-2011 Gianluca Massera <emmegian@yahoo.it>                *
00004  *                                                                              *
00005  *  This program is free software; you can redistribute it and/or modify        *
00006  *  it under the terms of the GNU General Public License as published by        *
00007  *  the Free Software Foundation; either version 2 of the License, or           *
00008  *  (at your option) any later version.                                         *
00009  *                                                                              *
00010  *  This program is distributed in the hope that it will be useful,             *
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of              *
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               *
00013  *  GNU General Public License for more details.                                *
00014  *                                                                              *
00015  *  You should have received a copy of the GNU General Public License           *
00016  *  along with this program; if not, write to the Free Software                 *
00017  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA  *
00018  ********************************************************************************/
00019 
00020 #ifndef WMATRIX_H
00021 #define WMATRIX_H
00022 
00023 #include "worldsimconfig.h"
00024 #include "wvector.h"
00025 #include <cstring>
00026 
00027 #ifdef FARSA_USE_GSL
00028     #include <gsl/gsl_blas.h>
00029 #endif
00030 
00031 namespace farsa {
00032 
00033 class wQuaternion;
00034 
00046 class FARSA_WSIM_TEMPLATE wMatrix {
00047 public:
00049     wMatrix();
00056     wMatrix( const wVector &X, const wVector &Y, const wVector &Z, const wVector &P );
00061     wMatrix( const wQuaternion &rotation, const wVector &position );
00067     wMatrix( const real* position, const real* rotation );
00068 
00070     wMatrix( const wMatrix &other );
00072     wMatrix& operator=( const wMatrix &other );
00073 
00075     wVectorT<true>& operator[](int i);
00077     const wVectorT<true>& operator[](int i) const;
00078 
00080     wMatrix inverse() const;
00082     wMatrix transpose() const;
00084     wMatrix transpose4X4() const;
00086     wVector getEuleroAngles() const;
00092     wMatrix rotateAround( const wVector& axis, const wVector& centre, real angle ) const;
00094     wMatrix rotateMatrix( const wMatrix& tm ) const;
00096     wVector rotateVector(const wVector &v) const;
00098     wVector unrotateVector(const wVector &v) const;
00100     wVector transformVector(const wVector &v) const;
00102     wVector untransformVector(const wVector &v) const;
00104     wVector transformPlane(const wVector &localPlane) const;
00106     wVector untransformPlane(const wVector &globalPlane) const;
00112     void transformTriplex( real* dst, int dstStrideInBytes, real* src, int srcStrideInBytes, int count) const;
00113 
00115     wMatrix operator*( const wMatrix &B ) const;
00116 
00118     bool sanityCheck();
00120     void sanitifize();
00121 
00123     static wMatrix identity();
00125     static wMatrix zero();
00129     static wMatrix grammSchmidt(const wVector& dir);
00131     static wMatrix pitch( real ang );
00133     static wMatrix yaw( real ang );
00135     static wMatrix roll( real ang );
00136 
00137     wVectorT<true> x_ax;
00138     wVectorT<true> y_ax;
00139     wVectorT<true> z_ax;
00140     wVectorT<true> w_pos;
00141 
00142 private:
00143     real data[16];
00144     wVectorT<true>* vecs[4]; // This is only useful for operator[] functions
00145 };
00146 
00147 } // end namespace farsa
00148 
00149 //--- this is included here because wMatrix and wQuaternion have mutual dependencies
00150 #include "wquaternion.h"
00151 
00152 namespace farsa {
00153 
00154 inline wMatrix::wMatrix() : x_ax(&data[0]), y_ax(&data[4]), z_ax(&data[8]), w_pos(&data[12]) {
00155     vecs[0] = &x_ax;
00156     vecs[1] = &y_ax;
00157     vecs[2] = &z_ax;
00158     vecs[3] = &w_pos;
00159 }
00160 
00161 inline wMatrix::wMatrix ( const wVector &X, const wVector &Y, const wVector &Z, const wVector &P) : x_ax(&data[0]), y_ax(&data[4]), z_ax(&data[8]), w_pos(&data[12])  {
00162     vecs[0] = &x_ax;
00163     vecs[1] = &y_ax;
00164     vecs[2] = &z_ax;
00165     vecs[3] = &w_pos;
00166     x_ax = X;
00167     y_ax = Y;
00168     z_ax = Z;
00169     w_pos = P;
00170 }
00171 
00172 inline wMatrix::wMatrix( const wQuaternion &rotation, const wVector &position ) : x_ax(&data[0]), y_ax(&data[4]), z_ax(&data[8]), w_pos(&data[12])  {
00173     vecs[0] = &x_ax;
00174     vecs[1] = &y_ax;
00175     vecs[2] = &z_ax;
00176     vecs[3] = &w_pos;
00177     real x2;
00178     real y2;
00179     real z2;
00180 //  real w2;
00181     real xy;
00182     real xz;
00183     real xw;
00184     real yz;
00185     real yw;
00186     real zw;
00187 
00188 //  w2 = 2.0 * rotation.q0 * rotation.q0; COMMENTED OUT BECAUSE IT IS UNUSED
00189     x2 = 2.0 * rotation.q1 * rotation.q1;
00190     y2 = 2.0 * rotation.q2 * rotation.q2;
00191     z2 = 2.0 * rotation.q3 * rotation.q3;
00192     // INVARIANT: fabs(w2 + x2 + y2 + z2 - 2.0) < 1.5e-3f;
00193 
00194     xy = 2.0 * rotation.q1 * rotation.q2;
00195     xz = 2.0 * rotation.q1 * rotation.q3;
00196     xw = 2.0 * rotation.q1 * rotation.q0;
00197     yz = 2.0 * rotation.q2 * rotation.q3;
00198     yw = 2.0 * rotation.q2 * rotation.q0;
00199     zw = 2.0 * rotation.q3 * rotation.q0;
00200 
00201     x_ax = wVector( 1.0-y2-z2, xy+zw, xz-yw, 0.0 );
00202     y_ax = wVector( xy-zw, 1.0-x2-z2, yz+xw, 0.0 );
00203     z_ax = wVector( xz+yw, yz-xw, 1.0-x2-y2, 0.0 );
00204 
00205     w_pos.x = position.x;
00206     w_pos.y = position.y;
00207     w_pos.z = position.z;
00208     w_pos.w = 1.0;
00209 }
00210 
00211 inline wMatrix::wMatrix( const real* pos, const real* rot ) : x_ax(&data[0]), y_ax(&data[4]), z_ax(&data[8]), w_pos(&data[12])  {
00212     vecs[0] = &x_ax;
00213     vecs[1] = &y_ax;
00214     vecs[2] = &z_ax;
00215     vecs[3] = &w_pos;
00216      x_ax[0]=rot[0];  x_ax[1]=rot[1];  x_ax[2]=rot[2];  x_ax[3]=0.0 /*rot[3]*/;
00217      y_ax[0]=rot[4];  y_ax[1]=rot[5];  y_ax[2]=rot[6];  y_ax[3]=0.0 /*rot[7]*/;
00218      z_ax[0]=rot[8];  z_ax[1]=rot[9];  z_ax[2]=rot[10]; z_ax[3]=0.0 /*rot[11]*/;
00219     w_pos[0]=pos[0]; w_pos[1]=pos[1]; w_pos[2]=pos[2]; w_pos[3]=1.0 /*pos[3*/;
00220 }
00221 
00222 inline wMatrix::wMatrix( const wMatrix &other ) : x_ax(&data[0]), y_ax(&data[4]), z_ax(&data[8]), w_pos(&data[12]) {
00223     vecs[0] = &x_ax;
00224     vecs[1] = &y_ax;
00225     vecs[2] = &z_ax;
00226     vecs[3] = &w_pos;
00227     memcpy(data, other.data, 16 * sizeof(real));
00228 }
00229 
00230 inline wMatrix& wMatrix::operator=( const wMatrix &other )
00231 {
00232     if (&other == this) {
00233         return *this;
00234     }
00235 
00236     memcpy(data, other.data, 16 * sizeof(real));
00237 
00238     return *this;
00239 }
00240 
00241 inline wVectorT<true>& wMatrix::operator[](int i) {
00242     return *(vecs[i]);
00243 }
00244 
00245 inline const wVectorT<true>& wMatrix::operator[](int i) const {
00246     return *(vecs[i]);
00247 }
00248 
00249 inline wMatrix wMatrix::inverse() const {
00250     return wMatrix( wVector(x_ax.x, y_ax.x, z_ax.x, 0.0f),
00251                     wVector(x_ax.y, y_ax.y, z_ax.y, 0.0f),
00252                     wVector(x_ax.z, y_ax.z, z_ax.z, 0.0f),
00253                     wVector(- (w_pos % x_ax), - (w_pos % y_ax), - (w_pos % z_ax), 1.0f));
00254 }
00255 
00256 inline wMatrix wMatrix::transpose() const {
00257     return wMatrix( wVector(x_ax.x, y_ax.x, z_ax.x, 0.0f),
00258                     wVector(x_ax.y, y_ax.y, z_ax.y, 0.0f),
00259                     wVector(x_ax.z, y_ax.z, z_ax.z, 0.0f),
00260                     wVector(0.0f, 0.0f, 0.0f, 1.0f));
00261 }
00262 
00263 inline wMatrix wMatrix::transpose4X4() const {
00264     return wMatrix( wVector(x_ax.x, y_ax.x, z_ax.x, w_pos.x),
00265                     wVector(x_ax.y, y_ax.y, z_ax.y, w_pos.y),
00266                     wVector(x_ax.z, y_ax.z, z_ax.z, w_pos.z),
00267                     wVector(x_ax.w, y_ax.w, z_ax.w, w_pos.w));
00268 }
00269 
00270 inline wVector wMatrix::getEuleroAngles() const {
00271     real yaw;
00272     real roll = 0.0;
00273     real pitch = 0.0;
00274     const real minSin = 0.99995f;
00275     const wMatrix& matrix = *this;
00276 
00277     yaw = asin( -min( max( matrix[0][2], -0.999999 ), 0.999999) );
00278     if( matrix[0][2] < minSin ) {
00279         if( matrix[0][2] > -minSin ) {
00280             roll = atan2( matrix[0][1], matrix[0][0] );
00281             pitch = atan2( matrix[1][2], matrix[2][2] );
00282         } else {
00283             pitch = atan2( matrix[1][0], matrix[1][1] );
00284         }
00285     } else {
00286         pitch = -atan2( matrix[1][0], matrix[1][1] );
00287     }
00288 
00289     return wVector(pitch, yaw, roll, 0.0);
00290 }
00291 
00292 inline wMatrix wMatrix::rotateAround( const wVector& axis, const wVector& centre, real angle ) const {
00293     //--- OPTIMIZE_ME this routine is very inefficient. Please Optimize Me
00294 /*  wMatrix ret = *this;
00295     wQuaternion ql( axis, angle );
00296     wMatrix rot = wMatrix( ql, wVector(0,0,0) );
00297     ret = rot.rotateMatrix( ret );
00298     wVector c = w_pos - centre; //centre-w_pos;
00299     qDebug() << c[0] << c[1] << c[2];
00300     //ret.w_pos += rot.rotateVector( c ) - c;
00301     ret.w_pos = centre + rot.rotateVector( c );
00302     return ret;*/
00303 
00304     /*
00305     wMatrix ret = *this;
00306     wVector centrel = ret.w_pos - centre; //centre - ret.w_pos;
00307     ret.w_pos = centrel;
00308     wQuaternion ql( axis, angle );
00309     ret = ret * wMatrix( ql, wVector(0,0,0) );
00310     ret.w_pos += w_pos - centrel;
00311     return ret;
00312     */
00313     
00314     // --- using rotateAround of wVector
00315     wMatrix ret = *this;
00316     ret.x_ax.rotateAround( axis, angle );
00317     ret.y_ax.rotateAround( axis, angle );
00318     ret.z_ax.rotateAround( axis, angle );
00319     wVector diffCentre = ret.w_pos - centre;
00320     diffCentre.rotateAround( axis, angle );
00321     ret.w_pos = diffCentre + centre;
00322     return ret;
00323 }
00324 
00325 inline wMatrix wMatrix::rotateMatrix( const wMatrix& B ) const {
00326     const wMatrix& A = *this;
00327     return wMatrix (wVector (A[0][0] * B[0][0] + A[0][1] * B[1][0] + A[0][2] * B[2][0] + A[0][3] * B[3][0],
00328                              A[0][0] * B[0][1] + A[0][1] * B[1][1] + A[0][2] * B[2][1] + A[0][3] * B[3][1],
00329                              A[0][0] * B[0][2] + A[0][1] * B[1][2] + A[0][2] * B[2][2] + A[0][3] * B[3][2],
00330                              A[0][0] * B[0][3] + A[0][1] * B[1][3] + A[0][2] * B[2][3] + A[0][3] * B[3][3]),
00331                     wVector (A[1][0] * B[0][0] + A[1][1] * B[1][0] + A[1][2] * B[2][0] + A[1][3] * B[3][0],
00332                              A[1][0] * B[0][1] + A[1][1] * B[1][1] + A[1][2] * B[2][1] + A[1][3] * B[3][1],
00333                              A[1][0] * B[0][2] + A[1][1] * B[1][2] + A[1][2] * B[2][2] + A[1][3] * B[3][2],
00334                              A[1][0] * B[0][3] + A[1][1] * B[1][3] + A[1][2] * B[2][3] + A[1][3] * B[3][3]),
00335                     wVector (A[2][0] * B[0][0] + A[2][1] * B[1][0] + A[2][2] * B[2][0] + A[2][3] * B[3][0],
00336                              A[2][0] * B[0][1] + A[2][1] * B[1][1] + A[2][2] * B[2][1] + A[2][3] * B[3][1],
00337                              A[2][0] * B[0][2] + A[2][1] * B[1][2] + A[2][2] * B[2][2] + A[2][3] * B[3][2],
00338                              A[2][0] * B[0][3] + A[2][1] * B[1][3] + A[2][2] * B[2][3] + A[2][3] * B[3][3]),
00339                     wVector ( A[3][3] * B[3][0],
00340                               A[3][3] * B[3][1],
00341                               A[3][3] * B[3][2],
00342                               A[3][3] * B[3][3]));
00343 }
00344 
00345 inline wVector wMatrix::rotateVector(const wVector &v) const {
00346     return wVector(  v.x * x_ax.x + v.y * y_ax.x + v.z * z_ax.x,
00347                      v.x * x_ax.y + v.y * y_ax.y + v.z * z_ax.y,
00348                      v.x * x_ax.z + v.y * y_ax.z + v.z * z_ax.z);
00349 }
00350 
00351 inline wVector wMatrix::unrotateVector(const wVector &v) const {
00352     return wVector( v%x_ax, v%y_ax, v%z_ax );
00353 }
00354 
00355 inline wVector wMatrix::transformVector(const wVector &v) const {
00356     return w_pos + rotateVector(v);
00357 }
00358 
00359 inline wVector wMatrix::untransformVector(const wVector &v) const {
00360     return unrotateVector( v-w_pos );
00361 }
00362 
00363 inline void wMatrix::transformTriplex( real* dst, int dstStrideInBytes, real* src, int srcStrideInBytes, int count ) const {
00364     real x;
00365     real y;
00366     real z;
00367 
00368     dstStrideInBytes /= sizeof(real);
00369     srcStrideInBytes /= sizeof(real);
00370 
00371     for( int i=0; i<count; i++ ) {
00372         x = src[0];
00373         y = src[1];
00374         z = src[2];
00375         dst[0] = x*x_ax.x + y*y_ax.x + z*z_ax.x + w_pos.x;
00376         dst[1] = x*x_ax.y + y*y_ax.y + z*z_ax.y + w_pos.y;
00377         dst[2] = x*x_ax.z + y*y_ax.z + z*z_ax.z + w_pos.z;
00378         dst += dstStrideInBytes;
00379         src += srcStrideInBytes;
00380     }
00381 }
00382 
00383 inline wMatrix wMatrix::operator*( const wMatrix &B ) const {
00384     const wMatrix& A = *this;
00385 #ifdef FARSA_USE_GSL
00386     wMatrix res;
00387     cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 4, 4, 4, 1.0, A.data, 4, B.data, 4, 0.0, res.data, 4);
00388     //cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 4, 4, 4, 1.0, A.data, 4, B.data, 4, 0.0, res.data, 4);
00389     return res;
00390 #else
00391     return wMatrix (wVector (A[0][0] * B[0][0] + A[0][1] * B[1][0] + A[0][2] * B[2][0] + A[0][3] * B[3][0],
00392                              A[0][0] * B[0][1] + A[0][1] * B[1][1] + A[0][2] * B[2][1] + A[0][3] * B[3][1],
00393                              A[0][0] * B[0][2] + A[0][1] * B[1][2] + A[0][2] * B[2][2] + A[0][3] * B[3][2],
00394                              A[0][0] * B[0][3] + A[0][1] * B[1][3] + A[0][2] * B[2][3] + A[0][3] * B[3][3]),
00395                     wVector (A[1][0] * B[0][0] + A[1][1] * B[1][0] + A[1][2] * B[2][0] + A[1][3] * B[3][0],
00396                              A[1][0] * B[0][1] + A[1][1] * B[1][1] + A[1][2] * B[2][1] + A[1][3] * B[3][1],
00397                              A[1][0] * B[0][2] + A[1][1] * B[1][2] + A[1][2] * B[2][2] + A[1][3] * B[3][2],
00398                              A[1][0] * B[0][3] + A[1][1] * B[1][3] + A[1][2] * B[2][3] + A[1][3] * B[3][3]),
00399                     wVector (A[2][0] * B[0][0] + A[2][1] * B[1][0] + A[2][2] * B[2][0] + A[2][3] * B[3][0],
00400                              A[2][0] * B[0][1] + A[2][1] * B[1][1] + A[2][2] * B[2][1] + A[2][3] * B[3][1],
00401                              A[2][0] * B[0][2] + A[2][1] * B[1][2] + A[2][2] * B[2][2] + A[2][3] * B[3][2],
00402                              A[2][0] * B[0][3] + A[2][1] * B[1][3] + A[2][2] * B[2][3] + A[2][3] * B[3][3]),
00403                     wVector (A[3][0] * B[0][0] + A[3][1] * B[1][0] + A[3][2] * B[2][0] + A[3][3] * B[3][0],
00404                              A[3][0] * B[0][1] + A[3][1] * B[1][1] + A[3][2] * B[2][1] + A[3][3] * B[3][1],
00405                              A[3][0] * B[0][2] + A[3][1] * B[1][2] + A[3][2] * B[2][2] + A[3][3] * B[3][2],
00406                              A[3][0] * B[0][3] + A[3][1] * B[1][3] + A[3][2] * B[2][3] + A[3][3] * B[3][3]));
00407 #endif
00408 }
00409 
00410 inline wVector wMatrix::transformPlane( const wVector &localPlane ) const {
00411     wVector tmp( rotateVector(localPlane) );  
00412     tmp.w = localPlane.w - ( localPlane%unrotateVector( w_pos ) );  
00413     return tmp;  
00414 }
00415 
00416 inline wVector wMatrix::untransformPlane( const wVector &globalPlane ) const {
00417     wVector tmp( unrotateVector( globalPlane ) );
00418     tmp.w = globalPlane % w_pos + globalPlane.w;
00419     return tmp;
00420 }
00421 
00422 inline bool wMatrix::sanityCheck() {
00423     // it correspond to (x_ax * y_ax) % z_ax
00424     real zz = (x_ax.y*y_ax.z - x_ax.z*y_ax.y)*z_ax.x
00425             + (x_ax.z*y_ax.x - x_ax.x*y_ax.z)*z_ax.y
00426             + (x_ax.x*y_ax.y - x_ax.y*y_ax.x)*z_ax.z;
00427     //--- Gianluca: era <0.9999f e produceva molti errori, cmq nessuno al di sopra
00428     //              di 0.999f; forse era dovuto solo ad errori numerici per via della
00429     //              precisione (float)
00430     if( fabs( zz ) < 0.99f) {
00431         //--- comment out by Gianluca - qDebug() << zz;
00432         return false;
00433     }
00434     x_ax.w = 0.0;
00435     y_ax.w = 0.0;
00436     z_ax.w = 0.0;
00437     w_pos.w = 1.0;
00438     return true;
00439 }
00440 
00441 inline void wMatrix::sanitifize() {
00442     //x_ax.normalize();
00443     //y_ax.normalize();
00444     //z_ax.normalize();
00445     x_ax.w = 0.0;
00446     y_ax.w = 0.0;
00447     z_ax.w = 0.0;
00448     w_pos.w = 1.0;
00449 }
00450 
00451 inline wMatrix wMatrix::identity() {
00452     return wMatrix( wVector (1.0f, 0.0f, 0.0f, 0.0f),
00453                     wVector (0.0f, 1.0f, 0.0f, 0.0f),
00454                     wVector (0.0f, 0.0f, 1.0f, 0.0f),
00455                     wVector (0.0f, 0.0f, 0.0f, 1.0f) );
00456 }
00457 
00458 inline wMatrix wMatrix::zero() {
00459     return wMatrix( wVector (0.0f, 0.0f, 0.0f, 0.0f),
00460                     wVector (0.0f, 0.0f, 0.0f, 0.0f),
00461                     wVector (0.0f, 0.0f, 0.0f, 0.0f),
00462                     wVector (0.0f, 0.0f, 0.0f, 0.0f) );
00463 }
00464 
00465 inline wMatrix wMatrix::grammSchmidt(const wVector& dir) {
00466     wVector X;
00467     wVector Y;
00468     wVector Z( dir );
00469 
00470     Z.normalize();
00471     if( fabs(Z.z) > 0.577f ) {
00472         X = Z * wVector( -Z.y, Z.z, 0.0f );
00473     } else {
00474         X = Z * wVector( -Z.y, Z.x, 0.0f );
00475     }
00476     X.normalize();
00477     Y = Z * X;
00478 
00479     X.w = 0.0f;
00480     Y.w = 0.0f;
00481     Z.w = 0.0f;
00482     return wMatrix( X, Y, Z, wVector(0.0f, 0.0f, 0.0f, 1.0f) );
00483 }
00484 
00485 inline wMatrix wMatrix::pitch( real ang ) {
00486     real cosAng = cos(ang);
00487     real sinAng = sin(ang);
00488     return wMatrix( wVector(1.0f,    0.0f,    0.0f, 0.0f), 
00489                     wVector(0.0f,  cosAng,  sinAng, 0.0f),
00490                     wVector(0.0f, -sinAng,  cosAng, 0.0f), 
00491                     wVector(0.0f,    0.0f,    0.0f, 1.0f) );
00492 }
00493 
00494 inline wMatrix wMatrix::yaw( real ang) {
00495     real cosAng = cos(ang);
00496     real sinAng = sin(ang);
00497     return wMatrix( wVector (cosAng, 0.0f, -sinAng, 0.0f), 
00498                     wVector (0.0f,   1.0f,    0.0f, 0.0f), 
00499                     wVector (sinAng, 0.0f,  cosAng, 0.0f), 
00500                     wVector (0.0f,   0.0f,    0.0f, 1.0f) );
00501 }
00502 
00503 inline wMatrix wMatrix::roll( real ang ) {
00504     real cosAng = cos(ang);
00505     real sinAng = sin(ang);
00506     return wMatrix( wVector ( cosAng, sinAng, 0.0f, 0.0f), 
00507                     wVector (-sinAng, cosAng, 0.0f, 0.0f),
00508                     wVector (   0.0f,   0.0f, 1.0f, 0.0f), 
00509                     wVector (   0.0f,   0.0f, 0.0f, 1.0f) );
00510 }
00511 
00512 } // end namespace farsa
00513 
00514 #endif