/// <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);
        }
Example #2
0
        /// <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);
            }
        }
Example #3
0
        /// <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);
        }