GteDistCircle3Circle3.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 
10 #include <LowLevel/GteLogger.h>
14 #include <Mathematics/GteCircle3.h>
16 
17 // The 3D circle-circle distance algorithm is described in
18 // http://www.geometrictools.com/Documentation/DistanceToCircle3.pdf
19 // The notation used in the code matches that of the document.
20 
21 namespace gte
22 {
23 
24 template <typename Real>
25 class DCPQuery<Real, Circle3<Real>, Circle3<Real>>
26 {
27 public:
28  struct Result
29  {
32  Vector3<Real> circle0Closest[2], circle1Closest[2];
34  };
35 
36  Result operator()(Circle3<Real> const& circle0,
37  Circle3<Real> const& circle1);
38 
39 private:
40  class SCPolynomial
41  {
42  public:
43  SCPolynomial();
44  SCPolynomial(Real oneTerm, Real cosTerm, Real sinTerm);
45 
46  inline Polynomial1<Real> const& operator[] (unsigned int i) const;
47  inline Polynomial1<Real>& operator[] (unsigned int i);
48 
49  SCPolynomial operator+(SCPolynomial const& object) const;
50  SCPolynomial operator-(SCPolynomial const& object) const;
51  SCPolynomial operator*(SCPolynomial const& object) const;
52  SCPolynomial operator*(Real scalar) const;
53 
54  private:
55  Polynomial1<Real> mPoly[2]; // poly0(c) + s * poly1(c)
56  };
57 
58  struct ClosestInfo
59  {
61  Vector3<Real> circle0Closest, circle1Closest;
63 
64  bool operator< (ClosestInfo const& info) const
65  {
66  return sqrDistance < info.sqrDistance;
67  }
68  };
69 
70  // The two circles are in parallel planes where D = C1 - C0, the
71  // difference of circle centers.
72  void DoQueryParallelPlanes(Circle3<Real> const& circle0,
73  Circle3<Real> const& circle1, Vector3<Real> const& D, Result& result);
74 };
75 
76 
77 template <typename Real>
80  Circle3<Real> const& circle0, Circle3<Real> const& circle1)
81 {
82  Result result;
83  Vector3<Real> const vzero = Vector3<Real>::Zero();
84  Real const zero = (Real)0;
85 
86  Vector3<Real> N0 = circle0.normal, N1 = circle1.normal;
87  Real r0 = circle0.radius, r1 = circle1.radius;
88  Vector3<Real> D = circle1.center - circle0.center;
89  Vector3<Real> N0xN1 = Cross(N0, N1);
90 
91  if (N0xN1 != vzero)
92  {
93  // Get parameters for constructing the degree-8 polynomial phi.
94  Real const one = (Real)1, two = (Real)2;
95  Real r0sqr = r0 * r0, r1sqr = r1 * r1;
96 
97  // Compute U1 and V1 for the plane of circle1.
98  Vector3<Real> basis[3];
99  basis[0] = circle1.normal;
100  ComputeOrthogonalComplement(1, basis);
101  Vector3<Real> U1 = basis[1], V1 = basis[2];
102 
103  // Construct the polynomial phi(cos(theta)).
104  Vector3<Real> N0xD = Cross(N0, D);
105  Vector3<Real> N0xU1 = Cross(N0, U1), N0xV1 = Cross(N0, V1);
106  Real a0 = r1 * Dot(D, U1), a1 = r1 * Dot(D, V1);
107  Real a2 = Dot(N0xD, N0xD), a3 = r1 * Dot(N0xD, N0xU1);
108  Real a4 = r1 * Dot(N0xD, N0xV1), a5 = r1sqr * Dot(N0xU1, N0xU1);
109  Real a6 = r1sqr * Dot(N0xU1, N0xV1), a7 = r1sqr * Dot(N0xV1, N0xV1);
110  Polynomial1<Real> p0{ a2 + a7, two * a3, a5 - a7 };
111  Polynomial1<Real> p1{ two * a4, two * a6 };
112  Polynomial1<Real> p2{ zero, a1 };
113  Polynomial1<Real> p3{ -a0 };
114  Polynomial1<Real> p4{ -a6, a4, two * a6 };
115  Polynomial1<Real> p5{ -a3, a7 - a5 };
116  Polynomial1<Real> tmp0{ one, zero, -one };
117  Polynomial1<Real> tmp1 = p2 * p2 + tmp0 * p3 * p3;
118  Polynomial1<Real> tmp2 = two * p2 * p3;
119  Polynomial1<Real> tmp3 = p4 * p4 + tmp0 * p5 * p5;
120  Polynomial1<Real> tmp4 = two * p4 * p5;
121  Polynomial1<Real> p6 = p0 * tmp1 + tmp0 * p1 * tmp2 - r0sqr * tmp3;
122  Polynomial1<Real> p7 = p0 * tmp2 + p1 * tmp1 - r0sqr * tmp4;
123 
124  // The use of 'double' is intentional in case Real is a BSNumber or
125  // BSRational type. We want the bisections to terminate in a
126  // reasonable amount of time.
127  unsigned int const maxIterations =
129  Real roots[8], sn, temp;
130  int i, degree, numRoots;
131 
132  // The RootsPolynomial<Real>::Find(...) function currently does not
133  // combine duplicate roots. We need only the unique ones here.
134  std::set<Real> uniqueRoots;
135 
136  std::array<std::pair<Real, Real>, 16> pairs;
137  int numPairs = 0;
138  if (p7.GetDegree() > 0 || p7[0] != zero)
139  {
140  // H(cs,sn) = p6(cs) + sn * p7(cs)
141  Polynomial1<Real> phi = p6 * p6 - tmp0 * p7 * p7;
142  degree = static_cast<int>(phi.GetDegree());
143  LogAssert(degree > 0, "Unexpected degree for phi.");
144  numRoots = RootsPolynomial<Real>::Find(degree, &phi[0],
145  maxIterations, roots);
146  for (i = 0; i < numRoots; ++i)
147  {
148  uniqueRoots.insert(roots[i]);
149  }
150 
151  for (auto cs : uniqueRoots)
152  {
153  if (std::abs(cs) <= one)
154  {
155  temp = p7(cs);
156  if (temp != zero)
157  {
158  sn = -p6(cs) / temp;
159  pairs[numPairs++] = std::make_pair(cs, sn);
160  }
161  else
162  {
163  temp = std::max(one - cs * cs, zero);
164  sn = Function<Real>::Sqrt(temp);
165  pairs[numPairs++] = std::make_pair(cs, sn);
166  if (sn != zero)
167  {
168  pairs[numPairs++] = std::make_pair(cs, -sn);
169  }
170  }
171  }
172  }
173  }
174  else
175  {
176  // H(cs,sn) = p6(cs)
177  degree = static_cast<int>(p6.GetDegree());
178  LogAssert(degree > 0, "Unexpected degree for p6.");
179  numRoots = RootsPolynomial<Real>::Find(degree, &p6[0],
180  maxIterations, roots);
181  for (i = 0; i < numRoots; ++i)
182  {
183  uniqueRoots.insert(roots[i]);
184  }
185 
186  for (auto cs : uniqueRoots)
187  {
188  if (std::abs(cs) <= one)
189  {
190  temp = std::max(one - cs * cs, zero);
191  sn = Function<Real>::Sqrt(temp);
192  pairs[numPairs++] = std::make_pair(cs, sn);
193  if (sn != zero)
194  {
195  pairs[numPairs++] = std::make_pair(cs, -sn);
196  }
197  }
198  }
199  }
200 
201  std::array<ClosestInfo, 16> candidates;
202  for (i = 0; i < numPairs; ++i)
203  {
204  ClosestInfo& info = candidates[i];
205  Vector3<Real> delta =
206  D + r1 * (pairs[i].first * U1 + pairs[i].second * V1);
207  info.circle1Closest = circle0.center + delta;
208  Real N0dDelta = Dot(N0, delta);
209  Real lenN0xDelta = Length(Cross(N0, delta));
210  if (lenN0xDelta > 0)
211  {
212  Real diff = lenN0xDelta - r0;
213  info.sqrDistance = N0dDelta * N0dDelta + diff * diff;
214  delta -= N0dDelta * circle0.normal;
215  Normalize(delta);
216  info.circle0Closest = circle0.center + r0 * delta;
217  info.equidistant = false;
218  }
219  else
220  {
221  Vector3<Real> r0U0 = r0 * GetOrthogonal(N0, true);
222  Vector3<Real> diff = delta - r0U0;
223  info.sqrDistance = Dot(diff, diff);
224  info.circle0Closest = circle0.center + r0U0;
225  info.equidistant = true;
226  }
227  }
228 
229  std::sort(candidates.begin(), candidates.begin() + numPairs);
230 
231  result.numClosestPairs = 1;
232  result.sqrDistance = candidates[0].sqrDistance;
233  result.circle0Closest[0] = candidates[0].circle0Closest;
234  result.circle1Closest[0] = candidates[0].circle1Closest;
235  result.equidistant = candidates[0].equidistant;
236  if (numRoots > 1
237  && candidates[1].sqrDistance == candidates[0].sqrDistance)
238  {
239  result.numClosestPairs = 2;
240  result.circle0Closest[1] = candidates[1].circle0Closest;
241  result.circle1Closest[1] = candidates[1].circle1Closest;
242  }
243  }
244  else
245  {
246  // The planes of the circles are parallel. Whether the planes are the
247  // same or different, the problem reduces to determining how two
248  // circles in the same plane are separated, tangent with one circle
249  // outside the other, overlapping, or one circle contained inside the
250  // other circle.
251  DoQueryParallelPlanes(circle0, circle1, D, result);
252  }
253 
254  result.distance = Function<Real>::Sqrt(result.sqrDistance);
255  return result;
256 }
257 
258 template <typename Real>
259 void DCPQuery<Real, Circle3<Real>, Circle3<Real>>::DoQueryParallelPlanes(
260  Circle3<Real> const& circle0, Circle3<Real> const& circle1,
261  Vector3<Real> const& D, Result& result)
262 {
263  Real N0dD = Dot(circle0.normal, D);
264  Vector3<Real> normProj = N0dD * circle0.normal;
265  Vector3<Real> compProj = D - normProj;
266  Vector3<Real> U = compProj;
267  Real d = Normalize(U);
268 
269  // The configuration is determined by the relative location of the
270  // intervals of projection of the circles on to the D-line. Circle0
271  // projects to [-r0,r0] and circle1 projects to [d-r1,d+r1].
272  Real r0 = circle0.radius, r1 = circle1.radius;
273  Real dmr1 = d - r1;
274  Real distance;
275  if (dmr1 >= r0) // d >= r0 + r1
276  {
277  // The circles are separated (d > r0 + r1) or tangent with one
278  // outside the other (d = r0 + r1).
279  distance = dmr1 - r0;
280  result.numClosestPairs = 1;
281  result.circle0Closest[0] = circle0.center + r0 * U;
282  result.circle1Closest[0] = circle1.center - r1 * U;
283  result.equidistant = false;
284  }
285  else // d < r0 + r1
286  {
287  // The cases implicitly use the knowledge that d >= 0.
288  Real dpr1 = d + r1;
289  if (dpr1 <= r0)
290  {
291  // Circle1 is inside circle0.
292  distance = r0 - dpr1;
293  result.numClosestPairs = 1;
294  if (d > (Real)0)
295  {
296  result.circle0Closest[0] = circle0.center + r0 * U;
297  result.circle1Closest[0] = circle1.center + r1 * U;
298  result.equidistant = false;
299  }
300  else
301  {
302  // The circles are concentric, so U = (0,0,0). Construct
303  // a vector perpendicular to N0 to use for closest points.
304  U = GetOrthogonal(circle0.normal, true);
305  result.circle0Closest[0] = circle0.center + r0 * U;
306  result.circle1Closest[0] = circle1.center + r1 * U;
307  result.equidistant = true;
308  }
309  }
310  else if (dmr1 <= -r0)
311  {
312  // Circle0 is inside circle1.
313  distance = -r0 - dmr1;
314  result.numClosestPairs = 1;
315  if (d > (Real)0)
316  {
317  result.circle0Closest[0] = circle0.center - r0 * U;
318  result.circle1Closest[0] = circle1.center - r1 * U;
319  result.equidistant = false;
320  }
321  else
322  {
323  // The circles are concentric, so U = (0,0,0). Construct
324  // a vector perpendicular to N0 to use for closest points.
325  U = GetOrthogonal(circle0.normal, true);
326  result.circle0Closest[0] = circle0.center + r0 * U;
327  result.circle1Closest[0] = circle1.center + r1 * U;
328  result.equidistant = true;
329  }
330  }
331  else
332  {
333  // The circles are overlapping. The two points of intersection
334  // are C0 + s*(C1-C0) +/- h*Cross(N,U), where
335  // s = (1 + (r0^2 - r1^2)/d^2)/2 and h = sqrt(r0^2 - s^2 * d^2).
336  Real r0sqr = r0 * r0, r1sqr = r1 * r1, dsqr = d * d;
337  Real s = ((Real)1 + (r0sqr - r1sqr) / dsqr) / (Real)2;
338  Real arg = std::max(r0sqr - dsqr * s * s, (Real)0);
339  Real h = Function<Real>::Sqrt(arg);
340  Vector3<Real> midpoint = circle0.center + s * compProj;
341  Vector3<Real> hNxU = h * Cross(circle0.normal, U);
342  distance = (Real)0;
343  result.numClosestPairs = 2;
344  result.circle0Closest[0] = midpoint + hNxU;
345  result.circle0Closest[1] = midpoint - hNxU;
346  result.circle1Closest[0] = result.circle0Closest[0] + normProj;
347  result.circle1Closest[1] = result.circle0Closest[1] + normProj;
348  result.equidistant = false;
349  }
350  }
351 
352  result.sqrDistance = distance * distance + N0dD * N0dD;
353 }
354 
355 template <typename Real>
356 DCPQuery<Real, Circle3<Real>, Circle3<Real>>::SCPolynomial::SCPolynomial()
357 {
358 }
359 
360 template <typename Real>
361 DCPQuery<Real, Circle3<Real>, Circle3<Real>>::SCPolynomial::SCPolynomial(
362  Real oneTerm, Real cosTerm, Real sinTerm)
363 {
364  mPoly[0] = Polynomial1<Real>{oneTerm, cosTerm};
365  mPoly[1] = Polynomial1<Real>{sinTerm};
366 }
367 
368 template <typename Real> inline
369  Polynomial1<Real> const&
370  DCPQuery<Real, Circle3<Real>, Circle3<Real>>::SCPolynomial::operator[] (
371  unsigned int i) const
372 {
373  return mPoly[i];
374 }
375 
376 template <typename Real> inline
378  DCPQuery<Real, Circle3<Real>, Circle3<Real>>::SCPolynomial::operator[] (
379  unsigned int i)
380 {
381  return mPoly[i];
382 }
383 
384 template <typename Real>
385 typename DCPQuery<Real, Circle3<Real>, Circle3<Real>>::SCPolynomial
386  DCPQuery<Real, Circle3<Real>, Circle3<Real>>::SCPolynomial::operator+(
387  SCPolynomial const& object) const
388 {
389  SCPolynomial result;
390  result.mPoly[0] = mPoly[0] + object.mPoly[0];
391  result.mPoly[1] = mPoly[1] + object.mPoly[1];
392  return result;
393 }
394 
395 template <typename Real>
396 typename DCPQuery<Real, Circle3<Real>, Circle3<Real>>::SCPolynomial
397  DCPQuery<Real, Circle3<Real>, Circle3<Real>>::SCPolynomial::operator-(
398  SCPolynomial const& object) const
399 {
400  SCPolynomial result;
401  result.mPoly[0] = mPoly[0] - object.mPoly[0];
402  result.mPoly[1] = mPoly[1] - object.mPoly[1];
403  return result;
404 }
405 
406 template <typename Real>
407 typename DCPQuery<Real, Circle3<Real>, Circle3<Real>>::SCPolynomial
408  DCPQuery<Real, Circle3<Real>, Circle3<Real>>::SCPolynomial::operator*(
409  SCPolynomial const& object) const
410 {
411  Polynomial1<Real> omcsqr{ (Real)1, (Real)0, (Real)-1 }; // 1 - c^2
412  SCPolynomial result;
413  result.mPoly[0] = mPoly[0] * object.mPoly[0] +
414  omcsqr * mPoly[1] * object.mPoly[1];
415  result.mPoly[1] = mPoly[0] * object.mPoly[1] + mPoly[1] * object.mPoly[0];
416  return result;
417 }
418 
419 template <typename Real>
420 typename DCPQuery<Real, Circle3<Real>, Circle3<Real>>::SCPolynomial
421  DCPQuery<Real, Circle3<Real>, Circle3<Real>>::SCPolynomial::operator*(
422  Real scalar) const
423 {
424  SCPolynomial result;
425  result.mPoly[0] = scalar * mPoly[0];
426  result.mPoly[1] = scalar * mPoly[1];
427  return result;
428 }
429 
430 
431 }
unsigned int GetDegree() const
gte::BSNumber< UIntegerType > abs(gte::BSNumber< UIntegerType > const &number)
Definition: GteBSNumber.h:966
#define LogAssert(condition, message)
Definition: GteLogger.h:86
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 > GetOrthogonal(Vector< N, Real > const &v, bool unitLength)
Definition: GteVector.h:574
Result operator()(Type0 const &primitive0, Type1 const &primitive1)
DualQuaternion< Real > operator+(DualQuaternion< Real > const &d)
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
DualQuaternion< Real > Cross(DualQuaternion< Real > const &d0, DualQuaternion< Real > const &d1)
GLfloat GLfloat GLfloat GLfloat h
Definition: glcorearb.h:1997
DualQuaternion< Real > Length(DualQuaternion< Real > const &d, bool robust=false)
GLdouble s
Definition: glext.h:231
DualQuaternion< Real > operator-(DualQuaternion< Real > const &d)
Real ComputeOrthogonalComplement(int numInputs, Vector2< Real > *v, bool robust=false)
Definition: GteVector2.h:123
Vector3< Real > center
Definition: GteCircle3.h:31
GLuint object
Definition: glext.h:6426
Vector4< float > operator*(Transform const &M, Vector4< float > const &V)
GLuint64EXT * result
Definition: glext.h:10003
static int Find(int degree, Real const *c, unsigned int maxIterations, Real *roots)


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