00001
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005
00006
00007
00008 #include "vimt_transform_2d.h"
00009 #include <vcl_cmath.h>
00010 #include <vcl_cstdlib.h>
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
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_);
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 )
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
00122
00123 if (S2(0,1)*S2(0,1) + S2(1,0)*S2(1,0) >= tol*tol*6)
00124 return *this;
00125
00126
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
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
00308
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
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
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)
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
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)
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);
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> ();
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> ();
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
00593 vimt_transform_2d operator*(const vimt_transform_2d& L, const vimt_transform_2d& R)
00594 {
00595
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
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
00655
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
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
00711
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);
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
00841 vsl_indent_inc(os);
00842 t.print_summary(os);
00843 vsl_indent_dec(os);
00844 }