Save This Page
Home » openjdk-7 » java » awt » geom » [javadoc | source]
    1   /*
    2    * Copyright 1996-2006 Sun Microsystems, Inc.  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.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package java.awt.geom;
   27   
   28   import java.awt.Shape;
   29   
   30   /**
   31    * The <code>AffineTransform</code> class represents a 2D affine transform
   32    * that performs a linear mapping from 2D coordinates to other 2D
   33    * coordinates that preserves the "straightness" and
   34    * "parallelness" of lines.  Affine transformations can be constructed
   35    * using sequences of translations, scales, flips, rotations, and shears.
   36    * <p>
   37    * Such a coordinate transformation can be represented by a 3 row by
   38    * 3 column matrix with an implied last row of [ 0 0 1 ].  This matrix
   39    * transforms source coordinates {@code (x,y)} into
   40    * destination coordinates {@code (x',y')} by considering
   41    * them to be a column vector and multiplying the coordinate vector
   42    * by the matrix according to the following process:
   43    * <pre>
   44    *      [ x']   [  m00  m01  m02  ] [ x ]   [ m00x + m01y + m02 ]
   45    *      [ y'] = [  m10  m11  m12  ] [ y ] = [ m10x + m11y + m12 ]
   46    *      [ 1 ]   [   0    0    1   ] [ 1 ]   [         1         ]
   47    * </pre>
   48    * <p>
   49    * <a name="quadrantapproximation"><h4>Handling 90-Degree Rotations</h4></a>
   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       public AffineTransform(float m00, float m10,
  512                              float m01, float m11,
  513                              float m02, float m12) {
  514           this.m00 = m00;
  515           this.m10 = m10;
  516           this.m01 = m01;
  517           this.m11 = m11;
  518           this.m02 = m02;
  519           this.m12 = m12;
  520           updateState();
  521       }
  522   
  523       /**
  524        * Constructs a new <code>AffineTransform</code> from an array of
  525        * floating point values representing either the 4 non-translation
  526        * enries or the 6 specifiable entries of the 3x3 transformation
  527        * matrix.  The values are retrieved from the array as
  528        * {&nbsp;m00&nbsp;m10&nbsp;m01&nbsp;m11&nbsp;[m02&nbsp;m12]}.
  529        * @param flatmatrix the float array containing the values to be set
  530        * in the new <code>AffineTransform</code> object. The length of the
  531        * array is assumed to be at least 4. If the length of the array is
  532        * less than 6, only the first 4 values are taken. If the length of
  533        * the array is greater than 6, the first 6 values are taken.
  534        * @since 1.2
  535        */
  536       public AffineTransform(float[] flatmatrix) {
  537           m00 = flatmatrix[0];
  538           m10 = flatmatrix[1];
  539           m01 = flatmatrix[2];
  540           m11 = flatmatrix[3];
  541           if (flatmatrix.length > 5) {
  542               m02 = flatmatrix[4];
  543               m12 = flatmatrix[5];
  544           }
  545           updateState();
  546       }
  547   
  548       /**
  549        * Constructs a new <code>AffineTransform</code> from 6 double
  550        * precision values representing the 6 specifiable entries of the 3x3
  551        * transformation matrix.
  552        *
  553        * @param m00 the X coordinate scaling element of the 3x3 matrix
  554        * @param m10 the Y coordinate shearing element of the 3x3 matrix
  555        * @param m01 the X coordinate shearing element of the 3x3 matrix
  556        * @param m11 the Y coordinate scaling element of the 3x3 matrix
  557        * @param m02 the X coordinate translation element of the 3x3 matrix
  558        * @param m12 the Y coordinate translation element of the 3x3 matrix
  559        * @since 1.2
  560        */
  561       public AffineTransform(double m00, double m10,
  562                              double m01, double m11,
  563                              double m02, double m12) {
  564           this.m00 = m00;
  565           this.m10 = m10;
  566           this.m01 = m01;
  567           this.m11 = m11;
  568           this.m02 = m02;
  569           this.m12 = m12;
  570           updateState();
  571       }
  572   
  573       /**
  574        * Constructs a new <code>AffineTransform</code> from an array of
  575        * double precision values representing either the 4 non-translation
  576        * entries or the 6 specifiable entries of the 3x3 transformation
  577        * matrix. The values are retrieved from the array as
  578        * {&nbsp;m00&nbsp;m10&nbsp;m01&nbsp;m11&nbsp;[m02&nbsp;m12]}.
  579        * @param flatmatrix the double array containing the values to be set
  580        * in the new <code>AffineTransform</code> object. The length of the
  581        * array is assumed to be at least 4. If the length of the array is
  582        * less than 6, only the first 4 values are taken. If the length of
  583        * the array is greater than 6, the first 6 values are taken.
  584        * @since 1.2
  585        */
  586       public AffineTransform(double[] flatmatrix) {
  587           m00 = flatmatrix[0];
  588           m10 = flatmatrix[1];
  589           m01 = flatmatrix[2];
  590           m11 = flatmatrix[3];
  591           if (flatmatrix.length > 5) {
  592               m02 = flatmatrix[4];
  593               m12 = flatmatrix[5];
  594           }
  595           updateState();
  596       }
  597   
  598       /**
  599        * Returns a transform representing a translation transformation.
  600        * The matrix representing the returned transform is:
  601        * <pre>
  602        *          [   1    0    tx  ]
  603        *          [   0    1    ty  ]
  604        *          [   0    0    1   ]
  605        * </pre>
  606        * @param tx the distance by which coordinates are translated in the
  607        * X axis direction
  608        * @param ty the distance by which coordinates are translated in the
  609        * Y axis direction
  610        * @return an <code>AffineTransform</code> object that represents a
  611        *  translation transformation, created with the specified vector.
  612        * @since 1.2
  613        */
  614       public static AffineTransform getTranslateInstance(double tx, double ty) {
  615           AffineTransform Tx = new AffineTransform();
  616           Tx.setToTranslation(tx, ty);
  617           return Tx;
  618       }
  619   
  620       /**
  621        * Returns a transform representing a rotation transformation.
  622        * The matrix representing the returned transform is:
  623        * <pre>
  624        *          [   cos(theta)    -sin(theta)    0   ]
  625        *          [   sin(theta)     cos(theta)    0   ]
  626        *          [       0              0         1   ]
  627        * </pre>
  628        * Rotating by a positive angle theta rotates points on the positive
  629        * X axis toward the positive Y axis.
  630        * Note also the discussion of
  631        * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
  632        * above.
  633        * @param theta the angle of rotation measured in radians
  634        * @return an <code>AffineTransform</code> object that is a rotation
  635        *  transformation, created with the specified angle of rotation.
  636        * @since 1.2
  637        */
  638       public static AffineTransform getRotateInstance(double theta) {
  639           AffineTransform Tx = new AffineTransform();
  640           Tx.setToRotation(theta);
  641           return Tx;
  642       }
  643   
  644       /**
  645        * Returns a transform that rotates coordinates around an anchor point.
  646        * This operation is equivalent to translating the coordinates so
  647        * that the anchor point is at the origin (S1), then rotating them
  648        * about the new origin (S2), and finally translating so that the
  649        * intermediate origin is restored to the coordinates of the original
  650        * anchor point (S3).
  651        * <p>
  652        * This operation is equivalent to the following sequence of calls:
  653        * <pre>
  654        *     AffineTransform Tx = new AffineTransform();
  655        *     Tx.translate(anchorx, anchory);    // S3: final translation
  656        *     Tx.rotate(theta);                  // S2: rotate around anchor
  657        *     Tx.translate(-anchorx, -anchory);  // S1: translate anchor to origin
  658        * </pre>
  659        * The matrix representing the returned transform is:
  660        * <pre>
  661        *          [   cos(theta)    -sin(theta)    x-x*cos+y*sin  ]
  662        *          [   sin(theta)     cos(theta)    y-x*sin-y*cos  ]
  663        *          [       0              0               1        ]
  664        * </pre>
  665        * Rotating by a positive angle theta rotates points on the positive
  666        * X axis toward the positive Y axis.
  667        * Note also the discussion of
  668        * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
  669        * above.
  670        *
  671        * @param theta the angle of rotation measured in radians
  672        * @param anchorx the X coordinate of the rotation anchor point
  673        * @param anchory the Y coordinate of the rotation anchor point
  674        * @return an <code>AffineTransform</code> object that rotates
  675        *  coordinates around the specified point by the specified angle of
  676        *  rotation.
  677        * @since 1.2
  678        */
  679       public static AffineTransform getRotateInstance(double theta,
  680                                                       double anchorx,
  681                                                       double anchory)
  682       {
  683           AffineTransform Tx = new AffineTransform();
  684           Tx.setToRotation(theta, anchorx, anchory);
  685           return Tx;
  686       }
  687   
  688       /**
  689        * Returns a transform that rotates coordinates according to
  690        * a rotation vector.
  691        * All coordinates rotate about the origin by the same amount.
  692        * The amount of rotation is such that coordinates along the former
  693        * positive X axis will subsequently align with the vector pointing
  694        * from the origin to the specified vector coordinates.
  695        * If both <code>vecx</code> and <code>vecy</code> are 0.0,
  696        * an identity transform is returned.
  697        * This operation is equivalent to calling:
  698        * <pre>
  699        *     AffineTransform.getRotateInstance(Math.atan2(vecy, vecx));
  700        * </pre>
  701        *
  702        * @param vecx the X coordinate of the rotation vector
  703        * @param vecy the Y coordinate of the rotation vector
  704        * @return an <code>AffineTransform</code> object that rotates
  705        *  coordinates according to the specified rotation vector.
  706        * @since 1.6
  707        */
  708       public static AffineTransform getRotateInstance(double vecx, double vecy) {
  709           AffineTransform Tx = new AffineTransform();
  710           Tx.setToRotation(vecx, vecy);
  711           return Tx;
  712       }
  713   
  714       /**
  715        * Returns a transform that rotates coordinates around an anchor
  716        * point accordinate to a rotation vector.
  717        * All coordinates rotate about the specified anchor coordinates
  718        * by the same amount.
  719        * The amount of rotation is such that coordinates along the former
  720        * positive X axis will subsequently align with the vector pointing
  721        * from the origin to the specified vector coordinates.
  722        * If both <code>vecx</code> and <code>vecy</code> are 0.0,
  723        * an identity transform is returned.
  724        * This operation is equivalent to calling:
  725        * <pre>
  726        *     AffineTransform.getRotateInstance(Math.atan2(vecy, vecx),
  727        *                                       anchorx, anchory);
  728        * </pre>
  729        *
  730        * @param vecx the X coordinate of the rotation vector
  731        * @param vecy the Y coordinate of the rotation vector
  732        * @param anchorx the X coordinate of the rotation anchor point
  733        * @param anchory the Y coordinate of the rotation anchor point
  734        * @return an <code>AffineTransform</code> object that rotates
  735        *  coordinates around the specified point according to the
  736        *  specified rotation vector.
  737        * @since 1.6
  738        */
  739       public static AffineTransform getRotateInstance(double vecx,
  740                                                       double vecy,
  741                                                       double anchorx,
  742                                                       double anchory)
  743       {
  744           AffineTransform Tx = new AffineTransform();
  745           Tx.setToRotation(vecx, vecy, anchorx, anchory);
  746           return Tx;
  747       }
  748   
  749       /**
  750        * Returns a transform that rotates coordinates by the specified
  751        * number of quadrants.
  752        * This operation is equivalent to calling:
  753        * <pre>
  754        *     AffineTransform.getRotateInstance(numquadrants * Math.PI / 2.0);
  755        * </pre>
  756        * Rotating by a positive number of quadrants rotates points on
  757        * the positive X axis toward the positive Y axis.
  758        * @param numquadrants the number of 90 degree arcs to rotate by
  759        * @return an <code>AffineTransform</code> object that rotates
  760        *  coordinates by the specified number of quadrants.
  761        * @since 1.6
  762        */
  763       public static AffineTransform getQuadrantRotateInstance(int numquadrants) {
  764           AffineTransform Tx = new AffineTransform();
  765           Tx.setToQuadrantRotation(numquadrants);
  766           return Tx;
  767       }
  768   
  769       /**
  770        * Returns a transform that rotates coordinates by the specified
  771        * number of quadrants around the specified anchor point.
  772        * This operation is equivalent to calling:
  773        * <pre>
  774        *     AffineTransform.getRotateInstance(numquadrants * Math.PI / 2.0,
  775        *                                       anchorx, anchory);
  776        * </pre>
  777        * Rotating by a positive number of quadrants rotates points on
  778        * the positive X axis toward the positive Y axis.
  779        *
  780        * @param numquadrants the number of 90 degree arcs to rotate by
  781        * @param anchorx the X coordinate of the rotation anchor point
  782        * @param anchory the Y coordinate of the rotation anchor point
  783        * @return an <code>AffineTransform</code> object that rotates
  784        *  coordinates by the specified number of quadrants around the
  785        *  specified anchor point.
  786        * @since 1.6
  787        */
  788       public static AffineTransform getQuadrantRotateInstance(int numquadrants,
  789                                                               double anchorx,
  790                                                               double anchory)
  791       {
  792           AffineTransform Tx = new AffineTransform();
  793           Tx.setToQuadrantRotation(numquadrants, anchorx, anchory);
  794           return Tx;
  795       }
  796   
  797       /**
  798        * Returns a transform representing a scaling transformation.
  799        * The matrix representing the returned transform is:
  800        * <pre>
  801        *          [   sx   0    0   ]
  802        *          [   0    sy   0   ]
  803        *          [   0    0    1   ]
  804        * </pre>
  805        * @param sx the factor by which coordinates are scaled along the
  806        * X axis direction
  807        * @param sy the factor by which coordinates are scaled along the
  808        * Y axis direction
  809        * @return an <code>AffineTransform</code> object that scales
  810        *  coordinates by the specified factors.
  811        * @since 1.2
  812        */
  813       public static AffineTransform getScaleInstance(double sx, double sy) {
  814           AffineTransform Tx = new AffineTransform();
  815           Tx.setToScale(sx, sy);
  816           return Tx;
  817       }
  818   
  819       /**
  820        * Returns a transform representing a shearing transformation.
  821        * The matrix representing the returned transform is:
  822        * <pre>
  823        *          [   1   shx   0   ]
  824        *          [  shy   1    0   ]
  825        *          [   0    0    1   ]
  826        * </pre>
  827        * @param shx the multiplier by which coordinates are shifted in the
  828        * direction of the positive X axis as a factor of their Y coordinate
  829        * @param shy the multiplier by which coordinates are shifted in the
  830        * direction of the positive Y axis as a factor of their X coordinate
  831        * @return an <code>AffineTransform</code> object that shears
  832        *  coordinates by the specified multipliers.
  833        * @since 1.2
  834        */
  835       public static AffineTransform getShearInstance(double shx, double shy) {
  836           AffineTransform Tx = new AffineTransform();
  837           Tx.setToShear(shx, shy);
  838           return Tx;
  839       }
  840   
  841       /**
  842        * Retrieves the flag bits describing the conversion properties of
  843        * this transform.
  844        * The return value is either one of the constants TYPE_IDENTITY
  845        * or TYPE_GENERAL_TRANSFORM, or a combination of the
  846        * appriopriate flag bits.
  847        * A valid combination of flag bits is an exclusive OR operation
  848        * that can combine
  849        * the TYPE_TRANSLATION flag bit
  850        * in addition to either of the
  851        * TYPE_UNIFORM_SCALE or TYPE_GENERAL_SCALE flag bits
  852        * as well as either of the
  853        * TYPE_QUADRANT_ROTATION or TYPE_GENERAL_ROTATION flag bits.
  854        * @return the OR combination of any of the indicated flags that
  855        * apply to this transform
  856        * @see #TYPE_IDENTITY
  857        * @see #TYPE_TRANSLATION
  858        * @see #TYPE_UNIFORM_SCALE
  859        * @see #TYPE_GENERAL_SCALE
  860        * @see #TYPE_QUADRANT_ROTATION
  861        * @see #TYPE_GENERAL_ROTATION
  862        * @see #TYPE_GENERAL_TRANSFORM
  863        * @since 1.2
  864        */
  865       public int getType() {
  866           if (type == TYPE_UNKNOWN) {
  867               calculateType();
  868           }
  869           return type;
  870       }
  871   
  872       /**
  873        * This is the utility function to calculate the flag bits when
  874        * they have not been cached.
  875        * @see #getType
  876        */
  877       private void calculateType() {
  878           int ret = TYPE_IDENTITY;
  879           boolean sgn0, sgn1;
  880           double M0, M1, M2, M3;
  881           updateState();
  882           switch (state) {
  883           default:
  884               stateError();
  885               /* NOTREACHED */
  886           case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
  887               ret = TYPE_TRANSLATION;
  888               /* NOBREAK */
  889           case (APPLY_SHEAR | APPLY_SCALE):
  890               if ((M0 = m00) * (M2 = m01) + (M3 = m10) * (M1 = m11) != 0) {
  891                   // Transformed unit vectors are not perpendicular...
  892                   this.type = TYPE_GENERAL_TRANSFORM;
  893                   return;
  894               }
  895               sgn0 = (M0 >= 0.0);
  896               sgn1 = (M1 >= 0.0);
  897               if (sgn0 == sgn1) {
  898                   // sgn(M0) == sgn(M1) therefore sgn(M2) == -sgn(M3)
  899                   // This is the "unflipped" (right-handed) state
  900                   if (M0 != M1 || M2 != -M3) {
  901                       ret |= (TYPE_GENERAL_ROTATION | TYPE_GENERAL_SCALE);
  902                   } else if (M0 * M1 - M2 * M3 != 1.0) {
  903                       ret |= (TYPE_GENERAL_ROTATION | TYPE_UNIFORM_SCALE);
  904                   } else {
  905                       ret |= TYPE_GENERAL_ROTATION;
  906                   }
  907               } else {
  908                   // sgn(M0) == -sgn(M1) therefore sgn(M2) == sgn(M3)
  909                   // This is the "flipped" (left-handed) state
  910                   if (M0 != -M1 || M2 != M3) {
  911                       ret |= (TYPE_GENERAL_ROTATION |
  912                               TYPE_FLIP |
  913                               TYPE_GENERAL_SCALE);
  914                   } else if (M0 * M1 - M2 * M3 != 1.0) {
  915                       ret |= (TYPE_GENERAL_ROTATION |
  916                               TYPE_FLIP |
  917                               TYPE_UNIFORM_SCALE);
  918                   } else {
  919                       ret |= (TYPE_GENERAL_ROTATION | TYPE_FLIP);
  920                   }
  921               }
  922               break;
  923           case (APPLY_SHEAR | APPLY_TRANSLATE):
  924               ret = TYPE_TRANSLATION;
  925               /* NOBREAK */
  926           case (APPLY_SHEAR):
  927               sgn0 = ((M0 = m01) >= 0.0);
  928               sgn1 = ((M1 = m10) >= 0.0);
  929               if (sgn0 != sgn1) {
  930                   // Different signs - simple 90 degree rotation
  931                   if (M0 != -M1) {
  932                       ret |= (TYPE_QUADRANT_ROTATION | TYPE_GENERAL_SCALE);
  933                   } else if (M0 != 1.0 && M0 != -1.0) {
  934                       ret |= (TYPE_QUADRANT_ROTATION | TYPE_UNIFORM_SCALE);
  935                   } else {
  936                       ret |= TYPE_QUADRANT_ROTATION;
  937                   }
  938               } else {
  939                   // Same signs - 90 degree rotation plus an axis flip too
  940                   if (M0 == M1) {
  941                       ret |= (TYPE_QUADRANT_ROTATION |
  942                               TYPE_FLIP |
  943                               TYPE_UNIFORM_SCALE);
  944                   } else {
  945                       ret |= (TYPE_QUADRANT_ROTATION |
  946                               TYPE_FLIP |
  947                               TYPE_GENERAL_SCALE);
  948                   }
  949               }
  950               break;
  951           case (APPLY_SCALE | APPLY_TRANSLATE):
  952               ret = TYPE_TRANSLATION;
  953               /* NOBREAK */
  954           case (APPLY_SCALE):
  955               sgn0 = ((M0 = m00) >= 0.0);
  956               sgn1 = ((M1 = m11) >= 0.0);
  957               if (sgn0 == sgn1) {
  958                   if (sgn0) {
  959                       // Both scaling factors non-negative - simple scale
  960                       // Note: APPLY_SCALE implies M0, M1 are not both 1
  961                       if (M0 == M1) {
  962                           ret |= TYPE_UNIFORM_SCALE;
  963                       } else {
  964                           ret |= TYPE_GENERAL_SCALE;
  965                       }
  966                   } else {
  967                       // Both scaling factors negative - 180 degree rotation
  968                       if (M0 != M1) {
  969                           ret |= (TYPE_QUADRANT_ROTATION | TYPE_GENERAL_SCALE);
  970                       } else if (M0 != -1.0) {
  971                           ret |= (TYPE_QUADRANT_ROTATION | TYPE_UNIFORM_SCALE);
  972                       } else {
  973                           ret |= TYPE_QUADRANT_ROTATION;
  974                       }
  975                   }
  976               } else {
  977                   // Scaling factor signs different - flip about some axis
  978                   if (M0 == -M1) {
  979                       if (M0 == 1.0 || M0 == -1.0) {
  980                           ret |= TYPE_FLIP;
  981                       } else {
  982                           ret |= (TYPE_FLIP | TYPE_UNIFORM_SCALE);
  983                       }
  984                   } else {
  985                       ret |= (TYPE_FLIP | TYPE_GENERAL_SCALE);
  986                   }
  987               }
  988               break;
  989           case (APPLY_TRANSLATE):
  990               ret = TYPE_TRANSLATION;
  991               break;
  992           case (APPLY_IDENTITY):
  993               break;
  994           }
  995           this.type = ret;
  996       }
  997   
  998       /**
  999        * Returns the determinant of the matrix representation of the transform.
 1000        * The determinant is useful both to determine if the transform can
 1001        * be inverted and to get a single value representing the
 1002        * combined X and Y scaling of the transform.
 1003        * <p>
 1004        * If the determinant is non-zero, then this transform is
 1005        * invertible and the various methods that depend on the inverse
 1006        * transform do not need to throw a
 1007        * {@link NoninvertibleTransformException}.
 1008        * If the determinant is zero then this transform can not be
 1009        * inverted since the transform maps all input coordinates onto
 1010        * a line or a point.
 1011        * If the determinant is near enough to zero then inverse transform
 1012        * operations might not carry enough precision to produce meaningful
 1013        * results.
 1014        * <p>
 1015        * If this transform represents a uniform scale, as indicated by
 1016        * the <code>getType</code> method then the determinant also
 1017        * represents the square of the uniform scale factor by which all of
 1018        * the points are expanded from or contracted towards the origin.
 1019        * If this transform represents a non-uniform scale or more general
 1020        * transform then the determinant is not likely to represent a
 1021        * value useful for any purpose other than determining if inverse
 1022        * transforms are possible.
 1023        * <p>
 1024        * Mathematically, the determinant is calculated using the formula:
 1025        * <pre>
 1026        *          |  m00  m01  m02  |
 1027        *          |  m10  m11  m12  |  =  m00 * m11 - m01 * m10
 1028        *          |   0    0    1   |
 1029        * </pre>
 1030        *
 1031        * @return the determinant of the matrix used to transform the
 1032        * coordinates.
 1033        * @see #getType
 1034        * @see #createInverse
 1035        * @see #inverseTransform
 1036        * @see #TYPE_UNIFORM_SCALE
 1037        * @since 1.2
 1038        */
 1039       public double getDeterminant() {
 1040           switch (state) {
 1041           default:
 1042               stateError();
 1043               /* NOTREACHED */
 1044           case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
 1045           case (APPLY_SHEAR | APPLY_SCALE):
 1046               return m00 * m11 - m01 * m10;
 1047           case (APPLY_SHEAR | APPLY_TRANSLATE):
 1048           case (APPLY_SHEAR):
 1049               return -(m01 * m10);
 1050           case (APPLY_SCALE | APPLY_TRANSLATE):
 1051           case (APPLY_SCALE):
 1052               return m00 * m11;
 1053           case (APPLY_TRANSLATE):
 1054           case (APPLY_IDENTITY):
 1055               return 1.0;
 1056           }
 1057       }
 1058   
 1059       /**
 1060        * Manually recalculates the state of the transform when the matrix
 1061        * changes too much to predict the effects on the state.
 1062        * The following table specifies what the various settings of the
 1063        * state field say about the values of the corresponding matrix
 1064        * element fields.
 1065        * Note that the rules governing the SCALE fields are slightly
 1066        * different depending on whether the SHEAR flag is also set.
 1067        * <pre>
 1068        *                     SCALE            SHEAR          TRANSLATE
 1069        *                    m00/m11          m01/m10          m02/m12
 1070        *
 1071        * IDENTITY             1.0              0.0              0.0
 1072        * TRANSLATE (TR)       1.0              0.0          not both 0.0
 1073        * SCALE (SC)       not both 1.0         0.0              0.0
 1074        * TR | SC          not both 1.0         0.0          not both 0.0
 1075        * SHEAR (SH)           0.0          not both 0.0         0.0
 1076        * TR | SH              0.0          not both 0.0     not both 0.0
 1077        * SC | SH          not both 0.0     not both 0.0         0.0
 1078        * TR | SC | SH     not both 0.0     not both 0.0     not both 0.0
 1079        * </pre>
 1080        */
 1081       void updateState() {
 1082           if (m01 == 0.0 && m10 == 0.0) {
 1083               if (m00 == 1.0 && m11 == 1.0) {
 1084                   if (m02 == 0.0 && m12 == 0.0) {
 1085                       state = APPLY_IDENTITY;
 1086                       type = TYPE_IDENTITY;
 1087                   } else {
 1088                       state = APPLY_TRANSLATE;
 1089                       type = TYPE_TRANSLATION;
 1090                   }
 1091               } else {
 1092                   if (m02 == 0.0 && m12 == 0.0) {
 1093                       state = APPLY_SCALE;
 1094                       type = TYPE_UNKNOWN;
 1095                   } else {
 1096                       state = (APPLY_SCALE | APPLY_TRANSLATE);
 1097                       type = TYPE_UNKNOWN;
 1098                   }
 1099               }
 1100           } else {
 1101               if (m00 == 0.0 && m11 == 0.0) {
 1102                   if (m02 == 0.0 && m12 == 0.0) {
 1103                       state = APPLY_SHEAR;
 1104                       type = TYPE_UNKNOWN;
 1105                   } else {
 1106                       state = (APPLY_SHEAR | APPLY_TRANSLATE);
 1107                       type = TYPE_UNKNOWN;
 1108                   }
 1109               } else {
 1110                   if (m02 == 0.0 && m12 == 0.0) {
 1111                       state = (APPLY_SHEAR | APPLY_SCALE);
 1112                       type = TYPE_UNKNOWN;
 1113                   } else {
 1114                       state = (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE);
 1115                       type = TYPE_UNKNOWN;
 1116                   }
 1117               }
 1118           }
 1119       }
 1120   
 1121       /*
 1122        * Convenience method used internally to throw exceptions when
 1123        * a case was forgotten in a switch statement.
 1124        */
 1125       private void stateError() {
 1126           throw new InternalError("missing case in transform state switch");
 1127       }
 1128   
 1129       /**
 1130        * Retrieves the 6 specifiable values in the 3x3 affine transformation
 1131        * matrix and places them into an array of double precisions values.
 1132        * The values are stored in the array as
 1133        * {&nbsp;m00&nbsp;m10&nbsp;m01&nbsp;m11&nbsp;m02&nbsp;m12&nbsp;}.
 1134        * An array of 4 doubles can also be specified, in which case only the
 1135        * first four elements representing the non-transform
 1136        * parts of the array are retrieved and the values are stored into
 1137        * the array as {&nbsp;m00&nbsp;m10&nbsp;m01&nbsp;m11&nbsp;}
 1138        * @param flatmatrix the double array used to store the returned
 1139        * values.
 1140        * @see #getScaleX
 1141        * @see #getScaleY
 1142        * @see #getShearX
 1143        * @see #getShearY
 1144        * @see #getTranslateX
 1145        * @see #getTranslateY
 1146        * @since 1.2
 1147        */
 1148       public void getMatrix(double[] flatmatrix) {
 1149           flatmatrix[0] = m00;
 1150           flatmatrix[1] = m10;
 1151           flatmatrix[2] = m01;
 1152           flatmatrix[3] = m11;
 1153           if (flatmatrix.length > 5) {
 1154               flatmatrix[4] = m02;
 1155               flatmatrix[5] = m12;
 1156           }
 1157       }
 1158   
 1159       /**
 1160        * Returns the X coordinate scaling element (m00) of the 3x3
 1161        * affine transformation matrix.
 1162        * @return a double value that is the X coordinate of the scaling
 1163        *  element of the affine transformation matrix.
 1164        * @see #getMatrix
 1165        * @since 1.2
 1166        */
 1167       public double getScaleX() {
 1168           return m00;
 1169       }
 1170   
 1171       /**
 1172        * Returns the Y coordinate scaling element (m11) of the 3x3
 1173        * affine transformation matrix.
 1174        * @return a double value that is the Y coordinate of the scaling
 1175        *  element of the affine transformation matrix.
 1176        * @see #getMatrix
 1177        * @since 1.2
 1178        */
 1179       public double getScaleY() {
 1180           return m11;
 1181       }
 1182   
 1183       /**
 1184        * Returns the X coordinate shearing element (m01) of the 3x3
 1185        * affine transformation matrix.
 1186        * @return a double value that is the X coordinate of the shearing
 1187        *  element of the affine transformation matrix.
 1188        * @see #getMatrix
 1189        * @since 1.2
 1190        */
 1191       public double getShearX() {
 1192           return m01;
 1193       }
 1194   
 1195       /**
 1196        * Returns the Y coordinate shearing element (m10) of the 3x3
 1197        * affine transformation matrix.
 1198        * @return a double value that is the Y coordinate of the shearing
 1199        *  element of the affine transformation matrix.
 1200        * @see #getMatrix
 1201        * @since 1.2
 1202        */
 1203       public double getShearY() {
 1204           return m10;
 1205       }
 1206   
 1207       /**
 1208        * Returns the X coordinate of the translation element (m02) of the
 1209        * 3x3 affine transformation matrix.
 1210        * @return a double value that is the X coordinate of the translation
 1211        *  element of the affine transformation matrix.
 1212        * @see #getMatrix
 1213        * @since 1.2
 1214        */
 1215       public double getTranslateX() {
 1216           return m02;
 1217       }
 1218   
 1219       /**
 1220        * Returns the Y coordinate of the translation element (m12) of the
 1221        * 3x3 affine transformation matrix.
 1222        * @return a double value that is the Y coordinate of the translation
 1223        *  element of the affine transformation matrix.
 1224        * @see #getMatrix
 1225        * @since 1.2
 1226        */
 1227       public double getTranslateY() {
 1228           return m12;
 1229       }
 1230   
 1231       /**
 1232        * Concatenates this transform with a translation transformation.
 1233        * This is equivalent to calling concatenate(T), where T is an
 1234        * <code>AffineTransform</code> represented by the following matrix:
 1235        * <pre>
 1236        *          [   1    0    tx  ]
 1237        *          [   0    1    ty  ]
 1238        *          [   0    0    1   ]
 1239        * </pre>
 1240        * @param tx the distance by which coordinates are translated in the
 1241        * X axis direction
 1242        * @param ty the distance by which coordinates are translated in the
 1243        * Y axis direction
 1244        * @since 1.2
 1245        */
 1246       public void translate(double tx, double ty) {
 1247           switch (state) {
 1248           default:
 1249               stateError();
 1250               /* NOTREACHED */
 1251           case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
 1252               m02 = tx * m00 + ty * m01 + m02;
 1253               m12 = tx * m10 + ty * m11 + m12;
 1254               if (m02 == 0.0 && m12 == 0.0) {
 1255                   state = APPLY_SHEAR | APPLY_SCALE;
 1256                   if (type != TYPE_UNKNOWN) {
 1257                       type -= TYPE_TRANSLATION;
 1258                   }
 1259               }
 1260               return;
 1261           case (APPLY_SHEAR | APPLY_SCALE):
 1262               m02 = tx * m00 + ty * m01;
 1263               m12 = tx * m10 + ty * m11;
 1264               if (m02 != 0.0 || m12 != 0.0) {
 1265                   state = APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE;
 1266                   type |= TYPE_TRANSLATION;
 1267               }
 1268               return;
 1269           case (APPLY_SHEAR | APPLY_TRANSLATE):
 1270               m02 = ty * m01 + m02;
 1271               m12 = tx * m10 + m12;
 1272               if (m02 == 0.0 && m12 == 0.0) {
 1273                   state = APPLY_SHEAR;
 1274                   if (type != TYPE_UNKNOWN) {
 1275                       type -= TYPE_TRANSLATION;
 1276                   }
 1277               }
 1278               return;
 1279           case (APPLY_SHEAR):
 1280               m02 = ty * m01;
 1281               m12 = tx * m10;
 1282               if (m02 != 0.0 || m12 != 0.0) {
 1283                   state = APPLY_SHEAR | APPLY_TRANSLATE;
 1284                   type |= TYPE_TRANSLATION;
 1285               }
 1286               return;
 1287           case (APPLY_SCALE | APPLY_TRANSLATE):
 1288               m02 = tx * m00 + m02;
 1289               m12 = ty * m11 + m12;
 1290               if (m02 == 0.0 && m12 == 0.0) {
 1291                   state = APPLY_SCALE;
 1292                   if (type != TYPE_UNKNOWN) {
 1293                       type -= TYPE_TRANSLATION;
 1294                   }
 1295               }
 1296               return;
 1297           case (APPLY_SCALE):
 1298               m02 = tx * m00;
 1299               m12 = ty * m11;
 1300               if (m02 != 0.0 || m12 != 0.0) {
 1301                   state = APPLY_SCALE | APPLY_TRANSLATE;
 1302                   type |= TYPE_TRANSLATION;
 1303               }
 1304               return;
 1305           case (APPLY_TRANSLATE):
 1306               m02 = tx + m02;
 1307               m12 = ty + m12;
 1308               if (m02 == 0.0 && m12 == 0.0) {
 1309                   state = APPLY_IDENTITY;
 1310                   type = TYPE_IDENTITY;
 1311               }
 1312               return;
 1313           case (APPLY_IDENTITY):
 1314               m02 = tx;
 1315               m12 = ty;
 1316               if (tx != 0.0 || ty != 0.0) {
 1317                   state = APPLY_TRANSLATE;
 1318                   type = TYPE_TRANSLATION;
 1319               }
 1320               return;
 1321           }
 1322       }
 1323   
 1324       // Utility methods to optimize rotate methods.
 1325       // These tables translate the flags during predictable quadrant
 1326       // rotations where the shear and scale values are swapped and negated.
 1327       private static final int rot90conversion[] = {
 1328           /* IDENTITY => */        APPLY_SHEAR,
 1329           /* TRANSLATE (TR) => */  APPLY_SHEAR | APPLY_TRANSLATE,
 1330           /* SCALE (SC) => */      APPLY_SHEAR,
 1331           /* SC | TR => */         APPLY_SHEAR | APPLY_TRANSLATE,
 1332           /* SHEAR (SH) => */      APPLY_SCALE,
 1333           /* SH | TR => */         APPLY_SCALE | APPLY_TRANSLATE,
 1334           /* SH | SC => */         APPLY_SHEAR | APPLY_SCALE,
 1335           /* SH | SC | TR => */    APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE,
 1336       };
 1337       private final void rotate90() {
 1338           double M0 = m00;
 1339           m00 = m01;
 1340           m01 = -M0;
 1341           M0 = m10;
 1342           m10 = m11;
 1343           m11 = -M0;
 1344           int state = rot90conversion[this.state];
 1345           if ((state & (APPLY_SHEAR | APPLY_SCALE)) == APPLY_SCALE &&
 1346               m00 == 1.0 && m11 == 1.0)
 1347           {
 1348               state -= APPLY_SCALE;
 1349           }
 1350           this.state = state;
 1351           type = TYPE_UNKNOWN;
 1352       }
 1353       private final void rotate180() {
 1354           m00 = -m00;
 1355           m11 = -m11;
 1356           int state = this.state;
 1357           if ((state & (APPLY_SHEAR)) != 0) {
 1358               // If there was a shear, then this rotation has no
 1359               // effect on the state.
 1360               m01 = -m01;
 1361               m10 = -m10;
 1362           } else {
 1363               // No shear means the SCALE state may toggle when
 1364               // m00 and m11 are negated.
 1365               if (m00 == 1.0 && m11 == 1.0) {
 1366                   this.state = state & ~APPLY_SCALE;
 1367               } else {
 1368                   this.state = state | APPLY_SCALE;
 1369               }
 1370           }
 1371           type = TYPE_UNKNOWN;
 1372       }
 1373       private final void rotate270() {
 1374           double M0 = m00;
 1375           m00 = -m01;
 1376           m01 = M0;
 1377           M0 = m10;
 1378           m10 = -m11;
 1379           m11 = M0;
 1380           int state = rot90conversion[this.state];
 1381           if ((state & (APPLY_SHEAR | APPLY_SCALE)) == APPLY_SCALE &&
 1382               m00 == 1.0 && m11 == 1.0)
 1383           {
 1384               state -= APPLY_SCALE;
 1385           }
 1386           this.state = state;
 1387           type = TYPE_UNKNOWN;
 1388       }
 1389   
 1390       /**
 1391        * Concatenates this transform with a rotation transformation.
 1392        * This is equivalent to calling concatenate(R), where R is an
 1393        * <code>AffineTransform</code> represented by the following matrix:
 1394        * <pre>
 1395        *          [   cos(theta)    -sin(theta)    0   ]
 1396        *          [   sin(theta)     cos(theta)    0   ]
 1397        *          [       0              0         1   ]
 1398        * </pre>
 1399        * Rotating by a positive angle theta rotates points on the positive
 1400        * X axis toward the positive Y axis.
 1401        * Note also the discussion of
 1402        * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
 1403        * above.
 1404        * @param theta the angle of rotation measured in radians
 1405        * @since 1.2
 1406        */
 1407       public void rotate(double theta) {
 1408           double sin = Math.sin(theta);
 1409           if (sin == 1.0) {
 1410               rotate90();
 1411           } else if (sin == -1.0) {
 1412               rotate270();
 1413           } else {
 1414               double cos = Math.cos(theta);
 1415               if (cos == -1.0) {
 1416                   rotate180();
 1417               } else if (cos != 1.0) {
 1418                   double M0, M1;
 1419                   M0 = m00;
 1420                   M1 = m01;
 1421                   m00 =  cos * M0 + sin * M1;
 1422                   m01 = -sin * M0 + cos * M1;
 1423                   M0 = m10;
 1424                   M1 = m11;
 1425                   m10 =  cos * M0 + sin * M1;
 1426                   m11 = -sin * M0 + cos * M1;
 1427                   updateState();
 1428               }
 1429           }
 1430       }
 1431   
 1432       /**
 1433        * Concatenates this transform with a transform that rotates
 1434        * coordinates around an anchor point.
 1435        * This operation is equivalent to translating the coordinates so
 1436        * that the anchor point is at the origin (S1), then rotating them
 1437        * about the new origin (S2), and finally translating so that the
 1438        * intermediate origin is restored to the coordinates of the original
 1439        * anchor point (S3).
 1440        * <p>
 1441        * This operation is equivalent to the following sequence of calls:
 1442        * <pre>
 1443        *     translate(anchorx, anchory);      // S3: final translation
 1444        *     rotate(theta);                    // S2: rotate around anchor
 1445        *     translate(-anchorx, -anchory);    // S1: translate anchor to origin
 1446        * </pre>
 1447        * Rotating by a positive angle theta rotates points on the positive
 1448        * X axis toward the positive Y axis.
 1449        * Note also the discussion of
 1450        * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
 1451        * above.
 1452        *
 1453        * @param theta the angle of rotation measured in radians
 1454        * @param anchorx the X coordinate of the rotation anchor point
 1455        * @param anchory the Y coordinate of the rotation anchor point
 1456        * @since 1.2
 1457        */
 1458       public void rotate(double theta, double anchorx, double anchory) {
 1459           // REMIND: Simple for now - optimize later
 1460           translate(anchorx, anchory);
 1461           rotate(theta);
 1462           translate(-anchorx, -anchory);
 1463       }
 1464   
 1465       /**
 1466        * Concatenates this transform with a transform that rotates
 1467        * coordinates according to a rotation vector.
 1468        * All coordinates rotate about the origin by the same amount.
 1469        * The amount of rotation is such that coordinates along the former
 1470        * positive X axis will subsequently align with the vector pointing
 1471        * from the origin to the specified vector coordinates.
 1472        * If both <code>vecx</code> and <code>vecy</code> are 0.0,
 1473        * no additional rotation is added to this transform.
 1474        * This operation is equivalent to calling:
 1475        * <pre>
 1476        *          rotate(Math.atan2(vecy, vecx));
 1477        * </pre>
 1478        *
 1479        * @param vecx the X coordinate of the rotation vector
 1480        * @param vecy the Y coordinate of the rotation vector
 1481        * @since 1.6
 1482        */
 1483       public void rotate(double vecx, double vecy) {
 1484           if (vecy == 0.0) {
 1485               if (vecx < 0.0) {
 1486                   rotate180();
 1487               }
 1488               // If vecx > 0.0 - no rotation
 1489               // If vecx == 0.0 - undefined rotation - treat as no rotation
 1490           } else if (vecx == 0.0) {
 1491               if (vecy > 0.0) {
 1492                   rotate90();
 1493               } else {  // vecy must be < 0.0
 1494                   rotate270();
 1495               }
 1496           } else {
 1497               double len = Math.sqrt(vecx * vecx + vecy * vecy);
 1498               double sin = vecy / len;
 1499               double cos = vecx / len;
 1500               double M0, M1;
 1501               M0 = m00;
 1502               M1 = m01;
 1503               m00 =  cos * M0 + sin * M1;
 1504               m01 = -sin * M0 + cos * M1;
 1505               M0 = m10;
 1506               M1 = m11;
 1507               m10 =  cos * M0 + sin * M1;
 1508               m11 = -sin * M0 + cos * M1;
 1509               updateState();
 1510           }
 1511       }
 1512   
 1513       /**
 1514        * Concatenates this transform with a transform that rotates
 1515        * coordinates around an anchor point according to a rotation
 1516        * vector.
 1517        * All coordinates rotate about the specified anchor coordinates
 1518        * by the same amount.
 1519        * The amount of rotation is such that coordinates along the former
 1520        * positive X axis will subsequently align with the vector pointing
 1521        * from the origin to the specified vector coordinates.
 1522        * If both <code>vecx</code> and <code>vecy</code> are 0.0,
 1523        * the transform is not modified in any way.
 1524        * This method is equivalent to calling:
 1525        * <pre>
 1526        *     rotate(Math.atan2(vecy, vecx), anchorx, anchory);
 1527        * </pre>
 1528        *
 1529        * @param vecx the X coordinate of the rotation vector
 1530        * @param vecy the Y coordinate of the rotation vector
 1531        * @param anchorx the X coordinate of the rotation anchor point
 1532        * @param anchory the Y coordinate of the rotation anchor point
 1533        * @since 1.6
 1534        */
 1535       public void rotate(double vecx, double vecy,
 1536                          double anchorx, double anchory)
 1537       {
 1538           // REMIND: Simple for now - optimize later
 1539           translate(anchorx, anchory);
 1540           rotate(vecx, vecy);
 1541           translate(-anchorx, -anchory);
 1542       }
 1543   
 1544       /**
 1545        * Concatenates this transform with a transform that rotates
 1546        * coordinates by the specified number of quadrants.
 1547        * This is equivalent to calling:
 1548        * <pre>
 1549        *     rotate(numquadrants * Math.PI / 2.0);
 1550        * </pre>
 1551        * Rotating by a positive number of quadrants rotates points on
 1552        * the positive X axis toward the positive Y axis.
 1553        * @param numquadrants the number of 90 degree arcs to rotate by
 1554        * @since 1.6
 1555        */
 1556       public void quadrantRotate(int numquadrants) {
 1557           switch (numquadrants & 3) {
 1558           case 0:
 1559               break;
 1560           case 1:
 1561               rotate90();
 1562               break;
 1563           case 2:
 1564               rotate180();
 1565               break;
 1566           case 3:
 1567               rotate270();
 1568               break;
 1569           }
 1570       }
 1571   
 1572       /**
 1573        * Concatenates this transform with a transform that rotates
 1574        * coordinates by the specified number of quadrants around
 1575        * the specified anchor point.
 1576        * This method is equivalent to calling:
 1577        * <pre>
 1578        *     rotate(numquadrants * Math.PI / 2.0, anchorx, anchory);
 1579        * </pre>
 1580        * Rotating by a positive number of quadrants rotates points on
 1581        * the positive X axis toward the positive Y axis.
 1582        *
 1583        * @param numquadrants the number of 90 degree arcs to rotate by
 1584        * @param anchorx the X coordinate of the rotation anchor point
 1585        * @param anchory the Y coordinate of the rotation anchor point
 1586        * @since 1.6
 1587        */
 1588       public void quadrantRotate(int numquadrants,
 1589                                  double anchorx, double anchory)
 1590       {
 1591           switch (numquadrants & 3) {
 1592           case 0:
 1593               return;
 1594           case 1:
 1595               m02 += anchorx * (m00 - m01) + anchory * (m01 + m00);
 1596               m12 += anchorx * (m10 - m11) + anchory * (m11 + m10);
 1597               rotate90();
 1598               break;
 1599           case 2:
 1600               m02 += anchorx * (m00 + m00) + anchory * (m01 + m01);
 1601               m12 += anchorx * (m10 + m10) + anchory * (m11 + m11);
 1602               rotate180();
 1603               break;
 1604           case 3:
 1605               m02 += anchorx * (m00 + m01) + anchory * (m01 - m00);
 1606               m12 += anchorx * (m10 + m11) + anchory * (m11 - m10);
 1607               rotate270();
 1608               break;
 1609           }
 1610           if (m02 == 0.0 && m12 == 0.0) {
 1611               state &= ~APPLY_TRANSLATE;
 1612           } else {
 1613               state |= APPLY_TRANSLATE;
 1614           }
 1615       }
 1616   
 1617       /**
 1618        * Concatenates this transform with a scaling transformation.
 1619        * This is equivalent to calling concatenate(S), where S is an
 1620        * <code>AffineTransform</code> represented by the following matrix:
 1621        * <pre>
 1622        *          [   sx   0    0   ]
 1623        *          [   0    sy   0   ]
 1624        *          [   0    0    1   ]
 1625        * </pre>
 1626        * @param sx the factor by which coordinates are scaled along the
 1627        * X axis direction
 1628        * @param sy the factor by which coordinates are scaled along the
 1629        * Y axis direction
 1630        * @since 1.2
 1631        */
 1632       public void scale(double sx, double sy) {
 1633           int state = this.state;
 1634           switch (state) {
 1635           default:
 1636               stateError();
 1637               /* NOTREACHED */
 1638           case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
 1639           case (APPLY_SHEAR | APPLY_SCALE):
 1640               m00 *= sx;
 1641               m11 *= sy;
 1642               /* NOBREAK */
 1643           case (APPLY_SHEAR | APPLY_TRANSLATE):
 1644           case (APPLY_SHEAR):
 1645               m01 *= sy;
 1646               m10 *= sx;
 1647               if (m01 == 0 && m10 == 0) {
 1648                   state &= APPLY_TRANSLATE;
 1649                   if (m00 == 1.0 && m11 == 1.0) {
 1650                       this.type = (state == APPLY_IDENTITY
 1651                                    ? TYPE_IDENTITY
 1652                                    : TYPE_TRANSLATION);
 1653                   } else {
 1654                       state |= APPLY_SCALE;
 1655                       this.type = TYPE_UNKNOWN;
 1656                   }
 1657                   this.state = state;
 1658               }
 1659               return;
 1660           case (APPLY_SCALE | APPLY_TRANSLATE):
 1661           case (APPLY_SCALE):
 1662               m00 *= sx;
 1663               m11 *= sy;
 1664               if (m00 == 1.0 && m11 == 1.0) {
 1665                   this.state = (state &= APPLY_TRANSLATE);
 1666                   this.type = (state == APPLY_IDENTITY
 1667                                ? TYPE_IDENTITY
 1668                                : TYPE_TRANSLATION);
 1669               } else {
 1670                   this.type = TYPE_UNKNOWN;
 1671               }
 1672               return;
 1673           case (APPLY_TRANSLATE):
 1674           case (APPLY_IDENTITY):
 1675               m00 = sx;
 1676               m11 = sy;
 1677               if (sx != 1.0 || sy != 1.0) {
 1678                   this.state = state | APPLY_SCALE;
 1679                   this.type = TYPE_UNKNOWN;
 1680               }
 1681               return;
 1682           }
 1683       }
 1684   
 1685       /**
 1686        * Concatenates this transform with a shearing transformation.
 1687        * This is equivalent to calling concatenate(SH), where SH is an
 1688        * <code>AffineTransform</code> represented by the following matrix:
 1689        * <pre>
 1690        *          [   1   shx   0   ]
 1691        *          [  shy   1    0   ]
 1692        *          [   0    0    1   ]
 1693        * </pre>
 1694        * @param shx the multiplier by which coordinates are shifted in the
 1695        * direction of the positive X axis as a factor of their Y coordinate
 1696        * @param shy the multiplier by which coordinates are shifted in the
 1697        * direction of the positive Y axis as a factor of their X coordinate
 1698        * @since 1.2
 1699        */
 1700       public void shear(double shx, double shy) {
 1701           int state = this.state;
 1702           switch (state) {
 1703           default:
 1704               stateError();
 1705               /* NOTREACHED */
 1706           case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
 1707           case (APPLY_SHEAR | APPLY_SCALE):
 1708               double M0, M1;
 1709               M0 = m00;
 1710               M1 = m01;
 1711               m00 = M0 + M1 * shy;
 1712               m01 = M0 * shx + M1;
 1713   
 1714               M0 = m10;
 1715               M1 = m11;
 1716               m10 = M0 + M1 * shy;
 1717               m11 = M0 * shx + M1;
 1718               updateState();
 1719               return;
 1720           case (APPLY_SHEAR | APPLY_TRANSLATE):
 1721           case (APPLY_SHEAR):
 1722               m00 = m01 * shy;
 1723               m11 = m10 * shx;
 1724               if (m00 != 0.0 || m11 != 0.0) {
 1725                   this.state = state | APPLY_SCALE;
 1726               }
 1727               this.type = TYPE_UNKNOWN;
 1728               return;
 1729           case (APPLY_SCALE | APPLY_TRANSLATE):
 1730           case (APPLY_SCALE):
 1731               m01 = m00 * shx;
 1732               m10 = m11 * shy;
 1733               if (m01 != 0.0 || m10 != 0.0) {
 1734                   this.state = state | APPLY_SHEAR;
 1735               }
 1736               this.type = TYPE_UNKNOWN;
 1737               return;
 1738           case (APPLY_TRANSLATE):
 1739           case (APPLY_IDENTITY):
 1740               m01 = shx;
 1741               m10 = shy;
 1742               if (m01 != 0.0 || m10 != 0.0) {
 1743                   this.state = state | APPLY_SCALE | APPLY_SHEAR;
 1744                   this.type = TYPE_UNKNOWN;
 1745               }
 1746               return;
 1747           }
 1748       }
 1749   
 1750       /**
 1751        * Resets this transform to the Identity transform.
 1752        * @since 1.2
 1753        */
 1754       public void setToIdentity() {
 1755           m00 = m11 = 1.0;
 1756           m10 = m01 = m02 = m12 = 0.0;
 1757           state = APPLY_IDENTITY;
 1758           type = TYPE_IDENTITY;
 1759       }
 1760   
 1761       /**
 1762        * Sets this transform to a translation transformation.
 1763        * The matrix representing this transform becomes:
 1764        * <pre>
 1765        *          [   1    0    tx  ]
 1766        *          [   0    1    ty  ]
 1767        *          [   0    0    1   ]
 1768        * </pre>
 1769        * @param tx the distance by which coordinates are translated in the
 1770        * X axis direction
 1771        * @param ty the distance by which coordinates are translated in the
 1772        * Y axis direction
 1773        * @since 1.2
 1774        */
 1775       public void setToTranslation(double tx, double ty) {
 1776           m00 = 1.0;
 1777           m10 = 0.0;
 1778           m01 = 0.0;
 1779           m11 = 1.0;
 1780           m02 = tx;
 1781           m12 = ty;
 1782           if (tx != 0.0 || ty != 0.0) {
 1783               state = APPLY_TRANSLATE;
 1784               type = TYPE_TRANSLATION;
 1785           } else {
 1786               state = APPLY_IDENTITY;
 1787               type = TYPE_IDENTITY;
 1788           }
 1789       }
 1790   
 1791       /**
 1792        * Sets this transform to a rotation transformation.
 1793        * The matrix representing this transform becomes:
 1794        * <pre>
 1795        *          [   cos(theta)    -sin(theta)    0   ]
 1796        *          [   sin(theta)     cos(theta)    0   ]
 1797        *          [       0              0         1   ]
 1798        * </pre>
 1799        * Rotating by a positive angle theta rotates points on the positive
 1800        * X axis toward the positive Y axis.
 1801        * Note also the discussion of
 1802        * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
 1803        * above.
 1804        * @param theta the angle of rotation measured in radians
 1805        * @since 1.2
 1806        */
 1807       public void setToRotation(double theta) {
 1808           double sin = Math.sin(theta);
 1809           double cos;
 1810           if (sin == 1.0 || sin == -1.0) {
 1811               cos = 0.0;
 1812               state = APPLY_SHEAR;
 1813               type = TYPE_QUADRANT_ROTATION;
 1814           } else {
 1815               cos = Math.cos(theta);
 1816               if (cos == -1.0) {
 1817                   sin = 0.0;
 1818                   state = APPLY_SCALE;
 1819                   type = TYPE_QUADRANT_ROTATION;
 1820               } else if (cos == 1.0) {
 1821                   sin = 0.0;
 1822                   state = APPLY_IDENTITY;
 1823                   type = TYPE_IDENTITY;
 1824               } else {
 1825                   state = APPLY_SHEAR | APPLY_SCALE;
 1826                   type = TYPE_GENERAL_ROTATION;
 1827               }
 1828           }
 1829           m00 =  cos;
 1830           m10 =  sin;
 1831           m01 = -sin;
 1832           m11 =  cos;
 1833           m02 =  0.0;
 1834           m12 =  0.0;
 1835       }
 1836   
 1837       /**
 1838        * Sets this transform to a translated rotation transformation.
 1839        * This operation is equivalent to translating the coordinates so
 1840        * that the anchor point is at the origin (S1), then rotating them
 1841        * about the new origin (S2), and finally translating so that the
 1842        * intermediate origin is restored to the coordinates of the original
 1843        * anchor point (S3).
 1844        * <p>
 1845        * This operation is equivalent to the following sequence of calls:
 1846        * <pre>
 1847        *     setToTranslation(anchorx, anchory); // S3: final translation
 1848        *     rotate(theta);                      // S2: rotate around anchor
 1849        *     translate(-anchorx, -anchory);      // S1: translate anchor to origin
 1850        * </pre>
 1851        * The matrix representing this transform becomes:
 1852        * <pre>
 1853        *          [   cos(theta)    -sin(theta)    x-x*cos+y*sin  ]
 1854        *          [   sin(theta)     cos(theta)    y-x*sin-y*cos  ]
 1855        *          [       0              0               1        ]
 1856        * </pre>
 1857        * Rotating by a positive angle theta rotates points on the positive
 1858        * X axis toward the positive Y axis.
 1859        * Note also the discussion of
 1860        * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
 1861        * above.
 1862        *
 1863        * @param theta the angle of rotation measured in radians
 1864        * @param anchorx the X coordinate of the rotation anchor point
 1865        * @param anchory the Y coordinate of the rotation anchor point
 1866        * @since 1.2
 1867        */
 1868       public void setToRotation(double theta, double anchorx, double anchory) {
 1869           setToRotation(theta);
 1870           double sin = m10;
 1871           double oneMinusCos = 1.0 - m00;
 1872           m02 = anchorx * oneMinusCos + anchory * sin;
 1873           m12 = anchory * oneMinusCos - anchorx * sin;
 1874           if (m02 != 0.0 || m12 != 0.0) {
 1875               state |= APPLY_TRANSLATE;
 1876               type |= TYPE_TRANSLATION;
 1877           }
 1878       }
 1879   
 1880       /**
 1881        * Sets this transform to a rotation transformation that rotates
 1882        * coordinates according to a rotation vector.
 1883        * All coordinates rotate about the origin by the same amount.
 1884        * The amount of rotation is such that coordinates along the former
 1885        * positive X axis will subsequently align with the vector pointing
 1886        * from the origin to the specified vector coordinates.
 1887        * If both <code>vecx</code> and <code>vecy</code> are 0.0,
 1888        * the transform is set to an identity transform.
 1889        * This operation is equivalent to calling:
 1890        * <pre>
 1891        *     setToRotation(Math.atan2(vecy, vecx));
 1892        * </pre>
 1893        *
 1894        * @param vecx the X coordinate of the rotation vector
 1895        * @param vecy the Y coordinate of the rotation vector
 1896        * @since 1.6
 1897        */
 1898       public void setToRotation(double vecx, double vecy) {
 1899           double sin, cos;
 1900           if (vecy == 0) {
 1901               sin = 0.0;
 1902               if (vecx < 0.0) {
 1903                   cos = -1.0;
 1904                   state = APPLY_SCALE;
 1905                   type = TYPE_QUADRANT_ROTATION;
 1906               } else {
 1907                   cos = 1.0;
 1908                   state = APPLY_IDENTITY;
 1909                   type = TYPE_IDENTITY;
 1910               }
 1911           } else if (vecx == 0) {
 1912               cos = 0.0;
 1913               sin = (vecy > 0.0) ? 1.0 : -1.0;
 1914               state = APPLY_SHEAR;
 1915               type = TYPE_QUADRANT_ROTATION;
 1916           } else {
 1917               double len = Math.sqrt(vecx * vecx + vecy * vecy);
 1918               cos = vecx / len;
 1919               sin = vecy / len;
 1920               state = APPLY_SHEAR | APPLY_SCALE;
 1921               type = TYPE_GENERAL_ROTATION;
 1922           }
 1923           m00 =  cos;
 1924           m10 =  sin;
 1925           m01 = -sin;
 1926           m11 =  cos;
 1927           m02 =  0.0;
 1928           m12 =  0.0;
 1929       }
 1930   
 1931       /**
 1932        * Sets this transform to a rotation transformation that rotates
 1933        * coordinates around an anchor point according to a rotation
 1934        * vector.
 1935        * All coordinates rotate about the specified anchor coordinates
 1936        * by the same amount.
 1937        * The amount of rotation is such that coordinates along the former
 1938        * positive X axis will subsequently align with the vector pointing
 1939        * from the origin to the specified vector coordinates.
 1940        * If both <code>vecx</code> and <code>vecy</code> are 0.0,
 1941        * the transform is set to an identity transform.
 1942        * This operation is equivalent to calling:
 1943        * <pre>
 1944        *     setToTranslation(Math.atan2(vecy, vecx), anchorx, anchory);
 1945        * </pre>
 1946        *
 1947        * @param vecx the X coordinate of the rotation vector
 1948        * @param vecy the Y coordinate of the rotation vector
 1949        * @param anchorx the X coordinate of the rotation anchor point
 1950        * @param anchory the Y coordinate of the rotation anchor point
 1951        * @since 1.6
 1952        */
 1953       public void setToRotation(double vecx, double vecy,
 1954                                 double anchorx, double anchory)
 1955       {
 1956           setToRotation(vecx, vecy);
 1957           double sin = m10;
 1958           double oneMinusCos = 1.0 - m00;
 1959           m02 = anchorx * oneMinusCos + anchory * sin;
 1960           m12 = anchory * oneMinusCos - anchorx * sin;
 1961           if (m02 != 0.0 || m12 != 0.0) {
 1962               state |= APPLY_TRANSLATE;
 1963               type |= TYPE_TRANSLATION;
 1964           }
 1965       }
 1966   
 1967       /**
 1968        * Sets this transform to a rotation transformation that rotates
 1969        * coordinates by the specified number of quadrants.
 1970        * This operation is equivalent to calling:
 1971        * <pre>
 1972        *     setToRotation(numquadrants * Math.PI / 2.0);
 1973        * </pre>
 1974        * Rotating by a positive number of quadrants rotates points on
 1975        * the positive X axis toward the positive Y axis.
 1976        * @param numquadrants the number of 90 degree arcs to rotate by
 1977        * @since 1.6
 1978        */
 1979       public void setToQuadrantRotation(int numquadrants) {
 1980           switch (numquadrants & 3) {
 1981           case 0:
 1982               m00 =  1.0;
 1983               m10 =  0.0;
 1984               m01 =  0.0;
 1985               m11 =  1.0;
 1986               m02 =  0.0;
 1987               m12 =  0.0;
 1988               state = APPLY_IDENTITY;
 1989               type = TYPE_IDENTITY;
 1990               break;
 1991           case 1:
 1992               m00 =  0.0;
 1993               m10 =  1.0;
 1994               m01 = -1.0;
 1995               m11 =  0.0;
 1996               m02 =  0.0;
 1997               m12 =  0.0;
 1998               state = APPLY_SHEAR;
 1999               type = TYPE_QUADRANT_ROTATION;
 2000               break;
 2001           case 2:
 2002               m00 = -1.0;
 2003               m10 =  0.0;
 2004               m01 =  0.0;
 2005               m11 = -1.0;
 2006               m02 =  0.0;
 2007               m12 =  0.0;
 2008               state = APPLY_SCALE;
 2009               type = TYPE_QUADRANT_ROTATION;
 2010               break;
 2011           case 3:
 2012               m00 =  0.0;
 2013               m10 = -1.0;
 2014               m01 =  1.0;
 2015               m11 =  0.0;
 2016               m02 =  0.0;
 2017               m12 =  0.0;
 2018               state = APPLY_SHEAR;
 2019               type = TYPE_QUADRANT_ROTATION;
 2020               break;
 2021           }
 2022       }
 2023   
 2024       /**
 2025        * Sets this transform to a translated rotation transformation
 2026        * that rotates coordinates by the specified number of quadrants
 2027        * around the specified anchor point.
 2028        * This operation is equivalent to calling:
 2029        * <pre>
 2030        *     setToRotation(numquadrants * Math.PI / 2.0, anchorx, anchory);
 2031        * </pre>
 2032        * Rotating by a positive number of quadrants rotates points on
 2033        * the positive X axis toward the positive Y axis.
 2034        *
 2035        * @param numquadrants the number of 90 degree arcs to rotate by
 2036        * @param anchorx the X coordinate of the rotation anchor point
 2037        * @param anchory the Y coordinate of the rotation anchor point
 2038        * @since 1.6
 2039        */
 2040       public void setToQuadrantRotation(int numquadrants,
 2041                                         double anchorx, double anchory)
 2042       {
 2043           switch (numquadrants & 3) {
 2044           case 0:
 2045               m00 =  1.0;
 2046               m10 =  0.0;
 2047               m01 =  0.0;
 2048               m11 =  1.0;
 2049               m02 =  0.0;
 2050               m12 =  0.0;
 2051               state = APPLY_IDENTITY;
 2052               type = TYPE_IDENTITY;
 2053               break;
 2054           case 1:
 2055               m00 =  0.0;
 2056               m10 =  1.0;
 2057               m01 = -1.0;
 2058               m11 =  0.0;
 2059               m02 =  anchorx + anchory;
 2060               m12 =  anchory - anchorx;
 2061               if (m02 == 0.0 && m12 == 0.0) {
 2062                   state = APPLY_SHEAR;
 2063                   type = TYPE_QUADRANT_ROTATION;
 2064               } else {
 2065                   state = APPLY_SHEAR | APPLY_TRANSLATE;
 2066                   type = TYPE_QUADRANT_ROTATION | TYPE_TRANSLATION;
 2067               }
 2068               break;
 2069           case 2:
 2070               m00 = -1.0;
 2071               m10 =  0.0;
 2072               m01 =  0.0;
 2073               m11 = -1.0;
 2074               m02 =  anchorx + anchorx;
 2075               m12 =  anchory + anchory;
 2076               if (m02 == 0.0 && m12 == 0.0) {
 2077                   state = APPLY_SCALE;
 2078                   type = TYPE_QUADRANT_ROTATION;
 2079               } else {
 2080                   state = APPLY_SCALE | APPLY_TRANSLATE;
 2081                   type = TYPE_QUADRANT_ROTATION | TYPE_TRANSLATION;
 2082               }
 2083               break;
 2084           case 3:
 2085               m00 =  0.0;
 2086               m10 = -1.0;
 2087               m01 =  1.0;
 2088               m11 =  0.0;
 2089               m02 =  anchorx - anchory;
 2090               m12 =  anchory + anchorx;
 2091               if (m02 == 0.0 && m12 == 0.0) {
 2092                   state = APPLY_SHEAR;
 2093                   type = TYPE_QUADRANT_ROTATION;
 2094               } else {
 2095                   state = APPLY_SHEAR | APPLY_TRANSLATE;
 2096                   type = TYPE_QUADRANT_ROTATION | TYPE_TRANSLATION;
 2097               }
 2098               break;
 2099           }
 2100       }
 2101   
 2102       /**
 2103        * Sets this transform to a scaling transformation.
 2104        * The matrix representing this transform becomes:
 2105        * <pre>
 2106        *          [   sx   0    0   ]
 2107        *          [   0    sy   0   ]
 2108        *          [   0    0    1   ]
 2109        * </pre>
 2110        * @param sx the factor by which coordinates are scaled along the
 2111        * X axis direction
 2112        * @param sy the factor by which coordinates are scaled along the
 2113        * Y axis direction
 2114        * @since 1.2
 2115        */
 2116       public void setToScale(double sx, double sy) {
 2117           m00 = sx;
 2118           m10 = 0.0;
 2119           m01 = 0.0;
 2120           m11 = sy;
 2121           m02 = 0.0;
 2122           m12 = 0.0;
 2123           if (sx != 1.0 || sy != 1.0) {
 2124               state = APPLY_SCALE;
 2125               type = TYPE_UNKNOWN;
 2126           } else {
 2127               state = APPLY_IDENTITY;
 2128               type = TYPE_IDENTITY;
 2129           }
 2130       }
 2131   
 2132       /**
 2133        * Sets this transform to a shearing transformation.
 2134        * The matrix representing this transform becomes:
 2135        * <pre>
 2136        *          [   1   shx   0   ]
 2137        *          [  shy   1    0   ]
 2138        *          [   0    0    1   ]
 2139        * </pre>
 2140        * @param shx the multiplier by which coordinates are shifted in the
 2141        * direction of the positive X axis as a factor of their Y coordinate
 2142        * @param shy the multiplier by which coordinates are shifted in the
 2143        * direction of the positive Y axis as a factor of their X coordinate
 2144        * @since 1.2
 2145        */
 2146       public void setToShear(double shx, double shy) {
 2147           m00 = 1.0;
 2148           m01 = shx;
 2149           m10 = shy;
 2150           m11 = 1.0;
 2151           m02 = 0.0;
 2152           m12 = 0.0;
 2153           if (shx != 0.0 || shy != 0.0) {
 2154               state = (APPLY_SHEAR | APPLY_SCALE);
 2155               type = TYPE_UNKNOWN;
 2156           } else {
 2157               state = APPLY_IDENTITY;
 2158               type = TYPE_IDENTITY;
 2159           }
 2160       }
 2161   
 2162       /**
 2163        * Sets this transform to a copy of the transform in the specified
 2164        * <code>AffineTransform</code> object.
 2165        * @param Tx the <code>AffineTransform</code> object from which to
 2166        * copy the transform
 2167        * @since 1.2
 2168        */
 2169       public void setTransform(AffineTransform Tx) {
 2170           this.m00 = Tx.m00;
 2171           this.m10 = Tx.m10;
 2172           this.m01 = Tx.m01;
 2173           this.m11 = Tx.m11;
 2174           this.m02 = Tx.m02;
 2175           this.m12 = Tx.m12;
 2176           this.state = Tx.state;
 2177           this.type = Tx.type;
 2178       }
 2179   
 2180       /**
 2181        * Sets this transform to the matrix specified by the 6
 2182        * double precision values.
 2183        *
 2184        * @param m00 the X coordinate scaling element of the 3x3 matrix
 2185        * @param m10 the Y coordinate shearing element of the 3x3 matrix
 2186        * @param m01 the X coordinate shearing element of the 3x3 matrix
 2187        * @param m11 the Y coordinate scaling element of the 3x3 matrix
 2188        * @param m02 the X coordinate translation element of the 3x3 matrix
 2189        * @param m12 the Y coordinate translation element of the 3x3 matrix
 2190        * @since 1.2
 2191        */
 2192       public void setTransform(double m00, double m10,
 2193                                double m01, double m11,
 2194                                double m02, double m12) {
 2195           this.m00 = m00;
 2196           this.m10 = m10;
 2197           this.m01 = m01;
 2198           this.m11 = m11;
 2199           this.m02 = m02;
 2200           this.m12 = m12;
 2201           updateState();
 2202       }
 2203   
 2204       /**
 2205        * Concatenates an <code>AffineTransform</code> <code>Tx</code> to
 2206        * this <code>AffineTransform</code> Cx in the most commonly useful
 2207        * way to provide a new user space
 2208        * that is mapped to the former user space by <code>Tx</code>.
 2209        * Cx is updated to perform the combined transformation.
 2210        * Transforming a point p by the updated transform Cx' is
 2211        * equivalent to first transforming p by <code>Tx</code> and then
 2212        * transforming the result by the original transform Cx like this:
 2213        * Cx'(p) = Cx(Tx(p))
 2214        * In matrix notation, if this transform Cx is
 2215        * represented by the matrix [this] and <code>Tx</code> is represented
 2216        * by the matrix [Tx] then this method does the following:
 2217        * <pre>
 2218        *          [this] = [this] x [Tx]
 2219        * </pre>
 2220        * @param Tx the <code>AffineTransform</code> object to be
 2221        * concatenated with this <code>AffineTransform</code> object.
 2222        * @see #preConcatenate
 2223        * @since 1.2
 2224        */
 2225       public void concatenate(AffineTransform Tx) {
 2226           double M0, M1;
 2227           double T00, T01, T10, T11;
 2228           double T02, T12;
 2229           int mystate = state;
 2230           int txstate = Tx.state;
 2231           switch ((txstate << HI_SHIFT) | mystate) {
 2232   
 2233               /* ---------- Tx == IDENTITY cases ---------- */
 2234           case (HI_IDENTITY | APPLY_IDENTITY):
 2235           case (HI_IDENTITY | APPLY_TRANSLATE):
 2236           case (HI_IDENTITY | APPLY_SCALE):
 2237           case (HI_IDENTITY | APPLY_SCALE | APPLY_TRANSLATE):
 2238           case (HI_IDENTITY | APPLY_SHEAR):
 2239           case (HI_IDENTITY | APPLY_SHEAR | APPLY_TRANSLATE):
 2240           case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE):
 2241           case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
 2242               return;
 2243   
 2244               /* ---------- this == IDENTITY cases ---------- */
 2245           case (HI_SHEAR | HI_SCALE | HI_TRANSLATE | APPLY_IDENTITY):
 2246               m01 = Tx.m01;
 2247               m10 = Tx.m10;
 2248               /* NOBREAK */
 2249           case (HI_SCALE | HI_TRANSLATE | APPLY_IDENTITY):
 2250               m00 = Tx.m00;
 2251               m11 = Tx.m11;
 2252               /* NOBREAK */
 2253           case (HI_TRANSLATE | APPLY_IDENTITY):
 2254               m02 = Tx.m02;
 2255               m12 = Tx.m12;
 2256               state = txstate;
 2257               type = Tx.type;
 2258               return;
 2259           case (HI_SHEAR | HI_SCALE | APPLY_IDENTITY):
 2260               m01 = Tx.m01;
 2261               m10 = Tx.m10;
 2262               /* NOBREAK */
 2263           case (HI_SCALE | APPLY_IDENTITY):
 2264               m00 = Tx.m00;
 2265               m11 = Tx.m11;
 2266               state = txstate;
 2267               type = Tx.type;
 2268               return;
 2269           case (HI_SHEAR | HI_TRANSLATE | APPLY_IDENTITY):
 2270               m02 = Tx.m02;
 2271               m12 = Tx.m12;
 2272               /* NOBREAK */
 2273           case (HI_SHEAR | APPLY_IDENTITY):
 2274               m01 = Tx.m01;
 2275               m10 = Tx.m10;
 2276               m00 = m11 = 0.0;
 2277               state = txstate;
 2278               type = Tx.type;
 2279               return;
 2280   
 2281               /* ---------- Tx == TRANSLATE cases ---------- */
 2282           case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
 2283           case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE):
 2284           case (HI_TRANSLATE | APPLY_SHEAR | APPLY_TRANSLATE):
 2285           case (HI_TRANSLATE | APPLY_SHEAR):
 2286           case (HI_TRANSLATE | APPLY_SCALE | APPLY_TRANSLATE):
 2287           case (HI_TRANSLATE | APPLY_SCALE):
 2288           case (HI_TRANSLATE | APPLY_TRANSLATE):
 2289               translate(Tx.m02, Tx.m12);
 2290               return;
 2291   
 2292               /* ---------- Tx == SCALE cases ---------- */
 2293           case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
 2294           case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE):
 2295           case (HI_SCALE | APPLY_SHEAR | APPLY_TRANSLATE):
 2296           case (HI_SCALE | APPLY_SHEAR):
 2297           case (HI_SCALE | APPLY_SCALE | APPLY_TRANSLATE):
 2298           case (HI_SCALE | APPLY_SCALE):
 2299           case (HI_SCALE | APPLY_TRANSLATE):
 2300               scale(Tx.m00, Tx.m11);
 2301               return;
 2302   
 2303               /* ---------- Tx == SHEAR cases ---------- */
 2304           case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
 2305           case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE):
 2306               T01 = Tx.m01; T10 = Tx.m10;
 2307               M0 = m00;
 2308               m00 = m01 * T10;
 2309               m01 = M0 * T01;
 2310               M0 = m10;
 2311               m10 = m11 * T10;
 2312               m11 = M0 * T01;
 2313               type = TYPE_UNKNOWN;
 2314               return;
 2315           case (HI_SHEAR | APPLY_SHEAR | APPLY_TRANSLATE):
 2316           case (HI_SHEAR | APPLY_SHEAR):
 2317               m00 = m01 * Tx.m10;
 2318               m01 = 0.0;
 2319               m11 = m10 * Tx.m01;
 2320               m10 = 0.0;
 2321               state = mystate ^ (APPLY_SHEAR | APPLY_SCALE);
 2322               type = TYPE_UNKNOWN;
 2323               return;
 2324           case (HI_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
 2325           case (HI_SHEAR | APPLY_SCALE):
 2326               m01 = m00 * Tx.m01;
 2327               m00 = 0.0;
 2328               m10 = m11 * Tx.m10;
 2329               m11 = 0.0;
 2330               state = mystate ^ (APPLY_SHEAR | APPLY_SCALE);
 2331               type = TYPE_UNKNOWN;
 2332               return;
 2333           case (HI_SHEAR | APPLY_TRANSLATE):
 2334               m00 = 0.0;
 2335               m01 = Tx.m01;
 2336               m10 = Tx.m10;
 2337               m11 = 0.0;
 2338               state = APPLY_TRANSLATE | APPLY_SHEAR;
 2339               type = TYPE_UNKNOWN;
 2340               return;
 2341           }
 2342           // If Tx has more than one attribute, it is not worth optimizing
 2343           // all of those cases...
 2344           T00 = Tx.m00; T01 = Tx.m01; T02 = Tx.m02;
 2345           T10 = Tx.m10; T11 = Tx.m11; T12 = Tx.m12;
 2346           switch (mystate) {
 2347           default:
 2348               stateError();
 2349               /* NOTREACHED */
 2350           case (APPLY_SHEAR | APPLY_SCALE):
 2351               state = mystate | txstate;
 2352               /* NOBREAK */
 2353           case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
 2354               M0 = m00;
 2355               M1 = m01;
 2356               m00  = T00 * M0 + T10 * M1;
 2357               m01  = T01 * M0 + T11 * M1;
 2358               m02 += T02 * M0 + T12 * M1;
 2359   
 2360               M0 = m10;
 2361               M1 = m11;
 2362               m10  = T00 * M0 + T10 * M1;
 2363               m11  = T01 * M0 + T11 * M1;
 2364               m12 += T02 * M0 + T12 * M1;
 2365               type = TYPE_UNKNOWN;
 2366               return;
 2367   
 2368           case (APPLY_SHEAR | APPLY_TRANSLATE):
 2369           case (APPLY_SHEAR):
 2370               M0 = m01;
 2371               m00  = T10 * M0;
 2372               m01  = T11 * M0;
 2373               m02 += T12 * M0;
 2374   
 2375               M0 = m10;
 2376               m10  = T00 * M0;
 2377               m11  = T01 * M0;
 2378               m12 += T02 * M0;
 2379               break;
 2380   
 2381           case (APPLY_SCALE | APPLY_TRANSLATE):
 2382           case (APPLY_SCALE):
 2383               M0 = m00;
 2384               m00  = T00 * M0;
 2385               m01  = T01 * M0;
 2386               m02 += T02 * M0;
 2387   
 2388               M0 = m11;
 2389               m10  = T10 * M0;
 2390               m11  = T11 * M0;
 2391               m12 += T12 * M0;
 2392               break;
 2393   
 2394           case (APPLY_TRANSLATE):
 2395               m00  = T00;
 2396               m01  = T01;
 2397               m02 += T02;
 2398   
 2399               m10  = T10;
 2400               m11  = T11;
 2401               m12 += T12;
 2402               state = txstate | APPLY_TRANSLATE;
 2403               type = TYPE_UNKNOWN;
 2404               return;
 2405           }
 2406           updateState();
 2407       }
 2408   
 2409       /**
 2410        * Concatenates an <code>AffineTransform</code> <code>Tx</code> to
 2411        * this <code>AffineTransform</code> Cx
 2412        * in a less commonly used way such that <code>Tx</code> modifies the
 2413        * coordinate transformation relative to the absolute pixel
 2414        * space rather than relative to the existing user space.
 2415        * Cx is updated to perform the combined transformation.
 2416        * Transforming a point p by the updated transform Cx' is
 2417        * equivalent to first transforming p by the original transform
 2418        * Cx and then transforming the result by
 2419        * <code>Tx</code> like this:
 2420        * Cx'(p) = Tx(Cx(p))
 2421        * In matrix notation, if this transform Cx
 2422        * is represented by the matrix [this] and <code>Tx</code> is
 2423        * represented by the matrix [Tx] then this method does the
 2424        * following:
 2425        * <pre>
 2426        *          [this] = [Tx] x [this]
 2427        * </pre>
 2428        * @param Tx the <code>AffineTransform</code> object to be
 2429        * concatenated with this <code>AffineTransform</code> object.
 2430        * @see #concatenate
 2431        * @since 1.2
 2432        */
 2433       public void preConcatenate(AffineTransform Tx) {
 2434           double M0, M1;
 2435           double T00, T01, T10, T11;
 2436           double T02, T12;
 2437           int mystate = state;
 2438           int txstate = Tx.state;
 2439           switch ((txstate << HI_SHIFT) | mystate) {
 2440           case (HI_IDENTITY | APPLY_IDENTITY):
 2441           case (HI_IDENTITY | APPLY_TRANSLATE):
 2442           case (HI_IDENTITY | APPLY_SCALE):
 2443           case (HI_IDENTITY | APPLY_SCALE | APPLY_TRANSLATE):
 2444           case (HI_IDENTITY | APPLY_SHEAR):
 2445           case (HI_IDENTITY | APPLY_SHEAR | APPLY_TRANSLATE):
 2446           case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE):
 2447           case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
 2448               // Tx is IDEN