GteApprPolynomial3.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/GteArray2.h>
11 #include <Mathematics/GteGMatrix.h>
13 #include <array>
14 
15 // The samples are (x[i],y[i],w[i]) for 0 <= i < S. Think of w as a function
16 // of x and y, say w = f(x,y). The function fits the samples with a
17 // polynomial of degree d0 in x and degree d1 in y, say
18 // w = sum_{i=0}^{d0} sum_{j=0}^{d1} c[i][j]*x^i*y^j
19 // The method is a least-squares fitting algorithm. The mParameters stores
20 // c[i][j] = mParameters[i+(d0+1)*j] for a total of (d0+1)*(d1+1)
21 // coefficients. The observation type is std::array<Real,3>, which represents
22 // a triple (x,y,w).
23 //
24 // WARNING. The fitting algorithm for polynomial terms
25 // (1,x,x^2,...,x^d0), (1,y,y^2,...,y^d1)
26 // is known to be nonrobust for large degrees and for large magnitude data.
27 // One alternative is to use orthogonal polynomials
28 // (f[0](x),...,f[d0](x)), (g[0](y),...,g[d1](y))
29 // and apply the least-squares algorithm to these. Another alternative is to
30 // transform
31 // (x',y',w') = ((x-xcen)/rng, (y-ycen)/rng, w/rng)
32 // where xmin = min(x[i]), xmax = max(x[i]), xcen = (xmin+xmax)/2,
33 // ymin = min(y[i]), ymax = max(y[i]), ycen = (ymin+ymax)/2, and
34 // rng = max(xmax-xmin,ymax-ymin). Fit the (x',y',w') points,
35 // w' = sum_{i=0}^{d0} sum_{j=0}^{d1} c'[i][j]*(x')^i*(y')^j
36 // The original polynomial is evaluated as
37 // w = rng * sum_{i=0}^{d0} sum_{j=0}^{d1} c'[i][j] *
38 // ((x-xcen)/rng)^i * ((y-ycen)/rng)^j
39 
40 namespace gte
41 {
42 
43 template <typename Real>
45  :
46  public ApprQuery<Real, ApprPolynomial3<Real>, std::array<Real, 3>>
47 {
48 public:
49  // Initialize the model parameters to zero.
50  ApprPolynomial3(int xDegree, int yDegree);
51 
52  // The minimum number of observations required to fit the model.
53  int GetMinimumRequired() const;
54 
55  // Estimate the model parameters for all observations specified by the
56  // indices. This function is called by the base-class Fit(...) functions.
57  bool Fit(std::vector<std::array<Real, 3>> const& observations,
58  std::vector<int> const& indices);
59 
60  // Compute the model error for the specified observation for the current
61  // model parameters. The returned value for observation (x0,y0,w0) is
62  // |w(x0,y0) - w0|, where w(x,y) is the fitted polynomial.
63  Real Error(std::array<Real, 3> const& observation) const;
64 
65  // Get the parameters of the model.
66  std::vector<Real> const& GetParameters() const;
67 
68  // Evaluate the polynomial. The domain intervals are provided so you can
69  // interpolate ((x,y) in domain) or extrapolate ((x,y) not in domain).
70  std::array<Real, 2> const& GetXDomain() const;
71  std::array<Real, 2> const& GetYDomain() const;
72  Real Evaluate(Real x, Real y) const;
73 
74 private:
76  std::array<Real, 2> mXDomain, mYDomain;
77  std::vector<Real> mParameters;
78 
79  // This array is used by Evaluate() to avoid reallocation of the 'vector'
80  // for each call. The member is mutable because, to the user, the call
81  // to Evaluate does not modify the polynomial.
82  mutable std::vector<Real> mYCoefficient;
83 };
84 
85 
86 template <typename Real>
87 ApprPolynomial3<Real>::ApprPolynomial3(int xDegree, int yDegree)
88  :
89  mXDegree(xDegree),
90  mYDegree(yDegree),
91  mXDegreeP1(xDegree + 1),
92  mYDegreeP1(yDegree + 1),
96 {
97  mXDomain[0] = std::numeric_limits<Real>::max();
98  mXDomain[1] = -mXDomain[0];
99  mYDomain[0] = std::numeric_limits<Real>::max();
100  mYDomain[1] = -mYDomain[0];
101  std::fill(mParameters.begin(), mParameters.end(), (Real)0);
102  std::fill(mYCoefficient.begin(), mYCoefficient.end(), (Real)0);
103 }
104 
105 template <typename Real>
107 {
108  return mSize;
109 }
110 
111 template <typename Real>
113  std::vector<std::array<Real, 3>> const& observations,
114  std::vector<int> const& indices)
115 {
116  if (indices.size() > 0)
117  {
118  int s, i0, j0, k0, i1, j1, k1;
119 
120  // Compute the powers of x and y.
121  int numSamples = static_cast<int>(indices.size());
122  int twoXDegree = 2 * mXDegree;
123  int twoYDegree = 2 * mYDegree;
124  Array2<Real> xPower(twoXDegree + 1, numSamples);
125  Array2<Real> yPower(twoYDegree + 1, numSamples);
126  for (s = 0; s < numSamples; ++s)
127  {
128  Real x = observations[indices[s]][0];
129  Real y = observations[indices[s]][1];
130  mXDomain[0] = std::min(x, mXDomain[0]);
131  mXDomain[1] = std::max(x, mXDomain[1]);
132  mYDomain[0] = std::min(y, mYDomain[0]);
133  mYDomain[1] = std::max(y, mYDomain[1]);
134 
135  xPower[s][0] = (Real)1;
136  for (i0 = 1; i0 <= twoXDegree; ++i0)
137  {
138  xPower[s][i0] = x * xPower[s][i0 - 1];
139  }
140 
141  yPower[s][0] = (Real)1;
142  for (j0 = 1; j0 <= twoYDegree; ++j0)
143  {
144  yPower[s][j0] = y * yPower[s][j0 - 1];
145  }
146  }
147 
148  // Matrix A is the Vandermonde matrix and vector B is the right-hand
149  // side of the linear system A*X = B.
151  GVector<Real> B(mSize);
152  for (j0 = 0; j0 <= mYDegree; ++j0)
153  {
154  for (i0 = 0; i0 <= mXDegree; ++i0)
155  {
156  Real sum = (Real)0;
157  k0 = i0 + mXDegreeP1 * j0;
158  for (s = 0; s < numSamples; ++s)
159  {
160  Real w = observations[indices[s]][2];
161  sum += w * xPower[s][i0] * yPower[s][j0];
162  }
163 
164  B[k0] = sum;
165 
166  for (j1 = 0; j1 <= mYDegree; ++j1)
167  {
168  for (i1 = 0; i1 <= mXDegree; ++i1)
169  {
170  sum = (Real)0;
171  k1 = i1 + mXDegreeP1 * j1;
172  for (s = 0; s < numSamples; ++s)
173  {
174  sum += xPower[s][i0 + i1] * yPower[s][j0 + j1];
175  }
176 
177  A(k0, k1) = sum;
178  }
179  }
180  }
181  }
182 
183  // Solve for the polynomial coefficients.
184  GVector<Real> coefficients = Inverse(A) * B;
185  bool hasNonzero = false;
186  for (int i = 0; i < mSize; ++i)
187  {
188  mParameters[i] = coefficients[i];
189  if (coefficients[i] != (Real)0)
190  {
191  hasNonzero = true;
192  }
193  }
194  return hasNonzero;
195  }
196 
197  std::fill(mParameters.begin(), mParameters.end(), (Real)0);
198  return false;
199 }
200 
201 template <typename Real>
202 Real ApprPolynomial3<Real>::Error(std::array<Real, 3> const& observation)
203 const
204 {
205  Real w = Evaluate(observation[0], observation[1]);
206  Real error = std::abs(w - observation[2]);
207  return error;
208 }
209 
210 template <typename Real>
211 std::vector<Real> const& ApprPolynomial3<Real>::GetParameters() const
212 {
213  return mParameters;
214 }
215 
216 template <typename Real>
217 std::array<Real, 2> const& ApprPolynomial3<Real>::GetXDomain() const
218 {
219  return mXDomain;
220 }
221 
222 template <typename Real>
223 std::array<Real, 2> const& ApprPolynomial3<Real>::GetYDomain() const
224 {
225  return mYDomain;
226 }
227 
228 template <typename Real>
229 Real ApprPolynomial3<Real>::Evaluate(Real x, Real y) const
230 {
231  int i0, i1;
232  Real w;
233 
234  for (i1 = 0; i1 <= mYDegree; ++i1)
235  {
236  i0 = mXDegree;
237  w = mParameters[i0 + mXDegreeP1 * i1];
238  while (--i0 >= 0)
239  {
240  w = mParameters[i0 + mXDegreeP1 * i1] + w * x;
241  }
242  mYCoefficient[i1] = w;
243  }
244 
245  i1 = mYDegree;
246  w = mYCoefficient[i1];
247  while (--i1 >= 0)
248  {
249  w = mYCoefficient[i1] + w * y;
250  }
251 
252  return w;
253 }
254 
255 
256 }
std::vector< Real > mYCoefficient
std::vector< Real > mParameters
bool Fit(std::vector< std::array< Real, 3 >> const &observations, std::vector< int > const &indices)
gte::BSNumber< UIntegerType > abs(gte::BSNumber< UIntegerType > const &number)
Definition: GteBSNumber.h:966
std::array< Real, 2 > mYDomain
GLint GLenum GLint x
Definition: glcorearb.h:404
GLubyte GLubyte GLubyte GLubyte w
Definition: glcorearb.h:852
ApprPolynomial3(int xDegree, int yDegree)
GLsizei GLenum const void * indices
Definition: glcorearb.h:401
std::array< Real, 2 > mXDomain
std::array< Real, 2 > const & GetXDomain() const
GLdouble s
Definition: glext.h:231
Real Evaluate(Real x, Real y) const
std::array< Real, 2 > const & GetYDomain() const
Real Error(std::array< Real, 3 > const &observation) const
Quaternion< Real > Inverse(Quaternion< Real > const &d)
int GetMinimumRequired() const
GLint y
Definition: glcorearb.h:98
std::vector< Real > const & GetParameters() const


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