GteBSplineSurfaceFit.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 
11 #include <Mathematics/GteVector3.h>
13 
14 namespace gte
15 {
16 
17 template <typename Real>
19 {
20 public:
21  // Construction. The preconditions for calling the constructor are
22  // 1 <= degree0 && degree0 + 1 < numControls0 <= numSamples0
23  // 1 <= degree1 && degree1 + 1 < numControls1 <= numSamples1
24  // The sample data must be in row-major order. The control data is
25  // also stored in row-major order.
26  BSplineSurfaceFit(int degree0, int numControls0, int numSamples0,
27  int degree1, int numControls1, int numSamples1,
28  Vector3<Real> const* sampleData);
29 
30  // Access to input sample information.
31  inline int GetNumSamples(int dimension) const;
32  inline Vector3<Real> const* GetSampleData() const;
33 
34  // Access to output control point and surface information.
35  inline int GetDegree(int dimension) const;
36  inline int GetNumControls(int dimension) const;
37  inline Vector3<Real> const* GetControlData() const;
38  inline BasisFunction<Real> const& GetBasis(int dimension) const;
39 
40  // Evaluation of the B-spline surface. It is defined for 0 <= u <= 1
41  // and 0 <= v <= 1. If a parameter value is outside [0,1], it is clamped
42  // to [0,1].
43  Vector3<Real> GetPosition(Real u, Real v) const;
44 
45 private:
46  // Input sample information.
47  int mNumSamples[2];
49 
50  // The fitted B-spline surface, open and with uniform knots.
51  int mDegree[2];
52  int mNumControls[2];
53  std::vector<Vector3<Real>> mControlData;
55 };
56 
57 
58 template <typename Real>
59 BSplineSurfaceFit<Real>::BSplineSurfaceFit(int degree0, int numControls0,
60  int numSamples0, int degree1, int numControls1, int numSamples1,
61  Vector3<Real> const* sampleData)
62  :
63  mSampleData(sampleData),
64  mControlData(numControls0 * numControls1)
65 {
66  LogAssert(1 <= degree0 && degree0 + 1 < numControls0, "Invalid degree.");
67  LogAssert(numControls0 <= numSamples0, "Invalid number of controls.");
68  LogAssert(1 <= degree1 && degree1 + 1 < numControls1, "Invalid degree.");
69  LogAssert(numControls1 <= numSamples1, "Invalid number of controls.");
70  LogAssert(sampleData, "Invalid sample data.");
71 
72  mDegree[0] = degree0;
73  mNumSamples[0] = numSamples0;
74  mNumControls[0] = numControls0;
75  mDegree[1] = degree1;
76  mNumSamples[1] = numSamples1;
77  mNumControls[1] = numControls1;
78 
80  Real tMultiplier[2];
81  int dim;
82  for (dim = 0; dim < 2; ++dim)
83  {
84  input.numControls = mNumControls[dim];
85  input.degree = mDegree[dim];
86  input.uniform = true;
87  input.periodic = false;
88  input.numUniqueKnots = mNumControls[dim] - mDegree[dim] + 1;
89  input.uniqueKnots.resize(input.numUniqueKnots);
90  input.uniqueKnots[0].t = (Real)0;
91  input.uniqueKnots[0].multiplicity = mDegree[dim] + 1;
92  int last = input.numUniqueKnots - 1;
93  Real factor = ((Real)1) / (Real)last;
94  for (int i = 1; i < last; ++i)
95  {
96  input.uniqueKnots[i].t = factor * (Real)i;
97  input.uniqueKnots[i].multiplicity = 1;
98  }
99  input.uniqueKnots[last].t = (Real)1;
100  input.uniqueKnots[last].multiplicity = mDegree[dim] + 1;
101  mBasis[dim].Create(input);
102 
103  tMultiplier[dim] = ((Real)1) / (Real)(mNumSamples[dim] - 1);
104  }
105 
106  // Fit the data points with a B-spline surface using a least-squares error
107  // metric. The problem is of the form A0^T*A0*Q*A1^T*A1 = A0^T*P*A1, where
108  // A0^T*A0 and A1^T*A1 are banded matrices, P contains the sample data,
109  // and Q is the unknown matrix of control points.
110  Real t;
111  int i0, i1, i2, imin, imax;
112 
113  // Construct the matrices A0^T*A0 and A1^T*A1.
114  BandedMatrix<Real> ATAMat[2] =
115  {
116  BandedMatrix<Real>(mNumControls[0], mDegree[0] + 1, mDegree[0] + 1),
117  BandedMatrix<Real>(mNumControls[1], mDegree[1] + 1, mDegree[1] + 1)
118  };
119 
120  for (dim = 0; dim < 2; ++dim)
121  {
122  for (i0 = 0; i0 < mNumControls[dim]; ++i0)
123  {
124  for (i1 = 0; i1 < i0; ++i1)
125  {
126  ATAMat[dim](i0, i1) = ATAMat[dim](i1, i0);
127  }
128 
129  int i1Max = i0 + mDegree[dim];
130  if (i1Max >= mNumControls[dim])
131  {
132  i1Max = mNumControls[dim] - 1;
133  }
134 
135  for (i1 = i0; i1 <= i1Max; ++i1)
136  {
137  Real value = (Real)0;
138  for (i2 = 0; i2 < mNumSamples[dim]; ++i2)
139  {
140  t = tMultiplier[dim] * (Real)i2;
141  mBasis[dim].Evaluate(t, 0, imin, imax);
142  if (imin <= i0 && i0 <= imax && imin <= i1 && i1 <= imax)
143  {
144  Real b0 = mBasis[dim].GetValue(0, i0);
145  Real b1 = mBasis[dim].GetValue(0, i1);
146  value += b0 * b1;
147  }
148  }
149  ATAMat[dim](i0, i1) = value;
150  }
151  }
152  }
153 
154  // Construct the matrices A0^T and A1^T. A[d]^T has mNumControls[d]
155  // rows and mNumSamples[d] columns.
156  Array2<Real> ATMat[2];
157  for (dim = 0; dim < 2; dim++)
158  {
159  ATMat[dim] = Array2<Real>(mNumSamples[dim], mNumControls[dim]);
160  size_t numBytes = mNumControls[dim] * mNumSamples[dim] * sizeof(Real);
161  memset(ATMat[dim][0], 0, numBytes);
162  for (i0 = 0; i0 < mNumControls[dim]; ++i0)
163  {
164  for (i1 = 0; i1 < mNumSamples[dim]; ++i1)
165  {
166  t = tMultiplier[dim] * (Real)i1;
167  mBasis[dim].Evaluate(t, 0, imin, imax);
168  if (imin <= i0 && i0 <= imax)
169  {
170  ATMat[dim][i0][i1] = mBasis[dim].GetValue(0, i0);
171  }
172  }
173  }
174  }
175 
176  // Compute X0 = (A0^T*A0)^{-1}*A0^T and X1 = (A1^T*A1)^{-1}*A1^T by
177  // solving the linear systems A0^T*A0*X0 = A0^T and A1^T*A1*X1 = A1^T.
178  for (dim = 0; dim < 2; ++dim)
179  {
180  bool solved = ATAMat[dim].template SolveSystem<true>(ATMat[dim][0],
181  mNumSamples[dim]);
182  LogAssert(solved, "Failed to solve linear system.");
183  (void)solved;
184  }
185 
186  // The control points for the fitted surface are stored in the matrix
187  // Q = X0*P*X1^T, where P is the matrix of sample data.
188  for (i1 = 0; i1 < mNumControls[1]; ++i1)
189  {
190  for (i0 = 0; i0 < mNumControls[0]; ++i0)
191  {
193  for (int j1 = 0; j1 < mNumSamples[1]; ++j1)
194  {
195  Real x1Value = ATMat[1][i1][j1];
196  for (int j0 = 0; j0 < mNumSamples[0]; ++j0)
197  {
198  Real x0Value = ATMat[0][i0][j0];
199  Vector3<Real> sample =
200  mSampleData[j0 + mNumSamples[0] * j1];
201  sum += (x0Value * x1Value) * sample;
202  }
203  }
204  mControlData[i0 + mNumControls[0] * i1] = sum;
205  }
206  }
207 }
208 
209 template <typename Real> inline
211 {
212  return mNumSamples[dimension];
213 }
214 
215 template <typename Real> inline
217 {
218  return mSampleData;
219 }
220 
221 template <typename Real> inline
222 int BSplineSurfaceFit<Real>::GetDegree(int dimension) const
223 {
224  return mDegree[dimension];
225 }
226 
227 template <typename Real> inline
229 {
230  return mNumControls[dimension];
231 }
232 
233 template <typename Real> inline
235 {
236  return &mControlData[0];
237 }
238 
239 template <typename Real> inline
241 const
242 {
243  return mBasis[dimension];
244 }
245 
246 template <typename Real>
248 {
249  int iumin, iumax, ivmin, ivmax;
250  mBasis[0].Evaluate(u, 0, iumin, iumax);
251  mBasis[1].Evaluate(v, 0, ivmin, ivmax);
252 
253  Vector3<Real> position = Vector3<Real>::Zero();
254  for (int iv = ivmin; iv <= ivmax; ++iv)
255  {
256  Real value1 = mBasis[1].GetValue(0, iv);
257  for (int iu = iumin; iu <= iumax; ++iu)
258  {
259  Real value0 = mBasis[0].GetValue(0, iu);
260  Vector3<Real> control = mControlData[iu + mNumControls[0] * iv];
261  position += (value0 * value1) * control;
262  }
263  }
264  return position;
265 }
266 
267 
268 }
std::vector< Vector3< Real > > mControlData
Vector3< Real > const * GetControlData() const
BasisFunction< Real > const & GetBasis(int dimension) const
#define LogAssert(condition, message)
Definition: GteLogger.h:86
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLsizei const GLfloat * value
Definition: glcorearb.h:819
BSplineSurfaceFit(int degree0, int numControls0, int numSamples0, int degree1, int numControls1, int numSamples1, Vector3< Real > const *sampleData)
Vector3< Real > GetPosition(Real u, Real v) const
Vector3< Real > const * GetSampleData() const
int GetNumSamples(int dimension) const
static Vector Zero()
Definition: GteVector.h:295
Vector3< Real > const * mSampleData
GLdouble GLdouble t
Definition: glext.h:239
BasisFunction< Real > mBasis[2]
const GLdouble * v
Definition: glcorearb.h:832
GLenum GLenum GLenum input
Definition: glext.h:9913
int GetNumControls(int dimension) const
std::vector< UniqueKnot< Real > > uniqueKnots
int GetDegree(int dimension) const


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