1 /*
2  * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package java.awt.geom;
27 
28 import java.awt.Shape;
29 import java.beans.ConstructorProperties;
30 
31 /**
32  * The <code>AffineTransform</code> class represents a 2D affine transform
33  * that performs a linear mapping from 2D coordinates to other 2D
34  * coordinates that preserves the "straightness" and
35  * "parallelness" of lines.  Affine transformations can be constructed
36  * using sequences of translations, scales, flips, rotations, and shears.
37  * <p>
38  * Such a coordinate transformation can be represented by a 3 row by
39  * 3 column matrix with an implied last row of [ 0 0 1 ].  This matrix
40  * transforms source coordinates {@code (x,y)} into
41  * destination coordinates {@code (x',y')} by considering
42  * them to be a column vector and multiplying the coordinate vector
43  * by the matrix according to the following process:
44  * <pre>
45  *      [ x']   [  m00  m01  m02  ] [ x ]   [ m00x + m01y + m02 ]
46  *      [ y'] = [  m10  m11  m12  ] [ y ] = [ m10x + m11y + m12 ]
47  *      [ 1 ]   [   0    0    1   ] [ 1 ]   [         1         ]
48  * </pre>
49  * <h3><a name="quadrantapproximation">Handling 90-Degree Rotations</a></h3>
50  * <p>
51  * In some variations of the <code>rotate</code> methods in the
52  * <code>AffineTransform</code> class, a double-precision argument
53  * specifies the angle of rotation in radians.
54  * These methods have special handling for rotations of approximately
55  * 90 degrees (including multiples such as 180, 270, and 360 degrees),
56  * so that the common case of quadrant rotation is handled more
57  * efficiently.
58  * This special handling can cause angles very close to multiples of
59  * 90 degrees to be treated as if they were exact multiples of
60  * 90 degrees.
61  * For small multiples of 90 degrees the range of angles treated
62  * as a quadrant rotation is approximately 0.00000121 degrees wide.
63  * This section explains why such special care is needed and how
64  * it is implemented.
65  * <p>
66  * Since 90 degrees is represented as <code>PI/2</code> in radians,
67  * and since PI is a transcendental (and therefore irrational) number,
68  * it is not possible to exactly represent a multiple of 90 degrees as
69  * an exact double precision value measured in radians.
70  * As a result it is theoretically impossible to describe quadrant
71  * rotations (90, 180, 270 or 360 degrees) using these values.
72  * Double precision floating point values can get very close to
73  * non-zero multiples of <code>PI/2</code> but never close enough
74  * for the sine or cosine to be exactly 0.0, 1.0 or -1.0.
75  * The implementations of <code>Math.sin()</code> and
76  * <code>Math.cos()</code> correspondingly never return 0.0
77  * for any case other than <code>Math.sin(0.0)</code>.
78  * These same implementations do, however, return exactly 1.0 and
79  * -1.0 for some range of numbers around each multiple of 90
80  * degrees since the correct answer is so close to 1.0 or -1.0 that
81  * the double precision significand cannot represent the difference
82  * as accurately as it can for numbers that are near 0.0.
83  * <p>
84  * The net result of these issues is that if the
85  * <code>Math.sin()</code> and <code>Math.cos()</code> methods
86  * are used to directly generate the values for the matrix modifications
87  * during these radian-based rotation operations then the resulting
88  * transform is never strictly classifiable as a quadrant rotation
89  * even for a simple case like <code>rotate(Math.PI/2.0)</code>,
90  * due to minor variations in the matrix caused by the non-0.0 values
91  * obtained for the sine and cosine.
92  * If these transforms are not classified as quadrant rotations then
93  * subsequent code which attempts to optimize further operations based
94  * upon the type of the transform will be relegated to its most general
95  * implementation.
96  * <p>
97  * Because quadrant rotations are fairly common,
98  * this class should handle these cases reasonably quickly, both in
99  * applying the rotations to the transform and in applying the resulting
100  * transform to the coordinates.
101  * To facilitate this optimal handling, the methods which take an angle
102  * of rotation measured in radians attempt to detect angles that are
103  * intended to be quadrant rotations and treat them as such.
104  * These methods therefore treat an angle <em>theta</em> as a quadrant
105  * rotation if either <code>Math.sin(<em>theta</em>)</code> or
106  * <code>Math.cos(<em>theta</em>)</code> returns exactly 1.0 or -1.0.
107  * As a rule of thumb, this property holds true for a range of
108  * approximately 0.0000000211 radians (or 0.00000121 degrees) around
109  * small multiples of <code>Math.PI/2.0</code>.
110  *
111  * @author Jim Graham
112  * @since 1.2
113  */
114 public class AffineTransform implements Cloneable, java.io.Serializable {
115 
116     /*
117      * This constant is only useful for the cached type field.
118      * It indicates that the type has been decached and must be recalculated.
119      */
120     private static final int TYPE_UNKNOWN = -1;
121 
122     /**
123      * This constant indicates that the transform defined by this object
124      * is an identity transform.
125      * An identity transform is one in which the output coordinates are
126      * always the same as the input coordinates.
127      * If this transform is anything other than the identity transform,
128      * the type will either be the constant GENERAL_TRANSFORM or a
129      * combination of the appropriate flag bits for the various coordinate
130      * conversions that this transform performs.
131      * @see #TYPE_TRANSLATION
132      * @see #TYPE_UNIFORM_SCALE
133      * @see #TYPE_GENERAL_SCALE
134      * @see #TYPE_FLIP
135      * @see #TYPE_QUADRANT_ROTATION
136      * @see #TYPE_GENERAL_ROTATION
137      * @see #TYPE_GENERAL_TRANSFORM
138      * @see #getType
139      * @since 1.2
140      */
141     public static final int TYPE_IDENTITY = 0;
142 
143     /**
144      * This flag bit indicates that the transform defined by this object
145      * performs a translation in addition to the conversions indicated
146      * by other flag bits.
147      * A translation moves the coordinates by a constant amount in x
148      * and y without changing the length or angle of vectors.
149      * @see #TYPE_IDENTITY
150      * @see #TYPE_UNIFORM_SCALE
151      * @see #TYPE_GENERAL_SCALE
152      * @see #TYPE_FLIP
153      * @see #TYPE_QUADRANT_ROTATION
154      * @see #TYPE_GENERAL_ROTATION
155      * @see #TYPE_GENERAL_TRANSFORM
156      * @see #getType
157      * @since 1.2
158      */
159     public static final int TYPE_TRANSLATION = 1;
160 
161     /**
162      * This flag bit indicates that the transform defined by this object
163      * performs a uniform scale in addition to the conversions indicated
164      * by other flag bits.
165      * A uniform scale multiplies the length of vectors by the same amount
166      * in both the x and y directions without changing the angle between
167      * vectors.
168      * This flag bit is mutually exclusive with the TYPE_GENERAL_SCALE flag.
169      * @see #TYPE_IDENTITY
170      * @see #TYPE_TRANSLATION
171      * @see #TYPE_GENERAL_SCALE
172      * @see #TYPE_FLIP
173      * @see #TYPE_QUADRANT_ROTATION
174      * @see #TYPE_GENERAL_ROTATION
175      * @see #TYPE_GENERAL_TRANSFORM
176      * @see #getType
177      * @since 1.2
178      */
179     public static final int TYPE_UNIFORM_SCALE = 2;
180 
181     /**
182      * This flag bit indicates that the transform defined by this object
183      * performs a general scale in addition to the conversions indicated
184      * by other flag bits.
185      * A general scale multiplies the length of vectors by different
186      * amounts in the x and y directions without changing the angle
187      * between perpendicular vectors.
188      * This flag bit is mutually exclusive with the TYPE_UNIFORM_SCALE flag.
189      * @see #TYPE_IDENTITY
190      * @see #TYPE_TRANSLATION
191      * @see #TYPE_UNIFORM_SCALE
192      * @see #TYPE_FLIP
193      * @see #TYPE_QUADRANT_ROTATION
194      * @see #TYPE_GENERAL_ROTATION
195      * @see #TYPE_GENERAL_TRANSFORM
196      * @see #getType
197      * @since 1.2
198      */
199     public static final int TYPE_GENERAL_SCALE = 4;
200 
201     /**
202      * This constant is a bit mask for any of the scale flag bits.
203      * @see #TYPE_UNIFORM_SCALE
204      * @see #TYPE_GENERAL_SCALE
205      * @since 1.2
206      */
207     public static final int TYPE_MASK_SCALE = (TYPE_UNIFORM_SCALE |
208                                                TYPE_GENERAL_SCALE);
209 
210     /**
211      * This flag bit indicates that the transform defined by this object
212      * performs a mirror image flip about some axis which changes the
213      * normally right handed coordinate system into a left handed
214      * system in addition to the conversions indicated by other flag bits.
215      * A right handed coordinate system is one where the positive X
216      * axis rotates counterclockwise to overlay the positive Y axis
217      * similar to the direction that the fingers on your right hand
218      * curl when you stare end on at your thumb.
219      * A left handed coordinate system is one where the positive X
220      * axis rotates clockwise to overlay the positive Y axis similar
221      * to the direction that the fingers on your left hand curl.
222      * There is no mathematical way to determine the angle of the
223      * original flipping or mirroring transformation since all angles
224      * of flip are identical given an appropriate adjusting rotation.
225      * @see #TYPE_IDENTITY
226      * @see #TYPE_TRANSLATION
227      * @see #TYPE_UNIFORM_SCALE
228      * @see #TYPE_GENERAL_SCALE
229      * @see #TYPE_QUADRANT_ROTATION
230      * @see #TYPE_GENERAL_ROTATION
231      * @see #TYPE_GENERAL_TRANSFORM
232      * @see #getType
233      * @since 1.2
234      */
235     public static final int TYPE_FLIP = 64;
236     /* NOTE: TYPE_FLIP was added after GENERAL_TRANSFORM was in public
237      * circulation and the flag bits could no longer be conveniently
238      * renumbered without introducing binary incompatibility in outside
239      * code.
240      */
241 
242     /**
243      * This flag bit indicates that the transform defined by this object
244      * performs a quadrant rotation by some multiple of 90 degrees in
245      * addition to the conversions indicated by other flag bits.
246      * A rotation changes the angles of vectors by the same amount
247      * regardless of the original direction of the vector and without
248      * changing the length of the vector.
249      * This flag bit is mutually exclusive with the TYPE_GENERAL_ROTATION flag.
250      * @see #TYPE_IDENTITY
251      * @see #TYPE_TRANSLATION
252      * @see #TYPE_UNIFORM_SCALE
253      * @see #TYPE_GENERAL_SCALE
254      * @see #TYPE_FLIP
255      * @see #TYPE_GENERAL_ROTATION
256      * @see #TYPE_GENERAL_TRANSFORM
257      * @see #getType
258      * @since 1.2
259      */
260     public static final int TYPE_QUADRANT_ROTATION = 8;
261 
262     /**
263      * This flag bit indicates that the transform defined by this object
264      * performs a rotation by an arbitrary angle in addition to the
265      * conversions indicated by other flag bits.
266      * A rotation changes the angles of vectors by the same amount
267      * regardless of the original direction of the vector and without
268      * changing the length of the vector.
269      * This flag bit is mutually exclusive with the
270      * TYPE_QUADRANT_ROTATION flag.
271      * @see #TYPE_IDENTITY
272      * @see #TYPE_TRANSLATION
273      * @see #TYPE_UNIFORM_SCALE
274      * @see #TYPE_GENERAL_SCALE
275      * @see #TYPE_FLIP
276      * @see #TYPE_QUADRANT_ROTATION
277      * @see #TYPE_GENERAL_TRANSFORM
278      * @see #getType
279      * @since 1.2
280      */
281     public static final int TYPE_GENERAL_ROTATION = 16;
282 
283     /**
284      * This constant is a bit mask for any of the rotation flag bits.
285      * @see #TYPE_QUADRANT_ROTATION
286      * @see #TYPE_GENERAL_ROTATION
287      * @since 1.2
288      */
289     public static final int TYPE_MASK_ROTATION = (TYPE_QUADRANT_ROTATION |
290                                                   TYPE_GENERAL_ROTATION);
291 
292     /**
293      * This constant indicates that the transform defined by this object
294      * performs an arbitrary conversion of the input coordinates.
295      * If this transform can be classified by any of the above constants,
296      * the type will either be the constant TYPE_IDENTITY or a
297      * combination of the appropriate flag bits for the various coordinate
298      * conversions that this transform performs.
299      * @see #TYPE_IDENTITY
300      * @see #TYPE_TRANSLATION
301      * @see #TYPE_UNIFORM_SCALE
302      * @see #TYPE_GENERAL_SCALE
303      * @see #TYPE_FLIP
304      * @see #TYPE_QUADRANT_ROTATION
305      * @see #TYPE_GENERAL_ROTATION
306      * @see #getType
307      * @since 1.2
308      */
309     public static final int TYPE_GENERAL_TRANSFORM = 32;
310 
311     /**
312      * This constant is used for the internal state variable to indicate
313      * that no calculations need to be performed and that the source
314      * coordinates only need to be copied to their destinations to
315      * complete the transformation equation of this transform.
316      * @see #APPLY_TRANSLATE
317      * @see #APPLY_SCALE
318      * @see #APPLY_SHEAR
319      * @see #state
320      */
321     static final int APPLY_IDENTITY = 0;
322 
323     /**
324      * This constant is used for the internal state variable to indicate
325      * that the translation components of the matrix (m02 and m12) need
326      * to be added to complete the transformation equation of this transform.
327      * @see #APPLY_IDENTITY
328      * @see #APPLY_SCALE
329      * @see #APPLY_SHEAR
330      * @see #state
331      */
332     static final int APPLY_TRANSLATE = 1;
333 
334     /**
335      * This constant is used for the internal state variable to indicate
336      * that the scaling components of the matrix (m00 and m11) need
337      * to be factored in to complete the transformation equation of
338      * this transform.  If the APPLY_SHEAR bit is also set then it
339      * indicates that the scaling components are not both 0.0.  If the
340      * APPLY_SHEAR bit is not also set then it indicates that the
341      * scaling components are not both 1.0.  If neither the APPLY_SHEAR
342      * nor the APPLY_SCALE bits are set then the scaling components
343      * are both 1.0, which means that the x and y components contribute
344      * to the transformed coordinate, but they are not multiplied by
345      * any scaling factor.
346      * @see #APPLY_IDENTITY
347      * @see #APPLY_TRANSLATE
348      * @see #APPLY_SHEAR
349      * @see #state
350      */
351     static final int APPLY_SCALE = 2;
352 
353     /**
354      * This constant is used for the internal state variable to indicate
355      * that the shearing components of the matrix (m01 and m10) need
356      * to be factored in to complete the transformation equation of this
357      * transform.  The presence of this bit in the state variable changes
358      * the interpretation of the APPLY_SCALE bit as indicated in its
359      * documentation.
360      * @see #APPLY_IDENTITY
361      * @see #APPLY_TRANSLATE
362      * @see #APPLY_SCALE
363      * @see #state
364      */
365     static final int APPLY_SHEAR = 4;
366 
367     /*
368      * For methods which combine together the state of two separate
369      * transforms and dispatch based upon the combination, these constants
370      * specify how far to shift one of the states so that the two states
371      * are mutually non-interfering and provide constants for testing the
372      * bits of the shifted (HI) state.  The methods in this class use
373      * the convention that the state of "this" transform is unshifted and
374      * the state of the "other" or "argument" transform is shifted (HI).
375      */
376     private static final int HI_SHIFT = 3;
377     private static final int HI_IDENTITY = APPLY_IDENTITY << HI_SHIFT;
378     private static final int HI_TRANSLATE = APPLY_TRANSLATE << HI_SHIFT;
379     private static final int HI_SCALE = APPLY_SCALE << HI_SHIFT;
380     private static final int HI_SHEAR = APPLY_SHEAR << HI_SHIFT;
381 
382     /**
383      * The X coordinate scaling element of the 3x3
384      * affine transformation matrix.
385      *
386      * @serial
387      */
388     double m00;
389 
390     /**
391      * The Y coordinate shearing element of the 3x3
392      * affine transformation matrix.
393      *
394      * @serial
395      */
396      double m10;
397 
398     /**
399      * The X coordinate shearing element of the 3x3
400      * affine transformation matrix.
401      *
402      * @serial
403      */
404      double m01;
405 
406     /**
407      * The Y coordinate scaling element of the 3x3
408      * affine transformation matrix.
409      *
410      * @serial
411      */
412      double m11;
413 
414     /**
415      * The X coordinate of the translation element of the
416      * 3x3 affine transformation matrix.
417      *
418      * @serial
419      */
420      double m02;
421 
422     /**
423      * The Y coordinate of the translation element of the
424      * 3x3 affine transformation matrix.
425      *
426      * @serial
427      */
428      double m12;
429 
430     /**
431      * This field keeps track of which components of the matrix need to
432      * be applied when performing a transformation.
433      * @see #APPLY_IDENTITY
434      * @see #APPLY_TRANSLATE
435      * @see #APPLY_SCALE
436      * @see #APPLY_SHEAR
437      */
438     transient int state;
439 
440     /**
441      * This field caches the current transformation type of the matrix.
442      * @see #TYPE_IDENTITY
443      * @see #TYPE_TRANSLATION
444      * @see #TYPE_UNIFORM_SCALE
445      * @see #TYPE_GENERAL_SCALE
446      * @see #TYPE_FLIP
447      * @see #TYPE_QUADRANT_ROTATION
448      * @see #TYPE_GENERAL_ROTATION
449      * @see #TYPE_GENERAL_TRANSFORM
450      * @see #TYPE_UNKNOWN
451      * @see #getType
452      */
453     private transient int type;
454 
AffineTransform(double m00, double m10, double m01, double m11, double m02, double m12, int state)455     private AffineTransform(double m00, double m10,
456                             double m01, double m11,
457                             double m02, double m12,
458                             int state) {
459         this.m00 = m00;
460         this.m10 = m10;
461         this.m01 = m01;
462         this.m11 = m11;
463         this.m02 = m02;
464         this.m12 = m12;
465         this.state = state;
466         this.type = TYPE_UNKNOWN;
467     }
468 
469     /**
470      * Constructs a new <code>AffineTransform</code> representing the
471      * Identity transformation.
472      * @since 1.2
473      */
AffineTransform()474     public AffineTransform() {
475         m00 = m11 = 1.0;
476         // m01 = m10 = m02 = m12 = 0.0;         /* Not needed. */
477         // state = APPLY_IDENTITY;              /* Not needed. */
478         // type = TYPE_IDENTITY;                /* Not needed. */
479     }
480 
481     /**
482      * Constructs a new <code>AffineTransform</code> that is a copy of
483      * the specified <code>AffineTransform</code> object.
484      * @param Tx the <code>AffineTransform</code> object to copy
485      * @since 1.2
486      */
AffineTransform(AffineTransform Tx)487     public AffineTransform(AffineTransform Tx) {
488         this.m00 = Tx.m00;
489         this.m10 = Tx.m10;
490         this.m01 = Tx.m01;
491         this.m11 = Tx.m11;
492         this.m02 = Tx.m02;
493         this.m12 = Tx.m12;
494         this.state = Tx.state;
495         this.type = Tx.type;
496     }
497 
498     /**
499      * Constructs a new <code>AffineTransform</code> from 6 floating point
500      * values representing the 6 specifiable entries of the 3x3
501      * transformation matrix.
502      *
503      * @param m00 the X coordinate scaling element of the 3x3 matrix
504      * @param m10 the Y coordinate shearing element of the 3x3 matrix
505      * @param m01 the X coordinate shearing element of the 3x3 matrix
506      * @param m11 the Y coordinate scaling element of the 3x3 matrix
507      * @param m02 the X coordinate translation element of the 3x3 matrix
508      * @param m12 the Y coordinate translation element of the 3x3 matrix
509      * @since 1.2
510      */
511     @ConstructorProperties({ "scaleX", "shearY", "shearX", "scaleY", "translateX", "translateY" })
AffineTransform(float m00, float m10, float m01, float m11, float m02, float m12)512     public AffineTransform(float m00, float m10,
513                            float m01, float m11,
514                            float m02, float m12) {
515         this.m00 = m00;
516         this.m10 = m10;
517         this.m01 = m01;
518         this.m11 = m11;
519         this.m02 = m02;
520         this.m12 = m12;
521         updateState();
522     }
523 
524     /**
525      * Constructs a new <code>AffineTransform</code> from an array of
526      * floating point values representing either the 4 non-translation
527      * entries or the 6 specifiable entries of the 3x3 transformation
528      * matrix.  The values are retrieved from the array as
529      * {&nbsp;m00&nbsp;m10&nbsp;m01&nbsp;m11&nbsp;[m02&nbsp;m12]}.
530      * @param flatmatrix the float array containing the values to be set
531      * in the new <code>AffineTransform</code> object. The length of the
532      * array is assumed to be at least 4. If the length of the array is
533      * less than 6, only the first 4 values are taken. If the length of
534      * the array is greater than 6, the first 6 values are taken.
535      * @since 1.2
536      */
AffineTransform(float[] flatmatrix)537     public AffineTransform(float[] flatmatrix) {
538         m00 = flatmatrix[0];
539         m10 = flatmatrix[1];
540         m01 = flatmatrix[2];
541         m11 = flatmatrix[3];
542         if (flatmatrix.length > 5) {
543             m02 = flatmatrix[4];
544             m12 = flatmatrix[5];
545         }
546         updateState();
547     }
548 
549     /**
550      * Constructs a new <code>AffineTransform</code> from 6 double
551      * precision values representing the 6 specifiable entries of the 3x3
552      * transformation matrix.
553      *
554      * @param m00 the X coordinate scaling element of the 3x3 matrix
555      * @param m10 the Y coordinate shearing element of the 3x3 matrix
556      * @param m01 the X coordinate shearing element of the 3x3 matrix
557      * @param m11 the Y coordinate scaling element of the 3x3 matrix
558      * @param m02 the X coordinate translation element of the 3x3 matrix
559      * @param m12 the Y coordinate translation element of the 3x3 matrix
560      * @since 1.2
561      */
AffineTransform(double m00, double m10, double m01, double m11, double m02, double m12)562     public AffineTransform(double m00, double m10,
563                            double m01, double m11,
564                            double m02, double m12) {
565         this.m00 = m00;
566         this.m10 = m10;
567         this.m01 = m01;
568         this.m11 = m11;
569         this.m02 = m02;
570         this.m12 = m12;
571         updateState();
572     }
573 
574     /**
575      * Constructs a new <code>AffineTransform</code> from an array of
576      * double precision values representing either the 4 non-translation
577      * entries or the 6 specifiable entries of the 3x3 transformation
578      * matrix. The values are retrieved from the array as
579      * {&nbsp;m00&nbsp;m10&nbsp;m01&nbsp;m11&nbsp;[m02&nbsp;m12]}.
580      * @param flatmatrix the double array containing the values to be set
581      * in the new <code>AffineTransform</code> object. The length of the
582      * array is assumed to be at least 4. If the length of the array is
583      * less than 6, only the first 4 values are taken. If the length of
584      * the array is greater than 6, the first 6 values are taken.
585      * @since 1.2
586      */
AffineTransform(double[] flatmatrix)587     public AffineTransform(double[] flatmatrix) {
588         m00 = flatmatrix[0];
589         m10 = flatmatrix[1];
590         m01 = flatmatrix[2];
591         m11 = flatmatrix[3];
592         if (flatmatrix.length > 5) {
593             m02 = flatmatrix[4];
594             m12 = flatmatrix[5];
595         }
596         updateState();
597     }
598 
599     /**
600      * Returns a transform representing a translation transformation.
601      * The matrix representing the returned transform is:
602      * <pre>
603      *          [   1    0    tx  ]
604      *          [   0    1    ty  ]
605      *          [   0    0    1   ]
606      * </pre>
607      * @param tx the distance by which coordinates are translated in the
608      * X axis direction
609      * @param ty the distance by which coordinates are translated in the
610      * Y axis direction
611      * @return an <code>AffineTransform</code> object that represents a
612      *  translation transformation, created with the specified vector.
613      * @since 1.2
614      */
getTranslateInstance(double tx, double ty)615     public static AffineTransform getTranslateInstance(double tx, double ty) {
616         AffineTransform Tx = new AffineTransform();
617         Tx.setToTranslation(tx, ty);
618         return Tx;
619     }
620 
621     /**
622      * Returns a transform representing a rotation transformation.
623      * The matrix representing the returned transform is:
624      * <pre>
625      *          [   cos(theta)    -sin(theta)    0   ]
626      *          [   sin(theta)     cos(theta)    0   ]
627      *          [       0              0         1   ]
628      * </pre>
629      * Rotating by a positive angle theta rotates points on the positive
630      * X axis toward the positive Y axis.
631      * Note also the discussion of
632      * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
633      * above.
634      * @param theta the angle of rotation measured in radians
635      * @return an <code>AffineTransform</code> object that is a rotation
636      *  transformation, created with the specified angle of rotation.
637      * @since 1.2
638      */
getRotateInstance(double theta)639     public static AffineTransform getRotateInstance(double theta) {
640         AffineTransform Tx = new AffineTransform();
641         Tx.setToRotation(theta);
642         return Tx;
643     }
644 
645     /**
646      * Returns a transform that rotates coordinates around an anchor point.
647      * This operation is equivalent to translating the coordinates so
648      * that the anchor point is at the origin (S1), then rotating them
649      * about the new origin (S2), and finally translating so that the
650      * intermediate origin is restored to the coordinates of the original
651      * anchor point (S3).
652      * <p>
653      * This operation is equivalent to the following sequence of calls:
654      * <pre>
655      *     AffineTransform Tx = new AffineTransform();
656      *     Tx.translate(anchorx, anchory);    // S3: final translation
657      *     Tx.rotate(theta);                  // S2: rotate around anchor
658      *     Tx.translate(-anchorx, -anchory);  // S1: translate anchor to origin
659      * </pre>
660      * The matrix representing the returned transform is:
661      * <pre>
662      *          [   cos(theta)    -sin(theta)    x-x*cos+y*sin  ]
663      *          [   sin(theta)     cos(theta)    y-x*sin-y*cos  ]
664      *          [       0              0               1        ]
665      * </pre>
666      * Rotating by a positive angle theta rotates points on the positive
667      * X axis toward the positive Y axis.
668      * Note also the discussion of
669      * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
670      * above.
671      *
672      * @param theta the angle of rotation measured in radians
673      * @param anchorx the X coordinate of the rotation anchor point
674      * @param anchory the Y coordinate of the rotation anchor point
675      * @return an <code>AffineTransform</code> object that rotates
676      *  coordinates around the specified point by the specified angle of
677      *  rotation.
678      * @since 1.2
679      */
getRotateInstance(double theta, double anchorx, double anchory)680     public static AffineTransform getRotateInstance(double theta,
681                                                     double anchorx,
682                                                     double anchory)
683     {
684         AffineTransform Tx = new AffineTransform();
685         Tx.setToRotation(theta, anchorx, anchory);
686         return Tx;
687     }
688 
689     /**
690      * Returns a transform that rotates coordinates according to
691      * a rotation vector.
692      * All coordinates rotate about the origin by the same amount.
693      * The amount of rotation is such that coordinates along the former
694      * positive X axis will subsequently align with the vector pointing
695      * from the origin to the specified vector coordinates.
696      * If both <code>vecx</code> and <code>vecy</code> are 0.0,
697      * an identity transform is returned.
698      * This operation is equivalent to calling:
699      * <pre>
700      *     AffineTransform.getRotateInstance(Math.atan2(vecy, vecx));
701      * </pre>
702      *
703      * @param vecx the X coordinate of the rotation vector
704      * @param vecy the Y coordinate of the rotation vector
705      * @return an <code>AffineTransform</code> object that rotates
706      *  coordinates according to the specified rotation vector.
707      * @since 1.6
708      */
getRotateInstance(double vecx, double vecy)709     public static AffineTransform getRotateInstance(double vecx, double vecy) {
710         AffineTransform Tx = new AffineTransform();
711         Tx.setToRotation(vecx, vecy);
712         return Tx;
713     }
714 
715     /**
716      * Returns a transform that rotates coordinates around an anchor
717      * point according to a rotation vector.
718      * All coordinates rotate about the specified anchor coordinates
719      * by the same amount.
720      * The amount of rotation is such that coordinates along the former
721      * positive X axis will subsequently align with the vector pointing
722      * from the origin to the specified vector coordinates.
723      * If both <code>vecx</code> and <code>vecy</code> are 0.0,
724      * an identity transform is returned.
725      * This operation is equivalent to calling:
726      * <pre>
727      *     AffineTransform.getRotateInstance(Math.atan2(vecy, vecx),
728      *                                       anchorx, anchory);
729      * </pre>
730      *
731      * @param vecx the X coordinate of the rotation vector
732      * @param vecy the Y coordinate of the rotation vector
733      * @param anchorx the X coordinate of the rotation anchor point
734      * @param anchory the Y coordinate of the rotation anchor point
735      * @return an <code>AffineTransform</code> object that rotates
736      *  coordinates around the specified point according to the
737      *  specified rotation vector.
738      * @since 1.6
739      */
getRotateInstance(double vecx, double vecy, double anchorx, double anchory)740     public static AffineTransform getRotateInstance(double vecx,
741                                                     double vecy,
742                                                     double anchorx,
743                                                     double anchory)
744     {
745         AffineTransform Tx = new AffineTransform();
746         Tx.setToRotation(vecx, vecy, anchorx, anchory);
747         return Tx;
748     }
749 
750     /**
751      * Returns a transform that rotates coordinates by the specified
752      * number of quadrants.
753      * This operation is equivalent to calling:
754      * <pre>
755      *     AffineTransform.getRotateInstance(numquadrants * Math.PI / 2.0);
756      * </pre>
757      * Rotating by a positive number of quadrants rotates points on
758      * the positive X axis toward the positive Y axis.
759      * @param numquadrants the number of 90 degree arcs to rotate by
760      * @return an <code>AffineTransform</code> object that rotates
761      *  coordinates by the specified number of quadrants.
762      * @since 1.6
763      */
getQuadrantRotateInstance(int numquadrants)764     public static AffineTransform getQuadrantRotateInstance(int numquadrants) {
765         AffineTransform Tx = new AffineTransform();
766         Tx.setToQuadrantRotation(numquadrants);
767         return Tx;
768     }
769 
770     /**
771      * Returns a transform that rotates coordinates by the specified
772      * number of quadrants around the specified anchor point.
773      * This operation is equivalent to calling:
774      * <pre>
775      *     AffineTransform.getRotateInstance(numquadrants * Math.PI / 2.0,
776      *                                       anchorx, anchory);
777      * </pre>
778      * Rotating by a positive number of quadrants rotates points on
779      * the positive X axis toward the positive Y axis.
780      *
781      * @param numquadrants the number of 90 degree arcs to rotate by
782      * @param anchorx the X coordinate of the rotation anchor point
783      * @param anchory the Y coordinate of the rotation anchor point
784      * @return an <code>AffineTransform</code> object that rotates
785      *  coordinates by the specified number of quadrants around the
786      *  specified anchor point.
787      * @since 1.6
788      */
getQuadrantRotateInstance(int numquadrants, double anchorx, double anchory)789     public static AffineTransform getQuadrantRotateInstance(int numquadrants,
790                                                             double anchorx,
791                                                             double anchory)
792     {
793         AffineTransform Tx = new AffineTransform();
794         Tx.setToQuadrantRotation(numquadrants, anchorx, anchory);
795         return Tx;
796     }
797 
798     /**
799      * Returns a transform representing a scaling transformation.
800      * The matrix representing the returned transform is:
801      * <pre>
802      *          [   sx   0    0   ]
803      *          [   0    sy   0   ]
804      *          [   0    0    1   ]
805      * </pre>
806      * @param sx the factor by which coordinates are scaled along the
807      * X axis direction
808      * @param sy the factor by which coordinates are scaled along the
809      * Y axis direction
810      * @return an <code>AffineTransform</code> object that scales
811      *  coordinates by the specified factors.
812      * @since 1.2
813      */
getScaleInstance(double sx, double sy)814     public static AffineTransform getScaleInstance(double sx, double sy) {
815         AffineTransform Tx = new AffineTransform();
816         Tx.setToScale(sx, sy);
817         return Tx;
818     }
819 
820     /**
821      * Returns a transform representing a shearing transformation.
822      * The matrix representing the returned transform is:
823      * <pre>
824      *          [   1   shx   0   ]
825      *          [  shy   1    0   ]
826      *          [   0    0    1   ]
827      * </pre>
828      * @param shx the multiplier by which coordinates are shifted in the
829      * direction of the positive X axis as a factor of their Y coordinate
830      * @param shy the multiplier by which coordinates are shifted in the
831      * direction of the positive Y axis as a factor of their X coordinate
832      * @return an <code>AffineTransform</code> object that shears
833      *  coordinates by the specified multipliers.
834      * @since 1.2
835      */
getShearInstance(double shx, double shy)836     public static AffineTransform getShearInstance(double shx, double shy) {
837         AffineTransform Tx = new AffineTransform();
838         Tx.setToShear(shx, shy);
839         return Tx;
840     }
841 
842     /**
843      * Retrieves the flag bits describing the conversion properties of
844      * this transform.
845      * The return value is either one of the constants TYPE_IDENTITY
846      * or TYPE_GENERAL_TRANSFORM, or a combination of the
847      * appropriate flag bits.
848      * A valid combination of flag bits is an exclusive OR operation
849      * that can combine
850      * the TYPE_TRANSLATION flag bit
851      * in addition to either of the
852      * TYPE_UNIFORM_SCALE or TYPE_GENERAL_SCALE flag bits
853      * as well as either of the
854      * TYPE_QUADRANT_ROTATION or TYPE_GENERAL_ROTATION flag bits.
855      * @return the OR combination of any of the indicated flags that
856      * apply to this transform
857      * @see #TYPE_IDENTITY
858      * @see #TYPE_TRANSLATION
859      * @see #TYPE_UNIFORM_SCALE
860      * @see #TYPE_GENERAL_SCALE
861      * @see #TYPE_QUADRANT_ROTATION
862      * @see #TYPE_GENERAL_ROTATION
863      * @see #TYPE_GENERAL_TRANSFORM
864      * @since 1.2
865      */
getType()866     public int getType() {
867         if (type == TYPE_UNKNOWN) {
868             calculateType();
869         }
870         return type;
871     }
872 
873     /**
874      * This is the utility function to calculate the flag bits when
875      * they have not been cached.
876      * @see #getType
877      */
878     @SuppressWarnings("fallthrough")
calculateType()879     private void calculateType() {
880         int ret = TYPE_IDENTITY;
881         boolean sgn0, sgn1;
882         double M0, M1, M2, M3;
883         updateState();
884         switch (state) {
885         default:
886             stateError();
887             /* NOTREACHED */
888         case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
889             ret = TYPE_TRANSLATION;
890             /* NOBREAK */
891         case (APPLY_SHEAR | APPLY_SCALE):
892             if ((M0 = m00) * (M2 = m01) + (M3 = m10) * (M1 = m11) != 0) {
893                 // Transformed unit vectors are not perpendicular...
894                 this.type = TYPE_GENERAL_TRANSFORM;
895                 return;
896             }
897             sgn0 = (M0 >= 0.0);
898             sgn1 = (M1 >= 0.0);
899             if (sgn0 == sgn1) {
900                 // sgn(M0) == sgn(M1) therefore sgn(M2) == -sgn(M3)
901                 // This is the "unflipped" (right-handed) state
902                 if (M0 != M1 || M2 != -M3) {
903                     ret |= (TYPE_GENERAL_ROTATION | TYPE_GENERAL_SCALE);
904                 } else if (M0 * M1 - M2 * M3 != 1.0) {
905                     ret |= (TYPE_GENERAL_ROTATION | TYPE_UNIFORM_SCALE);
906                 } else {
907                     ret |= TYPE_GENERAL_ROTATION;
908                 }
909             } else {
910                 // sgn(M0) == -sgn(M1) therefore sgn(M2) == sgn(M3)
911                 // This is the "flipped" (left-handed) state
912                 if (M0 != -M1 || M2 != M3) {
913                     ret |= (TYPE_GENERAL_ROTATION |
914                             TYPE_FLIP |
915                             TYPE_GENERAL_SCALE);
916                 } else if (M0 * M1 - M2 * M3 != 1.0) {
917                     ret |= (TYPE_GENERAL_ROTATION |
918                             TYPE_FLIP |
919                             TYPE_UNIFORM_SCALE);
920                 } else {
921                     ret |= (TYPE_GENERAL_ROTATION | TYPE_FLIP);
922                 }
923             }
924             break;
925         case (APPLY_SHEAR | APPLY_TRANSLATE):
926             ret = TYPE_TRANSLATION;
927             /* NOBREAK */
928         case (APPLY_SHEAR):
929             sgn0 = ((M0 = m01) >= 0.0);
930             sgn1 = ((M1 = m10) >= 0.0);
931             if (sgn0 != sgn1) {
932                 // Different signs - simple 90 degree rotation
933                 if (M0 != -M1) {
934                     ret |= (TYPE_QUADRANT_ROTATION | TYPE_GENERAL_SCALE);
935                 } else if (M0 != 1.0 && M0 != -1.0) {
936                     ret |= (TYPE_QUADRANT_ROTATION | TYPE_UNIFORM_SCALE);
937                 } else {
938                     ret |= TYPE_QUADRANT_ROTATION;
939                 }
940             } else {
941                 // Same signs - 90 degree rotation plus an axis flip too
942                 if (M0 == M1) {
943                     ret |= (TYPE_QUADRANT_ROTATION |
944                             TYPE_FLIP |
945                             TYPE_UNIFORM_SCALE);
946                 } else {
947                     ret |= (TYPE_QUADRANT_ROTATION |
948                             TYPE_FLIP |
949                             TYPE_GENERAL_SCALE);
950                 }
951             }
952             break;
953         case (APPLY_SCALE | APPLY_TRANSLATE):
954             ret = TYPE_TRANSLATION;
955             /* NOBREAK */
956         case (APPLY_SCALE):
957             sgn0 = ((M0 = m00) >= 0.0);
958             sgn1 = ((M1 = m11) >= 0.0);
959             if (sgn0 == sgn1) {
960                 if (sgn0) {
961                     // Both scaling factors non-negative - simple scale
962                     // Note: APPLY_SCALE implies M0, M1 are not both 1
963                     if (M0 == M1) {
964                         ret |= TYPE_UNIFORM_SCALE;
965                     } else {
966                         ret |= TYPE_GENERAL_SCALE;
967                     }
968                 } else {
969                     // Both scaling factors negative - 180 degree rotation
970                     if (M0 != M1) {
971                         ret |= (TYPE_QUADRANT_ROTATION | TYPE_GENERAL_SCALE);
972                     } else if (M0 != -1.0) {
973                         ret |= (TYPE_QUADRANT_ROTATION | TYPE_UNIFORM_SCALE);
974                     } else {
975                         ret |= TYPE_QUADRANT_ROTATION;
976                     }
977                 }
978             } else {
979                 // Scaling factor signs different - flip about some axis
980                 if (M0 == -M1) {
981                     if (M0 == 1.0 || M0 == -1.0) {
982                         ret |= TYPE_FLIP;
983                     } else {
984                         ret |= (TYPE_FLIP | TYPE_UNIFORM_SCALE);
985                     }
986                 } else {
987                     ret |= (TYPE_FLIP | TYPE_GENERAL_SCALE);
988                 }
989             }
990             break;
991         case (APPLY_TRANSLATE):
992             ret = TYPE_TRANSLATION;
993             break;
994         case (APPLY_IDENTITY):
995             break;
996         }
997         this.type = ret;
998     }
999 
1000     /**
1001      * Returns the determinant of the matrix representation of the transform.
1002      * The determinant is useful both to determine if the transform can
1003      * be inverted and to get a single value representing the
1004      * combined X and Y scaling of the transform.
1005      * <p>
1006      * If the determinant is non-zero, then this transform is
1007      * invertible and the various methods that depend on the inverse
1008      * transform do not need to throw a
1009      * {@link NoninvertibleTransformException}.
1010      * If the determinant is zero then this transform can not be
1011      * inverted since the transform maps all input coordinates onto
1012      * a line or a point.
1013      * If the determinant is near enough to zero then inverse transform
1014      * operations might not carry enough precision to produce meaningful
1015      * results.
1016      * <p>
1017      * If this transform represents a uniform scale, as indicated by
1018      * the <code>getType</code> method then the determinant also
1019      * represents the square of the uniform scale factor by which all of
1020      * the points are expanded from or contracted towards the origin.
1021      * If this transform represents a non-uniform scale or more general
1022      * transform then the determinant is not likely to represent a
1023      * value useful for any purpose other than determining if inverse
1024      * transforms are possible.
1025      * <p>
1026      * Mathematically, the determinant is calculated using the formula:
1027      * <pre>
1028      *          |  m00  m01  m02  |
1029      *          |  m10  m11  m12  |  =  m00 * m11 - m01 * m10
1030      *          |   0    0    1   |
1031      * </pre>
1032      *
1033      * @return the determinant of the matrix used to transform the
1034      * coordinates.
1035      * @see #getType
1036      * @see #createInverse
1037      * @see #inverseTransform
1038      * @see #TYPE_UNIFORM_SCALE
1039      * @since 1.2
1040      */
1041     @SuppressWarnings("fallthrough")
getDeterminant()1042     public double getDeterminant() {
1043         switch (state) {
1044         default:
1045             stateError();
1046             /* NOTREACHED */
1047         case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1048         case (APPLY_SHEAR | APPLY_SCALE):
1049             return m00 * m11 - m01 * m10;
1050         case (APPLY_SHEAR | APPLY_TRANSLATE):
1051         case (APPLY_SHEAR):
1052             return -(m01 * m10);
1053         case (APPLY_SCALE | APPLY_TRANSLATE):
1054         case (APPLY_SCALE):
1055             return m00 * m11;
1056         case (APPLY_TRANSLATE):
1057         case (APPLY_IDENTITY):
1058             return 1.0;
1059         }
1060     }
1061 
1062     /**
1063      * Manually recalculates the state of the transform when the matrix
1064      * changes too much to predict the effects on the state.
1065      * The following table specifies what the various settings of the
1066      * state field say about the values of the corresponding matrix
1067      * element fields.
1068      * Note that the rules governing the SCALE fields are slightly
1069      * different depending on whether the SHEAR flag is also set.
1070      * <pre>
1071      *                     SCALE            SHEAR          TRANSLATE
1072      *                    m00/m11          m01/m10          m02/m12
1073      *
1074      * IDENTITY             1.0              0.0              0.0
1075      * TRANSLATE (TR)       1.0              0.0          not both 0.0
1076      * SCALE (SC)       not both 1.0         0.0              0.0
1077      * TR | SC          not both 1.0         0.0          not both 0.0
1078      * SHEAR (SH)           0.0          not both 0.0         0.0
1079      * TR | SH              0.0          not both 0.0     not both 0.0
1080      * SC | SH          not both 0.0     not both 0.0         0.0
1081      * TR | SC | SH     not both 0.0     not both 0.0     not both 0.0
1082      * </pre>
1083      */
updateState()1084     void updateState() {
1085         if (m01 == 0.0 && m10 == 0.0) {
1086             if (m00 == 1.0 && m11 == 1.0) {
1087                 if (m02 == 0.0 && m12 == 0.0) {
1088                     state = APPLY_IDENTITY;
1089                     type = TYPE_IDENTITY;
1090                 } else {
1091                     state = APPLY_TRANSLATE;
1092                     type = TYPE_TRANSLATION;
1093                 }
1094             } else {
1095                 if (m02 == 0.0 && m12 == 0.0) {
1096                     state = APPLY_SCALE;
1097                     type = TYPE_UNKNOWN;
1098                 } else {
1099                     state = (APPLY_SCALE | APPLY_TRANSLATE);
1100                     type = TYPE_UNKNOWN;
1101                 }
1102             }
1103         } else {
1104             if (m00 == 0.0 && m11 == 0.0) {
1105                 if (m02 == 0.0 && m12 == 0.0) {
1106                     state = APPLY_SHEAR;
1107                     type = TYPE_UNKNOWN;
1108                 } else {
1109                     state = (APPLY_SHEAR | APPLY_TRANSLATE);
1110                     type = TYPE_UNKNOWN;
1111                 }
1112             } else {
1113                 if (m02 == 0.0 && m12 == 0.0) {
1114                     state = (APPLY_SHEAR | APPLY_SCALE);
1115                     type = TYPE_UNKNOWN;
1116                 } else {
1117                     state = (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE);
1118                     type = TYPE_UNKNOWN;
1119                 }
1120             }
1121         }
1122     }
1123 
1124     /*
1125      * Convenience method used internally to throw exceptions when
1126      * a case was forgotten in a switch statement.
1127      */
stateError()1128     private void stateError() {
1129         throw new InternalError("missing case in transform state switch");
1130     }
1131 
1132     /**
1133      * Retrieves the 6 specifiable values in the 3x3 affine transformation
1134      * matrix and places them into an array of double precisions values.
1135      * The values are stored in the array as
1136      * {&nbsp;m00&nbsp;m10&nbsp;m01&nbsp;m11&nbsp;m02&nbsp;m12&nbsp;}.
1137      * An array of 4 doubles can also be specified, in which case only the
1138      * first four elements representing the non-transform
1139      * parts of the array are retrieved and the values are stored into
1140      * the array as {&nbsp;m00&nbsp;m10&nbsp;m01&nbsp;m11&nbsp;}
1141      * @param flatmatrix the double array used to store the returned
1142      * values.
1143      * @see #getScaleX
1144      * @see #getScaleY
1145      * @see #getShearX
1146      * @see #getShearY
1147      * @see #getTranslateX
1148      * @see #getTranslateY
1149      * @since 1.2
1150      */
getMatrix(double[] flatmatrix)1151     public void getMatrix(double[] flatmatrix) {
1152         flatmatrix[0] = m00;
1153         flatmatrix[1] = m10;
1154         flatmatrix[2] = m01;
1155         flatmatrix[3] = m11;
1156         if (flatmatrix.length > 5) {
1157             flatmatrix[4] = m02;
1158             flatmatrix[5] = m12;
1159         }
1160     }
1161 
1162     /**
1163      * Returns the X coordinate scaling element (m00) of the 3x3
1164      * affine transformation matrix.
1165      * @return a double value that is the X coordinate of the scaling
1166      *  element of the affine transformation matrix.
1167      * @see #getMatrix
1168      * @since 1.2
1169      */
getScaleX()1170     public double getScaleX() {
1171         return m00;
1172     }
1173 
1174     /**
1175      * Returns the Y coordinate scaling element (m11) of the 3x3
1176      * affine transformation matrix.
1177      * @return a double value that is the Y coordinate of the scaling
1178      *  element of the affine transformation matrix.
1179      * @see #getMatrix
1180      * @since 1.2
1181      */
getScaleY()1182     public double getScaleY() {
1183         return m11;
1184     }
1185 
1186     /**
1187      * Returns the X coordinate shearing element (m01) of the 3x3
1188      * affine transformation matrix.
1189      * @return a double value that is the X coordinate of the shearing
1190      *  element of the affine transformation matrix.
1191      * @see #getMatrix
1192      * @since 1.2
1193      */
getShearX()1194     public double getShearX() {
1195         return m01;
1196     }
1197 
1198     /**
1199      * Returns the Y coordinate shearing element (m10) of the 3x3
1200      * affine transformation matrix.
1201      * @return a double value that is the Y coordinate of the shearing
1202      *  element of the affine transformation matrix.
1203      * @see #getMatrix
1204      * @since 1.2
1205      */
getShearY()1206     public double getShearY() {
1207         return m10;
1208     }
1209 
1210     /**
1211      * Returns the X coordinate of the translation element (m02) of the
1212      * 3x3 affine transformation matrix.
1213      * @return a double value that is the X coordinate of the translation
1214      *  element of the affine transformation matrix.
1215      * @see #getMatrix
1216      * @since 1.2
1217      */
getTranslateX()1218     public double getTranslateX() {
1219         return m02;
1220     }
1221 
1222     /**
1223      * Returns the Y coordinate of the translation element (m12) of the
1224      * 3x3 affine transformation matrix.
1225      * @return a double value that is the Y coordinate of the translation
1226      *  element of the affine transformation matrix.
1227      * @see #getMatrix
1228      * @since 1.2
1229      */
getTranslateY()1230     public double getTranslateY() {
1231         return m12;
1232     }
1233 
1234     /**
1235      * Concatenates this transform with a translation transformation.
1236      * This is equivalent to calling concatenate(T), where T is an
1237      * <code>AffineTransform</code> represented by the following matrix:
1238      * <pre>
1239      *          [   1    0    tx  ]
1240      *          [   0    1    ty  ]
1241      *          [   0    0    1   ]
1242      * </pre>
1243      * @param tx the distance by which coordinates are translated in the
1244      * X axis direction
1245      * @param ty the distance by which coordinates are translated in the
1246      * Y axis direction
1247      * @since 1.2
1248      */
translate(double tx, double ty)1249     public void translate(double tx, double ty) {
1250         switch (state) {
1251         default:
1252             stateError();
1253             /* NOTREACHED */
1254             return;
1255         case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1256             m02 = tx * m00 + ty * m01 + m02;
1257             m12 = tx * m10 + ty * m11 + m12;
1258             if (m02 == 0.0 && m12 == 0.0) {
1259                 state = APPLY_SHEAR | APPLY_SCALE;
1260                 if (type != TYPE_UNKNOWN) {
1261                     type -= TYPE_TRANSLATION;
1262                 }
1263             }
1264             return;
1265         case (APPLY_SHEAR | APPLY_SCALE):
1266             m02 = tx * m00 + ty * m01;
1267             m12 = tx * m10 + ty * m11;
1268             if (m02 != 0.0 || m12 != 0.0) {
1269                 state = APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE;
1270                 type |= TYPE_TRANSLATION;
1271             }
1272             return;
1273         case (APPLY_SHEAR | APPLY_TRANSLATE):
1274             m02 = ty * m01 + m02;
1275             m12 = tx * m10 + m12;
1276             if (m02 == 0.0 && m12 == 0.0) {
1277                 state = APPLY_SHEAR;
1278                 if (type != TYPE_UNKNOWN) {
1279                     type -= TYPE_TRANSLATION;
1280                 }
1281             }
1282             return;
1283         case (APPLY_SHEAR):
1284             m02 = ty * m01;
1285             m12 = tx * m10;
1286             if (m02 != 0.0 || m12 != 0.0) {
1287                 state = APPLY_SHEAR | APPLY_TRANSLATE;
1288                 type |= TYPE_TRANSLATION;
1289             }
1290             return;
1291         case (APPLY_SCALE | APPLY_TRANSLATE):
1292             m02 = tx * m00 + m02;
1293             m12 = ty * m11 + m12;
1294             if (m02 == 0.0 && m12 == 0.0) {
1295                 state = APPLY_SCALE;
1296                 if (type != TYPE_UNKNOWN) {
1297                     type -= TYPE_TRANSLATION;
1298                 }
1299             }
1300             return;
1301         case (APPLY_SCALE):
1302             m02 = tx * m00;
1303             m12 = ty * m11;
1304             if (m02 != 0.0 || m12 != 0.0) {
1305                 state = APPLY_SCALE | APPLY_TRANSLATE;
1306                 type |= TYPE_TRANSLATION;
1307             }
1308             return;
1309         case (APPLY_TRANSLATE):
1310             m02 = tx + m02;
1311             m12 = ty + m12;
1312             if (m02 == 0.0 && m12 == 0.0) {
1313                 state = APPLY_IDENTITY;
1314                 type = TYPE_IDENTITY;
1315             }
1316             return;
1317         case (APPLY_IDENTITY):
1318             m02 = tx;
1319             m12 = ty;
1320             if (tx != 0.0 || ty != 0.0) {
1321                 state = APPLY_TRANSLATE;
1322                 type = TYPE_TRANSLATION;
1323             }
1324             return;
1325         }
1326     }
1327 
1328     // Utility methods to optimize rotate methods.
1329     // These tables translate the flags during predictable quadrant
1330     // rotations where the shear and scale values are swapped and negated.
1331     private static final int rot90conversion[] = {
1332         /* IDENTITY => */        APPLY_SHEAR,
1333         /* TRANSLATE (TR) => */  APPLY_SHEAR | APPLY_TRANSLATE,
1334         /* SCALE (SC) => */      APPLY_SHEAR,
1335         /* SC | TR => */         APPLY_SHEAR | APPLY_TRANSLATE,
1336         /* SHEAR (SH) => */      APPLY_SCALE,
1337         /* SH | TR => */         APPLY_SCALE | APPLY_TRANSLATE,
1338         /* SH | SC => */         APPLY_SHEAR | APPLY_SCALE,
1339         /* SH | SC | TR => */    APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE,
1340     };
rotate90()1341     private final void rotate90() {
1342         double M0 = m00;
1343         m00 = m01;
1344         m01 = -M0;
1345         M0 = m10;
1346         m10 = m11;
1347         m11 = -M0;
1348         int state = rot90conversion[this.state];
1349         if ((state & (APPLY_SHEAR | APPLY_SCALE)) == APPLY_SCALE &&
1350             m00 == 1.0 && m11 == 1.0)
1351         {
1352             state -= APPLY_SCALE;
1353         }
1354         this.state = state;
1355         type = TYPE_UNKNOWN;
1356     }
rotate180()1357     private final void rotate180() {
1358         m00 = -m00;
1359         m11 = -m11;
1360         int state = this.state;
1361         if ((state & (APPLY_SHEAR)) != 0) {
1362             // If there was a shear, then this rotation has no
1363             // effect on the state.
1364             m01 = -m01;
1365             m10 = -m10;
1366         } else {
1367             // No shear means the SCALE state may toggle when
1368             // m00 and m11 are negated.
1369             if (m00 == 1.0 && m11 == 1.0) {
1370                 this.state = state & ~APPLY_SCALE;
1371             } else {
1372                 this.state = state | APPLY_SCALE;
1373             }
1374         }
1375         type = TYPE_UNKNOWN;
1376     }
rotate270()1377     private final void rotate270() {
1378         double M0 = m00;
1379         m00 = -m01;
1380         m01 = M0;
1381         M0 = m10;
1382         m10 = -m11;
1383         m11 = M0;
1384         int state = rot90conversion[this.state];
1385         if ((state & (APPLY_SHEAR | APPLY_SCALE)) == APPLY_SCALE &&
1386             m00 == 1.0 && m11 == 1.0)
1387         {
1388             state -= APPLY_SCALE;
1389         }
1390         this.state = state;
1391         type = TYPE_UNKNOWN;
1392     }
1393 
1394     /**
1395      * Concatenates this transform with a rotation transformation.
1396      * This is equivalent to calling concatenate(R), where R is an
1397      * <code>AffineTransform</code> represented by the following matrix:
1398      * <pre>
1399      *          [   cos(theta)    -sin(theta)    0   ]
1400      *          [   sin(theta)     cos(theta)    0   ]
1401      *          [       0              0         1   ]
1402      * </pre>
1403      * Rotating by a positive angle theta rotates points on the positive
1404      * X axis toward the positive Y axis.
1405      * Note also the discussion of
1406      * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
1407      * above.
1408      * @param theta the angle of rotation measured in radians
1409      * @since 1.2
1410      */
rotate(double theta)1411     public void rotate(double theta) {
1412         double sin = Math.sin(theta);
1413         if (sin == 1.0) {
1414             rotate90();
1415         } else if (sin == -1.0) {
1416             rotate270();
1417         } else {
1418             double cos = Math.cos(theta);
1419             if (cos == -1.0) {
1420                 rotate180();
1421             } else if (cos != 1.0) {
1422                 double M0, M1;
1423                 M0 = m00;
1424                 M1 = m01;
1425                 m00 =  cos * M0 + sin * M1;
1426                 m01 = -sin * M0 + cos * M1;
1427                 M0 = m10;
1428                 M1 = m11;
1429                 m10 =  cos * M0 + sin * M1;
1430                 m11 = -sin * M0 + cos * M1;
1431                 updateState();
1432             }
1433         }
1434     }
1435 
1436     /**
1437      * Concatenates this transform with a transform that rotates
1438      * coordinates around an anchor point.
1439      * This operation is equivalent to translating the coordinates so
1440      * that the anchor point is at the origin (S1), then rotating them
1441      * about the new origin (S2), and finally translating so that the
1442      * intermediate origin is restored to the coordinates of the original
1443      * anchor point (S3).
1444      * <p>
1445      * This operation is equivalent to the following sequence of calls:
1446      * <pre>
1447      *     translate(anchorx, anchory);      // S3: final translation
1448      *     rotate(theta);                    // S2: rotate around anchor
1449      *     translate(-anchorx, -anchory);    // S1: translate anchor to origin
1450      * </pre>
1451      * Rotating by a positive angle theta rotates points on the positive
1452      * X axis toward the positive Y axis.
1453      * Note also the discussion of
1454      * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
1455      * above.
1456      *
1457      * @param theta the angle of rotation measured in radians
1458      * @param anchorx the X coordinate of the rotation anchor point
1459      * @param anchory the Y coordinate of the rotation anchor point
1460      * @since 1.2
1461      */
rotate(double theta, double anchorx, double anchory)1462     public void rotate(double theta, double anchorx, double anchory) {
1463         // REMIND: Simple for now - optimize later
1464         translate(anchorx, anchory);
1465         rotate(theta);
1466         translate(-anchorx, -anchory);
1467     }
1468 
1469     /**
1470      * Concatenates this transform with a transform that rotates
1471      * coordinates according to a rotation vector.
1472      * All coordinates rotate about the origin by the same amount.
1473      * The amount of rotation is such that coordinates along the former
1474      * positive X axis will subsequently align with the vector pointing
1475      * from the origin to the specified vector coordinates.
1476      * If both <code>vecx</code> and <code>vecy</code> are 0.0,
1477      * no additional rotation is added to this transform.
1478      * This operation is equivalent to calling:
1479      * <pre>
1480      *          rotate(Math.atan2(vecy, vecx));
1481      * </pre>
1482      *
1483      * @param vecx the X coordinate of the rotation vector
1484      * @param vecy the Y coordinate of the rotation vector
1485      * @since 1.6
1486      */
rotate(double vecx, double vecy)1487     public void rotate(double vecx, double vecy) {
1488         if (vecy == 0.0) {
1489             if (vecx < 0.0) {
1490                 rotate180();
1491             }
1492             // If vecx > 0.0 - no rotation
1493             // If vecx == 0.0 - undefined rotation - treat as no rotation
1494         } else if (vecx == 0.0) {
1495             if (vecy > 0.0) {
1496                 rotate90();
1497             } else {  // vecy must be < 0.0
1498                 rotate270();
1499             }
1500         } else {
1501             double len = Math.sqrt(vecx * vecx + vecy * vecy);
1502             double sin = vecy / len;
1503             double cos = vecx / len;
1504             double M0, M1;
1505             M0 = m00;
1506             M1 = m01;
1507             m00 =  cos * M0 + sin * M1;
1508             m01 = -sin * M0 + cos * M1;
1509             M0 = m10;
1510             M1 = m11;
1511             m10 =  cos * M0 + sin * M1;
1512             m11 = -sin * M0 + cos * M1;
1513             updateState();
1514         }
1515     }
1516 
1517     /**
1518      * Concatenates this transform with a transform that rotates
1519      * coordinates around an anchor point according to a rotation
1520      * vector.
1521      * All coordinates rotate about the specified anchor coordinates
1522      * by the same amount.
1523      * The amount of rotation is such that coordinates along the former
1524      * positive X axis will subsequently align with the vector pointing
1525      * from the origin to the specified vector coordinates.
1526      * If both <code>vecx</code> and <code>vecy</code> are 0.0,
1527      * the transform is not modified in any way.
1528      * This method is equivalent to calling:
1529      * <pre>
1530      *     rotate(Math.atan2(vecy, vecx), anchorx, anchory);
1531      * </pre>
1532      *
1533      * @param vecx the X coordinate of the rotation vector
1534      * @param vecy the Y coordinate of the rotation vector
1535      * @param anchorx the X coordinate of the rotation anchor point
1536      * @param anchory the Y coordinate of the rotation anchor point
1537      * @since 1.6
1538      */
rotate(double vecx, double vecy, double anchorx, double anchory)1539     public void rotate(double vecx, double vecy,
1540                        double anchorx, double anchory)
1541     {
1542         // REMIND: Simple for now - optimize later
1543         translate(anchorx, anchory);
1544         rotate(vecx, vecy);
1545         translate(-anchorx, -anchory);
1546     }
1547 
1548     /**
1549      * Concatenates this transform with a transform that rotates
1550      * coordinates by the specified number of quadrants.
1551      * This is equivalent to calling:
1552      * <pre>
1553      *     rotate(numquadrants * Math.PI / 2.0);
1554      * </pre>
1555      * Rotating by a positive number of quadrants rotates points on
1556      * the positive X axis toward the positive Y axis.
1557      * @param numquadrants the number of 90 degree arcs to rotate by
1558      * @since 1.6
1559      */
quadrantRotate(int numquadrants)1560     public void quadrantRotate(int numquadrants) {
1561         switch (numquadrants & 3) {
1562         case 0:
1563             break;
1564         case 1:
1565             rotate90();
1566             break;
1567         case 2:
1568             rotate180();
1569             break;
1570         case 3:
1571             rotate270();
1572             break;
1573         }
1574     }
1575 
1576     /**
1577      * Concatenates this transform with a transform that rotates
1578      * coordinates by the specified number of quadrants around
1579      * the specified anchor point.
1580      * This method is equivalent to calling:
1581      * <pre>
1582      *     rotate(numquadrants * Math.PI / 2.0, anchorx, anchory);
1583      * </pre>
1584      * Rotating by a positive number of quadrants rotates points on
1585      * the positive X axis toward the positive Y axis.
1586      *
1587      * @param numquadrants the number of 90 degree arcs to rotate by
1588      * @param anchorx the X coordinate of the rotation anchor point
1589      * @param anchory the Y coordinate of the rotation anchor point
1590      * @since 1.6
1591      */
quadrantRotate(int numquadrants, double anchorx, double anchory)1592     public void quadrantRotate(int numquadrants,
1593                                double anchorx, double anchory)
1594     {
1595         switch (numquadrants & 3) {
1596         case 0:
1597             return;
1598         case 1:
1599             m02 += anchorx * (m00 - m01) + anchory * (m01 + m00);
1600             m12 += anchorx * (m10 - m11) + anchory * (m11 + m10);
1601             rotate90();
1602             break;
1603         case 2:
1604             m02 += anchorx * (m00 + m00) + anchory * (m01 + m01);
1605             m12 += anchorx * (m10 + m10) + anchory * (m11 + m11);
1606             rotate180();
1607             break;
1608         case 3:
1609             m02 += anchorx * (m00 + m01) + anchory * (m01 - m00);
1610             m12 += anchorx * (m10 + m11) + anchory * (m11 - m10);
1611             rotate270();
1612             break;
1613         }
1614         if (m02 == 0.0 && m12 == 0.0) {
1615             state &= ~APPLY_TRANSLATE;
1616         } else {
1617             state |= APPLY_TRANSLATE;
1618         }
1619     }
1620 
1621     /**
1622      * Concatenates this transform with a scaling transformation.
1623      * This is equivalent to calling concatenate(S), where S is an
1624      * <code>AffineTransform</code> represented by the following matrix:
1625      * <pre>
1626      *          [   sx   0    0   ]
1627      *          [   0    sy   0   ]
1628      *          [   0    0    1   ]
1629      * </pre>
1630      * @param sx the factor by which coordinates are scaled along the
1631      * X axis direction
1632      * @param sy the factor by which coordinates are scaled along the
1633      * Y axis direction
1634      * @since 1.2
1635      */
1636     @SuppressWarnings("fallthrough")
scale(double sx, double sy)1637     public void scale(double sx, double sy) {
1638         int state = this.state;
1639         switch (state) {
1640         default:
1641             stateError();
1642             /* NOTREACHED */
1643         case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1644         case (APPLY_SHEAR | APPLY_SCALE):
1645             m00 *= sx;
1646             m11 *= sy;
1647             /* NOBREAK */
1648         case (APPLY_SHEAR | APPLY_TRANSLATE):
1649         case (APPLY_SHEAR):
1650             m01 *= sy;
1651             m10 *= sx;
1652             if (m01 == 0 && m10 == 0) {
1653                 state &= APPLY_TRANSLATE;
1654                 if (m00 == 1.0 && m11 == 1.0) {
1655                     this.type = (state == APPLY_IDENTITY
1656                                  ? TYPE_IDENTITY
1657                                  : TYPE_TRANSLATION);
1658                 } else {
1659                     state |= APPLY_SCALE;
1660                     this.type = TYPE_UNKNOWN;
1661                 }
1662                 this.state = state;
1663             }
1664             return;
1665         case (APPLY_SCALE | APPLY_TRANSLATE):
1666         case (APPLY_SCALE):
1667             m00 *= sx;
1668             m11 *= sy;
1669             if (m00 == 1.0 && m11 == 1.0) {
1670                 this.state = (state &= APPLY_TRANSLATE);
1671                 this.type = (state == APPLY_IDENTITY
1672                              ? TYPE_IDENTITY
1673                              : TYPE_TRANSLATION);
1674             } else {
1675                 this.type = TYPE_UNKNOWN;
1676             }
1677             return;
1678         case (APPLY_TRANSLATE):
1679         case (APPLY_IDENTITY):
1680             m00 = sx;
1681             m11 = sy;
1682             if (sx != 1.0 || sy != 1.0) {
1683                 this.state = state | APPLY_SCALE;
1684                 this.type = TYPE_UNKNOWN;
1685             }
1686             return;
1687         }
1688     }
1689 
1690     /**
1691      * Concatenates this transform with a shearing transformation.
1692      * This is equivalent to calling concatenate(SH), where SH is an
1693      * <code>AffineTransform</code> represented by the following matrix:
1694      * <pre>
1695      *          [   1   shx   0   ]
1696      *          [  shy   1    0   ]
1697      *          [   0    0    1   ]
1698      * </pre>
1699      * @param shx the multiplier by which coordinates are shifted in the
1700      * direction of the positive X axis as a factor of their Y coordinate
1701      * @param shy the multiplier by which coordinates are shifted in the
1702      * direction of the positive Y axis as a factor of their X coordinate
1703      * @since 1.2
1704      */
shear(double shx, double shy)1705     public void shear(double shx, double shy) {
1706         int state = this.state;
1707         switch (state) {
1708         default:
1709             stateError();
1710             /* NOTREACHED */
1711             return;
1712         case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1713         case (APPLY_SHEAR | APPLY_SCALE):
1714             double M0, M1;
1715             M0 = m00;
1716             M1 = m01;
1717             m00 = M0 + M1 * shy;
1718             m01 = M0 * shx + M1;
1719 
1720             M0 = m10;
1721             M1 = m11;
1722             m10 = M0 + M1 * shy;
1723             m11 = M0 * shx + M1;
1724             updateState();
1725             return;
1726         case (APPLY_SHEAR | APPLY_TRANSLATE):
1727         case (APPLY_SHEAR):
1728             m00 = m01 * shy;
1729             m11 = m10 * shx;
1730             if (m00 != 0.0 || m11 != 0.0) {
1731                 this.state = state | APPLY_SCALE;
1732             }
1733             this.type = TYPE_UNKNOWN;
1734             return;
1735         case (APPLY_SCALE | APPLY_TRANSLATE):
1736         case (APPLY_SCALE):
1737             m01 = m00 * shx;
1738             m10 = m11 * shy;
1739             if (m01 != 0.0 || m10 != 0.0) {
1740                 this.state = state | APPLY_SHEAR;
1741             }
1742             this.type = TYPE_UNKNOWN;
1743             return;
1744         case (APPLY_TRANSLATE):
1745         case (APPLY_IDENTITY):
1746             m01 = shx;
1747             m10 = shy;
1748             if (m01 != 0.0 || m10 != 0.0) {
1749                 this.state = state | APPLY_SCALE | APPLY_SHEAR;
1750                 this.type = TYPE_UNKNOWN;
1751             }
1752             return;
1753         }
1754     }
1755 
1756     /**
1757      * Resets this transform to the Identity transform.
1758      * @since 1.2
1759      */
setToIdentity()1760     public void setToIdentity() {
1761         m00 = m11 = 1.0;
1762         m10 = m01 = m02 = m12 = 0.0;
1763         state = APPLY_IDENTITY;
1764         type = TYPE_IDENTITY;
1765     }
1766 
1767     /**
1768      * Sets this transform to a translation transformation.
1769      * The matrix representing this transform becomes:
1770      * <pre>
1771      *          [   1    0    tx  ]
1772      *          [   0    1    ty  ]
1773      *          [   0    0    1   ]
1774      * </pre>
1775      * @param tx the distance by which coordinates are translated in the
1776      * X axis direction
1777      * @param ty the distance by which coordinates are translated in the
1778      * Y axis direction
1779      * @since 1.2
1780      */
setToTranslation(double tx, double ty)1781     public void setToTranslation(double tx, double ty) {
1782         m00 = 1.0;
1783         m10 = 0.0;
1784         m01 = 0.0;
1785         m11 = 1.0;
1786         m02 = tx;
1787         m12 = ty;
1788         if (tx != 0.0 || ty != 0.0) {
1789             state = APPLY_TRANSLATE;
1790             type = TYPE_TRANSLATION;
1791         } else {
1792             state = APPLY_IDENTITY;
1793             type = TYPE_IDENTITY;
1794         }
1795     }
1796 
1797     /**
1798      * Sets this transform to a rotation transformation.
1799      * The matrix representing this transform becomes:
1800      * <pre>
1801      *          [   cos(theta)    -sin(theta)    0   ]
1802      *          [   sin(theta)     cos(theta)    0   ]
1803      *          [       0              0         1   ]
1804      * </pre>
1805      * Rotating by a positive angle theta rotates points on the positive
1806      * X axis toward the positive Y axis.
1807      * Note also the discussion of
1808      * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
1809      * above.
1810      * @param theta the angle of rotation measured in radians
1811      * @since 1.2
1812      */
setToRotation(double theta)1813     public void setToRotation(double theta) {
1814         double sin = Math.sin(theta);
1815         double cos;
1816         if (sin == 1.0 || sin == -1.0) {
1817             cos = 0.0;
1818             state = APPLY_SHEAR;
1819             type = TYPE_QUADRANT_ROTATION;
1820         } else {
1821             cos = Math.cos(theta);
1822             if (cos == -1.0) {
1823                 sin = 0.0;
1824                 state = APPLY_SCALE;
1825                 type = TYPE_QUADRANT_ROTATION;
1826             } else if (cos == 1.0) {
1827                 sin = 0.0;
1828                 state = APPLY_IDENTITY;
1829                 type = TYPE_IDENTITY;
1830             } else {
1831                 state = APPLY_SHEAR | APPLY_SCALE;
1832                 type = TYPE_GENERAL_ROTATION;
1833             }
1834         }
1835         m00 =  cos;
1836         m10 =  sin;
1837         m01 = -sin;
1838         m11 =  cos;
1839         m02 =  0.0;
1840         m12 =  0.0;
1841     }
1842 
1843     /**
1844      * Sets this transform to a translated rotation transformation.
1845      * This operation is equivalent to translating the coordinates so
1846      * that the anchor point is at the origin (S1), then rotating them
1847      * about the new origin (S2), and finally translating so that the
1848      * intermediate origin is restored to the coordinates of the original
1849      * anchor point (S3).
1850      * <p>
1851      * This operation is equivalent to the following sequence of calls:
1852      * <pre>
1853      *     setToTranslation(anchorx, anchory); // S3: final translation
1854      *     rotate(theta);                      // S2: rotate around anchor
1855      *     translate(-anchorx, -anchory);      // S1: translate anchor to origin
1856      * </pre>
1857      * The matrix representing this transform becomes:
1858      * <pre>
1859      *          [   cos(theta)    -sin(theta)    x-x*cos+y*sin  ]
1860      *          [   sin(theta)     cos(theta)    y-x*sin-y*cos  ]
1861      *          [       0              0               1        ]
1862      * </pre>
1863      * Rotating by a positive angle theta rotates points on the positive
1864      * X axis toward the positive Y axis.
1865      * Note also the discussion of
1866      * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
1867      * above.
1868      *
1869      * @param theta the angle of rotation measured in radians
1870      * @param anchorx the X coordinate of the rotation anchor point
1871      * @param anchory the Y coordinate of the rotation anchor point
1872      * @since 1.2
1873      */
setToRotation(double theta, double anchorx, double anchory)1874     public void setToRotation(double theta, double anchorx, double anchory) {
1875         setToRotation(theta);
1876         double sin = m10;
1877         double oneMinusCos = 1.0 - m00;
1878         m02 = anchorx * oneMinusCos + anchory * sin;
1879         m12 = anchory * oneMinusCos - anchorx * sin;
1880         if (m02 != 0.0 || m12 != 0.0) {
1881             state |= APPLY_TRANSLATE;
1882             type |= TYPE_TRANSLATION;
1883         }
1884     }
1885 
1886     /**
1887      * Sets this transform to a rotation transformation that rotates
1888      * coordinates according to a rotation vector.
1889      * All coordinates rotate about the origin by the same amount.
1890      * The amount of rotation is such that coordinates along the former
1891      * positive X axis will subsequently align with the vector pointing
1892      * from the origin to the specified vector coordinates.
1893      * If both <code>vecx</code> and <code>vecy</code> are 0.0,
1894      * the transform is set to an identity transform.
1895      * This operation is equivalent to calling:
1896      * <pre>
1897      *     setToRotation(Math.atan2(vecy, vecx));
1898      * </pre>
1899      *
1900      * @param vecx the X coordinate of the rotation vector
1901      * @param vecy the Y coordinate of the rotation vector
1902      * @since 1.6
1903      */
setToRotation(double vecx, double vecy)1904     public void setToRotation(double vecx, double vecy) {
1905         double sin, cos;
1906         if (vecy == 0) {
1907             sin = 0.0;
1908             if (vecx < 0.0) {
1909                 cos = -1.0;
1910                 state = APPLY_SCALE;
1911                 type = TYPE_QUADRANT_ROTATION;
1912             } else {
1913                 cos = 1.0;
1914                 state = APPLY_IDENTITY;
1915                 type = TYPE_IDENTITY;
1916             }
1917         } else if (vecx == 0) {
1918             cos = 0.0;
1919             sin = (vecy > 0.0) ? 1.0 : -1.0;
1920             state = APPLY_SHEAR;
1921             type = TYPE_QUADRANT_ROTATION;
1922         } else {
1923             double len = Math.sqrt(vecx * vecx + vecy * vecy);
1924             cos = vecx / len;
1925             sin = vecy / len;
1926             state = APPLY_SHEAR | APPLY_SCALE;
1927             type = TYPE_GENERAL_ROTATION;
1928         }
1929         m00 =  cos;
1930         m10 =  sin;
1931         m01 = -sin;
1932         m11 =  cos;
1933         m02 =  0.0;
1934         m12 =  0.0;
1935     }
1936 
1937     /**
1938      * Sets this transform to a rotation transformation that rotates
1939      * coordinates around an anchor point according to a rotation
1940      * vector.
1941      * All coordinates rotate about the specified anchor coordinates
1942      * by the same amount.
1943      * The amount of rotation is such that coordinates along the former
1944      * positive X axis will subsequently align with the vector pointing
1945      * from the origin to the specified vector coordinates.
1946      * If both <code>vecx</code> and <code>vecy</code> are 0.0,
1947      * the transform is set to an identity transform.
1948      * This operation is equivalent to calling:
1949      * <pre>
1950      *     setToTranslation(Math.atan2(vecy, vecx), anchorx, anchory);
1951      * </pre>
1952      *
1953      * @param vecx the X coordinate of the rotation vector
1954      * @param vecy the Y coordinate of the rotation vector
1955      * @param anchorx the X coordinate of the rotation anchor point
1956      * @param anchory the Y coordinate of the rotation anchor point
1957      * @since 1.6
1958      */
setToRotation(double vecx, double vecy, double anchorx, double anchory)1959     public void setToRotation(double vecx, double vecy,
1960                               double anchorx, double anchory)
1961     {
1962         setToRotation(vecx, vecy);
1963         double sin = m10;
1964         double oneMinusCos = 1.0 - m00;
1965         m02 = anchorx * oneMinusCos + anchory * sin;
1966         m12 = anchory * oneMinusCos - anchorx * sin;
1967         if (m02 != 0.0 || m12 != 0.0) {
1968             state |= APPLY_TRANSLATE;
1969             type |= TYPE_TRANSLATION;
1970         }
1971     }
1972 
1973     /**
1974      * Sets this transform to a rotation transformation that rotates
1975      * coordinates by the specified number of quadrants.
1976      * This operation is equivalent to calling:
1977      * <pre>
1978      *     setToRotation(numquadrants * Math.PI / 2.0);
1979      * </pre>
1980      * Rotating by a positive number of quadrants rotates points on
1981      * the positive X axis toward the positive Y axis.
1982      * @param numquadrants the number of 90 degree arcs to rotate by
1983      * @since 1.6
1984      */
setToQuadrantRotation(int numquadrants)1985     public void setToQuadrantRotation(int numquadrants) {
1986         switch (numquadrants & 3) {
1987         case 0:
1988             m00 =  1.0;
1989             m10 =  0.0;
1990             m01 =  0.0;
1991             m11 =  1.0;
1992             m02 =  0.0;
1993             m12 =  0.0;
1994             state = APPLY_IDENTITY;
1995             type = TYPE_IDENTITY;
1996             break;
1997         case 1:
1998             m00 =  0.0;
1999             m10 =  1.0;
2000             m01 = -1.0;
2001             m11 =  0.0;
2002             m02 =  0.0;
2003             m12 =  0.0;
2004             state = APPLY_SHEAR;
2005             type = TYPE_QUADRANT_ROTATION;
2006             break;
2007         case 2:
2008             m00 = -1.0;
2009             m10 =  0.0;
2010             m01 =  0.0;
2011             m11 = -1.0;
2012             m02 =  0.0;
2013             m12 =  0.0;
2014             state = APPLY_SCALE;
2015             type = TYPE_QUADRANT_ROTATION;
2016             break;
2017         case 3:
2018             m00 =  0.0;
2019             m10 = -1.0;
2020             m01 =  1.0;
2021             m11 =  0.0;
2022             m02 =  0.0;
2023             m12 =  0.0;
2024             state = APPLY_SHEAR;
2025             type = TYPE_QUADRANT_ROTATION;
2026             break;
2027         }
2028     }
2029 
2030     /**
2031      * Sets this transform to a translated rotation transformation
2032      * that rotates coordinates by the specified number of quadrants
2033      * around the specified anchor point.
2034      * This operation is equivalent to calling:
2035      * <pre>
2036      *     setToRotation(numquadrants * Math.PI / 2.0, anchorx, anchory);
2037      * </pre>
2038      * Rotating by a positive number of quadrants rotates points on
2039      * the positive X axis toward the positive Y axis.
2040      *
2041      * @param numquadrants the number of 90 degree arcs to rotate by
2042      * @param anchorx the X coordinate of the rotation anchor point
2043      * @param anchory the Y coordinate of the rotation anchor point
2044      * @since 1.6
2045      */
setToQuadrantRotation(int numquadrants, double anchorx, double anchory)2046     public void setToQuadrantRotation(int numquadrants,
2047                                       double anchorx, double anchory)
2048     {
2049         switch (numquadrants & 3) {
2050         case 0:
2051             m00 =  1.0;
2052             m10 =  0.0;
2053             m01 =  0.0;
2054             m11 =  1.0;
2055             m02 =  0.0;
2056             m12 =  0.0;
2057             state = APPLY_IDENTITY;
2058             type = TYPE_IDENTITY;
2059             break;
2060         case 1:
2061             m00 =  0.0;
2062             m10 =  1.0;
2063             m01 = -1.0;
2064             m11 =  0.0;
2065             m02 =  anchorx + anchory;
2066             m12 =  anchory - anchorx;
2067             if (m02 == 0.0 && m12 == 0.0) {
2068                 state = APPLY_SHEAR;
2069                 type = TYPE_QUADRANT_ROTATION;
2070             } else {
2071                 state = APPLY_SHEAR | APPLY_TRANSLATE;
2072                 type = TYPE_QUADRANT_ROTATION | TYPE_TRANSLATION;
2073             }
2074             break;
2075         case 2:
2076             m00 = -1.0;
2077             m10 =  0.0;
2078             m01 =  0.0;
2079             m11 = -1.0;
2080             m02 =  anchorx + anchorx;
2081             m12 =  anchory + anchory;
2082             if (m02 == 0.0 && m12 == 0.0) {
2083                 state = APPLY_SCALE;
2084                 type = TYPE_QUADRANT_ROTATION;
2085             } else {
2086                 state = APPLY_SCALE | APPLY_TRANSLATE;
2087                 type = TYPE_QUADRANT_ROTATION | TYPE_TRANSLATION;
2088             }
2089             break;
2090         case 3:
2091             m00 =  0.0;
2092             m10 = -1.0;
2093             m01 =  1.0;
2094             m11 =  0.0;
2095             m02 =  anchorx - anchory;
2096             m12 =  anchory + anchorx;
2097             if (m02 == 0.0 && m12 == 0.0) {
2098                 state = APPLY_SHEAR;
2099                 type = TYPE_QUADRANT_ROTATION;
2100             } else {
2101                 state = APPLY_SHEAR | APPLY_TRANSLATE;
2102                 type = TYPE_QUADRANT_ROTATION | TYPE_TRANSLATION;
2103             }
2104             break;
2105         }
2106     }
2107 
2108     /**
2109      * Sets this transform to a scaling transformation.
2110      * The matrix representing this transform becomes:
2111      * <pre>
2112      *          [   sx   0    0   ]
2113      *          [   0    sy   0   ]
2114      *          [   0    0    1   ]
2115      * </pre>
2116      * @param sx the factor by which coordinates are scaled along the
2117      * X axis direction
2118      * @param sy the factor by which coordinates are scaled along the
2119      * Y axis direction
2120      * @since 1.2
2121      */
setToScale(double sx, double sy)2122     public void setToScale(double sx, double sy) {
2123         m00 = sx;
2124         m10 = 0.0;
2125         m01 = 0.0;
2126         m11 = sy;
2127         m02 = 0.0;
2128         m12 = 0.0;
2129         if (sx != 1.0 || sy != 1.0) {
2130             state = APPLY_SCALE;
2131             type = TYPE_UNKNOWN;
2132         } else {
2133             state = APPLY_IDENTITY;
2134             type = TYPE_IDENTITY;
2135         }
2136     }
2137 
2138     /**
2139      * Sets this transform to a shearing transformation.
2140      * The matrix representing this transform becomes:
2141      * <pre>
2142      *          [   1   shx   0   ]
2143      *          [  shy   1    0   ]
2144      *          [   0    0    1   ]
2145      * </pre>
2146      * @param shx the multiplier by which coordinates are shifted in the
2147      * direction of the positive X axis as a factor of their Y coordinate
2148      * @param shy the multiplier by which coordinates are shifted in the
2149      * direction of the positive Y axis as a factor of their X coordinate
2150      * @since 1.2
2151      */
setToShear(double shx, double shy)2152     public void setToShear(double shx, double shy) {
2153         m00 = 1.0;
2154         m01 = shx;
2155         m10 = shy;
2156         m11 = 1.0;
2157         m02 = 0.0;
2158         m12 = 0.0;
2159         if (shx != 0.0 || shy != 0.0) {
2160             state = (APPLY_SHEAR | APPLY_SCALE);
2161             type = TYPE_UNKNOWN;
2162         } else {
2163             state = APPLY_IDENTITY;
2164             type = TYPE_IDENTITY;
2165         }
2166     }
2167 
2168     /**
2169      * Sets this transform to a copy of the transform in the specified
2170      * <code>AffineTransform</code> object.
2171      * @param Tx the <code>AffineTransform</code> object from which to
2172      * copy the transform
2173      * @since 1.2
2174      */
setTransform(AffineTransform Tx)2175     public void setTransform(AffineTransform Tx) {
2176         this.m00 = Tx.m00;
2177         this.m10 = Tx.m10;
2178         this.m01 = Tx.m01;
2179         this.m11 = Tx.m11;
2180         this.m02 = Tx.m02;
2181         this.m12 = Tx.m12;
2182         this.state = Tx.state;
2183         this.type = Tx.type;
2184     }
2185 
2186     /**
2187      * Sets this transform to the matrix specified by the 6
2188      * double precision values.
2189      *
2190      * @param m00 the X coordinate scaling element of the 3x3 matrix
2191      * @param m10 the Y coordinate shearing element of the 3x3 matrix
2192      * @param m01 the X coordinate shearing element of the 3x3 matrix
2193      * @param m11 the Y coordinate scaling element of the 3x3 matrix
2194      * @param m02 the X coordinate translation element of the 3x3 matrix
2195      * @param m12 the Y coordinate translation element of the 3x3 matrix
2196      * @since 1.2
2197      */
setTransform(double m00, double m10, double m01, double m11, double m02, double m12)2198     public void setTransform(double m00, double m10,
2199                              double m01, double m11,
2200                              double m02, double m12) {
2201         this.m00 = m00;
2202         this.m10 = m10;
2203         this.m01 = m01;
2204         this.m11 = m11;
2205         this.m02 = m02;
2206         this.m12 = m12;
2207         updateState();
2208     }
2209 
2210     /**
2211      * Concatenates an <code>AffineTransform</code> <code>Tx</code> to
2212      * this <code>AffineTransform</code> Cx in the most commonly useful
2213      * way to provide a new user space
2214      * that is mapped to the former user space by <code>Tx</code>.
2215      * Cx is updated to perform the combined transformation.
2216      * Transforming a point p by the updated transform Cx' is
2217      * equivalent to first transforming p by <code>Tx</code> and then
2218      * transforming the result by the original transform Cx like this:
2219      * Cx'(p) = Cx(Tx(p))
2220      * In matrix notation, if this transform Cx is
2221      * represented by the matrix [this] and <code>Tx</code> is represented
2222      * by the matrix [Tx] then this method does the following:
2223      * <pre>
2224      *          [this] = [this] x [Tx]
2225      * </pre>
2226      * @param Tx the <code>AffineTransform</code> object to be
2227      * concatenated with this <code>AffineTransform</code> object.
2228      * @see #preConcatenate
2229      * @since 1.2
2230      */
2231     @SuppressWarnings("fallthrough")
concatenate(AffineTransform Tx)2232     public void concatenate(AffineTransform Tx) {
2233         double M0, M1;
2234         double T00, T01, T10, T11;
2235         double T02, T12;
2236         int mystate = state;
2237         int txstate = Tx.state;
2238         switch ((txstate << HI_SHIFT) | mystate) {
2239 
2240             /* ---------- Tx == IDENTITY cases ---------- */
2241         case (HI_IDENTITY | APPLY_IDENTITY):
2242         case (HI_IDENTITY | APPLY_TRANSLATE):
2243         case (HI_IDENTITY | APPLY_SCALE):
2244         case (HI_IDENTITY | APPLY_SCALE | APPLY_TRANSLATE):
2245         case (HI_IDENTITY | APPLY_SHEAR):
2246         case (HI_IDENTITY | APPLY_SHEAR | APPLY_TRANSLATE):
2247         case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE):
2248         case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2249             return;
2250 
2251             /* ---------- this == IDENTITY cases ---------- */
2252         case (HI_SHEAR | HI_SCALE | HI_TRANSLATE | APPLY_IDENTITY):
2253             m01 = Tx.m01;
2254             m10 = Tx.m10;
2255             /* NOBREAK */
2256         case (HI_SCALE | HI_TRANSLATE | APPLY_IDENTITY):
2257             m00 = Tx.m00;
2258             m11 = Tx.m11;
2259             /* NOBREAK */
2260         case (HI_TRANSLATE | APPLY_IDENTITY):
2261             m02 = Tx.m02;
2262             m12 = Tx.m12;
2263             state = txstate;
2264             type = Tx.type;
2265             return;
2266         case (HI_SHEAR | HI_SCALE | APPLY_IDENTITY):
2267             m01 = Tx.m01;
2268             m10 = Tx.m10;
2269             /* NOBREAK */
2270         case (HI_SCALE | APPLY_IDENTITY):
2271             m00 = Tx.m00;
2272             m11 = Tx.m11;
2273             state = txstate;
2274             type = Tx.type;
2275             return;
2276         case (HI_SHEAR | HI_TRANSLATE | APPLY_IDENTITY):
2277             m02 = Tx.m02;
2278             m12 = Tx.m12;
2279             /* NOBREAK */
2280         case (HI_SHEAR | APPLY_IDENTITY):
2281             m01 = Tx.m01;
2282             m10 = Tx.m10;
2283             m00 = m11 = 0.0;
2284             state = txstate;
2285             type = Tx.type;
2286             return;
2287 
2288             /* ---------- Tx == TRANSLATE cases ---------- */
2289         case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2290         case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE):
2291         case (HI_TRANSLATE | APPLY_SHEAR | APPLY_TRANSLATE):
2292         case (HI_TRANSLATE | APPLY_SHEAR):
2293         case (HI_TRANSLATE | APPLY_SCALE | APPLY_TRANSLATE):
2294         case (HI_TRANSLATE | APPLY_SCALE):
2295         case (HI_TRANSLATE | APPLY_TRANSLATE):
2296             translate(Tx.m02, Tx.m12);
2297             return;
2298 
2299             /* ---------- Tx == SCALE cases ---------- */
2300         case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2301         case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE):
2302         case (HI_SCALE | APPLY_SHEAR | APPLY_TRANSLATE):
2303         case (HI_SCALE | APPLY_SHEAR):
2304         case (HI_SCALE | APPLY_SCALE | APPLY_TRANSLATE):
2305         case (HI_SCALE | APPLY_SCALE):
2306         case (HI_SCALE | APPLY_TRANSLATE):
2307             scale(Tx.m00, Tx.m11);
2308             return;
2309 
2310             /* ---------- Tx == SHEAR cases ---------- */
2311         case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2312         case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE):
2313             T01 = Tx.m01; T10 = Tx.m10;
2314             M0 = m00;
2315             m00 = m01 * T10;
2316             m01 = M0 * T01;
2317             M0 = m10;
2318             m10 = m11 * T10;
2319             m11 = M0 * T01;
2320             type = TYPE_UNKNOWN;
2321             return;
2322         case (HI_SHEAR | APPLY_SHEAR | APPLY_TRANSLATE):
2323         case (HI_SHEAR | APPLY_SHEAR):
2324             m00 = m01 * Tx.m10;
2325             m01 = 0.0;
2326             m11 = m10 * Tx.m01;
2327             m10 = 0.0;
2328             state = mystate ^ (APPLY_SHEAR | APPLY_SCALE);
2329             type = TYPE_UNKNOWN;
2330             return;
2331         case (HI_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2332         case (HI_SHEAR | APPLY_SCALE):
2333             m01 = m00 * Tx.m01;
2334             m00 = 0.0;
2335             m10 = m11 * Tx.m10;
2336             m11 = 0.0;
2337             state = mystate ^ (APPLY_SHEAR | APPLY_SCALE);
2338             type = TYPE_UNKNOWN;
2339             return;
2340         case (HI_SHEAR | APPLY_TRANSLATE):
2341             m00 = 0.0;
2342             m01 = Tx.m01;
2343             m10 = Tx.m10;
2344             m11 = 0.0;
2345             state = APPLY_TRANSLATE | APPLY_SHEAR;
2346             type = TYPE_UNKNOWN;
2347             return;
2348         }
2349         // If Tx has more than one attribute, it is not worth optimizing
2350         // all of those cases...
2351         T00 = Tx.m00; T01 = Tx.m01; T02 = Tx.m02;
2352         T10 = Tx.m10; T11 = Tx.m11; T12 = Tx.m12;
2353         switch (mystate) {
2354         default:
2355             stateError();
2356             /* NOTREACHED */
2357         case (APPLY_SHEAR | APPLY_SCALE):
2358             state = mystate | txstate;
2359             /* NOBREAK */
2360         case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2361             M0 = m00;
2362             M1 = m01;
2363             m00  = T00 * M0 + T10 * M1;
2364             m01  = T01 * M0 + T11 * M1;
2365             m02 += T02 * M0 + T12 * M1;
2366 
2367             M0 = m10;
2368             M1 = m11;
2369             m10  = T00 * M0 + T10 * M1;
2370             m11  = T01 * M0 + T11 * M1;
2371             m12 += T02 * M0 + T12 * M1;
2372             type = TYPE_UNKNOWN;
2373             return;
2374 
2375         case (APPLY_SHEAR | APPLY_TRANSLATE):
2376         case (APPLY_SHEAR):
2377             M0 = m01;
2378             m00  = T10 * M0;
2379             m01  = T11 * M0;
2380             m02 += T12 * M0;
2381 
2382             M0 = m10;
2383             m10  = T00 * M0;
2384             m11  = T01 * M0;
2385             m12 += T02 * M0;
2386             break;
2387 
2388         case (APPLY_SCALE | APPLY_TRANSLATE):
2389         case (APPLY_SCALE):
2390             M0 = m00;
2391             m00  = T00 * M0;
2392             m01  = T01 * M0;
2393             m02 += T02 * M0;
2394 
2395             M0 = m11;
2396             m10  = T10 * M0;
2397             m11  = T11 * M0;
2398             m12 += T12 * M0;
2399             break;
2400 
2401         case (APPLY_TRANSLATE):
2402             m00  = T00;
2403             m01  = T01;
2404             m02 += T02;
2405 
2406             m10  = T10;
2407             m11  = T11;
2408             m12 += T12;
2409             state = txstate | APPLY_TRANSLATE;
2410             type = TYPE_UNKNOWN;
2411             return;
2412         }
2413         updateState();
2414     }
2415 
2416     /**
2417      * Concatenates an <code>AffineTransform</code> <code>Tx</code> to
2418      * this <code>AffineTransform</code> Cx
2419      * in a less commonly used way such that <code>Tx</code> modifies the
2420      * coordinate transformation relative to the absolute pixel
2421      * space rather than relative to the existing user space.
2422      * Cx is updated to perform the combined transformation.
2423      * Transforming a point p by the updated transform Cx' is
2424      * equivalent to first transforming p by the original transform
2425      * Cx and then transforming the result by
2426      * <code>Tx</code> like this:
2427      * Cx'(p) = Tx(Cx(p))
2428      * In matrix notation, if this transform Cx
2429      * is represented by the matrix [this] and <code>Tx</code> is
2430      * represented by the matrix [Tx] then this method does the
2431      * following:
2432      * <pre>
2433      *          [this] = [Tx] x [this]
2434      * </pre>
2435      * @param Tx the <code>AffineTransform</code> object to be
2436      * concatenated with this <code>AffineTransform</code> object.
2437      * @see #concatenate
2438      * @since 1.2
2439      */
2440     @SuppressWarnings("fallthrough")
preConcatenate(AffineTransform Tx)2441     public void preConcatenate(AffineTransform Tx) {
2442         double M0, M1;
2443         double T00, T01, T10, T11;
2444         double T02, T12;
2445         int mystate = state;
2446         int txstate = Tx.state;
2447         switch ((txstate << HI_SHIFT) | mystate) {
2448         case (HI_IDENTITY | APPLY_IDENTITY):
2449         case (HI_IDENTITY | APPLY_TRANSLATE):
2450         case (HI_IDENTITY | APPLY_SCALE):
2451         case (HI_IDENTITY | APPLY_SCALE | APPLY_TRANSLATE):
2452         case (HI_IDENTITY | APPLY_SHEAR):
2453         case (HI_IDENTITY | APPLY_SHEAR | APPLY_TRANSLATE):
2454         case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE):
2455         case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2456             // Tx is IDENTITY...
2457             return;
2458 
2459         case (HI_TRANSLATE | APPLY_IDENTITY):
2460         case (HI_TRANSLATE | APPLY_SCALE):
2461         case (HI_TRANSLATE | APPLY_SHEAR):
2462         case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE):
2463             // Tx is TRANSLATE, this has no TRANSLATE
2464             m02 = Tx.m02;
2465             m12 = Tx.m12;
2466             state = mystate | APPLY_TRANSLATE;
2467             type |= TYPE_TRANSLATION;
2468             return;
2469 
2470         case (HI_TRANSLATE | APPLY_TRANSLATE):
2471         case (HI_TRANSLATE | APPLY_SCALE | APPLY_TRANSLATE):
2472         case (HI_TRANSLATE | APPLY_SHEAR | APPLY_TRANSLATE):
2473         case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2474             // Tx is TRANSLATE, this has one too
2475             m02 = m02 + Tx.m02;
2476             m12 = m12 + Tx.m12;
2477             return;
2478 
2479         case (HI_SCALE | APPLY_TRANSLATE):
2480         case (HI_SCALE | APPLY_IDENTITY):
2481             // Only these two existing states need a new state
2482             state = mystate | APPLY_SCALE;
2483             /* NOBREAK */
2484         case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2485         case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE):
2486         case (HI_SCALE | APPLY_SHEAR | APPLY_TRANSLATE):
2487         case (HI_SCALE | APPLY_SHEAR):
2488         case (HI_SCALE | APPLY_SCALE | APPLY_TRANSLATE):
2489         case (HI_SCALE | APPLY_SCALE):
2490             // Tx is SCALE, this is anything
2491             T00 = Tx.m00;
2492             T11 = Tx.m11;
2493             if ((mystate & APPLY_SHEAR) != 0) {
2494                 m01 = m01 * T00;
2495                 m10 = m10 * T11;
2496                 if ((mystate & APPLY_SCALE) != 0) {
2497                     m00 = m00 * T00;
2498                     m11 = m11 * T11;
2499                 }
2500             } else {
2501                 m00 = m00 * T00;
2502                 m11 = m11 * T11;
2503             }
2504             if ((mystate & APPLY_TRANSLATE) != 0) {
2505                 m02 = m02 * T00;
2506                 m12 = m12 * T11;
2507             }
2508             type = TYPE_UNKNOWN;
2509             return;
2510         case (HI_SHEAR | APPLY_SHEAR | APPLY_TRANSLATE):
2511         case (HI_SHEAR | APPLY_SHEAR):
2512             mystate = mystate | APPLY_SCALE;
2513             /* NOBREAK */
2514         case (HI_SHEAR | APPLY_TRANSLATE):
2515         case (HI_SHEAR | APPLY_IDENTITY):
2516         case (HI_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2517         case (HI_SHEAR | APPLY_SCALE):
2518             state = mystate ^ APPLY_SHEAR;
2519             /* NOBREAK */
2520         case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2521         case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE):
2522             // Tx is SHEAR, this is anything
2523             T01 = Tx.m01;
2524             T10 = Tx.m10;
2525 
2526             M0 = m00;
2527             m00 = m10 * T01;
2528             m10 = M0 * T10;
2529 
2530             M0 = m01;
2531             m01 = m11 * T01;
2532             m11 = M0 * T10;
2533 
2534             M0 = m02;
2535             m02 = m12 * T01;
2536             m12 = M0 * T10;
2537             type = TYPE_UNKNOWN;
2538             return;
2539         }
2540         // If Tx has more than one attribute, it is not worth optimizing
2541         // all of those cases...
2542         T00 = Tx.m00; T01 = Tx.m01; T02 = Tx.m02;
2543         T10 = Tx.m10; T11 = Tx.m11; T12 = Tx.m12;
2544         switch (mystate) {
2545         default:
2546             stateError();
2547             /* NOTREACHED */
2548         case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2549             M0 = m02;
2550             M1 = m12;
2551             T02 += M0 * T00 + M1 * T01;
2552             T12 += M0 * T10 + M1 * T11;
2553 
2554             /* NOBREAK */
2555         case (APPLY_SHEAR | APPLY_SCALE):
2556             m02 = T02;
2557             m12 = T12;
2558 
2559             M0 = m00;
2560             M1 = m10;
2561             m00 = M0 * T00 + M1 * T01;
2562             m10 = M0 * T10 + M1 * T11;
2563 
2564             M0 = m01;
2565             M1 = m11;
2566             m01 = M0 * T00 + M1 * T01;
2567             m11 = M0 * T10 + M1 * T11;
2568             break;
2569 
2570         case (APPLY_SHEAR | APPLY_TRANSLATE):
2571             M0 = m02;
2572             M1 = m12;
2573             T02 += M0 * T00 + M1 * T01;
2574             T12 += M0 * T10 + M1 * T11;
2575 
2576             /* NOBREAK */
2577         case (APPLY_SHEAR):
2578             m02 = T02;
2579             m12 = T12;
2580 
2581             M0 = m10;
2582             m00 = M0 * T01;
2583             m10 = M0 * T11;
2584 
2585             M0 = m01;
2586             m01 = M0 * T00;
2587             m11 = M0 * T10;
2588             break;
2589 
2590         case (APPLY_SCALE | APPLY_TRANSLATE):
2591             M0 = m02;
2592             M1 = m12;
2593             T02 += M0 * T00 + M1 * T01;
2594             T12 += M0 * T10 + M1 * T11;
2595 
2596             /* NOBREAK */
2597         case (APPLY_SCALE):
2598             m02 = T02;
2599             m12 = T12;
2600 
2601             M0 = m00;
2602             m00 = M0 * T00;
2603             m10 = M0 * T10;
2604 
2605             M0 = m11;
2606             m01 = M0 * T01;
2607             m11 = M0 * T11;
2608             break;
2609 
2610         case (APPLY_TRANSLATE):
2611             M0 = m02;
2612             M1 = m12;
2613             T02 += M0 * T00 + M1 * T01;
2614             T12 += M0 * T10 + M1 * T11;
2615 
2616             /* NOBREAK */
2617         case (APPLY_IDENTITY):
2618             m02 = T02;
2619             m12 = T12;
2620 
2621             m00 = T00;
2622             m10 = T10;
2623 
2624             m01 = T01;
2625             m11 = T11;
2626 
2627             state = mystate | txstate;
2628             type = TYPE_UNKNOWN;
2629             return;
2630         }
2631         updateState();
2632     }
2633 
2634     /**
2635      * Returns an <code>AffineTransform</code> object representing the
2636      * inverse transformation.
2637      * The inverse transform Tx' of this transform Tx
2638      * maps coordinates transformed by Tx back
2639      * to their original coordinates.
2640      * In other words, Tx'(Tx(p)) = p = Tx(Tx'(p)).
2641      * <p>
2642      * If this transform maps all coordinates onto a point or a line
2643      * then it will not have an inverse, since coordinates that do
2644      * not lie on the destination point or line will not have an inverse
2645      * mapping.
2646      * The <code>getDeterminant</code> method can be used to determine if this
2647      * transform has no inverse, in which case an exception will be
2648      * thrown if the <code>createInverse</code> method is called.
2649      * @return a new <code>AffineTransform</code> object representing the
2650      * inverse transformation.
2651      * @see #getDeterminant
2652      * @exception NoninvertibleTransformException
2653      * if the matrix cannot be inverted.
2654      * @since 1.2
2655      */
createInverse()2656     public AffineTransform createInverse()
2657         throws NoninvertibleTransformException
2658     {
2659         double det;
2660         switch (state) {
2661         default:
2662             stateError();
2663             /* NOTREACHED */
2664             return null;
2665         case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2666             det = m00 * m11 - m01 * m10;
2667             if (Math.abs(det) <= Double.MIN_VALUE) {
2668                 throw new NoninvertibleTransformException("Determinant is "+
2669                                                           det);
2670             }
2671             return new AffineTransform( m11 / det, -m10 / det,
2672                                        -m01 / det,  m00 / det,
2673                                        (m01 * m12 - m11 * m02) / det,
2674                                        (m10 * m02 - m00 * m12) / det,
2675                                        (APPLY_SHEAR |
2676                                         APPLY_SCALE |
2677                                         APPLY_TRANSLATE));
2678         case (APPLY_SHEAR | APPLY_SCALE):
2679             det = m00 * m11 - m01 * m10;
2680             if (Math.abs(det) <= Double.MIN_VALUE) {
2681                 throw new NoninvertibleTransformException("Determinant is "+
2682                                                           det);
2683             }
2684             return new AffineTransform( m11 / det, -m10 / det,
2685                                        -m01 / det,  m00 / det,
2686                                         0.0,        0.0,
2687                                        (APPLY_SHEAR | APPLY_SCALE));
2688         case (APPLY_SHEAR | APPLY_TRANSLATE):
2689             if (m01 == 0.0 || m10 == 0.0) {
2690                 throw new NoninvertibleTransformException("Determinant is 0");
2691             }
2692             return new AffineTransform( 0.0,        1.0 / m01,
2693                                         1.0 / m10,  0.0,
2694                                        -m12 / m10, -m02 / m01,
2695                                        (APPLY_SHEAR | APPLY_TRANSLATE));
2696         case (APPLY_SHEAR):
2697             if (m01 == 0.0 || m10 == 0.0) {
2698                 throw new NoninvertibleTransformException("Determinant is 0");
2699             }
2700             return new AffineTransform(0.0,       1.0 / m01,
2701                                        1.0 / m10, 0.0,
2702                                        0.0,       0.0,
2703                                        (APPLY_SHEAR));
2704         case (APPLY_SCALE | APPLY_TRANSLATE):
2705             if (m00 == 0.0 || m11 == 0.0) {
2706                 throw new NoninvertibleTransformException("Determinant is 0");
2707             }
2708             return new AffineTransform( 1.0 / m00,  0.0,
2709                                         0.0,        1.0 / m11,
2710                                        -m02 / m00, -m12 / m11,
2711                                        (APPLY_SCALE | APPLY_TRANSLATE));
2712         case (APPLY_SCALE):
2713             if (m00 == 0.0 || m11 == 0.0) {
2714                 throw new NoninvertibleTransformException("Determinant is 0");
2715             }
2716             return new AffineTransform(1.0 / m00, 0.0,
2717                                        0.0,       1.0 / m11,
2718                                        0.0,       0.0,
2719                                        (APPLY_SCALE));
2720         case (APPLY_TRANSLATE):
2721             return new AffineTransform( 1.0,  0.0,
2722                                         0.0,  1.0,
2723                                        -m02, -m12,
2724                                        (APPLY_TRANSLATE));
2725         case (APPLY_IDENTITY):
2726             return new AffineTransform();
2727         }
2728 
2729         /* NOTREACHED */
2730     }
2731 
2732     /**
2733      * Sets this transform to the inverse of itself.
2734      * The inverse transform Tx' of this transform Tx
2735      * maps coordinates transformed by Tx back
2736      * to their original coordinates.
2737      * In other words, Tx'(Tx(p)) = p = Tx(Tx'(p)).
2738      * <p>
2739      * If this transform maps all coordinates onto a point or a line
2740      * then it will not have an inverse, since coordinates that do
2741      * not lie on the destination point or line will not have an inverse
2742      * mapping.
2743      * The <code>getDeterminant</code> method can be used to determine if this
2744      * transform has no inverse, in which case an exception will be
2745      * thrown if the <code>invert</code> method is called.
2746      * @see #getDeterminant
2747      * @exception NoninvertibleTransformException
2748      * if the matrix cannot be inverted.
2749      * @since 1.6
2750      */
invert()2751     public void invert()
2752         throws NoninvertibleTransformException
2753     {
2754         double M00, M01, M02;
2755         double M10, M11, M12;
2756         double det;
2757         switch (state) {
2758         default:
2759             stateError();
2760             /* NOTREACHED */
2761             return;
2762         case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2763             M00 = m00; M01 = m01; M02 = m02;
2764             M10 = m10; M11 = m11; M12 = m12;
2765             det = M00 * M11 - M01 * M10;
2766             if (Math.abs(det) <= Double.MIN_VALUE) {
2767                 throw new NoninvertibleTransformException("Determinant is "+
2768                                                           det);
2769             }
2770             m00 =  M11 / det;
2771             m10 = -M10 / det;
2772             m01 = -M01 / det;
2773             m11 =  M00 / det;
2774             m02 = (M01 * M12 - M11 * M02) / det;
2775             m12 = (M10 * M02 - M00 * M12) / det;
2776             break;
2777         case (APPLY_SHEAR | APPLY_SCALE):
2778             M00 = m00; M01 = m01;
2779             M10 = m10; M11 = m11;
2780             det = M00 * M11 - M01 * M10;
2781             if (Math.abs(det) <= Double.MIN_VALUE) {
2782                 throw new NoninvertibleTransformException("Determinant is "+
2783                                                           det);
2784             }
2785             m00 =  M11 / det;
2786             m10 = -M10 / det;
2787             m01 = -M01 / det;
2788             m11 =  M00 / det;
2789             // m02 = 0.0;
2790             // m12 = 0.0;
2791             break;
2792         case (APPLY_SHEAR | APPLY_TRANSLATE):
2793             M01 = m01; M02 = m02;
2794             M10 = m10; M12 = m12;
2795             if (M01 == 0.0 || M10 == 0.0) {
2796                 throw new NoninvertibleTransformException("Determinant is 0");
2797             }
2798             // m00 = 0.0;
2799             m10 = 1.0 / M01;
2800             m01 = 1.0 / M10;
2801             // m11 = 0.0;
2802             m02 = -M12 / M10;
2803             m12 = -M02 / M01;
2804             break;
2805         case (APPLY_SHEAR):
2806             M01 = m01;
2807             M10 = m10;
2808             if (M01 == 0.0 || M10 == 0.0) {
2809                 throw new NoninvertibleTransformException("Determinant is 0");
2810             }
2811             // m00 = 0.0;
2812             m10 = 1.0 / M01;
2813             m01 = 1.0 / M10;
2814             // m11 = 0.0;
2815             // m02 = 0.0;
2816             // m12 = 0.0;
2817             break;
2818         case (APPLY_SCALE | APPLY_TRANSLATE):
2819             M00 = m00; M02 = m02;
2820             M11 = m11; M12 = m12;
2821             if (M00 == 0.0 || M11 == 0.0) {
2822                 throw new NoninvertibleTransformException("Determinant is 0");
2823             }
2824             m00 = 1.0 / M00;
2825             // m10 = 0.0;
2826             // m01 = 0.0;
2827             m11 = 1.0 / M11;
2828             m02 = -M02 / M00;
2829             m12 = -M12 / M11;
2830             break;
2831         case (APPLY_SCALE):
2832             M00 = m00;
2833             M11 = m11;
2834             if (M00 == 0.0 || M11 == 0.0) {
2835                 throw new NoninvertibleTransformException("Determinant is 0");
2836             }
2837             m00 = 1.0 / M00;
2838             // m10 = 0.0;
2839             // m01 = 0.0;
2840             m11 = 1.0 / M11;
2841             // m02 = 0.0;
2842             // m12 = 0.0;
2843             break;
2844         case (APPLY_TRANSLATE):
2845             // m00 = 1.0;
2846             // m10 = 0.0;
2847             // m01 = 0.0;
2848             // m11 = 1.0;
2849             m02 = -m02;
2850             m12 = -m12;
2851             break;
2852         case (APPLY_IDENTITY):
2853             // m00 = 1.0;
2854             // m10 = 0.0;
2855             // m01 = 0.0;
2856             // m11 = 1.0;
2857             // m02 = 0.0;
2858             // m12 = 0.0;
2859             break;
2860         }
2861     }
2862 
2863     /**
2864      * Transforms the specified <code>ptSrc</code> and stores the result
2865      * in <code>ptDst</code>.
2866      * If <code>ptDst</code> is <code>null</code>, a new {@link Point2D}
2867      * object is allocated and then the result of the transformation is
2868      * stored in this object.
2869      * In either case, <code>ptDst</code>, which contains the
2870      * transformed point, is returned for convenience.
2871      * If <code>ptSrc</code> and <code>ptDst</code> are the same
2872      * object, the input point is correctly overwritten with
2873      * the transformed point.
2874      * @param ptSrc the specified <code>Point2D</code> to be transformed
2875      * @param ptDst the specified <code>Point2D</code> that stores the
2876      * result of transforming <code>ptSrc</code>
2877      * @return the <code>ptDst</code> after transforming
2878      * <code>ptSrc</code> and storing the result in <code>ptDst</code>.
2879      * @since 1.2
2880      */
transform(Point2D ptSrc, Point2D ptDst)2881     public Point2D transform(Point2D ptSrc, Point2D ptDst) {
2882         if (ptDst == null) {
2883             if (ptSrc instanceof Point2D.Double) {
2884                 ptDst = new Point2D.Double();
2885             } else {
2886                 ptDst = new Point2D.Float();
2887             }
2888         }
2889         // Copy source coords into local variables in case src == dst
2890         double x = ptSrc.getX();
2891         double y = ptSrc.getY();
2892         switch (state) {
2893         default:
2894             stateError();
2895             /* NOTREACHED */
2896             return null;
2897         case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2898             ptDst.setLocation(x * m00 + y * m01 + m02,
2899                               x * m10 + y * m11 + m12);
2900             return ptDst;
2901         case (APPLY_SHEAR | APPLY_SCALE):
2902             ptDst.setLocation(x * m00 + y * m01, x * m10 + y * m11);
2903             return ptDst;
2904         case (APPLY_SHEAR | APPLY_TRANSLATE):
2905             ptDst.setLocation(y * m01 + m02, x * m10 + m12);
2906             return ptDst;
2907         case (APPLY_SHEAR):
2908             ptDst.setLocation(y * m01, x * m10);
2909             return ptDst;
2910         case (APPLY_SCALE | APPLY_TRANSLATE):
2911             ptDst.setLocation(x * m00 + m02, y * m11 + m12);
2912             return ptDst;
2913         case (APPLY_SCALE):
2914             ptDst.setLocation(x * m00, y * m11);
2915             return ptDst;
2916         case (APPLY_TRANSLATE):
2917             ptDst.setLocation(x + m02, y + m12);
2918             return ptDst;
2919         case (APPLY_IDENTITY):
2920             ptDst.setLocation(x, y);
2921             return ptDst;
2922         }
2923 
2924         /* NOTREACHED */
2925     }
2926 
2927     /**
2928      * Transforms an array of point objects by this transform.
2929      * If any element of the <code>ptDst</code> array is
2930      * <code>null</code>, a new <code>Point2D</code> object is allocated
2931      * and stored into that element before storing the results of the
2932      * transformation.
2933      * <p>
2934      * Note that this method does not take any precautions to
2935      * avoid problems caused by storing results into <code>Point2D</code>
2936      * objects that will be used as the source for calculations
2937      * further down the source array.
2938      * This method does guarantee that if a specified <code>Point2D</code>
2939      * object is both the source and destination for the same single point
2940      * transform operation then the results will not be stored until
2941      * the calculations are complete to avoid storing the results on
2942      * top of the operands.
2943      * If, however, the destination <code>Point2D</code> object for one
2944      * operation is the same object as the source <code>Point2D</code>
2945      * object for another operation further down the source array then
2946      * the original coordinates in that point are overwritten before
2947      * they can be converted.
2948      * @param ptSrc the array containing the source point objects
2949      * @param ptDst the array into which the transform point objects are
2950      * returned
2951      * @param srcOff the offset to the first point object to be
2952      * transformed in the source array
2953      * @param dstOff the offset to the location of the first
2954      * transformed point object that is stored in the destination array
2955      * @param numPts the number of point objects to be transformed
2956      * @since 1.2
2957      */
transform(Point2D[] ptSrc, int srcOff, Point2D[] ptDst, int dstOff, int numPts)2958     public void transform(Point2D[] ptSrc, int srcOff,
2959                           Point2D[] ptDst, int dstOff,
2960                           int numPts) {
2961         int state = this.state;
2962         while (--numPts >= 0) {
2963             // Copy source coords into local variables in case src == dst
2964             Point2D src = ptSrc[srcOff++];
2965             double x = src.getX();
2966             double y = src.getY();
2967             Point2D dst = ptDst[dstOff++];
2968             if (dst == null) {
2969                 if (src instanceof Point2D.Double) {
2970                     dst = new Point2D.Double();
2971                 } else {
2972                     dst = new Point2D.Float();
2973                 }
2974                 ptDst[dstOff - 1] = dst;
2975             }
2976             switch (state) {
2977             default:
2978                 stateError();
2979                 /* NOTREACHED */
2980                 return;
2981             case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2982                 dst.setLocation(x * m00 + y * m01 + m02,
2983                                 x * m10 + y * m11 + m12);
2984                 break;
2985             case (APPLY_SHEAR | APPLY_SCALE):
2986                 dst.setLocation(x * m00 + y * m01, x * m10 + y * m11);
2987                 break;
2988             case (APPLY_SHEAR | APPLY_TRANSLATE):
2989                 dst.setLocation(y * m01 + m02, x * m10 + m12);
2990                 break;
2991             case (APPLY_SHEAR):
2992                 dst.setLocation(y * m01, x * m10);
2993                 break;
2994             case (APPLY_SCALE | APPLY_TRANSLATE):
2995                 dst.setLocation(x * m00 + m02, y * m11 + m12);
2996                 break;
2997             case (APPLY_SCALE):
2998                 dst.setLocation(x * m00, y * m11);
2999                 break;
3000             case (APPLY_TRANSLATE):
3001                 dst.setLocation(x + m02, y + m12);
3002                 break;
3003             case (APPLY_IDENTITY):
3004                 dst.setLocation(x, y);
3005                 break;
3006             }
3007         }
3008 
3009         /* NOTREACHED */
3010     }
3011 
3012     /**
3013      * Transforms an array of floating point coordinates by this transform.
3014      * The two coordinate array sections can be exactly the same or
3015      * can be overlapping sections of the same array without affecting the
3016      * validity of the results.
3017      * This method ensures that no source coordinates are overwritten by a
3018      * previous operation before they can be transformed.
3019      * The coordinates are stored in the arrays starting at the specified
3020      * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3021      * @param srcPts the array containing the source point coordinates.
3022      * Each point is stored as a pair of x,&nbsp;y coordinates.
3023      * @param dstPts the array into which the transformed point coordinates
3024      * are returned.  Each point is stored as a pair of x,&nbsp;y
3025      * coordinates.
3026      * @param srcOff the offset to the first point to be transformed
3027      * in the source array
3028      * @param dstOff the offset to the location of the first
3029      * transformed point that is stored in the destination array
3030      * @param numPts the number of points to be transformed
3031      * @since 1.2
3032      */
transform(float[] srcPts, int srcOff, float[] dstPts, int dstOff, int numPts)3033     public void transform(float[] srcPts, int srcOff,
3034                           float[] dstPts, int dstOff,
3035                           int numPts) {
3036         double M00, M01, M02, M10, M11, M12;    // For caching
3037         if (dstPts == srcPts &&
3038             dstOff > srcOff && dstOff < srcOff + numPts * 2)
3039         {
3040             // If the arrays overlap partially with the destination higher
3041             // than the source and we transform the coordinates normally
3042             // we would overwrite some of the later source coordinates
3043             // with results of previous transformations.
3044             // To get around this we use arraycopy to copy the points
3045             // to their final destination with correct overwrite
3046             // handling and then transform them in place in the new
3047             // safer location.
3048             System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts * 2);
3049             // srcPts = dstPts;         // They are known to be equal.
3050             srcOff = dstOff;
3051         }
3052         switch (state) {
3053         default:
3054             stateError();
3055             /* NOTREACHED */
3056             return;
3057         case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3058             M00 = m00; M01 = m01; M02 = m02;
3059             M10 = m10; M11 = m11; M12 = m12;
3060             while (--numPts >= 0) {
3061                 double x = srcPts[srcOff++];
3062                 double y = srcPts[srcOff++];
3063                 dstPts[dstOff++] = (float) (M00 * x + M01 * y + M02);
3064                 dstPts[dstOff++] = (float) (M10 * x + M11 * y + M12);
3065             }
3066             return;
3067         case (APPLY_SHEAR | APPLY_SCALE):
3068             M00 = m00; M01 = m01;
3069             M10 = m10; M11 = m11;
3070             while (--numPts >= 0) {
3071                 double x = srcPts[srcOff++];
3072                 double y = srcPts[srcOff++];
3073                 dstPts[dstOff++] = (float) (M00 * x + M01 * y);
3074                 dstPts[dstOff++] = (float) (M10 * x + M11 * y);
3075             }
3076             return;
3077         case (APPLY_SHEAR | APPLY_TRANSLATE):
3078             M01 = m01; M02 = m02;
3079             M10 = m10; M12 = m12;
3080             while (--numPts >= 0) {
3081                 double x = srcPts[srcOff++];
3082                 dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++] + M02);
3083                 dstPts[dstOff++] = (float) (M10 * x + M12);
3084             }
3085             return;
3086         case (APPLY_SHEAR):
3087             M01 = m01; M10 = m10;
3088             while (--numPts >= 0) {
3089                 double x = srcPts[srcOff++];
3090                 dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++]);
3091                 dstPts[dstOff++] = (float) (M10 * x);
3092             }
3093             return;
3094         case (APPLY_SCALE | APPLY_TRANSLATE):
3095             M00 = m00; M02 = m02;
3096             M11 = m11; M12 = m12;
3097             while (--numPts >= 0) {
3098                 dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++] + M02);
3099                 dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++] + M12);
3100             }
3101             return;
3102         case (APPLY_SCALE):
3103             M00 = m00; M11 = m11;
3104             while (--numPts >= 0) {
3105                 dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++]);
3106                 dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++]);
3107             }
3108             return;
3109         case (APPLY_TRANSLATE):
3110             M02 = m02; M12 = m12;
3111             while (--numPts >= 0) {
3112                 dstPts[dstOff++] = (float) (srcPts[srcOff++] + M02);
3113                 dstPts[dstOff++] = (float) (srcPts[srcOff++] + M12);
3114             }
3115             return;
3116         case (APPLY_IDENTITY):
3117             if (srcPts != dstPts || srcOff != dstOff) {
3118                 System.arraycopy(srcPts, srcOff, dstPts, dstOff,
3119                                  numPts * 2);
3120             }
3121             return;
3122         }
3123 
3124         /* NOTREACHED */
3125     }
3126 
3127     /**
3128      * Transforms an array of double precision coordinates by this transform.
3129      * The two coordinate array sections can be exactly the same or
3130      * can be overlapping sections of the same array without affecting the
3131      * validity of the results.
3132      * This method ensures that no source coordinates are
3133      * overwritten by a previous operation before they can be transformed.
3134      * The coordinates are stored in the arrays starting at the indicated
3135      * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3136      * @param srcPts the array containing the source point coordinates.
3137      * Each point is stored as a pair of x,&nbsp;y coordinates.
3138      * @param dstPts the array into which the transformed point
3139      * coordinates are returned.  Each point is stored as a pair of
3140      * x,&nbsp;y coordinates.
3141      * @param srcOff the offset to the first point to be transformed
3142      * in the source array
3143      * @param dstOff the offset to the location of the first
3144      * transformed point that is stored in the destination array
3145      * @param numPts the number of point objects to be transformed
3146      * @since 1.2
3147      */
transform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, int numPts)3148     public void transform(double[] srcPts, int srcOff,
3149                           double[] dstPts, int dstOff,
3150                           int numPts) {
3151         double M00, M01, M02, M10, M11, M12;    // For caching
3152         if (dstPts == srcPts &&
3153             dstOff > srcOff && dstOff < srcOff + numPts * 2)
3154         {
3155             // If the arrays overlap partially with the destination higher
3156             // than the source and we transform the coordinates normally
3157             // we would overwrite some of the later source coordinates
3158             // with results of previous transformations.
3159             // To get around this we use arraycopy to copy the points
3160             // to their final destination with correct overwrite
3161             // handling and then transform them in place in the new
3162             // safer location.
3163             System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts * 2);
3164             // srcPts = dstPts;         // They are known to be equal.
3165             srcOff = dstOff;
3166         }
3167         switch (state) {
3168         default:
3169             stateError();
3170             /* NOTREACHED */
3171             return;
3172         case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3173             M00 = m00; M01 = m01; M02 = m02;
3174             M10 = m10; M11 = m11; M12 = m12;
3175             while (--numPts >= 0) {
3176                 double x = srcPts[srcOff++];
3177                 double y = srcPts[srcOff++];
3178                 dstPts[dstOff++] = M00 * x + M01 * y + M02;
3179                 dstPts[dstOff++] = M10 * x + M11 * y + M12;
3180             }
3181             return;
3182         case (APPLY_SHEAR | APPLY_SCALE):
3183             M00 = m00; M01 = m01;
3184             M10 = m10; M11 = m11;
3185             while (--numPts >= 0) {
3186                 double x = srcPts[srcOff++];
3187                 double y = srcPts[srcOff++];
3188                 dstPts[dstOff++] = M00 * x + M01 * y;
3189                 dstPts[dstOff++] = M10 * x + M11 * y;
3190             }
3191             return;
3192         case (APPLY_SHEAR | APPLY_TRANSLATE):
3193             M01 = m01; M02 = m02;
3194             M10 = m10; M12 = m12;
3195             while (--numPts >= 0) {
3196                 double x = srcPts[srcOff++];
3197                 dstPts[dstOff++] = M01 * srcPts[srcOff++] + M02;
3198                 dstPts[dstOff++] = M10 * x + M12;
3199             }
3200             return;
3201         case (APPLY_SHEAR):
3202             M01 = m01; M10 = m10;
3203             while (--numPts >= 0) {
3204                 double x = srcPts[srcOff++];
3205                 dstPts[dstOff++] = M01 * srcPts[srcOff++];
3206                 dstPts[dstOff++] = M10 * x;
3207             }
3208             return;
3209         case (APPLY_SCALE | APPLY_TRANSLATE):
3210             M00 = m00; M02 = m02;
3211             M11 = m11; M12 = m12;
3212             while (--numPts >= 0) {
3213                 dstPts[dstOff++] = M00 * srcPts[srcOff++] + M02;
3214                 dstPts[dstOff++] = M11 * srcPts[srcOff++] + M12;
3215             }
3216             return;
3217         case (APPLY_SCALE):
3218             M00 = m00; M11 = m11;
3219             while (--numPts >= 0) {
3220                 dstPts[dstOff++] = M00 * srcPts[srcOff++];
3221                 dstPts[dstOff++] = M11 * srcPts[srcOff++];
3222             }
3223             return;
3224         case (APPLY_TRANSLATE):
3225             M02 = m02; M12 = m12;
3226             while (--numPts >= 0) {
3227                 dstPts[dstOff++] = srcPts[srcOff++] + M02;
3228                 dstPts[dstOff++] = srcPts[srcOff++] + M12;
3229             }
3230             return;
3231         case (APPLY_IDENTITY):
3232             if (srcPts != dstPts || srcOff != dstOff) {
3233                 System.arraycopy(srcPts, srcOff, dstPts, dstOff,
3234                                  numPts * 2);
3235             }
3236             return;
3237         }
3238 
3239         /* NOTREACHED */
3240     }
3241 
3242     /**
3243      * Transforms an array of floating point coordinates by this transform
3244      * and stores the results into an array of doubles.
3245      * The coordinates are stored in the arrays starting at the specified
3246      * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3247      * @param srcPts the array containing the source point coordinates.
3248      * Each point is stored as a pair of x,&nbsp;y coordinates.
3249      * @param dstPts the array into which the transformed point coordinates
3250      * are returned.  Each point is stored as a pair of x,&nbsp;y
3251      * coordinates.
3252      * @param srcOff the offset to the first point to be transformed
3253      * in the source array
3254      * @param dstOff the offset to the location of the first
3255      * transformed point that is stored in the destination array
3256      * @param numPts the number of points to be transformed
3257      * @since 1.2
3258      */
transform(float[] srcPts, int srcOff, double[] dstPts, int dstOff, int numPts)3259     public void transform(float[] srcPts, int srcOff,
3260                           double[] dstPts, int dstOff,
3261                           int numPts) {
3262         double M00, M01, M02, M10, M11, M12;    // For caching
3263         switch (state) {
3264         default:
3265             stateError();
3266             /* NOTREACHED */
3267             return;
3268         case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3269             M00 = m00; M01 = m01; M02 = m02;
3270             M10 = m10; M11 = m11; M12 = m12;
3271             while (--numPts >= 0) {
3272                 double x = srcPts[srcOff++];
3273                 double y = srcPts[srcOff++];
3274                 dstPts[dstOff++] = M00 * x + M01 * y + M02;
3275                 dstPts[dstOff++] = M10 * x + M11 * y + M12;
3276             }
3277             return;
3278         case (APPLY_SHEAR | APPLY_SCALE):
3279             M00 = m00; M01 = m01;
3280             M10 = m10; M11 = m11;
3281             while (--numPts >= 0) {
3282                 double x = srcPts[srcOff++];
3283                 double y = srcPts[srcOff++];
3284                 dstPts[dstOff++] = M00 * x + M01 * y;
3285                 dstPts[dstOff++] = M10 * x + M11 * y;
3286             }
3287             return;
3288         case (APPLY_SHEAR | APPLY_TRANSLATE):
3289             M01 = m01; M02 = m02;
3290             M10 = m10; M12 = m12;
3291             while (--numPts >= 0) {
3292                 double x = srcPts[srcOff++];
3293                 dstPts[dstOff++] = M01 * srcPts[srcOff++] + M02;
3294                 dstPts[dstOff++] = M10 * x + M12;
3295             }
3296             return;
3297         case (APPLY_SHEAR):
3298             M01 = m01; M10 = m10;
3299             while (--numPts >= 0) {
3300                 double x = srcPts[srcOff++];
3301                 dstPts[dstOff++] = M01 * srcPts[srcOff++];
3302                 dstPts[dstOff++] = M10 * x;
3303             }
3304             return;
3305         case (APPLY_SCALE | APPLY_TRANSLATE):
3306             M00 = m00; M02 = m02;
3307             M11 = m11; M12 = m12;
3308             while (--numPts >= 0) {
3309                 dstPts[dstOff++] = M00 * srcPts[srcOff++] + M02;
3310                 dstPts[dstOff++] = M11 * srcPts[srcOff++] + M12;
3311             }
3312             return;
3313         case (APPLY_SCALE):
3314             M00 = m00; M11 = m11;
3315             while (--numPts >= 0) {
3316                 dstPts[dstOff++] = M00 * srcPts[srcOff++];
3317                 dstPts[dstOff++] = M11 * srcPts[srcOff++];
3318             }
3319             return;
3320         case (APPLY_TRANSLATE):
3321             M02 = m02; M12 = m12;
3322             while (--numPts >= 0) {
3323                 dstPts[dstOff++] = srcPts[srcOff++] + M02;
3324                 dstPts[dstOff++] = srcPts[srcOff++] + M12;
3325             }
3326             return;
3327         case (APPLY_IDENTITY):
3328             while (--numPts >= 0) {
3329                 dstPts[dstOff++] = srcPts[srcOff++];
3330                 dstPts[dstOff++] = srcPts[srcOff++];
3331             }
3332             return;
3333         }
3334 
3335         /* NOTREACHED */
3336     }
3337 
3338     /**
3339      * Transforms an array of double precision coordinates by this transform
3340      * and stores the results into an array of floats.
3341      * The coordinates are stored in the arrays starting at the specified
3342      * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3343      * @param srcPts the array containing the source point coordinates.
3344      * Each point is stored as a pair of x,&nbsp;y coordinates.
3345      * @param dstPts the array into which the transformed point
3346      * coordinates are returned.  Each point is stored as a pair of
3347      * x,&nbsp;y coordinates.
3348      * @param srcOff the offset to the first point to be transformed
3349      * in the source array
3350      * @param dstOff the offset to the location of the first
3351      * transformed point that is stored in the destination array
3352      * @param numPts the number of point objects to be transformed
3353      * @since 1.2
3354      */
transform(double[] srcPts, int srcOff, float[] dstPts, int dstOff, int numPts)3355     public void transform(double[] srcPts, int srcOff,
3356                           float[] dstPts, int dstOff,
3357                           int numPts) {
3358         double M00, M01, M02, M10, M11, M12;    // For caching
3359         switch (state) {
3360         default:
3361             stateError();
3362             /* NOTREACHED */
3363             return;
3364         case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3365             M00 = m00; M01 = m01; M02 = m02;
3366             M10 = m10; M11 = m11; M12 = m12;
3367             while (--numPts >= 0) {
3368                 double x = srcPts[srcOff++];
3369                 double y = srcPts[srcOff++];
3370                 dstPts[dstOff++] = (float) (M00 * x + M01 * y + M02);
3371                 dstPts[dstOff++] = (float) (M10 * x + M11 * y + M12);
3372             }
3373             return;
3374         case (APPLY_SHEAR | APPLY_SCALE):
3375             M00 = m00; M01 = m01;
3376             M10 = m10; M11 = m11;
3377             while (--numPts >= 0) {
3378                 double x = srcPts[srcOff++];
3379                 double y = srcPts[srcOff++];
3380                 dstPts[dstOff++] = (float) (M00 * x + M01 * y);
3381                 dstPts[dstOff++] = (float) (M10 * x + M11 * y);
3382             }
3383             return;
3384         case (APPLY_SHEAR | APPLY_TRANSLATE):
3385             M01 = m01; M02 = m02;
3386             M10 = m10; M12 = m12;
3387             while (--numPts >= 0) {
3388                 double x = srcPts[srcOff++];
3389                 dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++] + M02);
3390                 dstPts[dstOff++] = (float) (M10 * x + M12);
3391             }
3392             return;
3393         case (APPLY_SHEAR):
3394             M01 = m01; M10 = m10;
3395             while (--numPts >= 0) {
3396                 double x = srcPts[srcOff++];
3397                 dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++]);
3398                 dstPts[dstOff++] = (float) (M10 * x);
3399             }
3400             return;
3401         case (APPLY_SCALE | APPLY_TRANSLATE):
3402             M00 = m00; M02 = m02;
3403             M11 = m11; M12 = m12;
3404             while (--numPts >= 0) {
3405                 dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++] + M02);
3406                 dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++] + M12);
3407             }
3408             return;
3409         case (APPLY_SCALE):
3410             M00 = m00; M11 = m11;
3411             while (--numPts >= 0) {
3412                 dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++]);
3413                 dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++]);
3414             }
3415             return;
3416         case (APPLY_TRANSLATE):
3417             M02 = m02; M12 = m12;
3418             while (--numPts >= 0) {
3419                 dstPts[dstOff++] = (float) (srcPts[srcOff++] + M02);
3420                 dstPts[dstOff++] = (float) (srcPts[srcOff++] + M12);
3421             }
3422             return;
3423         case (APPLY_IDENTITY):
3424             while (--numPts >= 0) {
3425                 dstPts[dstOff++] = (float) (srcPts[srcOff++]);
3426                 dstPts[dstOff++] = (float) (srcPts[srcOff++]);
3427             }
3428             return;
3429         }
3430 
3431         /* NOTREACHED */
3432     }
3433 
3434     /**
3435      * Inverse transforms the specified <code>ptSrc</code> and stores the
3436      * result in <code>ptDst</code>.
3437      * If <code>ptDst</code> is <code>null</code>, a new
3438      * <code>Point2D</code> object is allocated and then the result of the
3439      * transform is stored in this object.
3440      * In either case, <code>ptDst</code>, which contains the transformed
3441      * point, is returned for convenience.
3442      * If <code>ptSrc</code> and <code>ptDst</code> are the same
3443      * object, the input point is correctly overwritten with the
3444      * transformed point.
3445      * @param ptSrc the point to be inverse transformed
3446      * @param ptDst the resulting transformed point
3447      * @return <code>ptDst</code>, which contains the result of the
3448      * inverse transform.
3449      * @exception NoninvertibleTransformException  if the matrix cannot be
3450      *                                         inverted.
3451      * @since 1.2
3452      */
3453     @SuppressWarnings("fallthrough")
inverseTransform(Point2D ptSrc, Point2D ptDst)3454     public Point2D inverseTransform(Point2D ptSrc, Point2D ptDst)
3455         throws NoninvertibleTransformException
3456     {
3457         if (ptDst == null) {
3458             if (ptSrc instanceof Point2D.Double) {
3459                 ptDst = new Point2D.Double();
3460             } else {
3461                 ptDst = new Point2D.Float();
3462             }
3463         }
3464         // Copy source coords into local variables in case src == dst
3465         double x = ptSrc.getX();
3466         double y = ptSrc.getY();
3467         switch (state) {
3468         default:
3469             stateError();
3470             /* NOTREACHED */
3471         case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3472             x -= m02;
3473             y -= m12;
3474             /* NOBREAK */
3475         case (APPLY_SHEAR | APPLY_SCALE):
3476             double det = m00 * m11 - m01 * m10;
3477             if (Math.abs(det) <= Double.MIN_VALUE) {
3478                 throw new NoninvertibleTransformException("Determinant is "+
3479                                                           det);
3480             }
3481             ptDst.setLocation((x * m11 - y * m01) / det,
3482                               (y * m00 - x * m10) / det);
3483             return ptDst;
3484         case (APPLY_SHEAR | APPLY_TRANSLATE):
3485             x -= m02;
3486             y -= m12;
3487             /* NOBREAK */
3488         case (APPLY_SHEAR):
3489             if (m01 == 0.0 || m10 == 0.0) {
3490                 throw new NoninvertibleTransformException("Determinant is 0");
3491             }
3492             ptDst.setLocation(y / m10, x / m01);
3493             return ptDst;
3494         case (APPLY_SCALE | APPLY_TRANSLATE):
3495             x -= m02;
3496             y -= m12;
3497             /* NOBREAK */
3498         case (APPLY_SCALE):
3499             if (m00 == 0.0 || m11 == 0.0) {
3500                 throw new NoninvertibleTransformException("Determinant is 0");
3501             }
3502             ptDst.setLocation(x / m00, y / m11);
3503             return ptDst;
3504         case (APPLY_TRANSLATE):
3505             ptDst.setLocation(x - m02, y - m12);
3506             return ptDst;
3507         case (APPLY_IDENTITY):
3508             ptDst.setLocation(x, y);
3509             return ptDst;
3510         }
3511 
3512         /* NOTREACHED */
3513     }
3514 
3515     /**
3516      * Inverse transforms an array of double precision coordinates by
3517      * this transform.
3518      * The two coordinate array sections can be exactly the same or
3519      * can be overlapping sections of the same array without affecting the
3520      * validity of the results.
3521      * This method ensures that no source coordinates are
3522      * overwritten by a previous operation before they can be transformed.
3523      * The coordinates are stored in the arrays starting at the specified
3524      * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3525      * @param srcPts the array containing the source point coordinates.
3526      * Each point is stored as a pair of x,&nbsp;y coordinates.
3527      * @param dstPts the array into which the transformed point
3528      * coordinates are returned.  Each point is stored as a pair of
3529      * x,&nbsp;y coordinates.
3530      * @param srcOff the offset to the first point to be transformed
3531      * in the source array
3532      * @param dstOff the offset to the location of the first
3533      * transformed point that is stored in the destination array
3534      * @param numPts the number of point objects to be transformed
3535      * @exception NoninvertibleTransformException  if the matrix cannot be
3536      *                                         inverted.
3537      * @since 1.2
3538      */
inverseTransform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, int numPts)3539     public void inverseTransform(double[] srcPts, int srcOff,
3540                                  double[] dstPts, int dstOff,
3541                                  int numPts)
3542         throws NoninvertibleTransformException
3543     {
3544         double M00, M01, M02, M10, M11, M12;    // For caching
3545         double det;
3546         if (dstPts == srcPts &&
3547             dstOff > srcOff && dstOff < srcOff + numPts * 2)
3548         {
3549             // If the arrays overlap partially with the destination higher
3550             // than the source and we transform the coordinates normally
3551             // we would overwrite some of the later source coordinates
3552             // with results of previous transformations.
3553             // To get around this we use arraycopy to copy the points
3554             // to their final destination with correct overwrite
3555             // handling and then transform them in place in the new
3556             // safer location.
3557             System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts * 2);
3558             // srcPts = dstPts;         // They are known to be equal.
3559             srcOff = dstOff;
3560         }
3561         switch (state) {
3562         default:
3563             stateError();
3564             /* NOTREACHED */
3565             return;
3566         case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3567             M00 = m00; M01 = m01; M02 = m02;
3568             M10 = m10; M11 = m11; M12 = m12;
3569             det = M00 * M11 - M01 * M10;
3570             if (Math.abs(det) <= Double.MIN_VALUE) {
3571                 throw new NoninvertibleTransformException("Determinant is "+
3572                                                           det);
3573             }
3574             while (--numPts >= 0) {
3575                 double x = srcPts[srcOff++] - M02;
3576                 double y = srcPts[srcOff++] - M12;
3577                 dstPts[dstOff++] = (x * M11 - y * M01) / det;
3578                 dstPts[dstOff++] = (y * M00 - x * M10) / det;
3579             }
3580             return;
3581         case (APPLY_SHEAR | APPLY_SCALE):
3582             M00 = m00; M01 = m01;
3583             M10 = m10; M11 = m11;
3584             det = M00 * M11 - M01 * M10;
3585             if (Math.abs(det) <= Double.MIN_VALUE) {
3586                 throw new NoninvertibleTransformException("Determinant is "+
3587                                                           det);
3588             }
3589             while (--numPts >= 0) {
3590                 double x = srcPts[srcOff++];
3591                 double y = srcPts[srcOff++];
3592                 dstPts[dstOff++] = (x * M11 - y * M01) / det;
3593                 dstPts[dstOff++] = (y * M00 - x * M10) / det;
3594             }
3595             return;
3596         case (APPLY_SHEAR | APPLY_TRANSLATE):
3597             M01 = m01; M02 = m02;
3598             M10 = m10; M12 = m12;
3599             if (M01 == 0.0 || M10 == 0.0) {
3600                 throw new NoninvertibleTransformException("Determinant is 0");
3601             }
3602             while (--numPts >= 0) {
3603                 double x = srcPts[srcOff++] - M02;
3604                 dstPts[dstOff++] = (srcPts[srcOff++] - M12) / M10;
3605                 dstPts[dstOff++] = x / M01;
3606             }
3607             return;
3608         case (APPLY_SHEAR):
3609             M01 = m01; M10 = m10;
3610             if (M01 == 0.0 || M10 == 0.0) {
3611                 throw new NoninvertibleTransformException("Determinant is 0");
3612             }
3613             while (--numPts >= 0) {
3614                 double x = srcPts[srcOff++];
3615                 dstPts[dstOff++] = srcPts[srcOff++] / M10;
3616                 dstPts[dstOff++] = x / M01;
3617             }
3618             return;
3619         case (APPLY_SCALE | APPLY_TRANSLATE):
3620             M00 = m00; M02 = m02;
3621             M11 = m11; M12 = m12;
3622             if (M00 == 0.0 || M11 == 0.0) {
3623                 throw new NoninvertibleTransformException("Determinant is 0");
3624             }
3625             while (--numPts >= 0) {
3626                 dstPts[dstOff++] = (srcPts[srcOff++] - M02) / M00;
3627                 dstPts[dstOff++] = (srcPts[srcOff++] - M12) / M11;
3628             }
3629             return;
3630         case (APPLY_SCALE):
3631             M00 = m00; M11 = m11;
3632             if (M00 == 0.0 || M11 == 0.0) {
3633                 throw new NoninvertibleTransformException("Determinant is 0");
3634             }
3635             while (--numPts >= 0) {
3636                 dstPts[dstOff++] = srcPts[srcOff++] / M00;
3637                 dstPts[dstOff++] = srcPts[srcOff++] / M11;
3638             }
3639             return;
3640         case (APPLY_TRANSLATE):
3641             M02 = m02; M12 = m12;
3642             while (--numPts >= 0) {
3643                 dstPts[dstOff++] = srcPts[srcOff++] - M02;
3644                 dstPts[dstOff++] = srcPts[srcOff++] - M12;
3645             }
3646             return;
3647         case (APPLY_IDENTITY):
3648             if (srcPts != dstPts || srcOff != dstOff) {
3649                 System.arraycopy(srcPts, srcOff, dstPts, dstOff,
3650                                  numPts * 2);
3651             }
3652             return;
3653         }
3654 
3655         /* NOTREACHED */
3656     }
3657 
3658     /**
3659      * Transforms the relative distance vector specified by
3660      * <code>ptSrc</code> and stores the result in <code>ptDst</code>.
3661      * A relative distance vector is transformed without applying the
3662      * translation components of the affine transformation matrix
3663      * using the following equations:
3664      * <pre>
3665      *  [  x' ]   [  m00  m01 (m02) ] [  x  ]   [ m00x + m01y ]
3666      *  [  y' ] = [  m10  m11 (m12) ] [  y  ] = [ m10x + m11y ]
3667      *  [ (1) ]   [  (0)  (0) ( 1 ) ] [ (1) ]   [     (1)     ]
3668      * </pre>
3669      * If <code>ptDst</code> is <code>null</code>, a new
3670      * <code>Point2D</code> object is allocated and then the result of the
3671      * transform is stored in this object.
3672      * In either case, <code>ptDst</code>, which contains the
3673      * transformed point, is returned for convenience.
3674      * If <code>ptSrc</code> and <code>ptDst</code> are the same object,
3675      * the input point is correctly overwritten with the transformed
3676      * point.
3677      * @param ptSrc the distance vector to be delta transformed
3678      * @param ptDst the resulting transformed distance vector
3679      * @return <code>ptDst</code>, which contains the result of the
3680      * transformation.
3681      * @since 1.2
3682      */
deltaTransform(Point2D ptSrc, Point2D ptDst)3683     public Point2D deltaTransform(Point2D ptSrc, Point2D ptDst) {
3684         if (ptDst == null) {
3685             if (ptSrc instanceof Point2D.Double) {
3686                 ptDst = new Point2D.Double();
3687             } else {
3688                 ptDst = new Point2D.Float();
3689             }
3690         }
3691         // Copy source coords into local variables in case src == dst
3692         double x = ptSrc.getX();
3693         double y = ptSrc.getY();
3694         switch (state) {
3695         default:
3696             stateError();
3697             /* NOTREACHED */
3698             return null;
3699         case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3700         case (APPLY_SHEAR | APPLY_SCALE):
3701             ptDst.setLocation(x * m00 + y * m01, x * m10 + y * m11);
3702             return ptDst;
3703         case (APPLY_SHEAR | APPLY_TRANSLATE):
3704         case (APPLY_SHEAR):
3705             ptDst.setLocation(y * m01, x * m10);
3706             return ptDst;
3707         case (APPLY_SCALE | APPLY_TRANSLATE):
3708         case (APPLY_SCALE):
3709             ptDst.setLocation(x * m00, y * m11);
3710             return ptDst;
3711         case (APPLY_TRANSLATE):
3712         case (APPLY_IDENTITY):
3713             ptDst.setLocation(x, y);
3714             return ptDst;
3715         }
3716 
3717         /* NOTREACHED */
3718     }
3719 
3720     /**
3721      * Transforms an array of relative distance vectors by this
3722      * transform.
3723      * A relative distance vector is transformed without applying the
3724      * translation components of the affine transformation matrix
3725      * using the following equations:
3726      * <pre>
3727      *  [  x' ]   [  m00  m01 (m02) ] [  x  ]   [ m00x + m01y ]
3728      *  [  y' ] = [  m10  m11 (m12) ] [  y  ] = [ m10x + m11y ]
3729      *  [ (1) ]   [  (0)  (0) ( 1 ) ] [ (1) ]   [     (1)     ]
3730      * </pre>
3731      * The two coordinate array sections can be exactly the same or
3732      * can be overlapping sections of the same array without affecting the
3733      * validity of the results.
3734      * This method ensures that no source coordinates are
3735      * overwritten by a previous operation before they can be transformed.
3736      * The coordinates are stored in the arrays starting at the indicated
3737      * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3738      * @param srcPts the array containing the source distance vectors.
3739      * Each vector is stored as a pair of relative x,&nbsp;y coordinates.
3740      * @param dstPts the array into which the transformed distance vectors
3741      * are returned.  Each vector is stored as a pair of relative
3742      * x,&nbsp;y coordinates.
3743      * @param srcOff the offset to the first vector to be transformed
3744      * in the source array
3745      * @param dstOff the offset to the location of the first
3746      * transformed vector that is stored in the destination array
3747      * @param numPts the number of vector coordinate pairs to be
3748      * transformed
3749      * @since 1.2
3750      */
deltaTransform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, int numPts)3751     public void deltaTransform(double[] srcPts, int srcOff,
3752                                double[] dstPts, int dstOff,
3753                                int numPts) {
3754         double M00, M01, M10, M11;      // For caching
3755         if (dstPts == srcPts &&
3756             dstOff > srcOff && dstOff < srcOff + numPts * 2)
3757         {
3758             // If the arrays overlap partially with the destination higher
3759             // than the source and we transform the coordinates normally
3760             // we would overwrite some of the later source coordinates
3761             // with results of previous transformations.
3762             // To get around this we use arraycopy to copy the points
3763             // to their final destination with correct overwrite
3764             // handling and then transform them in place in the new
3765             // safer location.
3766             System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts * 2);
3767             // srcPts = dstPts;         // They are known to be equal.
3768             srcOff = dstOff;
3769         }
3770         switch (state) {
3771         default:
3772             stateError();
3773             /* NOTREACHED */
3774             return;
3775         case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3776         case (APPLY_SHEAR | APPLY_SCALE):
3777             M00 = m00; M01 = m01;
3778             M10 = m10; M11 = m11;
3779             while (--numPts >= 0) {
3780                 double x = srcPts[srcOff++];
3781                 double y = srcPts[srcOff++];
3782                 dstPts[dstOff++] = x * M00 + y * M01;
3783                 dstPts[dstOff++] = x * M10 + y * M11;
3784             }
3785             return;
3786         case (APPLY_SHEAR | APPLY_TRANSLATE):
3787         case (APPLY_SHEAR):
3788             M01 = m01; M10 = m10;
3789             while (--numPts >= 0) {
3790                 double x = srcPts[srcOff++];
3791                 dstPts[dstOff++] = srcPts[srcOff++] * M01;
3792                 dstPts[dstOff++] = x * M10;
3793             }
3794             return;
3795         case (APPLY_SCALE | APPLY_TRANSLATE):
3796         case (APPLY_SCALE):
3797             M00 = m00; M11 = m11;
3798             while (--numPts >= 0) {
3799                 dstPts[dstOff++] = srcPts[srcOff++] * M00;
3800                 dstPts[dstOff++] = srcPts[srcOff++] * M11;
3801             }
3802             return;
3803         case (APPLY_TRANSLATE):
3804         case (APPLY_IDENTITY):
3805             if (srcPts != dstPts || srcOff != dstOff) {
3806                 System.arraycopy(srcPts, srcOff, dstPts, dstOff,
3807                                  numPts * 2);
3808             }
3809             return;
3810         }
3811 
3812         /* NOTREACHED */
3813     }
3814 
3815     /**
3816      * Returns a new {@link Shape} object defined by the geometry of the
3817      * specified <code>Shape</code> after it has been transformed by
3818      * this transform.
3819      * @param pSrc the specified <code>Shape</code> object to be
3820      * transformed by this transform.
3821      * @return a new <code>Shape</code> object that defines the geometry
3822      * of the transformed <code>Shape</code>, or null if {@code pSrc} is null.
3823      * @since 1.2
3824      */
createTransformedShape(Shape pSrc)3825     public Shape createTransformedShape(Shape pSrc) {
3826         if (pSrc == null) {
3827             return null;
3828         }
3829         return new Path2D.Double(pSrc, this);
3830     }
3831 
3832     // Round values to sane precision for printing
3833     // Note that Math.sin(Math.PI) has an error of about 10^-16
_matround(double matval)3834     private static double _matround(double matval) {
3835         return Math.rint(matval * 1E15) / 1E15;
3836     }
3837 
3838     /**
3839      * Returns a <code>String</code> that represents the value of this
3840      * {@link Object}.
3841      * @return a <code>String</code> representing the value of this
3842      * <code>Object</code>.
3843      * @since 1.2
3844      */
toString()3845     public String toString() {
3846         return ("AffineTransform[["
3847                 + _matround(m00) + ", "
3848                 + _matround(m01) + ", "
3849                 + _matround(m02) + "], ["
3850                 + _matround(m10) + ", "
3851                 + _matround(m11) + ", "
3852                 + _matround(m12) + "]]");
3853     }
3854 
3855     /**
3856      * Returns <code>true</code> if this <code>AffineTransform</code> is
3857      * an identity transform.
3858      * @return <code>true</code> if this <code>AffineTransform</code> is
3859      * an identity transform; <code>false</code> otherwise.
3860      * @since 1.2
3861      */
isIdentity()3862     public boolean isIdentity() {
3863         return (state == APPLY_IDENTITY || (getType() == TYPE_IDENTITY));
3864     }
3865 
3866     /**
3867      * Returns a copy of this <code>AffineTransform</code> object.
3868      * @return an <code>Object</code> that is a copy of this
3869      * <code>AffineTransform</code> object.
3870      * @since 1.2
3871      */
clone()3872     public Object clone() {
3873         try {
3874             return super.clone();
3875         } catch (CloneNotSupportedException e) {
3876             // this shouldn't happen, since we are Cloneable
3877             throw new InternalError(e);
3878         }
3879     }
3880 
3881     /**
3882      * Returns the hashcode for this transform.
3883      * @return      a hash code for this transform.
3884      * @since 1.2
3885      */
hashCode()3886     public int hashCode() {
3887         long bits = Double.doubleToLongBits(m00);
3888         bits = bits * 31 + Double.doubleToLongBits(m01);
3889         bits = bits * 31 + Double.doubleToLongBits(m02);
3890         bits = bits * 31 + Double.doubleToLongBits(m10);
3891         bits = bits * 31 + Double.doubleToLongBits(m11);
3892         bits = bits * 31 + Double.doubleToLongBits(m12);
3893         return (((int) bits) ^ ((int) (bits >> 32)));
3894     }
3895 
3896     /**
3897      * Returns <code>true</code> if this <code>AffineTransform</code>
3898      * represents the same affine coordinate transform as the specified
3899      * argument.
3900      * @param obj the <code>Object</code> to test for equality with this
3901      * <code>AffineTransform</code>
3902      * @return <code>true</code> if <code>obj</code> equals this
3903      * <code>AffineTransform</code> object; <code>false</code> otherwise.
3904      * @since 1.2
3905      */
equals(Object obj)3906     public boolean equals(Object obj) {
3907         if (!(obj instanceof AffineTransform)) {
3908             return false;
3909         }
3910 
3911         AffineTransform a = (AffineTransform)obj;
3912 
3913         return ((m00 == a.m00) && (m01 == a.m01) && (m02 == a.m02) &&
3914                 (m10 == a.m10) && (m11 == a.m11) && (m12 == a.m12));
3915     }
3916 
3917     /* Serialization support.  A readObject method is neccessary because
3918      * the state field is part of the implementation of this particular
3919      * AffineTransform and not part of the public specification.  The
3920      * state variable's value needs to be recalculated on the fly by the
3921      * readObject method as it is in the 6-argument matrix constructor.
3922      */
3923 
3924     /*
3925      * JDK 1.2 serialVersionUID
3926      */
3927     private static final long serialVersionUID = 1330973210523860834L;
3928 
writeObject(java.io.ObjectOutputStream s)3929     private void writeObject(java.io.ObjectOutputStream s)
3930         throws java.lang.ClassNotFoundException, java.io.IOException
3931     {
3932         s.defaultWriteObject();
3933     }
3934 
readObject(java.io.ObjectInputStream s)3935     private void readObject(java.io.ObjectInputStream s)
3936         throws java.lang.ClassNotFoundException, java.io.IOException
3937     {
3938         s.defaultReadObject();
3939         updateState();
3940     }
3941 }
3942