View Javadoc

1   /*
2    * Copyright (c) 2003, 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    */
9   package edu.uci.ics.jung.visualization.transform.shape;
10  
11  import java.awt.Component;
12  import java.awt.Shape;
13  import java.awt.geom.GeneralPath;
14  import java.awt.geom.PathIterator;
15  import java.awt.geom.Point2D;
16  
17  import edu.uci.ics.jung.algorithms.layout.PolarPoint;
18  import edu.uci.ics.jung.visualization.transform.MagnifyTransformer;
19  import edu.uci.ics.jung.visualization.transform.MutableTransformer;
20  
21  /**
22   * MagnifyShapeTransformer extends MagnifyTransformer and
23   * adds implementations for methods in ShapeTransformer.
24   * It modifies the shapes (Vertex, Edge, and Arrowheads) so that
25   * they are enlarged by the magnify transformation
26   * 
27   * @author Tom Nelson
28   *
29   *
30   */
31  public class MagnifyShapeTransformer extends MagnifyTransformer 
32      implements ShapeFlatnessTransformer {
33  
34      /**
35       * Create an instance, setting values from the passed component
36       * and registering to listen for size changes on the component.
37       */
38      public MagnifyShapeTransformer(Component component) {
39          this(component, null);
40      }
41      
42      /**
43       * Create an instance, setting values from the passed component
44       * and registering to listen for size changes on the component,
45       * with a possibly shared transform <code>delegate</code>.
46       */
47      public MagnifyShapeTransformer(Component component, MutableTransformer delegate) {
48          super(component, delegate);
49     }
50      
51      /**
52       * Transform the supplied shape with the overridden transform
53       * method so that the shape is distorted by the magnify 
54       * transform.
55       * @param shape a shape to transform
56       * @return a GeneralPath for the transformed shape
57       */
58      public Shape transform(Shape shape) {
59          return transform(shape, 0);
60      }
61      public Shape transform(Shape shape, float flatness) {
62          GeneralPath newPath = new GeneralPath();
63          float[] coords = new float[6];
64          PathIterator iterator = null;
65          if(flatness == 0) {
66              iterator = shape.getPathIterator(null);
67          } else {
68              iterator = shape.getPathIterator(null, flatness);
69          }
70          for( ;
71              iterator.isDone() == false;
72              iterator.next()) {
73              int type = iterator.currentSegment(coords);
74              switch(type) {
75              case PathIterator.SEG_MOVETO:
76                  Point2D p = _transform(new Point2D.Float(coords[0], coords[1]));
77                  newPath.moveTo((float)p.getX(), (float)p.getY());
78                  break;
79                  
80              case PathIterator.SEG_LINETO:
81                  p = _transform(new Point2D.Float(coords[0], coords[1]));
82                  newPath.lineTo((float)p.getX(), (float) p.getY());
83                  break;
84                  
85              case PathIterator.SEG_QUADTO:
86                  p = _transform(new Point2D.Float(coords[0], coords[1]));
87                  Point2D q = _transform(new Point2D.Float(coords[2], coords[3]));
88                  newPath.quadTo((float)p.getX(), (float)p.getY(), (float)q.getX(), (float)q.getY());
89                  break;
90                  
91              case PathIterator.SEG_CUBICTO:
92                  p = _transform(new Point2D.Float(coords[0], coords[1]));
93                  q = _transform(new Point2D.Float(coords[2], coords[3]));
94                  Point2D r = _transform(new Point2D.Float(coords[4], coords[5]));
95                  newPath.curveTo((float)p.getX(), (float)p.getY(), 
96                          (float)q.getX(), (float)q.getY(),
97                          (float)r.getX(), (float)r.getY());
98                  break;
99                  
100             case PathIterator.SEG_CLOSE:
101                 newPath.closePath();
102                 break;
103                     
104             }
105         }
106         return newPath;
107     }
108 
109     public Shape inverseTransform(Shape shape) {
110         GeneralPath newPath = new GeneralPath();
111         float[] coords = new float[6];
112         for(PathIterator iterator=shape.getPathIterator(null);
113             iterator.isDone() == false;
114             iterator.next()) {
115             int type = iterator.currentSegment(coords);
116             switch(type) {
117             case PathIterator.SEG_MOVETO:
118                 Point2D p = _inverseTransform(new Point2D.Float(coords[0], coords[1]));
119                 newPath.moveTo((float)p.getX(), (float)p.getY());
120                 break;
121                 
122             case PathIterator.SEG_LINETO:
123                 p = _inverseTransform(new Point2D.Float(coords[0], coords[1]));
124                 newPath.lineTo((float)p.getX(), (float) p.getY());
125                 break;
126                 
127             case PathIterator.SEG_QUADTO:
128                 p = _inverseTransform(new Point2D.Float(coords[0], coords[1]));
129                 Point2D q = _inverseTransform(new Point2D.Float(coords[2], coords[3]));
130                 newPath.quadTo((float)p.getX(), (float)p.getY(), (float)q.getX(), (float)q.getY());
131                 break;
132                 
133             case PathIterator.SEG_CUBICTO:
134                 p = _inverseTransform(new Point2D.Float(coords[0], coords[1]));
135                 q = _inverseTransform(new Point2D.Float(coords[2], coords[3]));
136                 Point2D r = _inverseTransform(new Point2D.Float(coords[4], coords[5]));
137                 newPath.curveTo((float)p.getX(), (float)p.getY(), 
138                         (float)q.getX(), (float)q.getY(),
139                         (float)r.getX(), (float)r.getY());
140                 break;
141                 
142             case PathIterator.SEG_CLOSE:
143                 newPath.closePath();
144                 break;
145                     
146             }
147         }
148         return newPath;
149     }
150     /**
151      * 
152      */
153     private Point2D _transform(Point2D graphPoint) {
154         if(graphPoint == null) return null;
155         Point2D viewCenter = getViewCenter();
156         double viewRadius = getViewRadius();
157         double ratio = getRatio();
158         // transform the point from the graph to the view
159         Point2D viewPoint = graphPoint;
160 //        	delegate.transform(graphPoint);
161         // calculate point from center
162         double dx = viewPoint.getX() - viewCenter.getX();
163         double dy = viewPoint.getY() - viewCenter.getY();
164         // factor out ellipse
165         dx *= ratio;
166         Point2D pointFromCenter = new Point2D.Double(dx, dy);
167         
168         PolarPoint polar = PolarPoint.cartesianToPolar(pointFromCenter);
169         double theta = polar.getTheta();
170         double radius = polar.getRadius();
171         if(radius > viewRadius) return viewPoint;
172         
173         double mag = magnification;
174         radius *= mag;
175         
176         radius = Math.min(radius, viewRadius);
177         Point2D projectedPoint = PolarPoint.polarToCartesian(theta, radius);
178         projectedPoint.setLocation(projectedPoint.getX()/ratio, projectedPoint.getY());
179         Point2D translatedBack = new Point2D.Double(projectedPoint.getX()+viewCenter.getX(),
180                 projectedPoint.getY()+viewCenter.getY());
181         return translatedBack;
182     }
183     
184     /**
185      * override base class to un-project the fisheye effect
186      */
187     private Point2D _inverseTransform(Point2D viewPoint) {
188         
189     	viewPoint = delegate.inverseTransform(viewPoint);
190         Point2D viewCenter = getViewCenter();
191         double viewRadius = getViewRadius();
192         double ratio = getRatio();
193         double dx = viewPoint.getX() - viewCenter.getX();
194         double dy = viewPoint.getY() - viewCenter.getY();
195         // factor out ellipse
196         dx *= ratio;
197 
198         Point2D pointFromCenter = new Point2D.Double(dx, dy);
199         
200         PolarPoint polar = PolarPoint.cartesianToPolar(pointFromCenter);
201 
202         double radius = polar.getRadius();
203         if(radius > viewRadius) return viewPoint;
204         //delegate.inverseTransform(viewPoint);
205         
206         double mag = magnification;
207         radius /= mag;
208         polar.setRadius(radius);
209         Point2D projectedPoint = PolarPoint.polarToCartesian(polar);
210         projectedPoint.setLocation(projectedPoint.getX()/ratio, projectedPoint.getY());
211         Point2D translatedBack = new Point2D.Double(projectedPoint.getX()+viewCenter.getX(),
212                 projectedPoint.getY()+viewCenter.getY());
213 //        return delegate.inverseTransform(translatedBack);
214         return translatedBack;
215     }
216     /**
217      * magnify the shape, without considering the Lens
218      * @param shape
219      * @return
220      */
221     public Shape magnify(Shape shape) {
222         return magnify(shape, 0);
223     }
224     public Shape magnify(Shape shape, float flatness) {
225         GeneralPath newPath = new GeneralPath();
226         float[] coords = new float[6];
227         PathIterator iterator = null;
228         if(flatness == 0) {
229             iterator = shape.getPathIterator(null);
230         } else {
231             iterator = shape.getPathIterator(null, flatness);
232         }
233         for( ;
234             iterator.isDone() == false;
235             iterator.next()) {
236             int type = iterator.currentSegment(coords);
237             switch(type) {
238             case PathIterator.SEG_MOVETO:
239                 Point2D p = magnify(new Point2D.Float(coords[0], coords[1]));
240                 newPath.moveTo((float)p.getX(), (float)p.getY());
241                 break;
242                 
243             case PathIterator.SEG_LINETO:
244                 p = magnify(new Point2D.Float(coords[0], coords[1]));
245                 newPath.lineTo((float)p.getX(), (float) p.getY());
246                 break;
247                 
248             case PathIterator.SEG_QUADTO:
249                 p = magnify(new Point2D.Float(coords[0], coords[1]));
250                 Point2D q = magnify(new Point2D.Float(coords[2], coords[3]));
251                 newPath.quadTo((float)p.getX(), (float)p.getY(), (float)q.getX(), (float)q.getY());
252                 break;
253                 
254             case PathIterator.SEG_CUBICTO:
255                 p = magnify(new Point2D.Float(coords[0], coords[1]));
256                 q = magnify(new Point2D.Float(coords[2], coords[3]));
257                 Point2D r = magnify(new Point2D.Float(coords[4], coords[5]));
258                 newPath.curveTo((float)p.getX(), (float)p.getY(), 
259                         (float)q.getX(), (float)q.getY(),
260                         (float)r.getX(), (float)r.getY());
261                 break;
262                 
263             case PathIterator.SEG_CLOSE:
264                 newPath.closePath();
265                 break;
266                     
267             }
268         }
269         return newPath;
270     }
271 
272 }