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