/// <summary> /// This static method calculates the average fixation duration /// at the AOIs given in the table. /// </summary> /// <param name="fixationTable">A <see cref="DataTable"/> with the fixations /// to use.</param> /// <param name="aois">An <see cref="VGElementCollection"/> with the AOIs to calculate the parameter for.</param> /// <returns>An <see cref="int"/> with the average fixation duration at the AOIs in ms.</returns> public static AOIStatistic CalcAOIStatistic(DataView fixationTable, VGElementCollection aois) { AOIStatistic aoiStatistic = new AOIStatistic(); // NO Target AOI defined aoiStatistic.FixationDurationMean = -2; aoiStatistic.FixationDurationMedian = -2; aoiStatistic.FixationCount = -2; aoiStatistic.SumOfTimeOfAllFixations = -2; aoiStatistic.FirstHitTimeAfterBeeingOutside = -2; aoiStatistic.SaccadeDuration = -2; aoiStatistic.SaccadeLength = -2; aoiStatistic.SaccadeVelocity = -2; if (aois.Count == 0) { return aoiStatistic; } DataTable fixationsInAOIs = (DataTable)fixationTable.Table.Clone(); fixationsInAOIs.Clear(); int hitCount = 0; bool wasOutside = false; aoiStatistic.FirstHitTimeAfterBeeingOutside = -1; foreach (DataRowView fixRow in fixationTable) { if (IsFixAtTarget(aois, fixRow) != null) { hitCount++; aoiStatistic.HitTimes.Add(hitCount, (long)fixRow["StartTime"]); fixationsInAOIs.Rows.Add(fixRow.Row.ItemArray); if (wasOutside && aoiStatistic.FirstHitTimeAfterBeeingOutside == -1) { aoiStatistic.FirstHitTimeAfterBeeingOutside = (long)fixRow["StartTime"]; } } else { wasOutside = true; } } // Fixation Durations double[] fixationsDurations = GetFixationDurationsArray(fixationsInAOIs); Descriptive descriptives = new Descriptive(fixationsDurations); // -1 : no fixations in AOI if (fixationsDurations.Length > 0) { descriptives.Analyze(); // analyze the data } aoiStatistic.FixationDurationMean = fixationsDurations.Length == 0 ? -1 : descriptives.Result.Mean; aoiStatistic.FixationDurationMedian = fixationsDurations.Length == 0 ? -1 : descriptives.Result.Median; aoiStatistic.FixationCount = fixationsDurations.Length == 0 ? -1 : (int)descriptives.Result.Count; aoiStatistic.SumOfTimeOfAllFixations = fixationsDurations.Length == 0 ? -1 : descriptives.Result.Sum; // Saccade Durations double saccadeDuration; double saccadeLength; double saccadeVelocity; GetSaccadeArrays(fixationsInAOIs, out saccadeDuration, out saccadeLength, out saccadeVelocity); aoiStatistic.SaccadeDuration = saccadeDuration; aoiStatistic.SaccadeLength = saccadeLength; aoiStatistic.SaccadeVelocity = saccadeVelocity; return aoiStatistic; }
/// <summary> /// Submethod for calculating gaze statistics variables /// Calls the static methods used for calculating the variables. /// </summary> /// <param name="newRow">current row of statistic data grid view to fill with variables</param> /// <param name="trialRow">Trial table row for current subject.</param> /// <param name="subjectName">current calculated subjects name</param> /// <param name="targetAOIs">A <see cref="VGElementCollection"/> with the group of target AOIs.</param> /// <param name="searchRectAOIs">A <see cref="VGElementCollection"/> with the group of search rect AOIs.</param> public void FillGazeColumns( DataGridViewRow newRow, DataRowView trialRow, string subjectName, VGElementCollection targetAOIs, VGElementCollection searchRectAOIs) { // Calculate or read Fixation Columns float duration = Convert.ToSingle(trialRow["Duration"]); int trialID = (int)trialRow["TrialID"]; int trialSequence = (int)trialRow["TrialSequence"]; DataTable fixationTable = Document.ActiveDocument.DocDataSet.GazeFixationsAdapter.GetDataBySubjectAndSequence(subjectName, trialSequence); DataView fixationView = new DataView(fixationTable); SortedList<long, InputEvent> mouseEvents = Queries.GetTrialMouseEvents(subjectName, trialSequence); // Fixation Counts if (this.gazeParams == (this.gazeParams | GazeParams.Fixations)) { newRow.Cells["GFIXCOUN"].Value = fixationTable.Rows.Count; } if (this.gazeParams == (this.gazeParams | GazeParams.FixationsPS)) { newRow.Cells["GFIXCOpS"].Value = fixationTable.Rows.Count / duration * 1000; } if (this.gazeParams == (this.gazeParams | GazeParams.FixationsUntilFirstMouseClick)) { newRow.Cells["GFIXCO1C"].Value = CalcNumberOfFixationsUntilFirstMouseClick(mouseEvents, fixationTable); } // Fixation Duration double[] fixationsDurations = GetFixationDurationsArray(fixationTable); Descriptive descriptives = new Descriptive(fixationsDurations); if (fixationsDurations.Length > 0) { descriptives.Analyze(); // analyze the data } if (this.gazeParams == (this.gazeParams | GazeParams.FixationDurationMean)) { newRow.Cells["GFIXDURA"].Value = fixationsDurations.Length == 0 ? -1 : descriptives.Result.Mean; } if (this.gazeParams == (this.gazeParams | GazeParams.FixationDurationMedian)) { newRow.Cells["GFIXDUME"].Value = fixationsDurations.Length == 0 ? -1 : descriptives.Result.Median; } if (this.gazeParams == (this.gazeParams | GazeParams.FixationSaccadeRatio)) { newRow.Cells["GFIXDUpS"].Value = fixationsDurations.Length == 0 ? -1 : descriptives.Result.Sum / duration * 1000; } if (this.gazeParams == (this.gazeParams | GazeParams.TimeToFirstFixInSearchRect)) { if (searchRectAOIs.Count > 0) { AOIStatistic aoiStatistic = CalcAOIStatistic(fixationView, searchRectAOIs); newRow.Cells["GFIXRECT"].Value = aoiStatistic.HitTimes.Count > 0 ? aoiStatistic.HitTimes[1] : -1; } else { newRow.Cells["GFIXRECT"].Value = -2; } } if (targetAOIs.Count > 0) { AOIStatistic aoiStatistic = CalcAOIStatistic(fixationView, targetAOIs); // Target Fixations if (this.gazeParams == (this.gazeParams | GazeParams.TimeAtTarget)) { newRow.Cells["GFIXTAFT"].Value = aoiStatistic.SumOfTimeOfAllFixations; } if (this.gazeParams == (this.gazeParams | GazeParams.TimeToFirstFixAtTarget)) { newRow.Cells["GFIXTARG"].Value = aoiStatistic.HitTimes.Count > 0 ? aoiStatistic.HitTimes[1] : -1; } if (this.gazeParams == (this.gazeParams | GazeParams.TimeToSecondFixAtTarget)) { newRow.Cells["GFIX2TAR"].Value = aoiStatistic.HitTimes.Count > 1 ? aoiStatistic.HitTimes[2] : -1; } } else { if (this.gazeParams == (this.gazeParams | GazeParams.TimeAtTarget)) { newRow.Cells["GFIXTAFT"].Value = -1; } if (this.gazeParams == (this.gazeParams | GazeParams.TimeToFirstFixAtTarget)) { newRow.Cells["GFIXTARG"].Value = -1; } if (this.gazeParams == (this.gazeParams | GazeParams.TimeToSecondFixAtTarget)) { newRow.Cells["GFIX2TAR"].Value = -1; } } // Fixation connections path length float pathLengthGaze = CalcPathLengthOfFixationConnections(fixationTable); if (this.gazeParams == (this.gazeParams | GazeParams.Pathlength)) { newRow.Cells["GFIXPATH"].Value = pathLengthGaze; } if (this.gazeParams == (this.gazeParams | GazeParams.PathlengthPS)) { newRow.Cells["GFIXPApS"].Value = pathLengthGaze > 0 ? pathLengthGaze / duration * 1000 : -1; } if (this.gazeParams == (this.gazeParams | GazeParams.AverageSaccadeLength)) { newRow.Cells["GFIXSALE"].Value = pathLengthGaze > 0 ? pathLengthGaze / (fixationTable.Rows.Count - 1) : -1; } if (this.gazeParams == (this.gazeParams | GazeParams.AverageSaccadeVelocity)) { newRow.Cells["GFIXSAVE"].Value = CalcAverageSaccadeVelocity(fixationTable); } // Custom fixation variables if (this.gazeParams == (this.gazeParams | GazeParams.Custom)) { foreach (CustomVariable var in this.gazeCustomParams) { if (var.IsAOIGroup) { // AOI specifies AOI group DataTable aoiTable = Document.ActiveDocument.DocDataSet.AOIsAdapter.GetDataByTrialIDAndGroup(trialID, var.AOIName); VGElementCollection aois = new VGElementCollection(); foreach (DataRow row in aoiTable.Rows) { string strPtList = row["ShapePts"].ToString(); string aoiType = row["ShapeType"].ToString(); string aoiName = row["ShapeName"].ToString(); string shapeGroup = row["ShapeGroup"].ToString(); VGElement aoi = Queries.GetVGElementFromDatabase(aoiType, aoiName, shapeGroup, strPtList); aois.Add(aoi); } AOIStatistic aoiStatistic = CalcAOIStatistic(fixationView, aois); switch (var.ParamType) { case ParamTypes.CompleteTime: newRow.Cells[var.ColumnName].Value = aoiStatistic.SumOfTimeOfAllFixations; break; case ParamTypes.TimeUntil: newRow.Cells[var.ColumnName].Value = aoiStatistic.HitTimes.Count > var.Number - 1 ? aoiStatistic.HitTimes[var.Number] : -1; break; case ParamTypes.NumberOf: newRow.Cells[var.ColumnName].Value = aoiStatistic.FixationCount; break; case ParamTypes.FixationDurationMean: newRow.Cells[var.ColumnName].Value = aoiStatistic.FixationDurationMean; break; case ParamTypes.FixationDurationMedian: newRow.Cells[var.ColumnName].Value = aoiStatistic.FixationDurationMedian; break; case ParamTypes.Regressions: newRow.Cells[var.ColumnName].Value = CalcRegressions(fixationView, aois, var.Number); break; case ParamTypes.SaccadeDuration: newRow.Cells[var.ColumnName].Value = aoiStatistic.SaccadeDuration; break; case ParamTypes.SaccadeLength: newRow.Cells[var.ColumnName].Value = aoiStatistic.SaccadeLength; break; case ParamTypes.SaccadeVelocity: newRow.Cells[var.ColumnName].Value = aoiStatistic.SaccadeVelocity; break; } } else if (var.AOIName != string.Empty) { // AOI specifies a single AOI DataTable aoiTable = Document.ActiveDocument.DocDataSet.AOIsAdapter.GetDataByTrialIDAndShapeName(trialID, var.AOIName); if (aoiTable.Rows.Count == 1) { string strPtList = aoiTable.Rows[0]["ShapePts"].ToString(); string aoiType = aoiTable.Rows[0]["ShapeType"].ToString(); string aoiName = aoiTable.Rows[0]["ShapeName"].ToString(); string shapeGroup = aoiTable.Rows[0]["ShapeGroup"].ToString(); VGElement aoi = Queries.GetVGElementFromDatabase(aoiType, aoiName, shapeGroup, strPtList); VGElementCollection aoiContainer = new VGElementCollection(); aoiContainer.Add(aoi); AOIStatistic aoiStatistic = CalcAOIStatistic(fixationView, aoiContainer); switch (var.ParamType) { case ParamTypes.CompleteTime: newRow.Cells[var.ColumnName].Value = aoiStatistic.SumOfTimeOfAllFixations; break; case ParamTypes.TimeUntil: newRow.Cells[var.ColumnName].Value = aoiStatistic.HitTimes.Count > var.Number - 1 ? aoiStatistic.HitTimes[var.Number] : -1; break; case ParamTypes.NumberOf: newRow.Cells[var.ColumnName].Value = aoiStatistic.FixationCount; break; case ParamTypes.FixationDurationMean: newRow.Cells[var.ColumnName].Value = aoiStatistic.FixationDurationMean; break; case ParamTypes.FixationDurationMedian: newRow.Cells[var.ColumnName].Value = aoiStatistic.FixationDurationMedian; break; case ParamTypes.Regressions: newRow.Cells[var.ColumnName].Value = CalcRegressions(fixationView, aoiContainer, var.Number); break; case ParamTypes.SaccadeDuration: newRow.Cells[var.ColumnName].Value = aoiStatistic.SaccadeDuration; break; case ParamTypes.SaccadeLength: newRow.Cells[var.ColumnName].Value = aoiStatistic.SaccadeLength; break; case ParamTypes.SaccadeVelocity: newRow.Cells[var.ColumnName].Value = aoiStatistic.SaccadeVelocity; break; } } else { newRow.Cells[var.ColumnName].Value = -2; } } else if (var.ParamType == ParamTypes.Regressions) { newRow.Cells[var.ColumnName].Value = CalcRegressions(fixationView, null, var.Number); } else { newRow.Cells[var.ColumnName].Value = -2; } } } fixationTable.Dispose(); }
/// <summary> /// This static methods calculates the mean saccade duration, length and velocity from the given table of fixations /// from the database /// </summary> /// <param name="fixationsInAOIs">A <see cref="DataTable"/> with the fixations.</param> /// <param name="saccadeDuration">The mean saccade duration</param> /// <param name="saccadeLength">The mean saccade length</param> /// <param name="saccadeVelocity">The mean saccade velocity</param> private static void GetSaccadeArrays( DataTable fixationsInAOIs, out double saccadeDuration, out double saccadeLength, out double saccadeVelocity) { List<double> saccadeDurations = new List<double>(); List<double> saccadeLengths = new List<double>(); List<double> saccadeVelocitys = new List<double>(); PointF lastFixationCenter = PointF.Empty; double lastFixationEndTime = 0; int lastCountInTrial = 0; for (int i = 0; i < fixationsInAOIs.Rows.Count; i++) { DataRow row = fixationsInAOIs.Rows[i]; double posX = Convert.ToDouble(row["PosX"]); double posY = Convert.ToDouble(row["PosY"]); PointF fixationCenter = new PointF((float)posX, (float)posY); double fixationDuration = Convert.ToDouble(row["Length"]); double fixationStartTime = Convert.ToDouble(row["StartTime"]); int countInTrial = Convert.ToInt32(row["CountInTrial"]); if (i > 0 && (countInTrial == lastCountInTrial + 1)) { double currentSaccadeDuration = fixationStartTime - lastFixationEndTime; double currentSaccadeLength = VGPolyline.Distance(fixationCenter, lastFixationCenter); saccadeDurations.Add(currentSaccadeDuration); saccadeLengths.Add(currentSaccadeLength); saccadeVelocitys.Add(currentSaccadeLength / currentSaccadeDuration); } lastFixationEndTime = fixationStartTime + fixationDuration; lastFixationCenter = fixationCenter; lastCountInTrial = countInTrial; } // -1 : no saccades in AOI // Calculate saccade duration mean Descriptive descriptives = new Descriptive(saccadeDurations.ToArray()); if (saccadeDurations.Count > 0) { descriptives.Analyze(); // analyze the data } saccadeDuration = saccadeDurations.Count == 0 ? -1 : descriptives.Result.Mean; // Calculate saccade length mean descriptives = new Descriptive(saccadeLengths.ToArray()); if (saccadeLengths.Count > 0) { descriptives.Analyze(); // analyze the data } saccadeLength = saccadeLengths.Count == 0 ? -1 : descriptives.Result.Mean; // Calculate saccade velocitys mean descriptives = new Descriptive(saccadeVelocitys.ToArray()); if (saccadeVelocitys.Count > 0) { descriptives.Analyze(); // analyze the data } // -1 : no fixations in AOI saccadeVelocity = saccadeVelocitys.Count == 0 ? -1 : descriptives.Result.Mean; }