View Javadoc

1   /*
2    * Copyright (c) 2005, the JUNG Project and the Regents of the University of
3    * California All rights reserved.
4    *
5    * This software is open-source under the BSD license; see either "license.txt"
6    * or http://jung.sourceforge.net/license.txt for a description.
7    *
8    * Created on Apr 16, 2005
9    */
10  
11  package edu.uci.ics.jung.visualization.transform;
12  
13  import java.awt.Shape;
14  import java.awt.geom.AffineTransform;
15  import java.awt.geom.GeneralPath;
16  import java.awt.geom.NoninvertibleTransformException;
17  import java.awt.geom.PathIterator;
18  import java.awt.geom.Point2D;
19  
20  import edu.uci.ics.jung.visualization.transform.shape.ShapeTransformer;
21  
22  /**
23   *
24   * Provides methods to map points from one coordinate system to
25   * another, by delegating to a wrapped AffineTransform (uniform)
26   * and its inverse.
27   * 
28   * @author Tom Nelson
29   */
30  public class AffineTransformer implements BidirectionalTransformer, ShapeTransformer {
31  
32      protected AffineTransform inverse;
33  
34      /**
35       * the AffineTransform to use. Initialize to identity
36       * 
37       */
38      protected AffineTransform transform = new AffineTransform();
39      
40      /**
41       * create an instance that does not transform points
42       *
43       */
44      public AffineTransformer() {
45          // nothing left to do
46      }
47      /**
48       * Create an instance with the supplied transform
49       */
50      public AffineTransformer(AffineTransform transform) {
51          if(transform != null) 
52              this.transform = transform;
53      }
54  
55      /**
56       * @return Returns the transform.
57       */
58      public AffineTransform getTransform() {
59          return transform;
60      }
61      /**
62       * @param transform The transform to set.
63       */
64      public void setTransform(AffineTransform transform) {
65          this.transform = transform;
66      }
67      
68      /**
69       * applies the inverse transform to the supplied point
70       * @param p
71       * @return
72       */
73      public Point2D inverseTransform(Point2D p) {
74  
75          return getInverse().transform(p, null);
76      }
77      
78      public AffineTransform getInverse() {
79          if(inverse == null) {
80              try {
81                  inverse = transform.createInverse();
82              } catch (NoninvertibleTransformException e) {
83                  e.printStackTrace();
84              }
85          }
86          return inverse;
87      }
88      
89      /**
90       * getter for scalex
91       */
92      public double getScaleX() {
93          return transform.getScaleX();   
94      }
95      
96      /**
97       * getter for scaley
98       */
99      public double getScaleY() {
100         return transform.getScaleY();
101     }
102     
103     public double getScale() {
104     		return Math.sqrt(transform.getDeterminant());
105     }
106     
107     /**
108      * getter for shear in x axis
109      */
110     public double getShearX() {
111         return transform.getShearX();
112     }
113     
114     /**
115      * getter for shear in y axis
116      */
117     public double getShearY() {
118         return transform.getShearY();
119     }
120     
121     /**
122      * get the translate x value
123      */
124     public double getTranslateX() {
125         return transform.getTranslateX();
126     }
127     
128     /**
129      * get the translate y value
130      */
131     public double getTranslateY() {
132         return transform.getTranslateY();
133     }
134     
135 
136     
137     
138     
139     /**
140      * applies the transform to the supplied point
141      */
142     public Point2D transform(Point2D p) {
143         if(p == null) return null;
144         return transform.transform(p, null);
145     }
146     
147     /**
148      * transform the supplied shape from graph coordinates to
149      * screen coordinates
150      * @return the GeneralPath of the transformed shape
151      */
152     public Shape transform(Shape shape) {
153         GeneralPath newPath = new GeneralPath();
154         float[] coords = new float[6];
155         for(PathIterator iterator=shape.getPathIterator(null);
156             iterator.isDone() == false;
157             iterator.next()) {
158             int type = iterator.currentSegment(coords);
159             switch(type) {
160             case PathIterator.SEG_MOVETO:
161                 Point2D p = transform(new Point2D.Float(coords[0], coords[1]));
162                 newPath.moveTo((float)p.getX(), (float)p.getY());
163                 break;
164                 
165             case PathIterator.SEG_LINETO:
166                 p = transform(new Point2D.Float(coords[0], coords[1]));
167                 newPath.lineTo((float)p.getX(), (float) p.getY());
168                 break;
169                 
170             case PathIterator.SEG_QUADTO:
171                 p = transform(new Point2D.Float(coords[0], coords[1]));
172                 Point2D q = transform(new Point2D.Float(coords[2], coords[3]));
173                 newPath.quadTo((float)p.getX(), (float)p.getY(), (float)q.getX(), (float)q.getY());
174                 break;
175                 
176             case PathIterator.SEG_CUBICTO:
177                 p = transform(new Point2D.Float(coords[0], coords[1]));
178                 q = transform(new Point2D.Float(coords[2], coords[3]));
179                 Point2D r = transform(new Point2D.Float(coords[4], coords[5]));
180                 newPath.curveTo((float)p.getX(), (float)p.getY(), 
181                         (float)q.getX(), (float)q.getY(),
182                         (float)r.getX(), (float)r.getY());
183                 break;
184                 
185             case PathIterator.SEG_CLOSE:
186                 newPath.closePath();
187                 break;
188                     
189             }
190         }
191         return newPath;
192     }
193 
194     /**
195      * transform the supplied shape from graph coordinates to
196      * screen coordinates
197      * @return the GeneralPath of the transformed shape
198      */
199     public Shape inverseTransform(Shape shape) {
200         GeneralPath newPath = new GeneralPath();
201         float[] coords = new float[6];
202         for(PathIterator iterator=shape.getPathIterator(null);
203             iterator.isDone() == false;
204             iterator.next()) {
205             int type = iterator.currentSegment(coords);
206             switch(type) {
207             case PathIterator.SEG_MOVETO:
208                 Point2D p = inverseTransform(new Point2D.Float(coords[0], coords[1]));
209                 newPath.moveTo((float)p.getX(), (float)p.getY());
210                 break;
211                 
212             case PathIterator.SEG_LINETO:
213                 p = inverseTransform(new Point2D.Float(coords[0], coords[1]));
214                 newPath.lineTo((float)p.getX(), (float) p.getY());
215                 break;
216                 
217             case PathIterator.SEG_QUADTO:
218                 p = inverseTransform(new Point2D.Float(coords[0], coords[1]));
219                 Point2D q = inverseTransform(new Point2D.Float(coords[2], coords[3]));
220                 newPath.quadTo((float)p.getX(), (float)p.getY(), (float)q.getX(), (float)q.getY());
221                 break;
222                 
223             case PathIterator.SEG_CUBICTO:
224                 p = inverseTransform(new Point2D.Float(coords[0], coords[1]));
225                 q = inverseTransform(new Point2D.Float(coords[2], coords[3]));
226                 Point2D r = inverseTransform(new Point2D.Float(coords[4], coords[5]));
227                 newPath.curveTo((float)p.getX(), (float)p.getY(), 
228                         (float)q.getX(), (float)q.getY(),
229                         (float)r.getX(), (float)r.getY());
230                 break;
231                 
232             case PathIterator.SEG_CLOSE:
233                 newPath.closePath();
234                 break;
235                     
236             }
237         }
238         return newPath;
239     }
240     
241     public double getRotation() {    
242         double[] unitVector = new double[]{0,0,1,0};
243         double[] result = new double[4];
244 
245         transform.transform(unitVector, 0, result, 0, 2);
246 
247         double dy = Math.abs(result[3] - result[1]);
248         double length = Point2D.distance(result[0], result[1], result[2], result[3]);
249         double rotation = Math.asin(dy / length);        
250         
251         if (result[3] - result[1] > 0) {
252             if (result[2] - result[0] < 0) {
253                 rotation = Math.PI - rotation;
254             }
255         } else {
256             if (result[2] - result[0] > 0) {
257                 rotation = 2 * Math.PI - rotation;
258             } else {
259                 rotation = rotation + Math.PI;
260             }
261         }
262 
263         return rotation;
264     }
265 
266     @Override
267     public String toString() {
268         return "Transformer using "+transform;
269     }
270  
271 }