TrinityCore
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
G3D::Spline< Control > Class Template Reference

#include <Spline.h>

Public Member Functions

 Spline ()
 
void append (float t, const Control &c)
 
void append (const Control &c)
 
void clear ()
 
int size () const
 
void getControl (int i, float &t, Control &c) const
 
 Spline (const Any &any)
 
virtual Any toAny (const std::string &myName) const
 
Control evaluate (float s) const
 
- Public Member Functions inherited from G3D::SplineBase
 SplineBase ()
 
virtual ~SplineBase ()
 
float getFinalInterval () const
 
float duration () const
 
void computeIndex (float s, int &i, float &u) const
 

Public Attributes

Array< Control > control
 
- Public Attributes inherited from G3D::SplineBase
Array< float > time
 
SplineExtrapolationMode extrapolationMode
 
float finalInterval
 
SplineInterpolationMode interpolationMode
 

Protected Member Functions

void getControls (int i, float *T, Control *A, int N) const
 
virtual void ensureShortestPath (Control *A, int N) const
 
virtual void correct (Control &A) const
 
virtual void init (AnyTableReader &propertyTable)
 
- Protected Member Functions inherited from G3D::SplineBase
void computeIndexInBounds (float s, int &i, float &u) const
 

Protected Attributes

Control zero
 

Additional Inherited Members

- Static Public Member Functions inherited from G3D::SplineBase
static Matrix4 computeBasis ()
 

Detailed Description

template<typename Control>
class G3D::Spline< Control >

Smooth parameteric curve implemented using a piecewise 3rd-order Catmull-Rom spline curve. The spline is considered infinite and may either continue linearly from the specified control points or cycle through them. Control points are spaced uniformly in time at unit intervals by default, but irregular spacing may be explicitly specified.

The dimension of the spline can be set by varying the Control template parameter. For a 1D function, use Spline<float>. For a curve in the plane, Spline<Vector2>. Note that any template parameter that supports operator+(Control) and operator*(float) can be used; you can make splines out of G3D::Vector4, G3D::Matrix3, or your own classes.

To provide shortest-path interpolation, subclass G3D::Spline and override ensureShortestPath(). To provide normalization of interpolated points (e.g., projecting Quats onto the unit hypersphere) override correct().

See Real Time Rendering, 2nd edition, ch 12 for a general discussion of splines and their properties.

See also
G3D::UprightSpline

Constructor & Destructor Documentation

template<typename Control>
G3D::Spline< Control >::Spline ( )
inline
126  {
127  static Control x;
128  // Hide the fact from C++ that we are using an
129  // uninitialized variable here by pointer arithmetic.
130  // This is ok because any type that is a legal control
131  // point also supports multiplication by float.
132  zero = *(&x) * 0.0f;
133  }
Control zero
Definition: Spline.h:118
G3D::int16 x
Definition: Vector2int16.h:37
template<typename Control>
G3D::Spline< Control >::Spline ( const Any any)
inlineexplicit

Accepts a table of properties, or any valid PhysicsFrame specification for a single control

324  {
325  AnyTableReader propertyTable(any);
326  init(propertyTable);
327  propertyTable.verifyDone();
328  }
bool any(float x)
Definition: g3dmath.h:424
virtual void init(AnyTableReader &propertyTable)
Definition: Spline.h:303

Member Function Documentation

template<typename Control>
void G3D::Spline< Control >::append ( float  t,
const Control &  c 
)
inline

Appends a control point at a specific time that must be greater than that of the previous point.

137  {
138  debugAssertM((time.size() == 0) || (t > time.last()),
139  "Control points must have monotonically increasing times.");
140  time.append(t);
141  control.append(c);
142  debugAssert(control.size() == time.size());
143  }
const T & last() const
Definition: Array.h:923
Array< float > time
Definition: Spline.h:26
#define debugAssertM(exp, message)
Definition: debugAssert.h:161
#define debugAssert(exp)
Definition: debugAssert.h:160
int size() const
Definition: Array.h:430
Array< Control > control
Definition: Spline.h:124
void append(const T &value)
Definition: Array.h:583

+ Here is the caller graph for this function:

template<typename Control>
void G3D::Spline< Control >::append ( const Control &  c)
inline

