]> gerrit.simantics Code Review - simantics/3d.git/blobdiff - org.simantics.g3d/src/org/simantics/g3d/math/EulerTools.java
3D framework (Simca 2012)
[simantics/3d.git] / org.simantics.g3d / src / org / simantics / g3d / math / EulerTools.java
diff --git a/org.simantics.g3d/src/org/simantics/g3d/math/EulerTools.java b/org.simantics.g3d/src/org/simantics/g3d/math/EulerTools.java
new file mode 100644 (file)
index 0000000..4545ccb
--- /dev/null
@@ -0,0 +1,394 @@
+package org.simantics.g3d.math;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Quat4d;\r
+import javax.vecmath.Vector3d;\r
+\r
+public class EulerTools {\r
+\r
+       public enum Order {\r
+               XYX, XYZ, XZX, XZY, YXY, YXZ, YZX, YZY, ZXY, ZXZ, ZYX, ZYZ\r
+       };\r
+\r
+       public static Quat4d getQuatFromEuler(Order order, Vector3d a) {\r
+               return getQuatFromEuler(order, a.x, a.y, a.z);\r
+       }\r
+       \r
+       public static Quat4d getQuatFromEuler(Order order, double a1, double a2, double a3) {\r
+               Quat4d q1 = new Quat4d();\r
+               Quat4d q2 = new Quat4d();\r
+               Quat4d q3 = new Quat4d();\r
+               switch (order) {\r
+               case XYX:\r
+                       q1.set(new AxisAngle4d(1.0, 0.0, 0.0, a1));\r
+                       q2.set(new AxisAngle4d(0.0, 1.0, 0.0, a2));\r
+                       q3.set(new AxisAngle4d(1.0, 0.0, 0.0, a3));\r
+                       break;\r
+               case XYZ:\r
+                       q1.set(new AxisAngle4d(1.0, 0.0, 0.0, a1));\r
+                       q2.set(new AxisAngle4d(0.0, 1.0, 0.0, a2));\r
+                       q3.set(new AxisAngle4d(0.0, 0.0, 1.0, a3));\r
+                       break;\r
+               case XZX:\r
+                       q1.set(new AxisAngle4d(1.0, 0.0, 0.0, a1));\r
+                       q2.set(new AxisAngle4d(0.0, 0.0, 1.0, a2));\r
+                       q3.set(new AxisAngle4d(1.0, 0.0, 0.0, a3));\r
+                       break;\r
+               case XZY:\r
+                       q1.set(new AxisAngle4d(1.0, 0.0, 0.0, a1));\r
+                       q2.set(new AxisAngle4d(0.0, 0.0, 1.0, a2));\r
+                       q3.set(new AxisAngle4d(0.0, 1.0, 0.0, a3));\r
+                       break;\r
+               case YXY:\r
+                       q1.set(new AxisAngle4d(0.0, 1.0, 0.0, a1));\r
+                       q2.set(new AxisAngle4d(1.0, 0.0, 0.0, a2));\r
+                       q3.set(new AxisAngle4d(0.0, 1.0, 0.0, a3));\r
+                       break;\r
+               case YXZ:\r
+                       q1.set(new AxisAngle4d(0.0, 1.0, 0.0, a1));\r
+                       q2.set(new AxisAngle4d(1.0, 0.0, 0.0, a2));\r
+                       q3.set(new AxisAngle4d(0.0, 0.0, 1.0, a3));\r
+                       break;\r
+               case YZX:\r
+                       q1.set(new AxisAngle4d(0.0, 1.0, 0.0, a1));\r
+                       q2.set(new AxisAngle4d(0.0, 0.0, 1.0, a2));\r
+                       q3.set(new AxisAngle4d(1.0, 0.0, 0.0, a3));\r
+                       break;\r
+               case YZY:\r
+                       q1.set(new AxisAngle4d(0.0, 1.0, 0.0, a1));\r
+                       q2.set(new AxisAngle4d(0.0, 0.0, 1.0, a2));\r
+                       q3.set(new AxisAngle4d(0.0, 1.0, 0.0, a3));\r
+                       break;\r
+               case ZXY:\r
+                       q1.set(new AxisAngle4d(0.0, 0.0, 1.0, a1));\r
+                       q2.set(new AxisAngle4d(1.0, 0.0, 0.0, a2));\r
+                       q3.set(new AxisAngle4d(0.0, 1.0, 0.0, a3));\r
+                       break;\r
+               case ZXZ:\r
+                       q1.set(new AxisAngle4d(0.0, 0.0, 1.0, a1));\r
+                       q2.set(new AxisAngle4d(1.0, 0.0, 0.0, a2));\r
+                       q3.set(new AxisAngle4d(0.0, 0.0, 1.0, a3));\r
+                       break;\r
+               case ZYX:\r
+                       q1.set(new AxisAngle4d(0.0, 0.0, 1.0, a1));\r
+                       q2.set(new AxisAngle4d(0.0, 1.0, 0.0, a2));\r
+                       q3.set(new AxisAngle4d(1.0, 0.0, 0.0, a3));\r
+                       break;\r
+               case ZYZ:\r
+                       q1.set(new AxisAngle4d(0.0, 0.0, 1.0, a1));\r
+                       q2.set(new AxisAngle4d(0.0, 1.0, 0.0, a2));\r
+                       q3.set(new AxisAngle4d(0.0, 0.0, 1.0, a3));\r
+                       break;\r
+               }\r
+               q1.mul(q2);\r
+               q1.mul(q3);\r
+               return q1;\r
+       }\r
+       \r
+       /**\r
+        * See http://noelhughes.net/uploads/quat_2_euler_paper_ver3.pdf\r
+        * @param order\r
+        * @param q\r
+        * @return\r
+        */\r
+       public static Vector3d getEulerFromQuat(Order order, Quat4d q) {\r
+               Vector3d euler = new Vector3d();\r
+               \r
+//             Vector3d v1 = new Vector3d();\r
+//             Vector3d v2 = new Vector3d();\r
+               Vector3d v3 = new Vector3d();\r
+               Vector3d v3n = new Vector3d();\r
+               \r
+               switch (order) {\r
+               case XYX:\r
+//                     v1.x = 1.0;\r
+//                     v2.y = 1.0;\r
+                       v3.x = 1.0;\r
+                       v3n.y = 1.0;\r
+                       break;\r
+               case XYZ:\r
+//                     v1.x = 1.0;\r
+//                     v2.y = 1.0;\r
+                       v3.z = 1.0;\r
+                       v3n.x = 1.0;\r
+                       break;\r
+               case XZX:\r
+//                     v1.x = 1.0;\r
+//                     v2.z = 1.0;\r
+                       v3.x = 1.0;\r
+                       v3n.y = 1.0;\r
+                       break;\r
+               case XZY:\r
+//                     v1.x = 1.0;\r
+//                     v2.z = 1.0;\r
+                       v3.y = 1.0;\r
+                       v3n.z = 1.0;\r
+                       break;\r
+               case YXY:\r
+//                     v1.y = 1.0;\r
+//                     v2.x = 1.0;\r
+                       v3.y = 1.0;\r
+                       v3n.z = 1.0;\r
+                       break;\r
+               case YXZ:\r
+//                     v1.y = 1.0;\r
+//                     v2.x = 1.0;\r
+                       v3.z = 1.0;\r
+                       v3n.x = 1.0;\r
+                       break;\r
+               case YZX:\r
+//                     v1.y = 1.0;\r
+//                     v2.z = 1.0;\r
+                       v3.x = 1.0;\r
+                       v3n.y = 1.0;\r
+                       break;\r
+               case YZY:\r
+//                     v1.y = 1.0;\r
+//                     v2.z = 1.0;\r
+                       v3.y = 1.0;\r
+                       v3n.z = 1.0;\r
+                       break;\r
+               case ZXY:\r
+//                     v1.z = 1.0;\r
+//                     v2.x = 1.0;\r
+                       v3.y = 1.0;\r
+                       v3n.z = 1.0;\r
+                       break;\r
+               case ZXZ:\r
+//                     v1.z = 1.0;\r
+//                     v2.x = 1.0;\r
+                       v3.z = 1.0;\r
+                       v3n.x = 1.0;\r
+                       break;\r
+               case ZYX:\r
+//                     v1.z = 1.0;\r
+//                     v2.y = 1.0;\r
+                       v3.x = 1.0;\r
+                       v3n.y = 1.0;\r
+                       break;\r
+               case ZYZ:\r
+//                     v1.z = 1.0;\r
+//                     v2.y = 1.0;\r
+                       v3.z = 1.0;\r
+                       v3n.x = 1.0;\r
+                       break;\r
+               }\r
+               Vector3d v3r = new Vector3d();\r
+               MathTools.rotate(q, v3, v3r);\r
+               v3r.normalize();\r
+               \r
+               switch (order) {\r
+\r
+               case XZX:\r
+                       euler.x = Math.atan2(v3r.z, v3r.y);\r
+                       euler.y = Math.acos(v3r.x);\r
+                       break;\r
+               case YXY:\r
+                       euler.x = Math.atan2(v3r.x, v3r.z);\r
+                       euler.y = Math.acos(v3r.y);\r
+                       break;\r
+               case ZYZ:\r
+                       euler.x = Math.atan2(v3r.y, v3r.x);\r
+                       euler.y = Math.acos(v3r.z);\r
+                       break;\r
+                       \r
+               case XZY:\r
+                       euler.x = Math.atan2(v3r.z, v3r.y);\r
+                       euler.y = -Math.asin(v3r.x);\r
+                       break;\r
+               case YXZ:\r
+                       euler.x = Math.atan2(v3r.x, v3r.z);\r
+                       euler.y = -Math.asin(v3r.y);\r
+                       break;\r
+               case ZYX:\r
+                       euler.x = Math.atan2(v3r.y, v3r.x);\r
+                       euler.y = -Math.asin(v3r.z);\r
+                       break;\r
+                       \r
+               case XYX:\r
+                       euler.x = Math.atan2(v3r.y, -v3r.z);\r
+                       //euler.x = Math.atan2(v3r.y, -v3r.x);\r
+                       euler.y = Math.acos(v3r.x);\r
+                       break;\r
+               case YZY:\r
+                       euler.x = Math.atan2(v3r.z, -v3r.x);\r
+                       //euler.x = Math.atan2(v3r.z, -v3r.y);\r
+                       euler.y = Math.acos(v3r.y);\r
+                       break;\r
+               case ZXZ:\r
+                       euler.x = Math.atan2(v3r.x, -v3r.y);\r
+                       //euler.x = Math.atan2(v3r.x, -v3r.z);\r
+                       euler.y = Math.acos(v3r.z);\r
+                       break;\r
+                       \r
+               case XYZ:\r
+                       euler.x = Math.atan2(-v3r.y, v3r.z);\r
+                       euler.y = Math.asin(v3r.x);\r
+                       break;\r
+               case YZX:\r
+                       euler.x = Math.atan2(-v3r.z, v3r.x);\r
+                       euler.y = Math.asin(v3r.y);\r
+                       break;\r
+               case ZXY:\r
+                       euler.x = Math.atan2(-v3r.x, v3r.y);\r
+                       euler.y = Math.asin(v3r.z);\r
+                       break;\r
+               }\r
+               \r
+               Quat4d q1 = new Quat4d();\r
+               q1.w = Math.cos(euler.x*0.5);\r
+               Quat4d q2 = new Quat4d();\r
+               q2.w = Math.cos(euler.y*0.5);\r
+               \r
+               switch (order) {\r
+               case XYX:\r
+               case XYZ:\r
+               case XZX:\r
+               case XZY:\r
+                       q1.x = Math.sin(euler.x*0.5);\r
+                       break;\r
+               case YXY:\r
+               case YXZ:\r
+               case YZX:\r
+               case YZY:\r
+                       q1.y = Math.sin(euler.x*0.5);\r
+                       break;\r
+               case ZXY:\r
+               case ZXZ:\r
+               case ZYX:\r
+               case ZYZ:\r
+                       q1.z = Math.sin(euler.x*0.5);\r
+                       break;\r
+               }\r
+               \r
+               switch (order) {\r
+               case YXY:\r
+               case YXZ:\r
+               case ZXY:\r
+               case ZXZ:\r
+                       q2.x = Math.sin(euler.y*0.5);\r
+                       break;\r
+               case XYX:\r
+               case XYZ:\r
+               case ZYX:\r
+               case ZYZ:\r
+                       q2.y = Math.sin(euler.y*0.5);\r
+                       break;\r
+               case XZX:\r
+               case XZY:\r
+               case YZX:\r
+               case YZY:\r
+                       q2.z = Math.sin(euler.y*0.5);\r
+                       break;\r
+               }\r
+               \r
+               Quat4d q12 = new Quat4d();\r
+               q12.mul(q1, q2);\r
+               \r
+               Vector3d v3n12 = new Vector3d();\r
+               Vector3d v3ng = new Vector3d();\r
+               MathTools.rotate(q12, v3n, v3n12);\r
+               MathTools.rotate(q, v3n, v3ng);\r
+               \r
+               double dot = v3n12.dot(v3ng);\r
+               dot = MathTools.clamp(-1.0, 1.0, dot);\r
+               euler.z = Math.abs(Math.acos(dot));\r
+               Vector3d vc = new Vector3d();\r
+               vc.cross(v3n12, v3ng);\r
+               euler.z *= Math.signum(vc.dot(v3r));\r
+               \r
+               return euler;\r
+       }\r
+\r
+       \r
+       public static void main(String args[]) {\r
+               \r
+               boolean all = false;\r
+               boolean allOrder = false;\r
+               if (all) {\r
+                       testAll();\r
+               } else if (allOrder) {\r
+                       test(Order.YXZ);\r
+               } else {\r
+                       //test(Order.ZXY,30,60,45);\r
+                       //test(Order.YXZ,30,0,0);\r
+                       //test(Order.YXZ,30,90,60);\r
+                       test(Order.YXZ,300,240,360);\r
+               }\r
+       }\r
+       \r
+       private static void testAll() {\r
+               double start = 0.0;\r
+               double end = 90.0;\r
+               double step = 30.0;\r
+               for (double a1 = start;  a1 <= end; a1+= step) {\r
+                       double r1 = MathTools.degToRad(a1);\r
+                       for (double a2 = start;  a2 <= end; a2+= step) {\r
+                               double r2 = MathTools.degToRad(a2);\r
+                               for (double a3 = start;  a3 <= end; a3+= step) {\r
+                                       double r3 = MathTools.degToRad(a3);\r
+                                       for (Order order : Order.values()) {\r
+                                               Quat4d q = EulerTools.getQuatFromEuler(order, r1, r2, r3);\r
+                                               Vector3d a = EulerTools.getEulerFromQuat(order, q);\r
+                                               Quat4d q2 = EulerTools.getQuatFromEuler(order, a.x,a.y,a.z);\r
+                                               a.x = MathTools.radToDeg(a.x);\r
+                                               a.y = MathTools.radToDeg(a.y);\r
+                                               a.z = MathTools.radToDeg(a.z);\r
+                                               System.out.println(toString(a1) +" " + toString(a2) + " " + toString(a3) + " " + order + "\t" + toString(a) + "\t" + toString(q) + "\t" + toString(q2));\r
+                                       }\r
+                               }       \r
+                       }       \r
+               }\r
+       }\r
+       \r
+       private static void test(Order order) {\r
+               double start = 0.0;\r
+               double end = 360.0;\r
+               double step = 30.0;\r
+               for (double a1 = start;  a1 <= end; a1+= step) {\r
+                       double r1 = MathTools.degToRad(a1);\r
+                       for (double a2 = start;  a2 <= end; a2+= step) {\r
+                               double r2 = MathTools.degToRad(a2);\r
+                               for (double a3 = start;  a3 <= end; a3+= step) {\r
+                                       double r3 = MathTools.degToRad(a3);\r
+                                       \r
+                                       Quat4d q = EulerTools.getQuatFromEuler(order, r1, r2, r3);\r
+                                       Vector3d a = EulerTools.getEulerFromQuat(order, q);\r
+                                       Quat4d q2 = EulerTools.getQuatFromEuler(order, a.x,a.y,a.z);\r
+                                       a.x = MathTools.radToDeg(a.x);\r
+                                       a.y = MathTools.radToDeg(a.y);\r
+                                       a.z = MathTools.radToDeg(a.z);\r
+                                       \r
+                                       System.out.println(toString(a1) +" " + toString(a2) + " " + toString(a3) + " " + order + "\t" + toString(a) + "\t" + toString(q) + "\t" + toString(q2));\r
+                               }       \r
+                       }       \r
+               }\r
+       }\r
+       \r
+       private static String toString(double d) {\r
+               return String.format("%1$6.2f", d);\r
+       }\r
+       \r
+       private static String toString(Vector3d v) {\r
+               return "("+toString(v.x) +", "+ toString(v.y) + ", " + toString(v.z) +")";\r
+       }\r
+       \r
+       private static String toString(Quat4d v) {\r
+               return "("+toString(v.x) +", "+ toString(v.y) + ", " + toString(v.z) + ", " + toString(v.w) +")";\r
+       }\r
+       \r
+       private static void test(Order order, double deg1, double deg2, double deg3) {\r
+               double r1 = MathTools.degToRad(deg1);\r
+               double r2 = MathTools.degToRad(deg2);\r
+               double r3 = MathTools.degToRad(deg3);\r
+               \r
+               Quat4d q = EulerTools.getQuatFromEuler(order, r1, r2, r3);\r
+               Vector3d a = EulerTools.getEulerFromQuat(order, q);\r
+               Quat4d q2 = EulerTools.getQuatFromEuler(order, a.x,a.y,a.z);\r
+               a.x = MathTools.radToDeg(a.x);\r
+               a.y = MathTools.radToDeg(a.y);\r
+               a.z = MathTools.radToDeg(a.z);\r
+               System.out.println(toString(deg1) +" " + toString(deg2) + " " + toString(deg3) + " " + order + "\t" + toString(a) + "\t" + toString(q) + "\t" + toString(q2));\r
+\r
+       }\r
+}\r