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