/// <summary>
        /// Simulates the specified joints.
        /// </summary>
        /// <param name="joints">The joints.</param>
        /// <param name="links">The links.</param>
        /// <param name="Forward">The forward.</param>
        private void Simulate(List <Joint> joints, List <Link> links, Boolean Forward)
        {
            var timeStep          = (Forward == (InputSpeed > 0)) ? FixedTimeStep : -FixedTimeStep;
            var startingPosChange = (Forward == (InputSpeed > 0))
                ? Constants.DefaultStepSize
                : -Constants.DefaultStepSize;

            if (InputJoint.TypeOfJoint == JointType.P)
            {
                startingPosChange *= AverageLength;
            }
            var     maxLengthError = MaxSmoothingError * AverageLength;
            var     currentTime    = 0.0;
            Boolean validPosition;
            var     posFinder = new PositionFinder(joints, links, gearsData, simulationDriveIndex);
            var     velSolver = new VelocitySolver(joints, links, FirstInputJointIndex, simulationDriveIndex, InputLinkIndex,
                                                   InputSpeed, gearsData, AverageLength);
            var accelSolver = new AccelerationSolver(joints, links, FirstInputJointIndex, simulationDriveIndex,
                                                     InputLinkIndex, InputSpeed, gearsData, AverageLength);

            do
            {
                #region Find Next Positions

                if (useErrorMethod)
                {
                    var    k = 0;
                    double upperError;
                    do
                    {
                        timeStep = startingPosChange / InputSpeed;
                        NumericalPosition(timeStep, joints, links);
                        validPosition = posFinder.DefineNewPositions(startingPosChange, ref IsDyadic);
                        upperError    = posFinder.PositionError - maxLengthError;
                        if (validPosition && upperError < 0)
                        {
                            startingPosChange *= Constants.ErrorSizeIncrease;
                            // startingPosChange = startingPosChange * maxLengthError / (maxLengthError + upperError);
                        }
                        else
                        {
                            if (Math.Abs(startingPosChange * Constants.ConservativeErrorEstimation * 0.5) <
                                Constants.MinimumStepSize)
                            {
                                validPosition = false;
                            }
                            else
                            {
                                startingPosChange *= Constants.ConservativeErrorEstimation * 0.5;
                            }
                        }
                    } while ((!validPosition || upperError > 0) && k++ < Constants.MaxItersInPositionError
                             &&
                             (Math.Abs(startingPosChange * Constants.ConservativeErrorEstimation * 0.5) >=
                              Constants.MinimumStepSize));
                    //var tempStep = startingPosChange;
                    //startingPosChange = (Constants.ErrorEstimateInertia * prevStep + startingPosChange) / (1 + Constants.ErrorEstimateInertia);
                    //prevStep = tempStep;
                }
                else
                {
                    // this next function puts the xNumerical and yNumerical values in the joints
                    NumericalPosition(timeStep, joints, links);
                    var delta = InputSpeed * timeStep;
                    // this next function puts the x and y values in the joints
                    validPosition = posFinder.DefineNewPositions(delta, ref IsDyadic);
                }

                #endregion

                if (validPosition)
                {
                    if (Forward == (InputSpeed > 0))
                    {
                        lock (InputRange)
                        {
                            InputRange[1] = links[InputLinkIndex].Angle;
                        }
                    }
                    else
                    {
                        lock (InputRange)
                        {
                            InputRange[0] = links[InputLinkIndex].Angle;
                        }
                    }

                    #region Find Velocities for Current Position

                    // this next functions puts the vx and vy values as well as the vx_unit and vy_unit in the joints
                    if (!velSolver.Solve())
                    {
                        Status += "Instant Centers could not be found at" + currentTime + ".";
                        NumericalVelocity(timeStep, joints, links);
                    }

                    #endregion

                    #region Find Accelerations for Current Position

                    // this next functions puts the ax and ay values in the joints
                    if (!accelSolver.Solve())
                    {
                        Status += "Analytical acceleration could not be found at" + currentTime + ".";
                        NumericalAcceleration(timeStep, joints, links);
                    }

                    #endregion

                    currentTime += timeStep;
                    var jointParams = WriteJointStatesVariablesToMatrixAndToLast(joints);
                    var linkParams  = WriteLinkStatesVariablesToMatrixAndToLast(links);
                    if (Forward == (InputSpeed > 0))
                    {
                        lock (JointParameters)
                            JointParameters.AddNearEnd(currentTime, jointParams);
                        lock (LinkParameters)
                            LinkParameters.AddNearEnd(currentTime, linkParams);
                    }
                    else
                    {
                        lock (JointParameters)
                            JointParameters.AddNearBegin(currentTime, jointParams);
                        lock (LinkParameters)
                            LinkParameters.AddNearBegin(currentTime, linkParams);
                    }
                }
            } while (validPosition && LessThanFullRotation());
        }
        /// <summary>
        /// Sets the initial velocity and acceleration.
        /// </summary>
        /// <param name="joints">The joints.</param>
        /// <param name="links">The links.</param>
        /// <param name="initJointParams">The initialize joint parameters.</param>
        /// <param name="initLinkParams">The initialize link parameters.</param>
        private void SetInitialVelocityAndAcceleration(List <Joint> joints, List <Link> links,
                                                       out double[,] initJointParams, out double[,] initLinkParams)
        {
            var posFinder = new PositionFinder(joints, links, gearsData, simulationDriveIndex);

            posFinder.UpdateSliderPosition();
            var velSolver = new VelocitySolver(joints, links, FirstInputJointIndex, simulationDriveIndex, InputLinkIndex,
                                               InputSpeed, gearsData, AverageLength);
            var accelSolver = new AccelerationSolver(joints, links, FirstInputJointIndex, simulationDriveIndex,
                                                     InputLinkIndex, InputSpeed, gearsData, AverageLength);

            initJointParams = WriteJointStatesVariablesToMatrixAndToLast(joints);
            initLinkParams  = WriteLinkStatesVariablesToMatrixAndToLast(links);
            var smallTimeStep = (double.IsNaN(FixedTimeStep))
                ? Constants.SmallPerturbationFraction
                : Constants.SmallPerturbationFraction * FixedTimeStep;

            if (velSolver.Solve())
            {
                for (var i = 0; i <= simulationDriveIndex; i++)
                {
                    initJointParams[oIOSJ[i], 2] = joints[i].VxLast = joints[i].Vx;
                    initJointParams[oIOSJ[i], 3] = joints[i].VyLast = joints[i].Vy;
                }
                for (var i = 0; i <= InputLinkIndex; i++)
                {
                    initLinkParams[oIOSL[i], 1] = links[i].VelocityLast = links[i].Velocity;
                }
                if (accelSolver.Solve())
                {
                    for (var i = 0; i <= simulationDriveIndex; i++)
                    {
                        initJointParams[oIOSJ[i], 4] = joints[i].Ax;
                        initJointParams[oIOSJ[i], 5] = joints[i].Ay;
                    }
                    for (var i = 0; i <= InputLinkIndex; i++)
                    {
                        initLinkParams[oIOSL[i], 2] = links[i].Acceleration;
                    }
                }
                else
                {
                    /* velocity was successfully found, but not acceleration. */
                    if (posFinder.DefineNewPositions(smallTimeStep * InputSpeed, ref IsDyadic) &&
                        velSolver.Solve())
                    {
                        /* forward difference on velocities to create accelerations. */
                        for (var i = 0; i <= simulationDriveIndex; i++)
                        {
                            initJointParams[oIOSJ[i], 4] = joints[i].Ax = (joints[i].Vx - joints[i].VxLast) / smallTimeStep;
                            initJointParams[oIOSJ[i], 5] = joints[i].Ay = (joints[i].Vy - joints[i].VyLast) / smallTimeStep;
                        }
                        for (var i = 0; i <= InputLinkIndex; i++)
                        {
                            initLinkParams[oIOSL[i], 2] = links[i].Acceleration = (links[i].Velocity - links[i].VelocityLast) / smallTimeStep;
                        }

                        /* since the position solving wrote values to joints[i].x and .y, we need to reset them, for further work. */
                        foreach (var joint in SimulationJoints)
                        {
                            joint.X = joint.XInitial;
                            joint.Y = joint.YInitial;
                        }
                        foreach (var link in SimulationLinks)
                        {
                            link.Angle = link.AngleInitial;
                        }
                    }
                }
                return;
            }
            var ForwardJointParams = new double[NumAllJoints, 2];
            var ForwardLinkParams  = new double[NumLinks];
            /*** Stepping Forward in Time ***/
            var forwardSuccess = posFinder.DefineNewPositions(smallTimeStep * InputSpeed, ref IsDyadic);

            if (forwardSuccess)
            {
                for (var i = 0; i < NumAllJoints; i++)
                {
                    ForwardJointParams[oIOSJ[i], 0] = joints[i].X;
                    ForwardJointParams[oIOSJ[i], 1] = joints[i].Y;
                }
                for (var i = 0; i < NumLinks; i++)
                {
                    ForwardLinkParams[oIOSL[i]] = links[i].Angle;
                }
            }
            /*** Stepping Backward in Time ***/
            var BackwardJointParams = new double[NumAllJoints, 2];
            var BackwardLinkParams  = new double[NumLinks];
            var backwardSuccess     = posFinder.DefineNewPositions(-smallTimeStep * InputSpeed, ref IsDyadic);

            if (backwardSuccess)
            {
                for (var i = 0; i < NumAllJoints; i++)
                {
                    BackwardJointParams[oIOSJ[i], 0] = joints[i].X;
                    BackwardJointParams[oIOSJ[i], 1] = joints[i].Y;
                }
                for (var i = 0; i < NumLinks; i++)
                {
                    BackwardLinkParams[oIOSL[i]] = links[i].Angle;
                }
            }
            if (forwardSuccess && backwardSuccess)
            {
                /* central difference puts values in init parameters. */
                for (var i = 0; i < NumAllJoints; i++)
                {
                    /* first-order central finite difference */
                    initJointParams[i, 2] = (ForwardJointParams[i, 0] - BackwardJointParams[i, 0]) / (2 * smallTimeStep);
                    initJointParams[i, 3] = (ForwardJointParams[i, 1] - BackwardJointParams[i, 1]) / (2 * smallTimeStep);
                    /* second-order central finite difference */
                    initJointParams[i, 4] = (ForwardJointParams[i, 0] - 2 * initJointParams[i, 0] +
                                             BackwardJointParams[i, 0]) / (smallTimeStep * smallTimeStep);
                    initJointParams[i, 5] = (ForwardJointParams[i, 1] - 2 * initJointParams[i, 1] +
                                             BackwardJointParams[i, 1]) / (smallTimeStep * smallTimeStep);
                }
                for (var i = 0; i < NumAllLinks; i++)
                {
                    /* first-order central finite difference */
                    initLinkParams[i, 1] = (ForwardLinkParams[i] - BackwardLinkParams[i]) / (2 * smallTimeStep);
                    /* second-order central finite difference */
                    initLinkParams[i, 2] = (ForwardLinkParams[i] - 2 * initLinkParams[i, 0] + BackwardLinkParams[i])
                                           / (smallTimeStep * smallTimeStep);
                }
            }
            else if (forwardSuccess)
            {
                /* forward difference puts values in init parameters. */
                for (var i = 0; i < NumAllJoints; i++)
                {
                    /* first-order forward finite difference */
                    initJointParams[i, 2] = (ForwardJointParams[i, 0] - initJointParams[i, 0]) / smallTimeStep;
                    initJointParams[i, 3] = (ForwardJointParams[i, 1] - initJointParams[i, 1]) / smallTimeStep;
                }
                for (var i = 0; i < NumAllLinks; i++)
                {
                    /* first-order forward finite difference */
                    initLinkParams[i, 1] = (ForwardLinkParams[i] - initLinkParams[i, 0]) / smallTimeStep;
                }
            }
            else if (backwardSuccess)
            {
                /* backward difference puts values in init parameters. */
                for (var i = 0; i < NumAllJoints; i++)
                {
                    /* first-order backward finite difference */
                    initJointParams[i, 2] = (initJointParams[i, 0] - BackwardJointParams[i, 0]) / smallTimeStep;
                    initJointParams[i, 3] = (initJointParams[i, 1] - BackwardJointParams[i, 1]) / smallTimeStep;
                }
                for (var i = 0; i <= NumAllLinks; i++)
                {
                    /* first-order backward finite difference */
                    initLinkParams[i, 1] = (initLinkParams[i, 0] - BackwardLinkParams[i]) / smallTimeStep;
                }
            }
            /* since the position solving wrote values to joints[i].x and .y, we need to reset them, for further work. */
            foreach (var joint in SimulationJoints)
            {
                joint.X = joint.XInitial;
                joint.Y = joint.YInitial;
            }
            foreach (var link in SimulationLinks)
            {
                link.Angle = link.AngleInitial;
            }
        }