X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=org.simantics.g3d%2Fsrc%2Forg%2Fsimantics%2Fproconf%2Fg3d%2Factions%2FRotateAction.java;fp=org.simantics.g3d%2Fsrc%2Forg%2Fsimantics%2Fproconf%2Fg3d%2Factions%2FRotateAction.java;h=2526ee23fb7b086b0f0ec176d547dc1f321d9c88;hb=10f144a2bb2d7bec98b812b83acecb333fd098ea;hp=0000000000000000000000000000000000000000;hpb=3055b543aa5afc0cca4bb3b341704e7c5103fa6a;p=simantics%2F3d.git 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 index 00000000..2526ee23 --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/proconf/g3d/actions/RotateAction.java @@ -0,0 +1,453 @@ +/******************************************************************************* + * Copyright (c) 2007- VTT Technical Research Centre of Finland. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.actions; + +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.vecmath.AxisAngle4d; +import javax.vecmath.AxisAngle4f; +import javax.vecmath.Quat4d; +import javax.vecmath.Vector3d; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IToolBarManager; +import org.simantics.db.Graph; +import org.simantics.db.GraphRequest; +import org.simantics.db.GraphRequestAdapter; +import org.simantics.db.GraphRequestStatus; +import org.simantics.db.Session; +import org.simantics.db.Resource; +import org.simantics.layer0.utils.IEntity; +import org.simantics.layer0.utils.EntityFactory; +import org.simantics.proconf.g3d.Activator; +import org.simantics.proconf.g3d.Resources; +import org.simantics.proconf.g3d.base.G3DTools; +import org.simantics.proconf.g3d.base.JmeRenderingComponent; +import org.simantics.proconf.g3d.base.MathTools; +import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase; +import org.simantics.proconf.g3d.base.VecmathJmeTools; +import org.simantics.proconf.g3d.common.OrbitalCamera; +import org.simantics.proconf.g3d.gizmo.RotateGizmo; +import org.simantics.proconf.g3d.scenegraph.IGraphicsNode; +import org.simantics.proconf.g3d.stubs.G3DNode; + +public class RotateAction extends WriteInteractiveAction { + + private JmeRenderingComponent component; + + private RotateGizmo gizmo; + + private OrbitalCamera camera; + + private Map rotations = new HashMap(); + + private int steps; + private double angles[]; + + private Action csAction; + private boolean worldCoord = true; + private IToolBarManager manager; + + private List mos; + AxisAngle4d aa; + Quat4d q; + + public RotateAction(ThreeDimensionalEditorBase parent) { + super(parent,true); + component = parent.getRenderingComponent(); + camera = parent.getCamera(); + gizmo = new RotateGizmo(component.getDisplaySystem().getRenderer()); + csAction = new Action("World",Action.AS_CHECK_BOX) { + public void run() { + GraphRequest r = new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + setWorldCoord(g,!isChecked()); + return GraphRequestStatus.transactionComplete(); + } + }; + RotateAction.this.parent.getSession().asyncRead(r); + + } + }; + } + + public void init() { + this.setText("Rotate"); + this.setToolTipText("Rotate the object"); + this.setImageDescriptor(Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/rotate.png")); + steps = 36; + angles = new double[steps+1]; + for (int i = 0; i < angles.length; i++) { + angles[i] = - Math.PI + (Math.PI * i * 2.0 / steps); + } + } + + @Override + public boolean usable(Graph graph, List resources) { + if (resources.size() == 0) + return false; + for (Resource r : resources) { + IEntity t = EntityFactory.create(graph,r); + if (t.isInstanceOf(Resources.g3dResource.G3DNode)) { + Collection p = t.getRelatedObjects(Resources.g3dResource.HasLocalOrientation); + if (p == null || p.size() != 1) + return false; + } + + } + return true; + + } + + @Override + public void deactivate() { + inputType = InputType.NONE; + parent.setGizmo(null); + mos = null; + + } + + public void fillToolBar(IToolBarManager manager) { + super.fillToolBar(manager); + this.manager = manager; + csAction.setChecked(!worldCoord); + manager.add(csAction); + + } + + private void setWorldCoord(Graph graph,boolean b) { + if (worldCoord == b) + return; + worldCoord = b; + updateWorldCoord(graph); + } + + private void updateWorldCoord(Graph graph) { + if (worldCoord) { + csAction.setText("World"); + gizmo.setRotation(new AxisAngle4f()); + aa = null; + q = null; + } else { + csAction.setText("Local"); + aa = G3DTools.getOrientation(mos.get(0).getParent().getG3DNode(graph).getWorldOrientation()); + if (aa == null) + aa = new AxisAngle4d(); + gizmo.setRotation(new AxisAngle4f(aa)); + q = new Quat4d(); + q.set(aa); + } + if (manager != null) + manager.update(true); + this.parent.setViewChanged(true); + } + + @Override + public void activate() { + + Session session = parent.getSession(); + + GraphRequest r = new GraphRequestAdapter() { + @Override + public GraphRequestStatus perform(Graph g) throws Exception { + parent.setGizmo(gizmo); + + component.getNoShadowRoot().attachChild(gizmo.getNode()); + updateGizmo(); + + String text = ""; + mos = parent.getSelectionAdapter().getSelectedObjects(); + rotations = new HashMap(); + for (IGraphicsNode mo : mos) { + G3DNode n = mo.getG3DNode(g); + rotations.put(mo,G3DTools.getOrientation(n.getLocalOrientation())); + text += G3DTools.getOrientation(n.getLocalOrientation()) + " " + MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(g).getLocalOrientation())) + " "; + } + setInfoText(text); + parent.setViewChanged(true); + inputType = InputType.NONE; + return GraphRequestStatus.transactionComplete(); + } + }; + + session.syncRead(r); + + + } + + + private Vector3d getRotationAxis() { + switch (gizmo.getSelected()) { + case RotateGizmo.X: + return new Vector3d(1.0,0.0,0.0); + case RotateGizmo.Y: + return new Vector3d(0.0,1.0,0.0); + case RotateGizmo.Z: + return new Vector3d(0.0,0.0,1.0); + case RotateGizmo.XYZ: + Vector3d axis = camera.getUnNormalizedHeading(); + axis.normalize(); + return axis; + default: + return null; + } + } + private double prevS = 0.0; + + private Vector3d i = new Vector3d(); + private Vector3d j = new Vector3d(); + private double prevAngle = 0; + + enum InputType{INTERSECT,NONINTERSECT,KEY,NONE}; + InputType inputType; + private boolean useStep = false; + + @Override + public void doChanges(Graph graph) throws Exception { + + if (input.mousePressed()) { + Vector3d axis = getRotationAxis(); + if (axis != null) { + if (!worldCoord) { + MathTools.rotate(q, axis, axis); + } + Vector3d o = new Vector3d(); + Vector3d d = new Vector3d(); + parent.createPickRay(o, d); + Vector3d p = gizmo.getPosition(); + double s[] = new double[2]; + Vector3d i2 = new Vector3d(); + if ((input.pressModifiers() & MouseEvent.CTRL_MASK) > 0) { + useStep = true; + } else { + useStep = false; + } + if (MathTools.intersectStraightPlane(o, d, p, axis, i2, s) && Math.abs(d.dot(axis)) > 0.2) + inputType = InputType.INTERSECT; + else + inputType = InputType.NONINTERSECT; + + + if (inputType == InputType.INTERSECT) { + // picking ray and plane defined by gizmo's center point and + // rotation axis can intersect + // vector from center point to intersection point + i2.sub(p); + // creating vectors i and j that are lying on the plane and + // are perpendicular + // vectors are used to calculate polar coordinate for + // intersection point + j.set(i2); + i.cross(j, axis); + double angleI = i2.angle(i); + double angleJ = i2.angle(j); + prevAngle = Math.atan2(Math.cos(angleJ), Math.cos(angleI)); + } else { + // picking ray and plane defined by gizmo's center point and + // rotation axis are parallel, + // so we'll use cross product of rotation axis and picking + // ray to detect amount of rotation + i.cross(d, axis); + MathTools.intersectStraightStraight(o, d, p, i, new Vector3d(), new Vector3d(), s); + prevS = s[1]; + } + } + + + } + if (input.mouseClicked()) { + end(); + return; + } + Vector3d axis = null; + if (input.keyPressed(KeyEvent.VK_LEFT)) { + inputType = InputType.KEY; + axis = new Vector3d(0.0,1.0,0.0); + } else if (input.keyPressed(KeyEvent.VK_RIGHT)) { + inputType = InputType.KEY; + axis = new Vector3d(0.0,-1.0,0.0); + } else if (input.keyPressed(KeyEvent.VK_UP)) { + inputType = InputType.KEY; + axis = new Vector3d(1.0,0.0,0.0); + } else if (input.keyPressed(KeyEvent.VK_DOWN)) { + inputType = InputType.KEY; + axis = new Vector3d(-1.0,0.0,0.0); + } else if (!input.mouseDragged()) { + parent.getDefaultAction().update(); + return; + } + parent.setViewChanged(true); + + + updateGizmo(); + List mos = parent.getSelectionAdapter().getSelectedObjects(); + if (inputType != InputType.KEY) + axis = getRotationAxis(); + if (axis == null) { + parent.getDefaultAction().update(); + return; + } + Vector3d taxis = null; + if (!worldCoord) { + taxis = new Vector3d(axis); + MathTools.rotate(q, axis, axis); + } + String text = ""; + if (inputType == InputType.INTERSECT) { + Vector3d o = new Vector3d(); + Vector3d d = new Vector3d(); + parent.createPickRay(o, d); + Vector3d p = gizmo.getPosition(); + double s[] = new double[2]; + Vector3d i2 = new Vector3d(); + MathTools.intersectStraightPlane(o, d, p, axis, i2, s); + i2.sub(p); + double angleI = i2.angle(i); + double angleJ = i2.angle(j); + double angle = Math.atan2(Math.cos(angleJ), Math.cos(angleI)); + if(!worldCoord) + axis = taxis; + if (false && useStep) { + for (IGraphicsNode mo : mos) { + G3DTools.setOrientation(mo.getG3DNode(graph).getLocalOrientation(), rotations.get(mo)); + // FIXME : commit + G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,angle-prevAngle)); + //mo.setRotation(rotations.get(mo)); + //mo.modifyWorldRotation(axis, angle - prevAngle); + AxisAngle4d aa = G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()); + rotations.put(mo, aa); + prevAngle = angle; + Vector3d euler = MathTools.getEuler(aa); + euler.x = roundAngle(euler.x); + euler.y = roundAngle(euler.y); + euler.z = roundAngle(euler.z); + aa = MathTools.getFromEuler2(euler); + G3DTools.setOrientation(mo.getG3DNode(graph).getLocalOrientation(), aa); + //mo.setRotation(aa); + Vector3d e = MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation())); + e.scale(180.0/Math.PI); + text += G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()) + " " + e + " "; + } + } else { + for (IGraphicsNode mo : mos) { + if (worldCoord) + G3DTools.multiplyOrientation + (mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,angle-prevAngle)); + else + G3DTools.multiplyOrientation(mo.getG3DNode(graph).getLocalOrientation(), new AxisAngle4d(axis,angle-prevAngle)); + text += G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()) + " " + MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation())) + " "; + } + prevAngle = angle; + } + + } else if (inputType == InputType.NONINTERSECT){ + Vector3d o = new Vector3d(); + Vector3d d = new Vector3d(); + parent.createPickRay(o, d); + Vector3d p = gizmo.getPosition(); + double s[] = new double[2]; + MathTools.intersectStraightStraight(o, d, p, i, new Vector3d(), new Vector3d(), s); + if(!worldCoord) + axis = taxis; + if (false && useStep) { + for (IGraphicsNode mo : mos) { + G3DTools.setOrientation(mo.getG3DNode(graph).getLocalOrientation(), rotations.get(mo)); + G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,s[1] - prevS)); + //mo.setRotation(rotations.get(mo)); + //mo.modifyWorldRotation(axis, s[1] - prevS); + AxisAngle4d aa = G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()); + rotations.put(mo, aa); + Vector3d euler = MathTools.getEuler(aa); + euler.x = roundAngle(euler.x); + euler.y = roundAngle(euler.y); + euler.z = roundAngle(euler.z); + aa = MathTools.getFromEuler2(euler); + prevS = s[1]; + G3DTools.setOrientation(mo.getG3DNode(graph).getLocalOrientation(), aa); + //mo.setRotation(aa); + Vector3d e = MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation())); + e.scale(180.0/Math.PI); + text += G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()) + " " + e + " "; + } + } else { + for (IGraphicsNode mo : mos) { + if (worldCoord) + G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,s[1] - prevS)); + else + G3DTools.multiplyOrientation(mo.getG3DNode(graph).getLocalOrientation(), new AxisAngle4d(axis,s[1] - prevS)); + text += G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()) + " " + MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation())) + " "; + } + prevS = s[1]; + + } + + } else { + for (IGraphicsNode mo : mos) { + if (worldCoord) + G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,Math.PI * 0.5)); + else + G3DTools.multiplyOrientation(mo.getG3DNode(graph).getLocalOrientation(), new AxisAngle4d(axis,Math.PI * 0.5)); + text += G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()) + " " + MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation())) + " "; + } + } + setInfoText(text); + + } + /* + private double roundAngle(double current, double modify) { + double angle = roundAngle(current+modify); + if (Double.isNaN(angle)) { + angle = current+modify; + } + //System.out.println(angle + " " + (current+modify)); + return angle; + } + */ + + private double roundAngle(double angle) { + while (angle < - Math.PI) + angle += Math.PI*2.0; + while (angle > Math.PI) + angle -= Math.PI*2.0; + + + int index = 0; + while (angle > angles[index]) + index++; + if (index == 0) { + angle = angles[0]; + } else { + double d = angle - angles[index - 1]; + double d2 = angles[index] - angle; + if (d < d2) + angle = angles[index - 1]; + else + angle = angles[index]; + } + return angle; + } + + private void updateGizmo() { + List mos = parent.getSelectionAdapter().getSelectedObjects(); + //gizmo.update(XithTools.getPosition(mos.get(0).getGroup()),camera.getCameraPos(),component); + gizmo.update(VecmathJmeTools.getD(mos.get(0).getGroup().getWorldTranslation()),camera.getCameraPos(),component); + } + + public void setInfoText(String text) { + + } +} \ No newline at end of file