LC Technologies

File Name:       FIXFUNC.C
Program Name:    Eye Fixation Analysis Functions

Company:         LC Technologies, Inc.
                 1483 Chain Bridge Road, Suite 104
                 McLean, VA 22101
                 (703) 385-7133

Makers of the Eyegaze System, additional information about LC
Technologies and its products may be found at http://www.eyegaze.com

*****************************************************************************/
/* FUNCTION, VARIABLE AND CONSTANT DEFINITONS:                              */

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define RING_SIZE              31      /* length of the delay line in       */
                                       /*   DetectFixation() --             */
                                       /*   should be greater than          */
                                       /*   minimum_fix_samples             */
/****************************************************************************/
/* FUNCTION PROTOTYPES:                                                     */

SVOID ResetPresFixation(void);
SVOID ResetNewFixation(void);
SVOID StartPresFixAtGazepoint(float x_gaze, float y_gaze);
SVOID StartNewFixAtGazepoint(float x_gaze, float y_gaze);
SVOID UpdatePresFixation(float x_gaze, float y_gaze, int minimum_fix_samples);
SVOID UpdateNewFixation(float x_gaze, float y_gaze);
SVOID CalcGazeDeviationFromPresFix(float x_gaze, float y_gaze);
SVOID CalcGazeDeviationFromNewFix(float x_gaze, float y_gaze);
SVOID CheckIfFixating(int minimum_fix_samples);
SVOID MoveNewFixToPresFix(int minimum_fix_samples);
SVOID DeclareCompletedFixation(int minimum_fix_samples);
SVOID RestoreOutPoints(void);

/****************************************************************************/
/* GLOBAL FIXFUNC VARIABLES:                                                */

SLONG  lCallCount;              /* number of times this function has been   */
                                /*   called since it was initialized        */
                                /*   (30ths or 60ths of a second,           */
                                /*   depending on eyetracking sample rate)  */
SINT   iNNoEyeFound;            /* number of successive samples with no     */
                                /*   eye found                              */


                                /* DATA ON PREVIOUS FIXATION                */
SLONG  lPrevFixEndCount;        /* count that the previous fixation ended   */

                                /* DATA ON PRESENT FIXATION                 */
SLONG  lPresFixStartCount;      /* call count that the fixation starts      */
SLONG  lPresFixEndCount;        /* call count that the fixation ends        */
SINT   iNPresFixSamples;        /* number of samples in the present fix     */
SFLOAT fXPresFixSum;            /* summations for calculation of average    */
SFLOAT fYPresFixSum;            /*   fixation position                      */
SFLOAT fXPresFix;               /* average coordinate of the eye fixation   */
SFLOAT fYPresFix;               /*   point (user selected units)            */
SINT   iNPresOut;               /* number of samples outside the fixation   */
SFLOAT fPresDr;                 /* difference between gazepoint and         */
                                /*   fixation (x, y, and radius)            */

                                /* DATA ON NEW FIXATION                     */
SLONG  new_fix_start_count;     /* call count that the new fixation starts  */
SLONG  new_fix_end_count;       /* call count that the new fixation ends    */
SINT   n_new_fix_samples;       /* number of samples in the fixation        */
SFLOAT x_new_fix_sum;           /* summations for the FIR filter            */
SFLOAT y_new_fix_sum;           /*   calculations of the eye motion         */
SFLOAT x_new_fix;               /* average coordinate of the eye fixation   */
SFLOAT y_new_fix;               /*   point (user selected units)            */
SFLOAT new_dr;                  /* difference between gazepoint and         */
                                /*   fixation (x, y, and radius)            */

                                /* RING BUFFERS STORING PAST VALUES:        */
SFLOAT x_gaze_ring[RING_SIZE];
SFLOAT y_gaze_ring[RING_SIZE];
SBYTE  gaze_found_ring[RING_SIZE];
SINT   eye_motion_state[RING_SIZE];
                                /* state of the eye motion:                 */
                                /*   MOVING                                 */
                                /*   FIXATING                               */
                                /*   FIXATION_COMPLETED                     */
