TrinityCore
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Spline.h
Go to the documentation of this file.
1 
7 #ifndef G3D_Spline_h
8 #define G3D_Spline_h
9 
10 #include "G3D/platform.h"
11 #include "G3D/Array.h"
12 #include "G3D/g3dmath.h"
13 #include "G3D/Matrix4.h"
14 #include "G3D/Vector4.h"
15 #include "G3D/Any.h"
17 
18 namespace G3D {
19 
21 class SplineBase {
22 public:
23 
27 
34 
43 
45 
47  extrapolationMode(SplineExtrapolationMode::CYCLIC),
48  finalInterval(-1),
49  interpolationMode(SplineInterpolationMode::CUBIC) {}
50 
51  virtual ~SplineBase() {}
52 
55  float getFinalInterval() const;
56 
60  float duration() const;
61 
63  static Matrix4 computeBasis();
64 
65 protected:
66 
68  void computeIndexInBounds(float s, int& i, float& u) const;
69 
70 public:
71 
85  void computeIndex(float s, int& i, float& u) const;
86 };
87 
88 
114 template<typename Control>
115 class Spline : public SplineBase {
116 protected:
118  Control zero;
119 
120 public:
121 
125 
126  Spline() {
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  }
134 
137  void append(float t, const Control& c) {
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  }
144 
145 
149  void append(const Control& c) {
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  }
164 
168  void clear() {
169  control.clear();
170  time.clear();
171  }
172 
173 
175  int size() const {
176  debugAssert(time.size() == control.size());
177  return control.size();
178  }
179 
180 
195  void getControl(int i, float& t, Control& c) const {
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  }
279 
280 protected:
281 
285  void getControls(int i, float* T, Control* A, int N) const {
286  for (int j = 0; j < N; ++j) {
287  getControl(i + j, T[j], A[j]);
288  }
289  ensureShortestPath(A, N);
290  }
291 
297  virtual void ensureShortestPath(Control* A, int N) const { (void)A; (void) N;}
298 
300  virtual void correct(Control& A) const { (void)A; }
301 
303  virtual void init(AnyTableReader& propertyTable) {
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
320 
321 public:
322 
324  explicit Spline(const Any& any) {
325  AnyTableReader propertyTable(any);
326  init(propertyTable);
327  propertyTable.verifyDone();
328  }
329 
331  virtual Any toAny(const std::string& myName) const {
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  }
342 
343 
348  Control evaluate(float s) const {
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  }
432 };
433 
434 }
435 
436 #endif
void computeIndex(float s, int &i, float &u) const
Definition: SplineBase.cpp:90
Definition: Any.h:187
void computeIndexInBounds(float s, int &i, float &u) const
Definition: SplineBase.cpp:61
Definition: SplineExtrapolationMode.h:66
virtual void correct(Control &A) const
Definition: Spline.h:300
SplineExtrapolationMode extrapolationMode
Definition: Spline.h:33
Definition: SplineExtrapolationMode.h:36
bool getIfPresent(const std::string &s, ValueType &v)
Definition: Any.h:989
Control zero
Definition: Spline.h:118
void resize(size_t n, bool shrinkIfNecessary=true)
Definition: Array.h:490
float finalInterval
Definition: Spline.h:42
Definition: Spline.h:115
Definition: SplineExtrapolationMode.h:35
Definition: SplineExtrapolationMode.h:34
virtual Any toAny(const std::string &myName) const
Definition: Spline.h:331
virtual ~SplineBase()
Definition: Spline.h:51
Definition: AABox.h:25
void getControl(int i, float &t, Control &c) const
Definition: Spline.h:195
bool any(float x)
Definition: g3dmath.h:424
const T & last() const
Definition: Array.h:923
Definition: Any.h:890
Array< float > time
Definition: Spline.h:26
virtual void ensureShortestPath(Control *A, int N) const
Definition: Spline.h:297
Spline(const Any &any)
Definition: Spline.h:324
Definition: SplineExtrapolationMode.h:30
#define debugAssertM(exp, message)
Definition: debugAssert.h:161
SplineBase()
Definition: Spline.h:46
Control evaluate(float s) const
Definition: Spline.h:348
int size() const
Definition: Spline.h:175
void getControls(int i, float *T, Control *A, int N) const
Definition: Spline.h:285
float getFinalInterval() const
Definition: SplineBase.cpp:6
void append(float t, const Control &c)
Definition: Spline.h:137
static Matrix4 computeBasis()
Definition: SplineBase.cpp:22
Definition: Matrix4.h:36
Easy loading and saving of human-readable configuration files.
Definition: Any.h:184
#define debugAssert(exp)
Definition: debugAssert.h:160
Definition: Vector4.h:39
void append(const Control &c)
Definition: Spline.h:149
void clear(bool shrink=true)
Definition: Array.h:407
Definition: SplineExtrapolationMode.h:62
virtual void init(AnyTableReader &propertyTable)
Definition: Spline.h:303
int size() const
Definition: Array.h:430
Definition: Spline.h:21
float duration() const
Definition: SplineBase.cpp:52
int iWrap(int val, int hi)
Definition: g3dmath.h:594
void verifyDone() const
Definition: AnyTableReader.cpp:33
Array< Control > control
Definition: Spline.h:124
SplineInterpolationMode interpolationMode
Definition: Spline.h:44
void clear()
Definition: Spline.h:168
G3D::int16 x
Definition: Vector2int16.h:37
void append(const T &value)
Definition: Array.h:583
#define alwaysAssertM(exp, message)
Definition: debugAssert.h:165
Spline()
Definition: Spline.h:126