-/*******************************************************************************\r
- * Copyright (c) 2012, 2013 Association for Decentralized Information Management in\r
- * Industry THTH ry.\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.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
+/*******************************************************************************
+ * Copyright (c) 2012, 2013 Association for Decentralized Information Management in
+ * Industry THTH ry.
+ * 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.g3d.vtk.awt;
+
+import java.awt.Cursor;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+
+import javax.vecmath.AxisAngle4d;
+import javax.vecmath.Point3d;
+import javax.vecmath.Quat4d;
+import javax.vecmath.Vector3d;
+
+import org.simantics.g3d.math.EulerTools;
+import org.simantics.g3d.math.EulerTools.Order;
+import org.simantics.g3d.math.MathTools;
+import org.simantics.g3d.math.Ray;
+import org.simantics.g3d.preferences.PreferenceConstants;
+import org.simantics.g3d.scenegraph.IG3DNode;
+import org.simantics.g3d.scenegraph.structural.IStructuralNode;
+import org.simantics.g3d.vtk.Activator;
+import org.simantics.g3d.vtk.common.VTKNodeMap;
+import org.simantics.g3d.vtk.gizmo.RotateAxisGizmo;
+import org.simantics.g3d.vtk.utils.vtkUtil;
+import org.simantics.utils.threads.AWTThread;
+import org.simantics.utils.threads.ThreadUtils;
+
+import vtk.vtkProp;
+/**
+ * FIXME: complete rewrite.
+ *
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
+ *
+ */
+public class RotateAction extends vtkAwtAction{
+
+ public static final int X = 0;
+ public static final int Y = 1;
+ public static final int Z = 2;
+ public static final int P = 3;
+
+ private VTKNodeMap nodeMap;
+ //private TranslateGizmo gizmo = new TranslateGizmo();
+ private RotateAxisGizmo gizmo = new RotateAxisGizmo();
+ private IG3DNode node;
+
+
+
+ private Cursor activeCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
+ private Cursor dragCursor = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR);
+
+
+ int stepMethod = 1;
+ Order order = Order.YXZ;
+
+ private int steps;
+ private double angles[];
+
+ int index = P;
+ boolean valid = false;
+ private boolean worldCoord = true;
+ //private AxisAngle4d aa = null;
+ private Quat4d parentWorldOrientation = null;
+
+ //AxisAngle4d rotation = new AxisAngle4d();
+ Quat4d worldOrientation = new Quat4d();
+
+ public void setNode(IG3DNode node) {
+ this.node = node;
+ if ((node instanceof IStructuralNode) && ((IStructuralNode)node).isPartOfInstantiatedModel() && !((IStructuralNode)node).isInstantiatedModelRoot()) {
+ setEnabled(false);
+ } else {
+ setEnabled(true);
+ }
+
+ String set = org.simantics.g3d.Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.ORIENTATION_PRESENTATION);
+ if (set.equals("aa")) {
+ stepMethod = 0;
+ } else if (set.equals("euler")){
+ stepMethod = 1;
+ String eulerOrder = org.simantics.g3d.Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.EULER_ANGLE_ORDER);
+ try {
+ order = Order.valueOf(eulerOrder);
+ } catch (Exception e) {
+ order = Order.YXZ;
+ }
+ } else {
+ stepMethod = 2;
+ }
+ }
+
+ public IG3DNode getNode() {
+ return node;
+ }
+
+ public RotateAction(InteractiveVtkPanel panel, VTKNodeMap nodeMap) {
+ super(panel);
+ setImageDescriptor(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/arrow_rotate_clockwise.png"));
+ setText("Rotate");
+ this.nodeMap = nodeMap;
+
+
+ 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);
+ }
+ }
+
+ public void attach() {
+ if (node == null)
+ return;
+
+ super.attach();
+ ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {
+ public void run() {
+ attachUI();
+ update();
+ }
+ });
+
+
+
+ }
+
+ public void deattach() {
+
+ node = null;
+ nodeMap.commit();
+ deattachUI();
+ super.deattach();
+ panel.repaint();
+ }
+
+ private void attachUI() {
+ panel.setCursor(activeCursor);
+ gizmo.attach(panel);
+ }
+
+ private void deattachUI() {
+ panel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+ gizmo.deattach();
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+ if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
+ panel.useDefaultAction();
+ if (valid)
+ return;
+ if (e.getKeyCode() == KeyEvent.VK_X) {
+ if (index != X)
+ index = X;
+ else
+ index = P;
+ }
+ if (e.getKeyCode() == KeyEvent.VK_Y) {
+ if (index != Y)
+ index = Y;
+ else
+ index = P;
+ }
+ if (e.getKeyCode() == KeyEvent.VK_Z) {
+ if (index != Z)
+ index = Z;
+ else
+ index = P;
+ }
+ if (e.getKeyCode() == KeyEvent.VK_G) {
+ worldCoord = !worldCoord;
+ }
+ gizmo.setType(index);
+ panel.repaint();
+ }
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+
+ }
+
+
+
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ if (e.getClickCount() > 1) {
+ if (isOverNode(e)) {
+ return;
+ }
+ panel.useDefaultAction();
+ //if(!gizmo.isPartOf(actor))
+ // panel.useDefaultAction();
+
+ }
+ }
+
+ @Override
+ public void mouseEntered(MouseEvent e) {
+
+ }
+
+ @Override
+ public void mouseExited(MouseEvent e) {
+
+ }
+
+
+
+
+
+ public void setWorldCoord(boolean b) {
+ if (worldCoord == b)
+ return;
+ worldCoord = b;
+ update();
+
+ }
+
+
+ private void update() {
+ Vector3d nodePos = node.getWorldPosition();
+ System.out.println(nodePos);
+ gizmo.setPosition(nodePos);
+ if (worldCoord) {
+ gizmo.setRotation(new AxisAngle4d());
+ parentWorldOrientation = null;
+ } else {
+ AxisAngle4d aa = new AxisAngle4d();
+ parentWorldOrientation = ((IG3DNode)node.getParent()).getWorldOrientation();
+ aa.set(parentWorldOrientation);
+ gizmo.setRotation(aa);
+ }
+
+ Point3d camPos = new Point3d(panel.GetRenderer().GetActiveCamera().GetPosition());
+ Vector3d p = new Vector3d(nodePos);
+ p.sub(camPos);
+
+ if (parentWorldOrientation != null) {
+ Quat4d qi = new Quat4d(parentWorldOrientation);
+ qi.inverse();
+ MathTools.rotate(parentWorldOrientation, p, p);
+ }
+ if (panel.GetRenderer().GetActiveCamera().GetParallelProjection() == 0) {
+ double distance = p.length();
+ p.negate();
+ double fov = panel.GetRenderer().GetActiveCamera().GetViewAngle();
+ float s = (float) (Math.sin(fov) * distance * 0.1);
+
+ Vector3d scale = new Vector3d(1., 1., 1.);
+
+// if (p.x > 0.f)
+// scale.x = -1.;
+// if (p.y > 0.f)
+// scale.y = -1.;
+// if (p.z > 0.f)
+// scale.z = -1.;
+ scale.scale(s);
+ gizmo.setScale(scale);
+
+ } else {
+ Vector3d scale = new Vector3d(1.f, 1.f, 1.f);
+ double s = panel.GetRenderer().GetActiveCamera().GetParallelScale() / 5.;
+// if (p.x > 0.f)
+// scale.x = -1.;
+// if (p.y > 0.f)
+// scale.y = -1.;
+// if (p.z > 0.f)
+// scale.z = -1.;
+ scale.scale(s);
+ gizmo.setScale(scale);
+ }
+
+ panel.Render();
+ }
+
+ private boolean isOverNode(MouseEvent e) {
+ vtkProp picked[] = panel.pick(e.getX(), e.getY());
+ if (picked !=null) {
+ for (int i = 0; i < picked.length; i++) {
+ if (node.equals(nodeMap.getNode(picked[i])))
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+
+ @Override
+ public void mousePressed(MouseEvent e) {
+ if (e.getButton() == MouseEvent.BUTTON1) {
+
+
+ if (isOverNode(e)) {
+ valid = true;
+ if ((e.getModifiers() & MouseEvent.CTRL_MASK) > 0) {
+ useStep = true;
+ } else {
+ useStep = false;
+ }
+ worldOrientation = node.getWorldOrientation();
+ doChanges(true, e.getX(), e.getY());
+
+ panel.setCursor(dragCursor);
+ } else {
+ valid = false;
+ getDefaultAction().mousePressed(e);
+ panel.setCursor(activeCursor);
+ }
+ } else {
+ getDefaultAction().mousePressed(e);
+ }
+ }
+
+
+
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ if (e.getButton() == MouseEvent.BUTTON1) {
+ valid = false;
+ worldOrientation = null;
+ panel.setCursor(activeCursor);
+ } else {
+ getDefaultAction().mouseReleased(e);
+ }
+ }
+
+ @Override
+ public void mouseDragged(MouseEvent e) {
+ if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) > 0 && valid) {
+ if ((e.getModifiers() & MouseEvent.CTRL_MASK) > 0) {
+ useStep = true;
+ } else {
+ useStep = false;
+ }
+ doChanges(false, e.getX(), e.getY());
+
+ //nodeMap.modified(node);
+ update();
+ } else {
+ getDefaultAction().mouseDragged(e);
+ update();
+ }
+ }
+
+ Vector3d axis = null;
+
+ @Override
+ public void keyTyped(KeyEvent e) {
+ if (e.getKeyCode() == KeyEvent.VK_LEFT) {
+ inputType = InputType.KEY;
+ axis = new Vector3d(0.0,1.0,0.0);
+ } else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
+ inputType = InputType.KEY;
+ axis = new Vector3d(0.0,-1.0,0.0);
+ } else if (e.getKeyCode() ==KeyEvent.VK_UP) {
+ inputType = InputType.KEY;
+ axis = new Vector3d(1.0,0.0,0.0);
+ } else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
+ inputType = InputType.KEY;
+ axis = new Vector3d(-1.0,0.0,0.0);
+ }
+ }
+
+ public void doChanges(boolean pressed, int x, int y) {
+ Ray ray = vtkUtil.createMouseRay(panel.GetRenderer(),x, y);
+ Vector3d p = node.getWorldPosition();
+
+ if (pressed) {
+ Vector3d axis = getRotationAxis();
+ if (axis != null) {
+ if (!worldCoord) {
+ MathTools.rotate(parentWorldOrientation, axis, axis);
+ }
+
+
+ double s[] = new double[2];
+ Vector3d i2 = new Vector3d();
+
+ boolean intersect = MathTools.intersectStraightPlane(ray.pos, ray.dir, p, axis, i2, s);
+ double dot = Math.abs(ray.dir.dot(axis));
+ if (intersect && dot > 0.4)
+ 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);
+ System.out.println("I,J " + i + " " + j);
+ 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(ray.dir, axis);
+ MathTools.intersectStraightStraight(ray.pos, ray.dir, p, i, new Vector3d(), new Vector3d(), s);
+ prevS = s[1];
+ }
+ }
+
+
+ }
+
+ if (inputType != InputType.KEY)
+ axis = getRotationAxis();
+ if (axis == null) {
+ return;
+ }
+ Vector3d taxis = null;
+ if (!worldCoord) {
+ taxis = new Vector3d(axis);
+ MathTools.rotate(parentWorldOrientation, axis, axis);
+ }
+ System.out.println(inputType);
+ if (inputType == InputType.INTERSECT) {
+
+ double s[] = new double[2];
+ Vector3d i2 = new Vector3d();
+ MathTools.intersectStraightPlane(ray.pos, ray.dir, 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));
+ System.out.println("Angle " + angle + " i " + angleI + " j " + angleJ + " prev " + prevAngle);
+ if(!worldCoord)
+ axis = taxis;
+ if (useStep) {
+
+ //setOrientation(MathTools.getQuat(rotation));
+ AxisAngle4d rot = new AxisAngle4d(axis,angle-prevAngle);
+ Quat4d qrot = new Quat4d();
+ MathTools.getQuat(rot, qrot);
+ //prevAngle = angle;
+ qrot.mulInverse(worldOrientation);
+
+
+ if (stepMethod == 0) {
+ rot.set(qrot);
+ rot.angle = roundAngle(rot.angle);
+ //qrot.set(rot);
+ MathTools.getQuat(rot,qrot);
+ setOrientation(qrot);
+ } else if (stepMethod == 1){
+
+ //Vector3d euler = MathTools.getEuler(qrot);
+ Vector3d euler = EulerTools.getEulerFromQuat(order, qrot);
+ euler.x = roundAngle(euler.x);
+ euler.y = roundAngle(euler.y);
+ euler.z = roundAngle(euler.z);
+ //Quat4d q = MathTools.getQuat(euler);
+ Quat4d q = EulerTools.getQuatFromEuler(order, euler);
+ setOrientation(q);
+ System.out.println(" (" + MathTools.radToDeg(euler.x) + " " + MathTools.radToDeg(euler.y) + " " + MathTools.radToDeg(euler.z) + ") " + qrot + " "+ q);
+ } else {
+ setOrientation(qrot);
+ }
+
+ } else {
+ if (worldCoord) {
+ //G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,angle-prevAngle));
+ AxisAngle4d aa = MathTools.getAxisAngle(node.getWorldOrientation());
+ AxisAngle4d rot = new AxisAngle4d(axis,angle-prevAngle);
+ MathTools.multiplyOrientation(aa, rot);
+ setWorldOrientation(MathTools.getQuat(rot));
+ } else {
+ AxisAngle4d aa = MathTools.getAxisAngle(node.getOrientation());
+ AxisAngle4d rot = new AxisAngle4d(axis,angle-prevAngle);
+ MathTools.multiplyOrientation(aa, rot);
+ setOrientation(MathTools.getQuat(rot));
+ //G3DTools.multiplyOrientation(mo.getG3DNode(graph).getLocalOrientation(), new AxisAngle4d(axis,angle-prevAngle));
+ }
+ prevAngle = angle;
+ }
+
+ } else if (inputType == InputType.NONINTERSECT){
+
+ double s[] = new double[2];
+ MathTools.intersectStraightStraight(ray.pos, ray.dir, p, i, new Vector3d(), new Vector3d(), s);
+ if(!worldCoord)
+ axis = taxis;
+ if (useStep) {
+ //setOrientation(MathTools.getQuat(rotation));
+ AxisAngle4d rot = new AxisAngle4d(axis,s[1] - prevS);
+
+ Quat4d qrot = new Quat4d();
+ //qrot.set(rot);
+ MathTools.getQuat(rot, qrot);
+ //prevAngle = angle;
+ qrot.mulInverse(worldOrientation);
+
+
+ if (stepMethod == 0) {
+ rot.set(qrot);
+ rot.angle = roundAngle(rot.angle);
+ //qrot.set(rot);
+ MathTools.getQuat(rot,qrot);
+ setOrientation(qrot);
+ } else if (stepMethod == 1){
+
+ //Vector3d euler = MathTools.getEuler(qrot);
+ Vector3d euler = EulerTools.getEulerFromQuat(order, qrot);
+ euler.x = roundAngle(euler.x);
+ euler.y = roundAngle(euler.y);
+ euler.z = roundAngle(euler.z);
+ //Quat4d q = MathTools.getQuat(euler);
+ Quat4d q = EulerTools.getQuatFromEuler(order, euler);
+ setOrientation(q);
+ System.out.println(" (" + MathTools.radToDeg(euler.x) + " " + MathTools.radToDeg(euler.y) + " " + MathTools.radToDeg(euler.z) + ") " + qrot + " "+ q);
+ } else {
+ setOrientation(qrot);
+ }
+ prevS = s[1];
+
+// G3DTools.setOrientation(mo.getG3DNode(graph).getLocalOrientation(), rotations.get(mo));
+// G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(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);
+// 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 {
+ if (worldCoord) {
+ AxisAngle4d aa = MathTools.getAxisAngle(node.getWorldOrientation());
+ AxisAngle4d rot = new AxisAngle4d(axis,s[1] - prevS);
+ MathTools.multiplyOrientation(aa, rot);
+ setWorldOrientation(MathTools.getQuat(rot));
+ //G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,s[1] - prevS));
+ } else {
+ AxisAngle4d aa = MathTools.getAxisAngle(node.getOrientation());
+ AxisAngle4d rot = new AxisAngle4d(axis,s[1] - prevS);
+ MathTools.multiplyOrientation(aa, rot);
+ setOrientation(MathTools.getQuat(rot));
+ //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 {
+ if (worldCoord) {
+ AxisAngle4d aa = MathTools.getAxisAngle(node.getWorldOrientation());
+ AxisAngle4d rot = new AxisAngle4d(axis,Math.PI * 0.5);
+ MathTools.multiplyOrientation(aa, rot);
+ setWorldOrientation(MathTools.getQuat(rot));
+ //G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,Math.PI * 0.5));
+ } else {
+ AxisAngle4d aa = MathTools.getAxisAngle(node.getOrientation());
+ AxisAngle4d rot = new AxisAngle4d(axis,Math.PI * 0.5);
+ MathTools.multiplyOrientation(aa, rot);
+ setOrientation(MathTools.getQuat(rot));
+ //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);
+
+ }
+
+ protected void setOrientation(Quat4d q) {
+ node.setOrientation(q);
+ }
+
+ protected void setWorldOrientation(Quat4d q) {
+ node.setWorldOrientation(q);
+ }
+
+ @Override
+ public void mouseMoved(MouseEvent e) {
+ getDefaultAction().mouseMoved(e);
+ }
+
+ private Vector3d getRotationAxis() {
+ switch (index) {
+ case X:
+ return new Vector3d(1.0, 0.0, 0.0);
+ case Y:
+ return new Vector3d(0.0, 1.0, 0.0);
+ case Z:
+ return new Vector3d(0.0, 0.0, 1.0);
+ case P:
+ Vector3d axis = new Vector3d(panel.GetRenderer().GetActiveCamera()
+ .GetDirectionOfProjection());
+ 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;
+
+
+
+ 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;
+ }
+
+}