SFLOAT x_fix_ring[RING_SIZE];
SFLOAT y_fix_ring[RING_SIZE];
SFLOAT gaze_deviation_ring[RING_SIZE];
SINT   sac_duration_ring[RING_SIZE];
SINT   fix_duration_ring[RING_SIZE];
SINT   iRingIndex;              /* ring index of the present gaze sample    */
SINT   iRingIndexDelay;        /* ring index of the gaze sample taken      */
                                /*   minimum_fix_samples ago                */

/****************************************************************************/
void InitFixation(int minimum_fix_samples)
                                       /* minimum number of gaze samples    */
                                       /*   that can be considered a        */
                                       /*   fixation                        */
                                       /*   Note: if the input value is     */
                                       /*   is less than 3, the function    */
                                       /*   sets it to 3                    */

/* This function clears any previous, present and new fixations, and it     */
/* initializes DetectFixation()'s internal ring buffers of prior            */
/* gazepoint data.  InitFixation() should be called prior to a sequence     */
/* of calls to DetectFixation().                                            */

{
/* Initialize the internal ring buffer.                                     */
   for (iRingIndex = 0; iRingIndex < RING_SIZE; iRingIndex++)
   {
      x_gaze_ring[iRingIndex]         =  0.0F;
      y_gaze_ring[iRingIndex]         =  0.0F;
      gaze_found_ring[iRingIndex]     =  FALSE;
      eye_motion_state[iRingIndex]    =  MOVING;
      x_fix_ring[iRingIndex]          =  0.0F;
      y_fix_ring[iRingIndex]          =  0.0F;
      gaze_deviation_ring[iRingIndex] = -0.1F;
      sac_duration_ring[iRingIndex]   =  0;
      fix_duration_ring[iRingIndex]   =  0;
   }
   iRingIndex = 0;
   iRingIndexDelay = RING_SIZE - minimum_fix_samples;

/* Set the call count to zero, and initialize the previous fixation end     */
/* count so the first saccade duration is a legitimate count.               */
   lCallCount = 0;
   lPrevFixEndCount = 0;

/* Reset the present fixation data.                                         */
   ResetPresFixation();

/* Reset the new fixation data.                                             */
   ResetNewFixation();

/* Initialize the number of successive samples with no eye found.           */
   iNNoEyeFound = 0;
}
/****************************************************************************/
int DetectFixation(
                                       /* INPUT PARAMETERS:                 */
       BYTE  gazepoint_found,          /* flag indicating whether or not    */
                                       /*   the image processing algo       */
                                       /*   detected the eye and computed   */
                                       /*   a valid gazepoint (TRUE/FALSE)  */
       float x_gaze,                   /* present gazepoint                 */
       float y_gaze,                   /*   (user specified units)          */
       float gaze_deviation_threshold, /* distance that a gazepoint may     */
                                       /*   vary from the average fixation  */
                                       /*   point and still be considered   */
                                       /*   part of the fixation            */
                                       /*   (user specified units)          */
       int   minimum_fix_samples,      /* minimum number of gaze samples    */
                                       /*   that can be considered a        */
                                       /*   fixation                        */
                                       /*   Note: if the input value is     */
                                       /*   is less than 3, the function    */
                                       /*   sets it to 3                    */

                                       /* OUTPUT PARAMETERS:                */
                                       /* Delayed Gazepoint data with       */
                                       /*   fixation annotations:           */
       BYTE  *ptr_gazepoint_found_delayed,
                                       /* sample gazepoint-found flag,      */
                                       /*   min_fix_samples ago             */
       float *ptr_x_gaze_delayed,      /* sample gazepoint coordinates,     */
       float *ptr_y_gaze_delayed,      /*   min_fix_samples ago             */
       float *ptr_gaze_deviation_delayed,
                                       /* deviation of the gaze from the    */
                                       /*   present fixation,               */
                                       /*   min_fix_samples ago             */

                                       /* Fixation data - delayed:          */
       float *ptr_x_fix_delayed,       /* fixation point as estimated       */
       float *ptr_y_fix_delayed,       /*   min_fix_samples ago             */
       int   *ptr_saccade_duration_delayed,
                                       /* duration of the saccade           */
                                       /*   preceeding the preset fixation  */
                                       /*   (samples)                       */
       int   *ptr_fix_duration_delayed)/* duration of the present fixation  */
                                       /*   (samples)                       */

