GteNaturalSplineCurve.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>
11 #include <Mathematics/GteGMatrix.h>
13 
14 namespace gte
15 {
16 
17 template <int N, typename Real>
18 class NaturalSplineCurve : public ParametricCurve<N, Real>
19 {
20 public:
21  // Construction and destruction. The object copies the input arrays. The
22  // number of points M must be at least 2. The first constructor is for a
23  // spline with second derivatives zero at the endpoints (isFree = true)
24  // or a spline that is closed (isFree = false). The second constructor is
25  // for clamped splines, where you specify the first derivatives at the
26  // endpoints. Usually, derivative0 = points[1] - points[0] at the first
27  // point and derivative1 = points[M-1] - points[M-2]. To validate
28  // construction, create an object as shown:
29  // NaturalSplineCurve<N, Real> curve(parameters);
30  // if (!curve) { <constructor failed, handle accordingly>; }
31  virtual ~NaturalSplineCurve();
32  NaturalSplineCurve(bool isFree, int numPoints,
33  Vector<N, Real> const* points, Real const* times);
34  NaturalSplineCurve(int numPoints, Vector<N, Real> const* points,
35  Real const* times, Vector<N, Real> const& derivative0,
36  Vector<N, Real> const& derivative1);
37 
38  // Member access.
39  inline int GetNumPoints() const;
40  inline Vector<N, Real> const* GetPoints() const;
41 
42  // Evaluation of the curve. The function supports derivative calculation
43  // through order 3; that is, maxOrder <= 3 is required. If you want
44  // only the position, pass in maxOrder of 0. If you want the position and
45  // first derivative, pass in maxOrder of 1, and so on. The output
46  // 'values' are ordered as: position, first derivative, second derivative,
47  // third derivative.
48  virtual void Evaluate(Real t, unsigned int maxOrder,
49  Vector<N, Real> values[4]) const;
50 
51 protected:
52  // Support for construction.
53  void CreateFree();
54  void CreateClosed();
55  void CreateClamped(Vector<N, Real> const& derivative0,
56  Vector<N, Real> const& derivative1);
57 
58  // Determine the index i for which times[i] <= t < times[i+1].
59  void GetKeyInfo(Real t, int& key, Real& dt) const;
60 
61  // Polynomial coefficients. mA are the points (constant coefficients of
62  // polynomials. mB are the degree 1 coefficients, mC are the degree 2
63  // coefficients, and mD are the degree 3 coefficients.
64  std::vector<Vector<N, Real>> mA, mB, mC, mD;
65 };
66 
67 
68 template <int N, typename Real>
70 {
71 }
72 
73 template <int N, typename Real>
75  Vector<N, Real> const* points, Real const* times)
76  :
77  ParametricCurve<N, Real>(numPoints - 1, times)
78 {
79  if (numPoints < 2 || !points)
80  {
81  LogError("Invalid input.");
82  return;
83  }
84 
85  mA.resize(numPoints);
86  std::copy(points, points + numPoints, mA.begin());
87 
88  if (isFree)
89  {
90  CreateFree();
91  }
92  else
93  {
94  CreateClosed();
95  }
96 
97  this->mConstructed = true;
98 }
99 
100 template <int N, typename Real>
102  Vector<N, Real> const* points, Real const* times,
103  Vector<N, Real> const& derivative0, Vector<N, Real> const& derivative1)
104  :
105  ParametricCurve<N, Real>(numPoints - 1, times)
106 {
107  if (numPoints < 2 || !points)
108  {
109  LogError("Invalid input.");
110  return;
111  }
112 
113  mA.resize(numPoints);
114  std::copy(points, points + numPoints, mA.begin());
115 
116  CreateClamped(derivative0, derivative1);
117  this->mConstructed = true;
118 }
119 
120 template <int N, typename Real> inline
122 {
123  return static_cast<int>(mA.size());
124 }
125 
126 template <int N, typename Real> inline
128 {
129  return &mA[0];
130 }
131 
132 template <int N, typename Real>
133 void NaturalSplineCurve<N, Real>::Evaluate(Real t, unsigned int maxOrder,
134  Vector<N, Real> values[4]) const
135 {
136  if (!this->mConstructed)
137  {
138  // Errors were already generated during construction.
139  for (unsigned int order = 0; order < 4; ++order)
140  {
141  values[order].MakeZero();
142  }
143  return;
144  }
145 
146  int key;
147  Real dt;
148  GetKeyInfo(t, key, dt);
149 
150  // Compute position.
151  values[0] = mA[key] + dt * (mB[key] + dt * (mC[key] + dt * mD[key]));
152  if (maxOrder >= 1)
153  {
154  // Compute first derivative.
155  values[1] = mB[key] + dt * (((Real)2) * mC[key] +
156  ((Real)3) * dt * mD[key]);
157  if (maxOrder >= 2)
158  {
159  // Compute second derivative.
160  values[2] = ((Real)2) * mC[key] + ((Real)6) * dt * mD[key];
161  if (maxOrder == 3)
162  {
163  values[3] = ((Real)6) * mD[key];
164  }
165  else
166  {
167  values[3].MakeZero();
168  }
169  }
170  }
171 }
172 
173 template <int N, typename Real>
175 {
176  int numSegments = GetNumPoints() - 1;
177  std::vector<Real> dt(numSegments);
178  for (int i = 0; i < numSegments; ++i)
179  {
180  dt[i] = this->mTime[i + 1] - this->mTime[i];
181  }
182 
183  std::vector<Real> d2t(numSegments);
184  for (int i = 1; i < numSegments; ++i)
185  {
186  d2t[i] = this->mTime[i + 1] - this->mTime[i - 1];
187  }
188 
189  std::vector<Vector<N, Real>> alpha(numSegments);
190  for (int i = 1; i < numSegments; ++i)
191  {
192  Vector<N, Real> numer = ((Real)3)*(dt[i - 1] * mA[i + 1] -
193  d2t[i] * mA[i] + dt[i] * mA[i - 1]);
194  Real invDenom = ((Real)1) / (dt[i - 1] * dt[i]);
195  alpha[i] = invDenom * numer;
196  }
197 
198  std::vector<Real> ell(numSegments + 1);
199  std::vector<Real> mu(numSegments);
200  std::vector<Vector<N, Real>> z(numSegments + 1);
201  Real inv;
202 
203  ell[0] = (Real)1;
204  mu[0] = (Real)0;
205  z[0].MakeZero();
206  for (int i = 1; i < numSegments; ++i)
207  {
208  ell[i] = ((Real)2) * d2t[i] - dt[i - 1] * mu[i - 1];
209  inv = ((Real)1) / ell[i];
210  mu[i] = inv * dt[i];
211  z[i] = inv * (alpha[i] - dt[i - 1] * z[i - 1]);
212  }
213  ell[numSegments] = (Real)1;
214  z[numSegments].MakeZero();
215 
216  mB.resize(numSegments);
217  mC.resize(numSegments + 1);
218  mD.resize(numSegments);
219 
220  Real oneThird = ((Real)1) / (Real)3;
221  mC[numSegments].MakeZero();
222  for (int i = numSegments - 1; i >= 0; --i)
223  {
224  mC[i] = z[i] - mu[i] * mC[i + 1];
225  inv = ((Real)1) / dt[i];
226  mB[i] = inv * (mA[i + 1] - mA[i]) - oneThird * dt[i] * (mC[i + 1] +
227  ((Real)2) * mC[i]);
228  mD[i] = oneThird * inv * (mC[i + 1] - mC[i]);
229  }
230 }
231 
232 template <int N, typename Real>
234 {
235  // TODO: A general linear system solver is used here. The matrix
236  // corresponding to this case is actually "cyclic banded", so a faster
237  // linear solver can be used. The current linear system code does not
238  // have such a solver.
239 
240  int numSegments = GetNumPoints() - 1;
241  std::vector<Real> dt(numSegments);
242  for (int i = 0; i < numSegments; ++i)
243  {
244  dt[i] = this->mTime[i + 1] - this->mTime[i];
245  }
246 
247  // Construct matrix of system.
248  GMatrix<Real> mat(numSegments + 1, numSegments + 1);
249  mat(0, 0) = (Real)1;
250  mat(0, numSegments) = (Real)-1;
251  for (int i = 1; i <= numSegments - 1; ++i)
252  {
253  mat(i, i - 1) = dt[i - 1];
254  mat(i, i) = ((Real)2) * (dt[i - 1] + dt[i]);
255  mat(i, i + 1) = dt[i];
256  }
257  mat(numSegments, numSegments - 1) = dt[numSegments - 1];
258  mat(numSegments, 0) = ((Real)2) * (dt[numSegments - 1] + dt[0]);
259  mat(numSegments, 1) = dt[0];
260 
261  // Construct right-hand side of system.
262  mC.resize(numSegments + 1);
263  mC[0].MakeZero();
264  Real inv0, inv1;
265  for (int i = 1; i <= numSegments - 1; ++i)
266  {
267  inv0 = ((Real)1) / dt[i];
268  inv1 = ((Real)1) / dt[i - 1];
269  mC[i] = ((Real)3) * (inv0 * (mA[i + 1] - mA[i]) -
270  inv1*(mA[i] - mA[i - 1]));
271  }
272  inv0 = ((Real)1) / dt[0];
273  inv1 = ((Real)1) / dt[numSegments - 1];
274  mC[numSegments] = ((Real)3) * (inv0 * (mA[1] - mA[0]) -
275  inv1 * (mA[0] - mA[numSegments - 1]));
276 
277  // Solve the linear systems.
278  GMatrix<Real> invMat = Inverse(mat);
279  GVector<Real> input(numSegments + 1);
280  GVector<Real> output(numSegments + 1);
281  for (int j = 0; j < N; ++j)
282  {
283  for (int i = 0; i <= numSegments; ++i)
284  {
285  input[i] = mC[i][j];
286  }
287  output = invMat * input;
288  for (int i = 0; i <= numSegments; ++i)
289  {
290  mC[i][j] = output[i];
291  }
292  }
293 
294  Real oneThird = ((Real)1) / (Real)3;
295  mB.resize(numSegments);
296  mD.resize(numSegments);
297  for (int i = 0; i < numSegments; ++i)
298  {
299  inv0 = ((Real)1) / dt[i];
300  mB[i] = inv0 * (mA[i + 1] - mA[i]) - oneThird * (mC[i + 1] +
301  ((Real)2) * mC[i]) * dt[i];
302  mD[i] = oneThird * inv0 * (mC[i + 1] - mC[i]);
303  }
304 }
305 
306 template <int N, typename Real>
308  Vector<N, Real> const& derivative0, Vector<N, Real> const& derivative1)
309 {
310  int numSegments = GetNumPoints() - 1;
311  std::vector<Real> dt(numSegments);
312  for (int i = 0; i < numSegments; ++i)
313  {
314  dt[i] = this->mTime[i + 1] - this->mTime[i];
315  }
316 
317  std::vector<Real> d2t(numSegments);
318  for (int i = 1; i < numSegments; ++i)
319  {
320  d2t[i] = this->mTime[i + 1] - this->mTime[i - 1];
321  }
322 
323  std::vector<Vector<N, Real>> alpha(numSegments + 1);
324  Real inv = ((Real)1) / dt[0];
325  alpha[0] = ((Real)3) * (inv * (mA[1] - mA[0]) - derivative0);
326  inv = ((Real)1) / dt[numSegments - 1];
327  alpha[numSegments] = ((Real)3)*(derivative1 -
328  inv * (mA[numSegments] - mA[numSegments - 1]));
329  for (int i = 1; i < numSegments; ++i)
330  {
331  Vector<N, Real> numer = ((Real)3)*(dt[i - 1] * mA[i + 1] -
332  d2t[i] * mA[i] + dt[i] * mA[i - 1]);
333  Real invDenom = ((Real)1) / (dt[i - 1] * dt[i]);
334  alpha[i] = invDenom*numer;
335  }
336 
337  std::vector<Real> ell(numSegments + 1);
338  std::vector<Real> mu(numSegments);
339  std::vector<Vector<N, Real>> z(numSegments + 1);
340 
341  ell[0] = ((Real)2) * dt[0];
342  mu[0] = (Real)0.5;
343  inv = ((Real)1) / ell[0];
344  z[0] = inv * alpha[0];
345 
346  for (int i = 1; i < numSegments; ++i)
347  {
348  ell[i] = ((Real)2) * d2t[i] - dt[i - 1] * mu[i - 1];
349  inv = ((Real)1) / ell[i];
350  mu[i] = inv * dt[i];
351  z[i] = inv * (alpha[i] - dt[i - 1] * z[i - 1]);
352  }
353  ell[numSegments] = dt[numSegments - 1] *
354  (((Real)2) - mu[numSegments - 1]);
355  inv = ((Real)1) / ell[numSegments];
356  z[numSegments] = inv * (alpha[numSegments] - dt[numSegments - 1] *
357  z[numSegments - 1]);
358 
359  mB.resize(numSegments);
360  mC.resize(numSegments + 1);
361  mD.resize(numSegments);
362 
363  Real oneThird = ((Real)1) / (Real)3;
364  mC[numSegments] = z[numSegments];
365  for (int i = numSegments - 1; i >= 0; --i)
366  {
367  mC[i] = z[i] - mu[i] * mC[i + 1];
368  inv = ((Real)1) / dt[i];
369  mB[i] = inv * (mA[i + 1] - mA[i]) - oneThird*dt[i] * (mC[i + 1] +
370  ((Real)2) * mC[i]);
371  mD[i] = oneThird * inv * (mC[i + 1] - mC[i]);
372  }
373 }
374 
375 template <int N, typename Real>
376 void NaturalSplineCurve<N, Real>::GetKeyInfo(Real t, int& key, Real& dt) const
377 {
378  int numSegments = GetNumPoints() - 1;
379  if (t <= this->mTime[0])
380  {
381  key = 0;
382  dt = (Real)0;
383  }
384  else if (t >= this->mTime[numSegments])
385  {
386  key = numSegments - 1;
387  dt = this->mTime[numSegments] - this->mTime[numSegments - 1];
388  }
389  else
390  {
391  for (int i = 0; i < numSegments; ++i)
392  {
393  if (t < this->mTime[i + 1])
394  {
395  key = i;
396  dt = t - this->mTime[i];
397  break;
398  }
399  }
400  }
401 }
402 
403 
404 }
std::vector< Vector< N, Real > > mA
Vector< N, Real > const * GetPoints() const
void MakeZero()
Definition: GteVector.h:279
GLfloat GLfloat GLfloat alpha
Definition: glcorearb.h:107
GLfixed GLfixed GLint GLint order
Definition: glext.h:4927
virtual void Evaluate(Real t, unsigned int maxOrder, Vector< N, Real > values[4]) const
std::vector< Real > mTime
void GetKeyInfo(Real t, int &key, Real &dt) const
std::vector< Vector< N, Real > > mB
GLenum GLsizei GLsizei GLint * values
Definition: glcorearb.h:1597
void CreateClamped(Vector< N, Real > const &derivative0, Vector< N, Real > const &derivative1)
NaturalSplineCurve(bool isFree, int numPoints, Vector< N, Real > const *points, Real const *times)
GLfixed GLfixed GLint GLint GLfixed points
Definition: glext.h:4927
#define LogError(message)
Definition: GteLogger.h:92
GLdouble GLdouble t
Definition: glext.h:239
GLdouble GLdouble GLdouble z
Definition: glcorearb.h:843
GLenum GLenum GLenum input
Definition: glext.h:9913
std::vector< Vector< N, Real > > mD
GLsizei GLsizei numSegments
Definition: glext.h:9703
Quaternion< Real > Inverse(Quaternion< Real > const &d)
std::vector< Vector< N, Real > > mC


geometric_tools_engine
Author(s): Yijiang Huang
autogenerated on Thu Jul 18 2019 04:00:01