]> gerrit.simantics Code Review - simantics/3d.git/blobdiff - org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/RotateAction.java
3D framework (Simca 2012)
[simantics/3d.git] / org.simantics.g3d.vtk / src / org / simantics / g3d / vtk / action / RotateAction.java
diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/RotateAction.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/RotateAction.java
new file mode 100644 (file)
index 0000000..b2752c4
--- /dev/null
@@ -0,0 +1,647 @@
+package org.simantics.g3d.vtk.action;\r
+\r
+import java.awt.Cursor;\r
+import java.awt.event.KeyEvent;\r
+import java.awt.event.MouseEvent;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Quat4d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.g3d.math.EulerTools;\r
+import org.simantics.g3d.math.MathTools;\r
+import org.simantics.g3d.math.Ray;\r
+import org.simantics.g3d.math.EulerTools.Order;\r
+import org.simantics.g3d.preferences.PreferenceConstants;\r
+import org.simantics.g3d.scenegraph.IG3DNode;\r
+import org.simantics.g3d.scenegraph.structural.IStructuralNode;\r
+import org.simantics.g3d.vtk.Activator;\r
+import org.simantics.g3d.vtk.common.InteractiveVtkPanel;\r
+import org.simantics.g3d.vtk.common.VTKNodeMap;\r
+import org.simantics.g3d.vtk.gizmo.RotateAxisGizmo;\r
+import org.simantics.g3d.vtk.utils.vtkUtil;\r
+import org.simantics.utils.threads.AWTThread;\r
+import org.simantics.utils.threads.ThreadUtils;\r
+\r
+import vtk.vtkProp;\r
+/**\r
+ * FIXME: complete rewrite.\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class RotateAction extends vtkAction{\r
+       \r
+       public static final int X = 0;\r
+    public static final int Y = 1;\r
+    public static final int Z = 2;\r
+    public static final int P = 3;\r
+\r
+       private VTKNodeMap nodeMap;\r
+       //private TranslateGizmo  gizmo = new TranslateGizmo();\r
+       private RotateAxisGizmo gizmo = new RotateAxisGizmo();\r
+       private IG3DNode node;\r
+       \r
+       \r
+       \r
+       private Cursor activeCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);\r
+       private Cursor dragCursor = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR);\r
+       \r
+       \r
+       int stepMethod = 1;\r
+       Order order = Order.YXZ;\r
+       \r
+    private int steps; \r
+    private double angles[];\r
+       \r
+       int index = P;\r
+       boolean valid = false;\r
+       private boolean worldCoord = true;\r
+       //private AxisAngle4d aa = null;\r
+       private Quat4d parentWorldOrientation = null;\r
+       \r
+       //AxisAngle4d rotation = new AxisAngle4d();\r
+       Quat4d worldOrientation = new Quat4d();\r
+       \r
+       public void setNode(IG3DNode node) {\r
+               this.node = node;\r
+               if ((node instanceof IStructuralNode) && ((IStructuralNode)node).isPartOfInstantiatedModel() && !((IStructuralNode)node).isInstantiatedModelRoot()) {\r
+                       setEnabled(false);\r
+               } else {\r
+                       setEnabled(true);\r
+               }\r
+               \r
+               String set = org.simantics.g3d.Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.ORIENTATION_PRESENTATION);\r
+               if (set.equals("aa")) {\r
+                       stepMethod = 0;\r
+               } else if (set.equals("euler")){\r
+                       stepMethod = 1;\r
+                       String eulerOrder = org.simantics.g3d.Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.EULER_ANGLE_ORDER);\r
+                       try {\r
+                               order = Order.valueOf(eulerOrder);\r
+                       } catch (Exception e) {\r
+                               order = Order.YXZ;\r
+                       }\r
+               } else {\r
+                       stepMethod = 2;\r
+               }\r
+       }\r
+       \r
+       public IG3DNode getNode() {\r
+               return node;\r
+       }\r
+       \r
+       public RotateAction(InteractiveVtkPanel panel, VTKNodeMap nodeMap) {\r
+               super(panel);\r
+               setImageDescriptor(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/arrow_rotate_clockwise.png"));\r
+               setText("Rotate");\r
+               this.nodeMap = nodeMap;\r
+               \r
+               \r
+               steps = 36;\r
+        angles = new double[steps+1];\r
+        for (int i = 0; i < angles.length; i++) {\r
+            angles[i] = - Math.PI + (Math.PI * i * 2.0 / steps);\r
+        }\r
+       }\r
+       \r
+       public void attach() {\r
+               if (node == null)\r
+                       return;\r
+               \r
+               super.attach();\r
+               ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {\r
+                       public void run() {\r
+                               attachUI();\r
+                               update();\r
+                       }\r
+               });\r
+               \r
+               \r
+               \r
+       }\r
+       \r
+       public void deattach() {\r
+               \r
+               node = null;\r
+               nodeMap.commit();\r
+               deattachUI();\r
+               super.deattach();\r
+               panel.repaint();\r
+       }\r
+       \r
+       private void attachUI() {\r
+               panel.setCursor(activeCursor);\r
+               gizmo.attach(panel.GetRenderer());\r
+       }\r
+       \r
+       private void deattachUI() {\r
+               panel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));\r
+               gizmo.deattach();\r
+       }\r
+       \r
+       @Override\r
+       public void keyPressed(KeyEvent e) {\r
+               if (e.getKeyCode() == KeyEvent.VK_ESCAPE)\r
+                       panel.useDefaultAction();\r
+               if (valid)\r
+                       return;\r
+               if (e.getKeyCode() == KeyEvent.VK_X) {\r
+                       if (index != X)\r
+                               index = X;\r
+                       else\r
+                               index = P;\r
+               }\r
+               if (e.getKeyCode() == KeyEvent.VK_Y) {\r
+                       if (index != Y)\r
+                               index = Y;\r
+                       else\r
+                               index = P;\r
+               }\r
+               if (e.getKeyCode() == KeyEvent.VK_Z) {\r
+                       if (index != Z)\r
+                               index = Z;\r
+                       else\r
+                               index = P;\r
+               }\r
+               if (e.getKeyCode() == KeyEvent.VK_G) {\r
+                       worldCoord = !worldCoord;\r
+               }\r
+               gizmo.setType(index);\r
+               panel.repaint();\r
+       }\r
+       \r
+       @Override\r
+       public void keyReleased(KeyEvent e) {\r
+               \r
+       }\r
+       \r
+       \r
+       \r
+       @Override\r
+       public void mouseClicked(MouseEvent e) {\r
+               if (e.getClickCount() > 1) {\r
+                       if (isOverNode(e)) {\r
+                               return;\r
+                       }\r
+                       panel.useDefaultAction();\r
+                       //if(!gizmo.isPartOf(actor))\r
+                       //      panel.useDefaultAction();\r
+                       \r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public void mouseEntered(MouseEvent e) {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void mouseExited(MouseEvent e) {\r
+               \r
+       }\r
+       \r
+       \r
+\r
+       \r
+       \r
+       public void setWorldCoord(boolean b) {\r
+               if (worldCoord == b)\r
+                       return;\r
+               worldCoord = b;\r
+               update();\r
+                                       \r
+       }\r
+       \r
+       \r
+       private void update() {\r
+               Vector3d nodePos = node.getWorldPosition();\r
+               System.out.println(nodePos);\r
+               gizmo.setPosition(nodePos);\r
+               if (worldCoord) {\r
+                       gizmo.setRotation(new AxisAngle4d());\r
+                       parentWorldOrientation = null;\r
+               } else {\r
+                       AxisAngle4d aa = new AxisAngle4d();\r
+                       parentWorldOrientation = ((IG3DNode)node.getParent()).getWorldOrientation();\r
+                       aa.set(parentWorldOrientation);\r
+                       gizmo.setRotation(aa);\r
+               }\r
+\r
+               Point3d camPos = new Point3d(panel.GetRenderer().GetActiveCamera().GetPosition());\r
+               Vector3d p = new Vector3d(nodePos);\r
+               p.sub(camPos);\r
+               \r
+               if (parentWorldOrientation != null) {\r
+                       Quat4d qi = new Quat4d(parentWorldOrientation);\r
+                       qi.inverse();\r
+                       MathTools.rotate(parentWorldOrientation, p, p);\r
+               }\r
+               if (panel.GetRenderer().GetActiveCamera().GetParallelProjection() == 0) {\r
+                       double distance = p.length();\r
+                       p.negate();\r
+            double fov = panel.GetRenderer().GetActiveCamera().GetViewAngle();\r
+            float s = (float) (Math.sin(fov) * distance * 0.1); \r
+\r
+            Vector3d scale = new Vector3d(1., 1., 1.);\r
+            \r
+//            if (p.x > 0.f)\r
+//                scale.x = -1.;\r
+//            if (p.y > 0.f)\r
+//                scale.y = -1.;\r
+//            if (p.z > 0.f)\r
+//                scale.z = -1.;\r
+            scale.scale(s);\r
+            gizmo.setScale(scale);\r
+                       \r
+               } else {\r
+                       Vector3d scale = new Vector3d(1.f, 1.f, 1.f);\r
+            double s = panel.GetRenderer().GetActiveCamera().GetParallelScale() / 5.;\r
+//            if (p.x > 0.f)\r
+//                scale.x = -1.;\r
+//            if (p.y > 0.f)\r
+//                scale.y = -1.;\r
+//            if (p.z > 0.f)\r
+//                scale.z = -1.;\r
+            scale.scale(s);\r
+            gizmo.setScale(scale);\r
+               }\r
+               \r
+               panel.Render();\r
+       }\r
+       \r
+       private boolean isOverNode(MouseEvent e) {\r
+               vtkProp picked[] = panel.pick(e.getX(), e.getY());\r
+               if (picked !=null) {\r
+                       for (int i = 0; i < picked.length; i++) {\r
+                               if (node.equals(nodeMap.getNode(picked[i])))\r
+                                       return true;\r
+                       }\r
+               }\r
+               return false;\r
+       }\r
+       \r
+\r
+       \r
+       @Override\r
+       public void mousePressed(MouseEvent e) {\r
+               if (e.getButton() == MouseEvent.BUTTON1) {\r
+       \r
+       \r
+                       if (isOverNode(e)) {\r
+                               valid = true;\r
+                               if ((e.getModifiers() & MouseEvent.CTRL_MASK) > 0) {\r
+                                       useStep = true;\r
+                   } else {\r
+                       useStep = false;\r
+                   }\r
+                               worldOrientation = node.getWorldOrientation();\r
+                               doChanges(true, e.getX(), e.getY());\r
+                               \r
+                               panel.setCursor(dragCursor);\r
+                       } else {\r
+                               valid = false;\r
+                               panel.getDefaultAction().mousePressed(e);\r
+                               panel.setCursor(activeCursor);\r
+                       }\r
+               } else {\r
+                       panel.getDefaultAction().mousePressed(e);\r
+               }\r
+       }\r
+       \r
+       \r
+       \r
+       @Override\r
+       public void mouseReleased(MouseEvent e) {\r
+               if (e.getButton() == MouseEvent.BUTTON1) {\r
+                       valid = false;\r
+                       worldOrientation = null;\r
+                       panel.setCursor(activeCursor);\r
+               } else {\r
+                       panel.getDefaultAction().mouseReleased(e);\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public void mouseDragged(MouseEvent e) {\r
+               if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) > 0 && valid) { \r
+                       if ((e.getModifiers() & MouseEvent.CTRL_MASK) > 0) {\r
+                               useStep = true;\r
+            } else {\r
+                useStep = false;\r
+            }\r
+                       doChanges(false, e.getX(), e.getY());\r
+                       \r
+                       //nodeMap.modified(node);\r
+                       update();\r
+               } else {\r
+                       panel.getDefaultAction().mouseDragged(e);\r
+                       update();\r
+               }\r
+       }\r
+       \r
+        Vector3d axis = null;\r
+       \r
+       @Override\r
+       public void keyTyped(KeyEvent e) {\r
+                if (e.getKeyCode() == KeyEvent.VK_LEFT) {\r
+               inputType = InputType.KEY;\r
+               axis = new Vector3d(0.0,1.0,0.0);\r
+            } else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {\r
+                       inputType = InputType.KEY;\r
+                       axis = new Vector3d(0.0,-1.0,0.0);\r
+            } else if (e.getKeyCode() ==KeyEvent.VK_UP) {\r
+                       inputType = InputType.KEY;\r
+                       axis = new Vector3d(1.0,0.0,0.0);\r
+            } else if (e.getKeyCode() == KeyEvent.VK_DOWN) {\r
+                       inputType = InputType.KEY;\r
+                       axis = new Vector3d(-1.0,0.0,0.0);\r
+            } \r
+       }\r
+       \r
+    public void doChanges(boolean pressed, int x, int y) {\r
+       Ray ray = vtkUtil.createMouseRay(panel.GetRenderer(),x, y);\r
+       Vector3d p = node.getWorldPosition();\r
+        \r
+       if (pressed) {\r
+            Vector3d axis = getRotationAxis();\r
+            if (axis != null) {\r
+               if (!worldCoord) {\r
+                       MathTools.rotate(parentWorldOrientation, axis, axis);\r
+               }\r
+\r
+               \r
+                double s[] = new double[2];\r
+                Vector3d i2 = new Vector3d();\r
+               \r
+                boolean intersect = MathTools.intersectStraightPlane(ray.pos, ray.dir, p, axis, i2, s);\r
+                double dot = Math.abs(ray.dir.dot(axis));\r
+                if (intersect &&  dot > 0.4)\r
+                       inputType = InputType.INTERSECT;\r
+                else\r
+                       inputType = InputType.NONINTERSECT;\r
+                       \r
+                \r
+                if (inputType == InputType.INTERSECT) {\r
+                    // picking ray and plane defined by gizmo's center point and\r
+                    // rotation axis can intersect\r
+                    // vector from center point to intersection point\r
+                    i2.sub(p);\r
+                    // creating vectors i and j that are lying on the plane and\r
+                    // are perpendicular\r
+                    // vectors are used to calculate polar coordinate for\r
+                    // intersection point\r
+                    j.set(i2);\r
+                    i.cross(j, axis);\r
+                    System.out.println("I,J " + i + " " + j);\r
+                    double angleI = i2.angle(i);\r
+                    double angleJ = i2.angle(j);\r
+                    prevAngle = Math.atan2(Math.cos(angleJ), Math.cos(angleI));\r
+                } else {\r
+                    // picking ray and plane defined by gizmo's center point and\r
+                    // rotation axis are parallel,\r
+                    // so we'll use cross product of rotation axis and picking\r
+                    // ray to detect amount of rotation\r
+                    i.cross(ray.dir, axis);\r
+                    MathTools.intersectStraightStraight(ray.pos, ray.dir, p, i, new Vector3d(), new Vector3d(), s);\r
+                    prevS = s[1];\r
+                }\r
+            }\r
+           \r
+            \r
+        }\r
+\r
+        if (inputType != InputType.KEY)\r
+               axis = getRotationAxis();\r
+        if (axis == null) {\r
+            return;   \r
+        }\r
+        Vector3d taxis = null;\r
+        if (!worldCoord) {\r
+               taxis = new Vector3d(axis);\r
+               MathTools.rotate(parentWorldOrientation, axis, axis);\r
+       }\r
+        System.out.println(inputType);\r
+        if (inputType == InputType.INTERSECT) {\r
+\r
+            double s[] = new double[2];\r
+            Vector3d i2 = new Vector3d();\r
+            MathTools.intersectStraightPlane(ray.pos, ray.dir, p, axis, i2, s);\r
+            i2.sub(p);\r
+            double angleI = i2.angle(i);\r
+            double angleJ = i2.angle(j);\r
+            double angle = Math.atan2(Math.cos(angleJ), Math.cos(angleI));\r
+            System.out.println("Angle " + angle + " i " + angleI + " j " + angleJ + " prev " + prevAngle);\r
+            if(!worldCoord)\r
+               axis = taxis;\r
+            if (useStep) {\r
+\r
+               //setOrientation(MathTools.getQuat(rotation));\r
+               AxisAngle4d rot = new AxisAngle4d(axis,angle-prevAngle);\r
+               Quat4d qrot = new Quat4d();\r
+               MathTools.getQuat(rot, qrot);\r
+               //prevAngle = angle;\r
+               qrot.mulInverse(worldOrientation);\r
+               \r
+          \r
+               if (stepMethod == 0) {\r
+                       rot.set(qrot);\r
+                       rot.angle = roundAngle(rot.angle);\r
+                       //qrot.set(rot);\r
+                       MathTools.getQuat(rot,qrot);\r
+                       setOrientation(qrot);\r
+               } else if (stepMethod == 1){\r
+                         \r
+                       //Vector3d euler = MathTools.getEuler(qrot);\r
+                       Vector3d euler = EulerTools.getEulerFromQuat(order, qrot);\r
+                       euler.x = roundAngle(euler.x);\r
+                       euler.y = roundAngle(euler.y);\r
+                       euler.z = roundAngle(euler.z);\r
+                       //Quat4d q = MathTools.getQuat(euler);\r
+                       Quat4d q = EulerTools.getQuatFromEuler(order, euler);\r
+                       setOrientation(q);\r
+                       System.out.println(" (" + MathTools.radToDeg(euler.x) + " " + MathTools.radToDeg(euler.y) + " " + MathTools.radToDeg(euler.z) +  ") " + qrot + " "+ q);\r
+               } else {\r
+                       setOrientation(qrot);\r
+               }\r
+               \r
+            } else {\r
+                if (worldCoord) {\r
+                       //G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,angle-prevAngle));\r
+                       AxisAngle4d aa = MathTools.getAxisAngle(node.getWorldOrientation());\r
+                       AxisAngle4d rot = new AxisAngle4d(axis,angle-prevAngle);\r
+                       MathTools.multiplyOrientation(aa, rot);\r
+                       setWorldOrientation(MathTools.getQuat(rot));\r
+                } else {\r
+                       AxisAngle4d aa = MathTools.getAxisAngle(node.getOrientation());\r
+                       AxisAngle4d rot = new AxisAngle4d(axis,angle-prevAngle);\r
+                       MathTools.multiplyOrientation(aa, rot);\r
+                       setOrientation(MathTools.getQuat(rot));\r
+                       //G3DTools.multiplyOrientation(mo.getG3DNode(graph).getLocalOrientation(), new AxisAngle4d(axis,angle-prevAngle));\r
+                }\r
+                prevAngle = angle;\r
+            }\r
+            \r
+        } else if (inputType == InputType.NONINTERSECT){\r
+\r
+            double s[] = new double[2];\r
+            MathTools.intersectStraightStraight(ray.pos, ray.dir, p, i, new Vector3d(), new Vector3d(), s);\r
+            if(!worldCoord)\r
+               axis = taxis;\r
+            if (useStep) {\r
+               //setOrientation(MathTools.getQuat(rotation));\r
+               AxisAngle4d rot = new AxisAngle4d(axis,s[1] - prevS);\r
+                \r
+               Quat4d qrot = new Quat4d();\r
+               //qrot.set(rot);\r
+               MathTools.getQuat(rot, qrot);\r
+               //prevAngle = angle;\r
+               qrot.mulInverse(worldOrientation);\r
+               \r
+          \r
+               if (stepMethod == 0) {\r
+                       rot.set(qrot);\r
+                       rot.angle = roundAngle(rot.angle);\r
+                       //qrot.set(rot);\r
+                       MathTools.getQuat(rot,qrot);\r
+                       setOrientation(qrot);\r
+               } else if (stepMethod == 1){\r
+                         \r
+                       //Vector3d euler = MathTools.getEuler(qrot);\r
+                       Vector3d euler = EulerTools.getEulerFromQuat(order, qrot);\r
+                       euler.x = roundAngle(euler.x);\r
+                       euler.y = roundAngle(euler.y);\r
+                       euler.z = roundAngle(euler.z);\r
+                       //Quat4d q = MathTools.getQuat(euler);\r
+                       Quat4d q = EulerTools.getQuatFromEuler(order, euler);\r
+                       setOrientation(q);\r
+                       System.out.println(" (" + MathTools.radToDeg(euler.x) + " " + MathTools.radToDeg(euler.y) + " " + MathTools.radToDeg(euler.z) +  ") " + qrot + " "+ q);\r
+               } else {\r
+                       setOrientation(qrot);\r
+               }\r
+                prevS = s[1];\r
+               \r
+//                    G3DTools.setOrientation(mo.getG3DNode(graph).getLocalOrientation(), rotations.get(mo));\r
+//                    G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,s[1] - prevS));\r
+//                    AxisAngle4d aa = G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation());\r
+//                    rotations.put(mo, aa);\r
+//                    Vector3d euler = MathTools.getEuler(aa);\r
+//                    euler.x = roundAngle(euler.x);\r
+//                    euler.y = roundAngle(euler.y);\r
+//                    euler.z = roundAngle(euler.z);\r
+//                    aa = MathTools.getFromEuler2(euler);\r
+//                    prevS = s[1];\r
+//                    G3DTools.setOrientation(mo.getG3DNode(graph).getLocalOrientation(), aa);\r
+//                    Vector3d e = MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()));\r
+//                    e.scale(180.0/Math.PI);\r
+//                    text += G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()) + " " + e + " ";\r
+               \r
+               \r
+            } else {\r
+                       if (worldCoord) {\r
+                               AxisAngle4d aa =  MathTools.getAxisAngle(node.getWorldOrientation());\r
+                       AxisAngle4d rot = new AxisAngle4d(axis,s[1] - prevS);\r
+                       MathTools.multiplyOrientation(aa, rot);\r
+                       setWorldOrientation(MathTools.getQuat(rot));\r
+                               //G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,s[1] - prevS));\r
+                       } else {\r
+                               AxisAngle4d aa =  MathTools.getAxisAngle(node.getOrientation());\r
+                       AxisAngle4d rot = new AxisAngle4d(axis,s[1] - prevS);\r
+                       MathTools.multiplyOrientation(aa, rot);\r
+                       setOrientation(MathTools.getQuat(rot));\r
+                               //G3DTools.multiplyOrientation(mo.getG3DNode(graph).getLocalOrientation(), new AxisAngle4d(axis,s[1] - prevS));\r
+                       }\r
+                       //text += G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()) + " " + MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation())) + " ";\r
+                prevS = s[1];\r
+                \r
+            }\r
+           \r
+        } else {\r
+               if (worldCoord) {\r
+                       AxisAngle4d aa = MathTools.getAxisAngle(node.getWorldOrientation());\r
+               AxisAngle4d rot = new AxisAngle4d(axis,Math.PI * 0.5);\r
+               MathTools.multiplyOrientation(aa, rot);\r
+               setWorldOrientation(MathTools.getQuat(rot));\r
+                       //G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,Math.PI * 0.5));\r
+               } else {\r
+                       AxisAngle4d aa = MathTools.getAxisAngle(node.getOrientation());\r
+               AxisAngle4d rot = new AxisAngle4d(axis,Math.PI * 0.5);\r
+               MathTools.multiplyOrientation(aa, rot);\r
+               setOrientation(MathTools.getQuat(rot));\r
+                       //G3DTools.multiplyOrientation(mo.getG3DNode(graph).getLocalOrientation(), new AxisAngle4d(axis,Math.PI * 0.5));\r
+               }\r
+             //   text += G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()) + " " + MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation())) + " ";\r
+            \r
+        }\r
+        //setInfoText(text);\r
\r
+    }\r
+    \r
+    protected void setOrientation(Quat4d q) {\r
+       node.setOrientation(q);\r
+    }\r
+    \r
+    protected void setWorldOrientation(Quat4d q) {\r
+       node.setWorldOrientation(q);\r
+    }\r
+       \r
+       @Override\r
+       public void mouseMoved(MouseEvent e) {\r
+               panel.getDefaultAction().mouseMoved(e);\r
+       }\r
+       \r
+       private Vector3d getRotationAxis() {\r
+               switch (index) {\r
+               case X:\r
+                       return new Vector3d(1.0, 0.0, 0.0);\r
+               case Y:\r
+                       return new Vector3d(0.0, 1.0, 0.0);\r
+               case Z:\r
+                       return new Vector3d(0.0, 0.0, 1.0);\r
+               case P:\r
+                       Vector3d axis = new Vector3d(panel.GetRenderer().GetActiveCamera()\r
+                                       .GetDirectionOfProjection());\r
+                       axis.normalize();\r
+                       return axis;\r
+               default:\r
+                       return null;\r
+               }\r
+       }\r
+       \r
+        private double prevS = 0.0;\r
+           \r
+    private Vector3d i = new Vector3d();\r
+    private Vector3d j = new Vector3d();\r
+    private double prevAngle = 0;\r
+\r
+    enum InputType{INTERSECT,NONINTERSECT,KEY,NONE};\r
+    InputType inputType;\r
+    private boolean useStep = false;\r
+    \r
+    \r
+    \r
+    private double roundAngle(double angle) {\r
+        while (angle < - Math.PI)\r
+            angle += Math.PI*2.0;\r
+        while (angle > Math.PI)\r
+            angle -= Math.PI*2.0;\r
+        \r
+        \r
+        int index = 0;\r
+        while (angle > angles[index])\r
+            index++;\r
+        if (index == 0) {\r
+            angle = angles[0];\r
+        } else {\r
+            double d = angle - angles[index - 1];\r
+            double d2 = angles[index] - angle;\r
+            if (d < d2)\r
+                angle = angles[index - 1];\r
+            else\r
+                angle = angles[index];\r
+        }\r
+        return angle;\r
+    }\r
+       \r
+}\r