View Javadoc
1   /*
2    * Copyright (c) 2003, The JUNG Authors
3    * All rights reserved.
4    * 
5    * This software is open-source under the BSD license; see either "license.txt"
6    * or https://github.com/jrtom/jung/blob/master/LICENSE 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  public class MagnifyShapeTransformer extends MagnifyTransformer 
30      implements ShapeFlatnessTransformer {
31  
32      /**
33       * Create an instance, setting values from the passed component
34       * and registering to listen for size changes on the component.
35       * 
36       * @param component the component used for rendering
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       * @param component the component used for rendering
48       * @param delegate the transformer to use
49       */
50      public MagnifyShapeTransformer(Component component, MutableTransformer delegate) {
51          super(component, delegate);
52     }
53      
54      /**
55       * Transform the supplied shape with the overridden transform
56       * method so that the shape is distorted by the magnify 
57       * transform.
58       * @param shape a shape to transform
59       * @return a GeneralPath for the transformed shape
60       */
61      public Shape transform(Shape shape) {
62          return transform(shape, 0);
63      }
64      public Shape transform(Shape shape, float flatness) {
65          GeneralPath newPath = new GeneralPath();
66          float[] coords = new float[6];
67          PathIterator iterator = null;
68          if(flatness == 0) {
69              iterator = shape.getPathIterator(null);
70          } else {
71              iterator = shape.getPathIterator(null, flatness);
72          }
73          for( ;
74              iterator.isDone() == false;
75              iterator.next()) {
76              int type = iterator.currentSegment(coords);
77              switch(type) {
78              case PathIterator.SEG_MOVETO:
79                  Point2D p = _transform(new Point2D.Float(coords[0], coords[1]));
80                  newPath.moveTo((float)p.getX(), (float)p.getY());
81                  break;
82                  
83              case PathIterator.SEG_LINETO:
84                  p = _transform(new Point2D.Float(coords[0], coords[1]));
85                  newPath.lineTo((float)p.getX(), (float) p.getY());
86                  break;
87                  
88              case PathIterator.SEG_QUADTO:
89                  p = _transform(new Point2D.Float(coords[0], coords[1]));
90                  Point2D q = _transform(new Point2D.Float(coords[2], coords[3]));
91                  newPath.quadTo((float)p.getX(), (float)p.getY(), (float)q.getX(), (float)q.getY());
92                  break;
93                  
94              case PathIterator.SEG_CUBICTO:
95                  p = _transform(new Point2D.Float(coords[0], coords[1]));
96                  q = _transform(new Point2D.Float(coords[2], coords[3]));
97                  Point2D r = _transform(new Point2D.Float(coords[4], coords[5]));
98                  newPath.curveTo((float)p.getX(), (float)p.getY(), 
99                          (float)q.getX(), (float)q.getY(),
100                         (float)r.getX(), (float)r.getY());
101                 break;
102                 
103             case PathIterator.SEG_CLOSE:
104                 newPath.closePath();
105                 break;
106                     
107             }
108         }
109         return newPath;
110     }
111 
112     public Shape inverseTransform(Shape shape) {
113         GeneralPath newPath = new GeneralPath();
114         float[] coords = new float[6];
115         for(PathIterator iterator=shape.getPathIterator(null);
116             iterator.isDone() == false;
117             iterator.next()) {
118             int type = iterator.currentSegment(coords);
119             switch(type) {
120             case PathIterator.SEG_MOVETO:
121                 Point2D p = _inverseTransform(new Point2D.Float(coords[0], coords[1]));
122                 newPath.moveTo((float)p.getX(), (float)p.getY());
123                 break;
124                 
125             case PathIterator.SEG_LINETO:
126                 p = _inverseTransform(new Point2D.Float(coords[0], coords[1]));
127                 newPath.lineTo((float)p.getX(), (float) p.getY());
128                 break;
129                 
130             case PathIterator.SEG_QUADTO:
131                 p = _inverseTransform(new Point2D.Float(coords[0], coords[1]));
132                 Point2D q = _inverseTransform(new Point2D.Float(coords[2], coords[3]));
133                 newPath.quadTo((float)p.getX(), (float)p.getY(), (float)q.getX(), (float)q.getY());
134                 break;
135                 
136             case PathIterator.SEG_CUBICTO:
137                 p = _inverseTransform(new Point2D.Float(coords[0], coords[1]));
138                 q = _inverseTransform(new Point2D.Float(coords[2], coords[3]));
139                 Point2D r = _inverseTransform(new Point2D.Float(coords[4], coords[5]));
140                 newPath.curveTo((float)p.getX(), (float)p.getY(), 
141                         (float)q.getX(), (float)q.getY(),
142                         (float)r.getX(), (float)r.getY());
143                 break;
144                 
145             case PathIterator.SEG_CLOSE:
146                 newPath.closePath();
147                 break;
148                     
149             }
150         }
151         return newPath;
152     }
153     
154     private Point2D _transform(Point2D graphPoint) {
155         if(graphPoint == null) return null;
156         Point2D viewCenter = getViewCenter();
157         double viewRadius = getViewRadius();
158         double ratio = getRatio();
159         // transform the point from the graph to the view
160         Point2D viewPoint = 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         
205         double mag = magnification;
206         radius /= mag;
207         polar.setRadius(radius);
208         Point2D projectedPoint = PolarPoint.polarToCartesian(polar);
209         projectedPoint.setLocation(projectedPoint.getX()/ratio, projectedPoint.getY());
210         Point2D translatedBack = new Point2D.Double(projectedPoint.getX()+viewCenter.getX(),
211                 projectedPoint.getY()+viewCenter.getY());
212         return translatedBack;
213     }
214     
215     /**
216      * Magnify the shape, without considering the Lens.
217      * @param shape the shape to magnify
218      * @return the transformed shape
219      */
220     public Shape magnify(Shape shape) {
221         return magnify(shape, 0);
222     }
223     public Shape magnify(Shape shape, float flatness) {
224         GeneralPath newPath = new GeneralPath();
225         float[] coords = new float[6];
226         PathIterator iterator = null;
227         if(flatness == 0) {
228             iterator = shape.getPathIterator(null);
229         } else {
230             iterator = shape.getPathIterator(null, flatness);
231         }
232         for( ;
233             iterator.isDone() == false;
234             iterator.next()) {
235             int type = iterator.currentSegment(coords);
236             switch(type) {
237             case PathIterator.SEG_MOVETO:
238                 Point2D p = magnify(new Point2D.Float(coords[0], coords[1]));
239                 newPath.moveTo((float)p.getX(), (float)p.getY());
240                 break;
241                 
242             case PathIterator.SEG_LINETO:
243                 p = magnify(new Point2D.Float(coords[0], coords[1]));
244                 newPath.lineTo((float)p.getX(), (float) p.getY());
245                 break;
246                 
247             case PathIterator.SEG_QUADTO:
248                 p = magnify(new Point2D.Float(coords[0], coords[1]));
249                 Point2D q = magnify(new Point2D.Float(coords[2], coords[3]));
250                 newPath.quadTo((float)p.getX(), (float)p.getY(), (float)q.getX(), (float)q.getY());
251                 break;
252                 
253             case PathIterator.SEG_CUBICTO:
254                 p = magnify(new Point2D.Float(coords[0], coords[1]));
255                 q = magnify(new Point2D.Float(coords[2], coords[3]));
256                 Point2D r = magnify(new Point2D.Float(coords[4], coords[5]));
257                 newPath.curveTo((float)p.getX(), (float)p.getY(), 
258                         (float)q.getX(), (float)q.getY(),
259                         (float)r.getX(), (float)r.getY());
260                 break;
261                 
262             case PathIterator.SEG_CLOSE:
263                 newPath.closePath();
264                 break;
265                     
266             }
267         }
268         return newPath;
269     }
270 
271 }