JMU
Scientific Visualization and Animation of Trajectories


Prof. David Bernstein
James Madison University

Computer Science Department
bernstdh@jmu.edu


Overview
Representing Time
Adding Dimensions
Static Visualizations
\(x,y\) versus \(t\)
svaexamples/trajectory/staticXY.c
        #include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include "../sva/sva.h" // Must be after windows.h
#include "GL/gl.h"


/**
 * An application that displays a trajectory, [x(t), y(t)],
 * againts time using a static visualization.
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */




// Global Variables
//
// Note: Many variables must be global because the display()
// callback doesn't (and can't easily) have parameters
//
float *x;
float *y;
float *t;
float min[3], max[3];
float deltat, tFirst, tLast;
int   steps;                  // Number of times in [tFirst, tLast)





// Empty Functions Required by the SVA Library
//
void onMouseClick(int button, int state, GLfloat x, GLfloat y){}
void onMouseDrag(GLfloat x, GLfloat y){}
void onMouseMove(GLfloat x, GLfloat y){}
void onTimer(int value){}



/**
 * The display callback
 */
void onDisplay()
{
   char  label[80];

   glLineWidth(2);
   glColor3f(1.0, 0.0, 0.0);   
   glBegin(GL_POINTS);
   {
      for (int i=0; i<=steps; i++)
      {
         glVertex3f(x[i], y[i], t[i]);                      
      }      
   }   
   glEnd();
}


/**
 * Evaluate [x(t), y(t)] for the specified
 * values of t in [tFirst, tLast]
 *
 * Note: This function changes the global arrays x, y, and z
 */
void evaluate()
{
   float temp;
   
   temp = 0.;   
   for (int i=0; i<=steps; i++)
   {
      t[i] = temp;      
      x[i] = cos(3 * t[i]);
      y[i] = sin(5 * t[i]);

      temp += deltat;
   }
}




/**
 * Find the maximum and minimum of x, y, and z
 *
 * Note: This function changes the global arrays min and max
 */
void findExtrema()
{
   max[0] = min[0] = x[0];
   max[1] = min[1] = y[0];
   max[2] = min[2] = t[0];   
   for (int i=1; i<=steps; i++)
   {
      if (x[i] > max[0]) max[0] = x[i];
      if (y[i] > max[1]) max[1] = y[i];
      if (t[i] > max[2]) max[2] = t[i];

      if (x[i] < min[0]) min[0] = x[i];
      if (y[i] < min[1]) min[1] = y[i];
      if (t[i] < min[2]) min[2] = t[i];
   }
}



/**
 * The entry point of the application.
 *
 * @param argc  The number of command line arguments
 * @param argv  The array of command line arguments
 * @return      A status code
 */
int main(int argc, char **argv)
{
   // Note: We specify steps rather than deltat because of
   // inaccuracies in floating point numbers that cause
   // problems with functions like ceil()
   tFirst = 0.0;
   tLast = 6.28;   
   steps  = 2000;
   
   deltat = (tLast - tFirst) / (float)steps;
   
   x = new float[steps+1];
   y = new float[steps+1];
   t = new float[steps+1];
   


   // Evaluate the function at all times in the trajectory
   evaluate();
   findExtrema();
   
   // Create the SVA window
   svaCreate(argc, argv, min, max);
   svaSetAxesLabels("x", "y", "t");

   // Start the visualization
   svaStartVisualization();
}
        
Static Visualizations (cont.)
\(t\) Not on an Axis
svaexamples/trajectory/staticXYZ.c
        #include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include "../sva/sva.h" // Must be after windows.h
#include "GL/gl.h"


/**
 * An application that displays a trajectory, [x(t), y(t), z(t)],
 * using a static visualization.
 *
 * t is represented using both color and symbology
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */




// Global Variables
//
// Note: Many variables must be global because the display()
// callback doesn't (and can't easily) have parameters
//
float *x;
float *y;
float *z;
float min[3], max[3];
float deltat, tFirst, tLast;
int   steps;                  // Number of times in [tFirst, tLast)





// Empty Functions Required by the SVA Library
//
void onMouseClick(int button, int state, GLfloat x, GLfloat y){}
void onMouseDrag(GLfloat x, GLfloat y){}
void onMouseMove(GLfloat x, GLfloat y){}
void onTimer(int value){}



/**
 * The display callback
 */
void onDisplay()
{
   char  label[80];
   float t     = 0.;


   glLineWidth(2);
   glBegin(GL_POINTS);
   {
      for (int i=0; i<=steps; i++)
      {
         // Use color to represent t
         glColor3f((float)i/(float)steps, 0.0, 0.0);   
         glVertex3f(x[i], y[i], z[i]);                      

         t += deltat;
      }      
   }   
   glEnd();

   // Use symbology to represent t
   for (int i=0; i<=steps; i++)
   {
      if ((i % 200) == 0)
      {
         sprintf(label, "%5.2f", t);   
         glColor3f((float)i/(float)steps, 0.0, 0.0);   
         svaDrawString(x[i], y[i], z[i], label);
      }
      t += deltat;
   }      
   
}


