• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17 /**
18  * @author Denis M. Kishenko
19  * @version $Revision$
20  */
21 
22 package java.awt.geom;
23 
24 import java.awt.Shape;
25 import java.io.IOException;
26 import java.io.Serializable;
27 
28 import org.apache.harmony.awt.internal.nls.Messages;
29 import org.apache.harmony.misc.HashCode;
30 
31 /**
32  * The Class AffineTransform represents a linear transformation (rotation,
33  * scaling, or shear) followed by a translation that acts on a coordinate space.
34  * It preserves collinearity of points and ratios of distances between collinear
35  * points: so if A, B, and C are on a line, then after the space has been
36  * transformed via the affine transform, the images of the three points will
37  * still be on a line, and the ratio of the distance from A to B with the
38  * distance from B to C will be the same as the corresponding ratio in the image
39  * space.
40  *
41  * @since Android 1.0
42  */
43 public class AffineTransform implements Cloneable, Serializable {
44 
45     /**
46      * The Constant serialVersionUID.
47      */
48     private static final long serialVersionUID = 1330973210523860834L;
49 
50     /**
51      * The Constant TYPE_IDENTITY.
52      */
53     public static final int TYPE_IDENTITY = 0;
54 
55     /**
56      * The Constant TYPE_TRANSLATION.
57      */
58     public static final int TYPE_TRANSLATION = 1;
59 
60     /**
61      * The Constant TYPE_UNIFORM_SCALE.
62      */
63     public static final int TYPE_UNIFORM_SCALE = 2;
64 
65     /**
66      * The Constant TYPE_GENERAL_SCALE.
67      */
68     public static final int TYPE_GENERAL_SCALE = 4;
69 
70     /**
71      * The Constant TYPE_QUADRANT_ROTATION.
72      */
73     public static final int TYPE_QUADRANT_ROTATION = 8;
74 
75     /**
76      * The Constant TYPE_GENERAL_ROTATION.
77      */
78     public static final int TYPE_GENERAL_ROTATION = 16;
79 
80     /**
81      * The Constant TYPE_GENERAL_TRANSFORM.
82      */
83     public static final int TYPE_GENERAL_TRANSFORM = 32;
84 
85     /**
86      * The Constant TYPE_FLIP.
87      */
88     public static final int TYPE_FLIP = 64;
89 
90     /**
91      * The Constant TYPE_MASK_SCALE.
92      */
93     public static final int TYPE_MASK_SCALE = TYPE_UNIFORM_SCALE | TYPE_GENERAL_SCALE;
94 
95     /**
96      * The Constant TYPE_MASK_ROTATION.
97      */
98     public static final int TYPE_MASK_ROTATION = TYPE_QUADRANT_ROTATION | TYPE_GENERAL_ROTATION;
99 
100     /**
101      * The <code>TYPE_UNKNOWN</code> is an initial type value.
102      */
103     static final int TYPE_UNKNOWN = -1;
104 
105     /**
106      * The min value equivalent to zero. If absolute value less then ZERO it
107      * considered as zero.
108      */
109     static final double ZERO = 1E-10;
110 
111     /**
112      * The values of transformation matrix.
113      */
114     double m00;
115 
116     /**
117      * The m10.
118      */
119     double m10;
120 
121     /**
122      * The m01.
123      */
124     double m01;
125 
126     /**
127      * The m11.
128      */
129     double m11;
130 
131     /**
132      * The m02.
133      */
134     double m02;
135 
136     /**
137      * The m12.
138      */
139     double m12;
140 
141     /**
142      * The transformation <code>type</code>.
143      */
144     transient int type;
145 
146     /**
147      * Instantiates a new affine transform of type <code>TYPE_IDENTITY</code>
148      * (which leaves coordinates unchanged).
149      */
AffineTransform()150     public AffineTransform() {
151         type = TYPE_IDENTITY;
152         m00 = m11 = 1.0;
153         m10 = m01 = m02 = m12 = 0.0;
154     }
155 
156     /**
157      * Instantiates a new affine transform that has the same data as the given
158      * AffineTransform.
159      *
160      * @param t
161      *            the transform to copy.
162      */
AffineTransform(AffineTransform t)163     public AffineTransform(AffineTransform t) {
164         this.type = t.type;
165         this.m00 = t.m00;
166         this.m10 = t.m10;
167         this.m01 = t.m01;
168         this.m11 = t.m11;
169         this.m02 = t.m02;
170         this.m12 = t.m12;
171     }
172 
173     /**
174      * Instantiates a new affine transform by specifying the values of the 2x3
175      * transformation matrix as floats. The type is set to the default type:
176      * <code>TYPE_UNKNOWN</code>
177      *
178      * @param m00
179      *            the m00 entry in the transformation matrix.
180      * @param m10
181      *            the m10 entry in the transformation matrix.
182      * @param m01
183      *            the m01 entry in the transformation matrix.
184      * @param m11
185      *            the m11 entry in the transformation matrix.
186      * @param m02
187      *            the m02 entry in the transformation matrix.
188      * @param m12
189      *            the m12 entry in the transformation matrix.
190      */
AffineTransform(float m00, float m10, float m01, float m11, float m02, float m12)191     public AffineTransform(float m00, float m10, float m01, float m11, float m02, float m12) {
192         this.type = TYPE_UNKNOWN;
193         this.m00 = m00;
194         this.m10 = m10;
195         this.m01 = m01;
196         this.m11 = m11;
197         this.m02 = m02;
198         this.m12 = m12;
199     }
200 
201     /**
202      * Instantiates a new affine transform by specifying the values of the 2x3
203      * transformation matrix as doubles. The type is set to the default type:
204      * <code>TYPE_UNKNOWN</code>
205      *
206      * @param m00
207      *            the m00 entry in the transformation matrix.
208      * @param m10
209      *            the m10 entry in the transformation matrix.
210      * @param m01
211      *            the m01 entry in the transformation matrix.
212      * @param m11
213      *            the m11 entry in the transformation matrix.
214      * @param m02
215      *            the m02 entry in the transformation matrix.
216      * @param m12
217      *            the m12 entry in the transformation matrix.
218      */
AffineTransform(double m00, double m10, double m01, double m11, double m02, double m12)219     public AffineTransform(double m00, double m10, double m01, double m11, double m02, double m12) {
220         this.type = TYPE_UNKNOWN;
221         this.m00 = m00;
222         this.m10 = m10;
223         this.m01 = m01;
224         this.m11 = m11;
225         this.m02 = m02;
226         this.m12 = m12;
227     }
228 
229     /**
230      * Instantiates a new affine transform by reading the values of the
231      * transformation matrix from an array of floats. The mapping from the array
232      * to the matrix starts with <code>matrix[0]</code> giving the top-left
233      * entry of the matrix and proceeds with the usual left-to-right and
234      * top-down ordering.
235      * <p>
236      * If the array has only four entries, then the two entries of the last row
237      * of the transformation matrix default to zero.
238      *
239      * @param matrix
240      *            the array of four or six floats giving the values of the
241      *            matrix.
242      * @throws ArrayIndexOutOfBoundsException
243      *             if the size of the array is 0, 1, 2, 3, or 5.
244      */
AffineTransform(float[] matrix)245     public AffineTransform(float[] matrix) {
246         this.type = TYPE_UNKNOWN;
247         m00 = matrix[0];
248         m10 = matrix[1];
249         m01 = matrix[2];
250         m11 = matrix[3];
251         if (matrix.length > 4) {
252             m02 = matrix[4];
253             m12 = matrix[5];
254         }
255     }
256 
257     /**
258      * Instantiates a new affine transform by reading the values of the
259      * transformation matrix from an array of doubles. The mapping from the
260      * array to the matrix starts with <code>matrix[0]</code> giving the
261      * top-left entry of the matrix and proceeds with the usual left-to-right
262      * and top-down ordering.
263      * <p>
264      * If the array has only four entries, then the two entries of the last row
265      * of the transformation matrix default to zero.
266      *
267      * @param matrix
268      *            the array of four or six doubles giving the values of the
269      *            matrix.
270      * @throws ArrayIndexOutOfBoundsException
271      *             if the size of the array is 0, 1, 2, 3, or 5.
272      */
AffineTransform(double[] matrix)273     public AffineTransform(double[] matrix) {
274         this.type = TYPE_UNKNOWN;
275         m00 = matrix[0];
276         m10 = matrix[1];
277         m01 = matrix[2];
278         m11 = matrix[3];
279         if (matrix.length > 4) {
280             m02 = matrix[4];
281             m12 = matrix[5];
282         }
283     }
284 
285     /**
286      * Returns type of the affine transformation.
287      * <p>
288      * The type is computed as follows: Label the entries of the transformation
289      * matrix as three rows (m00, m01), (m10, m11), and (m02, m12). Then if the
290      * original basis vectors are (1, 0) and (0, 1), the new basis vectors after
291      * transformation are given by (m00, m01) and (m10, m11), and the
292      * translation vector is (m02, m12).
293      * <p>
294      * The types are classified as follows: <br/> TYPE_IDENTITY - no change<br/>
295      * TYPE_TRANSLATION - The translation vector isn't zero<br/>
296      * TYPE_UNIFORM_SCALE - The new basis vectors have equal length<br/>
297      * TYPE_GENERAL_SCALE - The new basis vectors dont' have equal length<br/>
298      * TYPE_FLIP - The new basis vector orientation differs from the original
299      * one<br/> TYPE_QUADRANT_ROTATION - The new basis is a rotation of the
300      * original by 90, 180, 270, or 360 degrees<br/> TYPE_GENERAL_ROTATION - The
301      * new basis is a rotation of the original by an arbitrary angle<br/>
302      * TYPE_GENERAL_TRANSFORM - The transformation can't be inverted.<br/>
303      * <p>
304      * Note that multiple types are possible, thus the types can be combined
305      * using bitwise combinations.
306      *
307      * @return the type of the Affine Transform.
308      */
getType()309     public int getType() {
310         if (type != TYPE_UNKNOWN) {
311             return type;
312         }
313 
314         int type = 0;
315 
316         if (m00 * m01 + m10 * m11 != 0.0) {
317             type |= TYPE_GENERAL_TRANSFORM;
318             return type;
319         }
320 
321         if (m02 != 0.0 || m12 != 0.0) {
322             type |= TYPE_TRANSLATION;
323         } else if (m00 == 1.0 && m11 == 1.0 && m01 == 0.0 && m10 == 0.0) {
324             type = TYPE_IDENTITY;
325             return type;
326         }
327 
328         if (m00 * m11 - m01 * m10 < 0.0) {
329             type |= TYPE_FLIP;
330         }
331 
332         double dx = m00 * m00 + m10 * m10;
333         double dy = m01 * m01 + m11 * m11;
334         if (dx != dy) {
335             type |= TYPE_GENERAL_SCALE;
336         } else if (dx != 1.0) {
337             type |= TYPE_UNIFORM_SCALE;
338         }
339 
340         if ((m00 == 0.0 && m11 == 0.0) || (m10 == 0.0 && m01 == 0.0 && (m00 < 0.0 || m11 < 0.0))) {
341             type |= TYPE_QUADRANT_ROTATION;
342         } else if (m01 != 0.0 || m10 != 0.0) {
343             type |= TYPE_GENERAL_ROTATION;
344         }
345 
346         return type;
347     }
348 
349     /**
350      * Gets the scale x entry of the transformation matrix (the upper left
351      * matrix entry).
352      *
353      * @return the scale x value.
354      */
getScaleX()355     public double getScaleX() {
356         return m00;
357     }
358 
359     /**
360      * Gets the scale y entry of the transformation matrix (the lower right
361      * entry of the linear transformation).
362      *
363      * @return the scale y value.
364      */
getScaleY()365     public double getScaleY() {
366         return m11;
367     }
368 
369     /**
370      * Gets the shear x entry of the transformation matrix (the upper right
371      * entry of the linear transformation).
372      *
373      * @return the shear x value.
374      */
getShearX()375     public double getShearX() {
376         return m01;
377     }
378 
379     /**
380      * Gets the shear y entry of the transformation matrix (the lower left entry
381      * of the linear transformation).
382      *
383      * @return the shear y value.
384      */
getShearY()385     public double getShearY() {
386         return m10;
387     }
388 
389     /**
390      * Gets the x coordinate of the translation vector.
391      *
392      * @return the x coordinate of the translation vector.
393      */
getTranslateX()394     public double getTranslateX() {
395         return m02;
396     }
397 
398     /**
399      * Gets the y coordinate of the translation vector.
400      *
401      * @return the y coordinate of the translation vector.
402      */
getTranslateY()403     public double getTranslateY() {
404         return m12;
405     }
406 
407     /**
408      * Checks if the AffineTransformation is the identity.
409      *
410      * @return true, if the AffineTransformation is the identity.
411      */
isIdentity()412     public boolean isIdentity() {
413         return getType() == TYPE_IDENTITY;
414     }
415 
416     /**
417      * Writes the values of the transformation matrix into the given array of
418      * doubles. If the array has length 4, only the linear transformation part
419      * will be written into it. If it has length greater than 4, the translation
420      * vector will be included as well.
421      *
422      * @param matrix
423      *            the array to fill with the values of the matrix.
424      * @throws ArrayIndexOutOfBoundsException
425      *             if the size of the array is 0, 1, 2, 3, or 5.
426      */
getMatrix(double[] matrix)427     public void getMatrix(double[] matrix) {
428         matrix[0] = m00;
429         matrix[1] = m10;
430         matrix[2] = m01;
431         matrix[3] = m11;
432         if (matrix.length > 4) {
433             matrix[4] = m02;
434             matrix[5] = m12;
435         }
436     }
437 
438     /**
439      * Gets the determinant of the linear transformation matrix.
440      *
441      * @return the determinant of the linear transformation matrix.
442      */
getDeterminant()443     public double getDeterminant() {
444         return m00 * m11 - m01 * m10;
445     }
446 
447     /**
448      * Sets the transform in terms of a list of double values.
449      *
450      * @param m00
451      *            the m00 coordinate of the transformation matrix.
452      * @param m10
453      *            the m10 coordinate of the transformation matrix.
454      * @param m01
455      *            the m01 coordinate of the transformation matrix.
456      * @param m11
457      *            the m11 coordinate of the transformation matrix.
458      * @param m02
459      *            the m02 coordinate of the transformation matrix.
460      * @param m12
461      *            the m12 coordinate of the transformation matrix.
462      */
setTransform(double m00, double m10, double m01, double m11, double m02, double m12)463     public void setTransform(double m00, double m10, double m01, double m11, double m02, double m12) {
464         this.type = TYPE_UNKNOWN;
465         this.m00 = m00;
466         this.m10 = m10;
467         this.m01 = m01;
468         this.m11 = m11;
469         this.m02 = m02;
470         this.m12 = m12;
471     }
472 
473     /**
474      * Sets the transform's data to match the data of the transform sent as a
475      * parameter.
476      *
477      * @param t
478      *            the transform that gives the new values.
479      */
setTransform(AffineTransform t)480     public void setTransform(AffineTransform t) {
481         type = t.type;
482         setTransform(t.m00, t.m10, t.m01, t.m11, t.m02, t.m12);
483     }
484 
485     /**
486      * Sets the transform to the identity transform.
487      */
setToIdentity()488     public void setToIdentity() {
489         type = TYPE_IDENTITY;
490         m00 = m11 = 1.0;
491         m10 = m01 = m02 = m12 = 0.0;
492     }
493 
494     /**
495      * Sets the transformation to a translation alone. Sets the linear part of
496      * the transformation to identity and the translation vector to the values
497      * sent as parameters. Sets the type to <code>TYPE_IDENTITY</code> if the
498      * resulting AffineTransformation is the identity transformation, otherwise
499      * sets it to <code>TYPE_TRANSLATION</code>.
500      *
501      * @param mx
502      *            the distance to translate in the x direction.
503      * @param my
504      *            the distance to translate in the y direction.
505      */
setToTranslation(double mx, double my)506     public void setToTranslation(double mx, double my) {
507         m00 = m11 = 1.0;
508         m01 = m10 = 0.0;
509         m02 = mx;
510         m12 = my;
511         if (mx == 0.0 && my == 0.0) {
512             type = TYPE_IDENTITY;
513         } else {
514             type = TYPE_TRANSLATION;
515         }
516     }
517 
518     /**
519      * Sets the transformation to being a scale alone, eliminating rotation,
520      * shear, and translation elements. Sets the type to
521      * <code>TYPE_IDENTITY</code> if the resulting AffineTransformation is the
522      * identity transformation, otherwise sets it to <code>TYPE_UNKNOWN</code>.
523      *
524      * @param scx
525      *            the scaling factor in the x direction.
526      * @param scy
527      *            the scaling factor in the y direction.
528      */
setToScale(double scx, double scy)529     public void setToScale(double scx, double scy) {
530         m00 = scx;
531         m11 = scy;
532         m10 = m01 = m02 = m12 = 0.0;
533         if (scx != 1.0 || scy != 1.0) {
534             type = TYPE_UNKNOWN;
535         } else {
536             type = TYPE_IDENTITY;
537         }
538     }
539 
540     /**
541      * Sets the transformation to being a shear alone, eliminating rotation,
542      * scaling, and translation elements. Sets the type to
543      * <code>TYPE_IDENTITY</code> if the resulting AffineTransformation is the
544      * identity transformation, otherwise sets it to <code>TYPE_UNKNOWN</code>.
545      *
546      * @param shx
547      *            the shearing factor in the x direction.
548      * @param shy
549      *            the shearing factor in the y direction.
550      */
setToShear(double shx, double shy)551     public void setToShear(double shx, double shy) {
552         m00 = m11 = 1.0;
553         m02 = m12 = 0.0;
554         m01 = shx;
555         m10 = shy;
556         if (shx != 0.0 || shy != 0.0) {
557             type = TYPE_UNKNOWN;
558         } else {
559             type = TYPE_IDENTITY;
560         }
561     }
562 
563     /**
564      * Sets the transformation to being a rotation alone, eliminating shearing,
565      * scaling, and translation elements. Sets the type to
566      * <code>TYPE_IDENTITY</code> if the resulting AffineTransformation is the
567      * identity transformation, otherwise sets it to <code>TYPE_UNKNOWN</code>.
568      *
569      * @param angle
570      *            the angle of rotation in radians.
571      */
setToRotation(double angle)572     public void setToRotation(double angle) {
573         double sin = Math.sin(angle);
574         double cos = Math.cos(angle);
575         if (Math.abs(cos) < ZERO) {
576             cos = 0.0;
577             sin = sin > 0.0 ? 1.0 : -1.0;
578         } else if (Math.abs(sin) < ZERO) {
579             sin = 0.0;
580             cos = cos > 0.0 ? 1.0 : -1.0;
581         }
582         m00 = m11 = cos;
583         m01 = -sin;
584         m10 = sin;
585         m02 = m12 = 0.0;
586         type = TYPE_UNKNOWN;
587     }
588 
589     /**
590      * Sets the transformation to being a rotation followed by a translation.
591      * Sets the type to <code>TYPE_UNKNOWN</code>.
592      *
593      * @param angle
594      *            the angle of rotation in radians.
595      * @param px
596      *            the distance to translate in the x direction.
597      * @param py
598      *            the distance to translate in the y direction.
599      */
setToRotation(double angle, double px, double py)600     public void setToRotation(double angle, double px, double py) {
601         setToRotation(angle);
602         m02 = px * (1.0 - m00) + py * m10;
603         m12 = py * (1.0 - m00) - px * m10;
604         type = TYPE_UNKNOWN;
605     }
606 
607     /**
608      * Creates a new AffineTransformation that is a translation alone with the
609      * translation vector given by the values sent as parameters. The new
610      * transformation's type is <code>TYPE_IDENTITY</code> if the
611      * AffineTransformation is the identity transformation, otherwise it's
612      * <code>TYPE_TRANSLATION</code>.
613      *
614      * @param mx
615      *            the distance to translate in the x direction.
616      * @param my
617      *            the distance to translate in the y direction.
618      * @return the new AffineTransformation.
619      */
getTranslateInstance(double mx, double my)620     public static AffineTransform getTranslateInstance(double mx, double my) {
621         AffineTransform t = new AffineTransform();
622         t.setToTranslation(mx, my);
623         return t;
624     }
625 
626     /**
627      * Creates a new AffineTransformation that is a scale alone. The new
628      * transformation's type is <code>TYPE_IDENTITY</code> if the
629      * AffineTransformation is the identity transformation, otherwise it's
630      * <code>TYPE_UNKNOWN</code>.
631      *
632      * @param scx
633      *            the scaling factor in the x direction.
634      * @param scY
635      *            the scaling factor in the y direction.
636      * @return the new AffineTransformation.
637      */
getScaleInstance(double scx, double scY)638     public static AffineTransform getScaleInstance(double scx, double scY) {
639         AffineTransform t = new AffineTransform();
640         t.setToScale(scx, scY);
641         return t;
642     }
643 
644     /**
645      * Creates a new AffineTransformation that is a shear alone. The new
646      * transformation's type is <code>TYPE_IDENTITY</code> if the
647      * AffineTransformation is the identity transformation, otherwise it's
648      * <code>TYPE_UNKNOWN</code>.
649      *
650      * @param shx
651      *            the shearing factor in the x direction.
652      * @param shy
653      *            the shearing factor in the y direction.
654      * @return the new AffineTransformation.
655      */
getShearInstance(double shx, double shy)656     public static AffineTransform getShearInstance(double shx, double shy) {
657         AffineTransform m = new AffineTransform();
658         m.setToShear(shx, shy);
659         return m;
660     }
661 
662     /**
663      * Creates a new AffineTransformation that is a rotation alone. The new
664      * transformation's type is <code>TYPE_IDENTITY</code> if the
665      * AffineTransformation is the identity transformation, otherwise it's
666      * <code>TYPE_UNKNOWN</code>.
667      *
668      * @param angle
669      *            the angle of rotation in radians.
670      * @return the new AffineTransformation.
671      */
getRotateInstance(double angle)672     public static AffineTransform getRotateInstance(double angle) {
673         AffineTransform t = new AffineTransform();
674         t.setToRotation(angle);
675         return t;
676     }
677 
678     /**
679      * Creates a new AffineTransformation that is a rotation followed by a
680      * translation. Sets the type to <code>TYPE_UNKNOWN</code>.
681      *
682      * @param angle
683      *            the angle of rotation in radians.
684      * @param x
685      *            the distance to translate in the x direction.
686      * @param y
687      *            the distance to translate in the y direction.
688      * @return the new AffineTransformation.
689      */
getRotateInstance(double angle, double x, double y)690     public static AffineTransform getRotateInstance(double angle, double x, double y) {
691         AffineTransform t = new AffineTransform();
692         t.setToRotation(angle, x, y);
693         return t;
694     }
695 
696     /**
697      * Applies a translation to this AffineTransformation.
698      *
699      * @param mx
700      *            the distance to translate in the x direction.
701      * @param my
702      *            the distance to translate in the y direction.
703      */
translate(double mx, double my)704     public void translate(double mx, double my) {
705         concatenate(AffineTransform.getTranslateInstance(mx, my));
706     }
707 
708     /**
709      * Applies a scaling transformation to this AffineTransformation.
710      *
711      * @param scx
712      *            the scaling factor in the x direction.
713      * @param scy
714      *            the scaling factor in the y direction.
715      */
scale(double scx, double scy)716     public void scale(double scx, double scy) {
717         concatenate(AffineTransform.getScaleInstance(scx, scy));
718     }
719 
720     /**
721      * Applies a shearing transformation to this AffineTransformation.
722      *
723      * @param shx
724      *            the shearing factor in the x direction.
725      * @param shy
726      *            the shearing factor in the y direction.
727      */
shear(double shx, double shy)728     public void shear(double shx, double shy) {
729         concatenate(AffineTransform.getShearInstance(shx, shy));
730     }
731 
732     /**
733      * Applies a rotation transformation to this AffineTransformation.
734      *
735      * @param angle
736      *            the angle of rotation in radians.
737      */
rotate(double angle)738     public void rotate(double angle) {
739         concatenate(AffineTransform.getRotateInstance(angle));
740     }
741 
742     /**
743      * Applies a rotation and translation transformation to this
744      * AffineTransformation.
745      *
746      * @param angle
747      *            the angle of rotation in radians.
748      * @param px
749      *            the distance to translate in the x direction.
750      * @param py
751      *            the distance to translate in the y direction.
752      */
rotate(double angle, double px, double py)753     public void rotate(double angle, double px, double py) {
754         concatenate(AffineTransform.getRotateInstance(angle, px, py));
755     }
756 
757     /**
758      * Multiplies the matrix representations of two AffineTransform objects.
759      *
760      * @param t1
761      *            - the AffineTransform object is a multiplicand
762      * @param t2
763      *            - the AffineTransform object is a multiplier
764      * @return an AffineTransform object that is the result of t1 multiplied by
765      *         the matrix t2.
766      */
multiply(AffineTransform t1, AffineTransform t2)767     AffineTransform multiply(AffineTransform t1, AffineTransform t2) {
768         return new AffineTransform(t1.m00 * t2.m00 + t1.m10 * t2.m01, // m00
769                 t1.m00 * t2.m10 + t1.m10 * t2.m11, // m01
770                 t1.m01 * t2.m00 + t1.m11 * t2.m01, // m10
771                 t1.m01 * t2.m10 + t1.m11 * t2.m11, // m11
772                 t1.m02 * t2.m00 + t1.m12 * t2.m01 + t2.m02, // m02
773                 t1.m02 * t2.m10 + t1.m12 * t2.m11 + t2.m12);// m12
774     }
775 
776     /**
777      * Applies the given AffineTransform to this AffineTransform via matrix
778      * multiplication.
779      *
780      * @param t
781      *            the AffineTransform to apply to this AffineTransform.
782      */
concatenate(AffineTransform t)783     public void concatenate(AffineTransform t) {
784         setTransform(multiply(t, this));
785     }
786 
787     /**
788      * Changes the current AffineTransform the one obtained by taking the
789      * transform t and applying this AffineTransform to it.
790      *
791      * @param t
792      *            the AffineTransform that this AffineTransform is multiplied
793      *            by.
794      */
preConcatenate(AffineTransform t)795     public void preConcatenate(AffineTransform t) {
796         setTransform(multiply(this, t));
797     }
798 
799     /**
800      * Creates an AffineTransform that is the inverse of this transform.
801      *
802      * @return the affine transform that is the inverse of this AffineTransform.
803      * @throws NoninvertibleTransformException
804      *             if this AffineTransform cannot be inverted (the determinant
805      *             of the linear transformation part is zero).
806      */
createInverse()807     public AffineTransform createInverse() throws NoninvertibleTransformException {
808         double det = getDeterminant();
809         if (Math.abs(det) < ZERO) {
810             // awt.204=Determinant is zero
811             throw new NoninvertibleTransformException(Messages.getString("awt.204")); //$NON-NLS-1$
812         }
813         return new AffineTransform(m11 / det, // m00
814                 -m10 / det, // m10
815                 -m01 / det, // m01
816                 m00 / det, // m11
817                 (m01 * m12 - m11 * m02) / det, // m02
818                 (m10 * m02 - m00 * m12) / det // m12
819         );
820     }
821 
822     /**
823      * Apply the current AffineTransform to the point.
824      *
825      * @param src
826      *            the original point.
827      * @param dst
828      *            Point2D object to be filled with the destination coordinates
829      *            (where the original point is sent by this AffineTransform).
830      *            May be null.
831      * @return the point in the AffineTransform's image space where the original
832      *         point is sent.
833      */
transform(Point2D src, Point2D dst)834     public Point2D transform(Point2D src, Point2D dst) {
835         if (dst == null) {
836             if (src instanceof Point2D.Double) {
837                 dst = new Point2D.Double();
838             } else {
839                 dst = new Point2D.Float();
840             }
841         }
842 
843         double x = src.getX();
844         double y = src.getY();
845 
846         dst.setLocation(x * m00 + y * m01 + m02, x * m10 + y * m11 + m12);
847         return dst;
848     }
849 
850     /**
851      * Applies this AffineTransform to an array of points.
852      *
853      * @param src
854      *            the array of points to be transformed.
855      * @param srcOff
856      *            the offset in the source point array of the first point to be
857      *            transformed.
858      * @param dst
859      *            the point array where the images of the points (after applying
860      *            the AffineTransformation) should be placed.
861      * @param dstOff
862      *            the offset in the destination array where the new values
863      *            should be written.
864      * @param length
865      *            the number of points to transform.
866      * @throws ArrayIndexOutOfBoundsException
867      *             if <code>srcOff + length > src.length</code> or
868      *             <code>dstOff + length > dst.length</code>.
869      */
transform(Point2D[] src, int srcOff, Point2D[] dst, int dstOff, int length)870     public void transform(Point2D[] src, int srcOff, Point2D[] dst, int dstOff, int length) {
871         while (--length >= 0) {
872             Point2D srcPoint = src[srcOff++];
873             double x = srcPoint.getX();
874             double y = srcPoint.getY();
875             Point2D dstPoint = dst[dstOff];
876             if (dstPoint == null) {
877                 if (srcPoint instanceof Point2D.Double) {
878                     dstPoint = new Point2D.Double();
879                 } else {
880                     dstPoint = new Point2D.Float();
881                 }
882             }
883             dstPoint.setLocation(x * m00 + y * m01 + m02, x * m10 + y * m11 + m12);
884             dst[dstOff++] = dstPoint;
885         }
886     }
887 
888     /**
889      * Applies this AffineTransform to a set of points given as an array of
890      * double values where every two values in the array give the coordinates of
891      * a point; the even-indexed values giving the x coordinates and the
892      * odd-indexed values giving the y coordinates.
893      *
894      * @param src
895      *            the array of points to be transformed.
896      * @param srcOff
897      *            the offset in the source point array of the first point to be
898      *            transformed.
899      * @param dst
900      *            the point array where the images of the points (after applying
901      *            the AffineTransformation) should be placed.
902      * @param dstOff
903      *            the offset in the destination array where the new values
904      *            should be written.
905      * @param length
906      *            the number of points to transform.
907      * @throws ArrayIndexOutOfBoundsException
908      *             if <code>srcOff + length*2 > src.length</code> or
909      *             <code>dstOff + length*2 > dst.length</code>.
910      */
transform(double[] src, int srcOff, double[] dst, int dstOff, int length)911     public void transform(double[] src, int srcOff, double[] dst, int dstOff, int length) {
912         int step = 2;
913         if (src == dst && srcOff < dstOff && dstOff < srcOff + length * 2) {
914             srcOff = srcOff + length * 2 - 2;
915             dstOff = dstOff + length * 2 - 2;
916             step = -2;
917         }
918         while (--length >= 0) {
919             double x = src[srcOff + 0];
920             double y = src[srcOff + 1];
921             dst[dstOff + 0] = x * m00 + y * m01 + m02;
922             dst[dstOff + 1] = x * m10 + y * m11 + m12;
923             srcOff += step;
924             dstOff += step;
925         }
926     }
927 
928     /**
929      * Applies this AffineTransform to a set of points given as an array of
930      * float values where every two values in the array give the coordinates of
931      * a point; the even-indexed values giving the x coordinates and the
932      * odd-indexed values giving the y coordinates.
933      *
934      * @param src
935      *            the array of points to be transformed.
936      * @param srcOff
937      *            the offset in the source point array of the first point to be
938      *            transformed.
939      * @param dst
940      *            the point array where the images of the points (after applying
941      *            the AffineTransformation) should be placed.
942      * @param dstOff
943      *            the offset in the destination array where the new values
944      *            should be written.
945      * @param length
946      *            the number of points to transform.
947      * @throws ArrayIndexOutOfBoundsException
948      *             if <code>srcOff + length*2 > src.length</code> or
949      *             <code>dstOff + length*2 > dst.length</code>.
950      */
transform(float[] src, int srcOff, float[] dst, int dstOff, int length)951     public void transform(float[] src, int srcOff, float[] dst, int dstOff, int length) {
952         int step = 2;
953         if (src == dst && srcOff < dstOff && dstOff < srcOff + length * 2) {
954             srcOff = srcOff + length * 2 - 2;
955             dstOff = dstOff + length * 2 - 2;
956             step = -2;
957         }
958         while (--length >= 0) {
959             float x = src[srcOff + 0];
960             float y = src[srcOff + 1];
961             dst[dstOff + 0] = (float)(x * m00 + y * m01 + m02);
962             dst[dstOff + 1] = (float)(x * m10 + y * m11 + m12);
963             srcOff += step;
964             dstOff += step;
965         }
966     }
967 
968     /**
969      * Applies this AffineTransform to a set of points given as an array of
970      * float values where every two values in the array give the coordinates of
971      * a point; the even-indexed values giving the x coordinates and the
972      * odd-indexed values giving the y coordinates. The destination coordinates
973      * are given as values of type <code>double</code>.
974      *
975      * @param src
976      *            the array of points to be transformed.
977      * @param srcOff
978      *            the offset in the source point array of the first point to be
979      *            transformed.
980      * @param dst
981      *            the point array where the images of the points (after applying
982      *            the AffineTransformation) should be placed.
983      * @param dstOff
984      *            the offset in the destination array where the new values
985      *            should be written.
986      * @param length
987      *            the number of points to transform.
988      * @throws ArrayIndexOutOfBoundsException
989      *             if <code>srcOff + length*2 > src.length</code> or
990      *             <code>dstOff + length*2 > dst.length</code>.
991      */
transform(float[] src, int srcOff, double[] dst, int dstOff, int length)992     public void transform(float[] src, int srcOff, double[] dst, int dstOff, int length) {
993         while (--length >= 0) {
994             float x = src[srcOff++];
995             float y = src[srcOff++];
996             dst[dstOff++] = x * m00 + y * m01 + m02;
997             dst[dstOff++] = x * m10 + y * m11 + m12;
998         }
999     }
1000 
1001     /**
1002      * Applies this AffineTransform to a set of points given as an array of
1003      * double values where every two values in the array give the coordinates of
1004      * a point; the even-indexed values giving the x coordinates and the
1005      * odd-indexed values giving the y coordinates. The destination coordinates
1006      * are given as values of type <code>float</code>.
1007      *
1008      * @param src
1009      *            the array of points to be transformed.
1010      * @param srcOff
1011      *            the offset in the source point array of the first point to be
1012      *            transformed.
1013      * @param dst
1014      *            the point array where the images of the points (after applying
1015      *            the AffineTransformation) should be placed.
1016      * @param dstOff
1017      *            the offset in the destination array where the new values
1018      *            should be written.
1019      * @param length
1020      *            the number of points to transform.
1021      * @throws ArrayIndexOutOfBoundsException
1022      *             if <code>srcOff + length*2 > src.length</code> or
1023      *             <code>dstOff + length*2 > dst.length</code>.
1024      */
transform(double[] src, int srcOff, float[] dst, int dstOff, int length)1025     public void transform(double[] src, int srcOff, float[] dst, int dstOff, int length) {
1026         while (--length >= 0) {
1027             double x = src[srcOff++];
1028             double y = src[srcOff++];
1029             dst[dstOff++] = (float)(x * m00 + y * m01 + m02);
1030             dst[dstOff++] = (float)(x * m10 + y * m11 + m12);
1031         }
1032     }
1033 
1034     /**
1035      * Transforms the point according to the linear transformation part of this
1036      * AffineTransformation (without applying the translation).
1037      *
1038      * @param src
1039      *            the original point.
1040      * @param dst
1041      *            the point object where the result of the delta transform is
1042      *            written.
1043      * @return the result of applying the delta transform (linear part only) to
1044      *         the original point.
1045      */
1046     // TODO: is this right? if dst is null, we check what it's an
1047     // instance of? Shouldn't it be src instanceof Point2D.Double?
deltaTransform(Point2D src, Point2D dst)1048     public Point2D deltaTransform(Point2D src, Point2D dst) {
1049         if (dst == null) {
1050             if (dst instanceof Point2D.Double) {
1051                 dst = new Point2D.Double();
1052             } else {
1053                 dst = new Point2D.Float();
1054             }
1055         }
1056 
1057         double x = src.getX();
1058         double y = src.getY();
1059 
1060         dst.setLocation(x * m00 + y * m01, x * m10 + y * m11);
1061         return dst;
1062     }
1063 
1064     /**
1065      * Applies the linear transformation part of this AffineTransform (ignoring
1066      * the translation part) to a set of points given as an array of double
1067      * values where every two values in the array give the coordinates of a
1068      * point; the even-indexed values giving the x coordinates and the
1069      * odd-indexed values giving the y coordinates.
1070      *
1071      * @param src
1072      *            the array of points to be transformed.
1073      * @param srcOff
1074      *            the offset in the source point array of the first point to be
1075      *            transformed.
1076      * @param dst
1077      *            the point array where the images of the points (after applying
1078      *            the delta transformation) should be placed.
1079      * @param dstOff
1080      *            the offset in the destination array where the new values
1081      *            should be written.
1082      * @param length
1083      *            the number of points to transform.
1084      * @throws ArrayIndexOutOfBoundsException
1085      *             if <code>srcOff + length*2 > src.length</code> or
1086      *             <code>dstOff + length*2 > dst.length</code>.
1087      */
deltaTransform(double[] src, int srcOff, double[] dst, int dstOff, int length)1088     public void deltaTransform(double[] src, int srcOff, double[] dst, int dstOff, int length) {
1089         while (--length >= 0) {
1090             double x = src[srcOff++];
1091             double y = src[srcOff++];
1092             dst[dstOff++] = x * m00 + y * m01;
1093             dst[dstOff++] = x * m10 + y * m11;
1094         }
1095     }
1096 
1097     /**
1098      * Transforms the point according to the inverse of this
1099      * AffineTransformation.
1100      *
1101      * @param src
1102      *            the original point.
1103      * @param dst
1104      *            the point object where the result of the inverse transform is
1105      *            written (may be null).
1106      * @return the result of applying the inverse transform. Inverse transform.
1107      * @throws NoninvertibleTransformException
1108      *             if this AffineTransform cannot be inverted (the determinant
1109      *             of the linear transformation part is zero).
1110      */
inverseTransform(Point2D src, Point2D dst)1111     public Point2D inverseTransform(Point2D src, Point2D dst)
1112             throws NoninvertibleTransformException {
1113         double det = getDeterminant();
1114         if (Math.abs(det) < ZERO) {
1115             // awt.204=Determinant is zero
1116             throw new NoninvertibleTransformException(Messages.getString("awt.204")); //$NON-NLS-1$
1117         }
1118 
1119         if (dst == null) {
1120             if (src instanceof Point2D.Double) {
1121                 dst = new Point2D.Double();
1122             } else {
1123                 dst = new Point2D.Float();
1124             }
1125         }
1126 
1127         double x = src.getX() - m02;
1128         double y = src.getY() - m12;
1129 
1130         dst.setLocation((x * m11 - y * m01) / det, (y * m00 - x * m10) / det);
1131         return dst;
1132     }
1133 
1134     /**
1135      * Applies the inverse of this AffineTransform to a set of points given as
1136      * an array of double values where every two values in the array give the
1137      * coordinates of a point; the even-indexed values giving the x coordinates
1138      * and the odd-indexed values giving the y coordinates.
1139      *
1140      * @param src
1141      *            the array of points to be transformed.
1142      * @param srcOff
1143      *            the offset in the source point array of the first point to be
1144      *            transformed.
1145      * @param dst
1146      *            the point array where the images of the points (after applying
1147      *            the inverse of the AffineTransformation) should be placed.
1148      * @param dstOff
1149      *            the offset in the destination array where the new values
1150      *            should be written.
1151      * @param length
1152      *            the number of points to transform.
1153      * @throws ArrayIndexOutOfBoundsException
1154      *             if <code>srcOff + length*2 > src.length</code> or
1155      *             <code>dstOff + length*2 > dst.length</code>.
1156      * @throws NoninvertibleTransformException
1157      *             if this AffineTransform cannot be inverted (the determinant
1158      *             of the linear transformation part is zero).
1159      */
inverseTransform(double[] src, int srcOff, double[] dst, int dstOff, int length)1160     public void inverseTransform(double[] src, int srcOff, double[] dst, int dstOff, int length)
1161             throws NoninvertibleTransformException {
1162         double det = getDeterminant();
1163         if (Math.abs(det) < ZERO) {
1164             // awt.204=Determinant is zero
1165             throw new NoninvertibleTransformException(Messages.getString("awt.204")); //$NON-NLS-1$
1166         }
1167 
1168         while (--length >= 0) {
1169             double x = src[srcOff++] - m02;
1170             double y = src[srcOff++] - m12;
1171             dst[dstOff++] = (x * m11 - y * m01) / det;
1172             dst[dstOff++] = (y * m00 - x * m10) / det;
1173         }
1174     }
1175 
1176     /**
1177      * Creates a new shape whose data is given by applying this AffineTransform
1178      * to the specified shape.
1179      *
1180      * @param src
1181      *            the original shape whose data is to be transformed.
1182      * @return the new shape found by applying this AffineTransform to the
1183      *         original shape.
1184      */
createTransformedShape(Shape src)1185     public Shape createTransformedShape(Shape src) {
1186         if (src == null) {
1187             return null;
1188         }
1189         if (src instanceof GeneralPath) {
1190             return ((GeneralPath)src).createTransformedShape(this);
1191         }
1192         PathIterator path = src.getPathIterator(this);
1193         GeneralPath dst = new GeneralPath(path.getWindingRule());
1194         dst.append(path, false);
1195         return dst;
1196     }
1197 
1198     @Override
toString()1199     public String toString() {
1200         return getClass().getName() + "[[" + m00 + ", " + m01 + ", " + m02 + "], [" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
1201                 + m10 + ", " + m11 + ", " + m12 + "]]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
1202     }
1203 
1204     @Override
clone()1205     public Object clone() {
1206         try {
1207             return super.clone();
1208         } catch (CloneNotSupportedException e) {
1209             throw new InternalError();
1210         }
1211     }
1212 
1213     @Override
hashCode()1214     public int hashCode() {
1215         HashCode hash = new HashCode();
1216         hash.append(m00);
1217         hash.append(m01);
1218         hash.append(m02);
1219         hash.append(m10);
1220         hash.append(m11);
1221         hash.append(m12);
1222         return hash.hashCode();
1223     }
1224 
1225     @Override
equals(Object obj)1226     public boolean equals(Object obj) {
1227         if (obj == this) {
1228             return true;
1229         }
1230         if (obj instanceof AffineTransform) {
1231             AffineTransform t = (AffineTransform)obj;
1232             return m00 == t.m00 && m01 == t.m01 && m02 == t.m02 && m10 == t.m10 && m11 == t.m11
1233                     && m12 == t.m12;
1234         }
1235         return false;
1236     }
1237 
1238     /**
1239      * Writes the AffineTrassform object to the output steam.
1240      *
1241      * @param stream
1242      *            - the output stream.
1243      * @throws IOException
1244      *             - if there are I/O errors while writing to the output stream.
1245      */
writeObject(java.io.ObjectOutputStream stream)1246     private void writeObject(java.io.ObjectOutputStream stream) throws IOException {
1247         stream.defaultWriteObject();
1248     }
1249 
1250     /**
1251      * Read the AffineTransform object from the input stream.
1252      *
1253      * @param stream
1254      *            - the input stream.
1255      * @throws IOException
1256      *             - if there are I/O errors while reading from the input
1257      *             stream.
1258      * @throws ClassNotFoundException
1259      *             - if class could not be found.
1260      */
readObject(java.io.ObjectInputStream stream)1261     private void readObject(java.io.ObjectInputStream stream) throws IOException,
1262             ClassNotFoundException {
1263         stream.defaultReadObject();
1264         type = TYPE_UNKNOWN;
1265     }
1266 
1267 }
1268