KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > awt > geom > AffineTransform


1 /*
2  * @(#)AffineTransform.java 1.71 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.awt.geom;
9
10 import java.awt.Shape JavaDoc;
11
12 /**
13  * The <code>AffineTransform</code> class represents a 2D affine transform
14  * that performs a linear mapping from 2D coordinates to other 2D
15  * coordinates that preserves the "straightness" and
16  * "parallelness" of lines. Affine transformations can be constructed
17  * using sequences of translations, scales, flips, rotations, and shears.
18  * <p>
19  * Such a coordinate transformation can be represented by a 3 row by
20  * 3 column matrix with an implied last row of [ 0 0 1 ]. This matrix
21  * transforms source coordinates <code>(x,&nbsp;y)</code> into
22  * destination coordinates <code>(x',&nbsp;y')</code> by considering
23  * them to be a column vector and multiplying the coordinate vector
24  * by the matrix according to the following process:
25  * <pre>
26  * [ x'] [ m00 m01 m02 ] [ x ] [ m00x + m01y + m02 ]
27  * [ y'] = [ m10 m11 m12 ] [ y ] = [ m10x + m11y + m12 ]
28  * [ 1 ] [ 0 0 1 ] [ 1 ] [ 1 ]
29  * </pre>
30  *
31  * @version 1.71, 12/19/03
32  * @author Jim Graham
33  */

