Source Code Cross Referenced for AffineTransform.java in  » Scripting » hecl » org » awt » geom » Java Source Code / Java DocumentationJava Source Code and Java Documentation

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 geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Scripting » hecl » org.awt.geom 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright (C) 2005, 2006 data2c GmbH (www.data2c.com)
0003:         *
0004:         * Author: Wolfgang S. Kechel - wolfgang.kechel@data2c.com
0005:         * 
0006:         * J2ME version of java.awt.geom.AffineTransform.
0007:         */
0008:
0009:        //#ifndef j2se
0010:        package org.awt.geom;
0011:
0012:        //#ifdef notdef
0013:        import java.awt.Shape;
0014:
0015:        //#endif
0016:
0017:        /**
0018:         * The <code>AffineTransform</code> class represents a 2D affine transform
0019:         * that performs a linear mapping from 2D coordinates to other 2D
0020:         * coordinates that preserves the "straightness" and
0021:         * "parallelness" of lines.  Affine transformations can be constructed
0022:         * using sequences of translations, scales, flips, rotations, and shears.
0023:         * <p>
0024:         * Such a coordinate transformation can be represented by a 3 row by
0025:         * 3 column matrix with an implied last row of [ 0 0 1 ].  This matrix 
0026:         * transforms source coordinates <code>(x,&nbsp;y)</code> into
0027:         * destination coordinates <code>(x',&nbsp;y')</code> by considering
0028:         * them to be a column vector and multiplying the coordinate vector
0029:         * by the matrix according to the following process:
0030:         * <pre>
0031:         *	[ x']   [  m00  m01  m02  ] [ x ]   [ m00x + m01y + m02 ]
0032:         *	[ y'] = [  m10  m11  m12  ] [ y ] = [ m10x + m11y + m12 ]
0033:         *	[ 1 ]   [   0    0    1   ] [ 1 ]   [         1         ]
0034:         * </pre>
0035:         */
0036:        public class AffineTransform /*implements Cloneable, java.io.Serializable*/{
0037:            /*
0038:             * This constant is only useful for the cached type field.
0039:             * It indicates that the type has been decached and must be recalculated.
0040:             */
0041:            private static final int TYPE_UNKNOWN = -1;
0042:
0043:            /**
0044:             * This constant indicates that the transform defined by this object
0045:             * is an identity transform.
0046:             * An identity transform is one in which the output coordinates are
0047:             * always the same as the input coordinates.
0048:             * If this transform is anything other than the identity transform,
0049:             * the type will either be the constant GENERAL_TRANSFORM or a
0050:             * combination of the appropriate flag bits for the various coordinate
0051:             * conversions that this transform performs.
0052:             * @see #TYPE_TRANSLATION
0053:             * @see #TYPE_UNIFORM_SCALE
0054:             * @see #TYPE_GENERAL_SCALE
0055:             * @see #TYPE_FLIP
0056:             * @see #TYPE_QUADRANT_ROTATION
0057:             * @see #TYPE_GENERAL_ROTATION
0058:             * @see #TYPE_GENERAL_TRANSFORM
0059:             * @see #getType
0060:             */
0061:            public static final int TYPE_IDENTITY = 0;
0062:
0063:            /**
0064:             * This flag bit indicates that the transform defined by this object
0065:             * performs a translation in addition to the conversions indicated
0066:             * by other flag bits.
0067:             * A translation moves the coordinates by a constant amount in x
0068:             * and y without changing the length or angle of vectors.
0069:             * @see #TYPE_IDENTITY
0070:             * @see #TYPE_UNIFORM_SCALE
0071:             * @see #TYPE_GENERAL_SCALE
0072:             * @see #TYPE_FLIP
0073:             * @see #TYPE_QUADRANT_ROTATION
0074:             * @see #TYPE_GENERAL_ROTATION
0075:             * @see #TYPE_GENERAL_TRANSFORM
0076:             * @see #getType
0077:             */
0078:            public static final int TYPE_TRANSLATION = 1;
0079:
0080:            /**
0081:             * This flag bit indicates that the transform defined by this object
0082:             * performs a uniform scale in addition to the conversions indicated
0083:             * by other flag bits.
0084:             * A uniform scale multiplies the length of vectors by the same amount
0085:             * in both the x and y directions without changing the angle between
0086:             * vectors.
0087:             * This flag bit is mutually exclusive with the TYPE_GENERAL_SCALE flag.
0088:             * @see #TYPE_IDENTITY
0089:             * @see #TYPE_TRANSLATION
0090:             * @see #TYPE_GENERAL_SCALE
0091:             * @see #TYPE_FLIP
0092:             * @see #TYPE_QUADRANT_ROTATION
0093:             * @see #TYPE_GENERAL_ROTATION
0094:             * @see #TYPE_GENERAL_TRANSFORM
0095:             * @see #getType
0096:             */
0097:            public static final int TYPE_UNIFORM_SCALE = 2;
0098:
0099:            /**
0100:             * This flag bit indicates that the transform defined by this object
0101:             * performs a general scale in addition to the conversions indicated
0102:             * by other flag bits.
0103:             * A general scale multiplies the length of vectors by different
0104:             * amounts in the x and y directions without changing the angle
0105:             * between perpendicular vectors.
0106:             * This flag bit is mutually exclusive with the TYPE_UNIFORM_SCALE flag.
0107:             * @see #TYPE_IDENTITY
0108:             * @see #TYPE_TRANSLATION
0109:             * @see #TYPE_UNIFORM_SCALE
0110:             * @see #TYPE_FLIP
0111:             * @see #TYPE_QUADRANT_ROTATION
0112:             * @see #TYPE_GENERAL_ROTATION
0113:             * @see #TYPE_GENERAL_TRANSFORM
0114:             * @see #getType
0115:             */
0116:            public static final int TYPE_GENERAL_SCALE = 4;
0117:
0118:            /**
0119:             * This constant is a bit mask for any of the scale flag bits.
0120:             * @see #TYPE_UNIFORM_SCALE
0121:             * @see #TYPE_GENERAL_SCALE
0122:             */
0123:            public static final int TYPE_MASK_SCALE = (TYPE_UNIFORM_SCALE | TYPE_GENERAL_SCALE);
0124:
0125:            /**
0126:             * This flag bit indicates that the transform defined by this object
0127:             * performs a mirror image flip about some axis which changes the
0128:             * normally right handed coordinate system into a left handed
0129:             * system in addition to the conversions indicated by other flag bits.
0130:             * A right handed coordinate system is one where the positive X
0131:             * axis rotates counterclockwise to overlay the positive Y axis
0132:             * similar to the direction that the fingers on your right hand
0133:             * curl when you stare end on at your thumb.
0134:             * A left handed coordinate system is one where the positive X
0135:             * axis rotates clockwise to overlay the positive Y axis similar
0136:             * to the direction that the fingers on your left hand curl.
0137:             * There is no mathematical way to determine the angle of the
0138:             * original flipping or mirroring transformation since all angles
0139:             * of flip are identical given an appropriate adjusting rotation.
0140:             * @see #TYPE_IDENTITY
0141:             * @see #TYPE_TRANSLATION
0142:             * @see #TYPE_UNIFORM_SCALE
0143:             * @see #TYPE_GENERAL_SCALE
0144:             * @see #TYPE_QUADRANT_ROTATION
0145:             * @see #TYPE_GENERAL_ROTATION
0146:             * @see #TYPE_GENERAL_TRANSFORM
0147:             * @see #getType
0148:             */
0149:            public static final int TYPE_FLIP = 64;
0150:            /* NOTE: TYPE_FLIP was added after GENERAL_TRANSFORM was in public
0151:             * circulation and the flag bits could no longer be conveniently
0152:             * renumbered without introducing binary incompatibility in outside
0153:             * code.
0154:             */
0155:
0156:            /**
0157:             * This flag bit indicates that the transform defined by this object
0158:             * performs a quadrant rotation by some multiple of 90 degrees in
0159:             * addition to the conversions indicated by other flag bits.
0160:             * A rotation changes the angles of vectors by the same amount
0161:             * regardless of the original direction of the vector and without
0162:             * changing the length of the vector.
0163:             * This flag bit is mutually exclusive with the TYPE_GENERAL_ROTATION flag.
0164:             * @see #TYPE_IDENTITY
0165:             * @see #TYPE_TRANSLATION
0166:             * @see #TYPE_UNIFORM_SCALE
0167:             * @see #TYPE_GENERAL_SCALE
0168:             * @see #TYPE_FLIP
0169:             * @see #TYPE_GENERAL_ROTATION
0170:             * @see #TYPE_GENERAL_TRANSFORM
0171:             * @see #getType
0172:             */
0173:            public static final int TYPE_QUADRANT_ROTATION = 8;
0174:
0175:            /**
0176:             * This flag bit indicates that the transform defined by this object
0177:             * performs a rotation by an arbitrary angle in addition to the
0178:             * conversions indicated by other flag bits.
0179:             * A rotation changes the angles of vectors by the same amount
0180:             * regardless of the original direction of the vector and without
0181:             * changing the length of the vector.
0182:             * This flag bit is mutually exclusive with the
0183:             * TYPE_QUADRANT_ROTATION flag.
0184:             * @see #TYPE_IDENTITY
0185:             * @see #TYPE_TRANSLATION
0186:             * @see #TYPE_UNIFORM_SCALE
0187:             * @see #TYPE_GENERAL_SCALE
0188:             * @see #TYPE_FLIP
0189:             * @see #TYPE_QUADRANT_ROTATION
0190:             * @see #TYPE_GENERAL_TRANSFORM
0191:             * @see #getType
0192:             */
0193:            public static final int TYPE_GENERAL_ROTATION = 16;
0194:
0195:            /**
0196:             * This constant is a bit mask for any of the rotation flag bits.
0197:             * @see #TYPE_QUADRANT_ROTATION
0198:             * @see #TYPE_GENERAL_ROTATION
0199:             */
0200:            public static final int TYPE_MASK_ROTATION = (TYPE_QUADRANT_ROTATION | TYPE_GENERAL_ROTATION);
0201:
0202:            /**
0203:             * This constant indicates that the transform defined by this object
0204:             * performs an arbitrary conversion of the input coordinates.
0205:             * If this transform can be classified by any of the above constants,
0206:             * the type will either be the constant TYPE_IDENTITY or a
0207:             * combination of the appropriate flag bits for the various coordinate
0208:             * conversions that this transform performs.
0209:             * @see #TYPE_IDENTITY
0210:             * @see #TYPE_TRANSLATION
0211:             * @see #TYPE_UNIFORM_SCALE
0212:             * @see #TYPE_GENERAL_SCALE
0213:             * @see #TYPE_FLIP
0214:             * @see #TYPE_QUADRANT_ROTATION
0215:             * @see #TYPE_GENERAL_ROTATION
0216:             * @see #getType
0217:             */
0218:            public static final int TYPE_GENERAL_TRANSFORM = 32;
0219:
0220:            /**
0221:             * This constant is used for the internal state variable to indicate
0222:             * that no calculations need to be performed and that the source
0223:             * coordinates only need to be copied to their destinations to
0224:             * complete the transformation equation of this transform.
0225:             * @see #APPLY_TRANSLATE
0226:             * @see #APPLY_SCALE
0227:             * @see #APPLY_SHEAR
0228:             * @see #state
0229:             */
0230:            static final int APPLY_IDENTITY = 0;
0231:
0232:            /**
0233:             * This constant is used for the internal state variable to indicate
0234:             * that the translation components of the matrix (m02 and m12) need
0235:             * to be added to complete the transformation equation of this transform.
0236:             * @see #APPLY_IDENTITY
0237:             * @see #APPLY_SCALE
0238:             * @see #APPLY_SHEAR
0239:             * @see #state
0240:             */
0241:            static final int APPLY_TRANSLATE = 1;
0242:
0243:            /**
0244:             * This constant is used for the internal state variable to indicate
0245:             * that the scaling components of the matrix (m00 and m11) need
0246:             * to be factored in to complete the transformation equation of
0247:             * this transform.  If the APPLY_SHEAR bit is also set then it
0248:             * indicates that the scaling components are not both 0.0.  If the
0249:             * APPLY_SHEAR bit is not also set then it indicates that the
0250:             * scaling components are not both 1.0.  If neither the APPLY_SHEAR
0251:             * nor the APPLY_SCALE bits are set then the scaling components
0252:             * are both 1.0, which means that the x and y components contribute
0253:             * to the transformed coordinate, but they are not multiplied by
0254:             * any scaling factor.
0255:             * @see #APPLY_IDENTITY
0256:             * @see #APPLY_TRANSLATE
0257:             * @see #APPLY_SHEAR
0258:             * @see #state
0259:             */
0260:            static final int APPLY_SCALE = 2;
0261:
0262:            /**
0263:             * This constant is used for the internal state variable to indicate
0264:             * that the shearing components of the matrix (m01 and m10) need
0265:             * to be factored in to complete the transformation equation of this
0266:             * transform.  The presence of this bit in the state variable changes
0267:             * the interpretation of the APPLY_SCALE bit as indicated in its
0268:             * documentation.
0269:             * @see #APPLY_IDENTITY
0270:             * @see #APPLY_TRANSLATE
0271:             * @see #APPLY_SCALE
0272:             * @see #state
0273:             */
0274:            static final int APPLY_SHEAR = 4;
0275:
0276:            /*
0277:             * For methods which combine together the state of two separate
0278:             * transforms and dispatch based upon the combination, these constants
0279:             * specify how far to shift one of the states so that the two states 
0280:             * are mutually non-interfering and provide constants for testing the
0281:             * bits of the shifted (HI) state.  The methods in this class use
0282:             * the convention that the state of "this" transform is unshifted and
0283:             * the state of the "other" or "argument" transform is shifted (HI).
0284:             */
0285:            private static final int HI_SHIFT = 3;
0286:            private static final int HI_IDENTITY = APPLY_IDENTITY << HI_SHIFT;
0287:            private static final int HI_TRANSLATE = APPLY_TRANSLATE << HI_SHIFT;
0288:            private static final int HI_SCALE = APPLY_SCALE << HI_SHIFT;
0289:            private static final int HI_SHEAR = APPLY_SHEAR << HI_SHIFT;
0290:
0291:            /**
0292:             * The X coordinate scaling element of the 3x3
0293:             * affine transformation matrix.
0294:             * 
0295:             * @serial
0296:             */
0297:            double m00;
0298:
0299:            /**
0300:             * The Y coordinate shearing element of the 3x3
0301:             * affine transformation matrix.
0302:             *
0303:             * @serial
0304:             */
0305:            double m10;
0306:
0307:            /**
0308:             * The X coordinate shearing element of the 3x3
0309:             * affine transformation matrix.
0310:             *
0311:             * @serial
0312:             */
0313:            double m01;
0314:
0315:            /**
0316:             * The Y coordinate scaling element of the 3x3
0317:             * affine transformation matrix.
0318:             * 
0319:             * @serial
0320:             */
0321:            double m11;
0322:
0323:            /**
0324:             * The X coordinate of the translation element of the
0325:             * 3x3 affine transformation matrix.
0326:             * 
0327:             * @serial
0328:             */
0329:            double m02;
0330:
0331:            /**
0332:             * The Y coordinate of the translation element of the
0333:             * 3x3 affine transformation matrix.
0334:             *
0335:             * @serial
0336:             */
0337:            double m12;
0338:
0339:            /**
0340:             * This field keeps track of which components of the matrix need to
0341:             * be applied when performing a transformation.
0342:             * @see #APPLY_IDENTITY
0343:             * @see #APPLY_TRANSLATE
0344:             * @see #APPLY_SCALE
0345:             * @see #APPLY_SHEAR
0346:             */
0347:            transient int state;
0348:
0349:            /**
0350:             * This field caches the current transformation type of the matrix.
0351:             * @see #TYPE_IDENTITY
0352:             * @see #TYPE_TRANSLATION
0353:             * @see #TYPE_UNIFORM_SCALE
0354:             * @see #TYPE_GENERAL_SCALE
0355:             * @see #TYPE_FLIP
0356:             * @see #TYPE_QUADRANT_ROTATION
0357:             * @see #TYPE_GENERAL_ROTATION
0358:             * @see #TYPE_GENERAL_TRANSFORM
0359:             * @see #TYPE_UNKNOWN
0360:             * @see #getType
0361:             */
0362:            private transient int type;
0363:
0364:            private AffineTransform(double m00, double m10, double m01,
0365:                    double m11, double m02, double m12, int state) {
0366:                this .m00 = m00;
0367:                this .m10 = m10;
0368:                this .m01 = m01;
0369:                this .m11 = m11;
0370:                this .m02 = m02;
0371:                this .m12 = m12;
0372:                this .state = state;
0373:                this .type = TYPE_UNKNOWN;
0374:            }
0375:
0376:            /**
0377:             * Constructs a new <code>AffineTransform</code> representing the
0378:             * Identity transformation.
0379:             */
0380:            public AffineTransform() {
0381:                m00 = m11 = 1.0;
0382:                // m01 = m10 = m02 = m12 = 0.0;		/* Not needed. */
0383:                // state = APPLY_IDENTITY;		/* Not needed. */
0384:                // type = TYPE_IDENTITY;		/* Not needed. */
0385:            }
0386:
0387:            /**
0388:             * Constructs a new <code>AffineTransform</code> that is a copy of
0389:             * the specified <code>AffineTransform</code> object.
0390:             * @param Tx the <code>AffineTransform</code> object to copy 
0391:             */
0392:            public AffineTransform(AffineTransform Tx) {
0393:                this .m00 = Tx.m00;
0394:                this .m10 = Tx.m10;
0395:                this .m01 = Tx.m01;
0396:                this .m11 = Tx.m11;
0397:                this .m02 = Tx.m02;
0398:                this .m12 = Tx.m12;
0399:                this .state = Tx.state;
0400:                this .type = Tx.type;
0401:            }
0402:
0403:            /**
0404:             * Constructs a new <code>AffineTransform</code> from 6 floating point
0405:             * values representing the 6 specifiable entries of the 3x3
0406:             * transformation matrix.
0407:             * @param m00,&nbsp;m01,&nbsp;m02,&nbsp;m10,&nbsp;m11,&nbsp;m12 the 
0408:             * 6 floating point values that compose the 3x3 transformation matrix
0409:             */
0410:            public AffineTransform(float m00, float m10, float m01, float m11,
0411:                    float m02, float m12) {
0412:                this .m00 = m00;
0413:                this .m10 = m10;
0414:                this .m01 = m01;
0415:                this .m11 = m11;
0416:                this .m02 = m02;
0417:                this .m12 = m12;
0418:                updateState();
0419:            }
0420:
0421:            /**
0422:             * Constructs a new <code>AffineTransform</code> from an array of
0423:             * floating point values representing either the 4 non-translation 
0424:             * enries or the 6 specifiable entries of the 3x3 transformation
0425:             * matrix.  The values are retrieved from the array as 
0426:             * {&nbsp;m00&nbsp;m10&nbsp;m01&nbsp;m11&nbsp;[m02&nbsp;m12]}.
0427:             * @param flatmatrix the float array containing the values to be set
0428:             * in the new <code>AffineTransform</code> object. The length of the
0429:             * array is assumed to be at least 4. If the length of the array is 
0430:             * less than 6, only the first 4 values are taken. If the length of
0431:             * the array is greater than 6, the first 6 values are taken.
0432:             */
0433:            public AffineTransform(float[] flatmatrix) {
0434:                m00 = flatmatrix[0];
0435:                m10 = flatmatrix[1];
0436:                m01 = flatmatrix[2];
0437:                m11 = flatmatrix[3];
0438:                if (flatmatrix.length > 5) {
0439:                    m02 = flatmatrix[4];
0440:                    m12 = flatmatrix[5];
0441:                }
0442:                updateState();
0443:            }
0444:
0445:            /**
0446:             * Constructs a new <code>AffineTransform</code> from 6 double
0447:             * precision values representing the 6 specifiable entries of the 3x3
0448:             * transformation matrix.
0449:             * @param m00,&nbsp;m01,&nbsp;m02,&nbsp;m10,&nbsp;m11,&nbsp;m12 the 
0450:             * 6 floating point values that compose the 3x3 transformation matrix
0451:             */
0452:            public AffineTransform(double m00, double m10, double m01,
0453:                    double m11, double m02, double m12) {
0454:                this .m00 = m00;
0455:                this .m10 = m10;
0456:                this .m01 = m01;
0457:                this .m11 = m11;
0458:                this .m02 = m02;
0459:                this .m12 = m12;
0460:                updateState();
0461:            }
0462:
0463:            /**
0464:             * Constructs a new <code>AffineTransform</code> from an array of
0465:             * double precision values representing either the 4 non-translation
0466:             * entries or the 6 specifiable entries of the 3x3 transformation
0467:             * matrix. The values are retrieved from the array as 
0468:             * {&nbsp;m00&nbsp;m10&nbsp;m01&nbsp;m11&nbsp;[m02&nbsp;m12]}.     
0469:             * @param flatmatrix the double array containing the values to be set
0470:             * in the new <code>AffineTransform</code> object. The length of the
0471:             * array is assumed to be at least 4. If the length of the array is 
0472:             * less than 6, only the first 4 values are taken. If the length of
0473:             * the array is greater than 6, the first 6 values are taken.
0474:             */
0475:            public AffineTransform(double[] flatmatrix) {
0476:                m00 = flatmatrix[0];
0477:                m10 = flatmatrix[1];
0478:                m01 = flatmatrix[2];
0479:                m11 = flatmatrix[3];
0480:                if (flatmatrix.length > 5) {
0481:                    m02 = flatmatrix[4];
0482:                    m12 = flatmatrix[5];
0483:                }
0484:                updateState();
0485:            }
0486:
0487:            /**
0488:             * Returns a transform representing a translation transformation.
0489:             * The matrix representing the returned transform is:
0490:             * <pre>
0491:             *		[   1    0    tx  ]
0492:             *		[   0    1    ty  ]
0493:             *		[   0    0    1   ]
0494:             * </pre>
0495:             * @param tx the distance by which coordinates are translated in the
0496:             * X axis direction
0497:             * @param ty the distance by which coordinates are translated in the
0498:             * Y axis direction
0499:             * @return an <code>AffineTransform</code> object that represents a
0500:             * 	translation transformation, created with the specified vector.
0501:             */
0502:            public static AffineTransform getTranslateInstance(double tx,
0503:                    double ty) {
0504:                AffineTransform Tx = new AffineTransform();
0505:                Tx.setToTranslation(tx, ty);
0506:                return Tx;
0507:            }
0508:
0509:            /**
0510:             * Returns a transform representing a rotation transformation.
0511:             * The matrix representing the returned transform is:
0512:             * <pre>
0513:             *		[   cos(theta)    -sin(theta)    0   ]
0514:             *		[   sin(theta)     cos(theta)    0   ]
0515:             *		[       0              0         1   ]
0516:             * </pre>
0517:             * Rotating with a positive angle theta rotates points on the positive
0518:             * x axis toward the positive y axis.
0519:             * @param theta the angle of rotation in radians
0520:             * @return an <code>AffineTransform</code> object that is a rotation
0521:             *	transformation, created with the specified angle of rotation.
0522:             */
0523:            public static AffineTransform getRotateInstance(double theta) {
0524:                AffineTransform Tx = new AffineTransform();
0525:                Tx.setToRotation(theta);
0526:                return Tx;
0527:            }
0528:
0529:            /**
0530:             * Returns a transform that rotates coordinates around an anchor point.
0531:             * This operation is equivalent to translating the coordinates so
0532:             * that the anchor point is at the origin (S1), then rotating them
0533:             * about the new origin (S2), and finally translating so that the
0534:             * intermediate origin is restored to the coordinates of the original
0535:             * anchor point (S3).
0536:             * <p>
0537:             * This operation is equivalent to the following sequence of calls:
0538:             * <pre>
0539:             *	    AffineTransform Tx = new AffineTransform();
0540:             *	    Tx.setToTranslation(x, y);	// S3: final translation
0541:             *	    Tx.rotate(theta);		// S2: rotate around anchor
0542:             *	    Tx.translate(-x, -y);	// S1: translate anchor to origin
0543:             * </pre>
0544:             * The matrix representing the returned transform is:
0545:             * <pre>
0546:             *		[   cos(theta)    -sin(theta)    x-x*cos+y*sin  ]
0547:             *		[   sin(theta)     cos(theta)    y-x*sin-y*cos  ]
0548:             *		[       0              0               1        ]
0549:             * </pre>
0550:             * Rotating with a positive angle theta rotates points on the positive
0551:             * x axis toward the positive y axis.
0552:             * @param theta the angle of rotation in radians
0553:             * @param x,&nbsp;y the coordinates of the anchor point of the
0554:             * rotation
0555:             * @return an <code>AffineTransform</code> object that rotates 
0556:             *	coordinates around the specified point by the specified angle of
0557:             *	rotation.
0558:             */
0559:            public static AffineTransform getRotateInstance(double theta,
0560:                    double x, double y) {
0561:                AffineTransform Tx = new AffineTransform();
0562:                Tx.setToRotation(theta, x, y);
0563:                return Tx;
0564:            }
0565:
0566:            /**
0567:             * Returns a transform representing a scaling transformation.
0568:             * The matrix representing the returned transform is:
0569:             * <pre>
0570:             *		[   sx   0    0   ]
0571:             *		[   0    sy   0   ]
0572:             *		[   0    0    1   ]
0573:             * </pre>
0574:             * @param sx the factor by which coordinates are scaled along the
0575:             * X axis direction
0576:             * @param sy the factor by which coordinates are scaled along the
0577:             * Y axis direction
0578:             * @return an <code>AffineTransform</code> object that scales 
0579:             *	coordinates by the specified factors.
0580:             */
0581:            public static AffineTransform getScaleInstance(double sx, double sy) {
0582:                AffineTransform Tx = new AffineTransform();
0583:                Tx.setToScale(sx, sy);
0584:                return Tx;
0585:            }
0586:
0587:            /**
0588:             * Returns a transform representing a shearing transformation.
0589:             * The matrix representing the returned transform is:
0590:             * <pre>
0591:             *		[   1   shx   0   ]
0592:             *		[  shy   1    0   ]
0593:             *		[   0    0    1   ]
0594:             * </pre>
0595:             * @param shx the multiplier by which coordinates are shifted in the
0596:             * direction of the positive X axis as a factor of their Y coordinate
0597:             * @param shy the multiplier by which coordinates are shifted in the
0598:             * direction of the positive Y axis as a factor of their X coordinate
0599:             * @return an <code>AffineTransform</code> object that shears 
0600:             *	coordinates by the specified multipliers.
0601:             */
0602:            public static AffineTransform getShearInstance(double shx,
0603:                    double shy) {
0604:                AffineTransform Tx = new AffineTransform();
0605:                Tx.setToShear(shx, shy);
0606:                return Tx;
0607:            }
0608:
0609:            /**
0610:             * Retrieves the flag bits describing the conversion properties of
0611:             * this transform.
0612:             * The return value is either one of the constants TYPE_IDENTITY
0613:             * or TYPE_GENERAL_TRANSFORM, or a combination of the
0614:             * appriopriate flag bits.
0615:             * A valid combination of flag bits is an exclusive OR operation
0616:             * that can combine
0617:             * the TYPE_TRANSLATION flag bit
0618:             * in addition to either of the
0619:             * TYPE_UNIFORM_SCALE or TYPE_GENERAL_SCALE flag bits
0620:             * as well as either of the
0621:             * TYPE_QUADRANT_ROTATION or TYPE_GENERAL_ROTATION flag bits.
0622:             * @return the OR combination of any of the indicated flags that
0623:             * apply to this transform
0624:             * @see #TYPE_IDENTITY
0625:             * @see #TYPE_TRANSLATION
0626:             * @see #TYPE_UNIFORM_SCALE
0627:             * @see #TYPE_GENERAL_SCALE
0628:             * @see #TYPE_QUADRANT_ROTATION
0629:             * @see #TYPE_GENERAL_ROTATION
0630:             * @see #TYPE_GENERAL_TRANSFORM
0631:             */
0632:            public int getType() {
0633:                if (type == TYPE_UNKNOWN) {
0634:                    calculateType();
0635:                }
0636:                return type;
0637:            }
0638:
0639:            /**
0640:             * This is the utility function to calculate the flag bits when
0641:             * they have not been cached.
0642:             * @see #getType
0643:             */
0644:            private void calculateType() {
0645:                int ret = TYPE_IDENTITY;
0646:                boolean sgn0, sgn1;
0647:                double M0, M1, M2, M3;
0648:                updateState();
0649:                switch (state) {
0650:                default:
0651:                    stateError();
0652:                    break;
0653:                /* NOTREACHED */
0654:                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
0655:                    ret = TYPE_TRANSLATION;
0656:                    /* NOBREAK */
0657:                case (APPLY_SHEAR | APPLY_SCALE):
0658:                    if ((M0 = m00) * (M2 = m01) + (M3 = m10) * (M1 = m11) != 0) {
0659:                        // Transformed unit vectors are not perpendicular...
0660:                        this .type = TYPE_GENERAL_TRANSFORM;
0661:                        return;
0662:                    }
0663:                    sgn0 = (M0 >= 0.0);
0664:                    sgn1 = (M1 >= 0.0);
0665:                    if (sgn0 == sgn1) {
0666:                        // sgn(M0) == sgn(M1) therefore sgn(M2) == -sgn(M3)
0667:                        // This is the "unflipped" (right-handed) state
0668:                        if (M0 != M1 || M2 != -M3) {
0669:                            ret |= (TYPE_GENERAL_ROTATION | TYPE_GENERAL_SCALE);
0670:                        } else if (M0 * M1 - M2 * M3 != 1.0) {
0671:                            ret |= (TYPE_GENERAL_ROTATION | TYPE_UNIFORM_SCALE);
0672:                        } else {
0673:                            ret |= TYPE_GENERAL_ROTATION;
0674:                        }
0675:                    } else {
0676:                        // sgn(M0) == -sgn(M1) therefore sgn(M2) == sgn(M3)
0677:                        // This is the "flipped" (left-handed) state
0678:                        if (M0 != -M1 || M2 != M3) {
0679:                            ret |= (TYPE_GENERAL_ROTATION | TYPE_FLIP | TYPE_GENERAL_SCALE);
0680:                        } else if (M0 * M1 - M2 * M3 != 1.0) {
0681:                            ret |= (TYPE_GENERAL_ROTATION | TYPE_FLIP | TYPE_UNIFORM_SCALE);
0682:                        } else {
0683:                            ret |= (TYPE_GENERAL_ROTATION | TYPE_FLIP);
0684:                        }
0685:                    }
0686:                    break;
0687:                case (APPLY_SHEAR | APPLY_TRANSLATE):
0688:                    ret = TYPE_TRANSLATION;
0689:                    /* NOBREAK */
0690:                case (APPLY_SHEAR):
0691:                    sgn0 = ((M0 = m01) >= 0.0);
0692:                    sgn1 = ((M1 = m10) >= 0.0);
0693:                    if (sgn0 != sgn1) {
0694:                        // Different signs - simple 90 degree rotation
0695:                        if (M0 != -M1) {
0696:                            ret |= (TYPE_QUADRANT_ROTATION | TYPE_GENERAL_SCALE);
0697:                        } else if (M0 != 1.0 && M0 != -1.0) {
0698:                            ret |= (TYPE_QUADRANT_ROTATION | TYPE_UNIFORM_SCALE);
0699:                        } else {
0700:                            ret |= TYPE_QUADRANT_ROTATION;
0701:                        }
0702:                    } else {
0703:                        // Same signs - 90 degree rotation plus an axis flip too
0704:                        if (M0 == M1) {
0705:                            ret |= (TYPE_QUADRANT_ROTATION | TYPE_FLIP | TYPE_UNIFORM_SCALE);
0706:                        } else {
0707:                            ret |= (TYPE_QUADRANT_ROTATION | TYPE_FLIP | TYPE_GENERAL_SCALE);
0708:                        }
0709:                    }
0710:                    break;
0711:                case (APPLY_SCALE | APPLY_TRANSLATE):
0712:                    ret = TYPE_TRANSLATION;
0713:                    /* NOBREAK */
0714:                case (APPLY_SCALE):
0715:                    sgn0 = ((M0 = m00) >= 0.0);
0716:                    sgn1 = ((M1 = m11) >= 0.0);
0717:                    if (sgn0 == sgn1) {
0718:                        if (sgn0) {
0719:                            // Both scaling factors non-negative - simple scale
0720:                            // Note: APPLY_SCALE implies M0, M1 are not both 1
0721:                            if (M0 == M1) {
0722:                                ret |= TYPE_UNIFORM_SCALE;
0723:                            } else {
0724:                                ret |= TYPE_GENERAL_SCALE;
0725:                            }
0726:                        } else {
0727:                            // Both scaling factors negative - 180 degree rotation
0728:                            if (M0 != M1) {
0729:                                ret |= (TYPE_QUADRANT_ROTATION | TYPE_GENERAL_SCALE);
0730:                            } else if (M0 != -1.0) {
0731:                                ret |= (TYPE_QUADRANT_ROTATION | TYPE_UNIFORM_SCALE);
0732:                            } else {
0733:                                ret |= TYPE_QUADRANT_ROTATION;
0734:                            }
0735:                        }
0736:                    } else {
0737:                        // Scaling factor signs different - flip about some axis
0738:                        if (M0 == -M1) {
0739:                            if (M0 == 1.0 || M0 == -1.0) {
0740:                                ret |= TYPE_FLIP;
0741:                            } else {
0742:                                ret |= (TYPE_FLIP | TYPE_UNIFORM_SCALE);
0743:                            }
0744:                        } else {
0745:                            ret |= (TYPE_FLIP | TYPE_GENERAL_SCALE);
0746:                        }
0747:                    }
0748:                    break;
0749:                case (APPLY_TRANSLATE):
0750:                    ret = TYPE_TRANSLATION;
0751:                    break;
0752:                case (APPLY_IDENTITY):
0753:                    break;
0754:                }
0755:                this .type = ret;
0756:            }
0757:
0758:            /**
0759:             * Returns the determinant of the matrix representation of the transform.
0760:             * The determinant is useful both to determine if the transform can
0761:             * be inverted and to get a single value representing the
0762:             * combined X and Y scaling of the transform.
0763:             * <p>
0764:             * If the determinant is non-zero, then this transform is
0765:             * invertible and the various methods that depend on the inverse
0766:             * transform do not need to throw a
0767:             * {@link NoninvertibleTransformException}.
0768:             * If the determinant is zero then this transform can not be
0769:             * inverted since the transform maps all input coordinates onto
0770:             * a line or a point.
0771:             * If the determinant is near enough to zero then inverse transform
0772:             * operations might not carry enough precision to produce meaningful
0773:             * results.
0774:             * <p>
0775:             * If this transform represents a uniform scale, as indicated by
0776:             * the <code>getType</code> method then the determinant also
0777:             * represents the square of the uniform scale factor by which all of
0778:             * the points are expanded from or contracted towards the origin.
0779:             * If this transform represents a non-uniform scale or more general
0780:             * transform then the determinant is not likely to represent a
0781:             * value useful for any purpose other than determining if inverse
0782:             * transforms are possible.
0783:             * <p>
0784:             * Mathematically, the determinant is calculated using the formula:
0785:             * <pre>
0786:             *		|  m00  m01  m02  |
0787:             *		|  m10  m11  m12  |  =  m00 * m11 - m01 * m10
0788:             *		|   0    0    1   |
0789:             * </pre>
0790:             *
0791:             * @return the determinant of the matrix used to transform the
0792:             * coordinates.
0793:             * @see #getType
0794:             * @see #createInverse
0795:             * @see #inverseTransform
0796:             * @see #TYPE_UNIFORM_SCALE
0797:             */
0798:            public double getDeterminant() {
0799:                switch (state) {
0800:                default:
0801:                    stateError();
0802:                    return 0;
0803:                    /* NOTREACHED */
0804:                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
0805:                case (APPLY_SHEAR | APPLY_SCALE):
0806:                    return m00 * m11 - m01 * m10;
0807:                case (APPLY_SHEAR | APPLY_TRANSLATE):
0808:                case (APPLY_SHEAR):
0809:                    return -(m01 * m10);
0810:                case (APPLY_SCALE | APPLY_TRANSLATE):
0811:                case (APPLY_SCALE):
0812:                    return m00 * m11;
0813:                case (APPLY_TRANSLATE):
0814:                case (APPLY_IDENTITY):
0815:                    return 1.0;
0816:                }
0817:            }
0818:
0819:            /**
0820:             * Manually recalculates the state of the transform when the matrix
0821:             * changes too much to predict the effects on the state.
0822:             * The following table specifies what the various settings of the
0823:             * state field say about the values of the corresponding matrix
0824:             * element fields.
0825:             * Note that the rules governing the SCALE fields are slightly
0826:             * different depending on whether the SHEAR flag is also set.
0827:             * <pre>
0828:             *                     SCALE            SHEAR          TRANSLATE
0829:             *                    m00/m11          m01/m10          m02/m12
0830:             *
0831:             * IDENTITY             1.0              0.0              0.0
0832:             * TRANSLATE (TR)       1.0              0.0          not both 0.0
0833:             * SCALE (SC)       not both 1.0         0.0              0.0
0834:             * TR | SC          not both 1.0         0.0          not both 0.0
0835:             * SHEAR (SH)           0.0          not both 0.0         0.0
0836:             * TR | SH              0.0          not both 0.0     not both 0.0
0837:             * SC | SH          not both 0.0     not both 0.0         0.0
0838:             * TR | SC | SH     not both 0.0     not both 0.0     not both 0.0
0839:             * </pre>
0840:             */
0841:            void updateState() {
0842:                if (m01 == 0.0 && m10 == 0.0) {
0843:                    if (m00 == 1.0 && m11 == 1.0) {
0844:                        if (m02 == 0.0 && m12 == 0.0) {
0845:                            state = APPLY_IDENTITY;
0846:                            type = TYPE_IDENTITY;
0847:                        } else {
0848:                            state = APPLY_TRANSLATE;
0849:                            type = TYPE_TRANSLATION;
0850:                        }
0851:                    } else {
0852:                        if (m02 == 0.0 && m12 == 0.0) {
0853:                            state = APPLY_SCALE;
0854:                            type = TYPE_UNKNOWN;
0855:                        } else {
0856:                            state = (APPLY_SCALE | APPLY_TRANSLATE);
0857:                            type = TYPE_UNKNOWN;
0858:                        }
0859:                    }
0860:                } else {
0861:                    if (m00 == 0.0 && m11 == 0.0) {
0862:                        if (m02 == 0.0 && m12 == 0.0) {
0863:                            state = APPLY_SHEAR;
0864:                            type = TYPE_UNKNOWN;
0865:                        } else {
0866:                            state = (APPLY_SHEAR | APPLY_TRANSLATE);
0867:                            type = TYPE_UNKNOWN;
0868:                        }
0869:                    } else {
0870:                        if (m02 == 0.0 && m12 == 0.0) {
0871:                            state = (APPLY_SHEAR | APPLY_SCALE);
0872:                            type = TYPE_UNKNOWN;
0873:                        } else {
0874:                            state = (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE);
0875:                            type = TYPE_UNKNOWN;
0876:                        }
0877:                    }
0878:                }
0879:            }
0880:
0881:            /*
0882:             * Convenience method used internally to throw exceptions when
0883:             * a case was forgotten in a switch statement.
0884:             */
0885:            private void stateError() {
0886:                //#ifdef notdef
0887:                throw new InternalError(
0888:                        "missing case in transform state switch");
0889:                //#else
0890:                System.out.println("missing case in transform state switch");
0891:                //#endif
0892:            }
0893:
0894:            /**
0895:             * Retrieves the 6 specifiable values in the 3x3 affine transformation
0896:             * matrix and places them into an array of double precisions values.
0897:             * The values are stored in the array as 
0898:             * {&nbsp;m00&nbsp;m10&nbsp;m01&nbsp;m11&nbsp;m02&nbsp;m12&nbsp;}.
0899:             * An array of 4 doubles can also be specified, in which case only the
0900:             * first four elements representing the non-transform
0901:             * parts of the array are retrieved and the values are stored into 
0902:             * the array as {&nbsp;m00&nbsp;m10&nbsp;m01&nbsp;m11&nbsp;}
0903:             * @param flatmatrix the double array used to store the returned
0904:             * values.
0905:             * @see #getScaleX
0906:             * @see #getScaleY
0907:             * @see #getShearX
0908:             * @see #getShearY
0909:             * @see #getTranslateX
0910:             * @see #getTranslateY
0911:             */
0912:            public void getMatrix(double[] flatmatrix) {
0913:                flatmatrix[0] = m00;
0914:                flatmatrix[1] = m10;
0915:                flatmatrix[2] = m01;
0916:                flatmatrix[3] = m11;
0917:                if (flatmatrix.length > 5) {
0918:                    flatmatrix[4] = m02;
0919:                    flatmatrix[5] = m12;
0920:                }
0921:            }
0922:
0923:            /**
0924:             * Returns the X coordinate scaling element (m00) of the 3x3
0925:             * affine transformation matrix.
0926:             * @return a double value that is the X coordinate of the scaling
0927:             *  element of the affine transformation matrix.
0928:             * @see #getMatrix
0929:             */
0930:            public double getScaleX() {
0931:                return m00;
0932:            }
0933:
0934:            /**
0935:             * Returns the Y coordinate scaling element (m11) of the 3x3
0936:             * affine transformation matrix.
0937:             * @return a double value that is the Y coordinate of the scaling
0938:             *  element of the affine transformation matrix.
0939:             * @see #getMatrix
0940:             */
0941:            public double getScaleY() {
0942:                return m11;
0943:            }
0944:
0945:            /**
0946:             * Returns the X coordinate shearing element (m01) of the 3x3
0947:             * affine transformation matrix.
0948:             * @return a double value that is the X coordinate of the shearing
0949:             *  element of the affine transformation matrix.
0950:             * @see #getMatrix
0951:             */
0952:            public double getShearX() {
0953:                return m01;
0954:            }
0955:
0956:            /**
0957:             * Returns the Y coordinate shearing element (m10) of the 3x3
0958:             * affine transformation matrix.
0959:             * @return a double value that is the Y coordinate of the shearing
0960:             *  element of the affine transformation matrix.
0961:             * @see #getMatrix
0962:             */
0963:            public double getShearY() {
0964:                return m10;
0965:            }
0966:
0967:            /**
0968:             * Returns the X coordinate of the translation element (m02) of the
0969:             * 3x3 affine transformation matrix.
0970:             * @return a double value that is the X coordinate of the translation
0971:             *  element of the affine transformation matrix.
0972:             * @see #getMatrix
0973:             */
0974:            public double getTranslateX() {
0975:                return m02;
0976:            }
0977:
0978:            /**
0979:             * Returns the Y coordinate of the translation element (m12) of the
0980:             * 3x3 affine transformation matrix.
0981:             * @return a double value that is the Y coordinate of the translation
0982:             *  element of the affine transformation matrix. 
0983:             * @see #getMatrix
0984:             */
0985:            public double getTranslateY() {
0986:                return m12;
0987:            }
0988:
0989:            /**
0990:             * Concatenates this transform with a translation transformation.
0991:             * This is equivalent to calling concatenate(T), where T is an
0992:             * <code>AffineTransform</code> represented by the following matrix:
0993:             * <pre>
0994:             *		[   1    0    tx  ]
0995:             *		[   0    1    ty  ]
0996:             *		[   0    0    1   ]
0997:             * </pre>
0998:             * @param tx the distance by which coordinates are translated in the
0999:             * X axis direction
1000:             * @param ty the distance by which coordinates are translated in the
1001:             * Y axis direction
1002:             */
1003:            public void translate(double tx, double ty) {
1004:                switch (state) {
1005:                default:
1006:                    stateError();
1007:                    break;
1008:                /* NOTREACHED */
1009:                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1010:                    m02 = tx * m00 + ty * m01 + m02;
1011:                    m12 = tx * m10 + ty * m11 + m12;
1012:                    if (m02 == 0.0 && m12 == 0.0) {
1013:                        state = APPLY_SHEAR | APPLY_SCALE;
1014:                        if (type != TYPE_UNKNOWN) {
1015:                            type -= TYPE_TRANSLATION;
1016:                        }
1017:                    }
1018:                    return;
1019:                case (APPLY_SHEAR | APPLY_SCALE):
1020:                    m02 = tx * m00 + ty * m01;
1021:                    m12 = tx * m10 + ty * m11;
1022:                    if (m02 != 0.0 || m12 != 0.0) {
1023:                        state = APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE;
1024:                        type |= TYPE_TRANSLATION;
1025:                    }
1026:                    return;
1027:                case (APPLY_SHEAR | APPLY_TRANSLATE):
1028:                    m02 = ty * m01 + m02;
1029:                    m12 = tx * m10 + m12;
1030:                    if (m02 == 0.0 && m12 == 0.0) {
1031:                        state = APPLY_SHEAR;
1032:                        if (type != TYPE_UNKNOWN) {
1033:                            type -= TYPE_TRANSLATION;
1034:                        }
1035:                    }
1036:                    return;
1037:                case (APPLY_SHEAR):
1038:                    m02 = ty * m01;
1039:                    m12 = tx * m10;
1040:                    if (m02 != 0.0 || m12 != 0.0) {
1041:                        state = APPLY_SHEAR | APPLY_TRANSLATE;
1042:                        type |= TYPE_TRANSLATION;
1043:                    }
1044:                    return;
1045:                case (APPLY_SCALE | APPLY_TRANSLATE):
1046:                    m02 = tx * m00 + m02;
1047:                    m12 = ty * m11 + m12;
1048:                    if (m02 == 0.0 && m12 == 0.0) {
1049:                        state = APPLY_SCALE;
1050:                        if (type != TYPE_UNKNOWN) {
1051:                            type -= TYPE_TRANSLATION;
1052:                        }
1053:                    }
1054:                    return;
1055:                case (APPLY_SCALE):
1056:                    m02 = tx * m00;
1057:                    m12 = ty * m11;
1058:                    if (m02 != 0.0 || m12 != 0.0) {
1059:                        state = APPLY_SCALE | APPLY_TRANSLATE;
1060:                        type |= TYPE_TRANSLATION;
1061:                    }
1062:                    return;
1063:                case (APPLY_TRANSLATE):
1064:                    m02 = tx + m02;
1065:                    m12 = ty + m12;
1066:                    if (m02 == 0.0 && m12 == 0.0) {
1067:                        state = APPLY_IDENTITY;
1068:                        type = TYPE_IDENTITY;
1069:                    }
1070:                    return;
1071:                case (APPLY_IDENTITY):
1072:                    m02 = tx;
1073:                    m12 = ty;
1074:                    if (tx != 0.0 || ty != 0.0) {
1075:                        state = APPLY_TRANSLATE;
1076:                        type = TYPE_TRANSLATION;
1077:                    }
1078:                    return;
1079:                }
1080:            }
1081:
1082:            /**
1083:             * Concatenates this transform with a rotation transformation.
1084:             * This is equivalent to calling concatenate(R), where R is an
1085:             * <code>AffineTransform</code> represented by the following matrix:
1086:             * <pre>
1087:             *		[   cos(theta)    -sin(theta)    0   ]
1088:             *		[   sin(theta)     cos(theta)    0   ]
1089:             *		[       0              0         1   ]
1090:             * </pre>
1091:             * Rotating with a positive angle theta rotates points on the positive
1092:             * x axis toward the positive y axis.
1093:             * @param theta the angle of rotation in radians
1094:             */
1095:            public void rotate(double theta) {
1096:                double sin = Math.sin(theta);
1097:                double cos = Math.cos(theta);
1098:                if (Math.abs(sin) < 1E-15) {
1099:                    if (cos < 0.0) {
1100:                        m00 = -m00;
1101:                        m11 = -m11;
1102:                        int state = this .state;
1103:                        if ((state & (APPLY_SHEAR)) != 0) {
1104:                            // If there was a shear, then this rotation has no
1105:                            // effect on the state.
1106:                            m01 = -m01;
1107:                            m10 = -m10;
1108:                        } else {
1109:                            // No shear means the SCALE state may toggle when
1110:                            // m00 and m11 are negated.
1111:                            if (m00 == 1.0 && m11 == 1.0) {
1112:                                this .state = state & ~APPLY_SCALE;
1113:                            } else {
1114:                                this .state = state | APPLY_SCALE;
1115:                            }
1116:                        }
1117:                        type = TYPE_UNKNOWN;
1118:                    }
1119:                    return;
1120:                }
1121:                if (Math.abs(cos) < 1E-15) {
1122:                    if (sin < 0.0) {
1123:                        double M0 = m00;
1124:                        m00 = -m01;
1125:                        m01 = M0;
1126:                        M0 = m10;
1127:                        m10 = -m11;
1128:                        m11 = M0;
1129:                    } else {
1130:                        double M0 = m00;
1131:                        m00 = m01;
1132:                        m01 = -M0;
1133:                        M0 = m10;
1134:                        m10 = m11;
1135:                        m11 = -M0;
1136:                    }
1137:                    int state = rot90conversion[this .state];
1138:                    if ((state & (APPLY_SHEAR | APPLY_SCALE)) == APPLY_SCALE
1139:                            && m00 == 1.0 && m11 == 1.0) {
1140:                        state -= APPLY_SCALE;
1141:                    }
1142:                    this .state = state;
1143:                    type = TYPE_UNKNOWN;
1144:                    return;
1145:                }
1146:                double M0, M1;
1147:                M0 = m00;
1148:                M1 = m01;
1149:                m00 = cos * M0 + sin * M1;
1150:                m01 = -sin * M0 + cos * M1;
1151:                M0 = m10;
1152:                M1 = m11;
1153:                m10 = cos * M0 + sin * M1;
1154:                m11 = -sin * M0 + cos * M1;
1155:                updateState();
1156:            }
1157:
1158:            private static int rot90conversion[] = { APPLY_SHEAR,
1159:                    APPLY_SHEAR | APPLY_TRANSLATE, APPLY_SHEAR,
1160:                    APPLY_SHEAR | APPLY_TRANSLATE, APPLY_SCALE,
1161:                    APPLY_SCALE | APPLY_TRANSLATE, APPLY_SHEAR | APPLY_SCALE,
1162:                    APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE, };
1163:
1164:            /**
1165:             * Concatenates this transform with a transform that rotates
1166:             * coordinates around an anchor point.
1167:             * This operation is equivalent to translating the coordinates so
1168:             * that the anchor point is at the origin (S1), then rotating them
1169:             * about the new origin (S2), and finally translating so that the
1170:             * intermediate origin is restored to the coordinates of the original
1171:             * anchor point (S3).
1172:             * <p>
1173:             * This operation is equivalent to the following sequence of calls:
1174:             * <pre>
1175:             *		translate(x, y);	// S3: final translation
1176:             *		rotate(theta);		// S2: rotate around anchor
1177:             *		translate(-x, -y);	// S1: translate anchor to origin
1178:             * </pre>
1179:             * Rotating with a positive angle theta rotates points on the positive
1180:             * x axis toward the positive y axis.
1181:             * @param theta the angle of rotation in radians
1182:             * @param x,&nbsp;y the coordinates of the anchor point of the
1183:             * rotation
1184:             */
1185:            public void rotate(double theta, double x, double y) {
1186:                // REMIND: Simple for now - optimize later
1187:                translate(x, y);
1188:                rotate(theta);
1189:                translate(-x, -y);
1190:            }
1191:
1192:            /**
1193:             * Concatenates this transform with a scaling transformation.
1194:             * This is equivalent to calling concatenate(S), where S is an
1195:             * <code>AffineTransform</code> represented by the following matrix:
1196:             * <pre>
1197:             *		[   sx   0    0   ]
1198:             *		[   0    sy   0   ]
1199:             *		[   0    0    1   ]
1200:             * </pre>
1201:             * @param sx the factor by which coordinates are scaled along the   
1202:             * X axis direction
1203:             * @param sy the factor by which coordinates are scaled along the
1204:             * Y axis direction 
1205:             */
1206:            public void scale(double sx, double sy) {
1207:                int state = this .state;
1208:                switch (state) {
1209:                default:
1210:                    stateError();
1211:                    break;
1212:                /* NOTREACHED */
1213:                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1214:                case (APPLY_SHEAR | APPLY_SCALE):
1215:                    m00 *= sx;
1216:                    m11 *= sy;
1217:                    /* NOBREAK */
1218:                case (APPLY_SHEAR | APPLY_TRANSLATE):
1219:                case (APPLY_SHEAR):
1220:                    m01 *= sy;
1221:                    m10 *= sx;
1222:                    if (m01 == 0 && m10 == 0) {
1223:                        this .state = state - APPLY_SHEAR;
1224:                        // REMIND: Is it possible for m00 and m11 to be both 1.0?
1225:                    }
1226:                    this .type = TYPE_UNKNOWN;
1227:                    return;
1228:                case (APPLY_SCALE | APPLY_TRANSLATE):
1229:                case (APPLY_SCALE):
1230:                    m00 *= sx;
1231:                    m11 *= sy;
1232:                    if (m00 == 1.0 && m11 == 1.0) {
1233:                        this .state = (state &= APPLY_TRANSLATE);
1234:                        this .type = (state == APPLY_IDENTITY ? TYPE_IDENTITY
1235:                                : TYPE_TRANSLATION);
1236:                    } else {
1237:                        this .type = TYPE_UNKNOWN;
1238:                    }
1239:                    return;
1240:                case (APPLY_TRANSLATE):
1241:                case (APPLY_IDENTITY):
1242:                    m00 = sx;
1243:                    m11 = sy;
1244:                    if (sx != 1.0 || sy != 1.0) {
1245:                        this .state = state | APPLY_SCALE;
1246:                        this .type = TYPE_UNKNOWN;
1247:                    }
1248:                    return;
1249:                }
1250:            }
1251:
1252:            /**
1253:             * Concatenates this transform with a shearing transformation.
1254:             * This is equivalent to calling concatenate(SH), where SH is an
1255:             * <code>AffineTransform</code> represented by the following matrix:
1256:             * <pre>
1257:             *		[   1   shx   0   ]
1258:             *		[  shy   1    0   ]
1259:             *		[   0    0    1   ]
1260:             * </pre>
1261:             * @param shx the multiplier by which coordinates are shifted in the
1262:             * direction of the positive X axis as a factor of their Y coordinate
1263:             * @param shy the multiplier by which coordinates are shifted in the
1264:             * direction of the positive Y axis as a factor of their X coordinate
1265:             */
1266:            public void shear(double shx, double shy) {
1267:                int state = this .state;
1268:                switch (state) {
1269:                default:
1270:                    stateError();
1271:                    break;
1272:                /* NOTREACHED */
1273:                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1274:                case (APPLY_SHEAR | APPLY_SCALE):
1275:                    double M0,
1276:                    M1;
1277:                    M0 = m00;
1278:                    M1 = m01;
1279:                    m00 = M0 + M1 * shy;
1280:                    m01 = M0 * shx + M1;
1281:
1282:                    M0 = m10;
1283:                    M1 = m11;
1284:                    m10 = M0 + M1 * shy;
1285:                    m11 = M0 * shx + M1;
1286:                    updateState();
1287:                    break;
1288:                case (APPLY_SHEAR | APPLY_TRANSLATE):
1289:                case (APPLY_SHEAR):
1290:                    m00 = m01 * shy;
1291:                    m11 = m10 * shx;
1292:                    if (m00 != 0.0 || m11 != 0.0) {
1293:                        this .state = state | APPLY_SCALE;
1294:                    }
1295:                    this .type = TYPE_UNKNOWN;
1296:                    break;
1297:                case (APPLY_SCALE | APPLY_TRANSLATE):
1298:                case (APPLY_SCALE):
1299:                    m01 = m00 * shx;
1300:                    m10 = m11 * shy;
1301:                    if (m01 != 0.0 || m10 != 0.0) {
1302:                        this .state = state | APPLY_SHEAR;
1303:                    }
1304:                    this .type = TYPE_UNKNOWN;
1305:                    break;
1306:                case (APPLY_TRANSLATE):
1307:                case (APPLY_IDENTITY):
1308:                    m01 = shx;
1309:                    m10 = shy;
1310:                    if (m01 != 0.0 || m10 != 0.0) {
1311:                        this .state = state | APPLY_SCALE | APPLY_SHEAR;
1312:                        this .type = TYPE_UNKNOWN;
1313:                    }
1314:                    break;
1315:                }
1316:            }
1317:
1318:            /**
1319:             * Resets this transform to the Identity transform.
1320:             */
1321:            public void setToIdentity() {
1322:                m00 = m11 = 1.0;
1323:                m10 = m01 = m02 = m12 = 0.0;
1324:                state = APPLY_IDENTITY;
1325:                type = TYPE_IDENTITY;
1326:            }
1327:
1328:            /**
1329:             * Sets this transform to a translation transformation.
1330:             * The matrix representing this transform becomes:
1331:             * <pre>
1332:             *		[   1    0    tx  ]
1333:             *		[   0    1    ty  ]
1334:             *		[   0    0    1   ]
1335:             * </pre>
1336:             * @param tx the distance by which coordinates are translated in the
1337:             * X axis direction
1338:             * @param ty the distance by which coordinates are translated in the
1339:             * Y axis direction
1340:             */
1341:            public void setToTranslation(double tx, double ty) {
1342:                m00 = m11 = 1.0;
1343:                m10 = m01 = 0.0;
1344:                m02 = tx;
1345:                m12 = ty;
1346:                if (tx != 0.0 || ty != 0.0) {
1347:                    state = APPLY_TRANSLATE;
1348:                    type = TYPE_TRANSLATION;
1349:                } else {
1350:                    state = APPLY_IDENTITY;
1351:                    type = TYPE_IDENTITY;
1352:                }
1353:            }
1354:
1355:            /**
1356:             * Sets this transform to a rotation transformation.
1357:             * The matrix representing this transform becomes:
1358:             * <pre>
1359:             *		[   cos(theta)    -sin(theta)    0   ]
1360:             *		[   sin(theta)     cos(theta)    0   ]
1361:             *		[       0              0         1   ]
1362:             * </pre>
1363:             * Rotating with a positive angle theta rotates points on the positive
1364:             * x axis toward the positive y axis.
1365:             * @param theta the angle of rotation in radians
1366:             */
1367:            public void setToRotation(double theta) {
1368:                m02 = m12 = 0.0;
1369:                double sin = Math.sin(theta);
1370:                double cos = Math.cos(theta);
1371:                if (Math.abs(sin) < 1E-15) {
1372:                    m01 = m10 = 0.0;
1373:                    if (cos < 0) {
1374:                        m00 = m11 = -1.0;
1375:                        state = APPLY_SCALE;
1376:                        type = TYPE_QUADRANT_ROTATION;
1377:                    } else {
1378:                        m00 = m11 = 1.0;
1379:                        state = APPLY_IDENTITY;
1380:                        type = TYPE_IDENTITY;
1381:                    }
1382:                    return;
1383:                }
1384:                if (Math.abs(cos) < 1E-15) {
1385:                    m00 = m11 = 0.0;
1386:                    if (sin < 0.0) {
1387:                        m01 = 1.0;
1388:                        m10 = -1.0;
1389:                    } else {
1390:                        m01 = -1.0;
1391:                        m10 = 1.0;
1392:                    }
1393:                    state = APPLY_SHEAR;
1394:                    type = TYPE_QUADRANT_ROTATION;
1395:                    return;
1396:                }
1397:                m00 = cos;
1398:                m01 = -sin;
1399:                m10 = sin;
1400:                m11 = cos;
1401:                state = APPLY_SHEAR | APPLY_SCALE;
1402:                type = TYPE_GENERAL_ROTATION;
1403:            }
1404:
1405:            /**
1406:             * Sets this transform to a translated rotation transformation.
1407:             * This operation is equivalent to translating the coordinates so
1408:             * that the anchor point is at the origin (S1), then rotating them
1409:             * about the new origin (S2), and finally translating so that the
1410:             * intermediate origin is restored to the coordinates of the original
1411:             * anchor point (S3).
1412:             * <p>
1413:             * This operation is equivalent to the following sequence of calls:
1414:             * <pre>
1415:             *	    setToTranslation(x, y);	// S3: final translation
1416:             *	    rotate(theta);		// S2: rotate around anchor
1417:             *	    translate(-x, -y);		// S1: translate anchor to origin
1418:             * </pre>
1419:             * The matrix representing this transform becomes:
1420:             * <pre>
1421:             *		[   cos(theta)    -sin(theta)    x-x*cos+y*sin  ]
1422:             *		[   sin(theta)     cos(theta)    y-x*sin-y*cos  ]
1423:             *		[       0              0               1        ]
1424:             * </pre>
1425:             * Rotating with a positive angle theta rotates points on the positive
1426:             * x axis toward the positive y axis.
1427:             * @param theta the angle of rotation in radians
1428:             * @param x,&nbsp;y the coordinates of the anchor point of the
1429:             * rotation
1430:             */
1431:            public void setToRotation(double theta, double x, double y) {
1432:                setToRotation(theta);
1433:                double sin = m10;
1434:                double oneMinusCos = 1.0 - m00;
1435:                m02 = x * oneMinusCos + y * sin;
1436:                m12 = y * oneMinusCos - x * sin;
1437:                if (m02 != 0.0 || m12 != 0.0) {
1438:                    state |= APPLY_TRANSLATE;
1439:                    type |= TYPE_TRANSLATION;
1440:                }
1441:            }
1442:
1443:            /**
1444:             * Sets this transform to a scaling transformation.
1445:             * The matrix representing this transform becomes:
1446:             * <pre>
1447:             *		[   sx   0    0   ]
1448:             *		[   0    sy   0   ]
1449:             *		[   0    0    1   ]
1450:             * </pre>
1451:             * @param sx the factor by which coordinates are scaled along the
1452:             * X axis direction
1453:             * @param sy the factor by which coordinates are scaled along the
1454:             * Y axis direction
1455:             */
1456:            public void setToScale(double sx, double sy) {
1457:                m01 = m02 = m10 = m12 = 0.0;
1458:                m00 = sx;
1459:                m11 = sy;
1460:                if (sx != 1.0 || sy != 1.0) {
1461:                    state = APPLY_SCALE;
1462:                    type = TYPE_UNKNOWN;
1463:                } else {
1464:                    state = APPLY_IDENTITY;
1465:                    type = TYPE_IDENTITY;
1466:                }
1467:            }
1468:
1469:            /**
1470:             * Sets this transform to a shearing transformation.
1471:             * The matrix representing this transform becomes:
1472:             * <pre>
1473:             *		[   1   shx   0   ]
1474:             *		[  shy   1    0   ]
1475:             *		[   0    0    1   ]
1476:             * </pre>
1477:             * @param shx the multiplier by which coordinates are shifted in the
1478:             * direction of the positive X axis as a factor of their Y coordinate
1479:             * @param shy the multiplier by which coordinates are shifted in the
1480:             * direction of the positive Y axis as a factor of their X coordinate
1481:             */
1482:            public void setToShear(double shx, double shy) {
1483:                m00 = m11 = 1.0;
1484:                m02 = m12 = 0.0;
1485:                m01 = shx;
1486:                m10 = shy;
1487:                if (shx != 0.0 || shy != 0.0) {
1488:                    state = (APPLY_SHEAR | APPLY_SCALE);
1489:                    type = TYPE_UNKNOWN;
1490:                } else {
1491:                    state = APPLY_IDENTITY;
1492:                    type = TYPE_IDENTITY;
1493:                }
1494:            }
1495:
1496:            /**
1497:             * Sets this transform to a copy of the transform in the specified
1498:             * <code>AffineTransform</code> object.
1499:             * @param Tx the <code>AffineTransform</code> object from which to
1500:             * copy the transform
1501:             */
1502:            public void setTransform(AffineTransform Tx) {
1503:                this .m00 = Tx.m00;
1504:                this .m10 = Tx.m10;
1505:                this .m01 = Tx.m01;
1506:                this .m11 = Tx.m11;
1507:                this .m02 = Tx.m02;
1508:                this .m12 = Tx.m12;
1509:                this .state = Tx.state;
1510:                this .type = Tx.type;
1511:            }
1512:
1513:            /**
1514:             * Sets this transform to the matrix specified by the 6
1515:             * double precision values.
1516:             * @param m00,&nbsp;m01,&nbsp;m02,&nbsp;m10,&nbsp;m11,&nbsp;m12 the
1517:             * 6 floating point values that compose the 3x3 transformation matrix
1518:             */
1519:            public void setTransform(double m00, double m10, double m01,
1520:                    double m11, double m02, double m12) {
1521:                this .m00 = m00;
1522:                this .m10 = m10;
1523:                this .m01 = m01;
1524:                this .m11 = m11;
1525:                this .m02 = m02;
1526:                this .m12 = m12;
1527:                updateState();
1528:            }
1529:
1530:            /**
1531:             * Concatenates an <code>AffineTransform</code> <code>Tx</code> to
1532:             * this <code>AffineTransform</code> Cx in the most commonly useful
1533:             * way to provide a new user space
1534:             * that is mapped to the former user space by <code>Tx</code>.
1535:             * Cx is updated to perform the combined transformation.
1536:             * Transforming a point p by the updated transform Cx' is
1537:             * equivalent to first transforming p by <code>Tx</code> and then
1538:             * transforming the result by the original transform Cx like this:
1539:             * Cx'(p) = Cx(Tx(p))  
1540:             * In matrix notation, if this transform Cx is
1541:             * represented by the matrix [this] and <code>Tx</code> is represented
1542:             * by the matrix [Tx] then this method does the following:
1543:             * <pre>
1544:             *		[this] = [this] x [Tx]
1545:             * </pre>
1546:             * @param Tx the <code>AffineTransform</code> object to be
1547:             * concatenated with this <code>AffineTransform</code> object.
1548:             * @see #preConcatenate
1549:             */
1550:            public void concatenate(AffineTransform Tx) {
1551:                double M0, M1;
1552:                double T00, T01, T10, T11;
1553:                double T02, T12;
1554:                int mystate = state;
1555:                int txstate = Tx.state;
1556:                switch ((txstate << HI_SHIFT) | mystate) {
1557:
1558:                /* ---------- Tx == IDENTITY cases ---------- */
1559:                case (HI_IDENTITY | APPLY_IDENTITY):
1560:                case (HI_IDENTITY | APPLY_TRANSLATE):
1561:                case (HI_IDENTITY | APPLY_SCALE):
1562:                case (HI_IDENTITY | APPLY_SCALE | APPLY_TRANSLATE):
1563:                case (HI_IDENTITY | APPLY_SHEAR):
1564:                case (HI_IDENTITY | APPLY_SHEAR | APPLY_TRANSLATE):
1565:                case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE):
1566:                case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1567:                    return;
1568:
1569:                    /* ---------- this == IDENTITY cases ---------- */
1570:                case (HI_SHEAR | HI_SCALE | HI_TRANSLATE | APPLY_IDENTITY):
1571:                    m01 = Tx.m01;
1572:                    m10 = Tx.m10;
1573:                    /* NOBREAK */
1574:                case (HI_SCALE | HI_TRANSLATE | APPLY_IDENTITY):
1575:                    m00 = Tx.m00;
1576:                    m11 = Tx.m11;
1577:                    /* NOBREAK */
1578:                case (HI_TRANSLATE | APPLY_IDENTITY):
1579:                    m02 = Tx.m02;
1580:                    m12 = Tx.m12;
1581:                    state = txstate;
1582:                    type = Tx.type;
1583:                    return;
1584:                case (HI_SHEAR | HI_SCALE | APPLY_IDENTITY):
1585:                    m01 = Tx.m01;
1586:                    m10 = Tx.m10;
1587:                    /* NOBREAK */
1588:                case (HI_SCALE | APPLY_IDENTITY):
1589:                    m00 = Tx.m00;
1590:                    m11 = Tx.m11;
1591:                    state = txstate;
1592:                    type = Tx.type;
1593:                    return;
1594:                case (HI_SHEAR | HI_TRANSLATE | APPLY_IDENTITY):
1595:                    m02 = Tx.m02;
1596:                    m12 = Tx.m12;
1597:                    /* NOBREAK */
1598:                case (HI_SHEAR | APPLY_IDENTITY):
1599:                    m01 = Tx.m01;
1600:                    m10 = Tx.m10;
1601:                    m00 = m11 = 0.0;
1602:                    state = txstate;
1603:                    type = Tx.type;
1604:                    return;
1605:
1606:                    /* ---------- Tx == TRANSLATE cases ---------- */
1607:                case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1608:                case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE):
1609:                case (HI_TRANSLATE | APPLY_SHEAR | APPLY_TRANSLATE):
1610:                case (HI_TRANSLATE | APPLY_SHEAR):
1611:                case (HI_TRANSLATE | APPLY_SCALE | APPLY_TRANSLATE):
1612:                case (HI_TRANSLATE | APPLY_SCALE):
1613:                case (HI_TRANSLATE | APPLY_TRANSLATE):
1614:                    translate(Tx.m02, Tx.m12);
1615:                    return;
1616:
1617:                    /* ---------- Tx == SCALE cases ---------- */
1618:                case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1619:                case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE):
1620:                case (HI_SCALE | APPLY_SHEAR | APPLY_TRANSLATE):
1621:                case (HI_SCALE | APPLY_SHEAR):
1622:                case (HI_SCALE | APPLY_SCALE | APPLY_TRANSLATE):
1623:                case (HI_SCALE | APPLY_SCALE):
1624:                case (HI_SCALE | APPLY_TRANSLATE):
1625:                    scale(Tx.m00, Tx.m11);
1626:                    return;
1627:
1628:                    /* ---------- Tx == SHEAR cases ---------- */
1629:                case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1630:                case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE):
1631:                    T01 = Tx.m01;
1632:                    T10 = Tx.m10;
1633:                    M0 = m00;
1634:                    m00 = m01 * T10;
1635:                    m01 = M0 * T01;
1636:                    M0 = m10;
1637:                    m10 = m11 * T10;
1638:                    m11 = M0 * T01;
1639:                    type = TYPE_UNKNOWN;
1640:                    return;
1641:                case (HI_SHEAR | APPLY_SHEAR | APPLY_TRANSLATE):
1642:                case (HI_SHEAR | APPLY_SHEAR):
1643:                    m00 = m01 * Tx.m10;
1644:                    m01 = 0.0;
1645:                    m11 = m10 * Tx.m01;
1646:                    m10 = 0.0;
1647:                    state = mystate ^ (APPLY_SHEAR | APPLY_SCALE);
1648:                    type = TYPE_UNKNOWN;
1649:                    return;
1650:                case (HI_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1651:                case (HI_SHEAR | APPLY_SCALE):
1652:                    m01 = m00 * Tx.m01;
1653:                    m00 = 0.0;
1654:                    m10 = m11 * Tx.m10;
1655:                    m11 = 0.0;
1656:                    state = mystate ^ (APPLY_SHEAR | APPLY_SCALE);
1657:                    type = TYPE_UNKNOWN;
1658:                    return;
1659:                case (HI_SHEAR | APPLY_TRANSLATE):
1660:                    m00 = 0.0;
1661:                    m01 = Tx.m01;
1662:                    m10 = Tx.m10;
1663:                    m11 = 0.0;
1664:                    state = APPLY_TRANSLATE | APPLY_SHEAR;
1665:                    type = TYPE_UNKNOWN;
1666:                    return;
1667:                }
1668:                // If Tx has more than one attribute, it is not worth optimizing
1669:                // all of those cases...
1670:                T00 = Tx.m00;
1671:                T01 = Tx.m01;
1672:                T02 = Tx.m02;
1673:                T10 = Tx.m10;
1674:                T11 = Tx.m11;
1675:                T12 = Tx.m12;
1676:                switch (mystate) {
1677:                default:
1678:                    stateError();
1679:                    return;
1680:                    /* NOTREACHED */
1681:                case (APPLY_SHEAR | APPLY_SCALE):
1682:                    state = mystate | txstate;
1683:                    /* NOBREAK */
1684:                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1685:                    M0 = m00;
1686:                    M1 = m01;
1687:                    m00 = T00 * M0 + T10 * M1;
1688:                    m01 = T01 * M0 + T11 * M1;
1689:                    m02 += T02 * M0 + T12 * M1;
1690:
1691:                    M0 = m10;
1692:                    M1 = m11;
1693:                    m10 = T00 * M0 + T10 * M1;
1694:                    m11 = T01 * M0 + T11 * M1;
1695:                    m12 += T02 * M0 + T12 * M1;
1696:                    type = TYPE_UNKNOWN;
1697:                    return;
1698:
1699:                case (APPLY_SHEAR | APPLY_TRANSLATE):
1700:                case (APPLY_SHEAR):
1701:                    M0 = m01;
1702:                    m00 = T10 * M0;
1703:                    m01 = T11 * M0;
1704:                    m02 += T12 * M0;
1705:
1706:                    M0 = m10;
1707:                    m10 = T00 * M0;
1708:                    m11 = T01 * M0;
1709:                    m12 += T02 * M0;
1710:                    break;
1711:
1712:                case (APPLY_SCALE | APPLY_TRANSLATE):
1713:                case (APPLY_SCALE):
1714:                    M0 = m00;
1715:                    m00 = T00 * M0;
1716:                    m01 = T01 * M0;
1717:                    m02 += T02 * M0;
1718:
1719:                    M0 = m11;
1720:                    m10 = T10 * M0;
1721:                    m11 = T11 * M0;
1722:                    m12 += T12 * M0;
1723:                    break;
1724:
1725:                case (APPLY_TRANSLATE):
1726:                    m00 = T00;
1727:                    m01 = T01;
1728:                    m02 += T02;
1729:
1730:                    m10 = T10;
1731:                    m11 = T11;
1732:                    m12 += T12;
1733:                    state = txstate | APPLY_TRANSLATE;
1734:                    type = TYPE_UNKNOWN;
1735:                    return;
1736:                }
1737:                updateState();
1738:            }
1739:
1740:            /**
1741:             * Concatenates an <code>AffineTransform</code> <code>Tx</code> to
1742:             * this <code>AffineTransform</code> Cx
1743:             * in a less commonly used way such that <code>Tx</code> modifies the
1744:             * coordinate transformation relative to the absolute pixel
1745:             * space rather than relative to the existing user space.
1746:             * Cx is updated to perform the combined transformation.
1747:             * Transforming a point p by the updated transform Cx' is
1748:             * equivalent to first transforming p by the original transform
1749:             * Cx and then transforming the result by 
1750:             * <code>Tx</code> like this: 
1751:             * Cx'(p) = Tx(Cx(p))  
1752:             * In matrix notation, if this transform Cx
1753:             * is represented by the matrix [this] and <code>Tx</code> is
1754:             * represented by the matrix [Tx] then this method does the
1755:             * following:
1756:             * <pre>
1757:             *		[this] = [Tx] x [this]
1758:             * </pre>
1759:             * @param Tx the <code>AffineTransform</code> object to be
1760:             * concatenated with this <code>AffineTransform</code> object.
1761:             * @see #concatenate
1762:             */
1763:            public void preConcatenate(AffineTransform Tx) {
1764:                double M0, M1;
1765:                double T00, T01, T10, T11;
1766:                double T02, T12;
1767:                int mystate = state;
1768:                int txstate = Tx.state;
1769:                switch ((txstate << HI_SHIFT) | mystate) {
1770:                case (HI_IDENTITY | APPLY_IDENTITY):
1771:                case (HI_IDENTITY | APPLY_TRANSLATE):
1772:                case (HI_IDENTITY | APPLY_SCALE):
1773:                case (HI_IDENTITY | APPLY_SCALE | APPLY_TRANSLATE):
1774:                case (HI_IDENTITY | APPLY_SHEAR):
1775:                case (HI_IDENTITY | APPLY_SHEAR | APPLY_TRANSLATE):
1776:                case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE):
1777:                case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1778:                    // Tx is IDENTITY...
1779:                    return;
1780:
1781:                case (HI_TRANSLATE | APPLY_IDENTITY):
1782:                case (HI_TRANSLATE | APPLY_SCALE):
1783:                case (HI_TRANSLATE | APPLY_SHEAR):
1784:                case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE):
1785:                    // Tx is TRANSLATE, this has no TRANSLATE
1786:                    m02 = Tx.m02;
1787:                    m12 = Tx.m12;
1788:                    state = mystate | APPLY_TRANSLATE;
1789:                    type |= TYPE_TRANSLATION;
1790:                    return;
1791:
1792:                case (HI_TRANSLATE | APPLY_TRANSLATE):
1793:                case (HI_TRANSLATE | APPLY_SCALE | APPLY_TRANSLATE):
1794:                case (HI_TRANSLATE | APPLY_SHEAR | APPLY_TRANSLATE):
1795:                case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1796:                    // Tx is TRANSLATE, this has one too
1797:                    m02 = m02 + Tx.m02;
1798:                    m12 = m12 + Tx.m12;
1799:                    return;
1800:
1801:                case (HI_SCALE | APPLY_TRANSLATE):
1802:                case (HI_SCALE | APPLY_IDENTITY):
1803:                    // Only these two existing states need a new state
1804:                    state = mystate | APPLY_SCALE;
1805:                    /* NOBREAK */
1806:                case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1807:                case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE):
1808:                case (HI_SCALE | APPLY_SHEAR | APPLY_TRANSLATE):
1809:                case (HI_SCALE | APPLY_SHEAR):
1810:                case (HI_SCALE | APPLY_SCALE | APPLY_TRANSLATE):
1811:                case (HI_SCALE | APPLY_SCALE):
1812:                    // Tx is SCALE, this is anything
1813:                    T00 = Tx.m00;
1814:                    T11 = Tx.m11;
1815:                    if ((mystate & APPLY_SHEAR) != 0) {
1816:                        m01 = m01 * T00;
1817:                        m10 = m10 * T11;
1818:                        if ((mystate & APPLY_SCALE) != 0) {
1819:                            m00 = m00 * T00;
1820:                            m11 = m11 * T11;
1821:                        }
1822:                    } else {
1823:                        m00 = m00 * T00;
1824:                        m11 = m11 * T11;
1825:                    }
1826:                    if ((mystate & APPLY_TRANSLATE) != 0) {
1827:                        m02 = m02 * T00;
1828:                        m12 = m12 * T11;
1829:                    }
1830:                    type = TYPE_UNKNOWN;
1831:                    return;
1832:                case (HI_SHEAR | APPLY_SHEAR | APPLY_TRANSLATE):
1833:                case (HI_SHEAR | APPLY_SHEAR):
1834:                    mystate = mystate | APPLY_SCALE;
1835:                    /* NOBREAK */
1836:                case (HI_SHEAR | APPLY_TRANSLATE):
1837:                case (HI_SHEAR | APPLY_IDENTITY):
1838:                case (HI_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1839:                case (HI_SHEAR | APPLY_SCALE):
1840:                    state = mystate ^ APPLY_SHEAR;
1841:                    /* NOBREAK */
1842:                case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1843:                case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE):
1844:                    // Tx is SHEAR, this is anything
1845:                    T01 = Tx.m01;
1846:                    T10 = Tx.m10;
1847:
1848:                    M0 = m00;
1849:                    m00 = m10 * T01;
1850:                    m10 = M0 * T10;
1851:
1852:                    M0 = m01;
1853:                    m01 = m11 * T01;
1854:                    m11 = M0 * T10;
1855:
1856:                    M0 = m02;
1857:                    m02 = m12 * T01;
1858:                    m12 = M0 * T10;
1859:                    type = TYPE_UNKNOWN;
1860:                    return;
1861:                }
1862:                // If Tx has more than one attribute, it is not worth optimizing
1863:                // all of those cases...
1864:                T00 = Tx.m00;
1865:                T01 = Tx.m01;
1866:                T02 = Tx.m02;
1867:                T10 = Tx.m10;
1868:                T11 = Tx.m11;
1869:                T12 = Tx.m12;
1870:                switch (mystate) {
1871:                default:
1872:                    stateError();
1873:                    return;
1874:                    /* NOTREACHED */
1875:                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1876:                    M0 = m02;
1877:                    M1 = m12;
1878:                    T02 += M0 * T00 + M1 * T01;
1879:                    T12 += M0 * T10 + M1 * T11;
1880:
1881:                    /* NOBREAK */
1882:                case (APPLY_SHEAR | APPLY_SCALE):
1883:                    m02 = T02;
1884:                    m12 = T12;
1885:
1886:                    M0 = m00;
1887:                    M1 = m10;
1888:                    m00 = M0 * T00 + M1 * T01;
1889:                    m10 = M0 * T10 + M1 * T11;
1890:
1891:                    M0 = m01;
1892:                    M1 = m11;
1893:                    m01 = M0 * T00 + M1 * T01;
1894:                    m11 = M0 * T10 + M1 * T11;
1895:                    break;
1896:
1897:                case (APPLY_SHEAR | APPLY_TRANSLATE):
1898:                    M0 = m02;
1899:                    M1 = m12;
1900:                    T02 += M0 * T00 + M1 * T01;
1901:                    T12 += M0 * T10 + M1 * T11;
1902:
1903:                    /* NOBREAK */
1904:                case (APPLY_SHEAR):
1905:                    m02 = T02;
1906:                    m12 = T12;
1907:
1908:                    M0 = m10;
1909:                    m00 = M0 * T01;
1910:                    m10 = M0 * T11;
1911:
1912:                    M0 = m01;
1913:                    m01 = M0 * T00;
1914:                    m11 = M0 * T10;
1915:                    break;
1916:
1917:                case (APPLY_SCALE | APPLY_TRANSLATE):
1918:                    M0 = m02;
1919:                    M1 = m12;
1920:                    T02 += M0 * T00 + M1 * T01;
1921:                    T12 += M0 * T10 + M1 * T11;
1922:
1923:                    /* NOBREAK */
1924:                case (APPLY_SCALE):
1925:                    m02 = T02;
1926:                    m12 = T12;
1927:
1928:                    M0 = m00;
1929:                    m00 = M0 * T00;
1930:                    m10 = M0 * T10;
1931:
1932:                    M0 = m11;
1933:                    m01 = M0 * T01;
1934:                    m11 = M0 * T11;
1935:                    break;
1936:
1937:                case (APPLY_TRANSLATE):
1938:                    M0 = m02;
1939:                    M1 = m12;
1940:                    T02 += M0 * T00 + M1 * T01;
1941:                    T12 += M0 * T10 + M1 * T11;
1942:
1943:                    /* NOBREAK */
1944:                case (APPLY_IDENTITY):
1945:                    m02 = T02;
1946:                    m12 = T12;
1947:
1948:                    m00 = T00;
1949:                    m10 = T10;
1950:
1951:                    m01 = T01;
1952:                    m11 = T11;
1953:
1954:                    state = mystate | txstate;
1955:                    type = TYPE_UNKNOWN;
1956:                    return;
1957:                }
1958:                updateState();
1959:            }
1960:
1961:            /**
1962:             * Returns an <code>AffineTransform</code> object representing the
1963:             * inverse transformation.
1964:             * The inverse transform Tx' of this transform Tx 
1965:             * maps coordinates transformed by Tx back
1966:             * to their original coordinates.
1967:             * In other words, Tx'(Tx(p)) = p = Tx(Tx'(p)).
1968:             * <p>
1969:             * If this transform maps all coordinates onto a point or a line
1970:             * then it will not have an inverse, since coordinates that do
1971:             * not lie on the destination point or line will not have an inverse
1972:             * mapping.
1973:             * The <code>getDeterminant</code> method can be used to determine if this
1974:             * transform has no inverse, in which case an exception will be
1975:             * thrown if the <code>createInverse</code> method is called.
1976:             * @return a new <code>AffineTransform</code> object representing the
1977:             * inverse transformation.
1978:             * @see #getDeterminant
1979:             * @exception NoninvertibleTransformException
1980:             * if the matrix cannot be inverted.
1981:             */
1982:            public AffineTransform createInverse()
1983:                    throws NoninvertibleTransformException {
1984:                double det;
1985:                switch (state) {
1986:                default:
1987:                    stateError();
1988:                    return null;
1989:                    /* NOTREACHED */
1990:                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1991:                    det = m00 * m11 - m01 * m10;
1992:                    if (Math.abs(det) <= Double.MIN_VALUE) {
1993:                        throw new NoninvertibleTransformException(
1994:                                "Determinant is " + det);
1995:                    }
1996:                    return new AffineTransform(m11 / det, -m10 / det, -m01
1997:                            / det, m00 / det, (m01 * m12 - m11 * m02) / det,
1998:                            (m10 * m02 - m00 * m12) / det, (APPLY_SHEAR
1999:                                    | APPLY_SCALE | APPLY_TRANSLATE));
2000:                case (APPLY_SHEAR | APPLY_SCALE):
2001:                    det = m00 * m11 - m01 * m10;
2002:                    if (Math.abs(det) <= Double.MIN_VALUE) {
2003:                        throw new NoninvertibleTransformException(
2004:                                "Determinant is " + det);
2005:                    }
2006:                    return new AffineTransform(m11 / det, -m10 / det, -m01
2007:                            / det, m00 / det, 0.0, 0.0,
2008:                            (APPLY_SHEAR | APPLY_SCALE));
2009:                case (APPLY_SHEAR | APPLY_TRANSLATE):
2010:                    if (m01 == 0.0 || m10 == 0.0) {
2011:                        throw new NoninvertibleTransformException(
2012:                                "Determinant is 0");
2013:                    }
2014:                    return new AffineTransform(0.0, 1.0 / m01, 1.0 / m10, 0.0,
2015:                            -m12 / m10, -m02 / m01,
2016:                            (APPLY_SHEAR | APPLY_TRANSLATE));
2017:                case (APPLY_SHEAR):
2018:                    if (m01 == 0.0 || m10 == 0.0) {
2019:                        throw new NoninvertibleTransformException(
2020:                                "Determinant is 0");
2021:                    }
2022:                    return new AffineTransform(0.0, 1.0 / m01, 1.0 / m10, 0.0,
2023:                            0.0, 0.0, (APPLY_SHEAR));
2024:                case (APPLY_SCALE | APPLY_TRANSLATE):
2025:                    if (m00 == 0.0 || m11 == 0.0) {
2026:                        throw new NoninvertibleTransformException(
2027:                                "Determinant is 0");
2028:                    }
2029:                    return new AffineTransform(1.0 / m00, 0.0, 0.0, 1.0 / m11,
2030:                            -m02 / m00, -m12 / m11,
2031:                            (APPLY_SCALE | APPLY_TRANSLATE));
2032:                case (APPLY_SCALE):
2033:                    if (m00 == 0.0 || m11 == 0.0) {
2034:                        throw new NoninvertibleTransformException(
2035:                                "Determinant is 0");
2036:                    }
2037:                    return new AffineTransform(1.0 / m00, 0.0, 0.0, 1.0 / m11,
2038:                            0.0, 0.0, (APPLY_SCALE));
2039:                case (APPLY_TRANSLATE):
2040:                    return new AffineTransform(1.0, 0.0, 0.0, 1.0, -m02, -m12,
2041:                            (APPLY_TRANSLATE));
2042:                case (APPLY_IDENTITY):
2043:                    return new AffineTransform();
2044:                }
2045:
2046:                /* NOTREACHED */
2047:            }
2048:
2049:            /**
2050:             * Transforms the specified <code>ptSrc</code> and stores the result
2051:             * in <code>ptDst</code>.
2052:             * If <code>ptDst</code> is <code>null</code>, a new {@link Point2D}
2053:             * object is allocated and then the result of the transformation is
2054:             * stored in this object.
2055:             * In either case, <code>ptDst</code>, which contains the
2056:             * transformed point, is returned for convenience.
2057:             * If <code>ptSrc</code> and <code>ptDst</code> are the same
2058:             * object, the input point is correctly overwritten with
2059:             * the transformed point.
2060:             * @param ptSrc the specified <code>Point2D</code> to be transformed
2061:             * @param ptDst the specified <code>Point2D</code> that stores the
2062:             * result of transforming <code>ptSrc</code>
2063:             * @return the <code>ptDst</code> after transforming
2064:             * <code>ptSrc</code> and stroring the result in <code>ptDst</code>.
2065:             */
2066:            public Point2D transform(Point2D ptSrc, Point2D ptDst) {
2067:                if (ptDst == null) {
2068:                    if (ptSrc instanceof  Point2D.Double) {
2069:                        ptDst = new Point2D.Double();
2070:                    } else {
2071:                        ptDst = new Point2D.Float();
2072:                    }
2073:                }
2074:                // Copy source coords into local variables in case src == dst
2075:                double x = ptSrc.getX();
2076:                double y = ptSrc.getY();
2077:                switch (state) {
2078:                default:
2079:                    stateError();
2080:                    break;
2081:                /* NOTREACHED */
2082:                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2083:                    ptDst.setLocation(x * m00 + y * m01 + m02, x * m10 + y
2084:                            * m11 + m12);
2085:                    break;
2086:                case (APPLY_SHEAR | APPLY_SCALE):
2087:                    ptDst.setLocation(x * m00 + y * m01, x * m10 + y * m11);
2088:                    break;
2089:                case (APPLY_SHEAR | APPLY_TRANSLATE):
2090:                    ptDst.setLocation(y * m01 + m02, x * m10 + m12);
2091:                    break;
2092:                case (APPLY_SHEAR):
2093:                    ptDst.setLocation(y * m01, x * m10);
2094:                    break;
2095:                case (APPLY_SCALE | APPLY_TRANSLATE):
2096:                    ptDst.setLocation(x * m00 + m02, y * m11 + m12);
2097:                    break;
2098:                case (APPLY_SCALE):
2099:                    ptDst.setLocation(x * m00, y * m11);
2100:                    break;
2101:                case (APPLY_TRANSLATE):
2102:                    ptDst.setLocation(x + m02, y + m12);
2103:                    break;
2104:                case (APPLY_IDENTITY):
2105:                    ptDst.setLocation(x, y);
2106:                    break;
2107:                }
2108:                return ptDst;
2109:            }
2110:
2111:            /**
2112:             * Transforms an array of point objects by this transform.
2113:             * If any element of the <code>ptDst</code> array is
2114:             * <code>null</code>, a new <code>Point2D</code> object is allocated
2115:             * and stored into that element before storing the results of the
2116:             * transformation.
2117:             * <p>
2118:             * Note that this method does not take any precautions to
2119:             * avoid problems caused by storing results into <code>Point2D</code>
2120:             * objects that will be used as the source for calculations
2121:             * further down the source array.
2122:             * This method does guarantee that if a specified <code>Point2D</code> 
2123:             * object is both the source and destination for the same single point
2124:             * transform operation then the results will not be stored until
2125:             * the calculations are complete to avoid storing the results on
2126:             * top of the operands.
2127:             * If, however, the destination <code>Point2D</code> object for one
2128:             * operation is the same object as the source <code>Point2D</code> 
2129:             * object for another operation further down the source array then
2130:             * the original coordinates in that point are overwritten before
2131:             * they can be converted.
2132:             * @param ptSrc the array containing the source point objects
2133:             * @param ptDst the array into which the transform point objects are
2134:             * returned
2135:             * @param srcOff the offset to the first point object to be
2136:             * transformed in the source array
2137:             * @param dstOff the offset to the location of the first
2138:             * transformed point object that is stored in the destination array
2139:             * @param numPts the number of point objects to be transformed
2140:             */
2141:            public void transform(Point2D[] ptSrc, int srcOff, Point2D[] ptDst,
2142:                    int dstOff, int numPts) {
2143:                int state = this .state;
2144:                while (--numPts >= 0) {
2145:                    // Copy source coords into local variables in case src == dst
2146:                    Point2D src = ptSrc[srcOff++];
2147:                    double x = src.getX();
2148:                    double y = src.getY();
2149:                    Point2D dst = ptDst[dstOff++];
2150:                    if (dst == null) {
2151:                        if (src instanceof  Point2D.Double) {
2152:                            dst = new Point2D.Double();
2153:                        } else {
2154:                            dst = new Point2D.Float();
2155:                        }
2156:                        ptDst[dstOff - 1] = dst;
2157:                    }
2158:                    switch (state) {
2159:                    default:
2160:                        stateError();
2161:                        break;
2162:                    /* NOTREACHED */
2163:                    case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2164:                        dst.setLocation(x * m00 + y * m01 + m02, x * m10 + y
2165:                                * m11 + m12);
2166:                        break;
2167:                    case (APPLY_SHEAR | APPLY_SCALE):
2168:                        dst.setLocation(x * m00 + y * m01, x * m10 + y * m11);
2169:                        break;
2170:                    case (APPLY_SHEAR | APPLY_TRANSLATE):
2171:                        dst.setLocation(y * m01 + m02, x * m10 + m12);
2172:                        break;
2173:                    case (APPLY_SHEAR):
2174:                        dst.setLocation(y * m01, x * m10);
2175:                        break;
2176:                    case (APPLY_SCALE | APPLY_TRANSLATE):
2177:                        dst.setLocation(x * m00 + m02, y * m11 + m12);
2178:                        break;
2179:                    case (APPLY_SCALE):
2180:                        dst.setLocation(x * m00, y * m11);
2181:                        break;
2182:                    case (APPLY_TRANSLATE):
2183:                        dst.setLocation(x + m02, y + m12);
2184:                        break;
2185:                    case (APPLY_IDENTITY):
2186:                        dst.setLocation(x, y);
2187:                        break;
2188:                    }
2189:                }
2190:            }
2191:
2192:            /**
2193:             * Transforms an array of floating point coordinates by this transform.
2194:             * The two coordinate array sections can be exactly the same or
2195:             * can be overlapping sections of the same array without affecting the
2196:             * validity of the results.
2197:             * This method ensures that no source coordinates are overwritten by a
2198:             * previous operation before they can be transformed.
2199:             * The coordinates are stored in the arrays starting at the specified
2200:             * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
2201:             * @param srcPts the array containing the source point coordinates.
2202:             * Each point is stored as a pair of x,&nbsp;y coordinates.
2203:             * @param dstPts the array into which the transformed point coordinates
2204:             * are returned.  Each point is stored as a pair of x,&nbsp;y
2205:             * coordinates.
2206:             * @param srcOff the offset to the first point to be transformed
2207:             * in the source array
2208:             * @param dstOff the offset to the location of the first
2209:             * transformed point that is stored in the destination array
2210:             * @param numPts the number of points to be transformed
2211:             */
2212:            public void transform(float[] srcPts, int srcOff, float[] dstPts,
2213:                    int dstOff, int numPts) {
2214:                double M00, M01, M02, M10, M11, M12; // For caching
2215:                if (dstPts == srcPts && dstOff > srcOff
2216:                        && dstOff < srcOff + numPts * 2) {
2217:                    // If the arrays overlap partially with the destination higher
2218:                    // than the source and we transform the coordinates normally
2219:                    // we would overwrite some of the later source coordinates
2220:                    // with results of previous transformations.
2221:                    // To get around this we use arraycopy to copy the points
2222:                    // to their final destination with correct overwrite
2223:                    // handling and then transform them in place in the new
2224:                    // safer location.
2225:                    System
2226:                            .arraycopy(srcPts, srcOff, dstPts, dstOff,
2227:                                    numPts * 2);
2228:                    // srcPts = dstPts;		// They are known to be equal.
2229:                    srcOff = dstOff;
2230:                }
2231:                switch (state) {
2232:                default:
2233:                    stateError();
2234:                    return;
2235:                    /* NOTREACHED */
2236:                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2237:                    M00 = m00;
2238:                    M01 = m01;
2239:                    M02 = m02;
2240:                    M10 = m10;
2241:                    M11 = m11;
2242:                    M12 = m12;
2243:                    while (--numPts >= 0) {
2244:                        double x = srcPts[srcOff++];
2245:                        double y = srcPts[srcOff++];
2246:                        dstPts[dstOff++] = (float) (M00 * x + M01 * y + M02);
2247:                        dstPts[dstOff++] = (float) (M10 * x + M11 * y + M12);
2248:                    }
2249:                    return;
2250:                case (APPLY_SHEAR | APPLY_SCALE):
2251:                    M00 = m00;
2252:                    M01 = m01;
2253:                    M10 = m10;
2254:                    M11 = m11;
2255:                    while (--numPts >= 0) {
2256:                        double x = srcPts[srcOff++];
2257:                        double y = srcPts[srcOff++];
2258:                        dstPts[dstOff++] = (float) (M00 * x + M01 * y);
2259:                        dstPts[dstOff++] = (float) (M10 * x + M11 * y);
2260:                    }
2261:                    return;
2262:                case (APPLY_SHEAR | APPLY_TRANSLATE):
2263:                    M01 = m01;
2264:                    M02 = m02;
2265:                    M10 = m10;
2266:                    M12 = m12;
2267:                    while (--numPts >= 0) {
2268:                        double x = srcPts[srcOff++];
2269:                        dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++] + M02);
2270:                        dstPts[dstOff++] = (float) (M10 * x + M12);
2271:                    }
2272:                    return;
2273:                case (APPLY_SHEAR):
2274:                    M01 = m01;
2275:                    M10 = m10;
2276:                    while (--numPts >= 0) {
2277:                        double x = srcPts[srcOff++];
2278:                        dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++]);
2279:                        dstPts[dstOff++] = (float) (M10 * x);
2280:                    }
2281:                    return;
2282:                case (APPLY_SCALE | APPLY_TRANSLATE):
2283:                    M00 = m00;
2284:                    M02 = m02;
2285:                    M11 = m11;
2286:                    M12 = m12;
2287:                    while (--numPts >= 0) {
2288:                        dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++] + M02);
2289:                        dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++] + M12);
2290:                    }
2291:                    return;
2292:                case (APPLY_SCALE):
2293:                    M00 = m00;
2294:                    M11 = m11;
2295:                    while (--numPts >= 0) {
2296:                        dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++]);
2297:                        dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++]);
2298:                    }
2299:                    return;
2300:                case (APPLY_TRANSLATE):
2301:                    M02 = m02;
2302:                    M12 = m12;
2303:                    while (--numPts >= 0) {
2304:                        dstPts[dstOff++] = (float) (srcPts[srcOff++] + M02);
2305:                        dstPts[dstOff++] = (float) (srcPts[srcOff++] + M12);
2306:                    }
2307:                    return;
2308:                case (APPLY_IDENTITY):
2309:                    if (srcPts != dstPts || srcOff != dstOff) {
2310:                        System.arraycopy(srcPts, srcOff, dstPts, dstOff,
2311:                                numPts * 2);
2312:                    }
2313:                    return;
2314:                }
2315:            }
2316:
2317:            /**
2318:             * Transforms an array of double precision coordinates by this transform.
2319:             * The two coordinate array sections can be exactly the same or
2320:             * can be overlapping sections of the same array without affecting the
2321:             * validity of the results.
2322:             * This method ensures that no source coordinates are
2323:             * overwritten by a previous operation before they can be transformed.
2324:             * The coordinates are stored in the arrays starting at the indicated
2325:             * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
2326:             * @param srcPts the array containing the source point coordinates.
2327:             * Each point is stored as a pair of x,&nbsp;y coordinates.
2328:             * @param dstPts the array into which the transformed point
2329:             * coordinates are returned.  Each point is stored as a pair of
2330:             * x,&nbsp;y coordinates.
2331:             * @param srcOff the offset to the first point to be transformed
2332:             * in the source array
2333:             * @param dstOff the offset to the location of the first
2334:             * transformed point that is stored in the destination array
2335:             * @param numPts the number of point objects to be transformed
2336:             */
2337:            public void transform(double[] srcPts, int srcOff, double[] dstPts,
2338:                    int dstOff, int numPts) {
2339:                double M00, M01, M02, M10, M11, M12; // For caching
2340:                if (dstPts == srcPts && dstOff > srcOff
2341:                        && dstOff < srcOff + numPts * 2) {
2342:                    // If the arrays overlap partially with the destination higher
2343:                    // than the source and we transform the coordinates normally
2344:                    // we would overwrite some of the later source coordinates
2345:                    // with results of previous transformations.
2346:                    // To get around this we use arraycopy to copy the points
2347:                    // to their final destination with correct overwrite
2348:                    // handling and then transform them in place in the new
2349:                    // safer location.
2350:                    System
2351:                            .arraycopy(srcPts, srcOff, dstPts, dstOff,
2352:                                    numPts * 2);
2353:                    // srcPts = dstPts;		// They are known to be equal.
2354:                    srcOff = dstOff;
2355:                }
2356:                switch (state) {
2357:                default:
2358:                    stateError();
2359:                    return;
2360:                    /* NOTREACHED */
2361:                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2362:                    M00 = m00;
2363:                    M01 = m01;
2364:                    M02 = m02;
2365:                    M10 = m10;
2366:                    M11 = m11;
2367:                    M12 = m12;
2368:                    while (--numPts >= 0) {
2369:                        double x = srcPts[srcOff++];
2370:                        double y = srcPts[srcOff++];
2371:                        dstPts[dstOff++] = M00 * x + M01 * y + M02;
2372:                        dstPts[dstOff++] = M10 * x + M11 * y + M12;
2373:                    }
2374:                    return;
2375:                case (APPLY_SHEAR | APPLY_SCALE):
2376:                    M00 = m00;
2377:                    M01 = m01;
2378:                    M10 = m10;
2379:                    M11 = m11;
2380:                    while (--numPts >= 0) {
2381:                        double x = srcPts[srcOff++];
2382:                        double y = srcPts[srcOff++];
2383:                        dstPts[dstOff++] = M00 * x + M01 * y;
2384:                        dstPts[dstOff++] = M10 * x + M11 * y;
2385:                    }
2386:                    return;
2387:                case (APPLY_SHEAR | APPLY_TRANSLATE):
2388:                    M01 = m01;
2389:                    M02 = m02;
2390:                    M10 = m10;
2391:                    M12 = m12;
2392:                    while (--numPts >= 0) {
2393:                        double x = srcPts[srcOff++];
2394:                        dstPts[dstOff++] = M01 * srcPts[srcOff++] + M02;
2395:                        dstPts[dstOff++] = M10 * x + M12;
2396:                    }
2397:                    return;
2398:                case (APPLY_SHEAR):
2399:                    M01 = m01;
2400:                    M10 = m10;
2401:                    while (--numPts >= 0) {
2402:                        double x = srcPts[srcOff++];
2403:                        dstPts[dstOff++] = M01 * srcPts[srcOff++];
2404:                        dstPts[dstOff++] = M10 * x;
2405:                    }
2406:                    return;
2407:                case (APPLY_SCALE | APPLY_TRANSLATE):
2408:                    M00 = m00;
2409:                    M02 = m02;
2410:                    M11 = m11;
2411:                    M12 = m12;
2412:                    while (--numPts >= 0) {
2413:                        dstPts[dstOff++] = M00 * srcPts[srcOff++] + M02;
2414:                        dstPts[dstOff++] = M11 * srcPts[srcOff++] + M12;
2415:                    }
2416:                    return;
2417:                case (APPLY_SCALE):
2418:                    M00 = m00;
2419:                    M11 = m11;
2420:                    while (--numPts >= 0) {
2421:                        dstPts[dstOff++] = M00 * srcPts[srcOff++];
2422:                        dstPts[dstOff++] = M11 * srcPts[srcOff++];
2423:                    }
2424:                    return;
2425:                case (APPLY_TRANSLATE):
2426:                    M02 = m02;
2427:                    M12 = m12;
2428:                    while (--numPts >= 0) {
2429:                        dstPts[dstOff++] = srcPts[srcOff++] + M02;
2430:                        dstPts[dstOff++] = srcPts[srcOff++] + M12;
2431:                    }
2432:                    return;
2433:                case (APPLY_IDENTITY):
2434:                    if (srcPts != dstPts || srcOff != dstOff) {
2435:                        System.arraycopy(srcPts, srcOff, dstPts, dstOff,
2436:                                numPts * 2);
2437:                    }
2438:                    return;
2439:                }
2440:
2441:                /* NOTREACHED */
2442:            }
2443:
2444:            /**
2445:             * Transforms an array of floating point coordinates by this transform
2446:             * and stores the results into an array of doubles.
2447:             * The coordinates are stored in the arrays starting at the specified
2448:             * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
2449:             * @param srcPts the array containing the source point coordinates.
2450:             * Each point is stored as a pair of x,&nbsp;y coordinates.
2451:             * @param dstPts the array into which the transformed point coordinates
2452:             * are returned.  Each point is stored as a pair of x,&nbsp;y
2453:             * coordinates.
2454:             * @param srcOff the offset to the first point to be transformed
2455:             * in the source array
2456:             * @param dstOff the offset to the location of the first
2457:             * transformed point that is stored in the destination array
2458:             * @param numPts the number of points to be transformed
2459:             */
2460:            public void transform(float[] srcPts, int srcOff, double[] dstPts,
2461:                    int dstOff, int numPts) {
2462:                double M00, M01, M02, M10, M11, M12; // For caching
2463:                switch (state) {
2464:                default:
2465:                    stateError();
2466:                    return;
2467:                    /* NOTREACHED */
2468:                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2469:                    M00 = m00;
2470:                    M01 = m01;
2471:                    M02 = m02;
2472:                    M10 = m10;
2473:                    M11 = m11;
2474:                    M12 = m12;
2475:                    while (--numPts >= 0) {
2476:                        double x = srcPts[srcOff++];
2477:                        double y = srcPts[srcOff++];
2478:                        dstPts[dstOff++] = M00 * x + M01 * y + M02;
2479:                        dstPts[dstOff++] = M10 * x + M11 * y + M12;
2480:                    }
2481:                    return;
2482:                case (APPLY_SHEAR | APPLY_SCALE):
2483:                    M00 = m00;
2484:                    M01 = m01;
2485:                    M10 = m10;
2486:                    M11 = m11;
2487:                    while (--numPts >= 0) {
2488:                        double x = srcPts[srcOff++];
2489:                        double y = srcPts[srcOff++];
2490:                        dstPts[dstOff++] = M00 * x + M01 * y;
2491:                        dstPts[dstOff++] = M10 * x + M11 * y;
2492:                    }
2493:                    return;
2494:                case (APPLY_SHEAR | APPLY_TRANSLATE):
2495:                    M01 = m01;
2496:                    M02 = m02;
2497:                    M10 = m10;
2498:                    M12 = m12;
2499:                    while (--numPts >= 0) {
2500:                        double x = srcPts[srcOff++];
2501:                        dstPts[dstOff++] = M01 * srcPts[srcOff++] + M02;
2502:                        dstPts[dstOff++] = M10 * x + M12;
2503:                    }
2504:                    return;
2505:                case (APPLY_SHEAR):
2506:                    M01 = m01;
2507:                    M10 = m10;
2508:                    while (--numPts >= 0) {
2509:                        double x = srcPts[srcOff++];
2510:                        dstPts[dstOff++] = M01 * srcPts[srcOff++];
2511:                        dstPts[dstOff++] = M10 * x;
2512:                    }
2513:                    return;
2514:                case (APPLY_SCALE | APPLY_TRANSLATE):
2515:                    M00 = m00;
2516:                    M02 = m02;
2517:                    M11 = m11;
2518:                    M12 = m12;
2519:                    while (--numPts >= 0) {
2520:                        dstPts[dstOff++] = M00 * srcPts[srcOff++] + M02;
2521:                        dstPts[dstOff++] = M11 * srcPts[srcOff++] + M12;
2522:                    }
2523:                    return;
2524:                case (APPLY_SCALE):
2525:                    M00 = m00;
2526:                    M11 = m11;
2527:                    while (--numPts >= 0) {
2528:                        dstPts[dstOff++] = M00 * srcPts[srcOff++];
2529:                        dstPts[dstOff++] = M11 * srcPts[srcOff++];
2530:                    }
2531:                    return;
2532:                case (APPLY_TRANSLATE):
2533:                    M02 = m02;
2534:                    M12 = m12;
2535:                    while (--numPts >= 0) {
2536:                        dstPts[dstOff++] = srcPts[srcOff++] + M02;
2537:                        dstPts[dstOff++] = srcPts[srcOff++] + M12;
2538:                    }
2539:                    return;
2540:                case (APPLY_IDENTITY):
2541:                    while (--numPts >= 0) {
2542:                        dstPts[dstOff++] = srcPts[srcOff++];
2543:                        dstPts[dstOff++] = srcPts[srcOff++];
2544:                    }
2545:                    return;
2546:                }
2547:
2548:                /* NOTREACHED */
2549:            }
2550:
2551:            /**
2552:             * Transforms an array of double precision coordinates by this transform
2553:             * and stores the results into an array of floats.
2554:             * The coordinates are stored in the arrays starting at the specified
2555:             * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
2556:             * @param srcPts the array containing the source point coordinates.
2557:             * Each point is stored as a pair of x,&nbsp;y coordinates.
2558:             * @param dstPts the array into which the transformed point
2559:             * coordinates are returned.  Each point is stored as a pair of 
2560:             * x,&nbsp;y coordinates.
2561:             * @param srcOff the offset to the first point to be transformed
2562:             * in the source array
2563:             * @param dstOff the offset to the location of the first
2564:             * transformed point that is stored in the destination array
2565:             * @param numPts the number of point objects to be transformed
2566:             */
2567:            public void transform(double[] srcPts, int srcOff, float[] dstPts,
2568:                    int dstOff, int numPts) {
2569:                double M00, M01, M02, M10, M11, M12; // For caching
2570:                switch (state) {
2571:                default:
2572:                    stateError();
2573:                    return;
2574:                    /* NOTREACHED */
2575:                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2576:                    M00 = m00;
2577:                    M01 = m01;
2578:                    M02 = m02;
2579:                    M10 = m10;
2580:                    M11 = m11;
2581:                    M12 = m12;
2582:                    while (--numPts >= 0) {
2583:                        double x = srcPts[srcOff++];
2584:                        double y = srcPts[srcOff++];
2585:                        dstPts[dstOff++] = (float) (M00 * x + M01 * y + M02);
2586:                        dstPts[dstOff++] = (float) (M10 * x + M11 * y + M12);
2587:                    }
2588:                    return;
2589:                case (APPLY_SHEAR | APPLY_SCALE):
2590:                    M00 = m00;
2591:                    M01 = m01;
2592:                    M10 = m10;
2593:                    M11 = m11;
2594:                    while (--numPts >= 0) {
2595:                        double x = srcPts[srcOff++];
2596:                        double y = srcPts[srcOff++];
2597:                        dstPts[dstOff++] = (float) (M00 * x + M01 * y);
2598:                        dstPts[dstOff++] = (float) (M10 * x + M11 * y);
2599:                    }
2600:                    return;
2601:                case (APPLY_SHEAR | APPLY_TRANSLATE):
2602:                    M01 = m01;
2603:                    M02 = m02;
2604:                    M10 = m10;
2605:                    M12 = m12;
2606:                    while (--numPts >= 0) {
2607:                        double x = srcPts[srcOff++];
2608:                        dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++] + M02);
2609:                        dstPts[dstOff++] = (float) (M10 * x + M12);
2610:                    }
2611:                    return;
2612:                case (APPLY_SHEAR):
2613:                    M01 = m01;
2614:                    M10 = m10;
2615:                    while (--numPts >= 0) {
2616:                        double x = srcPts[srcOff++];
2617:                        dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++]);
2618:                        dstPts[dstOff++] = (float) (M10 * x);
2619:                    }
2620:                    return;
2621:                case (APPLY_SCALE | APPLY_TRANSLATE):
2622:                    M00 = m00;
2623:                    M02 = m02;
2624:                    M11 = m11;
2625:                    M12 = m12;
2626:                    while (--numPts >= 0) {
2627:                        dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++] + M02);
2628:                        dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++] + M12);
2629:                    }
2630:                    return;
2631:                case (APPLY_SCALE):
2632:                    M00 = m00;
2633:                    M11 = m11;
2634:                    while (--numPts >= 0) {
2635:                        dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++]);
2636:                        dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++]);
2637:                    }
2638:                    return;
2639:                case (APPLY_TRANSLATE):
2640:                    M02 = m02;
2641:                    M12 = m12;
2642:                    while (--numPts >= 0) {
2643:                        dstPts[dstOff++] = (float) (srcPts[srcOff++] + M02);
2644:                        dstPts[dstOff++] = (float) (srcPts[srcOff++] + M12);
2645:                    }
2646:                    return;
2647:                case (APPLY_IDENTITY):
2648:                    while (--numPts >= 0) {
2649:                        dstPts[dstOff++] = (float) (srcPts[srcOff++]);
2650:                        dstPts[dstOff++] = (float) (srcPts[srcOff++]);
2651:                    }
2652:                    return;
2653:                }
2654:
2655:                /* NOTREACHED */
2656:            }
2657:
2658:            /**
2659:             * Inverse transforms the specified <code>ptSrc</code> and stores the
2660:             * result in <code>ptDst</code>.
2661:             * If <code>ptDst</code> is <code>null</code>, a new
2662:             * <code>Point2D</code> object is allocated and then the result of the
2663:             * transform is stored in this object.
2664:             * In either case, <code>ptDst</code>, which contains the transformed
2665:             * point, is returned for convenience.
2666:             * If <code>ptSrc</code> and <code>ptDst</code> are the same
2667:             * object, the input point is correctly overwritten with the
2668:             * transformed point.
2669:             * @param ptSrc the point to be inverse transformed
2670:             * @param ptDst the resulting transformed point
2671:             * @return <code>ptDst</code>, which contains the result of the 
2672:             * inverse transform.
2673:             * @exception NoninvertibleTransformException  if the matrix cannot be
2674:             *                                         inverted.
2675:             */
2676:            public Point2D inverseTransform(Point2D ptSrc, Point2D ptDst)
2677:                    throws NoninvertibleTransformException {
2678:                if (ptDst == null) {
2679:                    if (ptSrc instanceof  Point2D.Double) {
2680:                        ptDst = new Point2D.Double();
2681:                    } else {
2682:                        ptDst = new Point2D.Float();
2683:                    }
2684:                }
2685:                // Copy source coords into local variables in case src == dst
2686:                double x = ptSrc.getX();
2687:                double y = ptSrc.getY();
2688:                switch (state) {
2689:                default:
2690:                    stateError();
2691:                    return null;
2692:                    /* NOTREACHED */
2693:                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2694:                    x -= m02;
2695:                    y -= m12;
2696:                    /* NOBREAK */
2697:                case (APPLY_SHEAR | APPLY_SCALE):
2698:                    double det = m00 * m11 - m01 * m10;
2699:                    if (Math.abs(det) <= Double.MIN_VALUE) {
2700:                        throw new NoninvertibleTransformException(
2701:                                "Determinant is " + det);
2702:                    }
2703:                    ptDst.setLocation((x * m11 - y * m01) / det, (y * m00 - x
2704:                            * m10)
2705:                            / det);
2706:                    return ptDst;
2707:                case (APPLY_SHEAR | APPLY_TRANSLATE):
2708:                    x -= m02;
2709:                    y -= m12;
2710:                    /* NOBREAK */
2711:                case (APPLY_SHEAR):
2712:                    if (m01 == 0.0 || m10 == 0.0) {
2713:                        throw new NoninvertibleTransformException(
2714:                                "Determinant is 0");
2715:                    }
2716:                    ptDst.setLocation(y / m10, x / m01);
2717:                    return ptDst;
2718:                case (APPLY_SCALE | APPLY_TRANSLATE):
2719:                    x -= m02;
2720:                    y -= m12;
2721:                    /* NOBREAK */
2722:                case (APPLY_SCALE):
2723:                    if (m00 == 0.0 || m11 == 0.0) {
2724:                        throw new NoninvertibleTransformException(
2725:                                "Determinant is 0");
2726:                    }
2727:                    ptDst.setLocation(x / m00, y / m11);
2728:                    return ptDst;
2729:                case (APPLY_TRANSLATE):
2730:                    ptDst.setLocation(x - m02, y - m12);
2731:                    return ptDst;
2732:                case (APPLY_IDENTITY):
2733:                    ptDst.setLocation(x, y);
2734:                    return ptDst;
2735:                }
2736:
2737:                /* NOTREACHED */
2738:            }
2739:
2740:            /**
2741:             * Inverse transforms an array of double precision coordinates by
2742:             * this transform.  
2743:             * The two coordinate array sections can be exactly the same or
2744:             * can be overlapping sections of the same array without affecting the
2745:             * validity of the results.
2746:             * This method ensures that no source coordinates are
2747:             * overwritten by a previous operation before they can be transformed.
2748:             * The coordinates are stored in the arrays starting at the specified
2749:             * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
2750:             * @param srcPts the array containing the source point coordinates.
2751:             * Each point is stored as a pair of x,&nbsp;y coordinates.
2752:             * @param dstPts the array into which the transformed point
2753:             * coordinates are returned.  Each point is stored as a pair of 
2754:             * x,&nbsp;y coordinates.
2755:             * @param srcOff the offset to the first point to be transformed
2756:             * in the source array
2757:             * @param dstOff the offset to the location of the first
2758:             * transformed point that is stored in the destination array
2759:             * @param numPts the number of point objects to be transformed
2760:             * @exception NoninvertibleTransformException  if the matrix cannot be
2761:             *                                         inverted.
2762:             */
2763:            public void inverseTransform(double[] srcPts, int srcOff,
2764:                    double[] dstPts, int dstOff, int numPts)
2765:                    throws NoninvertibleTransformException {
2766:                double M00, M01, M02, M10, M11, M12; // For caching
2767:                double det;
2768:                if (dstPts == srcPts && dstOff > srcOff
2769:                        && dstOff < srcOff + numPts * 2) {
2770:                    // If the arrays overlap partially with the destination higher
2771:                    // than the source and we transform the coordinates normally
2772:                    // we would overwrite some of the later source coordinates
2773:                    // with results of previous transformations.
2774:                    // To get around this we use arraycopy to copy the points
2775:                    // to their final destination with correct overwrite
2776:                    // handling and then transform them in place in the new
2777:                    // safer location.
2778:                    System
2779:                            .arraycopy(srcPts, srcOff, dstPts, dstOff,
2780:                                    numPts * 2);
2781:                    // srcPts = dstPts;		// They are known to be equal.
2782:                    srcOff = dstOff;
2783:                }
2784:                switch (state) {
2785:                default:
2786:                    stateError();
2787:                    return;
2788:                    /* NOTREACHED */
2789:                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2790:                    M00 = m00;
2791:                    M01 = m01;
2792:                    M02 = m02;
2793:                    M10 = m10;
2794:                    M11 = m11;
2795:                    M12 = m12;
2796:                    det = M00 * M11 - M01 * M10;
2797:                    if (Math.abs(det) <= Double.MIN_VALUE) {
2798:                        throw new NoninvertibleTransformException(
2799:                                "Determinant is " + det);
2800:                    }
2801:                    while (--numPts >= 0) {
2802:                        double x = srcPts[srcOff++] - M02;
2803:                        double y = srcPts[srcOff++] - M12;
2804:                        dstPts[dstOff++] = (x * M11 - y * M01) / det;
2805:                        dstPts[dstOff++] = (y * M00 - x * M10) / det;
2806:                    }
2807:                    return;
2808:                case (APPLY_SHEAR | APPLY_SCALE):
2809:                    M00 = m00;
2810:                    M01 = m01;
2811:                    M10 = m10;
2812:                    M11 = m11;
2813:                    det = M00 * M11 - M01 * M10;
2814:                    if (Math.abs(det) <= Double.MIN_VALUE) {
2815:                        throw new NoninvertibleTransformException(
2816:                                "Determinant is " + det);
2817:                    }
2818:                    while (--numPts >= 0) {
2819:                        double x = srcPts[srcOff++];
2820:                        double y = srcPts[srcOff++];
2821:                        dstPts[dstOff++] = (x * M11 - y * M01) / det;
2822:                        dstPts[dstOff++] = (y * M00 - x * M10) / det;
2823:                    }
2824:                    return;
2825:                case (APPLY_SHEAR | APPLY_TRANSLATE):
2826:                    M01 = m01;
2827:                    M02 = m02;
2828:                    M10 = m10;
2829:                    M12 = m12;
2830:                    if (M01 == 0.0 || M10 == 0.0) {
2831:                        throw new NoninvertibleTransformException(
2832:                                "Determinant is 0");
2833:                    }
2834:                    while (--numPts >= 0) {
2835:                        double x = srcPts[srcOff++] - M02;
2836:                        dstPts[dstOff++] = (srcPts[srcOff++] - M12) / M10;
2837:                        dstPts[dstOff++] = x / M01;
2838:                    }
2839:                    return;
2840:                case (APPLY_SHEAR):
2841:                    M01 = m01;
2842:                    M10 = m10;
2843:                    if (M01 == 0.0 || M10 == 0.0) {
2844:                        throw new NoninvertibleTransformException(
2845:                                "Determinant is 0");
2846:                    }
2847:                    while (--numPts >= 0) {
2848:                        double x = srcPts[srcOff++];
2849:                        dstPts[dstOff++] = srcPts[srcOff++] / M10;
2850:                        dstPts[dstOff++] = x / M01;
2851:                    }
2852:                    return;
2853:                case (APPLY_SCALE | APPLY_TRANSLATE):
2854:                    M00 = m00;
2855:                    M02 = m02;
2856:                    M11 = m11;
2857:                    M12 = m12;
2858:                    if (M00 == 0.0 || M11 == 0.0) {
2859:                        throw new NoninvertibleTransformException(
2860:                                "Determinant is 0");
2861:                    }
2862:                    while (--numPts >= 0) {
2863:                        dstPts[dstOff++] = (srcPts[srcOff++] - M02) / M00;
2864:                        dstPts[dstOff++] = (srcPts[srcOff++] - M12) / M11;
2865:                    }
2866:                    return;
2867:                case (APPLY_SCALE):
2868:                    M00 = m00;
2869:                    M11 = m11;
2870:                    if (M00 == 0.0 || M11 == 0.0) {
2871:                        throw new NoninvertibleTransformException(
2872:                                "Determinant is 0");
2873:                    }
2874:                    while (--numPts >= 0) {
2875:                        dstPts[dstOff++] = srcPts[srcOff++] / M00;
2876:                        dstPts[dstOff++] = srcPts[srcOff++] / M11;
2877:                    }
2878:                    return;
2879:                case (APPLY_TRANSLATE):
2880:                    M02 = m02;
2881:                    M12 = m12;
2882:                    while (--numPts >= 0) {
2883:                        dstPts[dstOff++] = srcPts[srcOff++] - M02;
2884:                        dstPts[dstOff++] = srcPts[srcOff++] - M12;
2885:                    }
2886:                    return;
2887:                case (APPLY_IDENTITY):
2888:                    if (srcPts != dstPts || srcOff != dstOff) {
2889:                        System.arraycopy(srcPts, srcOff, dstPts, dstOff,
2890:                                numPts * 2);
2891:                    }
2892:                    return;
2893:                }
2894:
2895:                /* NOTREACHED */
2896:            }
2897:
2898:            /**
2899:             * Transforms the relative distance vector specified by 
2900:             * <code>ptSrc</code> and stores the result in <code>ptDst</code>.
2901:             * A relative distance vector is transformed without applying the
2902:             * translation components of the affine transformation matrix
2903:             * using the following equations:
2904:             * <pre>
2905:             *	[  x' ]   [  m00  m01 (m02) ] [  x  ]   [ m00x + m01y ]
2906:             *	[  y' ] = [  m10  m11 (m12) ] [  y  ] = [ m10x + m11y ]
2907:             *	[ (1) ]   [  (0)  (0) ( 1 ) ] [ (1) ]   [     (1)     ]
2908:             * </pre>
2909:             * If <code>ptDst</code> is <code>null</code>, a new
2910:             * <code>Point2D</code> object is allocated and then the result of the
2911:             * transform is stored in this object.
2912:             * In either case, <code>ptDst</code>, which contains the
2913:             * transformed point, is returned for convenience.
2914:             * If <code>ptSrc</code> and <code>ptDst</code> are the same object,
2915:             * the input point is correctly overwritten with the transformed
2916:             * point.
2917:             * @param ptSrc the distance vector to be delta transformed
2918:             * @param ptDst the resulting transformed distance vector
2919:             * @return <code>ptDst</code>, which contains the result of the
2920:             * transformation.
2921:             */
2922:            public Point2D deltaTransform(Point2D ptSrc, Point2D ptDst) {
2923:                if (ptDst == null) {
2924:                    if (ptSrc instanceof  Point2D.Double) {
2925:                        ptDst = new Point2D.Double();
2926:                    } else {
2927:                        ptDst = new Point2D.Float();
2928:                    }
2929:                }
2930:                // Copy source coords into local variables in case src == dst
2931:                double x = ptSrc.getX();
2932:                double y = ptSrc.getY();
2933:                switch (state) {
2934:                default:
2935:                    stateError();
2936:                    return null;
2937:                    /* NOTREACHED */
2938:                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2939:                case (APPLY_SHEAR | APPLY_SCALE):
2940:                    ptDst.setLocation(x * m00 + y * m01, x * m10 + y * m11);
2941:                    return ptDst;
2942:                case (APPLY_SHEAR | APPLY_TRANSLATE):
2943:                case (APPLY_SHEAR):
2944:                    ptDst.setLocation(y * m01, x * m10);
2945:                    return ptDst;
2946:                case (APPLY_SCALE | APPLY_TRANSLATE):
2947:                case (APPLY_SCALE):
2948:                    ptDst.setLocation(x * m00, y * m11);
2949:                    return ptDst;
2950:                case (APPLY_TRANSLATE):
2951:                case (APPLY_IDENTITY):
2952:                    ptDst.setLocation(x, y);
2953:                    return ptDst;
2954:                }
2955:
2956:                /* NOTREACHED */
2957:            }
2958:
2959:            /**
2960:             * Transforms an array of relative distance vectors by this
2961:             * transform.
2962:             * A relative distance vector is transformed without applying the
2963:             * translation components of the affine transformation matrix
2964:             * using the following equations:
2965:             * <pre>
2966:             *	[  x' ]   [  m00  m01 (m02) ] [  x  ]   [ m00x + m01y ]
2967:             *	[  y' ] = [  m10  m11 (m12) ] [  y  ] = [ m10x + m11y ]
2968:             *	[ (1) ]   [  (0)  (0) ( 1 ) ] [ (1) ]   [     (1)     ]
2969:             * </pre>
2970:             * The two coordinate array sections can be exactly the same or
2971:             * can be overlapping sections of the same array without affecting the
2972:             * validity of the results.
2973:             * This method ensures that no source coordinates are
2974:             * overwritten by a previous operation before they can be transformed.
2975:             * The coordinates are stored in the arrays starting at the indicated
2976:             * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
2977:             * @param srcPts the array containing the source distance vectors.
2978:             * Each vector is stored as a pair of relative x,&nbsp;y coordinates.
2979:             * @param dstPts the array into which the transformed distance vectors
2980:             * are returned.  Each vector is stored as a pair of relative
2981:             * x,&nbsp;y coordinates.
2982:             * @param srcOff the offset to the first vector to be transformed
2983:             * in the source array
2984:             * @param dstOff the offset to the location of the first
2985:             * transformed vector that is stored in the destination array
2986:             * @param numPts the number of vector coordinate pairs to be
2987:             * transformed
2988:             */
2989:            public void deltaTransform(double[] srcPts, int srcOff,
2990:                    double[] dstPts, int dstOff, int numPts) {
2991:                double M00, M01, M10, M11; // For caching
2992:                if (dstPts == srcPts && dstOff > srcOff
2993:                        && dstOff < srcOff + numPts * 2) {
2994:                    // If the arrays overlap partially with the destination higher
2995:                    // than the source and we transform the coordinates normally
2996:                    // we would overwrite some of the later source coordinates
2997:                    // with results of previous transformations.
2998:                    // To get around this we use arraycopy to copy the points
2999:                    // to their final destination with correct overwrite
3000:                    // handling and then transform them in place in the new
3001:                    // safer location.
3002:                    System
3003:                            .arraycopy(srcPts, srcOff, dstPts, dstOff,
3004:                                    numPts * 2);
3005:                    // srcPts = dstPts;		// They are known to be equal.
3006:                    srcOff = dstOff;
3007:                }
3008:                switch (state) {
3009:                default:
3010:                    stateError();
3011:                    return;
3012:                    /* NOTREACHED */
3013:                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3014:                case (APPLY_SHEAR | APPLY_SCALE):
3015:                    M00 = m00;
3016:                    M01 = m01;
3017:                    M10 = m10;
3018:                    M11 = m11;
3019:                    while (--numPts >= 0) {
3020:                        double x = srcPts[srcOff++];
3021:                        double y = srcPts[srcOff++];
3022:                        dstPts[dstOff++] = x * M00 + y * M01;
3023:                        dstPts[dstOff++] = x * M10 + y * M11;
3024:                    }
3025:                    return;
3026:                case (APPLY_SHEAR | APPLY_TRANSLATE):
3027:                case (APPLY_SHEAR):
3028:                    M01 = m01;
3029:                    M10 = m10;
3030:                    while (--numPts >= 0) {
3031:                        double x = srcPts[srcOff++];
3032:                        dstPts[dstOff++] = srcPts[srcOff++] * M01;
3033:                        dstPts[dstOff++] = x * M10;
3034:                    }
3035:                    return;
3036:                case (APPLY_SCALE | APPLY_TRANSLATE):
3037:                case (APPLY_SCALE):
3038:                    M00 = m00;
3039:                    M11 = m11;
3040:                    while (--numPts >= 0) {
3041:                        dstPts[dstOff++] = srcPts[srcOff++] * M00;
3042:                        dstPts[dstOff++] = srcPts[srcOff++] * M11;
3043:                    }
3044:                    return;
3045:                case (APPLY_TRANSLATE):
3046:                case (APPLY_IDENTITY):
3047:                    if (srcPts != dstPts || srcOff != dstOff) {
3048:                        System.arraycopy(srcPts, srcOff, dstPts, dstOff,
3049:                                numPts * 2);
3050:                    }
3051:                    return;
3052:                }
3053:
3054:                /* NOTREACHED */
3055:            }
3056:
3057:            /* *
3058:             * Returns a new {@link Shape} object defined by the geometry of the
3059:             * specified <code>Shape</code> after it has been transformed by
3060:             * this transform.
3061:             * @param pSrc the specified <code>Shape</code> object to be
3062:             * transformed by this transform.
3063:             * @return a new <code>Shape</code> object that defines the geometry
3064:             * of the transformed <code>Shape</code>.
3065:             */
3066:            //#ifdef notdef    
3067:            public Shape createTransformedShape(Shape pSrc) {
3068:                if (pSrc == null) {
3069:                    return null;
3070:                }
3071:
3072:                if (pSrc instanceof  GeneralPath) {
3073:                    return ((GeneralPath) pSrc).createTransformedShape(this );
3074:                } else {
3075:                    PathIterator pi = pSrc.getPathIterator(this );
3076:                    GeneralPath gp = new GeneralPath(pi.getWindingRule());
3077:                    gp.append(pi, false);
3078:                    return gp;
3079:                }
3080:
3081:                /* NOTREACHED */
3082:            }
3083:
3084:            //#endif
3085:
3086:            private static double _matround(double matval) {
3087:                // Round values to sane precision for printing
3088:                // Note that Math.sin(Math.PI) has an error of about 10^-16
3089:                //return Math.rint(matval * 1E15) / 1E15;
3090:                return matval;
3091:            }
3092:
3093:            /**
3094:             * Returns a <code>String</code> that represents the value of this
3095:             * {@link Object}.
3096:             * @return a <code>String</code> representing the value of this
3097:             * <code>Object</code>.
3098:             */
3099:            public String toString() {
3100:                return ("AffineTransform[[" + _matround(m00) + ", "
3101:                        + _matround(m01) + ", " + _matround(m02) + "], ["
3102:                        + _matround(m10) + ", " + _matround(m11) + ", "
3103:                        + _matround(m12) + "]]");
3104:            }
3105:
3106:            /**
3107:             * Returns <code>true</code> if this <code>AffineTransform</code> is
3108:             * an identity transform.
3109:             * @return <code>true</code> if this <code>AffineTransform</code> is
3110:             * an identity transform; <code>false</code> otherwise.
3111:             */
3112:            public boolean isIdentity() {
3113:                return (state == APPLY_IDENTITY || (getType() == TYPE_IDENTITY));
3114:            }
3115:
3116:            /*  *
3117:             * Returns a copy of this <code>AffineTransform</code> object.
3118:             * @return an <code>Object</code> that is a copy of this
3119:             * <code>AffineTransform</code> object.
3120:             */
3121:            //#ifdef notdef
3122:            public Object clone() {
3123:                try {
3124:                    return super .clone();
3125:                } catch (CloneNotSupportedException e) {
3126:                    // this shouldn't happen, since we are Cloneable
3127:                    throw new InternalError();
3128:                }
3129:            }
3130:
3131:            //#endif
3132:
3133:            /**
3134:             * Returns the hashcode for this transform.
3135:             * @return      a hash code for this transform.
3136:             */
3137:            public int hashCode() {
3138:                long bits = Double.doubleToLongBits(m00);
3139:                bits = bits * 31 + Double.doubleToLongBits(m01);
3140:                bits = bits * 31 + Double.doubleToLongBits(m02);
3141:                bits = bits * 31 + Double.doubleToLongBits(m10);
3142:                bits = bits * 31 + Double.doubleToLongBits(m11);
3143:                bits = bits * 31 + Double.doubleToLongBits(m12);
3144:                return (((int) bits) ^ ((int) (bits >> 32)));
3145:            }
3146:
3147:            /**
3148:             * Returns <code>true</code> if this <code>AffineTransform</code> 
3149:             * represents the same affine coordinate transform as the specified
3150:             * argument.
3151:             * @param obj the <code>Object</code> to test for equality with this
3152:             * <code>AffineTransform</code>
3153:             * @return <code>true</code> if <code>obj</code> equals this
3154:             * <code>AffineTransform</code> object; <code>false</code> otherwise.
3155:             */
3156:            public boolean equals(Object obj) {
3157:                if (!(obj instanceof  AffineTransform)) {
3158:                    return false;
3159:                }
3160:
3161:                AffineTransform a = (AffineTransform) obj;
3162:
3163:                return ((m00 == a.m00) && (m01 == a.m01) && (m02 == a.m02)
3164:                        && (m10 == a.m10) && (m11 == a.m11) && (m12 == a.m12));
3165:            }
3166:
3167:            /* Serialization support.  A readObject method is neccessary because
3168:             * the state field is part of the implementation of this particular
3169:             * AffineTransform and not part of the public specification.  The
3170:             * state variable's value needs to be recalculated on the fly by the
3171:             * readObject method as it is in the 6-argument matrix constructor.
3172:             */
3173:            //#ifdef notdef
3174:            private void writeObject(java.io.ObjectOutputStream s)
3175:                    throws java.lang.ClassNotFoundException,
3176:                    java.io.IOException {
3177:                s.defaultWriteObject();
3178:            }
3179:
3180:            private void readObject(java.io.ObjectInputStream s)
3181:                    throws java.lang.ClassNotFoundException,
3182:                    java.io.IOException {
3183:                s.defaultReadObject();
3184:                updateState();
3185:            }
3186:            //#endif
3187:        }
3188:        //#endif
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.