/// <summary> /// This static method is to be used by the ConditionData instance when creating the /// special start-area trial after reading trial number 1 in a XML log file. The special /// start-area trial is not logged explicitly, but it can be created from the information /// in trial number 1. /// </summary> /// <param name="trialOne">The first trial in the condition whose last target is used to /// create the special start-area trial.</param> /// <returns>The special start-area trial for a 2D task.</returns> internal static TrialData2D CreateStartArea(TrialData2D trialOne) { TrialData2D sa = new TrialData2D(); sa._number = 0; sa._practice = true; sa._thisCircle = trialOne._lastCircle; sa._isoCenter = trialOne._isoCenter; sa._tInterval = trialOne._tInterval; return(sa); }
/// <summary> /// Constructs a FittsCondition instance. A FittsCondition encapsulates an (A x W x MT%) or an (A x W) /// condition in a Fitts' law study. Its trials are created here with the appropriate condition values, /// but no data is added to them until performance occurs. /// </summary> /// <param name="block">The 0-based block index number to which this condition belongs. A block is the repeat of all conditions.</param> /// <param name="index">The 0-based index of this condition within its block.</param> /// <param name="A">The nominal movement amplitude for trials in this condition.</param> /// <param name="W">The nominal target width for trials in this condition.</param> /// <param name="MTpct">The percentage of MTpred that represents the normative movement time for /// trials in this metronome condition, or -1.0 if not using a metronome.</param> /// <param name="MTpred">The Fitts-predicted movement time in milliseconds for trials in this metronome /// condition, or -1L if not using a metronome.</param> /// <param name="trials">The number of trials to create with these parameters within this condition. This does /// not include the special start trial at index 0.</param> /// <param name="practice">The number of trials that are to be flagged as practice trials.</param> /// <param name="is2D">If true, circular targets in the ISO 9241-9 pattern will be created; if false, vertical ribbon targets will be created.</param> public ConditionData(int block, int index, int A, int W, double MTpct, long MTpred, int trials, int practice, bool is2D) { // // Set the variables that define this condition. // _block = block; _index = index; _a = A; _w = W; _circular = is2D; _tAppeared = -1L; _mtpct = MTpct; _mtpred = MTpred; long mt = (_mtpct != -1.0) ? (long)(_mtpct * _mtpred) : -1L; // // Find the center of the display area. // Rectangle bounds = Screen.PrimaryScreen.Bounds; PointF center = new PointF(bounds.Width / 2f, bounds.Height / 2f); // // Build up arrays of the circular or rectangular targets. // CircleF[] circles = null; RectangleF[] rects = null; if (is2D) // ISO 9241-9 task { double radians = 3.0 * Math.PI / 2.0; // start from the top (270 degrees) double delta = (2.0 * Math.PI) / trials; // radian delta between circles CircleF[] tmpCircles = new CircleF[trials + 1]; // add 1 for special start-area trial at index 0 for (int i = 0; i < tmpCircles.Length; i++) { float x = center.X + (float)(Math.Cos(radians) * (A / 2.0)); float y = center.Y + (float)(Math.Sin(radians) * (A / 2.0)); tmpCircles[i] = new CircleF(x, y, W / 2f); radians += delta; } // order the targets appropriately according to the ISO 9241-9 standard circles = new CircleF[tmpCircles.Length]; for (int i = 0, j = 0; i < circles.Length / 2; i++, j += 2) // even slots { circles[j] = tmpCircles[i]; } for (int i = circles.Length / 2, j = 1; i < circles.Length; i++, j += 2) // odd slots { circles[j] = tmpCircles[i]; } } else // traditional Fitts' reciprocal task with vertical ribbons { rects = new RectangleF[trials + 1]; // add 1 for special start-area trial at index 0 for (int i = 0; i < rects.Length; i++) { int j = (i % 2 == 0) ? -1 : +1; float cx = center.X + j * (A / 2f); rects[i] = new RectangleF(cx - W / 2f, 0f, W, bounds.Height); } } // // Create the trial instances that represent the trials with the given targets. This includes // creating the special start-area trial at index 0 in the condition representing the starting // area that, when clicked, starts the actual trials. // _trials = new List <TrialData>(trials + 1); for (int i = 0; i < trials + 1; i++) { TrialData td; if (is2D) { td = new TrialData2D(i, i <= practice, i == 0 ? CircleF.Empty : circles[i - 1], circles[i], center, mt, trials); } else { td = new TrialData1D(i, i <= practice, i == 0 ? RectangleF.Empty : rects[i - 1], rects[i], mt); } _trials.Add(td); } }
/// <summary> /// Reads a data object from XML and returns an instance of the object. /// </summary> /// <param name="reader">An open XML reader. The reader will be closed by this /// method after reading.</param> /// <returns>Returns <b>true</b> if successful; <b>false</b> otherwise.</returns> /// <remarks>Clients should first create a new instance using a default constructor, and then /// call this method to populate the data fields of the default instance.</remarks> public bool ReadFromXml(XmlTextReader reader) { reader.Read(); // <Condition> if (reader.Name != "Condition") { throw new XmlException("XML format error: Expected the <Condition> tag."); } _block = XmlConvert.ToInt32(reader.GetAttribute("block")); _index = XmlConvert.ToInt32(reader.GetAttribute("index")); _circular = XmlConvert.ToBoolean(reader.GetAttribute("circular")); int trials = XmlConvert.ToInt32(reader.GetAttribute("trials")); _mtpct = XmlConvert.ToDouble(reader.GetAttribute("MTPct")); _mtpred = XmlConvert.ToInt64(reader.GetAttribute("MTPred")); _a = XmlConvert.ToInt32(reader.GetAttribute("A")); _w = XmlConvert.ToInt32(reader.GetAttribute("W")); // read in the trials and add them to the condition _trials = new List <TrialData>(trials + 1); // include slot for special start-area trial for (int i = 1; i <= trials; i++) { TrialData td; if (_circular) { td = new TrialData2D(); if (!td.ReadFromXml(reader)) { throw new XmlException("Failed to read the TrialData2D."); } if (i == 1) { TrialData2D sa = TrialData2D.CreateStartArea((TrialData2D)td); _trials.Add(sa); // add special start-area trial } } else // 1D { td = new TrialData1D(); if (!td.ReadFromXml(reader)) { throw new XmlException("Failed to read the TrialData1D."); } if (i == 1) { TrialData1D sa = TrialData1D.CreateStartArea((TrialData1D)td); _trials.Add(sa); // add special start-area trial } } // now add the trial just read in _trials.Add(td); } reader.Read(); // </Condition> if (reader.Name != "Condition" || reader.NodeType != XmlNodeType.EndElement) { throw new XmlException("XML format error: Expected the </Condition> tag."); } return(true); }