]> gerrit.simantics Code Review - simantics/3d.git/blob - org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/action/TranslateAction.java
4d99999f576ad4cff57841917d2d3e960d211304
[simantics/3d.git] / org.simantics.g3d.vtk / src / org / simantics / g3d / vtk / action / TranslateAction.java
1 /*******************************************************************************\r
2  * Copyright (c) 2012, 2013 Association for Decentralized Information Management in\r
3  * Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.g3d.vtk.action;\r
13 \r
14 import java.awt.Cursor;\r
15 import java.awt.event.KeyEvent;\r
16 import java.awt.event.MouseEvent;\r
17 import java.math.BigDecimal;\r
18 \r
19 import javax.vecmath.AxisAngle4d;\r
20 import javax.vecmath.Point3d;\r
21 import javax.vecmath.Quat4d;\r
22 import javax.vecmath.Vector3d;\r
23 \r
24 import org.simantics.g3d.math.MathTools;\r
25 import org.simantics.g3d.math.Ray;\r
26 import org.simantics.g3d.scenegraph.IG3DNode;\r
27 import org.simantics.g3d.scenegraph.structural.IStructuralNode;\r
28 import org.simantics.g3d.vtk.Activator;\r
29 import org.simantics.g3d.vtk.common.InteractiveVtkPanel;\r
30 import org.simantics.g3d.vtk.common.VTKNodeMap;\r
31 import org.simantics.g3d.vtk.gizmo.TranslateAxisGizmo;\r
32 import org.simantics.g3d.vtk.utils.vtkUtil;\r
33 import org.simantics.utils.threads.AWTThread;\r
34 import org.simantics.utils.threads.ThreadUtils;\r
35 \r
36 import vtk.vtkProp;\r
37 \r
38 public class TranslateAction extends vtkAction{\r
39         \r
40         public static final int X = 0;\r
41     public static final int Y = 1;\r
42     public static final int Z = 2;\r
43     public static final int XY = 3;\r
44     public static final int XZ = 4;\r
45     public static final int YZ = 5;\r
46     public static final int P = 6;\r
47 \r
48         private VTKNodeMap nodeMap;\r
49         //private TranslateGizmo  gizmo = new TranslateGizmo();\r
50         private TranslateAxisGizmo gizmo = new TranslateAxisGizmo();\r
51         private IG3DNode node;\r
52         \r
53         \r
54         \r
55         private Cursor activeCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);\r
56         private Cursor dragCursor = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR);\r
57         \r
58         public void setNode(IG3DNode node) {\r
59                 this.node = node;\r
60                 if ((node instanceof IStructuralNode) && ((IStructuralNode)node).isPartOfInstantiatedModel() && !((IStructuralNode)node).isInstantiatedModelRoot()) {\r
61                         setEnabled(false);\r
62                 } else {\r
63                         setEnabled(true);\r
64                 }\r
65         }\r
66         \r
67         public IG3DNode getNode() {\r
68                 return node;\r
69         }\r
70         \r
71         public TranslateAction(InteractiveVtkPanel panel, VTKNodeMap nodeMap) {\r
72                 super(panel);\r
73                 setImageDescriptor(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/arrow_out.png"));\r
74                 setText("Translate");\r
75                 this.nodeMap = nodeMap;\r
76         }\r
77         \r
78         public void attach() {\r
79                 if (node == null)\r
80                         return;\r
81                 \r
82                 super.attach();\r
83                 ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {\r
84                         public void run() {\r
85                                 attachUI();\r
86                                 update();\r
87                         }\r
88                 });\r
89                 \r
90                 \r
91                 \r
92         }\r
93         \r
94         public void deattach() {\r
95                 \r
96                 node = null;\r
97                 nodeMap.commit();\r
98                 deattachUI();\r
99                 super.deattach();\r
100                 panel.repaint();\r
101         }\r
102         \r
103         private void attachUI() {\r
104                 panel.setCursor(activeCursor);\r
105                 gizmo.attach(panel.GetRenderer());\r
106         }\r
107         \r
108         private void deattachUI() {\r
109                 panel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));\r
110                 gizmo.deattach();\r
111         }\r
112         \r
113         @Override\r
114         public void keyPressed(KeyEvent e) {\r
115                 if (e.getKeyCode() == KeyEvent.VK_ESCAPE)\r
116                         panel.useDefaultAction();\r
117                 if (valid)\r
118                         return;\r
119                 if (e.getKeyCode() == KeyEvent.VK_X) {\r
120                         if (index != X)\r
121                                 index = X;\r
122                         else\r
123                                 index = P;\r
124                 }\r
125                 if (e.getKeyCode() == KeyEvent.VK_Y) {\r
126                         if (index != Y)\r
127                                 index = Y;\r
128                         else\r
129                                 index = P;\r
130                 }\r
131                 if (e.getKeyCode() == KeyEvent.VK_Z) {\r
132                         if (index != Z)\r
133                                 index = Z;\r
134                         else\r
135                                 index = P;\r
136                 }\r
137                 if (e.getKeyCode() == KeyEvent.VK_G) {\r
138                         worldCoord = !worldCoord;\r
139                 }\r
140                 gizmo.setType(index);\r
141                 \r
142                 update();\r
143                 //panel.repaint();\r
144         }\r
145         \r
146         @Override\r
147         public void keyReleased(KeyEvent e) {\r
148                 \r
149         }\r
150         \r
151         @Override\r
152         public void keyTyped(KeyEvent e) {\r
153                 \r
154         }\r
155         \r
156         @Override\r
157         public void mouseClicked(MouseEvent e) {\r
158                 if (e.getClickCount() > 1) {\r
159                         if (isOverNode(e)) {\r
160                                 return;\r
161                         } else {\r
162                                 panel.useDefaultAction();\r
163                         }\r
164                         //if(!gizmo.isPartOf(actor))\r
165                         //      panel.useDefaultAction();\r
166                         \r
167                 }\r
168         }\r
169         \r
170         private boolean isOverNode(MouseEvent e) {\r
171                 vtkProp picked[] = panel.pick(e.getX(), e.getY());\r
172                 if (picked !=null) {\r
173                         for (int i = 0; i < picked.length; i++) {\r
174                                 if (node.equals(nodeMap.getNode(picked[i])))\r
175                                         return true;\r
176                         }\r
177                 }\r
178                 return false;\r
179         }\r
180         \r
181         @Override\r
182         public void mouseEntered(MouseEvent e) {\r
183                 \r
184         }\r
185         \r
186         @Override\r
187         public void mouseExited(MouseEvent e) {\r
188                 \r
189         }\r
190         \r
191         int index = P;\r
192         boolean valid = false;\r
193         private boolean worldCoord = true;\r
194         private AxisAngle4d aa = null;\r
195         private Quat4d q = null;\r
196         \r
197         \r
198         public void setWorldCoord(boolean b) {\r
199                 if (worldCoord == b)\r
200                         return;\r
201                 worldCoord = b;\r
202                 update();\r
203                                         \r
204         }\r
205         \r
206         \r
207         private void update() {\r
208                 if (node == null)\r
209                         return;\r
210                 if (worldCoord) {\r
211                         gizmo.setRotation(new AxisAngle4d());\r
212                         aa = null;\r
213                         q = null;\r
214                 } else {\r
215                         aa = new AxisAngle4d();\r
216                         aa.set(((IG3DNode)node.getParent()).getWorldOrientation());\r
217                         gizmo.setRotation(aa);\r
218                         q = new Quat4d();\r
219                         MathTools.getQuat(aa, q);\r
220                 }\r
221                 \r
222                 Vector3d nodePos = node.getWorldPosition();\r
223                 //System.out.println(nodePos);\r
224                 gizmo.setPosition(nodePos);\r
225 \r
226                 \r
227                 Point3d camPos = new Point3d(panel.GetRenderer().GetActiveCamera().GetPosition());\r
228                 Vector3d p = new Vector3d(nodePos);\r
229                 p.sub(camPos);\r
230                 \r
231                 if (q != null) {\r
232                         Quat4d qi = new Quat4d(q);\r
233                         qi.inverse();\r
234                         MathTools.rotate(q, p, p);\r
235                 }\r
236                 if (panel.GetRenderer().GetActiveCamera().GetParallelProjection() == 0) {\r
237                         double distance = p.length();\r
238                         p.negate();\r
239             double fov = panel.GetRenderer().GetActiveCamera().GetViewAngle();\r
240             float s = (float) (Math.sin(fov) * distance * 0.1); \r
241 \r
242             Vector3d scale = new Vector3d(1., 1., 1.);\r
243             \r
244 //            if (p.x > 0.f)\r
245 //                scale.x = -1.;\r
246 //            if (p.y > 0.f)\r
247 //                scale.y = -1.;\r
248 //            if (p.z > 0.f)\r
249 //                scale.z = -1.;\r
250             scale.scale(s);\r
251             gizmo.setScale(scale);\r
252                         \r
253                 } else {\r
254                         Vector3d scale = new Vector3d(1.f, 1.f, 1.f);\r
255             double s = panel.GetRenderer().GetActiveCamera().GetParallelScale() / 5.;\r
256 //            if (p.x > 0.f)\r
257 //                scale.x = -1.;\r
258 //            if (p.y > 0.f)\r
259 //                scale.y = -1.;\r
260 //            if (p.z > 0.f)\r
261 //                scale.z = -1.;\r
262             scale.scale(s);\r
263             gizmo.setScale(scale);\r
264                 }\r
265                 \r
266                 //panel.Render();\r
267                 panel.repaint();\r
268         }\r
269         \r
270         Vector3d prevTranslate = null;\r
271         \r
272         @Override\r
273         public void mousePressed(MouseEvent e) {\r
274                 if (e.getButton() == MouseEvent.BUTTON1) {\r
275 \r
276                         if (isOverNode(e)) {\r
277                                 prevTranslate = getTranslate(e.getX(), e.getY());\r
278                                 valid = true;\r
279                                 panel.setCursor(dragCursor);\r
280                         } else {\r
281                                 valid = false;\r
282                                 panel.getDefaultAction().mousePressed(e);\r
283                                 panel.setCursor(activeCursor);\r
284                         }\r
285                 } else {\r
286                         panel.getDefaultAction().mousePressed(e);\r
287                 }\r
288                 //index = gizmo.getTranslateAxis(actor);\r
289                 //if (index == -1) {\r
290                 //  valid = false;\r
291                 //      panel.getDefaultAction().mousePressed(e);\r
292                 //      return;\r
293                 //}\r
294                 //valid = true; \r
295                 //prevTranslate = getTranslate(e.getX(), e.getY());\r
296                 //System.out.println("start translate " + prevTranslate);\r
297         }\r
298         \r
299         \r
300         \r
301         @Override\r
302         public void mouseReleased(MouseEvent e) {\r
303                 if (e.getButton() == MouseEvent.BUTTON1) {\r
304                         valid = false;\r
305                         prevTranslate = null;\r
306                         panel.setCursor(activeCursor);\r
307                 } else {\r
308                         panel.getDefaultAction().mouseReleased(e);\r
309                 }\r
310         }\r
311         \r
312         @Override\r
313         public void mouseDragged(MouseEvent e) {\r
314                 if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) > 0 && valid) { \r
315                         \r
316                         Vector3d translate = getTranslate(e.getX(), e.getY(), prevTranslate);\r
317                         //System.out.println("translate " + translate);\r
318                         if (translate == null)\r
319                                 return;\r
320                         boolean step = ((e.getModifiers() & MouseEvent.CTRL_MASK) > 0);\r
321                         if (worldCoord) {\r
322                                 Vector3d pos = new Vector3d(node.getWorldPosition());\r
323                                 pos.add(translate);\r
324                                 pos = constaints(pos, step);\r
325                                 setWorldPos(pos);\r
326                         } else {\r
327                                 Vector3d pos = new Vector3d(node.getPosition());\r
328                                 pos.add(translate);\r
329                                 pos = constaints(pos, step);\r
330                                 setPos(pos);\r
331                         }\r
332                         //mapping.rangeModified(node);\r
333                         \r
334                         //nodeMap.modified(node);\r
335                         update();\r
336                 } else {\r
337                         panel.getDefaultAction().mouseDragged(e);\r
338                         update();\r
339                 }\r
340         }\r
341         \r
342         protected void setPos(Vector3d pos) {\r
343                 node.setPosition(pos);\r
344         }\r
345         \r
346         protected void setWorldPos(Vector3d pos) {\r
347                 node.setWorldPosition(pos);\r
348         }\r
349         \r
350          private double istep = 10.0;\r
351          private int decimals = 2;\r
352         \r
353         private Vector3d constaints(Vector3d p, boolean step) {\r
354                 if(!step)\r
355                         return p;\r
356                 switch (index) {\r
357                 case X:\r
358                          p.x = Math.round(istep * p.x) / istep;\r
359              BigDecimal bx = new BigDecimal(p.x);\r
360              bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);\r
361              p.x = bx.doubleValue();\r
362                         break;\r
363                 case Y:\r
364                          p.y = Math.round(istep * p.y) / istep;\r
365              BigDecimal by = new BigDecimal(p.y);\r
366              by.setScale(decimals, BigDecimal.ROUND_HALF_UP);\r
367              p.y = by.doubleValue();\r
368                         break;\r
369                         \r
370                 case Z:\r
371                          p.z = Math.round(istep * p.z) / istep;\r
372              BigDecimal bz = new BigDecimal(p.z);\r
373              bz.setScale(decimals, BigDecimal.ROUND_HALF_UP);\r
374              p.z = bz.doubleValue();\r
375                         break;\r
376                 }\r
377                 return p;\r
378         }\r
379         \r
380         @Override\r
381         public void mouseMoved(MouseEvent e) {\r
382                 panel.getDefaultAction().mouseMoved(e);\r
383         }\r
384         \r
385         Vector3d getTranslate(double x, double y) {\r
386                 return getTranslate(x, y, new Vector3d());\r
387         }\r
388         \r
389         Vector3d getTranslate(double x, double y, Vector3d offset) {\r
390                 Vector3d translate = new Vector3d();\r
391                 \r
392                 Ray ray = vtkUtil.createMouseRay(panel.GetRenderer(),x, y);\r
393                 \r
394                 Vector3d p = node.getWorldPosition();\r
395                 Vector3d dir = null;\r
396                 \r
397                 switch (index) {\r
398                 case P:\r
399                         Vector3d normal = new Vector3d(panel.GetRenderer().GetActiveCamera().GetDirectionOfProjection());\r
400                         if (!worldCoord) {\r
401                                 MathTools.rotate(q, normal, normal);\r
402                         }\r
403                         normal.normalize();\r
404                         double s[] = new double[1];\r
405             Vector3d r = new Vector3d();\r
406             if (MathTools.intersectStraightPlane(ray.pos, ray.dir, p, normal, r)) {\r
407                 r.sub(p);\r
408                 translate.x = r.x;\r
409                 translate.y = r.y;\r
410                 translate.z = r.z;\r
411             }\r
412             break;\r
413 \r
414                  case X :\r
415                     dir = new Vector3d(1.0,0.0,0.0);\r
416                     if(!worldCoord)\r
417                         MathTools.rotate(q, dir, dir);\r
418                     Vector3d i1 = new Vector3d();\r
419                     Vector3d i2 = new Vector3d();\r
420                     s = new double[2];\r
421                     MathTools.intersectStraightStraight( p, dir,ray.pos, ray.dir, i2, i1,s);\r
422                     translate.x = s[0];\r
423                     \r
424                     break;\r
425                 case Y :\r
426                     dir = new Vector3d(0.0,1.0,0.0);\r
427                     if(!worldCoord)\r
428                         MathTools.rotate(q, dir, dir);\r
429                     i1 = new Vector3d();\r
430                     i2 = new Vector3d();\r
431                     s = new double[2];\r
432                     MathTools.intersectStraightStraight( p, dir,ray.pos, ray.dir, i2, i1,s);\r
433                     translate.y = s[0];\r
434                     break;\r
435                 case Z :\r
436                     dir = new Vector3d(0.0,0.0,1.0);\r
437                     if(!worldCoord)\r
438                         MathTools.rotate(q, dir, dir);\r
439                     i1 = new Vector3d();\r
440                     i2 = new Vector3d();\r
441                     s = new double[2];\r
442                     MathTools.intersectStraightStraight( p, dir,ray.pos, ray.dir, i2, i1,s);\r
443                     translate.z = s[0];\r
444                     break;\r
445                 case XY :\r
446                     normal = new Vector3d(0.0,0.0,1.0);\r
447                     if(!worldCoord)\r
448                         MathTools.rotate(q, normal, normal);\r
449                     r = new Vector3d();\r
450                     if (MathTools.intersectStraightPlane(ray.pos, ray.dir, p, normal, r)) {\r
451                         r.sub(p);\r
452                         translate.x = r.x;\r
453                         translate.y = r.y;\r
454                     }\r
455                     break;\r
456                 case XZ :\r
457                     normal = new Vector3d(0.0,1.0,0.0);\r
458                     if(!worldCoord)\r
459                         MathTools.rotate(q, normal, normal);\r
460                     r = new Vector3d();\r
461                     if (MathTools.intersectStraightPlane(ray.pos, ray.dir, p, normal, r)) {\r
462                         r.sub(p);\r
463                         translate.x = r.x;\r
464                         translate.z = r.z;\r
465                     }\r
466                     break;\r
467                 case YZ :\r
468                     normal = new Vector3d(1.0,0.0,0.0);\r
469                     if(!worldCoord)\r
470                         MathTools.rotate(q, normal, normal);\r
471                     r = new Vector3d();\r
472                     if (MathTools.intersectStraightPlane(ray.pos, ray.dir, p, normal, r)) {\r
473                         r.sub(p);\r
474                         translate.y = r.y;\r
475                         translate.z = r.z;\r
476                     }\r
477                     break;\r
478                 default :\r
479                     \r
480                     return null;\r
481                 }\r
482                 translate.sub(offset);\r
483                 return translate;\r
484         }\r
485         \r
486 }\r