]> gerrit.simantics Code Review - simantics/3d.git/blob - org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/swt/RotateAction.java
Camera rotation with stable rotation speed
[simantics/3d.git] / org.simantics.g3d.vtk / src / org / simantics / g3d / vtk / swt / RotateAction.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
15 import java.awt.event.KeyEvent;
16 import java.awt.event.MouseEvent;
17
18 import javax.vecmath.AxisAngle4d;
19 import javax.vecmath.Point3d;
20 import javax.vecmath.Quat4d;
21 import javax.vecmath.Vector3d;
22
23 import org.eclipse.swt.SWT;
24 import org.eclipse.swt.events.SelectionAdapter;
25 import org.eclipse.swt.events.SelectionEvent;
26 import org.eclipse.swt.graphics.Cursor;
27 import org.eclipse.swt.widgets.Button;
28 import org.eclipse.swt.widgets.Combo;
29 import org.eclipse.swt.widgets.Display;
30 import org.eclipse.swt.widgets.Label;
31 import org.simantics.g3d.math.EulerTools;
32 import org.simantics.g3d.math.EulerTools.Order;
33 import org.simantics.g3d.math.MathTools;
34 import org.simantics.g3d.math.Ray;
35 import org.simantics.g3d.preferences.PreferenceConstants;
36 import org.simantics.g3d.scenegraph.IG3DNode;
37 import org.simantics.g3d.scenegraph.base.INode;
38 import org.simantics.g3d.scenegraph.structural.IStructuralNode;
39 import org.simantics.g3d.toolbar.ToolComposite;
40 import org.simantics.g3d.vtk.Activator;
41 import org.simantics.g3d.vtk.common.VTKNodeMap;
42 import org.simantics.g3d.vtk.gizmo.RotateAxisGizmo;
43 import org.simantics.g3d.vtk.utils.vtkUtil;
44 import org.simantics.utils.threads.ThreadUtils;
45
46 import vtk.vtkProp;
47 /**
48  * FIXME: complete rewrite.
49  * 
50  * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
51  *
52  */
53 public class RotateAction extends vtkSwtAction{
54         
55         public static final int X = 0;
56         public static final int Y = 1;
57         public static final int Z = 2;
58         public static final int P = 3;
59
60         private VTKNodeMap<?, ? extends INode> nodeMap;
61         //private TranslateGizmo  gizmo = new TranslateGizmo();
62         private RotateAxisGizmo gizmo = new RotateAxisGizmo();
63         private IG3DNode node;
64         
65         
66         
67         private Cursor activeCursor;// = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
68         private Cursor dragCursor;// = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR);
69         
70         
71         int stepMethod = 1;
72         Order order = Order.YXZ;
73         
74         private int steps; 
75         private double angles[];
76         
77         int index = P;
78         boolean valid = false;
79         private boolean worldCoord = true;
80         //private AxisAngle4d aa = null;
81         private Quat4d parentWorldOrientation = null;
82         
83         //AxisAngle4d rotation = new AxisAngle4d();
84         Quat4d worldOrientation = new Quat4d();
85         
86         protected ToolComposite toolComposite;
87     protected Combo axisCombo;
88         
89         public void setNode(IG3DNode node) {
90                 this.node = node;
91                 if ((node instanceof IStructuralNode) && ((IStructuralNode)node).isPartOfInstantiatedModel() && !((IStructuralNode)node).isInstantiatedModelRoot()) {
92                         setEnabled(false);
93                 } else {
94                         setEnabled(true);
95                 }
96                 
97                 String set = org.simantics.g3d.Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.ORIENTATION_PRESENTATION);
98                 if (set.equals("aa")) {
99                         stepMethod = 0;
100                 } else if (set.equals("euler")){
101                         stepMethod = 1;
102                         String eulerOrder = org.simantics.g3d.Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.EULER_ANGLE_ORDER);
103                         try {
104                                 order = Order.valueOf(eulerOrder);
105                         } catch (Exception e) {
106                                 order = Order.YXZ;
107                         }
108                 } else {
109                         stepMethod = 2;
110                 }
111         }
112         
113         public IG3DNode getNode() {
114                 return node;
115         }
116         
117         public RotateAction(InteractiveVtkComposite panel, VTKNodeMap<?, ? extends INode> nodeMap, ToolComposite toolComposite) {
118                 super(panel);
119                 setImageDescriptor(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/arrow_rotate_clockwise.png"));
120                 setText("Rotate");
121                 this.nodeMap = nodeMap;
122                 this.toolComposite = toolComposite;
123                 
124                 steps = 36;
125                 angles = new double[steps+1];
126                 for (int i = 0; i < angles.length; i++) {
127                         angles[i] = - Math.PI + (Math.PI * i * 2.0 / steps);
128                 }
129                 
130                 activeCursor = Display.getCurrent().getSystemCursor(SWT.CURSOR_HAND);
131                 dragCursor = Display.getCurrent().getSystemCursor(SWT.CURSOR_CROSS);
132         }
133         
134         protected void createTools(ToolComposite toolComposite) {
135         Label label = new Label(toolComposite, SWT.READ_ONLY);
136         label.setText("Rotate axis:");
137         axisCombo = new Combo(toolComposite, SWT.READ_ONLY);
138         axisCombo.add("X");
139         axisCombo.add("Y");
140         axisCombo.add("Z");
141         axisCombo.add("Camera");
142         axisCombo.addSelectionListener(new SelectionAdapter() {
143             @Override
144             public void widgetSelected(SelectionEvent e) {
145                 Combo c = (Combo)e.getSource();
146                 index = c.getSelectionIndex();
147                 updateLock();
148                 panel.getComponent().setFocus();
149             }
150         });
151         axisCombo.select(index);
152        
153         Button close = new Button(toolComposite, SWT.PUSH);
154         close.setText("Close");
155         close.addSelectionListener(new SelectionAdapter() {
156             public void widgetSelected(SelectionEvent e) {
157                 panel.useDefaultAction();
158             };
159         });
160         toolComposite.relayout();
161     }
162         
163         public void attach() {
164                 if (node == null)
165                         return;
166                 if (toolComposite != null) {
167                    createTools(toolComposite); 
168             }
169                 super.attach();
170                 ThreadUtils.asyncExec(panel.getThreadQueue(), new Runnable() {
171                         public void run() {
172                                 attachUI();
173                                 update();
174                         }
175                 });
176                 setDBUndo(false);
177                 
178                 
179         }
180         
181         public void deattach() {
182             setDBUndo(true);
183             if (toolComposite != null) {
184             toolComposite.clear();
185             axisCombo = null;
186         }
187                 node = null;
188                 nodeMap.commit("Rotate");
189                 deattachUI();
190                 super.deattach();
191                 panel.refresh();
192         }
193         
194         private void attachUI() {
195                 panel.getComponent().setCursor(activeCursor);
196                 gizmo.attach(panel);
197         }
198         
199         private void deattachUI() {
200                 panel.getComponent().setCursor(Display.getCurrent().getSystemCursor(SWT.CURSOR_ARROW));
201                 gizmo.deattach();
202         }
203         
204         @Override
205         public boolean keyPressed(KeyEvent e) {
206                 if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
207                         panel.useDefaultAction();
208                 if (valid)
209                         return true;
210                 if (e.getKeyCode() == KeyEvent.VK_X) {
211                         if (index != X)
212                                 index = X;
213                         else
214                                 index = P;
215                 }
216                 if (e.getKeyCode() == KeyEvent.VK_Y) {
217                         if (index != Y)
218                                 index = Y;
219                         else
220                                 index = P;
221                 }
222                 if (e.getKeyCode() == KeyEvent.VK_Z) {
223                         if (index != Z)
224                                 index = Z;
225                         else
226                                 index = P;
227                 }
228                 if (e.getKeyCode() == KeyEvent.VK_G) {
229                         worldCoord = !worldCoord;
230                 }
231                 
232                 updateLock();
233                 
234                 return true;
235         }
236         
237         private void updateLock() {
238             gizmo.setType(index);
239             if (axisCombo != null)
240             axisCombo.select(index);
241         panel.refresh();
242         }
243         
244         @Override
245         public boolean keyReleased(KeyEvent e) {
246                 return false;
247         }
248         
249         
250         
251         @Override
252         public boolean mouseClicked(MouseEvent e) {
253                 if (e.getClickCount() > 1) {
254                         if (isOverNode(e)) {
255                                 return true;
256                         }
257                         panel.useDefaultAction();
258                         //if(!gizmo.isPartOf(actor))
259                         //      panel.useDefaultAction();
260                         return true;
261                 }
262                 return false;
263         }
264         
265         
266         
267         
268
269         
270         
271         public void setWorldCoord(boolean b) {
272                 if (worldCoord == b)
273                         return;
274                 worldCoord = b;
275                 update();
276                                         
277         }
278         
279         
280         private void update() {
281                 Vector3d nodePos = node.getWorldPosition();
282 //              System.out.println(nodePos);
283                 gizmo.setPosition(nodePos);
284                 if (worldCoord) {
285                         gizmo.setRotation(new AxisAngle4d());
286                         parentWorldOrientation = null;
287                 } else {
288                         AxisAngle4d aa = new AxisAngle4d();
289                         parentWorldOrientation = ((IG3DNode)node.getParent()).getWorldOrientation();
290                         aa.set(parentWorldOrientation);
291                         gizmo.setRotation(aa);
292                 }
293
294                 Point3d camPos = new Point3d(panel.getRenderer().GetActiveCamera().GetPosition());
295                 Vector3d p = new Vector3d(nodePos);
296                 p.sub(camPos);
297                 
298                 if (parentWorldOrientation != null) {
299                         Quat4d qi = new Quat4d(parentWorldOrientation);
300                         qi.inverse();
301                         MathTools.rotate(parentWorldOrientation, p, p);
302                 }
303                 if (panel.getRenderer().GetActiveCamera().GetParallelProjection() == 0) {
304                         double distance = p.length();
305                         p.negate();
306                         double fov = panel.getRenderer().GetActiveCamera().GetViewAngle();
307                         float s = (float) (Math.sin(fov) * distance * 0.1); 
308
309                         Vector3d scale = new Vector3d(1., 1., 1.);
310                         
311 //            if (p.x > 0.f)
312 //                scale.x = -1.;
313 //            if (p.y > 0.f)
314 //                scale.y = -1.;
315 //            if (p.z > 0.f)
316 //                scale.z = -1.;
317                         scale.scale(s);
318                         gizmo.setScale(scale);
319                         
320                 } else {
321                         Vector3d scale = new Vector3d(1.f, 1.f, 1.f);
322                         double s = panel.getRenderer().GetActiveCamera().GetParallelScale() / 5.;
323 //            if (p.x > 0.f)
324 //                scale.x = -1.;
325 //            if (p.y > 0.f)
326 //                scale.y = -1.;
327 //            if (p.z > 0.f)
328 //                scale.z = -1.;
329                         scale.scale(s);
330                         gizmo.setScale(scale);
331                 }
332                 
333                 panel.refresh();
334         }
335         
336         private boolean isOverNode(MouseEvent e) {
337                 vtkProp picked[] = panel.pick(e.getX(), e.getY());
338                 if (picked !=null) {
339                         for (int i = 0; i < picked.length; i++) {
340                                 if (node.equals(nodeMap.getNode(picked[i])))
341                                         return true;
342                         }
343                 }
344                 return false;
345         }
346         
347
348         
349         @Override
350         public boolean mousePressed(MouseEvent e) {
351                 if (e.getButton() == MouseEvent.BUTTON1) {
352         
353         
354                         if (isOverNode(e)) {
355                                 valid = true;
356                                 if ((e.getModifiers() & MouseEvent.CTRL_MASK) > 0) {
357                                         useStep = true;
358                                 } else {
359                                         useStep = false;
360                                 }
361                                 worldOrientation = node.getWorldOrientation();
362                                 doChanges(true, e.getX(), e.getY());
363                                 
364                                 panel.getComponent().setCursor(dragCursor);
365                         } else {
366                                 valid = false;
367                                 getDefaultAction().mousePressed(e);
368                                 panel.getComponent().setCursor(activeCursor);
369                         }
370                 } else {
371                         getDefaultAction().mousePressed(e);
372                 }
373                 return true;
374         }
375         
376         
377         
378         @Override
379         public boolean mouseReleased(MouseEvent e) {
380                 if (e.getButton() == MouseEvent.BUTTON1) {
381                         valid = false;
382                         worldOrientation = null;
383                         panel.getComponent().setCursor(activeCursor);
384                 } else {
385                         getDefaultAction().mouseReleased(e);
386                 }
387                 return true;
388         }
389         
390         @Override
391         public boolean mouseDragged(MouseEvent e) {
392                 if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) > 0 && valid) { 
393                         if ((e.getModifiers() & MouseEvent.CTRL_MASK) > 0) {
394                                 useStep = true;
395                         } else {
396                                 useStep = false;
397                         }
398                         doChanges(false, e.getX(), e.getY());
399                         
400                         //nodeMap.modified(node);
401                         update();
402                 } else {
403                         getDefaultAction().mouseDragged(e);
404                         update();
405                 }
406                 return true;
407         }
408         
409         Vector3d axis = null;
410         
411         @Override
412         public boolean keyTyped(KeyEvent e) {
413                 if (e.getKeyCode() == KeyEvent.VK_LEFT) {
414                         inputType = InputType.KEY;
415                         axis = new Vector3d(0.0,1.0,0.0);
416                 } else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
417                         inputType = InputType.KEY;
418                         axis = new Vector3d(0.0,-1.0,0.0);
419                 } else if (e.getKeyCode() ==KeyEvent.VK_UP) {
420                         inputType = InputType.KEY;
421                         axis = new Vector3d(1.0,0.0,0.0);
422                 } else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
423                         inputType = InputType.KEY;
424                         axis = new Vector3d(-1.0,0.0,0.0);
425                 } 
426                 return true;
427         }
428         
429         public void doChanges(boolean pressed, int x, int y) {
430                 Ray ray = vtkUtil.createMouseRay(panel.getRenderer(),x, y);
431                 Vector3d p = node.getWorldPosition();
432                 
433                 if (pressed) {
434                         Vector3d axis = getRotationAxis();
435                         if (axis != null) {
436                                 if (!worldCoord) {
437                                         MathTools.rotate(parentWorldOrientation, axis, axis);
438                                 }
439
440                                 
441                                 double s[] = new double[2];
442                                 Vector3d i2 = new Vector3d();
443                                 
444                                 boolean intersect = MathTools.intersectStraightPlane(ray.pos, ray.dir, p, axis, i2, s);
445                                 double dot = Math.abs(ray.dir.dot(axis));
446                                 if (intersect &&  dot > 0.4)
447                                         inputType = InputType.INTERSECT;
448                                 else
449                                         inputType = InputType.NONINTERSECT;
450                                         
451                                 
452                                 if (inputType == InputType.INTERSECT) {
453                                         // picking ray and plane defined by gizmo's center point and
454                                         // rotation axis can intersect
455                                         // vector from center point to intersection point
456                                         i2.sub(p);
457                                         // creating vectors i and j that are lying on the plane and
458                                         // are perpendicular
459                                         // vectors are used to calculate polar coordinate for
460                                         // intersection point
461                                         j.set(i2);
462                                         i.cross(j, axis);
463 //                                      System.out.println("I,J " + i + " " + j);
464                                         double angleI = i2.angle(i);
465                                         double angleJ = i2.angle(j);
466                                         prevAngle = Math.atan2(Math.cos(angleJ), Math.cos(angleI));
467                                 } else {
468                                         // picking ray and plane defined by gizmo's center point and
469                                         // rotation axis are parallel,
470                                         // so we'll use cross product of rotation axis and picking
471                                         // ray to detect amount of rotation
472                                         i.cross(ray.dir, axis);
473                                         MathTools.intersectStraightStraight(ray.pos, ray.dir, p, i, new Vector3d(), new Vector3d(), s);
474                                         prevS = s[1];
475                                 }
476                         }
477                         
478                         
479                 }
480
481                 if (inputType != InputType.KEY)
482                         axis = getRotationAxis();
483                 if (axis == null) {
484                         return;   
485                 }
486                 Vector3d taxis = null;
487                 if (!worldCoord) {
488                         taxis = new Vector3d(axis);
489                         MathTools.rotate(parentWorldOrientation, axis, axis);
490                 }
491 //              System.out.println(inputType);
492                 if (inputType == InputType.INTERSECT) {
493
494                         double s[] = new double[2];
495                         Vector3d i2 = new Vector3d();
496                         MathTools.intersectStraightPlane(ray.pos, ray.dir, p, axis, i2, s);
497                         i2.sub(p);
498                         double angleI = i2.angle(i);
499                         double angleJ = i2.angle(j);
500                         double angle = Math.atan2(Math.cos(angleJ), Math.cos(angleI));
501 //                      System.out.println("Angle " + angle + " i " + angleI + " j " + angleJ + " prev " + prevAngle);
502                         if(!worldCoord)
503                                 axis = taxis;
504                         if (useStep) {
505
506                                 //setOrientation(MathTools.getQuat(rotation));
507                                 AxisAngle4d rot = new AxisAngle4d(axis,angle-prevAngle);
508                                 Quat4d qrot = new Quat4d();
509                                 MathTools.getQuat(rot, qrot);
510                                 //prevAngle = angle;
511                                 qrot.mulInverse(worldOrientation);
512                                 
513                                 
514                                 if (stepMethod == 0) {
515                                         rot.set(qrot);
516                                         rot.angle = roundAngle(rot.angle);
517                                         //qrot.set(rot);
518                                         MathTools.getQuat(rot,qrot);
519                                         setOrientation(qrot);
520                                 } else if (stepMethod == 1){
521                                         
522                                         //Vector3d euler = MathTools.getEuler(qrot);
523                                         Vector3d euler = EulerTools.getEulerFromQuat(order, qrot);
524                                         euler.x = roundAngle(euler.x);
525                                         euler.y = roundAngle(euler.y);
526                                         euler.z = roundAngle(euler.z);
527                                         //Quat4d q = MathTools.getQuat(euler);
528                                         Quat4d q = EulerTools.getQuatFromEuler(order, euler);
529                                         setOrientation(q);
530 //                                      System.out.println(" (" + MathTools.radToDeg(euler.x) + " " + MathTools.radToDeg(euler.y) + " " + MathTools.radToDeg(euler.z) +  ") " + qrot + " "+ q);
531                                 } else {
532                                         setOrientation(qrot);
533                                 }
534                                 
535                         } else {
536                                 if (worldCoord) {
537                                         //G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,angle-prevAngle));
538                                         AxisAngle4d aa = MathTools.getAxisAngle(node.getWorldOrientation());
539                                         AxisAngle4d rot = new AxisAngle4d(axis,angle-prevAngle);
540                                         MathTools.multiplyOrientation(aa, rot);
541                                         setWorldOrientation(MathTools.getQuat(rot));
542                                 } else {
543                                         AxisAngle4d aa = MathTools.getAxisAngle(node.getOrientation());
544                                         AxisAngle4d rot = new AxisAngle4d(axis,angle-prevAngle);
545                                         MathTools.multiplyOrientation(aa, rot);
546                                         setOrientation(MathTools.getQuat(rot));
547                                         //G3DTools.multiplyOrientation(mo.getG3DNode(graph).getLocalOrientation(), new AxisAngle4d(axis,angle-prevAngle));
548                                 }
549                                 prevAngle = angle;
550                         }
551                         
552                 } else if (inputType == InputType.NONINTERSECT){
553
554                         double s[] = new double[2];
555                         MathTools.intersectStraightStraight(ray.pos, ray.dir, p, i, new Vector3d(), new Vector3d(), s);
556                         if(!worldCoord)
557                                 axis = taxis;
558                         if (useStep) {
559                                 //setOrientation(MathTools.getQuat(rotation));
560                                 AxisAngle4d rot = new AxisAngle4d(axis,s[1] - prevS);
561                                 
562                                 Quat4d qrot = new Quat4d();
563                                 //qrot.set(rot);
564                                 MathTools.getQuat(rot, qrot);
565                                 //prevAngle = angle;
566                                 qrot.mulInverse(worldOrientation);
567                                 
568                                 
569                                 if (stepMethod == 0) {
570                                         rot.set(qrot);
571                                         rot.angle = roundAngle(rot.angle);
572                                         //qrot.set(rot);
573                                         MathTools.getQuat(rot,qrot);
574                                         setOrientation(qrot);
575                                 } else if (stepMethod == 1){
576                                         
577                                         //Vector3d euler = MathTools.getEuler(qrot);
578                                         Vector3d euler = EulerTools.getEulerFromQuat(order, qrot);
579                                         euler.x = roundAngle(euler.x);
580                                         euler.y = roundAngle(euler.y);
581                                         euler.z = roundAngle(euler.z);
582                                         //Quat4d q = MathTools.getQuat(euler);
583                                         Quat4d q = EulerTools.getQuatFromEuler(order, euler);
584                                         setOrientation(q);
585 //                                      System.out.println(" (" + MathTools.radToDeg(euler.x) + " " + MathTools.radToDeg(euler.y) + " " + MathTools.radToDeg(euler.z) +  ") " + qrot + " "+ q);
586                                 } else {
587                                         setOrientation(qrot);
588                                 }
589                                 prevS = s[1];
590                                 
591 //                    G3DTools.setOrientation(mo.getG3DNode(graph).getLocalOrientation(), rotations.get(mo));
592 //                    G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,s[1] - prevS));
593 //                    AxisAngle4d aa = G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation());
594 //                    rotations.put(mo, aa);
595 //                    Vector3d euler = MathTools.getEuler(aa);
596 //                    euler.x = roundAngle(euler.x);
597 //                    euler.y = roundAngle(euler.y);
598 //                    euler.z = roundAngle(euler.z);
599 //                    aa = MathTools.getFromEuler2(euler);
600 //                    prevS = s[1];
601 //                    G3DTools.setOrientation(mo.getG3DNode(graph).getLocalOrientation(), aa);
602 //                    Vector3d e = MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()));
603 //                    e.scale(180.0/Math.PI);
604 //                    text += G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()) + " " + e + " ";
605                                 
606                                 
607                         } else {
608                                         if (worldCoord) {
609                                                 AxisAngle4d aa =  MathTools.getAxisAngle(node.getWorldOrientation());
610                                                 AxisAngle4d rot = new AxisAngle4d(axis,s[1] - prevS);
611                                                 MathTools.multiplyOrientation(aa, rot);
612                                                 setWorldOrientation(MathTools.getQuat(rot));
613                                                 //G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,s[1] - prevS));
614                                         } else {
615                                                 AxisAngle4d aa =  MathTools.getAxisAngle(node.getOrientation());
616                                                 AxisAngle4d rot = new AxisAngle4d(axis,s[1] - prevS);
617                                                 MathTools.multiplyOrientation(aa, rot);
618                                                 setOrientation(MathTools.getQuat(rot));
619                                                 //G3DTools.multiplyOrientation(mo.getG3DNode(graph).getLocalOrientation(), new AxisAngle4d(axis,s[1] - prevS));
620                                         }
621                                         //text += G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()) + " " + MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation())) + " ";
622                                 prevS = s[1];
623                                 
624                         }
625                 
626                 } else {
627                         if (worldCoord) {
628                                 AxisAngle4d aa = MathTools.getAxisAngle(node.getWorldOrientation());
629                                 AxisAngle4d rot = new AxisAngle4d(axis,Math.PI * 0.5);
630                                 MathTools.multiplyOrientation(aa, rot);
631                                 setWorldOrientation(MathTools.getQuat(rot));
632                                 //G3DTools.multiplyOrientation(mo.getG3DNode(graph).getWorldOrientation(), new AxisAngle4d(axis,Math.PI * 0.5));
633                         } else {
634                                 AxisAngle4d aa = MathTools.getAxisAngle(node.getOrientation());
635                                 AxisAngle4d rot = new AxisAngle4d(axis,Math.PI * 0.5);
636                                 MathTools.multiplyOrientation(aa, rot);
637                                 setOrientation(MathTools.getQuat(rot));
638                                 //G3DTools.multiplyOrientation(mo.getG3DNode(graph).getLocalOrientation(), new AxisAngle4d(axis,Math.PI * 0.5));
639                         }
640                         //   text += G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation()) + " " + MathTools.getEuler(G3DTools.getOrientation(mo.getG3DNode(graph).getLocalOrientation())) + " ";
641                         
642                 }
643                 //setInfoText(text);
644                 
645         }
646         
647         protected void setOrientation(Quat4d q) {
648                 node.setOrientation(q);
649         }
650         
651         protected void setWorldOrientation(Quat4d q) {
652                 node.setWorldOrientation(q);
653         }
654         
655         @Override
656         public boolean mouseMoved(MouseEvent e) {
657                 return getDefaultAction().mouseMoved(e);
658         }
659         
660         private Vector3d getRotationAxis() {
661                 switch (index) {
662                 case X:
663                         return new Vector3d(1.0, 0.0, 0.0);
664                 case Y:
665                         return new Vector3d(0.0, 1.0, 0.0);
666                 case Z:
667                         return new Vector3d(0.0, 0.0, 1.0);
668                 case P:
669                         Vector3d axis = new Vector3d(panel.getRenderer().GetActiveCamera().GetDirectionOfProjection());
670                         axis.normalize();
671                         return axis;
672                 default:
673                         return null;
674                 }
675         }
676         
677         private double prevS = 0.0;
678                 
679         private Vector3d i = new Vector3d();
680         private Vector3d j = new Vector3d();
681         private double prevAngle = 0;
682
683         enum InputType{INTERSECT,NONINTERSECT,KEY,NONE};
684         InputType inputType;
685         private boolean useStep = false;
686         
687         
688         
689         private double roundAngle(double angle) {
690                 while (angle < - Math.PI)
691                         angle += Math.PI*2.0;
692                 while (angle > Math.PI)
693                         angle -= Math.PI*2.0;
694                 
695                 
696                 int index = 0;
697                 while (angle > angles[index])
698                         index++;
699                 if (index == 0) {
700                         angle = angles[0];
701                 } else {
702                         double d = angle - angles[index - 1];
703                         double d2 = angles[index] - angle;
704                         if (d < d2)
705                                 angle = angles[index - 1];
706                         else
707                                 angle = angles[index];
708                 }
709                 return angle;
710         }
711         
712 }