Maths - Matrix Code - C#

related classes

/*Title:      mjbWorld
Copyright (c) 1998-2007 Martin John BakerThis program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.For information about the GNU General Public License see http://www.gnu.org/To discuss this program http://sourceforge.net/forum/forum.php?forum_id=122133 also see website https://www.euclideanspace.com/ */namespace mjbModel { using System; using System.ComponentModel; using System.IO; using System.Collections; using System.Reflection; using System.Text; using System.Data; using System.Xml;/// <summary> /// a class to hold a 4x4 matrix and to allow various transforms on it. /// </summary> class sftransform : property { /// <summary> /// element 0,0 of matrix /// </summary> public double m00; /// <summary> /// element 0,1 of matrix /// </summary> public double m01; /// <summary> /// element 0,2 of matrix /// </summary> public double m02; /// <summary> /// element 0,3 of matrix /// </summary> public double m03; /// <summary> /// element 1,0 of matrix /// </summary> public double m10; /// <summary> /// element 1,1 of matrix /// </summary> public double m11; /// <summary> /// element 1,2 of matrix /// </summary> public double m12; /// <summary> /// element 1,3 of matrix /// </summary> public double m13; /// <summary> /// element 2,0 of matrix /// </summary> public double m20; /// <summary> /// element 2,1 of matrix /// </summary> public double m21; /// <summary> /// element 2,2 of matrix /// </summary> public double m22; /// <summary> /// element 2,3 of matrix /// </summary> public double m23; /// <summary> /// element 3,0 of matrix /// </summary> public double m30; /// <summary> /// element 3,1 of matrix /// </summary> public double m31; /// <summary> /// element 3,2 of matrix /// </summary> public double m32; /// <summary> /// element 3,3 of matrix /// </summary> public double m33;/// <summary> /// constructor for initialy zero matrix /// </summary> public sftransform() { 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; }/// <summary> /// copy constructor /// </summary> /// <param name="a"></param> public sftransform(sftransform a) { m00 = a.m00; m01 = a.m01; m02 = a.m02; m03 = a.m03; m10 = a.m10; m11 = a.m11; m12 = a.m12; m13 = a.m13; m20 = a.m20; m21 = a.m21; m22 = a.m22; m23 = a.m23; m30 = a.m30; m31 = a.m31; m32 = a.m32; m33 = a.m33; }/// <summary> /// constructor set to value of a times b /// </summary> /// <param name="a">first matrix</param> /// <param name="b">second matrix</param> public sftransform(sftransform a,sftransform b) { combine(a,b); }/// <summary> /// destructor /// </summary> ~sftransform() { }/// <summary> /// a static class to return the VRML name of this property /// </summary> /// <returns>the VRML name of this property</returns> public static string vrmlType_s(){ return "SFTransform"; }/// <summary> /// gets the VRML name of this property, we need a non static class so that it can be overriden /// </summary> /// <returns>the VRML name of this property</returns> public override string vrmlType(){ return "SFTransform"; }/// <summary> /// returns the type of a class which can edit this transform /// </summary> /// <returns>type of a class which can edit this transform</returns> public static Type getEditClass(){ return typeof(sftransformEditor); }/// <summary> /// sets this transform to the identity matrix, multiplying by the /// identity matrix does not alter the other matrix. /// for theory see: /// https://www.euclideanspace.com/maths/algebra/matrix/arithmetic/index.htm /// </summary> public void setIdentity(){ 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; }/// <summary> /// overrides the clone method for this class /// </summary> /// <returns></returns> public override property clone() { return new sftransform(this); }/// <summary> /// sets the value of this transform to a copy of the transform supplied to it /// </summary> /// <param name="input">instance to copy</param> public void copy(sftransform input){ m00 = input.m00; m01 = input.m01; m02 = input.m02; m03 = input.m03; m10 = input.m10; m11 = input.m11; m12 = input.m12; m13 = input.m13; m20 = input.m20; m21 = input.m21; m22 = input.m22; m23 = input.m23; m30 = input.m30; m31 = input.m31; m32 = input.m32; m33 = input.m33; }/// <summary> /// create an array of transforms /// </summary> /// <param name="size">size of array</param> /// <returns>the array of transforms created</returns> public override property[] createArray(int size){ return new sftransform[size]; }/// <summary> /// sets this transform to the value calculated form a VRML tranform parameter /// which are: translation,rotation,center,sc and scaleOrientation /// for theory see: /// https://www.euclideanspace.com/maths/geometry/rotations/rotationAndTranslation/nonMatrix/index.htm /// /// </summary> /// <param name="translation">linier offset</param> /// <param name="rotation">rotation</param> /// <param name="center">centre of rotation</param> /// <param name="sc">scale factor in x,y and z dimensions</param> /// <param name="scaleOrientation">orientation of scale factor</param> public void calcTransform(sfvec3f translation, sfrotation rotation, sfvec3f center, sfvec3f sc, sfrotation scaleOrientation){ setIdentity(); if (translation!=null) translate(translation); if (rotation!=null) rotate(rotation,center); if (scaleOrientation!=null) rotate(scaleOrientation,center); if (sc!=null) { // if scale is (0,0,0), such as when scale first // enabled this will generate a non-afine error // so do following check if ((sc.x != 0) & (sc.y != 0) & (sc.z != 0)) scale(sc); } if (scaleOrientation!=null) rotate(scaleOrientation.getMinus(),center); }/// <summary> /// multiply this matrix with the matrix supplied (m1) /// for theory see: /// https://www.euclideanspace.com/maths/algebra/matrix/arithmetic/index.htm /// </summary> /// <param name="m1">matrix to multiply by</param> public void combine(sftransform m1) { sftransform tmp = new sftransform(this); combine(tmp,m1); }/// <summary> /// multiply the matrix supplied (m1) with this matrix. This is different /// from the combine because the order of multipication is significant /// for theory see: /// https://www.euclideanspace.com/maths/algebra/matrix/arithmetic/index.htm /// </summary> /// <param name="m1">matrix which we multiply this by</param> public void combineInverse(sftransform m1) { sftransform tmp = new sftransform(this); combine(m1,tmp); }/// <summary> /// sets the value of this to m1 * m2 /// for theory see: /// https://www.euclideanspace.com/maths/algebra/matrix/arithmetic/index.htm /// </summary> /// <param name="m1">martix 1</param> /// <param name="m2">matrix 2</param> public void combine(sftransform m1,sftransform m2) { m00 = m1.m00*m2.m00 + m1.m01*m2.m10 + m1.m02*m2.m20 + m1.m03*m2.m30; m01 = m1.m00*m2.m01 + m1.m01*m2.m11 + m1.m02*m2.m21 + m1.m03*m2.m31; m02 = m1.m00*m2.m02 + m1.m01*m2.m12 + m1.m02*m2.m22 + m1.m03*m2.m32; m03 = m1.m00*m2.m03 + m1.m01*m2.m13 + m1.m02*m2.m23 + m1.m03*m2.m33; m10 = m1.m10*m2.m00 + m1.m11*m2.m10 + m1.m12*m2.m20 + m1.m13*m2.m30; m11 = m1.m10*m2.m01 + m1.m11*m2.m11 + m1.m12*m2.m21 + m1.m13*m2.m31; m12 = m1.m10*m2.m02 + m1.m11*m2.m12 + m1.m12*m2.m22 + m1.m13*m2.m32; m13 = m1.m10*m2.m03 + m1.m11*m2.m13 + m1.m12*m2.m23 + m1.m13*m2.m33; m20 = m1.m20*m2.m00 + m1.m21*m2.m10 + m1.m22*m2.m20 + m1.m23*m2.m30; m21 = m1.m20*m2.m01 + m1.m21*m2.m11 + m1.m22*m2.m21 + m1.m23*m2.m31; m22 = m1.m20*m2.m02 + m1.m21*m2.m12 + m1.m22*m2.m22 + m1.m23*m2.m32; m23 = m1.m20*m2.m03 + m1.m21*m2.m13 + m1.m22*m2.m23 + m1.m23*m2.m33; m30 = m1.m30*m2.m00 + m1.m31*m2.m10 + m1.m32*m2.m20 + m1.m33*m2.m30; m31 = m1.m30*m2.m01 + m1.m31*m2.m11 + m1.m32*m2.m21 + m1.m33*m2.m31; m32 = m1.m30*m2.m02 + m1.m31*m2.m12 + m1.m32*m2.m22 + m1.m33*m2.m32; m33 = m1.m30*m2.m03 + m1.m31*m2.m13 + m1.m32*m2.m23 + m1.m33*m2.m33; }/// <summary> /// transform the vector supplied using this transform /// for theory see: /// https://www.euclideanspace.com/maths/algebra/matrix/transforms/index.htm /// </summary> /// <param name="v">vector to be transformed</param> public void transform(sfvec3f v){ if (v==null) { Console.WriteLine("sftransform.transform v==null"); return; } sfvec3f temp = new sfvec3f(v); v.x = m00 * temp.x + m01 * temp.y + m02 * temp.z + m03; v.y = m10 * temp.x + m11 * temp.y + m12 * temp.z + m13; v.z = m20 * temp.x + m21 * temp.y + m22 * temp.z + m23; }/// <summary> /// linear translation, ie add the vector supplied to the translation part of this matrix /// for theory see: /// https://www.euclideanspace.com/maths/algebra/matrix/transforms/index.htm /// </summary> /// <param name="v">ammount of translation</param> public void translate(sfvec3f v){ if (v==null) { Console.WriteLine("sftransform.translate v==null"); return; } m03 += v.x; m13 += v.y; m23 += v.z; m33 = 1.0; }/// <summary> /// scale this transform, /// for theory see: /// https://www.euclideanspace.com/maths/geometry/rotations/rotationAndTranslation/nonMatrix/index.htm /// </summary> /// <param name="v">scale factor in x,y and z dimensions</param> public void scale(sfvec3f v){ m00 *= v.x; m01 *= v.x; m02 *= v.x; m10 *= v.y; m11 *= v.y; m12 *= v.y; m20 *= v.z; m21 *= v.z; m22 *= v.z; m33 = 1.0; }/// <summary> /// scale equally in all dimensions /// https://www.euclideanspace.com/maths/geometry/rotations/rotationAndTranslation/nonMatrix/index.htm /// </summary> /// <param name="scale">the scale factor for the matrix</param> public void scale(double scale) { m00 *= scale; m01 *= scale; m02 *= scale; m03 *= scale; m10 *= scale; m11 *= scale; m12 *= scale; m13 *= scale; m20 *= scale; m21 *= scale; m22 *= scale; m23 *= scale; m30 *= scale; m31 *= scale; m32 *= scale; m33 *= scale; }/// <summary> /// set this translation to rotate around a point /// for theory see: /// https://www.euclideanspace.com/maths/algebra/matrix/orthogonal/rotation/index.htm /// </summary> /// <param name="rot">ammount of rotation</param> /// <param name="centre">centre of rotation</param> public void rotate(sfrotation rot,sfvec3f centre) { sftransform t1 = new sftransform(this); sftransform t2 = new sftransform(); t2.setRotate(rot,centre); combine(t1,t2); }/// <summary> /// rotate around a point /// for theory see: /// https://www.euclideanspace.com/maths/algebra/matrix/orthogonal/rotation/index.htm /// </summary> /// <param name="rot"></param> /// <param name="centre"></param> public void setRotate(sfrotation rot,sfvec3f centre) { if (rot.coding == (int)sfrotation.cde.CODING_AXISANGLE | rot.coding == (int)sfrotation.cde.CODING_AXISANGLE_SAVEASQUAT) { double c = Math.Cos(rot.angle); double s = Math.Sin(rot.angle); double t = 1.0 - c; m00 = c + rot.x*rot.x*t; m11 = c + rot.y*rot.y*t; m22 = c + rot.z*rot.z*t; double tmp1 = rot.x*rot.y*t; double tmp2 = rot.z*s; m10 = tmp1 + tmp2; m01 = tmp1 - tmp2; tmp1 = rot.x*rot.z*t; tmp2 = rot.y*s; m20 = tmp1 - tmp2; m02 = tmp1 + tmp2; tmp1 = rot.y*rot.z*t; tmp2 = rot.x*s; m21 = tmp1 + tmp2; m12 = tmp1 - tmp2; } else { //Console.WriteLine("sftransform.setRotate({0},{1}) type = quat",rot,centre); double sqw = rot.angle*rot.angle; double sqx = rot.x*rot.x; double sqy = rot.y*rot.y; double sqz = rot.z*rot.z; m00 = sqx - sqy - sqz + sqw; // since sqw + sqx + sqy + sqz =1 m11 = -sqx + sqy - sqz + sqw; m22 = -sqx - sqy + sqz + sqw; double tmp1 = rot.x*rot.y; double tmp2 = rot.z*rot.angle; m10 = 2.0 * (tmp1 + tmp2); m01 = 2.0 * (tmp1 - tmp2); tmp1 = rot.x*rot.z; tmp2 = rot.y*rot.angle; m20 = 2.0 * (tmp1 - tmp2); m02 = 2.0 * (tmp1 + tmp2); tmp1 = rot.y*rot.z; tmp2 = rot.x*rot.angle; m21 = 2.0 * (tmp1 + tmp2); m12 = 2.0 * (tmp1 - tmp2); } double a1,a2,a3; if (centre == null) { a1=a2=a3=0; } else { a1 = centre.x; a2 = centre.y; a3 = centre.z; } m03 = a1 - a1 * m00 - a2 * m01 - a3 * m02; m13 = a2 - a1 * m10 - a2 * m11 - a3 * m12; m23 = a3 - a1 * m20 - a2 * m21 - a3 * m22; m30 = m31 = m32 = 0.0; m33 = 1.0; }/// <summary> /// rotate about a point, rotation given by euler angles /// for theory see: /// https://www.euclideanspace.com/maths/algebra/matrix/orthogonal/rotation/index.htm /// </summary> /// <param name="centre">point to rotate around</param> /// <param name="theta">angle in radians</param> /// <param name="phi">angle in radians</param> /// <param name="alpha">angle in radians</param> public void setRotate(sfvec3f centre, double theta,double phi,double alpha) { double cosAlpha, sinAlpha, cosPhi, sinPhi, cosTheta, sinTheta, cosPhi2, sinPhi2, cosTheta2, sinTheta2, c, a1,a2,a3; if (centre==null) { a1=a2=a3=0; } else { a1 = centre.x; a2 = centre.y; a3 = centre.z; } cosPhi = Math.Cos(phi); sinPhi = Math.Sin(phi); cosPhi2 = cosPhi * cosPhi; sinPhi2 = sinPhi * sinPhi; cosTheta = Math.Cos(theta); sinTheta = Math.Sin(theta); cosTheta2 = cosTheta * cosTheta; sinTheta2 = sinTheta * sinTheta; cosAlpha = Math.Cos(alpha); sinAlpha = Math.Sin(alpha); c = 1.0 - cosAlpha; m00 = cosTheta2 * (cosAlpha * cosPhi2 + sinPhi2) + cosAlpha * sinTheta2; m10 = sinAlpha * cosPhi + c * sinPhi2 * cosTheta * sinTheta; m20 = sinPhi * (cosPhi * cosTheta * c - sinAlpha * sinTheta); m30 = 0.0; m01 = sinPhi2 * cosTheta * sinTheta * c - sinAlpha * cosPhi; m11 = sinTheta2 * (cosAlpha * cosPhi2 + sinPhi2) + cosAlpha * cosTheta2; m21 = sinPhi * (cosPhi * sinTheta * c + sinAlpha * cosTheta); m31 = 0.0; m02 = sinPhi * (cosPhi * cosTheta * c + sinAlpha * sinTheta); m12 = sinPhi * (cosPhi * sinTheta * c - sinAlpha * cosTheta); m22 = cosAlpha * sinPhi2 + cosPhi2; m32 = 0.0; m03 = a1 - a1 * m00 - a2 * m01 - a3 * m02; m13 = a2 - a1 * m10 - a2 * m11 - a3 * m12; m23 = a3 - a1 * m20 - a2 * m21 - a3 * m22; m33 = 1.0; }/// <summary> /// format values into a string with square brackets /// </summary> /// <returns>a string representation of this class</returns> public override string ToString(){ string s1=String.Concat("[",m00.ToString(),",",m01.ToString(),",",m02.ToString(),",",m03.ToString(),"]"); string s2=String.Concat("[",m10.ToString(),",",m11.ToString(),",",m12.ToString(),",",m13.ToString(),"]"); string s3=String.Concat("[",m20.ToString(),",",m21.ToString(),",",m22.ToString(),",",m23.ToString(),"]"); string s4=String.Concat("[",m30.ToString(),",",m31.ToString(),",",m32.ToString(),",",m33.ToString(),"]"); return String.Concat(s1,"\n",s2,"\n",s3,"\n",s4); }/// <summary> /// generate java code to file /// </summary> /// <param name="f"></param> /// <param name="mode"></param> /// <param name="maxInstances"></param> public void writeJava(filter f,int mode,int maxInstances){ try { if (mode != 0) return; // no procedure defn required f.status(GetType().Name); f.writeln(String.Concat("// code for ",GetType().Name),0); f.writeln("Transform3D t3d = new Transform3D();",2); f.writeln("Matrix4d m = new Matrix4d();",2); f.writeln("double []d = {",2); f.writeln(String.Concat(m00.ToString(),",",m01.ToString(),",",m02.ToString(),",",m03.ToString(),","),2); f.writeln(String.Concat(m10.ToString(),",",m11.ToString(),",",m12.ToString(),",",m13.ToString(),","),2); f.writeln(String.Concat(m20.ToString(),",",m21.ToString(),",",m22.ToString(),",",m23.ToString(),","),2); f.writeln(String.Concat(m30.ToString(),",",m31.ToString(),",",m32.ToString(),",",m33.ToString(),","),2); f.writeln("};",2); f.writeln("m.set(d);",2); f.writeln("t3d.set(m);",2); } catch (Exception e) { Console.WriteLine("sftransform.writeJava error: {0}",e); } return; }/// <summary> /// write in VRML mode (except that SFTransform does not exist in VRML) /// </summary> /// <param name="f">file parameters and methods</param> /// <param name="mode">mode values /// 0 - output VRML97 modified values /// 1 - output VRML97 original values /// 2 - output xml (x3d) /// 3 - output attribute in brackets /// 4 - output with f prefix</param> /// <param name="indent"></param> public override void write(filter f,int mode,int indent){ f.write(ToString()); }/// <summary> /// read in VRML mode (except that SFTransform does not exist in VRML) /// used by mfparam.vrml2par /// </summary> /// <param name="f">file parameters and methods</param> /// <param name="sfp"></param> /// <param name="n"></param> /// <param name="mode"></param> /// <returns></returns> public override bool instring(filter f,sfparam sfp,nodeBean n,int mode) { return false; }/// <summary> /// find inverse matrix /// for theory see: /// https://www.euclideanspace.com/maths/algebra/matrix/arithmetic/index.htm /// </summary> public void invert() { double det = determinant(); double t00 = m12*m23*m31 - m13*m22*m31 + m13*m21*m32 - m11*m23*m32 - m12*m21*m33 + m11*m22*m33; double t01 = m03*m22*m31 - m02*m23*m31 - m03*m21*m32 + m01*m23*m32 + m02*m21*m33 - m01*m22*m33; double t02 = m02*m13*m31 - m03*m12*m31 + m03*m11*m32 - m01*m13*m32 - m02*m11*m33 + m01*m12*m33; double t03 = m03*m12*m21 - m02*m13*m21 - m03*m11*m22 + m01*m13*m22 + m02*m11*m23 - m01*m12*m23; double t10 = m13*m22*m30 - m12*m23*m30 - m13*m20*m32 + m10*m23*m32 + m12*m20*m33 - m10*m22*m33; double t11 = m02*m23*m30 - m03*m22*m30 + m03*m20*m32 - m00*m23*m32 - m02*m20*m33 + m00*m22*m33; double t12 = m03*m12*m30 - m02*m13*m30 - m03*m10*m32 + m00*m13*m32 + m02*m10*m33 - m00*m12*m33; double t13 = m02*m13*m20 - m03*m12*m20 + m03*m10*m22 - m00*m13*m22 - m02*m10*m23 + m00*m12*m23; double t20 = m11*m23*m30 - m13*m21*m30 + m13*m20*m31 - m10*m23*m31 - m11*m20*m33 + m10*m21*m33; double t21 = m03*m21*m30 - m01*m23*m30 - m03*m20*m31 + m00*m23*m31 + m01*m20*m33 - m00*m21*m33; double t22 = m01*m13*m30 - m03*m11*m30 + m03*m10*m31 - m00*m13*m31 - m01*m10*m33 + m00*m11*m33; double t23 = m03*m11*m20 - m01*m13*m20 - m03*m10*m21 + m00*m13*m21 + m01*m10*m23 - m00*m11*m23; double t30 = m12*m21*m30 - m11*m22*m30 - m12*m20*m31 + m10*m22*m31 + m11*m20*m32 - m10*m21*m32; double t31 = m01*m22*m30 - m02*m21*m30 + m02*m20*m31 - m00*m22*m31 - m01*m20*m32 + m00*m21*m32; double t32 = m02*m11*m30 - m01*m12*m30 - m02*m10*m31 + m00*m12*m31 + m01*m10*m32 - m00*m11*m32; double t33 = m01*m12*m20 - m02*m11*m20 + m02*m10*m21 - m00*m12*m21 - m01*m10*m22 + m00*m11*m22; m00 = t00; m01 = t01; m02 = t02; m03 = t03; m10 = t10; m11 = t11; m12 = t12; m13 = t13; m20 = t20; m21 = t21; m22 = t22; m23 = t23; m30 = t30; m31 = t31; m32 = t32; m33 = t33; scale(1/det); }/// <summary> /// for theory see: /// https://www.euclideanspace.com/maths/algebra/matrix/arithmetic/index.htm /// </summary> public void invertAffine() { double d = determinantAffine(); if (d != 0.0) { double t00 = (m11*m22 - m12*m21) / d; double t01 = (m02*m21 - m01*m22) / d; double t02 = (m01*m12 - m02*m11) / d; double t10 = (m12*m20 - m10*m22) / d; double t11 = (m00*m22 - m02*m20) / d; double t12 = (m02*m10 - m00*m12) / d; double t20 = (m10*m21 - m11*m20) / d; double t21 = (m01*m20 - m00*m21) / d; double t22 = (m00*m11 - m01*m10) / d; m00 = t00; m01 = t01; m02 = t02; m10 = t10; m11 = t11; m12 = t12; m20 = t20; m21 = t21; m22 = t22; } m03 *= -1.0; m13 *= -1.0; m23 *= -1.0; }/// <summary> /// Calculates the determinant of this matrix /// for theory see: /// https://www.euclideanspace.com/maths/algebra/matrix/arithmetic/index.htm /// </summary> /// <returns>the determinant of the matrix</returns> public double determinant() { double value; value = m03 * m12 * m21 * m30-m02 * m13 * m21 * m30-m03 * m11 * m22 * m30+m01 * m13 * m22 * m30+ m02 * m11 * m23 * m30-m01 * m12 * m23 * m30-m03 * m12 * m20 * m31+m02 * m13 * m20 * m31+ m03 * m10 * m22 * m31-m00 * m13 * m22 * m31-m02 * m10 * m23 * m31+m00 * m12 * m23 * m31+ m03 * m11 * m20 * m32-m01 * m13 * m20 * m32-m03 * m10 * m21 * m32+m00 * m13 * m21 * m32+ m01 * m10 * m23 * m32-m00 * m11 * m23 * m32-m02 * m11 * m20 * m33+m01 * m12 * m20 * m33+ m02 * m10 * m21 * m33-m00 * m12 * m21 * m33-m01 * m10 * m22 * m33+m00 * m11 * m22 * m33; return value; }/// <summary> /// calculates the affine determinant of this matrix. /// for theory see: /// https://www.euclideanspace.com/maths/algebra/matrix/arithmetic/index.htm /// </summary> /// <returns>the determinant of the matrix</returns> public double determinantAffine() { double value; value = m00 * ( m11 * m22 - m21 * m12 ); value -= m01 * ( m10 * m22 - m20 * m12 ); value += m02 * ( m10 * m21 - m20 * m11 ); return value; }/// <summary> /// calculates the transpose /// for theory see: /// https://www.euclideanspace.com/maths/algebra/matrix/arithmetic/index.htm /// </summary> public void transpose() { double tmp = m01; m01 = m10; m10 = tmp; tmp = m02; m02 = m20; m20 = tmp; tmp = m03; m03 = m30; m30 = tmp; tmp = m12; m12 = m21; m21 = tmp; tmp = m13; m13 = m31; m31 = tmp; tmp = m23; m23 = m32; m32 = tmp; } } // class } //namespace mjbModel

metadata block
see also:

 

Correspondence about this page david

Book Shop - Further reading.

Where I can, I have put links to Amazon for books that are relevant to the subject, click on the appropriate country flag to get more details of the book or to buy it from them.

cover Mathematics for 3D game Programming - Includes introduction to Vectors, Matrices, Transforms and Trigonometry. (But no euler angles or quaternions). Also includes ray tracing and some linear & rotational physics also collision detection (but not collision response).

Terminology and Notation

Specific to this page here:

 

This site may have errors. Don't use for critical systems.

Copyright (c) 1998-2017 Martin John Baker - All rights reserved - privacy policy.