/// <summary> /// Adds a range of <see cref="VGElement"/>s to the collection. /// </summary> /// <param name="elementCollection">The <see cref="VGElementCollection"/> to be /// added to the end of the collection.</param> public void AddRange(VGElementCollection elementCollection) { foreach (VGElement element in elementCollection) { this.List.Add(element); } }
/// <summary> /// Initializes a new instance of the Slide class. /// </summary> public Slide() { this.stimuli = new VGElementCollection(); this.activeXElements = new VGElementCollection(); this.targets = new VGElementCollection(); this.correctResponses = new StopConditionCollection(); this.links = new StopConditionCollection(); this.stopConditions = new StopConditionCollection(); this.category = string.Empty; this.TriggerSignal = new Trigger(TriggerSignaling.None, TriggerOutputDevices.LPT, 40, 255, 0x0378); this.IdOfPreSlideFixationTrial = -1; }
/// <summary> /// Removes the first occurrence of a specific /// <see cref="VGElement"/> from the collection. /// </summary> /// <param name="list">The <see cref="VGElement"/> /// to remove from the collection.</param> public void RemoveAll(VGElementCollection list) { if (list != null && list.Count > 0) { foreach (VGElement element in list) { if (this.List.Contains(element)) { this.List.Remove(element); } } } }
/// <summary> /// Searches the collection list for all members with /// the given group and returns this items in a new /// <see cref="VGElementCollection"/> /// </summary> /// <param name="searchGroup">The <see cref="VGStyleGroup"/> /// that the elements should match.</param> /// <returns>A <see cref="VGElementCollection"/> with the /// members of the list that are in the given search group.</returns> public VGElementCollection FindAllGroupMembers(VGStyleGroup searchGroup) { VGElementCollection subList = new VGElementCollection(); foreach (VGElement element in this.List) { if ((element.StyleGroup & searchGroup) == searchGroup) { subList.Add(element); } } return(subList); }
/// <summary> /// Removes all occurrences of <see cref="VGElement"/>s /// with the given name from the collection. /// </summary> /// <param name="name">The <see cref="string"/> with the name of the elements /// to remove from the collection.</param> public void Remove(string name) { if (name != string.Empty) { VGElementCollection removeList = new VGElementCollection(); foreach (VGElement element in this.List) { if (element.Name == name) { removeList.Add(element); } } foreach (VGElement element in removeList) { this.List.Remove(element); } } }
/// <summary> /// Initializes a new instance of the Slide class. /// </summary> /// <param name="newName">A <see cref="string"/> with the unique name of this Slide</param> /// <param name="newBackgroundColor">A <see cref="Color"/> with the background color for this slide</param> /// <param name="newBackgroundImage">A <see cref="Image"/> with the background image for this slide</param> /// <param name="newStopConditions">A <see cref="StopConditionCollection"/> list /// of responses for which the slide presentation should stop.</param> /// <param name="newResponses">An optional <see cref="StopConditionCollection"/> with responses /// that indicate correct answers.</param> /// <param name="newCategory">A <see cref="string"/> with an optional category /// that gives an additional slide distinction.</param> /// <param name="newPresentationSize">A <see cref="Size"/> with the original /// presentation size of this slide.</param> public Slide( string newName, Color newBackgroundColor, Image newBackgroundImage, StopConditionCollection newStopConditions, StopConditionCollection newResponses, string newCategory, Size newPresentationSize) { this.stimuli = new VGElementCollection(); this.activeXElements = new VGElementCollection(); this.targets = new VGElementCollection(); this.links = new StopConditionCollection(); this.stopConditions = newStopConditions; this.BackgroundColor = newBackgroundColor; this.BackgroundImage = newBackgroundImage; this.name = newName; this.correctResponses = newResponses; this.category = newCategory; this.PresentationSize = newPresentationSize; this.IdOfPreSlideFixationTrial = -1; }
/// <summary> /// Removes all occurrences of <see cref="VGElement"/>s /// with the given name from the collection. /// </summary> /// <param name="name">The <see cref="string"/> with the name of the elements /// to remove from the collection.</param> public void Remove(string name) { if (name != string.Empty) { VGElementCollection removeList = new VGElementCollection(); foreach (VGElement element in this.List) { if (element.Name == name) { removeList.Add(element); } } foreach (VGElement element in removeList) { this.List.Remove(element); } } }
/// <summary> /// This static method calculates the number of regressions in the given AOI /// using the given table of fixations and line height. /// </summary> /// <param name="fixationView">A <see cref="DataView"/> with the list of fixations</param> /// <param name="aois">A <see cref="VGElementCollection"/> with the AOIs.</param> /// <param name="lineHeight">The line height of the textual area.</param> /// <returns>An <see cref="Int32"/> with the number of regressions.</returns> private static int CalcRegressions( DataView fixationView, VGElementCollection aois, int lineHeight) { int regressionCount = 0; // Check if we are using AOIs and we did not found any. if (aois != null && aois.Count == 0) { // -2 = this AOIs was not definded in this trial regressionCount = -2; return regressionCount; } PointF lastLocation = PointF.Empty; VGElement lastHittedAOI = null; foreach (DataRowView fixRow in fixationView) { // Calculate overall regressions if (aois != null) { // Calculate regressions in single AOI if (aois.Count == 1) { if (IsFixAtTarget(aois, fixRow) == null) { // Reset last location if fixation was outside AOI // so first refixation in AOI will restart the count lastLocation = PointF.Empty; continue; } } else { // Calculate regressions in AOI groups VGElement hittedAOI = IsFixAtTarget(aois, fixRow); if (hittedAOI == null) { // Reset last location if fixation was outside AOI // so first refixation in AOI will restart the count lastLocation = PointF.Empty; lastHittedAOI = null; continue; } else if (hittedAOI != lastHittedAOI) { // Reset last location if fixation was outside last AOI // but inside other AOI of same group // so first refixation in AOI will restart the count lastLocation = PointF.Empty; lastHittedAOI = hittedAOI; continue; } } } // Get Fixation location PointF currentLocation = new PointF( Convert.ToSingle(fixRow["PosX"]), Convert.ToSingle(fixRow["PosY"])); if (currentLocation.X > lastLocation.X) { // Default forward, no regression lastLocation = currentLocation; continue; } if (currentLocation.Y > lastLocation.Y + lineHeight) { // Default line change, no regression lastLocation = currentLocation; continue; } if (currentLocation.Y < lastLocation.Y - 2 * lineHeight) { // Big Line skipping upwards, no regression lastLocation = currentLocation; continue; } // Either go back in the line or go back vertical, // both is a regression lastLocation = currentLocation; regressionCount++; } return regressionCount; }
/// <summary> /// Initializes a new instance of the Slide class. /// </summary> /// <param name="newName">A <see cref="string"/> with the unique name of this Slide</param> /// <param name="newBackgroundColor">A <see cref="Color"/> with the background color for this slide</param> /// <param name="newBackgroundImage">A <see cref="Image"/> with the background image for this slide</param> /// <param name="newStopConditions">A <see cref="StopConditionCollection"/> list /// of responses for which the slide presentation should stop.</param> /// <param name="newResponses">An optional <see cref="StopConditionCollection"/> with responses /// that indicate correct answers.</param> /// <param name="newCategory">A <see cref="string"/> with an optional category /// that gives an additional slide distinction.</param> /// <param name="newPresentationSize">A <see cref="Size"/> with the original /// presentation size of this slide.</param> public Slide( string newName, Color newBackgroundColor, Image newBackgroundImage, StopConditionCollection newStopConditions, StopConditionCollection newResponses, string newCategory, Size newPresentationSize) { this.stimuli = new VGElementCollection(); this.activeXElements = new VGElementCollection(); this.targets = new VGElementCollection(); this.links = new StopConditionCollection(); this.stopConditions = newStopConditions; this.BackgroundColor = newBackgroundColor; this.BackgroundImage = newBackgroundImage; this.name = newName; this.correctResponses = newResponses; this.category = newCategory; this.PresentationSize = newPresentationSize; this.IdOfPreSlideFixationTrial = -1; }
/// <summary> /// Calculates whether the fixation given in datarow hits one of the /// areas of interest given in the AOI Table and returns the /// name of the AOI and its category. /// </summary> /// <param name="aoiCollection"><see cref="VGElementCollection"/> of areas of interest for current trial</param> /// <param name="fixationRow">fixational row</param> /// <returns>List of AOI name/group pairs that are hitted from fixation.</returns> public static List<string[]> FixationHitsAOI( VGElementCollection aoiCollection, DataRowView fixationRow) { List<string[]> hittedAOIs = new List<string[]>(); string aoiName = "nowhere"; string aoiGroup = "nowhere"; foreach (VGElement aoiElement in aoiCollection) { // Check for intersection between newPath and Clicklist or Fixationlist PointF searchPoint = new PointF( Convert.ToSingle(fixationRow["PosX"]), Convert.ToSingle(fixationRow["PosY"])); if (aoiElement.Contains(searchPoint, tolerance)) { aoiGroup = aoiElement.ElementGroup == null ? string.Empty : aoiElement.ElementGroup.Trim(); aoiName = aoiElement.Name.Trim(); if (aoiGroup == string.Empty || aoiGroup == " ") { aoiGroup = "nowhere"; } string[] hittedAOI = { aoiName, aoiGroup }; hittedAOIs.Add(hittedAOI); } } return hittedAOIs; }
/// <summary> /// Calculates whether the fixation given in datarow hits one of the /// areas of interest given in the AOI Table /// </summary> /// <param name="aois">A <see cref="VGElementCollection"/> with the areas of interest for current trial.</param> /// <param name="fixationRow">fixational row</param> /// <returns>Row number of aoi that is hitted from fixation.</returns> private static VGElement IsFixAtTarget(VGElementCollection aois, DataRowView fixationRow) { foreach (VGElement aoi in aois) { // Check for intersection PointF searchPoint = new PointF( Convert.ToSingle(fixationRow["PosX"]), Convert.ToSingle(fixationRow["PosY"])); if (aoi.Contains(searchPoint, tolerance)) { return aoi; } } return null; }
/// <summary> /// This method converts the AOI table with areas of interest from the database /// into a list of <see cref="VGElement"/>s. /// </summary> /// <param name="aoiTable">The <see cref="DataTable"/> with the AOIs.</param> /// <returns>A <see cref="List{VGElement}"/> with the shapes.</returns> protected virtual VGElementCollection GetAOIElements(DataTable aoiTable) { Pen defaultPen = new Pen(Properties.Settings.Default.AOIStandardColor, Properties.Settings.Default.AOIStandardWidth); Pen targetPen = new Pen(Properties.Settings.Default.AOITargetColor, Properties.Settings.Default.AOITargetWidth); Pen searchRectPen = new Pen(Properties.Settings.Default.AOISearchRectColor, Properties.Settings.Default.AOISearchRectWidth); Font defaultFont = (Font)Properties.Settings.Default.AOIStandardFont.Clone(); Font targetFont = (Font)Properties.Settings.Default.AOITargetFont.Clone(); Font searchRectFont = (Font)Properties.Settings.Default.AOISearchRectFont.Clone(); Color defaultFontColor = Properties.Settings.Default.AOIStandardFontColor; Color targetFontColor = Properties.Settings.Default.AOITargetFontColor; Color searchRectFontColor = Properties.Settings.Default.AOISearchRectFontColor; VGElementCollection aoiList = new VGElementCollection(); int counter = 0; try { foreach (DataRow row in aoiTable.Rows) { string strPtList = row["ShapePts"].ToString(); string shapeName = row["ShapeName"].ToString(); Pen usedPen = defaultPen; Font usedFont = defaultFont; Color usedFontColor = defaultFontColor; VGStyleGroup usedStyleGroup = VGStyleGroup.AOI_NORMAL; List<PointF> pointList = ObjectStringConverter.StringToPointFList(strPtList); string usedElementGroup = row["ShapeGroup"].ToString(); switch (usedElementGroup) { case "Target": usedPen = targetPen; usedFont = targetFont; usedFontColor = targetFontColor; usedStyleGroup = VGStyleGroup.SCA_GRID_AOI; break; case "SearchRect": usedPen = searchRectPen; usedFont = searchRectFont; usedFontColor = searchRectFontColor; usedStyleGroup = VGStyleGroup.SCA_GRID_AOI; break; default: usedPen = defaultPen; usedFont = defaultFont; usedFontColor = defaultFontColor; usedStyleGroup = VGStyleGroup.SCA_GRID_AOI; break; } // Create the shape depending on ShapeType RectangleF boundingRect = new RectangleF(); switch (row["ShapeType"].ToString()) { case "Rectangle": boundingRect.Location = pointList[0]; boundingRect.Width = pointList[2].X - pointList[0].X; boundingRect.Height = pointList[2].Y - pointList[0].Y; // Create Rect with defined stroke VGRectangle newRect = new VGRectangle( ShapeDrawAction.NameAndEdge, usedPen, usedFont, usedFontColor, boundingRect, usedStyleGroup, shapeName, usedElementGroup); aoiList.Add(newRect); break; case "Ellipse": boundingRect.Location = pointList[0]; boundingRect.Width = pointList[2].X - pointList[0].X; boundingRect.Height = pointList[2].Y - pointList[0].Y; // Create Rect with defined stroke VGEllipse newEllipse = new VGEllipse( ShapeDrawAction.NameAndEdge, usedPen, usedFont, usedFontColor, boundingRect, usedStyleGroup, shapeName, usedElementGroup); aoiList.Add(newEllipse); break; case "Polyline": // Create Polyline with defined stroke VGPolyline newPolyline = new VGPolyline( ShapeDrawAction.NameAndEdge, usedPen, usedFont, usedFontColor, usedStyleGroup, shapeName, usedElementGroup); foreach (PointF point in pointList) { newPolyline.AddPt(point); } newPolyline.ClosePolyline(); aoiList.Add(newPolyline); boundingRect = newPolyline.Bounds; break; } counter++; } } catch (Exception ex) { ExceptionMethods.HandleException(ex); } return aoiList; }
/// <summary> /// Calculates whether the mouse click position given in datarow hits one of the /// areas of interest given in the AOI Table /// </summary> /// <param name="aois">A <see cref="VGElementCollection"/> with the areas of interest for current trial.</param> /// <param name="clickLocation">A <see cref="Point"/> with the location of the click in screen coordinates.</param> /// <returns>Row number of AOI that is hitted from the mouse click.</returns> private static int IsClickAtTarget(VGElementCollection aois, Point clickLocation) { // Never over AOI int hitIndex = -1; if (aois.Count == 0) { // NO AOIs definded hitIndex = -2; return hitIndex; } int rowCounter = 0; foreach (VGElement target in aois) { // Check for intersection between newPath and Clicklist or Fixationlist if (target.Contains(clickLocation, tolerance)) { hitIndex = rowCounter; break; } rowCounter++; } return hitIndex; }
/// <summary> /// Custom initializations. /// </summary> private void InitializeOther() { this.elements = new VGElementCollection(); this.grayBrush = new SolidBrush(Color.FromArgb(200, Color.Black)); this.presentationSize = Screen.PrimaryScreen.Bounds.Size; }
/// <summary> /// Overridden <see cref="Control.MouseDown"/> event handler. /// Starts requested shape creation when left mouse button is pressed. /// Otherwise looks for elements under mouse cursor and selects them. /// If there is already a selected element and the mouse is over a grab /// handle it is selected. /// </summary> /// <remarks>Pressing the ALT key during selection iterates /// through the elementsUnderMouseCursor collection.</remarks> /// <param name="e">The <see cref="MouseEventArgs"/> with the event data (click point).</param> protected override void OnMouseDown(MouseEventArgs e) { // base.OnMouseDown(e); // Achieve focus to the picture, because otherwise it will not // receive input keys which are interesting as modifiers. this.Focus(); if (Control.ModifierKeys != Keys.ShiftKey) { // Transform mouse down point to stimulus coordinates PointF mouseLocationF = this.GetTransformedMouseLocation(e.Location); Point mouseLocation = Point.Round(mouseLocationF); if (this.state != BuildState.None) { // Is creating a new shape // Left Mouse Button pressed, so start Logging if (e.Button == MouseButtons.Left) { this.state = BuildState.FirstPointSet; // Add the new shape to the list. if (!this.Elements.Contains(this.newShape)) { this.Elements.Add(this.newShape); } // Select it this.SelectedElement = this.newShape; // save click point for later bounding rectangle creation this.firstClickPoint = mouseLocationF; // Special handling for polyline construction // every click is a polyline point // up to the moment the polyline is closed if (this.newShape is VGPolyline) { this.currentLine.FirstPoint = this.firstClickPoint; // Add the _CurrentLine element during polyline // creation if (!Elements.Contains(this.currentLine)) { Elements.Add(this.currentLine); } // Cast newShape to polyline VGPolyline poly = (VGPolyline)this.newShape; // Check for closing polyline conditions if (this.PointsAreNear(poly.FirstPt, mouseLocationF) && poly.GetPointCount() > 2) { // If the mouse click point is near the first point // close polyline. poly.ClosePolyline(); this.state = BuildState.None; // New Graphic element created, so notify listeners. this.OnShapeAdded(new ShapeEventArgs(this.newShape)); // CleanUp creation mode this.Elements.Remove(this.currentLine); this.newShape = null; } else { // Point is anywhere else, but not near the first // polyline point. // Add new polyline point and update CurrentLine. this.currentLine.FirstPoint = mouseLocationF; poly.AddPt(mouseLocationF); } } else if (this.newShape is VGLine) { // Cast newShape to VGLine VGLine line = (VGLine)this.newShape; line.FirstPoint = this.firstClickPoint; } else if (this.newShape is VGFlash) { // Cast newShape to VGFlash VGFlash flash = (VGFlash)this.newShape; flash.InitializeOnControl(this.Parent, false, this.StimulusToScreen); } } } else { // We are not in new shape creation mode if (e.Button == MouseButtons.Left) { this.mouseDownPoint = e.Location; // Store elements under mouse cursor. VGElementCollection elementsUnderMouseCursor = new VGElementCollection(); int numberOfElements = this.Elements.Count; for (int i = 0; i < numberOfElements; i++) { VGElement currentElement = this.Elements[numberOfElements - i - 1]; if (currentElement.Contains(mouseLocation)) { elementsUnderMouseCursor.Add(currentElement); if (currentElement == this.SelectedElement) { this.counterUnderCursor = elementsUnderMouseCursor.Count - 1; } } } if (this.selectedElement == null) { // Check whether an element lies under // mouse cursor. Select the next item. if (elementsUnderMouseCursor.Count > 0) { this.SelectedElement = elementsUnderMouseCursor[0]; this.selectedElement.IsInEditMode = true; } else { this.SelectedElement = null; } } else if (this.selectedElement.Contains(mouseLocation)) { // Click in selected element // could be more than one, so iterate if Modifier alt is pressed. if (Control.ModifierKeys == Keys.Alt) { this.Cursor = Cursors.Default; this.counterUnderCursor++; // Reset counter if larger than element list size. if (this.counterUnderCursor >= elementsUnderMouseCursor.Count) { this.counterUnderCursor = 0; } // Select next item if there is any if (elementsUnderMouseCursor.Count > 1) { this.ResetSelectedElement(); // Use property to invoke Shape Selected event. this.SelectedElement = elementsUnderMouseCursor[this.counterUnderCursor]; this.selectedElement.IsInEditMode = true; } } else { // No alt is pressed // Select grab handle, if mouse is over it foreach (GrabHandle handle in this.selectedElement.GrabHandles) { if (handle.Contains(mouseLocation)) { this.activeGrabHandle = handle; break; } // Select center handle this.activeGrabHandle = this.selectedElement.GrabHandles[0]; } } } else { // Click in region outside current selected element // Reset selected element. And look for other element // under mouse cursor. this.ResetSelectedElement(); // Select the first element that lies under mouse cursor. if (elementsUnderMouseCursor.Count > 0) { this.SelectedElement = elementsUnderMouseCursor[0]; this.selectedElement.IsInEditMode = true; } else { this.SelectedElement = null; } } this.DrawForeground(false); } } } }
/// <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 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> /// This method calculates the transition matrix /// of the given trial between the AOIs of this trial. /// </summary> /// <param name="fixations">The fixations of the current trial</param> /// <param name="trialsAOIs">A <see cref="VGElementCollection"/> with the AOIs.</param> /// <returns>An two dimensional <see cref="Array"/> with /// integers indicating the number of transitions between AOI in row and column.</returns> public static Array CreateTransitionMatrixForSingleAOIs( DataView fixations, VGElementCollection trialsAOIs) { int aoiCount = trialsAOIs.Count; // Create transition matrix Array transitionMatrix = Array.CreateInstance(typeof(int), aoiCount + 1, aoiCount + 1); // Assign names and indices of AOI. Dictionary<string, int> groupIndexAssignment = new Dictionary<string, int>(); groupIndexAssignment.Add("nowhere", 0); for (int i = 0; i < aoiCount; i++) { string aoiGroupEntry = trialsAOIs[i].Name; if (!groupIndexAssignment.ContainsKey(aoiGroupEntry)) { groupIndexAssignment.Add(aoiGroupEntry, i + 1); } } // Iterate selected subjects string foregoingHittedAOIName = string.Empty; string foregoingSubjectName = string.Empty; foreach (DataRowView fixationRow in fixations) { string subjectName = fixationRow["SubjectName"].ToString(); if (subjectName != foregoingSubjectName) { foregoingHittedAOIName = string.Empty; foregoingSubjectName = subjectName; } string hittedAOIName = "nowhere"; string hittedAOIGroup = "nowhere"; List<string[]> hittedAOIs = Statistic.FixationHitsAOI(trialsAOIs, fixationRow); if (hittedAOIs.Count > 0) { // Take only first hitted AOI hittedAOIName = hittedAOIs[0][0]; hittedAOIGroup = hittedAOIs[0][1]; } if (foregoingHittedAOIName != string.Empty) { int indexOfHittedGroup = groupIndexAssignment[hittedAOIName]; int indexOfForegoingGroup = groupIndexAssignment[foregoingHittedAOIName]; int oldEntry = (int)transitionMatrix.GetValue(indexOfForegoingGroup, indexOfHittedGroup); int newEntry = oldEntry + 1; transitionMatrix.SetValue(newEntry, indexOfForegoingGroup, indexOfHittedGroup); } foregoingHittedAOIName = hittedAOIName; } return transitionMatrix; }
/// <summary> /// Removes the first occurrence of a specific /// <see cref="VGElement"/> from the collection. /// </summary> /// <param name="list">The <see cref="VGElement"/> /// to remove from the collection.</param> public void RemoveAll(VGElementCollection list) { if (list != null && list.Count > 0) { foreach (VGElement element in list) { if (this.List.Contains(element)) { this.List.Remove(element); } } } }
/// <summary> /// Searches the collection list for all members with /// the given group and returns this items in a new /// <see cref="VGElementCollection"/> /// </summary> /// <param name="searchGroup">The <see cref="VGStyleGroup"/> /// that the elements should match.</param> /// <returns>A <see cref="VGElementCollection"/> with the /// members of the list that are in the given search group.</returns> public VGElementCollection FindAllGroupMembers(VGStyleGroup searchGroup) { VGElementCollection subList = new VGElementCollection(); foreach (VGElement element in this.List) { if ((element.StyleGroup & searchGroup) == searchGroup) { subList.Add(element); } } return subList; }
/// <summary> /// This method removes the elements for which the onset time /// is greater than the time of the given /// first valid sample. /// </summary> /// <param name="firstValidSample"> /// A <see cref="TimedPoint"/> /// with the sample that is the first one not to be removed /// </param> private void RemoveFixations(TimedPoint firstValidSample) { var elementsToRemove = new VGElementCollection(); var removedGazeFixationsCount = 0; var removedMouseFixationsCount = 0; foreach (VGElement element in this.Elements) { if (element.ElementGroup != "Default") { if (element.OnsetTime > firstValidSample.Time) { if (element.StyleGroup == VGStyleGroup.RPL_PEN_GAZE_FIX) { removedGazeFixationsCount++; } else if (element.StyleGroup == VGStyleGroup.RPL_PEN_MOUSE_FIX) { removedMouseFixationsCount++; } elementsToRemove.Add(element); } else if (element.EndTime > firstValidSample.Time) { // Scale ellipse } } } this.gazeFixations.RemoveRange(this.gazeFixations.Count - removedGazeFixationsCount, removedGazeFixationsCount); this.mouseFixations.RemoveRange(this.mouseFixations.Count - removedMouseFixationsCount, removedMouseFixationsCount); this.gazeFixConPolyline.RemoveLastPts(removedGazeFixationsCount); this.mouseFixConPolyline.RemoveLastPts(removedMouseFixationsCount); this.Elements.RemoveAll(elementsToRemove); }
/////////////////////////////////////////////////////////////////////////////// // Construction and Initializing methods // /////////////////////////////////////////////////////////////////////////////// #region CONSTRUCTION /// <summary> /// Initializes a new instance of the VGElementCollectionPropertyDescriptor class. /// </summary> /// <param name="collection">The <see cref="VGElementCollection"/> /// for this <see cref="PropertyDescriptor"/></param> /// <param name="index">The index to use.</param> public VGElementCollectionPropertyDescriptor(VGElementCollection collection, int index) : base("#" + index.ToString(), null) { this.collection = collection; this.index = index; }
/// <summary> /// This method draws the statistic bubbles and transisiton arrows /// of given <see cref="SampleType"/> in given <see cref="VisualizationModes"/>. /// </summary> /// <param name="mode"> /// The <see cref="VisualizationModes"/> to be used. /// </param> /// <param name="sampleType"> /// The <see cref="SampleType"/> of the data. /// </param> public void DrawAOIStatistics(VisualizationModes mode, SampleType sampleType) { // Skip if no data available if (this.aoiStatistics == null) { return; } // Get all statistical elements var statisticalElements = this.Elements.FindAllGroupMembers(VGStyleGroup.AOI_STATISTICS_ARROW); statisticalElements.AddRange(this.Elements.FindAllGroupMembers(VGStyleGroup.AOI_STATISTICS_BUBBLE)); this.Elements.RemoveAll(statisticalElements); var distances = new List<int>(); var aoisWithoutSearchRects = new VGElementCollection(); foreach (VGElement aoi in this.AoiCollection) { if (aoi.StyleGroup != VGStyleGroup.AOI_SEARCHRECT) { aoisWithoutSearchRects.Add(aoi); } } foreach (VGElement aoi in aoisWithoutSearchRects) { if (!this.aoiStatistics.ContainsKey(aoi.Name)) { continue; } var aoiStatistic = this.aoiStatistics[aoi.Name]; if ((mode & VisualizationModes.FixationTime) == VisualizationModes.FixationTime) { if (aoiStatistic.SumOfTimeOfAllFixations > 0) { var bounds = this.GetCircleBounds(aoi.Center, aoiStatistic.SumOfTimeOfAllFixations, mode); var ellipse = new VGEllipse( this.BubbleDrawAction, this.BubblePen, this.BubbleBrush, this.BubbleFont, this.BubbleFontColor, bounds, VGStyleGroup.AOI_STATISTICS_BUBBLE, aoiStatistic.SumOfTimeOfAllFixations + " ms", string.Empty); ellipse.TextAlignment = this.BubbleTextAlignment; distances.Add((int)(bounds.Width / 2)); this.Elements.Add(ellipse); } } if ((mode & VisualizationModes.NumberOfFixations) == VisualizationModes.NumberOfFixations) { if (aoiStatistic.FixationCount > 0) { var bounds = this.GetCircleBounds(aoi.Center, aoiStatistic.FixationCount, mode); var ellipse = new VGEllipse( this.BubbleDrawAction, this.BubblePen, this.BubbleBrush, this.BubbleFont, this.BubbleFontColor, bounds, VGStyleGroup.AOI_STATISTICS_BUBBLE, aoiStatistic.FixationCount.ToString(CultureInfo.InvariantCulture), string.Empty); ellipse.TextAlignment = this.BubbleTextAlignment; distances.Add((int)(bounds.Width / 2)); this.Elements.Add(ellipse); } } if ((mode & VisualizationModes.AverageFixationDuration) == VisualizationModes.AverageFixationDuration) { if (aoiStatistic.FixationDurationMean > 0) { var bounds = this.GetCircleBounds(aoi.Center, aoiStatistic.FixationDurationMean, mode); var ellipse = new VGEllipse( this.BubbleDrawAction, this.BubblePen, this.BubbleBrush, this.BubbleFont, this.BubbleFontColor, bounds, VGStyleGroup.AOI_STATISTICS_BUBBLE, aoiStatistic.FixationDurationMean.ToString("N0") + " ms", string.Empty); ellipse.TextAlignment = this.BubbleTextAlignment; distances.Add((int)(bounds.Width / 2)); this.Elements.Add(ellipse); } } } // Check for absolute or relative transition values var absolute = (mode & VisualizationModes.AbsoluteTransitions) == VisualizationModes.AbsoluteTransitions; if ((mode & VisualizationModes.RelativeTransitions) == VisualizationModes.RelativeTransitions || (mode & VisualizationModes.AbsoluteTransitions) == VisualizationModes.AbsoluteTransitions) { DataView trialsFixations = null; // Get filtered fixations data view switch (sampleType) { case SampleType.Gaze: trialsFixations = this.GazeFixationsView; break; case SampleType.Mouse: trialsFixations = this.MouseFixationsView; break; } var transitions = Statistics.Statistic.CreateTransitionMatrixForSingleAOIs( trialsFixations, aoisWithoutSearchRects); float transitionSum = 0; // Calculate transition total sum only if relative values are requested. if (!absolute) { for (var i = 0; i <= transitions.GetUpperBound(0); i++) { // Skip nowhere transitions if (i == 0) { continue; } for (var j = 0; j <= transitions.GetUpperBound(1); j++) { // Only take values outside the diagonal if (i == j || j == 0) { continue; } transitionSum += (int)transitions.GetValue(i, j); } } } // Write transitionMatrix to dgv for (var i = transitions.GetLowerBound(0); i <= transitions.GetUpperBound(0); i++) { // Skip nowhere transitions if (i == 0) { continue; } for (var j = transitions.GetLowerBound(1); j <= transitions.GetUpperBound(1); j++) { // Only take values above the diagonal if (i >= j) { continue; } float transAtoB; float transBtoA; if (absolute) { transAtoB = (int)transitions.GetValue(i, j); transBtoA = (int)transitions.GetValue(j, i); } else { transAtoB = (float)Math.Round((int)transitions.GetValue(i, j) / transitionSum * 100, 1); transBtoA = (float)Math.Round((int)transitions.GetValue(j, i) / transitionSum * 100, 1); } if (transAtoB > 0 || transBtoA > 0) { var showNumbers = false; if ((this.ArrowDrawAction & ShapeDrawAction.Name) == ShapeDrawAction.Name) { this.ArrowDrawAction |= ~ShapeDrawAction.Name; showNumbers = true; } var arrow = new VGArrow(this.ArrowDrawAction, this.ArrowPen); arrow.Brush = this.ArrowBrush; if (!showNumbers) { arrow.HideWeights = true; } var location1 = aoisWithoutSearchRects[i - 1].Center; var location2 = aoisWithoutSearchRects[j - 1].Center; var distanceFirst = distances.Count >= i ? distances[i - 1] : 15; var distanceSecond = distances.Count >= j ? distances[j - 1] : 15; if (location1.X <= location2.X) { arrow.FirstPoint = location1; arrow.SecondPoint = location2; arrow.FirstPointDistance = distanceFirst; arrow.SecondPointDistance = distanceSecond; arrow.FirstPointWeight = transBtoA; arrow.SecondPointWeight = transAtoB; } else { arrow.FirstPoint = location2; arrow.SecondPoint = location1; arrow.FirstPointDistance = distanceSecond; arrow.SecondPointDistance = distanceFirst; arrow.FirstPointWeight = transAtoB; arrow.SecondPointWeight = transBtoA; } arrow.FormatString = "N0"; if (!absolute) { if (arrow.FirstPointWeight < 1 && arrow.SecondPointWeight < 1) { arrow.FormatString = "N1"; } arrow.AddOnString = "%"; } arrow.WeightFont = this.ArrowFont; arrow.WeightFontColor = this.ArrowFontColor; arrow.ScaleFactor = this.ArrowFactor; arrow.StyleGroup = VGStyleGroup.AOI_STATISTICS_ARROW; arrow.TextAlignment = this.ArrowTextAlignment; this.Elements.Add(arrow); } } } } this.DrawForeground(true); }
/// <summary> /// Initializes a new instance of the Slide class as a clone of /// the given slide. /// </summary> /// <param name="slide">The <see cref="Slide"/> to clone.</param> public Slide(Slide slide) { // Clone stimuli this.stimuli = new VGElementCollection(); foreach (VGElement element in slide.VGStimuli) { this.stimuli.Add((VGElement)element.Clone()); } // Clone activeXElements this.activeXElements = new VGElementCollection(); foreach (VGElement element in slide.ActiveXStimuli) { this.activeXElements.Add((VGElement)element.Clone()); } // Clone stop conditions this.stopConditions = new StopConditionCollection(); foreach (StopCondition condition in slide.StopConditions) { this.stopConditions.Add((StopCondition)condition.Clone()); } // Clone background properties this.BackgroundColor = slide.BackgroundColor; if (slide.BackgroundImage != null) { this.BackgroundImage = (Image)slide.BackgroundImage.Clone(); } if (slide.BackgroundSound != null) { this.BackgroundSound = (AudioFile)slide.BackgroundSound.Clone(); } // Clone trigger this.TriggerSignal = slide.TriggerSignal; this.IsDesktopSlide = slide.IsDesktopSlide; this.IdOfPreSlideFixationTrial = slide.IdOfPreSlideFixationTrial; this.IsDisabled = slide.IsDisabled; // Clone correct responses this.correctResponses = new StopConditionCollection(); foreach (StopCondition condition in slide.CorrectResponses) { this.correctResponses.Add((StopCondition)condition.Clone()); } // Clone links this.links = new StopConditionCollection(); foreach (StopCondition condition in slide.Links) { this.links.Add((StopCondition)condition.Clone()); } // Clone description this.name = slide.Name; this.category = slide.Category; // Clone target areas this.targets = new VGElementCollection(); foreach (VGElement target in slide.TargetShapes) { this.targets.Add((VGElement)target.Clone()); } // Clone mouse properties this.MouseInitialPosition = slide.MouseInitialPosition; this.MouseCursorVisible = slide.MouseCursorVisible; this.ForceMousePositionChange = slide.ForceMousePositionChange; this.PresentationSize = slide.PresentationSize; this.Modified = slide.Modified; }
/// <summary> /// Initializes a new instance of the Slide class. /// </summary> public Slide() { this.stimuli = new VGElementCollection(); this.activeXElements = new VGElementCollection(); this.targets = new VGElementCollection(); this.correctResponses = new StopConditionCollection(); this.links = new StopConditionCollection(); this.stopConditions = new StopConditionCollection(); this.category = string.Empty; this.TriggerSignal = new Trigger(TriggerSignaling.None, TriggerOutputDevices.LPT, 40, 255, 0x0378); this.IdOfPreSlideFixationTrial = -1; }
/////////////////////////////////////////////////////////////////////////////// // 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 the time to the first fixation in given area of interest. /// AOI table has normally only one row. /// </summary> /// <param name="aois">A <see cref="VGElementCollection"/> with the areas of interest for current trial.</param> /// <param name="inputTable">Table with fixation list.</param> /// <param name="numberOfFixation">Set to number of fixation that should be /// detected (first, second, third)</param> /// <returns>Number of fixation that is the "numberOfFixation" (first, second, third) in given AOI</returns> private static int GetNumberOfFixationInGivenAOIList( VGElementCollection aois, DataTable inputTable, int numberOfFixation) { // Never over AOI int hitIndex = -1; if (aois.Count == 0) { // NO AOIs definded hitIndex = -2; return hitIndex; } int rowCounter = 0; int hitCount = 0; // Check for intersection between pathIncludingAllAOIs and Clicklist or Fixationlist foreach (DataRow inputRow in inputTable.Rows) { PointF searchPoint = new PointF( Convert.ToSingle(inputRow["PosX"]), Convert.ToSingle(inputRow["PosY"])); foreach (VGElement aoi in aois) { if (aoi.Contains(searchPoint, tolerance)) { // That means given point lies in current AOI. hitCount++; if (hitCount == numberOfFixation) { hitIndex = rowCounter; break; } } } rowCounter++; } return hitIndex; }
/// <summary> /// Calculates the statistical parameters for the current trial and <see cref="SampleType"/> /// </summary> /// <param name="sampleType"> /// The <see cref="SampleType"/> of which the data should be used. /// </param> public void CalculateAOIStatistics(SampleType sampleType) { this.aoiStatistics = new Dictionary<string, AOIStatistic>(); foreach (VGElement aoi in this.AoiCollection) { var aoiStatistic = new AOIStatistic(); var aoiContainer = new VGElementCollection(); aoiContainer.Add(aoi); switch (sampleType) { case SampleType.Gaze: aoiStatistic = Statistics.Statistic.CalcAOIStatistic(this.GazeFixationsView, aoiContainer); break; case SampleType.Mouse: aoiStatistic = Statistics.Statistic.CalcAOIStatistic(this.MouseFixationsView, aoiContainer); break; } if (!this.aoiStatistics.ContainsKey(aoi.Name)) { this.aoiStatistics.Add(aoi.Name, aoiStatistic); } } }
/// <summary> /// Iterates selected trials and calculates the transition table. /// </summary> /// <param name="worker"> /// The <see cref="BackgroundWorker"/> /// </param> /// <param name="e"> /// A <see cref="DoWorkEventArgs"/> with the event data. /// </param> private void FillTransitionsWithData(BackgroundWorker worker, DoWorkEventArgs e) { DataTable aoiTable = Document.ActiveDocument.DocDataSet.AOIs; var trialsAOIs = new DataView(aoiTable); DataTable subjectsTable = Document.ActiveDocument.DocDataSet.SubjectsAdapter.GetData(); var trialAOIs = new VGElementCollection(); List<string> checkedSubjects = GetCheckedSubjects(this.trvTransitionsSubjects); if (this.rdbTransitionUseAOIGroups.Checked) { int aoiGroupCount = this.aoiGroups.Count; Array transitionMatrix = Array.CreateInstance(typeof(int), aoiGroupCount + 1, aoiGroupCount + 1); var groupIndexAssignment = new Dictionary<string, int>(); groupIndexAssignment.Add("nowhere", 0); for (int i = 0; i < aoiGroupCount; i++) { string aoiGroupEntry = this.aoiGroups[i]; groupIndexAssignment.Add(aoiGroupEntry, i + 1); } // Get selected trials var trialIDs = new List<int>(); foreach (TreeNode categoryNode in this.trvTrialsAOI.Nodes) { foreach (TreeNode trialNode in categoryNode.Nodes) { if (trialNode.Checked) { trialIDs.Add(Convert.ToInt32(trialNode.Name)); } } } // Iterate selected subjects foreach (DataRow subjectRow in subjectsTable.Rows) { string subjectName = subjectRow["SubjectName"].ToString(); if (checkedSubjects.Contains(subjectName)) { DataView fixations = null; if (this.btnEye.Checked) { fixations = new DataView(Document.ActiveDocument.DocDataSet.GazeFixationsAdapter.GetDataBySubject(subjectName)); } else if (this.btnMouse.Checked) { fixations = new DataView(Document.ActiveDocument.DocDataSet.MouseFixationsAdapter.GetDataBySubject(subjectName)); } string foregoingHittedAOIGroup = string.Empty; int foregoingTrialID = -1; foreach (DataRowView fixationRow in fixations) { var trialID = (int)fixationRow["TrialID"]; if (!trialIDs.Contains(trialID)) { continue; } if (trialID != foregoingTrialID) { trialsAOIs.RowFilter = "TrialID=" + trialID.ToString(); foregoingTrialID = trialID; trialAOIs.Clear(); foreach (DataRowView row in trialsAOIs) { 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); trialAOIs.Add(aoi); } } string hittedAOIName = string.Empty; string hittedAOIGroup = string.Empty; List<string[]> hittedAOIs = Statistic.FixationHitsAOI(trialAOIs, fixationRow); if (hittedAOIs.Count > 0) { // Take only first hitted AOI hittedAOIName = hittedAOIs[0][0]; hittedAOIGroup = hittedAOIs[0][1]; } if (foregoingHittedAOIGroup != string.Empty) { if (hittedAOIGroup == string.Empty) { hittedAOIGroup = "nowhere"; } int indexOfHittedGroup = groupIndexAssignment[hittedAOIGroup]; int indexOfForegoingGroup = groupIndexAssignment[foregoingHittedAOIGroup]; var oldEntry = (int)transitionMatrix.GetValue(indexOfForegoingGroup, indexOfHittedGroup); int newEntry = oldEntry + 1; transitionMatrix.SetValue(newEntry, indexOfForegoingGroup, indexOfHittedGroup); } foregoingHittedAOIGroup = hittedAOIGroup; } } } // Write transitionMatrix to dgv for (int i = transitionMatrix.GetLowerBound(0); i <= transitionMatrix.GetUpperBound(0); i++) { // Get a datagridview via asynchronous call. DataGridViewRow newRow = this.GetTransitionsDataGridViewRow(); if (i > 0) { newRow.Cells[0].Value = this.aoiGroups[i - 1]; } else { newRow.Cells[0].Value = "nowhere"; } for (int j = transitionMatrix.GetLowerBound(1); j <= transitionMatrix.GetUpperBound(1); j++) { newRow.Cells[j + 1].Value = transitionMatrix.GetValue(i, j); } } } else if (this.rdbTransitionsUseTrial.Checked) { trialAOIs.Clear(); trialsAOIs.RowFilter = "TrialID=" + e.Argument; foreach (DataRowView row in trialsAOIs) { 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); trialAOIs.Add(aoi); } var gazeFixations = new DataView(Document.ActiveDocument.DocDataSet.GazeFixationsAdapter.GetDataByTrialID((int)e.Argument)); var mouseFixations = new DataView(Document.ActiveDocument.DocDataSet.MouseFixationsAdapter.GetDataByTrialID((int)e.Argument)); string filterString = string.Empty; foreach (string subject in checkedSubjects) { filterString += "(SubjectName='" + subject + "') OR "; } filterString = filterString.Substring(0, filterString.Length - 4); gazeFixations.RowFilter = filterString; mouseFixations.RowFilter = filterString; Array transitionMatrix = null; if (this.btnEye.Checked) { transitionMatrix = Statistic.CreateTransitionMatrixForSingleAOIs(gazeFixations, trialAOIs); } else if (this.btnMouse.Checked) { transitionMatrix = Statistic.CreateTransitionMatrixForSingleAOIs(mouseFixations, trialAOIs); } // Write transitionMatrix to dgv for (int i = transitionMatrix.GetLowerBound(0); i <= transitionMatrix.GetUpperBound(0); i++) { // Get a datagridview via asynchronous call. DataGridViewRow newRow = this.GetTransitionsDataGridViewRow(); if (i > 0) { newRow.Cells[0].Value = trialAOIs[i - 1].Name; } else { newRow.Cells[0].Value = "nowhere"; } for (int j = transitionMatrix.GetLowerBound(1); j <= transitionMatrix.GetUpperBound(1); j++) { newRow.Cells[j + 1].Value = transitionMatrix.GetValue(i, j); } } } }
/////////////////////////////////////////////////////////////////////////////// // Methods for doing main class job // /////////////////////////////////////////////////////////////////////////////// #region METHODS /// <summary> /// This method exports the fixations of the given <see cref="SampleType"/> /// to the given File including AOI information. /// </summary> /// <param name="options">An <see cref="ExportOptions"/> with options for the file export.</param> /// <param name="type">The <see cref="SampleType"/> to be exported.</param> private void Export(ExportOptions options, SampleType type) { string tableName = string.Empty; string fileName = string.Empty; DataTable dataTable = new DataTable(); switch (type) { case SampleType.Gaze: tableName = "GazeFixations"; dataTable = Document.ActiveDocument.DocDataSet.GazeFixations; fileName = options.GazeFileName; break; case SampleType.Mouse: tableName = "MouseFixations"; dataTable = Document.ActiveDocument.DocDataSet.MouseFixations; fileName = options.MouseFileName; break; } bool unknownSubjectFound = false; string missingSubjectName = string.Empty; using (StreamWriter exportFileWriter = new StreamWriter(fileName)) { // Write Documentation exportFileWriter.WriteLine("# File: " + Path.GetFileName(fileName)); exportFileWriter.WriteLine("# Created: " + DateTime.Today.Date.ToLongDateString() + "," + DateTime.Now.ToLongTimeString()); exportFileWriter.WriteLine("# with: " + Application.ProductName + " Version: " + Document.ActiveDocument.ExperimentSettings.OgamaVersion.ToString(3)); exportFileWriter.WriteLine("# Contents: " + tableName + " table."); exportFileWriter.WriteLine("# Applies to Projekt:" + Document.ActiveDocument.ExperimentSettings.Name); exportFileWriter.WriteLine("#"); if (options.ExportFixations) { // Write Column Names foreach (DataColumn dataColumn in dataTable.Columns) { exportFileWriter.Write(dataColumn.Caption); exportFileWriter.Write("\t"); } } else { // We should export saccades which need some other column descriptions exportFileWriter.Write("SubjectName"); exportFileWriter.Write("\t"); exportFileWriter.Write("TrialID"); exportFileWriter.Write("\t"); exportFileWriter.Write("TrialSequence"); exportFileWriter.Write("\t"); exportFileWriter.Write("CountInTrial"); exportFileWriter.Write("\t"); exportFileWriter.Write("StartTime"); exportFileWriter.Write("\t"); exportFileWriter.Write("Duration"); exportFileWriter.Write("\t"); exportFileWriter.Write("Distance"); exportFileWriter.Write("\t"); exportFileWriter.Write("Velocity"); exportFileWriter.Write("\t"); exportFileWriter.Write("Validity"); exportFileWriter.Write("\t"); } if (options.ExportSubjectDetails) { exportFileWriter.Write("SubjectCategory"); exportFileWriter.Write("\t"); exportFileWriter.Write("Age"); exportFileWriter.Write("\t"); exportFileWriter.Write("Sex"); exportFileWriter.Write("\t"); exportFileWriter.Write("Handedness"); exportFileWriter.Write("\t"); exportFileWriter.Write("Comments"); exportFileWriter.Write("\t"); DataTable customParams = Document.ActiveDocument.DocDataSet.ParamsAdapter.GetData(); foreach (DataRow paramRow in customParams.Rows) { exportFileWriter.Write(paramRow["Param"]); exportFileWriter.Write("\t"); } } if (options.ExportTrialDetails) { exportFileWriter.Write("Trial Name"); exportFileWriter.Write("\t"); exportFileWriter.Write("Trial Category"); exportFileWriter.Write("\t"); exportFileWriter.Write("SlideNr"); exportFileWriter.Write("\t"); } if (options.ExportAOIDetails) { if (options.ExportFixations) { exportFileWriter.Write("AOI"); exportFileWriter.Write("\t"); exportFileWriter.Write("AOI group"); exportFileWriter.Write("\t"); } else { exportFileWriter.Write("Saccade Target AOI"); exportFileWriter.Write("\t"); exportFileWriter.Write("Saccade Target AOI group"); exportFileWriter.Write("\t"); } } exportFileWriter.WriteLine(); int trialID = -1; int lastTrialID = -1; string subjectName = string.Empty; string lastsubjectName = "LastSubjectKLSMA"; DataView trialsAOIsView = new DataView(Document.ActiveDocument.DocDataSet.AOIs); SubjectsData subjectData = new SubjectsData(); Dictionary<string, string> subjectParams = new Dictionary<string, string>(); // Sort fixation data DataView fixationsView = new DataView(dataTable); fixationsView.Sort = "SubjectName, TrialSequence, CountInTrial ASC"; VGElementCollection trialAOIs = new VGElementCollection(); string category = string.Empty; string trialName = string.Empty; PointF lastFixationCenter = PointF.Empty; long lastFixationEndTime = 0; int lastFixationDuration = 0; int countInTrial = 0; int slideNr = 0; List<long> slideStartTimes = new List<long>(); foreach (DataRowView dataRow in fixationsView) { trialID = (int)dataRow["TrialID"]; // Skip trials that are not selected. if (!options.CheckedTrialIDs.Contains(trialID)) { continue; } int trialSequence = (int)dataRow["TrialSequence"]; long startTime = (long)dataRow["StartTime"]; int length = (int)dataRow["Length"]; float posX = Convert.ToSingle(dataRow["PosX"]); float posY = Convert.ToSingle(dataRow["PosY"]); PointF fixationCenter = new PointF(posX, posY); subjectName = dataRow["SubjectName"].ToString(); if (!options.CheckedSubjects.Contains(subjectName)) { continue; } if (options.ExportSubjectDetails) { if (subjectName != lastsubjectName) { subjectData = new SubjectsData(); DataTable subjectsTable = Document.ActiveDocument.DocDataSet.SubjectsAdapter.GetDataBySubject(subjectName); if (subjectsTable.Rows.Count == 0) { unknownSubjectFound = true; missingSubjectName = subjectName; continue; } // Parse subject information if (!subjectsTable.Rows[0].IsNull("Age")) { subjectData.Age = (int)subjectsTable.Rows[0]["Age"]; } subjectData.Category = subjectsTable.Rows[0]["Category"].ToString(); subjectData.Comments = subjectsTable.Rows[0]["Comments"].ToString(); subjectData.Handedness = subjectsTable.Rows[0]["Handedness"].ToString(); subjectData.Sex = subjectsTable.Rows[0]["Sex"].ToString(); // Parse custom subject information subjectParams.Clear(); DataTable subjectParamsTable = Document.ActiveDocument.DocDataSet.SubjectParametersAdapter.GetDataBySubject(subjectName); foreach (DataRow paramRow in subjectParamsTable.Rows) { subjectParams.Add(paramRow["Param"].ToString(), paramRow["ParamValue"].ToString()); } lastsubjectName = subjectName; } } if (trialID != lastTrialID) { slideStartTimes.Clear(); DataTable trialEvents = Document.ActiveDocument.DocDataSet.TrialEventsAdapter.GetDataBySubjectNameTrialSequenceButOnlySlideChangeResponses(subjectName, trialSequence); foreach (DataRow slideEventRow in trialEvents.Rows) { slideStartTimes.Add((long)slideEventRow["EventTime"]); } countInTrial = 0; slideNr = 0; if (options.ExportTrialDetails || options.ExportAOIDetails) { DataTable trialTable = Document.ActiveDocument.DocDataSet.TrialsAdapter.GetDataBySubjectAndTrialID(subjectName, trialID); if (trialTable.Rows.Count > 0) { category = trialTable.Rows[0]["Category"].ToString(); trialName = trialTable.Rows[0]["TrialName"].ToString(); } string filter = "TrialID=" + trialID + string.Empty; trialsAOIsView.RowFilter = filter; lastTrialID = trialID; trialAOIs.Clear(); foreach (DataRowView row in trialsAOIsView) { 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); trialAOIs.Add(aoi); } } } if (slideStartTimes.Count > (slideNr + 1) && startTime > slideStartTimes[slideNr]) { slideNr++; } if (options.ExportFixations) { // Write fixation table content foreach (object cellValue in dataRow.Row.ItemArray) { exportFileWriter.Write(cellValue.ToString()); exportFileWriter.Write("\t"); } } else { if (countInTrial != 0) { // we should export saccades exportFileWriter.Write(subjectName); exportFileWriter.Write("\t"); exportFileWriter.Write(trialID); exportFileWriter.Write("\t"); exportFileWriter.Write(trialSequence); exportFileWriter.Write("\t"); exportFileWriter.Write(countInTrial); exportFileWriter.Write("\t"); exportFileWriter.Write(lastFixationEndTime); exportFileWriter.Write("\t"); int duration = (int)(startTime - lastFixationEndTime); exportFileWriter.Write(duration); exportFileWriter.Write("\t"); float distance = VGPolyline.Distance(lastFixationCenter, fixationCenter); exportFileWriter.Write(distance); exportFileWriter.Write("\t"); exportFileWriter.Write(distance / duration); exportFileWriter.Write("\t"); int validity = 0; if (duration > lastFixationDuration) { validity = -1; } exportFileWriter.Write(validity); exportFileWriter.Write("\t"); } } if (options.ExportSubjectDetails) { if (options.ExportFixations || countInTrial != 0) { // Write subject information exportFileWriter.Write(subjectData.Category); exportFileWriter.Write("\t"); exportFileWriter.Write(subjectData.Age); exportFileWriter.Write("\t"); exportFileWriter.Write(subjectData.Sex); exportFileWriter.Write("\t"); exportFileWriter.Write(subjectData.Handedness); exportFileWriter.Write("\t"); exportFileWriter.Write(subjectData.Comments); exportFileWriter.Write("\t"); foreach (string paramValue in subjectParams.Values) { exportFileWriter.Write(paramValue); exportFileWriter.Write("\t"); } } } if (options.ExportTrialDetails) { if (options.ExportFixations || countInTrial != 0) { // Write trial information exportFileWriter.Write(trialName != string.Empty ? trialName : "NamelessTrial"); exportFileWriter.Write("\t"); exportFileWriter.Write(category); exportFileWriter.Write("\t"); exportFileWriter.Write(slideNr); exportFileWriter.Write("\t"); } } if (options.ExportAOIDetails) { if (options.ExportFixations || countInTrial != 0) { // Retrieve AOI position string hittedAOIName = string.Empty; string hittedAOIGroup = string.Empty; List<string[]> hittedAOIs = Statistics.Statistic.FixationHitsAOI(trialAOIs, dataRow); if (hittedAOIs.Count == 0) { hittedAOIName = "nowhere"; hittedAOIGroup = "nowhere"; } foreach (string[] aoi in hittedAOIs) { // Concatenate hitted AOIs hittedAOIName += aoi[0] + "#"; hittedAOIGroup += aoi[1] + "#"; } if (hittedAOIs.Count > 0) { hittedAOIName = hittedAOIName.Substring(0, hittedAOIName.Length - 1); hittedAOIGroup = hittedAOIGroup.Substring(0, hittedAOIGroup.Length - 1); } exportFileWriter.Write(hittedAOIName); exportFileWriter.Write("\t"); exportFileWriter.Write(hittedAOIGroup); exportFileWriter.Write("\t"); } } if (options.ExportFixations || countInTrial != 0) { // Write new line for next row. exportFileWriter.WriteLine(); } countInTrial++; lastFixationCenter = fixationCenter; lastFixationEndTime = startTime + length; lastFixationDuration = length; } } if (unknownSubjectFound) { string message = "At least one fixation of an subject that is not in the database anymore " + "was found. Subject: '" + missingSubjectName + "'" + Environment.NewLine + "Please re-run a complete fixation calculation for all subjects."; ExceptionMethods.ProcessMessage("Old subject fixations found", message); } ExceptionMethods.ProcessMessage("Export successful.", "Fixations were successfully exported to file"); }
/// <summary> /// This static method parses the aoi table filtered by the given trialID /// for AOIs within the given group and returns them in a <see cref="VGElementCollection"/> /// </summary> /// <param name="trialID"> /// An <see cref="Int32"/> with the trial ID /// </param> /// <param name="groupName"> /// A <see cref="string"/> with the group name. /// </param> /// <returns> /// A <see cref="VGElementCollection"/> with the AOIs of the given group. /// </returns> private VGElementCollection GetGroupAOIs(int trialID, string groupName) { var groupAOIs = new VGElementCollection(); DataTable targetTable = Document.ActiveDocument.DocDataSet.AOIsAdapter.GetDataByTrialIDAndGroup( trialID, groupName); var targetAois = new VGElementCollection(); foreach (DataRow row in targetTable.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); groupAOIs.Add(aoi); } return groupAOIs; }
/// <summary> /// Initializes a new instance of the Slide class as a clone of /// the given slide. /// </summary> /// <param name="slide">The <see cref="Slide"/> to clone.</param> public Slide(Slide slide) { // Clone stimuli this.stimuli = new VGElementCollection(); foreach (VGElement element in slide.VGStimuli) { this.stimuli.Add((VGElement)element.Clone()); } // Clone activeXElements this.activeXElements = new VGElementCollection(); foreach (VGElement element in slide.ActiveXStimuli) { this.activeXElements.Add((VGElement)element.Clone()); } // Clone stop conditions this.stopConditions = new StopConditionCollection(); foreach (StopCondition condition in slide.StopConditions) { this.stopConditions.Add((StopCondition)condition.Clone()); } // Clone background properties this.BackgroundColor = slide.BackgroundColor; if (slide.BackgroundImage != null) { this.BackgroundImage = (Image)slide.BackgroundImage.Clone(); } if (slide.BackgroundSound != null) { this.BackgroundSound = (AudioFile)slide.BackgroundSound.Clone(); } // Clone trigger this.TriggerSignal = slide.TriggerSignal; this.IsDesktopSlide = slide.IsDesktopSlide; this.IdOfPreSlideFixationTrial = slide.IdOfPreSlideFixationTrial; this.IsDisabled = slide.IsDisabled; // Clone correct responses this.correctResponses = new StopConditionCollection(); foreach (StopCondition condition in slide.CorrectResponses) { this.correctResponses.Add((StopCondition)condition.Clone()); } // Clone links this.links = new StopConditionCollection(); foreach (StopCondition condition in slide.Links) { this.links.Add((StopCondition)condition.Clone()); } // Clone description this.name = slide.Name; this.category = slide.Category; // Clone target areas this.targets = new VGElementCollection(); foreach (VGElement target in slide.TargetShapes) { this.targets.Add((VGElement)target.Clone()); } // Clone mouse properties this.MouseInitialPosition = slide.MouseInitialPosition; this.MouseCursorVisible = slide.MouseCursorVisible; this.ForceMousePositionChange = slide.ForceMousePositionChange; this.PresentationSize = slide.PresentationSize; this.Modified = slide.Modified; }
/// <summary> /// Adds a range of <see cref="VGElement"/>s to the collection. /// </summary> /// <param name="elementCollection">The <see cref="VGElementCollection"/> to be /// added to the end of the collection.</param> public void AddRange(VGElementCollection elementCollection) { foreach (VGElement element in elementCollection) { this.List.Add(element); } }
/////////////////////////////////////////////////////////////////////////////// // Construction and Initializing methods // /////////////////////////////////////////////////////////////////////////////// #region CONSTRUCTION /// <summary> /// Initializes a new instance of the VGElementCollectionPropertyDescriptor class. /// </summary> /// <param name="collection">The <see cref="VGElementCollection"/> /// for this <see cref="PropertyDescriptor"/></param> /// <param name="index">The index to use.</param> public VGElementCollectionPropertyDescriptor(VGElementCollection collection, int index) : base("#" + index.ToString(), null) { this.collection = collection; this.index = index; }
/// <summary> /// This static method calculates the number of clicks at the given AOI or AOI group. /// </summary> /// <param name="mouseStopConditions">A <see cref="List{MouseStopCondition}"/> with the clicks.</param> /// <param name="aoiTable">A <see cref="DataTable"/> with the aoi or aois.</param> /// <param name="button">A <see cref="MouseButtons"/> with the button to count for.</param> /// <returns>An <see cref="Int32"/> with the number of clicks of the given /// mouse button at the given AOI(s).</returns> private static int CalcNumberOfClicksAtAOIs( List<MouseStopCondition> mouseStopConditions, DataTable aoiTable, MouseButtons button) { 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); } // Never over AOI int numberOfClicksAtAOI = -1; List<Point> clickLocations = ParseConditionsForLocations(mouseStopConditions, button); if (aois.Count == 0) { // no AOIs definded return -2; } if (clickLocations.Count == 0) { // no clicks of given type at all return -3; } int count = 0; foreach (Point clickLocation in clickLocations) { int hitIndex = IsClickAtTarget(aois, clickLocation); if (hitIndex >= 0) { count++; } } numberOfClicksAtAOI = count == 0 ? -1 : count; // -1: Never over AOI // -2; no AOIs definded // -3; no clicks of given type at all return numberOfClicksAtAOI; }