vgl_closest_point.hxx
Go to the documentation of this file.
1 // This is core/vgl/vgl_closest_point.hxx
2 #ifndef vgl_closest_point_hxx_
3 #define vgl_closest_point_hxx_
4 #include <limits>
5 #include <cmath>
6 #ifdef _MSC_VER
7 # include <vcl_msvc_warnings.h>
8 #endif
9 //:
10 // \file
11 // \author Peter Vanroose, KULeuven, ESAT/PSI
12 
13 #include "vgl_closest_point.h"
14 #include <vgl/vgl_distance.h>
15 #include <vgl/vgl_line_2d.h>
16 #include <vgl/vgl_homg_line_2d.h>
17 #include <vgl/vgl_point_2d.h>
18 #include <vgl/vgl_point_3d.h>
19 #include <vgl/vgl_vector_3d.h>
20 #include <vgl/vgl_homg_point_2d.h>
21 #include <vgl/vgl_homg_point_3d.h>
22 #include <vgl/vgl_plane_3d.h>
23 #include <vgl/vgl_sphere_3d.h>
24 #include <vgl/vgl_homg_plane_3d.h>
29 #include <vgl/vgl_polygon.h>
30 #include <vgl/vgl_ray_3d.h>
31 #include <vgl/vgl_pointset_3d.h>
33 #include <cassert>
34 
35 template <class T>
36 static inline T square(T x) { return x*x; }
37 
38 
39 // Consider numbers smaller than this to be zero
40 const double SMALL_DOUBLE = 1e-12;
41 
42 
43 // Borland has trouble deducing template types when parameters have
44 // type const T instead of T. This occurs in
45 // vgl_distance2_to_linesegment. The workaround is to make the T const
46 // parameter a T parameter.
47 //
48 #define DIST_SQR_TO_LINE_SEG_2D( T, x1, y1, x2, y2, x, y ) \
49  vgl_distance2_to_linesegment(x1, y1, x2, y2, x, y );
50 #define DIST_SQR_TO_LINE_SEG_3D( T, x1, y1, z1, x2, y2, z2, x, y, z ) \
51  vgl_distance2_to_linesegment(x1, y1, z1, x2, y2, z2, x, y, z );
52 
53 
54 template <class T>
55 void vgl_closest_point_to_linesegment(T& ret_x, T& ret_y,
56  T x1, T y1,
57  T x2, T y2,
58  T x0, T y0)
59 {
60  // squared distance between endpoints:
61  T ddh = square(x2-x1) + square(y2-y1);
62 
63  // squared distance to endpoints:
64  T dd1 = square(x0-x1) + square(y0-y1);
65  T dd2 = square(x0-x2) + square(y0-y2);
66 
67  // if closest to the start point:
68  if (dd2 > ddh + dd1) { ret_x=x1; ret_y=y1; return; }
69 
70  // if closest to the end point :
71  if (dd1 > ddh + dd2) { ret_x=x2; ret_y=y2; return; }
72 
73  // line through (x0,y0) and perpendicular to the given line is
74  // the line with equation (x-x0)(x2-x1)+(y-y0)(y2-y1)=0.
75  // Then it just remains to intersect these two lines:
76  T dx = x2-x1;
77  T dy = y2-y1;
78  double c = dx*dx+dy*dy;
79  ret_x = T((dx*dx*x0+dy*dy*x1-dx*dy*(y1-y0))/c); // possible rounding error!
80  ret_y = T((dx*dx*y1+dy*dy*y0-dx*dy*(x1-x0))/c);
81 }
82 
83 template <class T>
84 void vgl_closest_point_to_linesegment(T& ret_x, T& ret_y, T& ret_z,
85  T x1, T y1, T z1,
86  T x2, T y2, T z2,
87  T x, T y, T z)
88 {
89  // squared distance between endpoints:
90  T ddh = square(x2-x1) + square(y2-y1) + square(z2-z1);
91 
92  // squared distance to endpoints :
93  T dd1 = square(x-x1) + square(y-y1) + square(z-z1);
94  T dd2 = square(x-x2) + square(y-y2) + square(z-z2);
95 
96  // if closest to the start point:
97  if (dd2 > ddh + dd1) { ret_x=x1; ret_y=y1; ret_z=z1; return; }
98 
99  // if closest to the end point :
100  if (dd1 > ddh + dd2) { ret_x=x2; ret_y=y2; ret_z=z2; return; }
101 
102  // plane through (x,y,z) and orthogonal to the line is a(X-x)+b(Y-y)+c(Z-z)=0
103  // where (a,b,c) is the direction of the line.
104  T a = x2-x1, b = y2-y1, c = z2-z1;
105  // The closest point is then the intersection of this plane with the line.
106  // This point equals (x1,y1,z1) + lambda * (a,b,c), with this lambda:
107  double lambda = (a*(x-x1)+b*(y-y1)+c*(z-z1))/double(a*a+b*b+c*c);
108  ret_x = x1+T(lambda*a); ret_y = y1+T(lambda*b); ret_z = z1+T(lambda*c);
109 }
110 
111 template <class T>
113  T const px[], T const py[], unsigned int n,
114  T x, T y)
115 {
116  assert(n>1);
117  double dd = DIST_SQR_TO_LINE_SEG_2D(T,px[0],py[0], px[1],py[1], x,y);
118  int di = 0;
119  for (unsigned i=1; i+1<n; ++i)
120  {
121  double nd = DIST_SQR_TO_LINE_SEG_2D(T,px[i],py[i], px[i+1],py[i+1], x,y);
122  if (nd<dd) { dd=nd; di=i; }
123  }
124  vgl_closest_point_to_linesegment(ret_x,ret_y, px[di],py[di], px[di+1],py[di+1], x,y);
125  return di;
126 }
127 
128 template <class T>
129 int vgl_closest_point_to_non_closed_polygon(T& ret_x, T& ret_y, T& ret_z,
130  T const px[], T const py[], T const pz[], unsigned int n,
131  T x, T y, T z)
132 {
133  assert(n>1);
134  double dd = DIST_SQR_TO_LINE_SEG_3D(T,px[0],py[0],pz[0], px[1],py[1],pz[1], x,y,z);
135  int di = 0;
136  for (unsigned i=1; i+1<n; ++i)
137  {
138  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);
139  if (nd<dd) { dd=nd; di=i; }
140  }
141  vgl_closest_point_to_linesegment(ret_x,ret_y,ret_z, px[di],py[di],pz[di],
142  px[di+1],py[di+1],pz[di+1], x,y,z);
143  return di;
144 }
145 
146 template <class T>
147 int vgl_closest_point_to_closed_polygon(T& ret_x, T& ret_y,
148  T const px[], T const py[], unsigned int n,
149  T x, T y)
150 {
151  assert(n>1);
152  double dd = DIST_SQR_TO_LINE_SEG_2D(T,px[0],py[0], px[n-1],py[n-1], x,y);
153  int di = -1;
154  for (unsigned i=0; i+1<n; ++i)
155  {
156  double nd = DIST_SQR_TO_LINE_SEG_2D(T,px[i],py[i], px[i+1],py[i+1], x,y);
157  if (nd<dd) { dd=nd; di=i; }
158  }
159  if (di == -1) di+=n,
160  vgl_closest_point_to_linesegment(ret_x,ret_y, px[0],py[0], px[n-1],py[n-1], x,y);
161  else
162  vgl_closest_point_to_linesegment(ret_x,ret_y, px[di],py[di], px[di+1],py[di+1], x,y);
163  return di;
164 }
165 
166 template <class T>
167 int vgl_closest_point_to_closed_polygon(T& ret_x, T& ret_y, T& ret_z,
168  T const px[], T const py[], T const pz[], unsigned int n,
169  T x, T y, T z)
170 {
171  assert(n>1);
172  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);
173  int di = -1;
174  for (unsigned i=0; i+1<n; ++i)
175  {
176  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);
177  if (nd<dd) { dd=nd; di=i; }
178  }
179  if (di == -1) di+=n,
180  vgl_closest_point_to_linesegment(ret_x,ret_y,ret_z, px[0],py[0],pz[0],
181  px[n-1],py[n-1],pz[n-1], x,y,z);
182  else
183  vgl_closest_point_to_linesegment(ret_x,ret_y,ret_z, px[di],py[di],pz[di],
184  px[di+1],py[di+1],pz[di+1], x,y,z);
185  return di;
186 }
187 
188 template <class T>
190 {
191  T d = l.a()*l.a()+l.b()*l.b();
192  return vgl_point_2d<T>(-l.a()*l.c()/d, -l.b()*l.c()/d);
193 }
194 
195 template <class T>
197 {
198  return vgl_homg_point_2d<T>(l.a()*l.c(), l.b()*l.c(),
199  -l.a()*l.a()-l.b()*l.b());
200 }
201 
202 template <class T>
204 {
205  T d = pl.a()*pl.a()+pl.b()*pl.b()+pl.c()*pl.c();
206  return vgl_point_3d<T>(-pl.a()*pl.d()/d, -pl.b()*pl.d()/d, -pl.c()*pl.d()/d);
207 }
208 
209 template <class T>
211 {
212  return vgl_homg_point_3d<T>(pl.a()*pl.d(), pl.b()*pl.d(), pl.c()*pl.d(),
213  -pl.a()*pl.a()-pl.b()*pl.b()-pl.c()*pl.c());
214 }
215 
216 template <class T>
218 {
219  vgl_homg_point_3d<T> const& q = l.point_finite();
220  // The plane through the origin and orthogonal to l is ax+by+cz=0
221  // where (a,b,c,0) is the point at infinity of l.
222  T a = l.point_infinite().x(), b = l.point_infinite().y(), c = l.point_infinite().z(),
223  d = a*a+b*b+c*c;
224  // The closest point is then the intersection of this plane with the line l.
225  // This point equals d * l.point_finite - lambda * l.direction, with lambda:
226  T lambda = a*q.x()+b*q.y()+c*q.z();
227  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());
228 }
229 
230 template <class T>
232 {
233  vgl_point_3d<T> const& q = l.point1();
234  // The plane through the origin and orthogonal to l is ax+by+cz=0
235  // where (a,b,c) is the direction of l.
236  T a = l.point2().x()-q.x(), b = l.point2().y()-q.y(), c = l.point2().z()-q.z(),
237  d = a*a+b*b+c*c;
238  // The closest point is then the intersection of this plane with the line l.
239  // This point equals l.point1 - lambda * l.direction, with lambda:
240  T lambda = (a*q.x()+b*q.y()+c*q.z())/d; // possible rounding error!
241  return vgl_point_3d<T>(q.x()-lambda*a, q.y()-lambda*b, q.z()-lambda*c);
242 }
243 
244 template <class T>
246  vgl_point_2d<T> const& p)
247 {
248  T d = l.a()*l.a()+l.b()*l.b();
249  assert(d!=0); // line should not be the line at infinity
250  return vgl_point_2d<T>((l.b()*l.b()*p.x()-l.a()*l.b()*p.y()-l.a()*l.c())/d,
251  (l.a()*l.a()*p.y()-l.a()*l.b()*p.x()-l.b()*l.c())/d);
252 }
253 
254 template <class T>
256  vgl_homg_point_2d<T> const& p)
257 {
258  T d = l.a()*l.a()+l.b()*l.b();
259  assert(d!=0); // line should not be the line at infinity
260  return vgl_homg_point_2d<T>(l.b()*l.b()*p.x()-l.a()*l.b()*p.y()-l.a()*l.c(),
261  l.a()*l.a()*p.y()-l.a()*l.b()*p.x()-l.b()*l.c(),
262  d);
263 }
264 
265 template <class T>
267  vgl_point_3d<T> const& p)
268 {
269  // The planes b(x-x0)=a(y-y0) and c(x-x0)=a(z-z0) are orthogonal
270  // to ax+by+cz+d=0 and go through the point (x0,y0,z0).
271  // Hence take the intersection of these three planes:
272  T d = l.a()*l.a()+l.b()*l.b()+l.c()*l.c();
273  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,
274  ((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,
275  ((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);
276 }
277 
278 template <class T>
280  vgl_homg_point_3d<T> const& p)
281 {
282  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(),
283  (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(),
284  (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(),
285  l.a()*l.a()+l.b()*l.b()+l.c()*l.c());
286 }
287 
288 template <class T>
290  vgl_point_2d<T> const& point,
291  bool closed)
292 {
293  T x=point.x(), y=point.y();
294  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);
295  int si = 0, di = 0;
296  for ( unsigned int s=0; s < poly.num_sheets(); ++s )
297  {
298  unsigned int n = (unsigned int)(poly[s].size());
299  assert( n > 1 );
300  for (unsigned i=0; i+1<n; ++i)
301  {
302  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);
303  if (nd<dd) { dd=nd; di=i; si=s; }
304  }
305  if (closed)
306  {
307  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);
308  if (nd<dd) { dd=nd; di=-1; si=s; }
309  }
310  }
311  T ret_x, ret_y;
312  unsigned int n = (unsigned int)(poly[si].size());
313  if (di == -1)
314  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);
315  else
316  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);
317  return vgl_point_2d<T>(T(ret_x), T(ret_y));
318 }
319 
320 template <class T>
321 std::pair<vgl_homg_point_3d<T>, vgl_homg_point_3d<T> >
323  vgl_homg_line_3d_2_points<T> const& line2)
324 {
325  std::pair<vgl_homg_point_3d<T>, vgl_homg_point_3d<T> > ret;
326  // parallel or equal lines
327  if ((line1==line2)||(line1.point_infinite()==line2.point_infinite()))
328  {
329  ret.first = ret.second = line1.point_infinite();
330  }
331  // intersecting lines
332  else if (concurrent(line1, line2))
333  {
334  ret.first = ret.second = intersection(line1, line2);
335  }
336  // neither parallel nor intersecting
337  // this is the Paul Bourke code - suitably modified for vxl
338  else
339  {
340  // direction of the two lines and of a crossing line
341  vgl_homg_point_3d<T> p21 = line1.point_infinite();
342  vgl_homg_point_3d<T> p43 = line2.point_infinite();
343  vgl_vector_3d<T> p13 = line1.point_finite()-line2.point_finite();
344 
345  T d1343 = p13.x() * p43.x() + p13.y() * p43.y() + p13.z() * p43.z();
346  T d4321 = p43.x() * p21.x() + p43.y() * p21.y() + p43.z() * p21.z();
347  T d1321 = p13.x() * p21.x() + p13.y() * p21.y() + p13.z() * p21.z();
348  T d4343 = p43.x() * p43.x() + p43.y() * p43.y() + p43.z() * p43.z();
349  T d2121 = p21.x() * p21.x() + p21.y() * p21.y() + p21.z() * p21.z();
350 
351  T denom = d2121 * d4343 - d4321 * d4321;
352  T numer = d1343 * d4321 - d1321 * d4343;
353 
354  // avoid divisions:
355  //T mua = numer / denom;
356  //T mub = (d1343 + d4321 * mua) / d4343;
357  T mu_n = d1343 * denom + d4321 * numer;
358  T mu_d = d4343 * denom;
359 
360  ret.first.set(denom*line1.point_finite().x()+numer*p21.x(),
361  denom*line1.point_finite().y()+numer*p21.y(),
362  denom*line1.point_finite().z()+numer*p21.z(),
363  denom);
364  ret.second.set(mu_d*line2.point_finite().x()+mu_n*p43.x(),
365  mu_d*line2.point_finite().y()+mu_n*p43.y(),
366  mu_d*line2.point_finite().z()+mu_n*p43.z(),
367  mu_d);
368  }
369  return ret;
370 }
371 
372 template <class T>
374  vgl_homg_point_3d<T> const& p)
375 {
376  // Invalid case: the given point is at infinity:
377  if (p.w() == 0) return l.point_infinite();
378  vgl_homg_point_3d<T> const& q = l.point_finite();
379  vgl_vector_3d<T> v = p-q;
380  // The plane through p and orthogonal to l is a(x-px)+b(y-py)+c(z-pz)=0
381  // where (a,b,c,0) is the point at infinity of l.
382  T a = l.point_infinite().x(), b = l.point_infinite().y(), c = l.point_infinite().z(),
383  d = a*a+b*b+c*c;
384  // The closest point is then the intersection of this plane with the line l.
385  // This point equals d * l.point_finite + lambda * l.direction, with lambda:
386  T lambda = a*v.x()+b*v.y()+c*v.z();
387  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());
388 }
389 
390 template <class T>
392  vgl_point_3d<T> const& p)
393 {
394  vgl_point_3d<T> const& q = l.point1();
395  vgl_vector_3d<T> v = p-q;
396  // The plane through p and orthogonal to l is a(x-px)+b(y-py)+c(z-pz)=0
397  // where (a,b,c,0) is the direction of l.
398  double a = l.point2().x()-q.x(), b = l.point2().y()-q.y(),
399  c = l.point2().z()-q.z(), d = a*a+b*b+c*c;
400  // The closest point is then the intersection of this plane with the line l.
401  // This point equals l.point1 + lambda * l.direction, with lambda:
402  double lambda = (a*v.x()+b*v.y()+c*v.z())/d;
403  return lambda;
404 }
405 
406 // NB This function could be written in terms of the preceding function vgl_closest_point_t()
407 template <class T>
409  vgl_point_3d<T> const& p)
410 {
411  vgl_point_3d<T> const& q = l.point1();
412  vgl_vector_3d<T> v = p-q;
413  // The plane through p and orthogonal to l is a(x-px)+b(y-py)+c(z-pz)=0
414  // where (a,b,c,0) is the direction of l.
415  T a = l.point2().x()-q.x(), b = l.point2().y()-q.y(), c = l.point2().z()-q.z(),
416  d = a*a+b*b+c*c;
417  // The closest point is then the intersection of this plane with the line l.
418  // This point equals l.point1 + lambda * l.direction, with lambda:
419  T lambda = (a*v.x()+b*v.y()+c*v.z())/d; // possible rounding error!
420  return vgl_point_3d<T>(q.x()+lambda*a, q.y()+lambda*b, q.z()+lambda*c);
421 }
422 
423 //: Return the points of closest approach on 2 3D lines.
424 template <class T>
425 std::pair<vgl_point_3d<T>, vgl_point_3d<T> >
427  const vgl_line_3d_2_points<T>& l2,
428  bool* unique/*=0*/)
429 {
430  std::pair<vgl_point_3d<T>, vgl_point_3d<T> > ret;
431 
432  // Get the parametric equation of each line
433  // l1: p(s) = p1 + su; u = p2 - p1
434  // l2: q(t) = q1 + tv; v = q2 - q1
435  vgl_vector_3d<T> u = l1.direction();
437 
438  // Get a vector w from first point on line1 to first point on line2
439  vgl_vector_3d<T> w = l1.point1() - l2.point1();
440 
441  double a = dot_product(u,u);
442  double b = dot_product(u,v);
443  double c = dot_product(v,v);
444  double d = dot_product(u,w);
445  double e = dot_product(v,w);
446 
447  // Calculate the parameters s,t for the closest point on each line
448  double denom = a*c - b*b; // should always be non-negative
449  if (denom<0.0) denom = 0.0;
450  if (denom>SMALL_DOUBLE)
451  {
452  double s = (b*e - c*d) / denom;
453  double t = (a*e - b*d) / denom;
454 
455  ret.first = l1.point_t(s);
456  ret.second = l2.point_t(t);
457  if (unique) *unique = true;
458  }
459  else
460  {
461  // Lines are parallel or collinear.
462  // Arbitrarily, return the first point on line1 and the closest point on line2.
463  double s = 0.0;
464  double t = (b>c ? d/b : e/c);
465  ret.first = l1.point_t(s);
466  ret.second = l2.point_t(t);
467  if (unique) *unique = false;
468  }
469 
470  return ret;
471 }
472 
473 template <class T>
475  vgl_ray_3d<T> const& r)
476 {
478  return vgl_closest_point(p,l2);
479 }
480 
481 //: Return the points of closest approach on 2 3D line segments.
482 template <class T>
483 std::pair<vgl_point_3d<T>, vgl_point_3d<T> >
485  vgl_line_segment_3d<T> const& l2,
486  bool* unique/*=0*/)
487 {
488  std::pair<vgl_point_3d<T>, vgl_point_3d<T> > ret;
489 
490  // Get the parametric equation of each line
491  // l1: p(s) = p1 + su; u = p2 - p1
492  // l2: q(t) = q1 + tv; v = q2 - q1
493  vgl_vector_3d<T> u = l1.direction();
495 
496  // Get a vector w from first point on line2 to first point on line1
497  vgl_vector_3d<T> w = l1.point1() - l2.point1();
498 
499  double a = dot_product(u,u); assert(a>0.0);
500  double b = dot_product(u,v);
501  double c = dot_product(v,v); assert(c>0.0);
502  double d = dot_product(u,w);
503  double e = dot_product(v,w);
504 
505  // Calculate the parameters s,t for the closest point on each infinite line
506  double denom = a*c - b*b; // should always be non-negative
507  assert(denom>=0.0);
508 
509  // Check whether the closest points on the infinite lines are also
510  // on the finite line segments.
511  // Consider the square [0,1][0,1] in the plane (s,t).
512  // Closest points (s,t) on the infinite lines may lie outside this square.
513  // Closest points on line segments will then lie on the boundary of this square.
514  // Hence, need to check either 1 or 2 edges of the square.
515  double s_numer;
516  double s_denom = denom;
517  double t_numer;
518  double t_denom = denom;
519 
520  if (denom < SMALL_DOUBLE)
521  {
522  // Lines are parallel or collinear
523  s_numer = 0.0;
524  s_denom = 1.0;
525  t_numer = e;
526  t_denom = c;
527  if (unique) *unique = false; // assume this for now; check below.
528  }
529  else
530  {
531  // Calculate the closest points on the infinite lines
532  s_numer = (b*e - c*d);
533  t_numer = (a*e - b*d);
534  if (s_numer < 0.0)
535  {
536  // If sc<0 then the s=0 edge is a candidate
537  s_numer = 0.0;
538  t_numer = e;
539  t_denom = c;
540  }
541  else if (s_numer > s_denom)
542  {
543  // If sc>1 then the s=1 edge is a candidate
544  s_numer = s_denom;
545  t_numer = e + b;
546  t_denom = c;
547  }
548  if (unique) *unique = true;
549  }
550 
551  if (t_numer < 0.0)
552  {
553  // If tc<0 then the t=0 edge is a candidate
554  t_numer = 0.0;
555 
556  // Recalculate sc for this edge
557  if (-d < 0.0)
558  s_numer = 0.0;
559  else if (-d > a)
560  s_numer = s_denom;
561  else
562  {
563  s_numer = -d;
564  s_denom = a;
565  }
566  }
567  else if (t_numer > t_denom)
568  {
569  // If tc>1 then the t=1 edge is a candidate
570  t_numer = t_denom;
571 
572  // Recalculate sc for this edge
573  if ((-d + b) < 0.0)
574  s_numer = 0.0;
575  else if ((-d + b) > a)
576  s_numer = s_denom;
577  else
578  {
579  s_numer = (-d + b);
580  s_denom = a;
581  }
582  }
583 
584  // Now calculate the required values of (s,t)
585  double s = (std::abs(s_numer) < SMALL_DOUBLE ? 0.0 : s_numer / s_denom);
586  double t = (std::abs(t_numer) < SMALL_DOUBLE ? 0.0 : t_numer / t_denom);
587 
588  // Need to verify whether returned closest points are unique
589  // in the case of parallel/collinear line segments
590  if (unique && ! *unique)
591  {
592  if ((s==0.0 || s==1.0) && (t==0.0 || t==1.0))
593  *unique = true;
594  }
595 
596  ret.first = l1.point_t(s);
597  ret.second = l2.point_t(t);
598 
599  return ret;
600 }
601 
602 template <class T>
604  vgl_point_2d<T> const& p)
605 {
606  vgl_point_2d<T> q;
608  l.point1().x(), l.point1().y(),
609  l.point2().x(), l.point2().y(),
610  p.x(), p.y());
611  return q;
612 }
613 
614 template <class T>
616  vgl_point_3d<T> const& p)
617 {
618  vgl_point_3d<T> q;
619  vgl_closest_point_to_linesegment(q.x(), q.y(), q.z(),
620  l.point1().x(), l.point1().y(), l.point1().z(),
621  l.point2().x(), l.point2().y(), l.point2().z(),
622  p.x(), p.y(), p.z());
623  return q;
624 }
625 template <class T>
627  vgl_point_3d<T> const& p){
628  const vgl_point_3d<T>& c = s.centre();
629  // offset p by sphere center
630  double vx = static_cast<double>(p.x()-c.x()), vy = static_cast<double>(p.y()-c.y()),
631  vz = static_cast<double>(p.z()-c.z());
632  double radius = std::sqrt(vx*vx + vy*vy + vz*vz);
633  T azimuth = static_cast<T>(std::atan2(vy, vx));
634  T elevation = static_cast<T>(std::acos(vz/radius));
635  vgl_point_3d<T> ret;
636  s.spherical_to_cartesian(elevation, azimuth, ret);
637  return ret;
638 }
639 
640 template <class T>
642  vgl_point_3d<T> const& p, T dist){
643  unsigned n = ptset.npts();
644  if(n == 0)
645  return vgl_point_3d<T>();
646  unsigned iclose = 0;
647  double d_close = 1.0/SMALL_DOUBLE;
648  for(unsigned i = 0; i<n; ++i){
649  vgl_point_3d<T> pi = ptset.p(i);
650  double d = (pi-p).length();
651  if(d<d_close){
652  d_close = d;
653  iclose = i;
654  }
655  }
656  vgl_point_3d<T> pc = ptset.p(iclose);
657  if(!ptset.has_normals())
658  return pc;
659  const vgl_vector_3d<T>& norm = ptset.n(iclose);
660  //otherwise construct the plane and find closest point on that
661  if(std::numeric_limits<T>::is_integer){
662  // closest point can be templated over int so cast to double for plane computations
663  vgl_point_3d<double> pd(static_cast<double>(p.x()), static_cast<double>(p.y()), static_cast<double>(p.z()));
664  vgl_point_3d<double> pcd(static_cast<double>(pc.x()), static_cast<double>(pc.y()), static_cast<double>(pc.z()));
665 
666  vgl_vector_3d<double> normd(static_cast<double>(norm.x()),static_cast<double>(norm.y()),static_cast<double>(norm.z()));
667  vgl_plane_3d<double> pld(normd, pcd);
668  vgl_point_3d<double> pc_planed = vgl_closest_point(pld, pd);
669  T dpd = static_cast<T>((pc_planed-pcd).length());
670  if(dpd>dist)
671  return pc;
672  vgl_point_3d<T> pc_plane_T(static_cast<T>(pc_planed.x()), static_cast<T>(pc_planed.y()), static_cast<T>(pc_planed.z()));
673  return pc_plane_T;
674  }else{
675  vgl_plane_3d<T> pl(norm, pc);
676  vgl_point_3d<T> pc_plane = vgl_closest_point(pl, p);
677  T dp = static_cast<T>((pc_plane-p).length());
678  if(dp>dist)
679  return pc;
680  return pc_plane;
681  }
682 }
683 template <class T>
685  // find the closest knot
686  std::vector<vgl_point_3d<T> > const& knots = cspl.const_knots();
687  unsigned n = cspl.n_knots();
688  double min_dist = std::numeric_limits<double>::max();
689  unsigned min_index = 0;
690  for(unsigned i = 0; i<n; ++i){
691  double d = vgl_distance(knots[i],p);
692  if(d<min_dist){
693  min_dist = d;
694  min_index = i;
695  }
696  }
697  unsigned start_index = 0, end_index = 0;
698  // find the interval assuming that the closest knots span the closest point
699  // cases
700  if(min_index == 0){
701  if(cspl.closed()){
702  double dm = vgl_distance(knots[n-2], p);
703  double dp = vgl_distance(knots[1], p);
704  if(dp<dm){
705  start_index = 0;
706  end_index = 1;
707  }else{
708  start_index = n-2;
709  end_index = n-1;
710  }
711  }else{
712  start_index = 0;
713  end_index = 1;
714  }
715  }else if(min_index == n-1){
716  if(cspl.closed()){
717  double dm = vgl_distance(knots[n-2], p);
718  double dp = vgl_distance(knots[1], p);
719  if(dp<dm){
720  start_index = 0;
721  end_index = 1;
722  }else{
723  start_index = n-2;
724  end_index = n-1;
725  }
726  }else{
727  start_index = n-2;
728  end_index = n-1;
729  }
730  }else{
731  double dm = vgl_distance(knots[min_index-1], p);
732  double dp = vgl_distance(knots[min_index+1], p);
733  if(dp<dm){
734  start_index = min_index;
735  end_index = min_index+1;
736  }else{
737  start_index = min_index-1;
738  end_index = min_index;
739  }
740  }
741  // iterate to fine closest point (within 1/1000 of the interval)
742  T sindx = static_cast<T>(start_index), eindx = static_cast<T>(end_index);
743  bool first = true;
744  unsigned iter = 0;
745  double tolerance = vgl_distance(knots[start_index],knots[end_index])/T(1000);
746  T t = (sindx+ eindx)/T(2);
747  vgl_point_3d<T> cp = cspl(t);
748  double dcm = vgl_distance(p, cp), dcm0 = 0.0 ;
749  unsigned max_iter = 100;
750  while(first || ((std::fabs(dcm - dcm0)>tolerance)&&iter<max_iter)){
751  dcm0 = dcm;
752  first = false;
753  T tp = (t+eindx)/T(2), tm = (t+sindx)/T(2);
754  double dp = vgl_distance(p, cspl(tp));
755  double dm = vgl_distance(p, cspl(tm));
756  if(dp<dm){
757  sindx = t;
758  t = tp;
759  }else{
760  eindx = t;
761  t = tm;
762  }
763  cp = cspl(t);
764  dcm = vgl_distance(p,cp);
765  iter++;
766  }
767  if(iter>=max_iter)
768  std::cout << " Warning: exceeded num interations in closest point cubic_spline_3d\n";
769  return cp;
770 }
771 
772 #undef DIST_SQR_TO_LINE_SEG_2D
773 #undef DIST_SQR_TO_LINE_SEG_3D
774 
775 #undef VGL_CLOSEST_POINT_INSTANTIATE
776 #define VGL_CLOSEST_POINT_INSTANTIATE(T) \
777 template void vgl_closest_point_to_linesegment(T&,T&,T,T,T,T,T,T); \
778 template void vgl_closest_point_to_linesegment(T&,T&,T&,T,T,T,T,T,T,T,T,T); \
779 template int vgl_closest_point_to_non_closed_polygon(T&,T&,T const[],T const[],unsigned int,T,T); \
780 template int vgl_closest_point_to_non_closed_polygon(T&,T&,T&,T const[],T const[],T const[],unsigned int,T,T,T); \
781 template int vgl_closest_point_to_closed_polygon(T&,T&,T const[],T const[],unsigned int,T,T); \
782 template int vgl_closest_point_to_closed_polygon(T&,T&,T&,T const[],T const[],T const[],unsigned int,T,T,T); \
783 template vgl_point_2d<T > vgl_closest_point_origin(vgl_line_2d<T >const& l); \
784 template vgl_point_3d<T > vgl_closest_point_origin(vgl_plane_3d<T > const& pl); \
785 template vgl_point_3d<T > vgl_closest_point_origin(vgl_line_3d_2_points<T > const& l); \
786 template vgl_homg_point_2d<T > vgl_closest_point_origin(vgl_homg_line_2d<T >const& l); \
787 template vgl_homg_point_3d<T > vgl_closest_point_origin(vgl_homg_plane_3d<T > const& pl); \
788 template vgl_homg_point_3d<T > vgl_closest_point_origin(vgl_homg_line_3d_2_points<T > const& l); \
789 template vgl_point_2d<T > vgl_closest_point(vgl_line_2d<T >const&,vgl_point_2d<T >const&); \
790 template vgl_point_2d<T > vgl_closest_point(vgl_point_2d<T >const&,vgl_line_2d<T >const&); \
791 template double vgl_closest_point_t(vgl_line_3d_2_points<T >const&,vgl_point_3d<T >const&); \
792 template vgl_point_3d<T > vgl_closest_point(vgl_line_3d_2_points<T >const&,vgl_point_3d<T >const&); \
793 template vgl_point_3d<T > vgl_closest_point(vgl_point_3d<T > const& p,vgl_ray_3d<T > const& r); \
794 template vgl_homg_point_2d<T > vgl_closest_point(vgl_homg_line_2d<T >const&,vgl_homg_point_2d<T >const&); \
795 template vgl_homg_point_2d<T > vgl_closest_point(vgl_homg_point_2d<T >const&,vgl_homg_line_2d<T >const&); \
796 template vgl_point_3d<T > vgl_closest_point(vgl_plane_3d<T >const&,vgl_point_3d<T >const&); \
797 template vgl_point_3d<T > vgl_closest_point(vgl_point_3d<T >const&,vgl_plane_3d<T >const&); \
798 template vgl_homg_point_3d<T > vgl_closest_point(vgl_homg_plane_3d<T >const&,vgl_homg_point_3d<T >const&); \
799 template vgl_homg_point_3d<T > vgl_closest_point(vgl_homg_point_3d<T >const&,vgl_homg_plane_3d<T >const&); \
800 template vgl_point_2d<T > vgl_closest_point(vgl_polygon<T >const&,vgl_point_2d<T >const&,bool); \
801 template std::pair<vgl_homg_point_3d<T >,vgl_homg_point_3d<T > > \
802  vgl_closest_points(vgl_homg_line_3d_2_points<T >const&,vgl_homg_line_3d_2_points<T >const&); \
803 template vgl_homg_point_3d<T > vgl_closest_point(vgl_homg_line_3d_2_points<T >const&,vgl_homg_point_3d<T >const&); \
804 template vgl_homg_point_3d<T > vgl_closest_point(vgl_homg_point_3d<T >const&,vgl_homg_line_3d_2_points<T >const&); \
805 template std::pair<vgl_point_3d<T >,vgl_point_3d<T > > \
806  vgl_closest_points(vgl_line_3d_2_points<T >const&, vgl_line_3d_2_points<T >const&, bool*); \
807 template std::pair<vgl_point_3d<T >,vgl_point_3d<T > > \
808  vgl_closest_points(vgl_line_segment_3d<T >const&, vgl_line_segment_3d<T >const&, bool*); \
809 template vgl_point_2d<T > vgl_closest_point(vgl_line_segment_2d<T > const&, vgl_point_2d<T > const&); \
810 template vgl_point_3d<T > vgl_closest_point(vgl_line_segment_3d<T > const&, vgl_point_3d<T > const&); \
811 template vgl_point_3d<T> vgl_closest_point(vgl_sphere_3d<T> const& s, vgl_point_3d<T> const& p); \
812 template vgl_point_3d<T> vgl_closest_point(vgl_pointset_3d<T> const& ptset, vgl_point_3d<T> const& p, T dist); \
813 template vgl_point_3d<T> vgl_closest_point(vgl_cubic_spline_3d<T> const& cspl, vgl_point_3d<T> const& p)
814 #endif // vgl_closest_point_hxx_
A 3-d cubic spline curve defined by a set of knots (3-d points)
homogeneous plane in 3D projective space
point in projective 3D space
T dot_product(v const &a, v const &b)
dot product or inner product of two vectors.
vgl_point_3d< Type > point1() const
a point in 2D nonhomogeneous space
void vgl_closest_point_to_linesegment(T &ret_x, T &ret_y, T x1, T y1, T x2, T y2, T x0, T y0)
Closest point to (x,y) on the line segment (x1,y1)-(x2,y2).
vgl_point_3d< Type > point_t(const double t) const
Return a point on the line defined by a scalar parameter t such that t=0.0 at point1 and t=1....
Represents a homogeneous 2D line.
Definition: vgl_fwd.h:14
vgl_point_3d< Type > p(unsigned i) const
std::vector< vgl_point_3d< Type > > const & const_knots() const
vgl_point_3d< Type > point_t(const double t) const
Return a point on the line defined by a scalar parameter t.
T a() const
Return x coefficient.
Definition: vgl_plane_3d.h:89
direction vector in Euclidean 3D space
Type b() const
Return y coefficient.
Type c() const
Return z coefficient.
bool concurrent(l const &l1, l const &l2, l const &l3)
Are three lines concurrent, i.e., do they pass through a common point?.
vgl_vector_3d< Type > direction() const
Return the direction vector of this line (not normalised - but perhaps it should be,...
A 3-d ray defined by an origin and a direction vector.
Type d() const
Return homogeneous scaling coefficient.
line in projective 2D space
double length(v const &a)
Return the length of a vector.
Definition: vgl_vector_2d.h:94
Represents a homogeneous 3D point.
Definition: vgl_fwd.h:9
Type & z()
Definition: vgl_point_3d.h:73
A class to hold a non-homogeneous representation of a 3D line.
Definition: vgl_fwd.h:17
#define v
Definition: vgl_vector_2d.h:74
#define DIST_SQR_TO_LINE_SEG_3D(T, x1, y1, z1, x2, y2, z2, x, y, z)
Set of closest-point functions.
vgl_point_2d< T > vgl_closest_point_origin(vgl_line_2d< T > const &l)
Return the point on the given line closest to the origin.
int vgl_closest_point_to_non_closed_polygon(T &ret_x, T &ret_y, T const px[], T const py[], unsigned int n, T x, T y)
Closest point to (x,y) on open polygon (px[i],py[i]).
T b() const
Return y coefficient.
Definition: vgl_plane_3d.h:92
const double SMALL_DOUBLE
unsigned n_knots() const
a point in 3D nonhomogeneous space
line segment in 3D nonhomogeneous space
vgl_point_2d< T > vgl_closest_point(vgl_line_2d< T > const &l, vgl_point_2d< T > const &p)
Return the point on the given line closest to the given point.
A 3-d pointset.
bool closed() const
accessors.
int vgl_closest_point_to_closed_polygon(T &ret_x, T &ret_y, T const px[], T const py[], unsigned int n, T x, T y)
Closest point to (x,y) on closed polygon (px[i],py[i]).
bool has_normals() const
accessors.
T y() const
Definition: vgl_vector_3d.h:37
Type & y()
Definition: vgl_point_2d.h:72
vgl_point_3d< Type > point1() const
Return the first point representing this line.
Represents a Euclidean 3D plane.
Definition: vgl_fwd.h:23
Represents a 3D line segment using two points.
Definition: vgl_fwd.h:19
Represents a 3-d ray.
Definition: vgl_fwd.h:21
a sphere in 3D nonhomogeneous space
T x() const
Definition: vgl_vector_3d.h:36
point in projective 2D space
T d() const
Return constant coefficient.
Definition: vgl_plane_3d.h:98
T z() const
Definition: vgl_vector_3d.h:38
Type a() const
Return x coefficient.
vgl_point_3d< Type > origin() const
Accessors.
Definition: vgl_ray_3d.h:66
Type & x()
Definition: vgl_point_3d.h:71
Direction vector in Euclidean 3D space, templated by type of element.
Definition: vgl_fwd.h:13
#define DIST_SQR_TO_LINE_SEG_2D(T, x1, y1, x2, y2, x, y)
const vgl_point_3d< Type > & centre() const
Definition: vgl_sphere_3d.h:45
double vgl_distance(vgl_point_2d< T >const &p1, vgl_point_2d< T >const &p2)
return the distance between two points.
Definition: vgl_distance.h:104
#define l
vgl_homg_point_3d< Type > intersection(l const &l1, l const &l2)
Return the intersection point of two concurrent lines.
a plane in 3D nonhomogeneous space
double vgl_closest_point_t(vgl_line_3d_2_points< T > const &l, vgl_point_3d< T > const &p)
Return the point on the given line which is closest to the given point.
non-homogeneous 3D line, represented by 2 points.
vgl_vector_3d< Type > direction() const
Return the direction vector of this line (not normalised - but perhaps it should be,...
Set of distance functions.
Represents a homogeneous 2D point.
Definition: vgl_fwd.h:8
unsigned int num_sheets() const
Definition: vgl_polygon.h:116
Store a polygon.
Definition: vgl_area.h:6
vgl_homg_point_3d< Type > point_finite() const
Finite point (Could be an ideal point, if the whole line is at infinity.).
size_t npts() const
vgl_vector_3d< Type > direction() const
Definition: vgl_ray_3d.h:68
void spherical_to_cartesian(Type elevation_rad, Type azimuth_rad, Type &x, Type &y, Type &z) const
convert point on sphere to Cartesian coordinates, angles in radians.
T c() const
Return z coefficient.
Definition: vgl_plane_3d.h:95
Type & y()
Definition: vgl_point_3d.h:72
Type & x()
Definition: vgl_point_2d.h:71
std::pair< vgl_homg_point_3d< T >, vgl_homg_point_3d< T > > vgl_closest_points(vgl_homg_line_3d_2_points< T > const &line1, vgl_homg_line_3d_2_points< T > const &line2)
Return the two points of nearest approach of two 3D lines, one on each line.
vgl_vector_3d< Type > n(unsigned i) const
vgl_homg_point_3d< Type > point_infinite() const
Infinite point: the intersection of the line with the plane at infinity.
Represents a homogeneous 3D line using two points.
Definition: vgl_fwd.h:15