/* RETURN VALUES - Eye Motion State:                                        */
/*                                                                          */
/*  MOVING                0   The eye was in motion min_fix_samples ago.    */
/*  FIXATING              1   The eye was fixating min_fix_samples ago.     */
/*  FIXATION_COMPLETED    2   A completed fixation has just been detected;  */
/*                              the fixation ended min_fix_samples ago.     */
/*                                                                          */
/* Include FIXFUNC.H for function prototype and above constant definitions. */
/*                                                                          */
/* SUMMARY                                                                  */
/*                                                                          */
/*    This function converts a series of uniformly-sampled (raw) gaze       */
/* points into a series of variable-duration saccades and fixations.        */
/* Fixation analysis may be performed in real time or after the fact.  To   */
/* allow eye fixation analysis during real-time eyegaze data collection,    */
/* the function is designed to be called once per sample.  When the eye     */
/* is in motion, ie during saccades, the function returns 0 (MOVING).       */
/* When the eye is still, ie during fixations, the function returns 1       */
/* (FIXATING).  Upon the detected completion of a fixation, the function    */
/* returns 2 (FIXATION_COMPLETED) and produces:                             */
/*   a) the time duration of the saccade between the last and present       */
/*      eye fixation (eyegaze samples)                                      */
/*   b) the time duration of the present, just completed fixation           */
/*      (eyegaze samples)                                                   */
/*   c) the average x and y coordinates of the eye fixation                 */
/*      (in user defined units of x_gaze and y_gaze)                        */
/* Note: Although this function is intended to work in "real time", there   */
/* is a delay of minimum_fix_samples in the filter which detects the        */
/* motion/fixation condition of the eye.                                    */
/*                                                                          */
/* PRINCIPLE OF OPERATION                                                   */
/*                                                                          */
/*    This function detects fixations by looking for sequences of gaze-     */
/* point measurements that remain relatively constant.  If a new gazepoint  */
/* lies within a circular region around the running average of an on-going  */
/* fixation, the fixation is extended to include the new gazepoint.         */
/* (The radius of the acceptance circle is user specified by setting the    */
/* value of the function argument gaze_deviation_threshold.)                */
/*    To accommodate noisy eyegaze measurements, a gazepoint that exceeds   */
/* the deviation threshold is included in an on-going fixation if the       */
/* subsequent gazepoint returns to a position within the threshold.         */
/*    If a gazepoint is not found, during a blink for example, a fixation   */
/* is extended if a) the next legitimate gazepoint measurement falls within */
/* the acceptance circle, and b) there are less than minimum_fix_samples    */
/* of successive missed gazepoints.  Otherwise, the previous fixation       */
/* is considered to end at the last good gazepoint measurement.             */
/*                                                                          */
/* UNITS OF MEASURE                                                         */
/*                                                                          */
/*    The gaze position/direction may be expressed in any units (e.g.       */
/* millimeters, pixels, or radians), but the filter threshold must be       */
/* expressed in the same units.                                             */
/*                                                                          */
/* INITIALIZING THE FUNCTION                                                */
/*                                                                          */
/*    Prior to analyzing a sequence of gazepoint data, the InitFixation     */
/* function should be called to clear any previous, present and new         */
/* fixations and to initialize the ring buffers of prior gazepoint data.    */
/*                                                                          */
/* PROGRAM NOTES                                                            */
/*                                                                          */
/* For purposes of describing an ongoing sequence of fixations, fixations   */
/* in this program are referred to as "previous", "present", and "new".     */
/* The present fixation is the one that is going on right now, or, if a     */
/* new fixation has just started, the present fixation is the one that      */
/* just finished.  The previous fixation is the one immediatly preceeding   */
/* the present one, and a new fixation is the one immediately following     */
/* the present one.  Once the present fixation is declared to be completed, */
/* the present fixation becomes the previous one, the new fixation becomes  */
/* the present one, and there is not yet a new fixation.                    */

