contrib/mul/vimt/vimt_transform_2d.h
Go to the documentation of this file.
00001 // This is mul/vimt/vimt_transform_2d.h
00002 #ifndef vimt_transform_2d_h_
00003 #define vimt_transform_2d_h_
00004 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00005 #pragma interface
00006 #endif
00007 //:
00008 // \file
00009 // \author Tim Cootes
00010 // \brief 2D transform, which can be up to a projective transformation
00011 // \verbatim
00012 //  Modifications
00013 //   2011-06-10 Peter Vanroose - modified signature of set_*() to return *this
00014 // \endverbatim
00015 
00016 #include <vnl/vnl_fwd.h>
00017 #include <vgl/vgl_vector_2d.h>
00018 #include <vgl/vgl_point_2d.h>
00019 #include <vsl/vsl_binary_io.h>
00020 #include <vcl_iosfwd.h>
00021 
00022 //: 2D transform, which can be up to a projective transformation.
00023 // In order of complexity the transform can be
00024 // \verbatim
00025 // Identity     x->x, y->y
00026 // Translation  x->x + tx, y->y + ty
00027 // ZoomOnly     x->sx.x + tx, y->sy.y + ty
00028 // RigidBody    (Translate + rotation)
00029 // Euclidean    (Translation + rotation + scale)
00030 // Affine
00031 // Projective
00032 // \endverbatim
00033 //
00034 // NOTES:
00035 // The transformation can be represented by a 3x3 matrix mapping homogeneous co-ordinates about.
00036 // \verbatim
00037 // ( xx xy xt )
00038 // ( yx yy yt )
00039 // ( tx ty tt )
00040 // \endverbatim
00041 // For efficiency the elements are stored explicitly, rather than in a vnl_matrix<double>, to avoid lots
00042 // of copying of matrices with all the attendant memory allocation.
00043 //
00044 //
00045 //  Example:
00046 // \code
00047 // vimt_transform_2d T1;
00048 // vimt_transform_2d T2;
00049 // T1.set_zoom(scale,translation.x(),translation.y());
00050 // T2.set_similarity(scale2,theta,translation2.x(),translation2.y());
00051 //
00052 // vimt_transform_2d T3 = T2 * T1; // T1 followed by T2
00053 //
00054 // vgl_point_2d<double>  p(10,10);
00055 // vgl_point_2d<double>  p_new = T3(p);
00056 //
00057 // vimt_transform_2d T_inverse = T3.inverse();
00058 // \endcode
00059 class vimt_transform_2d
00060 {
00061  public:
00062     //: Defines form of transformation
00063     enum Form { Identity,
00064                 Translation,
00065                 ZoomOnly,
00066                 RigidBody,
00067                 Similarity,
00068                 Affine,
00069                 Projective,
00070                 Reflection};
00071 
00072     vimt_transform_2d() :
00073         xx_(1),xy_(0),xt_(0),
00074         yx_(0),yy_(1),yt_(0),
00075         tx_(0),ty_(0),tt_(1),
00076         form_(Identity),inv_uptodate_(0) {}
00077 
00078 
00079     bool is_identity() const { return form_==Identity; }
00080     Form form() const { return form_; }
00081     vnl_matrix<double> matrix() const;
00082     void matrix(vnl_matrix<double>&) const;
00083 
00084     //: Define the transform in terms of a 3x3 homogeneous matrix.
00085     // \param M 3x3 homogeneous matrix defining the transform.
00086     // \note Client must ensure that \a M is a valid representation of an affine (or simpler) transform.
00087     // \note The form will be set to Affine - call simplify() if you need the simplest form.
00088     vimt_transform_2d& set_matrix(const vnl_matrix<double>& M);
00089 
00090     //: Fills v with parameters
00091     void params(vnl_vector<double>& v) const { params_of(v,form_); }
00092     //: Fills v with parameters of transform of type Form
00093     void params_of(vnl_vector<double>& v, Form) const;
00094     //: Sets transform using v (converse of params(v))
00095     vimt_transform_2d& set(const vnl_vector<double>& v, Form); // Sets transform using v
00096     //: Set to identity transformation
00097     vimt_transform_2d& set_identity();
00098     //: Sets the transformation to be separable affine.
00099     // x' = s_x.x + t_x,  y' = s_y.y + t_y
00100     // s_x: Scaling in x
00101     // s_y: Scaling in y
00102     // t_x: Translation in x
00103     // t_y: Translation in y
00104     vimt_transform_2d& set_zoom_only(double s_x, double s_y, double t_x, double t_y);
00105     //: Sets the transformation to be a zoom.
00106     // x' = s.x + t_x,  y' = s.y + t_y
00107     //   s: Scaling
00108     // t_x: Translation in x
00109     // t_y: Translation in y
00110     vimt_transform_2d& set_zoom_only(double s, double t_x, double t_y) { return set_zoom_only(s,s,t_x,t_y); }
00111     //: Sets the transformation to be separable affine.
00112     // x' = s_x.x + xt_,  y' = s_y.y + yt_
00113     // s_x: Scaling in x
00114     // s_y: Scaling in y
00115     // Translation in x and y kept as it was
00116     vimt_transform_2d& set_zoom_only(double s_x, double s_y) { return set_zoom_only(s_x,s_y,xt_,yt_); }
00117     //: Sets the transformation to be a zoom.
00118     // x' = s.x + xt_,  y' = s.y + yt_
00119     //   s: Scaling
00120     // Translation in x and y kept as it was
00121     vimt_transform_2d& set_zoom_only(double s) { return set_zoom_only(s,s,xt_,yt_); }
00122     //: Sets the transformation to be a translation.
00123     // t_x: Translation in x
00124     // t_y: Translation in y
00125     vimt_transform_2d& set_translation(double t_x, double t_y);
00126     //: Sets the transformation to rotation then translation.
00127     // theta: rotation
00128     // t_x: Translation in x
00129     // t_y: Translation in y
00130     vimt_transform_2d& set_rigid_body(double theta, double t_x, double t_y);
00131     //: Sets the transformation to apply scaling, rotation then translation.
00132     // s: Scaling
00133     // theta: rotation
00134     // t_x: Translation in x
00135     // t_y: Translation in y
00136     vimt_transform_2d& set_similarity(double s, double theta, double t_x, double t_y);
00137     //: Sets Euclidean transformation.
00138     // \param dx  Rotation and scaling of x axis
00139     // \param t  Translation
00140     vimt_transform_2d& set_similarity(const vgl_point_2d<double> & dx,
00141                                       const vgl_point_2d<double> & t);
00142     //: Sets Euclidean transformation.
00143     // \param dx  Rotation and scaling of x axis
00144     // \param t  Translation
00145     vimt_transform_2d& set_similarity(const vgl_vector_2d<double> & dx,
00146                                       const vgl_point_2d<double> & t);
00147     //: reflect about a line though the points m1, and m2
00148     vimt_transform_2d& set_reflection( const vgl_point_2d<double> & m1,
00149                                        const vgl_point_2d<double> & m2);
00150     //: Sets to be 2D affine transformation using 2x3 matrix
00151     vimt_transform_2d& set_affine(const vnl_matrix<double>&);
00152     //: Sets to be 2D affine transformation T(x,y)=p+x.u+y.v
00153     vimt_transform_2d& set_affine(const vgl_point_2d<double> & p,
00154                                   const vgl_vector_2d<double> & u,
00155                                   const vgl_vector_2d<double> & v);
00156     //: Sets to be 2D projective transformation
00157     vimt_transform_2d& set_projective(const vnl_matrix<double>&);   // 3x3 matrix
00158 
00159     //: Returns the coordinates of the origin.
00160     // I.e. operator()(vgl_point_2d<double> (0,0))
00161     vgl_point_2d<double>  origin() const { return vgl_point_2d<double>(xt_/tt_,yt_/tt_); }
00162 
00163     //: Modifies the transformation so that operator()(vgl_point_2d<double> (0,0)) == p.
00164     // The rest of the transformation is unaffected.
00165     // If the transformation was previously the identity,
00166     // it becomes a translation.
00167     vimt_transform_2d& set_origin( const vgl_point_2d<double> & );
00168 
00169     //: Applies transformation to (x,y)
00170     vgl_point_2d<double>  operator()(double x, double y) const;
00171     //: Returns transformation applied to point p
00172     vgl_point_2d<double>  operator()(const vgl_point_2d<double> & p) const { return operator()(p.x(),p.y()); }
00173 
00174     //: Calculates inverse of this transformation
00175     vimt_transform_2d inverse() const;
00176     //: Returns change in transformed point when original point moved by dp.
00177     // Point dp: Movement from point
00178     // Returns: T(p+dp)-T(p)
00179     vgl_vector_2d<double>  delta(const vgl_point_2d<double> & p, const vgl_vector_2d<double> & dp) const;
00180 
00181     friend vimt_transform_2d operator*(const vimt_transform_2d&,
00182                                        const vimt_transform_2d&);
00183 
00184     short version_no() const;
00185     void print_summary(vcl_ostream&) const;
00186     void b_write(vsl_b_ostream& bfs) const;
00187     void b_read(vsl_b_istream& bfs);
00188 
00189     //: True if t is the same as this
00190     bool operator==(const vimt_transform_2d& t) const;
00191 
00192     //: Reduce to the simplest form possible.
00193     vimt_transform_2d& simplify(double tol =1e-10);
00194 
00195  private:
00196 
00197     double xx_,xy_,xt_,yx_,yy_,yt_,tx_,ty_,tt_;
00198     Form form_;
00199 
00200     // Notice the mutable here - take care if using threads!
00201     mutable double xx2_,xy2_,xt2_,yx2_,yy2_,yt2_,tx2_,ty2_,tt2_; // Inverse
00202     mutable bool inv_uptodate_;
00203 
00204     void calcInverse() const;
00205     void setCheck(int n1,int n2,const char* str) const;
00206 };
00207 
00208 
00209 vcl_ostream& operator<<(vcl_ostream&,const vimt_transform_2d& t);
00210 
00211 //: Binary file stream output operator for pointer to class
00212 void vsl_b_write(vsl_b_ostream& bfs, const vimt_transform_2d& b);
00213 
00214 //: Binary file stream input operator for class reference
00215 void vsl_b_read(vsl_b_istream& bfs, vimt_transform_2d& b);
00216 
00217 //: Stream output operator for class reference
00218 void vsl_print_summary(vcl_ostream& os,const vimt_transform_2d& t);
00219 
00220 
00221 #endif // vimt_transform_2d_h_