OregonCore  revision be9e804-git
Your Favourite TBC server
spline.cpp
Go to the documentation of this file.
1 /*
2 * This file is part of the OregonCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17 
18 #include "spline.h"
19 #include <sstream>
20 #include "G3D/Matrix4.h"
21 
22 namespace Movement
23 {
25  {
29  (EvaluationMethtod)& SplineBase::UninitializedSpline,
30  };
31 
33  {
37  (EvaluationMethtod)& SplineBase::UninitializedSpline,
38  };
39 
41  {
45  (SegLenghtMethtod)& SplineBase::UninitializedSpline,
46  };
47 
49  {
50  //&SplineBase::InitLinear,
51  &SplineBase::InitCatmullRom, // we should use catmullrom initializer even for linear mode! (client's internal structure limitation)
54  (InitMethtod)& SplineBase::UninitializedSpline,
55  };
56 
58  #pragma region evaluation methtods
59 
60  using G3D::Matrix4;
61  static const Matrix4 s_catmullRomCoeffs(
62  -0.5f, 1.5f, -1.5f, 0.5f,
63  1.f, -2.5f, 2.f, -0.5f,
64  -0.5f, 0.f, 0.5f, 0.f,
65  0.f, 1.f, 0.f, 0.f);
66 
67  static const Matrix4 s_Bezier3Coeffs(
68  -1.f, 3.f, -3.f, 1.f,
69  3.f, -6.f, 3.f, 0.f,
70  -3.f, 3.f, 0.f, 0.f,
71  1.f, 0.f, 0.f, 0.f);
72 
73  /* classic view:
74  inline void C_Evaluate(const Vector3 *vertice, float t, const float (&matrix)[4][4], Vector3 &position)
75  {
76  Vector3 tvec(t*t*t, t*t, t);
77  int i = 0;
78  double c;
79  double x = 0, y = 0, z = 0;
80  while ( i < 4 )
81  {
82  c = matrix[0][i]*tvec.x + matrix[1][i]*tvec.y + matrix[2][i]*tvec.z + matrix[3][i];
83 
84  x += c * vertice->x;
85  y += c * vertice->y;
86  z += c * vertice->z;
87 
88  ++i;
89  ++vertice;
90  }
91 
92  position.x = x;
93  position.y = y;
94  position.z = z;
95  }*/
96 
97  inline void C_Evaluate(const Vector3* vertice, float t, const Matrix4& matr, Vector3& result)
98  {
99  Vector4 tvec(t * t * t, t * t, t, 1.f);
100  Vector4 weights(tvec * matr);
101 
102  result = vertice[0] * weights[0] + vertice[1] * weights[1]
103  + vertice[2] * weights[2] + vertice[3] * weights[3];
104  }
105 
106  inline void C_Evaluate_Derivative(const Vector3* vertice, float t, const Matrix4& matr, Vector3& result)
107  {
108  Vector4 tvec(3.f * t * t, 2.f * t, 1.f, 0.f);
109  Vector4 weights(tvec * matr);
110 
111  result = vertice[0] * weights[0] + vertice[1] * weights[1]
112  + vertice[2] * weights[2] + vertice[3] * weights[3];
113  }
114 
115  void SplineBase::EvaluateLinear(index_type index, float u, Vector3& result) const
116  {
117  ASSERT(index >= index_lo && index < index_hi);
118  result = points[index] + (points[index + 1] - points[index]) * u;
119  }
120 
121  void SplineBase::EvaluateCatmullRom(index_type index, float t, Vector3& result) const
122  {
123  ASSERT(index >= index_lo && index < index_hi);
124  C_Evaluate(&points[index - 1], t, s_catmullRomCoeffs, result);
125  }
126 
127  void SplineBase::EvaluateBezier3(index_type index, float t, Vector3& result) const
128  {
129  index *= 3u;
130  ASSERT(index >= index_lo && index < index_hi);
131  C_Evaluate(&points[index], t, s_Bezier3Coeffs, result);
132  }
133 
134  void SplineBase::EvaluateDerivativeLinear(index_type index, float, Vector3& result) const
135  {
136  ASSERT(index >= index_lo && index < index_hi);
137  result = points[index + 1] - points[index];
138  }
139 
140  void SplineBase::EvaluateDerivativeCatmullRom(index_type index, float t, Vector3& result) const
141  {
142  ASSERT(index >= index_lo && index < index_hi);
143  C_Evaluate_Derivative(&points[index - 1], t, s_catmullRomCoeffs, result);
144  }
145 
146  void SplineBase::EvaluateDerivativeBezier3(index_type index, float t, Vector3& result) const
147  {
148  index *= 3u;
149  ASSERT(index >= index_lo && index < index_hi);
150  C_Evaluate_Derivative(&points[index], t, s_Bezier3Coeffs, result);
151  }
152 
154  {
155  ASSERT(index >= index_lo && index < index_hi);
156  return (points[index] - points[index + 1]).length();
157  }
158 
160  {
161  ASSERT(index >= index_lo && index < index_hi);
162 
163  Vector3 curPos, nextPos;
164  const Vector3* p = &points[index - 1];
165  curPos = nextPos = p[1];
166 
167  index_type i = 1;
168  double length = 0;
169  while (i <= STEPS_PER_SEGMENT)
170  {
171  C_Evaluate(p, float(i) / float(STEPS_PER_SEGMENT), s_catmullRomCoeffs, nextPos);
172  length += (nextPos - curPos).length();
173  curPos = nextPos;
174  ++i;
175  }
176  return length;
177  }
178 
180  {
181  index *= 3u;
182  ASSERT(index >= index_lo && index < index_hi);
183 
184  Vector3 curPos, nextPos;
185  const Vector3* p = &points[index];
186 
187  C_Evaluate(p, 0.f, s_Bezier3Coeffs, nextPos);
188  curPos = nextPos;
189 
190  index_type i = 1;
191  double length = 0;
192  while (i <= STEPS_PER_SEGMENT)
193  {
194  C_Evaluate(p, float(i) / float(STEPS_PER_SEGMENT), s_Bezier3Coeffs, nextPos);
195  length += (nextPos - curPos).length();
196  curPos = nextPos;
197  ++i;
198  }
199  return length;
200  }
201  #pragma endregion
202 
203  void SplineBase::init_spline(const Vector3* controls, index_type count, EvaluationMode m)
204  {
205  m_mode = m;
206  cyclic = false;
207 
208  (this->*initializers[m_mode])(controls, count, cyclic, 0);
209  }
210 
211  void SplineBase::init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point)
212  {
213  m_mode = m;
214  cyclic = true;
215 
216  (this->*initializers[m_mode])(controls, count, cyclic, cyclic_point);
217  }
218 
219  void SplineBase::InitLinear(const Vector3* controls, index_type count, bool cyclic, index_type cyclic_point)
220  {
221  ASSERT(count >= 2);
222  const int real_size = count + 1;
223 
224  points.resize(real_size);
225 
226  memcpy(&points[0], controls, sizeof(Vector3) * count);
227 
228  // first and last two indexes are space for special 'virtual points'
229  // these points are required for proper C_Evaluate and C_Evaluate_Derivative methtod work
230  if (cyclic)
231  points[count] = controls[cyclic_point];
232  else
233  points[count] = controls[count - 1];
234 
235  index_lo = 0;
236  index_hi = cyclic ? count : (count - 1);
237  }
238 
239  void SplineBase::InitCatmullRom(const Vector3* controls, index_type count, bool cyclic, index_type cyclic_point)
240  {
241  const int real_size = count + (cyclic ? (1 + 2) : (1 + 1));
242 
243  points.resize(real_size);
244 
245  int lo_index = 1;
246  int high_index = lo_index + count - 1;
247 
248  memcpy(&points[lo_index], controls, sizeof(Vector3) * count);
249 
250  // first and last two indexes are space for special 'virtual points'
251  // these points are required for proper C_Evaluate and C_Evaluate_Derivative methtod work
252  if (cyclic)
253  {
254  if (cyclic_point == 0)
255  points[0] = controls[count - 1];
256  else
257  points[0] = controls[0].lerp(controls[1], -1);
258 
259  points[high_index + 1] = controls[cyclic_point];
260  points[high_index + 2] = controls[cyclic_point + 1];
261  }
262  else
263  {
264  points[0] = controls[0].lerp(controls[1], -1);
265  points[high_index + 1] = controls[count - 1];
266  }
267 
268  index_lo = lo_index;
269  index_hi = high_index + (cyclic ? 1 : 0);
270  }
271 
272  void SplineBase::InitBezier3(const Vector3* controls, index_type count, bool /*cyclic*/, index_type /*cyclic_point*/)
273  {
274  index_type c = count / 3u * 3u;
275  index_type t = c / 3u;
276 
277  points.resize(c);
278  memcpy(&points[0], controls, sizeof(Vector3) * c);
279 
280  index_lo = 0;
281  index_hi = t - 1;
282  // mov_assert(points.size() % 3 == 0);
283  }
284 
286  {
287  index_lo = 0;
288  index_hi = 0;
289  points.clear();
290  }
291 
292  std::string SplineBase::ToString() const
293  {
294  std::stringstream str;
295  const char* mode_str[ModesEnd] = {"Linear", "CatmullRom", "Bezier3", "Uninitialized"};
296 
297  index_type count = this->points.size();
298  str << "mode: " << mode_str[mode()] << std::endl;
299  str << "points count: " << count << std::endl;
300  for (index_type i = 0; i < count; ++i)
301  str << "point " << i << " : " << points[i].toString() << std::endl;
302 
303  return str.str();
304  }
305 }
float(SplineBase::* SegLenghtMethtod)(index_type) const
Definition: spline.h:75
void InitLinear(const Vector3 *, index_type, bool, index_type)
Definition: spline.cpp:219
void(SplineBase::* InitMethtod)(const Vector3 *, index_type, bool, index_type)
Definition: spline.h:81
void init_cyclic_spline(const Vector3 *controls, index_type count, EvaluationMode m, index_type cyclic_point)
Definition: spline.cpp:211
void init_spline(const Vector3 *controls, index_type count, EvaluationMode m)
Definition: spline.cpp:203
void(SplineBase::* EvaluationMethtod)(index_type, float, Vector3 &) const
Definition: spline.h:64
void C_Evaluate(const Vector3 *vertice, float t, const Matrix4 &matr, Vector3 &result)
Definition: spline.cpp:97
float SegLengthCatmullRom(index_type) const
Definition: spline.cpp:159
static EvaluationMethtod evaluators[ModesEnd]
Definition: spline.h:65
static SegLenghtMethtod seglengths[ModesEnd]
Definition: spline.h:76
static EvaluationMethtod derivative_evaluators[ModesEnd]
Definition: spline.h:70
void EvaluateDerivativeCatmullRom(index_type, float, Vector3 &) const
Definition: spline.cpp:140
void UninitializedSpline() const
Definition: spline.h:84
void EvaluateDerivativeLinear(index_type, float, Vector3 &) const
Definition: spline.cpp:134
void EvaluateLinear(index_type, float, Vector3 &) const
Definition: spline.cpp:115
static InitMethtod initializers[ModesEnd]
Definition: spline.h:82
void InitBezier3(const Vector3 *, index_type, bool, index_type)
Definition: spline.cpp:272
std::string ToString() const
Definition: spline.cpp:292
index_type index_lo
Definition: spline.h:44
float SegLengthBezier3(index_type) const
Definition: spline.cpp:179
ControlArray points
Definition: spline.h:42
index_type index_hi
Definition: spline.h:45
void EvaluateCatmullRom(index_type, float, Vector3 &) const
Definition: spline.cpp:121
#define ASSERT
Definition: Errors.h:29
void EvaluateDerivativeBezier3(index_type, float, Vector3 &) const
Definition: spline.cpp:146
void C_Evaluate_Derivative(const Vector3 *vertice, float t, const Matrix4 &matr, Vector3 &result)
Definition: spline.cpp:106
float SegLengthLinear(index_type) const
Definition: spline.cpp:153
void EvaluateBezier3(index_type, float, Vector3 &) const
Definition: spline.cpp:127
EvaluationMode mode() const
Definition: spline.h:107
void InitCatmullRom(const Vector3 *, index_type, bool, index_type)
Definition: spline.cpp:239