/*--------------------------------------------------------------------------*/
{
/* Make sure the minimum fix time is at least 3 samples.                    */
   if (minimum_fix_samples < 3) minimum_fix_samples = 3;

/* Make sure the ring size is large enough to handle the delay.             */
   if (minimum_fix_samples >= RING_SIZE)
   {
      lct_settextmode();
      printf("minimum_fix_samples %i >= RING_SIZE %i\n",
              minimum_fix_samples,      RING_SIZE);
      printf("Press any key to terminate...");
      getch();
      exit(99);
   }

/* Increment the call count, the ring index, and the delayed ring index.    */
   lCallCount++;
   iRingIndex++;
   if (iRingIndex >= RING_SIZE) iRingIndex = 0;
   iRingIndexDelay = iRingIndex - minimum_fix_samples;
   if (iRingIndexDelay < 0) iRingIndexDelay += RING_SIZE;

/* Update the storage rings.                                                */
   x_gaze_ring[iRingIndex]     = x_gaze;
   y_gaze_ring[iRingIndex]     = y_gaze;
   gaze_found_ring[iRingIndex] = gazepoint_found;

/* Initially assume the eye is moving.                                      */
/* Note: These values are updated during the processing of this and         */
/* subsequent gazepoints.                                                   */
   eye_motion_state[iRingIndex]    = MOVING;
   x_fix_ring[iRingIndex]          = -0.0F;
   y_fix_ring[iRingIndex]          = -0.0F;
   gaze_deviation_ring[iRingIndex] = -0.1F;
   sac_duration_ring[iRingIndex]   =  0;
   fix_duration_ring[iRingIndex]   =  0;

/*- - - - - - - - - - - - - Process Tracked Eye  - - - - - - - - - - - - - -*/

/* A1 If the eye's gazepoint was successfully measured this sample,         */
   if (gazepoint_found == TRUE)
   {
/*    The number of successive no-tracks is zero.                           */
      iNNoEyeFound = 0;

/* B1 If there is a present fixation,                                       */
      if (iNPresFixSamples > 0)
      {
/*       Compute the deviation of the gazepoint from the present fixation.  */
         CalcGazeDeviationFromPresFix(x_gaze, y_gaze);

/*   C1  If the gazepoint is within the present fixation region,            */
         if (fPresDr <= gaze_deviation_threshold)
         {
/*          Restore any previous gazepoints that were temporarily left      */
/*          out of the fixation.                                            */
            RestoreOutPoints();

/*          Update the present fixation hypothesis, and check if there      */
/*          are enough samples to declare that the eye is fixating.         */
            UpdatePresFixation(x_gaze, y_gaze, minimum_fix_samples);
         }

/*   C2  Otherwise, if the point is outside the present fixation region,    */
         else   /* if (fPresDr > gaze_deviation_threshold) */
         {
/*          Increment the number of gazepoint samples outside the           */
/*          present fix.                                                    */
            iNPresOut++;

/*      D1  If the present fixation is finished, i.e. if there have         */
/*          been minimum_fix_samples since the gazepoint last matched       */
/*          the present fixation, and the present fixation is long          */
/*          enough to count as a real fixation,                             */
            if (((int)(lCallCount - lPresFixEndCount) >=
                 minimum_fix_samples) &&
                (iNPresFixSamples >= minimum_fix_samples))
            {
/*             Declare the present fixation to be completed, move the       */
/*             present fixation to the prior, move the new fixation to      */
/*             the present, and check if the new (now present) fixation     */
/*             has enough points for the eye to be declared to be fixating. */
               DeclareCompletedFixation(minimum_fix_samples);

/*             Compute the deviation of the gazepoint from the now          */
/*             present fixation.                                            */
               CalcGazeDeviationFromPresFix(x_gaze, y_gaze);

/*         E1  If the gazepoint is within the now present fixation region,  */
               if (fPresDr <= gaze_deviation_threshold)
               {
/*                Update the present fixation data, and check if there      */
/*                are enough samples to declare that the eye is fixating.   */
                  UpdatePresFixation(x_gaze, y_gaze, minimum_fix_samples);
               }

/*         E2  Otherwise, if the gazepoint is outside the now present       */
/*             fixation,                                                    */
               else   /* if (fPresDr > gaze_deviation_threshold) */
               {
/*                Start a new fixation at the gazepoint.                    */
                  StartNewFixAtGazepoint(x_gaze, y_gaze);
               }
            }

/*      D2  Otherwise, if the present fixation is not finished,             */
            else
            {
/*         F1  If there is a new fixation hypothesis,                       */
               if (n_new_fix_samples > 0)
               {
/*                Compute the deviation of the gazepoint from the new       */
/*                fixation.                                                 */
                  CalcGazeDeviationFromNewFix(x_gaze, y_gaze);

/*            G1  If the new point falls within the new fix,                */
                  if (new_dr <= gaze_deviation_threshold)
                  {
/*                   Update the new fixation hypothesis.                    */
                     UpdateNewFixation(x_gaze, y_gaze);

/*               H.  If there are now enough points in the new fix          */
/*                   to declare it a real fix,                              */
                     if (n_new_fix_samples == minimum_fix_samples)
                     {
/*                      Drop the present fixation data, move the new        */
/*                      new fixation into the present fixation, and see     */
/*                      if the new (now present) fixation has enough        */
/*                      points to declare the eye to be fixating.           */
                        MoveNewFixToPresFix(minimum_fix_samples);
                     }
                  }

/*            G2  Otherwise, if the point is outside the new fix,           */
                  else   /* if (new_dr <= gaze_deviation_threshold) */
                  {
/*                   Start the new fixation at the new gazepoint.           */
                     StartNewFixAtGazepoint(x_gaze, y_gaze);
                  }
               }

/*         F2  Otherwise, If there is not a new fix,                        */
               else   /* if (n_new_fix_counts == 0) */
               {
/*                Start the new fixation at the gazepoint.                  */
                  StartNewFixAtGazepoint(x_gaze, y_gaze);
               }
            }
         }
      }

/* B2 Otherwise, if there is not a present fixation,                        */
      else  /* if (iNPresFixSamples = 0) */
      {
/*       Start the present fixation at the gazepoint and reset the          */
/*       new fixation.                                                      */
         StartPresFixAtGazepoint(x_gaze, y_gaze);
      }
   }

/*- - - - - - - - - - - - - Process Untracked Eye  - - - - - - - - - - - - -*/

/* A2 Otherwise, if the eye's gazepoint was not successfully measured       */
/* this sample,                                                             */
   else   /*  if (gazepoint_found == FALSE)  */
   {
/*    Increment the number of successive samples with no eye found.         */
      iNNoEyeFound++;

/*I   If it has been min-fix-samples since the last sample in the           */
/*    present fixation,                                                     */
      if ((int)(lCallCount - lPresFixEndCount) >= minimum_fix_samples)
      {
/*   J   If there had been a fixation prior to loosing track of the eye,    */
         if (iNPresFixSamples >= minimum_fix_samples)
         {
/*          Declare the present fixation to be completed, move the          */
/*          present fixation to the prior, move the new fixation to         */
/*          the present, and check if the new (now present) fixation        */
/*          has enough points for the eye to be declared to be fixating.    */
            DeclareCompletedFixation(minimum_fix_samples);
         }

/*       Reset the present fixation data.                                   */
         ResetPresFixation();
      }
   }

/*---------------------------- Pass Data Back ------------------------------*/

/* Pass the delayed gazepoint data, with the relevant saccade/fixation      */
/* data, back to the calling function.                                      */
   *ptr_x_gaze_delayed          = x_gaze_ring[iRingIndexDelay];
   *ptr_y_gaze_delayed          = y_gaze_ring[iRingIndexDelay];
   *ptr_gazepoint_found_delayed = gaze_found_ring[iRingIndexDelay];
   *ptr_x_fix_delayed           = x_fix_ring[iRingIndexDelay];
   *ptr_y_fix_delayed           = y_fix_ring[iRingIndexDelay];
   *ptr_gaze_deviation_delayed  = gaze_deviation_ring[iRingIndexDelay];
   *ptr_saccade_duration_delayed= sac_duration_ring[iRingIndexDelay];
   *ptr_fix_duration_delayed    = fix_duration_ring[iRingIndexDelay];

/* Return the eye motion/fixation state for the delayed point.              */
   return(eye_motion_state[iRingIndexDelay]);
}
/****************************************************************************/
SVOID ResetPresFixation(void)

