public Matrix4_4 T02()
    {
        float[,] m = new float[4, 4] {
            { cos(th1) * cos(th2), -cos(th1) * sin(th2), sin(th1), a2 *cos(th1) },
            { sin(th1) * cos(th2), -sin(th1) * sin(th2), -cos(th1), a2 *sin(th1) },
            { sin(th2), cos(th2), 0, 0 },
            { 0, 0, 0, 1 }
        };
        Matrix4_4 mat = new Matrix4_4();

        mat.setM(m);

        //check

        /*
         * Matrix4_4 rx2 = new Matrix4_4();
         * Matrix4_4 rz2 = new Matrix4_4();
         * rx2.Rx(alp2, a2);
         * rz2.Rz(th2, d2);
         * Matrix4_4 checkM = T01().x(rx2).x(rz2);
         * mat.show("T02: ");
         * checkM.show("T02 check: ");
         */

        return(mat);
    }
 public void set(Matrix4_4 m)
 {
     for (int i = 0; i < 4; i++)
     {
         for (int j = 0; j < 4; j++)
         {
             matrix[i, j] = m.matrix[i, j];
         }
     }
 }
 //改變旋轉矩陣
 public void changeRotateMatrix(Matrix4_4 changeM)
 {
     for (int i = 0; i < 3; i++)
     {
         for (int j = 0; j < 3; j++)
         {
             matrix[i, j] = changeM.matrix[i, j];
         }
     }
 }
    public Matrix4_4 T01()
    {
        Matrix4_4 mat = new Matrix4_4();

        mat.setM(1, 1, cos(th1));
        mat.setM(1, 2, -sin(th1));
        mat.setM(2, 1, sin(th1));
        mat.setM(2, 2, cos(th1));
        return(mat);
    }
    public bool rotateAxis6Z(float[] angle, float rotateAngle)
    {
        setPreT06(angle);
        Matrix4_4 flag;
        Matrix4_4 rz = new Matrix4_4();

        rz.Rz(rotateAngle);
        flag = preM.x(rz);
        preM.changeRotateMatrix(flag);
        return(setUniversalCoordinate());
    }
    public bool rotateUniY(float[] angle, float rotateAngle)
    {
        setPreT06(angle);
        Matrix4_4 flag;
        Matrix4_4 ry = new Matrix4_4();

        ry.Ry(rotateAngle);
        flag = ry.x(preM);
        preM.changeRotateMatrix(flag);

        return(setUniversalCoordinate());
    }
    public Matrix4_4 T06()
    {
        //check
        Matrix4_4 rx6 = new Matrix4_4();
        Matrix4_4 rz6 = new Matrix4_4();

        rx6.Rx(alp6, a6);
        rz6.Rz(th6, d6);
        Matrix4_4 mat = T05().x(rx6).x(rz6);

        return(mat);
    }
    public Matrix4_4 T05()
    {
        //check
        Matrix4_4 rx5 = new Matrix4_4();
        Matrix4_4 rz5 = new Matrix4_4();

        rx5.Rx(alp5, a5);
        rz5.Rz(th5, d5);
        Matrix4_4 mat = T04().x(rx5).x(rz5);

        //mat.show();
        return(mat);
    }
    public Matrix4_4 T36()
    {
        float[,] m = new float[4, 4] {
            { cos(th4) * cos(th5) * cos(th6) - sin(th4) * sin(th6), -cos(th4) * cos(th5) * sin(th6) - sin(th4) * cos(th5), cos(th4) * sin(th5), a4 + d6 * cos(th4) * sin(th5) },
            { sin(th5) * cos(th6), -sin(th5) * sin(th6), -cos(th5), -d4 - d6 * cos(th5) },
            { sin(th4) * cos(th5) * cos(th6) + cos(th4) * sin(th6), -sin(th4) * cos(th5) * sin(th6) + cos(th4) * cos(th6), sin(th4) * sin(th5), d6 *sin(th4) * sin(th5) },
            { 0, 0, 0, 1 }
        };
        Matrix4_4 mat = new Matrix4_4();

        mat.setM(m);

        return(mat);
    }
    //反矩陣
    public Matrix4_4 invert()
    {
        Matrix4_4 output = new Matrix4_4();

        for (int i = 1; i <= 3; i++)
        {
            for (int j = 1; j <= 3; j++)
            {
                output.setM(i, j, matrix[j - 1, i - 1]);
            }
            //output.setM(i, 4, -matrix[i - 1, 3]);
        }
        output.setM(1, 4, -(matrix[0, 0] * matrix[0, 3] + matrix[1, 0] * matrix[1, 3] + matrix[2, 0] * matrix[2, 3]));
        output.setM(2, 4, -(matrix[0, 1] * matrix[0, 3] + matrix[1, 1] * matrix[1, 3] + matrix[2, 1] * matrix[2, 3]));
        output.setM(3, 4, -(matrix[0, 2] * matrix[0, 3] + matrix[1, 2] * matrix[1, 3] + matrix[2, 2] * matrix[2, 3]));
        return(output);
    }
    //得到previous state的T06轉移矩陣
    private void setPreT06(float [] angle)
    {
        th1 = angle[0];
        th2 = angle[1] + 90;
        th3 = angle[2];
        th4 = angle[3];
        th5 = angle[4];
        th6 = angle[5];

        preM = T06();

        for (int i = 0; i < 6; i++)
        {
            preTh[i] = angle[i];
        }
        preTh[1] += 90;
    }
    //相乘
    public Matrix4_4 x(Matrix4_4 matA)
    {
        Matrix4_4 output = new Matrix4_4();

        for (int i = 0; i < 4; i++)
        {
            for (int j = 0; j < 4; j++)
            {
                float sum = 0;
                for (int k = 0; k < 4; k++)
                {
                    sum += matrix[i, k] * matA.matrix[k, j];
                }
                //Debug.Log(sum);
                output.matrix[i, j] = sum;
            }
        }
        return(output);
    }
    public Matrix4_4 T04()
    {
        Matrix4_4 mat = new Matrix4_4();

        mat.setM(1, 1, cos(th1) * cos(th2) * cos(th3) * cos(th4) - cos(th1) * sin(th2) * sin(th3) * cos(th4) + sin(th1) * sin(th4));
        mat.setM(2, 1, sin(th1) * cos(th2) * cos(th3) * cos(th4) - sin(th1) * sin(th2) * sin(th3) * cos(th4) - cos(th1) * sin(th4));
        mat.setM(3, 1, sin(th2) * cos(th3) * cos(th4) + cos(th2) * sin(th3) * cos(th4));

        mat.setM(1, 2, -cos(th1) * cos(th2) * cos(th3) * sin(th4) + cos(th1) * sin(th2) * sin(th3) * sin(th4) + sin(th1) * cos(th4));
        mat.setM(2, 2, -sin(th1) * cos(th2) * cos(th3) * sin(th4) + sin(th1) * sin(th2) * sin(th3) * sin(th4) - cos(th1) * cos(th4));
        mat.setM(3, 2, -sin(th2) * cos(th3) * sin(th4) - cos(th2) * sin(th3) * sin(th4));

        mat.setM(1, 3, cos(th1) * cos(th2) * sin(th3) + cos(th1) * sin(th2) * cos(th3));
        mat.setM(2, 3, sin(th1) * cos(th2) * sin(th3) + sin(th1) * sin(th2) * cos(th3));
        mat.setM(3, 3, sin(th2) * sin(th3) - cos(th2) * cos(th3));

        mat.setM(1, 4, a2 * cos(th1) + a3 * cos(th1) * cos(th2) + a4 * cos(th1) * cos(th2) * cos(th3) - a4 * cos(th1) * sin(th2) * sin(th3) + d4 * cos(th1) * cos(th2) * sin(th3) + d4 * cos(th1) * sin(th2) * cos(th3));
        mat.setM(2, 4, a2 * sin(th1) + a3 * sin(th1) * cos(th2) + a4 * sin(th1) * cos(th2) * cos(th3) - a4 * sin(th1) * sin(th2) * sin(th3) + d4 * sin(th1) * cos(th2) * sin(th3) + d4 * sin(th1) * sin(th2) * cos(th3));
        mat.setM(3, 4, a3 * sin(th2) + a4 * sin(th2) * cos(th3) + a4 * cos(th2) * sin(th3) + d4 * sin(th2) * sin(th3) - d4 * cos(th2) * cos(th3));

        //check

        /*
         * Matrix4_4 rx4 = new Matrix4_4();
         * Matrix4_4 rz4 = new Matrix4_4();
         * rx4.Rx(alp4, a4);
         * rz4.Rz(th4, d4);
         * Matrix4_4 checkM = T03().x(rx4).x(rz4);
         *
         * mat.show("T04 R:");
         * checkM.show("T04 C:");
         * mat.invert().show("invert");
         * mat.invert().x(mat).show("I :");
         */

        return(mat);
    }
    public Matrix4_4 T03()
    {
        float[,] m = new float[4, 4] {
            { cos(th1) * cos(th2) * cos(th3) - cos(th1) * sin(th2) * sin(th3), -cos(th1) * cos(th2) * sin(th3) - cos(th1) * sin(th2) * cos(th3), sin(th1), a2 *cos(th1) + a3 * cos(th1) * cos(th2) },
            { sin(th1) * cos(th2) * cos(th3) - sin(th1) * sin(th2) * sin(th3), -sin(th1) * cos(th2) * sin(th3) - sin(th1) * sin(th2) * cos(th3), -cos(th1), a2 *sin(th1) + a3 * sin(th1) * cos(th2) },
            { sin(th2) * cos(th3) + cos(th2) * sin(th3), -sin(th2) * sin(th3) + cos(th2) * cos(th3), 0, a3 *sin(th2) },
            { 0, 0, 0, 1 }
        };
        Matrix4_4 mat = new Matrix4_4();

        mat.setM(m);

        //check

        /*
         * Matrix4_4 rx3 = new Matrix4_4();
         * Matrix4_4 rz3 = new Matrix4_4();
         * rx3.Rx(alp3, a3);
         * rz3.Rz(th3, d3);
         * Matrix4_4 checkM = T02().x(rx3).x(rz3);
         * mat.show("T03 R:");
         */
        return(mat);
    }
    public bool setUniversalCoordinate()
    {
        Matrix4_4 m = preM;

        realX = m.matrix[0, 3];
        realY = m.matrix[1, 3];
        realZ = m.matrix[2, 3];

        //座標6,z軸向量
        float[] z6 = new float[3] {
            m.matrix[0, 2], m.matrix[1, 2], m.matrix[2, 2]
        };
        //座標4的位置
        float[] coor4 = new float[3] {
            realX - d6 * z6[0], realY - d6 * z6[1], realZ - d6 * z6[2]
        };


        //1軸角度推導
        th1 = (float)Math.Atan2(coor4[1], coor4[0]) * 180 / pi;
        if ((cos(th1) * cos(preTh[0]) + sin(th1) * sin(preTh[0])) > 0)
        {
            newTh[0] = th1;
        }
        else
        {
            th1      = (float)Math.Atan2(-coor4[1], -coor4[0]) * 180 / pi;
            newTh[0] = th1;
        }

        //2、3軸角度推導\
        float c1;

        if ((newTh[0] == 0) || (newTh[0] == 180))
        {
            c1 = coor4[0] / cos(newTh[0]) - a2;
        }
        else
        {
            c1 = coor4[1] / sin(newTh[0]) - a2;
        }

        float l23 = (float)Math.Sqrt(c1 * c1 + coor4[2] * coor4[2]);
        float r4  = (float)Math.Sqrt(a4 * a4 + d4 * d4);

        //檢查是否有解
        float cosThPi2 = (l23 * l23 + a3 * a3 - r4 * r4) / (2 * a3 * l23);

        if ((cosThPi2 > 1) || (cosThPi2 < -1))
        {
            return(false);
        }

        float gapR4 = (float)Math.Atan2(a4, d4);
        //th2 th3 可能的角度
        float theta21 = ((float)Math.Acos(cosThPi2) + (float)Math.Atan2(coor4[2], c1)) * 180 / pi;
        float theta22 = (-(float)Math.Acos(cosThPi2) + (float)Math.Atan2(coor4[2], c1)) * 180 / pi;
        float phi31   = (float)Math.Atan2((coor4[2] - a3 * sin(180 - theta21)) / r4, (-c1 - a3 * cos(180 - theta21)) / r4);
        float phi32   = (float)Math.Atan2((coor4[2] - a3 * sin(180 - theta22)) / r4, (-c1 - a3 * cos(180 - theta22)) / r4);
        float theta31 = 270 - (phi31 + gapR4) * 180 / pi - theta21;
        float theta32 = 270 - (phi32 + gapR4) * 180 / pi - theta22;

        //選擇角度
        if ((cos(theta21) * cos(preTh[1]) + sin(theta21) * sin(preTh[1])) > (cos(theta22) * cos(preTh[1]) + sin(theta22) * sin(preTh[1])))
        {
            //Debug.Log(theta32);
            newTh[1] = theta21;
            th2      = theta21;
            newTh[2] = theta31;
            th3      = theta31;
        }
        else
        {
            newTh[1] = theta22;
            th2      = theta22;
            newTh[2] = theta32;
            th3      = theta32;
        }


        //th2 th3 角度分類
        float th23case1 = a3 + a4 * cos(theta31) + d4 * sin(theta31) - c1 * cos(theta21) - coor4[2] * sin(theta21);
        float th23case2 = a3 + a4 * cos(theta32) + d4 * sin(theta32) - c1 * cos(theta22) - coor4[2] * sin(theta22);

        //4、5、6軸
        Matrix4_4 t03  = T03();
        Matrix4_4 t36  = t03.invert().x(m);
        Matrix4_4 t36c = T36();

        if (t36.matrix[1, 2] == -1)
        {
            float checkValue = t36.matrix[0, 0] - t36.matrix[2, 1];
            if (!((checkValue < 0.0001) && (checkValue > -0.0001)))
            {
                Debug.Log("break");
                return(false);
            }
            //t36.show("t03: ");
            newTh[4] = 0;
            newTh[3] = 0;
            newTh[5] = (float)Math.Atan2(t36.matrix[2, 0], t36.matrix[0, 0]) * 180 / pi;
        }
        else if (t36.matrix[1, 2] == 1)
        {
            float checkValue = t36.matrix[0, 0] + t36.matrix[2, 1];
            if (!((checkValue < 0.0001) && (checkValue > -0.0001)))
            {
                Debug.Log("break");
                return(false);
            }
            //t36.show("t03: ");
            newTh[4] = 180;
            newTh[3] = 0;
            newTh[5] = (float)Math.Atan2(t36.matrix[2, 0], -t36.matrix[0, 0]) * 180 / pi;
        }
        else
        {
            //t36.show("fake: ");

            newTh[5] = (float)Math.Atan2(-t36.matrix[1, 1], t36.matrix[1, 0]) * 180 / pi;
            newTh[3] = (float)Math.Atan2(t36.matrix[2, 2], t36.matrix[0, 2]) * 180 / pi;
            if ((newTh[3] == 0) || (newTh[3] == 180))
            {
                newTh[4] = (float)Math.Atan2(t36.matrix[0, 2] / cos(newTh[3]), -t36.matrix[1, 2]) * 180 / pi;
            }
            else
            {
                newTh[4] = (float)Math.Atan2(t36.matrix[2, 2] / sin(newTh[3]), -t36.matrix[1, 2]) * 180 / pi;
            }
        }

        uniX = realX;
        uniY = realZ;
        uniZ = realY;

        th4 = newTh[3];
        th5 = newTh[4];
        th6 = newTh[5];
        //preM.show("preState");
        //T06().show("nowState");
        return(true);
    }