core/vgl/vgl_closest_point.txx
Go to the documentation of this file.
00001 // This is core/vgl/vgl_closest_point.txx
00002 #ifndef vgl_closest_point_txx_
00003 #define vgl_closest_point_txx_
00004 //:
00005 // \file
00006 // \author Peter Vanroose, KULeuven, ESAT/PSI
00007 
00008 #include "vgl_closest_point.h"
00009 #include <vgl/vgl_distance.h>
00010 #include <vgl/vgl_line_2d.h>
00011 #include <vgl/vgl_homg_line_2d.h>
00012 #include <vgl/vgl_point_2d.h>
00013 #include <vgl/vgl_point_3d.h>
00014 #include <vgl/vgl_homg_point_2d.h>
00015 #include <vgl/vgl_homg_point_3d.h>
00016 #include <vgl/vgl_plane_3d.h>
00017 #include <vgl/vgl_homg_plane_3d.h>
00018 #include <vgl/vgl_homg_line_3d_2_points.h>
00019 #include <vgl/vgl_line_3d_2_points.h>
00020 #include <vgl/vgl_line_segment_3d.h>
00021 #include <vgl/vgl_polygon.h>
00022 #include <vcl_cassert.h>
00023 #include <vcl_cmath.h> // for std::abs(double)
00024 
00025 template <class T>
00026 static inline T square(T x) { return x*x; }
00027 
00028 
00029 // Consider numbers smaller than this to be zero
00030 const double SMALL_DOUBLE = 1e-12;
00031 
00032 
00033 // Borland has trouble deducing template types when parameters have
00034 // type const T instead of T. This occurs in
00035 // vgl_distance2_to_linesegment. The workaround is to make the T const
00036 // parameter a T parameter.
00037 //
00038 #ifdef VCL_BORLAND_55
00039 # define DIST_SQR_TO_LINE_SEG_2D( T, x1, y1, x2, y2, x, y ) \
00040      vgl_distance2_to_linesegment(T(x1), T(y1), T(x2), T(y2), T(x), T(y) );
00041 # define DIST_SQR_TO_LINE_SEG_3D( T, x1, y1, z1, x2, y2, z2, x, y, z ) \
00042      vgl_distance2_to_linesegment(T(x1), T(y1), T(z1), T(x2), T(y2), T(z2), T(x), T(y), T(z) );
00043 #else
00044 # define DIST_SQR_TO_LINE_SEG_2D( T, x1, y1, x2, y2, x, y ) \
00045      vgl_distance2_to_linesegment(x1, y1, x2, y2, x, y );
00046 # define DIST_SQR_TO_LINE_SEG_3D( T, x1, y1, z1, x2, y2, z2, x, y, z ) \
00047      vgl_distance2_to_linesegment(x1, y1, z1, x2, y2, z2, x, y, z );
00048 #endif
00049 
00050 
00051 template <class T>
00052 void vgl_closest_point_to_linesegment(T& ret_x, T& ret_y,
00053                                       T x1, T y1,
00054                                       T x2, T y2,
00055                                       T x0, T y0)
00056 {
00057   // squared distance between endpoints:
00058   T ddh = square(x2-x1) + square(y2-y1);
00059 
00060   // squared distance to endpoints:
00061   T dd1 = square(x0-x1) + square(y0-y1);
00062   T dd2 = square(x0-x2) + square(y0-y2);
00063 
00064   // if closest to the start point:
00065   if (dd2 > ddh + dd1) { ret_x=x1; ret_y=y1; return; }
00066 
00067   // if closest to the end point :
00068   if (dd1 > ddh + dd2) { ret_x=x2; ret_y=y2; return; }
00069 
00070   // line through (x0,y0) and perpendicular to the given line is
00071   // the line with equation (x-x0)(x2-x1)+(y-y0)(y2-y1)=0.
00072   // Then it just remains to intersect these two lines:
00073   T dx = x2-x1;
00074   T dy = y2-y1;
00075   double c = dx*dx+dy*dy;
00076   ret_x = T((dx*dx*x0+dy*dy*x1-dx*dy*(y1-y0))/c); // possible rounding error!
00077   ret_y = T((dx*dx*y1+dy*dy*y0-dx*dy*(x1-x0))/c);
00078 }
00079 
00080 template <class T>
00081 void vgl_closest_point_to_linesegment(T& ret_x, T& ret_y, T& ret_z,
00082                                       T x1, T y1, T z1,
00083                                       T x2, T y2, T z2,
00084                                       T x, T y, T z)
00085 {
00086   // squared distance between endpoints:
00087   T ddh = square(x2-x1) + square(y2-y1) + square(z2-z1);
00088 
00089   // squared distance to endpoints :
00090   T dd1 = square(x-x1) + square(y-y1) + square(z-z1);
00091   T dd2 = square(x-x2) + square(y-y2) + square(z-z2);
00092 
00093   // if closest to the start point:
00094   if (dd2 > ddh + dd1) { ret_x=x1; ret_y=y1; ret_z=z1; return; }
00095 
00096   // if closest to the end point :
00097   if (dd1 > ddh + dd2) { ret_x=x2; ret_y=y2; ret_z=z2; return; }
00098 
00099   // plane through (x,y,z) and orthogonal to the line is a(X-x)+b(Y-y)+c(Z-z)=0
00100   // where (a,b,c) is the direction of the line.
00101   T a = x2-x1, b = y2-y1, c = z2-z1;
00102   // The closest point is then the intersection of this plane with the line.
00103   // This point equals (x1,y1,z1) + lambda * (a,b,c), with this lambda:
00104   double lambda = (a*(x-x1)+b*(y-y1)+c*(z-z1))/double(a*a+b*b+c*c);
00105   ret_x = x1+T(lambda*a); ret_y = y1+T(lambda*b); ret_z = z1+T(lambda*c);
00106 }
00107 
00108 template <class T>
00109 int vgl_closest_point_to_non_closed_polygon(T& ret_x, T& ret_y,
00110                                             T const px[], T const py[], unsigned int n,
00111                                             T x, T y)
00112 {
00113   assert(n>1);
00114   double dd = DIST_SQR_TO_LINE_SEG_2D(T,px[0],py[0], px[1],py[1], x,y);
00115   int di = 0;
00116   for (unsigned i=1; i+1<n; ++i)
00117   {
00118     double nd = DIST_SQR_TO_LINE_SEG_2D(T,px[i],py[i], px[i+1],py[i+1], x,y);
00119     if (nd<dd) { dd=nd; di=i; }
00120   }
00121   vgl_closest_point_to_linesegment(ret_x,ret_y, px[di],py[di], px[di+1],py[di+1], x,y);
00122   return di;
00123 }
00124 
00125 template <class T>
00126 int vgl_closest_point_to_non_closed_polygon(T& ret_x, T& ret_y, T& ret_z,
00127                                             T const px[], T const py[], T const pz[], unsigned int n,
00128                                             T x, T y, T z)
00129 {
00130   assert(n>1);
00131   double dd = DIST_SQR_TO_LINE_SEG_3D(T,px[0],py[0],pz[0], px[1],py[1],pz[1], x,y,z);
00132   int di = 0;
00133   for (unsigned i=1; i+1<n; ++i)
00134   {
00135     double nd = DIST_SQR_TO_LINE_SEG_3D(T,px[i],py[i],pz[i], px[i+1],py[i+1],pz[i+1], x,y,z);
00136     if (nd<dd) { dd=nd; di=i; }
00137   }
00138   vgl_closest_point_to_linesegment(ret_x,ret_y,ret_z, px[di],py[di],pz[di],
00139                                    px[di+1],py[di+1],pz[di+1], x,y,z);
00140   return di;
00141 }
00142 
00143 template <class T>
00144 int vgl_closest_point_to_closed_polygon(T& ret_x, T& ret_y,
00145                                         T const px[], T const py[], unsigned int n,
00146                                         T x, T y)
00147 {
00148   assert(n>1);
00149   double dd = DIST_SQR_TO_LINE_SEG_2D(T,px[0],py[0], px[n-1],py[n-1], x,y);
00150   int di = -1;
00151   for (unsigned i=0; i+1<n; ++i)
00152   {
00153     double nd = DIST_SQR_TO_LINE_SEG_2D(T,px[i],py[i], px[i+1],py[i+1], x,y);
00154     if (nd<dd) { dd=nd; di=i; }
00155   }
00156   if (di == -1) di+=n,
00157     vgl_closest_point_to_linesegment(ret_x,ret_y, px[0],py[0], px[n-1],py[n-1], x,y);
00158   else
00159     vgl_closest_point_to_linesegment(ret_x,ret_y, px[di],py[di], px[di+1],py[di+1], x,y);
00160   return di;
00161 }
00162 
00163 template <class T>
00164 int vgl_closest_point_to_closed_polygon(T& ret_x, T& ret_y, T& ret_z,
00165                                         T const px[], T const py[], T const pz[], unsigned int n,
00166                                         T x, T y, T z)
00167 {
00168   assert(n>1);
00169   double dd = DIST_SQR_TO_LINE_SEG_3D(T,px[0],py[0],pz[0], px[n-1],py[n-1],pz[n-1], x,y,z);
00170   int di = -1;
00171   for (unsigned i=0; i+1<n; ++i)
00172   {
00173     double nd = DIST_SQR_TO_LINE_SEG_3D(T,px[i],py[i],pz[i], px[i+1],py[i+1],pz[i+1], x,y,z);
00174     if (nd<dd) { dd=nd; di=i; }
00175   }
00176   if (di == -1) di+=n,
00177     vgl_closest_point_to_linesegment(ret_x,ret_y,ret_z, px[0],py[0],pz[0],
00178                                      px[n-1],py[n-1],pz[n-1], x,y,z);
00179   else
00180     vgl_closest_point_to_linesegment(ret_x,ret_y,ret_z, px[di],py[di],pz[di],
00181                                      px[di+1],py[di+1],pz[di+1], x,y,z);
00182   return di;
00183 }
00184 
00185 template <class T>
00186 vgl_point_2d<T> vgl_closest_point_origin(vgl_line_2d<T> const& l)
00187 {
00188   T d = l.a()*l.a()+l.b()*l.b();
00189   return vgl_point_2d<T>(-l.a()*l.c()/d, -l.b()*l.c()/d);
00190 }
00191 
00192 template <class T>
00193 vgl_homg_point_2d<T> vgl_closest_point_origin(vgl_homg_line_2d<T> const& l)
00194 {
00195   return vgl_homg_point_2d<T>(l.a()*l.c(), l.b()*l.c(),
00196                               -l.a()*l.a()-l.b()*l.b());
00197 }
00198 
00199 template <class T>
00200 vgl_point_3d<T> vgl_closest_point_origin(vgl_plane_3d<T> const& pl)
00201 {
00202   T d = pl.a()*pl.a()+pl.b()*pl.b()+pl.c()*pl.c();
00203   return vgl_point_3d<T>(-pl.a()*pl.d()/d, -pl.b()*pl.d()/d, -pl.c()*pl.d()/d);
00204 }
00205 
00206 template <class T>
00207 vgl_homg_point_3d<T> vgl_closest_point_origin(vgl_homg_plane_3d<T> const& pl)
00208 {
00209   return vgl_homg_point_3d<T>(pl.a()*pl.d(), pl.b()*pl.d(), pl.c()*pl.d(),
00210                               -pl.a()*pl.a()-pl.b()*pl.b()-pl.c()*pl.c());
00211 }
00212 
00213 template <class T>
00214 vgl_homg_point_3d<T> vgl_closest_point_origin(vgl_homg_line_3d_2_points<T> const& l)
00215 {
00216   vgl_homg_point_3d<T> const& q = l.point_finite();
00217   // The plane through the origin and orthogonal to l is ax+by+cz=0
00218   // where (a,b,c,0) is the point at infinity of l.
00219   T a = l.point_infinite().x(), b = l.point_infinite().y(), c = l.point_infinite().z(),
00220     d = a*a+b*b+c*c;
00221   // The closest point is then the intersection of this plane with the line l.
00222   // This point equals d * l.point_finite - lambda * l.direction, with lambda:
00223   T lambda = a*q.x()+b*q.y()+c*q.z();
00224   return vgl_homg_point_3d<T>(d*q.x()-lambda*a*q.w(), d*q.y()-lambda*b*q.w(), d*q.z()-lambda*c*q.w(), d*q.w());
00225 }
00226 
00227 template <class T>
00228 vgl_point_3d<T> vgl_closest_point_origin(vgl_line_3d_2_points<T> const& l)
00229 {
00230   vgl_point_3d<T> const& q = l.point1();
00231   // The plane through the origin and orthogonal to l is ax+by+cz=0
00232   // where (a,b,c) is the direction of l.
00233   T a = l.point2().x()-q.x(), b = l.point2().y()-q.y(), c = l.point2().z()-q.z(),
00234     d = a*a+b*b+c*c;
00235   // The closest point is then the intersection of this plane with the line l.
00236   // This point equals l.point1 - lambda * l.direction, with lambda:
00237   T lambda = (a*q.x()+b*q.y()+c*q.z())/d; // possible rounding error!
00238   return vgl_point_3d<T>(q.x()-lambda*a, q.y()-lambda*b, q.z()-lambda*c);
00239 }
00240 
00241 template <class T>
00242 vgl_point_2d<T> vgl_closest_point(vgl_line_2d<T> const& l,
00243                                   vgl_point_2d<T> const& p)
00244 {
00245   T d = l.a()*l.a()+l.b()*l.b();
00246   assert(d!=0); // line should not be the line at infinity
00247   return vgl_point_2d<T>((l.b()*l.b()*p.x()-l.a()*l.b()*p.y()-l.a()*l.c())/d,
00248                          (l.a()*l.a()*p.y()-l.a()*l.b()*p.x()-l.b()*l.c())/d);
00249 }
00250 
00251 template <class T>
00252 vgl_homg_point_2d<T> vgl_closest_point(vgl_homg_line_2d<T> const& l,
00253                                        vgl_homg_point_2d<T> const& p)
00254 {
00255   T d = l.a()*l.a()+l.b()*l.b();
00256   assert(d!=0); // line should not be the line at infinity
00257   return vgl_homg_point_2d<T>(l.b()*l.b()*p.x()-l.a()*l.b()*p.y()-l.a()*l.c(),
00258                               l.a()*l.a()*p.y()-l.a()*l.b()*p.x()-l.b()*l.c(),
00259                               d);
00260 }
00261 
00262 template <class T>
00263 vgl_point_3d<T> vgl_closest_point(vgl_plane_3d<T> const& l,
00264                                   vgl_point_3d<T> const& p)
00265 {
00266   // The planes b(x-x0)=a(y-y0) and c(x-x0)=a(z-z0) are orthogonal
00267   // to ax+by+cz+d=0 and go through the point (x0,y0,z0).
00268   // Hence take the intersection of these three planes:
00269   T d = l.a()*l.a()+l.b()*l.b()+l.c()*l.c();
00270   return vgl_point_3d<T>(((l.b()*l.b()+l.c()*l.c())*p.x()-l.a()*l.b()*p.y()-l.a()*l.c()*p.z()-l.a()*l.d())/d,
00271                          ((l.a()*l.a()+l.c()*l.c())*p.y()-l.a()*l.b()*p.x()-l.b()*l.c()*p.z()-l.b()*l.d())/d,
00272                             ((l.a()*l.a()+l.b()*l.b())*p.z()-l.a()*l.c()*p.x()-l.b()*l.c()*p.y()-l.c()*l.d())/d);
00273 }
00274 
00275 template <class T>
00276 vgl_homg_point_3d<T> vgl_closest_point(vgl_homg_plane_3d<T> const& l,
00277                                        vgl_homg_point_3d<T> const& p)
00278 {
00279   return vgl_homg_point_3d<T>((l.b()*l.b()+l.c()*l.c())*p.x()-l.a()*l.b()*p.y()-l.a()*l.c()*p.z()-l.a()*l.d(),
00280                               (l.a()*l.a()+l.c()*l.c())*p.y()-l.a()*l.b()*p.x()-l.b()*l.c()*p.z()-l.b()*l.d(),
00281                               (l.a()*l.a()+l.b()*l.b())*p.z()-l.a()*l.c()*p.x()-l.b()*l.c()*p.y()-l.c()*l.d(),
00282                               l.a()*l.a()+l.b()*l.b()+l.c()*l.c());
00283 }
00284 
00285 template <class T>
00286 vgl_point_2d<T> vgl_closest_point(vgl_polygon<T> const& poly,
00287                                   vgl_point_2d<T> const& point,
00288                                   bool closed)
00289 {
00290   T x=point.x(), y=point.y();
00291   double dd = DIST_SQR_TO_LINE_SEG_2D(T,poly[0][0].x(),poly[0][0].y(), poly[0][1].x(),poly[0][1].y(), x,y);
00292   int si = 0, di = 0;
00293   for ( unsigned int s=0; s < poly.num_sheets(); ++s )
00294   {
00295     unsigned int n = poly[s].size();
00296     assert( n > 1 );
00297     for (unsigned i=0; i+1<n; ++i)
00298     {
00299       double nd = DIST_SQR_TO_LINE_SEG_2D(T,poly[s][i].x(),poly[s][i].y(), poly[s][i+1].x(),poly[s][i+1].y(), x,y);
00300       if (nd<dd) { dd=nd; di=i; si=s; }
00301     }
00302     if (closed)
00303     {
00304       double nd = DIST_SQR_TO_LINE_SEG_2D(T,poly[s][0].x(),poly[s][0].y(), poly[s][n-1].x(),poly[s][n-1].y(), x,y);
00305       if (nd<dd) { dd=nd; di=-1; si=s; }
00306     }
00307   }
00308   T ret_x, ret_y;
00309   unsigned int n = poly[si].size();
00310   if (di == -1)
00311     vgl_closest_point_to_linesegment(ret_x,ret_y, poly[si][0].x(),poly[si][0].y(), poly[si][n-1].x(),poly[si][n-1].y(), x,y);
00312   else
00313     vgl_closest_point_to_linesegment(ret_x,ret_y, poly[si][di].x(),poly[si][di].y(), poly[si][di+1].x(),poly[si][di+1].y(), x,y);
00314   return vgl_point_2d<T>(T(ret_x), T(ret_y));
00315 }
00316 
00317 template <class T>
00318 vcl_pair<vgl_homg_point_3d<T>, vgl_homg_point_3d<T> >
00319 vgl_closest_points(vgl_homg_line_3d_2_points<T> const& line1,
00320                    vgl_homg_line_3d_2_points<T> const& line2)
00321 {
00322   vcl_pair<vgl_homg_point_3d<T>, vgl_homg_point_3d<T> > ret;
00323   // parallel or equal lines
00324   if ((line1==line2)||(line1.point_infinite()==line2.point_infinite()))
00325   {
00326     ret.first = ret.second = line1.point_infinite();
00327   }
00328   // intersecting lines
00329   else if (concurrent(line1, line2))
00330   {
00331     ret.first = ret.second = intersection(line1, line2);
00332   }
00333   // neither parallel nor intersecting
00334   // this is the Paul Bourke code - suitably modified for vxl
00335   else
00336   {
00337     // direction of the two lines and of a crossing line
00338     vgl_homg_point_3d<T> p21 = line1.point_infinite();
00339     vgl_homg_point_3d<T> p43 = line2.point_infinite();
00340     vgl_vector_3d<T> p13 = line1.point_finite()-line2.point_finite();
00341 
00342     T d1343 = p13.x() * p43.x() + p13.y() * p43.y() + p13.z() * p43.z();
00343     T d4321 = p43.x() * p21.x() + p43.y() * p21.y() + p43.z() * p21.z();
00344     T d1321 = p13.x() * p21.x() + p13.y() * p21.y() + p13.z() * p21.z();
00345     T d4343 = p43.x() * p43.x() + p43.y() * p43.y() + p43.z() * p43.z();
00346     T d2121 = p21.x() * p21.x() + p21.y() * p21.y() + p21.z() * p21.z();
00347 
00348     T denom = d2121 * d4343 - d4321 * d4321;
00349     T numer = d1343 * d4321 - d1321 * d4343;
00350 
00351     // avoid divisions:
00352     //T mua = numer / denom;
00353     //T mub = (d1343 + d4321 * mua) / d4343;
00354     T mu_n = d1343 * denom + d4321 * numer;
00355     T mu_d = d4343 * denom;
00356 
00357     ret.first.set(denom*line1.point_finite().x()+numer*p21.x(),
00358                   denom*line1.point_finite().y()+numer*p21.y(),
00359                   denom*line1.point_finite().z()+numer*p21.z(),
00360                   denom);
00361     ret.second.set(mu_d*line2.point_finite().x()+mu_n*p43.x(),
00362                    mu_d*line2.point_finite().y()+mu_n*p43.y(),
00363                    mu_d*line2.point_finite().z()+mu_n*p43.z(),
00364                    mu_d);
00365   }
00366   return ret;
00367 }
00368 
00369 template <class T>
00370 vgl_homg_point_3d<T> vgl_closest_point(vgl_homg_line_3d_2_points<T> const& l,
00371                                        vgl_homg_point_3d<T> const& p)
00372 {
00373   // Invalid case: the given point is at infinity:
00374   if (p.w() == 0) return l.point_infinite();
00375   vgl_homg_point_3d<T> const& q = l.point_finite();
00376   vgl_vector_3d<T> v = p-q;
00377   // The plane through p and orthogonal to l is a(x-px)+b(y-py)+c(z-pz)=0
00378   // where (a,b,c,0) is the point at infinity of l.
00379   T a = l.point_infinite().x(), b = l.point_infinite().y(), c = l.point_infinite().z(),
00380     d = a*a+b*b+c*c;
00381   // The closest point is then the intersection of this plane with the line l.
00382   // This point equals d * l.point_finite + lambda * l.direction, with lambda:
00383   T lambda = a*v.x()+b*v.y()+c*v.z();
00384   return vgl_homg_point_3d<T>(d*q.x()+lambda*a*q.w(), d*q.y()+lambda*b*q.w(), d*q.z()+lambda*c*q.w(), d*q.w());
00385 }
00386 
00387 template <class T>
00388 double vgl_closest_point_t(vgl_line_3d_2_points<T> const& l,
00389                            vgl_point_3d<T> const& p)
00390 {
00391   vgl_point_3d<T> const& q = l.point1();
00392   vgl_vector_3d<T> v = p-q;
00393   // The plane through p and orthogonal to l is a(x-px)+b(y-py)+c(z-pz)=0
00394   // where (a,b,c,0) is the direction of l.
00395   double a = l.point2().x()-q.x(), b = l.point2().y()-q.y(),
00396          c = l.point2().z()-q.z(), d = a*a+b*b+c*c;
00397   // The closest point is then the intersection of this plane with the line l.
00398   // This point equals l.point1 + lambda * l.direction, with lambda:
00399   double lambda = (a*v.x()+b*v.y()+c*v.z())/d;
00400   return lambda;
00401 }
00402 
00403 // NB This function could be written in terms of the preceding function vgl_closest_point_t()
00404 template <class T>
00405 vgl_point_3d<T> vgl_closest_point(vgl_line_3d_2_points<T> const& l,
00406                                   vgl_point_3d<T> const& p)
00407 {
00408   vgl_point_3d<T> const& q = l.point1();
00409   vgl_vector_3d<T> v = p-q;
00410   // The plane through p and orthogonal to l is a(x-px)+b(y-py)+c(z-pz)=0
00411   // where (a,b,c,0) is the direction of l.
00412   T a = l.point2().x()-q.x(), b = l.point2().y()-q.y(), c = l.point2().z()-q.z(),
00413     d = a*a+b*b+c*c;
00414   // The closest point is then the intersection of this plane with the line l.
00415   // This point equals l.point1 + lambda * l.direction, with lambda:
00416   T lambda = (a*v.x()+b*v.y()+c*v.z())/d; // possible rounding error!
00417   return vgl_point_3d<T>(q.x()+lambda*a, q.y()+lambda*b, q.z()+lambda*c);
00418 }
00419 
00420 //: Return the points of closest approach on 2 3D lines.
00421 template <class T>
00422 vcl_pair<vgl_point_3d<T>, vgl_point_3d<T> >
00423 vgl_closest_points(const vgl_line_3d_2_points<T>& l1,
00424                    const vgl_line_3d_2_points<T>& l2,
00425                    bool* unique/*=0*/)
00426 {
00427   vcl_pair<vgl_point_3d<T>, vgl_point_3d<T> > ret;
00428 
00429   // Get the parametric equation of each line
00430   // l1: p(s) = p1 + su;  u = p2 - p1
00431   // l2: q(t) = q1 + tv;  v = q2 - q1
00432   vgl_vector_3d<T> u = l1.direction();
00433   vgl_vector_3d<T> v = l2.direction();
00434 
00435   // Get a vector w from first point on line1 to first point on line2
00436   vgl_vector_3d<T> w = l1.point1() - l2.point1();
00437 
00438   double a = dot_product(u,u);
00439   double b = dot_product(u,v);
00440   double c = dot_product(v,v);
00441   double d = dot_product(u,w);
00442   double e = dot_product(v,w);
00443 
00444   // Calculate the parameters s,t for the closest point on each line
00445   double denom = a*c - b*b; // should always be non-negative
00446   if (denom<0.0) denom = 0.0;
00447   if (denom>SMALL_DOUBLE)
00448   {
00449     double s = (b*e - c*d) / denom;
00450     double t = (a*e - b*d) / denom;
00451 
00452     ret.first = l1.point_t(s);
00453     ret.second = l2.point_t(t);
00454     if (unique) *unique = true;
00455   }
00456   else
00457   {
00458     // Lines are parallel or collinear.
00459     // Arbitrarily, return the first point on line1 and the closest point on line2.
00460     double s = 0.0;
00461     double t = (b>c ? d/b : e/c);
00462     ret.first = l1.point_t(s);
00463     ret.second = l2.point_t(t);
00464     if (unique) *unique = false;
00465   }
00466 
00467   return ret;
00468 }
00469 
00470 
00471 //: Return the points of closest approach on 2 3D line segments.
00472 template <class T>
00473 vcl_pair<vgl_point_3d<T>, vgl_point_3d<T> >
00474 vgl_closest_points(vgl_line_segment_3d<T> const& l1,
00475                    vgl_line_segment_3d<T> const& l2,
00476                    bool* unique/*=0*/)
00477 {
00478   vcl_pair<vgl_point_3d<T>, vgl_point_3d<T> > ret;
00479 
00480   // Get the parametric equation of each line
00481   // l1: p(s) = p1 + su;  u = p2 - p1
00482   // l2: q(t) = q1 + tv;  v = q2 - q1
00483   vgl_vector_3d<T> u = l1.direction();
00484   vgl_vector_3d<T> v = l2.direction();
00485 
00486   // Get a vector w from first point on line2 to first point on line1
00487   vgl_vector_3d<T> w = l1.point1() - l2.point1();
00488 
00489   double a = dot_product(u,u); assert(a>0.0);
00490   double b = dot_product(u,v);
00491   double c = dot_product(v,v); assert(c>0.0);
00492   double d = dot_product(u,w);
00493   double e = dot_product(v,w);
00494 
00495   // Calculate the parameters s,t for the closest point on each infinite line
00496   double denom = a*c - b*b; // should always be non-negative
00497   assert(denom>=0.0);
00498 
00499   // Check whether the closest points on the infinite lines are also
00500   // on the finite line segments.
00501   // Consider the square [0,1][0,1] in the plane (s,t).
00502   // Closest points (s,t) on the infinite lines may lie outside this square.
00503   // Closest points on line segments will then lie on the boundary of this square.
00504   // Hence, need to check either 1 or 2 edges of the square.
00505   double s_numer;
00506   double s_denom = denom;
00507   double t_numer;
00508   double t_denom = denom;
00509 
00510   if (denom < SMALL_DOUBLE)
00511   {
00512     // Lines are parallel or collinear
00513     s_numer = 0.0;
00514     s_denom = 1.0;
00515     t_numer = e;
00516     t_denom = c;
00517     if (unique) *unique = false; // assume this for now; check below.
00518   }
00519   else
00520   {
00521     // Calculate the closest points on the infinite lines
00522     s_numer = (b*e - c*d);
00523     t_numer = (a*e - b*d);
00524     if (s_numer < 0.0)
00525     {
00526       // If sc<0 then the s=0 edge is a candidate
00527       s_numer = 0.0;
00528       t_numer = e;
00529       t_denom = c;
00530     }
00531     else if (s_numer > s_denom)
00532     {
00533       // If sc>1 then the s=1 edge is a candidate
00534       s_numer = s_denom;
00535       t_numer = e + b;
00536       t_denom = c;
00537     }
00538     if (unique) *unique = true;
00539   }
00540 
00541   if (t_numer < 0.0)
00542   {
00543     // If tc<0 then the t=0 edge is a candidate
00544     t_numer = 0.0;
00545 
00546     // Recalculate sc for this edge
00547     if (-d < 0.0)
00548       s_numer = 0.0;
00549     else if (-d > a)
00550       s_numer = s_denom;
00551     else
00552     {
00553       s_numer = -d;
00554       s_denom = a;
00555     }
00556   }
00557   else if (t_numer > t_denom)
00558   {
00559     // If tc>1 then the t=1 edge is a candidate
00560     t_numer = t_denom;
00561 
00562     // Recalculate sc for this edge
00563     if ((-d + b) < 0.0)
00564       s_numer = 0.0;
00565     else if ((-d + b) > a)
00566       s_numer = s_denom;
00567     else
00568     {
00569       s_numer = (-d + b);
00570       s_denom = a;
00571     }
00572   }
00573 
00574   // Now calculate the required values of (s,t)
00575   double s = (vcl_abs(s_numer) < SMALL_DOUBLE ? 0.0 : s_numer / s_denom);
00576   double t = (vcl_abs(t_numer) < SMALL_DOUBLE ? 0.0 : t_numer / t_denom);
00577 
00578   // Need to verify whether returned closest points are unique
00579   // in the case of parallel/collinear line segments
00580   if (unique && ! *unique)
00581   {
00582     if ((s==0.0 || s==1.0) && (t==0.0 || t==1.0))
00583       *unique = true;
00584   }
00585 
00586   ret.first = l1.point_t(s);
00587   ret.second = l2.point_t(t);
00588 
00589   return ret;
00590 }
00591 
00592 
00593 #undef DIST_SQR_TO_LINE_SEG_2D
00594 #undef DIST_SQR_TO_LINE_SEG_3D
00595 
00596 
00597 #undef VGL_CLOSEST_POINT_INSTANTIATE
00598 #define VGL_CLOSEST_POINT_INSTANTIATE(T) \
00599 template void vgl_closest_point_to_linesegment(T&,T&,T,T,T,T,T,T); \
00600 template void vgl_closest_point_to_linesegment(T&,T&,T&,T,T,T,T,T,T,T,T,T); \
00601 template int vgl_closest_point_to_non_closed_polygon(T&,T&,T const[],T const[],unsigned int,T,T); \
00602 template int vgl_closest_point_to_non_closed_polygon(T&,T&,T&,T const[],T const[],T const[],unsigned int,T,T,T); \
00603 template int vgl_closest_point_to_closed_polygon(T&,T&,T const[],T const[],unsigned int,T,T); \
00604 template int vgl_closest_point_to_closed_polygon(T&,T&,T&,T const[],T const[],T const[],unsigned int,T,T,T); \
00605 template vgl_point_2d<T > vgl_closest_point_origin(vgl_line_2d<T >const& l); \
00606 template vgl_point_3d<T > vgl_closest_point_origin(vgl_plane_3d<T > const& pl); \
00607 template vgl_point_3d<T > vgl_closest_point_origin(vgl_line_3d_2_points<T > const& l); \
00608 template vgl_homg_point_2d<T > vgl_closest_point_origin(vgl_homg_line_2d<T >const& l); \
00609 template vgl_homg_point_3d<T > vgl_closest_point_origin(vgl_homg_plane_3d<T > const& pl); \
00610 template vgl_homg_point_3d<T > vgl_closest_point_origin(vgl_homg_line_3d_2_points<T > const& l); \
00611 template vgl_point_2d<T > vgl_closest_point(vgl_line_2d<T >const&,vgl_point_2d<T >const&); \
00612 template vgl_point_2d<T > vgl_closest_point(vgl_point_2d<T >const&,vgl_line_2d<T >const&); \
00613 template double vgl_closest_point_t(vgl_line_3d_2_points<T >const&,vgl_point_3d<T >const&); \
00614 template vgl_point_3d<T > vgl_closest_point(vgl_line_3d_2_points<T >const&,vgl_point_3d<T >const&); \
00615 template vgl_homg_point_2d<T > vgl_closest_point(vgl_homg_line_2d<T >const&,vgl_homg_point_2d<T >const&); \
00616 template vgl_homg_point_2d<T > vgl_closest_point(vgl_homg_point_2d<T >const&,vgl_homg_line_2d<T >const&); \
00617 template vgl_point_3d<T > vgl_closest_point(vgl_plane_3d<T >const&,vgl_point_3d<T >const&); \
00618 template vgl_point_3d<T > vgl_closest_point(vgl_point_3d<T >const&,vgl_plane_3d<T >const&); \
00619 template vgl_homg_point_3d<T > vgl_closest_point(vgl_homg_plane_3d<T >const&,vgl_homg_point_3d<T >const&); \
00620 template vgl_homg_point_3d<T > vgl_closest_point(vgl_homg_point_3d<T >const&,vgl_homg_plane_3d<T >const&); \
00621 template vgl_point_2d<T > vgl_closest_point(vgl_polygon<T >const&,vgl_point_2d<T >const&,bool); \
00622 template vcl_pair<vgl_homg_point_3d<T >,vgl_homg_point_3d<T > > \
00623          vgl_closest_points(vgl_homg_line_3d_2_points<T >const&,vgl_homg_line_3d_2_points<T >const&); \
00624 template vgl_homg_point_3d<T > vgl_closest_point(vgl_homg_line_3d_2_points<T >const&,vgl_homg_point_3d<T >const&); \
00625 template vgl_homg_point_3d<T > vgl_closest_point(vgl_homg_point_3d<T >const&,vgl_homg_line_3d_2_points<T >const&); \
00626 template vcl_pair<vgl_point_3d<T >,vgl_point_3d<T > > \
00627          vgl_closest_points(vgl_line_3d_2_points<T >const&, vgl_line_3d_2_points<T >const&, bool*); \
00628 template vcl_pair<vgl_point_3d<T >,vgl_point_3d<T > > \
00629          vgl_closest_points(vgl_line_segment_3d<T >const&, vgl_line_segment_3d<T >const&, bool*)
00630 
00631 #endif // vgl_closest_point_txx_