contrib/oxl/mvl/HomgOperator3D.cxx
Go to the documentation of this file.
00001 #include "HomgOperator3D.h"
00002 //:
00003 //  \file
00004 
00005 #include <vcl_cmath.h>
00006 #include <vcl_iostream.h>
00007 #include <vcl_vector.h>
00008 #include <vcl_utility.h>
00009 #include <vcl_algorithm.h>
00010 
00011 #include <vnl/algo/vnl_svd.h>
00012 #include <vnl/vnl_matrix_fixed.h>
00013 
00014 #include <mvl/HomgLine3D.h>
00015 #include <mvl/HomgPoint3D.h>
00016 #include <mvl/HomgPlane3D.h>
00017 
00018 // -----------------------------------------------------------------------------
00019 
00020 //: Given collinear 3D points in random order, sort them.
00021 void
00022 HomgOperator3D::sort_points(HomgPoint3D* points, int n)
00023 {
00024   if (n <= 0) return; // early return if possible
00025 
00026   // ho_quadvecstd_sort_quadvecs
00027 
00028   int num_finite = 0;
00029   HomgPoint3D finite_quadvec;
00030   for (int p_index = 0; p_index < n; p_index++) {
00031     HomgPoint3D* p = &points[p_index];
00032     if (p->w() != 0) {
00033       ++num_finite;
00034       finite_quadvec = *p;
00035     }
00036   }
00037   if (num_finite < n) {
00038     vcl_cerr << "WARNING HomgOperator3D::sort_points -- "
00039              << (n - num_finite) << " points at infinity\n";
00040   }
00041 
00042   if (num_finite == 0) {
00043     vcl_cerr << "HomgOperator3D::sort_points: all points at infinity - no action\n";
00044     return;
00045   }
00046 
00047   double distance_max = 0;
00048   HomgLine3D line;
00049   for (int p_index = 0; p_index < n; p_index++) {
00050     HomgPoint3D* p = &points[p_index];
00051     if (p->w() != 0) {
00052       double distance = HomgOperator3D::distance_squared(finite_quadvec, *p);
00053       if (distance > distance_max) {
00054         distance_max = distance;
00055         // ho_quadvecstd_points2_to_line
00056         line = HomgLine3D(finite_quadvec, *p);
00057       }
00058     }
00059   }
00060 
00061   /* now create a point which is bound to be beyond the endpoints of the set. */
00062   vnl_double_3 finite_trivec = finite_quadvec.get_double3();
00063 
00064 //vnl_double_3 start = line.get_point_finite().get_double3();
00065   vnl_double_3 dir = line.dir();
00066 
00067   vnl_double_3 faraway_trivec = finite_trivec + 2.0 * distance_max * dir;
00068   HomgPoint3D faraway(faraway_trivec[0], faraway_trivec[1], faraway_trivec[2], 1.0);
00069 
00070   typedef vcl_pair<float, int> pair_float_int;
00071   vcl_vector< pair_float_int > sort_table(n);
00072   vcl_vector< HomgPoint3D > tempoints(points, points + n);
00073 
00074   for (int p_index = 0; p_index < n; p_index++) {
00075     HomgPoint3D* p = &points[p_index];
00076     if (p->w() != 0) {
00077       sort_table[p_index].first = (float)HomgOperator3D::distance_squared(faraway, *p);
00078       sort_table[p_index].second = p_index;
00079     }
00080   }
00081 
00082   vcl_sort(sort_table.begin(), sort_table.end());
00083 
00084   for (int sort_index = 0; sort_index < n; sort_index++) {
00085     pair_float_int* sort = &sort_table[sort_index];
00086     tempoints[sort_index] = points[sort->second];
00087   }
00088 
00089   for (int i = 0; i < n; ++i)
00090     points[i] = tempoints[i];
00091 }
00092 
00093 //-----------------------------------------------------------------------------
00094 //
00095 //: Return the angle between the (oriented) lines (in radians)
00096 //
00097 double
00098 HomgOperator3D::angle_between_oriented_lines (const HomgLine3D& l1, const HomgLine3D& l2)
00099 {
00100   HomgPoint3D const& dir1 = l1.get_point_infinite();
00101   HomgPoint3D const& dir2 = l2.get_point_infinite();
00102   double n = dir1.x()*dir1.x()+dir1.y()*dir1.y()+dir1.z()*dir1.z();
00103   n       *= dir2.x()*dir2.x()+dir2.y()*dir2.y()+dir2.z()*dir2.z();
00104   // dot product of unit direction vectors:
00105   n = (dir1.x()*dir2.x()+dir1.y()*dir2.y()+dir1.z()*dir2.z())/vcl_sqrt(n);
00106   return vcl_acos(n);
00107 }
00108 
00109 
00110 //-----------------------------------------------------------------------------
00111 //
00112 //: Return the squared distance between the points
00113 //
00114 double
00115 HomgOperator3D::distance_squared (const HomgPoint3D& point1, const HomgPoint3D& point2)
00116 {
00117   return (point1.get_double3() - point2.get_double3()).magnitude();
00118 }
00119 
00120 //-----------------------------------------------------------------------------
00121 //
00122 //: Return the intersection point of the line and plane
00123 //
00124 HomgPoint3D
00125 HomgOperator3D::intersect_line_and_plane (const HomgLine3D &line, const HomgPlane3D& plane)
00126 {
00127   //
00128   /* use P.(S + lambda D) = 0 to find lambda, and hence a point on the plane. */
00129 
00130   const vnl_double_4& x1 = line.get_point_finite().get_vector();
00131   const vnl_double_4& x2 = line.get_point_infinite().get_vector();
00132   const vnl_double_4& p  = plane.get_vector();
00133 
00134   double numerator = -dot_product (x1, p);
00135   double denominator = dot_product (x2, p);
00136 
00137   // Scale for conditioning
00138   double scale = 1.0/(numerator + denominator);
00139   numerator *= scale;
00140   denominator *= scale;
00141 
00142   return denominator * x1 + numerator * x2;
00143 }
00144 
00145 //-----------------------------------------------------------------------------
00146 //
00147 // - Compute the intersection point of the lines, or the mid-point
00148 // of the common perpendicular if the lines are skew
00149 //
00150 HomgPoint3D
00151 HomgOperator3D::lines_to_point (const HomgLine3D& , const HomgLine3D& )
00152 {
00153   vcl_cerr << "Warning: HomgOperator3D::lines_to_point() not yet implemented\n";
00154   return HomgPoint3D();
00155 }
00156 
00157 
00158 //-----------------------------------------------------------------------------
00159 //
00160 // - Compute the best fit intersection point of the lines
00161 //
00162 HomgPoint3D
00163 HomgOperator3D::lines_to_point (const vcl_vector<HomgLine3D>& )
00164 {
00165   vcl_cerr << "Warning: HomgOperator3D::lines_to_point() not yet implemented\n";
00166   return HomgPoint3D();
00167 }
00168 
00169 //-----------------------------------------------------------------------------
00170 //
00171 // - Return the squared perpendicular distance between the line and point
00172 //
00173 double
00174 HomgOperator3D::perp_dist_squared (const HomgPoint3D& , const HomgLine3D& )
00175 {
00176   vcl_cerr << "Warning: HomgOperator3D::perp_dist_squared() not yet implemented\n";
00177   return 0;
00178 }
00179 
00180 //-----------------------------------------------------------------------------
00181 //
00182 // - Return the line which is perpendicular to *line and passes
00183 // through *point
00184 //
00185 HomgLine3D
00186 HomgOperator3D::perp_line_through_point (const HomgLine3D& , const HomgPoint3D& ) { return HomgLine3D(); }
00187 
00188 
00189 //-----------------------------------------------------------------------------
00190 //
00191 // - Compute the line which is the perpendicular projection of *point
00192 // onto *line
00193 //
00194 HomgPoint3D
00195 HomgOperator3D::perp_projection (const HomgLine3D& , const HomgPoint3D& )
00196 {
00197   vcl_cerr << "Warning: HomgOperator3D::perp_projection() not yet implemented\n";
00198   return HomgPoint3D();
00199 }
00200 
00201 
00202 //-----------------------------------------------------------------------------
00203 //
00204 //: Return the intersection line of the planes
00205 //
00206 HomgLine3D
00207 HomgOperator3D::planes_to_line (const HomgPlane3D& plane1, const HomgPlane3D& plane2)
00208 {
00209   vnl_matrix_fixed<double,2,4> M;
00210   M.set_row(0, plane1.get_vector());
00211   M.set_row(1, plane2.get_vector());
00212   vnl_svd<double> svd(M.as_ref());
00213   vnl_matrix_fixed<double,4,2> N = svd.nullspace(2);
00214   HomgPoint3D p1(N.get_column(0));
00215   HomgPoint3D p2(N.get_column(1));
00216   return HomgLine3D(p1, p2);
00217 }
00218 
00219 
00220 //-----------------------------------------------------------------------------
00221 //
00222 // - Compute the best-fit intersection line of the planes
00223 //
00224 HomgLine3D
00225 HomgOperator3D::planes_to_line (const vcl_vector<HomgPlane3D>&)
00226 {
00227   vcl_cerr << "Warning: HomgOperator3D::planes_to_line() not yet implemented\n";
00228   return HomgLine3D();
00229 }
00230 
00231 
00232 //-----------------------------------------------------------------------------
00233 //
00234 // - Return the line through the points
00235 //
00236 HomgLine3D
00237 HomgOperator3D::points_to_line (const HomgPoint3D&, const HomgPoint3D&)
00238 {
00239   vcl_cerr << "Warning: HomgOperator3D::points_to_line() not yet implemented\n";
00240   return HomgLine3D();
00241 }
00242 
00243 //-----------------------------------------------------------------------------
00244 //
00245 // - Compute the best-fit line through the points
00246 //
00247 HomgLine3D
00248 HomgOperator3D::points_to_line (const vcl_vector<HomgPoint3D>&)
00249 {
00250   vcl_cerr << "Warning: HomgOperator3D::points_to_line() not yet implemented\n";
00251   return HomgLine3D();
00252 }
00253 
00254 //-----------------------------------------------------------------------------
00255 //
00256 // - Return the plane through the points
00257 //
00258 HomgPlane3D
00259 HomgOperator3D::points_to_plane (const HomgPoint3D&, const HomgPoint3D&, const HomgPoint3D&)
00260 {
00261   vcl_cerr << "Warning: HomgOperator3D::points_to_plane() not yet implemented\n";
00262   return HomgPlane3D();
00263 }
00264 
00265 
00266 //-----------------------------------------------------------------------------
00267 //
00268 // - Compute the best-fit plane through the points
00269 //
00270 HomgPlane3D
00271 HomgOperator3D::points_to_plane (const vcl_vector<HomgPoint3D>&)
00272 {
00273   vcl_cerr << "Warning: HomgOperator3D::points_to_plane() not yet implemented\n";
00274   return HomgPlane3D();
00275 }
00276 
00277 //: Compute best-fit intersection of planes in a point.
00278 
00279 HomgPoint3D
00280 HomgOperator3D::intersection_point (const HomgPlane3D& plane1, const HomgPlane3D& plane2, const HomgPlane3D& plane3)
00281 {
00282   vnl_matrix<double> A(3, 4);
00283   A(0,0) = plane1.x();
00284   A(0,1) = plane1.y();
00285   A(0,2) = plane1.z();
00286   A(0,3) = plane1.w();
00287 
00288   A(1,0) = plane2.x();
00289   A(1,1) = plane2.y();
00290   A(1,2) = plane2.z();
00291   A(1,3) = plane2.w();
00292 
00293   A(2,0) = plane3.x();
00294   A(2,1) = plane3.y();
00295   A(2,2) = plane3.z();
00296   A(2,3) = plane3.w();
00297 
00298   vnl_svd<double> svd(A);
00299   return HomgPoint3D(svd.nullvector());
00300 }
00301 
00302 HomgPoint3D
00303 HomgOperator3D::intersection_point (const vcl_vector<HomgPlane3D>& planes)
00304 {
00305   int n = planes.size();
00306   vnl_matrix<double> A(planes.size(), 4);
00307 
00308   for (int i =0; i < n; ++i) {
00309     A(i,0) = planes[i].x();
00310     A(i,1) = planes[i].y();
00311     A(i,2) = planes[i].z();
00312     A(i,3) = planes[i].w();
00313   }
00314 
00315   vnl_svd<double> svd(A);
00316   return HomgPoint3D(svd.nullvector());
00317 }
00318 
00319 //-----------------------------------------------------------------------------
00320 //: Calculates the crossratio of four collinear points p1, p2, p3 and p4.
00321 // This number is projectively invariant, and it is the coordinate of p4
00322 // in the reference frame where p2 is the origin (coordinate 0), p3 is
00323 // the unity (coordinate 1) and p1 is the point at infinity.
00324 // This cross ratio is often denoted as ((p1, p2; p3, p4)) (which also
00325 // equals ((p3, p4; p1, p2)) or ((p2, p1; p4, p3)) or ((p4, p3; p2, p1)) )
00326 // and is calculated as
00327 //                      p1 - p3   p2 - p3      (p1-p3)(p2-p4)
00328 //                      ------- : --------  =  --------------
00329 //                      p1 - p4   p2 - p4      (p1-p4)(p2-p3)
00330 //
00331 // In principle, any single nonhomogeneous coordinate from the four points
00332 // can be used as parameters for CrossRatio (but of course the same for all
00333 // points). The most reliable answer will be obtained when the coordinate with
00334 // the largest spacing is used, i.e., the one with smallest slope.
00335 //
00336 double HomgOperator3D::CrossRatio(const Homg3D& a, const Homg3D& b, const Homg3D& c, const Homg3D& d)
00337 {
00338   double x1 = a.x(), y1 = a.y(), z1 = a.z(), w1 = a.w();
00339   double x2 = b.x(), y2 = b.y(), z2 = b.z(), w2 = b.w();
00340   double x3 = c.x(), y3 = c.y(), z3 = c.z(), w3 = c.w();
00341   double x4 = d.x(), y4 = d.y(), z4 = d.z(), w4 = d.w();
00342   double x = x1 - x2; if (x<0) x = -x; // assuming a != b ;-)
00343   double y = y1 - y2; if (y<0) y = -y;
00344   double z = z1 - z2; if (z<0) z = -z;
00345   double n = (x>y && x>z) ? (x1*w3-x3*w1)*(x2*w4-x4*w2) :
00346              (y>z)        ? (y1*w3-y3*w1)*(y2*w4-y4*w2) :
00347                             (z1*w3-z3*w1)*(z2*w4-z4*w2);
00348   double m = (x>y && x>z) ? (x1*w4-x4*w1)*(x2*w3-x3*w2) :
00349              (y>z)        ? (y1*w4-y4*w1)*(y2*w3-y3*w2) :
00350                             (z1*w4-z4*w1)*(z2*w3-z3*w2);
00351   if (n == 0 && m == 0)
00352     vcl_cerr << "CrossRatio not defined: three of the given points coincide\n";
00353   return n/m;
00354 }