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