/// <summary>
        /// This returns an array of joint angles from an input XYZ position
        /// </summary>
        /// <param name="Position"></param>
        /// <returns></returns>
        protected override double[] getJointAngles(Point3D Position)
        {
            if(!Initialized)
            {
                radAngle = new double[N + 1];
                radAngle.Initialize();

                thetaOffset = new double[N + 1];
                thetaOffset[0] = 0;
                for (int i = 1; i <= N; i++)
                {
                    thetaOffset[i] = DHparameters[i - 1, 3] * Math.PI / 180;
                }

                Initialized = true;
            }
            // create desired position vector
            Pd = new Vector3D(Position.X, Position.Y, Position.Z);
            // create desired orientation vector
            Rd = new Vector3D[3];
            Rh = new Vector3D[3];
            // declare 3D array for each joint frame axis (xi, yi, zi, Pi)
            frame = new Vector3D[N + 1, 4];
            frame.Initialize();
            // set base frame
            frame[0, 0].X = 1;
            frame[0, 1].Y = 1;
            frame[0, 2].Z = 1;

            Vector3D[] Pstar = new Vector3D[N];
            Pstar.Initialize();

            int link = N;
            int tries = 0;
            // begin Cyclic Coordinate Descent loop
            do
            {
                // initialize frame positions
                for (int i = 0; i < N + 1; i++)
                {
                    frame[i, 3].X = 0;
                    frame[i, 3].Y = 0;
                    frame[i, 3].Z = 0;
                }
                // forward recurrsion formulas for frame position and orientation
                for (int i = 1; i < N + 1; i++)
                {
                    // x(i) orientation vector
                    frame[i, 0] = Vector3D.Add((Vector3D.Multiply(Math.Cos(radAngle[i - 1]), frame[(i - 1), 0])), (Vector3D.Multiply(Math.Sin(radAngle[i - 1]), frame[(i - 1), 1])));
                    // z(i) orientation vector
                    frame[i, 2] = Vector3D.Add((Vector3D.Multiply(Math.Cos(DHparameters[i - 1, 0] * Math.PI / 180), frame[(i - 1), 2])), Vector3D.Multiply(Math.Sin(DHparameters[(i - 1), 0] * Math.PI / 180), Vector3D.CrossProduct(frame[i, 0], frame[(i - 1), 2])));
                    // y(i) orientation vector
                    frame[i, 1] = Vector3D.CrossProduct(frame[i, 2], frame[i, 0]);
                }
                // P* --> relative positions of next frame wrt present frame
                for (int i = 0; i < N; i++)
                {
                    Pstar[i] = Vector3D.Add(Vector3D.Multiply(DHparameters[i, 2], frame[i, 2]), Vector3D.Multiply(DHparameters[i, 1], frame[i + 1, 0]));
                }
                //P(i) --> frame positions wrt base frame
                for (int i = 1; i < N + 1; i++)
                {
                    frame[i, 3] = frame[i - 1, 3] + Pstar[i - 1];
                }
                // set position of end effector
                Ph = frame[N, 3];

                // compute relative positions
                Pih = new Vector3D[N + 1];
                for(int i = N - 1; i >= 0; i--)
                {
                    Pih[i] = Vector3D.Subtract(Ph, frame[i, 3]);
                }
                // set end effector orientation
                Rh[0] = frame[N, 0];
                Rh[1] = frame[N, 1];
                Rh[2] = frame[N, 2];
                // calculate orientation error
                Eo = 0;
                for (int i = 0; i < 3; i++)
                {
                    if(Sigma[i])
                    {
                        Eo += Math.Pow((Vector3D.DotProduct(Rd[i], Rh[i]) - 1), 2);
                    }
                }
                // calculate current position error
                Ec = Eo + Math.Pow(Vector3D.DotProduct(Vector3D.Subtract(Pd, Ph), Vector3D.Subtract(Pd, Ph)), 2);

                //if ((Ec > IK_POS_THRESH) && (Ec < BETA) && (Ec > Math.Pow(Ep, 2))) // begin BFGS optimization
                //{
                //    double epsg = 0.0000000001;
                //    double epsf = 0;
                //    double epsx = 0;
                //    int maxits = 0;             // maximum number of iterations, for unlimited = 0
                //    double[] optiAngle = new double[N];
                //    for(int i = 0; i < N; i++)
                //    {
                //        optiAngle[i] = radAngle[i + 1];
                //    }
                //    alglib.minlbfgsstate state;
                //    alglib.minlbfgsreport rep;

                //    alglib.minlbfgscreate(N, 4, optiAngle, out state);         // create optimizer with current joint angles for initial values
                //    alglib.minlbfgssetcond(state, epsg, epsf, epsx, maxits);        // set optimizer options
                //    alglib.minlbfgsoptimize(state, function1_grad, null, null);     // optimize
                //    alglib.minlbfgsresults(state, out optiAngle, out rep);           // get results
                //    for(int i = 0; i < N; i++)
                //    {
                //        radAngle[i + 1] = optiAngle[i];
                //    }
                //}
                if (Ec > IK_POS_THRESH) // begin Cyclic Coordinate Descent loop
                {
                    
                    // create target effector position vector
                    Vector3D Pid = Vector3D.Subtract(Pd, frame[link, 3]);
                    //Pid.Normalize();
                    //Pih[link].Normalize();
                    double wp = 1;      // position weight
                    double wo = 1;      // orientation weight

                    double k1 = 0;
                    for(int i = 0; i < 3; i++)
                    {
                        if(Sigma[i])
                            k1 += wo * Vector3D.DotProduct(Rd[i], frame[link, 2]) * Vector3D.DotProduct(Rh[i], frame[link, 2]);
                    }
                    k1 += wp * Vector3D.DotProduct(Pid, frame[link-1, 2]) * Vector3D.DotProduct(Pih[link], frame[link-1, 2]);

                    double k2 = 0;
                    for (int i = 0; i < 3; i++)
                    {
                        if(Sigma[i])
                            k2 += wo * Vector3D.DotProduct(Rd[i], Rh[i]);
                    }
                    k2 += wp * Vector3D.DotProduct(Pid, Pih[link]);

                    double k3 = 0;
                    Vector3D ko3 = new Vector3D();
                    for (int i = 0; i < 3; i++)
                    {
                        if (Sigma[i])
                            ko3 = Vector3D.Add(ko3, wo * Vector3D.CrossProduct(Rh[i], Rd[i]));
                    }
                    k3 = Vector3D.DotProduct(frame[link-1, 2], Vector3D.Add(wp * Vector3D.CrossProduct(Pih[link], Pid), ko3));
                    // minimize position and orientation error
                    double turnAngle = Math.Atan(-k3 / (k1 - k2));
                    radAngle[link] += turnAngle;
                    /*
                    // use the dot product to calculate the cos of the desired angle
                    double cosAngle = Vector3D.DotProduct(Pid,Pih[link]);
                    // check if we need to rotate the link
                    if(cosAngle < 0.99999)
                    {
                        // use cross product to check rotation direction
                        Vector3D crossResult = Vector3D.CrossProduct(Pih[link], Pid);
                        crossResult.Normalize();
                        double turnAngle = Vector3D.AngleBetween(Pid, Pih[link]) * Math.PI / 180;
                        double sign = Vector3D.DotProduct(frame[link, 2], crossResult);
                        if (sign < 0)
                            turnAngle = -turnAngle;
                        radAngle[link] += turnAngle;
                     */
                    // adjust angle based on joint limits
                    if (radAngle[link] < (MinMax[link - 1].X * Math.PI / 180))
                        radAngle[link] = MinMax[link - 1].X * Math.PI / 180;
                    else if (radAngle[link] > (MinMax[link - 1].Y * Math.PI / 180))
                        radAngle[link] = MinMax[link - 1].Y * Math.PI / 180;
                    if (double.IsNaN(radAngle[link]))
                        radAngle[link] = 0;
                    //}
                        
                    // backward recurssion through joints for CCD
                    if (link-- < 2) link = N;
                }
                // set previous error value for next loop
                Ep = Ec;
            }
            while (tries++ < IK_MAX_TRIES && Ec > IK_POS_THRESH);

            double[] angles;
            // check if we are outputting workspace forces
            if(OutputWorkspace)
            {
                double forceGain = 0.5;
                angles = new double[N + 2];
                // calculate workspace forces if our position error is greater than the threshold
                if (Ec > IK_POS_THRESH)
                {
                    Vector3D forces = Vector3D.Multiply(forceGain, Vector3D.Subtract(Pd, Ph));
                    // invert forces if desired
                    angles[N - 1] = InvertForces[0] ? -forces.X : forces.X;
                    angles[N] = InvertForces[1] ? -forces.Y : forces.Y;
                    angles[N + 1] = InvertForces[2] ? -forces.Z : forces.Z;
                    for(int i = N-1; i < N+2; i++)
                    {
                        if (angles[i] > maxForce) angles[i] = maxForce;
                        else if (angles[i] < -maxForce) angles[i] = -maxForce;
                    }
                }
                else
                {
                    // no workspace force if we can reach desired point
                    angles[N - 1] = 0;
                    angles[N] = 0;
                    angles[N + 1] = 0;
                }
            }
            else
                angles = new double[N - 1];
            // change output angles based on joint coupling
            switch(Coupling)
            {
                case CouplingType.None:
                    //convert angles to degrees
                    for (int i = 0; i < N - 1; i++)
                    {
                        angles[i] = radAngle[i + 1] * 180 / Math.PI;
                    }
                    break;
                case CouplingType.ShoulderTwoDOF:
                    angles[0] = (radAngle[1] + radAngle[2]) * 180 / Math.PI ;
                    angles[1] = (radAngle[1] - radAngle[2]) * 180 / Math.PI;
                    for (int i = 2; i < N - 1; i++)
                    {
                        angles[i] = radAngle[i + 1] * 180 / Math.PI;
                    }
                    break;
            }
            return angles;
        }
        public void function1_grad(double[] q, ref double func, double[] grad, object obj)
        {
            Vector3D[] Pstar = new Vector3D[N];
            Pstar.Initialize();

            // initialize frame positions
            for (int i = 0; i < N + 1; i++)
            {
                frame[i, 3].X = 0;
                frame[i, 3].Y = 0;
                frame[i, 3].Z = 0;
            }
            // forward recurrsion formulas for frame position and orientation
            for (int i = 1; i < N + 1; i++)
            {
                // x(i) orientation vector
                frame[i, 0] = Vector3D.Add((Vector3D.Multiply(Math.Cos(radAngle[i - 1]), frame[(i - 1), 0])), (Vector3D.Multiply(Math.Sin(radAngle[i - 1]), frame[(i - 1), 1])));
                // z(i) orientation vector
                frame[i, 2] = Vector3D.Add((Vector3D.Multiply(Math.Cos(DHparameters[i - 1, 0] * Math.PI / 180), frame[(i - 1), 2])), Vector3D.Multiply(Math.Sin(DHparameters[(i - 1), 0] * Math.PI / 180), Vector3D.CrossProduct(frame[i, 0], frame[(i - 1), 2])));
                // y(i) orientation vector
                frame[i, 1] = Vector3D.CrossProduct(frame[i, 2], frame[i, 0]);
            }
            // P* --> relative positions of next frame wrt present frame
            for (int i = 0; i < N; i++)
            {
                Pstar[i] = Vector3D.Add(Vector3D.Multiply(DHparameters[i, 2], frame[i, 2]), Vector3D.Multiply(DHparameters[i, 1], frame[i + 1, 0]));
            }
            //P(i) --> frame positions wrt base frame
            for (int i = 1; i < N + 1; i++)
            {
                frame[i, 3] = frame[i - 1, 3] + Pstar[i - 1];
            }
            // set position of end effector
            Ph = frame[N, 3];

            // compute relative positions
            Pih = new Vector3D[N + 1];
            for (int i = N - 1; i >= 0; i--)
            {
                Pih[i] = Vector3D.Subtract(Ph, frame[i, 3]);
            }
            // set end effector orientation
            Rh[0] = frame[N, 0];
            Rh[1] = frame[N, 1];
            Rh[2] = frame[N, 2];
            // calculate orientation error
            Eo = 0;
            for (int i = 0; i < 3; i++)
            {
                if (Sigma[i])
                {
                    Eo += Math.Pow((Vector3D.DotProduct(Rd[i], Rh[i]) - 1), 2);
                }
            }
            // function to be minimized
            func = Eo + Math.Pow(Vector3D.DotProduct(Vector3D.Subtract(Pd, Ph), Vector3D.Subtract(Pd, Ph)), 2);
            // declare gradient vector elements for each joint
            for (int i = 0; i < N-1; i++)
            {
                Vector3D gradO = new Vector3D();
                for (int j = 0; j < 3; j++ )
                {
                    if (Sigma[j])
                        gradO = Vector3D.Add(gradO, (Vector3D.DotProduct(Rd[j], Rh[j]) - 1) * Vector3D.CrossProduct(Rh[j], Rd[j]));
                }
                grad[i] = Vector3D.DotProduct(Vector3D.Multiply(2, frame[i, 2]), Vector3D.Add((Vector3D.CrossProduct(Vector3D.Subtract(Pd, Ph), Pih[i])), gradO));
            }
        }