34 public class AffineTransform implements Cloneable JavaDoc, java.io.Serializable JavaDoc {
35     /*
36      * This constant is only useful for the cached type field.
37      * It indicates that the type has been decached and must be recalculated.
38      */

39     private static final int TYPE_UNKNOWN = -1;
40
41     /**
42      * This constant indicates that the transform defined by this object
43      * is an identity transform.
44      * An identity transform is one in which the output coordinates are
45      * always the same as the input coordinates.
46      * If this transform is anything other than the identity transform,
47      * the type will either be the constant GENERAL_TRANSFORM or a
48      * combination of the appropriate flag bits for the various coordinate
49      * conversions that this transform performs.
50      * @see #TYPE_TRANSLATION
51      * @see #TYPE_UNIFORM_SCALE
52      * @see #TYPE_GENERAL_SCALE
53      * @see #TYPE_FLIP
54      * @see #TYPE_QUADRANT_ROTATION
55      * @see #TYPE_GENERAL_ROTATION
56      * @see #TYPE_GENERAL_TRANSFORM
57      * @see #getType
58      */

59     public static final int TYPE_IDENTITY = 0;
60
61     /**
62      * This flag bit indicates that the transform defined by this object
63      * performs a translation in addition to the conversions indicated
64      * by other flag bits.
65      * A translation moves the coordinates by a constant amount in x
66      * and y without changing the length or angle of vectors.
67      * @see #TYPE_IDENTITY
68      * @see #TYPE_UNIFORM_SCALE
69      * @see #TYPE_GENERAL_SCALE
70      * @see #TYPE_FLIP
71      * @see #TYPE_QUADRANT_ROTATION
72      * @see #TYPE_GENERAL_ROTATION
73      * @see #TYPE_GENERAL_TRANSFORM
74      * @see #getType
75      */

76     public static final int TYPE_TRANSLATION = 1;
77
78     /**
79      * This flag bit indicates that the transform defined by this object
80      * performs a uniform scale in addition to the conversions indicated
81      * by other flag bits.
82      * A uniform scale multiplies the length of vectors by the same amount
83      * in both the x and y directions without changing the angle between
84      * vectors.
85      * This flag bit is mutually exclusive with the TYPE_GENERAL_SCALE flag.
86      * @see #TYPE_IDENTITY
87      * @see #TYPE_TRANSLATION
88      * @see #TYPE_GENERAL_SCALE
89      * @see #TYPE_FLIP
90      * @see #TYPE_QUADRANT_ROTATION
91      * @see #TYPE_GENERAL_ROTATION
92      * @see #TYPE_GENERAL_TRANSFORM
93      * @see #getType
94      */

95     public static final int TYPE_UNIFORM_SCALE = 2;
96
97     /**
98      * This flag bit indicates that the transform defined by this object
99      * performs a general scale in addition to the conversions indicated
100      * by other flag bits.
101      * A general scale multiplies the length of vectors by different
102      * amounts in the x and y directions without changing the angle
103      * between perpendicular vectors.
104      * This flag bit is mutually exclusive with the TYPE_UNIFORM_SCALE flag.
105      * @see #TYPE_IDENTITY
106      * @see #TYPE_TRANSLATION
107      * @see #TYPE_UNIFORM_SCALE
108      * @see #TYPE_FLIP
109      * @see #TYPE_QUADRANT_ROTATION
110      * @see #TYPE_GENERAL_ROTATION
111      * @see #TYPE_GENERAL_TRANSFORM
112      * @see #getType
113      */

114     public static final int TYPE_GENERAL_SCALE = 4;
115
116     /**
117      * This constant is a bit mask for any of the scale flag bits.
118      * @see #TYPE_UNIFORM_SCALE
119      * @see #TYPE_GENERAL_SCALE
120      */

121     public static final int TYPE_MASK_SCALE = (TYPE_UNIFORM_SCALE |
122                            TYPE_GENERAL_SCALE);
123
124     /**
125      * This flag bit indicates that the transform defined by this object
126      * performs a mirror image flip about some axis which changes the
127      * normally right handed coordinate system into a left handed
128      * system in addition to the conversions indicated by other flag bits.
129      * A right handed coordinate system is one where the positive X
130      * axis rotates counterclockwise to overlay the positive Y axis
131      * similar to the direction that the fingers on your right hand
132      * curl when you stare end on at your thumb.
133      * A left handed coordinate system is one where the positive X
134      * axis rotates clockwise to overlay the positive Y axis similar
135      * to the direction that the fingers on your left hand curl.
136      * There is no mathematical way to determine the angle of the
137      * original flipping or mirroring transformation since all angles
138      * of flip are identical given an appropriate adjusting rotation.
139      * @see #TYPE_IDENTITY
140      * @see #TYPE_TRANSLATION
141      * @see #TYPE_UNIFORM_SCALE
142      * @see #TYPE_GENERAL_SCALE
143      * @see #TYPE_QUADRANT_ROTATION
144      * @see #TYPE_GENERAL_ROTATION
145      * @see #TYPE_GENERAL_TRANSFORM
146      * @see #getType
147      */

148     public static final int TYPE_FLIP = 64;
149     /* NOTE: TYPE_FLIP was added after GENERAL_TRANSFORM was in public
150      * circulation and the flag bits could no longer be conveniently
151      * renumbered without introducing binary incompatibility in outside
152      * code.
153      */

154
155     /**
156      * This flag bit indicates that the transform defined by this object
157      * performs a quadrant rotation by some multiple of 90 degrees in
158      * addition to the conversions indicated by other flag bits.
159      * A rotation changes the angles of vectors by the same amount
160      * regardless of the original direction of the vector and without
161      * changing the length of the vector.
162      * This flag bit is mutually exclusive with the TYPE_GENERAL_ROTATION flag.
163      * @see #TYPE_IDENTITY
164      * @see #TYPE_TRANSLATION
165      * @see #TYPE_UNIFORM_SCALE
166      * @see #TYPE_GENERAL_SCALE
167      * @see #TYPE_FLIP
168      * @see #TYPE_GENERAL_ROTATION
169      * @see #TYPE_GENERAL_TRANSFORM
170      * @see #getType
171      */

172     public static final int TYPE_QUADRANT_ROTATION = 8;
173
174     /**
175      * This flag bit indicates that the transform defined by this object
176      * performs a rotation by an arbitrary angle in addition to the
177      * conversions indicated by other flag bits.
178      * A rotation changes the angles of vectors by the same amount
179      * regardless of the original direction of the vector and without
180      * changing the length of the vector.
181      * This flag bit is mutually exclusive with the
182      * TYPE_QUADRANT_ROTATION flag.
183      * @see #TYPE_IDENTITY
184      * @see #TYPE_TRANSLATION
185      * @see #TYPE_UNIFORM_SCALE
186      * @see #TYPE_GENERAL_SCALE
187      * @see #TYPE_FLIP
188      * @see #TYPE_QUADRANT_ROTATION
189      * @see #TYPE_GENERAL_TRANSFORM
190      * @see #getType
191      */

192     public static final int TYPE_GENERAL_ROTATION = 16;
193
194     /**
195      * This constant is a bit mask for any of the rotation flag bits.
196      * @see #TYPE_QUADRANT_ROTATION
197      * @see #TYPE_GENERAL_ROTATION
198      */

199     public static final int TYPE_MASK_ROTATION = (TYPE_QUADRANT_ROTATION |
200                           TYPE_GENERAL_ROTATION);
201
202     /**
203      * This constant indicates that the transform defined by this object
204      * performs an arbitrary conversion of the input coordinates.
205      * If this transform can be classified by any of the above constants,
206      * the type will either be the constant TYPE_IDENTITY or a
207      * combination of the appropriate flag bits for the various coordinate
208      * conversions that this transform performs.
209      * @see #TYPE_IDENTITY
210      * @see #TYPE_TRANSLATION
211      * @see #TYPE_UNIFORM_SCALE
212      * @see #TYPE_GENERAL_SCALE
213      * @see #TYPE_FLIP
214      * @see #TYPE_QUADRANT_ROTATION
215      * @see #TYPE_GENERAL_ROTATION
216      * @see #getType
217      */

218     public static final int TYPE_GENERAL_TRANSFORM = 32;
219
220     /**
221      * This constant is used for the internal state variable to indicate
222      * that no calculations need to be performed and that the source
223      * coordinates only need to be copied to their destinations to
224      * complete the transformation equation of this transform.
225      * @see #APPLY_TRANSLATE
226      * @see #APPLY_SCALE
227      * @see #APPLY_SHEAR
228      * @see #state
229      */

230     static final int APPLY_IDENTITY = 0;
231
232     /**
233      * This constant is used for the internal state variable to indicate
234      * that the translation components of the matrix (m02 and m12) need
235      * to be added to complete the transformation equation of this transform.
236      * @see #APPLY_IDENTITY
237      * @see #APPLY_SCALE
238      * @see #APPLY_SHEAR
239      * @see #state
240      */

241     static final int APPLY_TRANSLATE = 1;
242
243     /**
244      * This constant is used for the internal state variable to indicate
245      * that the scaling components of the matrix (m00 and m11) need
246      * to be factored in to complete the transformation equation of
247      * this transform. If the APPLY_SHEAR bit is also set then it
248      * indicates that the scaling components are not both 0.0. If the
249      * APPLY_SHEAR bit is not also set then it indicates that the
250      * scaling components are not both 1.0. If neither the APPLY_SHEAR
251      * nor the APPLY_SCALE bits are set then the scaling components
252      * are both 1.0, which means that the x and y components contribute
253      * to the transformed coordinate, but they are not multiplied by
254      * any scaling factor.
255      * @see #APPLY_IDENTITY
256      * @see #APPLY_TRANSLATE
257      * @see #APPLY_SHEAR
258      * @see #state
259      */

260     static final int APPLY_SCALE = 2;
261
262     /**
263      * This constant is used for the internal state variable to indicate
264      * that the shearing components of the matrix (m01 and m10) need
265      * to be factored in to complete the transformation equation of this
266      * transform. The presence of this bit in the state variable changes
267      * the interpretation of the APPLY_SCALE bit as indicated in its
268      * documentation.
269      * @see #APPLY_IDENTITY
270      * @see #APPLY_TRANSLATE
271      * @see #APPLY_SCALE
272      * @see #state
273      */

274     static final int APPLY_SHEAR = 4;
275
276     /*
277      * For methods which combine together the state of two separate
278      * transforms and dispatch based upon the combination, these constants
279      * specify how far to shift one of the states so that the two states
280      * are mutually non-interfering and provide constants for testing the
281      * bits of the shifted (HI) state. The methods in this class use
282      * the convention that the state of "this" transform is unshifted and
283      * the state of the "other" or "argument" transform is shifted (HI).
284      */

285     private static final int HI_SHIFT = 3;
286     private static final int HI_IDENTITY = APPLY_IDENTITY << HI_SHIFT;
287     private static final int HI_TRANSLATE = APPLY_TRANSLATE << HI_SHIFT;
288     private static final int HI_SCALE = APPLY_SCALE << HI_SHIFT;
289     private static final int HI_SHEAR = APPLY_SHEAR << HI_SHIFT;
290
291     /**
292      * The X coordinate scaling element of the 3x3
293      * affine transformation matrix.
294      *
295      * @serial
296      */

297     double m00;
298
299     /**
300      * The Y coordinate shearing element of the 3x3
301      * affine transformation matrix.
302      *
303      * @serial
304      */

305      double m10;
306
307     /**
308      * The X coordinate shearing element of the 3x3
309      * affine transformation matrix.
310      *
311      * @serial
312      */

313      double m01;
314
315     /**
316      * The Y coordinate scaling element of the 3x3
317      * affine transformation matrix.
318      *
319      * @serial
320      */

321      double m11;
322
323     /**
324      * The X coordinate of the translation element of the
325      * 3x3 affine transformation matrix.
326      *
327      * @serial
328      */

329      double m02;
330
331     /**
332      * The Y coordinate of the translation element of the
333      * 3x3 affine transformation matrix.
334      *
335      * @serial
336      */

337      double m12;
338
339     /**
340      * This field keeps track of which components of the matrix need to
341      * be applied when performing a transformation.
342      * @see #APPLY_IDENTITY
343      * @see #APPLY_TRANSLATE
344      * @see #APPLY_SCALE
345      * @see #APPLY_SHEAR
346      */

347     transient int state;
348
349     /**
350      * This field caches the current transformation type of the matrix.
351      * @see #TYPE_IDENTITY
352      * @see #TYPE_TRANSLATION
353      * @see #TYPE_UNIFORM_SCALE
354      * @see #TYPE_GENERAL_SCALE
355      * @see #TYPE_FLIP
356      * @see #TYPE_QUADRANT_ROTATION
357      * @see #TYPE_GENERAL_ROTATION
358      * @see #TYPE_GENERAL_TRANSFORM
359      * @see #TYPE_UNKNOWN
360      * @see #getType
361      */

362     private transient int type;
363
364     private AffineTransform(double m00, double m10,
365                 double m01, double m11,
366                 double m02, double m12,
367                 int state) {
368     this.m00 = m00;
369     this.m10 = m10;
370     this.m01 = m01;
371     this.m11 = m11;
372     this.m02 = m02;
373     this.m12 = m12;
374     this.state = state;
375     this.type = TYPE_UNKNOWN;
376     }
377
378     /**
379      * Constructs a new <code>AffineTransform</code> representing the
380      * Identity transformation.
381      */

382     public AffineTransform() {
383     m00 = m11 = 1.0;
384     // m01 = m10 = m02 = m12 = 0.0; /* Not needed. */
385
// state = APPLY_IDENTITY; /* Not needed. */
386
// type = TYPE_IDENTITY; /* Not needed. */
387
}
388
389     /**
390      * Constructs a new <code>AffineTransform</code> that is a copy of
391      * the specified <code>AffineTransform</code> object.
392      * @param Tx the <code>AffineTransform</code> object to copy
393      */

394     public AffineTransform(AffineTransform JavaDoc Tx) {
395     this.m00 = Tx.m00;
396     this.m10 = Tx.m10;
397     this.m01 = Tx.m01;
398     this.m11 = Tx.m11;
399     this.m02 = Tx.m02;
400     this.m12 = Tx.m12;
401     this.state = Tx.state;
402     this.type = Tx.type;
403     }
404
405     /**
406      * Constructs a new <code>AffineTransform</code> from 6 floating point
407      * values representing the 6 specifiable entries of the 3x3
408      * transformation matrix.
409      * @param m00,&nbsp;m01,&nbsp;m02,&nbsp;m10,&nbsp;m11,&nbsp;m12 the
410      * 6 floating point values that compose the 3x3 transformation matrix
411      */

412     public AffineTransform(float m00, float m10,
413                float m01, float m11,
414                float m02, float m12) {
415     this.m00 = m00;
416     this.m10 = m10;
417     this.m01 = m01;
418     this.m11 = m11;
419     this.m02 = m02;
420     this.m12 = m12;
421     updateState();
422     }
423
424     /**
425      * Constructs a new <code>AffineTransform</code> from an array of
426      * floating point values representing either the 4 non-translation
427      * enries or the 6 specifiable entries of the 3x3 transformation
428      * matrix. The values are retrieved from the array as
429      * {&nbsp;m00&nbsp;m10&nbsp;m01&nbsp;m11&nbsp;[m02&nbsp;m12]}.
430      * @param flatmatrix the float array containing the values to be set
431      * in the new <code>AffineTransform</code> object. The length of the
432      * array is assumed to be at least 4. If the length of the array is
433      * less than 6, only the first 4 values are taken. If the length of
434      * the array is greater than 6, the first 6 values are taken.
435      */

436     public AffineTransform(float[] flatmatrix) {
437     m00 = flatmatrix[0];
438     m10 = flatmatrix[1];
439     m01 = flatmatrix[2];
440     m11 = flatmatrix[3];
441     if (flatmatrix.length > 5) {
442         m02 = flatmatrix[4];
443         m12 = flatmatrix[5];
444     }
445     updateState();
446     }
447
448     /**
449      * Constructs a new <code>AffineTransform</code> from 6 double
450      * precision values representing the 6 specifiable entries of the 3x3
451      * transformation matrix.
452      * @param m00,&nbsp;m01,&nbsp;m02,&nbsp;m10,&nbsp;m11,&nbsp;m12 the
453      * 6 floating point values that compose the 3x3 transformation matrix
454      */

455     public AffineTransform(double m00, double m10,
456                double m01, double m11,
457                double m02, double m12) {
458     this.m00 = m00;
459     this.m10 = m10;
460     this.m01 = m01;
461     this.m11 = m11;
462     this.m02 = m02;
463     this.m12 = m12;
464     updateState();
465     }
466
467     /**
468      * Constructs a new <code>AffineTransform</code> from an array of
469      * double precision values representing either the 4 non-translation
470      * entries or the 6 specifiable entries of the 3x3 transformation
471      * matrix. The values are retrieved from the array as
472      * {&nbsp;m00&nbsp;m10&nbsp;m01&nbsp;m11&nbsp;[m02&nbsp;m12]}.
473      * @param flatmatrix the double array containing the values to be set
474      * in the new <code>AffineTransform</code> object. The length of the
475      * array is assumed to be at least 4. If the length of the array is
476      * less than 6, only the first 4 values are taken. If the length of
477      * the array is greater than 6, the first 6 values are taken.
478      */

479     public AffineTransform(double[] flatmatrix) {
480     m00 = flatmatrix[0];
481     m10 = flatmatrix[1];
482     m01 = flatmatrix[2];
483     m11 = flatmatrix[3];
484     if (flatmatrix.length > 5) {
485         m02 = flatmatrix[4];
486         m12 = flatmatrix[5];
487     }
488     updateState();
489     }
490
491     /**
492      * Returns a transform representing a translation transformation.
493      * The matrix representing the returned transform is:
494      * <pre>
495      * [ 1 0 tx ]
496      * [ 0 1 ty ]
497      * [ 0 0 1 ]
498      * </pre>
499      * @param tx the distance by which coordinates are translated in the
500      * X axis direction
501      * @param ty the distance by which coordinates are translated in the
502      * Y axis direction
503      * @return an <code>AffineTransform</code> object that represents a
504      * translation transformation, created with the specified vector.
505      */

506     public static AffineTransform JavaDoc getTranslateInstance(double tx, double ty) {
507     AffineTransform JavaDoc Tx = new AffineTransform JavaDoc();
508     Tx.setToTranslation(tx, ty);
509     return Tx;
510     }
511
512     /**
513      * Returns a transform representing a rotation transformation.
514      * The matrix representing the returned transform is:
515      * <pre>
516      * [ cos(theta) -sin(theta) 0 ]
517      * [ sin(theta) cos(theta) 0 ]
518      * [ 0 0 1 ]
519      * </pre>
520      * Rotating with a positive angle theta rotates points on the positive
521      * x axis toward the positive y axis.
522      * @param theta the angle of rotation in radians
523      * @return an <code>AffineTransform</code> object that is a rotation
524      * transformation, created with the specified angle of rotation.
525      */

526     public static AffineTransform JavaDoc getRotateInstance(double theta) {
527     AffineTransform JavaDoc Tx = new AffineTransform JavaDoc();
528     Tx.setToRotation(theta);
529     return Tx;
530     }
531
532     /**
533      * Returns a transform that rotates coordinates around an anchor point.
534      * This operation is equivalent to translating the coordinates so
535      * that the anchor point is at the origin (S1), then rotating them
536      * about the new origin (S2), and finally translating so that the
537      * intermediate origin is restored to the coordinates of the original
538      * anchor point (S3).
539      * <p>
540      * This operation is equivalent to the following sequence of calls:
541      * <pre>
542      * AffineTransform Tx = new AffineTransform();
543      * Tx.setToTranslation(x, y); // S3: final translation
544      * Tx.rotate(theta); // S2: rotate around anchor
545      * Tx.translate(-x, -y); // S1: translate anchor to origin
546      * </pre>
547      * The matrix representing the returned transform is:
548      * <pre>
549      * [ cos(theta) -sin(theta) x-x*cos+y*sin ]
550      * [ sin(theta) cos(theta) y-x*sin-y*cos ]
551      * [ 0 0 1 ]
552      * </pre>
553      * Rotating with a positive angle theta rotates points on the positive
554      * x axis toward the positive y axis.
555      * @param theta the angle of rotation in radians
556      * @param x,&nbsp;y the coordinates of the anchor point of the
557      * rotation
558      * @return an <code>AffineTransform</code> object that rotates
559      * coordinates around the specified point by the specified angle of
560      * rotation.
561      */

562     public static AffineTransform JavaDoc getRotateInstance(double theta,
563                             double x, double y) {
564     AffineTransform JavaDoc Tx = new AffineTransform JavaDoc();
565     Tx.setToRotation(theta, x, y);
566     return Tx;
567     }
568
569     /**
570      * Returns a transform representing a scaling transformation.
571      * The matrix representing the returned transform is:
572      * <pre>
573      * [ sx 0 0 ]
574      * [ 0 sy 0 ]
575      * [ 0 0 1 ]
576      * </pre>
577      * @param sx the factor by which coordinates are scaled along the
578      * X axis direction
579      * @param sy the factor by which coordinates are scaled along the
580      * Y axis direction
581      * @return an <code>AffineTransform</code> object that scales
582      * coordinates by the specified factors.
583      */

584     public static AffineTransform JavaDoc getScaleInstance(double sx, double sy) {
585     AffineTransform JavaDoc Tx = new AffineTransform JavaDoc();
586     Tx.setToScale(sx, sy);
587     return Tx;
588     }
589
590     /**
591      * Returns a transform representing a shearing transformation.
592      * The matrix representing the returned transform is:
593      * <pre>
594      * [ 1 shx 0 ]
595      * [ shy 1 0 ]
596      * [ 0 0 1 ]
597      * </pre>
598      * @param shx the multiplier by which coordinates are shifted in the
599      * direction of the positive X axis as a factor of their Y coordinate
600      * @param shy the multiplier by which coordinates are shifted in the
601      * direction of the positive Y axis as a factor of their X coordinate
602      * @return an <code>AffineTransform</code> object that shears
603      * coordinates by the specified multipliers.
604      */

605     public static AffineTransform JavaDoc getShearInstance(double shx, double shy) {
606     AffineTransform JavaDoc Tx = new AffineTransform JavaDoc();
607     Tx.setToShear(shx, shy);
608     return Tx;
609     }
610
611     /**
612      * Retrieves the flag bits describing the conversion properties of
613      * this transform.
614      * The return value is either one of the constants TYPE_IDENTITY
615      * or TYPE_GENERAL_TRANSFORM, or a combination of the
616      * appriopriate flag bits.
617      * A valid combination of flag bits is an exclusive OR operation
618      * that can combine
619      * the TYPE_TRANSLATION flag bit
620      * in addition to either of the
621      * TYPE_UNIFORM_SCALE or TYPE_GENERAL_SCALE flag bits
622      * as well as either of the
623      * TYPE_QUADRANT_ROTATION or TYPE_GENERAL_ROTATION flag bits.
624      * @return the OR combination of any of the indicated flags that
625      * apply to this transform
626      * @see #TYPE_IDENTITY
627      * @see #TYPE_TRANSLATION
628      * @see #TYPE_UNIFORM_SCALE
629      * @see #TYPE_GENERAL_SCALE
630      * @see #TYPE_QUADRANT_ROTATION
631      * @see #TYPE_GENERAL_ROTATION
632      * @see #TYPE_GENERAL_TRANSFORM
633      */

634     public int getType() {
635     if (type == TYPE_UNKNOWN) {
636         calculateType();
637     }
638     return type;
639     }
640
641     /**
642      * This is the utility function to calculate the flag bits when
643      * they have not been cached.
644      * @see #getType
645      */

646     private void calculateType() {
647     int ret = TYPE_IDENTITY;
648     boolean sgn0, sgn1;
649     double M0, M1, M2, M3;
650     updateState();
651     switch (state) {
652     default:
653         stateError();
654         /* NOTREACHED */
655     case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
656         ret = TYPE_TRANSLATION;
657         /* NOBREAK */
658     case (APPLY_SHEAR | APPLY_SCALE):
659         if ((M0 = m00) * (M2 = m01) + (M3 = m10) * (M1 = m11) != 0) {
660         // Transformed unit vectors are not perpendicular...
661
this.type = TYPE_GENERAL_TRANSFORM;
662         return;
663         }
664         sgn0 = (M0 >= 0.0);
665         sgn1 = (M1 >= 0.0);
666         if (sgn0 == sgn1) {
667         // sgn(M0) == sgn(M1) therefore sgn(M2) == -sgn(M3)
668
// This is the "unflipped" (right-handed) state
669
if (M0 != M1 || M2 != -M3) {
670             ret |= (TYPE_GENERAL_ROTATION | TYPE_GENERAL_SCALE);
671         } else if (M0 * M1 - M2 * M3 != 1.0) {
672             ret |= (TYPE_GENERAL_ROTATION | TYPE_UNIFORM_SCALE);
673         } else {
674             ret |= TYPE_GENERAL_ROTATION;
675         }
676         } else {
677         // sgn(M0) == -sgn(M1) therefore sgn(M2) == sgn(M3)
678
// This is the "flipped" (left-handed) state
679
if (M0 != -M1 || M2 != M3) {
680             ret |= (TYPE_GENERAL_ROTATION |
681                 TYPE_FLIP |
682                 TYPE_GENERAL_SCALE);
683         } else if (M0 * M1 - M2 * M3 != 1.0) {
684             ret |= (TYPE_GENERAL_ROTATION |
685                 TYPE_FLIP |
686                 TYPE_UNIFORM_SCALE);
687         } else {
688             ret |= (TYPE_GENERAL_ROTATION | TYPE_FLIP);
689         }
690         }
691         break;
692     case (APPLY_SHEAR | APPLY_TRANSLATE):
693         ret = TYPE_TRANSLATION;
694         /* NOBREAK */
695     case (APPLY_SHEAR):
696         sgn0 = ((M0 = m01) >= 0.0);
697         sgn1 = ((M1 = m10) >= 0.0);
698         if (sgn0 != sgn1) {
699         // Different signs - simple 90 degree rotation
700
if (M0 != -M1) {
701             ret |= (TYPE_QUADRANT_ROTATION | TYPE_GENERAL_SCALE);
702         } else if (M0 != 1.0 && M0 != -1.0) {
703             ret |= (TYPE_QUADRANT_ROTATION | TYPE_UNIFORM_SCALE);
704         } else {
705             ret |= TYPE_QUADRANT_ROTATION;
706         }
707         } else {
708         // Same signs - 90 degree rotation plus an axis flip too
709
if (M0 == M1) {
710             ret |= (TYPE_QUADRANT_ROTATION |
711                 TYPE_FLIP |
712                 TYPE_UNIFORM_SCALE);
713         } else {
714             ret |= (TYPE_QUADRANT_ROTATION |
715                 TYPE_FLIP |
716                 TYPE_GENERAL_SCALE);
717         }
718         }
719         break;
720     case (APPLY_SCALE | APPLY_TRANSLATE):
721         ret = TYPE_TRANSLATION;
722         /* NOBREAK */
723     case (APPLY_SCALE):
724         sgn0 = ((M0 = m00) >= 0.0);
725         sgn1 = ((M1 = m11) >= 0.0);
726         if (sgn0 == sgn1) {
727         if (sgn0) {
728             // Both scaling factors non-negative - simple scale
729
// Note: APPLY_SCALE implies M0, M1 are not both 1
730
if (M0 == M1) {
731             ret |= TYPE_UNIFORM_SCALE;
732             } else {
733             ret |= TYPE_GENERAL_SCALE;
734             }
735         } else {
736             // Both scaling factors negative - 180 degree rotation
737
if (M0 != M1) {
738             ret |= (TYPE_QUADRANT_ROTATION | TYPE_GENERAL_SCALE);
739             } else if (M0 != -1.0) {
740             ret |= (TYPE_QUADRANT_ROTATION | TYPE_UNIFORM_SCALE);
741             } else {
742             ret |= TYPE_QUADRANT_ROTATION;
743             }
744         }
745         } else {
746         // Scaling factor signs different - flip about some axis
747
if (M0 == -M1) {
748             if (M0 == 1.0 || M0 == -1.0) {
749             ret |= TYPE_FLIP;
750             } else {
751             ret |= (TYPE_FLIP | TYPE_UNIFORM_SCALE);
752             }
753         } else {
754             ret |= (TYPE_FLIP | TYPE_GENERAL_SCALE);
755         }
756         }
757         break;
758     case (APPLY_TRANSLATE):
759         ret = TYPE_TRANSLATION;
760         break;
761     case (APPLY_IDENTITY):
762         break;
763     }
764     this.type = ret;
765     }
766
767     /**
768      * Returns the determinant of the matrix representation of the transform.
769      * The determinant is useful both to determine if the transform can
770      * be inverted and to get a single value representing the
771      * combined X and Y scaling of the transform.
772      * <p>
773      * If the determinant is non-zero, then this transform is
774      * invertible and the various methods that depend on the inverse
775      * transform do not need to throw a
776      * {@link NoninvertibleTransformException}.
777      * If the determinant is zero then this transform can not be
778      * inverted since the transform maps all input coordinates onto
779      * a line or a point.
780      * If the determinant is near enough to zero then inverse transform
781      * operations might not carry enough precision to produce meaningful
782      * results.
783      * <p>
784      * If this transform represents a uniform scale, as indicated by
785      * the <code>getType</code> method then the determinant also
786      * represents the square of the uniform scale factor by which all of
787      * the points are expanded from or contracted towards the origin.
788      * If this transform represents a non-uniform scale or more general
789      * transform then the determinant is not likely to represent a
790      * value useful for any purpose other than determining if inverse
791      * transforms are possible.
792      * <p>
793      * Mathematically, the determinant is calculated using the formula:
794      * <pre>
795      * | m00 m01 m02 |
796      * | m10 m11 m12 | = m00 * m11 - m01 * m10
797      * | 0 0 1 |
798      * </pre>
799      *
800      * @return the determinant of the matrix used to transform the
801      * coordinates.
802      * @see #getType
803      * @see #createInverse
804      * @see #inverseTransform
805      * @see #TYPE_UNIFORM_SCALE
806      */

807     public double getDeterminant() {
808     switch (state) {
809     default:
810         stateError();
811         /* NOTREACHED */
812     case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
813     case (APPLY_SHEAR | APPLY_SCALE):
814         return m00 * m11 - m01 * m10;
815     case (APPLY_SHEAR | APPLY_TRANSLATE):
816     case (APPLY_SHEAR):
817         return -(m01 * m10);
818     case (APPLY_SCALE | APPLY_TRANSLATE):
819     case (APPLY_SCALE):
820         return m00 * m11;
821     case (APPLY_TRANSLATE):
822     case (APPLY_IDENTITY):
823         return 1.0;
824     }
825     }
826
827     /**
828      * Manually recalculates the state of the transform when the matrix
829      * changes too much to predict the effects on the state.
830      * The following table specifies what the various settings of the
831      * state field say about the values of the corresponding matrix
832      * element fields.
833      * Note that the rules governing the SCALE fields are slightly
834      * different depending on whether the SHEAR flag is also set.
835      * <pre>
836      * SCALE SHEAR TRANSLATE
837      * m00/m11 m01/m10 m02/m12
838      *
839      * IDENTITY 1.0 0.0 0.0
840      * TRANSLATE (TR) 1.0 0.0 not both 0.0
841      * SCALE (SC) not both 1.0 0.0 0.0
842      * TR | SC not both 1.0 0.0 not both 0.0
843      * SHEAR (SH) 0.0 not both 0.0 0.0
844      * TR | SH 0.0 not both 0.0 not both 0.0
845      * SC | SH not both 0.0 not both 0.0 0.0
846      * TR | SC | SH not both 0.0 not both 0.0 not both 0.0
847      * </pre>
848      */

849     void updateState() {
850     if (m01 == 0.0 && m10 == 0.0) {
851         if (m00 == 1.0 && m11 == 1.0) {
852         if (m02 == 0.0 && m12 == 0.0) {
853             state = APPLY_IDENTITY;
854             type = TYPE_IDENTITY;
855         } else {
856             state = APPLY_TRANSLATE;
857             type = TYPE_TRANSLATION;
858         }
859         } else {
860         if (m02 == 0.0 && m12 == 0.0) {
861             state = APPLY_SCALE;
862             type = TYPE_UNKNOWN;
863         } else {
864             state = (APPLY_SCALE | APPLY_TRANSLATE);
865             type = TYPE_UNKNOWN;
866         }
867         }
868     } else {
869         if (m00 == 0.0 && m11 == 0.0) {
870         if (m02 == 0.0 && m12 == 0.0) {
871             state = APPLY_SHEAR;
872             type = TYPE_UNKNOWN;
873         } else {
874             state = (APPLY_SHEAR | APPLY_TRANSLATE);
875             type = TYPE_UNKNOWN;
876         }
877         } else {
878         if (m02 == 0.0 && m12 == 0.0) {
879             state = (APPLY_SHEAR | APPLY_SCALE);
880             type = TYPE_UNKNOWN;
881         } else {
882             state = (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE);
883             type = TYPE_UNKNOWN;
884         }
885         }
886     }
887     }
888
889     /*
890      * Convenience method used internally to throw exceptions when
891      * a case was forgotten in a switch statement.
892      */

893     private void stateError() {
894     throw new InternalError JavaDoc("missing case in transform state switch");
895     }
896     
897     /**
898      * Retrieves the 6 specifiable values in the 3x3 affine transformation
899      * matrix and places them into an array of double precisions values.
900      * The values are stored in the array as
901      * {&nbsp;m00&nbsp;m10&nbsp;m01&nbsp;m11&nbsp;m02&nbsp;m12&nbsp;}.
902      * An array of 4 doubles can also be specified, in which case only the
903      * first four elements representing the non-transform
904      * parts of the array are retrieved and the values are stored into
905      * the array as {&nbsp;m00&nbsp;m10&nbsp;m01&nbsp;m11&nbsp;}
906      * @param flatmatrix the double array used to store the returned
907      * values.
908      * @see #getScaleX
909      * @see #getScaleY
910      * @see #getShearX
911      * @see #getShearY
912      * @see #getTranslateX
913      * @see #getTranslateY
914      */

915     public void getMatrix(double[] flatmatrix) {
916     flatmatrix[0] = m00;
917     flatmatrix[1] = m10;
918     flatmatrix[2] = m01;
919     flatmatrix[3] = m11;
920     if (flatmatrix.length > 5) {
921         flatmatrix[4] = m02;
922         flatmatrix[5] = m12;
923     }
924     }
925
926     /**
927      * Returns the X coordinate scaling element (m00) of the 3x3
928      * affine transformation matrix.
929      * @return a double value that is the X coordinate of the scaling
930      * element of the affine transformation matrix.
931      * @see #getMatrix
932      */

933     public double getScaleX() {
934     return m00;
935     }
936
937     /**
938      * Returns the Y coordinate scaling element (m11) of the 3x3
939      * affine transformation matrix.
940      * @return a double value that is the Y coordinate of the scaling
941      * element of the affine transformation matrix.
942      * @see #getMatrix
943      */

944     public double getScaleY() {
945     return m11;
946     }
947
948     /**
949      * Returns the X coordinate shearing element (m01) of the 3x3
950      * affine transformation matrix.
951      * @return a double value that is the X coordinate of the shearing
952      * element of the affine transformation matrix.
953      * @see #getMatrix
954      */

955     public double getShearX() {
956     return m01;
957     }
958
959     /**
960      * Returns the Y coordinate shearing element (m10) of the 3x3
961      * affine transformation matrix.
962      * @return a double value that is the Y coordinate of the shearing
963      * element of the affine transformation matrix.
964      * @see #getMatrix
965      */

966     public double getShearY() {
967     return m10;
968     }
969
970     /**
971      * Returns the X coordinate of the translation element (m02) of the
972      * 3x3 affine transformation matrix.
973      * @return a double value that is the X coordinate of the translation
974      * element of the affine transformation matrix.
975      * @see #getMatrix
976      */

977     public double getTranslateX() {
978     return m02;
979     }
980
981     /**
982      * Returns the Y coordinate of the translation element (m12) of the
983      * 3x3 affine transformation matrix.
984      * @return a double value that is the Y coordinate of the translation
985      * element of the affine transformation matrix.
986      * @see #getMatrix
987      */

988     public double getTranslateY() {
989     return m12;
990     }
991
992     /**
993      * Concatenates this transform with a translation transformation.
994      * This is equivalent to calling concatenate(T), where T is an
995      * <code>AffineTransform</code> represented by the following matrix:
996      * <pre>
997      * [ 1 0 tx ]
998      * [ 0 1 ty ]
999      * [ 0 0 1 ]
1000     * </pre>
1001     * @param tx the distance by which coordinates are translated in the
1002     * X axis direction
1003     * @param ty the distance by which coordinates are translated in the
1004     * Y axis direction
1005     */

1006    public void translate(double tx, double ty) {
1007    switch (state) {
1008    default:
1009        stateError();
1010        /* NOTREACHED */
1011    case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1012        m02 = tx * m00 + ty * m01 + m02;
1013        m12 = tx * m10 + ty * m11 + m12;
1014        if (m02 == 0.0 && m12 == 0.0) {
1015        state = APPLY_SHEAR | APPLY_SCALE;
1016        if (type != TYPE_UNKNOWN) {
1017            type -= TYPE_TRANSLATION;
1018        }
1019        }
1020        return;
1021    case (APPLY_SHEAR | APPLY_SCALE):
1022        m02 = tx * m00 + ty * m01;
1023        m12 = tx * m10 + ty * m11;
1024        if (m02 != 0.0 || m12 != 0.0) {
1025        state = APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE;
1026        type |= TYPE_TRANSLATION;
1027        }
1028        return;
1029    case (APPLY_SHEAR | APPLY_TRANSLATE):
1030        m02 = ty * m01 + m02;
1031        m12 = tx * m10 + m12;
1032        if (m02 == 0.0 && m12 == 0.0) {
1033        state = APPLY_SHEAR;
1034        if (type != TYPE_UNKNOWN) {
1035            type -= TYPE_TRANSLATION;
1036        }
1037        }
1038        return;
1039    case (APPLY_SHEAR):
1040        m02 = ty * m01;
1041        m12 = tx * m10;
1042        if (m02 != 0.0 || m12 != 0.0) {
1043        state = APPLY_SHEAR | APPLY_TRANSLATE;
1044        type |= TYPE_TRANSLATION;
1045        }
1046        return;
1047    case (APPLY_SCALE | APPLY_TRANSLATE):
1048        m02 = tx * m00 + m02;
1049        m12 = ty * m11 + m12;
1050        if (m02 == 0.0 && m12 == 0.0) {
1051        state = APPLY_SCALE;
1052        if (type != TYPE_UNKNOWN) {
1053            type -= TYPE_TRANSLATION;
1054        }
1055        }
1056        return;
1057    case (APPLY_SCALE):
1058        m02 = tx * m00;
1059        m12 = ty * m11;
1060        if (m02 != 0.0 || m12 != 0.0) {
1061        state = APPLY_SCALE | APPLY_TRANSLATE;
1062        type |= TYPE_TRANSLATION;
1063        }
1064        return;
1065    case (APPLY_TRANSLATE):
1066        m02 = tx + m02;
1067        m12 = ty + m12;
1068        if (m02 == 0.0 && m12 == 0.0) {
1069        state = APPLY_IDENTITY;
1070        type = TYPE_IDENTITY;
1071        }
1072        return;
1073    case (APPLY_IDENTITY):
1074        m02 = tx;
1075        m12 = ty;
1076        if (tx != 0.0 || ty != 0.0) {
1077        state = APPLY_TRANSLATE;
1078        type = TYPE_TRANSLATION;
1079        }
1080        return;
1081    }
1082    }
1083
1084    /**
1085     * Concatenates this transform with a rotation transformation.
1086     * This is equivalent to calling concatenate(R), where R is an
1087     * <code>AffineTransform</code> represented by the following matrix:
1088     * <pre>
1089     * [ cos(theta) -sin(theta) 0 ]
1090     * [ sin(theta) cos(theta) 0 ]
1091     * [ 0 0 1 ]
1092     * </pre>
1093     * Rotating with a positive angle theta rotates points on the positive
1094     * x axis toward the positive y axis.
1095     * @param theta the angle of rotation in radians
1096     */

1097    public void rotate(double theta) {
1098    double sin = Math.sin(theta);
1099    double cos = Math.cos(theta);
1100    if (Math.abs(sin) < 1E-15) {
1101        if (cos < 0.0) {
1102        m00 = -m00;
1103        m11 = -m11;
1104        int state = this.state;
1105        if ((state & (APPLY_SHEAR)) != 0) {
1106            // If there was a shear, then this rotation has no
1107
// effect on the state.
1108
m01 = -m01;
1109            m10 = -m10;
1110        } else {
1111            // No shear means the SCALE state may toggle when
1112
// m00 and m11 are negated.
1113
if (m00 == 1.0 && m11 == 1.0) {
1114            this.state = state & ~APPLY_SCALE;
1115            } else {
1116            this.state = state | APPLY_SCALE;
1117            }
1118        }
1119        type = TYPE_UNKNOWN;
1120        }
1121        return;
1122    }
1123    if (Math.abs(cos) < 1E-15) {
1124        if (sin < 0.0) {
1125        double M0 = m00;
1126        m00 = -m01;
1127        m01 = M0;
1128        M0 = m10;
1129        m10 = -m11;
1130        m11 = M0;
1131        } else {
1132        double M0 = m00;
1133        m00 = m01;
1134        m01 = -M0;
1135        M0 = m10;
1136        m10 = m11;
1137        m11 = -M0;
1138        }
1139        int state = rot90conversion[this.state];
1140        if ((state & (APPLY_SHEAR | APPLY_SCALE)) == APPLY_SCALE &&
1141        m00 == 1.0 && m11 == 1.0)
1142        {
1143        state -= APPLY_SCALE;
1144        }
1145        this.state = state;
1146        type = TYPE_UNKNOWN;
1147        return;
1148    }
1149    double M0, M1;
1150    M0 = m00;
1151    M1 = m01;
1152    m00 = cos * M0 + sin * M1;
1153    m01 = -sin * M0 + cos * M1;
1154    M0 = m10;
1155    M1 = m11;
1156    m10 = cos * M0 + sin * M1;
1157    m11 = -sin * M0 + cos * M1;
1158    updateState();
1159    }
1160    private static int rot90conversion[] = {
1161    APPLY_SHEAR, APPLY_SHEAR | APPLY_TRANSLATE,
1162    APPLY_SHEAR, APPLY_SHEAR | APPLY_TRANSLATE,
1163    APPLY_SCALE, APPLY_SCALE | APPLY_TRANSLATE,
1164    APPLY_SHEAR | APPLY_SCALE,
1165    APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE,
1166    };
1167
1168    /**
1169     * Concatenates this transform with a transform that rotates
1170     * coordinates around an anchor point.
1171     * This operation is equivalent to translating the coordinates so
1172     * that the anchor point is at the origin (S1), then rotating them
1173     * about the new origin (S2), and finally translating so that the
1174     * intermediate origin is restored to the coordinates of the original
1175     * anchor point (S3).
1176     * <p>
1177     * This operation is equivalent to the following sequence of calls:
1178     * <pre>
1179     * translate(x, y); // S3: final translation
1180     * rotate(theta); // S2: rotate around anchor
1181     * translate(-x, -y); // S1: translate anchor to origin
1182     * </pre>
1183     * Rotating with a positive angle theta rotates points on the positive
1184     * x axis toward the positive y axis.
1185     * @param theta the angle of rotation in radians
1186     * @param x,&nbsp;y the coordinates of the anchor point of the
1187     * rotation
1188     */

1189    public void rotate(double theta, double x, double y) {
1190    // REMIND: Simple for now - optimize later
1191
translate(x, y);
1192    rotate(theta);
1193    translate(-x, -y);
1194    }
1195
1196    /**
1197     * Concatenates this transform with a scaling transformation.
1198     * This is equivalent to calling concatenate(S), where S is an
1199     * <code>AffineTransform</code> represented by the following matrix:
1200     * <pre>
1201     * [ sx 0 0 ]
1202     * [ 0 sy 0 ]
1203     * [ 0 0 1 ]
1204     * </pre>
1205     * @param sx the factor by which coordinates are scaled along the
1206     * X axis direction
1207     * @param sy the factor by which coordinates are scaled along the
1208     * Y axis direction
1209    */

1210    public void scale(double sx, double sy) {
1211    int state = this.state;
1212    switch (state) {
1213    default:
1214        stateError();
1215        /* NOTREACHED */
1216    case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1217    case (APPLY_SHEAR | APPLY_SCALE):
1218        m00 *= sx;
1219        m11 *= sy;
1220        /* NOBREAK */
1221    case (APPLY_SHEAR | APPLY_TRANSLATE):
1222    case (APPLY_SHEAR):
1223        m01 *= sy;
1224        m10 *= sx;
1225        if (m01 == 0 && m10 == 0) {
1226        this.state = state - APPLY_SHEAR;
1227        // REMIND: Is it possible for m00 and m11 to be both 1.0?
1228
}
1229        this.type = TYPE_UNKNOWN;
1230        return;
1231    case (APPLY_SCALE | APPLY_TRANSLATE):
1232    case (APPLY_SCALE):
1233        m00 *= sx;
1234        m11 *= sy;
1235        if (m00 == 1.0 && m11 == 1.0) {
1236        this.state = (state &= APPLY_TRANSLATE);
1237        this.type = (state == APPLY_IDENTITY
1238                 ? TYPE_IDENTITY
1239                 : TYPE_TRANSLATION);
1240        } else {
1241        this.type = TYPE_UNKNOWN;
1242        }
1243        return;
1244    case (APPLY_TRANSLATE):
1245    case (APPLY_IDENTITY):
1246        m00 = sx;
1247        m11 = sy;
1248        if (sx != 1.0 || sy != 1.0) {
1249        this.state = state | APPLY_SCALE;
1250        this.type = TYPE_UNKNOWN;
1251        }
1252        return;
1253    }
1254    }
1255
1256    /**
1257     * Concatenates this transform with a shearing transformation.
1258     * This is equivalent to calling concatenate(SH), where SH is an
1259     * <code>AffineTransform</code> represented by the following matrix:
1260     * <pre>
1261     * [ 1 shx 0 ]
1262     * [ shy 1 0 ]
1263     * [ 0 0 1 ]
1264     * </pre>
1265     * @param shx the multiplier by which coordinates are shifted in the
1266     * direction of the positive X axis as a factor of their Y coordinate
1267     * @param shy the multiplier by which coordinates are shifted in the
1268     * direction of the positive Y axis as a factor of their X coordinate
1269     */

1270    public void shear(double shx, double shy) {
1271    int state = this.state;
1272    switch (state) {
1273    default:
1274        stateError();
1275        /* NOTREACHED */
1276    case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1277    case (APPLY_SHEAR | APPLY_SCALE):
1278        double M0, M1;
1279        M0 = m00;
1280        M1 = m01;
1281        m00 = M0 + M1 * shy;
1282        m01 = M0 * shx + M1;
1283
1284        M0 = m10;
1285        M1 = m11;
1286        m10 = M0 + M1 * shy;
1287        m11 = M0 * shx + M1;
1288        updateState();
1289        return;
1290    case (APPLY_SHEAR | APPLY_TRANSLATE):
1291    case (APPLY_SHEAR):
1292        m00 = m01 * shy;
1293        m11 = m10 * shx;
1294        if (m00 != 0.0 || m11 != 0.0) {
1295        this.state = state | APPLY_SCALE;
1296        }
1297        this.type = TYPE_UNKNOWN;
1298        return;
1299    case (APPLY_SCALE | APPLY_TRANSLATE):
1300    case (APPLY_SCALE):
1301        m01 = m00 * shx;
1302        m10 = m11 * shy;
1303        if (m01 != 0.0 || m10 != 0.0) {
1304        this.state = state | APPLY_SHEAR;
1305        }
1306        this.type = TYPE_UNKNOWN;
1307        return;
1308    case (APPLY_TRANSLATE):
1309    case (APPLY_IDENTITY):
1310        m01 = shx;
1311        m10 = shy;
1312        if (m01 != 0.0 || m10 != 0.0) {
1313        this.state = state | APPLY_SCALE | APPLY_SHEAR;
1314        this.type = TYPE_UNKNOWN;
1315        }
1316        return;
1317    }
1318    }
1319
1320    /**
1321     * Resets this transform to the Identity transform.
1322     */

1323    public void setToIdentity() {
1324    m00 = m11 = 1.0;
1325    m10 = m01 = m02 = m12 = 0.0;
1326    state = APPLY_IDENTITY;
1327    type = TYPE_IDENTITY;
1328    }
1329
1330    /**
1331     * Sets this transform to a translation transformation.
1332     * The matrix representing this transform becomes:
1333     * <pre>
1334     * [ 1 0 tx ]
1335     * [ 0 1 ty ]
1336     * [ 0 0 1 ]
1337     * </pre>
1338     * @param tx the distance by which coordinates are translated in the
1339     * X axis direction
1340     * @param ty the distance by which coordinates are translated in the
1341     * Y axis direction
1342     */

1343    public void setToTranslation(double tx, double ty) {
1344    m00 = 1.0;
1345    m10 = 0.0;
1346    m01 = 0.0;
1347    m11 = 1.0;
1348    m02 = tx;
1349    m12 = ty;
1350    if (tx != 0.0 || ty != 0.0) {
1351        state = APPLY_TRANSLATE;
1352        type = TYPE_TRANSLATION;
1353    } else {
1354        state = APPLY_IDENTITY;
1355        type = TYPE_IDENTITY;
1356    }
1357    }
1358
1359    /**
1360     * Sets this transform to a rotation transformation.
1361     * The matrix representing this transform becomes:
1362     * <pre>
1363     * [ cos(theta) -sin(theta) 0 ]
1364     * [ sin(theta) cos(theta) 0 ]
1365     * [ 0 0 1 ]
1366     * </pre>
1367     * Rotating with a positive angle theta rotates points on the positive
1368     * x axis toward the positive y axis.
1369     * @param theta the angle of rotation in radians
1370     */

1371    public void setToRotation(double theta) {
1372    m02 = 0.0;
1373    m12 = 0.0;
1374    double sin = Math.sin(theta);
1375    double cos = Math.cos(theta);
1376    if (Math.abs(sin) < 1E-15) {
1377        m01 = m10 = 0.0;
1378        if (cos < 0) {
1379        m00 = m11 = -1.0;
1380        state = APPLY_SCALE;
1381        type = TYPE_QUADRANT_ROTATION;
1382        } else {
1383        m00 = m11 = 1.0;
1384        state = APPLY_IDENTITY;
1385        type = TYPE_IDENTITY;
1386        }
1387        return;
1388    }
1389    if (Math.abs(cos) < 1E-15) {
1390        m00 = m11 = 0.0;
1391        if (sin < 0.0) {
1392        m01 = 1.0;
1393        m10 = -1.0;
1394        } else {
1395        m01 = -1.0;
1396        m10 = 1.0;
1397        }
1398        state = APPLY_SHEAR;
1399        type = TYPE_QUADRANT_ROTATION;
1400        return;
1401    }
1402    m00 = cos;
1403    m01 = -sin;
1404    m10 = sin;
1405    m11 = cos;
1406    state = APPLY_SHEAR | APPLY_SCALE;
1407    type = TYPE_GENERAL_ROTATION;
1408    return;
1409    }
1410
1411    /**
1412     * Sets this transform to a translated rotation transformation.
1413     * This operation is equivalent to translating the coordinates so
1414     * that the anchor point is at the origin (S1), then rotating them
1415     * about the new origin (S2), and finally translating so that the
1416     * intermediate origin is restored to the coordinates of the original
1417     * anchor point (S3).
1418     * <p>
1419     * This operation is equivalent to the following sequence of calls:
1420     * <pre>
1421     * setToTranslation(x, y); // S3: final translation
1422     * rotate(theta); // S2: rotate around anchor
1423     * translate(-x, -y); // S1: translate anchor to origin
1424     * </pre>
1425     * The matrix representing this transform becomes:
1426     * <pre>
1427     * [ cos(theta) -sin(theta) x-x*cos+y*sin ]
1428     * [ sin(theta) cos(theta) y-x*sin-y*cos ]
1429     * [ 0 0 1 ]
1430     * </pre>
1431     * Rotating with a positive angle theta rotates points on the positive
1432     * x axis toward the positive y axis.
1433     * @param theta the angle of rotation in radians
1434     * @param x,&nbsp;y the coordinates of the anchor point of the
1435     * rotation
1436     */

1437    public void setToRotation(double theta, double x, double y) {
1438    setToRotation(theta);
1439    double sin = m10;
1440    double oneMinusCos = 1.0 - m00;
1441    m02 = x * oneMinusCos + y * sin;
1442    m12 = y * oneMinusCos - x * sin;
1443    if (m02 != 0.0 || m12 != 0.0) {
1444        state |= APPLY_TRANSLATE;
1445        type |= TYPE_TRANSLATION;
1446    }
1447    return;
1448    }
1449
1450    /**
1451     * Sets this transform to a scaling transformation.
1452     * The matrix representing this transform becomes:
1453     * <pre>
1454     * [ sx 0 0 ]
1455     * [ 0 sy 0 ]
1456     * [ 0 0 1 ]
1457     * </pre>
1458     * @param sx the factor by which coordinates are scaled along the
1459     * X axis direction
1460     * @param sy the factor by which coordinates are scaled along the
1461     * Y axis direction
1462     */

1463    public void setToScale(double sx, double sy) {
1464    m00 = sx;
1465    m10 = 0.0;
1466    m01 = 0.0;
1467    m11 = sy;
1468    m02 = 0.0;
1469    m12 = 0.0;
1470    if (sx != 1.0 || sy != 1.0) {
1471        state = APPLY_SCALE;
1472        type = TYPE_UNKNOWN;
1473    } else {
1474        state = APPLY_IDENTITY;
1475        type = TYPE_IDENTITY;
1476    }
1477    }
1478
1479    /**
1480     * Sets this transform to a shearing transformation.
1481     * The matrix representing this transform becomes:
1482     * <pre>
1483     * [ 1 shx 0 ]
1484     * [ shy 1 0 ]
1485     * [ 0 0 1 ]
1486     * </pre>
1487     * @param shx the multiplier by which coordinates are shifted in the
1488     * direction of the positive X axis as a factor of their Y coordinate
1489     * @param shy the multiplier by which coordinates are shifted in the
1490     * direction of the positive Y axis as a factor of their X coordinate
1491     */

1492    public void setToShear(double shx, double shy) {
1493    m00 = 1.0;
1494    m01 = shx;
1495    m10 = shy;
1496    m11 = 1.0;
1497    m02 = 0.0;
1498    m12 = 0.0;
1499    if (shx != 0.0 || shy != 0.0) {
1500        state = (APPLY_SHEAR | APPLY_SCALE);
1501        type = TYPE_UNKNOWN;
1502    } else {
1503        state = APPLY_IDENTITY;
1504        type = TYPE_IDENTITY;
1505    }
1506    }
1507
1508    /**
1509     * Sets this transform to a copy of the transform in the specified
1510     * <code>AffineTransform</code> object.
1511     * @param Tx the <code>AffineTransform</code> object from which to
1512     * copy the transform
1513     */

1514    public void setTransform(AffineTransform JavaDoc Tx) {
1515    this.m00 = Tx.m00;
1516    this.m10 = Tx.m10;
1517    this.m01 = Tx.m01;
1518    this.m11 = Tx.m11;
1519    this.m02 = Tx.m02;
1520    this.m12 = Tx.m12;
1521    this.state = Tx.state;
1522    this.type = Tx.type;
1523    }
1524
1525    /**
1526     * Sets this transform to the matrix specified by the 6
1527     * double precision values.
1528     * @param m00,&nbsp;m01,&nbsp;m02,&nbsp;m10,&nbsp;m11,&nbsp;m12 the
1529     * 6 floating point values that compose the 3x3 transformation matrix
1530     */

1531    public void setTransform(double m00, double m10,
1532                 double m01, double m11,
1533                 double m02, double m12) {
1534    this.m00 = m00;
1535    this.m10 = m10;
1536    this.m01 = m01;
1537    this.m11 = m11;
1538    this.m02 = m02;
1539    this.m12 = m12;
1540    updateState();
1541    }
1542
1543    /**
1544     * Concatenates an <code>AffineTransform</code> <code>Tx</code> to
1545     * this <code>AffineTransform</code> Cx in the most commonly useful
1546     * way to provide a new user space
1547     * that is mapped to the former user space by <code>Tx</code>.
1548     * Cx is updated to perform the combined transformation.
1549     * Transforming a point p by the updated transform Cx' is
1550     * equivalent to first transforming p by <code>Tx</code> and then
1551     * transforming the result by the original transform Cx like this:
1552     * Cx'(p) = Cx(Tx(p))
1553     * In matrix notation, if this transform Cx is
1554     * represented by the matrix [this] and <code>Tx</code> is represented
1555     * by the matrix [Tx] then this method does the following:
1556     * <pre>
1557     * [this] = [this] x [Tx]
1558     * </pre>
1559     * @param Tx the <code>AffineTransform</code> object to be
1560     * concatenated with this <code>AffineTransform</code> object.
1561     * @see #preConcatenate
1562     */

1563    public void concatenate(AffineTransform JavaDoc Tx) {
1564        double M0, M1;
1565    double T00, T01, T10, T11;
1566    double T02, T12;
1567    int mystate = state;
1568    int txstate = Tx.state;
1569    switch ((txstate << HI_SHIFT) | mystate) {
1570
1571        /* ---------- Tx == IDENTITY cases ---------- */
1572    case (HI_IDENTITY | APPLY_IDENTITY):
1573    case (HI_IDENTITY | APPLY_TRANSLATE):
1574    case (HI_IDENTITY | APPLY_SCALE):
1575    case (HI_IDENTITY | APPLY_SCALE | APPLY_TRANSLATE):
1576    case (HI_IDENTITY | APPLY_SHEAR):
1577    case (HI_IDENTITY | APPLY_SHEAR | APPLY_TRANSLATE):
1578    case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE):
1579    case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1580        return;
1581
1582        /* ---------- this == IDENTITY cases ---------- */
1583    case (HI_SHEAR | HI_SCALE | HI_TRANSLATE | APPLY_IDENTITY):
1584        m01 = Tx.m01;
1585        m10 = Tx.m10;
1586        /* NOBREAK */
1587    case (HI_SCALE | HI_TRANSLATE | APPLY_IDENTITY):
1588        m00 = Tx.m00;
1589        m11 = Tx.m11;
1590        /* NOBREAK */
1591    case (HI_TRANSLATE | APPLY_IDENTITY):
1592        m02 = Tx.m02;
1593        m12 = Tx.m12;
1594        state = txstate;
1595        type = Tx.type;
1596        return;
1597    case (HI_SHEAR | HI_SCALE | APPLY_IDENTITY):
1598        m01 = Tx.m01;
1599        m10 = Tx.m10;
1600        /* NOBREAK */
1601    case (HI_SCALE | APPLY_IDENTITY):
1602        m00 = Tx.m00;
1603        m11 = Tx.m11;
1604        state = txstate;
1605        type = Tx.type;
1606        return;
1607    case (HI_SHEAR | HI_TRANSLATE | APPLY_IDENTITY):
1608        m02 = Tx.m02;
1609        m12 = Tx.m12;
1610        /* NOBREAK */
1611    case (HI_SHEAR | APPLY_IDENTITY):
1612        m01 = Tx.m01;
1613        m10 = Tx.m10;
1614            m00 = m11 = 0.0;
1615        state = txstate;
1616        type = Tx.type;
1617        return;
1618
1619        /* ---------- Tx == TRANSLATE cases ---------- */
1620    case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1621    case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE):
1622    case (HI_TRANSLATE | APPLY_SHEAR | APPLY_TRANSLATE):
1623    case (HI_TRANSLATE | APPLY_SHEAR):
1624    case (HI_TRANSLATE | APPLY_SCALE | APPLY_TRANSLATE):
1625    case (HI_TRANSLATE | APPLY_SCALE):
1626    case (HI_TRANSLATE | APPLY_TRANSLATE):
1627        translate(Tx.m02, Tx.m12);
1628        return;
1629
1630        /* ---------- Tx == SCALE cases ---------- */
1631    case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1632    case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE):
1633    case (HI_SCALE | APPLY_SHEAR | APPLY_TRANSLATE):
1634    case (HI_SCALE | APPLY_SHEAR):
1635    case (HI_SCALE | APPLY_SCALE | APPLY_TRANSLATE):
1636    case (HI_SCALE | APPLY_SCALE):
1637    case (HI_SCALE | APPLY_TRANSLATE):
1638        scale(Tx.m00, Tx.m11);
1639        return;
1640
1641        /* ---------- Tx == SHEAR cases ---------- */
1642    case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1643    case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE):
1644        T01 = Tx.m01; T10 = Tx.m10;
1645        M0 = m00;
1646        m00 = m01 * T10;
1647        m01 = M0 * T01;
1648        M0 = m10;
1649        m10 = m11 * T10;
1650        m11 = M0 * T01;
1651        type = TYPE_UNKNOWN;
1652        return;
1653    case (HI_SHEAR | APPLY_SHEAR | APPLY_TRANSLATE):
1654    case (HI_SHEAR | APPLY_SHEAR):
1655        m00 = m01 * Tx.m10;
1656        m01 = 0.0;
1657        m11 = m10 * Tx.m01;
1658        m10 = 0.0;
1659        state = mystate ^ (APPLY_SHEAR | APPLY_SCALE);
1660        type = TYPE_UNKNOWN;
1661        return;
1662    case (HI_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1663    case (HI_SHEAR | APPLY_SCALE):
1664        m01 = m00 * Tx.m01;
1665        m00 = 0.0;
1666        m10 = m11 * Tx.m10;
1667        m11 = 0.0;
1668        state = mystate ^ (APPLY_SHEAR | APPLY_SCALE);
1669        type = TYPE_UNKNOWN;
1670        return;
1671    case (HI_SHEAR | APPLY_TRANSLATE):
1672        m00 = 0.0;
1673        m01 = Tx.m01;
1674        m10 = Tx.m10;
1675        m11 = 0.0;
1676        state = APPLY_TRANSLATE | APPLY_SHEAR;
1677        type = TYPE_UNKNOWN;
1678        return;
1679    }
1680    // If Tx has more than one attribute, it is not worth optimizing
1681
// all of those cases...
1682
T00 = Tx.m00; T01 = Tx.m01; T02 = Tx.m02;
1683    T10 = Tx.m10; T11 = Tx.m11; T12 = Tx.m12;
1684    switch (mystate) {
1685    default:
1686        stateError();
1687        /* NOTREACHED */
1688    case (APPLY_SHEAR | APPLY_SCALE):
1689        state = mystate | txstate;
1690        /* NOBREAK */
1691    case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1692        M0 = m00;
1693        M1 = m01;
1694        m00 = T00 * M0 + T10 * M1;
1695        m01 = T01 * M0 + T11 * M1;
1696        m02 += T02 * M0 + T12 * M1;
1697
1698        M0 = m10;
1699        M1 = m11;
1700        m10 = T00 * M0 + T10 * M1;
1701        m11 = T01 * M0 + T11 * M1;
1702        m12 += T02 * M0 + T12 * M1;
1703        type = TYPE_UNKNOWN;
1704        return;
1705
1706    case (APPLY_SHEAR | APPLY_TRANSLATE):
1707    case (APPLY_SHEAR):
1708        M0 = m01;
1709        m00 = T10 * M0;
1710        m01 = T11 * M0;
1711        m02 += T12 * M0;
1712
1713        M0 = m10;
1714        m10 = T00 * M0;
1715        m11 = T01 * M0;
1716        m12 += T02 * M0;
1717        break;
1718
1719    case (APPLY_SCALE | APPLY_TRANSLATE):
1720    case (APPLY_SCALE):
1721        M0 = m00;
1722        m00 = T00 * M0;
1723        m01 = T01 * M0;
1724        m02 += T02 * M0;
1725
1726        M0 = m11;
1727        m10 = T10 * M0;
1728        m11 = T11 * M0;
1729        m12 += T12 * M0;
1730        break;
1731
1732    case (APPLY_TRANSLATE):
1733        m00 = T00;
1734        m01 = T01;
1735        m02 += T02;
1736
1737        m10 = T10;
1738        m11 = T11;
1739        m12 += T12;
1740        state = txstate | APPLY_TRANSLATE;
1741        type = TYPE_UNKNOWN;
1742        return;
1743    }
1744    updateState();
1745    }
1746
1747    /**
1748     * Concatenates an <code>AffineTransform</code> <code>Tx</code> to
1749     * this <code>AffineTransform</code> Cx
1750     * in a less commonly used way such that <code>Tx</code> modifies the
1751     * coordinate transformation relative to the absolute pixel
1752     * space rather than relative to the existing user space.
1753     * Cx is updated to perform the combined transformation.
1754     * Transforming a point p by the updated transform Cx' is
1755     * equivalent to first transforming p by the original transform
1756     * Cx and then transforming the result by
1757     * <code>Tx</code> like this:
1758     * Cx'(p) = Tx(Cx(p))
1759     * In matrix notation, if this transform Cx
1760     * is represented by the matrix [this] and <code>Tx</code> is
1761     * represented by the matrix [Tx] then this method does the
1762     * following:
1763     * <pre>
1764     * [this] = [Tx] x [this]
1765     * </pre>
1766     * @param Tx the <code>AffineTransform</code> object to be
1767     * concatenated with this <code>AffineTransform</code> object.
1768     * @see #concatenate
1769     */

