GteDistLine3Circle3.h
Go to the documentation of this file.
1 // David Eberly, Geometric Tools, Redmond WA 98052
2 // Copyright (c) 1998-2017
3 // Distributed under the Boost Software License, Version 1.0.
4 // http://www.boost.org/LICENSE_1_0.txt
5 // http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
6 // File Version: 3.0.0 (2016/06/19)
7 
8 #pragma once
9 
12 #include <Mathematics/GteCircle3.h>
13 #include <Mathematics/GteLine.h>
16 #include <algorithm>
17 
18 // The 3D line-circle distance algorithm is described in
19 // http://www.geometrictools.com/Documentation/DistanceToCircle3.pdf
20 // The notation used in the code matches that of the document.
21 
22 namespace gte
23 {
24 
25 template <typename Real>
26 class DCPQuery<Real, Line3<Real>, Circle3<Real>>
27 {
28 public:
29  // The possible number of closest line-circle pairs is 1, 2 or all circle
30  // points. If 1 or 2, numClosestPairs is set to this number and
31  // 'equidistant' is false; the number of valid elements in lineClosest[]
32  // and circleClosest[] is numClosestPairs. If all circle points are
33  // closest, the line must be C+t*N where C is the circle center, N is
34  // the normal to the plane of the circle, and lineClosest[0] is set to C.
35  // In this case, 'equidistant' is true and circleClosest[0] is set to
36  // C+r*U, where r is the circle radius and U is a vector perpendicular
37  // to N.
38  struct Result
39  {
42  Vector3<Real> lineClosest[2], circleClosest[2];
44  };
45 
46  // The polynomial-based algorithm. Type Real can be floating-point or
47  // rational.
48  Result operator()(Line3<Real> const& line, Circle3<Real> const& circle);
49 
50  // The nonpolynomial-based algorithm that uses bisection. Because the
51  // bisection is iterative, you should choose Real to be a floating-point
52  // type. However, the algorithm will still work for a rational type, but
53  // it is costly because of the increase in arbitrary-size integers used
54  // during the bisection.
55  Result Robust(Line3<Real> const& line, Circle3<Real> const& circle);
56 
57 private:
58  // Support for operator(...).
59  struct ClosestInfo
60  {
62  Vector3<Real> lineClosest, circleClosest;
64 
65  bool operator< (ClosestInfo const& info) const
66  {
67  return sqrDistance < info.sqrDistance;
68  }
69  };
70 
71  void GetPair(Line3<Real> const& line, Circle3<Real> const& circle,
72  Vector3<Real> const& D, Real t, Vector3<Real>& lineClosest,
73  Vector3<Real>& circleClosest);
74 
75  // Support for Robust(...). Bisect the function
76  // F(s) = s + m2b2 - r*m0sqr*s/sqrt(m0sqr*s*s + b1sqr)
77  // on the specified interval [smin,smax].
78  Real Bisect(Real m2b2, Real rm0sqr, Real m0sqr, Real b1sqr,
79  Real smin, Real smax);
80 };
81 
82 
83 template <typename Real>
86  Line3<Real> const& line, Circle3<Real> const& circle)
87 {
88  Result result;
89  Vector3<Real> const vzero = Vector3<Real>::Zero();
90  Real const zero = (Real)0;
91 
92  Vector3<Real> D = line.origin - circle.center;
93  Vector3<Real> NxM = Cross(circle.normal, line.direction);
94  Vector3<Real> NxD = Cross(circle.normal, D);
95  Real t;
96 
97  if (NxM != vzero)
98  {
99  if (NxD != vzero)
100  {
101  Real NdM = Dot(circle.normal, line.direction);
102  if (NdM != zero)
103  {
104  // H(t) = (a*t^2 + 2*b*t + c)*(t + d)^2 - r^2*(a*t + b)^2
105  // = h0 + h1*t + h2*t^2 + h3*t^3 + h4*t^4
106  Real a = Dot(NxM, NxM), b = Dot(NxM, NxD);
107  Real c = Dot(NxD, NxD), d = Dot(line.direction, D);
108  Real rsqr = circle.radius * circle.radius;
109  Real asqr = a * a, bsqr = b * b, dsqr = d * d;
110  Real h0 = c * dsqr - bsqr * rsqr;
111  Real h1 = 2 * (c * d + b * dsqr - a * b * rsqr);
112  Real h2 = c + 4 * b * d + a * dsqr - asqr * rsqr;
113  Real h3 = 2 * (b + a * d);
114  Real h4 = a;
115 
116  std::map<Real, int> rmMap;
117  RootsPolynomial<Real>::template SolveQuartic<Real>(
118  h0, h1, h2, h3, h4, rmMap);
119  std::array<ClosestInfo, 4> candidates;
120  int numRoots = 0;
121  for (auto const& rm : rmMap)
122  {
123  t = rm.first;
124  ClosestInfo info;
125  Vector3<Real> NxDelta = NxD + t * NxM;
126  if (NxDelta != vzero)
127  {
128  GetPair(line, circle, D,t, info.lineClosest,
129  info.circleClosest);
130  info.equidistant = false;
131  }
132  else
133  {
134  Vector3<Real> U = GetOrthogonal(circle.normal, true);
135  info.lineClosest = circle.center;
136  info.circleClosest =
137  circle.center + circle.radius * U;
138  info.equidistant = true;
139  }
140  Vector3<Real> diff = info.lineClosest - info.circleClosest;
141  info.sqrDistance = Dot(diff, diff);
142  candidates[numRoots++] = info;
143  }
144 
145  std::sort(candidates.begin(), candidates.begin() + numRoots);
146 
147  result.numClosestPairs = 1;
148  result.lineClosest[0] = candidates[0].lineClosest;
149  result.circleClosest[0] = candidates[0].circleClosest;
150  if (numRoots > 1
151  && candidates[1].sqrDistance == candidates[0].sqrDistance)
152  {
153  result.numClosestPairs = 2;
154  result.lineClosest[1] = candidates[1].lineClosest;
155  result.circleClosest[1] = candidates[1].circleClosest;
156  }
157  }
158  else
159  {
160  // The line is parallel to the plane of the circle. The
161  // polynomial has the form H(t) = (t+v)^2*[(t+v)^2-(r^2-u^2)].
162  Real u = Dot(NxM, D), v = Dot(line.direction, D);
163  Real discr = circle.radius * circle.radius - u * u;
164  if (discr > zero)
165  {
166  result.numClosestPairs = 2;
167  Real rootDiscr = Function<Real>::Sqrt(discr);
168  t = -v + rootDiscr;
169  GetPair(line, circle, D, t, result.lineClosest[0],
170  result.circleClosest[0]);
171  t = -v - rootDiscr;
172  GetPair(line, circle, D, t, result.lineClosest[1],
173  result.circleClosest[1]);
174  }
175  else
176  {
177  result.numClosestPairs = 1;
178  t = -v;
179  GetPair(line, circle, D, t, result.lineClosest[0],
180  result.circleClosest[0]);
181  }
182  }
183  }
184  else
185  {
186  // The line is C+t*M, where M is not parallel to N. The polynomial
187  // is H(t) = |Cross(N,M)|^2*t^2*(t^2 - r^2*|Cross(N,M)|^2), where
188  // root t = 0 does not correspond to the global minimum. The other
189  // roots produce the global minimum.
190  result.numClosestPairs = 2;
191  t = circle.radius * Length(NxM);
192  GetPair(line, circle, D, t, result.lineClosest[0],
193  result.circleClosest[0]);
194  t = -t;
195  GetPair(line, circle, D, t, result.lineClosest[1],
196  result.circleClosest[1]);
197  }
198  result.equidistant = false;
199  }
200  else
201  {
202  if (NxD != vzero)
203  {
204  // The line is A+t*N (perpendicular to plane) but with A != C.
205  // The polyhomial is H(t) = |Cross(N,D)|^2*(t + Dot(M,D))^2.
206  result.numClosestPairs = 1;
207  t = -Dot(line.direction, D);
208  GetPair(line, circle, D, t, result.lineClosest[0],
209  result.circleClosest[0]);
210  result.equidistant = false;
211  }
212  else
213  {
214  // The line is C+t*N, so C is the closest point for the line and
215  // all circle points are equidistant from it.
216  Vector3<Real> U = GetOrthogonal(circle.normal, true);
217  result.numClosestPairs = 1;
218  result.lineClosest[0] = circle.center;
219  result.circleClosest[0] = circle.center + circle.radius * U;
220  result.equidistant = true;
221  }
222  }
223 
224  Vector3<Real> diff = result.lineClosest[0] - result.circleClosest[0];
225  result.sqrDistance = Dot(diff, diff);
226  result.distance = Function<Real>::Sqrt(result.sqrDistance);
227  return result;
228 }
229 
230 template <typename Real>
231 typename DCPQuery<Real, Line3<Real>, Circle3<Real>>::Result
233  Line3<Real> const& line, Circle3<Real> const& circle)
234 {
235  // The line is P(t) = B+t*M. The circle is |X-C| = r with Dot(N,X-C)=0.
236  Result result;
238  Real const zero = (Real)0;
239 
240  Vector3<Real> D = line.origin - circle.center;
241  Vector3<Real> MxN = Cross(line.direction, circle.normal);
242  Vector3<Real> DxN = Cross(D, circle.normal);
243 
244  Real m0sqr = Dot(MxN, MxN);
245  if (m0sqr > zero)
246  {
247  // Compute the critical points s for F'(s) = 0.
248  Vector3<Real> P0, P1;
249  Real s, t;
250  int numRoots = 0;
251  std::array<Real, 3> roots;
252 
253  // The line direction M and the plane normal N are not parallel. Move
254  // the line origin B = (b0,b1,b2) to B' = B + lambda*line.direction =
255  // (0,b1',b2').
256  Real m0 = Function<Real>::Sqrt(m0sqr);
257  Real rm0 = circle.radius * m0;
258  Real lambda = -Dot(MxN, DxN) / m0sqr;
259  Vector3<Real> oldD = D;
260  D += lambda * line.direction;
261  DxN += lambda * MxN;
262  Real m2b2 = Dot(line.direction, D);
263  Real b1sqr = Dot(DxN, DxN);
264  if (b1sqr > zero)
265  {
266  // B' = (0,b1',b2') where b1' != 0. See Sections 1.1.2 and 1.2.2
267  // of the PDF documentation.
268  Real b1 = Function<Real>::Sqrt(b1sqr);
269  Real rm0sqr = circle.radius * m0sqr;
270  if (rm0sqr > b1)
271  {
272  Real const twoThirds = (Real)2 / (Real)3;
274  rm0sqr * b1sqr, twoThirds) - b1sqr) / m0;
275  Real gHat = rm0sqr * sHat / Function<Real>::Sqrt(
276  m0sqr * sHat * sHat + b1sqr);
277  Real cutoff = gHat - sHat;
278  if (m2b2 <= -cutoff)
279  {
280  s = Bisect(m2b2, rm0sqr, m0sqr, b1sqr, -m2b2,
281  -m2b2 + rm0);
282  roots[numRoots++] = s;
283  if (m2b2 == -cutoff)
284  {
285  roots[numRoots++] = -sHat;
286  }
287  }
288  else if (m2b2 >= cutoff)
289  {
290  s = Bisect(m2b2, rm0sqr, m0sqr, b1sqr, -m2b2 - rm0,
291  -m2b2);
292  roots[numRoots++] = s;
293  if (m2b2 == cutoff)
294  {
295  roots[numRoots++] = sHat;
296  }
297  }
298  else
299  {
300  if (m2b2 <= zero)
301  {
302  s = Bisect(m2b2, rm0sqr, m0sqr, b1sqr, -m2b2,
303  -m2b2 + rm0);
304  roots[numRoots++] = s;
305  s = Bisect(m2b2, rm0sqr, m0sqr, b1sqr, -m2b2 - rm0,
306  -sHat);
307  roots[numRoots++] = s;
308  }
309  else
310  {
311  s = Bisect(m2b2, rm0sqr, m0sqr, b1sqr, -m2b2 - rm0,
312  -m2b2);
313  roots[numRoots++] = s;
314  s = Bisect(m2b2, rm0sqr, m0sqr, b1sqr, sHat,
315  -m2b2 + rm0);
316  roots[numRoots++] = s;
317  }
318  }
319  }
320  else
321  {
322  if (m2b2 < zero)
323  {
324  s = Bisect(m2b2, rm0sqr, m0sqr, b1sqr, -m2b2,
325  -m2b2 + rm0);
326  }
327  else if (m2b2 > zero)
328  {
329  s = Bisect(m2b2, rm0sqr, m0sqr, b1sqr, -m2b2 - rm0,
330  -m2b2);
331  }
332  else
333  {
334  s = zero;
335  }
336  roots[numRoots++] = s;
337  }
338  }
339  else
340  {
341  // The new line origin is B' = (0,0,b2').
342  if (m2b2 < zero)
343  {
344  s = -m2b2 + rm0;
345  roots[numRoots++] = s;
346  }
347  else if (m2b2 > zero)
348  {
349  s = -m2b2 - rm0;
350  roots[numRoots++] = s;
351  }
352  else
353  {
354  s = -m2b2 + rm0;
355  roots[numRoots++] = s;
356  s = -m2b2 - rm0;
357  roots[numRoots++] = s;
358  }
359  }
360 
361  std::array<ClosestInfo, 4> candidates;
362  for (int i = 0; i < numRoots; ++i)
363  {
364  t = roots[i] + lambda;
365  ClosestInfo info;
366  Vector3<Real> NxDelta =
367  Cross(circle.normal, oldD + t * line.direction);
368  if (NxDelta != vzero)
369  {
370  GetPair(line, circle, oldD, t, info.lineClosest,
371  info.circleClosest);
372  info.equidistant = false;
373  }
374  else
375  {
376  Vector3<Real> U = GetOrthogonal(circle.normal, true);
377  info.lineClosest = circle.center;
378  info.circleClosest = circle.center + circle.radius * U;
379  info.equidistant = true;
380  }
381  Vector3<Real> diff = info.lineClosest - info.circleClosest;
382  info.sqrDistance = Dot(diff, diff);
383  candidates[i] = info;
384  }
385 
386  std::sort(candidates.begin(), candidates.begin() + numRoots);
387 
388  result.numClosestPairs = 1;
389  result.lineClosest[0] = candidates[0].lineClosest;
390  result.circleClosest[0] = candidates[0].circleClosest;
391  if (numRoots > 1
392  && candidates[1].sqrDistance == candidates[0].sqrDistance)
393  {
394  result.numClosestPairs = 2;
395  result.lineClosest[1] = candidates[1].lineClosest;
396  result.circleClosest[1] = candidates[1].circleClosest;
397  }
398 
399  result.equidistant = false;
400  }
401  else
402  {
403  // The line direction and the plane normal are parallel.
404  if (DxN != vzero)
405  {
406  // The line is A+t*N but with A != C.
407  result.numClosestPairs = 1;
408  GetPair(line, circle, D, -Dot(line.direction, D),
409  result.lineClosest[0], result.circleClosest[0]);
410  result.equidistant = false;
411  }
412  else
413  {
414  // The line is C+t*N, so C is the closest point for the line and
415  // all circle points are equidistant from it.
416  Vector3<Real> U = GetOrthogonal(circle.normal, true);
417  result.numClosestPairs = 1;
418  result.lineClosest[0] = circle.center;
419  result.circleClosest[0] = circle.center + circle.radius * U;
420  result.equidistant = true;
421  }
422  }
423 
424  Vector3<Real> diff = result.lineClosest[0] - result.circleClosest[0];
425  result.sqrDistance = Dot(diff, diff);
426  result.distance = Function<Real>::Sqrt(result.sqrDistance);
427  return result;
428 }
429 
430 template <typename Real>
432  Line3<Real> const& line, Circle3<Real> const& circle,
433  Vector3<Real> const& D, Real t, Vector3<Real>& lineClosest,
434  Vector3<Real>& circleClosest)
435 {
436  Vector3<Real> delta = D + t * line.direction;
437  lineClosest = circle.center + delta;
438  delta -= Dot(circle.normal, delta) * circle.normal;
439  Normalize(delta);
440  circleClosest = circle.center + circle.radius * delta;
441 }
442 
443 template <typename Real>
444 Real DCPQuery<Real, Line3<Real>, Circle3<Real>>::Bisect(Real m2b2,
445  Real rm0sqr, Real m0sqr, Real b1sqr, Real smin, Real smax)
446 {
447  std::function<Real(Real)> G = [&, m2b2, rm0sqr, m0sqr, b1sqr](Real s)
448  {
449  return s + m2b2 - rm0sqr*s / Function<Real>::Sqrt(m0sqr*s*s + b1sqr);
450  };
451 
452  // The function is known to be increasing, so we can specify -1 and +1
453  // as the function values at the bounding interval endpoints. The use
454  // of 'double' is intentional in case Real is a BSNumber or BSRational
455  // type. We want the bisections to terminate in a reasonable amount of
456  // time.
457  unsigned int const maxIterations = Function<double>::GetMaxBisections();
458  Real root;
459  RootsBisection<Real>::Find(G, smin, smax, (Real)-1, (Real)+1,
460  maxIterations, root);
461  Real gmin;
462  gmin = G(root);
463  return root;
464 }
465 
466 
467 }
static unsigned int GetMaxBisections()
Vector3< Real > normal
Definition: GteCircle3.h:31
GLsizei GLsizei GLfloat distance
Definition: glext.h:9704
static Real Sqrt(Real const &x)
Definition: GteFunctions.h:937
Vector< N, Real > direction
Definition: GteLine.h:29
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1217
Vector< N, Real > GetOrthogonal(Vector< N, Real > const &v, bool unitLength)
Definition: GteVector.h:574
const GLubyte * c
Definition: glext.h:11671
Result operator()(Type0 const &primitive0, Type1 const &primitive1)
static Vector Zero()
Definition: GteVector.h:295
DualQuaternion< Real > Dot(DualQuaternion< Real > const &d0, DualQuaternion< Real > const &d1)
Real Normalize(GVector< Real > &v, bool robust=false)
Definition: GteGVector.h:454
GLdouble GLdouble t
Definition: glext.h:239
DualQuaternion< Real > Cross(DualQuaternion< Real > const &d0, DualQuaternion< Real > const &d1)
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1217
DualQuaternion< Real > Length(DualQuaternion< Real > const &d, bool robust=false)
const GLdouble * v
Definition: glcorearb.h:832
GLdouble s
Definition: glext.h:231
Vector< N, Real > origin
Definition: GteLine.h:29
Vector3< Real > center
Definition: GteCircle3.h:31
GLuint64EXT * result
Definition: glext.h:10003
static unsigned int Find(std::function< Real(Real)> const &F, Real t0, Real t1, unsigned int maxIterations, Real &root)


geometric_tools_engine
Author(s): Yijiang Huang
autogenerated on Thu Jul 18 2019 03:59:59