/* * Returns true if: * The speed of eye movement does not exceed (radiusMM / ConfigManager.fixationMinDurationMs) millimeters/seconds * measured over a total duration of minMs. * * This function should be called when it's acceptable for the eyes to continue moving slowly and still count it as fixation. */ public static bool IsMovingFixation(int minMs, int radiusMm) { if (warpPointer == null) { return(false); } List <Point> rawGazePoints = warpPointer.GetGazeHistory(); if (rawGazePoints == null || rawGazePoints.Count == 0) { return(false); } int sampleRate = warpPointer.GetSampleRate(); //total number of samples that should be meet the fixation width criteria int lookbackSampleCount = (int)Math.Max(1, sampleRate * minMs / 1000); if (lookbackSampleCount > rawGazePoints.Count) { return(false); } //moving window samples amount int windowSampleCount = Math.Max(sampleRate * ConfigManager.fixationMinDurationMs / 1000, 1); int stopIndex = Math.Max(0, rawGazePoints.Count - windowSampleCount); //Get average of the first window //We start at the most recent point in history Point runningSum = new Point(0, 0); Point runningAvg = new Point(0, 0); for (int i = rawGazePoints.Count - 1; i >= stopIndex; i--) { runningSum.X += rawGazePoints[i].X; runningSum.Y += rawGazePoints[i].Y; } runningAvg.X = runningSum.X / windowSampleCount; runningAvg.Y = runningSum.Y / windowSampleCount; //Check that each point in the current window meets the fixation width criteria for (int i = rawGazePoints.Count - 1; i >= stopIndex; i--) { if (PointHelper.GetPointDistance(runningAvg, rawGazePoints[i]) > ScreenPixelHelper.ConvertMmToPixels(radiusMm)) { return(false); //this point is too far from the avg } } //slide window until we complete lookbackSampleCount many stopIndex = Math.Max(0, rawGazePoints.Count - lookbackSampleCount); int lowerIndex = rawGazePoints.Count - 1 - windowSampleCount; while (lowerIndex >= stopIndex) { int upperIndex = lowerIndex + windowSampleCount; //Remove one point from window runningSum.X -= rawGazePoints[upperIndex].X; runningSum.Y -= rawGazePoints[upperIndex].Y; //Add another point to the window runningSum.X += rawGazePoints[lowerIndex].X; runningSum.Y += rawGazePoints[lowerIndex].Y; //Recalculate avg runningAvg.X = runningSum.X / windowSampleCount; runningAvg.Y = runningSum.Y / windowSampleCount; //See if newest point is within the average if (PointHelper.GetPointDistance(runningAvg, rawGazePoints[lowerIndex]) > ScreenPixelHelper.ConvertMmToPixels(radiusMm)) { return(false); //this point is too far from the avg } lowerIndex--; } //Been through lookbackSampleCount and all of them according to the moving window are within fixation width requirement return(true); }