GteContEllipsoid3MinCR.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>
12 #include <random>
13 
14 // Compute the minimum-volume ellipsoid, (X-C)^T R D R^T (X-C) = 1, given the
15 // center C and orientation matrix R. The columns of R are the axes of the
16 // ellipsoid. The algorithm computes the diagonal matrix D. The minimum
17 // volume is (4*pi/3)/sqrt(D[0]*D[1]*D[2]), where D = diag(D[0],D[1],D[2]).
18 // The problem is equivalent to maximizing the product D[0]*D[1]*D[2] for a
19 // given C and R, and subject to the constraints
20 // (P[i]-C)^T R D R^T (P[i]-C) <= 1
21 // for all input points P[i] with 0 <= i < N. Each constraint has the form
22 // A[0]*D[0] + A[1]*D[1] + A[2]*D[2] <= 1
23 // where A[0] >= 0, A[1] >= 0, and A[2] >= 0.
24 
25 namespace gte
26 {
27 
28 template <typename Real>
30 {
31 public:
32  void operator()(int numPoints, Vector3<Real> const* points,
33  Vector3<Real> const& C, Matrix3x3<Real> const& R, Real D[3]);
34 
35 private:
36  void FindEdgeMax(std::vector<Vector3<Real>>& A, int& plane0,
37  int& plane1, Real D[3]);
38 
39  void FindFacetMax(std::vector<Vector3<Real>>& A, int& plane0,
40  Real D[3]);
41 
42  void MaxProduct(std::vector<Vector3<Real>>& A, Real D[3]);
43 };
44 
45 
46 template <typename Real>
48  Vector3<Real> const* points, Vector3<Real> const& C,
49  Matrix3x3<Real> const& R, Real D[3])
50 {
51  // Compute the constraint coefficients, of the form (A[0],A[1]) for
52  // each i.
53  std::vector<Vector3<Real>> A(numPoints);
54  for (int i = 0; i < numPoints; ++i)
55  {
56  Vector3<Real> diff = points[i] - C; // P[i] - C
57  Vector3<Real> prod = diff*R; // R^T*(P[i] - C) = (u,v,w)
58  A[i] = prod * prod; // (u^2, v^2, w^2)
59  }
60 
61  // TODO: Sort the constraints to eliminate redundant ones. It is clear
62  // how to do this in ContEllipse2MinCR. How to do this in 3D?
63 
64  MaxProduct(A, D);
65 }
66 
67 template <typename Real>
69  int& plane0, int& plane1, Real D[3])
70 {
71  // Compute direction to local maximum point on line of intersection.
72  Real xDir = A[plane0][1] * A[plane1][2] - A[plane1][1] * A[plane0][2];
73  Real yDir = A[plane0][2] * A[plane1][0] - A[plane1][2] * A[plane0][0];
74  Real zDir = A[plane0][0] * A[plane1][1] - A[plane1][0] * A[plane0][1];
75 
76  // Build quadratic Q'(t) = (d/dt)(x(t)y(t)z(t)) = a0+a1*t+a2*t^2.
77  Real a0 = D[0] * D[1] * zDir + D[0] * D[2] * yDir + D[1] * D[2] * xDir;
78  Real a1 = ((Real)2)*(D[2] * xDir*yDir + D[1] * xDir*zDir + D[0] * yDir*zDir);
79  Real a2 = ((Real)3)*(xDir*yDir*zDir);
80 
81  // Find root to Q'(t) = 0 corresponding to maximum.
82  Real tFinal;
83  if (a2 != (Real)0)
84  {
85  Real invA2 = ((Real)1) / a2;
86  Real discr = a1*a1 - ((Real)4)*a0*a2;
87  discr = sqrt(std::max(discr, (Real)0));
88  tFinal = -((Real)0.5)*(a1 + discr)*invA2;
89  if (a1 + ((Real)2)*a2*tFinal > (Real)0)
90  {
91  tFinal = ((Real)0.5)*(-a1 + discr)*invA2;
92  }
93  }
94  else if (a1 != (Real)0)
95  {
96  tFinal = -a0 / a1;
97  }
98  else if (a0 != (Real)0)
99  {
100  Real fmax = std::numeric_limits<Real>::max();
101  tFinal = (a0 >= (Real)0 ? fmax : -fmax);
102  }
103  else
104  {
105  return;
106  }
107 
108  if (tFinal < (Real)0)
109  {
110  // Make (xDir,yDir,zDir) point in direction of increase of Q.
111  tFinal = -tFinal;
112  xDir = -xDir;
113  yDir = -yDir;
114  zDir = -zDir;
115  }
116 
117  // Sort remaining planes along line from current point to local maximum.
118  Real tMax = tFinal;
119  int plane2 = -1;
120  int numPoints = static_cast<int>(A.size());
121  for (int i = 0; i < numPoints; ++i)
122  {
123  if (i == plane0 || i == plane1)
124  {
125  continue;
126  }
127 
128  Real norDotDir = A[i][0] * xDir + A[i][1] * yDir + A[i][2] * zDir;
129  if (norDotDir <= (Real)0)
130  {
131  continue;
132  }
133 
134  // Theoretically the numerator must be nonnegative since an invariant
135  // in the algorithm is that (x0,y0,z0) is on the convex hull of the
136  // constraints. However, some numerical error may make this a small
137  // negative number. In that case set tmax = 0 (no change in
138  // position).
139  Real numer = (Real)1 - A[i][0] * D[0] - A[i][1] * D[1] - A[i][2] * D[2];
140  if (numer < (Real)0)
141  {
142  LogError("Unexpected condition.");
143  plane2 = i;
144  tMax = (Real)0;
145  break;
146  }
147 
148  Real t = numer / norDotDir;
149  if (0 <= t && t < tMax)
150  {
151  plane2 = i;
152  tMax = t;
153  }
154  }
155 
156  D[0] += tMax*xDir;
157  D[1] += tMax*yDir;
158  D[2] += tMax*zDir;
159 
160  if (tMax == tFinal)
161  {
162  return;
163  }
164 
165  if (tMax > (Real)0)
166  {
167  plane0 = plane2;
168  FindFacetMax(A, plane0, D);
169  return;
170  }
171 
172  // tmax == 0, so return with D[0], D[1], and D[2] unchanged.
173 }
174 
175 template <typename Real>
177  int& plane0, Real D[3])
178 {
179  Real tFinal, xDir, yDir, zDir;
180 
181  if (A[plane0][0] > (Real)0
182  && A[plane0][1] > (Real)0
183  && A[plane0][2] > (Real)0)
184  {
185  // Compute local maximum point on plane.
186  Real oneThird = ((Real)1) / (Real)3;
187  Real xMax = oneThird / A[plane0][0];
188  Real yMax = oneThird / A[plane0][1];
189  Real zMax = oneThird / A[plane0][2];
190 
191  // Compute direction to local maximum point on plane.
192  tFinal = (Real)1;
193  xDir = xMax - D[0];
194  yDir = yMax - D[1];
195  zDir = zMax - D[2];
196  }
197  else
198  {
199  tFinal = std::numeric_limits<Real>::max();
200 
201  if (A[plane0][0] > (Real)0)
202  {
203  xDir = (Real)0;
204  }
205  else
206  {
207  xDir = (Real)1;
208  }
209 
210  if (A[plane0][1] > (Real)0)
211  {
212  yDir = (Real)0;
213  }
214  else
215  {
216  yDir = (Real)1;
217  }
218 
219  if (A[plane0][2] > (Real)0)
220  {
221  zDir = (Real)0;
222  }
223  else
224  {
225  zDir = (Real)1;
226  }
227  }
228 
229  // Sort remaining planes along line from current point.
230  Real tMax = tFinal;
231  int plane1 = -1;
232  int numPoints = static_cast<int>(A.size());
233  for (int i = 0; i < numPoints; ++i)
234  {
235  if (i == plane0)
236  {
237  continue;
238  }
239 
240  Real norDotDir = A[i][0] * xDir + A[i][1] * yDir + A[i][2] * zDir;
241  if (norDotDir <= (Real)0)
242  {
243  continue;
244  }
245 
246  // Theoretically the numerator must be nonnegative since an invariant
247  // in the algorithm is that (x0,y0,z0) is on the convex hull of the
248  // constraints. However, some numerical error may make this a small
249  // negative number. In that case, set tmax = 0 (no change in
250  // position).
251  Real numer = (Real)1 - A[i][0] * D[0] - A[i][1] * D[1] - A[i][2] * D[2];
252  if (numer < (Real)0)
253  {
254  LogError("Unexpected condition.");
255  plane1 = i;
256  tMax = (Real)0;
257  break;
258  }
259 
260  Real t = numer / norDotDir;
261  if (0 <= t && t < tMax)
262  {
263  plane1 = i;
264  tMax = t;
265  }
266  }
267 
268  D[0] += tMax*xDir;
269  D[1] += tMax*yDir;
270  D[2] += tMax*zDir;
271 
272  if (tMax == (Real)1)
273  {
274  return;
275  }
276 
277  if (tMax > (Real)0)
278  {
279  plane0 = plane1;
280  FindFacetMax(A, plane0, D);
281  return;
282  }
283 
284  FindEdgeMax(A, plane0, plane1, D);
285 }
286 
287 template <typename Real>
289  Real D[3])
290 {
291  // Maximize x*y*z subject to x >= 0, y >= 0, z >= 0, and
292  // A[i]*x+B[i]*y+C[i]*z <= 1 for 0 <= i < N where A[i] >= 0,
293  // B[i] >= 0, and C[i] >= 0.
294 
295  // Jitter the lines to avoid cases where more than three planes
296  // intersect at the same point. Should also break parallelism
297  // and planes parallel to the coordinate planes.
298  std::mt19937 mte;
299  std::uniform_real_distribution<Real> rnd((Real)0, (Real)1);
300  Real maxJitter = (Real)1e-12;
301  int numPoints = static_cast<int>(A.size());
302  int i;
303  for (i = 0; i < numPoints; ++i)
304  {
305  A[i][0] += maxJitter*rnd(mte);
306  A[i][1] += maxJitter*rnd(mte);
307  A[i][2] += maxJitter*rnd(mte);
308  }
309 
310  // Sort lines along the z-axis (x = 0 and y = 0).
311  int plane = -1;
312  Real zmax = (Real)0;
313  for (i = 0; i < numPoints; ++i)
314  {
315  if (A[i][2] > zmax)
316  {
317  zmax = A[i][2];
318  plane = i;
319  }
320  }
321  LogAssert(plane != -1, "Unexpected condition.");
322 
323  // Walk along convex hull searching for maximum.
324  D[0] = (Real)0;
325  D[1] = (Real)0;
326  D[2] = ((Real)1) / zmax;
327  FindFacetMax(A, plane, D);
328 }
329 
330 
331 }
#define LogAssert(condition, message)
Definition: GteLogger.h:86
void operator()(int numPoints, Vector3< Real > const *points, Vector3< Real > const &C, Matrix3x3< Real > const &R, Real D[3])
GLfixed GLfixed GLint GLint GLfixed points
Definition: glext.h:4927
void FindEdgeMax(std::vector< Vector3< Real >> &A, int &plane0, int &plane1, Real D[3])
#define LogError(message)
Definition: GteLogger.h:92
void FindFacetMax(std::vector< Vector3< Real >> &A, int &plane0, Real D[3])
GLclampd zmax
Definition: glext.h:6450
GLdouble GLdouble t
Definition: glext.h:239
void MaxProduct(std::vector< Vector3< Real >> &A, Real D[3])


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