--- /dev/null
+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
+import java.math.BigDecimal;\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.MathTools;\r
+import org.simantics.g3d.math.Ray;\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.TranslateAxisGizmo;\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
+public class TranslateAction 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 XY = 3;\r
+ public static final int XZ = 4;\r
+ public static final int YZ = 5;\r
+ public static final int P = 6;\r
+\r
+ private VTKNodeMap nodeMap;\r
+ //private TranslateGizmo gizmo = new TranslateGizmo();\r
+ private TranslateAxisGizmo gizmo = new TranslateAxisGizmo();\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
+ 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
+ \r
+ public IG3DNode getNode() {\r
+ return node;\r
+ }\r
+ \r
+ public TranslateAction(InteractiveVtkPanel panel, VTKNodeMap nodeMap) {\r
+ super(panel);\r
+ setImageDescriptor(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/arrow_out.png"));\r
+ setText("Translate");\r
+ this.nodeMap = nodeMap;\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
+ \r
+ update();\r
+ //panel.repaint();\r
+ }\r
+ \r
+ @Override\r
+ public void keyReleased(KeyEvent e) {\r
+ \r
+ }\r
+ \r
+ @Override\r
+ public void keyTyped(KeyEvent e) {\r
+ \r
+ }\r
+ \r
+ @Override\r
+ public void mouseClicked(MouseEvent e) {\r
+ if (e.getClickCount() > 1) {\r
+ if (isOverNode(e)) {\r
+ return;\r
+ } else {\r
+ panel.useDefaultAction();\r
+ }\r
+ //if(!gizmo.isPartOf(actor))\r
+ // panel.useDefaultAction();\r
+ \r
+ }\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
+ @Override\r
+ public void mouseEntered(MouseEvent e) {\r
+ \r
+ }\r
+ \r
+ @Override\r
+ public void mouseExited(MouseEvent e) {\r
+ \r
+ }\r
+ \r
+ int index = P;\r
+ boolean valid = false;\r
+ private boolean worldCoord = true;\r
+ private AxisAngle4d aa = null;\r
+ private Quat4d q = null;\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
+ if (node == null)\r
+ return;\r
+ if (worldCoord) {\r
+ gizmo.setRotation(new AxisAngle4d());\r
+ aa = null;\r
+ q = null;\r
+ } else {\r
+ aa = new AxisAngle4d();\r
+ aa.set(((IG3DNode)node.getParent()).getWorldOrientation());\r
+ gizmo.setRotation(aa);\r
+ q = new Quat4d();\r
+ MathTools.getQuat(aa, q);\r
+ }\r
+ \r
+ Vector3d nodePos = node.getWorldPosition();\r
+ //System.out.println(nodePos);\r
+ gizmo.setPosition(nodePos);\r
+\r
+ \r
+ Point3d camPos = new Point3d(panel.GetRenderer().GetActiveCamera().GetPosition());\r
+ Vector3d p = new Vector3d(nodePos);\r
+ p.sub(camPos);\r
+ \r
+ if (q != null) {\r
+ Quat4d qi = new Quat4d(q);\r
+ qi.inverse();\r
+ MathTools.rotate(q, 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
+ panel.repaint();\r
+ }\r
+ \r
+ Vector3d prevTranslate = null;\r
+ \r
+ @Override\r
+ public void mousePressed(MouseEvent e) {\r
+ if (e.getButton() == MouseEvent.BUTTON1) {\r
+\r
+ if (isOverNode(e)) {\r
+ prevTranslate = getTranslate(e.getX(), e.getY());\r
+ valid = true;\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
+ //index = gizmo.getTranslateAxis(actor);\r
+ //if (index == -1) {\r
+ // valid = false;\r
+ // panel.getDefaultAction().mousePressed(e);\r
+ // return;\r
+ //}\r
+ //valid = true; \r
+ //prevTranslate = getTranslate(e.getX(), e.getY());\r
+ //System.out.println("start translate " + prevTranslate);\r
+ }\r
+ \r
+ \r
+ \r
+ @Override\r
+ public void mouseReleased(MouseEvent e) {\r
+ if (e.getButton() == MouseEvent.BUTTON1) {\r
+ valid = false;\r
+ prevTranslate = 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
+ \r
+ Vector3d translate = getTranslate(e.getX(), e.getY(), prevTranslate);\r
+ //System.out.println("translate " + translate);\r
+ if (translate == null)\r
+ return;\r
+ boolean step = ((e.getModifiers() & MouseEvent.CTRL_MASK) > 0);\r
+ if (worldCoord) {\r
+ Vector3d pos = new Vector3d(node.getWorldPosition());\r
+ pos.add(translate);\r
+ pos = constaints(pos, step);\r
+ setWorldPos(pos);\r
+ } else {\r
+ Vector3d pos = new Vector3d(node.getPosition());\r
+ pos.add(translate);\r
+ pos = constaints(pos, step);\r
+ setPos(pos);\r
+ }\r
+ //mapping.rangeModified(node);\r
+ \r
+ //nodeMap.modified(node);\r
+ update();\r
+ } else {\r
+ panel.getDefaultAction().mouseDragged(e);\r
+ update();\r
+ }\r
+ }\r
+ \r
+ protected void setPos(Vector3d pos) {\r
+ node.setPosition(pos);\r
+ }\r
+ \r
+ protected void setWorldPos(Vector3d pos) {\r
+ node.setWorldPosition(pos);\r
+ }\r
+ \r
+ private double istep = 10.0;\r
+ private int decimals = 2;\r
+ \r
+ private Vector3d constaints(Vector3d p, boolean step) {\r
+ if(!step)\r
+ return p;\r
+ switch (index) {\r
+ case X:\r
+ p.x = Math.round(istep * p.x) / istep;\r
+ BigDecimal bx = new BigDecimal(p.x);\r
+ bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);\r
+ p.x = bx.doubleValue();\r
+ break;\r
+ case Y:\r
+ p.y = Math.round(istep * p.y) / istep;\r
+ BigDecimal by = new BigDecimal(p.y);\r
+ by.setScale(decimals, BigDecimal.ROUND_HALF_UP);\r
+ p.y = by.doubleValue();\r
+ break;\r
+ \r
+ case Z:\r
+ p.z = Math.round(istep * p.z) / istep;\r
+ BigDecimal bz = new BigDecimal(p.z);\r
+ bz.setScale(decimals, BigDecimal.ROUND_HALF_UP);\r
+ p.z = bz.doubleValue();\r
+ break;\r
+ }\r
+ return p;\r
+ }\r
+ \r
+ @Override\r
+ public void mouseMoved(MouseEvent e) {\r
+ panel.getDefaultAction().mouseMoved(e);\r
+ }\r
+ \r
+ Vector3d getTranslate(double x, double y) {\r
+ return getTranslate(x, y, new Vector3d());\r
+ }\r
+ \r
+ Vector3d getTranslate(double x, double y, Vector3d offset) {\r
+ Vector3d translate = new Vector3d();\r
+ \r
+ Ray ray = vtkUtil.createMouseRay(panel.GetRenderer(),x, y);\r
+ \r
+ Vector3d p = node.getWorldPosition();\r
+ Vector3d dir = null;\r
+ \r
+ switch (index) {\r
+ case P:\r
+ Vector3d normal = new Vector3d(panel.GetRenderer().GetActiveCamera().GetDirectionOfProjection());\r
+ if (!worldCoord) {\r
+ MathTools.rotate(q, normal, normal);\r
+ }\r
+ normal.normalize();\r
+ double s[] = new double[1];\r
+ Vector3d r = new Vector3d();\r
+ if (MathTools.intersectStraightPlane(ray.pos, ray.dir, p, normal, r)) {\r
+ r.sub(p);\r
+ translate.x = r.x;\r
+ translate.y = r.y;\r
+ translate.z = r.z;\r
+ }\r
+ break;\r
+\r
+ case X :\r
+ dir = new Vector3d(1.0,0.0,0.0);\r
+ if(!worldCoord)\r
+ MathTools.rotate(q, dir, dir);\r
+ Vector3d i1 = new Vector3d();\r
+ Vector3d i2 = new Vector3d();\r
+ s = new double[2];\r
+ MathTools.intersectStraightStraight( p, dir,ray.pos, ray.dir, i2, i1,s);\r
+ translate.x = s[0];\r
+ \r
+ break;\r
+ case Y :\r
+ dir = new Vector3d(0.0,1.0,0.0);\r
+ if(!worldCoord)\r
+ MathTools.rotate(q, dir, dir);\r
+ i1 = new Vector3d();\r
+ i2 = new Vector3d();\r
+ s = new double[2];\r
+ MathTools.intersectStraightStraight( p, dir,ray.pos, ray.dir, i2, i1,s);\r
+ translate.y = s[0];\r
+ break;\r
+ case Z :\r
+ dir = new Vector3d(0.0,0.0,1.0);\r
+ if(!worldCoord)\r
+ MathTools.rotate(q, dir, dir);\r
+ i1 = new Vector3d();\r
+ i2 = new Vector3d();\r
+ s = new double[2];\r
+ MathTools.intersectStraightStraight( p, dir,ray.pos, ray.dir, i2, i1,s);\r
+ translate.z = s[0];\r
+ break;\r
+ case XY :\r
+ normal = new Vector3d(0.0,0.0,1.0);\r
+ if(!worldCoord)\r
+ MathTools.rotate(q, normal, normal);\r
+ r = new Vector3d();\r
+ if (MathTools.intersectStraightPlane(ray.pos, ray.dir, p, normal, r)) {\r
+ r.sub(p);\r
+ translate.x = r.x;\r
+ translate.y = r.y;\r
+ }\r
+ break;\r
+ case XZ :\r
+ normal = new Vector3d(0.0,1.0,0.0);\r
+ if(!worldCoord)\r
+ MathTools.rotate(q, normal, normal);\r
+ r = new Vector3d();\r
+ if (MathTools.intersectStraightPlane(ray.pos, ray.dir, p, normal, r)) {\r
+ r.sub(p);\r
+ translate.x = r.x;\r
+ translate.z = r.z;\r
+ }\r
+ break;\r
+ case YZ :\r
+ normal = new Vector3d(1.0,0.0,0.0);\r
+ if(!worldCoord)\r
+ MathTools.rotate(q, normal, normal);\r
+ r = new Vector3d();\r
+ if (MathTools.intersectStraightPlane(ray.pos, ray.dir, p, normal, r)) {\r
+ r.sub(p);\r
+ translate.y = r.y;\r
+ translate.z = r.z;\r
+ }\r
+ break;\r
+ default :\r
+ \r
+ return null;\r
+ }\r
+ translate.sub(offset);\r
+ return translate;\r
+ }\r
+ \r
+}\r