/* This function resets the present fixation, i.e. declares it nonexistent. */

{
   lPresFixStartCount = 0;
   lPresFixEndCount   = 0;
   iNPresFixSamples   = 0;
   fXPresFixSum       = 0.0F;
   fYPresFixSum       = 0.0F;
   fXPresFix          = 0.0F;
   fYPresFix          = 0.0F;
   iNPresOut          = 0;
}
/****************************************************************************/
SVOID ResetNewFixation(void)

/* This function resets the new fixation, i.e. declares it nonexistent.     */

{
   new_fix_start_count = 0;
   new_fix_end_count   = 0;
   n_new_fix_samples   = 0;
   x_new_fix_sum       = 0.0F;
   y_new_fix_sum       = 0.0F;
   x_new_fix           = 0.0F;
   y_new_fix           = 0.0F;
}
/****************************************************************************/
SVOID StartPresFixAtGazepoint(float x_gaze, float y_gaze)

/* This function starts the present fixation at the argument gazepoint      */
/* and makes sure there is no new fixation hypothesis.                      */

{

/* Start the present fixation at the argument gazepoint.                    */
   iNPresFixSamples   = 1;
   fXPresFixSum       = x_gaze;
   fYPresFixSum       = y_gaze;
   fXPresFix           = x_gaze;
   fYPresFix           = y_gaze;
   lPresFixStartCount = lCallCount;
   lPresFixEndCount   = lCallCount;
   iNPresOut           = 0;

/* Make sure there is no new fixation.                                      */
   ResetNewFixation();
}
/****************************************************************************/
SVOID StartNewFixAtGazepoint(float x_gaze, float y_gaze)

