contrib/oxl/mvl/TriTensor.cxx
Go to the documentation of this file.
00001 // This is oxl/mvl/TriTensor.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 
00008 #include "TriTensor.h"
00009 
00010 #include <vcl_iostream.h>
00011 #include <vcl_cmath.h>
00012 #include <vcl_cassert.h>
00013 #include <vcl_vector.h>
00014 
00015 #include <vul/vul_printf.h>
00016 
00017 #include <vnl/vnl_matrix.h>
00018 #include <vnl/vnl_matlab_print.h>
00019 #include <vnl/vnl_double_3.h>
00020 #include <vnl/vnl_double_3x3.h>
00021 #include <vnl/vnl_identity_3x3.h>
00022 #include <vnl/vnl_cross_product_matrix.h>
00023 #include <vnl/algo/vnl_svd.h>
00024 #include <vnl/vnl_inverse.h>
00025 
00026 #include <vgl/vgl_homg_point_2d.h>
00027 #include <vgl/vgl_homg_line_2d.h>
00028 #include <vgl/algo/vgl_h_matrix_2d.h>
00029 #include <vgl/algo/vgl_homg_operators_2d.h>
00030 
00031 #include <mvl/HomgLine2D.h>
00032 #include <mvl/HomgPoint2D.h>
00033 #include <mvl/HMatrix2D.h>
00034 #include <mvl/FMatrix.h>
00035 #include <mvl/PMatrix.h>
00036 #include <mvl/PMatrixDecompAa.h>
00037 #include <mvl/HMatrix3D.h>
00038 #include <mvl/HomgOperator2D.h>
00039 #include <mvl/FManifoldProject.h>
00040 
00041 struct OuterProduct3x3 : public vnl_double_3x3
00042 {
00043   OuterProduct3x3(vnl_double_3 const& a, vnl_double_3 const& b)
00044   {
00045     for (int i = 0; i < 3; ++i)
00046       for (int j = 0; j < 3; ++j)
00047         put(i,j, a[i] * b[j]);
00048   }
00049 };
00050 
00051 static bool tt_verbose = false;
00052 
00053 #define MUTABLE_CAST(slot) (((TriTensor*)this)->slot) // const violation ...
00054 
00055 //--------------------------------------------------------------
00056 
00057 
00058 //: Default constructor.
00059 TriTensor::TriTensor()
00060   : T(3, 3, 3), e12_(0), e13_(0), fmp12_(0), fmp13_(0), fmp23_(0)
00061 {
00062 }
00063 
00064 //
00065 //: Construct a TriTensor from a linear array of doubles.
00066 // The doubles are stored in ``matrix'' order, with the last index
00067 // increasing fastest.
00068 TriTensor::TriTensor(const double *tritensor_array)
00069   : T(3, 3, 3, tritensor_array), e12_(0), e13_(0), fmp12_(0), fmp13_(0), fmp23_(0)
00070 {
00071 }
00072 
00073 //: Copy constructor.
00074 TriTensor::TriTensor(const TriTensor& that)
00075   : T(that.T), e12_(0), e13_(0), fmp12_(0), fmp13_(0), fmp23_(0)
00076 {
00077 }
00078 
00079 //: Construct from 3 projection matrices.
00080 TriTensor::TriTensor(PMatrix const& P1,
00081                      PMatrix const& P2,
00082                      PMatrix const& P3)
00083   : T(3, 3, 3), e12_(0), e13_(0), fmp12_(0), fmp13_(0), fmp23_(0)
00084 {
00085   set(P1, P2, P3);
00086 }
00087 
00088 //: Construct from 2 projection matrices, as described in set.
00089 TriTensor::TriTensor(PMatrix const& P2,
00090                      PMatrix const& P3)
00091   : T(3, 3, 3), e12_(0), e13_(0), fmp12_(0), fmp13_(0), fmp23_(0)
00092 {
00093   set(P2, P3);
00094 }
00095 
00096 //: Construct from 3 matrices.
00097 TriTensor::TriTensor(vnl_matrix<double> const& T1,
00098                      vnl_matrix<double> const& T2,
00099                      vnl_matrix<double> const& T3)
00100   : T(3, 3, 3), e12_(0), e13_(0), fmp12_(0), fmp13_(0), fmp23_(0)
00101 {
00102   set(T1, T2, T3);
00103 }
00104 
00105 //: Assignment
00106 TriTensor& TriTensor::operator=(const TriTensor& that)
00107 {
00108   T = that.T;
00109   delete_caches();
00110 
00111   return *this;
00112 }
00113 
00114 //: Destructor
00115 TriTensor::~TriTensor()
00116 {
00117   delete_caches();
00118 }
00119 
00120 // - Delete and zero epipole and manifold projector classes.
00121 void TriTensor::delete_caches() const
00122 {
00123   delete e12_; e12_ = 0;
00124   delete e13_; e13_ = 0;
00125   delete fmp12_; fmp12_ = 0;
00126   delete fmp13_; fmp13_ = 0;
00127   delete fmp23_; fmp23_ = 0;
00128 }
00129 
00130 //: Convert T to 27x1 matrix. Out is assumed to have been appropriately resized.
00131 void TriTensor::convert_to_vector(vnl_matrix<double> * out) const
00132 {
00133   // tr_convert_tensor_to_vector
00134   assert(out-> rows() == 27 && out-> columns() == 1);
00135   T.get(out->data_block());
00136 }
00137 
00138 //: Convert from 27x1 matrix.
00139 void TriTensor::set(const vnl_matrix<double>& in)
00140 {
00141   assert(in.rows() == 27 && in.columns() == 1);
00142   T.set(in.data_block());
00143   delete_caches();
00144 }
00145 
00146 // == BUILDING ==
00147 
00148 //: Construct from 3 projection matrices.
00149 void
00150 TriTensor::set(const PMatrix& P1, const PMatrix& P2, const PMatrix& P3)
00151 {
00152   PMatrixDecompAa p2;
00153   PMatrixDecompAa p3;
00154 
00155   bool canon1 = P1.is_canonical(1e-12);
00156   if (canon1) {
00157     p2.set(P2);
00158     p3.set(P3);
00159   }
00160   else {
00161     HMatrix3D H = P1.get_canonical_H();
00162     p2.set(P2 * H);
00163     p3.set(P3 * H);
00164   }
00165 
00166   for (int i = 0; i < 3; ++i)
00167     for (int j = 0; j < 3; ++j)
00168       for (int k = 0; k < 3; ++k)
00169         T(i,j,k) = p2.A(j,i) * p3.a[k] - p3.A(k,i) * p2.a[j];
00170   delete_caches();
00171 }
00172 
00173 //: Construct from 2 projection matrices, P2 and P3.
00174 //  The first is assumed to be the canonical [I | 0].
00175 void
00176 TriTensor::set(const PMatrix& P2, const PMatrix& P3)
00177 {
00178   PMatrixDecompAa p2;
00179   PMatrixDecompAa p3;
00180 
00181   p2.set(P2);
00182   p3.set(P3);
00183 
00184   for (int i = 0; i < 3; ++i)
00185     for (int j = 0; j < 3; ++j)
00186       for (int k = 0; k < 3; ++k)
00187         T(i,j,k) = p2.A(j,i) * p3.a[k] - p3.A(k,i) * p2.a[j];
00188 
00189   delete_caches();
00190 }
00191 
00192 //: Construct from 3 T matrices.
00193 void
00194 TriTensor::set(vnl_matrix<double> const& T1,
00195                vnl_matrix<double> const& T2,
00196                vnl_matrix<double> const& T3)
00197 {
00198   vcl_cerr << "TriTensor: construct from 3 T-matrices: Unimplemented\n";
00199   vnl_matrix<double> const* Ts[3];
00200   Ts[0] = &T1;
00201   Ts[1] = &T2;
00202   Ts[2] = &T3;
00203 
00204   for (int i = 0; i < 3; ++i) {
00205     const vnl_matrix<double>& Ti = *Ts[i];
00206     for (int j = 0; j < 3; ++j)
00207       for (int k = 0; k < 3; ++k)
00208         T(i,j,k) = Ti(j,k);
00209   }
00210   delete_caches();
00211 }
00212 
00213 // == TRANSFER ==
00214 
00215 //-----------------------------------------------------------------------------
00216 //
00217 //: For the specified points in image 1/2, return the transferred point in image 3.
00218 // Transfer is via optimal backprojection.
00219 //
00220 
00221 HomgPoint2D
00222 TriTensor::image3_transfer(HomgPoint2D const& point1,
00223                            HomgPoint2D const& point2,
00224                            HomgPoint2D corrected[]) const
00225 {
00226   HomgPoint2D corr[2];
00227   if (!corrected) corrected = corr;
00228   get_fmp12()->correct(point1, point2, &corrected[0], &corrected[1]);
00229 
00230   vcl_vector<HomgLine2D> constraint_lines(9);
00231   get_constraint_lines_image3(corrected[0], corrected[1], &constraint_lines);
00232   return HomgOperator2D::lines_to_point(constraint_lines);
00233 }
00234 
00235 //-----------------------------------------------------------------------------
00236 //
00237 //: For the specified points in image 1/3, return the transferred point in image 2.
00238 //
00239 
00240 HomgPoint2D
00241 TriTensor::image2_transfer(HomgPoint2D const& point1,
00242                            HomgPoint2D const& point3,
00243                            HomgPoint2D corrected[]) const
00244 {
00245   HomgPoint2D corr[2];
00246   if (!corrected) corrected = corr;
00247   get_fmp13()->correct(point1, point3, &corrected[0], &corrected[1]);
00248 
00249   vcl_vector<HomgLine2D> constraint_lines(9);
00250   get_constraint_lines_image2(corrected[0], corrected[1], &constraint_lines);
00251   return HomgOperator2D::lines_to_point(constraint_lines);
00252 }
00253 
00254 //-----------------------------------------------------------------------------
00255 //
00256 //: For the specified points in image 2/3, return the transferred point in image 1.
00257 //
00258 
00259 vgl_homg_point_2d<double>
00260 TriTensor::image1_transfer(vgl_homg_point_2d<double> const& point2,
00261                            vgl_homg_point_2d<double> const& point3,
00262                            vgl_homg_point_2d<double> corrected[]) const
00263 {
00264   vgl_homg_point_2d<double> corr[2];
00265   if (!corrected) corrected = corr;
00266   get_fmp23()->correct(point2, point3, corrected[0], corrected[1]);
00267 
00268   vcl_vector<vgl_homg_line_2d<double> > constraint_lines(9);
00269   get_constraint_lines_image1(corrected[0], corrected[1], constraint_lines);
00270   return vgl_homg_operators_2d<double>::lines_to_point(constraint_lines);
00271 }
00272 
00273 HomgPoint2D
00274 TriTensor::image1_transfer(HomgPoint2D const& point2,
00275                            HomgPoint2D const& point3,
00276                            HomgPoint2D corrected[]) const
00277 {
00278   HomgPoint2D corr[2];
00279   if (!corrected) corrected = corr;
00280   get_fmp23()->correct(point2, point3, &corrected[0], &corrected[1]);
00281 
00282   vcl_vector<HomgLine2D> constraint_lines(9);
00283   get_constraint_lines_image1(corrected[0], corrected[1], &constraint_lines);
00284   return HomgOperator2D::lines_to_point(constraint_lines);
00285 }
00286 
00287 // == TRANSFER: ``Quick and Dirty'' ==
00288 
00289 //-----------------------------------------------------------------------------
00290 //
00291 //: For the specified points in image 1/2, return the transferred point in image 3.
00292 //
00293 
00294 vgl_homg_point_2d<double>
00295 TriTensor::image3_transfer_qd(vgl_homg_point_2d<double> const& point1,
00296                               vgl_homg_point_2d<double> const& point2) const
00297 {
00298   // tr_transfer_point_12_to_3
00299   vcl_vector<vgl_homg_line_2d<double> > constraint_lines(9);
00300   get_constraint_lines_image3(point1, point2, constraint_lines);
00301   return vgl_homg_operators_2d<double>::lines_to_point(constraint_lines);
00302 }
00303 
00304 HomgPoint2D
00305 TriTensor::image3_transfer_qd(HomgPoint2D const& point1,
00306                               HomgPoint2D const& point2) const
00307 {
00308   // tr_transfer_point_12_to_3
00309   vcl_vector<HomgLine2D> constraint_lines(9);
00310   get_constraint_lines_image3(point1, point2, &constraint_lines);
00311   return HomgOperator2D::lines_to_point(constraint_lines);
00312 }
00313 
00314 //-----------------------------------------------------------------------------
00315 //
00316 //: For the specified points in image 1/3, return the transferred point in image 2.
00317 //
00318 
00319 vgl_homg_point_2d<double>
00320 TriTensor::image2_transfer_qd(vgl_homg_point_2d<double> const& point1,
00321                               vgl_homg_point_2d<double> const& point3) const
00322 {
00323   vcl_vector<vgl_homg_line_2d<double> > constraint_lines(9);
00324   get_constraint_lines_image2(point1, point3, constraint_lines);
00325   return vgl_homg_operators_2d<double>::lines_to_point(constraint_lines);
00326 }
00327 
00328 HomgPoint2D
00329 TriTensor::image2_transfer_qd(HomgPoint2D const& point1,
00330                               HomgPoint2D const& point3) const
00331 {
00332   vcl_vector<HomgLine2D> constraint_lines(9);
00333   get_constraint_lines_image2(point1, point3, &constraint_lines);
00334   return HomgOperator2D::lines_to_point(constraint_lines);
00335 }
00336 
00337 //-----------------------------------------------------------------------------
00338 //
00339 //: For the specified points in image 2/3, return the transferred point in image 1.
00340 //
00341 
00342 vgl_homg_point_2d<double>
00343 TriTensor::image1_transfer_qd(vgl_homg_point_2d<double> const& point2,
00344                               vgl_homg_point_2d<double> const& point3) const
00345 {
00346   vcl_vector<vgl_homg_line_2d<double> > constraint_lines(9);
00347   get_constraint_lines_image1(point2, point3, constraint_lines);
00348   return vgl_homg_operators_2d<double>::lines_to_point(constraint_lines);
00349 }
00350 
00351 HomgPoint2D
00352 TriTensor::image1_transfer_qd(HomgPoint2D const& point2,
00353                               HomgPoint2D const& point3) const
00354 {
00355   vcl_vector<HomgLine2D> constraint_lines(9);
00356   get_constraint_lines_image1(point2, point3, &constraint_lines);
00357   return HomgOperator2D::lines_to_point(constraint_lines);
00358 }
00359 
00360 //-----------------------------------------------------------------------------
00361 //
00362 //: For the specified lines in image 2/3, return the transferred line in image 1.
00363 //
00364 
00365 vgl_homg_line_2d<double>
00366 TriTensor::image1_transfer(vgl_homg_line_2d<double> const& line2,
00367                            vgl_homg_line_2d<double> const& line3) const
00368 {
00369   vnl_double_3 l1(0.0,0.0,0.0);
00370   vnl_double_3 l2(line2.a(),line2.b(),line2.c());
00371   vnl_double_3 l3(line3.a(),line3.b(),line3.c());
00372 
00373   for (int i = 0; i < 3; i++)
00374     for (int j = 0; j < 3; j++)
00375       for (int k = 0; k < 3; k++)
00376         l1 [i] +=  T(i,j,k) * l2 [j] * l3 [k];
00377 
00378   return vgl_homg_line_2d<double>(l1[0],l1[1],l1[2]);
00379 }
00380 
00381 HomgLine2D
00382 TriTensor::image1_transfer(HomgLine2D const& line2,
00383                            HomgLine2D const& line3) const
00384 {
00385   vnl_double_3 l1(0,0,0);
00386   const vnl_vector<double>& l2 = line2.get_vector().as_ref();
00387   const vnl_vector<double>& l3 = line3.get_vector().as_ref();
00388 
00389   for (int i = 0; i < 3; i++)
00390     for (int j = 0; j < 3; j++)
00391       for (int k = 0; k < 3; k++)
00392         l1 [i] +=  T(i,j,k) * l2 [j] * l3 [k];
00393 
00394   return HomgLine2D(l1);
00395 }
00396 
00397 //-----------------------------------------------------------------------------
00398 //
00399 //: For the specified lines in image 2/3, return the transferred line in image 1.
00400 //
00401 
00402 vgl_homg_line_2d<double>
00403 TriTensor::image2_transfer(vgl_homg_line_2d<double> const& line1,
00404                            vgl_homg_line_2d<double> const& line3) const
00405 {
00406   vnl_double_3 l1(line1.a(),line1.b(),line1.c());
00407   vnl_double_3 l3(line3.a(),line3.b(),line3.c());
00408   vnl_double_3 l = vnl_inverse(dot3(l3)) * l1;
00409   return vgl_homg_line_2d<double>(l[0],l[1],l[2]);
00410 }
00411 
00412 HomgLine2D
00413 TriTensor::image2_transfer(HomgLine2D const& line1,
00414                            HomgLine2D const& line3) const
00415 {
00416   return HomgLine2D(vnl_inverse(dot3(line3.get_vector().as_ref())) * line1.get_vector());
00417 }
00418 
00419 //-----------------------------------------------------------------------------
00420 //
00421 //: For the specified lines in image 1/2, return the transferred line in image 3.
00422 //
00423 
00424 vgl_homg_line_2d<double>
00425 TriTensor::image3_transfer(vgl_homg_line_2d<double> const& line1,
00426                            vgl_homg_line_2d<double> const& line2) const
00427 {
00428   vnl_double_3 l1(line1.a(),line1.b(),line1.c());
00429   vnl_double_3 l2(line2.a(),line2.b(),line2.c());
00430   vnl_double_3 l = vnl_inverse(dot2(l2)) * l1;
00431   return vgl_homg_line_2d<double>(l[0],l[1],l[2]);
00432 }
00433 
00434 HomgLine2D
00435 TriTensor::image3_transfer(HomgLine2D const& line1,
00436                            HomgLine2D const& line2) const
00437 {
00438   return HomgLine2D(vnl_inverse(dot2(line2.get_vector().as_ref())) * line1.get_vector());
00439 }
00440 
00441 // == HOMOGRAPHIES FROM LINES ==
00442 
00443 //: Return the planar homography between views 3 and 1 induced by line 2
00444 vgl_h_matrix_2d<double> TriTensor::get_hmatrix_31(vgl_homg_line_2d<double> const& line2) const
00445 {
00446   vnl_double_3 l2(line2.a(),line2.b(),line2.c());
00447   return vgl_h_matrix_2d<double>(dot2(l2));
00448 }
00449 
00450 HMatrix2D TriTensor::get_hmatrix_31(const HomgLine2D& line2) const
00451 {
00452   return HMatrix2D(dot2(line2.get_vector().as_ref()));
00453 }
00454 
00455 //: Return the planar homography between views 2 and 1 induced by line 3
00456 vgl_h_matrix_2d<double> TriTensor::get_hmatrix_21(vgl_homg_line_2d<double> const& line3) const
00457 {
00458   vnl_double_3 l3(line3.a(),line3.b(),line3.c());
00459   return vgl_h_matrix_2d<double>(dot3(l3));
00460 }
00461 
00462 HMatrix2D TriTensor::get_hmatrix_21(const HomgLine2D& line3) const
00463 {
00464   return HMatrix2D(dot3(line3.get_vector().as_ref()));
00465 }
00466 
00467 // == CONTRACTION WITH VECTORS ==
00468 
00469 //: Compute ${\tt M}_{jk} = T_{ijk} v_i$.
00470 vnl_double_3x3 TriTensor::dot1(const vnl_double_3& v) const
00471 {
00472   vnl_double_3x3 answer; answer.fill(0.0);
00473   for (int i = 0; i < 3; i++)
00474     for (int j = 0; j < 3; j++)
00475       for (int k = 0; k < 3; k++)
00476         answer(j,k) += v[i] * T(i,j,k);
00477   return answer;
00478 }
00479 
00480 //: Compute ${\tt M}_{ik} = T_{ijk} v_j$.
00481 vnl_double_3x3 TriTensor::dot2(const vnl_double_3& v) const
00482 {
00483   vnl_double_3x3 answer; answer.fill(0.0);
00484   for (int i = 0; i < 3; i++)
00485     for (int j = 0; j < 3; j++)
00486       for (int k = 0; k < 3; k++)
00487         answer(i,k) += v[j] * T(i,j,k);
00488   return answer;
00489 }
00490 
00491 //: Compute ${\tt M}_{ij} = T_{ijk} v_k$.
00492 vnl_double_3x3 TriTensor::dot3(const vnl_double_3& v) const
00493 {
00494   vnl_double_3x3 answer; answer.fill(0.0);
00495   for (int i = 0; i < 3; i++)
00496     for (int j = 0; j < 3; j++)
00497       for (int k = 0; k < 3; k++)
00498         answer(i,j) += v[k] * T(i,j,k);
00499   return answer;
00500 }
00501 
00502 //: Compute ${\tt M}_{kj} = T_{ijk} v_i$. (The transpose of dot1).
00503 vnl_double_3x3 TriTensor::dot1t(const vnl_double_3& v) const
00504 {
00505   vnl_double_3x3 answer; answer.fill(0.0);
00506   for (int i = 0; i < 3; i++)
00507     for (int j = 0; j < 3; j++)
00508       for (int k = 0; k < 3; k++)
00509         answer(k,j) += v[i] * T(i,j,k);
00510   return answer;
00511 }
00512 
00513 //: Compute ${\tt M}_{ki} = T_{ijk} v_j$.
00514 vnl_double_3x3 TriTensor::dot2t(const vnl_double_3& v) const
00515 {
00516   vnl_double_3x3 answer; answer.fill(0.0);
00517   for (int i = 0; i < 3; i++)
00518     for (int j = 0; j < 3; j++)
00519       for (int k = 0; k < 3; k++)
00520         answer(k,i) += v[j] * T(i,j,k);
00521   return answer;
00522 }
00523 
00524 //: Compute ${\tt M}_{ji} = T_{ijk} v_k$.
00525 vnl_double_3x3 TriTensor::dot3t(const vnl_double_3& v) const
00526 {
00527   vnl_double_3x3 answer; answer.fill(0.0);
00528   for (int i = 0; i < 3; i++)
00529     for (int j = 0; j < 3; j++)
00530       for (int k = 0; k < 3; k++)
00531         answer(j,i) += v[k] * T(i,j,k);
00532   return answer;
00533 }
00534 
00535 // == COMPOSITION WITH MATRICES ==
00536 
00537 //: Contract tensor axis tensor_axis with first component of matrix $M$.
00538 // That is, where $S$ is the result of the operation:
00539 //
00540 // - For tensor_axis = 1, compute $S_{ijk} = T_{pjk} M_{pi}$
00541 // - For tensor_axis = 2, compute $S_{ijk} = T_{ipk} M_{pj}$
00542 // - For tensor_axis = 3, compute $S_{ijk} = T_{ijp} M_{pk}$
00543 TriTensor TriTensor::postmultiply(unsigned tensor_axis, const vnl_matrix<double>& M) const
00544 {
00545   switch (tensor_axis) {
00546   case 1: return postmultiply1(M);
00547   case 2: return postmultiply2(M);
00548   case 3: return postmultiply3(M);
00549   default:
00550     assert(tensor_axis <= 3);
00551     return *this; // Shut up compiler
00552   }
00553 }
00554 
00555 //: Contract tensor axis tensor_axis with second component of matrix $M$.
00556 // That is, where $S$ is the result of the operation:
00557 //
00558 // - For tensor_axis = 1, compute $S_{ijk} = M_{ip} T_{pjk}$
00559 // - For tensor_axis = 2, compute $S_{ijk} = M_{jp} T_{ipk}$
00560 // - For tensor_axis = 3, compute $S_{ijk} = M_{kp} T_{ijp}$
00561 TriTensor TriTensor::premultiply(unsigned tensor_axis, const vnl_matrix<double>& M) const
00562 {
00563   switch (tensor_axis) {
00564   case 1: return premultiply1(M);
00565   case 2: return premultiply2(M);
00566   case 3: return premultiply3(M);
00567   default:
00568     assert(tensor_axis <= 3);
00569     return *this; // Shut up compiler
00570   }
00571 }
00572 
00573 //: Compute $ S_{ijk} = T_{pjk} M_{pi} $.
00574 TriTensor TriTensor::postmultiply1(const vnl_matrix<double>& M) const
00575 {
00576   TriTensor S;
00577   for (int i = 0; i < 3; ++i)
00578     for (int j = 0; j < 3; ++j)
00579       for (int k = 0; k < 3; ++k) {
00580         double v = 0;
00581         for (int p = 0; p < 3; ++p)
00582           v += T(p,j,k) * M(p,i);
00583         S(i,j,k) = v;
00584       }
00585   return S;
00586 }
00587 
00588 //: Compute $ S_{ijk} = T_{ipk} M_{pj} $.
00589 TriTensor TriTensor::postmultiply2(const vnl_matrix<double>& M) const
00590 {
00591   TriTensor S;
00592   for (int i = 0; i < 3; ++i)
00593     for (int j = 0; j < 3; ++j)
00594       for (int k = 0; k < 3; ++k) {
00595         double v = 0;
00596         for (int p = 0; p < 3; ++p)
00597           v += T(i,p,k) * M(p,j);
00598         S(i,j,k) = v;
00599       }
00600   return S;
00601 }
00602 
00603 //: Compute $ S_{ijk} = T_{ijp} M_{pk} $.
00604 TriTensor TriTensor::postmultiply3(const vnl_matrix<double>& M) const
00605 {
00606   TriTensor S;
00607   for (int i = 0; i < 3; ++i)
00608     for (int j = 0; j < 3; ++j)
00609       for (int k = 0; k < 3; ++k) {
00610         double v = 0;
00611         for (int p = 0; p < 3; ++p)
00612           v += T(i,j,p) * M(p,k);
00613         S(i,j,k) = v;
00614       }
00615   return S;
00616 }
00617 
00618 //: Compute $ S_{ijk} = M_{ip} T_{pjk} $.
00619 TriTensor TriTensor::premultiply1(const vnl_matrix<double>& M) const
00620 {
00621   TriTensor S;
00622   for (int i = 0; i < 3; ++i)
00623     for (int j = 0; j < 3; ++j)
00624       for (int k = 0; k < 3; ++k) {
00625         double v = 0;
00626         for (int p = 0; p < 3; ++p)
00627           v += M(i,p) * T(p,j,k);
00628         S(i,j,k) = v;
00629       }
00630   return S;
00631 }
00632 
00633 //: Compute $ S_{ijk} = M_{jp} T_{ipk} $.
00634 TriTensor TriTensor::premultiply2(const vnl_matrix<double>& M) const
00635 {
00636   TriTensor S;
00637   for (int i = 0; i < 3; ++i)
00638     for (int j = 0; j < 3; ++j)
00639       for (int k = 0; k < 3; ++k) {
00640         double v = 0;
00641         for (int p = 0; p < 3; ++p)
00642           v += M(j,p) * T(i,p,k);
00643         S(i,j,k) = v;
00644       }
00645   return S;
00646 }
00647 
00648 //: Compute $ S_{ijk} = M_{kp} T_{ijp} $.
00649 TriTensor TriTensor::premultiply3(const vnl_matrix<double>& M) const
00650 {
00651   TriTensor S;
00652   for (int i = 0; i < 3; ++i)
00653     for (int j = 0; j < 3; ++j)
00654       for (int k = 0; k < 3; ++k) {
00655         double v = 0;
00656         for (int p = 0; p < 3; ++p)
00657           v += M(k,p) * T(i,j,p);
00658         S(i,j,k) = v;
00659       }
00660   return S;
00661 }
00662 
00663 // INTERNALS---------------------------------------------------------------
00664 
00665 // == TRANSFORMATION ==
00666 
00667 //:
00668 // The ${\tt C}_{123}$ are line transformation matrices.  If
00669 // ${\tt C}_{v} l_v = \hat l_v$ describes the transformation of each image plane under
00670 // a planar homography, and $l_1 = T l_2 l_3$ describes the action of this TriTensor, then
00671 // this routine computes $\hat T$ such that $\hat l_1 = \hat T \hat l_2 \hat l_3$.
00672 //
00673 // Specifically $\hat T = T.\mbox{decondition}(C_1^{-1}, C_2, C_3)$ is the
00674 // transformed tensor.  Note that unless transfer is via Hartley-Sturm, the deconditioned
00675 // tensor will not be covariant with the conditioned one.
00676 TriTensor TriTensor::condition(vnl_matrix<double> const& line_1_denorm,
00677                                vnl_matrix<double> const& line_2_norm,
00678                                vnl_matrix<double> const& line_3_norm) const
00679 {
00680   return premultiply1(line_1_denorm).postmultiply2(line_2_norm).postmultiply3(line_3_norm);
00681 }
00682 
00683 TriTensor TriTensor::decondition(vnl_matrix<double> const& line_1_norm,
00684                                  vnl_matrix<double> const& line_2_denorm,
00685                                  vnl_matrix<double> const& line_3_denorm) const
00686 {
00687   return premultiply1(line_1_norm).postmultiply2(line_2_denorm).postmultiply3(line_3_denorm);
00688 }
00689 
00690 //-----------------------------------------------------------------------------
00691 // - Return the 9 lines on which a transferred point ought to lie.
00692 void TriTensor::get_constraint_lines_image3(vgl_homg_point_2d<double> const& p1,
00693                                             vgl_homg_point_2d<double> const& p2,
00694                                             vcl_vector<vgl_homg_line_2d<double> >& lines) const
00695 {
00696   // use the same notation as the output of tr_hartley_equation.
00697   double x1 = p1.x();
00698   double y1 = p1.y();
00699   double z1 = p1.w();
00700 
00701   double x2 = p2.x();
00702   double y2 = p2.y();
00703   double z2 = p2.w();
00704 
00705   lines.clear();
00706 
00707   /* 0 */
00708   {
00709     double lx =
00710       -x1 * x2 * T(0,1,1) + x1 * y2 * T(0,0,1)
00711       -y1 * x2 * T(1,1,1) + y1 * y2 * T(1,0,1)
00712       -z1 * x2 * T(2,1,1) + z1 * y2 * T(2,0,1);
00713 
00714     double ly =
00715       x1 * x2 * T(0,1,0) - x1 * y2 * T(0,0,0) +
00716       y1 * x2 * T(1,1,0) - y1 * y2 * T(1,0,0) +
00717       z1 * x2 * T(2,1,0) - z1 * y2 * T(2,0,0);
00718 
00719     double lz = 0;
00720     lines.push_back(vgl_homg_line_2d<double>(lx, ly, lz));
00721   }
00722 
00723   /* 1 */
00724   {
00725     double lx =
00726       -x1 * x2 * T(0,1,2) + x1 * y2 * T(0,0,2)
00727       - y1 * x2 * T(1,1,2) + y1 * y2 * T(1,0,2)
00728       - z1 * x2 * T(2,1,2) + z1 * y2 * T(2,0,2);
00729 
00730     double ly = 0;
00731 
00732     double lz
00733     = x1 * x2 * T(0,1,0) - x1 * y2 * T(0,0,0)
00734     + y1 * x2 * T(1,1,0) - y1 * y2 * T(1,0,0)
00735     + z1 * x2 * T(2,1,0) - z1 * y2 * T(2,0,0);
00736 
00737     lines.push_back(vgl_homg_line_2d<double>(lx, ly, lz));
00738   }
00739 
00740   /* 2 */
00741   {
00742     double lx =
00743       0;
00744 
00745     double ly =
00746       -x1 * x2 * T(0,1,2) + x1 * y2 * T(0,0,2)
00747       -y1 * x2 * T(1,1,2) + y1 * y2 * T(1,0,2)
00748       -z1 * x2 * T(2,1,2) + z1 * y2 * T(2,0,2);
00749 
00750     double lz =
00751       x1 * x2 * T(0,1,1) - x1 * y2 * T(0,0,1)
00752       + y1 * x2 * T(1,1,1) - y1 * y2 * T(1,0,1)
00753       + z1 * x2 * T(2,1,1) - z1 * y2 * T(2,0,1);
00754 
00755     lines.push_back(vgl_homg_line_2d<double>(lx, ly, lz));
00756   }
00757 
00758   /* 3 */
00759   {
00760     double lx =
00761       -x1 * x2 * T(0,2,1) + x1 * z2 * T(0,0,1)
00762       - y1 * x2 * T(1,2,1) + y1 * z2 * T(1,0,1)
00763       - z1 * x2 * T(2,2,1) + z1 * z2 * T(2,0,1);
00764 
00765     double ly =
00766       x1 * x2 * T(0,2,0) - x1 * z2 * T(0,0,0)
00767       + y1 * x2 * T(1,2,0) - y1 * z2 * T(1,0,0)
00768       + z1 * x2 * T(2,2,0) - z1 * z2 * T(2,0,0);
00769 
00770     double lz = 0;
00771     lines.push_back(vgl_homg_line_2d<double>(lx, ly, lz));
00772   }
00773 
00774   /* 4 */
00775   {
00776     double lx =
00777       -x1 * x2 * T(0,2,2) + x1 * z2 * T(0,0,2)
00778       -y1 * x2 * T(1,2,2) + y1 * z2 * T(1,0,2)
00779       -z1 * x2 * T(2,2,2) + z1 * z2 * T(2,0,2);
00780 
00781     double ly = 0;
00782 
00783     double lz =
00784       x1 * x2 * T(0,2,0) - x1 * z2 * T(0,0,0) +
00785       y1 * x2 * T(1,2,0) - y1 * z2 * T(1,0,0) +
00786       z1 * x2 * T(2,2,0) - z1 * z2 * T(2,0,0);
00787     lines.push_back(vgl_homg_line_2d<double>(lx, ly, lz));
00788   }
00789 
00790   /* 5 */
00791   {
00792     double lx = 0;
00793 
00794     double ly =
00795       -x1 * x2 * T(0,2,2) + x1 * z2 * T(0,0,2)
00796       -y1 * x2 * T(1,2,2) + y1 * z2 * T(1,0,2)
00797       -z1 * x2 * T(2,2,2) + z1 * z2 * T(2,0,2);
00798 
00799     double lz
00800         = x1 * x2 * T(0,2,1) - x1 * z2 * T(0,0,1)
00801         + y1 * x2 * T(1,2,1) - y1 * z2 * T(1,0,1)
00802         + z1 * x2 * T(2,2,1) - z1 * z2 * T(2,0,1);
00803     lines.push_back(vgl_homg_line_2d<double>(lx, ly, lz));
00804   }
00805 
00806   /* 6 */
00807   {
00808     double lx
00809         = - x1 * y2 * T(0,2,1) + x1 * z2 * T(0,1,1)
00810         - y1 * y2 * T(1,2,1) + y1 * z2 * T(1,1,1)
00811         - z1 * y2 * T(2,2,1) + z1 * z2 * T(2,1,1);
00812 
00813     double ly
00814         = x1 * y2 * T(0,2,0) - x1 * z2 * T(0,1,0)
00815         + y1 * y2 * T(1,2,0) - y1 * z2 * T(1,1,0)
00816         + z1 * y2 * T(2,2,0) - z1 * z2 * T(2,1,0);
00817 
00818     double lz = 0;
00819     lines.push_back(vgl_homg_line_2d<double>(lx, ly, lz));
00820   }
00821 
00822   /* 7 */
00823   {
00824     double lx
00825         = -x1 * y2 * T(0,2,2) + x1 * z2 * T(0,1,2)
00826         - y1 * y2 * T(1,2,2) + y1 * z2 * T(1,1,2)
00827         - z1 * y2 * T(2,2,2) + z1 * z2 * T(2,1,2);
00828 
00829     double ly = 0;
00830 
00831     double lz
00832         = x1 * y2 * T(0,2,0) - x1 * z2 * T(0,1,0)
00833         + y1 * y2 * T(1,2,0) - y1 * z2 * T(1,1,0)
00834         + z1 * y2 * T(2,2,0) - z1 * z2 * T(2,1,0);
00835 
00836     lines.push_back(vgl_homg_line_2d<double>(lx, ly, lz));
00837   }
00838 
00839   /* 8 */
00840   {
00841     double lx = 0;
00842 
00843     double ly
00844         = -x1 * y2 * T(0,2,2) + x1 * z2 * T(0,1,2)
00845         - y1 * y2 * T(1,2,2) + y1 * z2 * T(1,1,2)
00846         - z1 * y2 * T(2,2,2) + z1 * z2 * T(2,1,2);
00847 
00848     double lz
00849         = x1 * y2 * T(0,2,1) - x1 * z2 * T(0,1,1)
00850         + y1 * y2 * T(1,2,1) - y1 * z2 * T(1,1,1)
00851         + z1 * y2 * T(2,2,1) - z1 * z2 * T(2,1,1);
00852 
00853     lines.push_back(vgl_homg_line_2d<double>(lx, ly, lz));
00854   }
00855 
00856   assert(lines.size() == 9);
00857   if (tt_verbose)
00858     for (int i = 0; i < 9; ++i)
00859       vcl_cerr << lines[i]<< '\n';
00860 
00861   return;
00862 }
00863 
00864 void TriTensor::get_constraint_lines_image3(HomgPoint2D const& p1,
00865                                             HomgPoint2D const& p2,
00866                                             vcl_vector<HomgLine2D>* lines) const
00867 {
00868 #if 0 // Old code assumed points were in image coordinates and conditioned them,
00869       // deconditioning the lines on return.
00870   ma2_static_multiply_3x3_trivec(tritensor_ptr->corner1_norm_matrix, trivec1_ptr, &mapped_trivec1);
00871   ma2_static_multiply_3x3_trivec(tritensor_ptr->corner2_norm_matrix, trivec2_ptr, &mapped_trivec2);
00872 #endif // 0
00873 
00874   // use the same notation as the output of tr_hartley_equation.
00875   double x1 = p1.x();
00876   double y1 = p1.y();
00877   double z1 = p1.w();
00878 
00879   double x2 = p2.x();
00880   double y2 = p2.y();
00881   double z2 = p2.w();
00882 
00883 #ifdef DEBUG
00884   vcl_cerr << "CLINES = [" << x1 << ' ' << y1 << ' ' << z1 << "; " << x2 << ' ' << y2 << ' ' << z2 << "];\n";
00885 #endif
00886 
00887   lines->resize(0);
00888 
00889 
00890   /* 0 */
00891   {
00892     double lx =
00893       -x1 * x2 * T(0,1,1) + x1 * y2 * T(0,0,1)
00894       -y1 * x2 * T(1,1,1) + y1 * y2 * T(1,0,1)
00895       -z1 * x2 * T(2,1,1) + z1 * y2 * T(2,0,1);
00896 
00897     double ly =
00898       x1 * x2 * T(0,1,0) - x1 * y2 * T(0,0,0) +
00899       y1 * x2 * T(1,1,0) - y1 * y2 * T(1,0,0) +
00900       z1 * x2 * T(2,1,0) - z1 * y2 * T(2,0,0);
00901 
00902     double lz = 0;
00903     lines->push_back(HomgLine2D(lx, ly, lz));
00904   }
00905 
00906   /* 1 */
00907   {
00908     double lx =
00909       -x1 * x2 * T(0,1,2) + x1 * y2 * T(0,0,2)
00910       - y1 * x2 * T(1,1,2) + y1 * y2 * T(1,0,2)
00911       - z1 * x2 * T(2,1,2) + z1 * y2 * T(2,0,2);
00912 
00913     double ly = 0;
00914 
00915     double lz
00916     = x1 * x2 * T(0,1,0) - x1 * y2 * T(0,0,0)
00917     + y1 * x2 * T(1,1,0) - y1 * y2 * T(1,0,0)
00918     + z1 * x2 * T(2,1,0) - z1 * y2 * T(2,0,0);
00919 
00920     lines->push_back(HomgLine2D(lx, ly, lz));
00921   }
00922 
00923   /* 2 */
00924   {
00925     double lx =
00926       0;
00927 
00928     double ly =
00929       -x1 * x2 * T(0,1,2) + x1 * y2 * T(0,0,2)
00930       -y1 * x2 * T(1,1,2) + y1 * y2 * T(1,0,2)
00931       -z1 * x2 * T(2,1,2) + z1 * y2 * T(2,0,2);
00932 
00933     double lz =
00934       x1 * x2 * T(0,1,1) - x1 * y2 * T(0,0,1)
00935       + y1 * x2 * T(1,1,1) - y1 * y2 * T(1,0,1)
00936       + z1 * x2 * T(2,1,1) - z1 * y2 * T(2,0,1);
00937 
00938     lines->push_back(HomgLine2D(lx, ly, lz));
00939   }
00940 
00941   /* 3 */
00942   {
00943     double lx =
00944       -x1 * x2 * T(0,2,1) + x1 * z2 * T(0,0,1)
00945       - y1 * x2 * T(1,2,1) + y1 * z2 * T(1,0,1)
00946       - z1 * x2 * T(2,2,1) + z1 * z2 * T(2,0,1);
00947 
00948     double ly =
00949       x1 * x2 * T(0,2,0) - x1 * z2 * T(0,0,0)
00950       + y1 * x2 * T(1,2,0) - y1 * z2 * T(1,0,0)
00951       + z1 * x2 * T(2,2,0) - z1 * z2 * T(2,0,0);
00952 
00953     double lz = 0;
00954     lines->push_back(HomgLine2D(lx, ly, lz));
00955   }
00956 
00957   /* 4 */
00958   {
00959     double lx =
00960       -x1 * x2 * T(0,2,2) + x1 * z2 * T(0,0,2)
00961       -y1 * x2 * T(1,2,2) + y1 * z2 * T(1,0,2)
00962       -z1 * x2 * T(2,2,2) + z1 * z2 * T(2,0,2);
00963 
00964     double ly = 0;
00965 
00966     double lz =
00967       x1 * x2 * T(0,2,0) - x1 * z2 * T(0,0,0) +
00968       y1 * x2 * T(1,2,0) - y1 * z2 * T(1,0,0) +
00969       z1 * x2 * T(2,2,0) - z1 * z2 * T(2,0,0);
00970     lines->push_back(HomgLine2D(lx, ly, lz));
00971   }
00972 
00973   /* 5 */
00974   {
00975     double lx = 0;
00976 
00977     double ly =
00978       -x1 * x2 * T(0,2,2) + x1 * z2 * T(0,0,2)
00979       -y1 * x2 * T(1,2,2) + y1 * z2 * T(1,0,2)
00980       -z1 * x2 * T(2,2,2) + z1 * z2 * T(2,0,2);
00981 
00982     double lz
00983         = x1 * x2 * T(0,2,1) - x1 * z2 * T(0,0,1)
00984         + y1 * x2 * T(1,2,1) - y1 * z2 * T(1,0,1)
00985         + z1 * x2 * T(2,2,1) - z1 * z2 * T(2,0,1);
00986     lines->push_back(HomgLine2D(lx, ly, lz));
00987   }
00988 
00989   /* 6 */
00990   {
00991     double lx
00992         = - x1 * y2 * T(0,2,1) + x1 * z2 * T(0,1,1)
00993         - y1 * y2 * T(1,2,1) + y1 * z2 * T(1,1,1)
00994         - z1 * y2 * T(2,2,1) + z1 * z2 * T(2,1,1);
00995 
00996     double ly
00997         = x1 * y2 * T(0,2,0) - x1 * z2 * T(0,1,0)
00998         + y1 * y2 * T(1,2,0) - y1 * z2 * T(1,1,0)
00999         + z1 * y2 * T(2,2,0) - z1 * z2 * T(2,1,0);
01000 
01001     double lz = 0;
01002     lines->push_back(HomgLine2D(lx, ly, lz));
01003   }
01004 
01005   /* 7 */
01006   {
01007     double lx
01008         = -x1 * y2 * T(0,2,2) + x1 * z2 * T(0,1,2)
01009         - y1 * y2 * T(1,2,2) + y1 * z2 * T(1,1,2)
01010         - z1 * y2 * T(2,2,2) + z1 * z2 * T(2,1,2);
01011 
01012     double ly = 0;
01013 
01014     double lz
01015         = x1 * y2 * T(0,2,0) - x1 * z2 * T(0,1,0)
01016         + y1 * y2 * T(1,2,0) - y1 * z2 * T(1,1,0)
01017         + z1 * y2 * T(2,2,0) - z1 * z2 * T(2,1,0);
01018 
01019     lines->push_back(HomgLine2D(lx, ly, lz));
01020   }
01021 
01022   /* 8 */
01023   {
01024     double lx = 0;
01025 
01026     double ly
01027         = -x1 * y2 * T(0,2,2) + x1 * z2 * T(0,1,2)
01028         - y1 * y2 * T(1,2,2) + y1 * z2 * T(1,1,2)
01029         - z1 * y2 * T(2,2,2) + z1 * z2 * T(2,1,2);
01030 
01031     double lz
01032         = x1 * y2 * T(0,2,1) - x1 * z2 * T(0,1,1)
01033         + y1 * y2 * T(1,2,1) - y1 * z2 * T(1,1,1)
01034         + z1 * y2 * T(2,2,1) - z1 * z2 * T(2,1,1);
01035 
01036     lines->push_back(HomgLine2D(lx, ly, lz));
01037   }
01038 
01039   assert(lines->size() == 9);
01040   if (tt_verbose)
01041     for (int i = 0; i < 9; ++i)
01042       vcl_cerr << (*lines)[i]<< '\n';
01043 
01044   return;
01045 
01046 #if 0
01047   *trivec3_ptr = ho_trivec_orthog(line_table_ptr);
01048   ma2_static_multiply_3x3_trivec(point_invnorm_matrix3, trivec3_ptr, trivec3_ptr);
01049 
01050   // Decondition lines
01051   if (false)
01052     for (int line_index = 0; line_index < lines->size(); line_index++)
01053       ma2_static_multiply_3x3_trivec(line_invnorm_matrix3, lines[line_index], lines[line_index]);
01054 
01055 
01056   ho_triveccam_aspect_lines_to_point(line_table_ptr, trivec3_ptr);
01057 #endif
01058 }
01059 
01060 void TriTensor::get_constraint_lines_image2(vgl_homg_point_2d<double> const& p1,
01061                                             vgl_homg_point_2d<double> const& p3,
01062                                             vcl_vector<vgl_homg_line_2d<double> >& lines) const
01063 {
01064   double x1 = p1.x();
01065   double y1 = p1.y();
01066   double z1 = p1.w();
01067 
01068   double x3 = p3.x();
01069   double y3 = p3.y();
01070   double z3 = p3.w();
01071 
01072   lines.resize(0);
01073 
01074   /* 0 */
01075   {
01076     double lx
01077         = x1 * y3 * T(0,1,0) - x1 * x3 * T(0,1,1)
01078         + y1 * y3 * T(1,1,0) - y1 * x3 * T(1,1,1)
01079         + z1 * y3 * T(2,1,0) - z1 * x3 * T(2,1,1);
01080 
01081     double ly
01082         = - x1 * y3 * T(0,0,0) + x1 * x3 * T(0,0,1)
01083         - y1 * y3 * T(1,0,0) + y1 * x3 * T(1,0,1)
01084         - z1 * y3 * T(2,0,0) + z1 * x3 * T(2,0,1);
01085 
01086     double lz = 0;
01087 
01088     lines.push_back(vgl_homg_line_2d<double>(lx, ly, lz));
01089   }
01090 
01091   /* 1 */
01092   {
01093     double lx
01094         = x1 * z3 * T(0,1,0) - x1 * x3 * T(0,1,2)
01095         + y1 * z3 * T(1,1,0) - y1 * x3 * T(1,1,2)
01096         + z1 * z3 * T(2,1,0) - z1 * x3 * T(2,1,2);
01097 
01098     double ly
01099         = - x1 * z3 * T(0,0,0) + x1 * x3 * T(0,0,2)
01100         - y1 * z3 * T(1,0,0) + y1 * x3 * T(1,0,2)
01101         - z1 * z3 * T(2,0,0) + z1 * x3 * T(2,0,2);
01102 
01103     double lz = 0;
01104 
01105     lines.push_back(vgl_homg_line_2d<double>(lx, ly, lz));
01106   }
01107 
01108   /* 2 */
01109   {
01110     double lx
01111         = x1 * z3 * T(0,1,1) - x1 * y3 * T(0,1,2)
01112         + y1 * z3 * T(1,1,1) - y1 * y3 * T(1,1,2)
01113         + z1 * z3 * T(2,1,1) - z1 * y3 * T(2,1,2);
01114 
01115     double ly
01116         = -x1 * z3 * T(0,0,1) + x1 * y3 * T(0,0,2)
01117         - y1 * z3 * T(1,0,1) + y1 * y3 * T(1,0,2)
01118         - z1 * z3 * T(2,0,1) + z1 * y3 * T(2,0,2);
01119 
01120     double lz = 0;
01121 
01122     lines.push_back(vgl_homg_line_2d<double>(lx, ly, lz));
01123   }
01124 
01125   /* 3 */
01126   {
01127     double lx
01128         = x1 * y3 * T(0,2,0) - x1 * x3 * T(0,2,1)
01129         + y1 * y3 * T(1,2,0) - y1 * x3 * T(1,2,1)
01130         + z1 * y3 * T(2,2,0) - z1 * x3 * T(2,2,1);
01131 
01132     double ly = 0;
01133 
01134     double lz
01135         = -x1 * y3 * T(0,0,0) + x1 * x3 * T(0,0,1)
01136         - y1 * y3 * T(1,0,0) + y1 * x3 * T(1,0,1)
01137         - z1 * y3 * T(2,0,0) + z1 * x3 * T(2,0,1);
01138 
01139     lines.push_back(vgl_homg_line_2d<double>(lx, ly, lz));
01140   }
01141 
01142   /* 4 */
01143   {
01144     double lx
01145         = x1 * z3 * T(0,2,0) - x1 * x3 * T(0,2,2)
01146         + y1 * z3 * T(1,2,0) - y1 * x3 * T(1,2,2)
01147         + z1 * z3 * T(2,2,0) - z1 * x3 * T(2,2,2);
01148 
01149     double ly = 0;
01150 
01151     double lz
01152         = - x1 * z3 * T(0,0,0) + x1 * x3 * T(0,0,2)
01153         - y1 * z3 * T(1,0,0) + y1 * x3 * T(1,0,2)
01154         - z1 * z3 * T(2,0,0) + z1 * x3 * T(2,0,2);
01155 
01156     lines.push_back(vgl_homg_line_2d<double>(lx, ly, lz));
01157   }
01158 
01159   /* 5 */
01160   {
01161     double lx
01162         = x1 * z3 * T(0,2,1) - x1 * y3 * T(0,2,2)
01163         + y1 * z3 * T(1,2,1) - y1 * y3 * T(1,2,2)
01164         + z1 * z3 * T(2,2,1) - z1 * y3 * T(2,2,2);
01165 
01166     double ly = 0;
01167 
01168     double lz
01169         = - x1 * z3 * T(0,0,1) + x1 * y3 * T(0,0,2)
01170         - y1 * z3 * T(1,0,1) + y1 * y3 * T(1,0,2)
01171         - z1 * z3 * T(2,0,1) + z1 * y3 * T(2,0,2);
01172 
01173     lines.push_back(vgl_homg_line_2d<double>(lx, ly, lz));
01174   }
01175 
01176   /* 6 */
01177   {
01178     double lx = 0;
01179 
01180     double ly
01181         = x1 * y3 * T(0,2,0) - x1 * x3 * T(0,2,1)
01182         + y1 * y3 * T(1,2,0) - y1 * x3 * T(1,2,1)
01183         + z1 * y3 * T(2,2,0) - z1 * x3 * T(2,2,1);
01184 
01185     double lz
01186         = -x1 * y3 * T(0,1,0) + x1 * x3 * T(0,1,1)
01187         - y1 * y3 * T(1,1,0) + y1 * x3 * T(1,1,1)
01188         - z1 * y3 * T(2,1,0) + z1 * x3 * T(2,1,1);
01189 
01190     lines.push_back(vgl_homg_line_2d<double>(lx, ly, lz));
01191   }
01192 
01193   /* 7 */
01194   {
01195     double lx = 0;
01196 
01197     double ly
01198         = x1 * z3 * T(0,2,0) - x1 * x3 * T(0,2,2)
01199         + y1 * z3 * T(1,2,0) - y1 * x3 * T(1,2,2)
01200         + z1 * z3 * T(2,2,0) - z1 * x3 * T(2,2,2);
01201 
01202     double lz
01203         = - x1 * z3 * T(0,1,0) + x1 * x3 * T(0,1,2)
01204         - y1 * z3 * T(1,1,0) + y1 * x3 * T(1,1,2)
01205         - z1 * z3 * T(2,1,0) + z1 * x3 * T(2,1,2);
01206 
01207     lines.push_back(vgl_homg_line_2d<double>(lx, ly, lz));
01208   }
01209 
01210   /* 8 */
01211   {
01212     double lx = 0;
01213 
01214     double ly
01215         = x1 * z3 * T(0,2,1) - x1 * y3 * T(0,2,2)
01216         + y1 * z3 * T(1,2,1) - y1 * y3 * T(1,2,2)
01217         + z1 * z3 * T(2,2,1) - z1 * y3 * T(2,2,2);
01218 
01219     double lz
01220         = - x1 * z3 * T(0,1,1) + x1 * y3 * T(0,1,2)
01221         - y1 * z3 * T(1,1,1) + y1 * y3 * T(1,1,2)
01222         - z1 * z3 * T(2,1,1) + z1 * y3 * T(2,1,2);
01223 
01224     lines.push_back(vgl_homg_line_2d<double>(lx, ly, lz));
01225   }
01226 }
01227 
01228 void TriTensor::get_constraint_lines_image2(HomgPoint2D const& p1,
01229                                             HomgPoint2D const& p3,
01230                                             vcl_vector<HomgLine2D>* lines) const
01231 {
01232   double x1 = p1.x();
01233   double y1 = p1.y();
01234   double z1 = p1.w();
01235 
01236   double x3 = p3.x();
01237   double y3 = p3.y();
01238   double z3 = p3.w();
01239 
01240   lines->resize(0);
01241 
01242   /* 0 */
01243   {
01244     double lx
01245         = x1 * y3 * T(0,1,0) - x1 * x3 * T(0,1,1)
01246         + y1 * y3 * T(1,1,0) - y1 * x3 * T(1,1,1)
01247         + z1 * y3 * T(2,1,0) - z1 * x3 * T(2,1,1);
01248 
01249     double ly
01250         = - x1 * y3 * T(0,0,0) + x1 * x3 * T(0,0,1)
01251         - y1 * y3 * T(1,0,0) + y1 * x3 * T(1,0,1)
01252         - z1 * y3 * T(2,0,0) + z1 * x3 * T(2,0,1);
01253 
01254     double lz = 0;
01255 
01256     lines->push_back(HomgLine2D(lx, ly, lz));
01257   }
01258 
01259   /* 1 */
01260   {
01261     double lx
01262         = x1 * z3 * T(0,1,0) - x1 * x3 * T(0,1,2)
01263         + y1 * z3 * T(1,1,0) - y1 * x3 * T(1,1,2)
01264         + z1 * z3 * T(2,1,0) - z1 * x3 * T(2,1,2);
01265 
01266     double ly
01267         = - x1 * z3 * T(0,0,0) + x1 * x3 * T(0,0,2)
01268         - y1 * z3 * T(1,0,0) + y1 * x3 * T(1,0,2)
01269         - z1 * z3 * T(2,0,0) + z1 * x3 * T(2,0,2);
01270 
01271     double lz = 0;
01272 
01273     lines->push_back(HomgLine2D(lx, ly, lz));
01274   }
01275 
01276   /* 2 */
01277   {
01278     double lx
01279         = x1 * z3 * T(0,1,1) - x1 * y3 * T(0,1,2)
01280         + y1 * z3 * T(1,1,1) - y1 * y3 * T(1,1,2)
01281         + z1 * z3 * T(2,1,1) - z1 * y3 * T(2,1,2);
01282 
01283     double ly
01284         = -x1 * z3 * T(0,0,1) + x1 * y3 * T(0,0,2)
01285         - y1 * z3 * T(1,0,1) + y1 * y3 * T(1,0,2)
01286         - z1 * z3 * T(2,0,1) + z1 * y3 * T(2,0,2);
01287 
01288     double lz = 0;
01289 
01290     lines->push_back(HomgLine2D(lx, ly, lz));
01291   }
01292 
01293   /* 3 */
01294   {
01295     double lx
01296         = x1 * y3 * T(0,2,0) - x1 * x3 * T(0,2,1)
01297         + y1 * y3 * T(1,2,0) - y1 * x3 * T(1,2,1)
01298         + z1 * y3 * T(2,2,0) - z1 * x3 * T(2,2,1);
01299 
01300     double ly = 0;
01301 
01302     double lz
01303         = -x1 * y3 * T(0,0,0) + x1 * x3 * T(0,0,1)
01304         - y1 * y3 * T(1,0,0) + y1 * x3 * T(1,0,1)
01305         - z1 * y3 * T(2,0,0) + z1 * x3 * T(2,0,1);
01306 
01307     lines->push_back(HomgLine2D(lx, ly, lz));
01308   }
01309 
01310   /* 4 */
01311   {
01312     double lx
01313         = x1 * z3 * T(0,2,0) - x1 * x3 * T(0,2,2)
01314         + y1 * z3 * T(1,2,0) - y1 * x3 * T(1,2,2)
01315         + z1 * z3 * T(2,2,0) - z1 * x3 * T(2,2,2);
01316 
01317     double ly = 0;
01318 
01319     double lz
01320         = - x1 * z3 * T(0,0,0) + x1 * x3 * T(0,0,2)
01321         - y1 * z3 * T(1,0,0) + y1 * x3 * T(1,0,2)
01322         - z1 * z3 * T(2,0,0) + z1 * x3 * T(2,0,2);
01323 
01324     lines->push_back(HomgLine2D(lx, ly, lz));
01325   }
01326 
01327   /* 5 */
01328   {
01329     double lx
01330         = x1 * z3 * T(0,2,1) - x1 * y3 * T(0,2,2)
01331         + y1 * z3 * T(1,2,1) - y1 * y3 * T(1,2,2)
01332         + z1 * z3 * T(2,2,1) - z1 * y3 * T(2,2,2);
01333 
01334     double ly = 0;
01335 
01336     double lz
01337         = - x1 * z3 * T(0,0,1) + x1 * y3 * T(0,0,2)
01338         - y1 * z3 * T(1,0,1) + y1 * y3 * T(1,0,2)
01339         - z1 * z3 * T(2,0,1) + z1 * y3 * T(2,0,2);
01340 
01341     lines->push_back(HomgLine2D(lx, ly, lz));
01342   }
01343 
01344   /* 6 */
01345   {
01346     double lx = 0;
01347 
01348     double ly
01349         = x1 * y3 * T(0,2,0) - x1 * x3 * T(0,2,1)
01350         + y1 * y3 * T(1,2,0) - y1 * x3 * T(1,2,1)
01351         + z1 * y3 * T(2,2,0) - z1 * x3 * T(2,2,1);
01352 
01353     double lz
01354         = -x1 * y3 * T(0,1,0) + x1 * x3 * T(0,1,1)
01355         - y1 * y3 * T(1,1,0) + y1 * x3 * T(1,1,1)
01356         - z1 * y3 * T(2,1,0) + z1 * x3 * T(2,1,1);
01357 
01358     lines->push_back(HomgLine2D(lx, ly, lz));
01359   }
01360 
01361   /* 7 */
01362   {
01363     double lx = 0;
01364 
01365     double ly
01366         = x1 * z3 * T(0,2,0) - x1 * x3 * T(0,2,2)
01367         + y1 * z3 * T(1,2,0) - y1 * x3 * T(1,2,2)
01368         + z1 * z3 * T(2,2,0) - z1 * x3 * T(2,2,2);
01369 
01370     double lz
01371         = - x1 * z3 * T(0,1,0) + x1 * x3 * T(0,1,2)
01372         - y1 * z3 * T(1,1,0) + y1 * x3 * T(1,1,2)
01373         - z1 * z3 * T(2,1,0) + z1 * x3 * T(2,1,2);
01374 
01375     lines->push_back(HomgLine2D(lx, ly, lz));
01376   }
01377 
01378   /* 8 */
01379   {
01380     double lx = 0;
01381 
01382     double ly
01383         = x1 * z3 * T(0,2,1) - x1 * y3 * T(0,2,2)
01384         + y1 * z3 * T(1,2,1) - y1 * y3 * T(1,2,2)
01385         + z1 * z3 * T(2,2,1) - z1 * y3 * T(2,2,2);
01386 
01387     double lz
01388         = - x1 * z3 * T(0,1,1) + x1 * y3 * T(0,1,2)
01389         - y1 * z3 * T(1,1,1) + y1 * y3 * T(1,1,2)
01390         - z1 * z3 * T(2,1,1) + z1 * y3 * T(2,1,2);
01391 
01392     lines->push_back(HomgLine2D(lx, ly, lz));
01393   }
01394 
01395   // awf removed deconditioning
01396 }
01397 
01398 void TriTensor::get_constraint_lines_image1(vgl_homg_point_2d<double> const& p2,
01399                                             vgl_homg_point_2d<double> const& p3,
01400                                             vcl_vector<vgl_homg_line_2d<double> >& lines) const
01401 {
01402   // use the same notation as the output of tr_hartley_equation.
01403 
01404   double x2 = p2.x();
01405   double y2 = p2.y();
01406   double z2 = p2.w();
01407 
01408   double x3 = p3.x();
01409   double y3 = p3.y();
01410   double z3 = p3.w();
01411 
01412   lines.resize(0);
01413 
01414   /* 0 */
01415 
01416   {
01417     double lx
01418       = x2 * y3 * T(0,1,0)
01419       - y2 * y3 * T(0,0,0)
01420       - x2 * x3 * T(0,1,1)
01421       + y2 * x3 * T(0,0,1);
01422 
01423     double ly
01424       = x2 * y3 * T(1,1,0)
01425       - y2 * y3 * T(1,0,0)
01426       - x2 * x3 * T(1,1,1)
01427       + y2 * x3 * T(1,0,1);
01428 
01429     double lz
01430       = x2 * y3 * T(2,1,0)
01431       - y2 * y3 * T(2,0,0)
01432       - x2 * x3 * T(2,1,1)
01433       + y2 * x3 * T(2,0,1);
01434 
01435     lines.push_back(vgl_homg_line_2d<double>(lx, ly, lz));
01436   }
01437 
01438   /* 1 */
01439   {
01440     double lx
01441       = x2 * z3 * T(0,1,0)
01442       - y2 * z3 * T(0,0,0)
01443       - x2 * x3 * T(0,1,2)
01444       + y2 * x3 * T(0,0,2);
01445 
01446     double ly
01447       = x2 * z3 * T(1,1,0)
01448       - y2 * z3 * T(1,0,0)
01449       - x2 * x3 * T(1,1,2)
01450       + y2 * x3 * T(1,0,2);
01451 
01452     double lz
01453       = x2 * z3 * T(2,1,0)
01454       - y2 * z3 * T(2,0,0)
01455       - x2 * x3 * T(2,1,2)
01456       + y2 * x3 * T(2,0,2);
01457 
01458     lines.push_back(vgl_homg_line_2d<double>(lx, ly, lz));
01459   }
01460 
01461   /* 2 */
01462   {
01463     double lx
01464       = x2 * z3 * T(0,1,1)
01465       - y2 * z3 * T(0,0,1)
01466       - x2 * y3 * T(0,1,2)
01467       + y2 * y3 * T(0,0,2);
01468 
01469     double ly
01470       = x2 * z3 * T(1,1,1)
01471       - y2 * z3 * T(1,0,1)
01472       - x2 * y3 * T(1,1,2)
01473       + y2 * y3 * T(1,0,2);
01474 
01475     double lz
01476       = x2 * z3 * T(2,1,1)
01477       - y2 * z3 * T(2,0,1)
01478       - x2 * y3 * T(2,1,2)
01479       + y2 * y3 * T(2,0,2);
01480 
01481     lines.push_back(vgl_homg_line_2d<double>(lx, ly, lz));
01482   }
01483 
01484   /* 3 */
01485   {
01486     double lx
01487       = x2 * y3 * T(0,2,0)
01488       - z2 * y3 * T(0,0,0)
01489       - x2 * x3 * T(0,2,1)
01490       + z2 * x3 * T(0,0,1);
01491 
01492     double ly
01493       = x2 * y3 * T(1,2,0)
01494       - z2 * y3 * T(1,0,0)
01495       - x2 * x3 * T(1,2,1)
01496       + z2 * x3 * T(1,0,1);
01497 
01498     double lz
01499       = x2 * y3 * T(2,2,0)
01500       - z2 * y3 * T(2,0,0)
01501       - x2 * x3 * T(2,2,1)
01502       + z2 * x3 * T(2,0,1);
01503 
01504     lines.push_back(vgl_homg_line_2d<double>(lx, ly, lz));
01505   }
01506 
01507   /* 4 */
01508   {
01509     double lx
01510       = x2 * z3 * T(0,2,0)
01511       - z2 * z3 * T(0,0,0)
01512       - x2 * x3 * T(0,2,2)
01513       + z2 * x3 * T(0,0,2);
01514 
01515     double ly
01516       = x2 * z3 * T(1,2,0)
01517       - z2 * z3 * T(1,0,0)
01518       - x2 * x3 * T(1,2,2)
01519       + z2 * x3 * T(1,0,2);
01520 
01521     double lz
01522       = x2 * z3 * T(2,2,0)
01523       - z2 * z3 * T(2,0,0)
01524       - x2 * x3 * T(2,2,2)
01525       + z2 * x3 * T(2,0,2);
01526 
01527     lines.push_back(vgl_homg_line_2d<double>(lx, ly, lz));
01528   }
01529 
01530   /* 5 */
01531   {
01532     double lx
01533       = x2 * z3 * T(0,2,1)
01534       - z2 * z3 * T(0,0,1)
01535       - x2 * y3 * T(0,2,2)
01536       + z2 * y3 * T(0,0,2);
01537 
01538     double ly
01539       = x2 * z3 * T(1,2,1)
01540       - z2 * z3 * T(1,0,1)
01541       - x2 * y3 * T(1,2,2)
01542       + z2 * y3 * T(1,0,2);
01543 
01544     double lz
01545       = x2 * z3 * T(2,2,1)
01546       - z2 * z3 * T(2,0,1)
01547       - x2 * y3 * T(2,2,2)
01548       + z2 * y3 * T(2,0,2);
01549 
01550     lines.push_back(vgl_homg_line_2d<double>(lx, ly, lz));
01551   }
01552 
01553   /* 6 */
01554   {
01555     double lx
01556       = y2 * y3 * T(0,2,0)
01557       - z2 * y3 * T(0,1,0)
01558       - y2 * x3 * T(0,2,1)
01559       + z2 * x3 * T(0,1,1);
01560 
01561     double ly
01562       = y2 * y3 * T(1,2,0)
01563       - z2 * y3 * T(1,1,0)
01564       - y2 * x3 * T(1,2,1)
01565       + z2 * x3 * T(1,1,1);
01566 
01567     double lz
01568       = y2 * y3 * T(2,2,0)
01569       - z2 * y3 * T(2,1,0)
01570       - y2 * x3 * T(2,2,1)
01571       + z2 * x3 * T(2,1,1);
01572 
01573     lines.push_back(vgl_homg_line_2d<double>(lx, ly, lz));
01574   }
01575 
01576   /* 7 */
01577   {
01578     double lx
01579       = y2 * z3 * T(0,2,0)
01580       - z2 * z3 * T(0,1,0)
01581       - y2 * x3 * T(0,2,2)
01582       + z2 * x3 * T(0,1,2);
01583 
01584     double ly
01585       = y2 * z3 * T(1,2,0)
01586       - z2 * z3 * T(1,1,0)
01587       - y2 * x3 * T(1,2,2)
01588       + z2 * x3 * T(1,1,2);
01589 
01590     double lz
01591       = y2 * z3 * T(2,2,0)
01592       - z2 * z3 * T(2,1,0)
01593       - y2 * x3 * T(2,2,2)
01594       + z2 * x3 * T(2,1,2);
01595 
01596     lines.push_back(vgl_homg_line_2d<double>(lx, ly, lz));
01597   }
01598 
01599   /* 8 */
01600   {
01601     double lx
01602       = y2 * z3 * T(0,2,1)
01603       - z2 * z3 * T(0,1,1)
01604       - y2 * y3 * T(0,2,2)
01605       + z2 * y3 * T(0,1,2);
01606 
01607     double ly
01608       = y2 * z3 * T(1,2,1)
01609       - z2 * z3 * T(1,1,1)
01610       - y2 * y3 * T(1,2,2)
01611       + z2 * y3 * T(1,1,2);
01612 
01613     double lz
01614       = y2 * z3 * T(2,2,1)
01615       - z2 * z3 * T(2,1,1)
01616       - y2 * y3 * T(2,2,2)
01617       + z2 * y3 * T(2,1,2);
01618 
01619     lines.push_back(vgl_homg_line_2d<double>(lx, ly, lz));
01620   }
01621 }
01622 
01623 void TriTensor::get_constraint_lines_image1(HomgPoint2D const& p2,
01624                                             HomgPoint2D const& p3,
01625                                             vcl_vector<HomgLine2D>* lines) const
01626 {
01627   // use the same notation as the output of tr_hartley_equation.
01628 
01629   double x2 = p2.x();
01630   double y2 = p2.y();
01631   double z2 = p2.w();
01632 
01633   double x3 = p3.x();
01634   double y3 = p3.y();
01635   double z3 = p3.w();
01636 
01637   lines->resize(0);
01638 
01639   /* 0 */
01640 
01641   {
01642     double lx
01643       = x2 * y3 * T(0,1,0)
01644       - y2 * y3 * T(0,0,0)
01645       - x2 * x3 * T(0,1,1)
01646       + y2 * x3 * T(0,0,1);
01647 
01648     double ly
01649       = x2 * y3 * T(1,1,0)
01650       - y2 * y3 * T(1,0,0)
01651       - x2 * x3 * T(1,1,1)
01652       + y2 * x3 * T(1,0,1);
01653 
01654     double lz
01655       = x2 * y3 * T(2,1,0)
01656       - y2 * y3 * T(2,0,0)
01657       - x2 * x3 * T(2,1,1)
01658       + y2 * x3 * T(2,0,1);
01659 
01660     lines->push_back(HomgLine2D(lx, ly, lz));
01661   }
01662 
01663   /* 1 */
01664   {
01665     double lx
01666       = x2 * z3 * T(0,1,0)
01667       - y2 * z3 * T(0,0,0)
01668       - x2 * x3 * T(0,1,2)
01669       + y2 * x3 * T(0,0,2);
01670 
01671     double ly
01672       = x2 * z3 * T(1,1,0)
01673       - y2 * z3 * T(1,0,0)
01674       - x2 * x3 * T(1,1,2)
01675       + y2 * x3 * T(1,0,2);
01676 
01677     double lz
01678       = x2 * z3 * T(2,1,0)
01679       - y2 * z3 * T(2,0,0)
01680       - x2 * x3 * T(2,1,2)
01681       + y2 * x3 * T(2,0,2);
01682 
01683     lines->push_back(HomgLine2D(lx, ly, lz));
01684   }
01685 
01686   /* 2 */
01687   {
01688     double lx
01689       = x2 * z3 * T(0,1,1)
01690       - y2 * z3 * T(0,0,1)
01691       - x2 * y3 * T(0,1,2)
01692       + y2 * y3 * T(0,0,2);
01693 
01694     double ly
01695       = x2 * z3 * T(1,1,1)
01696       - y2 * z3 * T(1,0,1)
01697       - x2 * y3 * T(1,1,2)
01698       + y2 * y3 * T(1,0,2);
01699 
01700     double lz
01701       = x2 * z3 * T(2,1,1)
01702       - y2 * z3 * T(2,0,1)
01703       - x2 * y3 * T(2,1,2)
01704       + y2 * y3 * T(2,0,2);
01705 
01706     lines->push_back(HomgLine2D(lx, ly, lz));
01707   }
01708 
01709   /* 3 */
01710   {
01711     double lx
01712       = x2 * y3 * T(0,2,0)
01713       - z2 * y3 * T(0,0,0)
01714       - x2 * x3 * T(0,2,1)
01715       + z2 * x3 * T(0,0,1);
01716 
01717     double ly
01718       = x2 * y3 * T(1,2,0)
01719       - z2 * y3 * T(1,0,0)
01720       - x2 * x3 * T(1,2,1)
01721       + z2 * x3 * T(1,0,1);
01722 
01723     double lz
01724       = x2 * y3 * T(2,2,0)
01725       - z2 * y3 * T(2,0,0)
01726       - x2 * x3 * T(2,2,1)
01727       + z2 * x3 * T(2,0,1);
01728 
01729     lines->push_back(HomgLine2D(lx, ly, lz));
01730   }
01731 
01732   /* 4 */
01733   {
01734     double lx
01735       = x2 * z3 * T(0,2,0)
01736       - z2 * z3 * T(0,0,0)
01737       - x2 * x3 * T(0,2,2)
01738       + z2 * x3 * T(0,0,2);
01739 
01740     double ly
01741       = x2 * z3 * T(1,2,0)
01742       - z2 * z3 * T(1,0,0)
01743       - x2 * x3 * T(1,2,2)
01744       + z2 * x3 * T(1,0,2);
01745 
01746     double lz
01747       = x2 * z3 * T(2,2,0)
01748       - z2 * z3 * T(2,0,0)
01749       - x2 * x3 * T(2,2,2)
01750       + z2 * x3 * T(2,0,2);
01751 
01752     lines->push_back(HomgLine2D(lx, ly, lz));
01753   }
01754 
01755   /* 5 */
01756   {
01757     double lx
01758       = x2 * z3 * T(0,2,1)
01759       - z2 * z3 * T(0,0,1)
01760       - x2 * y3 * T(0,2,2)
01761       + z2 * y3 * T(0,0,2);
01762 
01763     double ly
01764       = x2 * z3 * T(1,2,1)
01765       - z2 * z3 * T(1,0,1)
01766       - x2 * y3 * T(1,2,2)
01767       + z2 * y3 * T(1,0,2);
01768 
01769     double lz
01770       = x2 * z3 * T(2,2,1)
01771       - z2 * z3 * T(2,0,1)
01772       - x2 * y3 * T(2,2,2)
01773       + z2 * y3 * T(2,0,2);
01774 
01775     lines->push_back(HomgLine2D(lx, ly, lz));
01776   }
01777 
01778   /* 6 */
01779   {
01780     double lx
01781       = y2 * y3 * T(0,2,0)
01782       - z2 * y3 * T(0,1,0)
01783       - y2 * x3 * T(0,2,1)
01784       + z2 * x3 * T(0,1,1);
01785 
01786     double ly
01787       = y2 * y3 * T(1,2,0)
01788       - z2 * y3 * T(1,1,0)
01789       - y2 * x3 * T(1,2,1)
01790       + z2 * x3 * T(1,1,1);
01791 
01792     double lz
01793       = y2 * y3 * T(2,2,0)
01794       - z2 * y3 * T(2,1,0)
01795       - y2 * x3 * T(2,2,1)
01796       + z2 * x3 * T(2,1,1);
01797 
01798     lines->push_back(HomgLine2D(lx, ly, lz));
01799   }
01800 
01801   /* 7 */
01802   {
01803     double lx
01804       = y2 * z3 * T(0,2,0)
01805       - z2 * z3 * T(0,1,0)
01806       - y2 * x3 * T(0,2,2)
01807       + z2 * x3 * T(0,1,2);
01808 
01809     double ly
01810       = y2 * z3 * T(1,2,0)
01811       - z2 * z3 * T(1,1,0)
01812       - y2 * x3 * T(1,2,2)
01813       + z2 * x3 * T(1,1,2);
01814 
01815     double lz
01816       = y2 * z3 * T(2,2,0)
01817       - z2 * z3 * T(2,1,0)
01818       - y2 * x3 * T(2,2,2)
01819       + z2 * x3 * T(2,1,2);
01820 
01821     lines->push_back(HomgLine2D(lx, ly, lz));
01822   }
01823 
01824   /* 8 */
01825   {
01826     double lx
01827       = y2 * z3 * T(0,2,1)
01828       - z2 * z3 * T(0,1,1)
01829       - y2 * y3 * T(0,2,2)
01830       + z2 * y3 * T(0,1,2);
01831 
01832     double ly
01833       = y2 * z3 * T(1,2,1)
01834       - z2 * z3 * T(1,1,1)
01835       - y2 * y3 * T(1,2,2)
01836       + z2 * y3 * T(1,1,2);
01837 
01838     double lz
01839       = y2 * z3 * T(2,2,1)
01840       - z2 * z3 * T(2,1,1)
01841       - y2 * y3 * T(2,2,2)
01842       + z2 * y3 * T(2,1,2);
01843 
01844     lines->push_back(HomgLine2D(lx, ly, lz));
01845   }
01846 
01847   // awf removed deconditioning
01848 }
01849 
01850 
01851 // == INPUT/OUTPUT ==
01852 
01853 //-----------------------------------------------------------------------------
01854 //: Read from ASCII vcl_istream
01855 vcl_istream& operator>>(vcl_istream& s, TriTensor& T)
01856 {
01857   for (int i = 0; i < 3; ++i)
01858     for (int j = 0; j < 3; ++j)
01859       for (int k = 0; k < 3; ++k)
01860         s >> T(i,j,k);
01861   return s;
01862 }
01863 
01864 //-----------------------------------------------------------------------------
01865 //: Print in ASCII to vcl_ostream
01866 vcl_ostream& operator<<(vcl_ostream& s, const TriTensor& T)
01867 {
01868   for (int i = 0; i < 3; ++i) {
01869     for (int j = 0; j < 3; ++j) {
01870       for (int k = 0; k < 3; ++k)
01871         vul_printf(s, "%20.16e ", T(i,j,k));
01872       s << vcl_endl;
01873     }
01874     s << vcl_endl;
01875   }
01876   return s;
01877 }
01878 
01879 struct Column3x3 : public vnl_double_3x3
01880 {
01881   Column3x3(const vnl_vector<double>& v1, const vnl_vector<double>& v2, const vnl_vector<double>& v3)
01882   {
01883     (*this)(0,0) = v1[0];   (*this)(0,1) = v2[0];  (*this)(0,2) = v3[0];
01884     (*this)(1,0) = v1[1];   (*this)(1,1) = v2[1];  (*this)(1,2) = v3[1];
01885     (*this)(2,0) = v1[2];   (*this)(2,1) = v2[2];  (*this)(2,2) = v3[2];
01886   }
01887 };
01888 
01889 // == FUNDAMENTAL MATRICES AND EPIPOLES ==
01890 
01891 //: Compute and cache the two epipoles from image 1.
01892 bool TriTensor::compute_epipoles() const
01893 {
01894   vnl_double_3x3 T1 = dot1(vnl_double_3(1,0,0).as_ref());
01895   vnl_double_3x3 T2 = dot1(vnl_double_3(0,1,0).as_ref());
01896   vnl_double_3x3 T3 = dot1(vnl_double_3(0,0,1).as_ref());
01897 
01898   vnl_svd<double> svd1(T1.as_ref());
01899   vnl_double_3 u1 = svd1.nullvector();
01900   vnl_double_3 v1 = svd1.left_nullvector();
01901 
01902   vnl_svd<double> svd2(T2.as_ref());
01903   vnl_double_3 u2 = svd2.nullvector();
01904   vnl_double_3 v2 = svd2.left_nullvector();
01905 
01906   vnl_svd<double> svd3(T3.as_ref());
01907   vnl_double_3 u3 = svd3.nullvector();
01908   vnl_double_3 v3 = svd3.left_nullvector();
01909 
01910   vnl_double_3x3 V;
01911   V(0,0) = v1[0];   V(0,1) = v2[0];  V(0,2) = v3[0];
01912   V(1,0) = v1[1];   V(1,1) = v2[1];  V(1,2) = v3[1];
01913   V(2,0) = v1[2];   V(2,1) = v2[2];  V(2,2) = v3[2];
01914 
01915   vnl_svd<double> svdv(V.as_ref());
01916 
01917   delete e12_;
01918   e12_ = new HomgPoint2D(svdv.left_nullvector());
01919 
01920   vnl_double_3x3 U;
01921   U(0,0) = u1[0];   U(0,1) = u2[0];  U(0,2) = u3[0];
01922   U(1,0) = u1[1];   U(1,1) = u2[1];  U(1,2) = u3[1];
01923   U(2,0) = u1[2];   U(2,1) = u2[2];  U(2,2) = u3[2];
01924 
01925   vnl_svd<double> svdu(U.as_ref());
01926 
01927   delete e13_;
01928   e13_ = new HomgPoint2D(svdu.left_nullvector());
01929 
01930   return e12_!=0 && e13_!=0;
01931 }
01932 
01933 //: Return epipoles e2 and e3, from image 1 into images 2 and 3 respectively.
01934 bool TriTensor::get_epipoles(vgl_homg_point_2d<double>& e2,
01935                              vgl_homg_point_2d<double>& e3) const
01936 {
01937   // Check if cached.
01938   if (!e12_ || !e13_)
01939     compute_epipoles();
01940 
01941   e2.set(e12_->x(),e12_->y(),e12_->w());
01942   e3.set(e13_->x(),e13_->y(),e13_->w());
01943   return true;
01944 }
01945 
01946 bool TriTensor::get_epipoles(HomgPoint2D* e2,
01947                              HomgPoint2D* e3) const
01948 {
01949   // Check if cached.
01950   if (!e12_ || !e13_)
01951     compute_epipoles();
01952 
01953   if (e2) *e2 = *e12_;
01954   if (e3) *e3 = *e13_;
01955   return true;
01956 }
01957 
01958 //: Return epipole12.
01959 HomgPoint2D TriTensor::get_epipole_12() const
01960 {
01961   get_epipoles(0,0);
01962   return *e12_;
01963 }
01964 
01965 //: Return epipole13.
01966 HomgPoint2D TriTensor::get_epipole_13() const
01967 {
01968   get_epipoles(0,0);
01969   return *e13_;
01970 }
01971 
01972 //: Return F12, the fundamental matrix between images 1 and 2
01973 FMatrix TriTensor::get_fmatrix_12() const
01974 {
01975   get_epipoles(0,0);
01976   return FMatrix(vnl_cross_product_matrix(e12_->get_vector()) * dot3(e13_->get_vector().as_ref()).transpose().as_ref());
01977 }
01978 
01979 //: Return F13, the fundamental matrix between images 1 and 3
01980 FMatrix TriTensor::get_fmatrix_13() const
01981 {
01982   get_epipoles(0,0);
01983   return FMatrix(vnl_cross_product_matrix(e13_->get_vector()) * dot2(e12_->get_vector().as_ref()).transpose().as_ref());
01984 }
01985 
01986 FMatrix TriTensor::compute_fmatrix_23() const
01987 {
01988   PMatrix P2, P3;
01989   compute_P_matrices(&P2, &P3);
01990   return FMatrix(P2, P3);
01991 }
01992 
01993 //: Return a manifold-projector for the Fundamental matrix between 1 and 2.
01994 // The projector is cached until the next time T is changed.
01995 const FManifoldProject* TriTensor::get_fmp12() const
01996 {
01997   // If not cached, compute it.
01998   if (!fmp12_) fmp12_ = new FManifoldProject(get_fmatrix_12());
01999   return fmp12_;
02000 }
02001 
02002 //: Return a manifold-projector as above, between 1 and 3.
02003 const FManifoldProject* TriTensor::get_fmp13() const
02004 {
02005   // If not cached, compute it.
02006   if (!fmp13_) fmp13_ = new FManifoldProject(get_fmatrix_13());
02007   return fmp13_;
02008 }
02009 
02010 //: Return a manifold-projector as above, between 2 and 3.
02011 const FManifoldProject* TriTensor::get_fmp23() const
02012 {
02013   // If not cached, compute it.
02014   if (!fmp23_) {
02015     // Need to get FMatrix 23
02016     PMatrix P2;
02017     PMatrix P3;
02018     compute_P_matrices(&P2, &P3);
02019     FMatrix f23(P2,P3);
02020 
02021     fmp23_ = new FManifoldProject(f23);
02022   }
02023   return fmp23_;
02024 }
02025 
02026 //: Compute one of the family of P matrix triplets consistent with this T
02027 void TriTensor::compute_P_matrices(const vnl_double_3& x, double alpha, double beta, PMatrix* P2, PMatrix* P3) const
02028 {
02029   HomgPoint2D e2 = get_epipole_12();
02030   HomgPoint2D e3 = get_epipole_13();
02031 
02032   vnl_double_3x3 Te3 = dot3t(e3.as_ref());
02033   vnl_double_3x3 TTe2 = dot2t(e2.as_ref());
02034 
02035   MATLABPRINT((vnl_matrix<double> const&/*2.7*/)Te3);
02036   MATLABPRINT((vnl_matrix<double> const&/*2.7*/)TTe2);
02037 
02038   vnl_double_3x3 M = vnl_identity_3x3() - OuterProduct3x3(e3,e3);
02039 
02040   vnl_double_3x3 B0 = -M * TTe2;
02041 
02042   vnl_double_3x3 DIFF = B0 + TTe2 - OuterProduct3x3(e3, TTe2.transpose()*e3);
02043   double diffmag = DIFF.fro_norm();
02044   if (diffmag > 1e-12) {
02045     vcl_cerr << "TriTensor::compute_P_matrices: DIFF = " << DIFF << '\n';
02046   }
02047 
02048   vnl_double_3x3& A0 = Te3;
02049 
02050   // P1 = [I O];
02051   //P2 = [A0 + e2 * x(:)' , beta*e2];
02052   //P3 = [B0 + e3 * x(:)' , alpha*e3 ];
02053 
02054   P2->set(A0 + OuterProduct3x3(e2, x), beta*e2);
02055   P3->set(B0 + OuterProduct3x3(e3, x), alpha*e3);
02056 
02057   vcl_cerr << *P2 << '\n'
02058            << *P3 << '\n';
02059 
02060   // Check
02061   this->check_equal_up_to_scale(TriTensor(*P2, *P3));
02062 }
02063 
02064 struct maxabs
02065 {
02066   int i, j, k;
02067   double maxval;
02068   maxabs(const TriTensor& T);
02069 };
02070 
02071 maxabs::maxabs(const TriTensor& T) : i(0), j(0), k(0), maxval(0.0)
02072 {
02073   for (int i = 0; i < 3; ++i)
02074     for (int j = 0; j < 3; ++j)
02075       for (int k = 0; k < 3; ++k) {
02076         double v = vcl_fabs(T(i,j,k));
02077         if (v >= maxval) {
02078           maxval = v;
02079           this->i = i;
02080           this->j = j;
02081           this->k = k;
02082         }
02083       }
02084 }
02085 
02086 static bool check_same(const TriTensor& T1, const TriTensor& T2)
02087 {
02088   maxabs m1(T1);
02089   double scale1 = 1/m1.maxval;
02090   double scale2 = 1/vcl_fabs(T2(m1.i,m1.j,m1.k));
02091 
02092   double rms = 0;
02093   for (int i = 0; i < 3; ++i)
02094     for (int j = 0; j < 3; ++j)
02095       for (int k = 0; k < 3; ++k) {
02096         double d = T1(i,j,k)*scale1 - T2(i,j,k) * scale2;
02097         rms += d*d;
02098       }
02099 
02100   rms /= 27;
02101 
02102   if (rms > 1e-15) {
02103     vcl_cerr << "check_same: different TriTensors\n"
02104              << "T1 =\n" << T1
02105              << "T2 =\n" << T2;
02106     return false;
02107   }
02108 
02109   return true;
02110 }
02111 
02112 //: Check that another trifocal tensor is equal to this one up to scale.
02113 // Finds largest component of this, scales both tritensors so that this
02114 // component is one, and checks that fronorm of difference is small.
02115 // Prints a message if not.
02116 bool TriTensor::check_equal_up_to_scale(const TriTensor& that) const
02117 {
02118   return check_same(*this, that);
02119 }