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 }