/**
 * Evaluate [x(t), y(t), z(t)] for the specified
 * values of t in [tFirst, tLast]
 *
 * Note: This function changes the global arrays x, y, and z
 */
void evaluate()
{
   float t     = 0;
   
   
   for (int i=0; i<=steps; i++)
   {
      
      x[i] = 3 * t;
      y[i] = t * t;
      z[i] = sin(M_PI * t);      

      t += deltat;
   }
}



/**
 * Find the maximum and minimum of x, y, and z
 *
 * Note: This function changes the global arrays min and max
 */
void findExtrema()
{
   max[0] = min[0] = x[0];
   max[1] = min[1] = y[0];
   max[2] = min[2] = z[0];   
   for (int i=1; i<=steps; i++)
   {
      if (x[i] > max[0]) max[0] = x[i];
      if (y[i] > max[1]) max[1] = y[i];
      if (z[i] > max[2]) max[2] = z[i];

      if (x[i] < min[0]) min[0] = x[i];
      if (y[i] < min[1]) min[1] = y[i];
      if (z[i] < min[2]) min[2] = z[i];
   }
}



/**
 * The entry point of the application.
 *
 * @param argc  The number of command line arguments
 * @param argv  The array of command line arguments
 * @return      A status code
 */
int main(int argc, char **argv)
{
   // Note: We specify steps rather than deltat because of
   // inaccuracies in floating point numbers that cause
   // problems with functions like ceil()
   tFirst = 0.0;
   tLast  = 2.0;
   steps  = 2000;
   
   deltat = (tLast - tFirst) / (float)steps;
   
   x = new float[steps+1];
   y = new float[steps+1];
   z = new float[steps+1];
   


   // Evaluate the function at all times in the trajectory
   evaluate();
   findExtrema();
   
   // Create the SVA window
   svaCreate(argc, argv, min, max);

   // Start the visualization
   svaStartVisualization();
}
        
Third-Person Animations
\(x,y\) versus \(t\)
svaexamples/trajectory/animationXY.c
        #include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include "../sva/sva.h" // Must be after windows.h
#include "GL/gl.h"

/**
 * An application that displays a trajectory, [x(t), y(t)],
 * using a third-person animation
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */


// Global Variables
//
// Note: Many variables must be global because the display()
// callback doesn't (and can't easily) have parameters
//
float currentTime;
float *x;
float *y;
float *t;
float min[3], max[3];
float deltat, tFirst, tLast;
int   currentIndex;
int   steps;                  // Number of times in [tFirst, tLast)




// Empty Functions Required by the SVA Library
//
void onMouseClick(int button, int state, GLfloat x, GLfloat y){}
void onMouseDrag(GLfloat x, GLfloat y){}
void onMouseMove(GLfloat x, GLfloat y){}




/**
 * The timer callback
 *
 * @param value  The current elapsed animation time (in milliseconds)
 */
void onTimer(int value)
{
   if (currentIndex < steps)
   {
      currentIndex++;   
      currentTime += deltat;      
   }
}




/**
 * The display callback
 */
void onDisplay()
{
   char  label[80];

   glColor3f(1.0, 0.0, 0.0);   
   glLineWidth(2);
   glBegin(GL_POINTS);
   {
      for (int i=0; i<=currentIndex; i++)
      {
         glVertex3f(x[i], y[i], t[i]);                      
      }      
   }   
   glEnd();

   glColor3f(0.0, 0.0, 1.0);   
   sprintf(label, "Time: %5.3f", currentTime);   
   svaDrawLabel(0, 0, label);   
}




/**
 * Evaluate [x(t), y(t)] for the specified
 * values of t in [tFirst, tLast]
 *
 * Note: This function changes the global arrays x, y, and z
 */
void evaluate()
{
   float temp;
   
   temp = 0.;   
   for (int i=0; i<=steps; i++)
   {
      t[i] = temp;      
      x[i] = cos(3 * t[i]);
      y[i] = sin(5 * t[i]);

      temp += deltat;
   }
}




/**
 * Find the maximum and minimum of x, y, and t
 *
 * Note: This function changes the global arrays min and max
 */
void findExtrema()
{

   max[0] = min[0] = x[0];
   max[1] = min[1] = y[0];
   max[2] = min[2] = t[0];   
   for (int i=1; i<=steps; i++)
   {
      if (x[i] > max[0]) max[0] = x[i];
      if (y[i] > max[1]) max[1] = y[i];
      if (t[i] > max[2]) max[2] = t[i];

      if (x[i] < min[0]) min[0] = x[i];
      if (y[i] < min[1]) min[1] = y[i];
      if (t[i] < min[2]) min[2] = t[i];
   }
}




/**
 * The entry point of the application.
 *
 * @param argc  The number of command line arguments
 * @param argv  The array of command line arguments
 * @return      A status code
 */
