GteApprQuadratic2.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 <Mathematics/GteMatrix.h>
11 #include <Mathematics/GteVector2.h>
14 
15 namespace gte
16 {
17 
18 // The quadratic fit is
19 //
20 // 0 = C[0] + C[1]*X + C[2]*Y + C[3]*X^2 + C[4]*Y^2 + C[5]*X*Y
21 //
22 // subject to Length(C) = 1. Minimize E(C) = C^t M C with Length(C) = 1
23 // and M = (sum_i V_i)(sum_i V_i)^t where
24 //
25 // V = (1, X, Y, X^2, Y^2, X*Y)
26 //
27 // The minimum value is the smallest eigenvalue of M and C is a corresponding
28 // unit length eigenvector.
29 //
30 // Input:
31 // n = number of points to fit
32 // p[0..n-1] = array of points to fit
33 //
34 // Output:
35 // c[0..5] = coefficients of quadratic fit (the eigenvector)
36 // return value of function is nonnegative and a measure of the fit
37 // (the minimum eigenvalue; 0 = exact fit, positive otherwise)
38 
39 // Canonical forms. The quadratic equation can be factored into
40 // P^T A P + B^T P + K = 0 where P = (X,Y,Z), K = C[0], B = (C[1],C[2],C[3]),
41 // and A is a 3x3 symmetric matrix with A00 = C[4], A11 = C[5], A22 = C[6],
42 // A01 = C[7]/2, A02 = C[8]/2, and A12 = C[9]/2. Matrix A = R^T D R where
43 // R is orthogonal and D is diagonal (using an eigendecomposition). Define
44 // V = R P = (v0,v1,v2), E = R B = (e0,e1,e2), D = diag(d0,d1,d2), and f = K
45 // to obtain
46 //
47 // d0 v0^2 + d1 v1^2 + d2 v^2 + e0 v0 + e1 v1 + e2 v2 + f = 0
48 //
49 // The characterization depends on the signs of the d_i.
50 
51 template <typename Real>
53 {
54 public:
55  Real operator()(int numPoints, Vector2<Real> const* points,
56  Real coefficients[6]);
57 };
58 
59 
60 // If you think your points are nearly circular, use this. The circle is of
61 // the form C'[0]+C'[1]*X+C'[2]*Y+C'[3]*(X^2+Y^2), where Length(C') = 1. The
62 // function returns C = (C'[0]/C'[3],C'[1]/C'[3],C'[2]/C'[3]), so the fitted
63 // circle is C[0]+C[1]*X+C[2]*Y+X^2+Y^2. The center is (xc,yc) =
64 // -0.5*(C[1],C[2]) and the radius is r = sqrt(xc*xc+yc*yc-C[0]).
65 
66 template <typename Real>
68 {
69 public:
70  Real operator()(int numPoints, Vector2<Real> const* points,
71  Circle2<Real>& circle);
72 };
73 
74 
75 template <typename Real>
77  Vector2<Real> const* points, Real coefficients[6])
78 {
80  for (int i = 0; i < numPoints; ++i)
81  {
82  Real x = points[i][0];
83  Real y = points[i][1];
84  Real x2 = x*x;
85  Real y2 = y*y;
86  Real xy = x*y;
87  Real x3 = x*x2;
88  Real xy2 = x*y2;
89  Real x2y = x*xy;
90  Real y3 = y*y2;
91  Real x4 = x*x3;
92  Real x2y2 = x*xy2;
93  Real x3y = x*x2y;
94  Real y4 = y*y3;
95  Real xy3 = x*y3;
96 
97  A(0, 1) += x;
98  A(0, 2) += y;
99  A(0, 3) += x2;
100  A(0, 4) += y2;
101  A(0, 5) += xy;
102  A(1, 3) += x3;
103  A(1, 4) += xy2;
104  A(1, 5) += x2y;
105  A(2, 4) += y3;
106  A(3, 3) += x4;
107  A(3, 4) += x2y2;
108  A(3, 5) += x3y;
109  A(4, 4) += y4;
110  A(4, 5) += xy3;
111  }
112 
113  A(0, 0) = static_cast<Real>(numPoints);
114  A(1, 1) = A(0, 3);
115  A(1, 2) = A(0, 5);
116  A(2, 2) = A(0, 4);
117  A(2, 3) = A(1, 5);
118  A(2, 5) = A(1, 4);
119  A(5, 5) = A(3, 4);
120 
121  for (int row = 0; row < 6; ++row)
122  {
123  for (int col = 0; col < row; ++col)
124  {
125  A(row, col) = A(col, row);
126  }
127  }
128 
129  Real invNumPoints = ((Real)1) / static_cast<Real>(numPoints);
130  for (int row = 0; row < 6; ++row)
131  {
132  for (int col = 0; col < 6; ++col)
133  {
134  A(row, col) *= invNumPoints;
135  }
136  }
137 
138  SymmetricEigensolver<Real> es(6, 1024);
139  es.Solve(&A[0], +1);
140  es.GetEigenvector(0, &coefficients[0]);
141 
142  // For an exact fit, numeric round-off errors might make the minimum
143  // eigenvalue just slightly negative. Return the absolute value since
144  // the application might rely on the return value being nonnegative.
145  return std::abs(es.GetEigenvalue(0));
146 }
147 
148 template <typename Real>
150  Vector2<Real> const* points, Circle2<Real>& circle)
151 {
153  for (int i = 0; i < numPoints; ++i)
154  {
155  Real x = points[i][0];
156  Real y = points[i][1];
157  Real x2 = x*x;
158  Real y2 = y*y;
159  Real xy = x*y;
160  Real r2 = x2 + y2;
161  Real xr2 = x*r2;
162  Real yr2 = y*r2;
163  Real r4 = r2*r2;
164 
165  A(0, 1) += x;
166  A(0, 2) += y;
167  A(0, 3) += r2;
168  A(1, 1) += x2;
169  A(1, 2) += xy;
170  A(1, 3) += xr2;
171  A(2, 2) += y2;
172  A(2, 3) += yr2;
173  A(3, 3) += r4;
174  }
175 
176  A(0, 0) = static_cast<Real>(numPoints);
177 
178  for (int row = 0; row < 4; ++row)
179  {
180  for (int col = 0; col < row; ++col)
181  {
182  A(row, col) = A(col, row);
183  }
184  }
185 
186  Real invNumPoints = ((Real)1) / static_cast<Real>(numPoints);
187  for (int row = 0; row < 4; ++row)
188  {
189  for (int col = 0; col < 4; ++col)
190  {
191  A(row, col) *= invNumPoints;
192  }
193  }
194 
195  SymmetricEigensolver<Real> es(4, 1024);
196  es.Solve(&A[0], +1);
197  Vector<4, Real> evector;
198  es.GetEigenvector(0, &evector[0]);
199 
200  Real inv = ((Real)1) / evector[3]; // TODO: Guard against zero divide?
201  Real coefficients[3];
202  for (int row = 0; row < 3; ++row)
203  {
204  coefficients[row] = inv * evector[row];
205  }
206 
207  circle.center[0] = ((Real)-0.5) * coefficients[1];
208  circle.center[1] = ((Real)-0.5) * coefficients[2];
209  circle.radius = sqrt(std::abs(Dot(circle.center, circle.center) -
210  coefficients[0]));
211 
212  // For an exact fit, numeric round-off errors might make the minimum
213  // eigenvalue just slightly negative. Return the absolute value since
214  // the application might rely on the return value being nonnegative.
215  return std::abs(es.GetEigenvalue(0));
216 }
217 
218 
219 }
gte::BSNumber< UIntegerType > abs(gte::BSNumber< UIntegerType > const &number)
Definition: GteBSNumber.h:966
void GetEigenvector(int c, Real *eigenvector) const
GLfixed GLfixed GLfixed y2
Definition: glext.h:4952
GLint GLenum GLint x
Definition: glcorearb.h:404
GLfixed GLfixed GLint GLint GLfixed points
Definition: glext.h:4927
GLenum GLenum GLsizei void * row
Definition: glext.h:2725
unsigned int Solve(Real const *input, int sortType)
DualQuaternion< Real > Dot(DualQuaternion< Real > const &d0, DualQuaternion< Real > const &d1)
Real operator()(int numPoints, Vector2< Real > const *points, Real coefficients[6])
GLfixed GLfixed x2
Definition: glext.h:4952
Real operator()(int numPoints, Vector2< Real > const *points, Circle2< Real > &circle)
Vector< N, Real > center
GLint y
Definition: glcorearb.h:98


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