The Route Class
The purpose of the Route class is to store a list of paths that form the animation route. The Route class has the functions AddLinePath(), which adds a StraightLinePath object to the list, AddCurvePath(), which adds a CurvePath object to the list, GetStartTime() to get the time of the animation for time-based updates, and GetPosition(), which returns the current position based on the time passed in as a parameter. The Route class also has two member variables: a pointer to the Path class, which acts as the root node in the link list, and a timer variable. The Route class declaration is shown in Listing 7.
Listing 7. The Route Class
class Route
{
public:
Route();
~Route();
bool AddLinePath(Vector3D start, Vector3D end);
bool AddCurvePath(Vector3D p1, Vector3D cnt1,
Vector3D cnt2, Vector3D p2);
float GetStartTime();
Vector3D GetPosition(float time);
void Release()
private:
Path *m_path;
float m_startTime;
};
|
The Route class’s GetStartTime() function returns the class’s timer value, the constructor initializes the two variables, and the destructor calls the Release() function. In the Release() function the Release() function of the Path
class object is called to cause a recursive transversal through the
link list to delete all nodes. Once that has occurred, the root node
itself is deleted and set to NULL. The constructor, destructor, and GetStartTime() and Release() functions are shown in Listing 8.
Listing 8. The Route Class’s Constructor, Destructor, GetStartTime() Function and Release() Function
Route::Route()
{
m_path = NULL;
m_startTime = 0;
}
Route::~Route()
{
Release()
}
float Route::GetStartTime()
{
return m_startTime;
}
void Route::Release()
{
if(m_path)
{
m_path->Release()
delete m_path;
m_path = NULL;
}
}
|
The AddLinePath() and AddCurvePath() functions are fairly straightforward. They begin by testing if the root node of the link list is NULL.
If it is, then we can simply allocate the node to a new instance of the
type of path we are creating and set the node’s start and total times.
The start time is 0 in this case, and the total time is set to depend on
the length of the path.
If the root node is not NULL, then a
pointer to the root node is created, and we use that pointer to move
through the link list until we find a free spot. Once we find that spot,
it is allocated to the appropriate path type, the total time is set to
the length of the path, and the start time is set to the start time plus
the total time of the previous path. This allows us to know when each
path starts, how long it is, and when it ends. The ending time of a path
isn’t stored, since the next path in the list will have that same value
as its start time.
The AddLinePath() function is shown in Listing 9, and AddCurvePath is shown in Listing 10.
Listing 9. The AddLinePath() Function
bool Route::AddLinePath(Vector3D start, Vector3D end)
{
Path *ptr = NULL;
if(m_path == NULL)
{
// Allocate data for the root node.
m_path = new StraightLinePath(start, end);
// Make sure all went well.
if(m_path == NULL)
return false;
// Since this is the start node, its start m_total is 0.
m_path->m_start = 0;
m_path->m_total = Vector3D(start - end).Magnitude();
}
else
{
// Prepare to move through root until we find a NULL spot.
ptr = m_path;
// Search to a node without a next pointer.
while(ptr->m_next != NULL)
ptr = ptr->m_next;
// Create the m_next path.
ptr->m_next = new StraightLinePath(start, end);
// Error checking.
if(ptr->m_next == NULL)
return false;
// This start is determined by the total of the last path.
ptr->m_next->m_start = ptr->m_total + ptr->m_start;
ptr->m_next->m_total = Vector3D(start - end).Magnitude();
}
return true;
}
|
Listing 10. The AddCurvePath() Function
bool Route::AddCurvePath(Vector3D p1, Vector3D cnt1,
Vector3D cnt2, Vector3D p2)
{
Path *ptr = NULL;
if(m_path == NULL)
{
// Allocate data for the root node.
m_path = new CurvePath(p1, cnt1, cnt2, p2);
// Make sure all went well.
if(m_path == NULL)
return false;
// Since this is the start node, its start is 0.
m_path->m_start = 0;
float Length01 = Vector3D(cnt1 - p1).Magnitude();
float Length12 = Vector3D(cnt2 - cnt1).Magnitude();
float Length23 = Vector3D(p2 - cnt2).Magnitude();
float Length03 = Vector3D(p2 - p1).Magnitude();
m_path->m_total = (Length01 + Length12 + Length23) *
0.5f + Length03 * 0.5f;
}
else
{
// Prepare to move through root until we find a NULL spot.
ptr = m_path;
// Search to a node without a next pointer.
while(ptr->m_next != NULL)
ptr = ptr->m_next;
// Create the m_next path in our list.
ptr->m_next = new CurvePath(p1, cnt1, cnt2, p2);
// Error checking.
if(ptr->m_next == NULL)
return false;
// This start is determined by the total of the last path.
ptr->m_next->m_start = ptr->m_total + ptr->m_start;
float Length01 = Vector3D(cnt1 - p1).Magnitude();
float Length12 = Vector3D(cnt2 - cnt1).Magnitude();
float Length23 = Vector3D(p2 - cnt2).Magnitude();
float Length03 = Vector3D(p2 - p1).Magnitude();
ptr->m_next->m_total = (Length01 + Length12 + Length23) *
0.5f + Length03 * 0.5f;
}
return true;
}
|
The last function in the Route class is the GetPosition()
function. This function takes the time as a parameter and loops through
each path until it finds a path that falls within the time passed in
the parameter of the function. Once it finds this path, it calls the
path’s GetPathPos() to return the interpolated position of the path within which the time falls. The function also resets the Route class’s timer once the animation is complete to simulate a looping effect. The GetPosition() function is shown in Listing 11.
Listing 11. The GetPosition() Function
Vector3D Route::GetPosition(float time)
{
Path *ptr = m_path;
Vector3D nullPos;
// Error checking.
if(m_path == NULL)
return nullPos;
// Initialize the start time if it has not been already.
if(m_startTime == 0)
m_startTime = (float)timeGetTime();
// Loop through each path to see where this object is.
do
{
// Check if the object falls in along this path.
if(time >= ptr->m_start &&
time < ptr->m_start + ptr->m_total)
{
// Calculate distance traveled within this path.
time -= ptr->m_start;
// Parameter as a percent traveled.
return ptr->GetPathPos(time / ptr->m_total);
}
else
{
// Reset to loop through the route again.
if(ptr->m_next == 0)
m_startTime = (float)timeGetTime();
}
ptr = ptr->m_next;
}while(ptr != NULL);
return nullPos;
}
|