int main(int argc, char **argv)
{
   float animationLength, delayPerStep;
   

   tFirst = 0.0;
   tLast = 6.28;   
   steps  = 2000;
   
   deltat = (tLast - tFirst) / (float)steps;
   
   x = new float[steps+1];
   y = new float[steps+1];
   t = new float[steps+1];


   // Evaluate the function at all times in the trajectory
   evaluate();
   findExtrema();
   

   svaCreate(argc, argv, min, max);

   svaSetAxesLabels("x", "y", "t");
   

   animationLength = 10.0; // shortest possible length in seconds
   delayPerStep    = animationLength / (float)steps;

   currentIndex    = -1;
   currentTime     = -deltat;   

   svaStartAnimation((int)(delayPerStep*1000.));  // in milliseconds
}
        
Third-Person Animations
\(t\) Not on an Axis
svaexamples/trajectory/animationXYZ.c
        #include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include "../sva/sva.h" // Must be after windows.h
#include "GL/gl.h"

/**
 * An application that displays a trajectory, [x(t), y(t), z(t)],
 * using a third-person animation
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */


// Global Variables
//
// Note: Many variables must be global because the display()
// callback doesn't (and can't easily) have parameters
//
float currentTime;
float *x;
float *y;
float *z;
float min[3], max[3];
float deltat, tFirst, tLast;
int   currentIndex;
int   steps;                  // Number of times in [tFirst, tLast)




// Empty Functions Required by the SVA Library
//
void onMouseClick(int button, int state, GLfloat x, GLfloat y){}
void onMouseDrag(GLfloat x, GLfloat y){}
void onMouseMove(GLfloat x, GLfloat y){}




/**
 * The timer callback
 *
 * @param value  The current elapsed animation time (in milliseconds)
 */
void onTimer(int value)
{
   if (currentIndex < steps)
   {
      currentIndex++;   
      currentTime += deltat;      
   }
}




/**
 * The display callback
 */
void onDisplay()
{
   char  label[80];

   glColor3f(1.0, 0.0, 0.0);   
   glLineWidth(2);
   glBegin(GL_POINTS);
   {
      for (int i=0; i<=currentIndex; i++)
      {
         glVertex3f(x[i], y[i], z[i]);                      
      }      
   }   
   glEnd();

   glColor3f(0.0, 0.0, 1.0);   
   sprintf(label, "Time: %5.3f", currentTime);   
   svaDrawLabel(0, 0, label);   
}


/**
 * Evaluate [x(t), y(t), z(t)] for the specified
 * values of t in [tFirst, tLast]
 *
 * Note: This function changes the global arrays x, y, and z
 */
void evaluate()
{
   float t     = 0;

   /* Example 1
   for (int i=0; i<=steps; i++)
   {
      
      x[i] = 3 * t;
      y[i] = t * t;
      z[i] = sin(M_PI * t);      

      t += deltat;
   }
   */

   /* Example 2 */
   float a, b, c, d, lambda, mu, theta;

   a = 1.0;
   b = 0.5;
   c = sqrt(4.0*a*b);
   d = 0.0;   

   for (int i=0; i<=steps; i++)
   {
      

      theta  = 2.0 * M_PI * t;     
      lambda = 1.0 + d*sin(2*theta);
      mu     = 1.0 - d*sin(2*theta);
      
      x[i] = lambda*(a*cos(theta + M_PI/4.0) - b*cos(theta + M_PI/4.0));
      y[i] = mu*    (a*sin(theta + M_PI/4.0) - b*sin(theta + M_PI/4.0));
      z[i] = c*sin(2*theta);      

      t += deltat;
   }
   
}


/**
 * Find the maximum and minimum of x, y, and z
 *
 * Note: This function changes the global arrays min and max
 */
void findExtrema()
{

   max[0] = min[0] = x[0];
   max[1] = min[1] = y[0];
   max[2] = min[2] = z[0];   
   for (int i=1; i<=steps; i++)
   {
      if (x[i] > max[0]) max[0] = x[i];
      if (y[i] > max[1]) max[1] = y[i];
      if (z[i] > max[2]) max[2] = z[i];

      if (x[i] < min[0]) min[0] = x[i];
      if (y[i] < min[1]) min[1] = y[i];
      if (z[i] < min[2]) min[2] = z[i];
   }
}




/**
 * The entry point of the application.
 *
 * @param argc  The number of command line arguments
 * @param argv  The array of command line arguments
 * @return      A status code
 */
int main(int argc, char **argv)
{
   float animationLength, delayPerStep;
   

   tFirst = 0.0;
   tLast  = 2.0;
   steps  = 2000;
   
   deltat = (tLast - tFirst) / (float)steps;
   
   x = new float[steps+1];
   y = new float[steps+1];
   z = new float[steps+1];


   // Evaluate the function at all times in the trajectory
   evaluate();
   findExtrema();
   

   svaCreate(argc, argv, min, max);

   svaSetAxesLabels("x", "y", "z");
   

   animationLength = 10.0; // shortest possible length in seconds
   delayPerStep    = animationLength / (float)steps;

   currentIndex    = -1;
   currentTime     = -deltat;   

   svaStartAnimation((int)(delayPerStep*1000.));  // in milliseconds
}