Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
NUSpline.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2009 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "precompiled.h"
19 #include "NUSpline.h"
20 #include "Matrix3D.h"
21 
22 //Note: column major order! Each set of 4 constitutes a column.
23 CMatrix3D HermiteSpline( 2.f, -3.f, 0.f, 1.f,
24  -2.f, 3.f, 0.f, 0.f,
25  1.f, -2.f, 1.f, 0.f,
26  1.f, -1.f, 0.f, 0.f ); // Matrix H in article
27 
28 
29 // cubic curve defined by 2 positions and 2 velocities
30 CVector3D GetPositionOnCubic(const CVector3D &startPos, const CVector3D &startVel, const CVector3D &endPos, const CVector3D &endVel, float time)
31 {
32  CMatrix3D m( startPos.X, endPos.X, startVel.X, endVel.X,
33  startPos.Y, endPos.Y, startVel.Y, endVel.Y,
34  startPos.Z, endPos.Z, startVel.Z, endVel.Z,
35  0.0f, 0.0f, 0.0f, 1.0f );
36 
37  m = m * HermiteSpline; // multiply by the mixer
38 
39 
40  CVector3D TimeVector(time*time*time, time*time, time);
41  CVector3D Result;
42  m.Transform(TimeVector, Result);
43  return Result;
44 }
45 
46 /*********************************** R N S **************************************************/
47 
48 // adds node and updates segment length
49 void RNSpline::AddNode(const CVector3D &pos)
50 {
51  if ( NodeCount >= MAX_SPLINE_NODES )
52  return;
53  if (NodeCount == 0)
54  MaxDistance = 0.f;
55  else
56  {
57  Node[NodeCount-1].Distance = (Node[NodeCount-1].Position - pos).Length();
58  MaxDistance += Node[NodeCount-1].Distance;
59  }
60  SplineData temp;
61  temp.Position = pos;
62  Node.push_back(temp);
63  NodeCount++;
64 }
65 
66 
67 // called after all nodes added. This function calculates the node velocities
69 {
70  if ( NodeCount == 2 )
71  {
72  Node[0].Velocity = GetStartVelocity(0);
73  Node[NodeCount-1].Velocity = GetEndVelocity(NodeCount-1);
74  return;
75  }
76  else if ( NodeCount < 2 )
77  return;
78 
79  for (int i = 1; i<NodeCount-1; i++)
80  {
81  CVector3D Next = Node[i+1].Position - Node[i].Position;
82  CVector3D Previous = Node[i-1].Position - Node[i].Position;
83  Next.Normalize();
84  Previous.Normalize();
85 
86  // split the angle (figure 4)
87  Node[i].Velocity = Next - Previous;
88  Node[i].Velocity.Normalize();
89  }
90  // calculate start and end velocities
91  Node[0].Velocity = GetStartVelocity(0);
92  Node[NodeCount-1].Velocity = GetEndVelocity(NodeCount-1);
93 }
94 
95 // spline access function. time is 0 -> 1
97 {
98  if ( NodeCount < 2 )
99  return CVector3D(0.0f, 0.0f, 0.0f);
100  if ( time > 1.0f )
101  time = 1.0f;
102  float Distance = time * MaxDistance;
103  float CurrentDistance = 0.f;
104  int i = 0;
105 
106  //Find which node we're on
107  while (CurrentDistance + Node[i].Distance < Distance
108  && i < NodeCount - 2)
109  {
110  CurrentDistance += Node[i].Distance;
111  i++;
112  }
113  ENSURE( i < NodeCount - 1 );
114  float t = Distance - CurrentDistance;
115  t /= Node[i].Distance; // scale t in range 0 - 1
116  CVector3D startVel = Node[i].Velocity * Node[i].Distance;
117  CVector3D endVel = Node[i+1].Velocity * Node[i].Distance;
118  return GetPositionOnCubic(Node[i].Position, startVel,
119  Node[i+1].Position, endVel, t);
120 }
121 
122 // internal. Based on Equation 14
124 {
125  if ( index >= NodeCount - 1 || index < 0)
126  return CVector3D(0.0f, 0.0f, 0.0f);
127  CVector3D temp = (Node[index+1].Position - Node[index].Position) * 3.0f * ( 1.0f / Node[index].Distance) ;
128  return (temp - Node[index+1].Velocity)*0.5f;
129 }
130 
131 // internal. Based on Equation 15
133 {
134  if ( index >= NodeCount || index < 1)
135  return CVector3D(0.0f, 0.0f, 0.0f);
136  CVector3D temp = (Node[index].Position - Node[index-1].Position) * 3.0f * (1.0f / Node[index-1].Distance);
137  return (temp - Node[index-1].Velocity) * 0.5f;
138 }
139 
140 /*********************************** S N S **************************************************/
141 
142 // smoothing filter.
144 {
145  if ( NodeCount < 3 )
146  return;
147  CVector3D newVel;
148  CVector3D oldVel = GetStartVelocity(0);
149  for (int i = 1; i<NodeCount-1; i++)
150  {
151  // Equation 12
152  newVel = GetEndVelocity(i) * Node[i].Distance +
153  GetStartVelocity(i) * Node[i-1].Distance;
154  newVel = newVel * ( 1 / (Node[i-1].Distance + Node[i].Distance) );
155  Node[i-1].Velocity = oldVel;
156  oldVel = newVel;
157  }
158  Node[NodeCount-1].Velocity = GetEndVelocity(NodeCount-1);
159  Node[NodeCount-2].Velocity = oldVel;
160 }
161 
162 /*********************************** T N S **************************************************/
163 
164 // as with RNSpline but use timePeriod in place of actual node spacing
165 // ie time period is time from last node to this node
166 void TNSpline::AddNode(const CVector3D &pos, const CVector3D& rotation, float timePeriod)
167 {
168  if ( NodeCount >= MAX_SPLINE_NODES )
169  return;
170  if (NodeCount == 0)
171  MaxDistance = 0.f;
172  else
173  {
174  Node[NodeCount-1].Distance = timePeriod;
175  MaxDistance += Node[NodeCount-1].Distance;
176  }
177 
178  SplineData temp;
179  temp.Position = pos;
180 
181  //make sure we don't end up using undefined numbers...
182  temp.Distance = 0.0f;
183  temp.Velocity = CVector3D( 0.0f, 0.0f, 0.0f );
184  temp.Rotation = rotation;
185  Node.push_back(temp);
186  NodeCount++;
187 }
188 
189 //Inserts node before position
190 void TNSpline::InsertNode(const int index, const CVector3D &pos, const CVector3D& rotation, float timePeriod)
191 {
192  if ( NodeCount >= MAX_SPLINE_NODES || index < NodeCount - 1 )
193  return;
194  if (NodeCount == 0)
195  MaxDistance = 0.f;
196  else
197  {
198  Node[NodeCount-1].Distance = timePeriod;
199  Node[NodeCount-1].Rotation = rotation;
200  MaxDistance += Node[NodeCount-1].Distance;
201  }
202  SplineData temp;
203  temp.Position = pos;
204  Node.insert(Node.begin() + index, temp);
205  NodeCount++;
206 }
207 //Removes node at index
208 void TNSpline::RemoveNode(const int index)
209 {
210  if (NodeCount == 0 || index > NodeCount - 1 )
211  {
212  return;
213  }
214  else
215  {
216  MaxDistance -= Node[index].Distance;
217  MaxDistance -= Node[index-1].Distance;
218  Node[index-1].Distance = 0.0f;
219  Node.erase( Node.begin() + index, Node.begin() + index + 1 );
220  }
221  NodeCount--;
222 }
223 void TNSpline::UpdateNodeTime(const int index, float time)
224 {
225  if (NodeCount == 0 || index > NodeCount - 1 )
226  {
227  return;
228  }
229  Node[index].Distance = time;
230 }
231 void TNSpline::UpdateNodePos(const int index, const CVector3D &pos)
232 {
233  if (NodeCount == 0 || index > NodeCount - 1 )
234  {
235  return;
236  }
237  Node[index].Position = pos;
238 }
240 {
241  if ( NodeCount < 3 )
242  return;
243  for (int i = 1; i<NodeCount-1; i++)
244  {
245  // Equation 13
246  float r0 = (Node[i].Position-Node[i-1].Position).Length() / Node[i-1].Distance;
247  float r1 = (Node[i+1].Position - Node[i].Position).Length() / Node[i].Distance;
248  Node[i].Velocity *= 4.0f*r0*r1/((r0+r1)*(r0+r1));
249  }
250 }
251 
#define MAX_SPLINE_NODES
Definition: NUSpline.h:25
CVector3D GetPosition(float time) const
Definition: NUSpline.cpp:96
CVector3D Position
Definition: NUSpline.h:31
float MaxDistance
Definition: NUSpline.h:50
void InsertNode(const int index, const CVector3D &pos, const CVector3D &rotation, float timePeriod)
Definition: NUSpline.cpp:190
void UpdateNodePos(const int index, const CVector3D &pos)
Definition: NUSpline.cpp:231
Definition: wnuma.cpp:46
CVector3D Transform(const CVector3D &vector) const
Definition: Matrix3D.h:272
void Normalize()
Definition: Vector3D.cpp:77
CVector3D Velocity
Definition: NUSpline.h:32
CVector3D GetPositionOnCubic(const CVector3D &startPos, const CVector3D &startVel, const CVector3D &endPos, const CVector3D &endVel, float time)
Definition: NUSpline.cpp:30
void RemoveNode(const int index)
Definition: NUSpline.cpp:208
CVector3D GetStartVelocity(int index)
Definition: NUSpline.cpp:123
float Distance
Definition: NUSpline.h:34
int NodeCount
Definition: NUSpline.h:51
#define ENSURE(expr)
ensure the expression &lt;expr&gt; evaluates to non-zero.
Definition: debug.h:282
void UpdateNodeTime(const int index, float time)
Definition: NUSpline.cpp:223
float X
Definition: Vector3D.h:31
void Smooth()
Definition: NUSpline.cpp:143
float Y
Definition: Vector3D.h:31
CVector3D GetEndVelocity(int index)
Definition: NUSpline.cpp:132
CMatrix3D HermiteSpline(2.f,-3.f, 0.f, 1.f,-2.f, 3.f, 0.f, 0.f, 1.f,-2.f, 1.f, 0.f, 1.f,-1.f, 0.f, 0.f)
void Constrain()
Definition: NUSpline.cpp:239
void AddNode(const CVector3D &pos, const CVector3D &rotation, float timePeriod)
Definition: NUSpline.cpp:166
void BuildSpline()
Definition: NUSpline.cpp:68
float Z
Definition: Vector3D.h:31
void AddNode(const CVector3D &pos)
Definition: NUSpline.cpp:49
static float Length(const SVec3 v)
Definition: mikktspace.cpp:112
CVector3D Rotation
Definition: NUSpline.h:33