GteContEllipse2MinCR.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 <algorithm>
13 
14 // Compute the minimum-area ellipse, (X-C)^T R D R^T (X-C) = 1, given the
15 // center C and the orientation matrix R. The columns of R are the axes of
16 // the ellipse. The algorithm computes the diagonal matrix D. The minimum
17 // area is pi/sqrt(D[0]*D[1]), where D = diag(D[0],D[1]). The problem is
18 // equivalent to maximizing the product D[0]*D[1] for a given C and R, and
19 // 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] <= 1
23 // where A[0] >= 0 and A[1] >= 0.
24 
25 namespace gte
26 {
27 
28 template <typename Real>
30 {
31 public:
32  void operator()(int numPoints, Vector2<Real> const* points,
33  Vector2<Real> const& C, Matrix2x2<Real> const& R, Real D[2]) const;
34 
35 private:
36  static void MaxProduct(std::vector<Vector2<Real>>& A, Real D[2]);
37 };
38 
39 
40 template <typename Real>
42  Vector2<Real> const* points, Vector2<Real> const& C,
43  Matrix2x2<Real>const & R, Real D[2]) const
44 {
45  // Compute the constraint coefficients, of the form (A[0],A[1]) for
46  // each i.
47  std::vector<Vector2<Real>> A(numPoints);
48  for (int i = 0; i < numPoints; ++i)
49  {
50  Vector2<Real> diff = points[i] - C; // P[i] - C
51  Vector2<Real> prod = diff*R; // R^T*(P[i] - C) = (u,v)
52  A[i] = prod * prod; // (u^2, v^2)
53  }
54 
55  // Sort to eliminate redundant constraints. Use a lexicographical sort,
56  // (x0,y0) > (x1,y1) if x0 > x1 or if x0 = x1 and y0 > y1. Remove all
57  // but the first entry in blocks with x0 = x1 because the corresponding
58  // constraint lines for the first entry "hides" all the others from the
59  // origin.
60  std::sort(A.begin(), A.end(),
61  [](Vector2<Real> const& P0, Vector2<Real> const& P1)
62  {
63  if (P0[0] > P1[0]) { return true; }
64  if (P0[0] < P1[0]) { return false; }
65  return P0[1] > P1[1];
66  }
67  );
68  auto end = std::unique(A.begin(), A.end(),
69  [](Vector2<Real> const& P0, Vector2<Real> const& P1)
70  {
71  return P0[0] == P1[0];
72  }
73  );
74  A.erase(end, A.end());
75 
76  // Lexicographical sort, (x0,y0) > (x1,y1) if y0 > y1 or if y0 = y1 and
77  // x0 > x1. Remove all but first entry in blocks with y0 = y1 since the
78  // corresponding constraint lines for the first entry "hides" all the
79  // others from the origin.
80  std::sort(A.begin(), A.end(),
81  [](Vector2<Real> const& P0, Vector2<Real> const& P1)
82  {
83  if (P0[1] > P1[1])
84  {
85  return true;
86  }
87 
88  if (P0[1] < P1[1])
89  {
90  return false;
91  }
92 
93  return P0[0] > P1[0];
94  }
95  );
96  end = std::unique(A.begin(), A.end(),
97  [](Vector2<Real> const& P0, Vector2<Real> const& P1)
98  {
99  return P0[1] == P1[1];
100  }
101  );
102  A.erase(end, A.end());
103 
104  MaxProduct(A, D);
105 }
106 
107 template <typename Real>
109  Real D[2])
110 {
111  // Keep track of which constraint lines have already been used in the
112  // search.
113  int numConstraints = static_cast<int>(A.size());
114  std::vector<bool> used(A.size());
115  std::fill(used.begin(), used.end(), false);
116 
117  // Find the constraint line whose y-intercept (0,ymin) is closest to the
118  // origin. This line contributes to the convex hull of the constraints
119  // and the search for the maximum starts here. Also find the constraint
120  // line whose x-intercept (xmin,0) is closest to the origin. This line
121  // contributes to the convex hull of the constraints and the search for
122  // the maximum terminates before or at this line.
123  int i, iYMin = -1;
124  int iXMin = -1;
125  Real axMax = (Real)0, ayMax = (Real)0; // A[i] >= (0,0) by design
126  for (i = 0; i < numConstraints; ++i)
127  {
128  // The minimum x-intercept is 1/A[iXMin][0] for A[iXMin][0] the
129  // maximum of the A[i][0].
130  if (A[i][0] > axMax)
131  {
132  axMax = A[i][0];
133  iXMin = i;
134  }
135 
136  // The minimum y-intercept is 1/A[iYMin][1] for A[iYMin][1] the
137  // maximum of the A[i][1].
138  if (A[i][1] > ayMax)
139  {
140  ayMax = A[i][1];
141  iYMin = i;
142  }
143  }
144  LogAssert(iXMin != -1 && iYMin != -1, "Unexpected condition.");
145  used[iYMin] = true;
146 
147  // The convex hull is searched in a clockwise manner starting with the
148  // constraint line constructed above. The next vertex of the hull occurs
149  // as the closest point to the first vertex on the current constraint
150  // line. The following loop finds each consecutive vertex.
151  Real x0 = (Real)0, xMax = ((Real)1) / axMax;
152  int j;
153  for (j = 0; j < numConstraints; ++j)
154  {
155  // Find the line whose intersection with the current line is closest
156  // to the last hull vertex. The last vertex is at (x0,y0) on the
157  // current line.
158  Real x1 = xMax;
159  int line = -1;
160  for (i = 0; i < numConstraints; ++i)
161  {
162  if (!used[i])
163  {
164  // This line not yet visited, process it. Given current
165  // constraint line a0*x+b0*y =1 and candidate line
166  // a1*x+b1*y = 1, find the point of intersection. The
167  // determinant of the system is d = a0*b1-a1*b0. We only
168  // care about lines that have more negative slope than the
169  // previous one, that is, -a1/b1 < -a0/b0, in which case we
170  // process only lines for which d < 0.
171  Real det = DotPerp(A[iYMin], A[i]);
172  if (det < (Real)0)
173  {
174  // Compute the x-value for the point of intersection,
175  // (x1,y1). There may be floating point error issues in
176  // the comparision 'D[0] <= fX1'. Consider modifying to
177  // 'D[0] <= fX1+epsilon'.
178  D[0] = (A[i][1] - A[iYMin][1]) / det;
179  if (x0 < D[0] && D[0] <= x1)
180  {
181  line = i;
182  x1 = D[0];
183  }
184  }
185  }
186  }
187 
188  // Next vertex is at (x1,y1) whose x-value was computed above. First
189  // check for the maximum of x*y on the current line for x in [x0,x1].
190  // On this interval the function is f(x) = x*(1-a0*x)/b0. The
191  // derivative is f'(x) = (1-2*a0*x)/b0 and f'(r) = 0 when
192  // r = 1/(2*a0). The three candidates for the maximum are f(x0),
193  // f(r), and f(x1). Comparisons are made between r and the end points
194  // x0 and x1. Since a0 = 0 is possible (constraint line is horizontal
195  // and f is increasing on line), the division in r is not performed
196  // and the comparisons are made between 1/2 = a0*r and a0*x0 or a0*x1.
197 
198  // Compare r < x0.
199  if ((Real)0.5 < A[iYMin][0] * x0)
200  {
201  // The maximum is f(x0) since the quadratic f decreases for
202  // x > r.
203  D[0] = x0;
204  D[1] = ((Real)1 - A[iYMin][0] * D[0]) / A[iYMin][1]; // = f(x0)
205  break;
206  }
207 
208  // Compare r < x1.
209  if ((Real)0.5 < A[iYMin][0] * x1)
210  {
211  // The maximum is f(r). The search ends here because the
212  // current line is tangent to the level curve of f(x)=f(r)
213  // and x*y can therefore only decrease as we traverse further
214  // around the hull in the clockwise direction.
215  D[0] = ((Real)0.5) / A[iYMin][0];
216  D[1] = ((Real)0.5) / A[iYMin][1]; // = f(r)
217  break;
218  }
219 
220  // The maximum is f(x1). The function x*y is potentially larger
221  // on the next line, so continue the search.
222  LogAssert(line != -1, "Unexpected condition.");
223  x0 = x1;
224  x1 = xMax;
225  used[line] = true;
226  iYMin = line;
227  }
228 
229  LogAssert(j < numConstraints, "Unexpected condition.");
230 }
231 
232 
233 }
static void MaxProduct(std::vector< Vector2< Real >> &A, Real D[2])
#define LogAssert(condition, message)
Definition: GteLogger.h:86
GLfixed GLfixed GLint GLint GLfixed points
Definition: glext.h:4927
void operator()(int numPoints, Vector2< Real > const *points, Vector2< Real > const &C, Matrix2x2< Real > const &R, Real D[2]) const
GLuint GLuint end
Definition: glcorearb.h:470
Real DotPerp(Vector2< Real > const &v0, Vector2< Real > const &v1)
Definition: GteVector2.h:117
GLuint GLfloat x0
Definition: glext.h:9013
GLuint GLfloat GLfloat GLfloat x1
Definition: glext.h:9013


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