Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

mat4.C

Go to the documentation of this file.
00001 #include "mlib/mat4.H"
00002 #include "mlib/vec3.H"
00003 #include "mlib/global.H"
00004 
00005 /*!
00006  *  \file Mat4.C
00007  *  \brief Contains the definitions of member functions for the Mat4 class.
00008  *  \ingroup group_MLIB
00009  *
00010  */
00011 
00012 /*!
00013  *  Construct a rigid motion transformation from given coordinate
00014  *  system (origin,x_dir,y_dir,z_dir). This transformation will
00015  *  transform points from (origin,x_dir,y_dir,z_dir) to world.
00016  *
00017  *  \param[in] origin The origin of the coordinate system that will be defined
00018  *  by the new matrix.
00019  *  \param[in] x_dir The direction of the x-axis of the coordinate system that
00020  *  will be defined by the new matrix.
00021  *  \param[in] y_dir The direction of the y-axis of the coordinate system that
00022  *  will be defined by the new matrix.
00023  *  \param[in] z_dir The direction of the z-axis of the coordinate system that
00024  *  will be defined by the new matrix.
00025  *
00026  *  \todo Change use of temp matrix to direct access to the this pointer.
00027  *
00028  */
00029 template <typename M, typename P, typename V, typename L, typename Q>
00030 MLIB_INLINE
00031 mlib::Mat4<M,P,V,L,Q>::Mat4(
00032    const P& origin, 
00033    const V& x_dir, 
00034    const V& y_dir, 
00035    const V& z_dir
00036    )
00037 {
00038    const V xx = x_dir.normalized();
00039    const V yy = y_dir.normalized();
00040    const V zz = z_dir.normalized();
00041 
00042    assert(!xx.is_null());
00043    assert(!yy.is_null());
00044    assert(!zz.is_null());
00045 
00046    Mat4<M,P,V,L,Q> t;
00047 
00048    for (int i = 0; i < 3; i++) {
00049       t(i,0) = xx    [i];
00050       t(i,1) = yy    [i];
00051       t(i,2) = zz    [i];
00052       t(i,3) = origin[i];
00053       t(3,i) = 0.0;
00054    }
00055    t(3,3) = 1.0;
00056 
00057    (*this) = t;
00058 } 
00059 
00060 /*!
00061  *  Construct a matrix whose columns are the given vectors.
00062  *
00063  *  \param[in] col0 Becomes the first 3 rows of the first column of the matrix.
00064  *  \param[in] col1 Becomes the first 3 rows of the second column of the matrix.
00065  *  \param[in] col2 Becomes the first 3 rows of the third column of the matrix.
00066  *
00067  *  \todo Change use of temp matrix to direct access to the this pointer.
00068  *
00069  */
00070 template <typename M,typename P, typename V, typename L, typename Q>
00071 MLIB_INLINE
00072 mlib::Mat4<M,P,V,L,Q>::Mat4(const V& col0, const V& col1, const V& col2)
00073 {
00074    Mat4<M,P,V,L,Q> t;
00075 
00076    for (int i = 0; i < 3; i++) {
00077       t(i,0) = col0  [i];
00078       t(i,1) = col1  [i];
00079       t(i,2) = col2  [i];
00080       t(i,3) = t(3,i) = 0.0;
00081    }
00082    t(3,3) = 1.0;
00083 
00084    (*this) = t;
00085 } 
00086 
00087 /*!
00088  *  Construct a rigid motion transformation from the coordinate
00089  *  system (origin,x_dir,y_dir,cross(x_dir,y_dir)). This transformation will
00090  *  transform points from (origin,x_dir,y_dir,cross(x_dir,y_dir)) to world.
00091  *
00092  *  \param[in] origin The origin of the coordinate system that will be defined
00093  *  by the new matrix.
00094  *  \param[in] x_dir The direction of the x-axis of the coordinate system that
00095  *  will be defined by the new matrix.
00096  *  \param[in] y_dir The direction of the y-axis of the coordinate system that
00097  *  will be defined by the new matrix.
00098  *
00099  *  \note \a y_dir is recomputed to be cross(cross(x_dir,y_dir), x_dir).
00100  *
00101  *  \note If the result of cross(x_dir,y_dir) is a null vector, then the
00102  *  constructed matrix will be the identity matrix.
00103  *
00104  *  \todo Change use of temp matrix to direct access to the this pointer.
00105  *
00106  */
00107 template <typename M,typename P, typename V, typename L, typename Q>
00108 MLIB_INLINE
00109 mlib::Mat4<M,P,V,L,Q>::Mat4(const P& origin, const V& x_dir, const V& y_dir)
00110 {
00111    // isError = false;
00112 
00113    const V xx = x_dir.normalized();
00114    const V zz = cross(xx, y_dir).normalized();
00115 
00116    if (zz.is_null()) {
00117       *this = M();
00118       // isError = true;
00119       return;
00120    }
00121 
00122    const V yy = cross(zz, xx).normalized();
00123    *this = M(origin, xx, yy, zz);
00124 }
00125 
00126 
00127 
00128 /*!
00129  *  Construct a transform that moves origin to axis.point and
00130  *  z-axis to axis.vector. The x and y axes are constructed
00131  *  according to an arbitrary axis algorithm.
00132  *
00133  *  \param[in] axis A line specifying the origin and z-axis of the coordinate
00134  *  system that will be defined by the new matrix.
00135  *
00136  */
00137 template <typename M,typename P, typename V, typename L, typename Q>
00138 MLIB_INLINE
00139 mlib::Mat4<M,P,V,L,Q>::Mat4(const L& axis)
00140 {
00141    // isError = false;
00142 
00143    const V zDir = axis.vector().normalized();
00144 
00145    if (zDir.is_null())
00146    {
00147        *this = M(axis.point(), V(1,0,0), V(0,1,0), V(0,0,1));
00148        // isError = true;
00149    } else {
00150       const V xDir = zDir.perpend();
00151       const V yDir = cross(zDir, xDir);
00152       *this = M(axis.point(), xDir, yDir, zDir);
00153    }
00154 }
00155 
00156 /*!
00157  *  \param[in] origin The origin of the rigid motion transform.
00158  *
00159  */
00160 template <typename M,typename P, typename V, typename L, typename Q>
00161 MLIB_INLINE
00162 mlib::Mat4<M,P,V,L,Q>::Mat4(const P& origin) 
00163 {
00164    M t;
00165 
00166    t(0,3) = origin[0];
00167    t(1,3) = origin[1];
00168    t(2,3) = origin[2];
00169 
00170    (*this) = t;
00171 } 
00172 
00173 
00174 /*!
00175  *  \param[in] vec A vector describing the length and direction of the
00176  *  translation.
00177  *
00178  */
00179 template <typename M,typename P, typename V, typename L, typename Q>
00180 MLIB_INLINE
00181 M 
00182 mlib::Mat4<M,P,V,L,Q>::translation(const V& vec)
00183 {
00184    M t;
00185 
00186    t(0,3) = vec[0]; 
00187    t(1,3) = vec[1];
00188    t(2,3) = vec[2];
00189 
00190    return t;
00191 }
00192 
00193 
00194 
00195 /*!
00196  *  \param[in] axis A vector describing the axis to rotate about.
00197  *  \param[in] angle The angle to rotate through (in radians).
00198  *
00199  */
00200 template <typename M,typename P, typename V, typename L, typename Q>
00201 MLIB_INLINE
00202 M 
00203 mlib::Mat4<M,P,V,L,Q>::rotation(const V& axis, double angle)
00204 {
00205    return  rotation(L(P(), axis), angle); 
00206 }
00207 
00208 /*!
00209  *  \param[in] axis A line describing the axis to rotate about.
00210  *  \param[in] angle The angle to rotate through (in radians).
00211  *
00212  */
00213 template <typename M,typename P, typename V, typename L, typename Q>
00214 MLIB_INLINE
00215 M
00216 mlib::Mat4<M,P,V,L,Q>::rotation(const L& axis, double angle)
00217 {
00218    const V      v  = axis.vector().normalized();
00219    const P      p  = axis.point();
00220    const double sa = sin(angle);
00221    const double ca = cos(angle);
00222 
00223    M t;
00224 
00225    t(0,0) = v[0]*v[0]  + ca*(1.0-v[0]*v[0]);
00226    t(0,1) = v[0]*v[1]*(1.0-ca) - v[2]*sa;
00227    t(0,2) = v[2]*v[0]*(1.0-ca) + v[1]*sa;
00228 
00229    t(1,0) = v[0]*v[1]*(1.0-ca) + v[2]*sa;
00230    t(1,1) = v[1]*v[1] + ca*(1.0-v[1]*v[1]);
00231    t(1,2) = v[1]*v[2]*(1.0-ca) - v[0]*sa;
00232 
00233    t(2,0) = v[0]*v[2]*(1.0-ca) - v[1]*sa;
00234    t(2,1) = v[1]*v[2]*(1.0-ca) + v[0]*sa;
00235    t(2,2) = v[2]*v[2] + ca*(1.0-v[2]*v[2]);
00236 
00237    t(0,3) = p[0] - (t(0,0)*p[0] + t(0,1)*p[1] + t(0,2)*p[2]);
00238    t(1,3) = p[1] - (t(1,0)*p[0] + t(1,1)*p[1] + t(1,2)*p[2]);
00239    t(2,3) = p[2] - (t(2,0)*p[0] + t(2,1)*p[1] + t(2,2)*p[2]);
00240 
00241    t(3,0) = t(3,1) = t(3,2) = 0;
00242    t(3,3) = 1.0;
00243 
00244    return t;
00245 } 
00246 
00247 
00248 /*!
00249  *  \param[in] quat A quaternion describing the rotation.
00250  *
00251  */
00252 template <typename M,typename P, typename V, typename L, typename Q>
00253 MLIB_INLINE
00254 M 
00255 mlib::Mat4<M,P,V,L,Q>::rotation(const Q& quat)
00256 {
00257    double angle = 2.0 * Acos(quat.w());
00258    const V axis = (angle != 0.0) ? quat.v()/sin(angle/2.0) : V(0,1,0);
00259    return rotation(axis, angle);
00260 }
00261 
00262 /*!
00263  *  \param[in] fixed_pt The point that should remain fixed after the scaling.
00264  *  \param[in] factor The amount to scale by in the x-, y- and z-directions.
00265  *
00266  */
00267 template <typename M,typename P, typename V, typename L, typename Q>
00268 MLIB_INLINE
00269 M 
00270 mlib::Mat4<M,P,V,L,Q>::scaling(const P& fixed_pt, double factor)
00271 {
00272    return scaling(fixed_pt, V(factor, factor, factor));
00273 }
00274 
00275 /*!
00276  *  \param[in] factor The amount to scale by along the x-, y- and z-axes.
00277  *
00278  */ 
00279 template <typename M,typename P, typename V, typename L, typename Q>
00280 MLIB_INLINE
00281 M 
00282 mlib::Mat4<M,P,V,L,Q>::scaling(double factor)
00283 {
00284    return scaling(P(), V(factor, factor, factor));
00285 }
00286 
00287 
00288 /*!
00289  *  \param[in] xyz_factors A vector whose components are the amount to scale by
00290  *  along their corresponding directions.
00291  *
00292  */
00293 template <typename M,typename P, typename V, typename L, typename Q>
00294 MLIB_INLINE
00295 M
00296 mlib::Mat4<M,P,V,L,Q>::scaling(const V& xyz_factors)
00297 {
00298    return scaling(P(), xyz_factors);
00299 } 
00300 
00301 /*!
00302  *  \param[in] fixed_pt The point that should remain fixed after the scaling.
00303  *  \param[in] xyz_factors A vector whose components are the amount to scale by
00304  *  along their corresponding directions.
00305  *
00306  */
00307 template <typename M,typename P, typename V, typename L, typename Q>
00308 MLIB_INLINE
00309 M 
00310 mlib::Mat4<M,P,V,L,Q>::scaling(const P& fixed_pt, const V& xyz_factors)
00311 {
00312    M t;
00313 
00314    t(0,0) = xyz_factors[0];
00315    t(1,1) = xyz_factors[1];
00316    t(2,2) = xyz_factors[2];
00317 
00318    t(0,3) = fixed_pt[0] * (1.0-xyz_factors[0]);
00319    t(1,3) = fixed_pt[1] * (1.0-xyz_factors[1]);
00320    t(2,3) = fixed_pt[2] * (1.0-xyz_factors[2]);
00321 
00322    return t;
00323 } 
00324 
00325 /*!
00326  *  \param[in] normal Some sort of normal vector.  Not sure exactly what this is
00327  *  (perhaps the normal vector to the plane that will be sheared?).
00328  *  \param[in] shear_vec A vector describing the shear.  Not sure exactly how
00329  *  this is interpreted.
00330  *
00331  *  \todo Document this function more completely.
00332  *
00333  *  \question What are the exact meanings of the parameters?
00334  *
00335  */
00336 template <typename M,typename P, typename V, typename L, typename Q>
00337 MLIB_INLINE
00338 M 
00339 mlib::Mat4<M,P,V,L,Q>::shear(const V& normal, const V& shear_vec)
00340 {
00341    M t;
00342 
00343    V      realShear = shear_vec;
00344    double dot       = normal * shear_vec;
00345 
00346    // Shear vec must be perpendicular to normal
00347    if (fabs(dot) > epsAbsSqrdMath()) 
00348       realShear = shear_vec - normal * dot;
00349 
00350    // Set rows to coordinate axes transformed by shear
00351    for (int j = 0; j < 3; j++) { 
00352       t(j, 0) += normal[0] * realShear[j];
00353       t(j, 1) += normal[1] * realShear[j];
00354       t(j, 2) += normal[2] * realShear[j];
00355    }
00356 
00357    return t;
00358 }
00359 
00360 
00361 
00362 /*!
00363  *  \param[in] axis A line describing the direction to stretch along and the
00364  *  amount to stretch as well as the point that should remain fixed after the
00365  *  stretching.
00366  *
00367  */
00368 template <typename M,typename P, typename V, typename L, typename Q>
00369 MLIB_INLINE
00370 M 
00371 mlib::Mat4<M,P,V,L,Q>::stretching(const L& axis)
00372 {
00373    const M t    = M(axis);
00374    const M invt = t.inverse();
00375 
00376    P q = invt * axis.point();  
00377    M mat = scaling(q, V(1,1,axis.vector().length()));
00378 
00379    return t * mat * invt;
00380 }
00381 
00382 
00383 /*!
00384  *  Contruct a rotation / non-uniform scale matrix that maps
00385  *  the line segment joining anchor -- old_pt to the segment
00386  *  joining anchor -- new_pt:
00387  *  
00388  *  <tt>                                                
00389  *                                                  
00390  *               new point                          
00391  *                 /                                
00392  *                /                                 
00393  *               /                                  
00394  *              /                                   
00395  *             /                                    
00396  *            /                                     
00397  *           /                                      
00398  *     anchor ------------------- old point         
00399  *                                                  
00400  *  </tt>
00401  *
00402  */ 
00403 template <typename M,typename P, typename V, typename L, typename Q>
00404 MLIB_INLINE
00405 M 
00406 mlib::Mat4<M,P,V,L,Q>::anchor_scale_rot(
00407    const P& anchor,
00408    const P& old_pt,
00409    const P& new_pt)
00410 {                                                
00411 
00412    V   old_vec = (old_pt - anchor).normalized();
00413    V   new_vec = (new_pt - anchor).normalized();
00414    double old_len = anchor.dist(old_pt);
00415    double new_len = anchor.dist(new_pt);
00416 
00417    // Avoid division by zero:
00418    if (old_len < gEpsAbsMath) {
00419       err_msg("Mat4::anchor_scale_rot: Original segment too short");
00420       return M();
00421    }
00422 
00423    // First non-uniformly scale the old segment to the length of
00424    // the new one:
00425    M z2old = M(L(anchor, old_vec));     // rotates z-axis to old seg
00426    M ret = (
00427       z2old *                                   // z-axis to old seg
00428       M::scaling(V(1,1,new_len/old_len)) *      // scale z-axis
00429       z2old.inverse()                        // old seg to z-axis
00430       );
00431 
00432    // now rotate the old segment to the new one:
00433    V n = cross(new_vec, old_vec).normalized();
00434    if (n.is_null())
00435       return ret;       // Rotation not necessary
00436 
00437    return M::rotation(L(anchor,n), -Acos(new_vec*old_vec)) * ret;
00438 }
00439 
00440 
00441 template <typename M, typename P, typename V, typename L, typename Q>
00442 MLIB_INLINE
00443 M 
00444 mlib::operator*(const Mat4<M,P,V,L,Q> &m, const Mat4<M,P,V,L,Q>& m2)
00445 {
00446    M        t;
00447 
00448    t(0,0) = m(0,0) * m2(0,0) +
00449             m(0,1) * m2(1,0) +
00450             m(0,2) * m2(2,0) +
00451             m(0,3) * m2(3,0) ;
00452 
00453    t(0,1) = m(0,0) * m2(0,1) +
00454             m(0,1) * m2(1,1) +
00455             m(0,2) * m2(2,1) +
00456             m(0,3) * m2(3,1) ;
00457 
00458    t(0,2) = m(0,0) * m2(0,2) +
00459             m(0,1) * m2(1,2) +
00460             m(0,2) * m2(2,2) +
00461             m(0,3) * m2(3,2) ;
00462 
00463    t(0,3) = m(0,0) * m2(0,3) +
00464             m(0,1) * m2(1,3) +
00465             m(0,2) * m2(2,3) +
00466             m(0,3) * m2(3,3) ;
00467 
00468    t(1,0) = m(1,0) * m2(0,0) +
00469             m(1,1) * m2(1,0) +
00470             m(1,2) * m2(2,0) +
00471             m(1,3) * m2(3,0) ;
00472 
00473    t(1,1) = m(1,0) * m2(0,1) +
00474             m(1,1) * m2(1,1) +
00475             m(1,2) * m2(2,1) +
00476             m(1,3) * m2(3,1) ;
00477 
00478    t(1,2) = m(1,0) * m2(0,2) +
00479             m(1,1) * m2(1,2) +
00480             m(1,2) * m2(2,2) +
00481             m(1,3) * m2(3,2) ;
00482 
00483    t(1,3) = m(1,0) * m2(0,3) +
00484             m(1,1) * m2(1,3) +
00485             m(1,2) * m2(2,3) +
00486             m(1,3) * m2(3,3) ;
00487 
00488    t(2,0) = m(2,0) * m2(0,0) +
00489             m(2,1) * m2(1,0) +
00490             m(2,2) * m2(2,0) +
00491             m(2,3) * m2(3,0) ;
00492 
00493    t(2,1) = m(2,0) * m2(0,1) +
00494             m(2,1) * m2(1,1) +
00495             m(2,2) * m2(2,1) +
00496             m(2,3) * m2(3,1) ;
00497 
00498    t(2,2) = m(2,0) * m2(0,2) +
00499             m(2,1) * m2(1,2) +
00500             m(2,2) * m2(2,2) +
00501             m(2,3) * m2(3,2) ;
00502 
00503    t(2,3) = m(2,0) * m2(0,3) +
00504             m(2,1) * m2(1,3) +
00505             m(2,2) * m2(2,3) +
00506             m(2,3) * m2(3,3) ;
00507 
00508    t(3,0) = m(3,0) * m2(0,0) +
00509             m(3,1) * m2(1,0) +
00510             m(3,2) * m2(2,0) +
00511             m(3,3) * m2(3,0) ;
00512 
00513    t(3,1) = m(3,0) * m2(0,1) +
00514             m(3,1) * m2(1,1) +
00515             m(3,2) * m2(2,1) +
00516             m(3,3) * m2(3,1) ;
00517 
00518    t(3,2) = m(3,0) * m2(0,2) +
00519             m(3,1) * m2(1,2) +
00520             m(3,2) * m2(2,2) +
00521             m(3,3) * m2(3,2) ;
00522 
00523    t(3,3) = m(3,0) * m2(0,3) +
00524             m(3,1) * m2(1,3) +
00525             m(3,2) * m2(2,3) +
00526             m(3,3) * m2(3,3) ;
00527 
00528    t.set_perspective(m.is_perspective() || m2.is_perspective());
00529 
00530    return t;
00531 
00532 } // operator *
00533 
00534 /*!
00535  *  Convenience version of inverse that returns the inverse rather than passing
00536  *  it back by reference.  This version also prints an error message if a
00537  *  singular matrix is detected (in which case the returned matrix is undefined).
00538  *
00539  *  \return The inverse of the matrix.
00540  *
00541  */
00542 template <typename M,typename P, typename V, typename L, typename Q>
00543 MLIB_INLINE
00544 M
00545 mlib::Mat4<M,P,V,L,Q>::inverse(bool debug) const
00546 {
00547    // Compute the inverse, store in ret, return determinant
00548    M ret;
00549    double det = inverse(ret); 
00550    if (debug && isZero(det)) {
00551       // Complain if result is singular:
00552       cerr << "Mat4::inverse: error: singular matrix" << endl;
00553       // gdb won't recognize line numbers in templated functions
00554       // like this, but it does recognize the following function in
00555       // case you want to set a breakpoint there to find out who is
00556       // trying to compute the inverse of a singular matrix:
00557       fn_gdb_will_recognize_so_i_can_set_a_fuggin_breakpoint();
00558    }
00559    return ret;
00560 }
00561 
00562 /*!
00563  *  \brief Matrix inversion code for 4x4 matrices using Gaussian elimination
00564  *  with partial pivoting.  This is a specialized version of a
00565  *  procedure originally due to Paul Heckbert <ph@cs.cmu.edu>.
00566  *
00567  *  If the matrix is singular, returns 0 and leaves trash in \p inv.
00568  *
00569  *  \param[out] inv The result of inverting the matrix.  If the matrix is
00570  *  singular, the value of \p inv is undefined.
00571  *  
00572  *  \return Determinant of the matrix.  If the matrix is singular, the
00573  *  determinant will be 0 (or very close to 0).
00574  *
00575  *  \libgfx This function was taken directly from libgfx.
00576  *
00577  */
00578 template <typename M,typename P, typename V, typename L, typename Q>
00579 MLIB_INLINE
00580 double
00581 mlib::Mat4<M,P,V,L,Q>::inverse(Mat4<M,P,V,L,Q> &inv) const
00582 {
00583    Mat4<M,P,V,L,Q> A = *this;
00584    int i, j, k;
00585    double maxval, t, detr, pivot;
00586 
00587    /*---------- forward elimination ----------*/
00588 
00589    for (i=0; i<4; i++)                /* put identity matrix in inv */
00590       for (j=0; j<4; j++)
00591          inv(i, j) = (double)(i==j);
00592 
00593    detr = 1.0;
00594    for (i=0; i<4; i++) {              /* eliminate in column i, below diag */
00595       maxval = -1.;
00596       for (k=i; k<4; k++)             /* find pivot for column i */
00597          if (fabs(A(k, i)) > maxval) {
00598             maxval = fabs(A(k, i));
00599             j = k;
00600          }
00601       if (maxval<=0.) return 0.;      /* if no nonzero pivot, PUNT */
00602       if (j!=i) {                     /* swap rows i and j */
00603          for (k=i; k<4; k++)
00604             { t = A(i,k); A(i,k) = A(j,k); A(j,k) = t; }
00605          for (k=0; k<4; k++)
00606             { t = inv(i,k); inv(i,k) = inv(j,k); inv(j,k) = t; }
00607          detr = -detr;
00608       }
00609       pivot = A(i, i);
00610       detr *= pivot;
00611       for (k=i+1; k<4; k++)           /* only do elems to right of pivot */
00612          A(i, k) /= pivot;
00613       for (k=0; k<4; k++)
00614          inv(i, k) /= pivot;
00615       /* we know that A(i, i) will be set to 1, so don't bother to do it */
00616 
00617       for (j=i+1; j<4; j++) {         /* eliminate in rows below i */
00618          t = A(j, i);                 /* we're gonna zero this guy */
00619          for (k=i+1; k<4; k++)        /* subtract scaled row i from row j */
00620             A(j, k) -= A(i, k)*t;     /* (ignore k<=i, we know they're 0) */
00621          for (k=0; k<4; k++)
00622             inv(j, k) -= inv(i, k)*t;
00623       }
00624    }
00625 
00626    /*---------- backward elimination ----------*/
00627 
00628    for (i=4-1; i>0; i--) {            /* eliminate in column i, above diag */
00629       for (j=0; j<i; j++) {           /* eliminate in rows above i */
00630          t = A(j, i);                 /* we're gonna zero this guy */
00631          for (k=0; k<4; k++)          /* subtract scaled row i from row j */
00632              inv(j, k) -= inv(i, k)*t;
00633       }
00634    }
00635 
00636    inv.perspective = perspective;
00637    
00638    return detr;
00639 
00640 }
00641 
00642 /*!
00643  *  Returns the derivative of the map "mult by this matrix".  Of
00644  *  course, this is only interesting for perspective matrices, since
00645  *  otherwise the derivative is the matrix itself. (We can ignore the
00646  *  translational component of the matrix since the derivative should
00647  *  only be multiplied with vectors, and the translational component
00648  *  doesn't affect them).
00649  *
00650  *  \param[in] p The point at which the derivative is computed.
00651  *
00652  *  \note The derivative is only computed for matrices with
00653  *  perspective set to true.
00654  *
00655  */
00656 template <typename M,typename P, typename V, typename L, typename Q>
00657 MLIB_INLINE
00658 M 
00659 mlib::Mat4<M,P,V,L,Q>::derivative(const P& p) const
00660 {
00661    const M &t = (const M&)(*this);
00662    
00663    if (!perspective)
00664       return t;
00665 
00666    double h = t(3,0)*p[0] + t(3,1)*p[1] + t(3,2)*p[2] + t(3,3);
00667    if (fabs(h) < 1e-6) {
00668       cerr << "Mat4::derivative: bad homogeneous coordinate" << endl;
00669       return t;
00670    }
00671    P q = t * p;
00672    V px(q[0], q[1], q[2]);
00673 
00674    return M(
00675       (t.X() - t(3,0)*px)/h,
00676       (t.Y() - t(3,1)*px)/h,
00677       (t.Z() - t(3,2)*px)/h
00678       );
00679 }
00680 
00681 template <typename M,typename P, typename V, typename L, typename Q>
00682 MLIB_INLINE
00683 M
00684 mlib::Mat4<M,P,V,L,Q>::unscaled() const
00685 {
00686    P o;
00687    V x,y,z;
00688    get_coord_system(o,x,y,z);
00689 
00690    return M(o,x,y,z);
00691 }
00692 
00693 /*!
00694  *  Return a copy of the matrix with the axes of the coordinate
00695  *  system it defines normalized and the origin of that coordinate system
00696  *  replaced with the origin of the world coordinate system, (0, 0, 0).
00697  *
00698  */
00699 template <typename M,typename P, typename V, typename L, typename Q>
00700 MLIB_INLINE
00701 M
00702 mlib::Mat4<M,P,V,L,Q>::normalized_basis() const
00703 {
00704    P o;
00705    V x,y,z;
00706    get_coord_system(o,x,y,z);
00707 
00708    return M(P(),x,y,z);
00709 }
00710 
00711 /*!
00712  *  Creates a new matrix that defines a coordinate system with the
00713  *  same origin as the coordinate system defined by the original matrix,
00714  *  but x-axis normalized, the y-axis redefined to be perpendicular to the
00715  *  x-axis (and also unit length), and the z-axis redefined to be
00716  *  perpendicular to both (but the same length as before).
00717  *
00718  *  \todo Come up with a better description of this function.
00719  *
00720  */
00721 template <typename M,typename P, typename V, typename L, typename Q>
00722 MLIB_INLINE
00723 M
00724 mlib::Mat4<M,P,V,L,Q>::orthogonalized() const
00725 {
00726    P o;
00727    V x,y,z;
00728    get_coord_system(o,x,y,z);
00729 
00730    V xn(x.normalized());
00731    y = (y - (xn * (xn*y))).normalized() * y.length();
00732    V yn(y.normalized());
00733    z = cross(xn,yn).normalized() * z.length();
00734 
00735    return align_and_scale(o,x,y,z);
00736 }
00737 
00738 template <typename M, typename P, typename V, typename L, typename Q>
00739 MLIB_INLINE
00740 P
00741 mlib::operator*(const Mat4<M,P,V,L,Q> &m, const P& p)
00742 {  
00743    Vec4 p4(p, 1.0);
00744    if (m.is_perspective()) {
00745       double hcoord = m(3,0)*p[0] + m(3,1)*p[1]
00746                     + m(3,2)*p[2] + m(3,3);
00747       if (hcoord != 0.0) {
00748          hcoord = 1.0/hcoord;
00749       } else {
00750          cerr << "Bad homogeneous coordinate - divide by zero" << endl;
00751          // isError = true;
00752       }
00753       //return P(t(0,0)*p[0] + t(0,1)*p[1] + t(0,2)*p[2] + t(0,3),
00754       //         t(1,0)*p[0] + t(1,1)*p[1] + t(1,2)*p[2] + t(1,3),
00755       //         t(2,0)*p[0] + t(2,1)*p[1] + t(2,2)*p[2] + t(2,3))
00756       //         * hcoord;
00757       return P(m[0] * p4 * hcoord, m[1] * p4 * hcoord, m[2] * p4 * hcoord);
00758    } else {
00759       return P(m[0] * p4, m[1] * p4, m[2] * p4);
00760    }
00761 }
00762 
00763 
00764 template <typename M, typename P, typename V, typename L, typename Q>
00765 MLIB_INLINE
00766 V
00767 mlib::operator*(const Mat4<M,P,V,L,Q> &m, const Vec3<V>& v)
00768 {     
00769    Vec4 v4(v, 0.0);
00770    return V(m[0] * v4, m[1] * v4, m[2] * v4);
00771 }
00772 
00773 
00774 template <typename M, typename P, typename V, typename L, typename Q>
00775 MLIB_INLINE
00776 L
00777 mlib::operator*(const Mat4<M,P,V,L,Q> &m, const Line<L,P,V>& l)
00778 {
00779    return L(m * l.point(), m * l.vector());
00780 }
00781 
00782 
00783 template <typename M, typename P, typename V, typename L, typename Q>
00784 MLIB_INLINE
00785 bool
00786 mlib::Mat4<M,P,V,L,Q>::is_identity() const
00787 {
00788    static const double EPS = gEpsAbsMath*1e2;
00789    return fabs(row[0][0]-1)<EPS && fabs(row[1][1]-1)<EPS && fabs(row[2][2]-1)<EPS&&
00790           fabs(row[3][3]-1)<EPS && fabs(row[0][1])<EPS && fabs(row[0][2])<EPS &&
00791           fabs(row[0][3])<EPS && fabs(row[1][0])<EPS && fabs(row[1][2])<EPS &&
00792           fabs(row[1][3])<EPS && fabs(row[2][0])<EPS && fabs(row[2][1])<EPS &&
00793           fabs(row[2][3])<EPS && fabs(row[3][0])<EPS && fabs(row[3][1])<EPS &&
00794           (row[3][2]==0);
00795 }
00796 
00797 
00798 template <typename M,typename P, typename V, typename L, typename Q>
00799 MLIB_INLINE
00800 bool 
00801 mlib::Mat4<M,P,V,L,Q>::is_orthogonal() const
00802 {
00803    P  origin;
00804    V x;
00805    V y;
00806    V z;
00807 
00808    get_coord_system(origin, x, y, z);
00809 
00810    return x.is_perpend(y) && y.is_perpend(z) && z.is_perpend(x);
00811 }
00812 
00813 template <typename M,typename P, typename V, typename L, typename Q>
00814 MLIB_INLINE
00815 bool 
00816 mlib::Mat4<M,P,V,L,Q>::is_equal_scaling_orthogonal() const
00817 {
00818    if (!is_orthogonal())
00819       return false;
00820 
00821    V s = get_scale();
00822 
00823    return fabs(s[0]/s[1] - 1) < epsNorMath() && 
00824           fabs(s[1]/s[2] - 1) < epsNorMath() &&
00825           fabs(s[2]/s[0] - 1) < epsNorMath();
00826 }
00827 
00828 
00829 template <typename M,typename P, typename V, typename L, typename Q>
00830 MLIB_INLINE
00831 M 
00832 mlib::Mat4<M,P,V,L,Q>::transpose() const
00833 {
00834    M  ret;
00835 
00836    for (int i = 0; i < 4; i++)
00837       for (int j = 0; j < 4; j++)
00838          ret(i,j) = row[j][i];
00839 
00840    return ret;
00841 }
00842 
00843 /*!
00844  *  \libgfx This function was taken directly from libgfx (it was only modified
00845  *  to make it into a member function).
00846  *
00847  */
00848 template <typename M,typename P, typename V, typename L, typename Q>
00849 MLIB_INLINE
00850 M
00851 mlib::Mat4<M,P,V,L,Q>::adjoint() const
00852 {
00853     M A;
00854 
00855     A[0] = -cross( row[1], row[2], row[3]);
00856     A[1] = -cross(-row[0], row[2], row[3]);
00857     A[2] = -cross( row[0], row[1], row[3]);
00858     A[3] = -cross(-row[0], row[1], row[2]);
00859         
00860     return A;
00861 }
00862 
00863 /*!
00864  *  As align(src1, src2, src3, dst1, dst2, dst3), but src3 and dst3 are equal
00865  *  and computed to be cross(src2, dst2).  If cross(src2, dst2) is the null
00866  *  vector, then src3 and dst3 are perpendicular to src2 (computed using an
00867  *  arbitrary axis algorithm) is src2 and dst2 point away from each other.
00868  *  Otherwise, a translation matrix from sr1 to dst1 is returned.
00869  *
00870  */
00871 template <typename M,typename P, typename V, typename L, typename Q>
00872 MLIB_INLINE
00873 M 
00874 mlib::Mat4<M,P,V,L,Q>::align(
00875    const P&  src1,
00876    const V&  src2,
00877    const P&  dst1,
00878    const V&  dst2
00879    )
00880 {
00881    V planeNormal = cross(src2, dst2);
00882 
00883    if (planeNormal.is_null()) {
00884       if (src2 * dst2 < 0) {
00885          planeNormal = src2.perpend();
00886       } else {
00887          return translation(dst1 - src1);
00888       }
00889    }
00890 
00891    return align(src1, src2, planeNormal, dst1, dst2, planeNormal);
00892 }
00893 
00894 
00895 
00896 /*!
00897  *  The transformation maps points and vectors as follows:
00898  *  
00899  *  <tt>
00900  *  point src1            --> point  dst1
00901  *  vec src2              --> vector dst2
00902  *  plane(src1,src2,src3) --> plane(dst1,dst2,dst3)
00903  *  </tt>
00904  *
00905  */
00906 template <typename M,typename P, typename V, typename L, typename Q>
00907 MLIB_INLINE
00908 M 
00909 mlib::Mat4<M,P,V,L,Q>::align(
00910    const P& src1,
00911    const V& src2,
00912    const V& src3,
00913    const P& dst1,
00914    const V& dst2,
00915    const V& dst3
00916    )
00917 {
00918     // isError = false;
00919 
00920    const M t1 = M(src1, src2, src3);
00921 
00922 //    checkError(!isError, eSourceArgumentsAreColinearOrCoincident);
00923 
00924    const M t2 = M(dst1, dst2, dst3);
00925 
00926 //    checkError(!isError, eDestinationArgumentsAreColinearOrCoincident);
00927 
00928    return t2 * t1.inverse();
00929 }
00930 
00931 /*!
00932  *  The transformation maps points as follows:
00933  *  
00934  *  point  src1             maps to point  dst1
00935  *  vec    (src1,src2)      maps to vector (dst1,dst2)
00936  *  plane  (src1,src2,src3) maps to plane  (dst1,dst2,dst3)
00937  *
00938  */
00939 template <typename M,typename P, typename V, typename L, typename Q>
00940 MLIB_INLINE
00941 M 
00942 mlib::Mat4<M,P,V,L,Q>::align(
00943    const P& src1,
00944    const P& src2,
00945    const P& src3,
00946    const P& dst1,
00947    const P& dst2,
00948    const P& dst3
00949    )
00950 {
00951    return align(src1, src2-src1, src3-src1, dst1, dst2-dst1, dst3-dst1);
00952 }
00953 
00954 /*!
00955  *  Construct a rigid motion transformation from given coordinate
00956  *  system (origin,xx,yy,zz). This transformation will
00957  *  transform points from (origin,xx,yy,zz) to world.
00958  *  The axes xx, yy, and zz are not normalized before the matrix is constructed.
00959  *
00960  */
00961 template <typename M,typename P, typename V, typename L, typename Q>
00962 MLIB_INLINE
00963 M
00964 mlib::Mat4<M,P,V,L,Q>::align_and_scale(
00965    const P& origin,
00966    const V& xx,
00967    const V& yy,
00968    const V& zz
00969    )
00970 {
00971    assert(!xx.is_null());
00972    assert(!yy.is_null());
00973    assert(!zz.is_null());
00974 
00975    M t;
00976 
00977    for (int i = 0; i < 3; i++)       {
00978       t(i,0) = xx    [i];
00979       t(i,1) = yy    [i];
00980       t(i,2) = zz    [i];
00981       t(i,3) = origin[i];
00982       t(3,i) = 0.0;
00983    }
00984    t(3,3) = 1.0;
00985 
00986    return t;
00987 }
00988 
00989 /*!
00990  *  \libgfx This function was take directly from libgfx (it was only
00991  *  modified to make it into a static member function).
00992  *
00993  */
00994 template <typename M,typename P, typename V, typename L, typename Q>
00995 MLIB_INLINE
00996 M
00997 mlib::Mat4<M,P,V,L,Q>::glu_perspective(double fovy, double aspect, 
00998                                        double zmin, double zmax)
00999 {
01000    double A, B;
01001    M t;
01002    
01003    if( zmax==0.0 ){
01004       A = B = 1.0;
01005    } else {
01006       A = (zmax+zmin)/(zmin-zmax);
01007       B = (2*zmax*zmin)/(zmin-zmax);
01008    }
01009    
01010    double f = 1.0/tan(fovy*M_PI/180.0/2.0);
01011    t(0,0) = f/aspect;
01012    t(1,1) = f;
01013    t(2,2) = A;
01014    t(2,3) = B;
01015    t(3,2) = -1;
01016    t(3,3) = 0;
01017    
01018    t.perspective = true;
01019    
01020    return t;
01021 }
01022 
01023 /*!
01024  *  \libgfx This function was take directly from libgfx (it was only
01025  *  modified to make it into a static member function).
01026  *
01027  */
01028 template <typename M,typename P, typename V, typename L, typename Q>
01029 MLIB_INLINE
01030 M
01031 mlib::Mat4<M,P,V,L,Q>::glu_lookat(const V& from, const V& at, const V& v_up)
01032 {
01033     V up = v_up.normalized();
01034     V f = (at - from).normalized();
01035 
01036     // NOTE: Normalization in these two steps is left out of the GL man page!!
01037     V s = cross(f, up).normalized();
01038     V u = cross(s, f).normalized();
01039 
01040     M t(Vec4(s, 0), Vec4(u, 0), Vec4(-f, 0), Vec4(0, 0, 0, 1));
01041 
01042     return t * translation(-from);
01043 }
01044 
01045 /*!
01046  *  \libgfx This function was take directly from libgfx (it was only
01047  *  modified to make it into a static member function).
01048  *
01049  */
01050 template <typename M,typename P, typename V, typename L, typename Q>
01051 MLIB_INLINE
01052 M
01053 mlib::Mat4<M,P,V,L,Q>::gl_viewport(double w, double h)
01054 {
01055     return scaling(V(w/2.0, -h/2.0, 1)) * translation(V(1, -1, 0));
01056 }
01057 
01058 template <typename M,typename P, typename V, typename L, typename Q>
01059 MLIB_INLINE
01060 bool 
01061 mlib::Mat4<M,P,V,L,Q>::is_valid() const
01062 {
01063    const V x = V(row[0][0], row[1][0], row[2][0]).normalized();
01064    const V y = V(row[0][1], row[1][1], row[2][1]).normalized();
01065    const V z = V(row[0][2], row[1][2], row[2][2]).normalized();
01066 
01067    return (fabs(mlib::det(x, y, z)) > epsNorMath());
01068 }
01069 
01070 
01071 
01072 
01073 template <typename M,typename P, typename V, typename L, typename Q>
01074 MLIB_INLINE
01075 ostream &
01076 mlib::operator << (ostream &os, const Mat4<M,P,V,L,Q> &x) 
01077 {
01078    os<<"["<<
01079        "["<<x(0,0)<<","<<x(0,1)<<","<<x(0,2)<<","<<x(0,3)<<"]"<<endl<<
01080        "["<<x(1,0)<<","<<x(1,1)<<","<<x(1,2)<<","<<x(1,3)<<"]"<<endl<<
01081        "["<<x(2,0)<<","<<x(2,1)<<","<<x(2,2)<<","<<x(2,3)<<"]"<<endl<<
01082        "["<<x(3,0)<<","<<x(3,1)<<","<<x(3,2)<<","<<x(3,3)<<"]"<<endl<<
01083        "]"<<endl;
01084    return os; 
01085 }

Generated on Mon Sep 18 11:39:32 2006 for jot by  doxygen 1.4.4