context: using System;
  
  namespace Tilar.Framework.Math
  {
      public class Matrix4d
      {
  
          private const long serialVersionUID = 1L;
          public const int PLANE_NX = 0;
          public const int PLANE_PX = 1;
          public const int PLANE_NY = 2;
          public const int PLANE_PY = 3;
          public const int PLANE_NZ = 4;
          public const int PLANE_PZ = 5;
          public const int CORNER_NXNYNZ = 0;
          public const int CORNER_PXNYNZ = 1;
          public const int CORNER_PXPYNZ = 2;
          public const int CORNER_NXPYNZ = 3;
          public const int CORNER_PXNYPZ = 4;
          public const int CORNER_NXNYPZ = 5;
          public const int CORNER_NXPYPZ = 6;
          public const int CORNER_PXPYPZ = 7;
  
          public double m00, m10, m20, m30;
          public double m01, m11, m21, m31;
          public double m02, m12, m22, m32;
          public double m03, m13, m23, m33;
  
          public Matrix4d()
          {
              m00 = 1.0;
              m01 = 0.0;
              m02 = 0.0;
              m03 = 0.0;
              m10 = 0.0;
              m11 = 1.0;
              m12 = 0.0;
              m13 = 0.0;
              m20 = 0.0;
              m21 = 0.0;
              m22 = 1.0;
              m23 = 0.0;
              m30 = 0.0;
              m31 = 0.0;
              m32 = 0.0;
              m33 = 1.0;
          }
          public Matrix4d(Matrix4d mat)
          {
              m00 = mat.m00;
              m01 = mat.m01;
              m02 = mat.m02;
              m03 = mat.m03;
              m10 = mat.m10;
              m11 = mat.m11;
              m12 = mat.m12;
              m13 = mat.m13;
              m20 = mat.m20;
              m21 = mat.m21;
              m22 = mat.m22;
              m23 = mat.m23;
              m30 = mat.m30;
              m31 = mat.m31;
              m32 = mat.m32;
              m33 = mat.m33;
          }
          public Matrix4d(Matrix4f mat)
          {
              m00 = mat.m00;
              m01 = mat.m01;
              m02 = mat.m02;
              m03 = mat.m03;
              m10 = mat.m10;
              m11 = mat.m11;
              m12 = mat.m12;
              m13 = mat.m13;
              m20 = mat.m20;
              m21 = mat.m21;
              m22 = mat.m22;
              m23 = mat.m23;
              m30 = mat.m30;
              m31 = mat.m31;
              m32 = mat.m32;
              m33 = mat.m33;
          }
          public Matrix4d(Matrix3d mat)
          {
              m00 = mat.m00;
              m01 = mat.m01;
              m02 = mat.m02;
              m10 = mat.m10;
              m11 = mat.m11;
              m12 = mat.m12;
              m20 = mat.m20;
              m21 = mat.m21;
              m22 = mat.m22;
              m33 = 1.0;
          }
          public Matrix4d(double m00, double m01, double m02, double m03,
                          double m10, double m11, double m12, double m13,
                          double m20, double m21, double m22, double m23,
                          double m30, double m31, double m32, double m33)
          {
              this.m00 = m00;
              this.m01 = m01;
              this.m02 = m02;
              this.m03 = m03;
              this.m10 = m10;
              this.m11 = m11;
              this.m12 = m12;
              this.m13 = m13;
              this.m20 = m20;
              this.m21 = m21;
              this.m22 = m22;
              this.m23 = m23;
              this.m30 = m30;
              this.m31 = m31;
              this.m32 = m32;
              this.m33 = m33;
          }
          public Matrix4d identity()
          {
              m00 = 1.0;
              m01 = 0.0;
              m02 = 0.0;
              m03 = 0.0;
              m10 = 0.0;
              m11 = 1.0;
              m12 = 0.0;
              m13 = 0.0;
              m20 = 0.0;
              m21 = 0.0;
              m22 = 1.0;
              m23 = 0.0;
              m30 = 0.0;
              m31 = 0.0;
              m32 = 0.0;
              m33 = 1.0;
              return this;
          }
          public Matrix4d set(Matrix4d m)
          {
              m00 = m.m00;
              m01 = m.m01;
              m02 = m.m02;
              m03 = m.m03;
              m10 = m.m10;
              m11 = m.m11;
              m12 = m.m12;
              m13 = m.m13;
              m20 = m.m20;
              m21 = m.m21;
              m22 = m.m22;
              m23 = m.m23;
              m30 = m.m30;
              m31 = m.m31;
              m32 = m.m32;
              m33 = m.m33;
              return this;
          }
          public Matrix4d set(Matrix4f m)
          {
              m00 = m.m00;
              m01 = m.m01;
              m02 = m.m02;
              m03 = m.m03;
              m10 = m.m10;
              m11 = m.m11;
              m12 = m.m12;
              m13 = m.m13;
              m20 = m.m20;
              m21 = m.m21;
              m22 = m.m22;
              m23 = m.m23;
              m30 = m.m30;
              m31 = m.m31;
              m32 = m.m32;
              m33 = m.m33;
              return this;
          }
          public Matrix4d set(Matrix3d mat)
          {
              m00 = mat.m00;
              m01 = mat.m01;
              m02 = mat.m02;
              m03 = 0.0;
              m10 = mat.m10;
              m11 = mat.m11;
              m12 = mat.m12;
              m13 = 0.0;
              m20 = mat.m20;
              m21 = mat.m21;
              m22 = mat.m22;
              m23 = 0.0;
              m30 = 0.0;
              m31 = 0.0;
              m32 = 0.0;
              m33 = 1.0;
              return this;
          }
          public Matrix4d set3x3(Matrix4d mat)
          {
              m00 = mat.m00;
              m01 = mat.m01;
              m02 = mat.m02;
              m03 = 0.0;
              m10 = mat.m10;
              m11 = mat.m11;
              m12 = mat.m12;
              m13 = 0.0;
              m20 = mat.m20;
              m21 = mat.m21;
              m22 = mat.m22;
              m23 = 0.0;
              m30 = 0.0;
              m31 = 0.0;
              m32 = 0.0;
              m33 = 1.0;
              return this;
          }
          public Matrix4d set(AxisAngle4f axisAngle)
          {
              double x = axisAngle.x;
              double y = axisAngle.y;
              double z = axisAngle.z;
              double angle = axisAngle.angle;
              double invLength = 1.0 / System.Math.Sqrt(x * x + y * y + z * z);
              x *= invLength;
              y *= invLength;
              z *= invLength;
              double c = System.Math.Cos(angle);
              double s = System.Math.Sin(angle);
              double omc = 1.0 - c;
              m00 = c + x * x * omc;
              m11 = c + y * y * omc;
              m22 = c + z * z * omc;
              double tmp1 = x * y * omc;
              double tmp2 = z * s;
              m10 = tmp1 - tmp2;
              m01 = tmp1 + tmp2;
              tmp1 = x * z * omc;
              tmp2 = y * s;
              m20 = tmp1 + tmp2;
              m02 = tmp1 - tmp2;
              tmp1 = y * z * omc;
              tmp2 = x * s;
              m21 = tmp1 - tmp2;
              m12 = tmp1 + tmp2;
              m30 = 0.0;
              m31 = 0.0;
              m32 = 0.0;
              m33 = 1.0;
              return this;
          }
          public Matrix4d set(AxisAngle4d axisAngle)
          {
              double x = axisAngle.x;
              double y = axisAngle.y;
              double z = axisAngle.z;
              double angle = axisAngle.angle;
              double invLength = 1.0 / System.Math.Sqrt(x * x + y * y + z * z);
              x *= invLength;
              y *= invLength;
              z *= invLength;
              double c = System.Math.Cos(angle);
              double s = System.Math.Sin(angle);
              double omc = 1.0 - c;
              m00 = c + x * x * omc;
              m11 = c + y * y * omc;
              m22 = c + z * z * omc;
              double tmp1 = x * y * omc;
              double tmp2 = z * s;
              m10 = tmp1 - tmp2;
              m01 = tmp1 + tmp2;
              tmp1 = x * z * omc;
              tmp2 = y * s;
              m20 = tmp1 + tmp2;
              m02 = tmp1 - tmp2;
              tmp1 = y * z * omc;
              tmp2 = x * s;
              m21 = tmp1 - tmp2;
              m12 = tmp1 + tmp2;
              m30 = 0.0;
              m31 = 0.0;
              m32 = 0.0;
              m33 = 1.0;
              return this;
          }
          public Matrix4d set(Quaternionf q)
          {
              return q.get(this);
          }
          public Matrix4d set(Quaterniond q)
          {
              return q.get(this);
          }
  
  
          public Matrix4d mul(Matrix4d right)
          {
              return mul(right, this);
          }
          public Matrix4d mul(Matrix4d right, Matrix4d dest)
          {
              dest.set(m00 * right.m00 + m10 * right.m01 + m20 * right.m02 + m30 * right.m03,
                       m01 * right.m00 + m11 * right.m01 + m21 * right.m02 + m31 * right.m03,
                       m02 * right.m00 + m12 * right.m01 + m22 * right.m02 + m32 * right.m03,
                       m03 * right.m00 + m13 * right.m01 + m23 * right.m02 + m33 * right.m03,
                       m00 * right.m10 + m10 * right.m11 + m20 * right.m12 + m30 * right.m13,
                       m01 * right.m10 + m11 * right.m11 + m21 * right.m12 + m31 * right.m13,
                       m02 * right.m10 + m12 * right.m11 + m22 * right.m12 + m32 * right.m13,
                       m03 * right.m10 + m13 * right.m11 + m23 * right.m12 + m33 * right.m13,
                       m00 * right.m20 + m10 * right.m21 + m20 * right.m22 + m30 * right.m23,
                       m01 * right.m20 + m11 * right.m21 + m21 * right.m22 + m31 * right.m23,
                       m02 * right.m20 + m12 * right.m21 + m22 * right.m22 + m32 * right.m23,
                       m03 * right.m20 + m13 * right.m21 + m23 * right.m22 + m33 * right.m23,
                       m00 * right.m30 + m10 * right.m31 + m20 * right.m32 + m30 * right.m33,
                       m01 * right.m30 + m11 * right.m31 + m21 * right.m32 + m31 * right.m33,
                       m02 * right.m30 + m12 * right.m31 + m22 * right.m32 + m32 * right.m33,
                       m03 * right.m30 + m13 * right.m31 + m23 * right.m32 + m33 * right.m33);
              return dest;
          }
          public Matrix4d mul(Matrix4f right)
          {
              return mul(right, this);
          }
          public Matrix4d mul(Matrix4f right, Matrix4d dest)
          {
              dest.set(m00 * right.m00 + m10 * right.m01 + m20 * right.m02 + m30 * right.m03,
                       m01 * right.m00 + m11 * right.m01 + m21 * right.m02 + m31 * right.m03,
                       m02 * right.m00 + m12 * right.m01 + m22 * right.m02 + m32 * right.m03,
                       m03 * right.m00 + m13 * right.m01 + m23 * right.m02 + m33 * right.m03,
                       m00 * right.m10 + m10 * right.m11 + m20 * right.m12 + m30 * right.m13,
                       m01 * right.m10 + m11 * right.m11 + m21 * right.m12 + m31 * right.m13,
                       m02 * right.m10 + m12 * right.m11 + m22 * right.m12 + m32 * right.m13,
                       m03 * right.m10 + m13 * right.m11 + m23 * right.m12 + m33 * right.m13,
                       m00 * right.m20 + m10 * right.m21 + m20 * right.m22 + m30 * right.m23,
                       m01 * right.m20 + m11 * right.m21 + m21 * right.m22 + m31 * right.m23,
                       m02 * right.m20 + m12 * right.m21 + m22 * right.m22 + m32 * right.m23,
                       m03 * right.m20 + m13 * right.m21 + m23 * right.m22 + m33 * right.m23,
                       m00 * right.m30 + m10 * right.m31 + m20 * right.m32 + m30 * right.m33,
                       m01 * right.m30 + m11 * right.m31 + m21 * right.m32 + m31 * right.m33,
                       m02 * right.m30 + m12 * right.m31 + m22 * right.m32 + m32 * right.m33,
                       m03 * right.m30 + m13 * right.m31 + m23 * right.m32 + m33 * right.m33);
              return dest;
          }
          public static void mul(Matrix4f left, Matrix4d right, Matrix4d dest)
          {
              dest.set(left.m00 * right.m00 + left.m10 * right.m01 + left.m20 * right.m02 + left.m30 * right.m03,
                       left.m01 * right.m00 + left.m11 * right.m01 + left.m21 * right.m02 + left.m31 * right.m03,
                       left.m02 * right.m00 + left.m12 * right.m01 + left.m22 * right.m02 + left.m32 * right.m03,
                       left.m03 * right.m00 + left.m13 * right.m01 + left.m23 * right.m02 + left.m33 * right.m03,
                       left.m00 * right.m10 + left.m10 * right.m11 + left.m20 * right.m12 + left.m30 * right.m13,
                       left.m01 * right.m10 + left.m11 * right.m11 + left.m21 * right.m12 + left.m31 * right.m13,
                       left.m02 * right.m10 + left.m12 * right.m11 + left.m22 * right.m12 + left.m32 * right.m13,
                       left.m03 * right.m10 + left.m13 * right.m11 + left.m23 * right.m12 + left.m33 * right.m13,
                       left.m00 * right.m20 + left.m10 * right.m21 + left.m20 * right.m22 + left.m30 * right.m23,
                       left.m01 * right.m20 + left.m11 * right.m21 + left.m21 * right.m22 + left.m31 * right.m23,
                       left.m02 * right.m20 + left.m12 * right.m21 + left.m22 * right.m22 + left.m32 * right.m23,
                       left.m03 * right.m20 + left.m13 * right.m21 + left.m23 * right.m22 + left.m33 * right.m23,
                       left.m00 * right.m30 + left.m10 * right.m31 + left.m20 * right.m32 + left.m30 * right.m33,
                       left.m01 * right.m30 + left.m11 * right.m31 + left.m21 * right.m32 + left.m31 * right.m33,
                       left.m02 * right.m30 + left.m12 * right.m31 + left.m22 * right.m32 + left.m32 * right.m33,
                       left.m03 * right.m30 + left.m13 * right.m31 + left.m23 * right.m32 + left.m33 * right.m33);
          }
          public Matrix4d mul4x3r(Matrix4d right)
          {
              return mul4x3r(right, this);
          }
          public Matrix4d mul4x3r(Matrix4d right, Matrix4d dest)
          {
              dest.set(m00 * right.m00 + m10 * right.m01 + m20 * right.m02,
                       m01 * right.m00 + m11 * right.m01 + m21 * right.m02,
                       m02 * right.m00 + m12 * right.m01 + m22 * right.m02,
                       m03 * right.m00 + m13 * right.m01 + m23 * right.m02,
                       m00 * right.m10 + m10 * right.m11 + m20 * right.m12,
                       m01 * right.m10 + m11 * right.m11 + m21 * right.m12,
                       m02 * right.m10 + m12 * right.m11 + m22 * right.m12,
                       m03 * right.m10 + m13 * right.m11 + m23 * right.m12,
                       m00 * right.m20 + m10 * right.m21 + m20 * right.m22,
                       m01 * right.m20 + m11 * right.m21 + m21 * right.m22,
                       m02 * right.m20 + m12 * right.m21 + m22 * right.m22,
                       m03 * right.m20 + m13 * right.m21 + m23 * right.m22,
                       m00 * right.m30 + m10 * right.m31 + m20 * right.m32 + m30,
                       m01 * right.m30 + m11 * right.m31 + m21 * right.m32 + m31,
                       m02 * right.m30 + m12 * right.m31 + m22 * right.m32 + m32,
                       m03 * right.m30 + m13 * right.m31 + m23 * right.m32 + m33);
              return dest;
          }
          public Matrix4d mul4x3(Matrix4d right)
          {
              return mul4x3(right, this);
          }
          public Matrix4d mul4x3(Matrix4d right, Matrix4d dest)
          {
              dest.set(m00 * right.m00 + m10 * right.m01 + m20 * right.m02,
                       m01 * right.m00 + m11 * right.m01 + m21 * right.m02,
                       m02 * right.m00 + m12 * right.m01 + m22 * right.m02,
                       m03,
                       m00 * right.m10 + m10 * right.m11 + m20 * right.m12,
                       m01 * right.m10 + m11 * right.m11 + m21 * right.m12,
                       m02 * right.m10 + m12 * right.m11 + m22 * right.m12,
                       m13,
                       m00 * right.m20 + m10 * right.m21 + m20 * right.m22,
                       m01 * right.m20 + m11 * right.m21 + m21 * right.m22,
                       m02 * right.m20 + m12 * right.m21 + m22 * right.m22,
                       m23,
                       m00 * right.m30 + m10 * right.m31 + m20 * right.m32 + m30,
                       m01 * right.m30 + m11 * right.m31 + m21 * right.m32 + m31,
                       m02 * right.m30 + m12 * right.m31 + m22 * right.m32 + m32,
                       m33);
              return dest;
          }
          public Matrix4d fma4x3(Matrix4d other, double otherFactor)
          {
              return fma4x3(other, otherFactor, this);
          }
          public Matrix4d fma4x3(Matrix4d other, double otherFactor, Matrix4d dest)
          {
              dest.m00 = m00 + other.m00 * otherFactor;
              dest.m01 = m01 + other.m01 * otherFactor;
              dest.m02 = m02 + other.m02 * otherFactor;
              dest.m03 = m03;
              dest.m10 = m10 + other.m10 * otherFactor;
              dest.m11 = m11 + other.m11 * otherFactor;
              dest.m12 = m12 + other.m12 * otherFactor;
              dest.m13 = m13;
              dest.m20 = m20 + other.m20 * otherFactor;
              dest.m21 = m21 + other.m21 * otherFactor;
              dest.m22 = m22 + other.m22 * otherFactor;
              dest.m23 = m23;
              dest.m30 = m30 + other.m30 * otherFactor;
              dest.m31 = m31 + other.m31 * otherFactor;
              dest.m32 = m32 + other.m32 * otherFactor;
              dest.m33 = m33;
              return dest;
          }
          public Matrix4d add(Matrix4d other)
          {
              return add(other, this);
          }
          public Matrix4d add(Matrix4d other, Matrix4d dest)
          {
              dest.m00 = m00 + other.m00;
              dest.m01 = m01 + other.m01;
              dest.m02 = m02 + other.m02;
              dest.m03 = m03 + other.m03;
              dest.m10 = m10 + other.m10;
              dest.m11 = m11 + other.m11;
              dest.m12 = m12 + other.m12;
              dest.m13 = m13 + other.m13;
              dest.m20 = m20 + other.m20;
              dest.m21 = m21 + other.m21;
              dest.m22 = m22 + other.m22;
              dest.m23 = m23 + other.m23;
              dest.m30 = m30 + other.m30;
              dest.m31 = m31 + other.m31;
              dest.m32 = m32 + other.m32;
              dest.m33 = m33 + other.m33;
              return dest;
          }
          public Matrix4d sub(Matrix4d subtrahend)
          {
              return sub(subtrahend, this);
          }
          public Matrix4d sub(Matrix4d subtrahend, Matrix4d dest)
          {
              dest.m00 = m00 - subtrahend.m00;
              dest.m01 = m01 - subtrahend.m01;
              dest.m02 = m02 - subtrahend.m02;
              dest.m03 = m03 - subtrahend.m03;
              dest.m10 = m10 - subtrahend.m10;
              dest.m11 = m11 - subtrahend.m11;
              dest.m12 = m12 - subtrahend.m12;
              dest.m13 = m13 - subtrahend.m13;
              dest.m20 = m20 - subtrahend.m20;
              dest.m21 = m21 - subtrahend.m21;
              dest.m22 = m22 - subtrahend.m22;
              dest.m23 = m23 - subtrahend.m23;
              dest.m30 = m30 - subtrahend.m30;
              dest.m31 = m31 - subtrahend.m31;
              dest.m32 = m32 - subtrahend.m32;
              dest.m33 = m33 - subtrahend.m33;
              return dest;
          }
          public Matrix4d mulComponentWise(Matrix4d other)
          {
              return mulComponentWise(other, this);
          }
          public Matrix4d mulComponentWise(Matrix4d other, Matrix4d dest)
          {
              dest.m00 = m00 * other.m00;
              dest.m01 = m01 * other.m01;
              dest.m02 = m02 * other.m02;
              dest.m03 = m03 * other.m03;
              dest.m10 = m10 * other.m10;
              dest.m11 = m11 * other.m11;
              dest.m12 = m12 * other.m12;
              dest.m13 = m13 * other.m13;
              dest.m20 = m20 * other.m20;
              dest.m21 = m21 * other.m21;
              dest.m22 = m22 * other.m22;
              dest.m23 = m23 * other.m23;
              dest.m30 = m30 * other.m30;
              dest.m31 = m31 * other.m31;
              dest.m32 = m32 * other.m32;
              dest.m33 = m33 * other.m33;
              return dest;
          }
          public Matrix4d add4x3(Matrix4d other)
          {
              return add4x3(other, this);
          }
          public Matrix4d add4x3(Matrix4d other, Matrix4d dest)
          {
              dest.m00 = m00 + other.m00;
              dest.m01 = m01 + other.m01;
              dest.m02 = m02 + other.m02;
              dest.m03 = m03;
              dest.m10 = m10 + other.m10;
              dest.m11 = m11 + other.m11;
              dest.m12 = m12 + other.m12;
              dest.m13 = m13;
              dest.m20 = m20 + other.m20;
              dest.m21 = m21 + other.m21;
              dest.m22 = m22 + other.m22;
              dest.m23 = m23;
              dest.m30 = m30 + other.m30;
              dest.m31 = m31 + other.m31;
              dest.m32 = m32 + other.m32;
              dest.m33 = m33;
              return dest;
          }
          public Matrix4d sub4x3(Matrix4d subtrahend)
          {
              return sub4x3(subtrahend, this);
          }
          public Matrix4d sub4x3(Matrix4d subtrahend, Matrix4d dest)
          {
              dest.m00 = m00 - subtrahend.m00;
              dest.m01 = m01 - subtrahend.m01;
              dest.m02 = m02 - subtrahend.m02;
              dest.m03 = m03;
              dest.m10 = m10 - subtrahend.m10;
              dest.m11 = m11 - subtrahend.m11;
              dest.m12 = m12 - subtrahend.m12;
              dest.m13 = m13;
              dest.m20 = m20 - subtrahend.m20;
              dest.m21 = m21 - subtrahend.m21;
              dest.m22 = m22 - subtrahend.m22;
              dest.m23 = m23;
              dest.m30 = m30 - subtrahend.m30;
              dest.m31 = m31 - subtrahend.m31;
              dest.m32 = m32 - subtrahend.m32;
              dest.m33 = m33;
              return dest;
          }
          public Matrix4d mul4x3ComponentWise(Matrix4d other)
          {
              return mul4x3ComponentWise(other, this);
          }
          public Matrix4d mul4x3ComponentWise(Matrix4d other, Matrix4d dest)
          {
              dest.m00 = m00 * other.m00;
              dest.m01 = m01 * other.m01;
              dest.m02 = m02 * other.m02;
              dest.m03 = m03;
              dest.m10 = m10 * other.m10;
              dest.m11 = m11 * other.m11;
              dest.m12 = m12 * other.m12;
              dest.m13 = m13;
              dest.m20 = m20 * other.m20;
              dest.m21 = m21 * other.m21;
              dest.m22 = m22 * other.m22;
              dest.m23 = m23;
              dest.m30 = m30 * other.m30;
              dest.m31 = m31 * other.m31;
              dest.m32 = m32 * other.m32;
              dest.m33 = m33;
              return dest;
          }
          public Matrix4d set(double m00, double m01, double m02, double m03,
                              double m10, double m11, double m12, double m13,
                              double m20, double m21, double m22, double m23,
                              double m30, double m31, double m32, double m33)
          {
              this.m00 = m00;
              this.m01 = m01;
              this.m02 = m02;
              this.m03 = m03;
              this.m10 = m10;
              this.m11 = m11;
              this.m12 = m12;
              this.m13 = m13;
              this.m20 = m20;
              this.m21 = m21;
              this.m22 = m22;
              this.m23 = m23;
              this.m30 = m30;
              this.m31 = m31;
              this.m32 = m32;
              this.m33 = m33;
              return this;
          }
          public Matrix4d set(double[] m)
          {
              m00 = m[0];
              m01 = m[1];
              m02 = m[2];
              m03 = m[3];
              m10 = m[4];
              m11 = m[5];
              m12 = m[6];
              m13 = m[7];
              m20 = m[8];
              m21 = m[9];
              m22 = m[10];
              m23 = m[11];
              m30 = m[12];
              m31 = m[13];
              m32 = m[14];
              m33 = m[15];
              return this;
          }
          public Matrix4d set(float[] m)
          {
              m00 = m[0];
              m01 = m[1];
              m02 = m[2];
              m03 = m[3];
              m10 = m[4];
              m11 = m[5];
              m12 = m[6];
              m13 = m[7];
              m20 = m[8];
              m21 = m[9];
              m22 = m[10];
              m23 = m[11];
              m30 = m[12];
              m31 = m[13];
              m32 = m[14];
              m33 = m[15];
              return this;
          }
          public double determinant()
          {
              return (m00 * m11 - m01 * m10) * (m22 * m33 - m23 * m32)
                   + (m02 * m10 - m00 * m12) * (m21 * m33 - m23 * m31)
                   + (m00 * m13 - m03 * m10) * (m21 * m32 - m22 * m31)
                   + (m01 * m12 - m02 * m11) * (m20 * m33 - m23 * m30)
                   + (m03 * m11 - m01 * m13) * (m20 * m32 - m22 * m30)
                   + (m02 * m13 - m03 * m12) * (m20 * m31 - m21 * m30);
          }
          public double determinant3x3()
          {
              return m00 * (m11 * m22 - m12 * m21)
                   + m01 * (m12 * m20 - m10 * m22)
                   + m02 * (m01 * m21 - m11 * m20);
          }
          public double determinant4x3()
          {
              return (m00 * m11 - m01 * m10) * m22
                   + (m02 * m10 - m00 * m12) * m21
                   + (m01 * m12 - m02 * m11) * m20;
          }
          public Matrix4d invert()
          {
              return invert(this);
          }
          public Matrix4d invert(Matrix4d dest)
          {
              double a = m00 * m11 - m01 * m10;
              double b = m00 * m12 - m02 * m10;
              double c = m00 * m13 - m03 * m10;
              double d = m01 * m12 - m02 * m11;
              double e = m01 * m13 - m03 * m11;
              double f = m02 * m13 - m03 * m12;
              double g = m20 * m31 - m21 * m30;
              double h = m20 * m32 - m22 * m30;
              double i = m20 * m33 - m23 * m30;
              double j = m21 * m32 - m22 * m31;
              double k = m21 * m33 - m23 * m31;
              double l = m22 * m33 - m23 * m32;
              double det = a * l - b * k + c * j + d * i - e * h + f * g;
              det = 1.0 / det;
              dest.set((m11 * l - m12 * k + m13 * j) * det,
                       (-m01 * l + m02 * k - m03 * j) * det,
                       (m31 * f - m32 * e + m33 * d) * det,
                       (-m21 * f + m22 * e - m23 * d) * det,
                       (-m10 * l + m12 * i - m13 * h) * det,
                       (m00 * l - m02 * i + m03 * h) * det,
                       (-m30 * f + m32 * c - m33 * b) * det,
                       (m20 * f - m22 * c + m23 * b) * det,
                       (m10 * k - m11 * i + m13 * g) * det,
                       (-m00 * k + m01 * i - m03 * g) * det,
                       (m30 * e - m31 * c + m33 * a) * det,
                       (-m20 * e + m21 * c - m23 * a) * det,
                       (-m10 * j + m11 * h - m12 * g) * det,
                       (m00 * j - m01 * h + m02 * g) * det,
                       (-m30 * d + m31 * b - m32 * a) * det,
                       (m20 * d - m21 * b + m22 * a) * det);
              return dest;
          }
          public Matrix4d invert4x3(Matrix4d dest)
          {
              double s = determinant4x3();
              s = 1.0 / s;
              double m10m22 = m10 * m22;
              double m10m21 = m10 * m21;
              double m10m02 = m10 * m02;
              double m10m01 = m10 * m01;
              double m11m22 = m11 * m22;
              double m11m20 = m11 * m20;
              double m11m02 = m11 * m02;
              double m11m00 = m11 * m00;
              double m12m21 = m12 * m21;
              double m12m20 = m12 * m20;
              double m12m01 = m12 * m01;
              double m12m00 = m12 * m00;
              double m20m02 = m20 * m02;
              double m20m01 = m20 * m01;
              double m21m02 = m21 * m02;
              double m21m00 = m21 * m00;
              double m22m01 = m22 * m01;
              double m22m00 = m22 * m00;
              dest.set((m11m22 - m12m21) * s,
                       (m21m02 - m22m01) * s,
                       (m12m01 - m11m02) * s,
                       0.0,
                       (m12m20 - m10m22) * s,
                       (m22m00 - m20m02) * s,
                       (m10m02 - m12m00) * s,
                       0.0,
                       (m10m21 - m11m20) * s,
                       (m20m01 - m21m00) * s,
                       (m11m00 - m10m01) * s,
                       0.0,
                       (m10m22 * m31 - m10m21 * m32 + m11m20 * m32 - m11m22 * m30 + m12m21 * m30 - m12m20 * m31) * s,
                       (m20m02 * m31 - m20m01 * m32 + m21m00 * m32 - m21m02 * m30 + m22m01 * m30 - m22m00 * m31) * s,
                       (m11m02 * m30 - m12m01 * m30 + m12m00 * m31 - m10m02 * m31 + m10m01 * m32 - m11m00 * m32) * s,
                       1.0);
              return dest;
          }
          public Matrix4d invert4x3()
          {
              return invert4x3(this);
          }
          public Matrix4d transpose()
          {
              return transpose(this);
          }
          public Matrix4d transpose(Matrix4d dest)
          {
              dest.set(m00, m10, m20, m30,
                       m01, m11, m21, m31,
                       m02, m12, m22, m32,
                       m03, m13, m23, m33);
              return dest;
          }
          public Matrix4d transpose3x3()
          {
              return transpose3x3(this);
          }
          public Matrix4d transpose3x3(Matrix4d dest)
          {
              dest.set(m00, m10, m20, 0.0,
                       m01, m11, m21, 0.0,
                       m02, m12, m22, 0.0,
                       0.0, 0.0, 0.0, 1.0);
              return dest;
          }
          public Matrix3d transpose3x3(Matrix3d dest)
          {
              dest.m00 = m00;
              dest.m01 = m10;
              dest.m02 = m20;
              dest.m10 = m01;
              dest.m11 = m11;
              dest.m12 = m21;
              dest.m20 = m02;
              dest.m21 = m12;
              dest.m22 = m22;
              return dest;
          }
          public Matrix4d translation(double x, double y, double z)
          {
              m00 = 1.0;
              m01 = 0.0;
              m02 = 0.0;
              m03 = 0.0;
              m10 = 0.0;
              m11 = 1.0;
              m12 = 0.0;
              m13 = 0.0;
              m20 = 0.0;
              m21 = 0.0;
              m22 = 1.0;
              m23 = 0.0;
              m30 = x;
              m31 = y;
              m32 = z;
              m33 = 1.0;
              return this;
          }
          public Matrix4d translation(Vector3f offset)
          {
              return translation(offset.x, offset.y, offset.z);
          }
          public Matrix4d translation(Vector3d offset)
          {
              return translation(offset.x, offset.y, offset.z);
          }
          public Matrix4d setTranslation(double x, double y, double z)
          {
              m30 = x;
              m31 = y;
              m32 = z;
              return this;
          }
          public Matrix4d setTranslation(Vector3d xyz)
          {
              m30 = xyz.x;
              m31 = xyz.y;
              m32 = xyz.z;
              return this;
          }
  
          public Vector3d getTranslation(Vector3d dest)
          {
              dest.x = m30;
              dest.y = m31;
              dest.z = m32;
              return dest;
          }
          public Vector3d getScale(Vector3d dest)
          {
              dest.x = System.Math.Sqrt(m00 * m00 + m01 * m01 + m02 * m02);
              dest.y = System.Math.Sqrt(m10 * m10 + m11 * m11 + m12 * m12);
              dest.z = System.Math.Sqrt(m20 * m20 + m21 * m21 + m22 * m22);
              return dest;
          }
          public Matrix4d get(Matrix4d dest)
          {
              return dest.set(this);
          }
          public Quaternionf getUnnormalizedRotation(Quaternionf dest)
          {
              return dest.setFromUnnormalized(this);
          }
          public Quaternionf getNormalizedRotation(Quaternionf dest)
          {
              return dest.setFromNormalized(this);
          }
          public Quaterniond getUnnormalizedRotation(Quaterniond dest)
          {
              return dest.setFromUnnormalized(this);
          }
          public Quaterniond getNormalizedRotation(Quaterniond dest)
          {
              return dest.setFromNormalized(this);
          }
          public double[] get(double[] arr, int offset)
          {
              arr[offset + 0] = m00;
              arr[offset + 1] = m01;
              arr[offset + 2] = m02;
              arr[offset + 3] = m03;
              arr[offset + 4] = m10;
              arr[offset + 5] = m11;
              arr[offset + 6] = m12;
              arr[offset + 7] = m13;
              arr[offset + 8] = m20;
              arr[offset + 9] = m21;
              arr[offset + 10] = m22;
              arr[offset + 11] = m23;
              arr[offset + 12] = m30;
              arr[offset + 13] = m31;
              arr[offset + 14] = m32;
              arr[offset + 15] = m33;
              return arr;
          }
          public Matrix4d zero()
          {
              m00 = 0.0;
              m01 = 0.0;
              m02 = 0.0;
              m03 = 0.0;
              m10 = 0.0;
              m11 = 0.0;
              m12 = 0.0;
              m13 = 0.0;
              m20 = 0.0;
              m21 = 0.0;
              m22 = 0.0;
              m23 = 0.0;
              m30 = 0.0;
              m31 = 0.0;
              m32 = 0.0;
              m33 = 0.0;
              return this;
          }
          public Matrix4d scaling(double factor)
          {
              m00 = factor;
              m01 = 0.0;
              m02 = 0.0;
              m03 = 0.0;
              m10 = 0.0;
              m11 = factor;
              m12 = 0.0;
              m13 = 0.0;
              m20 = 0.0;
              m21 = 0.0;
              m22 = factor;
              m23 = 0.0;
              m30 = 0.0;
              m31 = 0.0;
              m32 = 0.0;
              m33 = 1.0;
              return this;
          }
          public Matrix4d scaling(double x, double y, double z)
          {
              m00 = x;
              m01 = 0.0;
              m02 = 0.0;
              m03 = 0.0;
              m10 = 0.0;
              m11 = y;
              m12 = 0.0;
              m13 = 0.0;
              m20 = 0.0;
              m21 = 0.0;
              m22 = z;
              m23 = 0.0;
              m30 = 0.0;
              m31 = 0.0;
              m32 = 0.0;
              m33 = 1.0;
              return this;
          }
          public Matrix4d scaling(Vector3d xyz)
          {
              return scaling(xyz.x, xyz.y, xyz.z);
          }
          public Matrix4d rotation(double angle, double x, double y, double z)
          {
              double cos = System.Math.Cos(angle);
              double sin = System.Math.Sin(angle);
              double C = 1.0 - cos;
              double xy = x * y, xz = x * z, yz = y * z;
              m00 = cos + x * x * C;
              m10 = xy * C - z * sin;
              m20 = xz * C + y * sin;
              m30 = 0.0;
              m01 = xy * C + z * sin;
              m11 = cos + y * y * C;
              m21 = yz * C - x * sin;
              m31 = 0.0;
              m02 = xz * C - y * sin;
              m12 = yz * C + x * sin;
              m22 = cos + z * z * C;
              m32 = 0.0;
              m03 = 0.0;
              m13 = 0.0;
              m23 = 0.0;
              m33 = 1.0;
              return this;
          }
          public Matrix4d rotationX(double ang)
          {
              double cos = System.Math.Cos(ang);
              double sin = System.Math.Sin(ang);
              m00 = 1.0;
              m01 = 0.0;
              m02 = 0.0;
              m03 = 0.0;
              m10 = 0.0;
              m11 = cos;
              m12 = sin;
              m13 = 0.0;
              m20 = 0.0;
              m21 = -sin;
              m22 = cos;
              m23 = 0.0;
              m30 = 0.0;
              m31 = 0.0;
              m32 = 0.0;
              m33 = 1.0;
              return this;
          }
          public Matrix4d rotationY(double ang)
          {
              double cos = System.Math.Cos(ang);
              double sin = System.Math.Sin(ang);
              m00 = cos;
              m01 = 0.0;
              m02 = -sin;
              m03 = 0.0;
              m10 = 0.0;
              m11 = 1.0;
              m12 = 0.0;
              m13 = 0.0;
              m20 = sin;
              m21 = 0.0;
              m22 = cos;
              m23 = 0.0;
              m30 = 0.0;
              m31 = 0.0;
              m32 = 0.0;
              m33 = 1.0;
              return this;
          }
          public Matrix4d rotationZ(double ang)
          {
              double cos = System.Math.Cos(ang);
              double sin = System.Math.Sin(ang);
              m00 = cos;
              m01 = sin;
              m02 = 0.0;
              m03 = 0.0;
              m10 = -sin;
              m11 = cos;
              m12 = 0.0;
              m13 = 0.0;
              m20 = 0.0;
              m21 = 0.0;
              m22 = 1.0;
              m23 = 0.0;
              m30 = 0.0;
              m31 = 0.0;
              m32 = 0.0;
              m33 = 1.0;
              return this;
          }
          public Matrix4d rotationXYZ(double angleX, double angleY, double angleZ)
          {
              return rotationXYZ(angleX, angleY, angleZ, this);
          }
          public Matrix4d rotationXYZ(double angleX, double angleY, double angleZ, Matrix4d dest)
          {
              double cosX = System.Math.Cos(angleX);
  
gt:             double sinX = System.Math.Sin(angleX);