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;
10  
11  import java.awt.Component;
12  import java.awt.Dimension;
13  import java.awt.Shape;
14  import java.awt.event.ComponentAdapter;
15  import java.awt.event.ComponentEvent;
16  import java.awt.geom.AffineTransform;
17  import java.awt.geom.Ellipse2D;
18  import java.awt.geom.Point2D;
19  import java.awt.geom.Rectangle2D;
20  import java.awt.geom.RectangularShape;
21  
22  /**
23   * LensTransformer wraps a MutableAffineTransformer and modifies
24   * the transform and inverseTransform methods so that they create a
25   * projection of the graph points within an elliptical lens.
26   * 
27   * LensTransformer uses an
28   * affine transform to cause translation, scaling, rotation, and shearing
29   * while applying a possibly non-affine filter in its transform and
30   * inverseTransform methods.
31   * 
32   * @author Tom Nelson
33   */
34  public abstract class LensTransformer extends MutableTransformerDecorator implements MutableTransformer {
35  
36      /**
37       * the area affected by the transform
38       */
39      protected RectangularShape lensShape = new Ellipse2D.Float();
40      
41      protected float magnification = 0.7f;
42      
43      /**
44       * Create an instance with a possibly shared transform.
45       * 
46       * @param component the component used for rendering
47       * @param delegate the transformer to use
48       */
49      public LensTransformer(Component component, MutableTransformer delegate) {
50      		super(delegate);
51          setComponent(component);
52          component.addComponentListener(new ComponentListenerImpl());
53     }
54      
55      /**
56       * Set values from the passed component.
57       * @param component the component used for rendering
58       */
59      private void setComponent(Component component) {
60          Dimension d = component.getSize();
61          if(d.width <= 0 || d.height <= 0) {
62              d = component.getPreferredSize();
63          }
64          float ewidth = d.width/1.5f;
65          float eheight = d.height/1.5f;
66          lensShape.setFrame(d.width/2-ewidth/2, d.height/2-eheight/2, ewidth, eheight);
67      }
68      
69      public float getMagnification() {
70          return magnification;
71      }
72  
73      public void setMagnification(float magnification) {
74          this.magnification = magnification;
75      }
76      
77      public Point2D getViewCenter() {
78          return new Point2D.Double(lensShape.getCenterX(), lensShape.getCenterY());
79      }
80  
81      public void setViewCenter(Point2D viewCenter) {
82          double width = lensShape.getWidth();
83          double height = lensShape.getHeight();
84          lensShape.setFrame(viewCenter.getX()-width/2,
85                  viewCenter.getY()-height/2,
86                  width, height);
87      }
88  
89      public double getViewRadius() {
90          return lensShape.getHeight()/2;
91      }
92  
93      public void setViewRadius(double viewRadius) {
94          double x = lensShape.getCenterX();
95          double y = lensShape.getCenterY();
96          double viewRatio = getRatio();
97          lensShape.setFrame(x-viewRadius/viewRatio,
98                  y-viewRadius,
99                  2*viewRadius/viewRatio,
100                 2*viewRadius);
101     }
102     
103     /**
104      * @return the ratio between the lens height and lens width
105      */
106     public double getRatio() {
107         return lensShape.getHeight()/lensShape.getWidth();
108     }
109     
110     public void setLensShape(RectangularShape ellipse) {
111         this.lensShape = ellipse;
112     }
113     public RectangularShape getLensShape() {
114         return lensShape;
115     }
116     public void setToIdentity() {
117         this.delegate.setToIdentity();
118     }
119 
120     /**
121      * react to size changes on a component
122      */
123     protected class ComponentListenerImpl extends ComponentAdapter {
124         public void componentResized(ComponentEvent e) {
125             setComponent(e.getComponent());
126          }
127     }
128     
129     /**
130      * override base class transform to project the fisheye effect
131      */
132     public abstract Point2D transform(Point2D graphPoint);
133     
134     /**
135      * override base class to un-project the fisheye effect
136      */
137     public abstract Point2D inverseTransform(Point2D viewPoint);
138     
139     public double getDistanceFromCenter(Point2D p) {
140     	
141         double dx = lensShape.getCenterX()-p.getX();
142         double dy = lensShape.getCenterY()-p.getY();
143         dx *= getRatio();
144         return Math.sqrt(dx*dx + dy*dy);
145     }
146     
147     /**
148      * return the supplied shape, translated to the coordinates
149      * that result from calling transform on its center
150      */
151     public Shape transform(Shape shape) {
152     	Rectangle2D bounds = shape.getBounds2D();
153     	Point2D center = new Point2D.Double(bounds.getCenterX(),bounds.getCenterY());
154     	Point2D newCenter = transform(center);
155     	double dx = newCenter.getX()-center.getX();
156     	double dy = newCenter.getY()-center.getY();
157     	AffineTransform at = AffineTransform.getTranslateInstance(dx,dy);
158     	return at.createTransformedShape(shape);
159     }
160     
161     /**
162      * Returns the supplied shape, translated to the coordinates
163      * that result from calling inverseTransform on its center.
164      */
165     public Shape inverseTransform(Shape shape) {
166     	Rectangle2D bounds = shape.getBounds2D();
167     	Point2D center = new Point2D.Double(bounds.getCenterX(),bounds.getCenterY());
168     	Point2D newCenter = inverseTransform(center);
169     	double dx = newCenter.getX()-center.getX();
170     	double dy = newCenter.getY()-center.getY();
171     	AffineTransform at = AffineTransform.getTranslateInstance(dx,dy);
172     	return at.createTransformedShape(shape);
173     }
174 
175 }