CSpline.h
Go to the documentation of this file.
1 
2 #pragma once
3 
4 #include <ionCore.h>
5 
6 #include "ISpline.h"
7 #include "ISplineInterpolator.h"
9 
10 
11 namespace ion
12 {
13  namespace Animation
14  {
15 
16  int IntermediateToIndex(float const Mu);
17 
18  template <typename TSplineNode>
19  class CSpline : public ISpline<TSplineNode>
20  {
21 
22  protected:
23 
24  std::vector<TSplineNode> Nodes;
25  std::vector<float> DistanceTable;
26  float MuIncrement = 0;
27  bool Looping = true;
28 
30 
31  public:
32 
33  std::vector<TSplineNode> const & GetNodes() const;
34  std::vector<TSplineNode> & GetNodes();
35 
36  void AddNode(TSplineNode const & Node);
37 
38  void SetLooping(bool const looping);
39  bool IsLooping() const;
40 
43 
44  int SanitizeIndex(int Index) const;
45 
46  TSplineNode const & GetNode(int const Index) const;
47  TSplineNode GetNodeInterpolated(float const Intermediate, SharedPointer<ISplineInterpolator<TSplineNode>> Interpolator = 0) const;
48 
49  float BuildDistanceTable(float const Increment = 0.1f, SharedPointer<ISplineInterpolator<TSplineNode>> Interpolator = 0);
50  float GetIntermediateFromDistance(float const Distance, SharedPointer<ISplineInterpolator<TSplineNode>> Interpolator = 0);
51  TSplineNode GetNodeFromDistance(float const Distance, SharedPointer<ISplineInterpolator<TSplineNode>> Interpolator = 0);
52  float GetTotalPathLength();
53 
54  };
55 
56  template <typename TSplineNode>
57  std::vector<TSplineNode> const & CSpline<TSplineNode>::GetNodes() const
58  {
59  return Nodes;
60  }
61 
62  template <typename TSplineNode>
63  std::vector<TSplineNode> & CSpline<TSplineNode>::GetNodes()
64  {
65  return Nodes;
66  }
67 
68  template <typename TSplineNode>
69  void CSpline<TSplineNode>::AddNode(TSplineNode const & Node)
70  {
71  Nodes.push_back(Node);
72  DistanceTable.clear();
73  }
74 
75  template <typename TSplineNode>
76  void CSpline<TSplineNode>::SetLooping(bool const looping)
77  {
78  DistanceTable.clear();
79  Looping = looping;
80  }
81 
82  template <typename TSplineNode>
84  {
85  return Looping;
86  }
87 
88  template <typename TSplineNode>
90  {
91  DefaultInterpolator = defaultInterpolator;
92  }
93 
94  template <typename TSplineNode>
96  {
97  return DefaultInterpolator;
98  }
99 
100  template <typename TSplineNode>
102  {
103  if (! Nodes.size())
104  return -1;
105 
106  if (Looping)
107  {
108  while (Index < 0)
109  Index += (int) Nodes.size();
110 
111  if (Index >= static_cast<int>(Nodes.size()))
112  Index %= (int) Nodes.size();
113  }
114  else
115  {
116  Index = Clamp<int>(Index, 0, (int) Nodes.size() - 1);
117  }
118 
119  return Index;
120  }
121 
122  template <typename TSplineNode>
123  TSplineNode const & CSpline<TSplineNode>::GetNode(int const Index) const
124  {
125  return Nodes[SanitizeIndex(Index)];
126  }
127 
128  template <typename TSplineNode>
130  {
131  if (! Interpolator)
132  Interpolator = DefaultInterpolator;
133 
134  if (! Interpolator)
135  return TSplineNode();
136 
137  int const Index = SanitizeIndex(IntermediateToIndex(Mu));
138 
139  if (Index < 0)
140  return TSplineNode();
141 
142  return Interpolator->Interpolate(* this, Index, fmodf(Mu, 1.f));
143  }
144 
145  template <typename TSplineNode>
147  {
148  if (! Interpolator)
149  Interpolator = DefaultInterpolator;
150 
151  if (! Interpolator)
152  return 0.f;
153 
154  if (! Nodes.size())
155  return 0.f;
156 
157  DistanceTable.clear();
158  // Store the increment at which this table was built
159  MuIncrement = Increment;
160 
161  float const Max = static_cast<float>(Looping ? Nodes.size() : Nodes.size() - 1);
162  TSplineNode Last = Interpolator->Interpolate(* this, 0, 0.f);
163  DistanceTable.push_back(0.f);
164 
165  for (float Mu = Increment;; Mu += Increment)
166  {
167  if (Mu > Max)
168  {
169  TSplineNode Current = Interpolator->Interpolate(* this, SanitizeIndex(IntermediateToIndex(Max)), fmodf(Max, 1.f));
170  DistanceTable.push_back((Current - Last).GetLength() + (DistanceTable.size() ? DistanceTable.back() : 0.f));
171  break;
172  }
173 
174  TSplineNode Current = Interpolator->Interpolate(* this, SanitizeIndex(IntermediateToIndex(Mu)), fmodf(Mu, 1.f));
175  DistanceTable.push_back((Current - Last).GetLength() + (DistanceTable.size() ? DistanceTable.back() : 0.f));
176  Last = Current;
177  }
178 
179  return DistanceTable.back();
180  }
181 
182 
183  template <typename TSplineNode>
185  {
186  if (DistanceTable.size() == 0)
187  BuildDistanceTable(0.1f, Interpolator);
188 
189  if (DistanceTable.size() == 0)
190  return 0.f;
191 
192  uint Max = (uint) DistanceTable.size() - 1, Min = 0;
193 
194  float const ModulatedDistance = fmodf(Distance, DistanceTable.back());
195 
196  while (Max > Min + 1)
197  {
198  uint const Midpoint = (Max + Min) / 2;
199  float const Value = DistanceTable[Midpoint];
200  if (ModulatedDistance > Value)
201  Min = Midpoint;
202  else
203  Max = Midpoint;
204  }
205 
206  if (Max != Min + 1)
207  std::cerr << "Unexpected values of Max and Min in getNodeArcLengthParametized(...): " << Min << " " << Max << std::endl;
208 
209  return (Min + (ModulatedDistance - DistanceTable[Min]) / (DistanceTable[Min+1] - DistanceTable[Min])) * MuIncrement;
210  }
211 
212  template <typename TSplineNode>
214  {
215  if (! Interpolator)
216  Interpolator = DefaultInterpolator;
217 
218  if (! Interpolator)
219  return TSplineNode();
220 
221  float const Mu = GetIntermediateFromDistance(Distance);
222  int const Index = SanitizeIndex(IntermediateToIndex(Mu));
223 
224  if (Index < 0)
225  return TSplineNode();
226 
227  return Interpolator->Interpolate(* this, Index, fmodf(Mu, 1.f));
228  }
229 
230  template <typename TSplineNode>
232  {
233  if (DistanceTable.size() == 0)
234  {
235  BuildDistanceTable(0.1f);
236  }
237 
238  if (DistanceTable.size() == 0)
239  {
240  return 0.f;
241  }
242 
243  return DistanceTable.back();
244  }
245 
246  }
247 }
float MuIncrement
Definition: CSpline.h:26
TSplineNode const & GetNode(int const Index) const
Definition: CSpline.h:123
float GetTotalPathLength()
Definition: CSpline.h:231
std::shared_ptr< T > SharedPointer
Definition: ionSmartPointer.h:22
std::vector< float > DistanceTable
Definition: CSpline.h:25
int SanitizeIndex(int Index) const
Definition: CSpline.h:101
Definition: CLinearSplineInterpolator.h:13
std::vector< TSplineNode > Nodes
Definition: CSpline.h:24
bool Looping
Definition: CSpline.h:27
float GetIntermediateFromDistance(float const Distance, SharedPointer< ISplineInterpolator< TSplineNode >> Interpolator=0)
Definition: CSpline.h:184
SharedPointer< ISplineInterpolator< TSplineNode > > DefaultInterpolator
Definition: CSpline.h:29
Definition: ISplineInterpolator.h:14
void AddNode(TSplineNode const &Node)
Definition: CSpline.h:69
float BuildDistanceTable(float const Increment=0.1f, SharedPointer< ISplineInterpolator< TSplineNode >> Interpolator=0)
Definition: CSpline.h:146
unsigned int uint
Definition: ionTypes.h:99
Definition: CSpline.h:19
Definition: CCatmullRomAdvancedSplineInterpolator.h:7
SharedPointer< ISplineInterpolator< TSplineNode > > GetDefaultInterpolator() const
Definition: CSpline.h:95
bool IsLooping() const
Definition: CSpline.h:83
void SetDefaultInterpolator(SharedPointer< ISplineInterpolator< TSplineNode >> defaultInterpolator)
Definition: CSpline.h:89
int IntermediateToIndex(float const Mu)
Definition: CSpline.cpp:10
std::vector< TSplineNode > const & GetNodes() const
Definition: CSpline.h:57
Definition: ISpline.h:13
void SetLooping(bool const looping)
Definition: CSpline.h:76
TSplineNode GetNodeFromDistance(float const Distance, SharedPointer< ISplineInterpolator< TSplineNode >> Interpolator=0)
Definition: CSpline.h:213
TSplineNode GetNodeInterpolated(float const Intermediate, SharedPointer< ISplineInterpolator< TSplineNode >> Interpolator=0) const
Definition: CSpline.h:129