contrib/mul/vimt/vimt_transform_2d.cxx
Go to the documentation of this file.
00001 // This is mul/vimt/vimt_transform_2d.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 //  \file
00007 
00008 #include "vimt_transform_2d.h"
00009 #include <vcl_cmath.h>
00010 #include <vcl_cstdlib.h> // for vcl_abort()
00011 #include <vcl_cassert.h>
00012 #include <vsl/vsl_indent.h>
00013 #include <vnl/vnl_vector.h>
00014 #include <vnl/vnl_matrix.h>
00015 #include <vnl/vnl_inverse.h>
00016 #include <vnl/vnl_det.h>
00017 #include <vnl/vnl_math.h>
00018 
00019 vnl_matrix<double> vimt_transform_2d::matrix() const
00020 {
00021     vnl_matrix<double> M(3,3);
00022     matrix(M);
00023     return M;
00024 }
00025 
00026 void vimt_transform_2d::matrix(vnl_matrix<double>& M) const
00027 {
00028     M.set_size(3,3);
00029     double**m_data = M.data_array();
00030     m_data[0][0]=xx_;   m_data[0][1]=xy_;   m_data[0][2]=xt_;
00031     m_data[1][0]=yx_;   m_data[1][1]=yy_;   m_data[1][2]=yt_;
00032     m_data[2][0]=tx_;   m_data[2][1]=ty_;   m_data[2][2]=tt_;
00033 }
00034 
00035 //=======================================================================
00036 // Define the transform in terms of a 3x3 homogeneous matrix.
00037 vimt_transform_2d& vimt_transform_2d::set_matrix(const vnl_matrix<double>& M)
00038 {
00039     if (M.rows()!=3 || M.cols()!=3)
00040     {
00041         vcl_cerr<<"vimt_transform_2d::set_matrix(mat): mat not 3x3\n";
00042         vcl_abort();
00043     }
00044 
00045     form_=Affine;
00046     xx_=M[0][0]; xy_=M[0][1]; xt_=M[0][2];
00047     yx_=M[1][0]; yy_=M[1][1]; yt_=M[1][2];
00048     tx_=M[2][0]; ty_=M[2][1]; tt_=M[2][2];
00049 
00050     return *this;
00051 }
00052 
00053 
00054 void vimt_transform_2d::params_of(vnl_vector<double>& v, Form form) const
00055 {
00056     double *v_data;
00057     switch (form)
00058     {
00059         case (Identity):
00060             v.set_size(0);
00061             break;
00062         case (Translation):
00063             v.set_size(2);
00064             v(0)=xt_; v(1)=yt_;
00065             break;
00066         case (ZoomOnly):
00067             v.set_size(4);
00068             v(0)=xx_; v(1)=yy_;
00069             v(2)=xt_; v(3)=yt_;
00070             break;
00071         case (RigidBody):
00072             v.set_size(3);
00073             v(0)=vcl_atan2(-xy_,xx_); // Angle
00074             v(1)=xt_; v(2)=yt_;
00075             break;
00076         case (Reflection):
00077             v.set_size(4);
00078             v_data = v.begin();
00079             v_data[0]=xx_; v_data[1]=xy_;
00080             v_data[2]=xt_; v_data[3]=yt_;
00081             break;
00082         case (Similarity):
00083             v.set_size(4);
00084             v_data = v.begin();
00085             v_data[0]=xx_; v_data[1]=xy_;
00086             v_data[2]=xt_; v_data[3]=yt_;
00087             break;
00088         case (Affine):
00089             v.set_size(6);
00090             v_data = v.begin();
00091             v_data[0]=xx_; v_data[1]=xy_; v_data[2]=xt_;
00092             v_data[3]=yx_; v_data[4]=yy_; v_data[5]=yt_;
00093             break;
00094         case (Projective):
00095             v.set_size(9);
00096             v_data = v.begin();
00097             v_data[0]=xx_; v_data[1]=xy_; v_data[2]=xt_;
00098             v_data[3]=yx_; v_data[4]=yy_; v_data[5]=yt_;
00099             v_data[6]=tx_; v_data[7]=ty_; v_data[8]=tt_;
00100             break;
00101         default:
00102             vcl_cerr<<"vimt_transform_2d::params() Unexpected form: "<<int(form)<<'\n';
00103             vcl_abort();
00104     }
00105 }
00106 
00107 //=======================================================================
00108 vimt_transform_2d& vimt_transform_2d::simplify(double tol /*=1e-10*/)
00109 {
00110     double r;
00111     double sx, sy;
00112     double det;
00113     switch (form_)
00114     {
00115         case Affine:
00116         {
00117             r = vcl_atan2(-xy_,xx_);
00118             double matrix_form[]= {xx_, yx_, xy_, yy_};
00119             vnl_matrix_fixed<double, 2, 2> X(matrix_form);
00120             vnl_matrix_fixed<double, 2, 2> S2 = X.transpose() * X;
00121             // if X=R*S then X'X = S'*R'*R*S
00122             // if R is a rotation matrix then R'*R=I and so X'X = S'*S = [s_x^2 0 0; 0 s_y^2 0]
00123             if (S2(0,1)*S2(0,1) + S2(1,0)*S2(1,0) >= tol*tol*6)
00124                 return *this;
00125 
00126             // mirroring if det is negative;
00127             double mirror=vnl_math_sgn(vnl_det(X[0], X[1]));
00128 
00129             sx = vcl_sqrt(vcl_abs(S2(0,0))) * mirror;
00130             sy = vcl_sqrt(vcl_abs(S2(1,1))) * mirror;
00131             if (vnl_math_sqr(sx-sy) < tol*tol)
00132                 return this->set_similarity(sx, r, xt_, yt_ ).simplify();
00133             else if (r*r < tol*tol)
00134                 return this->set_zoom_only(sx, sy, xt_, yt_).simplify();
00135             else if (vnl_math_sqr(vcl_abs(r) - vnl_math::pi)< tol)
00136                 return this->set_zoom_only(-sx, -sy, xt_, yt_).simplify();
00137             else
00138                 return *this;
00139         }
00140         case Similarity:
00141             r = vcl_atan2(-xy_,xx_);
00142 
00143             det=+xx_*yy_-yx_*xy_;
00144             sx=vcl_sqrt(xx_*xx_ + yx_*yx_)* vnl_math_sgn(det);
00145 
00146             if (r*r < tol*tol)
00147                 return this->set_zoom_only(sx, xt_, yt_).simplify();
00148             else if (vnl_math_sqr(vcl_abs(r) - vnl_math::pi)< tol)
00149                 return this->set_zoom_only(-sx, xt_, yt_).simplify();
00150             else if (vnl_math_sqr(sx-1.0) < tol*tol)
00151                 return this->set_rigid_body(r, xt_, yt_).simplify();
00152             else
00153                 return *this;
00154 
00155         case RigidBody:
00156             r = vcl_atan2(-xy_,xx_);
00157 
00158             if (r*r < tol*tol)
00159                 return this->set_translation(xt_, yt_).simplify();
00160             else
00161                 return *this;
00162         case ZoomOnly:
00163             if (vnl_math_sqr(xx_-1.0) + vnl_math_sqr(yy_-1.0) < tol*tol)
00164                 return set_translation(xt_, yt_);
00165             else
00166                 return *this;
00167         case Translation:
00168             if (xt_*xt_+yt_*yt_<tol*tol)
00169                 return set_identity();
00170             else
00171                 return *this;
00172         case Identity:
00173             return *this;
00174         default:
00175             vcl_cerr << "vimt3d_transform_3d::simplify() Unexpected form:" <<  form_ << '\n';
00176             vcl_abort();
00177     }
00178     return *this;
00179 }
00180 
00181 void vimt_transform_2d::setCheck(int n1,int n2,const char* str) const
00182 {
00183     if (n1==n2) return;
00184     vcl_cerr<<"vimt_transform_2d::set() "<<n1<<" parameters required for "
00185             <<str<<". Passed "<<n2<<'\n';
00186     vcl_abort();
00187 }
00188 
00189 vimt_transform_2d& vimt_transform_2d::set(const vnl_vector<double>& v, Form form)
00190 {
00191     int n=v.size();
00192     const double* v_data = v.begin();
00193 
00194     switch (form)
00195     {
00196         case (Identity):
00197             return set_identity();
00198         case (Translation):
00199             setCheck(2,n,"Translation");
00200             return set_translation(v_data[0],v_data[1]);
00201         case (ZoomOnly):
00202             setCheck(4,n,"ZoomOnly");
00203             return set_zoom_only(v_data[0],v_data[1],v_data[2],v_data[3]);
00204         case (RigidBody):
00205             setCheck(3,n,"RigidBody");
00206             return set_rigid_body(v_data[0],v_data[1],v_data[2]);
00207         case (Reflection):
00208             setCheck(4,n,"Reflection");
00209             form_ = Reflection;
00210             inv_uptodate_=false;
00211             xx_ = v_data[0]; xy_ = v_data[1];
00212             yx_ = xy_; yy_ = -xx_;
00213             xt_ = v_data[2]; yt_ = v_data[3];
00214             return *this;
00215         case (Similarity):
00216             setCheck(4,n,"Similarity");
00217             form_ = Similarity;
00218             inv_uptodate_=false;
00219             xx_ = v_data[0]; xy_ = v_data[1];
00220             yx_ = -xy_; yy_=xx_;
00221             xt_ = v_data[2]; yt_ = v_data[3];
00222             return *this;
00223         case (Affine):
00224             setCheck(6,n,"Affine");
00225             form_ = Affine;
00226             inv_uptodate_=false;
00227             xx_ = v_data[0]; xy_ = v_data[1]; xt_ = v_data[2];
00228             yx_ = v_data[3]; yy_ = v_data[4]; yt_ = v_data[5];
00229             return *this;
00230         case (Projective):
00231             setCheck(9,n,"Projective");
00232             form_ = Projective;
00233             inv_uptodate_=false;
00234             xx_ = v_data[0]; xy_ = v_data[1]; xt_ = v_data[2];
00235             yx_ = v_data[3]; yy_ = v_data[4]; yt_ = v_data[5];
00236             tx_ = v_data[6]; ty_ = v_data[7]; tt_ = v_data[8];
00237             return *this;
00238         default:
00239             vcl_cerr<<"vimt_transform_2d::set() Unexpected form: "<<int(form)<<'\n';
00240             vcl_abort();
00241     }
00242     return *this;
00243 }
00244 
00245 
00246 vimt_transform_2d& vimt_transform_2d::set_identity()
00247 {
00248     if (form_==Identity) return *this;
00249     form_=Identity;
00250     inv_uptodate_=false;
00251     xx_=yy_=tt_=1.0;
00252     xy_=xt_=yx_=yt_=tx_=ty_=0.0;
00253     return *this;
00254 }
00255 
00256 vimt_transform_2d& vimt_transform_2d::set_translation(double t_x, double t_y)
00257 {
00258     if (t_x==0 && t_y==0)
00259         return set_identity();
00260     else
00261     {
00262         form_=Translation;
00263         inv_uptodate_=false;
00264         xx_=yy_=tt_=1.0;
00265         xy_=0.0;
00266         yx_=0.0;
00267         tx_=ty_=0.0;
00268         xt_=t_x;
00269         yt_=t_y;
00270         return *this;
00271     }
00272 }
00273 
00274 vimt_transform_2d& vimt_transform_2d::set_origin( const vgl_point_2d<double> & p )
00275 {
00276     if (form_ == Identity) form_=Translation;
00277     inv_uptodate_=false;
00278     xt_ = p.x()*tt_;
00279     yt_ = p.y()*tt_;
00280     return *this;
00281 }
00282 
00283 vimt_transform_2d& vimt_transform_2d::set_zoom_only(double s_x, double s_y, double t_x, double t_y)
00284 {
00285     form_=ZoomOnly;
00286     inv_uptodate_=false;
00287     xx_=s_x;   yy_=s_y;   tt_=1.0;
00288     xt_=t_x;   yt_=t_y;
00289     xy_=yx_=tx_=ty_=0.0;
00290     return *this;
00291 }
00292 
00293 //: reflect about a line though the points m1, and m2
00294 vimt_transform_2d& vimt_transform_2d::set_reflection( const vgl_point_2d<double> & m1, const vgl_point_2d<double> & m2)
00295 {
00296     form_=Reflection;
00297 
00298     assert (m1 != m2);
00299     const double m1x = m1.x();
00300     const double m1y = m1.y();
00301     const double m2x = m2.x();
00302     const double m2y = m2.y();
00303     const double dx = m2x - m1x;
00304     const double dy = m2y - m1y;
00305     const double dx2dy2 = dx*dx + dy*dy;
00306 
00307 // after plugging all the equations for mirroring into matlab symbolic calculator,
00308 // I had to rearrange the equations to avoid divide-by-zero. See notebook for details. IMS
00309 
00310     xx_ = (dx*dx - dy*dy) / dx2dy2;
00311 
00312     xy_ = 2.0*dx*dy / dx2dy2;
00313 
00314     xt_ = (2.0*m1x*dy*dy - 2.0*m1y*dx*dy) / dx2dy2;
00315 
00316     yx_ = 2.0*dx*dy / dx2dy2;
00317 
00318     yy_ = (dy*dy - dx*dx) / dx2dy2;
00319 
00320     yt_ = (2.0*m1y*dx*dx - 2.0*m1x*dx*dy) / dx2dy2;
00321 
00322     tx_ = ty_ = 0.0;
00323     tt_ = 1.0;
00324 
00325     return *this;
00326 }
00327 
00328 vimt_transform_2d& vimt_transform_2d::set_rigid_body(double theta, double t_x, double t_y)
00329 {
00330     if (theta==0.0)
00331         return set_translation(t_x,t_y);
00332     else
00333     {
00334         form_=RigidBody;
00335         inv_uptodate_=false;
00336         double a=vcl_cos(theta);
00337         double b=vcl_sin(theta);
00338         xx_=a;   yx_=b;   tx_=0.0;
00339         xy_=-b;  yy_=a;   ty_=0.0;
00340         xt_=t_x; yt_=t_y; tt_=1.0;
00341         return *this;
00342     }
00343 }
00344 
00345 vimt_transform_2d& vimt_transform_2d::set_similarity(double s, double theta, double t_x, double t_y)
00346 {
00347     if (s==1.0)
00348         return set_rigid_body(theta,t_x,t_y);
00349     else
00350     {
00351         form_=Similarity;
00352         inv_uptodate_=false;
00353         double a=s*vcl_cos(theta);
00354         double b=s*vcl_sin(theta);
00355         xx_=a;   yx_=b;   tx_=0.0;
00356         xy_=-b;  yy_=a;   ty_=0.0;
00357         xt_=t_x; yt_=t_y; tt_=1.0;
00358         return *this;
00359     }
00360 }
00361 
00362 //: Sets Euclidean transformation.
00363 vimt_transform_2d& vimt_transform_2d::set_similarity(const vgl_point_2d<double> & dx,
00364                                                      const vgl_point_2d<double> & t)
00365 {
00366     form_=Similarity;
00367     inv_uptodate_=false;
00368     xx_ = dx.x();  yx_ = dx.y(); tx_=0.0;
00369     xy_ = -dx.y(); yy_ = dx.x(); ty_=0.0;
00370     xt_ = t.x();   yt_ = t.y();  tt_=1.0;
00371     return *this;
00372 }
00373 
00374 //: Sets Euclidean transformation.
00375 vimt_transform_2d& vimt_transform_2d::set_similarity(const vgl_vector_2d<double> & dx,
00376                                                      const vgl_point_2d<double> & t)
00377 {
00378     form_=Similarity;
00379     inv_uptodate_=false;
00380     xx_ = dx.x();  yx_ = dx.y(); tx_=0.0;
00381     xy_ = -dx.y(); yy_ = dx.x(); ty_=0.0;
00382     xt_ = t.x();   yt_ = t.y();  tt_=1.0;
00383     return *this;
00384 }
00385 
00386 
00387 vimt_transform_2d& vimt_transform_2d::set_affine(const vnl_matrix<double>& M23)  // 2x3 matrix
00388 {
00389     if ((M23.rows()!=2) || (M23.columns()!=3))
00390     {
00391         vcl_cerr<<"vimt_transform_2d::affine : Expect 2x3 matrix, got "<<M23.rows()<<" x "<<M23.columns()<<'\n';
00392         vcl_abort();
00393     }
00394 
00395     const double *const *m_data=M23.data_array();
00396 
00397     if (m_data[0][0]*m_data[1][1] < m_data[0][1]*m_data[1][0])
00398     {
00399         vcl_cerr << "vimt_transform_2d::affine :\n"
00400                  << "sub (2x2) matrix should have positive determinant\n";
00401         vcl_abort();
00402     }
00403 
00404     form_=Affine;
00405     inv_uptodate_=false;
00406     xx_=m_data[0][0];   xy_=m_data[0][1]; xt_=m_data[0][2];
00407     yx_=m_data[1][0];   yy_=m_data[1][1]; yt_=m_data[1][2];
00408     tx_=0.0;            ty_=0.0;          tt_=1.0;
00409     return *this;
00410 }
00411 
00412 //: Sets to be 2D affine transformation T(x,y)=p+x.u+y.v
00413 vimt_transform_2d& vimt_transform_2d::set_affine(const vgl_point_2d<double> & p,
00414                                                  const vgl_vector_2d<double> & u,
00415                                                  const vgl_vector_2d<double> & v)
00416 {
00417     form_=Affine;
00418     inv_uptodate_=false;
00419     xt_ = p.x();
00420     yt_ = p.y();
00421     xx_ = u.x();
00422     yx_ = u.y();
00423     xy_ = v.x();
00424     yy_ = v.y();
00425     return *this;
00426 }
00427 
00428 vimt_transform_2d& vimt_transform_2d::set_projective(const vnl_matrix<double>& M33)   // 3x3 matrix
00429 {
00430     if ((M33.rows()!=3) || (M33.columns()!=3))
00431     {
00432         vcl_cerr<<"vimt_transform_2d::projective : Expect 3x3 matrix, got "<<M33.rows()<<" x "<<M33.columns()<<'\n';
00433         vcl_abort();
00434     }
00435 
00436     form_=Projective;
00437     inv_uptodate_=false;
00438     const double *const *m_data=M33.data_array();
00439     xx_=m_data[0][0];   xy_=m_data[0][1]; xt_=m_data[0][2];
00440     yx_=m_data[1][0];   yy_=m_data[1][1]; yt_=m_data[1][2];
00441     tx_=m_data[2][0];   ty_=m_data[2][1]; tt_=m_data[2][2];
00442     return *this;
00443 }
00444 
00445 vgl_point_2d<double>  vimt_transform_2d::operator()(double x, double y) const
00446 {
00447     double z;
00448     switch (form_)
00449     {
00450         case Identity :
00451             return vgl_point_2d<double> (x,y);
00452         case Translation :
00453             return vgl_point_2d<double> (x+xt_,y+yt_);
00454         case ZoomOnly :
00455             return vgl_point_2d<double> (x*xx_+xt_,y*yy_+yt_);
00456         case RigidBody :
00457         case Similarity :
00458         case Reflection :
00459         case Affine :
00460             return vgl_point_2d<double> (x*xx_+y*xy_+xt_,x*yx_+y*yy_+yt_);
00461         case Projective :
00462             z=x*tx_+y*ty_+tt_;
00463             if (z==0) return vgl_point_2d<double> (0,0);   // Or should it be inf,inf?
00464             else      return vgl_point_2d<double> ((x*xx_+y*xy_+xt_)/z,(x*yx_+y*yy_+yt_)/z);
00465         default:
00466             vcl_cerr<<"vimt_transform_2d::operator() : Unrecognised form:"<<int(form_)<<'\n';
00467             vcl_abort();
00468     }
00469 
00470     return vgl_point_2d<double> (); // To keep over-zealous compilers happy
00471 }
00472 
00473 vgl_vector_2d<double>  vimt_transform_2d::delta(const vgl_point_2d<double>& p, const vgl_vector_2d<double>& dp) const
00474 {
00475     switch (form_)
00476     {
00477         case Identity :
00478         case Translation:
00479             return dp;
00480         case ZoomOnly :
00481             return vgl_vector_2d<double> (dp.x()*xx_,dp.y()*yy_);
00482         case RigidBody :
00483         case Similarity :
00484         case Reflection :
00485         case Affine :
00486             return vgl_vector_2d<double> (dp.x()*xx_+dp.y()*xy_,dp.x()*yx_+dp.y()*yy_);
00487         case Projective :
00488             return operator()(p+dp)-operator()(p);
00489         default:
00490             vcl_cerr<<"vimt_transform_2d::delta() : Unrecognised form:"<<int(form_)<<'\n';
00491             vcl_abort();
00492     }
00493 
00494     return vgl_vector_2d<double> (); // To keep over-zealous compilers happy
00495 }
00496 
00497 
00498 vimt_transform_2d vimt_transform_2d::inverse() const
00499 {
00500     if (!inv_uptodate_) calcInverse();
00501 
00502     vimt_transform_2d inv;
00503 
00504     inv.xx_ = xx2_; inv.xy_ = xy2_; inv.xt_ = xt2_;
00505     inv.yx_ = yx2_; inv.yy_ = yy2_; inv.yt_ = yt2_;
00506     inv.tx_ = tx2_; inv.ty_ = ty2_; inv.tt_ = tt2_;
00507 
00508     inv.xx2_ = xx_; inv.xy2_ = xy_; inv.xt2_ = xt_;
00509     inv.yx2_ = yx_; inv.yy2_ = yy_; inv.yt2_ = yt_;
00510     inv.tx2_ = tx_; inv.ty2_ = ty_; inv.tt2_ = tt_;
00511 
00512     inv.form_ = form_;
00513     inv.inv_uptodate_ = 1;
00514 
00515     return inv;
00516 }
00517 
00518 void vimt_transform_2d::calcInverse()  const
00519 {
00520     xx2_ = yy2_ = tt2_ = 1;
00521     xy2_ = xt2_ = yx2_ = yt2_ = tx2_ = ty2_ = 0;
00522 
00523     switch (form_)
00524     {
00525         case Identity :
00526             break;
00527         case Translation :
00528             xt2_ = -xt_;
00529             yt2_ = -yt_;
00530             break;
00531         case ZoomOnly :
00532             assert(xx_ != 0 && yy_ != 0);
00533             xx2_=1.0/xx_;
00534             xt2_=-xt_/xx_;
00535             yy2_=1.0/yy_;
00536             yt2_=-yt_/yy_;
00537             break;
00538         case RigidBody :
00539             xx2_ = xx_; xy2_ = yx_;
00540             yx2_ = xy_; yy2_ = yy_;
00541             xt2_ = -(xx2_*xt_ + xy2_*yt_);
00542             yt2_ = -(yx2_*xt_ + yy2_*yt_);
00543             break;
00544         case Similarity :
00545         case Affine :
00546         {
00547             double det = xx_*yy_-xy_*yx_;
00548             if (det==0)
00549             {
00550                 vcl_cerr<<"vimt_transform_2d::calcInverse() : No inverse exists for this affine transform (det==0)\n";
00551                 vcl_abort();
00552             }
00553             xx2_=yy_/det;   xy2_=-xy_/det;
00554             yx2_=-yx_/det;   yy2_=xx_/det;
00555             xt2_=-xx2_*xt_-xy2_*yt_;
00556             yt2_=-yx2_*xt_-yy2_*yt_;
00557             break;
00558         }
00559         case Projective :
00560         {
00561             vnl_matrix<double> M(3,3),M_inv(3,3);
00562             matrix(M);
00563             M_inv = vnl_inverse(M);
00564             double **m_data=M_inv.data_array();
00565             xx2_=m_data[0][0];   xy2_=m_data[0][1]; xt2_=m_data[0][2];
00566             yx2_=m_data[1][0];   yy2_=m_data[1][1]; yt2_=m_data[1][2];
00567             tx2_=m_data[2][0];   ty2_=m_data[2][1]; tt2_=m_data[2][2];
00568             break;
00569         }
00570         default:
00571             vcl_cerr<<"vimt_transform_2d::calcInverse() : Unrecognised form:"<<int(form_)<<'\n';
00572             vcl_abort();
00573     }
00574 
00575     inv_uptodate_=true;
00576 }
00577 
00578 bool vimt_transform_2d::operator==(const vimt_transform_2d& t) const
00579 {
00580     return
00581         xx_ == t.xx_ &&
00582         xy_ == t.xy_ &&
00583         xt_ == t.xt_ &&
00584         yx_ == t.yx_ &&
00585         yy_ == t.yy_ &&
00586         yt_ == t.yt_ &&
00587         tx_ == t.tx_ &&
00588         ty_ == t.ty_ &&
00589         tt_ == t.tt_;
00590 }
00591 
00592 //: Transform composition (L*R)(x) = L(R(x))
00593 vimt_transform_2d operator*(const vimt_transform_2d& L, const vimt_transform_2d& R)
00594 {
00595                 // Default is identity_
00596     vimt_transform_2d T;
00597 
00598     if (L.form() == vimt_transform_2d::Identity)
00599         return R;
00600     else
00601     if (R.form() == vimt_transform_2d::Identity)
00602         return L;
00603     else
00604     if (L.form() == vimt_transform_2d::Translation)
00605     {
00606         T = R;
00607 
00608         if (R.form() == vimt_transform_2d::Projective)
00609         {
00610             T.xx_ += L.xt_*R.tx_;
00611             T.xy_ += L.xt_*R.ty_;
00612             T.xt_ += L.xt_*R.tt_;
00613 
00614             T.yx_ += L.yt_*R.tx_;
00615             T.yy_ += L.yt_*R.ty_;
00616             T.yt_ += L.yt_*R.tt_;
00617         }
00618         else
00619         {
00620             T.xt_ += L.xt_;
00621             T.yt_ += L.yt_;
00622         }
00623     }
00624     else
00625     if (R.form() == vimt_transform_2d::Translation)
00626     {
00627         T = L;
00628 
00629         T.xt_ += L.xx_*R.xt_ +
00630                 L.xy_*R.yt_;
00631         T.yt_ += L.yx_*R.xt_ +
00632                 L.yy_*R.yt_;
00633         T.tt_ += L.tx_*R.xt_ +
00634                 L.ty_*R.yt_;
00635     }
00636     else
00637     {
00638         if (R.form() == vimt_transform_2d::Projective ||
00639             L.form() == vimt_transform_2d::Projective)
00640         {
00641                             // full monty_...
00642             T.xx_ = L.xx_*R.xx_ + L.xy_*R.yx_ + L.xt_*R.tx_;
00643             T.xy_ = L.xx_*R.xy_ + L.xy_*R.yy_ + L.xt_*R.ty_;
00644             T.xt_ = L.xx_*R.xt_ + L.xy_*R.yt_ + L.xt_*R.tt_;
00645             T.yx_ = L.yx_*R.xx_ + L.yy_*R.yx_ + L.yt_*R.tx_;
00646             T.yy_ = L.yx_*R.xy_ + L.yy_*R.yy_ + L.yt_*R.ty_;
00647             T.yt_ = L.yx_*R.xt_ + L.yy_*R.yt_ + L.yt_*R.tt_;
00648             T.tx_ = L.tx_*R.xx_ + L.ty_*R.yx_ + L.tt_*R.tx_;
00649             T.ty_ = L.tx_*R.xy_ + L.ty_*R.yy_ + L.tt_*R.ty_;
00650             T.tt_ = L.tx_*R.xt_ + L.ty_*R.yt_ + L.tt_*R.tt_;
00651         }
00652         else
00653         {
00654                             // Affine, Similarity, Reflection
00655                             // ZoomOnly, RigidBody
00656             T.xx_ = L.xx_*R.xx_ + L.xy_*R.yx_;
00657             T.xy_ = L.xx_*R.xy_ + L.xy_*R.yy_;
00658             T.xt_ = L.xx_*R.xt_ + L.xy_*R.yt_ + L.xt_;
00659             T.yx_ = L.yx_*R.xx_ + L.yy_*R.yx_;
00660             T.yy_ = L.yx_*R.xy_ + L.yy_*R.yy_;
00661             T.yt_ = L.yx_*R.xt_ + L.yy_*R.yt_ + L.yt_;
00662         }
00663 
00664                             // now set the type using the type of L and R
00665         if (R.form() == L.form())
00666             T.form_ = R.form();
00667         else
00668         {
00669             if (R.form() == vimt_transform_2d::Projective ||
00670                 L.form() == vimt_transform_2d::Projective)
00671                 T.form_ = vimt_transform_2d::Projective;
00672             else
00673             if (R.form() == vimt_transform_2d::Affine ||
00674                 L.form() == vimt_transform_2d::Affine)
00675                 T.form_ = vimt_transform_2d::Affine;
00676             else
00677             if (R.form() == vimt_transform_2d::Reflection ||
00678                 L.form() == vimt_transform_2d::Reflection)
00679                 T.form_ = vimt_transform_2d::Affine;
00680             else
00681             if (R.form() == vimt_transform_2d::Similarity ||
00682                 L.form() == vimt_transform_2d::Similarity)
00683                 T.form_ = vimt_transform_2d::Similarity;
00684             else
00685             if (R.form() == vimt_transform_2d::RigidBody ||
00686                 L.form() == vimt_transform_2d::RigidBody)
00687             {
00688                 if (R.form() == vimt_transform_2d::ZoomOnly)
00689                     if (R.xx_ == R.yy_)
00690                         T.form_ = vimt_transform_2d::Similarity;
00691                     else
00692                         T.form_ = vimt_transform_2d::Affine;
00693                 else
00694                 if (L.form() == vimt_transform_2d::ZoomOnly)
00695                     if (L.xx_ == L.yy_)
00696                         T.form_ = vimt_transform_2d::Similarity;
00697                     else
00698                         T.form_ = vimt_transform_2d::Affine;
00699                 else
00700                     T.form_ = vimt_transform_2d::RigidBody;
00701             }
00702             else
00703             if (R.form() == vimt_transform_2d::ZoomOnly ||
00704                 L.form() == vimt_transform_2d::ZoomOnly)
00705                 T.form_ = vimt_transform_2d::ZoomOnly;
00706             else
00707                 T.form_ = vimt_transform_2d::Translation;
00708         }
00709 
00710                 // make sure det == 1 for rigid body (prevents
00711                 // accumulated rounding errors)
00712         if (T.form_ == vimt_transform_2d::RigidBody)
00713         {
00714             double det = T.xx_*T.yy_ - T.xy_*T.yx_;
00715             T.xx_ /= det;
00716             T.xy_ /= det;
00717             T.yx_ /= det;
00718             T.yy_ /= det;
00719         }
00720     }
00721 
00722     T.inv_uptodate_ = false;
00723     return T;
00724 }
00725 
00726 void vimt_transform_2d::print_summary(vcl_ostream& o) const
00727 {
00728     o << vsl_indent()<< "Form: ";
00729     vsl_indent_inc(o);
00730     switch (form_)
00731     {
00732         case Identity:
00733             o << "Identity";
00734             break;
00735 
00736         case Translation:
00737             o << "Translation (" << xt_ << ',' << yt_ << ')';
00738             break;
00739 
00740         case ZoomOnly:
00741             o << "ZoomOnly\n"
00742               << vsl_indent()<< "scale factor = (" << xx_ << ',' << yy_ << ")\n"
00743               << vsl_indent()<< "translation = (" << xt_ << ',' << yt_ << ')';
00744             break;
00745 
00746         case RigidBody:
00747             o << "RigidBody\n"
00748               << vsl_indent()<< "angle = " << vcl_atan2(yx_,xx_) << '\n'
00749               << vsl_indent()<< "translation = (" << xt_ << ',' << yt_ << ')';
00750             break;
00751 
00752         case Similarity:
00753             o << "Similarity {"
00754               << " s= " << vcl_sqrt(xx_*xx_+xy_*xy_)
00755               << " A= " << vcl_atan2(xy_,xx_)
00756               << " t= (" << xt_ << ',' << yt_ << " ) }";
00757             break;
00758 
00759         case Reflection:
00760             o << "Reflection\n"
00761               << vsl_indent()<< xx_ << ' ' << xy_ << '\n'
00762               << vsl_indent()<< yx_ << ' ' << yy_ << '\n'
00763               << vsl_indent()<< "translation = (" << xt_ << ',' << yt_ << ')';
00764             break;
00765 
00766         case Affine:
00767             o << "Affine\n"
00768               << vsl_indent()<< xx_ << ' ' << xy_ << '\n'
00769               << vsl_indent()<< yx_ << ' ' << yy_ << '\n'
00770               << vsl_indent()<< "translation = (" << xt_ << ',' << yt_ << ')';
00771             break;
00772 
00773         case Projective:
00774             o << "Projective\n"
00775               << vsl_indent()<< xx_ << ' ' << xy_ << ' ' << xt_ << '\n'
00776               << vsl_indent()<< yx_ << ' ' << yy_ << ' ' << yt_ << '\n'
00777               << vsl_indent()<< tx_ << ' ' << ty_ << ' ' << tt_;
00778             break;
00779         default:
00780             assert(!"Invalid form");
00781     }
00782     vsl_indent_dec(o);
00783 }
00784 
00785 vcl_ostream& operator<<( vcl_ostream& os, const vimt_transform_2d& t )
00786 {
00787     os << "vimt_transform_2d:\n";
00788     vsl_indent_inc(os);
00789     t.print_summary(os);
00790     vsl_indent_dec(os);
00791     return os;
00792 }
00793 
00794 short vimt_transform_2d::version_no() const { return 1; }
00795 
00796 
00797 void vimt_transform_2d::b_write(vsl_b_ostream& bfs) const
00798 {
00799     vsl_b_write(bfs,version_no());
00800     vsl_b_write(bfs,int(form_));
00801     vsl_b_write(bfs,xx_); vsl_b_write(bfs,xy_); vsl_b_write(bfs,xt_);
00802     vsl_b_write(bfs,yx_); vsl_b_write(bfs,yy_); vsl_b_write(bfs,yt_);
00803     vsl_b_write(bfs,tx_); vsl_b_write(bfs,ty_); vsl_b_write(bfs,tt_);
00804 }
00805 
00806 void vimt_transform_2d::b_read(vsl_b_istream& bfs)
00807 {
00808     if (!bfs) return;
00809 
00810     short version;
00811     vsl_b_read(bfs,version);
00812     int f;
00813     switch (version) {
00814     case 1:
00815         inv_uptodate_ = false;
00816         vsl_b_read(bfs,f); form_=Form(f);
00817         vsl_b_read(bfs,xx_); vsl_b_read(bfs,xy_); vsl_b_read(bfs,xt_);
00818         vsl_b_read(bfs,yx_); vsl_b_read(bfs,yy_); vsl_b_read(bfs,yt_);
00819         vsl_b_read(bfs,tx_); vsl_b_read(bfs,ty_); vsl_b_read(bfs,tt_);
00820         break;
00821     default:
00822         vcl_cerr << "I/O ERROR: vimt_transform_2d::b_read(vsl_b_istream&)\n"
00823                  << "           Unknown version number "<< version << '\n';
00824         bfs.is().clear(vcl_ios::badbit); // Set an unrecoverable IO error on stream
00825     }
00826 }
00827 
00828 void vsl_b_read(vsl_b_istream& bfs,vimt_transform_2d& t)
00829 {
00830     t.b_read(bfs);
00831 }
00832 
00833 void vsl_b_write(vsl_b_ostream& bfs,const vimt_transform_2d& t)
00834 {
00835     t.b_write(bfs);
00836 }
00837 
00838 void vsl_print_summary(vcl_ostream& os,const vimt_transform_2d& t)
00839 {
00840     //os << t.is_a() << ": ";
00841     vsl_indent_inc(os);
00842     t.print_summary(os);
00843     vsl_indent_dec(os);
00844 }