1770    public void preConcatenate(AffineTransform JavaDoc Tx) {
1771    double M0, M1;
1772    double T00, T01, T10, T11;
1773    double T02, T12;
1774    int mystate = state;
1775    int txstate = Tx.state;
1776    switch ((txstate << HI_SHIFT) | mystate) {
1777    case (HI_IDENTITY | APPLY_IDENTITY):
1778    case (HI_IDENTITY | APPLY_TRANSLATE):
1779    case (HI_IDENTITY | APPLY_SCALE):
1780    case (HI_IDENTITY | APPLY_SCALE | APPLY_TRANSLATE):
1781    case (HI_IDENTITY | APPLY_SHEAR):
1782    case (HI_IDENTITY | APPLY_SHEAR | APPLY_TRANSLATE):
1783    case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE):
1784    case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1785        // Tx is IDENTITY...
1786
return;
1787
1788    case (HI_TRANSLATE | APPLY_IDENTITY):
1789    case (HI_TRANSLATE | APPLY_SCALE):
1790    case (HI_TRANSLATE | APPLY_SHEAR):
1791    case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE):
1792        // Tx is TRANSLATE, this has no TRANSLATE
1793
m02 = Tx.m02;
1794        m12 = Tx.m12;
1795        state = mystate | APPLY_TRANSLATE;
1796        type |= TYPE_TRANSLATION;
1797        return;
1798
1799    case (HI_TRANSLATE | APPLY_TRANSLATE):
1800    case (HI_TRANSLATE | APPLY_SCALE | APPLY_TRANSLATE):
1801    case (HI_TRANSLATE | APPLY_SHEAR | APPLY_TRANSLATE):
1802    case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1803        // Tx is TRANSLATE, this has one too
1804
m02 = m02 + Tx.m02;
1805        m12 = m12 + Tx.m12;
1806        return;
1807
1808    case (HI_SCALE | APPLY_TRANSLATE):
1809    case (HI_SCALE | APPLY_IDENTITY):
1810        // Only these two existing states need a new state
1811
state = mystate | APPLY_SCALE;
1812        /* NOBREAK */
1813    case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1814    case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE):
1815    case (HI_SCALE | APPLY_SHEAR | APPLY_TRANSLATE):
1816    case (HI_SCALE | APPLY_SHEAR):
1817    case (HI_SCALE | APPLY_SCALE | APPLY_TRANSLATE):
1818    case (HI_SCALE | APPLY_SCALE):
1819        // Tx is SCALE, this is anything
1820
T00 = Tx.m00;
1821        T11 = Tx.m11;
1822        if ((mystate & APPLY_SHEAR) != 0) {
1823        m01 = m01 * T00;
1824        m10 = m10 * T11;
1825        if ((mystate & APPLY_SCALE) != 0) {
1826            m00 = m00 * T00;
1827            m11 = m11 * T11;
1828        }
1829        } else {
1830        m00 = m00 * T00;
1831        m11 = m11 * T11;
1832        }
1833        if ((mystate & APPLY_TRANSLATE) != 0) {
1834        m02 = m02 * T00;
1835        m12 = m12 * T11;
1836        }
1837        type = TYPE_UNKNOWN;
1838        return;
1839    case (HI_SHEAR | APPLY_SHEAR | APPLY_TRANSLATE):
1840    case (HI_SHEAR | APPLY_SHEAR):
1841        mystate = mystate | APPLY_SCALE;
1842        /* NOBREAK */
1843    case (HI_SHEAR | APPLY_TRANSLATE):
1844    case (HI_SHEAR | APPLY_IDENTITY):
1845    case (HI_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1846    case (HI_SHEAR | APPLY_SCALE):
1847        state = mystate ^ APPLY_SHEAR;
1848        /* NOBREAK */
1849    case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1850    case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE):
1851        // Tx is SHEAR, this is anything
1852
T01 = Tx.m01;
1853        T10 = Tx.m10;
1854
1855        M0 = m00;
1856        m00 = m10 * T01;
1857        m10 = M0 * T10;
1858
1859        M0 = m01;
1860        m01 = m11 * T01;
1861        m11 = M0 * T10;
1862
1863        M0 = m02;
1864        m02 = m12 * T01;
1865        m12 = M0 * T10;
1866        type = TYPE_UNKNOWN;
1867        return;
1868    }
1869    // If Tx has more than one attribute, it is not worth optimizing
1870
// all of those cases...
1871
T00 = Tx.m00; T01 = Tx.m01; T02 = Tx.m02;
1872    T10 = Tx.m10; T11 = Tx.m11; T12 = Tx.m12;
1873    switch (mystate) {
1874    default:
1875        stateError();
1876        /* NOTREACHED */
1877    case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1878        M0 = m02;
1879        M1 = m12;
1880        T02 += M0 * T00 + M1 * T01;
1881        T12 += M0 * T10 + M1 * T11;
1882
1883        /* NOBREAK */
1884    case (APPLY_SHEAR | APPLY_SCALE):
1885        m02 = T02;
1886        m12 = T12;
1887
1888        M0 = m00;
1889        M1 = m10;
1890        m00 = M0 * T00 + M1 * T01;
1891        m10 = M0 * T10 + M1 * T11;
1892
1893        M0 = m01;
1894        M1 = m11;
1895        m01 = M0 * T00 + M1 * T01;
1896        m11 = M0 * T10 + M1 * T11;
1897        break;
1898
1899    case (APPLY_SHEAR | APPLY_TRANSLATE):
1900        M0 = m02;
1901        M1 = m12;
1902        T02 += M0 * T00 + M1 * T01;
1903        T12 += M0 * T10 + M1 * T11;
1904
1905        /* NOBREAK */
1906    case (APPLY_SHEAR):
1907        m02 = T02;
1908        m12 = T12;
1909
1910        M0 = m10;
1911        m00 = M0 * T01;
1912        m10 = M0 * T11;
1913
1914        M0 = m01;
1915        m01 = M0 * T00;
1916        m11 = M0 * T10;
1917        break;
1918
1919    case (APPLY_SCALE | APPLY_TRANSLATE):
1920        M0 = m02;
1921        M1 = m12;
1922        T02 += M0 * T00 + M1 * T01;
1923        T12 += M0 * T10 + M1 * T11;
1924
1925        /* NOBREAK */
1926    case (APPLY_SCALE):
1927        m02 = T02;
1928        m12 = T12;
1929
1930        M0 = m00;
1931        m00 = M0 * T00;
1932        m10 = M0 * T10;
1933
1934        M0 = m11;
1935        m01 = M0 * T01;
1936        m11 = M0 * T11;
1937        break;
1938
1939    case (APPLY_TRANSLATE):
1940        M0 = m02;
1941        M1 = m12;
1942        T02 += M0 * T00 + M1 * T01;
1943        T12 += M0 * T10 + M1 * T11;
1944
1945        /* NOBREAK */
1946    case (APPLY_IDENTITY):
1947        m02 = T02;
1948        m12 = T12;
1949
1950        m00 = T00;
1951        m10 = T10;
1952
1953        m01 = T01;
1954        m11 = T11;
1955
1956        state = mystate | txstate;
1957        type = TYPE_UNKNOWN;
1958        return;
1959    }
1960    updateState();
1961    }
1962
1963    /**
1964     * Returns an <code>AffineTransform</code> object representing the
1965     * inverse transformation.
1966     * The inverse transform Tx' of this transform Tx
1967     * maps coordinates transformed by Tx back
1968     * to their original coordinates.
1969     * In other words, Tx'(Tx(p)) = p = Tx(Tx'(p)).
1970     * <p>
1971     * If this transform maps all coordinates onto a point or a line
1972     * then it will not have an inverse, since coordinates that do
1973     * not lie on the destination point or line will not have an inverse
1974     * mapping.
1975     * The <code>getDeterminant</code> method can be used to determine if this
1976     * transform has no inverse, in which case an exception will be
1977     * thrown if the <code>createInverse</code> method is called.
1978     * @return a new <code>AffineTransform</code> object representing the
1979     * inverse transformation.
1980     * @see #getDeterminant
1981     * @exception NoninvertibleTransformException
1982     * if the matrix cannot be inverted.
1983     */

1984    public AffineTransform JavaDoc createInverse()
1985    throws NoninvertibleTransformException JavaDoc
1986    {
1987    double det;
1988    switch (state) {
1989    default:
1990        stateError();
1991        /* NOTREACHED */
1992    case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1993        det = m00 * m11 - m01 * m10;
1994        if (Math.abs(det) <= Double.MIN_VALUE) {
1995        throw new NoninvertibleTransformException JavaDoc("Determinant is "+
1996                              det);
1997        }
1998        return new AffineTransform JavaDoc( m11 / det, -m10 / det,
1999                       -m01 / det, m00 / det,
2000                       (m01 * m12 - m11 * m02) / det,
2001                       (m10 * m02 - m00 * m12) / det,
2002                       (APPLY_SHEAR |
2003                    APPLY_SCALE |
2004                    APPLY_TRANSLATE));
2005    case (APPLY_SHEAR | APPLY_SCALE):
2006        det = m00 * m11 - m01 * m10;
2007        if (Math.abs(det) <= Double.MIN_VALUE) {
2008        throw new NoninvertibleTransformException JavaDoc("Determinant is "+
2009                              det);
2010        }
2011        return new AffineTransform JavaDoc( m11 / det, -m10 / det,
2012                       -m01 / det, m00 / det,
2013                        0.0, 0.0,
2014                       (APPLY_SHEAR | APPLY_SCALE));
2015    case (APPLY_SHEAR | APPLY_TRANSLATE):
2016        if (m01 == 0.0 || m10 == 0.0) {
2017        throw new NoninvertibleTransformException JavaDoc("Determinant is 0");
2018        }
2019        return new AffineTransform JavaDoc( 0.0, 1.0 / m01,
2020                        1.0 / m10, 0.0,
2021                       -m12 / m10, -m02 / m01,
2022                       (APPLY_SHEAR | APPLY_TRANSLATE));
2023    case (APPLY_SHEAR):
2024        if (m01 == 0.0 || m10 == 0.0) {
2025        throw new NoninvertibleTransformException JavaDoc("Determinant is 0");
2026        }
2027        return new AffineTransform JavaDoc(0.0, 1.0 / m01,
2028                       1.0 / m10, 0.0,
2029                       0.0, 0.0,
2030                       (APPLY_SHEAR));
2031    case (APPLY_SCALE | APPLY_TRANSLATE):
2032        if (m00 == 0.0 || m11 == 0.0) {
2033        throw new NoninvertibleTransformException JavaDoc("Determinant is 0");
2034        }
2035        return new AffineTransform JavaDoc( 1.0 / m00, 0.0,
2036                        0.0, 1.0 / m11,
2037                       -m02 / m00, -m12 / m11,
2038                       (APPLY_SCALE | APPLY_TRANSLATE));
2039    case (APPLY_SCALE):
2040        if (m00 == 0.0 || m11 == 0.0) {
2041        throw new NoninvertibleTransformException JavaDoc("Determinant is 0");
2042        }
2043        return new AffineTransform JavaDoc(1.0 / m00, 0.0,
2044                       0.0, 1.0 / m11,
2045                       0.0, 0.0,
2046                       (APPLY_SCALE));
2047    case (APPLY_TRANSLATE):
2048        return new AffineTransform JavaDoc( 1.0, 0.0,
2049                        0.0, 1.0,
2050                       -m02, -m12,
2051                       (APPLY_TRANSLATE));
2052    case (APPLY_IDENTITY):
2053        return new AffineTransform JavaDoc();
2054    }
2055
2056    /* NOTREACHED */
2057    }
2058
2059    /**
2060     * Transforms the specified <code>ptSrc</code> and stores the result
2061     * in <code>ptDst</code>.
2062     * If <code>ptDst</code> is <code>null</code>, a new {@link Point2D}
2063     * object is allocated and then the result of the transformation is
2064     * stored in this object.
2065     * In either case, <code>ptDst</code>, which contains the
2066     * transformed point, is returned for convenience.
2067     * If <code>ptSrc</code> and <code>ptDst</code> are the same
2068     * object, the input point is correctly overwritten with
2069     * the transformed point.
2070     * @param ptSrc the specified <code>Point2D</code> to be transformed
2071     * @param ptDst the specified <code>Point2D</code> that stores the
2072     * result of transforming <code>ptSrc</code>
2073     * @return the <code>ptDst</code> after transforming
2074     * <code>ptSrc</code> and stroring the result in <code>ptDst</code>.
2075     */

2076    public Point2D JavaDoc transform(Point2D JavaDoc ptSrc, Point2D JavaDoc ptDst) {
2077    if (ptDst == null) {
2078        if (ptSrc instanceof Point2D.Double JavaDoc) {
2079        ptDst = new Point2D.Double JavaDoc();
2080        } else {
2081        ptDst = new Point2D.Float JavaDoc();
2082        }
2083    }
2084    // Copy source coords into local variables in case src == dst
2085
double x = ptSrc.getX();
2086    double y = ptSrc.getY();
2087    switch (state) {
2088    default:
2089        stateError();
2090        /* NOTREACHED */
2091    case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2092        ptDst.setLocation(x * m00 + y * m01 + m02,
2093                  x * m10 + y * m11 + m12);
2094        return ptDst;
2095    case (APPLY_SHEAR | APPLY_SCALE):
2096        ptDst.setLocation(x * m00 + y * m01, x * m10 + y * m11);
2097        return ptDst;
2098    case (APPLY_SHEAR | APPLY_TRANSLATE):
2099        ptDst.setLocation(y * m01 + m02, x * m10 + m12);
2100        return ptDst;
2101    case (APPLY_SHEAR):
2102        ptDst.setLocation(y * m01, x * m10);
2103        return ptDst;
2104    case (APPLY_SCALE | APPLY_TRANSLATE):
2105        ptDst.setLocation(x * m00 + m02, y * m11 + m12);
2106        return ptDst;
2107    case (APPLY_SCALE):
2108        ptDst.setLocation(x * m00, y * m11);
2109        return ptDst;
2110    case (APPLY_TRANSLATE):
2111        ptDst.setLocation(x + m02, y + m12);
2112        return ptDst;
2113    case (APPLY_IDENTITY):
2114        ptDst.setLocation(x, y);
2115        return ptDst;
2116    }
2117
2118    /* NOTREACHED */
2119    }
2120
2121    /**
2122     * Transforms an array of point objects by this transform.
2123     * If any element of the <code>ptDst</code> array is
2124     * <code>null</code>, a new <code>Point2D</code> object is allocated
2125     * and stored into that element before storing the results of the
2126     * transformation.
2127     * <p>
2128     * Note that this method does not take any precautions to
2129     * avoid problems caused by storing results into <code>Point2D</code>
2130     * objects that will be used as the source for calculations
2131     * further down the source array.
2132     * This method does guarantee that if a specified <code>Point2D</code>
2133     * object is both the source and destination for the same single point
2134     * transform operation then the results will not be stored until
2135     * the calculations are complete to avoid storing the results on
2136     * top of the operands.
2137     * If, however, the destination <code>Point2D</code> object for one
2138     * operation is the same object as the source <code>Point2D</code>
2139     * object for another operation further down the source array then
2140     * the original coordinates in that point are overwritten before
2141     * they can be converted.
2142     * @param ptSrc the array containing the source point objects
2143     * @param ptDst the array into which the transform point objects are
2144     * returned
2145     * @param srcOff the offset to the first point object to be
2146     * transformed in the source array
2147     * @param dstOff the offset to the location of the first
2148     * transformed point object that is stored in the destination array
2149     * @param numPts the number of point objects to be transformed
2150     */

2151    public void transform(Point2D JavaDoc[] ptSrc, int srcOff,
2152              Point2D JavaDoc[] ptDst, int dstOff,
2153              int numPts) {
2154    int state = this.state;
2155        while (--numPts >= 0) {
2156            // Copy source coords into local variables in case src == dst
2157
Point2D JavaDoc src = ptSrc[srcOff++];
2158            double x = src.getX();
2159            double y = src.getY();
2160        Point2D JavaDoc dst = ptDst[dstOff++];
2161        if (dst == null) {
2162        if (src instanceof Point2D.Double JavaDoc) {
2163            dst = new Point2D.Double JavaDoc();
2164        } else {
2165            dst = new Point2D.Float JavaDoc();
2166        }
2167        ptDst[dstOff - 1] = dst;
2168        }
2169        switch (state) {
2170        default:
2171        stateError();
2172        /* NOTREACHED */
2173        case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2174        dst.setLocation(x * m00 + y * m01 + m02,
2175                x * m10 + y * m11 + m12);
2176        break;
2177        case (APPLY_SHEAR | APPLY_SCALE):
2178        dst.setLocation(x * m00 + y * m01, x * m10 + y * m11);
2179        break;
2180        case (APPLY_SHEAR | APPLY_TRANSLATE):
2181        dst.setLocation(y * m01 + m02, x * m10 + m12);
2182        break;
2183        case (APPLY_SHEAR):
2184        dst.setLocation(y * m01, x * m10);
2185        break;
2186        case (APPLY_SCALE | APPLY_TRANSLATE):
2187        dst.setLocation(x * m00 + m02, y * m11 + m12);
2188        break;
2189        case (APPLY_SCALE):
2190        dst.setLocation(x * m00, y * m11);
2191        break;
2192        case (APPLY_TRANSLATE):
2193        dst.setLocation(x + m02, y + m12);
2194        break;
2195        case (APPLY_IDENTITY):
2196        dst.setLocation(x, y);
2197        break;
2198        }
2199    }
2200
2201    /* NOTREACHED */
2202    }
2203
2204    /**
2205     * Transforms an array of floating point coordinates by this transform.
2206     * The two coordinate array sections can be exactly the same or
2207     * can be overlapping sections of the same array without affecting the
2208     * validity of the results.
2209     * This method ensures that no source coordinates are overwritten by a
2210     * previous operation before they can be transformed.
2211     * The coordinates are stored in the arrays starting at the specified
2212     * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
2213     * @param srcPts the array containing the source point coordinates.
2214     * Each point is stored as a pair of x,&nbsp;y coordinates.
2215     * @param dstPts the array into which the transformed point coordinates
2216     * are returned. Each point is stored as a pair of x,&nbsp;y
2217     * coordinates.
2218     * @param srcOff the offset to the first point to be transformed
2219     * in the source array
2220     * @param dstOff the offset to the location of the first
2221     * transformed point that is stored in the destination array
2222     * @param numPts the number of points to be transformed
2223     */

2224    public void transform(float[] srcPts, int srcOff,
2225              float[] dstPts, int dstOff,
2226              int numPts) {
2227    double M00, M01, M02, M10, M11, M12; // For caching
2228
if (dstPts == srcPts &&
2229        dstOff > srcOff && dstOff < srcOff + numPts * 2)
2230    {
2231        // If the arrays overlap partially with the destination higher
2232
// than the source and we transform the coordinates normally
2233
// we would overwrite some of the later source coordinates
2234
// with results of previous transformations.
2235
// To get around this we use arraycopy to copy the points
2236
// to their final destination with correct overwrite
2237
// handling and then transform them in place in the new
2238
// safer location.
2239
System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts * 2);
2240        // srcPts = dstPts; // They are known to be equal.
2241
srcOff = dstOff;
2242    }
2243    switch (state) {
2244    default:
2245        stateError();
2246        /* NOTREACHED */
2247    case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2248        M00 = m00; M01 = m01; M02 = m02;
2249        M10 = m10; M11 = m11; M12 = m12;
2250        while (--numPts >= 0) {
2251        double x = srcPts[srcOff++];
2252        double y = srcPts[srcOff++];
2253        dstPts[dstOff++] = (float) (M00 * x + M01 * y + M02);
2254        dstPts[dstOff++] = (float) (M10 * x + M11 * y + M12);
2255        }
2256        return;
2257    case (APPLY_SHEAR | APPLY_SCALE):
2258        M00 = m00; M01 = m01;
2259        M10 = m10; M11 = m11;
2260        while (--numPts >= 0) {
2261        double x = srcPts[srcOff++];
2262        double y = srcPts[srcOff++];
2263        dstPts[dstOff++] = (float) (M00 * x + M01 * y);
2264        dstPts[dstOff++] = (float) (M10 * x + M11 * y);
2265        }
2266        return;
2267    case (APPLY_SHEAR | APPLY_TRANSLATE):
2268        M01 = m01; M02 = m02;
2269        M10 = m10; M12 = m12;
2270        while (--numPts >= 0) {
2271        double x = srcPts[srcOff++];
2272        dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++] + M02);
2273        dstPts[dstOff++] = (float) (M10 * x + M12);
2274        }
2275        return;
2276    case (APPLY_SHEAR):
2277        M01 = m01; M10 = m10;
2278        while (--numPts >= 0) {
2279        double x = srcPts[srcOff++];
2280        dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++]);
2281        dstPts[dstOff++] = (float) (M10 * x);
2282        }
2283        return;
2284    case (APPLY_SCALE | APPLY_TRANSLATE):
2285        M00 = m00; M02 = m02;
2286        M11 = m11; 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; M11 = m11;
2294        while (--numPts >= 0) {
2295        dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++]);
2296        dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++]);
2297        }
2298        return;
2299    case (APPLY_TRANSLATE):
2300        M02 = m02; M12 = m12;
2301        while (--numPts >= 0) {
2302        dstPts[dstOff++] = (float) (srcPts[srcOff++] + M02);
2303        dstPts[dstOff++] = (float) (srcPts[srcOff++] + M12);
2304        }
2305        return;
2306    case (APPLY_IDENTITY):
2307        if (srcPts != dstPts || srcOff != dstOff) {
2308        System.arraycopy(srcPts, srcOff, dstPts, dstOff,
2309                 numPts * 2);
2310        }
2311        return;
2312    }
2313
2314    /* NOTREACHED */
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,
2338              double[] dstPts, int dstOff,
2339              int numPts) {
2340    double M00, M01, M02, M10, M11, M12; // For caching
2341
if (dstPts == srcPts &&
2342        dstOff > srcOff && dstOff < srcOff + numPts * 2)
2343    {
2344        // If the arrays overlap partially with the destination higher
2345
// than the source and we transform the coordinates normally
2346
// we would overwrite some of the later source coordinates
2347
// with results of previous transformations.
2348
// To get around this we use arraycopy to copy the points
2349
// to their final destination with correct overwrite
2350
// handling and then transform them in place in the new
2351
// safer location.
2352
System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts * 2);
2353        // srcPts = dstPts; // They are known to be equal.
2354
srcOff = dstOff;
2355    }
2356    switch (state) {
2357    default:
2358        stateError();
2359        /* NOTREACHED */
2360    case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2361        M00 = m00; M01 = m01; M02 = m02;
2362        M10 = m10; M11 = m11; M12 = m12;
2363        while (--numPts >= 0) {
2364        double x = srcPts[srcOff++];
2365        double y = srcPts[srcOff++];
2366        dstPts[dstOff++] = M00 * x + M01 * y + M02;
2367        dstPts[dstOff++] = M10 * x + M11 * y + M12;
2368        }
2369        return;
2370    case (APPLY_SHEAR | APPLY_SCALE):
2371        M00 = m00; M01 = m01;
2372        M10 = m10; M11 = m11;
2373        while (--numPts >= 0) {
2374        double x = srcPts[srcOff++];
2375        double y = srcPts[srcOff++];
2376        dstPts[dstOff++] = M00 * x + M01 * y;
2377        dstPts[dstOff++] = M10 * x + M11 * y;
2378        }
2379        return;
2380    case (APPLY_SHEAR | APPLY_TRANSLATE):
2381        M01 = m01; M02 = m02;
2382        M10 = m10; M12 = m12;
2383        while (--numPts >= 0) {
2384        double x = srcPts[srcOff++];
2385        dstPts[dstOff++] = M01 * srcPts[srcOff++] + M02;
2386        dstPts[dstOff++] = M10 * x + M12;
2387        }
2388        return;
2389    case (APPLY_SHEAR):
2390        M01 = m01; M10 = m10;
2391        while (--numPts >= 0) {
2392        double x = srcPts[srcOff++];
2393        dstPts[dstOff++] = M01 * srcPts[srcOff++];
2394        dstPts[dstOff++] = M10 * x;
2395        }
2396        return;
2397    case (APPLY_SCALE | APPLY_TRANSLATE):
2398        M00 = m00; M02 = m02;
2399        M11 = m11; M12 = m12;
2400        while (--numPts >= 0) {
2401        dstPts[dstOff++] = M00 * srcPts[srcOff++] + M02;
2402        dstPts[dstOff++] = M11 * srcPts[srcOff++] + M12;
2403        }
2404        return;
2405    case (APPLY_SCALE):
2406        M00 = m00; M11 = m11;
2407        while (--numPts >= 0) {
2408        dstPts[dstOff++] = M00 * srcPts[srcOff++];
2409        dstPts[dstOff++] = M11 * srcPts[srcOff++];
2410        }
2411        return;
2412    case (APPLY_TRANSLATE):
2413        M02 = m02; M12 = m12;
2414        while (--numPts >= 0) {
2415        dstPts[dstOff++] = srcPts[srcOff++] + M02;
2416        dstPts[dstOff++] = srcPts[srcOff++] + M12;
2417        }
2418        return;
2419    case (APPLY_IDENTITY):
2420        if (srcPts != dstPts || srcOff != dstOff) {
2421        System.arraycopy(srcPts, srcOff, dstPts, dstOff,
2422                 numPts * 2);
2423        }
2424        return;
2425    }
2426
2427    /* NOTREACHED */
2428    }
2429
2430    /**
2431     * Transforms an array of floating point coordinates by this transform
2432     * and stores the results into an array of doubles.
2433     * The coordinates are stored in the arrays starting at the specified
2434     * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
2435     * @param srcPts the array containing the source point coordinates.
2436     * Each point is stored as a pair of x,&nbsp;y coordinates.
2437     * @param dstPts the array into which the transformed point coordinates
2438     * are returned. Each point is stored as a pair of x,&nbsp;y
2439     * coordinates.
2440     * @param srcOff the offset to the first point to be transformed
2441     * in the source array
2442     * @param dstOff the offset to the location of the first
2443     * transformed point that is stored in the destination array
2444     * @param numPts the number of points to be transformed
2445     */

2446    public void transform(float[] srcPts, int srcOff,
2447              double[] dstPts, int dstOff,
2448              int numPts) {
2449    double M00, M01, M02, M10, M11, M12; // For caching
2450
switch (state) {
2451    default:
2452        stateError();
2453        /* NOTREACHED */
2454    case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2455        M00 = m00; M01 = m01; M02 = m02;
2456        M10 = m10; M11 = m11; M12 = m12;
2457        while (--numPts >= 0) {
2458        double x = srcPts[srcOff++];
2459        double y = srcPts[srcOff++];
2460        dstPts[dstOff++] = M00 * x + M01 * y + M02;
2461        dstPts[dstOff++] = M10 * x + M11 * y + M12;
2462        }
2463        return;
2464    case (APPLY_SHEAR | APPLY_SCALE):
2465        M00 = m00; M01 = m01;
2466        M10 = m10; M11 = m11;
2467        while (--numPts >= 0) {
2468        double x = srcPts[srcOff++];
2469        double y = srcPts[srcOff++];
2470        dstPts[dstOff++] = M00 * x + M01 * y;
2471        dstPts[dstOff++] = M10 * x + M11 * y;
2472        }
2473        return;
2474    case (APPLY_SHEAR | APPLY_TRANSLATE):
2475        M01 = m01; M02 = m02;
2476        M10 = m10; M12 = m12;
2477        while (--numPts >= 0) {
2478        double x = srcPts[srcOff++];
2479        dstPts[dstOff++] = M01 * srcPts[srcOff++] + M02;
2480        dstPts[dstOff++] = M10 * x + M12;
2481        }
2482        return;
2483    case (APPLY_SHEAR):
2484        M01 = m01; M10 = m10;
2485        while (--numPts >= 0) {
2486        double x = srcPts[srcOff++];
2487        dstPts[dstOff++] = M01 * srcPts[srcOff++];
2488        dstPts[dstOff++] = M10 * x;
2489        }
2490        return;
2491    case (APPLY_SCALE | APPLY_TRANSLATE):
2492        M00 = m00; M02 = m02;
2493        M11 = m11; M12 = m12;
2494        while (--numPts >= 0) {
2495        dstPts[dstOff++] = M00 * srcPts[srcOff++] + M02;
2496        dstPts[dstOff++] = M11 * srcPts[srcOff++] + M12;
2497        }
2498        return;
2499    case (APPLY_SCALE):
2500        M00 = m00; M11 = m11;
2501        while (--numPts >= 0) {
2502        dstPts[dstOff++] = M00 * srcPts[srcOff++];
2503        dstPts[dstOff++] = M11 * srcPts[srcOff++];
2504        }
2505        return;
2506    case (APPLY_TRANSLATE):
2507        M02 = m02; M12 = m12;
2508        while (--numPts >= 0) {
2509        dstPts[dstOff++] = srcPts[srcOff++] + M02;
2510        dstPts[dstOff++] = srcPts[srcOff++] + M12;
2511        }
2512        return;
2513    case (APPLY_IDENTITY):
2514        while (--numPts >= 0) {
2515        dstPts[dstOff++] = srcPts[srcOff++];
2516        dstPts[dstOff++] = srcPts[srcOff++];
2517        }
2518        return;
2519    }
2520
2521    /* NOTREACHED */
2522    }
2523
2524    /**
2525     * Transforms an array of double precision coordinates by this transform
2526     * and stores the results into an array of floats.
2527     * The coordinates are stored in the arrays starting at the specified
2528     * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
2529     * @param srcPts the array containing the source point coordinates.
2530     * Each point is stored as a pair of x,&nbsp;y coordinates.
2531     * @param dstPts the array into which the transformed point
2532     * coordinates are returned. Each point is stored as a pair of
2533     * x,&nbsp;y coordinates.
2534     * @param srcOff the offset to the first point to be transformed
2535     * in the source array
2536     * @param dstOff the offset to the location of the first
2537     * transformed point that is stored in the destination array
2538     * @param numPts the number of point objects to be transformed
2539     */

2540    public void transform(double[] srcPts, int srcOff,
2541              float[] dstPts, int dstOff,
2542              int numPts) {
2543    double M00, M01, M02, M10, M11, M12; // For caching
2544
switch (state) {
2545    default:
2546        stateError();
2547        /* NOTREACHED */
2548    case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2549        M00 = m00; M01 = m01; M02 = m02;
2550        M10 = m10; M11 = m11; M12 = m12;
2551        while (--numPts >= 0) {
2552        double x = srcPts[srcOff++];
2553        double y = srcPts[srcOff++];
2554        dstPts[dstOff++] = (float) (M00 * x + M01 * y + M02);
2555        dstPts[dstOff++] = (float) (M10 * x + M11 * y + M12);
2556        }
2557        return;
2558    case (APPLY_SHEAR | APPLY_SCALE):
2559        M00 = m00; M01 = m01;
2560        M10 = m10; M11 = m11;
2561        while (--numPts >= 0) {
2562        double x = srcPts[srcOff++];
2563        double y = srcPts[srcOff++];
2564        dstPts[dstOff++] = (float) (M00 * x + M01 * y);
2565        dstPts[dstOff++] = (float) (M10 * x + M11 * y);
2566        }
2567        return;
2568    case (APPLY_SHEAR | APPLY_TRANSLATE):
2569        M01 = m01; M02 = m02;
2570        M10 = m10; M12 = m12;
2571        while (--numPts >= 0) {
2572        double x = srcPts[srcOff++];
2573        dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++] + M02);
2574        dstPts[dstOff++] = (float) (M10 * x + M12);
2575        }
2576        return;
2577    case (APPLY_SHEAR):
2578        M01 = m01; M10 = m10;
2579        while (--numPts >= 0) {
2580        double x = srcPts[srcOff++];
2581        dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++]);
2582        dstPts[dstOff++] = (float) (M10 * x);
2583        }
2584        return;
2585    case (APPLY_SCALE | APPLY_TRANSLATE):
2586        M00 = m00; M02 = m02;
2587        M11 = m11; M12 = m12;
2588        while (--numPts >= 0) {
2589        dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++] + M02);
2590        dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++] + M12);
2591        }
2592        return;
2593    case (APPLY_SCALE):
2594        M00 = m00; M11 = m11;
2595        while (--numPts >= 0) {
2596        dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++]);
2597        dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++]);
2598        }
2599        return;
2600    case (APPLY_TRANSLATE):
2601        M02 = m02; M12 = m12;
2602        while (--numPts >= 0) {
2603        dstPts[dstOff++] = (float) (srcPts[srcOff++] + M02);
2604        dstPts[dstOff++] = (float) (srcPts[srcOff++] + M12);
2605        }
2606        return;
2607    case (APPLY_IDENTITY):
2608        while (--numPts >= 0) {
2609        dstPts[dstOff++] = (float) (srcPts[srcOff++]);
2610        dstPts[dstOff++] = (float) (srcPts[srcOff++]);
2611        }
2612        return;
2613    }
2614
2615    /* NOTREACHED */
2616    }
2617
2618    /**
2619     * Inverse transforms the specified <code>ptSrc</code> and stores the
2620     * result in <code>ptDst</code>.
2621     * If <code>ptDst</code> is <code>null</code>, a new
2622     * <code>Point2D</code> object is allocated and then the result of the
2623     * transform is stored in this object.
2624     * In either case, <code>ptDst</code>, which contains the transformed
2625     * point, is returned for convenience.
2626     * If <code>ptSrc</code> and <code>ptDst</code> are the same
2627     * object, the input point is correctly overwritten with the
2628     * transformed point.
2629     * @param ptSrc the point to be inverse transformed
2630     * @param ptDst the resulting transformed point
2631     * @return <code>ptDst</code>, which contains the result of the
2632     * inverse transform.
2633     * @exception NoninvertibleTransformException if the matrix cannot be
2634     * inverted.
2635     */

2636    public Point2D JavaDoc inverseTransform(Point2D JavaDoc ptSrc, Point2D JavaDoc ptDst)
2637    throws NoninvertibleTransformException JavaDoc
2638    {
2639    if (ptDst == null) {
2640        if (ptSrc instanceof Point2D.Double JavaDoc) {
2641        ptDst = new Point2D.Double JavaDoc();
2642        } else {
2643        ptDst = new Point2D.Float JavaDoc();
2644        }
2645    }
2646    // Copy source coords into local variables in case src == dst
2647
double x = ptSrc.getX();
2648    double y = ptSrc.getY();
2649    switch (state) {
2650    default:
2651        stateError();
2652        /* NOTREACHED */
2653    case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2654        x -= m02;
2655        y -= m12;
2656        /* NOBREAK */
2657    case (APPLY_SHEAR | APPLY_SCALE):
2658        double det = m00 * m11 - m01 * m10;
2659        if (Math.abs(det) <= Double.MIN_VALUE) {
2660        throw new NoninvertibleTransformException JavaDoc("Determinant is "+
2661                              det);
2662        }
2663        ptDst.setLocation((x * m11 - y * m01) / det,
2664                  (y * m00 - x * m10) / det);
2665        return ptDst;
2666    case (APPLY_SHEAR | APPLY_TRANSLATE):
2667        x -= m02;
2668        y -= m12;
2669        /* NOBREAK */
2670    case (APPLY_SHEAR):
2671        if (m01 == 0.0 || m10 == 0.0) {
2672        throw new NoninvertibleTransformException JavaDoc("Determinant is 0");
2673        }
2674        ptDst.setLocation(y / m10, x / m01);
2675        return ptDst;
2676    case (APPLY_SCALE | APPLY_TRANSLATE):
2677        x -= m02;
2678        y -= m12;
2679        /* NOBREAK */
2680    case (APPLY_SCALE):
2681        if (m00 == 0.0 || m11 == 0.0) {
2682        throw new NoninvertibleTransformException JavaDoc("Determinant is 0");
2683        }
2684        ptDst.setLocation(x / m00, y / m11);
2685        return ptDst;
2686    case (APPLY_TRANSLATE):
2687        ptDst.setLocation(x - m02, y - m12);
2688        return ptDst;
2689    case (APPLY_IDENTITY):
2690        ptDst.setLocation(x, y);
2691        return ptDst;
2692    }
2693
2694    /* NOTREACHED */
2695    }
2696
2697    /**
2698     * Inverse transforms an array of double precision coordinates by
2699     * this transform.
2700     * The two coordinate array sections can be exactly the same or
2701     * can be overlapping sections of the same array without affecting the
2702     * validity of the results.
2703     * This method ensures that no source coordinates are
2704     * overwritten by a previous operation before they can be transformed.
2705     * The coordinates are stored in the arrays starting at the specified
2706     * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
2707     * @param srcPts the array containing the source point coordinates.
2708     * Each point is stored as a pair of x,&nbsp;y coordinates.
2709     * @param dstPts the array into which the transformed point
2710     * coordinates are returned. Each point is stored as a pair of
2711     * x,&nbsp;y coordinates.
2712     * @param srcOff the offset to the first point to be transformed
2713     * in the source array
2714     * @param dstOff the offset to the location of the first
2715     * transformed point that is stored in the destination array
2716     * @param numPts the number of point objects to be transformed
2717     * @exception NoninvertibleTransformException if the matrix cannot be
2718     * inverted.
2719     */

2720    public void inverseTransform(double[] srcPts, int srcOff,
2721                                 double[] dstPts, int dstOff,
2722                                 int numPts)
2723    throws NoninvertibleTransformException JavaDoc
2724    {
2725    double M00, M01, M02, M10, M11, M12; // For caching
2726
double det;
2727    if (dstPts == srcPts &&
2728        dstOff > srcOff && dstOff < srcOff + numPts * 2)
2729    {
2730        // If the arrays overlap partially with the destination higher
2731
// than the source and we transform the coordinates normally
2732
// we would overwrite some of the later source coordinates
2733
// with results of previous transformations.
2734
// To get around this we use arraycopy to copy the points
2735
// to their final destination with correct overwrite
2736
// handling and then transform them in place in the new
2737
// safer location.
2738
System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts * 2);
2739        // srcPts = dstPts; // They are known to be equal.
2740
srcOff = dstOff;
2741    }
2742    switch (state) {
2743    default:
2744        stateError();
2745        /* NOTREACHED */
2746    case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2747        M00 = m00; M01 = m01; M02 = m02;
2748        M10 = m10; M11 = m11; M12 = m12;
2749        det = M00 * M11 - M01 * M10;
2750        if (Math.abs(det) <= Double.MIN_VALUE) {
2751        throw new NoninvertibleTransformException JavaDoc("Determinant is "+
2752                              det);
2753        }
2754        while (--numPts >= 0) {
2755        double x = srcPts[srcOff++] - M02;
2756        double y = srcPts[srcOff++] - M12;
2757        dstPts[dstOff++] = (x * M11 - y * M01) / det;
2758        dstPts[dstOff++] = (y * M00 - x * M10) / det;
2759        }
2760        return;
2761    case (APPLY_SHEAR | APPLY_SCALE):
2762        M00 = m00; M01 = m01;
2763        M10 = m10; M11 = m11;
2764        det = M00 * M11 - M01 * M10;
2765        if (Math.abs(det) <= Double.MIN_VALUE) {
2766        throw new NoninvertibleTransformException JavaDoc("Determinant is "+
2767                              det);
2768        }
2769        while (--numPts >= 0) {
2770        double x = srcPts[srcOff++];
2771        double y = srcPts[srcOff++];
2772        dstPts[dstOff++] = (x * M11 - y * M01) / det;
2773        dstPts[dstOff++] = (y * M00 - x * M10) / det;
2774        }
2775        return;
2776    case (APPLY_SHEAR | APPLY_TRANSLATE):
2777        M01 = m01; M02 = m02;
2778        M10 = m10; M12 = m12;
2779        if (M01 == 0.0 || M10 == 0.0) {
2780        throw new NoninvertibleTransformException JavaDoc("Determinant is 0");
2781        }
2782        while (--numPts >= 0) {
2783        double x = srcPts[srcOff++] - M02;
2784        dstPts[dstOff++] = (srcPts[srcOff++] - M12) / M10;
2785        dstPts[dstOff++] = x / M01;
2786        }
2787        return;
2788    case (APPLY_SHEAR):
2789        M01 = m01; M10 = m10;
2790        if (M01 == 0.0 || M10 == 0.0) {
2791        throw new NoninvertibleTransformException JavaDoc("Determinant is 0");
2792        }
2793        while (--numPts >= 0) {
2794        double x = srcPts[srcOff++];
2795        dstPts[dstOff++] = srcPts[srcOff++] / M10;
2796        dstPts[dstOff++] = x / M01;
2797        }
2798        return;
2799    case (APPLY_SCALE | APPLY_TRANSLATE):
2800        M00 = m00; M02 = m02;
2801        M11 = m11; M12 = m12;
2802        if (M00 == 0.0 || M11 == 0.0) {
2803        throw new NoninvertibleTransformException JavaDoc("Determinant is 0");
2804        }
2805        while (--numPts >= 0) {
2806        dstPts[dstOff++] = (srcPts[srcOff++] - M02) / M00;
2807        dstPts[dstOff++] = (srcPts[srcOff++] - M12) / M11;
2808        }
2809        return;
2810    case (APPLY_SCALE):
2811        M00 = m00; M11 = m11;
2812        if (M00 == 0.0 || M11 == 0.0) {
2813        throw new NoninvertibleTransformException JavaDoc("Determinant is 0");
2814        }
2815        while (--numPts >= 0) {
2816        dstPts[dstOff++] = srcPts[srcOff++] / M00;
2817        dstPts[dstOff++] = srcPts[srcOff++] / M11;
2818        }
2819        return;
2820    case (APPLY_TRANSLATE):
2821        M02 = m02; M12 = m12;
2822        while (--numPts >= 0) {
2823        dstPts[dstOff++] = srcPts[srcOff++] - M02;
2824        dstPts[dstOff++] = srcPts[srcOff++] - M12;
2825        }
2826        return;
2827    case (APPLY_IDENTITY):
2828        if (srcPts != dstPts || srcOff != dstOff) {
2829        System.arraycopy(srcPts, srcOff, dstPts, dstOff,
2830                 numPts * 2);
2831        }
2832        return;
2833    }
2834
2835    /* NOTREACHED */
2836    }
2837
2838    /**
2839     * Transforms the relative distance vector specified by
2840     * <code>ptSrc</code> and stores the result in <code>ptDst</code>.
2841     * A relative distance vector is transformed without applying the
2842     * translation components of the affine transformation matrix
2843     * using the following equations:
2844     * <pre>
2845     * [ x' ] [ m00 m01 (m02) ] [ x ] [ m00x + m01y ]
2846     * [ y' ] = [ m10 m11 (m12) ] [ y ] = [ m10x + m11y ]
2847     * [ (1) ] [ (0) (0) ( 1 ) ] [ (1) ] [ (1) ]
2848     * </pre>
2849     * If <code>ptDst</code> is <code>null</code>, a new
2850     * <code>Point2D</code> object is allocated and then the result of the
2851     * transform is stored in this object.
2852     * In either case, <code>ptDst</code>, which contains the
2853     * transformed point, is returned for convenience.
2854     * If <code>ptSrc</code> and <code>ptDst</code> are the same object,
2855     * the input point is correctly overwritten with the transformed
2856     * point.
2857     * @param ptSrc the distance vector to be delta transformed
2858     * @param ptDst the resulting transformed distance vector
2859     * @return <code>ptDst</code>, which contains the result of the
2860     * transformation.
2861     */

2862    public Point2D JavaDoc deltaTransform(Point2D JavaDoc ptSrc, Point2D JavaDoc ptDst) {
2863    if (ptDst == null) {
2864        if (ptSrc instanceof Point2D.Double JavaDoc) {
2865        ptDst = new Point2D.Double JavaDoc();
2866        } else {
2867        ptDst = new Point2D.Float JavaDoc();
2868        }
2869    }
2870    // Copy source coords into local variables in case src == dst
2871
double x = ptSrc.getX();
2872    double y = ptSrc.getY();
2873    switch (state) {
2874    default:
2875        stateError();
2876        /* NOTREACHED */
2877    case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2878    case (APPLY_SHEAR | APPLY_SCALE):
2879        ptDst.setLocation(x * m00 + y * m01, x * m10 + y * m11);
2880        return ptDst;
2881    case (APPLY_SHEAR | APPLY_TRANSLATE):
2882    case (APPLY_SHEAR):
2883        ptDst.setLocation(y * m01, x * m10);
2884        return ptDst;
2885    case (APPLY_SCALE | APPLY_TRANSLATE):
2886    case (APPLY_SCALE):
2887        ptDst.setLocation(x * m00, y * m11);
2888        return ptDst;
2889    case (APPLY_TRANSLATE):
2890    case (APPLY_IDENTITY):
2891        ptDst.setLocation(x, y);
2892        return ptDst;
2893    }
2894
2895    /* NOTREACHED */
2896    }
2897
2898    /**
2899     * Transforms an array of relative distance vectors by this
2900     * transform.
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     * The two coordinate array sections can be exactly the same or
2910     * can be overlapping sections of the same array without affecting the
2911     * validity of the results.
2912     * This method ensures that no source coordinates are
2913     * overwritten by a previous operation before they can be transformed.
2914     * The coordinates are stored in the arrays starting at the indicated
2915     * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
2916     * @param srcPts the array containing the source distance vectors.
2917     * Each vector is stored as a pair of relative x,&nbsp;y coordinates.
2918     * @param dstPts the array into which the transformed distance vectors
2919     * are returned. Each vector is stored as a pair of relative
2920     * x,&nbsp;y coordinates.
2921     * @param srcOff the offset to the first vector to be transformed
2922     * in the source array
2923     * @param dstOff the offset to the location of the first
2924     * transformed vector that is stored in the destination array
2925     * @param numPts the number of vector coordinate pairs to be
2926     * transformed
2927     */

2928    public void deltaTransform(double[] srcPts, int srcOff,
2929                   double[] dstPts, int dstOff,
2930                   int numPts) {
2931    double M00, M01, M10, M11; // For caching
2932
if (dstPts == srcPts &&
2933        dstOff > srcOff && dstOff < srcOff + numPts * 2)
2934    {
2935        // If the arrays overlap partially with the destination higher
2936
// than the source and we transform the coordinates normally
2937
// we would overwrite some of the later source coordinates
2938
// with results of previous transformations.
2939
// To get around this we use arraycopy to copy the points
2940
// to their final destination with correct overwrite
2941
// handling and then transform them in place in the new
2942
// safer location.
2943
System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts * 2);
2944        // srcPts = dstPts; // They are known to be equal.
2945
srcOff = dstOff;
2946    }
2947    switch (state) {
2948    default:
2949        stateError();
2950        /* NOTREACHED */
2951    case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2952    case (APPLY_SHEAR | APPLY_SCALE):
2953        M00 = m00; M01 = m01;
2954        M10 = m10; M11 = m11;
2955        while (--numPts >= 0) {
2956        double x = srcPts[srcOff++];
2957        double y = srcPts[srcOff++];
2958        dstPts[dstOff++] = x * M00 + y * M01;
2959        dstPts[dstOff++] = x * M10 + y * M11;
2960        }
2961        return;
2962    case (APPLY_SHEAR | APPLY_TRANSLATE):
2963    case (APPLY_SHEAR):
2964        M01 = m01; M10 = m10;
2965        while (--numPts >= 0) {
2966        double x = srcPts[srcOff++];
2967        dstPts[dstOff++] = srcPts[srcOff++] * M01;
2968        dstPts[dstOff++] = x * M10;
2969        }
2970        return;
2971    case (APPLY_SCALE | APPLY_TRANSLATE):
2972    case (APPLY_SCALE):
2973        M00 = m00; M11 = m11;
2974        while (--numPts >= 0) {
2975        dstPts[dstOff++] = srcPts[srcOff++] * M00;
2976        dstPts[dstOff++] = srcPts[srcOff++] * M11;
2977        }
2978        return;
2979    case (APPLY_TRANSLATE):
2980    case (APPLY_IDENTITY):
2981        if (srcPts != dstPts || srcOff != dstOff) {
2982        System.arraycopy(srcPts, srcOff, dstPts, dstOff,
2983                 numPts * 2);
2984        }
2985        return;
2986    }
2987
2988    /* NOTREACHED */
2989    }
2990
2991    /**
2992     * Returns a new {@link Shape} object defined by the geometry of the
2993     * specified <code>Shape</code> after it has been transformed by
2994     * this transform.
2995     * @param pSrc the specified <code>Shape</code> object to be
2996     * transformed by this transform.
2997     * @return a new <code>Shape</code> object that defines the geometry
2998     * of the transformed <code>Shape</code>.
2999     */

3000    public Shape JavaDoc createTransformedShape(Shape JavaDoc pSrc) {
3001        if (pSrc == null) {
3002            return null;
3003        }
3004        
3005        if (pSrc instanceof GeneralPath JavaDoc) {
3006            return ((GeneralPath JavaDoc)pSrc).createTransformedShape(this);
3007        } else {
3008            PathIterator JavaDoc pi = pSrc.getPathIterator(this);
3009            GeneralPath JavaDoc gp = new GeneralPath JavaDoc(pi.getWindingRule());
3010        gp.append(pi, false);
3011            return gp;
3012        }
3013
3014    /* NOTREACHED */
3015    }
3016
3017    // Round values to sane precision for printing
3018
// Note that Math.sin(Math.PI) has an error of about 10^-16
3019
private static double _matround(double matval) {
3020    return Math.rint(matval * 1E15) / 1E15;
3021    }
3022
3023    /**
3024     * Returns a <code>String</code> that represents the value of this
3025     * {@link Object}.
3026     * @return a <code>String</code> representing the value of this
3027     * <code>Object</code>.
3028     */

3029    public String JavaDoc toString() {
3030    return ("AffineTransform[["
3031        + _matround(m00) + ", "
3032        + _matround(m01) + ", "
3033        + _matround(m02) + "], ["
3034        + _matround(m10) + ", "
3035        + _matround(m11) + ", "
3036        + _matround(m12) + "]]");
3037    }
3038
3039    /**
3040     * Returns <code>true</code> if this <code>AffineTransform</code> is
3041     * an identity transform.
3042     * @return <code>true</code> if this <code>AffineTransform</code> is
3043     * an identity transform; <code>false</code> otherwise.
3044     */

3045    public boolean isIdentity() {
3046        return (state == APPLY_IDENTITY || (getType() == TYPE_IDENTITY));
3047    }
3048
3049    /**
3050     * Returns a copy of this <code>AffineTransform</code> object.
3051     * @return an <code>Object</code> that is a copy of this
3052     * <code>AffineTransform</code> object.
3053     */

3054    public Object JavaDoc clone() {
3055    try {
3056        return super.clone();
3057    } catch (CloneNotSupportedException JavaDoc e) {
3058        // this shouldn't happen, since we are Cloneable
3059
throw new InternalError JavaDoc();
3060    }
3061    }
3062
3063    /**
3064     * Returns the hashcode for this transform.
3065     * @return a hash code for this transform.
3066     */

3067    public int hashCode() {
3068    long bits = Double.doubleToLongBits(m00);
3069    bits = bits * 31 + Double.doubleToLongBits(m01);
3070    bits = bits * 31 + Double.doubleToLongBits(m02);
3071    bits = bits * 31 + Double.doubleToLongBits(m10);
3072    bits = bits * 31 + Double.doubleToLongBits(m11);
3073    bits = bits * 31 + Double.doubleToLongBits(m12);
3074    return (((int) bits) ^ ((int) (bits >> 32)));
3075    }
3076
3077    /**
3078     * Returns <code>true</code> if this <code>AffineTransform</code>
3079     * represents the same affine coordinate transform as the specified
3080     * argument.
3081     * @param obj the <code>Object</code> to test for equality with this
3082     * <code>AffineTransform</code>
3083     * @return <code>true</code> if <code>obj</code> equals this
3084     * <code>AffineTransform</code> object; <code>false</code> otherwise.
3085     */

3086    public boolean equals(Object JavaDoc obj) {
3087        if (!(obj instanceof AffineTransform JavaDoc)) {
3088            return false;
3089        }
3090
3091        AffineTransform JavaDoc a = (AffineTransform JavaDoc)obj;
3092
3093    return ((m00 == a.m00) && (m01 == a.m01) && (m02 == a.m02) &&
3094        (m10 == a.m10) && (m11 == a.m11) && (m12 == a.m12));
3095    }
3096
3097    /* Serialization support. A readObject method is neccessary because
3098     * the state field is part of the implementation of this particular
3099     * AffineTransform and not part of the public specification. The
3100     * state variable's value needs to be recalculated on the fly by the
3101     * readObject method as it is in the 6-argument matrix constructor.
3102     */

3103
3104    private void writeObject(java.io.ObjectOutputStream JavaDoc s)
3105    throws java.lang.ClassNotFoundException JavaDoc, java.io.IOException JavaDoc
3106    {
3107    s.defaultWriteObject();
3108    }
3109
3110    private void readObject(java.io.ObjectInputStream JavaDoc s)
3111    throws java.lang.ClassNotFoundException JavaDoc, java.io.IOException JavaDoc
3112    {
3113    s.defaultReadObject();
3114    updateState();
3115    }
3116}
3117
Popular Tags