GteIntrEllipsoid3Ellipsoid3.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>
13 #include <Mathematics/GteFIQuery.h>
14 #include <Mathematics/GteTIQuery.h>
18 
19 namespace gte
20 {
21 
22 template <typename Real>
23 class TIQuery<Real, Ellipsoid3<Real>, Ellipsoid3<Real>>
24 {
25 public:
26  enum
27  {
31  ELLIPSOID1_CONTAINS_ELLIPSOID0
32  };
33 
34  struct Result
35  {
36  // As solids, the ellipsoids intersect as long as they are not
37  // separated.
38  bool intersect;
39 
40  // This is one of the four enumerations listed above.
42  };
43 
44  Result operator()(Ellipsoid3<Real> const& ellipsoid0,
45  Ellipsoid3<Real> const& ellipsoid1);
46 
47 private:
48  void GetRoots(Real d0, Real c0, int& numRoots, Real* roots);
49  void GetRoots(Real d0, Real d1, Real c0, Real c1, int& numRoots,
50  Real* roots);
51  void GetRoots(Real d0, Real d1, Real d2, Real c0, Real c1, Real c2,
52  int& numRoots, Real* roots);
53 };
54 
55 
56 template <typename Real>
59  Ellipsoid3<Real> const& ellipsoid0, Ellipsoid3<Real> const& ellipsoid1)
60 {
61  Result result;
62 
63  Real const zero = (Real)0;
64  Real const one = (Real)1;
65 
66  // Get the parameters of ellipsoid0.
67  Vector3<Real> K0 = ellipsoid0.center;
68  Matrix3x3<Real> R0;
69  R0.SetCol(0, ellipsoid0.axis[0]);
70  R0.SetCol(1, ellipsoid0.axis[1]);
71  R0.SetCol(2, ellipsoid0.axis[2]);
72  Matrix3x3<Real> D0{
73  one / (ellipsoid0.extent[0] * ellipsoid0.extent[0]),
74  one / (ellipsoid0.extent[1] * ellipsoid0.extent[1]),
75  one / (ellipsoid0.extent[2] * ellipsoid0.extent[2]) };
76 
77  // Get the parameters of ellipsoid1.
78  Vector3<Real> K1 = ellipsoid1.center;
79  Matrix3x3<Real> R1;
80  R1.SetCol(0, ellipsoid1.axis[0]);
81  R1.SetCol(1, ellipsoid1.axis[1]);
82  R1.SetCol(2, ellipsoid1.axis[2]);
83  Matrix3x3<Real> D1{
84  one / (ellipsoid1.extent[0] * ellipsoid1.extent[0]),
85  one / (ellipsoid1.extent[1] * ellipsoid1.extent[1]),
86  one / (ellipsoid1.extent[2] * ellipsoid1.extent[2]) };
87 
88  // Compute K2.
89  Matrix3x3<Real> D0NegHalf{
90  ellipsoid0.extent[0],
91  ellipsoid0.extent[1],
92  ellipsoid0.extent[2] };
93  Matrix3x3<Real> D0Half{
94  one / ellipsoid0.extent[0],
95  one / ellipsoid0.extent[1],
96  one / ellipsoid0.extent[2] };
97  Vector3<Real> K2 = D0Half*((K1 - K0)*R0);
98 
99  // Compute M2.
100  Matrix3x3<Real> R1TR0D0NegHalf = MultiplyATB(R1, R0*D0NegHalf);
101  Matrix3x3<Real> M2 = MultiplyATB(R1TR0D0NegHalf, D1)*R1TR0D0NegHalf;
102 
103  // Factor M2 = R*D*R^T.
105  std::array<Real, 3> D;
106  std::array<std::array<Real, 3>, 3> evec;
107  es(M2(0, 0), M2(0, 1), M2(0, 2), M2(1, 1), M2(1, 2), M2(2, 2), false, +1,
108  D, evec);
109  Matrix3x3<Real> R;
110  R.SetCol(0, evec[0]);
111  R.SetCol(1, evec[1]);
112  R.SetCol(2, evec[2]);
113 
114  // Compute K = R^T*K2.
115  Vector3<Real> K = K2*R;
116 
117  // Transformed ellipsoid0 is Z^T*Z = 1 and transformed ellipsoid1 is
118  // (Z-K)^T*D*(Z-K) = 0.
119 
120  // The minimum and maximum squared distances from the origin of points on
121  // transformed ellipsoid1 are used to determine whether the ellipsoids
122  // intersect, are separated, or one contains the other.
123  Real minSqrDistance = std::numeric_limits<Real>::max();
124  Real maxSqrDistance = zero;
125  int i;
126 
127  if (K == Vector3<Real>::Zero())
128  {
129  // The special case of common centers must be handled separately. It
130  // is not possible for the ellipsoids to be separated.
131  for (i = 0; i < 3; ++i)
132  {
133  Real invD = one / D[i];
134  if (invD < minSqrDistance)
135  {
136  minSqrDistance = invD;
137  }
138  if (invD > maxSqrDistance)
139  {
140  maxSqrDistance = invD;
141  }
142  }
143 
144  if (maxSqrDistance < one)
145  {
146  result.relationship = ELLIPSOID0_CONTAINS_ELLIPSOID1;
147  }
148  else if (minSqrDistance >(Real)1)
149  {
150  result.relationship = ELLIPSOID1_CONTAINS_ELLIPSOID0;
151  }
152  else
153  {
154  result.relationship = ELLIPSOIDS_INTERSECTING;
155  }
156  result.intersect = true;
157  return result;
158  }
159 
160  // The closest point P0 and farthest point P1 are solutions to
161  // s0*D*(P0 - K) = P0 and s1*D*(P1 - K) = P1 for some scalars s0 and s1
162  // that are roots to the function
163  // f(s) = d0*k0^2/(d0*s-1)^2+d1*k1^2/(d1*s-1)^2+d2*k2^2/(d2*s-1)^2-1
164  // where D = diagonal(d0,d1,d2) and K = (k0,k1,k2).
165  Real d0 = D[0], d1 = D[1], d2 = D[2];
166  Real c0 = K[0] * K[0], c1 = K[1] * K[1], c2 = K[2] * K[2];
167 
168  // Sort the values so that d0 >= d1 >= d2. This allows us to bound the
169  // roots of f(s), of which there are at most 6.
170  std::vector<std::pair<Real, Real>> param(3);
171  param[0] = std::make_pair(d0, c0);
172  param[1] = std::make_pair(d1, c1);
173  param[2] = std::make_pair(d2, c2);
174  std::sort(param.begin(), param.end(),
175  std::greater<std::pair<Real, Real>>());
176 
177  std::vector<std::pair<Real, Real>> valid;
178  valid.reserve(3);
179  if (param[0].first > param[1].first)
180  {
181  if (param[1].first > param[2].first)
182  {
183  // d0 > d1 > d2
184  for (i = 0; i < 3; ++i)
185  {
186  if (param[i].second >(Real)0)
187  {
188  valid.push_back(param[i]);
189  }
190  }
191  }
192  else
193  {
194  // d0 > d1 = d2
195  if (param[0].second > (Real)0)
196  {
197  valid.push_back(param[0]);
198  }
199  param[1].second += param[0].second;
200  if (param[1].second > (Real)0)
201  {
202  valid.push_back(param[1]);
203  }
204  }
205  }
206  else
207  {
208  if (param[1].first > param[2].first)
209  {
210  // d0 = d1 > d2
211  param[0].second += param[1].second;
212  if (param[0].second > (Real)0)
213  {
214  valid.push_back(param[0]);
215  }
216  if (param[2].second > (Real)0)
217  {
218  valid.push_back(param[2]);
219  }
220  }
221  else
222  {
223  // d0 = d1 = d2
224  param[0].second += param[1].second + param[2].second;
225  if (param[0].second > (Real)0)
226  {
227  valid.push_back(param[0]);
228  }
229  }
230  }
231 
232  size_t numValid = valid.size();
233  int numRoots;
234  Real roots[6];
235  if (numValid == 3)
236  {
237  GetRoots(valid[0].first, valid[1].first, valid[2].first,
238  valid[0].second, valid[1].second, valid[2].second, numRoots,
239  roots);
240  }
241  else if (numValid == 2)
242  {
243  GetRoots(valid[0].first, valid[1].first, valid[0].second,
244  valid[1].second, numRoots, roots);
245  }
246  else if (numValid == 1)
247  {
248  GetRoots(valid[0].first, valid[0].second, numRoots, roots);
249  }
250  else
251  {
252  // numValid cannot be zero because we already handled case K = 0
253  LogError("Unexpected condition.");
254  result.intersect = true;
255  result.relationship = ELLIPSOIDS_INTERSECTING;
256  return result;
257  }
258 
259  for (i = 0; i < numRoots; ++i)
260  {
261  Real s = roots[i];
262  Real p0 = d0*K[0] * s / (d0 * s - (Real)1);
263  Real p1 = d1*K[1] * s / (d1 * s - (Real)1);
264  Real p2 = d2*K[2] * s / (d2 * s - (Real)1);
265  Real sqrDistance = p0 * p0 + p1 * p1 + p2 * p2;
266  if (sqrDistance < minSqrDistance)
267  {
268  minSqrDistance = sqrDistance;
269  }
270  if (sqrDistance > maxSqrDistance)
271  {
272  maxSqrDistance = sqrDistance;
273  }
274  }
275 
276  if (maxSqrDistance < one)
277  {
278  result.intersect = true;
279  result.relationship = ELLIPSOID0_CONTAINS_ELLIPSOID1;
280  }
281  else if (minSqrDistance >(Real)1)
282  {
283  if (d0 * c0 + d1 * c1 + d2 * c2 > one)
284  {
285  result.intersect = false;
286  result.relationship = ELLIPSOIDS_SEPARATED;
287  }
288  else
289  {
290  result.intersect = true;
291  result.relationship = ELLIPSOID1_CONTAINS_ELLIPSOID0;
292  }
293  }
294  else
295  {
296  result.intersect = true;
297  result.relationship = ELLIPSOIDS_INTERSECTING;
298  }
299 
300  return result;
301 }
302 
303 template <typename Real>
305  Real c0, int& numRoots, Real* roots)
306 {
307  // f(s) = d0*c0/(d0*s-1)^2 - 1
308  Real const one = (Real)1;
309  Real temp = sqrt(d0*c0);
310  Real inv = one / d0;
311  numRoots = 2;
312  roots[0] = (one - temp) * inv;
313  roots[1] = (one + temp) * inv;
314 }
315 
316 template <typename Real>
317 void TIQuery<Real, Ellipsoid3<Real>, Ellipsoid3<Real>>::GetRoots(Real d0,
318  Real d1, Real c0, Real c1, int& numRoots, Real* roots)
319 {
320  // f(s) = d0*c0/(d0*s-1)^2 + d1*c1/(d1*s-1)^2 - 1
321  // with d0 > d1
322 
323  Real const zero = (Real)0;
324  Real const one = (Real)1;
325  Real const two = (Real)2;
326  Real d0c0 = d0 * c0;
327  Real d1c1 = d1 * c1;
328 
329  std::function<Real(Real)> F = [&one, d0, d1, d0c0, d1c1](Real s)
330  {
331  Real invN0 = one / (d0*s - one);
332  Real invN1 = one / (d1*s - one);
333  Real term0 = d0c0 * invN0 * invN0;
334  Real term1 = d1c1 * invN1 * invN1;
335  Real f = term0 + term1 - one;
336  return f;
337  };
338 
339  std::function<Real(Real)> DF = [&one, &two, d0, d1, d0c0, d1c1](Real s)
340  {
341  Real invN0 = one / (d0*s - one);
342  Real invN1 = one / (d1*s - one);
343  Real term0 = d0 * d0c0 * invN0 * invN0 * invN0;
344  Real term1 = d1 * d1c1 * invN1 * invN1 * invN1;
345  Real df = -two * (term0 + term1);
346  return df;
347  };
348 
349  unsigned int const maxIterations = 1024;
350  unsigned int iterations;
351  numRoots = 0;
352 
353  // TODO: What role does epsilon play?
354  Real const epsilon = (Real)0.001;
355  Real multiplier0 = sqrt(two / (one - epsilon));
356  Real multiplier1 = sqrt(one / (one + epsilon));
357  Real sqrtd0c0 = sqrt(d0c0);
358  Real sqrtd1c1 = sqrt(d1c1);
359  Real invD0 = one / d0;
360  Real invD1 = one / d1;
361  Real temp0, temp1, smin, smax, s;
362 
363  // Compute root in (-infinity,1/d0).
364  temp0 = (one - multiplier0 * sqrtd0c0) * invD0;
365  temp1 = (one - multiplier0 * sqrtd1c1) * invD1;
366  smin = std::min(temp0, temp1);
367  LogAssert(F(smin) < zero, "Unexpected condition.");
368  smax = (one - multiplier1*sqrtd0c0)*invD0;
369  LogAssert(F(smax) > zero, "Unexpected condition.");
370  iterations = RootsBisection<Real>::Find(F, smin, smax, maxIterations, s);
371  LogAssert(iterations > 0, "Unexpected condition.");
372  roots[numRoots++] = s;
373 
374  // Compute roots (if any) in (1/d0,1/d1). It is the case that
375  // F(1/d0) = +infinity, F'(1/d0) = -infinity
376  // F(1/d1) = +infinity, F'(1/d1) = +infinity
377  // F"(s) > 0 for all s in the domain of F
378  // Compute the unique root r of F'(s) on (1/d0,1/d1). The bisector needs
379  // only the signs at the endpoints, so we pass -1 and +1 instead of the
380  // infinite values. If F(r) < 0, F(s) has two roots in the interval.
381  // If F(r) = 0, F(s) has only one root in the interval.
382  Real smid;
383  iterations = RootsBisection<Real>::Find(DF, invD0, invD1, -one, one,
384  maxIterations, smid);
385  LogAssert(iterations > 0, "Unexpected condition.");
386  if (F(smid) < zero)
387  {
388  // Pass in signs rather than infinities, because the bisector cares
389  // only about the signs.
390  iterations = RootsBisection<Real>::Find(F, invD0, smid, one, -one,
391  maxIterations, s);
392  LogAssert(iterations > 0, "Unexpected condition.");
393  roots[numRoots++] = s;
394  iterations = RootsBisection<Real>::Find(F, smid, invD1, -one, one,
395  maxIterations, s);
396  LogAssert(iterations > 0, "Unexpected condition.");
397  roots[numRoots++] = s;
398  }
399 
400  // Compute root in (1/d1,+infinity).
401  temp0 = (one + multiplier0 * sqrtd0c0) * invD0;
402  temp1 = (one + multiplier0 * sqrtd1c1) * invD1;
403  smax = std::max(temp0, temp1);
404  LogAssert(F(smax) < zero, "Unexpected condition.");
405  smin = (one + multiplier1 * sqrtd1c1) * invD1;
406  LogAssert(F(smin) > zero, "Unexpected condition.");
407  iterations = RootsBisection<Real>::Find(F, smin, smax, maxIterations, s);
408  LogAssert(iterations > 0, "Unexpected condition.");
409  roots[numRoots++] = s;
410 }
411 
412 template <typename Real>
413 void TIQuery<Real, Ellipsoid3<Real>, Ellipsoid3<Real>>::GetRoots(Real d0,
414  Real d1, Real d2, Real c0, Real c1, Real c2, int& numRoots, Real* roots)
415 {
416  // f(s) = d0*c0/(d0*s-1)^2 + d1*c1/(d1*s-1)^2 + d2*c2/(d2*s-1)^2 - 1
417  // with d0 > d1 > d2
418 
419  Real const zero = (Real)0;
420  Real const one = (Real)1;
421  Real const three = (Real)3;
422  Real d0c0 = d0 * c0;
423  Real d1c1 = d1 * c1;
424  Real d2c2 = d2 * c2;
425 
426  std::function<Real(Real)> F = [&one, d0, d1, d2, d0c0, d1c1, d2c2](Real s)
427  {
428  Real invN0 = one / (d0*s - one);
429  Real invN1 = one / (d1*s - one);
430  Real invN2 = one / (d2*s - one);
431  Real term0 = d0c0 * invN0 * invN0;
432  Real term1 = d1c1 * invN1 * invN1;
433  Real term2 = d2c2 * invN2 * invN2;
434  Real f = term0 + term1 + term2 - one;
435  return f;
436  };
437 
438  std::function<Real(Real)> DF = [&one, d0, d1, d2, d0c0, d1c1, d2c2](Real s)
439  {
440  Real const two = (Real)2;
441  Real invN0 = one / (d0*s - one);
442  Real invN1 = one / (d1*s - one);
443  Real invN2 = one / (d2*s - one);
444  Real term0 = d0 * d0c0 * invN0 * invN0 * invN0;
445  Real term1 = d1 * d1c1 * invN1 * invN1 * invN1;
446  Real term2 = d2 * d2c2 * invN2 * invN2 * invN2;
447  Real df = -two * (term0 + term1 + term2);
448  return df;
449  };
450 
451  unsigned int const maxIterations = 1024;
452  unsigned int iterations;
453  numRoots = 0;
454 
455  // TODO: What role does epsilon play?
456  Real epsilon = (Real)0.001;
457  Real multiplier0 = sqrt(three / (one - epsilon));
458  Real multiplier1 = sqrt(one / (one + epsilon));
459  Real sqrtd0c0 = sqrt(d0c0);
460  Real sqrtd1c1 = sqrt(d1c1);
461  Real sqrtd2c2 = sqrt(d2c2);
462  Real invD0 = one / d0;
463  Real invD1 = one / d1;
464  Real invD2 = one / d2;
465  Real temp0, temp1, temp2, smin, smax, s;
466 
467  // Compute root in (-infinity,1/d0).
468  temp0 = (one - multiplier0*sqrtd0c0)*invD0;
469  temp1 = (one - multiplier0*sqrtd1c1)*invD1;
470  temp2 = (one - multiplier0*sqrtd2c2)*invD2;
471  smin = std::min(std::min(temp0, temp1), temp2);
472  LogAssert(F(smin) < zero, "Unexpected condition.");
473  smax = (one - multiplier1*sqrtd0c0)*invD0;
474  LogAssert(F(smax) > zero, "Unexpected condition.");
475  iterations = RootsBisection<Real>::Find(F, smin, smax, maxIterations, s);
476  LogAssert(iterations > 0, "Unexpected condition.");
477  roots[numRoots++] = s;
478 
479  // Compute roots (if any) in (1/d0,1/d1). It is the case that
480  // F(1/d0) = +infinity, F'(1/d0) = -infinity
481  // F(1/d1) = +infinity, F'(1/d1) = +infinity
482  // F"(s) > 0 for all s in the domain of F
483  // Compute the unique root r of F'(s) on (1/d0,1/d1). The bisector needs
484  // only the signs at the endpoints, so we pass -1 and +1 instead of the
485  // infinite values. If F(r) < 0, F(s) has two roots in the interval.
486  // If F(r) = 0, F(s) has only one root in the interval.
487  Real smid;
488  iterations = RootsBisection<Real>::Find(DF, invD0, invD1, -one, one,
489  maxIterations, smid);
490  LogAssert(iterations > 0, "Unexpected condition.");
491  if (F(smid) < zero)
492  {
493  // Pass in signs rather than infinities, because the bisector cares
494  // only about the signs.
495  iterations = RootsBisection<Real>::Find(F, invD0, smid, one, -one,
496  maxIterations, s);
497  LogAssert(iterations > 0, "Unexpected condition.");
498  roots[numRoots++] = s;
499  iterations = RootsBisection<Real>::Find(F, smid, invD1, -one, one,
500  maxIterations, s);
501  LogAssert(iterations > 0, "Unexpected condition.");
502  roots[numRoots++] = s;
503  }
504 
505  // Compute roots (if any) in (1/d1,1/d2). It is the case that
506  // F(1/d1) = +infinity, F'(1/d1) = -infinity
507  // F(1/d2) = +infinity, F'(1/d2) = +infinity
508  // F"(s) > 0 for all s in the domain of F
509  // Compute the unique root r of F'(s) on (1/d1,1/d2). The bisector needs
510  // only the signs at the endpoints, so we pass -1 and +1 instead of the
511  // infinite values. If F(r) < 0, F(s) has two roots in the interval.
512  // If F(r) = 0, F(s) has only one root in the interval.
513  iterations = RootsBisection<Real>::Find(DF, invD1, invD2, -one, one,
514  maxIterations, smid);
515  LogAssert(iterations > 0, "Unexpected condition.");
516  if (F(smid) < zero)
517  {
518  // Pass in signs rather than infinities, because the bisector cares
519  // only about the signs.
520  iterations = RootsBisection<Real>::Find(F, invD1, smid, one, -one,
521  maxIterations, s);
522  LogAssert(iterations > 0, "Unexpected condition.");
523  roots[numRoots++] = s;
524  iterations = RootsBisection<Real>::Find(F, smid, invD2, -one, one,
525  maxIterations, s);
526  LogAssert(iterations > 0, "Unexpected condition.");
527  roots[numRoots++] = s;
528  }
529 
530  // Compute root in (1/d2,+infinity).
531  temp0 = (one + multiplier0*sqrtd0c0)*invD0;
532  temp1 = (one + multiplier0*sqrtd1c1)*invD1;
533  temp2 = (one + multiplier0*sqrtd2c2)*invD2;
534  smax = std::max(std::max(temp0, temp1), temp2);
535  LogAssert(F(smax) < zero, "Unexpected condition.");
536  smin = (one + multiplier1*sqrtd2c2)*invD2;
537  LogAssert(F(smin) > zero, "Unexpected condition.");
538  iterations = RootsBisection<Real>::Find(F, smin, smax, maxIterations, s);
539  LogAssert(iterations > 0, "Unexpected condition.");
540  roots[numRoots++] = s;
541 }
542 
543 
544 }
GLenum GLfloat param
Definition: glcorearb.h:99
#define LogAssert(condition, message)
Definition: GteLogger.h:86
GMatrix< Real > MultiplyATB(GMatrix< Real > const &A, GMatrix< Real > const &B)
Definition: GteGMatrix.h:737
#define LogError(message)
Definition: GteLogger.h:92
GLint first
Definition: glcorearb.h:400
void SetCol(int c, Vector< NumRows, Real > const &vec)
Definition: GteMatrix.h:362
GLdouble s
Definition: glext.h:231
GLfloat f
Definition: glcorearb.h:1921
Result operator()(Type0 const &primitive0, Type1 const &primitive1)
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 04:00:00