contrib/oxl/mvl/mvl_psi.cxx
Go to the documentation of this file.
00001 // This is oxl/mvl/mvl_psi.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 // \author fsm
00008 
00009 #include "mvl_psi.h"
00010 
00011 #include <vcl_cmath.h>
00012 #include <vcl_cassert.h>
00013 #include <vcl_cstdlib.h>
00014 
00015 #if 0
00016 # define mvl_psi_temp_name(l, r) U l = r
00017 #else
00018 # define mvl_psi_temp_name(l, r) U const &l = r
00019 #endif
00020 
00021 // Evaluate the cubic constraint on \psi(X) = (a,b,c,d,e)
00022 // by computing the determinant of [ e e b ; d c b ; d a a ]
00023 // The image of psi is cut out by the vanishing of this determinant.
00024 template <mvl_typename U>
00025 U mvl_psi_constraint(U const abcde[5])
00026 {
00027   //     [ e e b ]
00028   // det [ d c b ]
00029   //     [ e a a ]
00030   mvl_psi_temp_name(a, abcde[0]);
00031   mvl_psi_temp_name(b, abcde[1]);
00032   mvl_psi_temp_name(c, abcde[2]);
00033   mvl_psi_temp_name(d, abcde[3]);
00034   mvl_psi_temp_name(e, abcde[4]);
00035 
00036   return a*b*d - a*b*e + a*c*e - a*d*e - b*c*d + b*d*e;
00037 }
00038 
00039 // Compute coefficient vector of the cubic form f(s*p + t*q).
00040 template <mvl_typename U>
00041 void mvl_psi_constraint_restrict(U const p[5],
00042                                  U const q[5],
00043                                  U coeffs[4])
00044 {
00045   // The coefficients of a homogeneous cubic polynomial in
00046   // two variables can be computed from the values which it
00047   // takes at the four points (1, 0), (0, 1), (1, 1), (1, -1).
00048   //
00049   // [ c0 ]   [  2     0     0     0 ] [ v0 ]
00050   // [ c1 ] = [  0    -2     1    -1 ] [ v1 ]
00051   // [ c2 ]   [ -2     0     1     1 ] [ v2 ]
00052   // [ c3 ]   [  0     2     0     0 ] [ v3 ]
00053 
00054   // evaluate.
00055   U values[4]; {
00056     values[0] = mvl_psi_constraint(p);
00057     values[1] = mvl_psi_constraint(q);
00058     U tmp[5];
00059     for (int i=0; i<5; ++i) tmp[i] = p[i] + q[i];
00060     values[2] = mvl_psi_constraint(tmp);
00061     for (int i=0; i<5; ++i) tmp[i] = p[i] - q[i];
00062     values[3] = mvl_psi_constraint(tmp);
00063   }
00064 
00065   // recover coefficients.
00066   coeffs[0] =  2 * values[0];
00067   coeffs[1] =                - 2 * values[1] + values[2] - values[3];
00068   coeffs[2] = -2 * values[0]                 + values[2] + values[3];
00069   coeffs[3] =                  2 * values[1];
00070 }
00071 
00072 template <mvl_typename U>
00073 void mvl_psi_apply(U const XYZT[4], U abcde[5])
00074 {
00075   mvl_psi_temp_name(X, XYZT[0]);
00076   mvl_psi_temp_name(Y, XYZT[1]);
00077   mvl_psi_temp_name(Z, XYZT[2]);
00078   mvl_psi_temp_name(W, XYZT[3]);
00079 
00080   abcde[0] = X*Y - X*W;
00081   abcde[1] = X*Z - X*W;
00082   abcde[2] = Y*Z - X*W;
00083   abcde[3] = Y*W - X*W;
00084   abcde[4] = Z*W - X*W;
00085 }
00086 
00087 template <mvl_typename U>
00088 void mvl_psi_invert_direct(U const abcde[5], U XYZT[4], int which)
00089 {
00090   mvl_psi_temp_name(a, abcde[0]);
00091   mvl_psi_temp_name(b, abcde[1]);
00092   mvl_psi_temp_name(c, abcde[2]);
00093   mvl_psi_temp_name(d, abcde[3]);
00094   mvl_psi_temp_name(e, abcde[4]);
00095 
00096   switch (which) {
00097   case 0:
00098     //% X=1
00099     //ux=[
00100     //  1
00101     //  (c-d)/(b  )
00102     //  (c-e)/(a  )
00103     //  (d-e)/(a-b)
00104     //  ];
00105     XYZT[0] = 1;
00106     XYZT[1] = (c-d)/(b  );
00107     XYZT[2] = (c-e)/(a  );
00108     XYZT[3] = (d-e)/(a-b);
00109     break;
00110 
00111   case 1:
00112     //% Y=1
00113     //uy=[
00114     //  (b  )/(c-d)
00115     //  1
00116     //  (b-e)/(a-d)
00117     //  ( -e)/(a-c)
00118     //  ];
00119     XYZT[0] = (b  )/(c-d);
00120     XYZT[1] = 1;
00121     XYZT[2] = (b-e)/(a-d);
00122     XYZT[3] = ( -e)/(a-c);
00123     break;
00124 
00125   case 2:
00126     //% Z=1
00127     //uz=[
00128     //  (a  )/(c-e)
00129     //  (a-d)/(b-e)
00130     //  1
00131     //  ( -d)/(b-c)
00132     //  ];
00133     XYZT[0] = (a  )/(c-e);
00134     XYZT[1] = (a-d)/(b-e);
00135     XYZT[2] = 1;
00136     XYZT[3] = ( -d)/(b-c);
00137     break;
00138 
00139   case 3:
00140     //% T=1
00141     //ut=[
00142     //  (a-b)/(d-e)
00143     //  (a-c)/( -e)
00144     //  (b-c)/( -d)
00145     //  1
00146     //  ];
00147     XYZT[0] = (a-b)/(d-e);
00148     XYZT[1] = (a-c)/( -e);
00149     XYZT[2] = (b-c)/( -d);
00150     XYZT[3] = 1;
00151     break;
00152 
00153   default:
00154     vcl_abort();
00155   };
00156 }
00157 
00158 template <mvl_typename U>
00159 void mvl_psi_invert_direct(U const abcde[5], U XYZT[4])
00160 {
00161   mvl_psi_temp_name(a, abcde[0]);
00162   mvl_psi_temp_name(b, abcde[1]);
00163   mvl_psi_temp_name(c, abcde[2]);
00164   mvl_psi_temp_name(d, abcde[3]);
00165   mvl_psi_temp_name(e, abcde[4]);
00166 
00167   // c - d          b
00168   // c - e          a
00169   // d - e          a - b
00170   // b - e          a - d
00171   // a - c          e
00172   // b - c          d
00173   bool cd_b  = vcl_abs(c - d) <= vcl_abs(b);
00174   bool ce_a  = vcl_abs(c - e) <= vcl_abs(a);
00175   bool de_ab = vcl_abs(d - e) <= vcl_abs(a - b);
00176   bool be_ad = vcl_abs(b - e) <= vcl_abs(a - d);
00177   bool ac_e  = vcl_abs(a - c) <= vcl_abs(e);
00178   bool bc_d  = vcl_abs(b - c) <= vcl_abs(d);
00179 
00180   if (false)
00181     { }
00182 
00183   else if (cd_b && ce_a && de_ab)
00184     mvl_psi_invert_direct(abcde, XYZT, 0);
00185 
00186   else if (!cd_b && be_ad && !ac_e)
00187     mvl_psi_invert_direct(abcde, XYZT, 1);
00188 
00189   else if (!ce_a && !be_ad && !bc_d)
00190     mvl_psi_invert_direct(abcde, XYZT, 2);
00191 
00192   else if (!de_ab && ac_e && bc_d)
00193     mvl_psi_invert_direct(abcde, XYZT, 3);
00194 
00195   else
00196     assert(false); // did you get here? probably a round-off problem...
00197 }
00198 
00199 #include <vnl/vnl_matrix_ref.h>
00200 #include <vnl/algo/vnl_svd_economy.h>
00201 
00202 template <mvl_typename U>
00203 void mvl_psi_invert_design(U const abcde[5], U XYZT[4])
00204 {
00205   mvl_psi_temp_name(a, abcde[0]);
00206   mvl_psi_temp_name(b, abcde[1]);
00207   mvl_psi_temp_name(c, abcde[2]);
00208   mvl_psi_temp_name(d, abcde[3]);
00209   mvl_psi_temp_name(e, abcde[4]);
00210 
00211   U design[6*4] = {
00212     e-d, 0  , 0  , a-b, // X:T
00213     e-c, 0  , a  , 0  , // X:Z
00214     d-c, b  , 0  , 0  , // X:Y
00215     0  , e  , 0  , a-c, // Y:T
00216     0  , e-b, a-d, 0  , // Y:Z
00217     0  , 0  , d  , b-c  // Z:T
00218   };
00219   // capes_at_robots - much faster than full vnl_svd.
00220   vnl_svd_economy<U> svd(vnl_matrix_ref<U>(6, 4, design));
00221   svd.nullvector().copy_out(XYZT);
00222 }
00223 
00224 template <mvl_typename U>
00225 void mvl_psi_invert(U const abcde[5], U XYZT[4])
00226 {
00227 #if 1 // capes_at_robots - mvl_psi_invert_direct fails occasionally : I think it is missing a case.
00228   mvl_psi_invert_design(abcde, XYZT);
00229 #else
00230   mvl_psi_invert_direct(abcde, XYZT);
00231 #endif
00232 }
00233 
00234 //----------------------------------------------------------------------
00235 
00236 #define instantiate(U) \
00237 template U mvl_psi_constraint(U const [5]); \
00238 template void mvl_psi_constraint_restrict(U const [5], U const [5], U [4]); \
00239 template void mvl_psi_apply(U const [4], U [5]); \
00240 template void mvl_psi_invert_direct(U const [5], U [4], int); \
00241 template void mvl_psi_invert_direct(U const [5], U [4]); \
00242 template void mvl_psi_invert_design(U const [5], U [4]); \
00243 template void mvl_psi_invert(U const [5], U [4])
00244 
00245 instantiate(double);
00246 //instantiate(vcl_complex<double>);
00247 #undef instantiate