Appends control point spaced in time based on the previous control point, or spaced at unit intervals if this is the first control point.

149  {
150  switch (time.size()) {
151  case 0:
152  append(0, c);
153  break;
154 
155  case 1:
156  append(time[0] + 1, c);
157  break;
158 
159  default:
160  append(2 * time[time.size() - 1] - time[time.size() - 2], c);
161  }
162  debugAssert(control.size() == time.size());
163  }
Array< float > time
Definition: Spline.h:26
void append(float t, const Control &c)
Definition: Spline.h:137
#define debugAssert(exp)
Definition: debugAssert.h:160
int size() const
Definition: Array.h:430
Array< Control > control
Definition: Spline.h:124
template<typename Control>
void G3D::Spline< Control >::clear ( )
inline

Erases all control points and times, but retains the state of cyclic and finalInterval.

168  {
169  control.clear();
170  time.clear();
171  }
Array< float > time
Definition: Spline.h:26
void clear(bool shrink=true)
Definition: Array.h:407
Array< Control > control
Definition: Spline.h:124
template<typename Control>
virtual void G3D::Spline< Control >::correct ( Control &  A) const
inlineprotectedvirtual

Normalize or otherwise adjust this interpolated Control.

Reimplemented in G3D::PhysicsFrameSpline.

300 { (void)A; }

+ Here is the caller graph for this function:

template<typename Control>
virtual void G3D::Spline< Control >::ensureShortestPath ( Control *  A,
int  N 
) const
inlineprotectedvirtual

Mutates the array of N control points that begins at A. It is useful to override this method by one that wraps the values if they are angles or quaternions for which "shortest path" interpolation is significant.

Reimplemented in G3D::UprightSpline, and G3D::PhysicsFrameSpline.

297 { (void)A; (void) N;}

+ Here is the caller graph for this function:

template<typename Control>
Control G3D::Spline< Control >::evaluate ( float  s) const
inline

Return the position at time s. The spline is defined outside of the time samples by extrapolation or cycling.

348  {
349  debugAssertM(control.size() == time.size(), "Corrupt spline: wrong number of control points.");
350 
351  /*
352  @cite http://www.gamedev.net/reference/articles/article1497.asp
353  Derivation of basis matrix follows.
354 
355  Given control points with positions p[i] at times t[i], 0 <= i <= 3, find the position
356  at time t[1] <= s <= t[2].
357 
358  Let u = s - t[0]
359  Let U = [u^0 u^1 u^2 u^3] = [1 u u^2 u^3]
360  Let dt0 = t[0] - t[-1]
361  Let dt1 = t[1] - t[0]
362  Let dt2 = t[2] - t[1]
363  */
364 
365  // Index of the first control point (i.e., the u = 0 point)
366  int i = 0;
367  // Fractional part of the time
368  float u = 0;
369 
370  computeIndex(s, i, u);
371 
372  Control p[4];
373  float t[4];
374  getControls(i - 1, t, p, 4);
375 
376  const Control& p0 = p[0];
377  const Control& p1 = p[1];
378  const Control& p2 = p[2];
379  const Control& p3 = p[3];
380 
381  // Compute the weighted sum of the neighboring control points.
382  Control sum;
383 
385  const float a = (s - t[1]) / (t[2] - t[1]);
386  sum = p1 * (1.0f - a) + p2 * a;
387  correct(sum);
388  return sum;
389  }
390 
391  float dt0 = t[1] - t[0];
392  float dt1 = t[2] - t[1];
393  float dt2 = t[3] - t[2];
394 
395  static const Matrix4 basis = computeBasis();
396 
397  // Powers of u
398  Vector4 uvec((float)(u*u*u), (float)(u*u), (float)u, 1.0f);
399 
400  // Compute the weights on each of the control points.
401  const Vector4& weights = uvec * basis;
402 
403 
404  // The factor of 1/2 from averaging two time intervals is
405  // already factored into the basis
406 
407  // tan1 = (dp0 / dt0 + dp1 / dt1) * ((dt0 + dt1) * 0.5);
408  // The last term normalizes for unequal time intervals
409  float x = (dt0 + dt1) * 0.5f;
410  float n0 = x / dt0;
411  float n1 = x / dt1;
412  float n2 = x / dt2;
413 
414  const Control& dp0 = p1 + (p0*-1.0f);
415  const Control& dp1 = p2 + (p1*-1.0f);
416  const Control& dp2 = p3 + (p2*-1.0f);
417 
418  const Control& dp1n1 = dp1 * n1;
419  const Control& tan1 = dp0 * n0 + dp1n1;
420  const Control& tan2 = dp1n1 + dp2 * n2;
421 
422  sum =
423  tan1 * weights[0] +
424  p1 * weights[1] +
425  p2 * weights[2] +
426  tan2 * weights[3];
427 
428 
429  correct(sum);
430  return sum;
431  }
void computeIndex(float s, int &i, float &u) const
Definition: SplineBase.cpp:90
Definition: SplineExtrapolationMode.h:66
virtual void correct(Control &A) const
Definition: Spline.h:300
Array< float > time
Definition: Spline.h:26
#define debugAssertM(exp, message)
Definition: debugAssert.h:161
void getControls(int i, float *T, Control *A, int N) const
Definition: Spline.h:285
static Matrix4 computeBasis()
Definition: SplineBase.cpp:22
int size() const
Definition: Array.h:430
Array< Control > control
Definition: Spline.h:124
SplineInterpolationMode interpolationMode
Definition: Spline.h:44
G3D::int16 x
Definition: Vector2int16.h:37
template<typename Control>
void G3D::Spline< Control >::getControl ( int  i,
float &  t,
Control &  c 
) const
inline