/* This function starts the new fixation at the argument gazepoint.         */

{
   n_new_fix_samples   = 1;
   x_new_fix_sum       = x_gaze;
   y_new_fix_sum       = y_gaze;
   x_new_fix           = x_gaze;
   y_new_fix           = y_gaze;
   new_fix_start_count = lCallCount;
   new_fix_end_count   = lCallCount;
}
/****************************************************************************/
SVOID UpdatePresFixation(float x_gaze, float y_gaze, int minimum_fix_samples)

/* This function updates the present fixation with the argument gazepoint,  */
/* checks if there are enough samples to declare that the eye is now        */
/* fixating, and makes sure there is no hypothesis for a new fixation.      */

{
/* Update the present fixation with the argument gazepoint.                 */
   iNPresFixSamples++;
   fXPresFixSum    += x_gaze;
   fYPresFixSum    += y_gaze;
   fXPresFix         = fXPresFixSum / iNPresFixSamples;
   fYPresFix         = fYPresFixSum / iNPresFixSamples;
   lPresFixEndCount = lCallCount;
   iNPresOut         = 0;

/* Check if there are enough samples in the present fixation hypothesis     */
/* to declare that the eye is fixating.                                     */
   CheckIfFixating(minimum_fix_samples);

/* There is no hypothesis for a new fixation.                               */
   ResetNewFixation();
}
/****************************************************************************/
SVOID UpdateNewFixation(float x_gaze, float y_gaze)

/* This function updates the new fixation with the argument gazepoint.      */

{
/* Update the new fixation with the argument gazepoint.                     */
   n_new_fix_samples++;
   x_new_fix_sum    += x_gaze;
   y_new_fix_sum    += y_gaze;
   x_new_fix         = x_new_fix_sum / n_new_fix_samples;
   y_new_fix         = y_new_fix_sum / n_new_fix_samples;
   new_fix_end_count = lCallCount;
}
/****************************************************************************/
SVOID CalcGazeDeviationFromPresFix(float x_gaze, float y_gaze)

/* This function calculates the deviation of the gazepoint from the         */
/* present fixation location.                                               */

{
   float dx, dy;                   /* horizontal and vertical deviations    */

   dx = x_gaze - fXPresFix;
   dy = y_gaze - fYPresFix;
   fPresDr = (float)sqrt(dx * dx + dy * dy);

/* Put the deviation in the ring buffer for future reference.               */
   gaze_deviation_ring[iRingIndex] = fPresDr;
}
/****************************************************************************/
SVOID CalcGazeDeviationFromNewFix(float x_gaze, float y_gaze)

/* This function calculate the deviation of the gazepoint from the new      */
/* fixation location.                                                       */

{
   float dx, dy;                   /* horizontal and vertical deviations    */

   dx = x_gaze - x_new_fix;
   dy = y_gaze - y_new_fix;
   new_dr = (float)sqrt(dx * dx + dy * dy);
}
/****************************************************************************/
SVOID CheckIfFixating(int minimum_fix_samples)

