]> gerrit.simantics Code Review - simantics/3d.git/blobdiff - org.simantics.g3d/src/org/simantics/proconf/g3d/actions/RotateAction.java
git-svn-id: https://www.simantics.org/svn/simantics/3d/trunk@22280 ac1ea38d-2e2b...
[simantics/3d.git] / org.simantics.g3d / src / org / simantics / proconf / g3d / actions / RotateAction.java
diff --git a/org.simantics.g3d/src/org/simantics/proconf/g3d/actions/RotateAction.java b/org.simantics.g3d/src/org/simantics/proconf/g3d/actions/RotateAction.java
new file mode 100644 (file)
index 0000000..2526ee2
--- /dev/null
@@ -0,0 +1,453 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007- VTT Technical Research Centre of Finland.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.proconf.g3d.actions;\r
+\r
+import java.awt.event.KeyEvent;\r
+import java.awt.event.MouseEvent;\r
+import java.util.Collection;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.AxisAngle4f;\r
+import javax.vecmath.Quat4d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.eclipse.jface.action.Action;\r
+import org.eclipse.jface.action.IToolBarManager;\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.GraphRequest;\r
+import org.simantics.db.GraphRequestAdapter;\r
+import org.simantics.db.GraphRequestStatus;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.Resource;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.proconf.g3d.Activator;\r
+import org.simantics.proconf.g3d.Resources;\r
+import org.simantics.proconf.g3d.base.G3DTools;\r
+import org.simantics.proconf.g3d.base.JmeRenderingComponent;\r
+import org.simantics.proconf.g3d.base.MathTools;\r
+import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;\r
+import org.simantics.proconf.g3d.base.VecmathJmeTools;\r
+import org.simantics.proconf.g3d.common.OrbitalCamera;\r
+import org.simantics.proconf.g3d.gizmo.RotateGizmo;\r
+import org.simantics.proconf.g3d.scenegraph.IGraphicsNode;\r
+import org.simantics.proconf.g3d.stubs.G3DNode;\r
+\r
+public class RotateAction extends WriteInteractiveAction {\r
+       \r
+       private JmeRenderingComponent component;\r
+       \r
+    private RotateGizmo gizmo;\r
+\r
+    private OrbitalCamera camera;\r
+    \r
+    private Map<IGraphicsNode, AxisAngle4d > rotations = new HashMap<IGraphicsNode, AxisAngle4d>();\r
+    \r
+    private int steps; \r
+    private double angles[];\r
+    \r
+    private Action csAction;\r
+    private boolean worldCoord = true;\r
+    private IToolBarManager manager;\r
+    \r
+    private List<IGraphicsNode> mos;\r
+    AxisAngle4d aa;\r
+    Quat4d q;\r
+    \r
+    public RotateAction(ThreeDimensionalEditorBase parent) {\r
+        super(parent,true);\r
+        component = parent.getRenderingComponent();\r
+        camera = parent.getCamera();\r
+        gizmo = new RotateGizmo(component.getDisplaySystem().getRenderer());\r
+        csAction = new Action("World",Action.AS_CHECK_BOX) {\r
+               public void run() {\r
+                       GraphRequest r = new GraphRequestAdapter() {\r
+                               @Override\r
+                               public GraphRequestStatus perform(Graph g) throws Exception {\r
+                                       setWorldCoord(g,!isChecked());\r
+                                       return GraphRequestStatus.transactionComplete();\r
+                               }\r
+                       };\r
+                       RotateAction.this.parent.getSession().asyncRead(r);\r
+                       \r
+               }\r
+        };\r
+    }\r
+    \r
+    public void init() {\r
+        this.setText("Rotate");\r
+        this.setToolTipText("Rotate the object");\r
+        this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/rotate.png"));\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
+    @Override\r
+    public boolean usable(Graph graph, List<Resource> resources) {\r
+        if (resources.size() == 0)\r
+            return false;\r
+        for (Resource r : resources) {\r
+               IEntity t = EntityFactory.create(graph,r);\r
+            if (t.isInstanceOf(Resources.g3dResource.G3DNode)) {\r
+                Collection<IEntity> p = t.getRelatedObjects(Resources.g3dResource.HasLocalOrientation);\r
+                if (p == null || p.size() != 1)\r
+                    return false;\r
+            }\r
+               \r
+        }\r
+        return true;\r
+        \r
+    }\r
+    \r
+    @Override\r
+    public void deactivate() {\r
+       inputType = InputType.NONE;\r
+        parent.setGizmo(null);\r
+        mos = null;\r
+\r
+    }\r
+    \r
+    public void fillToolBar(IToolBarManager manager) {\r
+       super.fillToolBar(manager);\r
+       this.manager = manager;\r
+        csAction.setChecked(!worldCoord);\r
+        manager.add(csAction);\r
+        \r
+    }\r
+    \r
+    private void setWorldCoord(Graph graph,boolean b) {\r
+       if (worldCoord == b)\r
+               return;\r
+       worldCoord = b;\r
+       updateWorldCoord(graph);\r
+    }\r
+    \r
+    private void updateWorldCoord(Graph graph) {\r
+       if (worldCoord) {\r
+                       csAction.setText("World");\r
+                       gizmo.setRotation(new AxisAngle4f());\r
+                       aa = null;\r
+                       q = null;\r
+       } else {\r
+                       csAction.setText("Local");\r
+                       aa = G3DTools.getOrientation(mos.get(0).getParent().getG3DNode(graph).getWorldOrientation());\r
+                       if (aa == null)\r
+                               aa = new AxisAngle4d();\r
+                       gizmo.setRotation(new AxisAngle4f(aa));\r
+                       q = new Quat4d();\r
+               q.set(aa);\r
+       }\r
+       if (manager != null)\r
+               manager.update(true);\r
+       this.parent.setViewChanged(true);\r
+    }\r
+    \r
+    @Override\r
+    public void activate() {\r
+       \r
+       Session session = parent.getSession();\r
+       \r
+       GraphRequest r = new GraphRequestAdapter() {\r
+               @Override\r
+               public GraphRequestStatus perform(Graph g) throws Exception {\r
+                       parent.setGizmo(gizmo);\r
+               \r
+               component.getNoShadowRoot().attachChild(gizmo.getNode());\r
+               updateGizmo();\r
+\r
+               String text = "";\r
+               mos = parent.getSelectionAdapter().getSelectedObjects();\r
+               rotations = new HashMap<IGraphicsNode, AxisAngle4d>();\r
+               for (IGraphicsNode mo : mos) {\r
+                       G3DNode n = mo.getG3DNode(g);\r
+                   rotations.put(mo,G3DTools.getOrientation(n.getLocalOrientation()));\r
+                   text += G3DTools.getOrientation(n.getLocalOrientation()) + " " + MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(g).getLocalOrientation())) + " ";\r
+               }\r
+               setInfoText(text);\r
+               parent.setViewChanged(true);\r
+               inputType = InputType.NONE;\r
+               return GraphRequestStatus.transactionComplete();\r
+               }\r
+       };\r
+       \r
+       session.syncRead(r);\r
+       \r
+        \r
+    }\r
+    \r
+    \r
+    private Vector3d getRotationAxis() {\r
+        switch (gizmo.getSelected()) {\r
+        case RotateGizmo.X:\r
+            return new Vector3d(1.0,0.0,0.0);\r
+        case RotateGizmo.Y:\r
+            return new Vector3d(0.0,1.0,0.0);\r
+        case RotateGizmo.Z:\r
+            return new Vector3d(0.0,0.0,1.0);\r
+        case RotateGizmo.XYZ:\r
+            Vector3d axis = camera.getUnNormalizedHeading();\r
+            axis.normalize();\r
+            return axis;\r
+        default:\r
+            return null;\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
+    @Override\r
+    public void doChanges(Graph graph) throws Exception {\r
+       \r
+        if (input.mousePressed()) {\r
+            Vector3d axis = getRotationAxis();\r
+            if (axis != null) {\r
+               if (!worldCoord) {\r
+                       MathTools.rotate(q, axis, axis);\r
+               }\r
+                Vector3d o = new Vector3d();\r
+                Vector3d d = new Vector3d();\r
+                parent.createPickRay(o, d);\r
+                Vector3d p = gizmo.getPosition();\r
+                double s[] = new double[2];\r
+                Vector3d i2 = new Vector3d();\r
+                if ((input.pressModifiers() & MouseEvent.CTRL_MASK) > 0) {\r
+                    useStep = true;\r
+                } else {\r
+                    useStep = false;\r
+                }\r
+                if (MathTools.intersectStraightPlane(o, d, p, axis, i2, s) && Math.abs(d.dot(axis)) > 0.2)\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
+                    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(d, axis);\r
+                    MathTools.intersectStraightStraight(o, d, p, i, new Vector3d(), new Vector3d(), s);\r
+                    prevS = s[1];\r
+                }\r
+            }\r
+           \r
+            \r
+        }\r
+        if (input.mouseClicked()) {\r
+            end();\r
+            return;\r
+        }\r
+        Vector3d axis = null;\r
+        if (input.keyPressed(KeyEvent.VK_LEFT)) {\r
+               inputType = InputType.KEY;\r
+               axis = new Vector3d(0.0,1.0,0.0);\r
+        } else if (input.keyPressed(KeyEvent.VK_RIGHT)) {\r
+               inputType = InputType.KEY;\r
+               axis = new Vector3d(0.0,-1.0,0.0);\r
+        } else if (input.keyPressed(KeyEvent.VK_UP)) {\r
+               inputType = InputType.KEY;\r
+               axis = new Vector3d(1.0,0.0,0.0);\r
+        } else if (input.keyPressed(KeyEvent.VK_DOWN)) {\r
+               inputType = InputType.KEY;\r
+               axis = new Vector3d(-1.0,0.0,0.0);\r
+        } else if (!input.mouseDragged()) {\r
+            parent.getDefaultAction().update();\r
+            return;\r
+        }\r
+        parent.setViewChanged(true);\r
+        \r
+        \r
+        updateGizmo();\r
+        List<IGraphicsNode> mos = parent.getSelectionAdapter().getSelectedObjects();\r
+        if (inputType != InputType.KEY)\r
+               axis = getRotationAxis();\r
+        if (axis == null) {\r
+            parent.getDefaultAction().update();\r
+            return;   \r
+        }\r
+        Vector3d taxis = null;\r
+        if (!worldCoord) {\r
+               taxis = new Vector3d(axis);\r
+               MathTools.rotate(q, axis, axis);\r
+       }\r
+        String text = "";\r
+        if (inputType == InputType.INTERSECT) {\r
+            Vector3d o = new Vector3d();\r
+            Vector3d d = new Vector3d();\r
+            parent.createPickRay(o, d);\r
+            Vector3d p = gizmo.getPosition();\r
+            double s[] = new double[2];\r
+            Vector3d i2 = new Vector3d();\r
+            MathTools.intersectStraightPlane(o, d, 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
+            if(!worldCoord)\r
+               axis = taxis;\r
+            if (false && useStep) {\r
+                for (IGraphicsNode mo : mos) {\r
+                    G3DTools.setOrientation(mo.getG3DNode(graph).getLocalOrientation(), rotations.get(mo));\r
+                    // FIXME : commit\r
+                    G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,angle-prevAngle));\r
+                    //mo.setRotation(rotations.get(mo));\r
+                    //mo.modifyWorldRotation(axis, angle - prevAngle);\r
+                    AxisAngle4d aa = G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation());\r
+                    rotations.put(mo, aa);\r
+                    prevAngle = angle;\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
+                    G3DTools.setOrientation(mo.getG3DNode(graph).getLocalOrientation(), aa);\r
+                    //mo.setRotation(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
+            } else  {\r
+                for (IGraphicsNode mo : mos) {\r
+                    if (worldCoord)\r
+                               G3DTools.multiplyOrientation\r
+                               (mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,angle-prevAngle));\r
+                       else\r
+                               G3DTools.multiplyOrientation(mo.getG3DNode(graph).getLocalOrientation(), new AxisAngle4d(axis,angle-prevAngle));\r
+                       text += G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()) + " " + MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation())) + " ";\r
+                }\r
+                prevAngle = angle;\r
+            }\r
+            \r
+        } else if (inputType == InputType.NONINTERSECT){\r
+            Vector3d o = new Vector3d();\r
+            Vector3d d = new Vector3d();\r
+            parent.createPickRay(o, d);\r
+            Vector3d p = gizmo.getPosition();\r
+            double s[] = new double[2];\r
+            MathTools.intersectStraightStraight(o, d, p, i, new Vector3d(), new Vector3d(), s);\r
+            if(!worldCoord)\r
+               axis = taxis;\r
+            if (false && useStep) {\r
+                for (IGraphicsNode mo : mos) {\r
+                    G3DTools.setOrientation(mo.getG3DNode(graph).getLocalOrientation(), rotations.get(mo));\r
+                    G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,s[1] - prevS));\r
+                    //mo.setRotation(rotations.get(mo));\r
+                    //mo.modifyWorldRotation(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
+                    //mo.setRotation(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
+            } else {\r
+                for (IGraphicsNode mo : mos) {\r
+                       if (worldCoord)\r
+                               G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,s[1] - prevS));\r
+                       else\r
+                               G3DTools.multiplyOrientation(mo.getG3DNode(graph).getLocalOrientation(), new AxisAngle4d(axis,s[1] - prevS));\r
+                    text += G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()) + " " + MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation())) + " ";\r
+                }\r
+                prevS = s[1];\r
+                \r
+            }\r
+           \r
+        } else {\r
+               for (IGraphicsNode mo : mos) {\r
+               if (worldCoord)\r
+                       G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,Math.PI * 0.5));\r
+               else\r
+                       G3DTools.multiplyOrientation(mo.getG3DNode(graph).getLocalOrientation(), new AxisAngle4d(axis,Math.PI * 0.5));\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
+    private double roundAngle(double current, double modify) {\r
+        double angle = roundAngle(current+modify);\r
+        if (Double.isNaN(angle)) {\r
+            angle = current+modify;\r
+        }\r
+        //System.out.println(angle + " " + (current+modify));\r
+        return angle;\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
+    private void updateGizmo() {\r
+        List<IGraphicsNode> mos = parent.getSelectionAdapter().getSelectedObjects();\r
+        //gizmo.update(XithTools.getPosition(mos.get(0).getGroup()),camera.getCameraPos(),component);\r
+        gizmo.update(VecmathJmeTools.getD(mos.get(0).getGroup().getWorldTranslation()),camera.getCameraPos(),component);\r
+    }\r
+    \r
+    public void setInfoText(String text) {\r
+       \r
+    }\r
+}
\ No newline at end of file