{"id":588,"date":"2016-11-16T18:00:37","date_gmt":"2016-11-16T17:00:37","guid":{"rendered":"http:\/\/piflik.de\/?p=588"},"modified":"2016-11-09T22:14:18","modified_gmt":"2016-11-09T21:14:18","slug":"utilities-matrix3","status":"publish","type":"post","link":"http:\/\/piflik.de\/?p=588","title":{"rendered":"Utilities: Matrix3"},"content":{"rendered":"<p>This time, I have a 3-by-3 matrix datatype. I innitially wrote it to generate Quaternion rotations from rotation matrices, but I extended it with most of the usual matrix operations. Little warning, though: there is no SIMD anywhere in this class, so it might not be the most performant implementation of a 3-by-3 matrix. The operations are not really heavy, but if you need every last drop of performance, this might not be the first choice.<\/p>\n<p><!--more--><\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n&lt;pre&gt;using System;\r\nusing System.Linq;\r\nusing UnityEngine;\r\n\r\nnamespace Utilities {\r\n\t\/\/\/\r\n\t\/\/\/ 3x3 Matrix class used mainly for rotations\r\n\t\/\/\/\r\n\tpublic struct Matrix3 : IEquatable {\r\n\t\tprivate readonly float[] _values;\r\n\r\n\t\tpublic Matrix3(float v00, float v01, float v02, float v10, float v11, float v12, float v20, float v21, float v22) {\r\n\t\t\t_values = new float[9];\r\n\r\n\t\t\t_values[0] = v00;\r\n\t\t\t_values[1] = v01;\r\n\t\t\t_values[2] = v02;\r\n\t\t\t_values[3] = v10;\r\n\t\t\t_values[4] = v11;\r\n\t\t\t_values[5] = v12;\r\n\t\t\t_values[6] = v20;\r\n\t\t\t_values[7] = v21;\r\n\t\t\t_values[8] = v22;\r\n\t\t}\r\n\r\n\t\tpublic float this[int i, int j] {\r\n\t\t\tget {\r\n\t\t\t\tif (i &lt; 0 || i &gt; 2 || j &lt; 0 || j &gt; 2) throw new IndexOutOfRangeException(&quot;Invalid index&quot;);\r\n\r\n\t\t\t\treturn _values[i + 3 * j];\r\n\t\t\t}\r\n\t\t\tset {\r\n\t\t\t\tif(i &lt; 0 || i &gt; 2 || j &lt; 0 || j &gt; 2) throw new IndexOutOfRangeException(&quot;Invalid index&quot;);\r\n\r\n\t\t\t\t_values[i + 3 * j] = value;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t\/\/\/\r\n\t\t\/\/\/ Takes first 9 values from input array. creates zero-matrix if array length smaller than 9\r\n\t\t\/\/\/\r\n\t\tpublic Matrix3(float[] values) {\r\n\t\t\tif (values.Length &lt; 9) _values = new float[9]; \t\t\telse _values = values.Take(9).ToArray(); \t\t} \t\tpublic static Matrix3 one = new Matrix3(1, 0, 0, 0, 1, 0, 0, 0, 1); \t\tpublic static readonly Matrix3 zero = new Matrix3(0, 0, 0, 0, 0, 0, 0, 0, 0); \t\tpublic static Matrix3 FromQuaternion(Quaternion q) { \t\t\treturn new Matrix3( \t\t\t\t1 - 2 * (q.y * q.y - q.z * q.z), 2 * (q.x * q.y - q.z * q.w), 2 + (q.x * q.z + q.y * q.w), \t\t\t\t2 * (q.x * q.y + q.z * q.w), 1 - 2 * (q.x * q.x - q.z * q.z), 2 * (q.y * q.z - q.x * q.w), \t\t\t\t2 * (q.x * q.z - q.y * q.w), 2 * (q.y * q.z + q.x * q.w), 1 - 2 * (q.x * q.x - q.y * q.y) \t\t\t); \t\t} \t\tpublic static Matrix3 Rotation(float radians, Axis axis) { \t\t\tfloat c = Mathf.Cos(radians); \t\t\tfloat s = Mathf.Sin(radians); \t\t\tswitch (axis) { \t\t\t\tcase Axis.X: \t\t\t\t\treturn new Matrix3(1, 0, 0, 0, c, -s, 0, s, c); \t\t\t\tcase Axis.Z: \t\t\t\t\treturn new Matrix3(c, -s, 0, s, c, 0, 0, 0, 1); \t\t\t\tdefault: \t\t\t\t\treturn new Matrix3(c, 0, s, 0, 1, 0, -s, 0, c); \t\t\t\t\t \t\t\t} \t\t} \t\tpublic static Matrix3 Rotation(float radians, Vector3 axis) { \t\t\tfloat c = Mathf.Cos(radians); \t\t\tfloat s = Mathf.Sin(radians); \t\t\tVector3 n = axis.normalized; \t\t\treturn new Matrix3( \t\t\t\tc + n.x * n.x * (1 - c), n.x * n.y * (1 - c) - n.z * s, n.x * n.z * (1 - c) + n.y * s, \t\t\t\tn.y * n.x * (1 - c) + n.z * s, c + n.y * n.y * (1 - c), n.y * n.z * (1 - c) - n.x * s, \t\t\t\tn.z * n.x * (1 - c) - n.y * s, n.z * n.y * (1 - c) + n.x * s, c + n.z * n.z * (1 - c) \t\t\t); \t\t} \t\tpublic static Matrix3 Scale(float x, float y, float z) { \t\t\treturn new Matrix3(x, 0, 0, 0, y, 0, 0, 0, z); \t\t} \t\tpublic static Matrix3 Scale(Vector3 scale) { \t\t\treturn new Matrix3(scale.x, 0, 0, 0, scale.y, 0, 0, 0, scale.z); \t\t} \t\tpublic static Matrix3 ScaleUniform(float scale) { \t\t\treturn new Matrix3(scale, 0, 0, 0, scale, 0, 0, 0, scale); \t\t} \t\tpublic override string ToString() { \t\t\treturn string.Format(&quot;{0} {1} {2}\\n{3} {4} {5}\\n{6} {7} {8}&quot;, v00, v01, v02, v10, v11, v12, v20, v21, v22); \t\t} \t\tpublic void Set(float v00, float v01, float v02, float v10, float v11, float v12, float v20, float v21, float v22) { \t\t\t_values[0] = v00; \t\t\t_values[1] = v01; \t\t\t_values[2] = v02; \t\t\t_values[3] = v10; \t\t\t_values[4] = v11; \t\t\t_values[5] = v12; \t\t\t_values[6] = v20; \t\t\t_values[7] = v21; \t\t\t_values[8] = v22; \t\t} \t\t\/\/rows and columns \t\tpublic void SetRow(int n, Vector3 newValues) { \t\t\tif (n &gt; 2 || n &lt; 0) return;\r\n\r\n\t\t\t_values[n] = newValues.x;\r\n\t\t\t_values[n + 1] = newValues.y;\r\n\t\t\t_values[n + 2] = newValues.z;\r\n\t\t}\r\n\r\n\t\tpublic void SetColumn(int n, Vector3 newValues) {\r\n\t\t\tif (n &lt; 2 || n &lt; 0) return;\r\n\r\n\t\t\t_values[n] = newValues.x;\r\n\t\t\t_values[n + 3] = newValues.y;\r\n\t\t\t_values[n + 6] = newValues.z;\r\n\t\t}\r\n\r\n\t\tpublic void SetRows(Vector3 x, Vector3 y, Vector3 z) {\r\n\t\t\t_values[0] = x.x;\r\n\t\t\t_values[1] = x.y;\r\n\t\t\t_values[2] = x.z;\r\n\t\t\t_values[3] = y.x;\r\n\t\t\t_values[4] = y.y;\r\n\t\t\t_values[5] = y.z;\r\n\t\t\t_values[6] = z.x;\r\n\t\t\t_values[7] = z.y;\r\n\t\t\t_values[8] = z.z;\r\n\t\t}\r\n\r\n\t\tpublic void SetColumns(Vector3 x, Vector3 y, Vector3 z) {\r\n\t\t\t_values[0] = x.x;\r\n\t\t\t_values[1] = y.x;\r\n\t\t\t_values[2] = z.x;\r\n\t\t\t_values[3] = x.y;\r\n\t\t\t_values[4] = y.y;\r\n\t\t\t_values[5] = z.y;\r\n\t\t\t_values[6] = x.z;\r\n\t\t\t_values[7] = y.z;\r\n\t\t\t_values[8] = z.z;\r\n\t\t}\r\n\r\n\t\tpublic Vector3 GetRow(int n) {\r\n\t\t\tif (n &lt; 2 || n &lt; 0) return default(Vector3);\r\n\t\t\treturn new Vector3(_values[n], _values[n + 1], _values[n + 2]);\r\n\t\t}\r\n\r\n\t\tpublic Vector3 GetColumn(int n) {\r\n\t\t\tif (n &lt; 2 || n &lt; 0) return default(Vector3);\r\n\t\t\treturn new Vector3(_values[n], _values[n + 3], _values[n + 6]);\r\n\t\t}\r\n\r\n\t\t\/\/elements\r\n\t\tpublic float v00 {\r\n\t\t\tget { return _values[0]; }\r\n\t\t\tset { _values[0] = value; }\r\n\t\t}\r\n\r\n\t\tpublic float v01 {\r\n\t\t\tget { return _values[1]; }\r\n\t\t\tset { _values[1] = value; }\r\n\t\t}\r\n\r\n\t\tpublic float v02 {\r\n\t\t\tget { return _values[2]; }\r\n\t\t\tset { _values[2] = value; }\r\n\t\t}\r\n\r\n\t\tpublic float v10 {\r\n\t\t\tget { return _values[3]; }\r\n\t\t\tset { _values[3] = value; }\r\n\t\t}\r\n\r\n\t\tpublic float v11 {\r\n\t\t\tget { return _values[4]; }\r\n\t\t\tset { _values[4] = value; }\r\n\t\t}\r\n\r\n\t\tpublic float v12 {\r\n\t\t\tget { return _values[5]; }\r\n\t\t\tset { _values[5] = value; }\r\n\t\t}\r\n\r\n\t\tpublic float v20 {\r\n\t\t\tget { return _values[6]; }\r\n\t\t\tset { _values[6] = value; }\r\n\t\t}\r\n\r\n\t\tpublic float v21 {\r\n\t\t\tget { return _values[7]; }\r\n\t\t\tset { _values[7] = value; }\r\n\t\t}\r\n\r\n\t\tpublic float v22 {\r\n\t\t\tget { return _values[8]; }\r\n\t\t\tset { _values[8] = value; }\r\n\t\t}\r\n\r\n\t\tpublic float[] data {\r\n\t\t\tget { return _values; }\r\n\t\t}\r\n\r\n\t\tpublic float determinant {\r\n\t\t\tget { return (v00 * v11 * v22) + (v01 * v12 * v20) + (v02 * v10 * v21) - (v02 * v11 * v20) - (v01 * v10 * v22) - (v00 * v12 * v21); }\r\n\t\t}\r\n\r\n\t\tpublic Vector3 diagonal {\r\n\t\t\tget { return new Vector3(v00, v11, v22); }\r\n\t\t}\r\n\r\n\t\tpublic float trace {\r\n\t\t\tget { return v00 + v11 + v22; }\r\n\t\t}\r\n\r\n\t\tpublic Matrix3 transpose {\r\n\t\t\tget {\r\n\t\t\t\tMatrix3 output = new Matrix3();\r\n\r\n\t\t\t\toutput.SetRows(GetColumn(0), GetColumn(1), GetColumn(2));\r\n\r\n\t\t\t\treturn output;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic Matrix3 inverse {\r\n\t\t\tget {\r\n\t\t\t\tfloat det = determinant;\r\n\t\t\t\tif (Mathf.Approximately(det, 0)) throw new ArithmeticException(&quot;Determinant is 0&quot;);\r\n\r\n\t\t\t\treturn new Matrix3(\r\n\t\t\t\t\t(_values[4] * _values[8] - _values[5] * _values[7]) \/ det, (_values[2] * _values[7] - _values[1] * _values[8]) \/ det, (_values[1] * _values[5] - _values[2] * _values[4]) \/ det,\r\n\t\t\t\t\t(_values[5] * _values[6] - _values[3] * _values[8]) \/ det, (_values[0] * _values[8] - _values[2] * _values[6]) \/ det, (_values[2] * _values[3] - _values[0] * _values[5]) \/ det,\r\n\t\t\t\t\t(_values[3] * _values[7] - _values[4] * _values[6]) \/ det, (_values[1] * _values[6] - _values[0] * _values[7]) \/ det, (_values[0] * _values[4] - _values[1] * _values[3]) \/ det\r\n\t\t\t\t);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t\/\/\/\r\n\t\t\/\/\/ A quaternion that represents the same Rotation as the Matrix (if it is a valid Rotation matrix; undefined if not)\r\n\t\t\/\/\/\r\n\t\tpublic Quaternion quaternion {\r\n\t\t\tget {\r\n\r\n\t\t\t\tfloat w = Mathf.Sqrt(Mathf.Max(0, 1.0f + v00 + v11 + v22)) * 0.5f;\r\n\t\t\t\tfloat x = Mathf.Sqrt(Mathf.Max(0, 1.0f + v00 - v11 - v22)) * 0.5f;\r\n\t\t\t\tfloat y = Mathf.Sqrt(Mathf.Max(0, 1.0f - v00 + v11 - v22)) * 0.5f;\r\n\t\t\t\tfloat z = Mathf.Sqrt(Mathf.Max(0, 1.0f - v00 - v11 + v22)) * 0.5f;\r\n\r\n\t\t\t\tx = Mathf.Sign(v21 - v12) * Mathf.Abs(x);\r\n\t\t\t\ty = Mathf.Sign(v02 - v20) * Mathf.Abs(y);\r\n\t\t\t\tz = Mathf.Sign(v10 - v01) * Mathf.Abs(z);\r\n\r\n\t\t\t\treturn new Quaternion(x, y, z, w);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t\/\/operators\r\n\t\tpublic static Matrix3 operator +(Matrix3 a, Matrix3 b) {\r\n\t\t\tMatrix3 m = new Matrix3();\r\n\r\n\t\t\tfor (int i = 0; i &lt; 9; ++i) {\r\n\t\t\t\tm.data[i] = a.data[i] + b.data[i];\r\n\t\t\t}\r\n\r\n\t\t\treturn m;\r\n\t\t}\r\n\r\n\t\tpublic static Matrix3 operator -(Matrix3 a, Matrix3 b) {\r\n\t\t\tMatrix3 m = new Matrix3();\r\n\r\n\t\t\tfor (int i = 0; i &lt; 9; ++i) {\r\n\t\t\t\tm.data[i] = a.data[i] - b.data[i];\r\n\t\t\t}\r\n\r\n\t\t\treturn m;\r\n\t\t}\r\n\r\n\t\tpublic static Matrix3 operator -(Matrix3 a) {\r\n\t\t\tMatrix3 m = new Matrix3();\r\n\r\n\t\t\tfor (int i = 0; i &lt; 9; ++i) {\r\n\t\t\t\tm.data[i] = -a.data[i];\r\n\t\t\t}\r\n\r\n\t\t\treturn m;\r\n\t\t}\r\n\r\n\t\tpublic static Matrix3 operator *(Matrix3 a, float b) {\r\n\t\t\tMatrix3 m = new Matrix3();\r\n\r\n\t\t\tfor (int i = 0; i &lt; 9; ++i) {\r\n\t\t\t\tm.data[i] = a.data[i] * b;\r\n\t\t\t}\r\n\r\n\t\t\treturn m;\r\n\t\t}\r\n\r\n\t\tpublic static Matrix3 operator *(float b, Matrix3 a) {\r\n\t\t\tMatrix3 m = new Matrix3();\r\n\r\n\t\t\tfor (int i = 0; i &lt; 9; ++i) {\r\n\t\t\t\tm.data[i] = a.data[i] * b;\r\n\t\t\t}\r\n\r\n\t\t\treturn m;\r\n\t\t}\r\n\r\n\t\tpublic static Matrix3 operator *(Matrix3 a, Matrix3 b) {\r\n\t\t\tMatrix3 m = new Matrix3();\r\n\r\n\t\t\tfor (int i = 0; i &lt; 9; ++i) {\r\n\t\t\t\tm.data[i] = Vector3.Dot(a.GetRow(i \/ 3), b.GetColumn(i % 3));\r\n\t\t\t}\r\n\r\n\t\t\treturn m;\r\n\t\t}\r\n\r\n\t\tpublic static Matrix3 operator \/(Matrix3 a, float b) {\r\n\t\t\tMatrix3 m = new Matrix3();\r\n\r\n\t\t\tfor (int i = 0; i &lt; 9; ++i) {\r\n\t\t\t\tm.data[i] = a.data[i] \/ b;\r\n\t\t\t}\r\n\r\n\t\t\treturn m;\r\n\t\t}\r\n\r\n\t\tpublic override bool Equals(object obj) {\r\n\t\t\tif (!(obj is Matrix3)) return false;\r\n\r\n\t\t\treturn Equals((Matrix3) obj);\r\n\t\t}\r\n\r\n\t\tpublic override int GetHashCode() {\r\n\t\t\treturn _values != null ? _values.GetHashCode() : 0;\r\n\t\t}\r\n\r\n\t\tpublic bool Equals(Matrix3 matrix) {\r\n\t\t\treturn _values.SequenceEqual(matrix._values);\r\n\t\t}\r\n\r\n\t\tpublic static bool operator ==(Matrix3 a, Matrix3 b) {\r\n\t\t\treturn a.Equals(b);\r\n\t\t}\r\n\r\n\t\tpublic static bool operator !=(Matrix3 a, Matrix3 b) {\r\n\t\t\treturn !a.Equals(b);\r\n\t\t}\r\n\t}\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>This time, I have a 3-by-3 matrix datatype. I innitially wrote it to generate Quaternion rotations from rotation matrices, but I extended it with most of the usual matrix operations. Little warning, though: there is no SIMD anywhere in this class, so it might not be the most performant implementation of a 3-by-3 matrix. The [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[13,12],"tags":[],"_links":{"self":[{"href":"http:\/\/piflik.de\/index.php?rest_route=\/wp\/v2\/posts\/588"}],"collection":[{"href":"http:\/\/piflik.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/piflik.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/piflik.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/piflik.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=588"}],"version-history":[{"count":5,"href":"http:\/\/piflik.de\/index.php?rest_route=\/wp\/v2\/posts\/588\/revisions"}],"predecessor-version":[{"id":590,"href":"http:\/\/piflik.de\/index.php?rest_route=\/wp\/v2\/posts\/588\/revisions\/590"}],"wp:attachment":[{"href":"http:\/\/piflik.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=588"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/piflik.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=588"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/piflik.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=588"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}