GteMinimumVolumeSphere3.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 <algorithm>
14 #include <random>
15 
16 // Compute the minimum volume sphere containing the input set of points. The
17 // algorithm randomly permutes the input points so that the construction
18 // occurs in 'expected' O(N) time. All internal minimal sphere calculations
19 // store the squared radius in the radius member of Sphere3. Only at
20 // the end is a sqrt computed.
21 
22 namespace gte
23 {
24 
25 template <typename InputType, typename ComputeType>
27 {
28 public:
29  bool operator()(int numPoints, Vector3<InputType> const* points,
30  Sphere3<InputType>& minimal);
31 
32  // Member access.
33  inline int GetNumSupport() const;
34  inline std::array<int, 4> const& GetSupport() const;
35 
36 private:
37  // Test whether point P is inside sphere S using squared distance and
38  // squared radius.
39  bool Contains(int i, Sphere3<ComputeType> const& sphere) const;
40 
41  Sphere3<ComputeType> ExactSphere1(int i0) const;
42  Sphere3<ComputeType> ExactSphere2(int i0, int i1) const;
43  Sphere3<ComputeType> ExactSphere3(int i0, int i1, int i2) const;
44  Sphere3<ComputeType> ExactSphere4(int i0, int i1, int i2, int i3) const;
45 
50 
51  // Indices of points that support current minimum volume sphere.
52  bool SupportContains(int j) const;
53 
55  std::array<int, 4> mSupport;
56 
57  // Random permutation of the unique input points to produce expected
58  // linear time for the algorithm.
59  std::vector<Vector3<ComputeType>> mComputePoints;
60 };
61 
62 
63 template <typename InputType, typename ComputeType>
66 {
67  if (numPoints >= 1 && points)
68  {
69  // Function array to avoid switch statement in the main loop.
70  std::function<Sphere3<ComputeType>(int)> update[5];
71  update[1] = [this](int i) { return UpdateSupport1(i); };
72  update[2] = [this](int i) { return UpdateSupport2(i); };
73  update[3] = [this](int i) { return UpdateSupport3(i); };
74  update[4] = [this](int i) { return UpdateSupport4(i); };
75 
76  // Process only the unique points.
77  std::vector<int> permuted(numPoints);
78  for (int i = 0; i < numPoints; ++i)
79  {
80  permuted[i] = i;
81  }
82  std::sort(permuted.begin(), permuted.end(),
83  [points](int i0, int i1) { return points[i0] < points[i1]; });
84  auto end = std::unique(permuted.begin(), permuted.end(),
85  [points](int i0, int i1) { return points[i0] == points[i1]; });
86  permuted.erase(end, permuted.end());
87  numPoints = static_cast<int>(permuted.size());
88 
89  // Create a random permutation of the points.
90  std::shuffle(permuted.begin(), permuted.end(),
91  std::default_random_engine());
92 
93  // Convert to the compute type, which is a simple copy when
94  // ComputeType is the same as InputType.
95  mComputePoints.resize(numPoints);
96  for (int i = 0; i < numPoints; ++i)
97  {
98  for (int j = 0; j < 3; ++j)
99  {
100  mComputePoints[i][j] = points[permuted[i]][j];
101  }
102  }
103 
104  // Start with the first point.
105  Sphere3<ComputeType> ctMinimal = ExactSphere1(0);
106  mNumSupport = 1;
107  mSupport[0] = 0;
108 
109  // The loop restarts from the beginning of the point list each time
110  // the sphere needs updating. Linus Källberg (Computer Science at
111  // Mälardalen University in Sweden) discovered that performance is
112  // better when the remaining points in the array are processed before
113  // restarting. The points processed before the point that caused the
114  // update are likely to be enclosed by the new sphere (or near the
115  // sphere boundary) because they were enclosed by the previous sphere.
116  // The chances are better that points after the current one will cause
117  // growth of the bounding sphere.
118  for (int i = 1 % numPoints, n = 0; i != n; i = (i + 1) % numPoints)
119  {
120  if (!SupportContains(i))
121  {
122  if (!Contains(i, ctMinimal))
123  {
124  Sphere3<ComputeType> sphere = update[mNumSupport](i);
125  if (sphere.radius > ctMinimal.radius)
126  {
127  ctMinimal = sphere;
128  n = i;
129  }
130  }
131  }
132  }
133 
134  for (int j = 0; j < 3; ++j)
135  {
136  minimal.center[j] = static_cast<InputType>(ctMinimal.center[j]);
137  }
138  minimal.radius = static_cast<InputType>(ctMinimal.radius);
139  minimal.radius = sqrt(minimal.radius);
140 
141  for (int i = 0; i < mNumSupport; ++i)
142  {
143  mSupport[i] = permuted[mSupport[i]];
144  }
145  return true;
146  }
147  else
148  {
149  LogError("Input must contain points.");
150  minimal.center = Vector3<InputType>::Zero();
151  minimal.radius = std::numeric_limits<InputType>::max();
152  return false;
153  }
154 }
155 
156 template <typename InputType, typename ComputeType> inline
158 {
159  return mNumSupport;
160 }
161 
162 template <typename InputType, typename ComputeType> inline
163 std::array<int, 4> const&
165 {
166  return mSupport;
167 }
168 
169 template <typename InputType, typename ComputeType>
171  Sphere3<ComputeType> const& sphere) const
172 {
173  // NOTE: In this algorithm, sphere.radius is the *squared radius*.
174  Vector3<ComputeType> diff = mComputePoints[i] - sphere.center;
175  return Dot(diff, diff) <= sphere.radius;
176 }
177 
178 template <typename InputType, typename ComputeType>
180 ExactSphere1(int i0) const
181 {
182  Sphere3<ComputeType> minimal;
183  minimal.center = mComputePoints[i0];
184  minimal.radius = (ComputeType)0;
185  return minimal;
186 }
187 
188 template <typename InputType, typename ComputeType>
190 ExactSphere2(int i0, int i1) const
191 {
192  Vector3<ComputeType> const& P0 = mComputePoints[i0];
193  Vector3<ComputeType> const& P1 = mComputePoints[i1];
194  Sphere3<ComputeType> minimal;
195  minimal.center = ((ComputeType)0.5)*(P0 + P1);
196  Vector3<ComputeType> diff = P1 - P0;
197  minimal.radius = ((ComputeType)0.25)*Dot(diff, diff);
198  return minimal;
199 }
200 
201 template <typename InputType, typename ComputeType>
203 ExactSphere3(int i0, int i1, int i2) const
204 {
205  // Compute the 3D circle containing P0, P1, and P2. The center in
206  // barycentric coordinates is C = x0*P0 + x1*P1 + x2*P2, where
207  // x0 + x1 + x2 = 1. The center is equidistant from the three points,
208  // so |C - P0| = |C - P1| = |C - P2| = R, where R is the radius of the
209  // circle. From these conditions,
210  // C - P0 = x0*E0 + x1*E1 - E0
211  // C - P1 = x0*E0 + x1*E1 - E1
212  // C - P2 = x0*E0 + x1*E1
213  // where E0 = P0 - P2 and E1 = P1 - P2, which leads to
214  // r^2 = |x0*E0 + x1*E1|^2 - 2*Dot(E0, x0*E0 + x1*E1) + |E0|^2
215  // r^2 = |x0*E0 + x1*E1|^2 - 2*Dot(E1, x0*E0 + x1*E1) + |E1|^2
216  // r^2 = |x0*E0 + x1*E1|^2
217  // Subtracting the last equation from the first two and writing the
218  // equations as a linear system,
219  //
220  // +- -++ -+ +- -+
221  // | Dot(E0,E0) Dot(E0,E1) || x0 | = 0.5 | Dot(E0,E0) |
222  // | Dot(E1,E0) Dot(E1,E1) || x1 | | Dot(E1,E1) |
223  // +- -++ -+ +- -+
224  //
225  // The following code solves this system for x0 and x1 and then evaluates
226  // the third equation in r^2 to obtain r.
227 
228  Vector3<ComputeType> const& P0 = mComputePoints[i0];
229  Vector3<ComputeType> const& P1 = mComputePoints[i1];
230  Vector3<ComputeType> const& P2 = mComputePoints[i2];
231 
232  Vector3<ComputeType> E0 = P0 - P2;
233  Vector3<ComputeType> E1 = P1 - P2;
234 
236  A(0, 0) = Dot(E0, E0);
237  A(0, 1) = Dot(E0, E1);
238  A(1, 0) = A(0, 1);
239  A(1, 1) = Dot(E1, E1);
240 
241  ComputeType const half = (ComputeType)0.5;
242  Vector2<ComputeType> B{ half*A(0, 0), half*A(1, 1) };
243 
244  Sphere3<ComputeType> minimal;
247  {
248  ComputeType x2 = (ComputeType)1 - X[0] - X[1];
249  minimal.center = X[0] * P0 + X[1] * P1 + x2 *P2;
250  Vector3<ComputeType> tmp = X[0] * E0 + X[1] * E1;
251  minimal.radius = Dot(tmp, tmp);
252  }
253  else
254  {
256  minimal.radius = (ComputeType)std::numeric_limits<InputType>::max();
257  }
258  return minimal;
259 }
260 
261 template <typename InputType, typename ComputeType>
263 ExactSphere4(int i0, int i1, int i2, int i3) const
264 {
265  // Compute the sphere containing P0, P1, P2, and p3. The center in
266  // barycentric coordinates is C = x0*P0 + x1*P1 + x2*P2 + x3*P3, where
267  // x0 + x1 + x2 + x3 = 1. The center is equidistant from the three
268  // points, so |C - P0| = |C - P1| = |C - P2| = |C - P3| = R, where R is
269  // the radius of the sphere. From these conditions,
270  // C - P0 = x0*E0 + x1*E1 + x2*E2 - E0
271  // C - P1 = x0*E0 + x1*E1 + x2*E2 - E1
272  // C - P2 = x0*E0 + x1*E1 + x2*E2 - E2
273  // C - P3 = x0*E0 + x1*E1 + x2*E2
274  // where E0 = P0 - P3, E1 = P1 - P3, and E2 = P2 - P3, which leads to
275  // r^2 = |x0*E0+x1*E1+x2*E2|^2 - 2*Dot(E0,x0*E0+x1*E1+x2*E2) + |E0|^2
276  // r^2 = |x0*E0+x1*E1+x2*E2|^2 - 2*Dot(E1,x0*E0+x1*E1+x2*E2) + |E1|^2
277  // r^2 = |x0*E0+x1*E1+x2*E2|^2 - 2*Dot(E2,x0*E0+x1*E1+x2*E2) + |E2|^2
278  // r^2 = |x0*E0+x1*E1+x2*E2|^2
279  // Subtracting the last equation from the first three and writing the
280  // equations as a linear system,
281  //
282  // +- -++ -+ +- -+
283  // | Dot(E0,E0) Dot(E0,E1) Dot(E0,E2) || x0 | = 0.5 | Dot(E0,E0) |
284  // | Dot(E1,E0) Dot(E1,E1) Dot(E1,E2) || x1 | | Dot(E1,E1) |
285  // | Dot(E2,E0) Dot(E2,E1) Dot(E2,E2) || x2 | | Dot(E2,E2) |
286  // +- -++ -+ +- -+
287  //
288  // The following code solves this system for x0, x1, and x2 and then
289  // evaluates the fourth equation in r^2 to obtain r.
290 
291  Vector3<ComputeType> const& P0 = mComputePoints[i0];
292  Vector3<ComputeType> const& P1 = mComputePoints[i1];
293  Vector3<ComputeType> const& P2 = mComputePoints[i2];
294  Vector3<ComputeType> const& P3 = mComputePoints[i3];
295 
296  Vector3<ComputeType> E0 = P0 - P3;
297  Vector3<ComputeType> E1 = P1 - P3;
298  Vector3<ComputeType> E2 = P2 - P3;
299 
301  A(0, 0) = Dot(E0, E0);
302  A(0, 1) = Dot(E0, E1);
303  A(0, 2) = Dot(E0, E2);
304  A(1, 0) = A(0, 1);
305  A(1, 1) = Dot(E1, E1);
306  A(1, 2) = Dot(E1, E2);
307  A(2, 0) = A(0, 2);
308  A(2, 1) = A(1, 2);
309  A(2, 2) = Dot(E2, E2);
310 
311  ComputeType const half = (ComputeType)0.5;
312  Vector3<ComputeType> B{ half*A(0, 0), half*A(1, 1), half*A(2, 2) };
313 
314  Sphere3<ComputeType> minimal;
317  {
318  ComputeType x3 = (ComputeType)1 - X[0] - X[1] - X[2];
319  minimal.center = X[0] * P0 + X[1] * P1 + X[2] * P2 + x3 * P3;
320  Vector3<ComputeType> tmp = X[0] * E0 + X[1] * E1 + X[2] * E2;
321  minimal.radius = Dot(tmp, tmp);
322  }
323  else
324  {
326  minimal.radius = (ComputeType)std::numeric_limits<InputType>::max();
327  }
328  return minimal;
329 }
330 
331 template <typename InputType, typename ComputeType>
334 {
335  Sphere3<ComputeType> minimal = ExactSphere2(mSupport[0], i);
336  mNumSupport = 2;
337  mSupport[1] = i;
338  return minimal;
339 }
340 
341 template <typename InputType, typename ComputeType>
344 {
345  // Permutations of type 2, used for calling ExactSphere2(...).
346  int const numType2 = 2;
347  int const type2[numType2][2] =
348  {
349  { 0, /*2*/ 1 },
350  { 1, /*2*/ 0 }
351  };
352 
353  // Permutations of type 3, used for calling ExactSphere3(...).
354  int const numType3 = 1; // {0, 1, 2}
355 
356  Sphere3<ComputeType> sphere[numType2 + numType3];
357  ComputeType minRSqr = (ComputeType)std::numeric_limits<InputType>::max();
358  int iSphere = 0, iMinRSqr = -1;
359  int k0, k1;
360 
361  // Permutations of type 2.
362  for (int j = 0; j < numType2; ++j, ++iSphere)
363  {
364  k0 = mSupport[type2[j][0]];
365  sphere[iSphere] = ExactSphere2(k0, i);
366  if (sphere[iSphere].radius < minRSqr)
367  {
368  k1 = mSupport[type2[j][1]];
369  if (Contains(k1, sphere[iSphere]))
370  {
371  minRSqr = sphere[iSphere].radius;
372  iMinRSqr = iSphere;
373  }
374  }
375  }
376 
377  // Permutations of type 3.
378  k0 = mSupport[0];
379  k1 = mSupport[1];
380  sphere[iSphere] = ExactSphere3(k0, k1, i);
381  if (sphere[iSphere].radius < minRSqr)
382  {
383  minRSqr = sphere[iSphere].radius;
384  iMinRSqr = iSphere;
385  }
386 
387  // For exact arithmetic, iMinRSqr >= 0, but for floating-point arithmetic,
388  // round-off errors can lead to iMinRSqr == -1. When this happens, just
389  // use the sphere for the current support.
390  if (iMinRSqr == -1)
391  {
392  iMinRSqr = iSphere;
393  }
394 
395  switch (iMinRSqr)
396  {
397  case 0:
398  mSupport[1] = i;
399  break;
400  case 1:
401  mSupport[0] = i;
402  break;
403  case 2:
404  mNumSupport = 3;
405  mSupport[2] = i;
406  break;
407  }
408 
409  return sphere[iMinRSqr];
410 }
411 
412 template <typename InputType, typename ComputeType>
415 {
416  // Permutations of type 2, used for calling ExactSphere2(...).
417  int const numType2 = 3;
418  int const type2[numType2][3] =
419  {
420  { 0, /*3*/ 1, 2 },
421  { 1, /*3*/ 0, 2 },
422  { 2, /*3*/ 0, 1 }
423  };
424 
425  // Permutations of type 3, used for calling ExactSphere3(...).
426  int const numType3 = 3;
427  int const type3[numType3][3] =
428  {
429  { 0, 1, /*3*/ 2 },
430  { 0, 2, /*3*/ 1 },
431  { 1, 2, /*3*/ 0 }
432  };
433 
434  // Permutations of type 4, used for calling ExactSphere4(...).
435  int const numType4 = 1; // {0, 1, 2, 3}
436 
437  Sphere3<ComputeType> sphere[numType2 + numType3 + numType4];
438  ComputeType minRSqr = (ComputeType)std::numeric_limits<InputType>::max();
439  int iSphere = 0, iMinRSqr = -1;
440  int k0, k1, k2;
441 
442  // Permutations of type 2.
443  for (int j = 0; j < numType2; ++j, ++iSphere)
444  {
445  k0 = mSupport[type2[j][0]];
446  sphere[iSphere] = ExactSphere2(k0, i);
447  if (sphere[iSphere].radius < minRSqr)
448  {
449  k1 = mSupport[type2[j][1]];
450  k2 = mSupport[type2[j][2]];
451  if (Contains(k1, sphere[iSphere])
452  && Contains(k2, sphere[iSphere]))
453  {
454  minRSqr = sphere[iSphere].radius;
455  iMinRSqr = iSphere;
456  }
457  }
458  }
459 
460  // Permutations of type 3.
461  for (int j = 0; j < numType3; ++j, ++iSphere)
462  {
463  k0 = mSupport[type3[j][0]];
464  k1 = mSupport[type3[j][1]];
465  sphere[iSphere] = ExactSphere3(k0, k1, i);
466  if (sphere[iSphere].radius < minRSqr)
467  {
468  k2 = mSupport[type3[j][2]];
469  if (Contains(k2, sphere[iSphere]))
470  {
471  minRSqr = sphere[iSphere].radius;
472  iMinRSqr = iSphere;
473  }
474  }
475  }
476 
477  // Permutations of type 4.
478  k0 = mSupport[0];
479  k1 = mSupport[1];
480  k2 = mSupport[2];
481  sphere[iSphere] = ExactSphere4(k0, k1, k2, i);
482  if (sphere[iSphere].radius < minRSqr)
483  {
484  minRSqr = sphere[iSphere].radius;
485  iMinRSqr = iSphere;
486  }
487 
488  // For exact arithmetic, iMinRSqr >= 0, but for floating-point arithmetic,
489  // round-off errors can lead to iMinRSqr == -1. When this happens, just
490  // use the sphere for the current support.
491  if (iMinRSqr == -1)
492  {
493  iMinRSqr = iSphere;
494  }
495 
496  switch (iMinRSqr)
497  {
498  case 0:
499  mNumSupport = 2;
500  mSupport[1] = i;
501  break;
502  case 1:
503  mNumSupport = 2;
504  mSupport[0] = i;
505  break;
506  case 2:
507  mNumSupport = 2;
508  mSupport[0] = mSupport[2];
509  mSupport[1] = i;
510  break;
511  case 3:
512  mSupport[2] = i;
513  break;
514  case 4:
515  mSupport[1] = i;
516  break;
517  case 5:
518  mSupport[0] = i;
519  break;
520  case 6:
521  mNumSupport = 4;
522  mSupport[3] = i;
523  break;
524  }
525 
526  return sphere[iMinRSqr];
527 }
528 
529 template <typename InputType, typename ComputeType>
532 {
533  // Permutations of type 2, used for calling ExactSphere2(...).
534  int const numType2 = 4;
535  int const type2[numType2][4] =
536  {
537  { 0, /*4*/ 1, 2, 3 },
538  { 1, /*4*/ 0, 2, 3 },
539  { 2, /*4*/ 0, 1, 3 },
540  { 3, /*4*/ 0, 1, 2 }
541  };
542 
543  // Permutations of type 3, used for calling ExactSphere3(...).
544  int const numType3 = 6;
545  int const type3[numType3][4] =
546  {
547  { 0, 1, /*4*/ 2, 3 },
548  { 0, 2, /*4*/ 1, 3 },
549  { 0, 3, /*4*/ 1, 2 },
550  { 1, 2, /*4*/ 0, 3 },
551  { 1, 3, /*4*/ 0, 2 },
552  { 2, 3, /*4*/ 0, 1 }
553  };
554 
555  // Permutations of type 4, used for calling ExactSphere4(...).
556  int const numType4 = 4;
557  int const type4[numType4][4] =
558  {
559  { 0, 1, 2, /*4*/ 3 },
560  { 0, 1, 3, /*4*/ 2 },
561  { 0, 2, 3, /*4*/ 1 },
562  { 1, 2, 3, /*4*/ 0 }
563  };
564 
565  Sphere3<ComputeType> sphere[numType2 + numType3 + numType4];
566  ComputeType minRSqr = (ComputeType)std::numeric_limits<InputType>::max();
567  int iSphere = 0, iMinRSqr = -1;
568  int k0, k1, k2, k3;
569 
570  // Permutations of type 2.
571  for (int j = 0; j < numType2; ++j, ++iSphere)
572  {
573  k0 = mSupport[type2[j][0]];
574  sphere[iSphere] = ExactSphere2(k0, i);
575  if (sphere[iSphere].radius < minRSqr)
576  {
577  k1 = mSupport[type2[j][1]];
578  k2 = mSupport[type2[j][2]];
579  k3 = mSupport[type2[j][3]];
580  if (Contains(k1, sphere[iSphere])
581  && Contains(k2, sphere[iSphere])
582  && Contains(k3, sphere[iSphere]))
583  {
584  minRSqr = sphere[iSphere].radius;
585  iMinRSqr = iSphere;
586  }
587  }
588  }
589 
590  // Permutations of type 3.
591  for (int j = 0; j < numType3; ++j, ++iSphere)
592  {
593  k0 = mSupport[type3[j][0]];
594  k1 = mSupport[type3[j][1]];
595  sphere[iSphere] = ExactSphere3(k0, k1, i);
596  if (sphere[iSphere].radius < minRSqr)
597  {
598  k2 = mSupport[type3[j][2]];
599  k3 = mSupport[type3[j][3]];
600  if (Contains(k2, sphere[iSphere])
601  && Contains(k3, sphere[iSphere]))
602  {
603  minRSqr = sphere[iSphere].radius;
604  iMinRSqr = iSphere;
605  }
606  }
607  }
608 
609  // Permutations of type 4.
610  for (int j = 0; j < numType4; ++j, ++iSphere)
611  {
612  k0 = mSupport[type4[j][0]];
613  k1 = mSupport[type4[j][1]];
614  k2 = mSupport[type4[j][2]];
615  sphere[iSphere] = ExactSphere4(k0, k1, k2, i);
616  if (sphere[iSphere].radius < minRSqr)
617  {
618  k3 = mSupport[type4[j][3]];
619  if (Contains(k3, sphere[iSphere]))
620  {
621  minRSqr = sphere[iSphere].radius;
622  iMinRSqr = iSphere;
623  }
624  }
625  }
626 
627  // For exact arithmetic, iMinRSqr >= 0, but for floating-point arithmetic,
628  // round-off errors can lead to iMinRSqr == -1. When this happens, just
629  // use the sphere for the current support.
630  if (iMinRSqr == -1)
631  {
632  iMinRSqr = iSphere;
633  }
634 
635  switch (iMinRSqr)
636  {
637  case 0:
638  mNumSupport = 2;
639  mSupport[1] = i;
640  break;
641  case 1:
642  mNumSupport = 2;
643  mSupport[0] = i;
644  break;
645  case 2:
646  mNumSupport = 2;
647  mSupport[0] = mSupport[2];
648  mSupport[1] = i;
649  break;
650  case 3:
651  mNumSupport = 2;
652  mSupport[0] = mSupport[3];
653  mSupport[1] = i;
654  break;
655  case 4:
656  mNumSupport = 3;
657  mSupport[2] = i;
658  break;
659  case 5:
660  mNumSupport = 3;
661  mSupport[1] = i;
662  break;
663  case 6:
664  mNumSupport = 3;
665  mSupport[1] = mSupport[3];
666  mSupport[2] = i;
667  break;
668  case 7:
669  mNumSupport = 3;
670  mSupport[0] = i;
671  break;
672  case 8:
673  mNumSupport = 3;
674  mSupport[0] = mSupport[3];
675  mSupport[2] = i;
676  break;
677  case 9:
678  mNumSupport = 3;
679  mSupport[0] = mSupport[3];
680  mSupport[1] = i;
681  break;
682  case 10:
683  mSupport[3] = i;
684  break;
685  case 11:
686  mSupport[2] = i;
687  break;
688  case 12:
689  mSupport[1] = i;
690  break;
691  case 13:
692  mSupport[0] = i;
693  break;
694  }
695 
696  return sphere[iMinRSqr];
697 }
698 
699 template <typename InputType, typename ComputeType>
701 const
702 {
703  for (int i = 0; i < mNumSupport; ++i)
704  {
705  if (j == mSupport[i])
706  {
707  return true;
708  }
709  }
710  return false;
711 }
712 
713 
714 }
GLdouble n
Definition: glcorearb.h:2003
Sphere3< ComputeType > UpdateSupport1(int i)
std::array< int, 4 > const & GetSupport() const
Sphere3< ComputeType > UpdateSupport3(int i)
Sphere3< ComputeType > UpdateSupport4(int i)
GLfixed GLfixed GLint GLint GLfixed points
Definition: glext.h:4927
Sphere3< ComputeType > ExactSphere4(int i0, int i1, int i2, int i3) const
GLuint GLuint end
Definition: glcorearb.h:470
typedef int(WINAPI *PFNWGLRELEASEPBUFFERDCARBPROC)(HPBUFFERARB hPbuffer
#define LogError(message)
Definition: GteLogger.h:92
static Vector Zero()
Definition: GteVector.h:295
Sphere3< ComputeType > ExactSphere1(int i0) const
DualQuaternion< Real > Dot(DualQuaternion< Real > const &d0, DualQuaternion< Real > const &d1)
Sphere3< ComputeType > ExactSphere2(int i0, int i1) const
Sphere3< ComputeType > UpdateSupport2(int i)
bool Contains(int i, Sphere3< ComputeType > const &sphere) const
GLfixed GLfixed x2
Definition: glext.h:4952
bool operator()(int numPoints, Vector3< InputType > const *points, Sphere3< InputType > &minimal)
Vector< N, Real > center
Sphere3< ComputeType > ExactSphere3(int i0, int i1, int i2) const
std::vector< Vector3< ComputeType > > mComputePoints


geometric_tools_engine
Author(s): Yijiang Huang
autogenerated on Thu Jul 18 2019 04:00:01