View Javadoc

1   // Copyright 2004-2005, FreeHEP.
2   package hep.wired.edit;
3   
4   import java.awt.*;
5   import java.awt.geom.*;
6   import java.util.logging.*;
7   import javax.swing.*;
8   import javax.swing.undo.*;
9   
10  import hep.wired.services.RecordPlot;
11  import hep.wired.services.GraphicsPanel;
12  import hep.wired.util.Matrix3D;
13  import hep.wired.feature.Rotateable2D;
14  import hep.wired.feature.Rotateable3D;
15  
16  /***
17   * Rotates a plot in 2D or 3D.
18   *
19   * @author Mark Donszelmann
20   * @version $Id: Rotate.java 689 2005-03-16 09:06:57Z duns $
21   */
22  public class Rotate extends AnimatedWiredEdit implements GraphicsPanelEdit {
23  
24      private static Logger logger = Logger.getLogger(Rotate.class.getPackage().getName());
25      
26      // Note: due to precision problems, we keep both the matrix (int the last edit)
27      // and vector and theta in each edit. 
28      // We use vector and theta for the actual changes, while we use the matrix
29      // to display the redo/undo presentation name.
30      // FIXME WIRED-224 We need to decide if we implement rotate with a orthonormalized matrix
31      // rather than extracting a vector and an angle
32      private double nx, ny, nz;
33      private double theta;
34      private Matrix3D matrix;
35  
36      /***
37       * Creates a rotate edit with no rotation.
38       */
39      public Rotate() {
40          this(0, 0, 0, 1);
41      }
42  
43      /***    
44       * Creates a rotate edit with given rotation.
45       */    
46      public Rotate(double theta, double nx, double ny, double nz) {
47          this(theta, nx, ny, nz, null, 0);
48      }
49  
50      /***    
51       * Creates a rotate edit with given rotation, animation shape and number of frames.
52       */    
53      public Rotate(double theta, double nx, double ny, double nz,
54                    Shape shape, int frames) {
55          super(shape, frames);
56          matrix = Matrix3D.getRotateInstance(theta, nx, ny, nz);
57          this.theta = theta;
58          this.nx = nx;
59          this.ny = ny;
60          this.nz = nz;
61      }
62      
63      public WiredEdit copy(RecordPlot plot) {
64          WiredEdit copy = new Rotate(theta, nx, ny, nz, getShape(), getFrames());
65          copy.setRecordPlot(plot);
66          return copy;
67      }
68      
69      protected Shape[] getShapes(Shape shape, int steps) {
70          if ((shape == null) || (steps <= 1)) return null;
71  
72          // only for rotation over Z-axis        
73          if ((nx != 0) || (ny != 0) || (nz != 1)) return null;
74  
75          Shape[] shapes = new Shape[steps];
76  
77          // calculate rotate increments
78          double dtheta = theta/(steps-1);
79  
80          // calculate window offset
81          double w = getRecordPlot().getWidth()/2.0;
82          double h = getRecordPlot().getHeight()/2.0;
83  
84          // calculate steps
85          for (int i=0; i<steps; i++) {
86              AffineTransform transform = new AffineTransform();
87              // rotate
88              transform.rotate(-i*dtheta, w, h);
89              // transform
90              shapes[i] = transform.createTransformedShape(shape);
91          }
92          return shapes;
93      }
94  
95      public Shape createTransformedShape(Component component, Shape shape) {
96          // only for rotation over Z-axis        
97          if ((nx != 0) || (ny != 0) || (nz != 1)) return null;
98  
99          double w = component.getWidth()/2.0;
100         double h = component.getHeight()/2.0;
101 
102         AffineTransform transform = new AffineTransform();
103         transform.rotate(-theta, w, h);
104         return transform.createTransformedShape(shape);
105     }
106 
107     public String getPresentationName() {
108         double[] n = new double[3];
109         double theta = matrix.getRotation(n);
110         return toString()+" "+format.format(Math.toDegrees(theta))+" degrees over ("+format.format(n[0])+", "+format.format(n[1])+", "+format.format(n[2])+")";
111     }
112     
113     public String toString() {
114         return "Rotate";
115     }
116 
117     public boolean addEdit(UndoableEdit edit) {
118         if (edit instanceof Rotate) {
119             Rotate rotate = (Rotate)edit;
120             matrix.preConcatenate(rotate.matrix);
121             // orthonormalize to keep matrix from skewing...
122             matrix = matrix.createOrthonormalized();
123             // copy the matrix into the edit
124             rotate.matrix = matrix;
125             
126             // we return false to keep the single rotations stacked up.            
127             return false;
128         }
129         return false;
130     }
131 
132     public boolean isSupportedBy(GraphicsPanel p) {
133         return p.supports(Rotateable2D.class) || p.supports(Rotateable3D.class);
134     }
135 
136     protected void redoEdit() {
137         GraphicsPanel panel = getRecordPlot().getGraphicsPanel();
138         Rotateable3D rotateable3D = (Rotateable3D)panel.getFeature(Rotateable3D.class);
139         if (rotateable3D != null) {        
140             rotateable3D.rotate(theta, nx, ny, nz);          
141         } else {
142             Rotateable2D rotateable2D = (Rotateable2D)panel.getFeature(Rotateable2D.class);
143             if (rotateable2D == null) {
144                 System.err.println("Could not redo: "+this);
145                 return;
146             }
147             // FIXME, WIRED-224 theta may not be correct...
148             rotateable2D.rotate(theta);
149         }
150         getRecordPlot().repaint();
151         logger.finer(toString());
152     }
153 
154     protected void undoEdit() {
155         GraphicsPanel panel = getRecordPlot().getGraphicsPanel();
156         Rotateable3D rotateable3D = (Rotateable3D)panel.getFeature(Rotateable3D.class);
157         if (rotateable3D != null) {        
158             rotateable3D.rotate(-theta, nx, ny, nz);          
159         } else {
160             Rotateable2D rotateable2D = (Rotateable2D)panel.getFeature(Rotateable2D.class);
161             if (rotateable2D == null) {
162                 System.err.println("Could not undo: "+this);
163                 return;
164             }
165             // FIXME, WIRED-224 theta may not be correct...
166             rotateable2D.rotate(-theta);
167         }
168         getRecordPlot().repaint();
169         logger.finer(toString());
170     }
171 }