View Javadoc
1   /*
2    * Copyright (c) 2005, 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    * Created on Apr 16, 2005
9    */
10  
11  package edu.uci.ics.jung.visualization.transform;
12  
13  import java.awt.geom.AffineTransform;
14  import java.awt.geom.Point2D;
15  
16  import javax.swing.event.ChangeListener;
17  import javax.swing.event.EventListenerList;
18  
19  import edu.uci.ics.jung.visualization.transform.shape.ShapeTransformer;
20  import edu.uci.ics.jung.visualization.util.ChangeEventSupport;
21  import edu.uci.ics.jung.visualization.util.DefaultChangeEventSupport;
22  
23  /**
24   *
25   * Provides methods to mutate the AffineTransform used by AffineTransformer
26   * base class to map points from one coordinate system to
27   * another.
28   * 
29   * 
30   * @author Tom Nelson
31   *
32   * 
33   */
34  public class MutableAffineTransformer extends AffineTransformer 
35  implements MutableTransformer, ShapeTransformer, ChangeEventSupport {
36  
37      protected ChangeEventSupport changeSupport =
38          new DefaultChangeEventSupport(this);
39      
40      /**
41       * create an instance that does not transform points
42       */
43      public MutableAffineTransformer() {
44          // nothing left to do
45      }
46  
47      /**
48       * Create an instance with the supplied transform
49       * @param transform the transform to use
50       */
51      public MutableAffineTransformer(AffineTransform transform) {
52          super(transform);
53      }
54  
55      public String toString() {
56          return "MutableAffineTransformer using "+transform;
57      }
58  
59      /**
60       * setter for the scale
61       * fires a PropertyChangeEvent with the AffineTransforms representing
62       * the previous and new values for scale and offset
63       * @param scalex the amount to scale in the x direction
64       * @param scaley the amount to scale in the y direction
65       * @param from the point to transform
66       */
67      public void scale(double scalex, double scaley, Point2D from) {
68          AffineTransform xf = AffineTransform.getTranslateInstance(from.getX(),from.getY());
69          xf.scale(scalex, scaley);
70          xf.translate(-from.getX(), -from.getY());
71          inverse = null;
72          transform.preConcatenate(xf);
73          fireStateChanged();
74      }
75      
76      /**
77       * setter for the scale
78       * fires a PropertyChangeEvent with the AffineTransforms representing
79       * the previous and new values for scale and offset
80       * @param scalex the amount to scale in the x direction
81       * @param scaley the amount to scale in the y direction
82       * @param from the point to transform
83       */
84      public void setScale(double scalex, double scaley, Point2D from) {
85          transform.setToIdentity();
86          scale(scalex, scaley, from);
87      }
88      
89      /**
90       * shears the transform by passed parameters
91       * @param shx x value to shear
92       * @param shy y value to shear
93       * @param from the point to transform
94       */
95      public void shear(double shx, double shy, Point2D from) {
96          inverse = null;
97          AffineTransform at = 
98              AffineTransform.getTranslateInstance(from.getX(), from.getY());
99          at.shear(shx, shy);
100         at.translate(-from.getX(), -from.getY());
101         transform.preConcatenate(at);
102         fireStateChanged();
103     }
104     
105     /**
106      * Replace the Transform's translate x and y values
107      * with the passed values, leaving the scale values
108      * unchanged.
109      * @param tx the x value of the translation
110      * @param ty the y value of the translation
111      */
112     public void setTranslate(double tx, double ty) {
113         float scalex = (float) transform.getScaleX();
114         float scaley = (float) transform.getScaleY();
115         float shearx = (float) transform.getShearX();
116         float sheary = (float) transform.getShearY();
117         inverse = null;
118         transform.setTransform(scalex, 
119                 sheary, 
120                 shearx, 
121                 scaley,
122                 tx, ty);
123         fireStateChanged();
124     }
125     
126     /**
127      * Apply the passed values to the current Transform
128      * @param offsetx the x-value
129      * @param offsety the y-value
130      */
131     public void translate(double offsetx, double offsety) {
132         inverse = null;
133         transform.translate(offsetx, offsety);
134         fireStateChanged();
135     }
136     
137     /**
138      * preconcatenates the rotation at the supplied point with the current transform
139      * @param theta the angle by which to rotate the point
140      * @param from the point to transform
141      */
142     public void rotate(double theta, Point2D from) {
143         AffineTransform rotate = 
144             AffineTransform.getRotateInstance(theta, from.getX(), from.getY());
145         inverse = null;
146         transform.preConcatenate(rotate);
147 
148         fireStateChanged();
149     }
150     
151     /**
152      * rotates the current transform at the supplied points
153      * @param radians angle by which to rotate the supplied coordinates
154      * @param x the x coordinate of the point to transform
155      * @param y the y coordinate of the point to transform
156      */
157     public void rotate(double radians, double x, double y) {
158         inverse = null;
159         transform.rotate(radians, x, y);
160         fireStateChanged();
161     }
162     
163     public void concatenate(AffineTransform xform) {
164         inverse = null;
165         transform.concatenate(xform);
166         fireStateChanged();
167         
168     }
169     public void preConcatenate(AffineTransform xform) {
170         inverse = null;
171         transform.preConcatenate(xform);
172         fireStateChanged();
173     }   
174 
175     
176     /**
177      * Adds a <code>ChangeListener</code>.
178      * @param l the listener to be added
179      */
180     public void addChangeListener(ChangeListener l) {
181         changeSupport.addChangeListener(l);
182     }
183     
184     /**
185      * Removes a ChangeListener.
186      * @param l the listener to be removed
187      */
188     public void removeChangeListener(ChangeListener l) {
189         changeSupport.removeChangeListener(l);
190     }
191     
192     /**
193      * Returns an array of all the <code>ChangeListener</code>s added
194      * with addChangeListener().
195      *
196      * @return all of the <code>ChangeListener</code>s added or an empty
197      *         array if no listeners have been added
198      */
199     public ChangeListener[] getChangeListeners() {
200         return changeSupport.getChangeListeners();
201     }
202 
203     /**
204      * Notifies all listeners that have registered interest for
205      * notification on this event type.  The event instance 
206      * is lazily created.
207      * @see EventListenerList
208      */
209     public void fireStateChanged() {
210         changeSupport.fireStateChanged();
211     }
212     
213     public void setToIdentity() {
214         inverse = null;
215         transform.setToIdentity();
216         fireStateChanged();
217     }
218 }