Source Code Cross Referenced for AffineTransform.java in  » 6.0-JDK-Core » AWT » java » awt » geom » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Home
Java Source Code / Java Documentation
1.6.0 JDK Core
2.6.0 JDK Modules
3.6.0 JDK Modules com.sun
4.6.0 JDK Modules com.sun.java
5.6.0 JDK Modules sun
6.6.0 JDK Platform
7.Ajax
8.Apache Harmony Java SE
9.Aspect oriented
10.Authentication Authorization
11.Blogger System
12.Build
13.Byte Code
14.Cache
15.Chart
16.Chat
17.Code Analyzer
18.Collaboration
19.Content Management System
20.Database Client
21.Database DBMS
22.Database JDBC Connection Pool
23.Database ORM
24.Development
25.EJB Server
26.ERP CRM Financial
27.ESB
28.Forum
29.Game
30.GIS
31.Graphic 3D
32.Graphic Library
33.Groupware
34.HTML Parser
35.IDE
36.IDE Eclipse
37.IDE Netbeans
38.Installer
39.Internationalization Localization
40.Inversion of Control
41.Issue Tracking
42.J2EE
43.J2ME
44.JBoss
45.JMS
46.JMX
47.Library
48.Mail Clients
49.Music
50.Net
51.Parser
52.PDF
53.Portal
54.Profiler
55.Project Management
56.Report
57.RSS RDF
58.Rule Engine
59.Science
60.Scripting
61.Search Engine
62.Security
63.Sevlet Container
64.Source Control
65.Swing Library
66.Template Engine
67.Test Coverage
68.Testing
69.UML
70.Web Crawler
71.Web Framework
72.Web Mail
73.Web Server
74.Web Services
75.Web Services apache cxf 2.2.6
76.Web Services AXIS2
77.Wiki Engine
78.Workflow Engines
79.XML
80.XML UI
Java Source Code / Java Documentation » 6.0 JDK Core » AWT » java.awt.geom 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001        /*
0002         * Copyright 1996-2006 Sun Microsystems, Inc.  All Rights Reserved.
0003         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004         *
0005         * This code is free software; you can redistribute it and/or modify it
0006         * under the terms of the GNU General Public License version 2 only, as
0007         * published by the Free Software Foundation.  Sun designates this
0008         * particular file as subject to the "Classpath" exception as provided
0009         * by Sun in the LICENSE file that accompanied this code.
0010         *
0011         * This code is distributed in the hope that it will be useful, but WITHOUT
0012         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0014         * version 2 for more details (a copy is included in the LICENSE file that
0015         * accompanied this code).
0016         *
0017         * You should have received a copy of the GNU General Public License version
0018         * 2 along with this work; if not, write to the Free Software Foundation,
0019         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020         *
0021         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022         * CA 95054 USA or visit www.sun.com if you need additional information or
0023         * have any questions.
0024         */
0025
0026        package java.awt.geom;
0027
0028        import java.awt.Shape;
0029
0030        /**
0031         * The <code>AffineTransform</code> class represents a 2D affine transform
0032         * that performs a linear mapping from 2D coordinates to other 2D
0033         * coordinates that preserves the "straightness" and
0034         * "parallelness" of lines.  Affine transformations can be constructed
0035         * using sequences of translations, scales, flips, rotations, and shears.
0036         * <p>
0037         * Such a coordinate transformation can be represented by a 3 row by
0038         * 3 column matrix with an implied last row of [ 0 0 1 ].  This matrix 
0039         * transforms source coordinates {@code (x,y)} into
0040         * destination coordinates {@code (x',y')} by considering
0041         * them to be a column vector and multiplying the coordinate vector
0042         * by the matrix according to the following process:
0043         * <pre>
0044         *	[ x']   [  m00  m01  m02  ] [ x ]   [ m00x + m01y + m02 ]
0045         *	[ y'] = [  m10  m11  m12  ] [ y ] = [ m10x + m11y + m12 ]
0046         *	[ 1 ]   [   0    0    1   ] [ 1 ]   [         1         ]
0047         * </pre>
0048         * <p>
0049         * <a name="quadrantapproximation"><h4>Handling 90-Degree Rotations</h4></a>
0050         * <p>
0051         * In some variations of the <code>rotate</code> methods in the
0052         * <code>AffineTransform</code> class, a double-precision argument
0053         * specifies the angle of rotation in radians.
0054         * These methods have special handling for rotations of approximately
0055         * 90 degrees (including multiples such as 180, 270, and 360 degrees),
0056         * so that the common case of quadrant rotation is handled more
0057         * efficiently.
0058         * This special handling can cause angles very close to multiples of
0059         * 90 degrees to be treated as if they were exact multiples of
0060         * 90 degrees.
0061         * For small multiples of 90 degrees the range of angles treated
0062         * as a quadrant rotation is approximately 0.00000121 degrees wide.
0063         * This section explains why such special care is needed and how
0064         * it is implemented.
0065         * <p>
0066         * Since 90 degrees is represented as <code>PI/2</code> in radians,
0067         * and since PI is a transcendental (and therefore irrational) number,
0068         * it is not possible to exactly represent a multiple of 90 degrees as
0069         * an exact double precision value measured in radians.
0070         * As a result it is theoretically impossible to describe quadrant
0071         * rotations (90, 180, 270 or 360 degrees) using these values.
0072         * Double precision floating point values can get very close to
0073         * non-zero multiples of <code>PI/2</code> but never close enough
0074         * for the sine or cosine to be exactly 0.0, 1.0 or -1.0.
0075         * The implementations of <code>Math.sin()</code> and
0076         * <code>Math.cos()</code> correspondingly never return 0.0
0077         * for any case other than <code>Math.sin(0.0)</code>.
0078         * These same implementations do, however, return exactly 1.0 and
0079         * -1.0 for some range of numbers around each multiple of 90
0080         * degrees since the correct answer is so close to 1.0 or -1.0 that
0081         * the double precision significand cannot represent the difference
0082         * as accurately as it can for numbers that are near 0.0.
0083         * <p>
0084         * The net result of these issues is that if the
0085         * <code>Math.sin()</code> and <code>Math.cos()</code> methods
0086         * are used to directly generate the values for the matrix modifications
0087         * during these radian-based rotation operations then the resulting
0088         * transform is never strictly classifiable as a quadrant rotation
0089         * even for a simple case like <code>rotate(Math.PI/2.0)</code>,
0090         * due to minor variations in the matrix caused by the non-0.0 values
0091         * obtained for the sine and cosine.
0092         * If these transforms are not classified as quadrant rotations then
0093         * subsequent code which attempts to optimize further operations based
0094         * upon the type of the transform will be relegated to its most general
0095         * implementation.
0096         * <p>
0097         * Because quadrant rotations are fairly common,
0098         * this class should handle these cases reasonably quickly, both in
0099         * applying the rotations to the transform and in applying the resulting
0100         * transform to the coordinates.
0101         * To facilitate this optimal handling, the methods which take an angle
0102         * of rotation measured in radians attempt to detect angles that are
0103         * intended to be quadrant rotations and treat them as such.
0104         * These methods therefore treat an angle <em>theta</em> as a quadrant
0105         * rotation if either <code>Math.sin(<em>theta</em>)</code> or
0106         * <code>Math.cos(<em>theta</em>)</code> returns exactly 1.0 or -1.0.
0107         * As a rule of thumb, this property holds true for a range of
0108         * approximately 0.0000000211 radians (or 0.00000121 degrees) around
0109         * small multiples of <code>Math.PI/2.0</code>.
0110         *
0111         * @version 1.83, 05/05/07
0112         * @author Jim Graham
0113         * @since 1.2
0114         */
0115        public class AffineTransform implements  Cloneable, java.io.Serializable {
0116
0117            /*
0118             * This constant is only useful for the cached type field.
0119             * It indicates that the type has been decached and must be recalculated.
0120             */
0121            private static final int TYPE_UNKNOWN = -1;
0122
0123            /**
0124             * This constant indicates that the transform defined by this object
0125             * is an identity transform.
0126             * An identity transform is one in which the output coordinates are
0127             * always the same as the input coordinates.
0128             * If this transform is anything other than the identity transform,
0129             * the type will either be the constant GENERAL_TRANSFORM or a
0130             * combination of the appropriate flag bits for the various coordinate
0131             * conversions that this transform performs.
0132             * @see #TYPE_TRANSLATION
0133             * @see #TYPE_UNIFORM_SCALE
0134             * @see #TYPE_GENERAL_SCALE
0135             * @see #TYPE_FLIP
0136             * @see #TYPE_QUADRANT_ROTATION
0137             * @see #TYPE_GENERAL_ROTATION
0138             * @see #TYPE_GENERAL_TRANSFORM
0139             * @see #getType
0140             * @since 1.2
0141             */
0142            public static final int TYPE_IDENTITY = 0;
0143
0144            /**
0145             * This flag bit indicates that the transform defined by this object
0146             * performs a translation in addition to the conversions indicated
0147             * by other flag bits.
0148             * A translation moves the coordinates by a constant amount in x
0149             * and y without changing the length or angle of vectors.
0150             * @see #TYPE_IDENTITY
0151             * @see #TYPE_UNIFORM_SCALE
0152             * @see #TYPE_GENERAL_SCALE
0153             * @see #TYPE_FLIP
0154             * @see #TYPE_QUADRANT_ROTATION
0155             * @see #TYPE_GENERAL_ROTATION
0156             * @see #TYPE_GENERAL_TRANSFORM
0157             * @see #getType
0158             * @since 1.2
0159             */
0160            public static final int TYPE_TRANSLATION = 1;
0161
0162            /**
0163             * This flag bit indicates that the transform defined by this object
0164             * performs a uniform scale in addition to the conversions indicated
0165             * by other flag bits.
0166             * A uniform scale multiplies the length of vectors by the same amount
0167             * in both the x and y directions without changing the angle between
0168             * vectors.
0169             * This flag bit is mutually exclusive with the TYPE_GENERAL_SCALE flag.
0170             * @see #TYPE_IDENTITY
0171             * @see #TYPE_TRANSLATION
0172             * @see #TYPE_GENERAL_SCALE
0173             * @see #TYPE_FLIP
0174             * @see #TYPE_QUADRANT_ROTATION
0175             * @see #TYPE_GENERAL_ROTATION
0176             * @see #TYPE_GENERAL_TRANSFORM
0177             * @see #getType
0178             * @since 1.2
0179             */
0180            public static final int TYPE_UNIFORM_SCALE = 2;
0181
0182            /**
0183             * This flag bit indicates that the transform defined by this object
0184             * performs a general scale in addition to the conversions indicated
0185             * by other flag bits.
0186             * A general scale multiplies the length of vectors by different
0187             * amounts in the x and y directions without changing the angle
0188             * between perpendicular vectors.
0189             * This flag bit is mutually exclusive with the TYPE_UNIFORM_SCALE flag.
0190             * @see #TYPE_IDENTITY
0191             * @see #TYPE_TRANSLATION
0192             * @see #TYPE_UNIFORM_SCALE
0193             * @see #TYPE_FLIP
0194             * @see #TYPE_QUADRANT_ROTATION
0195             * @see #TYPE_GENERAL_ROTATION
0196             * @see #TYPE_GENERAL_TRANSFORM
0197             * @see #getType
0198             * @since 1.2
0199             */
0200            public static final int TYPE_GENERAL_SCALE = 4;
0201
0202            /**
0203             * This constant is a bit mask for any of the scale flag bits.
0204             * @see #TYPE_UNIFORM_SCALE
0205             * @see #TYPE_GENERAL_SCALE
0206             * @since 1.2
0207             */
0208            public static final int TYPE_MASK_SCALE = (TYPE_UNIFORM_SCALE | TYPE_GENERAL_SCALE);
0209
0210            /**
0211             * This flag bit indicates that the transform defined by this object
0212             * performs a mirror image flip about some axis which changes the
0213             * normally right handed coordinate system into a left handed
0214             * system in addition to the conversions indicated by other flag bits.
0215             * A right handed coordinate system is one where the positive X
0216             * axis rotates counterclockwise to overlay the positive Y axis
0217             * similar to the direction that the fingers on your right hand
0218             * curl when you stare end on at your thumb.
0219             * A left handed coordinate system is one where the positive X
0220             * axis rotates clockwise to overlay the positive Y axis similar
0221             * to the direction that the fingers on your left hand curl.
0222             * There is no mathematical way to determine the angle of the
0223             * original flipping or mirroring transformation since all angles
0224             * of flip are identical given an appropriate adjusting rotation.
0225             * @see #TYPE_IDENTITY
0226             * @see #TYPE_TRANSLATION
0227             * @see #TYPE_UNIFORM_SCALE
0228             * @see #TYPE_GENERAL_SCALE
0229             * @see #TYPE_QUADRANT_ROTATION
0230             * @see #TYPE_GENERAL_ROTATION
0231             * @see #TYPE_GENERAL_TRANSFORM
0232             * @see #getType
0233             * @since 1.2
0234             */
0235            public static final int TYPE_FLIP = 64;
0236            /* NOTE: TYPE_FLIP was added after GENERAL_TRANSFORM was in public
0237             * circulation and the flag bits could no longer be conveniently
0238             * renumbered without introducing binary incompatibility in outside
0239             * code.
0240             */
0241
0242            /**
0243             * This flag bit indicates that the transform defined by this object
0244             * performs a quadrant rotation by some multiple of 90 degrees in
0245             * addition to the conversions indicated by other flag bits.
0246             * A rotation changes the angles of vectors by the same amount
0247             * regardless of the original direction of the vector and without
0248             * changing the length of the vector.
0249             * This flag bit is mutually exclusive with the TYPE_GENERAL_ROTATION flag.
0250             * @see #TYPE_IDENTITY
0251             * @see #TYPE_TRANSLATION
0252             * @see #TYPE_UNIFORM_SCALE
0253             * @see #TYPE_GENERAL_SCALE
0254             * @see #TYPE_FLIP
0255             * @see #TYPE_GENERAL_ROTATION
0256             * @see #TYPE_GENERAL_TRANSFORM
0257             * @see #getType
0258             * @since 1.2
0259             */
0260            public static final int TYPE_QUADRANT_ROTATION = 8;
0261
0262            /**
0263             * This flag bit indicates that the transform defined by this object
0264             * performs a rotation by an arbitrary angle in addition to the
0265             * conversions indicated by other flag bits.
0266             * A rotation changes the angles of vectors by the same amount
0267             * regardless of the original direction of the vector and without
0268             * changing the length of the vector.
0269             * This flag bit is mutually exclusive with the
0270             * TYPE_QUADRANT_ROTATION flag.
0271             * @see #TYPE_IDENTITY
0272             * @see #TYPE_TRANSLATION
0273             * @see #TYPE_UNIFORM_SCALE
0274             * @see #TYPE_GENERAL_SCALE
0275             * @see #TYPE_FLIP
0276             * @see #TYPE_QUADRANT_ROTATION
0277             * @see #TYPE_GENERAL_TRANSFORM
0278             * @see #getType
0279             * @since 1.2
0280             */
0281            public static final int TYPE_GENERAL_ROTATION = 16;
0282
0283            /**
0284             * This constant is a bit mask for any of the rotation flag bits.
0285             * @see #TYPE_QUADRANT_ROTATION
0286             * @see #TYPE_GENERAL_ROTATION
0287             * @since 1.2
0288             */
0289            public static final int TYPE_MASK_ROTATION = (TYPE_QUADRANT_ROTATION | TYPE_GENERAL_ROTATION);
0290
0291            /**
0292             * This constant indicates that the transform defined by this object
0293             * performs an arbitrary conversion of the input coordinates.
0294             * If this transform can be classified by any of the above constants,
0295             * the type will either be the constant TYPE_IDENTITY or a
0296             * combination of the appropriate flag bits for the various coordinate
0297             * conversions that this transform performs.
0298             * @see #TYPE_IDENTITY
0299             * @see #TYPE_TRANSLATION
0300             * @see #TYPE_UNIFORM_SCALE
0301             * @see #TYPE_GENERAL_SCALE
0302             * @see #TYPE_FLIP
0303             * @see #TYPE_QUADRANT_ROTATION
0304             * @see #TYPE_GENERAL_ROTATION
0305             * @see #getType
0306             * @since 1.2
0307             */
0308            public static final int TYPE_GENERAL_TRANSFORM = 32;
0309
0310            /**
0311             * This constant is used for the internal state variable to indicate
0312             * that no calculations need to be performed and that the source
0313             * coordinates only need to be copied to their destinations to
0314             * complete the transformation equation of this transform.
0315             * @see #APPLY_TRANSLATE
0316             * @see #APPLY_SCALE
0317             * @see #APPLY_SHEAR
0318             * @see #state
0319             */
0320            static final int APPLY_IDENTITY = 0;
0321
0322            /**
0323             * This constant is used for the internal state variable to indicate
0324             * that the translation components of the matrix (m02 and m12) need
0325             * to be added to complete the transformation equation of this transform.
0326             * @see #APPLY_IDENTITY
0327             * @see #APPLY_SCALE
0328             * @see #APPLY_SHEAR
0329             * @see #state
0330             */
0331            static final int APPLY_TRANSLATE = 1;
0332
0333            /**
0334             * This constant is used for the internal state variable to indicate
0335             * that the scaling components of the matrix (m00 and m11) need
0336             * to be factored in to complete the transformation equation of
0337             * this transform.  If the APPLY_SHEAR bit is also set then it
0338             * indicates that the scaling components are not both 0.0.  If the
0339             * APPLY_SHEAR bit is not also set then it indicates that the
0340             * scaling components are not both 1.0.  If neither the APPLY_SHEAR
0341             * nor the APPLY_SCALE bits are set then the scaling components
0342             * are both 1.0, which means that the x and y components contribute
0343             * to the transformed coordinate, but they are not multiplied by
0344             * any scaling factor.
0345             * @see #APPLY_IDENTITY
0346             * @see #APPLY_TRANSLATE
0347             * @see #APPLY_SHEAR
0348             * @see #state
0349             */
0350            static final int APPLY_SCALE = 2;
0351
0352            /**
0353             * This constant is used for the internal state variable to indicate
0354             * that the shearing components of the matrix (m01 and m10) need
0355             * to be factored in to complete the transformation equation of this
0356             * transform.  The presence of this bit in the state variable changes
0357             * the interpretation of the APPLY_SCALE bit as indicated in its
0358             * documentation.
0359             * @see #APPLY_IDENTITY
0360             * @see #APPLY_TRANSLATE
0361             * @see #APPLY_SCALE
0362             * @see #state
0363             */
0364            static final int APPLY_SHEAR = 4;
0365
0366            /*
0367             * For methods which combine together the state of two separate
0368             * transforms and dispatch based upon the combination, these constants
0369             * specify how far to shift one of the states so that the two states 
0370             * are mutually non-interfering and provide constants for testing the
0371             * bits of the shifted (HI) state.  The methods in this class use
0372             * the convention that the state of "this" transform is unshifted and
0373             * the state of the "other" or "argument" transform is shifted (HI).
0374             */
0375            private static final int HI_SHIFT = 3;
0376            private static final int HI_IDENTITY = APPLY_IDENTITY << HI_SHIFT;
0377            private static final int HI_TRANSLATE = APPLY_TRANSLATE << HI_SHIFT;
0378            private static final int HI_SCALE = APPLY_SCALE << HI_SHIFT;
0379            private static final int HI_SHEAR = APPLY_SHEAR << HI_SHIFT;
0380
0381            /**
0382             * The X coordinate scaling element of the 3x3
0383             * affine transformation matrix.
0384             * 
0385             * @serial
0386             */
0387            double m00;
0388
0389            /**
0390             * The Y coordinate shearing element of the 3x3
0391             * affine transformation matrix.
0392             *
0393             * @serial
0394             */
0395            double m10;
0396
0397            /**
0398             * The X coordinate shearing element of the 3x3
0399             * affine transformation matrix.
0400             *
0401             * @serial
0402             */
0403            double m01;
0404
0405            /**
0406             * The Y coordinate scaling element of the 3x3
0407             * affine transformation matrix.
0408             * 
0409             * @serial
0410             */
0411            double m11;
0412
0413            /**
0414             * The X coordinate of the translation element of the
0415             * 3x3 affine transformation matrix.
0416             * 
0417             * @serial
0418             */
0419            double m02;
0420
0421            /**
0422             * The Y coordinate of the translation element of the
0423             * 3x3 affine transformation matrix.
0424             *
0425             * @serial
0426             */
0427            double m12;
0428
0429            /**
0430             * This field keeps track of which components of the matrix need to
0431             * be applied when performing a transformation.
0432             * @see #APPLY_IDENTITY
0433             * @see #APPLY_TRANSLATE
0434             * @see #APPLY_SCALE
0435             * @see #APPLY_SHEAR
0436             */
0437            transient int state;
0438
0439            /**
0440             * This field caches the current transformation type of the matrix.
0441             * @see #TYPE_IDENTITY
0442             * @see #TYPE_TRANSLATION
0443             * @see #TYPE_UNIFORM_SCALE
0444             * @see #TYPE_GENERAL_SCALE
0445             * @see #TYPE_FLIP
0446             * @see #TYPE_QUADRANT_ROTATION
0447             * @see #TYPE_GENERAL_ROTATION
0448             * @see #TYPE_GENERAL_TRANSFORM
0449             * @see #TYPE_UNKNOWN
0450             * @see #getType
0451             */
0452            private transient int type;
0453
0454            private AffineTransform(double m00, double m10, double m01,
0455                    double m11, double m02, double m12, int state) {
0456                this .m00 = m00;
0457                this .m10 = m10;
0458                this .m01 = m01;
0459                this .m11 = m11;
0460                this .m02 = m02;
0461                this .m12 = m12;
0462                this .state = state;
0463                this .type = TYPE_UNKNOWN;
0464            }
0465
0466            /**
0467             * Constructs a new <code>AffineTransform</code> representing the
0468             * Identity transformation.
0469             * @since 1.2
0470             */
0471            public AffineTransform() {
0472                m00 = m11 = 1.0;
0473                // m01 = m10 = m02 = m12 = 0.0;		/* Not needed. */
0474                // state = APPLY_IDENTITY;		/* Not needed. */
0475                // type = TYPE_IDENTITY;		/* Not needed. */
0476            }
0477
0478            /**
0479             * Constructs a new <code>AffineTransform</code> that is a copy of
0480             * the specified <code>AffineTransform</code> object.
0481             * @param Tx the <code>AffineTransform</code> object to copy 
0482             * @since 1.2
0483             */
0484            public AffineTransform(AffineTransform Tx) {
0485                this .m00 = Tx.m00;
0486                this .m10 = Tx.m10;
0487                this .m01 = Tx.m01;
0488                this .m11 = Tx.m11;
0489                this .m02 = Tx.m02;
0490                this .m12 = Tx.m12;
0491                this .state = Tx.state;
0492                this .type = Tx.type;
0493            }
0494
0495            /**
0496             * Constructs a new <code>AffineTransform</code> from 6 floating point
0497             * values representing the 6 specifiable entries of the 3x3
0498             * transformation matrix.
0499             *
0500             * @param m00 the X coordinate scaling element of the 3x3 matrix
0501             * @param m10 the Y coordinate shearing element of the 3x3 matrix
0502             * @param m01 the X coordinate shearing element of the 3x3 matrix
0503             * @param m11 the Y coordinate scaling element of the 3x3 matrix
0504             * @param m02 the X coordinate translation element of the 3x3 matrix
0505             * @param m12 the Y coordinate translation element of the 3x3 matrix
0506             * @since 1.2
0507             */
0508            public AffineTransform(float m00, float m10, float m01, float m11,
0509                    float m02, float m12) {
0510                this .m00 = m00;
0511                this .m10 = m10;
0512                this .m01 = m01;
0513                this .m11 = m11;
0514                this .m02 = m02;
0515                this .m12 = m12;
0516                updateState();
0517            }
0518
0519            /**
0520             * Constructs a new <code>AffineTransform</code> from an array of
0521             * floating point values representing either the 4 non-translation 
0522             * enries or the 6 specifiable entries of the 3x3 transformation
0523             * matrix.  The values are retrieved from the array as 
0524             * {&nbsp;m00&nbsp;m10&nbsp;m01&nbsp;m11&nbsp;[m02&nbsp;m12]}.
0525             * @param flatmatrix the float array containing the values to be set
0526             * in the new <code>AffineTransform</code> object. The length of the
0527             * array is assumed to be at least 4. If the length of the array is 
0528             * less than 6, only the first 4 values are taken. If the length of
0529             * the array is greater than 6, the first 6 values are taken.
0530             * @since 1.2
0531             */
0532            public AffineTransform(float[] flatmatrix) {
0533                m00 = flatmatrix[0];
0534                m10 = flatmatrix[1];
0535                m01 = flatmatrix[2];
0536                m11 = flatmatrix[3];
0537                if (flatmatrix.length > 5) {
0538                    m02 = flatmatrix[4];
0539                    m12 = flatmatrix[5];
0540                }
0541                updateState();
0542            }
0543
0544            /**
0545             * Constructs a new <code>AffineTransform</code> from 6 double
0546             * precision values representing the 6 specifiable entries of the 3x3
0547             * transformation matrix.
0548             *
0549             * @param m00 the X coordinate scaling element of the 3x3 matrix
0550             * @param m10 the Y coordinate shearing element of the 3x3 matrix
0551             * @param m01 the X coordinate shearing element of the 3x3 matrix
0552             * @param m11 the Y coordinate scaling element of the 3x3 matrix
0553             * @param m02 the X coordinate translation element of the 3x3 matrix
0554             * @param m12 the Y coordinate translation element of the 3x3 matrix
0555             * @since 1.2
0556             */
0557            public AffineTransform(double m00, double m10, double m01,
0558                    double m11, double m02, double m12) {
0559                this .m00 = m00;
0560                this .m10 = m10;
0561                this .m01 = m01;
0562                this .m11 = m11;
0563                this .m02 = m02;
0564                this .m12 = m12;
0565                updateState();
0566            }
0567
0568            /**
0569             * Constructs a new <code>AffineTransform</code> from an array of
0570             * double precision values representing either the 4 non-translation
0571             * entries or the 6 specifiable entries of the 3x3 transformation
0572             * matrix. The values are retrieved from the array as 
0573             * {&nbsp;m00&nbsp;m10&nbsp;m01&nbsp;m11&nbsp;[m02&nbsp;m12]}.     
0574             * @param flatmatrix the double array containing the values to be set
0575             * in the new <code>AffineTransform</code> object. The length of the
0576             * array is assumed to be at least 4. If the length of the array is 
0577             * less than 6, only the first 4 values are taken. If the length of
0578             * the array is greater than 6, the first 6 values are taken.
0579             * @since 1.2
0580             */
0581            public AffineTransform(double[] flatmatrix) {
0582                m00 = flatmatrix[0];
0583                m10 = flatmatrix[1];
0584                m01 = flatmatrix[2];
0585                m11 = flatmatrix[3];
0586                if (flatmatrix.length > 5) {
0587                    m02 = flatmatrix[4];
0588                    m12 = flatmatrix[5];
0589                }
0590                updateState();
0591            }
0592
0593            /**
0594             * Returns a transform representing a translation transformation.
0595             * The matrix representing the returned transform is:
0596             * <pre>
0597             *		[   1    0    tx  ]
0598             *		[   0    1    ty  ]
0599             *		[   0    0    1   ]
0600             * </pre>
0601             * @param tx the distance by which coordinates are translated in the
0602             * X axis direction
0603             * @param ty the distance by which coordinates are translated in the
0604             * Y axis direction
0605             * @return an <code>AffineTransform</code> object that represents a
0606             * 	translation transformation, created with the specified vector.
0607             * @since 1.2
0608             */
0609            public static AffineTransform getTranslateInstance(double tx,
0610                    double ty) {
0611                AffineTransform Tx = new AffineTransform();
0612                Tx.setToTranslation(tx, ty);
0613                return Tx;
0614            }
0615
0616            /**
0617             * Returns a transform representing a rotation transformation.
0618             * The matrix representing the returned transform is:
0619             * <pre>
0620             *		[   cos(theta)    -sin(theta)    0   ]
0621             *		[   sin(theta)     cos(theta)    0   ]
0622             *		[       0              0         1   ]
0623             * </pre>
0624             * Rotating by a positive angle theta rotates points on the positive
0625             * X axis toward the positive Y axis.
0626             * Note also the discussion of
0627             * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
0628             * above.
0629             * @param theta the angle of rotation measured in radians
0630             * @return an <code>AffineTransform</code> object that is a rotation
0631             *	transformation, created with the specified angle of rotation.
0632             * @since 1.2
0633             */
0634            public static AffineTransform getRotateInstance(double theta) {
0635                AffineTransform Tx = new AffineTransform();
0636                Tx.setToRotation(theta);
0637                return Tx;
0638            }
0639
0640            /**
0641             * Returns a transform that rotates coordinates around an anchor point.
0642             * This operation is equivalent to translating the coordinates so
0643             * that the anchor point is at the origin (S1), then rotating them
0644             * about the new origin (S2), and finally translating so that the
0645             * intermediate origin is restored to the coordinates of the original
0646             * anchor point (S3).
0647             * <p>
0648             * This operation is equivalent to the following sequence of calls:
0649             * <pre>
0650             *     AffineTransform Tx = new AffineTransform();
0651             *     Tx.translate(anchorx, anchory);    // S3: final translation
0652             *     Tx.rotate(theta);		      // S2: rotate around anchor
0653             *     Tx.translate(-anchorx, -anchory);  // S1: translate anchor to origin
0654             * </pre>
0655             * The matrix representing the returned transform is:
0656             * <pre>
0657             *		[   cos(theta)    -sin(theta)    x-x*cos+y*sin  ]
0658             *		[   sin(theta)     cos(theta)    y-x*sin-y*cos  ]
0659             *		[       0              0               1        ]
0660             * </pre>
0661             * Rotating by a positive angle theta rotates points on the positive
0662             * X axis toward the positive Y axis.
0663             * Note also the discussion of
0664             * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
0665             * above.
0666             *
0667             * @param theta the angle of rotation measured in radians
0668             * @param anchorx the X coordinate of the rotation anchor point
0669             * @param anchory the Y coordinate of the rotation anchor point
0670             * @return an <code>AffineTransform</code> object that rotates 
0671             *	coordinates around the specified point by the specified angle of
0672             *	rotation.
0673             * @since 1.2
0674             */
0675            public static AffineTransform getRotateInstance(double theta,
0676                    double anchorx, double anchory) {
0677                AffineTransform Tx = new AffineTransform();
0678                Tx.setToRotation(theta, anchorx, anchory);
0679                return Tx;
0680            }
0681
0682            /**
0683             * Returns a transform that rotates coordinates according to
0684             * a rotation vector.
0685             * All coordinates rotate about the origin by the same amount.
0686             * The amount of rotation is such that coordinates along the former
0687             * positive X axis will subsequently align with the vector pointing
0688             * from the origin to the specified vector coordinates.
0689             * If both <code>vecx</code> and <code>vecy</code> are 0.0,
0690             * an identity transform is returned.
0691             * This operation is equivalent to calling:
0692             * <pre>
0693             *     AffineTransform.getRotateInstance(Math.atan2(vecy, vecx));
0694             * </pre>
0695             *
0696             * @param vecx the X coordinate of the rotation vector
0697             * @param vecy the Y coordinate of the rotation vector
0698             * @return an <code>AffineTransform</code> object that rotates
0699             *  coordinates according to the specified rotation vector.
0700             * @since 1.6
0701             */
0702            public static AffineTransform getRotateInstance(double vecx,
0703                    double vecy) {
0704                AffineTransform Tx = new AffineTransform();
0705                Tx.setToRotation(vecx, vecy);
0706                return Tx;
0707            }
0708
0709            /**
0710             * Returns a transform that rotates coordinates around an anchor
0711             * point accordinate to a rotation vector.
0712             * All coordinates rotate about the specified anchor coordinates
0713             * by the same amount.
0714             * The amount of rotation is such that coordinates along the former
0715             * positive X axis will subsequently align with the vector pointing
0716             * from the origin to the specified vector coordinates.
0717             * If both <code>vecx</code> and <code>vecy</code> are 0.0,
0718             * an identity transform is returned.
0719             * This operation is equivalent to calling:
0720             * <pre>
0721             *     AffineTransform.getRotateInstance(Math.atan2(vecy, vecx),
0722             *                                       anchorx, anchory);
0723             * </pre>
0724             *
0725             * @param vecx the X coordinate of the rotation vector
0726             * @param vecy the Y coordinate of the rotation vector
0727             * @param anchorx the X coordinate of the rotation anchor point
0728             * @param anchory the Y coordinate of the rotation anchor point
0729             * @return an <code>AffineTransform</code> object that rotates 
0730             *	coordinates around the specified point according to the
0731             *  specified rotation vector.
0732             * @since 1.6
0733             */
0734            public static AffineTransform getRotateInstance(double vecx,
0735                    double vecy, double anchorx, double anchory) {
0736                AffineTransform Tx = new AffineTransform();
0737                Tx.setToRotation(vecx, vecy, anchorx, anchory);
0738                return Tx;
0739            }
0740
0741            /**
0742             * Returns a transform that rotates coordinates by the specified
0743             * number of quadrants.
0744             * This operation is equivalent to calling:
0745             * <pre>
0746             *     AffineTransform.getRotateInstance(numquadrants * Math.PI / 2.0);
0747             * </pre>
0748             * Rotating by a positive number of quadrants rotates points on
0749             * the positive X axis toward the positive Y axis.
0750             * @param numquadrants the number of 90 degree arcs to rotate by
0751             * @return an <code>AffineTransform</code> object that rotates
0752             *  coordinates by the specified number of quadrants.
0753             * @since 1.6
0754             */
0755            public static AffineTransform getQuadrantRotateInstance(
0756                    int numquadrants) {
0757                AffineTransform Tx = new AffineTransform();
0758                Tx.setToQuadrantRotation(numquadrants);
0759                return Tx;
0760            }
0761
0762            /**
0763             * Returns a transform that rotates coordinates by the specified
0764             * number of quadrants around the specified anchor point.
0765             * This operation is equivalent to calling:
0766             * <pre>
0767             *     AffineTransform.getRotateInstance(numquadrants * Math.PI / 2.0,
0768             *                                       anchorx, anchory);
0769             * </pre>
0770             * Rotating by a positive number of quadrants rotates points on
0771             * the positive X axis toward the positive Y axis.
0772             *
0773             * @param numquadrants the number of 90 degree arcs to rotate by
0774             * @param anchorx the X coordinate of the rotation anchor point
0775             * @param anchory the Y coordinate of the rotation anchor point
0776             * @return an <code>AffineTransform</code> object that rotates 
0777             *	coordinates by the specified number of quadrants around the
0778             *  specified anchor point.
0779             * @since 1.6
0780             */
0781            public static AffineTransform getQuadrantRotateInstance(
0782                    int numquadrants, double anchorx, double anchory) {
0783                AffineTransform Tx = new AffineTransform();
0784                Tx.setToQuadrantRotation(numquadrants, anchorx, anchory);
0785                return Tx;
0786            }
0787
0788            /**
0789             * Returns a transform representing a scaling transformation.
0790             * The matrix representing the returned transform is:
0791             * <pre>
0792             *		[   sx   0    0   ]
0793             *		[   0    sy   0   ]
0794             *		[   0    0    1   ]
0795             * </pre>
0796             * @param sx the factor by which coordinates are scaled along the
0797             * X axis direction
0798             * @param sy the factor by which coordinates are scaled along the
0799             * Y axis direction
0800             * @return an <code>AffineTransform</code> object that scales 
0801             *	coordinates by the specified factors.
0802             * @since 1.2
0803             */
0804            public static AffineTransform getScaleInstance(double sx, double sy) {
0805                AffineTransform Tx = new AffineTransform();
0806                Tx.setToScale(sx, sy);
0807                return Tx;
0808            }
0809
0810            /**
0811             * Returns a transform representing a shearing transformation.
0812             * The matrix representing the returned transform is:
0813             * <pre>
0814             *		[   1   shx   0   ]
0815             *		[  shy   1    0   ]
0816             *		[   0    0    1   ]
0817             * </pre>
0818             * @param shx the multiplier by which coordinates are shifted in the
0819             * direction of the positive X axis as a factor of their Y coordinate
0820             * @param shy the multiplier by which coordinates are shifted in the
0821             * direction of the positive Y axis as a factor of their X coordinate
0822             * @return an <code>AffineTransform</code> object that shears 
0823             *	coordinates by the specified multipliers.
0824             * @since 1.2
0825             */
0826            public static AffineTransform getShearInstance(double shx,
0827                    double shy) {
0828                AffineTransform Tx = new AffineTransform();
0829                Tx.setToShear(shx, shy);
0830                return Tx;
0831            }
0832
0833            /**
0834             * Retrieves the flag bits describing the conversion properties of
0835             * this transform.
0836             * The return value is either one of the constants TYPE_IDENTITY
0837             * or TYPE_GENERAL_TRANSFORM, or a combination of the
0838             * appriopriate flag bits.
0839             * A valid combination of flag bits is an exclusive OR operation
0840             * that can combine
0841             * the TYPE_TRANSLATION flag bit
0842             * in addition to either of the
0843             * TYPE_UNIFORM_SCALE or TYPE_GENERAL_SCALE flag bits
0844             * as well as either of the
0845             * TYPE_QUADRANT_ROTATION or TYPE_GENERAL_ROTATION flag bits.
0846             * @return the OR combination of any of the indicated flags that
0847             * apply to this transform
0848             * @see #TYPE_IDENTITY
0849             * @see #TYPE_TRANSLATION
0850             * @see #TYPE_UNIFORM_SCALE
0851             * @see #TYPE_GENERAL_SCALE
0852             * @see #TYPE_QUADRANT_ROTATION
0853             * @see #TYPE_GENERAL_ROTATION
0854             * @see #TYPE_GENERAL_TRANSFORM
0855             * @since 1.2
0856             */
0857            public int getType() {
0858                if (type == TYPE_UNKNOWN) {
0859                    calculateType();
0860                }
0861                return type;
0862            }
0863
0864            /**
0865             * This is the utility function to calculate the flag bits when
0866             * they have not been cached.
0867             * @see #getType
0868             */
0869            private void calculateType() {
0870                int ret = TYPE_IDENTITY;
0871                boolean sgn0, sgn1;
0872                double M0, M1, M2, M3;
0873                updateState();
0874                switch (state) {
0875                default:
0876                    stateError();
0877                    /* NOTREACHED */
0878                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
0879                    ret = TYPE_TRANSLATION;
0880                    /* NOBREAK */
0881                case (APPLY_SHEAR | APPLY_SCALE):
0882                    if ((M0 = m00) * (M2 = m01) + (M3 = m10) * (M1 = m11) != 0) {
0883                        // Transformed unit vectors are not perpendicular...
0884                        this .type = TYPE_GENERAL_TRANSFORM;
0885                        return;
0886                    }
0887                    sgn0 = (M0 >= 0.0);
0888                    sgn1 = (M1 >= 0.0);
0889                    if (sgn0 == sgn1) {
0890                        // sgn(M0) == sgn(M1) therefore sgn(M2) == -sgn(M3)
0891                        // This is the "unflipped" (right-handed) state
0892                        if (M0 != M1 || M2 != -M3) {
0893                            ret |= (TYPE_GENERAL_ROTATION | TYPE_GENERAL_SCALE);
0894                        } else if (M0 * M1 - M2 * M3 != 1.0) {
0895                            ret |= (TYPE_GENERAL_ROTATION | TYPE_UNIFORM_SCALE);
0896                        } else {
0897                            ret |= TYPE_GENERAL_ROTATION;
0898                        }
0899                    } else {
0900                        // sgn(M0) == -sgn(M1) therefore sgn(M2) == sgn(M3)
0901                        // This is the "flipped" (left-handed) state
0902                        if (M0 != -M1 || M2 != M3) {
0903                            ret |= (TYPE_GENERAL_ROTATION | TYPE_FLIP | TYPE_GENERAL_SCALE);
0904                        } else if (M0 * M1 - M2 * M3 != 1.0) {
0905                            ret |= (TYPE_GENERAL_ROTATION | TYPE_FLIP | TYPE_UNIFORM_SCALE);
0906                        } else {
0907                            ret |= (TYPE_GENERAL_ROTATION | TYPE_FLIP);
0908                        }
0909                    }
0910                    break;
0911                case (APPLY_SHEAR | APPLY_TRANSLATE):
0912                    ret = TYPE_TRANSLATION;
0913                    /* NOBREAK */
0914                case (APPLY_SHEAR):
0915                    sgn0 = ((M0 = m01) >= 0.0);
0916                    sgn1 = ((M1 = m10) >= 0.0);
0917                    if (sgn0 != sgn1) {
0918                        // Different signs - simple 90 degree rotation
0919                        if (M0 != -M1) {
0920                            ret |= (TYPE_QUADRANT_ROTATION | TYPE_GENERAL_SCALE);
0921                        } else if (M0 != 1.0 && M0 != -1.0) {
0922                            ret |= (TYPE_QUADRANT_ROTATION | TYPE_UNIFORM_SCALE);
0923                        } else {
0924                            ret |= TYPE_QUADRANT_ROTATION;
0925                        }
0926                    } else {
0927                        // Same signs - 90 degree rotation plus an axis flip too
0928                        if (M0 == M1) {
0929                            ret |= (TYPE_QUADRANT_ROTATION | TYPE_FLIP | TYPE_UNIFORM_SCALE);
0930                        } else {
0931                            ret |= (TYPE_QUADRANT_ROTATION | TYPE_FLIP | TYPE_GENERAL_SCALE);
0932                        }
0933                    }
0934                    break;
0935                case (APPLY_SCALE | APPLY_TRANSLATE):
0936                    ret = TYPE_TRANSLATION;
0937                    /* NOBREAK */
0938                case (APPLY_SCALE):
0939                    sgn0 = ((M0 = m00) >= 0.0);
0940                    sgn1 = ((M1 = m11) >= 0.0);
0941                    if (sgn0 == sgn1) {
0942                        if (sgn0) {
0943                            // Both scaling factors non-negative - simple scale
0944                            // Note: APPLY_SCALE implies M0, M1 are not both 1
0945                            if (M0 == M1) {
0946                                ret |= TYPE_UNIFORM_SCALE;
0947                            } else {
0948                                ret |= TYPE_GENERAL_SCALE;
0949                            }
0950                        } else {
0951                            // Both scaling factors negative - 180 degree rotation
0952                            if (M0 != M1) {
0953                                ret |= (TYPE_QUADRANT_ROTATION | TYPE_GENERAL_SCALE);
0954                            } else if (M0 != -1.0) {
0955                                ret |= (TYPE_QUADRANT_ROTATION | TYPE_UNIFORM_SCALE);
0956                            } else {
0957                                ret |= TYPE_QUADRANT_ROTATION;
0958                            }
0959                        }
0960                    } else {
0961                        // Scaling factor signs different - flip about some axis
0962                        if (M0 == -M1) {
0963                            if (M0 == 1.0 || M0 == -1.0) {
0964                                ret |= TYPE_FLIP;
0965                            } else {
0966                                ret |= (TYPE_FLIP | TYPE_UNIFORM_SCALE);
0967                            }
0968                        } else {
0969                            ret |= (TYPE_FLIP | TYPE_GENERAL_SCALE);
0970                        }
0971                    }
0972                    break;
0973                case (APPLY_TRANSLATE):
0974                    ret = TYPE_TRANSLATION;
0975                    break;
0976                case (APPLY_IDENTITY):
0977                    break;
0978                }
0979                this .type = ret;
0980            }
0981
0982            /**
0983             * Returns the determinant of the matrix representation of the transform.
0984             * The determinant is useful both to determine if the transform can
0985             * be inverted and to get a single value representing the
0986             * combined X and Y scaling of the transform.
0987             * <p>
0988             * If the determinant is non-zero, then this transform is
0989             * invertible and the various methods that depend on the inverse
0990             * transform do not need to throw a
0991             * {@link NoninvertibleTransformException}.
0992             * If the determinant is zero then this transform can not be
0993             * inverted since the transform maps all input coordinates onto
0994             * a line or a point.
0995             * If the determinant is near enough to zero then inverse transform
0996             * operations might not carry enough precision to produce meaningful
0997             * results.
0998             * <p>
0999             * If this transform represents a uniform scale, as indicated by
1000             * the <code>getType</code> method then the determinant also
1001             * represents the square of the uniform scale factor by which all of
1002             * the points are expanded from or contracted towards the origin.
1003             * If this transform represents a non-uniform scale or more general
1004             * transform then the determinant is not likely to represent a
1005             * value useful for any purpose other than determining if inverse
1006             * transforms are possible.
1007             * <p>
1008             * Mathematically, the determinant is calculated using the formula:
1009             * <pre>
1010             *		|  m00  m01  m02  |
1011             *		|  m10  m11  m12  |  =  m00 * m11 - m01 * m10
1012             *		|   0    0    1   |
1013             * </pre>
1014             *
1015             * @return the determinant of the matrix used to transform the
1016             * coordinates.
1017             * @see #getType
1018             * @see #createInverse
1019             * @see #inverseTransform
1020             * @see #TYPE_UNIFORM_SCALE
1021             * @since 1.2
1022             */
1023            public double getDeterminant() {
1024                switch (state) {
1025                default:
1026                    stateError();
1027                    /* NOTREACHED */
1028                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1029                case (APPLY_SHEAR | APPLY_SCALE):
1030                    return m00 * m11 - m01 * m10;
1031                case (APPLY_SHEAR | APPLY_TRANSLATE):
1032                case (APPLY_SHEAR):
1033                    return -(m01 * m10);
1034                case (APPLY_SCALE | APPLY_TRANSLATE):
1035                case (APPLY_SCALE):
1036                    return m00 * m11;
1037                case (APPLY_TRANSLATE):
1038                case (APPLY_IDENTITY):
1039                    return 1.0;
1040                }
1041            }
1042
1043            /**
1044             * Manually recalculates the state of the transform when the matrix
1045             * changes too much to predict the effects on the state.
1046             * The following table specifies what the various settings of the
1047             * state field say about the values of the corresponding matrix
1048             * element fields.
1049             * Note that the rules governing the SCALE fields are slightly
1050             * different depending on whether the SHEAR flag is also set.
1051             * <pre>
1052             *                     SCALE            SHEAR          TRANSLATE
1053             *                    m00/m11          m01/m10          m02/m12
1054             *
1055             * IDENTITY             1.0              0.0              0.0
1056             * TRANSLATE (TR)       1.0              0.0          not both 0.0
1057             * SCALE (SC)       not both 1.0         0.0              0.0
1058             * TR | SC          not both 1.0         0.0          not both 0.0
1059             * SHEAR (SH)           0.0          not both 0.0         0.0
1060             * TR | SH              0.0          not both 0.0     not both 0.0
1061             * SC | SH          not both 0.0     not both 0.0         0.0
1062             * TR | SC | SH     not both 0.0     not both 0.0     not both 0.0
1063             * </pre>
1064             */
1065            void updateState() {
1066                if (m01 == 0.0 && m10 == 0.0) {
1067                    if (m00 == 1.0 && m11 == 1.0) {
1068                        if (m02 == 0.0 && m12 == 0.0) {
1069                            state = APPLY_IDENTITY;
1070                            type = TYPE_IDENTITY;
1071                        } else {
1072                            state = APPLY_TRANSLATE;
1073                            type = TYPE_TRANSLATION;
1074                        }
1075                    } else {
1076                        if (m02 == 0.0 && m12 == 0.0) {
1077                            state = APPLY_SCALE;
1078                            type = TYPE_UNKNOWN;
1079                        } else {
1080                            state = (APPLY_SCALE | APPLY_TRANSLATE);
1081                            type = TYPE_UNKNOWN;
1082                        }
1083                    }
1084                } else {
1085                    if (m00 == 0.0 && m11 == 0.0) {
1086                        if (m02 == 0.0 && m12 == 0.0) {
1087                            state = APPLY_SHEAR;
1088                            type = TYPE_UNKNOWN;
1089                        } else {
1090                            state = (APPLY_SHEAR | APPLY_TRANSLATE);
1091                            type = TYPE_UNKNOWN;
1092                        }
1093                    } else {
1094                        if (m02 == 0.0 && m12 == 0.0) {
1095                            state = (APPLY_SHEAR | APPLY_SCALE);
1096                            type = TYPE_UNKNOWN;
1097                        } else {
1098                            state = (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE);
1099                            type = TYPE_UNKNOWN;
1100                        }
1101                    }
1102                }
1103            }
1104
1105            /*
1106             * Convenience method used internally to throw exceptions when
1107             * a case was forgotten in a switch statement.
1108             */
1109            private void stateError() {
1110                throw new InternalError(
1111                        "missing case in transform state switch");
1112            }
1113
1114            /**
1115             * Retrieves the 6 specifiable values in the 3x3 affine transformation
1116             * matrix and places them into an array of double precisions values.
1117             * The values are stored in the array as 
1118             * {&nbsp;m00&nbsp;m10&nbsp;m01&nbsp;m11&nbsp;m02&nbsp;m12&nbsp;}.
1119             * An array of 4 doubles can also be specified, in which case only the
1120             * first four elements representing the non-transform
1121             * parts of the array are retrieved and the values are stored into 
1122             * the array as {&nbsp;m00&nbsp;m10&nbsp;m01&nbsp;m11&nbsp;}
1123             * @param flatmatrix the double array used to store the returned
1124             * values.
1125             * @see #getScaleX
1126             * @see #getScaleY
1127             * @see #getShearX
1128             * @see #getShearY
1129             * @see #getTranslateX
1130             * @see #getTranslateY
1131             * @since 1.2
1132             */
1133            public void getMatrix(double[] flatmatrix) {
1134                flatmatrix[0] = m00;
1135                flatmatrix[1] = m10;
1136                flatmatrix[2] = m01;
1137                flatmatrix[3] = m11;
1138                if (flatmatrix.length > 5) {
1139                    flatmatrix[4] = m02;
1140                    flatmatrix[5] = m12;
1141                }
1142            }
1143
1144            /**
1145             * Returns the X coordinate scaling element (m00) of the 3x3
1146             * affine transformation matrix.
1147             * @return a double value that is the X coordinate of the scaling
1148             *  element of the affine transformation matrix.
1149             * @see #getMatrix
1150             * @since 1.2
1151             */
1152            public double getScaleX() {
1153                return m00;
1154            }
1155
1156            /**
1157             * Returns the Y coordinate scaling element (m11) of the 3x3
1158             * affine transformation matrix.
1159             * @return a double value that is the Y coordinate of the scaling
1160             *  element of the affine transformation matrix.
1161             * @see #getMatrix
1162             * @since 1.2
1163             */
1164            public double getScaleY() {
1165                return m11;
1166            }
1167
1168            /**
1169             * Returns the X coordinate shearing element (m01) of the 3x3
1170             * affine transformation matrix.
1171             * @return a double value that is the X coordinate of the shearing
1172             *  element of the affine transformation matrix.
1173             * @see #getMatrix
1174             * @since 1.2
1175             */
1176            public double getShearX() {
1177                return m01;
1178            }
1179
1180            /**
1181             * Returns the Y coordinate shearing element (m10) of the 3x3
1182             * affine transformation matrix.
1183             * @return a double value that is the Y coordinate of the shearing
1184             *  element of the affine transformation matrix.
1185             * @see #getMatrix
1186             * @since 1.2
1187             */
1188            public double getShearY() {
1189                return m10;
1190            }
1191
1192            /**
1193             * Returns the X coordinate of the translation element (m02) of the
1194             * 3x3 affine transformation matrix.
1195             * @return a double value that is the X coordinate of the translation
1196             *  element of the affine transformation matrix.
1197             * @see #getMatrix
1198             * @since 1.2
1199             */
1200            public double getTranslateX() {
1201                return m02;
1202            }
1203
1204            /**
1205             * Returns the Y coordinate of the translation element (m12) of the
1206             * 3x3 affine transformation matrix.
1207             * @return a double value that is the Y coordinate of the translation
1208             *  element of the affine transformation matrix. 
1209             * @see #getMatrix
1210             * @since 1.2
1211             */
1212            public double getTranslateY() {
1213                return m12;
1214            }
1215
1216            /**
1217             * Concatenates this transform with a translation transformation.
1218             * This is equivalent to calling concatenate(T), where T is an
1219             * <code>AffineTransform</code> represented by the following matrix:
1220             * <pre>
1221             *		[   1    0    tx  ]
1222             *		[   0    1    ty  ]
1223             *		[   0    0    1   ]
1224             * </pre>
1225             * @param tx the distance by which coordinates are translated in the
1226             * X axis direction
1227             * @param ty the distance by which coordinates are translated in the
1228             * Y axis direction
1229             * @since 1.2
1230             */
1231            public void translate(double tx, double ty) {
1232                switch (state) {
1233                default:
1234                    stateError();
1235                    /* NOTREACHED */
1236                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1237                    m02 = tx * m00 + ty * m01 + m02;
1238                    m12 = tx * m10 + ty * m11 + m12;
1239                    if (m02 == 0.0 && m12 == 0.0) {
1240                        state = APPLY_SHEAR | APPLY_SCALE;
1241                        if (type != TYPE_UNKNOWN) {
1242                            type -= TYPE_TRANSLATION;
1243                        }
1244                    }
1245                    return;
1246                case (APPLY_SHEAR | APPLY_SCALE):
1247                    m02 = tx * m00 + ty * m01;
1248                    m12 = tx * m10 + ty * m11;
1249                    if (m02 != 0.0 || m12 != 0.0) {
1250                        state = APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE;
1251                        type |= TYPE_TRANSLATION;
1252                    }
1253                    return;
1254                case (APPLY_SHEAR | APPLY_TRANSLATE):
1255                    m02 = ty * m01 + m02;
1256                    m12 = tx * m10 + m12;
1257                    if (m02 == 0.0 && m12 == 0.0) {
1258                        state = APPLY_SHEAR;
1259                        if (type != TYPE_UNKNOWN) {
1260                            type -= TYPE_TRANSLATION;
1261                        }
1262                    }
1263                    return;
1264                case (APPLY_SHEAR):
1265                    m02 = ty * m01;
1266                    m12 = tx * m10;
1267                    if (m02 != 0.0 || m12 != 0.0) {
1268                        state = APPLY_SHEAR | APPLY_TRANSLATE;
1269                        type |= TYPE_TRANSLATION;
1270                    }
1271                    return;
1272                case (APPLY_SCALE | APPLY_TRANSLATE):
1273                    m02 = tx * m00 + m02;
1274                    m12 = ty * m11 + m12;
1275                    if (m02 == 0.0 && m12 == 0.0) {
1276                        state = APPLY_SCALE;
1277                        if (type != TYPE_UNKNOWN) {
1278                            type -= TYPE_TRANSLATION;
1279                        }
1280                    }
1281                    return;
1282                case (APPLY_SCALE):
1283                    m02 = tx * m00;
1284                    m12 = ty * m11;
1285                    if (m02 != 0.0 || m12 != 0.0) {
1286                        state = APPLY_SCALE | APPLY_TRANSLATE;
1287                        type |= TYPE_TRANSLATION;
1288                    }
1289                    return;
1290                case (APPLY_TRANSLATE):
1291                    m02 = tx + m02;
1292                    m12 = ty + m12;
1293                    if (m02 == 0.0 && m12 == 0.0) {
1294                        state = APPLY_IDENTITY;
1295                        type = TYPE_IDENTITY;
1296                    }
1297                    return;
1298                case (APPLY_IDENTITY):
1299                    m02 = tx;
1300                    m12 = ty;
1301                    if (tx != 0.0 || ty != 0.0) {
1302                        state = APPLY_TRANSLATE;
1303                        type = TYPE_TRANSLATION;
1304                    }
1305                    return;
1306                }
1307            }
1308
1309            // Utility methods to optimize rotate methods.
1310            // These tables translate the flags during predictable quadrant
1311            // rotations where the shear and scale values are swapped and negated.
1312            private static final int rot90conversion[] = {
1313            /* IDENTITY => */APPLY_SHEAR,
1314            /* TRANSLATE (TR) => */APPLY_SHEAR | APPLY_TRANSLATE,
1315            /* SCALE (SC) => */APPLY_SHEAR,
1316            /* SC | TR => */APPLY_SHEAR | APPLY_TRANSLATE,
1317            /* SHEAR (SH) => */APPLY_SCALE,
1318            /* SH | TR => */APPLY_SCALE | APPLY_TRANSLATE,
1319            /* SH | SC => */APPLY_SHEAR | APPLY_SCALE,
1320            /* SH | SC | TR => */APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE, };
1321
1322            private final void rotate90() {
1323                double M0 = m00;
1324                m00 = m01;
1325                m01 = -M0;
1326                M0 = m10;
1327                m10 = m11;
1328                m11 = -M0;
1329                int state = rot90conversion[this .state];
1330                if ((state & (APPLY_SHEAR | APPLY_SCALE)) == APPLY_SCALE
1331                        && m00 == 1.0 && m11 == 1.0) {
1332                    state -= APPLY_SCALE;
1333                }
1334                this .state = state;
1335                type = TYPE_UNKNOWN;
1336            }
1337
1338            private final void rotate180() {
1339                m00 = -m00;
1340                m11 = -m11;
1341                int state = this .state;
1342                if ((state & (APPLY_SHEAR)) != 0) {
1343                    // If there was a shear, then this rotation has no
1344                    // effect on the state.
1345                    m01 = -m01;
1346                    m10 = -m10;
1347                } else {
1348                    // No shear means the SCALE state may toggle when
1349                    // m00 and m11 are negated.
1350                    if (m00 == 1.0 && m11 == 1.0) {
1351                        this .state = state & ~APPLY_SCALE;
1352                    } else {
1353                        this .state = state | APPLY_SCALE;
1354                    }
1355                }
1356                type = TYPE_UNKNOWN;
1357            }
1358
1359            private final void rotate270() {
1360                double M0 = m00;
1361                m00 = -m01;
1362                m01 = M0;
1363                M0 = m10;
1364                m10 = -m11;
1365                m11 = M0;
1366                int state = rot90conversion[this .state];
1367                if ((state & (APPLY_SHEAR | APPLY_SCALE)) == APPLY_SCALE
1368                        && m00 == 1.0 && m11 == 1.0) {
1369                    state -= APPLY_SCALE;
1370                }
1371                this .state = state;
1372                type = TYPE_UNKNOWN;
1373            }
1374
1375            /**
1376             * Concatenates this transform with a rotation transformation.
1377             * This is equivalent to calling concatenate(R), where R is an
1378             * <code>AffineTransform</code> represented by the following matrix:
1379             * <pre>
1380             *		[   cos(theta)    -sin(theta)    0   ]
1381             *		[   sin(theta)     cos(theta)    0   ]
1382             *		[       0              0         1   ]
1383             * </pre>
1384             * Rotating by a positive angle theta rotates points on the positive
1385             * X axis toward the positive Y axis.
1386             * Note also the discussion of
1387             * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
1388             * above.
1389             * @param theta the angle of rotation measured in radians
1390             * @since 1.2
1391             */
1392            public void rotate(double theta) {
1393                double sin = Math.sin(theta);
1394                if (sin == 1.0) {
1395                    rotate90();
1396                } else if (sin == -1.0) {
1397                    rotate270();
1398                } else {
1399                    double cos = Math.cos(theta);
1400                    if (cos == -1.0) {
1401                        rotate180();
1402                    } else if (cos != 1.0) {
1403                        double M0, M1;
1404                        M0 = m00;
1405                        M1 = m01;
1406                        m00 = cos * M0 + sin * M1;
1407                        m01 = -sin * M0 + cos * M1;
1408                        M0 = m10;
1409                        M1 = m11;
1410                        m10 = cos * M0 + sin * M1;
1411                        m11 = -sin * M0 + cos * M1;
1412                        updateState();
1413                    }
1414                }
1415            }
1416
1417            /**
1418             * Concatenates this transform with a transform that rotates
1419             * coordinates around an anchor point.
1420             * This operation is equivalent to translating the coordinates so
1421             * that the anchor point is at the origin (S1), then rotating them
1422             * about the new origin (S2), and finally translating so that the
1423             * intermediate origin is restored to the coordinates of the original
1424             * anchor point (S3).
1425             * <p>
1426             * This operation is equivalent to the following sequence of calls:
1427             * <pre>
1428             *     translate(anchorx, anchory);      // S3: final translation
1429             *     rotate(theta);                    // S2: rotate around anchor
1430             *     translate(-anchorx, -anchory);    // S1: translate anchor to origin
1431             * </pre>
1432             * Rotating by a positive angle theta rotates points on the positive
1433             * X axis toward the positive Y axis.
1434             * Note also the discussion of
1435             * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
1436             * above.
1437             *
1438             * @param theta the angle of rotation measured in radians
1439             * @param anchorx the X coordinate of the rotation anchor point
1440             * @param anchory the Y coordinate of the rotation anchor point
1441             * @since 1.2
1442             */
1443            public void rotate(double theta, double anchorx, double anchory) {
1444                // REMIND: Simple for now - optimize later
1445                translate(anchorx, anchory);
1446                rotate(theta);
1447                translate(-anchorx, -anchory);
1448            }
1449
1450            /**
1451             * Concatenates this transform with a transform that rotates
1452             * coordinates according to a rotation vector.
1453             * All coordinates rotate about the origin by the same amount.
1454             * The amount of rotation is such that coordinates along the former
1455             * positive X axis will subsequently align with the vector pointing
1456             * from the origin to the specified vector coordinates.
1457             * If both <code>vecx</code> and <code>vecy</code> are 0.0,
1458             * no additional rotation is added to this transform.
1459             * This operation is equivalent to calling:
1460             * <pre>
1461             *          rotate(Math.atan2(vecy, vecx));
1462             * </pre>
1463             *
1464             * @param vecx the X coordinate of the rotation vector
1465             * @param vecy the Y coordinate of the rotation vector
1466             * @since 1.6
1467             */
1468            public void rotate(double vecx, double vecy) {
1469                if (vecy == 0.0) {
1470                    if (vecx < 0.0) {
1471                        rotate180();
1472                    }
1473                    // If vecx > 0.0 - no rotation
1474                    // If vecx == 0.0 - undefined rotation - treat as no rotation
1475                } else if (vecx == 0.0) {
1476                    if (vecy > 0.0) {
1477                        rotate90();
1478                    } else { // vecy must be < 0.0
1479                        rotate270();
1480                    }
1481                } else {
1482                    double len = Math.sqrt(vecx * vecx + vecy * vecy);
1483                    double sin = vecy / len;
1484                    double cos = vecx / len;
1485                    double M0, M1;
1486                    M0 = m00;
1487                    M1 = m01;
1488                    m00 = cos * M0 + sin * M1;
1489                    m01 = -sin * M0 + cos * M1;
1490                    M0 = m10;
1491                    M1 = m11;
1492                    m10 = cos * M0 + sin * M1;
1493                    m11 = -sin * M0 + cos * M1;
1494                    updateState();
1495                }
1496            }
1497
1498            /**
1499             * Concatenates this transform with a transform that rotates
1500             * coordinates around an anchor point according to a rotation
1501             * vector.
1502             * All coordinates rotate about the specified anchor coordinates
1503             * by the same amount.
1504             * The amount of rotation is such that coordinates along the former
1505             * positive X axis will subsequently align with the vector pointing
1506             * from the origin to the specified vector coordinates.
1507             * If both <code>vecx</code> and <code>vecy</code> are 0.0,
1508             * the transform is not modified in any way.
1509             * This method is equivalent to calling:
1510             * <pre>
1511             *     rotate(Math.atan2(vecy, vecx), anchorx, anchory);
1512             * </pre>
1513             *
1514             * @param vecx the X coordinate of the rotation vector
1515             * @param vecy the Y coordinate of the rotation vector
1516             * @param anchorx the X coordinate of the rotation anchor point
1517             * @param anchory the Y coordinate of the rotation anchor point
1518             * @since 1.6
1519             */
1520            public void rotate(double vecx, double vecy, double anchorx,
1521                    double anchory) {
1522                // REMIND: Simple for now - optimize later
1523                translate(anchorx, anchory);
1524                rotate(vecx, vecy);
1525                translate(-anchorx, -anchory);
1526            }
1527
1528            /**
1529             * Concatenates this transform with a transform that rotates
1530             * coordinates by the specified number of quadrants.
1531             * This is equivalent to calling:
1532             * <pre>
1533             *     rotate(numquadrants * Math.PI / 2.0);
1534             * </pre>
1535             * Rotating by a positive number of quadrants rotates points on
1536             * the positive X axis toward the positive Y axis.
1537             * @param numquadrants the number of 90 degree arcs to rotate by
1538             * @since 1.6
1539             */
1540            public void quadrantRotate(int numquadrants) {
1541                switch (numquadrants & 3) {
1542                case 0:
1543                    break;
1544                case 1:
1545                    rotate90();
1546                    break;
1547                case 2:
1548                    rotate180();
1549                    break;
1550                case 3:
1551                    rotate270();
1552                    break;
1553                }
1554            }
1555
1556            /**
1557             * Concatenates this transform with a transform that rotates
1558             * coordinates by the specified number of quadrants around
1559             * the specified anchor point.
1560             * This method is equivalent to calling:
1561             * <pre>
1562             *     rotate(numquadrants * Math.PI / 2.0, anchorx, anchory);
1563             * </pre>
1564             * Rotating by a positive number of quadrants rotates points on
1565             * the positive X axis toward the positive Y axis.
1566             *
1567             * @param numquadrants the number of 90 degree arcs to rotate by
1568             * @param anchorx the X coordinate of the rotation anchor point
1569             * @param anchory the Y coordinate of the rotation anchor point
1570             * @since 1.6
1571             */
1572            public void quadrantRotate(int numquadrants, double anchorx,
1573                    double anchory) {
1574                switch (numquadrants & 3) {
1575                case 0:
1576                    return;
1577                case 1:
1578                    m02 += anchorx * (m00 - m01) + anchory * (m01 + m00);
1579                    m12 += anchorx * (m10 - m11) + anchory * (m11 + m10);
1580                    rotate90();
1581                    break;
1582                case 2:
1583                    m02 += anchorx * (m00 + m00) + anchory * (m01 + m01);
1584                    m12 += anchorx * (m10 + m10) + anchory * (m11 + m11);
1585                    rotate180();
1586                    break;
1587                case 3:
1588                    m02 += anchorx * (m00 + m01) + anchory * (m01 - m00);
1589                    m12 += anchorx * (m10 + m11) + anchory * (m11 - m10);
1590                    rotate270();
1591                    break;
1592                }
1593                if (m02 == 0.0 && m12 == 0.0) {
1594                    state &= ~APPLY_TRANSLATE;
1595                } else {
1596                    state |= APPLY_TRANSLATE;
1597                }
1598            }
1599
1600            /**
1601             * Concatenates this transform with a scaling transformation.
1602             * This is equivalent to calling concatenate(S), where S is an
1603             * <code>AffineTransform</code> represented by the following matrix:
1604             * <pre>
1605             *		[   sx   0    0   ]
1606             *		[   0    sy   0   ]
1607             *		[   0    0    1   ]
1608             * </pre>
1609             * @param sx the factor by which coordinates are scaled along the   
1610             * X axis direction
1611             * @param sy the factor by which coordinates are scaled along the
1612             * Y axis direction 
1613             * @since 1.2
1614             */
1615            public void scale(double sx, double sy) {
1616                int state = this .state;
1617                switch (state) {
1618                default:
1619                    stateError();
1620                    /* NOTREACHED */
1621                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1622                case (APPLY_SHEAR | APPLY_SCALE):
1623                    m00 *= sx;
1624                    m11 *= sy;
1625                    /* NOBREAK */
1626                case (APPLY_SHEAR | APPLY_TRANSLATE):
1627                case (APPLY_SHEAR):
1628                    m01 *= sy;
1629                    m10 *= sx;
1630                    if (m01 == 0 && m10 == 0) {
1631                        state &= APPLY_TRANSLATE;
1632                        if (m00 == 1.0 && m11 == 1.0) {
1633                            this .type = (state == APPLY_IDENTITY ? TYPE_IDENTITY
1634                                    : TYPE_TRANSLATION);
1635                        } else {
1636                            state |= APPLY_SCALE;
1637                            this .type = TYPE_UNKNOWN;
1638                        }
1639                        this .state = state;
1640                    }
1641                    return;
1642                case (APPLY_SCALE | APPLY_TRANSLATE):
1643                case (APPLY_SCALE):
1644                    m00 *= sx;
1645                    m11 *= sy;
1646                    if (m00 == 1.0 && m11 == 1.0) {
1647                        this .state = (state &= APPLY_TRANSLATE);
1648                        this .type = (state == APPLY_IDENTITY ? TYPE_IDENTITY
1649                                : TYPE_TRANSLATION);
1650                    } else {
1651                        this .type = TYPE_UNKNOWN;
1652                    }
1653                    return;
1654                case (APPLY_TRANSLATE):
1655                case (APPLY_IDENTITY):
1656                    m00 = sx;
1657                    m11 = sy;
1658                    if (sx != 1.0 || sy != 1.0) {
1659                        this .state = state | APPLY_SCALE;
1660                        this .type = TYPE_UNKNOWN;
1661                    }
1662                    return;
1663                }
1664            }
1665
1666            /**
1667             * Concatenates this transform with a shearing transformation.
1668             * This is equivalent to calling concatenate(SH), where SH is an
1669             * <code>AffineTransform</code> represented by the following matrix:
1670             * <pre>
1671             *		[   1   shx   0   ]
1672             *		[  shy   1    0   ]
1673             *		[   0    0    1   ]
1674             * </pre>
1675             * @param shx the multiplier by which coordinates are shifted in the
1676             * direction of the positive X axis as a factor of their Y coordinate
1677             * @param shy the multiplier by which coordinates are shifted in the
1678             * direction of the positive Y axis as a factor of their X coordinate
1679             * @since 1.2
1680             */
1681            public void shear(double shx, double shy) {
1682                int state = this .state;
1683                switch (state) {
1684                default:
1685                    stateError();
1686                    /* NOTREACHED */
1687                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1688                case (APPLY_SHEAR | APPLY_SCALE):
1689                    double M0,
1690                    M1;
1691                    M0 = m00;
1692                    M1 = m01;
1693                    m00 = M0 + M1 * shy;
1694                    m01 = M0 * shx + M1;
1695
1696                    M0 = m10;
1697                    M1 = m11;
1698                    m10 = M0 + M1 * shy;
1699                    m11 = M0 * shx + M1;
1700                    updateState();
1701                    return;
1702                case (APPLY_SHEAR | APPLY_TRANSLATE):
1703                case (APPLY_SHEAR):
1704                    m00 = m01 * shy;
1705                    m11 = m10 * shx;
1706                    if (m00 != 0.0 || m11 != 0.0) {
1707                        this .state = state | APPLY_SCALE;
1708                    }
1709                    this .type = TYPE_UNKNOWN;
1710                    return;
1711                case (APPLY_SCALE | APPLY_TRANSLATE):
1712                case (APPLY_SCALE):
1713                    m01 = m00 * shx;
1714                    m10 = m11 * shy;
1715                    if (m01 != 0.0 || m10 != 0.0) {
1716                        this .state = state | APPLY_SHEAR;
1717                    }
1718                    this .type = TYPE_UNKNOWN;
1719                    return;
1720                case (APPLY_TRANSLATE):
1721                case (APPLY_IDENTITY):
1722                    m01 = shx;
1723                    m10 = shy;
1724                    if (m01 != 0.0 || m10 != 0.0) {
1725                        this .state = state | APPLY_SCALE | APPLY_SHEAR;
1726                        this .type = TYPE_UNKNOWN;
1727                    }
1728                    return;
1729                }
1730            }
1731
1732            /**
1733             * Resets this transform to the Identity transform.
1734             * @since 1.2
1735             */
1736            public void setToIdentity() {
1737                m00 = m11 = 1.0;
1738                m10 = m01 = m02 = m12 = 0.0;
1739                state = APPLY_IDENTITY;
1740                type = TYPE_IDENTITY;
1741            }
1742
1743            /**
1744             * Sets this transform to a translation transformation.
1745             * The matrix representing this transform becomes:
1746             * <pre>
1747             *		[   1    0    tx  ]
1748             *		[   0    1    ty  ]
1749             *		[   0    0    1   ]
1750             * </pre>
1751             * @param tx the distance by which coordinates are translated in the
1752             * X axis direction
1753             * @param ty the distance by which coordinates are translated in the
1754             * Y axis direction
1755             * @since 1.2
1756             */
1757            public void setToTranslation(double tx, double ty) {
1758                m00 = 1.0;
1759                m10 = 0.0;
1760                m01 = 0.0;
1761                m11 = 1.0;
1762                m02 = tx;
1763                m12 = ty;
1764                if (tx != 0.0 || ty != 0.0) {
1765                    state = APPLY_TRANSLATE;
1766                    type = TYPE_TRANSLATION;
1767                } else {
1768                    state = APPLY_IDENTITY;
1769                    type = TYPE_IDENTITY;
1770                }
1771            }
1772
1773            /**
1774             * Sets this transform to a rotation transformation.
1775             * The matrix representing this transform becomes:
1776             * <pre>
1777             *		[   cos(theta)    -sin(theta)    0   ]
1778             *		[   sin(theta)     cos(theta)    0   ]
1779             *		[       0              0         1   ]
1780             * </pre>
1781             * Rotating by a positive angle theta rotates points on the positive
1782             * X axis toward the positive Y axis.
1783             * Note also the discussion of
1784             * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
1785             * above.
1786             * @param theta the angle of rotation measured in radians
1787             * @since 1.2
1788             */
1789            public void setToRotation(double theta) {
1790                double sin = Math.sin(theta);
1791                double cos;
1792                if (sin == 1.0 || sin == -1.0) {
1793                    cos = 0.0;
1794                    state = APPLY_SHEAR;
1795                    type = TYPE_QUADRANT_ROTATION;
1796                } else {
1797                    cos = Math.cos(theta);
1798                    if (cos == -1.0) {
1799                        sin = 0.0;
1800                        state = APPLY_SCALE;
1801                        type = TYPE_QUADRANT_ROTATION;
1802                    } else if (cos == 1.0) {
1803                        sin = 0.0;
1804                        state = APPLY_IDENTITY;
1805                        type = TYPE_IDENTITY;
1806                    } else {
1807                        state = APPLY_SHEAR | APPLY_SCALE;
1808                        type = TYPE_GENERAL_ROTATION;
1809                    }
1810                }
1811                m00 = cos;
1812                m10 = sin;
1813                m01 = -sin;
1814                m11 = cos;
1815                m02 = 0.0;
1816                m12 = 0.0;
1817            }
1818
1819            /**
1820             * Sets this transform to a translated rotation transformation.
1821             * This operation is equivalent to translating the coordinates so
1822             * that the anchor point is at the origin (S1), then rotating them
1823             * about the new origin (S2), and finally translating so that the
1824             * intermediate origin is restored to the coordinates of the original
1825             * anchor point (S3).
1826             * <p>
1827             * This operation is equivalent to the following sequence of calls:
1828             * <pre>
1829             *     setToTranslation(anchorx, anchory); // S3: final translation
1830             *     rotate(theta);                      // S2: rotate around anchor
1831             *     translate(-anchorx, -anchory);      // S1: translate anchor to origin
1832             * </pre>
1833             * The matrix representing this transform becomes:
1834             * <pre>
1835             *		[   cos(theta)    -sin(theta)    x-x*cos+y*sin  ]
1836             *		[   sin(theta)     cos(theta)    y-x*sin-y*cos  ]
1837             *		[       0              0               1        ]
1838             * </pre>
1839             * Rotating by a positive angle theta rotates points on the positive
1840             * X axis toward the positive Y axis.
1841             * Note also the discussion of
1842             * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
1843             * above.
1844             *
1845             * @param theta the angle of rotation measured in radians
1846             * @param anchorx the X coordinate of the rotation anchor point
1847             * @param anchory the Y coordinate of the rotation anchor point
1848             * @since 1.2
1849             */
1850            public void setToRotation(double theta, double anchorx,
1851                    double anchory) {
1852                setToRotation(theta);
1853                double sin = m10;
1854                double oneMinusCos = 1.0 - m00;
1855                m02 = anchorx * oneMinusCos + anchory * sin;
1856                m12 = anchory * oneMinusCos - anchorx * sin;
1857                if (m02 != 0.0 || m12 != 0.0) {
1858                    state |= APPLY_TRANSLATE;
1859                    type |= TYPE_TRANSLATION;
1860                }
1861            }
1862
1863            /**
1864             * Sets this transform to a rotation transformation that rotates
1865             * coordinates according to a rotation vector.
1866             * All coordinates rotate about the origin by the same amount.
1867             * The amount of rotation is such that coordinates along the former
1868             * positive X axis will subsequently align with the vector pointing
1869             * from the origin to the specified vector coordinates.
1870             * If both <code>vecx</code> and <code>vecy</code> are 0.0,
1871             * the transform is set to an identity transform.
1872             * This operation is equivalent to calling:
1873             * <pre>
1874             *     setToRotation(Math.atan2(vecy, vecx));
1875             * </pre>
1876             *
1877             * @param vecx the X coordinate of the rotation vector
1878             * @param vecy the Y coordinate of the rotation vector
1879             * @since 1.6
1880             */
1881            public void setToRotation(double vecx, double vecy) {
1882                double sin, cos;
1883                if (vecy == 0) {
1884                    sin = 0.0;
1885                    if (vecx < 0.0) {
1886                        cos = -1.0;
1887                        state = APPLY_SCALE;
1888                        type = TYPE_QUADRANT_ROTATION;
1889                    } else {
1890                        cos = 1.0;
1891                        state = APPLY_IDENTITY;
1892                        type = TYPE_IDENTITY;
1893                    }
1894                } else if (vecx == 0) {
1895                    cos = 0.0;
1896                    sin = (vecy > 0.0) ? 1.0 : -1.0;
1897                    state = APPLY_SHEAR;
1898                    type = TYPE_QUADRANT_ROTATION;
1899                } else {
1900                    double len = Math.sqrt(vecx * vecx + vecy * vecy);
1901                    cos = vecx / len;
1902                    sin = vecy / len;
1903                    state = APPLY_SHEAR | APPLY_SCALE;
1904                    type = TYPE_GENERAL_ROTATION;
1905                }
1906                m00 = cos;
1907                m10 = sin;
1908                m01 = -sin;
1909                m11 = cos;
1910                m02 = 0.0;
1911                m12 = 0.0;
1912            }
1913
1914            /**
1915             * Sets this transform to a rotation transformation that rotates
1916             * coordinates around an anchor point according to a rotation
1917             * vector.
1918             * All coordinates rotate about the specified anchor coordinates
1919             * by the same amount.
1920             * The amount of rotation is such that coordinates along the former
1921             * positive X axis will subsequently align with the vector pointing
1922             * from the origin to the specified vector coordinates.
1923             * If both <code>vecx</code> and <code>vecy</code> are 0.0,
1924             * the transform is set to an identity transform.
1925             * This operation is equivalent to calling:
1926             * <pre>
1927             *     setToTranslation(Math.atan2(vecy, vecx), anchorx, anchory);
1928             * </pre>
1929             *
1930             * @param vecx the X coordinate of the rotation vector
1931             * @param vecy the Y coordinate of the rotation vector
1932             * @param anchorx the X coordinate of the rotation anchor point
1933             * @param anchory the Y coordinate of the rotation anchor point
1934             * @since 1.6
1935             */
1936            public void setToRotation(double vecx, double vecy, double anchorx,
1937                    double anchory) {
1938                setToRotation(vecx, vecy);
1939                double sin = m10;
1940                double oneMinusCos = 1.0 - m00;
1941                m02 = anchorx * oneMinusCos + anchory * sin;
1942                m12 = anchory * oneMinusCos - anchorx * sin;
1943                if (m02 != 0.0 || m12 != 0.0) {
1944                    state |= APPLY_TRANSLATE;
1945                    type |= TYPE_TRANSLATION;
1946                }
1947            }
1948
1949            /**
1950             * Sets this transform to a rotation transformation that rotates
1951             * coordinates by the specified number of quadrants.
1952             * This operation is equivalent to calling:
1953             * <pre>
1954             *     setToRotation(numquadrants * Math.PI / 2.0);
1955             * </pre>
1956             * Rotating by a positive number of quadrants rotates points on
1957             * the positive X axis toward the positive Y axis.
1958             * @param numquadrants the number of 90 degree arcs to rotate by
1959             * @since 1.6
1960             */
1961            public void setToQuadrantRotation(int numquadrants) {
1962                switch (numquadrants & 3) {
1963                case 0:
1964                    m00 = 1.0;
1965                    m10 = 0.0;
1966                    m01 = 0.0;
1967                    m11 = 1.0;
1968                    m02 = 0.0;
1969                    m12 = 0.0;
1970                    state = APPLY_IDENTITY;
1971                    type = TYPE_IDENTITY;
1972                    break;
1973                case 1:
1974                    m00 = 0.0;
1975                    m10 = 1.0;
1976                    m01 = -1.0;
1977                    m11 = 0.0;
1978                    m02 = 0.0;
1979                    m12 = 0.0;
1980                    state = APPLY_SHEAR;
1981                    type = TYPE_QUADRANT_ROTATION;
1982                    break;
1983                case 2:
1984                    m00 = -1.0;
1985                    m10 = 0.0;
1986                    m01 = 0.0;
1987                    m11 = -1.0;
1988                    m02 = 0.0;
1989                    m12 = 0.0;
1990                    state = APPLY_SCALE;
1991                    type = TYPE_QUADRANT_ROTATION;
1992                    break;
1993                case 3:
1994                    m00 = 0.0;
1995                    m10 = -1.0;
1996                    m01 = 1.0;
1997                    m11 = 0.0;
1998                    m02 = 0.0;
1999                    m12 = 0.0;
2000                    state = APPLY_SHEAR;
2001                    type = TYPE_QUADRANT_ROTATION;
2002                    break;
2003                }
2004            }
2005
2006            /**
2007             * Sets this transform to a translated rotation transformation
2008             * that rotates coordinates by the specified number of quadrants
2009             * around the specified anchor point.
2010             * This operation is equivalent to calling:
2011             * <pre>
2012             *     setToRotation(numquadrants * Math.PI / 2.0, anchorx, anchory);
2013             * </pre>
2014             * Rotating by a positive number of quadrants rotates points on
2015             * the positive X axis toward the positive Y axis.
2016             *
2017             * @param numquadrants the number of 90 degree arcs to rotate by
2018             * @param anchorx the X coordinate of the rotation anchor point
2019             * @param anchory the Y coordinate of the rotation anchor point
2020             * @since 1.6
2021             */
2022            public void setToQuadrantRotation(int numquadrants, double anchorx,
2023                    double anchory) {
2024                switch (numquadrants & 3) {
2025                case 0:
2026                    m00 = 1.0;
2027                    m10 = 0.0;
2028                    m01 = 0.0;
2029                    m11 = 1.0;
2030                    m02 = 0.0;
2031                    m12 = 0.0;
2032                    state = APPLY_IDENTITY;
2033                    type = TYPE_IDENTITY;
2034                    break;
2035                case 1:
2036                    m00 = 0.0;
2037                    m10 = 1.0;
2038                    m01 = -1.0;
2039                    m11 = 0.0;
2040                    m02 = anchorx + anchory;
2041                    m12 = anchory - anchorx;
2042                    if (m02 == 0.0 && m12 == 0.0) {
2043                        state = APPLY_SHEAR;
2044                        type = TYPE_QUADRANT_ROTATION;
2045                    } else {
2046                        state = APPLY_SHEAR | APPLY_TRANSLATE;
2047                        type = TYPE_QUADRANT_ROTATION | TYPE_TRANSLATION;
2048                    }
2049                    break;
2050                case 2:
2051                    m00 = -1.0;
2052                    m10 = 0.0;
2053                    m01 = 0.0;
2054                    m11 = -1.0;
2055                    m02 = anchorx + anchorx;
2056                    m12 = anchory + anchory;
2057                    if (m02 == 0.0 && m12 == 0.0) {
2058                        state = APPLY_SCALE;
2059                        type = TYPE_QUADRANT_ROTATION;
2060                    } else {
2061                        state = APPLY_SCALE | APPLY_TRANSLATE;
2062                        type = TYPE_QUADRANT_ROTATION | TYPE_TRANSLATION;
2063                    }
2064                    break;
2065                case 3:
2066                    m00 = 0.0;
2067                    m10 = -1.0;
2068                    m01 = 1.0;
2069                    m11 = 0.0;
2070                    m02 = anchorx - anchory;
2071                    m12 = anchory + anchorx;
2072                    if (m02 == 0.0 && m12 == 0.0) {
2073                        state = APPLY_SHEAR;
2074                        type = TYPE_QUADRANT_ROTATION;
2075                    } else {
2076                        state = APPLY_SHEAR | APPLY_TRANSLATE;
2077                        type = TYPE_QUADRANT_ROTATION | TYPE_TRANSLATION;
2078                    }
2079                    break;
2080                }
2081            }
2082
2083            /**
2084             * Sets this transform to a scaling transformation.
2085             * The matrix representing this transform becomes:
2086             * <pre>
2087             *		[   sx   0    0   ]
2088             *		[   0    sy   0   ]
2089             *		[   0    0    1   ]
2090             * </pre>
2091             * @param sx the factor by which coordinates are scaled along the
2092             * X axis direction
2093             * @param sy the factor by which coordinates are scaled along the
2094             * Y axis direction
2095             * @since 1.2
2096             */
2097            public void setToScale(double sx, double sy) {
2098                m00 = sx;
2099                m10 = 0.0;
2100                m01 = 0.0;
2101                m11 = sy;
2102                m02 = 0.0;
2103                m12 = 0.0;
2104                if (sx != 1.0 || sy != 1.0) {
2105                    state = APPLY_SCALE;
2106                    type = TYPE_UNKNOWN;
2107                } else {
2108                    state = APPLY_IDENTITY;
2109                    type = TYPE_IDENTITY;
2110                }
2111            }
2112
2113            /**
2114             * Sets this transform to a shearing transformation.
2115             * The matrix representing this transform becomes:
2116             * <pre>
2117             *		[   1   shx   0   ]
2118             *		[  shy   1    0   ]
2119             *		[   0    0    1   ]
2120             * </pre>
2121             * @param shx the multiplier by which coordinates are shifted in the
2122             * direction of the positive X axis as a factor of their Y coordinate
2123             * @param shy the multiplier by which coordinates are shifted in the
2124             * direction of the positive Y axis as a factor of their X coordinate
2125             * @since 1.2
2126             */
2127            public void setToShear(double shx, double shy) {
2128                m00 = 1.0;
2129                m01 = shx;
2130                m10 = shy;
2131                m11 = 1.0;
2132                m02 = 0.0;
2133                m12 = 0.0;
2134                if (shx != 0.0 || shy != 0.0) {
2135                    state = (APPLY_SHEAR | APPLY_SCALE);
2136                    type = TYPE_UNKNOWN;
2137                } else {
2138                    state = APPLY_IDENTITY;
2139                    type = TYPE_IDENTITY;
2140                }
2141            }
2142
2143            /**
2144             * Sets this transform to a copy of the transform in the specified
2145             * <code>AffineTransform</code> object.
2146             * @param Tx the <code>AffineTransform</code> object from which to
2147             * copy the transform
2148             * @since 1.2
2149             */
2150            public void setTransform(AffineTransform Tx) {
2151                this .m00 = Tx.m00;
2152                this .m10 = Tx.m10;
2153                this .m01 = Tx.m01;
2154                this .m11 = Tx.m11;
2155                this .m02 = Tx.m02;
2156                this .m12 = Tx.m12;
2157                this .state = Tx.state;
2158                this .type = Tx.type;
2159            }
2160
2161            /**
2162             * Sets this transform to the matrix specified by the 6
2163             * double precision values.
2164             *
2165             * @param m00 the X coordinate scaling element of the 3x3 matrix
2166             * @param m10 the Y coordinate shearing element of the 3x3 matrix
2167             * @param m01 the X coordinate shearing element of the 3x3 matrix
2168             * @param m11 the Y coordinate scaling element of the 3x3 matrix
2169             * @param m02 the X coordinate translation element of the 3x3 matrix
2170             * @param m12 the Y coordinate translation element of the 3x3 matrix
2171             * @since 1.2
2172             */
2173            public void setTransform(double m00, double m10, double m01,
2174                    double m11, double m02, double m12) {
2175                this .m00 = m00;
2176                this .m10 = m10;
2177                this .m01 = m01;
2178                this .m11 = m11;
2179                this .m02 = m02;
2180                this .m12 = m12;
2181                updateState();
2182            }
2183
2184            /**
2185             * Concatenates an <code>AffineTransform</code> <code>Tx</code> to
2186             * this <code>AffineTransform</code> Cx in the most commonly useful
2187             * way to provide a new user space
2188             * that is mapped to the former user space by <code>Tx</code>.
2189             * Cx is updated to perform the combined transformation.
2190             * Transforming a point p by the updated transform Cx' is
2191             * equivalent to first transforming p by <code>Tx</code> and then
2192             * transforming the result by the original transform Cx like this:
2193             * Cx'(p) = Cx(Tx(p))  
2194             * In matrix notation, if this transform Cx is
2195             * represented by the matrix [this] and <code>Tx</code> is represented
2196             * by the matrix [Tx] then this method does the following:
2197             * <pre>
2198             *		[this] = [this] x [Tx]
2199             * </pre>
2200             * @param Tx the <code>AffineTransform</code> object to be
2201             * concatenated with this <code>AffineTransform</code> object.
2202             * @see #preConcatenate
2203             * @since 1.2
2204             */
2205            public void concatenate(AffineTransform Tx) {
2206                double M0, M1;
2207                double T00, T01, T10, T11;
2208                double T02, T12;
2209                int mystate = state;
2210                int txstate = Tx.state;
2211                switch ((txstate << HI_SHIFT) | mystate) {
2212
2213                /* ---------- Tx == IDENTITY cases ---------- */
2214                case (HI_IDENTITY | APPLY_IDENTITY):
2215                case (HI_IDENTITY | APPLY_TRANSLATE):
2216                case (HI_IDENTITY | APPLY_SCALE):
2217                case (HI_IDENTITY | APPLY_SCALE | APPLY_TRANSLATE):
2218                case (HI_IDENTITY | APPLY_SHEAR):
2219                case (HI_IDENTITY | APPLY_SHEAR | APPLY_TRANSLATE):
2220                case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE):
2221                case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2222                    return;
2223
2224                    /* ---------- this == IDENTITY cases ---------- */
2225                case (HI_SHEAR | HI_SCALE | HI_TRANSLATE | APPLY_IDENTITY):
2226                    m01 = Tx.m01;
2227                    m10 = Tx.m10;
2228                    /* NOBREAK */
2229                case (HI_SCALE | HI_TRANSLATE | APPLY_IDENTITY):
2230                    m00 = Tx.m00;
2231                    m11 = Tx.m11;
2232                    /* NOBREAK */
2233                case (HI_TRANSLATE | APPLY_IDENTITY):
2234                    m02 = Tx.m02;
2235                    m12 = Tx.m12;
2236                    state = txstate;
2237                    type = Tx.type;
2238                    return;
2239                case (HI_SHEAR | HI_SCALE | APPLY_IDENTITY):
2240                    m01 = Tx.m01;
2241                    m10 = Tx.m10;
2242                    /* NOBREAK */
2243                case (HI_SCALE | APPLY_IDENTITY):
2244                    m00 = Tx.m00;
2245                    m11 = Tx.m11;
2246                    state = txstate;
2247                    type = Tx.type;
2248                    return;
2249                case (HI_SHEAR | HI_TRANSLATE | APPLY_IDENTITY):
2250                    m02 = Tx.m02;
2251                    m12 = Tx.m12;
2252                    /* NOBREAK */
2253                case (HI_SHEAR | APPLY_IDENTITY):
2254                    m01 = Tx.m01;
2255                    m10 = Tx.m10;
2256                    m00 = m11 = 0.0;
2257                    state = txstate;
2258                    type = Tx.type;
2259                    return;
2260
2261                    /* ---------- Tx == TRANSLATE cases ---------- */
2262                case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2263                case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE):
2264                case (HI_TRANSLATE | APPLY_SHEAR | APPLY_TRANSLATE):
2265                case (HI_TRANSLATE | APPLY_SHEAR):
2266                case (HI_TRANSLATE | APPLY_SCALE | APPLY_TRANSLATE):
2267                case (HI_TRANSLATE | APPLY_SCALE):
2268                case (HI_TRANSLATE | APPLY_TRANSLATE):
2269                    translate(Tx.m02, Tx.m12);
2270                    return;
2271
2272                    /* ---------- Tx == SCALE cases ---------- */
2273                case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2274                case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE):
2275                case (HI_SCALE | APPLY_SHEAR | APPLY_TRANSLATE):
2276                case (HI_SCALE | APPLY_SHEAR):
2277                case (HI_SCALE | APPLY_SCALE | APPLY_TRANSLATE):
2278                case (HI_SCALE | APPLY_SCALE):
2279                case (HI_SCALE | APPLY_TRANSLATE):
2280                    scale(Tx.m00, Tx.m11);
2281                    return;
2282
2283                    /* ---------- Tx == SHEAR cases ---------- */
2284                case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2285                case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE):
2286                    T01 = Tx.m01;
2287                    T10 = Tx.m10;
2288                    M0 = m00;
2289                    m00 = m01 * T10;
2290                    m01 = M0 * T01;
2291                    M0 = m10;
2292                    m10 = m11 * T10;
2293                    m11 = M0 * T01;
2294                    type = TYPE_UNKNOWN;
2295                    return;
2296                case (HI_SHEAR | APPLY_SHEAR | APPLY_TRANSLATE):
2297                case (HI_SHEAR | APPLY_SHEAR):
2298                    m00 = m01 * Tx.m10;
2299                    m01 = 0.0;
2300                    m11 = m10 * Tx.m01;
2301                    m10 = 0.0;
2302                    state = mystate ^ (APPLY_SHEAR | APPLY_SCALE);
2303                    type = TYPE_UNKNOWN;
2304                    return;
2305                case (HI_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2306                case (HI_SHEAR | APPLY_SCALE):
2307                    m01 = m00 * Tx.m01;
2308                    m00 = 0.0;
2309                    m10 = m11 * Tx.m10;
2310                    m11 = 0.0;
2311                    state = mystate ^ (APPLY_SHEAR | APPLY_SCALE);
2312                    type = TYPE_UNKNOWN;
2313                    return;
2314                case (HI_SHEAR | APPLY_TRANSLATE):
2315                    m00 = 0.0;
2316                    m01 = Tx.m01;
2317                    m10 = Tx.m10;
2318                    m11 = 0.0;
2319                    state = APPLY_TRANSLATE | APPLY_SHEAR;
2320                    type = TYPE_UNKNOWN;
2321                    return;
2322                }
2323                // If Tx has more than one attribute, it is not worth optimizing
2324                // all of those cases...
2325                T00 = Tx.m00;
2326                T01 = Tx.m01;
2327                T02 = Tx.m02;
2328                T10 = Tx.m10;
2329                T11 = Tx.m11;
2330                T12 = Tx.m12;
2331                switch (mystate) {
2332                default:
2333                    stateError();
2334                    /* NOTREACHED */
2335                case (APPLY_SHEAR | APPLY_SCALE):
2336                    state = mystate | txstate;
2337                    /* NOBREAK */
2338                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2339                    M0 = m00;
2340                    M1 = m01;
2341                    m00 = T00 * M0 + T10 * M1;
2342                    m01 = T01 * M0 + T11 * M1;
2343                    m02 += T02 * M0 + T12 * M1;
2344
2345                    M0 = m10;
2346                    M1 = m11;
2347                    m10 = T00 * M0 + T10 * M1;
2348                    m11 = T01 * M0 + T11 * M1;
2349                    m12 += T02 * M0 + T12 * M1;
2350                    type = TYPE_UNKNOWN;
2351                    return;
2352
2353                case (APPLY_SHEAR | APPLY_TRANSLATE):
2354                case (APPLY_SHEAR):
2355                    M0 = m01;
2356                    m00 = T10 * M0;
2357                    m01 = T11 * M0;
2358                    m02 += T12 * M0;
2359
2360                    M0 = m10;
2361                    m10 = T00 * M0;
2362                    m11 = T01 * M0;
2363                    m12 += T02 * M0;
2364                    break;
2365
2366                case (APPLY_SCALE | APPLY_TRANSLATE):
2367                case (APPLY_SCALE):
2368                    M0 = m00;
2369                    m00 = T00 * M0;
2370                    m01 = T01 * M0;
2371                    m02 += T02 * M0;
2372
2373                    M0 = m11;
2374                    m10 = T10 * M0;
2375                    m11 = T11 * M0;
2376                    m12 += T12 * M0;
2377                    break;
2378
2379                case (APPLY_TRANSLATE):
2380                    m00 = T00;
2381                    m01 = T01;
2382                    m02 += T02;
2383
2384                    m10 = T10;
2385                    m11 = T11;
2386                    m12 += T12;
2387                    state = txstate | APPLY_TRANSLATE;
2388                    type = TYPE_UNKNOWN;
2389                    return;
2390                }
2391                updateState();
2392            }
2393
2394            /**
2395             * Concatenates an <code>AffineTransform</code> <code>Tx</code> to
2396             * this <code>AffineTransform</code> Cx
2397             * in a less commonly used way such that <code>Tx</code> modifies the
2398             * coordinate transformation relative to the absolute pixel
2399             * space rather than relative to the existing user space.
2400             * Cx is updated to perform the combined transformation.
2401             * Transforming a point p by the updated transform Cx' is
2402             * equivalent to first transforming p by the original transform
2403             * Cx and then transforming the result by 
2404             * <code>Tx</code> like this: 
2405             * Cx'(p) = Tx(Cx(p))  
2406             * In matrix notation, if this transform Cx
2407             * is represented by the matrix [this] and <code>Tx</code> is
2408             * represented by the matrix [Tx] then this method does the
2409             * following:
2410             * <pre>
2411             *		[this] = [Tx] x [this]
2412             * </pre>
2413             * @param Tx the <code>AffineTransform</code> object to be
2414             * concatenated with this <code>AffineTransform</code> object.
2415             * @see #concatenate
2416             * @since 1.2
2417             */
2418            public void preConcatenate(AffineTransform Tx) {
2419                double M0, M1;
2420                double T00, T01, T10, T11;
2421                double T02, T12;
2422                int mystate = state;
2423                int txstate = Tx.state;
2424                switch ((txstate << HI_SHIFT) | mystate) {
2425                case (HI_IDENTITY | APPLY_IDENTITY):
2426                case (HI_IDENTITY | APPLY_TRANSLATE):
2427                case (HI_IDENTITY | APPLY_SCALE):
2428                case (HI_IDENTITY | APPLY_SCALE | APPLY_TRANSLATE):
2429                case (HI_IDENTITY | APPLY_SHEAR):
2430                case (HI_IDENTITY | APPLY_SHEAR | APPLY_TRANSLATE):
2431                case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE):
2432                case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2433                    // Tx is IDENTITY...
2434                    return;
2435
2436                case (HI_TRANSLATE | APPLY_IDENTITY):
2437                case (HI_TRANSLATE | APPLY_SCALE):
2438                case (HI_TRANSLATE | APPLY_SHEAR):
2439                case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE):
2440                    // Tx is TRANSLATE, this has no TRANSLATE
2441                    m02 = Tx.m02;
2442                    m12 = Tx.m12;
2443                    state = mystate | APPLY_TRANSLATE;
2444                    type |= TYPE_TRANSLATION;
2445                    return;
2446
2447                case (HI_TRANSLATE | APPLY_TRANSLATE):
2448                case (HI_TRANSLATE | APPLY_SCALE | APPLY_TRANSLATE):
2449                case (HI_TRANSLATE | APPLY_SHEAR | APPLY_TRANSLATE):
2450                case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2451                    // Tx is TRANSLATE, this has one too
2452                    m02 = m02 + Tx.m02;
2453                    m12 = m12 + Tx.m12;
2454                    return;
2455
2456                case (HI_SCALE | APPLY_TRANSLATE):
2457                case (HI_SCALE | APPLY_IDENTITY):
2458                    // Only these two existing states need a new state
2459                    state = mystate | APPLY_SCALE;
2460                    /* NOBREAK */
2461                case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2462                case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE):
2463                case (HI_SCALE | APPLY_SHEAR | APPLY_TRANSLATE):
2464                case (HI_SCALE | APPLY_SHEAR):
2465                case (HI_SCALE | APPLY_SCALE | APPLY_TRANSLATE):
2466                case (HI_SCALE | APPLY_SCALE):
2467                    // Tx is SCALE, this is anything
2468                    T00 = Tx.m00;
2469                    T11 = Tx.m11;
2470                    if ((mystate & APPLY_SHEAR) != 0) {
2471                        m01 = m01 * T00;
2472                        m10 = m10 * T11;
2473                        if ((mystate & APPLY_SCALE) != 0) {
2474                            m00 = m00 * T00;
2475                            m11 = m11 * T11;
2476                        }
2477                    } else {
2478                        m00 = m00 * T00;
2479                        m11 = m11 * T11;
2480                    }
2481                    if ((mystate & APPLY_TRANSLATE) != 0) {
2482                        m02 = m02 * T00;
2483                        m12 = m12 * T11;
2484                    }
2485                    type = TYPE_UNKNOWN;
2486                    return;
2487                case (HI_SHEAR | APPLY_SHEAR | APPLY_TRANSLATE):
2488                case (HI_SHEAR | APPLY_SHEAR):
2489                    mystate = mystate | APPLY_SCALE;
2490                    /* NOBREAK */
2491                case (HI_SHEAR | APPLY_TRANSLATE):
2492                case (HI_SHEAR | APPLY_IDENTITY):
2493                case (HI_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2494                case (HI_SHEAR | APPLY_SCALE):
2495                    state = mystate ^ APPLY_SHEAR;
2496                    /* NOBREAK */
2497                case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2498                case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE):
2499                    // Tx is SHEAR, this is anything
2500                    T01 = Tx.m01;
2501                    T10 = Tx.m10;
2502
2503                    M0 = m00;
2504                    m00 = m10 * T01;
2505                    m10 = M0 * T10;
2506
2507                    M0 = m01;
2508                    m01 = m11 * T01;
2509                    m11 = M0 * T10;
2510
2511                    M0 = m02;
2512                    m02 = m12 * T01;
2513                    m12 = M0 * T10;
2514                    type = TYPE_UNKNOWN;
2515                    return;
2516                }
2517                // If Tx has more than one attribute, it is not worth optimizing
2518                // all of those cases...
2519                T00 = Tx.m00;
2520                T01 = Tx.m01;
2521                T02 = Tx.m02;
2522                T10 = Tx.m10;
2523                T11 = Tx.m11;
2524                T12 = Tx.m12;
2525                switch (mystate) {
2526                default:
2527                    stateError();
2528                    /* NOTREACHED */
2529                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2530                    M0 = m02;
2531                    M1 = m12;
2532                    T02 += M0 * T00 + M1 * T01;
2533                    T12 += M0 * T10 + M1 * T11;
2534
2535                    /* NOBREAK */
2536                case (APPLY_SHEAR | APPLY_SCALE):
2537                    m02 = T02;
2538                    m12 = T12;
2539
2540                    M0 = m00;
2541                    M1 = m10;
2542                    m00 = M0 * T00 + M1 * T01;
2543                    m10 = M0 * T10 + M1 * T11;
2544
2545                    M0 = m01;
2546                    M1 = m11;
2547                    m01 = M0 * T00 + M1 * T01;
2548                    m11 = M0 * T10 + M1 * T11;
2549                    break;
2550
2551                case (APPLY_SHEAR | APPLY_TRANSLATE):
2552                    M0 = m02;
2553                    M1 = m12;
2554                    T02 += M0 * T00 + M1 * T01;
2555                    T12 += M0 * T10 + M1 * T11;
2556
2557                    /* NOBREAK */
2558                case (APPLY_SHEAR):
2559                    m02 = T02;
2560                    m12 = T12;
2561
2562                    M0 = m10;
2563                    m00 = M0 * T01;
2564                    m10 = M0 * T11;
2565
2566                    M0 = m01;
2567                    m01 = M0 * T00;
2568                    m11 = M0 * T10;
2569                    break;
2570
2571                case (APPLY_SCALE | 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_SCALE):
2579                    m02 = T02;
2580                    m12 = T12;
2581
2582                    M0 = m00;
2583                    m00 = M0 * T00;
2584                    m10 = M0 * T10;
2585
2586                    M0 = m11;
2587                    m01 = M0 * T01;
2588                    m11 = M0 * T11;
2589                    break;
2590
2591                case (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_IDENTITY):
2599                    m02 = T02;
2600                    m12 = T12;
2601
2602                    m00 = T00;
2603                    m10 = T10;
2604
2605                    m01 = T01;
2606                    m11 = T11;
2607
2608                    state = mystate | txstate;
2609                    type = TYPE_UNKNOWN;
2610                    return;
2611                }
2612                updateState();
2613            }
2614
2615            /**
2616             * Returns an <code>AffineTransform</code> object representing the
2617             * inverse transformation.
2618             * The inverse transform Tx' of this transform Tx 
2619             * maps coordinates transformed by Tx back
2620             * to their original coordinates.
2621             * In other words, Tx'(Tx(p)) = p = Tx(Tx'(p)).
2622             * <p>
2623             * If this transform maps all coordinates onto a point or a line
2624             * then it will not have an inverse, since coordinates that do
2625             * not lie on the destination point or line will not have an inverse
2626             * mapping.
2627             * The <code>getDeterminant</code> method can be used to determine if this
2628             * transform has no inverse, in which case an exception will be
2629             * thrown if the <code>createInverse</code> method is called.
2630             * @return a new <code>AffineTransform</code> object representing the
2631             * inverse transformation.
2632             * @see #getDeterminant
2633             * @exception NoninvertibleTransformException
2634             * if the matrix cannot be inverted.
2635             * @since 1.2
2636             */
2637            public AffineTransform createInverse()
2638                    throws NoninvertibleTransformException {
2639                double det;
2640                switch (state) {
2641                default:
2642                    stateError();
2643                    /* NOTREACHED */
2644                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2645                    det = m00 * m11 - m01 * m10;
2646                    if (Math.abs(det) <= Double.MIN_VALUE) {
2647                        throw new NoninvertibleTransformException(
2648                                "Determinant is " + det);
2649                    }
2650                    return new AffineTransform(m11 / det, -m10 / det, -m01
2651                            / det, m00 / det, (m01 * m12 - m11 * m02) / det,
2652                            (m10 * m02 - m00 * m12) / det, (APPLY_SHEAR
2653                                    | APPLY_SCALE | APPLY_TRANSLATE));
2654                case (APPLY_SHEAR | APPLY_SCALE):
2655                    det = m00 * m11 - m01 * m10;
2656                    if (Math.abs(det) <= Double.MIN_VALUE) {
2657                        throw new NoninvertibleTransformException(
2658                                "Determinant is " + det);
2659                    }
2660                    return new AffineTransform(m11 / det, -m10 / det, -m01
2661                            / det, m00 / det, 0.0, 0.0,
2662                            (APPLY_SHEAR | APPLY_SCALE));
2663                case (APPLY_SHEAR | APPLY_TRANSLATE):
2664                    if (m01 == 0.0 || m10 == 0.0) {
2665                        throw new NoninvertibleTransformException(
2666                                "Determinant is 0");
2667                    }
2668                    return new AffineTransform(0.0, 1.0 / m01, 1.0 / m10, 0.0,
2669                            -m12 / m10, -m02 / m01,
2670                            (APPLY_SHEAR | APPLY_TRANSLATE));
2671                case (APPLY_SHEAR):
2672                    if (m01 == 0.0 || m10 == 0.0) {
2673                        throw new NoninvertibleTransformException(
2674                                "Determinant is 0");
2675                    }
2676                    return new AffineTransform(0.0, 1.0 / m01, 1.0 / m10, 0.0,
2677                            0.0, 0.0, (APPLY_SHEAR));
2678                case (APPLY_SCALE | APPLY_TRANSLATE):
2679                    if (m00 == 0.0 || m11 == 0.0) {
2680                        throw new NoninvertibleTransformException(
2681                                "Determinant is 0");
2682                    }
2683                    return new AffineTransform(1.0 / m00, 0.0, 0.0, 1.0 / m11,
2684                            -m02 / m00, -m12 / m11,
2685                            (APPLY_SCALE | APPLY_TRANSLATE));
2686                case (APPLY_SCALE):
2687                    if (m00 == 0.0 || m11 == 0.0) {
2688                        throw new NoninvertibleTransformException(
2689                                "Determinant is 0");
2690                    }
2691                    return new AffineTransform(1.0 / m00, 0.0, 0.0, 1.0 / m11,
2692                            0.0, 0.0, (APPLY_SCALE));
2693                case (APPLY_TRANSLATE):
2694                    return new AffineTransform(1.0, 0.0, 0.0, 1.0, -m02, -m12,
2695                            (APPLY_TRANSLATE));
2696                case (APPLY_IDENTITY):
2697                    return new AffineTransform();
2698                }
2699
2700                /* NOTREACHED */
2701            }
2702
2703            /**
2704             * Sets this transform to the inverse of itself.
2705             * The inverse transform Tx' of this transform Tx 
2706             * maps coordinates transformed by Tx back
2707             * to their original coordinates.
2708             * In other words, Tx'(Tx(p)) = p = Tx(Tx'(p)).
2709             * <p>
2710             * If this transform maps all coordinates onto a point or a line
2711             * then it will not have an inverse, since coordinates that do
2712             * not lie on the destination point or line will not have an inverse
2713             * mapping.
2714             * The <code>getDeterminant</code> method can be used to determine if this
2715             * transform has no inverse, in which case an exception will be
2716             * thrown if the <code>invert</code> method is called.
2717             * @see #getDeterminant
2718             * @exception NoninvertibleTransformException
2719             * if the matrix cannot be inverted.
2720             * @since 1.6
2721             */
2722            public void invert() throws NoninvertibleTransformException {
2723                double M00, M01, M02;
2724                double M10, M11, M12;
2725                double det;
2726                switch (state) {
2727                default:
2728                    stateError();
2729                    /* NOTREACHED */
2730                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2731                    M00 = m00;
2732                    M01 = m01;
2733                    M02 = m02;
2734                    M10 = m10;
2735                    M11 = m11;
2736                    M12 = m12;
2737                    det = M00 * M11 - M01 * M10;
2738                    if (Math.abs(det) <= Double.MIN_VALUE) {
2739                        throw new NoninvertibleTransformException(
2740                                "Determinant is " + det);
2741                    }
2742                    m00 = M11 / det;
2743                    m10 = -M10 / det;
2744                    m01 = -M01 / det;
2745                    m11 = M00 / det;
2746                    m02 = (M01 * M12 - M11 * M02) / det;
2747                    m12 = (M10 * M02 - M00 * M12) / det;
2748                    break;
2749                case (APPLY_SHEAR | APPLY_SCALE):
2750                    M00 = m00;
2751                    M01 = m01;
2752                    M10 = m10;
2753                    M11 = m11;
2754                    det = M00 * M11 - M01 * M10;
2755                    if (Math.abs(det) <= Double.MIN_VALUE) {
2756                        throw new NoninvertibleTransformException(
2757                                "Determinant is " + det);
2758                    }
2759                    m00 = M11 / det;
2760                    m10 = -M10 / det;
2761                    m01 = -M01 / det;
2762                    m11 = M00 / det;
2763                    // m02 = 0.0;
2764                    // m12 = 0.0;
2765                    break;
2766                case (APPLY_SHEAR | APPLY_TRANSLATE):
2767                    M01 = m01;
2768                    M02 = m02;
2769                    M10 = m10;
2770                    M12 = m12;
2771                    if (M01 == 0.0 || M10 == 0.0) {
2772                        throw new NoninvertibleTransformException(
2773                                "Determinant is 0");
2774                    }
2775                    // m00 = 0.0;
2776                    m10 = 1.0 / M01;
2777                    m01 = 1.0 / M10;
2778                    // m11 = 0.0;
2779                    m02 = -M12 / M10;
2780                    m12 = -M02 / M01;
2781                    break;
2782                case (APPLY_SHEAR):
2783                    M01 = m01;
2784                    M10 = m10;
2785                    if (M01 == 0.0 || M10 == 0.0) {
2786                        throw new NoninvertibleTransformException(
2787                                "Determinant is 0");
2788                    }
2789                    // m00 = 0.0;
2790                    m10 = 1.0 / M01;
2791                    m01 = 1.0 / M10;
2792                    // m11 = 0.0;
2793                    // m02 = 0.0;
2794                    // m12 = 0.0;
2795                    break;
2796                case (APPLY_SCALE | APPLY_TRANSLATE):
2797                    M00 = m00;
2798                    M02 = m02;
2799                    M11 = m11;
2800                    M12 = m12;
2801                    if (M00 == 0.0 || M11 == 0.0) {
2802                        throw new NoninvertibleTransformException(
2803                                "Determinant is 0");
2804                    }
2805                    m00 = 1.0 / M00;
2806                    // m10 = 0.0;
2807                    // m01 = 0.0;
2808                    m11 = 1.0 / M11;
2809                    m02 = -M02 / M00;
2810                    m12 = -M12 / M11;
2811                    break;
2812                case (APPLY_SCALE):
2813                    M00 = m00;
2814                    M11 = m11;
2815                    if (M00 == 0.0 || M11 == 0.0) {
2816                        throw new NoninvertibleTransformException(
2817                                "Determinant is 0");
2818                    }
2819                    m00 = 1.0 / M00;
2820                    // m10 = 0.0;
2821                    // m01 = 0.0;
2822                    m11 = 1.0 / M11;
2823                    // m02 = 0.0;
2824                    // m12 = 0.0;
2825                    break;
2826                case (APPLY_TRANSLATE):
2827                    // m00 = 1.0;
2828                    // m10 = 0.0;
2829                    // m01 = 0.0;
2830                    // m11 = 1.0;
2831                    m02 = -m02;
2832                    m12 = -m12;
2833                    break;
2834                case (APPLY_IDENTITY):
2835                    // m00 = 1.0;
2836                    // m10 = 0.0;
2837                    // m01 = 0.0;
2838                    // m11 = 1.0;
2839                    // m02 = 0.0;
2840                    // m12 = 0.0;
2841                    break;
2842                }
2843            }
2844
2845            /**
2846             * Transforms the specified <code>ptSrc</code> and stores the result
2847             * in <code>ptDst</code>.
2848             * If <code>ptDst</code> is <code>null</code>, a new {@link Point2D}
2849             * object is allocated and then the result of the transformation is
2850             * stored in this object.
2851             * In either case, <code>ptDst</code>, which contains the
2852             * transformed point, is returned for convenience.
2853             * If <code>ptSrc</code> and <code>ptDst</code> are the same
2854             * object, the input point is correctly overwritten with
2855             * the transformed point.
2856             * @param ptSrc the specified <code>Point2D</code> to be transformed
2857             * @param ptDst the specified <code>Point2D</code> that stores the
2858             * result of transforming <code>ptSrc</code>
2859             * @return the <code>ptDst</code> after transforming
2860             * <code>ptSrc</code> and stroring the result in <code>ptDst</code>.
2861             * @since 1.2
2862             */
2863            public Point2D transform(Point2D ptSrc, Point2D ptDst) {
2864                if (ptDst == null) {
2865                    if (ptSrc instanceof  Point2D.Double) {
2866                        ptDst = new Point2D.Double();
2867                    } else {
2868                        ptDst = new Point2D.Float();
2869                    }
2870                }
2871                // Copy source coords into local variables in case src == dst
2872                double x = ptSrc.getX();
2873                double y = ptSrc.getY();
2874                switch (state) {
2875                default:
2876                    stateError();
2877                    /* NOTREACHED */
2878                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2879                    ptDst.setLocation(x * m00 + y * m01 + m02, x * m10 + y
2880                            * m11 + m12);
2881                    return ptDst;
2882                case (APPLY_SHEAR | APPLY_SCALE):
2883                    ptDst.setLocation(x * m00 + y * m01, x * m10 + y * m11);
2884                    return ptDst;
2885                case (APPLY_SHEAR | APPLY_TRANSLATE):
2886                    ptDst.setLocation(y * m01 + m02, x * m10 + m12);
2887                    return ptDst;
2888                case (APPLY_SHEAR):
2889                    ptDst.setLocation(y * m01, x * m10);
2890                    return ptDst;
2891                case (APPLY_SCALE | APPLY_TRANSLATE):
2892                    ptDst.setLocation(x * m00 + m02, y * m11 + m12);
2893                    return ptDst;
2894                case (APPLY_SCALE):
2895                    ptDst.setLocation(x * m00, y * m11);
2896                    return ptDst;
2897                case (APPLY_TRANSLATE):
2898                    ptDst.setLocation(x + m02, y + m12);
2899                    return ptDst;
2900                case (APPLY_IDENTITY):
2901                    ptDst.setLocation(x, y);
2902                    return ptDst;
2903                }
2904
2905                /* NOTREACHED */
2906            }
2907
2908            /**
2909             * Transforms an array of point objects by this transform.
2910             * If any element of the <code>ptDst</code> array is
2911             * <code>null</code>, a new <code>Point2D</code> object is allocated
2912             * and stored into that element before storing the results of the
2913             * transformation.
2914             * <p>
2915             * Note that this method does not take any precautions to
2916             * avoid problems caused by storing results into <code>Point2D</code>
2917             * objects that will be used as the source for calculations
2918             * further down the source array.
2919             * This method does guarantee that if a specified <code>Point2D</code> 
2920             * object is both the source and destination for the same single point
2921             * transform operation then the results will not be stored until
2922             * the calculations are complete to avoid storing the results on
2923             * top of the operands.
2924             * If, however, the destination <code>Point2D</code> object for one
2925             * operation is the same object as the source <code>Point2D</code> 
2926             * object for another operation further down the source array then
2927             * the original coordinates in that point are overwritten before
2928             * they can be converted.
2929             * @param ptSrc the array containing the source point objects
2930             * @param ptDst the array into which the transform point objects are
2931             * returned
2932             * @param srcOff the offset to the first point object to be
2933             * transformed in the source array
2934             * @param dstOff the offset to the location of the first
2935             * transformed point object that is stored in the destination array
2936             * @param numPts the number of point objects to be transformed
2937             * @since 1.2
2938             */
2939            public void transform(Point2D[] ptSrc, int srcOff, Point2D[] ptDst,
2940                    int dstOff, int numPts) {
2941                int state = this .state;
2942                while (--numPts >= 0) {
2943                    // Copy source coords into local variables in case src == dst
2944                    Point2D src = ptSrc[srcOff++];
2945                    double x = src.getX();
2946                    double y = src.getY();
2947                    Point2D dst = ptDst[dstOff++];
2948                    if (dst == null) {
2949                        if (src instanceof  Point2D.Double) {
2950                            dst = new Point2D.Double();
2951                        } else {
2952                            dst = new Point2D.Float();
2953                        }
2954                        ptDst[dstOff - 1] = dst;
2955                    }
2956                    switch (state) {
2957                    default:
2958                        stateError();
2959                        /* NOTREACHED */
2960                    case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2961                        dst.setLocation(x * m00 + y * m01 + m02, x * m10 + y
2962                                * m11 + m12);
2963                        break;
2964                    case (APPLY_SHEAR | APPLY_SCALE):
2965                        dst.setLocation(x * m00 + y * m01, x * m10 + y * m11);
2966                        break;
2967                    case (APPLY_SHEAR | APPLY_TRANSLATE):
2968                        dst.setLocation(y * m01 + m02, x * m10 + m12);
2969                        break;
2970                    case (APPLY_SHEAR):
2971                        dst.setLocation(y * m01, x * m10);
2972                        break;
2973                    case (APPLY_SCALE | APPLY_TRANSLATE):
2974                        dst.setLocation(x * m00 + m02, y * m11 + m12);
2975                        break;
2976                    case (APPLY_SCALE):
2977                        dst.setLocation(x * m00, y * m11);
2978                        break;
2979                    case (APPLY_TRANSLATE):
2980                        dst.setLocation(x + m02, y + m12);
2981                        break;
2982                    case (APPLY_IDENTITY):
2983                        dst.setLocation(x, y);
2984                        break;
2985                    }
2986                }
2987
2988                /* NOTREACHED */
2989            }
2990
2991            /**
2992             * Transforms an array of floating point coordinates by this transform.
2993             * The two coordinate array sections can be exactly the same or
2994             * can be overlapping sections of the same array without affecting the
2995             * validity of the results.
2996             * This method ensures that no source coordinates are overwritten by a
2997             * previous operation before they can be transformed.
2998             * The coordinates are stored in the arrays starting at the specified
2999             * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3000             * @param srcPts the array containing the source point coordinates.
3001             * Each point is stored as a pair of x,&nbsp;y coordinates.
3002             * @param dstPts the array into which the transformed point coordinates
3003             * are returned.  Each point is stored as a pair of x,&nbsp;y
3004             * coordinates.
3005             * @param srcOff the offset to the first point to be transformed
3006             * in the source array
3007             * @param dstOff the offset to the location of the first
3008             * transformed point that is stored in the destination array
3009             * @param numPts the number of points to be transformed
3010             * @since 1.2
3011             */
3012            public void transform(float[] srcPts, int srcOff, float[] dstPts,
3013                    int dstOff, int numPts) {
3014                double M00, M01, M02, M10, M11, M12; // For caching
3015                if (dstPts == srcPts && dstOff > srcOff
3016                        && dstOff < srcOff + numPts * 2) {
3017                    // If the arrays overlap partially with the destination higher
3018                    // than the source and we transform the coordinates normally
3019                    // we would overwrite some of the later source coordinates
3020                    // with results of previous transformations.
3021                    // To get around this we use arraycopy to copy the points
3022                    // to their final destination with correct overwrite
3023                    // handling and then transform them in place in the new
3024                    // safer location.
3025                    System
3026                            .arraycopy(srcPts, srcOff, dstPts, dstOff,
3027                                    numPts * 2);
3028                    // srcPts = dstPts;		// They are known to be equal.
3029                    srcOff = dstOff;
3030                }
3031                switch (state) {
3032                default:
3033                    stateError();
3034                    /* NOTREACHED */
3035                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3036                    M00 = m00;
3037                    M01 = m01;
3038                    M02 = m02;
3039                    M10 = m10;
3040                    M11 = m11;
3041                    M12 = m12;
3042                    while (--numPts >= 0) {
3043                        double x = srcPts[srcOff++];
3044                        double y = srcPts[srcOff++];
3045                        dstPts[dstOff++] = (float) (M00 * x + M01 * y + M02);
3046                        dstPts[dstOff++] = (float) (M10 * x + M11 * y + M12);
3047                    }
3048                    return;
3049                case (APPLY_SHEAR | APPLY_SCALE):
3050                    M00 = m00;
3051                    M01 = m01;
3052                    M10 = m10;
3053                    M11 = m11;
3054                    while (--numPts >= 0) {
3055                        double x = srcPts[srcOff++];
3056                        double y = srcPts[srcOff++];
3057                        dstPts[dstOff++] = (float) (M00 * x + M01 * y);
3058                        dstPts[dstOff++] = (float) (M10 * x + M11 * y);
3059                    }
3060                    return;
3061                case (APPLY_SHEAR | APPLY_TRANSLATE):
3062                    M01 = m01;
3063                    M02 = m02;
3064                    M10 = m10;
3065                    M12 = m12;
3066                    while (--numPts >= 0) {
3067                        double x = srcPts[srcOff++];
3068                        dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++] + M02);
3069                        dstPts[dstOff++] = (float) (M10 * x + M12);
3070                    }
3071                    return;
3072                case (APPLY_SHEAR):
3073                    M01 = m01;
3074                    M10 = m10;
3075                    while (--numPts >= 0) {
3076                        double x = srcPts[srcOff++];
3077                        dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++]);
3078                        dstPts[dstOff++] = (float) (M10 * x);
3079                    }
3080                    return;
3081                case (APPLY_SCALE | APPLY_TRANSLATE):
3082                    M00 = m00;
3083                    M02 = m02;
3084                    M11 = m11;
3085                    M12 = m12;
3086                    while (--numPts >= 0) {
3087                        dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++] + M02);
3088                        dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++] + M12);
3089                    }
3090                    return;
3091                case (APPLY_SCALE):
3092                    M00 = m00;
3093                    M11 = m11;
3094                    while (--numPts >= 0) {
3095                        dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++]);
3096                        dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++]);
3097                    }
3098                    return;
3099                case (APPLY_TRANSLATE):
3100                    M02 = m02;
3101                    M12 = m12;
3102                    while (--numPts >= 0) {
3103                        dstPts[dstOff++] = (float) (srcPts[srcOff++] + M02);
3104                        dstPts[dstOff++] = (float) (srcPts[srcOff++] + M12);
3105                    }
3106                    return;
3107                case (APPLY_IDENTITY):
3108                    if (srcPts != dstPts || srcOff != dstOff) {
3109                        System.arraycopy(srcPts, srcOff, dstPts, dstOff,
3110                                numPts * 2);
3111                    }
3112                    return;
3113                }
3114
3115                /* NOTREACHED */
3116            }
3117
3118            /**
3119             * Transforms an array of double precision coordinates by this transform.
3120             * The two coordinate array sections can be exactly the same or
3121             * can be overlapping sections of the same array without affecting the
3122             * validity of the results.
3123             * This method ensures that no source coordinates are
3124             * overwritten by a previous operation before they can be transformed.
3125             * The coordinates are stored in the arrays starting at the indicated
3126             * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3127             * @param srcPts the array containing the source point coordinates.
3128             * Each point is stored as a pair of x,&nbsp;y coordinates.
3129             * @param dstPts the array into which the transformed point
3130             * coordinates are returned.  Each point is stored as a pair of
3131             * x,&nbsp;y coordinates.
3132             * @param srcOff the offset to the first point to be transformed
3133             * in the source array
3134             * @param dstOff the offset to the location of the first
3135             * transformed point that is stored in the destination array
3136             * @param numPts the number of point objects to be transformed
3137             * @since 1.2
3138             */
3139            public void transform(double[] srcPts, int srcOff, double[] dstPts,
3140                    int dstOff, int numPts) {
3141                double M00, M01, M02, M10, M11, M12; // For caching
3142                if (dstPts == srcPts && dstOff > srcOff
3143                        && dstOff < srcOff + numPts * 2) {
3144                    // If the arrays overlap partially with the destination higher
3145                    // than the source and we transform the coordinates normally
3146                    // we would overwrite some of the later source coordinates
3147                    // with results of previous transformations.
3148                    // To get around this we use arraycopy to copy the points
3149                    // to their final destination with correct overwrite
3150                    // handling and then transform them in place in the new
3151                    // safer location.
3152                    System
3153                            .arraycopy(srcPts, srcOff, dstPts, dstOff,
3154                                    numPts * 2);
3155                    // srcPts = dstPts;		// They are known to be equal.
3156                    srcOff = dstOff;
3157                }
3158                switch (state) {
3159                default:
3160                    stateError();
3161                    /* NOTREACHED */
3162                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3163                    M00 = m00;
3164                    M01 = m01;
3165                    M02 = m02;
3166                    M10 = m10;
3167                    M11 = m11;
3168                    M12 = m12;
3169                    while (--numPts >= 0) {
3170                        double x = srcPts[srcOff++];
3171                        double y = srcPts[srcOff++];
3172                        dstPts[dstOff++] = M00 * x + M01 * y + M02;
3173                        dstPts[dstOff++] = M10 * x + M11 * y + M12;
3174                    }
3175                    return;
3176                case (APPLY_SHEAR | APPLY_SCALE):
3177                    M00 = m00;
3178                    M01 = m01;
3179                    M10 = m10;
3180                    M11 = m11;
3181                    while (--numPts >= 0) {
3182                        double x = srcPts[srcOff++];
3183                        double y = srcPts[srcOff++];
3184                        dstPts[dstOff++] = M00 * x + M01 * y;
3185                        dstPts[dstOff++] = M10 * x + M11 * y;
3186                    }
3187                    return;
3188                case (APPLY_SHEAR | APPLY_TRANSLATE):
3189                    M01 = m01;
3190                    M02 = m02;
3191                    M10 = m10;
3192                    M12 = m12;
3193                    while (--numPts >= 0) {
3194                        double x = srcPts[srcOff++];
3195                        dstPts[dstOff++] = M01 * srcPts[srcOff++] + M02;
3196                        dstPts[dstOff++] = M10 * x + M12;
3197                    }
3198                    return;
3199                case (APPLY_SHEAR):
3200                    M01 = m01;
3201                    M10 = m10;
3202                    while (--numPts >= 0) {
3203                        double x = srcPts[srcOff++];
3204                        dstPts[dstOff++] = M01 * srcPts[srcOff++];
3205                        dstPts[dstOff++] = M10 * x;
3206                    }
3207                    return;
3208                case (APPLY_SCALE | APPLY_TRANSLATE):
3209                    M00 = m00;
3210                    M02 = m02;
3211                    M11 = m11;
3212                    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;
3220                    M11 = m11;
3221                    while (--numPts >= 0) {
3222                        dstPts[dstOff++] = M00 * srcPts[srcOff++];
3223                        dstPts[dstOff++] = M11 * srcPts[srcOff++];
3224                    }
3225                    return;
3226                case (APPLY_TRANSLATE):
3227                    M02 = m02;
3228                    M12 = m12;
3229                    while (--numPts >= 0) {
3230                        dstPts[dstOff++] = srcPts[srcOff++] + M02;
3231                        dstPts[dstOff++] = srcPts[srcOff++] + M12;
3232                    }
3233                    return;
3234                case (APPLY_IDENTITY):
3235                    if (srcPts != dstPts || srcOff != dstOff) {
3236                        System.arraycopy(srcPts, srcOff, dstPts, dstOff,
3237                                numPts * 2);
3238                    }
3239                    return;
3240                }
3241
3242                /* NOTREACHED */
3243            }
3244
3245            /**
3246             * Transforms an array of floating point coordinates by this transform
3247             * and stores the results into an array of doubles.
3248             * The coordinates are stored in the arrays starting at the specified
3249             * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3250             * @param srcPts the array containing the source point coordinates.
3251             * Each point is stored as a pair of x,&nbsp;y coordinates.
3252             * @param dstPts the array into which the transformed point coordinates
3253             * are returned.  Each point is stored as a pair of x,&nbsp;y
3254             * coordinates.
3255             * @param srcOff the offset to the first point to be transformed
3256             * in the source array
3257             * @param dstOff the offset to the location of the first
3258             * transformed point that is stored in the destination array
3259             * @param numPts the number of points to be transformed
3260             * @since 1.2
3261             */
3262            public void transform(float[] srcPts, int srcOff, double[] dstPts,
3263                    int dstOff, int numPts) {
3264                double M00, M01, M02, M10, M11, M12; // For caching
3265                switch (state) {
3266                default:
3267                    stateError();
3268                    /* NOTREACHED */
3269                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3270                    M00 = m00;
3271                    M01 = m01;
3272                    M02 = m02;
3273                    M10 = m10;
3274                    M11 = m11;
3275                    M12 = m12;
3276                    while (--numPts >= 0) {
3277                        double x = srcPts[srcOff++];
3278                        double y = srcPts[srcOff++];
3279                        dstPts[dstOff++] = M00 * x + M01 * y + M02;
3280                        dstPts[dstOff++] = M10 * x + M11 * y + M12;
3281                    }
3282                    return;
3283                case (APPLY_SHEAR | APPLY_SCALE):
3284                    M00 = m00;
3285                    M01 = m01;
3286                    M10 = m10;
3287                    M11 = m11;
3288                    while (--numPts >= 0) {
3289                        double x = srcPts[srcOff++];
3290                        double y = srcPts[srcOff++];
3291                        dstPts[dstOff++] = M00 * x + M01 * y;
3292                        dstPts[dstOff++] = M10 * x + M11 * y;
3293                    }
3294                    return;
3295                case (APPLY_SHEAR | APPLY_TRANSLATE):
3296                    M01 = m01;
3297                    M02 = m02;
3298                    M10 = m10;
3299                    M12 = m12;
3300                    while (--numPts >= 0) {
3301                        double x = srcPts[srcOff++];
3302                        dstPts[dstOff++] = M01 * srcPts[srcOff++] + M02;
3303                        dstPts[dstOff++] = M10 * x + M12;
3304                    }
3305                    return;
3306                case (APPLY_SHEAR):
3307                    M01 = m01;
3308                    M10 = m10;
3309                    while (--numPts >= 0) {
3310                        double x = srcPts[srcOff++];
3311                        dstPts[dstOff++] = M01 * srcPts[srcOff++];
3312                        dstPts[dstOff++] = M10 * x;
3313                    }
3314                    return;
3315                case (APPLY_SCALE | APPLY_TRANSLATE):
3316                    M00 = m00;
3317                    M02 = m02;
3318                    M11 = m11;
3319                    M12 = m12;
3320                    while (--numPts >= 0) {
3321                        dstPts[dstOff++] = M00 * srcPts[srcOff++] + M02;
3322                        dstPts[dstOff++] = M11 * srcPts[srcOff++] + M12;
3323                    }
3324                    return;
3325                case (APPLY_SCALE):
3326                    M00 = m00;
3327                    M11 = m11;
3328                    while (--numPts >= 0) {
3329                        dstPts[dstOff++] = M00 * srcPts[srcOff++];
3330                        dstPts[dstOff++] = M11 * srcPts[srcOff++];
3331                    }
3332                    return;
3333                case (APPLY_TRANSLATE):
3334                    M02 = m02;
3335                    M12 = m12;
3336                    while (--numPts >= 0) {
3337                        dstPts[dstOff++] = srcPts[srcOff++] + M02;
3338                        dstPts[dstOff++] = srcPts[srcOff++] + M12;
3339                    }
3340                    return;
3341                case (APPLY_IDENTITY):
3342                    while (--numPts >= 0) {
3343                        dstPts[dstOff++] = srcPts[srcOff++];
3344                        dstPts[dstOff++] = srcPts[srcOff++];
3345                    }
3346                    return;
3347                }
3348
3349                /* NOTREACHED */
3350            }
3351
3352            /**
3353             * Transforms an array of double precision coordinates by this transform
3354             * and stores the results into an array of floats.
3355             * The coordinates are stored in the arrays starting at the specified
3356             * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3357             * @param srcPts the array containing the source point coordinates.
3358             * Each point is stored as a pair of x,&nbsp;y coordinates.
3359             * @param dstPts the array into which the transformed point
3360             * coordinates are returned.  Each point is stored as a pair of 
3361             * x,&nbsp;y coordinates.
3362             * @param srcOff the offset to the first point to be transformed
3363             * in the source array
3364             * @param dstOff the offset to the location of the first
3365             * transformed point that is stored in the destination array
3366             * @param numPts the number of point objects to be transformed
3367             * @since 1.2
3368             */
3369            public void transform(double[] srcPts, int srcOff, float[] dstPts,
3370                    int dstOff, int numPts) {
3371                double M00, M01, M02, M10, M11, M12; // For caching
3372                switch (state) {
3373                default:
3374                    stateError();
3375                    /* NOTREACHED */
3376                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3377                    M00 = m00;
3378                    M01 = m01;
3379                    M02 = m02;
3380                    M10 = m10;
3381                    M11 = m11;
3382                    M12 = m12;
3383                    while (--numPts >= 0) {
3384                        double x = srcPts[srcOff++];
3385                        double y = srcPts[srcOff++];
3386                        dstPts[dstOff++] = (float) (M00 * x + M01 * y + M02);
3387                        dstPts[dstOff++] = (float) (M10 * x + M11 * y + M12);
3388                    }
3389                    return;
3390                case (APPLY_SHEAR | APPLY_SCALE):
3391                    M00 = m00;
3392                    M01 = m01;
3393                    M10 = m10;
3394                    M11 = m11;
3395                    while (--numPts >= 0) {
3396                        double x = srcPts[srcOff++];
3397                        double y = srcPts[srcOff++];
3398                        dstPts[dstOff++] = (float) (M00 * x + M01 * y);
3399                        dstPts[dstOff++] = (float) (M10 * x + M11 * y);
3400                    }
3401                    return;
3402                case (APPLY_SHEAR | APPLY_TRANSLATE):
3403                    M01 = m01;
3404                    M02 = m02;
3405                    M10 = m10;
3406                    M12 = m12;
3407                    while (--numPts >= 0) {
3408                        double x = srcPts[srcOff++];
3409                        dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++] + M02);
3410                        dstPts[dstOff++] = (float) (M10 * x + M12);
3411                    }
3412                    return;
3413                case (APPLY_SHEAR):
3414                    M01 = m01;
3415                    M10 = m10;
3416                    while (--numPts >= 0) {
3417                        double x = srcPts[srcOff++];
3418                        dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++]);
3419                        dstPts[dstOff++] = (float) (M10 * x);
3420                    }
3421                    return;
3422                case (APPLY_SCALE | APPLY_TRANSLATE):
3423                    M00 = m00;
3424                    M02 = m02;
3425                    M11 = m11;
3426                    M12 = m12;
3427                    while (--numPts >= 0) {
3428                        dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++] + M02);
3429                        dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++] + M12);
3430                    }
3431                    return;
3432                case (APPLY_SCALE):
3433                    M00 = m00;
3434                    M11 = m11;
3435                    while (--numPts >= 0) {
3436                        dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++]);
3437                        dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++]);
3438                    }
3439                    return;
3440                case (APPLY_TRANSLATE):
3441                    M02 = m02;
3442                    M12 = m12;
3443                    while (--numPts >= 0) {
3444                        dstPts[dstOff++] = (float) (srcPts[srcOff++] + M02);
3445                        dstPts[dstOff++] = (float) (srcPts[srcOff++] + M12);
3446                    }
3447                    return;
3448                case (APPLY_IDENTITY):
3449                    while (--numPts >= 0) {
3450                        dstPts[dstOff++] = (float) (srcPts[srcOff++]);
3451                        dstPts[dstOff++] = (float) (srcPts[srcOff++]);
3452                    }
3453                    return;
3454                }
3455
3456                /* NOTREACHED */
3457            }
3458
3459            /**
3460             * Inverse transforms the specified <code>ptSrc</code> and stores the
3461             * result in <code>ptDst</code>.
3462             * If <code>ptDst</code> is <code>null</code>, a new
3463             * <code>Point2D</code> object is allocated and then the result of the
3464             * transform is stored in this object.
3465             * In either case, <code>ptDst</code>, which contains the transformed
3466             * point, is returned for convenience.
3467             * If <code>ptSrc</code> and <code>ptDst</code> are the same
3468             * object, the input point is correctly overwritten with the
3469             * transformed point.
3470             * @param ptSrc the point to be inverse transformed
3471             * @param ptDst the resulting transformed point
3472             * @return <code>ptDst</code>, which contains the result of the 
3473             * inverse transform.
3474             * @exception NoninvertibleTransformException  if the matrix cannot be
3475             *                                         inverted.
3476             * @since 1.2
3477             */
3478            public Point2D inverseTransform(Point2D ptSrc, Point2D ptDst)
3479                    throws NoninvertibleTransformException {
3480                if (ptDst == null) {
3481                    if (ptSrc instanceof  Point2D.Double) {
3482                        ptDst = new Point2D.Double();
3483                    } else {
3484                        ptDst = new Point2D.Float();
3485                    }
3486                }
3487                // Copy source coords into local variables in case src == dst
3488                double x = ptSrc.getX();
3489                double y = ptSrc.getY();
3490                switch (state) {
3491                default:
3492                    stateError();
3493                    /* NOTREACHED */
3494                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3495                    x -= m02;
3496                    y -= m12;
3497                    /* NOBREAK */
3498                case (APPLY_SHEAR | APPLY_SCALE):
3499                    double det = m00 * m11 - m01 * m10;
3500                    if (Math.abs(det) <= Double.MIN_VALUE) {
3501                        throw new NoninvertibleTransformException(
3502                                "Determinant is " + det);
3503                    }
3504                    ptDst.setLocation((x * m11 - y * m01) / det, (y * m00 - x
3505                            * m10)
3506                            / det);
3507                    return ptDst;
3508                case (APPLY_SHEAR | APPLY_TRANSLATE):
3509                    x -= m02;
3510                    y -= m12;
3511                    /* NOBREAK */
3512                case (APPLY_SHEAR):
3513                    if (m01 == 0.0 || m10 == 0.0) {
3514                        throw new NoninvertibleTransformException(
3515                                "Determinant is 0");
3516                    }
3517                    ptDst.setLocation(y / m10, x / m01);
3518                    return ptDst;
3519                case (APPLY_SCALE | APPLY_TRANSLATE):
3520                    x -= m02;
3521                    y -= m12;
3522                    /* NOBREAK */
3523                case (APPLY_SCALE):
3524                    if (m00 == 0.0 || m11 == 0.0) {
3525                        throw new NoninvertibleTransformException(
3526                                "Determinant is 0");
3527                    }
3528                    ptDst.setLocation(x / m00, y / m11);
3529                    return ptDst;
3530                case (APPLY_TRANSLATE):
3531                    ptDst.setLocation(x - m02, y - m12);
3532                    return ptDst;
3533                case (APPLY_IDENTITY):
3534                    ptDst.setLocation(x, y);
3535                    return ptDst;
3536                }
3537
3538                /* NOTREACHED */
3539            }
3540
3541            /**
3542             * Inverse transforms an array of double precision coordinates by
3543             * this transform.  
3544             * The two coordinate array sections can be exactly the same or
3545             * can be overlapping sections of the same array without affecting the
3546             * validity of the results.
3547             * This method ensures that no source coordinates are
3548             * overwritten by a previous operation before they can be transformed.
3549             * The coordinates are stored in the arrays starting at the specified
3550             * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3551             * @param srcPts the array containing the source point coordinates.
3552             * Each point is stored as a pair of x,&nbsp;y coordinates.
3553             * @param dstPts the array into which the transformed point
3554             * coordinates are returned.  Each point is stored as a pair of 
3555             * x,&nbsp;y coordinates.
3556             * @param srcOff the offset to the first point to be transformed
3557             * in the source array
3558             * @param dstOff the offset to the location of the first
3559             * transformed point that is stored in the destination array
3560             * @param numPts the number of point objects to be transformed
3561             * @exception NoninvertibleTransformException  if the matrix cannot be
3562             *                                         inverted.
3563             * @since 1.2
3564             */
3565            public void inverseTransform(double[] srcPts, int srcOff,
3566                    double[] dstPts, int dstOff, int numPts)
3567                    throws NoninvertibleTransformException {
3568                double M00, M01, M02, M10, M11, M12; // For caching
3569                double det;
3570                if (dstPts == srcPts && dstOff > srcOff
3571                        && dstOff < srcOff + numPts * 2) {
3572                    // If the arrays overlap partially with the destination higher
3573                    // than the source and we transform the coordinates normally
3574                    // we would overwrite some of the later source coordinates
3575                    // with results of previous transformations.
3576                    // To get around this we use arraycopy to copy the points
3577                    // to their final destination with correct overwrite
3578                    // handling and then transform them in place in the new
3579                    // safer location.
3580                    System
3581                            .arraycopy(srcPts, srcOff, dstPts, dstOff,
3582                                    numPts * 2);
3583                    // srcPts = dstPts;		// They are known to be equal.
3584                    srcOff = dstOff;
3585                }
3586                switch (state) {
3587                default:
3588                    stateError();
3589                    /* NOTREACHED */
3590                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3591                    M00 = m00;
3592                    M01 = m01;
3593                    M02 = m02;
3594                    M10 = m10;
3595                    M11 = m11;
3596                    M12 = m12;
3597                    det = M00 * M11 - M01 * M10;
3598                    if (Math.abs(det) <= Double.MIN_VALUE) {
3599                        throw new NoninvertibleTransformException(
3600                                "Determinant is " + det);
3601                    }
3602                    while (--numPts >= 0) {
3603                        double x = srcPts[srcOff++] - M02;
3604                        double y = srcPts[srcOff++] - M12;
3605                        dstPts[dstOff++] = (x * M11 - y * M01) / det;
3606                        dstPts[dstOff++] = (y * M00 - x * M10) / det;
3607                    }
3608                    return;
3609                case (APPLY_SHEAR | APPLY_SCALE):
3610                    M00 = m00;
3611                    M01 = m01;
3612                    M10 = m10;
3613                    M11 = m11;
3614                    det = M00 * M11 - M01 * M10;
3615                    if (Math.abs(det) <= Double.MIN_VALUE) {
3616                        throw new NoninvertibleTransformException(
3617                                "Determinant is " + det);
3618                    }
3619                    while (--numPts >= 0) {
3620                        double x = srcPts[srcOff++];
3621                        double y = srcPts[srcOff++];
3622                        dstPts[dstOff++] = (x * M11 - y * M01) / det;
3623                        dstPts[dstOff++] = (y * M00 - x * M10) / det;
3624                    }
3625                    return;
3626                case (APPLY_SHEAR | APPLY_TRANSLATE):
3627                    M01 = m01;
3628                    M02 = m02;
3629                    M10 = m10;
3630                    M12 = m12;
3631                    if (M01 == 0.0 || M10 == 0.0) {
3632                        throw new NoninvertibleTransformException(
3633                                "Determinant is 0");
3634                    }
3635                    while (--numPts >= 0) {
3636                        double x = srcPts[srcOff++] - M02;
3637                        dstPts[dstOff++] = (srcPts[srcOff++] - M12) / M10;
3638                        dstPts[dstOff++] = x / M01;
3639                    }
3640                    return;
3641                case (APPLY_SHEAR):
3642                    M01 = m01;
3643                    M10 = m10;
3644                    if (M01 == 0.0 || M10 == 0.0) {
3645                        throw new NoninvertibleTransformException(
3646                                "Determinant is 0");
3647                    }
3648                    while (--numPts >= 0) {
3649                        double x = srcPts[srcOff++];
3650                        dstPts[dstOff++] = srcPts[srcOff++] / M10;
3651                        dstPts[dstOff++] = x / M01;
3652                    }
3653                    return;
3654                case (APPLY_SCALE | APPLY_TRANSLATE):
3655                    M00 = m00;
3656                    M02 = m02;
3657                    M11 = m11;
3658                    M12 = m12;
3659                    if (M00 == 0.0 || M11 == 0.0) {
3660                        throw new NoninvertibleTransformException(
3661                                "Determinant is 0");
3662                    }
3663                    while (--numPts >= 0) {
3664                        dstPts[dstOff++] = (srcPts[srcOff++] - M02) / M00;
3665                        dstPts[dstOff++] = (srcPts[srcOff++] - M12) / M11;
3666                    }
3667                    return;
3668                case (APPLY_SCALE):
3669                    M00 = m00;
3670                    M11 = m11;
3671                    if (M00 == 0.0 || M11 == 0.0) {
3672                        throw new NoninvertibleTransformException(
3673                                "Determinant is 0");
3674                    }
3675                    while (--numPts >= 0) {
3676                        dstPts[dstOff++] = srcPts[srcOff++] / M00;
3677                        dstPts[dstOff++] = srcPts[srcOff++] / M11;
3678                    }
3679                    return;
3680                case (APPLY_TRANSLATE):
3681                    M02 = m02;
3682                    M12 = m12;
3683                    while (--numPts >= 0) {
3684                        dstPts[dstOff++] = srcPts[srcOff++] - M02;
3685                        dstPts[dstOff++] = srcPts[srcOff++] - M12;
3686                    }
3687                    return;
3688                case (APPLY_IDENTITY):
3689                    if (srcPts != dstPts || srcOff != dstOff) {
3690                        System.arraycopy(srcPts, srcOff, dstPts, dstOff,
3691                                numPts * 2);
3692                    }
3693                    return;
3694                }
3695
3696                /* NOTREACHED */
3697            }
3698
3699            /**
3700             * Transforms the relative distance vector specified by 
3701             * <code>ptSrc</code> and stores the result in <code>ptDst</code>.
3702             * A relative distance vector is transformed without applying the
3703             * translation components of the affine transformation matrix
3704             * using the following equations:
3705             * <pre>
3706             *	[  x' ]   [  m00  m01 (m02) ] [  x  ]   [ m00x + m01y ]
3707             *	[  y' ] = [  m10  m11 (m12) ] [  y  ] = [ m10x + m11y ]
3708             *	[ (1) ]   [  (0)  (0) ( 1 ) ] [ (1) ]   [     (1)     ]
3709             * </pre>
3710             * If <code>ptDst</code> is <code>null</code>, a new
3711             * <code>Point2D</code> object is allocated and then the result of the
3712             * transform is stored in this object.
3713             * In either case, <code>ptDst</code>, which contains the
3714             * transformed point, is returned for convenience.
3715             * If <code>ptSrc</code> and <code>ptDst</code> are the same object,
3716             * the input point is correctly overwritten with the transformed
3717             * point.
3718             * @param ptSrc the distance vector to be delta transformed
3719             * @param ptDst the resulting transformed distance vector
3720             * @return <code>ptDst</code>, which contains the result of the
3721             * transformation.
3722             * @since 1.2
3723             */
3724            public Point2D deltaTransform(Point2D ptSrc, Point2D ptDst) {
3725                if (ptDst == null) {
3726                    if (ptSrc instanceof  Point2D.Double) {
3727                        ptDst = new Point2D.Double();
3728                    } else {
3729                        ptDst = new Point2D.Float();
3730                    }
3731                }
3732                // Copy source coords into local variables in case src == dst
3733                double x = ptSrc.getX();
3734                double y = ptSrc.getY();
3735                switch (state) {
3736                default:
3737                    stateError();
3738                    /* NOTREACHED */
3739                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3740                case (APPLY_SHEAR | APPLY_SCALE):
3741                    ptDst.setLocation(x * m00 + y * m01, x * m10 + y * m11);
3742                    return ptDst;
3743                case (APPLY_SHEAR | APPLY_TRANSLATE):
3744                case (APPLY_SHEAR):
3745                    ptDst.setLocation(y * m01, x * m10);
3746                    return ptDst;
3747                case (APPLY_SCALE | APPLY_TRANSLATE):
3748                case (APPLY_SCALE):
3749                    ptDst.setLocation(x * m00, y * m11);
3750                    return ptDst;
3751                case (APPLY_TRANSLATE):
3752                case (APPLY_IDENTITY):
3753                    ptDst.setLocation(x, y);
3754                    return ptDst;
3755                }
3756
3757                /* NOTREACHED */
3758            }
3759
3760            /**
3761             * Transforms an array of relative distance vectors by this
3762             * transform.
3763             * A relative distance vector is transformed without applying the
3764             * translation components of the affine transformation matrix
3765             * using the following equations:
3766             * <pre>
3767             *	[  x' ]   [  m00  m01 (m02) ] [  x  ]   [ m00x + m01y ]
3768             *	[  y' ] = [  m10  m11 (m12) ] [  y  ] = [ m10x + m11y ]
3769             *	[ (1) ]   [  (0)  (0) ( 1 ) ] [ (1) ]   [     (1)     ]
3770             * </pre>
3771             * The two coordinate array sections can be exactly the same or
3772             * can be overlapping sections of the same array without affecting the
3773             * validity of the results.
3774             * This method ensures that no source coordinates are
3775             * overwritten by a previous operation before they can be transformed.
3776             * The coordinates are stored in the arrays starting at the indicated
3777             * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3778             * @param srcPts the array containing the source distance vectors.
3779             * Each vector is stored as a pair of relative x,&nbsp;y coordinates.
3780             * @param dstPts the array into which the transformed distance vectors
3781             * are returned.  Each vector is stored as a pair of relative
3782             * x,&nbsp;y coordinates.
3783             * @param srcOff the offset to the first vector to be transformed
3784             * in the source array
3785             * @param dstOff the offset to the location of the first
3786             * transformed vector that is stored in the destination array
3787             * @param numPts the number of vector coordinate pairs to be
3788             * transformed
3789             * @since 1.2
3790             */
3791            public void deltaTransform(double[] srcPts, int srcOff,
3792                    double[] dstPts, int dstOff, int numPts) {
3793                double M00, M01, M10, M11; // For caching
3794                if (dstPts == srcPts && dstOff > srcOff
3795                        && dstOff < srcOff + numPts * 2) {
3796                    // If the arrays overlap partially with the destination higher
3797                    // than the source and we transform the coordinates normally
3798                    // we would overwrite some of the later source coordinates
3799                    // with results of previous transformations.
3800                    // To get around this we use arraycopy to copy the points
3801                    // to their final destination with correct overwrite
3802                    // handling and then transform them in place in the new
3803                    // safer location.
3804                    System
3805                            .arraycopy(srcPts, srcOff, dstPts, dstOff,
3806                                    numPts * 2);
3807                    // srcPts = dstPts;		// They are known to be equal.
3808                    srcOff = dstOff;
3809                }
3810                switch (state) {
3811                default:
3812                    stateError();
3813                    /* NOTREACHED */
3814                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3815                case (APPLY_SHEAR | APPLY_SCALE):
3816                    M00 = m00;
3817                    M01 = m01;
3818                    M10 = m10;
3819                    M11 = m11;
3820                    while (--numPts >= 0) {
3821                        double x = srcPts[srcOff++];
3822                        double y = srcPts[srcOff++];
3823                        dstPts[dstOff++] = x * M00 + y * M01;
3824                        dstPts[dstOff++] = x * M10 + y * M11;
3825                    }
3826                    return;
3827                case (APPLY_SHEAR | APPLY_TRANSLATE):
3828                case (APPLY_SHEAR):
3829                    M01 = m01;
3830                    M10 = m10;
3831                    while (--numPts >= 0) {
3832                        double x = srcPts[srcOff++];
3833                        dstPts[dstOff++] = srcPts[srcOff++] * M01;
3834                        dstPts[dstOff++] = x * M10;
3835                    }
3836                    return;
3837                case (APPLY_SCALE | APPLY_TRANSLATE):
3838                case (APPLY_SCALE):
3839                    M00 = m00;
3840                    M11 = m11;
3841                    while (--numPts >= 0) {
3842                        dstPts[dstOff++] = srcPts[srcOff++] * M00;
3843                        dstPts[dstOff++] = srcPts[srcOff++] * M11;
3844                    }
3845                    return;
3846                case (APPLY_TRANSLATE):
3847                case (APPLY_IDENTITY):
3848                    if (srcPts != dstPts || srcOff != dstOff) {
3849                        System.arraycopy(srcPts, srcOff, dstPts, dstOff,
3850                                numPts * 2);
3851                    }
3852                    return;
3853                }
3854
3855                /* NOTREACHED */
3856            }
3857
3858            /**
3859             * Returns a new {@link Shape} object defined by the geometry of the
3860             * specified <code>Shape</code> after it has been transformed by
3861             * this transform.
3862             * @param pSrc the specified <code>Shape</code> object to be
3863             * transformed by this transform.
3864             * @return a new <code>Shape</code> object that defines the geometry
3865             * of the transformed <code>Shape</code>, or null if {@code pSrc} is null.
3866             * @since 1.2
3867             */
3868            public Shape createTransformedShape(Shape pSrc) {
3869                if (pSrc == null) {
3870                    return null;
3871                }
3872                return new Path2D.Double(pSrc, this );
3873            }
3874
3875            // Round values to sane precision for printing
3876            // Note that Math.sin(Math.PI) has an error of about 10^-16
3877            private static double _matround(double matval) {
3878                return Math.rint(matval * 1E15) / 1E15;
3879            }
3880
3881            /**
3882             * Returns a <code>String</code> that represents the value of this
3883             * {@link Object}.
3884             * @return a <code>String</code> representing the value of this
3885             * <code>Object</code>.
3886             * @since 1.2
3887             */
3888            public String toString() {
3889                return ("AffineTransform[[" + _matround(m00) + ", "
3890                        + _matround(m01) + ", " + _matround(m02) + "], ["
3891                        + _matround(m10) + ", " + _matround(m11) + ", "
3892                        + _matround(m12) + "]]");
3893            }
3894
3895            /**
3896             * Returns <code>true</code> if this <code>AffineTransform</code> is
3897             * an identity transform.
3898             * @return <code>true</code> if this <code>AffineTransform</code> is
3899             * an identity transform; <code>false</code> otherwise.
3900             * @since 1.2
3901             */
3902            public boolean isIdentity() {
3903                return (state == APPLY_IDENTITY || (getType() == TYPE_IDENTITY));
3904            }
3905
3906            /**
3907             * Returns a copy of this <code>AffineTransform</code> object.
3908             * @return an <code>Object</code> that is a copy of this
3909             * <code>AffineTransform</code> object.
3910             * @since 1.2
3911             */
3912            public Object clone() {
3913                try {
3914                    return super .clone();
3915                } catch (CloneNotSupportedException e) {
3916                    // this shouldn't happen, since we are Cloneable
3917                    throw new InternalError();
3918                }
3919            }
3920
3921            /**
3922             * Returns the hashcode for this transform.
3923             * @return      a hash code for this transform.
3924             * @since 1.2
3925             */
3926            public int hashCode() {
3927                long bits = Double.doubleToLongBits(m00);
3928                bits = bits * 31 + Double.doubleToLongBits(m01);
3929                bits = bits * 31 + Double.doubleToLongBits(m02);
3930                bits = bits * 31 + Double.doubleToLongBits(m10);
3931                bits = bits * 31 + Double.doubleToLongBits(m11);
3932                bits = bits * 31 + Double.doubleToLongBits(m12);
3933                return (((int) bits) ^ ((int) (bits >> 32)));
3934            }
3935
3936            /**
3937             * Returns <code>true</code> if this <code>AffineTransform</code> 
3938             * represents the same affine coordinate transform as the specified
3939             * argument.
3940             * @param obj the <code>Object</code> to test for equality with this
3941             * <code>AffineTransform</code>
3942             * @return <code>true</code> if <code>obj</code> equals this
3943             * <code>AffineTransform</code> object; <code>false</code> otherwise.
3944             * @since 1.2
3945             */
3946            public boolean equals(Object obj) {
3947                if (!(obj instanceof  AffineTransform)) {
3948                    return false;
3949                }
3950
3951                AffineTransform a = (AffineTransform) obj;
3952
3953                return ((m00 == a.m00) && (m01 == a.m01) && (m02 == a.m02)
3954                        && (m10 == a.m10) && (m11 == a.m11) && (m12 == a.m12));
3955            }
3956
3957            /* Serialization support.  A readObject method is neccessary because
3958             * the state field is part of the implementation of this particular
3959             * AffineTransform and not part of the public specification.  The
3960             * state variable's value needs to be recalculated on the fly by the
3961             * readObject method as it is in the 6-argument matrix constructor.
3962             */
3963
3964            /*
3965             * JDK 1.2 serialVersionUID 
3966             */
3967            private static final long serialVersionUID = 1330973210523860834L;
3968
3969            private void writeObject(java.io.ObjectOutputStream s)
3970                    throws java.lang.ClassNotFoundException,
3971                    java.io.IOException {
3972                s.defaultWriteObject();
3973            }
3974
3975            private void readObject(java.io.ObjectInputStream s)
3976                    throws java.lang.ClassNotFoundException,
3977                    java.io.IOException {
3978                s.defaultReadObject();
3979                updateState();
3980            }
3981        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.