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