00001 #ifndef vimt3d_transform_3d_h_ 00002 #define vimt3d_transform_3d_h_ 00003 //: 00004 // \file 00005 // \brief A class to define and apply a 3D transformation up to affine. 00006 // \author Graham Vincent, Tim Cootes 00007 00008 #include <vsl/vsl_binary_io.h> 00009 #include <vgl/vgl_point_3d.h> 00010 #include <vgl/vgl_vector_3d.h> 00011 #include <vnl/io/vnl_io_matrix.h> 00012 00013 //======================================================================= 00014 00015 //: A class to define and apply a 3D transform. 00016 // The transform which can be up to an affine transformation. 00017 // In order of complexity the transform can be 00018 // - Identity x->x, y->y, z->z 00019 // - Translation x->x + tx, y->y + ty, z->z + tz 00020 // - RigidBody (Rotation, followed by translation) 00021 // - Similarity (Isotropic scaling, followed by rotation, then translation) 00022 // - ZoomOnly (Anisotropic scaling, followed by translation) 00023 // - Affine 00024 // 00025 // One useful special case of Affine involves anisotropic scaling, followed 00026 // by rotation, then translation. 00027 // 00028 // The transform types Translation, ZoomOnly, RigidBody and Similarity have 00029 // a defined order in which scaling, rotation and translation components 00030 // are applied, and the components are thus separable. 00031 // Other transformations (e.g. translation followed by rotation) can be 00032 // obtained by composing multiple transforms. The resulting transform will 00033 // in general be termed affine. 00034 // 00035 // The transformation can be represented by a 4x4 matrix of 00036 // homogeneous co-ordinates. 00037 // \verbatim 00038 // ( xx xy xz xt ) 00039 // ( yx yy yz yt ) 00040 // ( zx zy zz zt ) 00041 // ( tx ty tz tt ) 00042 // \endverbatim 00043 // For efficiency the elements are stored explicitly, rather than in a 00044 // vnl_matrix<double>, to avoid lots of copying of matrices with all the 00045 // attendant memory allocation. 00046 class vimt3d_transform_3d 00047 { 00048 public: 00049 00050 //: Defines form of transformation 00051 enum Form {Identity, 00052 Translation, 00053 ZoomOnly, //!< Anisotropic scaling, followed by translation 00054 RigidBody, //!< Rotation, followed by translation 00055 Similarity, //!< Isotropic scaling, followed by rotation, then translation 00056 Affine}; 00057 00058 //: Construct as identity transform 00059 vimt3d_transform_3d() : 00060 xx_(1), xy_(0), xz_(0), xt_(0), 00061 yx_(0), yy_(1), yz_(0), yt_(0), 00062 zx_(0), zy_(0), zz_(1), zt_(0), 00063 tx_(0), ty_(0), tz_(0), tt_(1), 00064 form_(Identity), inv_uptodate_(false) {} 00065 00066 // An explicit destructor is required to avoid an internal compiler 00067 // error in icc 8.0 (internal error: 0_1270) 00068 00069 //: Destructor 00070 ~vimt3d_transform_3d() {} 00071 00072 //: True if identity. 00073 bool is_identity() const { return form_==Identity; } 00074 00075 //: Form of transformation. 00076 Form form() const { return form_; } 00077 00078 //: Gets 4x4 Matrix representing transformation 00079 vnl_matrix<double> matrix() const; 00080 00081 //: Gets 4x4 Matrix representing transformation 00082 // \retval M a 4x4 Matrix representing transformation 00083 void matrix(vnl_matrix<double>& M) const; 00084 00085 //: Fills v with parameters 00086 void params(vnl_vector<double>& v) const; 00087 00088 //: Sets transform using v 00089 void set(const vnl_vector<double>& v, Form); 00090 00091 //: Sets transform to identity. 00092 void set_identity(); 00093 00094 //: Sets the transformation to be a translation. 00095 // \param t_x Translation in x 00096 // \param t_y Translation in y 00097 // \param t_z Translation in z 00098 void set_translation(double t_x, double t_y, double t_z); 00099 00100 //: Sets the transformation to be anisotropic scaling, followed by translation. 00101 // The transformation is separable affine. 00102 // x' = s_x.x + t_x, y' = s_y.y + t_y, z' = s_z.z + t_z 00103 // \param s_x Scaling in x 00104 // \param s_y Scaling in y 00105 // \param s_z Scaling in z 00106 // \param t_x Translation in x 00107 // \param t_y Translation in y 00108 // \param t_z Translation in z 00109 void set_zoom_only( double s_x, double s_y, double s_z, 00110 double t_x, double t_y, double t_z); 00111 00112 //: Sets the transformation to be isotropic scaling, followed by translation. 00113 // The transformation is separable affine. 00114 // x' = s.x + t_x, y' = s.y + t_y, z' = s.z + t_z 00115 // \param s Scaling in x, y and z 00116 // \param t_x Translation in x 00117 // \param t_y Translation in y 00118 // \param t_z Translation in z 00119 void set_zoom_only(double s, double t_x, double t_y, double t_z) 00120 { set_zoom_only(s, s, s, t_x, t_y, t_z); } 00121 00122 //: Sets the transformation to be rotation, followed by translation. 00123 // The transformation is separable affine. 00124 // \param r_x Angle of rotation in x 00125 // \param r_y Angle of rotation in y 00126 // \param r_z Angle of rotation in z 00127 // \param t_x Translation in x 00128 // \param t_y Translation in y 00129 // \param t_z Translation in z 00130 void set_rigid_body(double r_x, double r_y, double r_z, 00131 double t_x, double t_y, double t_z); 00132 00133 //: Sets the transformation to be isotropic scaling, followed by rotation, then translation. 00134 // The transformation is separable affine. 00135 // \param s Scaling factor 00136 // \param r_x Angle of rotation in x 00137 // \param r_y Angle of rotation in y 00138 // \param r_z Angle of rotation in z 00139 // \param t_x Translation in x 00140 // \param t_y Translation in y 00141 // \param t_z Translation in z 00142 void set_similarity(double s, 00143 double r_x, double r_y, double r_z, 00144 double t_x, double t_y, double t_z); 00145 00146 //: Sets the transformation to be a special case of Affine: anisotropic scaling, followed by rotation, then translation. 00147 // \param s_x Scaling factor in x 00148 // \param s_y Scaling factor in y 00149 // \param s_z Scaling factor in z 00150 // \param r_x Angle of rotation in x 00151 // \param r_y Angle of rotation in y 00152 // \param r_z Angle of rotation in z 00153 // \param t_x Translation in x 00154 // \param t_y Translation in y 00155 // \param t_z Translation in z 00156 // \note This creates a special case of Affine. Although this special case 00157 // is separable, in general Affine transformations are not separable. 00158 void set_affine(double s_x, double s_y, double s_z, 00159 double r_x, double r_y, double r_z, 00160 double t_x, double t_y, double t_z); 00161 00162 //: Sets the transformation to be a special case of Affine: anisotropic scaling, followed by rotation, then translation. 00163 // \param s_x Scaling factor in x 00164 // \param s_y Scaling factor in y 00165 // \param s_z Scaling factor in z 00166 // \param c_x First column of rotation matrix 00167 // \param c_y Second column of rotation matrix 00168 // \param c_z Third column of rotation matrix 00169 // \param t_x Translation in x 00170 // \param t_y Translation in y 00171 // \param t_z Translation in z 00172 // \note This creates a special case of Affine. Although this special case 00173 // is separable, in general Affine transformations are not 00174 // separable. The rotation matrix is assumed to be valid. 00175 void set_affine(double s_x, double s_y, double s_z, 00176 vgl_vector_3d<double> c_x, 00177 vgl_vector_3d<double> c_y, 00178 vgl_vector_3d<double> c_z, 00179 double t_x, double t_y, double t_z); 00180 00181 //: Sets the transformation to be a special case of Affine. 00182 // T(x,y,z) = p +x.u +y.v + z.w 00183 // \param p Origin point 00184 // \param u Vector to which the x-axis is mapped. The length of \a u indicates scaling in x. 00185 // \param v Vector to which the y-axis is mapped. The length of \a v indicates scaling in y. 00186 // \param w Vector to which the z-axis is mapped. The length of \a w indicates scaling in z. 00187 // \note Currently, the implementation assumes that u,v,w are orthogonal 00188 // and form a right-handed system. There are asserts for this condition. 00189 // \note This creates a special case of Affine. Although this special case 00190 // is separable, in general Affine transformations are not separable. 00191 void set_affine(const vgl_point_3d<double>& p, 00192 const vgl_vector_3d<double>& u, 00193 const vgl_vector_3d<double>& v, 00194 const vgl_vector_3d<double>& w); 00195 00196 //: Returns the coordinates of the origin 00197 vgl_point_3d<double> origin() const 00198 { return vgl_point_3d<double> (tt_==1?xt_:xt_/tt_,tt_==1?yt_:yt_/tt_,tt_==1?zt_:zt_/tt_); } 00199 00200 //: Modifies the transformation so that origin == p. 00201 // Modifies the transformation so that 00202 // operator()(vgl_point_3d<double> (0,0)) == p. 00203 // The rest of the transformation is unaffected. 00204 // If the transformation was previously the identity, 00205 // it becomes a translation. 00206 void set_origin( const vgl_point_3d<double> & ); 00207 00208 //: Applies transformation to (x,y,z) 00209 // \param x x coordinate 00210 // \param y y co-ord 00211 // \param z z co-ord 00212 //ret: Point = T(x,y,z) 00213 vgl_point_3d<double> operator()(double x, double y, double z) const 00214 { 00215 switch (form_) 00216 { 00217 case Identity : 00218 return vgl_point_3d<double> (x,y,z); 00219 case Translation : 00220 return vgl_point_3d<double> (x+xt_,y+yt_,z+zt_); 00221 case ZoomOnly : 00222 return vgl_point_3d<double> ( 00223 x*xx_+xt_, 00224 y*yy_+yt_, 00225 z*zz_+zt_); 00226 // case RigidBody, Similarity, Affine : 00227 default : 00228 return vgl_point_3d<double> ( 00229 x*xx_+y*xy_+z*xz_+xt_, 00230 x*yx_+y*yy_+z*yz_+yt_, 00231 x*zx_+y*zy_+z*zz_+zt_); 00232 } 00233 } 00234 00235 //: Applies transformation to point p 00236 // \param p Point 00237 // \return Point = T(p) 00238 vgl_point_3d<double> operator()(vgl_point_3d<double> p) const 00239 { return operator()(p.x(),p.y(),p.z()); } 00240 00241 //: Returns the inverse of the current transform 00242 // \return inverse of current transform. 00243 vimt3d_transform_3d inverse() const; 00244 00245 //: Returns change in transformed point when original point moved by dp 00246 // \param p point 00247 // \param dp movement from point 00248 // \return T(p+dp)-T(p) 00249 vgl_vector_3d<double> delta(vgl_point_3d<double> /*p*/, vgl_vector_3d<double> dp) const 00250 { 00251 switch (form_) 00252 { 00253 case Identity : 00254 case Translation: 00255 return dp; 00256 case ZoomOnly : 00257 return vgl_vector_3d<double> (dp.x()*xx_, 00258 dp.y()*yy_, 00259 dp.z()*zz_); 00260 // case RigidBody, Similarity, Affine : 00261 default : // Don't worry that the returned value is independent of p --- this is correct. 00262 return vgl_vector_3d<double> (dp.x()*xx_+dp.y()*xy_+dp.z()*xz_, 00263 dp.x()*yx_+dp.y()*yy_+dp.z()*yz_, 00264 dp.x()*zx_+dp.y()*zy_+dp.z()*zz_); 00265 } 00266 } 00267 00268 //: Calculates the product LR 00269 // \param L Transform 00270 // \param R Transform 00271 // \return Transform LR = R followed by L 00272 friend vimt3d_transform_3d operator*(const vimt3d_transform_3d& L, 00273 const vimt3d_transform_3d& R); 00274 00275 //: Print class to os 00276 // This function prints the extracted params. 00277 // \sa params() 00278 // \sa set() 00279 void print_summary(vcl_ostream& os) const; 00280 00281 //: Print class to os 00282 // This function prints the actual parameters xx_,xy_,xz_,xt_, yx_,yy_,yz_,yt_, zx_,zy_,zz_,zt_, tx_,ty_,tz_,tt_ 00283 void print_all(vcl_ostream& os) const; 00284 00285 //: Set transformation from stream; 00286 // You can specify the vector as used in the set() operation. 00287 // \verbatim 00288 // form: rigidbody 00289 // vector: { 0.1 0.1 0.1 2 2 2 } 00290 // \endverbatim 00291 // or with explicit parameter names from the set_...() methods. 00292 // \verbatim 00293 // form: rigidbody 00294 // r_x: 0.1 00295 // r_y: 0.1 00296 // r_z: 0.1 00297 // t_x: 2 00298 // t_y: 2 00299 // t_z: 2 00300 // \endverbatim 00301 void config(vcl_istream& is); 00302 00303 //: Save class to binary file stream 00304 void b_write(vsl_b_ostream& bfs) const; 00305 00306 //: Load class from binary file stream 00307 void b_read(vsl_b_istream& bfs); 00308 00309 //: True if t is the same as this. 00310 // \note All underlying parameters xx_, xy_, etc are required to be equal, 00311 // but the declared Form (etc RigidBody) need not be equal. 00312 bool operator==(const vimt3d_transform_3d&) const; 00313 00314 //: Reduce to the simplest form possible. 00315 void simplify(double tol =1e-10); 00316 00317 protected: 00318 00319 double xx_,xy_,xz_,xt_,yx_,yy_,yz_,yt_,zx_, zy_, zz_, zt_, tx_,ty_,tz_,tt_; 00320 Form form_; 00321 00322 // This is all the inverse data 00323 // Notice the mutable here - take care if using threads! 00324 mutable double xx2_,xy2_,xz2_,xt2_,yx2_,yy2_,yz2_,yt2_,zx2_, zy2_, zz2_, zt2_, tx2_,ty2_,tz2_,tt2_; 00325 mutable bool inv_uptodate_; 00326 00327 00328 void calcInverse() const; 00329 void setCheck(int n1,int n2,const char* str) const; 00330 void angles(double& phi_x, double& phi_y, double& phi_z) const; 00331 void setRotMat(double r_x, double r_y, double r_z); 00332 }; 00333 00334 00335 //: Calculates the product LR 00336 // \param L Transform 00337 // \param R Transform 00338 // \return Transform LR = R followed by L 00339 vimt3d_transform_3d operator*(const vimt3d_transform_3d& L, 00340 const vimt3d_transform_3d& R); 00341 00342 //: Binary file stream output operator for class reference 00343 void vsl_b_write(vsl_b_ostream& bfs, const vimt3d_transform_3d& b); 00344 00345 //: Binary file stream input operator for class reference 00346 void vsl_b_read(vsl_b_istream& bfs, vimt3d_transform_3d& b); 00347 00348 //: Stream output operator for class reference 00349 vcl_ostream& operator<<(vcl_ostream& os,const vimt3d_transform_3d& b); 00350 00351 //: Stream output operator for class reference 00352 inline void vsl_print_summary(vcl_ostream& afs, const vimt3d_transform_3d& b) 00353 { 00354 b.print_summary(afs); 00355 } 00356 00357 //: Test whether a 3D transform is zoom-only or lesser. 00358 // i.e. there may be translation and (anisotropic) scaling but no rotation. 00359 // \note This tests only for a commonly-occurring special case; there may 00360 // be other zoom-only transforms that are not detected. 00361 // \param zero_tol Used for testing whether elements are zero or not. 00362 bool vimt3d_transform_is_zoom_only(const vimt3d_transform_3d& transf, 00363 const double zero_tol=1e-9); 00364 00365 //======================================================================= 00366 00367 #endif // vimt3d_transform_3d_h_
1.7.5.1