View Javadoc
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 
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      */
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      */
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" })
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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")
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")
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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     };
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     }
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     }
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      */
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      */
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      */
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      */
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      */
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      */
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")
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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")
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")
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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")
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      */
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      */
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      */
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      */
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
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      */
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      */
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      */
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      */
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      */
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 
3929     private void writeObject(java.io.ObjectOutputStream s)
3930         throws java.lang.ClassNotFoundException, java.io.IOException
3931     {
3932         s.defaultWriteObject();
3933     }
3934 
3935     private void readObject(java.io.ObjectInputStream s)
3936         throws java.lang.ClassNotFoundException, java.io.IOException
3937     {
3938         s.defaultReadObject();
3939         updateState();
3940     }
3941 }