Returns the requested control point and time sample based on array index. If the array index is out of bounds, wraps (for a cyclic spline) or linearly extrapolates (for a non-cyclic spline), assuming time intervals follow the first or last sample recorded.

Calls correct() on the control point if it was extrapolated.

Returns 0 if there are no control points.

See also
Spline::control and Spline::time for the underlying control point array; Spline::computeIndex to find the index given a time.
195  {
196  int N = control.size();
197  if (N == 0) {
198  c = zero;
199  t = 0;
201  c = control[iWrap(i, N)];
202 
203  if (i < 0) {
204  // Wrapped around bottom
205 
206  // Number of times we wrapped around the cyclic array
207  int wraps = (N + 1 - i) / N;
208  int j = (i + wraps * N) % N;
209  t = time[j] - wraps * duration();
210 
211  } else if (i < N) {
212 
213  t = time[i];
214 
215  } else {
216  // Wrapped around top
217 
218  // Number of times we wrapped around the cyclic array
219  int wraps = i / N;
220  int j = i % N;
221  t = time[j] + wraps * duration();
222  }
223 
224  } else if (i < 0) {
225  // Are there enough points to extrapolate?
226  if (N >= 2) {
227  // Step away from control point 0
228  float dt = time[1] - time[0];
229 
231  // Extrapolate (note; i is negative)
232  c = control[1] * float(i) + control[0] * float(1 - i);
233  correct(c);
235  // Return the first, clamping
236  c = control[0];
237  } else {
238  alwaysAssertM(false, "Invalid extrapolation mode");
239  }
240  t = dt * i + time[0];
241 
242  } else {
243  // Just clamp
244  c = control[0];
245 
246  // Only 1 time; assume 1s intervals
247  t = time[0] + i;
248  }
249 
250  } else if (i >= N) {
251  if (N >= 2) {
252  float dt = time[N - 1] - time[N - 2];
253 
255  // Extrapolate (note; i is negative)
256  c = control[N - 1] * float(i - N + 2) + control[N - 2] * -float(i - N + 1);
257  correct(c);
259  // Return the last, clamping
260  c = control.last();
261  } else {
262  alwaysAssertM(false, "Invalid extrapolation mode");
263  }
264  // Extrapolate
265  t = time[N - 1] + dt * (i - N + 1);
266 
267  } else {
268  // Return the last, clamping
269  c = control.last();
270  // Only 1 time; assume 1s intervals
271  t = time[0] + i;
272  }
273  } else {
274  // In bounds
275  c = control[i];
276  t = time[i];
277  }
278  }
virtual void correct(Control &A) const
Definition: Spline.h:300
SplineExtrapolationMode extrapolationMode
Definition: Spline.h:33
Definition: SplineExtrapolationMode.h:36
Control zero
Definition: Spline.h:118
Definition: SplineExtrapolationMode.h:35
Definition: SplineExtrapolationMode.h:34
const T & last() const
Definition: Array.h:923
Array< float > time
Definition: Spline.h:26
int size() const
Definition: Array.h:430
float duration() const
Definition: SplineBase.cpp:52
int iWrap(int val, int hi)
Definition: g3dmath.h:594
Array< Control > control
Definition: Spline.h:124
#define alwaysAssertM(exp, message)
Definition: debugAssert.h:165

