/////////////////////////////////////////////////////////////////////////////// // Methods for doing main class job // /////////////////////////////////////////////////////////////////////////////// #region METHODS /// <summary> /// Initializes fields if applicable; /// </summary> private void InitializeFields() { // For Designer support check for empty Application settings if (Properties.Settings.Default != null) { this.currentLoopState = new LoopState(); this.currentLoopState.ProcessBeginningTime = DateTime.Now; this.showBlinks = Properties.Settings.Default.GazeModeBlinks; this.isGazeDiscreteLength = Properties.Settings.Default.GazeModeCutPath; this.isMouseDiscreteLength = Properties.Settings.Default.MouseModeCutPath; var speedValue = Properties.Settings.Default.ReplaySpeed; switch (speedValue) { case "10x": this.speed = 10f; break; case "5x": this.speed = 5f; break; case "3x": this.speed = 3f; break; case "2x": this.speed = 2f; break; case "1x": this.speed = 1f; break; case "0.5x": this.speed = 0.5f; break; case "0.3x": this.speed = 0.33f; break; case "0.2x": this.speed = 0.2f; break; case "0.1x": this.speed = 0.1f; break; default: this.speed = 1f; break; } this.objFixGazeDetection = new FixationDetection(); this.objFixMouseDetection = new FixationDetection(); this.gazeFixations = new VGElementCollection(); this.mouseFixations = new VGElementCollection(); if (Properties.Settings.Default.GazeModeCursor) { this.gazeDrawingMode |= ReplayDrawingModes.Cursor; } if (Properties.Settings.Default.GazeModePath) { this.gazeDrawingMode |= ReplayDrawingModes.Path; } if (Properties.Settings.Default.GazeModeFixations) { this.gazeDrawingMode |= ReplayDrawingModes.Fixations; } if (Properties.Settings.Default.GazeModeFixCon) { this.gazeDrawingMode |= ReplayDrawingModes.FixationConnections; } if (Properties.Settings.Default.GazeModeSpotlight) { this.gazeDrawingMode |= ReplayDrawingModes.Spotlight; } if (Properties.Settings.Default.MouseModeCursor) { this.mouseDrawingMode |= ReplayDrawingModes.Cursor; } if (Properties.Settings.Default.MouseModePath) { this.mouseDrawingMode |= ReplayDrawingModes.Path; } if (Properties.Settings.Default.MouseModeFixations) { this.mouseDrawingMode |= ReplayDrawingModes.Fixations; } if (Properties.Settings.Default.MouseModeFixCon) { this.mouseDrawingMode |= ReplayDrawingModes.FixationConnections; } if (Properties.Settings.Default.MouseModeSpotlight) { this.mouseDrawingMode |= ReplayDrawingModes.Spotlight; } this.maxLengthPath = (int)Properties.Settings.Default.MaxPointsPolyline; this.numFixToShow = (int)Properties.Settings.Default.MaxNumberFixations; // Initialize and load sounds for the replay of mouse clicks. this.sndLeftClick = new SoundPlayer(); this.sndLeftClick.Stream = Properties.Resources.clickLeft; this.sndLeftClick.LoadAsync(); this.sndRightClick = new SoundPlayer(); this.sndRightClick.Stream = Properties.Resources.clickRight; this.sndRightClick.LoadAsync(); } }
/// <summary> /// Calculates fixations from raw data and writes them into /// the database in the fixations tables. /// </summary> /// <param name="sampleType">The <see cref="SampleType"/> of the data, gaze or mouse</param> /// <param name="subject">A <see cref="String"/> with the subject name</param> /// <param name="trialsTable">The database trials <see cref="DataTable"/></param> /// <param name="worker">The <see cref="BackgroundWorker"/> of the calculation</param> /// <param name="e">The <see cref="DoWorkEventArgs"/> of the <see cref="BackgroundWorker"/></param> public void CalcFixations( SampleType sampleType, string subject, System.Data.DataTable trialsTable, BackgroundWorker worker, DoWorkEventArgs e) { // Fixation Calculating Objects ////////////////////////////////////////// FixationDetection objFixationDetection = new FixationDetection(); // Instantiate the delegate using the method as a parameter GetDataDelegate getDataMethod = null; int minSamples = 0; int maxDistance = 0; if (sampleType == (sampleType | SampleType.Gaze)) { getDataMethod = Queries.GetGazeData; minSamples = this.gazeMinSamples; maxDistance = this.gazeMaxDistance; } else if (sampleType == (sampleType | SampleType.Mouse)) { getDataMethod = Queries.GetMouseData; minSamples = this.mouseMinSamples; maxDistance = this.mouseMaxDistance; } bool point_found_delayed; /* sample gazepoint-found flag, */ /* min_fix_samples ago */ float x_delayed; /* sample gazepoint coordinates, */ float y_delayed; /* min_fix_samples ago */ float deviation_delayed; /* deviation of the gaze from the */ /* present fixation, */ /* min_fix_samples ago */ /* Fixation data - delayed: */ float x_fix_delayed = new float(); /* fixation point as estimated */ float y_fix_delayed = new float(); /* min_fix_samples ago */ int saccade_duration_delayed; /* duration of the saccade */ /* preceeding the preset fixation */ /* (samples) */ long fix_start_time = new long(); int fix_duration_delayed_samples = new int(); /* duration of the present fixation */ long fix_duration_delayed_milliseconds = new long(); /* duration of the present fixation */ EyeMotionState currentState = new EyeMotionState(); // OtherVars int counterTrial = 0; PointF trialLastFixCenter = new PointF(0, 0); // Loop Rows=Trials foreach (DataRow trialRow in trialsTable.Rows) { List<Fixation> fixations = new List<Fixation>(); // Reinitialize Fixation detection object // to ensure no overlay between fixations of // trials that follow each other. objFixationDetection.InitFixation(minSamples); int trialID = (int)trialRow["TrialID"]; int trialSequence = (int)trialRow["TrialSequence"]; // Holds RawData corresponding to selected trial and subject DataTable rawDataTable = Queries.GetRawDataBySubjectAndTrialSequence(subject, trialSequence); long trialStartTime = rawDataTable.Rows.Count > 0 ? (long)rawDataTable.Rows[0]["Time"] : 0; int counterRows = 0; int counterFix = 0; bool isFixation = false; // Loop RawData foreach (DataRow rowRaw in rawDataTable.Rows) { PointF? newPt; SampleValidity isValidData = getDataMethod( rowRaw, Document.ActiveDocument.PresentationSize, out newPt); bool useSample = false; switch (isValidData) { case SampleValidity.Valid: useSample = true; break; case SampleValidity.Empty: useSample = true; break; case SampleValidity.Null: break; case SampleValidity.OutOfStimulus: useSample = true; break; } if (useSample) { PointF dataPoint = newPt.Value; currentState = objFixationDetection.DetectFixation( dataPoint.IsEmpty ? false : true, Convert.ToInt64(rowRaw[3]), dataPoint.X, dataPoint.Y, maxDistance, minSamples, out point_found_delayed, out x_delayed, out y_delayed, out deviation_delayed, out x_fix_delayed, out y_fix_delayed, out saccade_duration_delayed, out fix_start_time, out fix_duration_delayed_milliseconds, out fix_duration_delayed_samples); switch (currentState) { case EyeMotionState.FIXATING: if (!isFixation) { isFixation = true; } break; case EyeMotionState.FIXATION_COMPLETED: PointF fixationCenter = new PointF(x_fix_delayed, y_fix_delayed); // if (!Queries.OutOfScreen(fixationCenter)) TODO { Fixation completedFixation = new Fixation(); completedFixation.CountInTrial = counterFix + 1; completedFixation.Length = fix_duration_delayed_milliseconds; completedFixation.PosX = x_fix_delayed; completedFixation.PosY = y_fix_delayed; completedFixation.SampleType = sampleType; completedFixation.StartTime = fix_start_time - trialStartTime; completedFixation.SubjectName = (string)trialRow["SubjectName"]; completedFixation.TrialID = (int)trialRow["TrialID"]; completedFixation.TrialSequence = (int)trialRow["TrialSequence"]; if (this.eliminateFirstFixation && this.eliminateFirstFixationSimple == false && counterFix == 0 && VGPolyline.Distance(fixationCenter, trialLastFixCenter) < maxDistance && fix_duration_delayed_milliseconds < this.limitForFirstFixation) { // Eliminate if applicable } else if (this.eliminateFirstFixationSimple && counterFix == 0) { // do nothing, just go on with the next fixation eliminating this one counterFix++; } else { fixations.Add(completedFixation); counterFix++; } } isFixation = false; break; case EyeMotionState.ERROR: break; default: break; } } counterRows++; // End RawData Loop } // Save last Fix if it has not been saved by a following saccade if (isFixation && fix_duration_delayed_milliseconds > 0) { Fixation lastFixation = new Fixation(); lastFixation.CountInTrial = counterFix + 1; lastFixation.Length = fix_duration_delayed_milliseconds; lastFixation.PosX = x_fix_delayed; lastFixation.PosY = y_fix_delayed; lastFixation.SampleType = sampleType; lastFixation.StartTime = fix_start_time - trialStartTime; lastFixation.SubjectName = (string)trialRow["SubjectName"]; lastFixation.TrialID = (int)trialRow["TrialID"]; lastFixation.TrialSequence = (int)trialRow["TrialSequence"]; fixations.Add(lastFixation); } // Save last FixCenter for Eliminating first Fix of new trial if choosen in UI trialLastFixCenter.X = x_fix_delayed; trialLastFixCenter.Y = y_fix_delayed; if (this.mergeConsecutiveFixations) { // Look for consecutive fixations that are beneath each other // (within GazeMaxDistance) because of // miscalculation due to blinks or missing data. List<Fixation> mergedFixations = new List<Fixation>(); if (fixations.Count > 1) { Fixation foregoingFixation = fixations[0]; bool merged = false; int mergedCounter = 0; int consecutiveMerges = 0; int trialFixCounter = 1; PointF foregoingFixationCenter = new PointF(foregoingFixation.PosX, foregoingFixation.PosY); for (int i = 1; i < fixations.Count; i++) { // Test if consecutive calculated fixations lie in GazeMaxDistanceRange PointF fixationCenter = new PointF(fixations[i].PosX, fixations[i].PosY); int distance = (int)VGPolyline.Distance(foregoingFixationCenter, fixationCenter); if (distance < maxDistance) { long sumOfDuration = foregoingFixation.Length + fixations[i].Length; foregoingFixation.PosX = (foregoingFixation.PosX * foregoingFixation.Length + fixations[i].PosX * fixations[i].Length) / sumOfDuration; foregoingFixation.PosY = (foregoingFixation.PosY * foregoingFixation.Length + fixations[i].PosY * fixations[i].Length) / sumOfDuration; foregoingFixation.Length = fixations[i].StartTime - foregoingFixation.StartTime + fixations[i].Length; merged = true; mergedCounter++; consecutiveMerges++; } else { if (!merged) { foregoingFixation.CountInTrial = trialFixCounter; mergedFixations.Add(foregoingFixation); trialFixCounter++; } else { merged = false; foregoingFixation.CountInTrial -= mergedCounter - 1; foregoingFixation.CountInTrial = trialFixCounter; mergedFixations.Add(foregoingFixation); consecutiveMerges = 0; trialFixCounter++; } foregoingFixation = fixations[i]; foregoingFixationCenter = fixationCenter; } } if (!merged) { foregoingFixation.CountInTrial = trialFixCounter; mergedFixations.Add(foregoingFixation); trialFixCounter++; } } else { mergedFixations = fixations; } foreach (Fixation fixationToSave in mergedFixations) { this.SaveFixationToTable(fixationToSave); } } else { // Don not merge fixations, use the originals. foreach (Fixation fixationToSave in fixations) { this.SaveFixationToTable(fixationToSave); } } // increase TrialCounter counterTrial++; if (worker != null) { if (worker.CancellationPending) { e.Cancel = true; break; } else { // Report progress as a percentage of the total task. int percentComplete = Convert.ToInt32(Convert.ToSingle(counterTrial) / trialsTable.Rows.Count * 100); worker.ReportProgress(percentComplete); } } // End Trial Loop } // Save Data to MDF File this.WriteToMDF(sampleType); }