00001 00005 /* 00006 * Author: Steven Ludtke (sludtke@bcm.edu) 00007 * Copyright (c) 2000-2006 Baylor College of Medicine 00008 * 00009 * This software is issued under a joint BSD/GNU license. You may use the 00010 * source code in this file under either license. However, note that the 00011 * complete EMAN2 and SPARX software packages have some GPL dependencies, 00012 * so you are responsible for compliance with the licenses of these packages 00013 * if you opt to use BSD licensing. The warranty disclaimer below holds 00014 * in either instance. 00015 * 00016 * This complete copyright notice must be included in any revised version of the 00017 * source code. Additional authorship citations may be added, but existing 00018 * author citations must be preserved. 00019 * 00020 * This program is free software; you can redistribute it and/or modify 00021 * it under the terms of the GNU General Public License as published by 00022 * the Free Software Foundation; either version 2 of the License, or 00023 * (at your option) any later version. 00024 * 00025 * This program is distributed in the hope that it will be useful, 00026 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00027 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00028 * GNU General Public License for more details. 00029 * 00030 * You should have received a copy of the GNU General Public License 00031 * along with this program; if not, write to the Free Software 00032 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00033 * 00034 * */ 00035 00036 00037 #ifndef eman__transform_h__ 00038 #define eman__transform_h__ 1 00039 00040 #ifdef _WIN32 00041 #pragma warning(disable:4819) 00042 #endif //_WIN32 00043 00044 #include "vec3.h" 00045 #include "emobject.h" 00046 #include <cstdio> 00047 // #include <vector> 00048 // using std::vector; 00049 // 00050 // #include <map> 00051 // using std::map; 00052 // 00053 // #include <string> 00054 // using std::string; 00055 00056 00057 00058 namespace EMAN 00059 { 00083 class Transform { 00084 // friend Transform EMAN::operator*(const Transform & M2, const Transform & M1); 00085 public: 00086 static const float ERR_LIMIT; 00087 00091 Transform(); 00092 00096 Transform( const Transform& rhs ); 00097 00101 Transform& operator=(const Transform& that); 00102 00107 bool operator==(const Transform& rhs) const; 00108 00113 bool operator!=(const Transform& rhs) const; 00114 00118 Transform(const Dict& d); 00119 00123 Transform(const float array[12]); 00124 00128 Transform(const vector<float> array); 00129 00130 00131 ~Transform() { } 00132 00137 void set_rotation( const Dict &rotation ); 00138 00144 void set_rotation(const Vec3f & v); 00145 00150 Dict get_rotation(const string& euler_type = "eman") const; 00151 00152 00156 Transform get_rotation_transform() const; 00157 00161 Transform get_hflip_transform() const; 00162 00166 Transform get_vflip_transform() const; 00167 00173 void set_params(const Dict& d); 00174 00181 void set_params_inverse(const Dict& d); 00182 00187 Dict get_params(const string& euler_type) const; 00188 00193 Dict get_params_inverse(const string& euler_type) const; 00194 00195 //=============== set and get post trans ============= 00201 void set_trans(const float& x, const float& y, const float& z=0); 00202 00206 inline void set_trans(const Vec3f& v) { set_trans(v[0],v[1],v[2]); } 00207 00211 inline void set_trans(const Vec2f& v) { set_trans(v[0],v[1]); } 00212 00216 Vec3f get_trans() const; 00217 00221 Vec2f get_trans_2d() const; 00222 00223 //================= get pre trans is supported ========= 00224 00229 Vec3f get_pre_trans() const; 00230 00235 Vec2f get_pre_trans_2d() const; 00236 00241 template<typename type> 00242 void set_pre_trans(const type& v); 00243 00244 //=============== set and get scale ============= 00248 void set_scale(const float& scale); 00249 00253 float get_scale() const; 00254 00255 //=============== set and get post x mirror ============= 00259 bool get_mirror() const; 00260 00264 void set_mirror(const bool x_mirror); 00265 00266 //=============== other stuff ============================ 00272 void get_scale_and_mirror(float& scale, bool& x_mirror) const; 00273 00276 void to_identity(); 00277 00280 bool is_identity() const; 00281 00288 void orthogonalize(); 00289 00293 float get_determinant() const; 00294 00297 void printme() const { 00298 printf("%8.6f %8.6f %8.6f %8.6f\n",matrix[0][0],matrix[0][1],matrix[0][2],matrix[0][3]); 00299 printf("%8.6f %8.6f %8.6f %8.6f\n",matrix[1][0],matrix[1][1],matrix[1][2],matrix[1][3]); 00300 printf("%8.6f %8.6f %8.6f %8.6f\n",matrix[2][0],matrix[2][1],matrix[2][2],matrix[2][3]); 00301 printf("%8.6f %8.6f %8.6f %8.6f\n",0.0,0.0,0.0,1.0); 00302 00303 } 00304 00305 //=============== get set matrix ============================ 00309 void set_matrix(const vector<float>& v); 00310 00314 vector<float> get_matrix() const; 00315 00319 void invert(); 00320 00324 Transform inverse() const; 00325 00328 void transpose_inplace(); 00329 00333 Transform transpose() const; 00334 00337 inline float at(int r,int c) const { return matrix[r][c]; } 00338 00341 inline void set(int r, int c, float value) { matrix[r][c] = value; } 00342 00346 inline float * operator[] (int i) { return matrix[i]; } 00347 00351 inline const float * operator[] (int i) const { return matrix[i]; } 00352 00358 inline Vec2f transform(const float& x, const float& y) const { 00359 // assert_valid_2d(); 00360 Vec2f ret; 00361 ret[0] = matrix[0][0]*x + matrix[0][1]*y + matrix[0][3]; 00362 ret[1] = matrix[1][0]*x + matrix[1][1]*y + matrix[1][3]; 00363 return ret; 00364 } 00365 00370 template<typename Type> 00371 inline Vec2f transform(const Vec2<Type>& v) const { 00372 return transform(v[0],v[1]); 00373 } 00374 00381 inline Vec3f transform(const float& x, const float& y, const float& z) const { 00382 // assert_consistent_type(THREED); 00383 Vec3f ret; 00384 ret[0] = matrix[0][0] * x + matrix[0][1] * y + matrix[0][2] * z + matrix[0][3]; 00385 ret[1] = matrix[1][0] * x + matrix[1][1] * y + matrix[1][2] * z + matrix[1][3]; 00386 ret[2] = matrix[2][0] * x + matrix[2][1] * y + matrix[2][2] * z + matrix[2][3]; 00387 return ret; 00388 } 00389 00394 template<typename Type> 00395 inline Vec3f transform(const Vec3<Type>& v) const { 00396 // assert_consistent_type(THREED); // Transform does the assertion 00397 return transform(v[0],v[1],v[2]); 00398 } 00399 00400 00406 inline Vec3f get_matrix3_row(int i) const { 00407 return Vec3f(matrix[i][0], matrix[i][1], matrix[i][2]); 00408 } 00409 00412 static int get_nsym(const string & sym); 00413 00418 Transform get_sym(const string & sym, int n) const; 00419 vector<Transform > get_sym_proj(const string & sym) const; 00420 00423 void copy_matrix_into_array(float* const) const; 00424 00429 Transform negate() const; 00430 00434 static Transform tet_3_to_2(); 00435 00439 static Transform icos_5_to_2(); 00440 00441 private: 00442 float matrix[3][4]; 00443 00444 void assert_valid_2d() const; 00445 00447 static vector<string> permissable_2d_not_rot; 00448 static vector<string> permissable_3d_not_rot; 00449 static map<string,vector<string> > permissable_rot_keys; 00450 00453 void init_permissable_keys(); 00454 00462 void detect_problem_keys(const Dict& d); 00463 00464 }; 00466 Transform operator*(const Transform & M2, const Transform & M1); 00467 00469 template<typename Type> 00470 Vec3f operator*( const Transform& M, const Vec3<Type> & v) 00471 { 00472 return M.transform(v); 00473 } 00474 00476 template<typename Type> 00477 Vec2f operator*( const Transform& M, const Vec2<Type> & v) 00478 { 00479 return M.transform(v); 00480 } 00481 00485 template<typename Type> 00486 Vec3f operator*(const Vec3<Type> & v, const Transform & M) 00487 { 00488 float x = v[0] * M[0][0] + v[1] * M[1][0] + v[2] * M[2][0] ; 00489 float y = v[0] * M[0][1] + v[1] * M[1][1] + v[2] * M[2][1]; 00490 float z = v[0] * M[0][2] + v[1] * M[1][2] + v[2] * M[2][2]; 00491 return Vec3f(x, y, z); 00492 } 00493 00494 template<typename type> 00495 void Transform::set_pre_trans(const type& v) { 00496 00497 Transform tmp; 00498 Dict rot = get_rotation("eman"); 00499 tmp.set_rotation(rot); 00500 00501 float scale = get_scale(); 00502 if (scale != 1.0 ) tmp.set_scale(scale); 00503 00504 Transform trans; 00505 trans.set_trans(v); 00506 00507 trans = tmp*trans; 00508 00509 Transform tmp2; 00510 tmp2.set_rotation(rot); 00511 tmp2.invert(); // invert 00512 if (scale != 1.0 ) tmp2.set_scale(1.0f/scale); 00513 00514 00515 trans = trans*tmp2; 00516 00517 set_trans(trans.get_trans()); 00518 } 00519 00563 // class Transform3D 00564 // { 00565 // public: 00566 // static const float ERR_LIMIT; 00567 // enum EulerType 00568 // { 00569 // UNKNOWN, 00570 // EMAN, 00571 // IMAGIC, 00572 // SPIN, 00573 // QUATERNION, 00574 // SGIROT, 00575 // SPIDER, 00576 // MRC, 00577 // XYZ, 00578 // MATRIX 00579 // }; 00580 // 00581 // /** Default constructor 00582 // * Internal matrix is the identity 00583 // */ 00584 // Transform3D(); 00585 // 00586 // /** Copy constructor 00587 // * @param rhs the object to be copied 00588 // */ 00589 // Transform3D( const Transform3D& rhs ); 00590 // 00591 // /** Construct a Transform3D object describing a rotation, assuming the EMAN Euler type 00592 // * @param az EMAN - az 00593 // * @param alt EMAN - alt 00594 // * @param phi EMAN - phi 00595 // */ 00596 // Transform3D(const float& az,const float& alt,const float& phi); // EMAN by default 00597 // 00598 // /** Construct a Transform3D object describing a rotation (assuming the EMAN Euler type) and 00599 // * a post translation 00600 // * @param az EMAN - az 00601 // * @param alt EMAN - alt 00602 // * @param phi EMAN - phi 00603 // * @param posttrans the post translation vector 00604 // */ 00605 // Transform3D(const float& az, const float& alt, const float& phi, const Vec3f& posttrans); 00606 // 00607 // /** Construct a Transform3D object describing a pre trans, a rotation 00608 // * assuming the EMAN Euler type) and a post translation 00609 // * @param pretrans the pre translation vector 00610 // * @param az EMAN - az 00611 // * @param alt EMAN - alt 00612 // * @param phi EMAN - phi 00613 // * @param posttrans the post translation vector 00614 // */ 00615 // Transform3D(const Vec3f & pretrans, const float& az,const float& alt,const float& phi, const Vec3f& posttrans); 00616 // 00617 // /** Construct a Transform3D object describing a rotation, using a specific Euler type. 00618 // * works for EMAN, SPIDER, MRC, IMAGIC and XYZ (Euler types required 3 parameters) 00619 // * @param euler_type the Euler type either EMAN, SPIDER, MRC, IMAGIC and XYZ 00620 // * @param a1 EMAN - az, SPIDER - phi, MRC - phi, IMAGIC - alpha, XYZ - xtilt 00621 // * @param a2 EMAN - alt, SPIDER - theta, MRC - theta, IMAGIC - beta, XYZ - ytilt 00622 // * @param a3 EMAN - phi, SPIDER - psi, MRC - omega, IMAGIC - gamma, XYZ - ztilt 00623 // */ 00624 // Transform3D(EulerType euler_type, const float& a1, const float& a2, const float& a3) ; 00625 // 00626 // /** Construct a Transform3D object describing a rotation, using a specific Euler type. 00627 // * Works for Euler types that require 4 parameters 00628 // * @param euler_type the Euler type either QUATERNION, SPIN or SGIROT 00629 // * @param a1 QUATERNION - e0, SPN and SGIROT - Omega 00630 // * @param a2 QUATERNION - e1, SPN and SGIROT - n1 00631 // * @param a3 QUATERNION - e2, SPN and SGIROT - n2 00632 // * @param a4 QUATERNION - e3, SPN and SGIROT - n3 00633 // */ 00634 // Transform3D(EulerType euler_type, const float& a1, const float& a2, const float& a3, const float& a4) ; // o 00635 // 00636 // /** Construct a Transform3D object consisting only of a rotation, using a specific Euler type. 00637 // * Works for all Euler types 00638 // * @param euler_type any Euler type 00639 // * @param rotation a dictionary containing all key-entry pair required of the associated Euler type 00640 // */ 00641 // Transform3D(EulerType euler_type, const Dict& rotation); 00642 // 00643 // /** Construct a Transform3D object consisting only of a rotation by initializing the internal 00644 // * rotation matrix component wise 00645 // * @param mij the value to be placed in the internal transformation matrix at coordinate (i-1,j-1) 00646 // */ 00647 // Transform3D(const float& m11, const float& m12, const float& m13, 00648 // const float& m21, const float& m22, const float& m23, 00649 // const float& m31, const float& m32, const float& m33); 00650 // 00651 // /** Destructor 00652 // */ 00653 // ~Transform3D(); 00654 // 00655 // /** FIXME insert comments 00656 // */ 00657 // void apply_scale(const float& scale); 00658 // 00659 // /** FIXME insert comments 00660 // */ 00661 // void set_scale(const float& scale); 00662 // 00663 // /** Reorthogonalize the matrix 00664 // */ 00665 // void orthogonalize(); 00666 // 00667 // /** create the transpose in place 00668 // */ 00669 // void transpose(); 00670 // 00671 // void set_rotation(const float& az, const float& alt,const float& phi); 00672 // 00673 // /** Sets the rotation as defined by the EulerType 00674 // * works for EMAN, SPIDER, MRC, IMAGIC and XYZ 00675 // * @param euler_type the Euler type either EMAN, SPIDER, MRC, IMAGIC and XYZ 00676 // * @param a1 EMAN - az, SPIDER - phi, MRC - phi, IMAGIC - alpha, XYZ - xtilt 00677 // * @param a2 EMAN - alt, SPIDER - theta, MRC - theta, IMAGIC - beta, XYZ - ytilt 00678 // * @param a3 EMAN - phi, SPIDER - psi, MRC - omega, IMAGIC - gamma, XYZ - ztilt 00679 // */ 00680 // void set_rotation(EulerType euler_type,const float& a1,const float& a2,const float& a3); 00681 // 00682 // /** Set quaternion-based rotations 00683 // * Works for QUATERNION, SPIN and SGIROT 00684 // * @param euler_type the Euler type either QUATERNION, SPIN or SGIROT 00685 // * @param a1 QUATERNION - e0, SPN and SGIROT - Omega 00686 // * @param a2 QUATERNION - e1, SPN and SGIROT - n1 00687 // * @param a3 QUATERNION - e2, SPN and SGIROT - n2 00688 // * @param a4 QUATERNION - e3, SPN and SGIROT - n3 00689 // */ 00690 // void set_rotation(EulerType euler_type,const float& a1,const float& a2,const float& a3, const float& a4); 00691 // 00692 // /** set the internal rotation matrix component wise 00693 // * @param mij the value to be placed in the internal transformation matrix at coordinate (i-1,j-1) 00694 // */ 00695 // void set_rotation(const float& m11, const float& m12, const float& m13, 00696 // const float& m21, const float& m22, const float& m23, 00697 // const float& m31, const float& m32, const float& m33); 00698 // 00702 // 00703 // /** Set a rotation using a specific Euler type and the dictionary interface 00704 // * Works for all Euler types 00705 // * @param euler_type any Euler type 00706 // * @param rotation a dictionary containing all key-entry pair required of the associated Euler type 00707 // */ 00708 // void set_rotation(EulerType euler_type, const Dict &rotation ); 00709 // 00710 // /** Get a rotation in any Euler format 00711 // * @param euler_type the requested Euler type 00712 // * @return a dictionary containing the key-entry pairs describing the rotations in terms of the requested Euler type 00713 // */ 00714 // Dict get_rotation(EulerType euler_type=EMAN) const; 00715 // 00716 // /** returns a rotation that maps a pair of unit vectors, a,b to a second pair A,B 00717 // * @param eahat, ebhat, eAhat, eBhat are all unit vectors 00718 // * @return a transform3D rotation 00719 // */ 00720 // void set_rotation(const Vec3f & eahat, const Vec3f & ebhat, 00721 // const Vec3f & eAhat, const Vec3f & eBhat); 00722 // /** returns the magnitude of the rotation 00723 // */ 00724 // float get_mag() const; 00725 // 00726 // /** returns the spin-axis (or finger) of the rotation 00727 // */ 00728 // Vec3f get_finger() const; 00729 // 00730 // /** Gets one of two pre translation vectors 00731 // * @param flag if 0 returns the pre translation vector, if 1 all translation is treated as pre 00732 // * @return the translation vector 00733 // */ 00734 // Vec3f get_pretrans( int flag=0) const; // flag=1 => all trans is pre 00735 // 00736 // /** Gets one of two post translation vectors. 00737 // * when the flag is 1 then the contents of the Transform3D matrix right column are returned 00738 // * @param flag if 0 returns the post translation vector, if 1 all translation is treated as post 00739 // * @return the translation vector 00740 // */ 00741 // Vec3f get_posttrans(int flag=0) const; // flag=1 => all trans is post 00742 // 00743 // /** Get the total translation as a post translation. Calls get_postrans(1) 00744 // * @return the translation vector 00745 // */ 00746 // Vec3f get_total_posttrans() const; 00747 // 00748 // /** Get the total translation as a pre translation. Calls get_pretrans(1) 00749 // * @return the translation vector 00750 // */ 00751 // Vec3f get_total_pretrans() const; 00752 // 00753 // /** This doesn't do anything, it returns an empty vector. Why is it being used? 00754 // */ 00755 // Vec3f get_center() const; // This doesn't do anything 00756 // 00757 // /** Get a matrix column as a Vec3f 00758 // * @param i the column number (starting at 0) 00759 // * @return the ith column 00760 // */ 00761 // Vec3f get_matrix3_col(int i) const; 00762 // 00763 // /** Get a matrix row as a Vec3f 00764 // * @param i the row number (starting at 0) 00765 // * @return the ith row 00766 // */ 00767 // Vec3f get_matrix3_row(int i) const; 00768 // 00769 // /** Perform a full transform a Vec3f using the internal transformation matrix 00770 // * @param v3f the vector to be transformed 00771 // * @return the transformed vector 00772 // */ 00773 // Vec3f transform(const Vec3f & v3f) const; 00774 // 00775 // /** Rotate a Vec3f using the internal rotation matrix 00776 // * @param v3f the vector to be rotated 00777 // * @return the rotated vector 00778 // */ 00779 // Vec3f rotate(const Vec3f & v3f) const; 00780 // 00781 // /** FIXME insert comments 00782 // */ 00783 // Transform3D inverseUsingAngs() const; 00784 // 00785 // /** FIXME insert comments 00786 // */ 00787 // Transform3D inverse() const; 00788 // 00789 // 00790 // /** Print the Transform3D matrix 00791 // */ 00792 // void printme() const { 00793 // for (int i=0; i<3; i++) { 00794 // printf("%6.15f\t%6.15f\t%6.15f\t%6.1f\n", 00795 // matrix[i][0],matrix[i][1],matrix[i][2],matrix[i][3]); 00796 // } 00797 // printf("%6.3f\t%6.3f\t%6.3f\t%6.3f\n",0.0,0.0,0.0,1.0); 00798 // printf("\n"); 00799 // } 00800 // 00801 // /** Get the value stored in the internal transformation matrix at at coordinate (r,c) 00802 // */ 00803 // inline float at(int r,int c) const { return matrix[r][c]; } 00804 // 00805 // /** Set the value stored in the internal transformation matrix at at coordinate (r,c) to value 00806 // */ 00807 // void set(int r, int c, float value) { matrix[r][c] = value; } 00808 // 00809 // /** Operator[] convenience 00810 // * so Transform3D[2][2] etc terminology can be used 00811 // */ 00812 // inline float * operator[] (int i) { return matrix[i]; } 00813 // 00814 // /** Operator[] convenience 00815 // * so Transform3D[2][2] etc terminology can be used 00816 // */ 00817 // inline const float * operator[] (int i) const { return matrix[i]; } 00818 // 00819 // static int get_nsym(const string & sym); 00820 // Transform3D get_sym(const string & sym, int n) const; 00821 // 00822 // /** Set functions FIXME insert more comments from here down 00823 // */ 00824 // void set_center(const Vec3f & center); 00825 // void set_pretrans(const Vec3f & pretrans); 00826 // void set_pretrans(const float& dx, const float& dy, const float& dz); 00827 // void set_pretrans(const float& dx, const float& dy); 00828 // void set_pretrans(const Vec2f& pretrans); 00829 // void set_posttrans(const Vec3f & posttrans); 00830 // void set_posttrans(const float& dx, const float& dy, const float& dz); 00831 // void set_posttrans(const float& dx, const float& dy); 00832 // void set_posttrans(const Vec2f& posttrans); 00833 // 00834 // void set_post_x_mirror(const bool b) { post_x_mirror = b; } 00835 // bool get_post_x_mirror() const { return post_x_mirror; } 00836 // 00837 // float get_scale() const; 00838 // 00839 // void to_identity(); 00840 // bool is_identity(); 00841 // 00842 // /** Convert a list of euler angles to a vector of Transform3D objects. 00843 // * 00844 // * @param[in] eulertype The type of Euler angles that is being passed in. 00845 // * @param[in] angles A flat vector of angles. 00846 // * 00847 // * @return Vector of pointers to Transform3D objects. 00848 // */ 00849 // static vector<Transform3D*> 00850 // angles2tfvec(EulerType eulertype, const vector<float> angles); 00851 // 00852 // /** This added by d.woolford, will eventually be removed by author 00853 // */ 00854 // void dsaw_zero_hack(){ 00855 // for (int j=0; j<4; ++j) { 00856 // for (int i=0; i<4; i++) { 00857 // if ( fabs(matrix[j][i]) < 0.000001 ) 00858 // matrix[j][i] = 0.0; 00859 // } 00860 // } 00861 // 00862 // } 00863 // 00864 // protected: 00865 // enum SymType 00866 // { CSYM, 00867 // DSYM, 00868 // TET_SYM, 00869 // ICOS_SYM, 00870 // OCT_SYM, 00871 // ISYM, 00872 // UNKNOWN_SYM 00873 // }; 00874 // 00875 // void init(); 00876 // 00877 // static SymType get_sym_type(const string & symname); 00878 // 00879 // float matrix[4][4]; 00880 // 00881 // bool post_x_mirror; 00882 // 00883 // Transform3D::EulerType s; 00884 // }; // ends Class 00885 // 00886 // Transform3D operator*(const Transform3D & M1, const Transform3D & M2); 00887 // Vec3f operator*(const Vec3f & v , const Transform3D & M); 00888 // Vec3f operator*(const Transform3D & M, const Vec3f & v ); 00889 00890 // template<typename Type> 00891 // Vec3f operator*(const Vec3<Type> & v, const Transform3D & M) // YYY 00892 // { 00894 // float x = v[0] * M[0][0] + v[1] * M[1][0] + v[2] * M[2][0] ; 00895 // float y = v[0] * M[0][1] + v[1] * M[1][1] + v[2] * M[2][1]; 00896 // float z = v[0] * M[0][2] + v[1] * M[1][2] + v[2] * M[2][2]; 00897 // return Vec3f(x, y, z); 00898 // } 00899 // 00900 // template<typename Type> 00901 // Vec3f operator*( const Transform3D & M, const Vec3<Type> & v) // YYY 00902 // { 00904 // float x = M[0][0] * v[0] + M[0][1] * v[1] + M[0][2] * v[2] + M[0][3]; 00905 // float y = M[1][0] * v[0] + M[1][1] * v[1] + M[1][2] * v[2] + M[1][3]; 00906 // float z = M[2][0] * v[0] + M[2][1] * v[1] + M[2][2] * v[2] + M[2][3]; 00907 // return Vec3f(x, y, z); 00908 // } 00909 // 00910 // 00911 // template<typename Type> 00912 // Vec2f operator*( const Transform3D & M, const Vec2<Type> & v) // YYY 00913 // { 00915 // float x = M[0][0] * v[0] + M[0][1] * v[1] + M[0][3] ; 00916 // float y = M[1][0] * v[0] + M[1][1] * v[1] + M[1][3]; 00917 // return Vec2f(x, y); 00918 // } 00919 00920 } // ends NameSpace EMAN 00921 00922 00923 00924 #endif 00925 00926 00927 /* vim: set ts=4 noet: */