+ Here is the caller graph for this function:

template<typename Control>
void G3D::Spline< Control >::getControls ( int  i,
float *  T,
Control *  A,
int  N 
) const
inlineprotected

Returns a series of N control points and times, fixing boundary issues. The indices may be assumed to be treated cyclically.

285  {
286  for (int j = 0; j < N; ++j) {
287  getControl(i + j, T[j], A[j]);
288  }
289  ensureShortestPath(A, N);
290  }
void getControl(int i, float &t, Control &c) const
Definition: Spline.h:195
virtual void ensureShortestPath(Control *A, int N) const
Definition: Spline.h:297

+ Here is the caller graph for this function:

template<typename Control>
virtual void G3D::Spline< Control >::init ( AnyTableReader propertyTable)
inlineprotectedvirtual

Does not invoke verifyDone() on the propertyTable because subclasses may have more properties

303  {
304  propertyTable.getIfPresent("extrapolationMode", extrapolationMode);
305  propertyTable.getIfPresent("interpolationMode", interpolationMode);
306  propertyTable.getIfPresent("finalInterval", finalInterval);
307 
308  const bool hasTime = propertyTable.getIfPresent("time", time);
309 
310  if (propertyTable.getIfPresent("control", control)) {
311  if (! hasTime) {
312  // Assign unit times
313  time.resize(control.size());
314  for (int i = 0; i < time.size(); ++i) {
315  time[i] = float(i);
316  }
317  } // if has time
318  } // if has control
319  } // init
SplineExtrapolationMode extrapolationMode
Definition: Spline.h:33
void resize(size_t n, bool shrinkIfNecessary=true)
Definition: Array.h:490
float finalInterval
Definition: Spline.h:42
Array< float > time
Definition: Spline.h:26
int size() const
Definition: Array.h:430
Array< Control > control
Definition: Spline.h:124
SplineInterpolationMode interpolationMode
Definition: Spline.h:44

+ Here is the caller graph for this function:

template<typename Control>
int G3D::Spline< Control >::size ( ) const
inline

Number of control points

175  {
176  debugAssert(time.size() == control.size());
177  return control.size();
178  }
Array< float > time
Definition: Spline.h:26
#define debugAssert(exp)
Definition: debugAssert.h:160
int size() const
Definition: Array.h:430
Array< Control > control
Definition: Spline.h:124

+ Here is the caller graph for this function:

template<typename Control>
virtual Any G3D::Spline< Control >::toAny ( const std::string &  myName) const
inlinevirtual

Note that invoking classes can call setName on the returned value instead of passing a name in.

Reimplemented in G3D::UprightSpline, and G3D::PhysicsFrameSpline.

331  {
332  Any a(Any::TABLE, myName);
333 
334  a["extrapolationMode"] = extrapolationMode;
335  a["interpolationMode"] = interpolationMode;
336  a["control"] = Any(control);
337  a["time"] = Any(time);
338  a["finalInterval"] = finalInterval;
339 
340  return a;
341  }
Definition: Any.h:187
SplineExtrapolationMode extrapolationMode
Definition: Spline.h:33
float finalInterval
Definition: Spline.h:42
Array< float > time
Definition: Spline.h:26
Array< Control > control
Definition: Spline.h:124
SplineInterpolationMode interpolationMode
Definition: Spline.h:44

+ Here is the caller graph for this function:

Member Data Documentation

template<typename Control>
Array<Control> G3D::Spline< Control >::control

Control points. Must have the same number of elements as Spline::time.

template<typename Control>
Control G3D::Spline< Control >::zero
protected

The additive identity control point.


The documentation for this class was generated from the following file: