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