/* This function checks to see whether there are enough samples in the      */
/* presently hypothesized fixation to declare that the eye is fixating      */
/* yet, and if there is a true fixation going on, it updates the ring       */
/* buffers to reflect the fixation.                                         */

{
   int  i, ii;                  /* dummy ring indices                       */

/* If there are enough samples for a fixation,                              */
   if (iNPresFixSamples >= minimum_fix_samples)
   {
/*    Declare the eye to be fixating.  Go back through the last             */
/*    minimum_fix_samples entries of the ring buffer making sure that all   */
/*    samples from the present fixation are marked as fixating, and set     */
/*    the entries with the newest estimate of the fixation location.        */
      for (i = 0; i < minimum_fix_samples; i++)
      {
         ii = iRingIndex - i;
         if (ii < 0) ii += RING_SIZE;

         eye_motion_state[ii] = FIXATING;
         x_fix_ring[ii] = fXPresFix;
         y_fix_ring[ii] = fYPresFix;

         sac_duration_ring[ii] = (int)(lPresFixStartCount -
                                       lPrevFixEndCount - 1);
         fix_duration_ring[ii] = (int)(lPresFixEndCount -
                                       lPresFixStartCount + 1 - i);
      }
   }
}
/****************************************************************************/
SVOID MoveNewFixToPresFix(int minimum_fix_samples)

/* This function copies the new fixation data into the present fixation,    */
/* and resets the new fixation.                                             */

{
/* Move the new fixation to the present fixation.                           */
   iNPresFixSamples   = n_new_fix_samples;
   fXPresFixSum       = x_new_fix_sum;
   fYPresFixSum       = y_new_fix_sum;
   fXPresFix          = x_new_fix;
   fYPresFix          = y_new_fix;
   lPresFixStartCount = new_fix_start_count;
   lPresFixEndCount   = new_fix_end_count;
   iNPresOut          = 0;

/* Reset the new fixation.                                                  */
   ResetNewFixation();

/* Check if there are enough samples in the new (now present) fixation to   */
/* declare that the eye is fixating.                                        */
   CheckIfFixating(minimum_fix_samples);
}
/****************************************************************************/
SVOID DeclareCompletedFixation(int minimum_fix_samples)

/* This function:                                                           */
/* a) declares the present fixation to be completed,                        */
/* b) moves the present fixation to the prior fixation,                     */
/* c) moves the new fixation, if any, to the present fixation, and          */

{

/* Declare the present fixation to be completed.                            */
   eye_motion_state[iRingIndexDelay] = FIXATION_COMPLETED;

/* Move the present fixation to the previous fixation.  This saves the      */
/* end time of the present fixation for later computation of the saccade    */
/* period between this and the next fixation.                               */
   lPrevFixEndCount = lPresFixEndCount;

/* Move the new fixation data, if any, to the present fixation, reset       */
/* the new fixation, and check if there are enough samples in the new       */
/* (now present) fixation to declare that the eye is fixating.              */
   MoveNewFixToPresFix(minimum_fix_samples);
}
/****************************************************************************/
SVOID RestoreOutPoints(void)

/* This function restores any previous gazepoints that were left out of     */
/* the fixation and are now known to be part of the present fixation.       */

{
   int  i, ii;                  /* dummy ring indices                       */

/* If there were some previous points that temporarily went out of the      */
/* fixation region,                                                         */
   if (iNPresOut > 0)
   {
/*    Undo the hypothesis that they were outside the fixation and declare   */
/*    them now to be part of the fix.                                       */
      for (i = 1; i <= iNPresOut; i++)
      {
         ii = iRingIndex - i;
         if (ii < 0) ii += RING_SIZE;

         if (gaze_found_ring[ii] == TRUE)
         {
            iNPresFixSamples++;
            fXPresFixSum    += x_gaze_ring[ii];
            fYPresFixSum    += y_gaze_ring[ii];
            eye_motion_state[ii] = FIXATING;
         }
      }

/*    Set the number of "out" points to be zero.                            */
      iNPresOut = 0;
   }
}
/****************************************************************************/

© 2003, LC Technologies, Inc. All rights reserved

LC Technologies Home Page