1 /*
2 * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package java.awt.geom;
27
28 import java.awt.Shape;
29
30 /**
31 * The <code>AffineTransform</code> class represents a 2D affine transform
32 * that performs a linear mapping from 2D coordinates to other 2D
33 * coordinates that preserves the "straightness" and
34 * "parallelness" of lines. Affine transformations can be constructed
35 * using sequences of translations, scales, flips, rotations, and shears.
36 * <p>
37 * Such a coordinate transformation can be represented by a 3 row by
38 * 3 column matrix with an implied last row of [ 0 0 1 ]. This matrix
39 * transforms source coordinates {@code (x,y)} into
40 * destination coordinates {@code (x',y')} by considering
41 * them to be a column vector and multiplying the coordinate vector
42 * by the matrix according to the following process:
43 * <pre>
44 * [ x'] [ m00 m01 m02 ] [ x ] [ m00x + m01y + m02 ]
45 * [ y'] = [ m10 m11 m12 ] [ y ] = [ m10x + m11y + m12 ]
46 * [ 1 ] [ 0 0 1 ] [ 1 ] [ 1 ]
47 * </pre>
48 * <p>
49 * <a name="quadrantapproximation"><h4>Handling 90-Degree Rotations</h4></a>
50 * <p>
51 * In some variations of the <code>rotate</code> methods in the
52 * <code>AffineTransform</code> class, a double-precision argument
53 * specifies the angle of rotation in radians.
54 * These methods have special handling for rotations of approximately
55 * 90 degrees (including multiples such as 180, 270, and 360 degrees),
56 * so that the common case of quadrant rotation is handled more
57 * efficiently.
58 * This special handling can cause angles very close to multiples of
59 * 90 degrees to be treated as if they were exact multiples of
60 * 90 degrees.
61 * For small multiples of 90 degrees the range of angles treated
62 * as a quadrant rotation is approximately 0.00000121 degrees wide.
63 * This section explains why such special care is needed and how
64 * it is implemented.
65 * <p>
66 * Since 90 degrees is represented as <code>PI/2</code> in radians,
67 * and since PI is a transcendental (and therefore irrational) number,
68 * it is not possible to exactly represent a multiple of 90 degrees as
69 * an exact double precision value measured in radians.
70 * As a result it is theoretically impossible to describe quadrant
71 * rotations (90, 180, 270 or 360 degrees) using these values.
72 * Double precision floating point values can get very close to
73 * non-zero multiples of <code>PI/2</code> but never close enough
74 * for the sine or cosine to be exactly 0.0, 1.0 or -1.0.
75 * The implementations of <code>Math.sin()</code> and
76 * <code>Math.cos()</code> correspondingly never return 0.0
77 * for any case other than <code>Math.sin(0.0)</code>.
78 * These same implementations do, however, return exactly 1.0 and
79 * -1.0 for some range of numbers around each multiple of 90
80 * degrees since the correct answer is so close to 1.0 or -1.0 that
81 * the double precision significand cannot represent the difference
82 * as accurately as it can for numbers that are near 0.0.
83 * <p>
84 * The net result of these issues is that if the
85 * <code>Math.sin()</code> and <code>Math.cos()</code> methods
86 * are used to directly generate the values for the matrix modifications
87 * during these radian-based rotation operations then the resulting
88 * transform is never strictly classifiable as a quadrant rotation
89 * even for a simple case like <code>rotate(Math.PI/2.0)</code>,
90 * due to minor variations in the matrix caused by the non-0.0 values
91 * obtained for the sine and cosine.
92 * If these transforms are not classified as quadrant rotations then
93 * subsequent code which attempts to optimize further operations based
94 * upon the type of the transform will be relegated to its most general
95 * implementation.
96 * <p>
97 * Because quadrant rotations are fairly common,
98 * this class should handle these cases reasonably quickly, both in
99 * applying the rotations to the transform and in applying the resulting
100 * transform to the coordinates.
101 * To facilitate this optimal handling, the methods which take an angle
102 * of rotation measured in radians attempt to detect angles that are
103 * intended to be quadrant rotations and treat them as such.
104 * These methods therefore treat an angle <em>theta</em> as a quadrant
105 * rotation if either <code>Math.sin(<em>theta</em>)</code> or
106 * <code>Math.cos(<em>theta</em>)</code> returns exactly 1.0 or -1.0.
107 * As a rule of thumb, this property holds true for a range of
108 * approximately 0.0000000211 radians (or 0.00000121 degrees) around
109 * small multiples of <code>Math.PI/2.0</code>.
110 *
111 * @author Jim Graham
112 * @since 1.2
113 */
114 public class AffineTransform implements Cloneable, java.io.Serializable {
115
116 /*
117 * This constant is only useful for the cached type field.
118 * It indicates that the type has been decached and must be recalculated.
119 */
120 private static final int TYPE_UNKNOWN = -1;
121
122 /**
123 * This constant indicates that the transform defined by this object
124 * is an identity transform.
125 * An identity transform is one in which the output coordinates are
126 * always the same as the input coordinates.
127 * If this transform is anything other than the identity transform,
128 * the type will either be the constant GENERAL_TRANSFORM or a
129 * combination of the appropriate flag bits for the various coordinate
130 * conversions that this transform performs.
131 * @see #TYPE_TRANSLATION
132 * @see #TYPE_UNIFORM_SCALE
133 * @see #TYPE_GENERAL_SCALE
134 * @see #TYPE_FLIP
135 * @see #TYPE_QUADRANT_ROTATION
136 * @see #TYPE_GENERAL_ROTATION
137 * @see #TYPE_GENERAL_TRANSFORM
138 * @see #getType
139 * @since 1.2
140 */
141 public static final int TYPE_IDENTITY = 0;
142
143 /**
144 * This flag bit indicates that the transform defined by this object
145 * performs a translation in addition to the conversions indicated
146 * by other flag bits.
147 * A translation moves the coordinates by a constant amount in x
148 * and y without changing the length or angle of vectors.
149 * @see #TYPE_IDENTITY
150 * @see #TYPE_UNIFORM_SCALE
151 * @see #TYPE_GENERAL_SCALE
152 * @see #TYPE_FLIP
153 * @see #TYPE_QUADRANT_ROTATION
154 * @see #TYPE_GENERAL_ROTATION
155 * @see #TYPE_GENERAL_TRANSFORM
156 * @see #getType
157 * @since 1.2
158 */
159 public static final int TYPE_TRANSLATION = 1;
160
161 /**
162 * This flag bit indicates that the transform defined by this object
163 * performs a uniform scale in addition to the conversions indicated
164 * by other flag bits.
165 * A uniform scale multiplies the length of vectors by the same amount
166 * in both the x and y directions without changing the angle between
167 * vectors.
168 * This flag bit is mutually exclusive with the TYPE_GENERAL_SCALE flag.
169 * @see #TYPE_IDENTITY
170 * @see #TYPE_TRANSLATION
171 * @see #TYPE_GENERAL_SCALE
172 * @see #TYPE_FLIP
173 * @see #TYPE_QUADRANT_ROTATION
174 * @see #TYPE_GENERAL_ROTATION
175 * @see #TYPE_GENERAL_TRANSFORM
176 * @see #getType
177 * @since 1.2
178 */
179 public static final int TYPE_UNIFORM_SCALE = 2;
180
181 /**
182 * This flag bit indicates that the transform defined by this object
183 * performs a general scale in addition to the conversions indicated
184 * by other flag bits.
185 * A general scale multiplies the length of vectors by different
186 * amounts in the x and y directions without changing the angle
187 * between perpendicular vectors.
188 * This flag bit is mutually exclusive with the TYPE_UNIFORM_SCALE flag.
189 * @see #TYPE_IDENTITY
190 * @see #TYPE_TRANSLATION
191 * @see #TYPE_UNIFORM_SCALE
192 * @see #TYPE_FLIP
193 * @see #TYPE_QUADRANT_ROTATION
194 * @see #TYPE_GENERAL_ROTATION
195 * @see #TYPE_GENERAL_TRANSFORM
196 * @see #getType
197 * @since 1.2
198 */
199 public static final int TYPE_GENERAL_SCALE = 4;
200
201 /**
202 * This constant is a bit mask for any of the scale flag bits.
203 * @see #TYPE_UNIFORM_SCALE
204 * @see #TYPE_GENERAL_SCALE
205 * @since 1.2
206 */
207 public static final int TYPE_MASK_SCALE = (TYPE_UNIFORM_SCALE |
208 TYPE_GENERAL_SCALE);
209
210 /**
211 * This flag bit indicates that the transform defined by this object
212 * performs a mirror image flip about some axis which changes the
213 * normally right handed coordinate system into a left handed
214 * system in addition to the conversions indicated by other flag bits.
215 * A right handed coordinate system is one where the positive X
216 * axis rotates counterclockwise to overlay the positive Y axis
217 * similar to the direction that the fingers on your right hand
218 * curl when you stare end on at your thumb.
219 * A left handed coordinate system is one where the positive X
220 * axis rotates clockwise to overlay the positive Y axis similar
221 * to the direction that the fingers on your left hand curl.
222 * There is no mathematical way to determine the angle of the
223 * original flipping or mirroring transformation since all angles
224 * of flip are identical given an appropriate adjusting rotation.
225 * @see #TYPE_IDENTITY
226 * @see #TYPE_TRANSLATION
227 * @see #TYPE_UNIFORM_SCALE
228 * @see #TYPE_GENERAL_SCALE
229 * @see #TYPE_QUADRANT_ROTATION
230 * @see #TYPE_GENERAL_ROTATION
231 * @see #TYPE_GENERAL_TRANSFORM
232 * @see #getType
233 * @since 1.2
234 */
235 public static final int TYPE_FLIP = 64;
236 /* NOTE: TYPE_FLIP was added after GENERAL_TRANSFORM was in public
237 * circulation and the flag bits could no longer be conveniently
238 * renumbered without introducing binary incompatibility in outside
239 * code.
240 */
241
242 /**
243 * This flag bit indicates that the transform defined by this object
244 * performs a quadrant rotation by some multiple of 90 degrees in
245 * addition to the conversions indicated by other flag bits.
246 * A rotation changes the angles of vectors by the same amount
247 * regardless of the original direction of the vector and without
248 * changing the length of the vector.
249 * This flag bit is mutually exclusive with the TYPE_GENERAL_ROTATION flag.
250 * @see #TYPE_IDENTITY
251 * @see #TYPE_TRANSLATION
252 * @see #TYPE_UNIFORM_SCALE
253 * @see #TYPE_GENERAL_SCALE
254 * @see #TYPE_FLIP
255 * @see #TYPE_GENERAL_ROTATION
256 * @see #TYPE_GENERAL_TRANSFORM
257 * @see #getType
258 * @since 1.2
259 */
260 public static final int TYPE_QUADRANT_ROTATION = 8;
261
262 /**
263 * This flag bit indicates that the transform defined by this object
264 * performs a rotation by an arbitrary angle in addition to the
265 * conversions indicated by other flag bits.
266 * A rotation changes the angles of vectors by the same amount
267 * regardless of the original direction of the vector and without
268 * changing the length of the vector.
269 * This flag bit is mutually exclusive with the
270 * TYPE_QUADRANT_ROTATION flag.
271 * @see #TYPE_IDENTITY
272 * @see #TYPE_TRANSLATION
273 * @see #TYPE_UNIFORM_SCALE
274 * @see #TYPE_GENERAL_SCALE
275 * @see #TYPE_FLIP
276 * @see #TYPE_QUADRANT_ROTATION
277 * @see #TYPE_GENERAL_TRANSFORM
278 * @see #getType
279 * @since 1.2
280 */
281 public static final int TYPE_GENERAL_ROTATION = 16;
282
283 /**
284 * This constant is a bit mask for any of the rotation flag bits.
285 * @see #TYPE_QUADRANT_ROTATION
286 * @see #TYPE_GENERAL_ROTATION
287 * @since 1.2
288 */
289 public static final int TYPE_MASK_ROTATION = (TYPE_QUADRANT_ROTATION |
290 TYPE_GENERAL_ROTATION);
291
292 /**
293 * This constant indicates that the transform defined by this object
294 * performs an arbitrary conversion of the input coordinates.
295 * If this transform can be classified by any of the above constants,
296 * the type will either be the constant TYPE_IDENTITY or a
297 * combination of the appropriate flag bits for the various coordinate
298 * conversions that this transform performs.
299 * @see #TYPE_IDENTITY
300 * @see #TYPE_TRANSLATION
301 * @see #TYPE_UNIFORM_SCALE
302 * @see #TYPE_GENERAL_SCALE
303 * @see #TYPE_FLIP
304 * @see #TYPE_QUADRANT_ROTATION
305 * @see #TYPE_GENERAL_ROTATION
306 * @see #getType
307 * @since 1.2
308 */
309 public static final int TYPE_GENERAL_TRANSFORM = 32;
310
311 /**
312 * This constant is used for the internal state variable to indicate
313 * that no calculations need to be performed and that the source
314 * coordinates only need to be copied to their destinations to
315 * complete the transformation equation of this transform.
316 * @see #APPLY_TRANSLATE
317 * @see #APPLY_SCALE
318 * @see #APPLY_SHEAR
319 * @see #state
320 */
321 static final int APPLY_IDENTITY = 0;
322
323 /**
324 * This constant is used for the internal state variable to indicate
325 * that the translation components of the matrix (m02 and m12) need
326 * to be added to complete the transformation equation of this transform.
327 * @see #APPLY_IDENTITY
328 * @see #APPLY_SCALE
329 * @see #APPLY_SHEAR
330 * @see #state
331 */
332 static final int APPLY_TRANSLATE = 1;
333
334 /**
335 * This constant is used for the internal state variable to indicate
336 * that the scaling components of the matrix (m00 and m11) need
337 * to be factored in to complete the transformation equation of
338 * this transform. If the APPLY_SHEAR bit is also set then it
339 * indicates that the scaling components are not both 0.0. If the
340 * APPLY_SHEAR bit is not also set then it indicates that the
341 * scaling components are not both 1.0. If neither the APPLY_SHEAR
342 * nor the APPLY_SCALE bits are set then the scaling components
343 * are both 1.0, which means that the x and y components contribute
344 * to the transformed coordinate, but they are not multiplied by
345 * any scaling factor.
346 * @see #APPLY_IDENTITY
347 * @see #APPLY_TRANSLATE
348 * @see #APPLY_SHEAR
349 * @see #state
350 */
351 static final int APPLY_SCALE = 2;
352
353 /**
354 * This constant is used for the internal state variable to indicate
355 * that the shearing components of the matrix (m01 and m10) need
356 * to be factored in to complete the transformation equation of this
357 * transform. The presence of this bit in the state variable changes
358 * the interpretation of the APPLY_SCALE bit as indicated in its
359 * documentation.
360 * @see #APPLY_IDENTITY
361 * @see #APPLY_TRANSLATE
362 * @see #APPLY_SCALE
363 * @see #state
364 */
365 static final int APPLY_SHEAR = 4;
366
367 /*
368 * For methods which combine together the state of two separate
369 * transforms and dispatch based upon the combination, these constants
370 * specify how far to shift one of the states so that the two states
371 * are mutually non-interfering and provide constants for testing the
372 * bits of the shifted (HI) state. The methods in this class use
373 * the convention that the state of "this" transform is unshifted and
374 * the state of the "other" or "argument" transform is shifted (HI).
375 */
376 private static final int HI_SHIFT = 3;
377 private static final int HI_IDENTITY = APPLY_IDENTITY << HI_SHIFT;
378 private static final int HI_TRANSLATE = APPLY_TRANSLATE << HI_SHIFT;
379 private static final int HI_SCALE = APPLY_SCALE << HI_SHIFT;
380 private static final int HI_SHEAR = APPLY_SHEAR << HI_SHIFT;
381
382 /**
383 * The X coordinate scaling element of the 3x3
384 * affine transformation matrix.
385 *
386 * @serial
387 */
388 double m00;
389
390 /**
391 * The Y coordinate shearing element of the 3x3
392 * affine transformation matrix.
393 *
394 * @serial
395 */
396 double m10;
397
398 /**
399 * The X coordinate shearing element of the 3x3
400 * affine transformation matrix.
401 *
402 * @serial
403 */
404 double m01;
405
406 /**
407 * The Y coordinate scaling element of the 3x3
408 * affine transformation matrix.
409 *
410 * @serial
411 */
412 double m11;
413
414 /**
415 * The X coordinate of the translation element of the
416 * 3x3 affine transformation matrix.
417 *
418 * @serial
419 */
420 double m02;
421
422 /**
423 * The Y coordinate of the translation element of the
424 * 3x3 affine transformation matrix.
425 *
426 * @serial
427 */
428 double m12;
429
430 /**
431 * This field keeps track of which components of the matrix need to
432 * be applied when performing a transformation.
433 * @see #APPLY_IDENTITY
434 * @see #APPLY_TRANSLATE
435 * @see #APPLY_SCALE
436 * @see #APPLY_SHEAR
437 */
438 transient int state;
439
440 /**
441 * This field caches the current transformation type of the matrix.
442 * @see #TYPE_IDENTITY
443 * @see #TYPE_TRANSLATION
444 * @see #TYPE_UNIFORM_SCALE
445 * @see #TYPE_GENERAL_SCALE
446 * @see #TYPE_FLIP
447 * @see #TYPE_QUADRANT_ROTATION
448 * @see #TYPE_GENERAL_ROTATION
449 * @see #TYPE_GENERAL_TRANSFORM
450 * @see #TYPE_UNKNOWN
451 * @see #getType
452 */
453 private transient int type;
454
455 private AffineTransform(double m00, double m10,
456 double m01, double m11,
457 double m02, double m12,
458 int state) {
459 this.m00 = m00;
460 this.m10 = m10;
461 this.m01 = m01;
462 this.m11 = m11;
463 this.m02 = m02;
464 this.m12 = m12;
465 this.state = state;
466 this.type = TYPE_UNKNOWN;
467 }
468
469 /**
470 * Constructs a new <code>AffineTransform</code> representing the
471 * Identity transformation.
472 * @since 1.2
473 */
474 public AffineTransform() {
475 m00 = m11 = 1.0;
476 // m01 = m10 = m02 = m12 = 0.0; /* Not needed. */
477 // state = APPLY_IDENTITY; /* Not needed. */
478 // type = TYPE_IDENTITY; /* Not needed. */
479 }
480
481 /**
482 * Constructs a new <code>AffineTransform</code> that is a copy of
483 * the specified <code>AffineTransform</code> object.
484 * @param Tx the <code>AffineTransform</code> object to copy
485 * @since 1.2
486 */
487 public AffineTransform(AffineTransform Tx) {
488 this.m00 = Tx.m00;
489 this.m10 = Tx.m10;
490 this.m01 = Tx.m01;
491 this.m11 = Tx.m11;
492 this.m02 = Tx.m02;
493 this.m12 = Tx.m12;
494 this.state = Tx.state;
495 this.type = Tx.type;
496 }
497
498 /**
499 * Constructs a new <code>AffineTransform</code> from 6 floating point
500 * values representing the 6 specifiable entries of the 3x3
501 * transformation matrix.
502 *
503 * @param m00 the X coordinate scaling element of the 3x3 matrix
504 * @param m10 the Y coordinate shearing element of the 3x3 matrix
505 * @param m01 the X coordinate shearing element of the 3x3 matrix
506 * @param m11 the Y coordinate scaling element of the 3x3 matrix
507 * @param m02 the X coordinate translation element of the 3x3 matrix
508 * @param m12 the Y coordinate translation element of the 3x3 matrix
509 * @since 1.2
510 */
511 public AffineTransform(float m00, float m10,
512 float m01, float m11,
513 float m02, float m12) {
514 this.m00 = m00;
515 this.m10 = m10;
516 this.m01 = m01;
517 this.m11 = m11;
518 this.m02 = m02;
519 this.m12 = m12;
520 updateState();
521 }
522
523 /**
524 * Constructs a new <code>AffineTransform</code> from an array of
525 * floating point values representing either the 4 non-translation
526 * enries or the 6 specifiable entries of the 3x3 transformation
527 * matrix. The values are retrieved from the array as
528 * { m00 m10 m01 m11 [m02 m12]}.
529 * @param flatmatrix the float array containing the values to be set
530 * in the new <code>AffineTransform</code> object. The length of the
531 * array is assumed to be at least 4. If the length of the array is
532 * less than 6, only the first 4 values are taken. If the length of
533 * the array is greater than 6, the first 6 values are taken.
534 * @since 1.2
535 */
536 public AffineTransform(float[] flatmatrix) {
537 m00 = flatmatrix[0];
538 m10 = flatmatrix[1];
539 m01 = flatmatrix[2];
540 m11 = flatmatrix[3];
541 if (flatmatrix.length > 5) {
542 m02 = flatmatrix[4];
543 m12 = flatmatrix[5];
544 }
545 updateState();
546 }
547
548 /**
549 * Constructs a new <code>AffineTransform</code> from 6 double
550 * precision values representing the 6 specifiable entries of the 3x3
551 * transformation matrix.
552 *
553 * @param m00 the X coordinate scaling element of the 3x3 matrix
554 * @param m10 the Y coordinate shearing element of the 3x3 matrix
555 * @param m01 the X coordinate shearing element of the 3x3 matrix
556 * @param m11 the Y coordinate scaling element of the 3x3 matrix
557 * @param m02 the X coordinate translation element of the 3x3 matrix
558 * @param m12 the Y coordinate translation element of the 3x3 matrix
559 * @since 1.2
560 */
561 public AffineTransform(double m00, double m10,
562 double m01, double m11,
563 double m02, double m12) {
564 this.m00 = m00;
565 this.m10 = m10;
566 this.m01 = m01;
567 this.m11 = m11;
568 this.m02 = m02;
569 this.m12 = m12;
570 updateState();
571 }
572
573 /**
574 * Constructs a new <code>AffineTransform</code> from an array of
575 * double precision values representing either the 4 non-translation
576 * entries or the 6 specifiable entries of the 3x3 transformation
577 * matrix. The values are retrieved from the array as
578 * { m00 m10 m01 m11 [m02 m12]}.
579 * @param flatmatrix the double array containing the values to be set
580 * in the new <code>AffineTransform</code> object. The length of the
581 * array is assumed to be at least 4. If the length of the array is
582 * less than 6, only the first 4 values are taken. If the length of
583 * the array is greater than 6, the first 6 values are taken.
584 * @since 1.2
585 */
586 public AffineTransform(double[] flatmatrix) {
587 m00 = flatmatrix[0];
588 m10 = flatmatrix[1];
589 m01 = flatmatrix[2];
590 m11 = flatmatrix[3];
591 if (flatmatrix.length > 5) {
592 m02 = flatmatrix[4];
593 m12 = flatmatrix[5];
594 }
595 updateState();
596 }
597
598 /**
599 * Returns a transform representing a translation transformation.
600 * The matrix representing the returned transform is:
601 * <pre>
602 * [ 1 0 tx ]
603 * [ 0 1 ty ]
604 * [ 0 0 1 ]
605 * </pre>
606 * @param tx the distance by which coordinates are translated in the
607 * X axis direction
608 * @param ty the distance by which coordinates are translated in the
609 * Y axis direction
610 * @return an <code>AffineTransform</code> object that represents a
611 * translation transformation, created with the specified vector.
612 * @since 1.2
613 */
614 public static AffineTransform getTranslateInstance(double tx, double ty) {
615 AffineTransform Tx = new AffineTransform();
616 Tx.setToTranslation(tx, ty);
617 return Tx;
618 }
619
620 /**
621 * Returns a transform representing a rotation transformation.
622 * The matrix representing the returned transform is:
623 * <pre>
624 * [ cos(theta) -sin(theta) 0 ]
625 * [ sin(theta) cos(theta) 0 ]
626 * [ 0 0 1 ]
627 * </pre>
628 * Rotating by a positive angle theta rotates points on the positive
629 * X axis toward the positive Y axis.
630 * Note also the discussion of
631 * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
632 * above.
633 * @param theta the angle of rotation measured in radians
634 * @return an <code>AffineTransform</code> object that is a rotation
635 * transformation, created with the specified angle of rotation.
636 * @since 1.2
637 */
638 public static AffineTransform getRotateInstance(double theta) {
639 AffineTransform Tx = new AffineTransform();
640 Tx.setToRotation(theta);
641 return Tx;
642 }
643
644 /**
645 * Returns a transform that rotates coordinates around an anchor point.
646 * This operation is equivalent to translating the coordinates so
647 * that the anchor point is at the origin (S1), then rotating them
648 * about the new origin (S2), and finally translating so that the
649 * intermediate origin is restored to the coordinates of the original
650 * anchor point (S3).
651 * <p>
652 * This operation is equivalent to the following sequence of calls:
653 * <pre>
654 * AffineTransform Tx = new AffineTransform();
655 * Tx.translate(anchorx, anchory); // S3: final translation
656 * Tx.rotate(theta); // S2: rotate around anchor
657 * Tx.translate(-anchorx, -anchory); // S1: translate anchor to origin
658 * </pre>
659 * The matrix representing the returned transform is:
660 * <pre>
661 * [ cos(theta) -sin(theta) x-x*cos+y*sin ]
662 * [ sin(theta) cos(theta) y-x*sin-y*cos ]
663 * [ 0 0 1 ]
664 * </pre>
665 * Rotating by a positive angle theta rotates points on the positive
666 * X axis toward the positive Y axis.
667 * Note also the discussion of
668 * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
669 * above.
670 *
671 * @param theta the angle of rotation measured in radians
672 * @param anchorx the X coordinate of the rotation anchor point
673 * @param anchory the Y coordinate of the rotation anchor point
674 * @return an <code>AffineTransform</code> object that rotates
675 * coordinates around the specified point by the specified angle of
676 * rotation.
677 * @since 1.2
678 */
679 public static AffineTransform getRotateInstance(double theta,
680 double anchorx,
681 double anchory)
682 {
683 AffineTransform Tx = new AffineTransform();
684 Tx.setToRotation(theta, anchorx, anchory);
685 return Tx;
686 }
687
688 /**
689 * Returns a transform that rotates coordinates according to
690 * a rotation vector.
691 * All coordinates rotate about the origin by the same amount.
692 * The amount of rotation is such that coordinates along the former
693 * positive X axis will subsequently align with the vector pointing
694 * from the origin to the specified vector coordinates.
695 * If both <code>vecx</code> and <code>vecy</code> are 0.0,
696 * an identity transform is returned.
697 * This operation is equivalent to calling:
698 * <pre>
699 * AffineTransform.getRotateInstance(Math.atan2(vecy, vecx));
700 * </pre>
701 *
702 * @param vecx the X coordinate of the rotation vector
703 * @param vecy the Y coordinate of the rotation vector
704 * @return an <code>AffineTransform</code> object that rotates
705 * coordinates according to the specified rotation vector.
706 * @since 1.6
707 */
708 public static AffineTransform getRotateInstance(double vecx, double vecy) {
709 AffineTransform Tx = new AffineTransform();
710 Tx.setToRotation(vecx, vecy);
711 return Tx;
712 }
713
714 /**
715 * Returns a transform that rotates coordinates around an anchor
716 * point accordinate to a rotation vector.
717 * All coordinates rotate about the specified anchor coordinates
718 * by the same amount.
719 * The amount of rotation is such that coordinates along the former
720 * positive X axis will subsequently align with the vector pointing
721 * from the origin to the specified vector coordinates.
722 * If both <code>vecx</code> and <code>vecy</code> are 0.0,
723 * an identity transform is returned.
724 * This operation is equivalent to calling:
725 * <pre>
726 * AffineTransform.getRotateInstance(Math.atan2(vecy, vecx),
727 * anchorx, anchory);
728 * </pre>
729 *
730 * @param vecx the X coordinate of the rotation vector
731 * @param vecy the Y coordinate of the rotation vector
732 * @param anchorx the X coordinate of the rotation anchor point
733 * @param anchory the Y coordinate of the rotation anchor point
734 * @return an <code>AffineTransform</code> object that rotates
735 * coordinates around the specified point according to the
736 * specified rotation vector.
737 * @since 1.6
738 */
739 public static AffineTransform getRotateInstance(double vecx,
740 double vecy,
741 double anchorx,
742 double anchory)
743 {
744 AffineTransform Tx = new AffineTransform();
745 Tx.setToRotation(vecx, vecy, anchorx, anchory);
746 return Tx;
747 }
748
749 /**
750 * Returns a transform that rotates coordinates by the specified
751 * number of quadrants.
752 * This operation is equivalent to calling:
753 * <pre>
754 * AffineTransform.getRotateInstance(numquadrants * Math.PI / 2.0);
755 * </pre>
756 * Rotating by a positive number of quadrants rotates points on
757 * the positive X axis toward the positive Y axis.
758 * @param numquadrants the number of 90 degree arcs to rotate by
759 * @return an <code>AffineTransform</code> object that rotates
760 * coordinates by the specified number of quadrants.
761 * @since 1.6
762 */
763 public static AffineTransform getQuadrantRotateInstance(int numquadrants) {
764 AffineTransform Tx = new AffineTransform();
765 Tx.setToQuadrantRotation(numquadrants);
766 return Tx;
767 }
768
769 /**
770 * Returns a transform that rotates coordinates by the specified
771 * number of quadrants around the specified anchor point.
772 * This operation is equivalent to calling:
773 * <pre>
774 * AffineTransform.getRotateInstance(numquadrants * Math.PI / 2.0,
775 * anchorx, anchory);
776 * </pre>
777 * Rotating by a positive number of quadrants rotates points on
778 * the positive X axis toward the positive Y axis.
779 *
780 * @param numquadrants the number of 90 degree arcs to rotate by
781 * @param anchorx the X coordinate of the rotation anchor point
782 * @param anchory the Y coordinate of the rotation anchor point
783 * @return an <code>AffineTransform</code> object that rotates
784 * coordinates by the specified number of quadrants around the
785 * specified anchor point.
786 * @since 1.6
787 */
788 public static AffineTransform getQuadrantRotateInstance(int numquadrants,
789 double anchorx,
790 double anchory)
791 {
792 AffineTransform Tx = new AffineTransform();
793 Tx.setToQuadrantRotation(numquadrants, anchorx, anchory);
794 return Tx;
795 }
796
797 /**
798 * Returns a transform representing a scaling transformation.
799 * The matrix representing the returned transform is:
800 * <pre>
801 * [ sx 0 0 ]
802 * [ 0 sy 0 ]
803 * [ 0 0 1 ]
804 * </pre>
805 * @param sx the factor by which coordinates are scaled along the
806 * X axis direction
807 * @param sy the factor by which coordinates are scaled along the
808 * Y axis direction
809 * @return an <code>AffineTransform</code> object that scales
810 * coordinates by the specified factors.
811 * @since 1.2
812 */
813 public static AffineTransform getScaleInstance(double sx, double sy) {
814 AffineTransform Tx = new AffineTransform();
815 Tx.setToScale(sx, sy);
816 return Tx;
817 }
818
819 /**
820 * Returns a transform representing a shearing transformation.
821 * The matrix representing the returned transform is:
822 * <pre>
823 * [ 1 shx 0 ]
824 * [ shy 1 0 ]
825 * [ 0 0 1 ]
826 * </pre>
827 * @param shx the multiplier by which coordinates are shifted in the
828 * direction of the positive X axis as a factor of their Y coordinate
829 * @param shy the multiplier by which coordinates are shifted in the
830 * direction of the positive Y axis as a factor of their X coordinate
831 * @return an <code>AffineTransform</code> object that shears
832 * coordinates by the specified multipliers.
833 * @since 1.2
834 */
835 public static AffineTransform getShearInstance(double shx, double shy) {
836 AffineTransform Tx = new AffineTransform();
837 Tx.setToShear(shx, shy);
838 return Tx;
839 }
840
841 /**
842 * Retrieves the flag bits describing the conversion properties of
843 * this transform.
844 * The return value is either one of the constants TYPE_IDENTITY
845 * or TYPE_GENERAL_TRANSFORM, or a combination of the
846 * appriopriate flag bits.
847 * A valid combination of flag bits is an exclusive OR operation
848 * that can combine
849 * the TYPE_TRANSLATION flag bit
850 * in addition to either of the
851 * TYPE_UNIFORM_SCALE or TYPE_GENERAL_SCALE flag bits
852 * as well as either of the
853 * TYPE_QUADRANT_ROTATION or TYPE_GENERAL_ROTATION flag bits.
854 * @return the OR combination of any of the indicated flags that
855 * apply to this transform
856 * @see #TYPE_IDENTITY
857 * @see #TYPE_TRANSLATION
858 * @see #TYPE_UNIFORM_SCALE
859 * @see #TYPE_GENERAL_SCALE
860 * @see #TYPE_QUADRANT_ROTATION
861 * @see #TYPE_GENERAL_ROTATION
862 * @see #TYPE_GENERAL_TRANSFORM
863 * @since 1.2
864 */
865 public int getType() {
866 if (type == TYPE_UNKNOWN) {
867 calculateType();
868 }
869 return type;
870 }
871
872 /**
873 * This is the utility function to calculate the flag bits when
874 * they have not been cached.
875 * @see #getType
876 */
877 private void calculateType() {
878 int ret = TYPE_IDENTITY;
879 boolean sgn0, sgn1;
880 double M0, M1, M2, M3;
881 updateState();
882 switch (state) {
883 default:
884 stateError();
885 /* NOTREACHED */
886 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
887 ret = TYPE_TRANSLATION;
888 /* NOBREAK */
889 case (APPLY_SHEAR | APPLY_SCALE):
890 if ((M0 = m00) * (M2 = m01) + (M3 = m10) * (M1 = m11) != 0) {
891 // Transformed unit vectors are not perpendicular...
892 this.type = TYPE_GENERAL_TRANSFORM;
893 return;
894 }
895 sgn0 = (M0 >= 0.0);
896 sgn1 = (M1 >= 0.0);
897 if (sgn0 == sgn1) {
898 // sgn(M0) == sgn(M1) therefore sgn(M2) == -sgn(M3)
899 // This is the "unflipped" (right-handed) state
900 if (M0 != M1 || M2 != -M3) {
901 ret |= (TYPE_GENERAL_ROTATION | TYPE_GENERAL_SCALE);
902 } else if (M0 * M1 - M2 * M3 != 1.0) {
903 ret |= (TYPE_GENERAL_ROTATION | TYPE_UNIFORM_SCALE);
904 } else {
905 ret |= TYPE_GENERAL_ROTATION;
906 }
907 } else {
908 // sgn(M0) == -sgn(M1) therefore sgn(M2) == sgn(M3)
909 // This is the "flipped" (left-handed) state
910 if (M0 != -M1 || M2 != M3) {
911 ret |= (TYPE_GENERAL_ROTATION |
912 TYPE_FLIP |
913 TYPE_GENERAL_SCALE);
914 } else if (M0 * M1 - M2 * M3 != 1.0) {
915 ret |= (TYPE_GENERAL_ROTATION |
916 TYPE_FLIP |
917 TYPE_UNIFORM_SCALE);
918 } else {
919 ret |= (TYPE_GENERAL_ROTATION | TYPE_FLIP);
920 }
921 }
922 break;
923 case (APPLY_SHEAR | APPLY_TRANSLATE):
924 ret = TYPE_TRANSLATION;
925 /* NOBREAK */
926 case (APPLY_SHEAR):
927 sgn0 = ((M0 = m01) >= 0.0);
928 sgn1 = ((M1 = m10) >= 0.0);
929 if (sgn0 != sgn1) {
930 // Different signs - simple 90 degree rotation
931 if (M0 != -M1) {
932 ret |= (TYPE_QUADRANT_ROTATION | TYPE_GENERAL_SCALE);
933 } else if (M0 != 1.0 && M0 != -1.0) {
934 ret |= (TYPE_QUADRANT_ROTATION | TYPE_UNIFORM_SCALE);
935 } else {
936 ret |= TYPE_QUADRANT_ROTATION;
937 }
938 } else {
939 // Same signs - 90 degree rotation plus an axis flip too
940 if (M0 == M1) {
941 ret |= (TYPE_QUADRANT_ROTATION |
942 TYPE_FLIP |
943 TYPE_UNIFORM_SCALE);
944 } else {
945 ret |= (TYPE_QUADRANT_ROTATION |
946 TYPE_FLIP |
947 TYPE_GENERAL_SCALE);
948 }
949 }
950 break;
951 case (APPLY_SCALE | APPLY_TRANSLATE):
952 ret = TYPE_TRANSLATION;
953 /* NOBREAK */
954 case (APPLY_SCALE):
955 sgn0 = ((M0 = m00) >= 0.0);
956 sgn1 = ((M1 = m11) >= 0.0);
957 if (sgn0 == sgn1) {
958 if (sgn0) {
959 // Both scaling factors non-negative - simple scale
960 // Note: APPLY_SCALE implies M0, M1 are not both 1
961 if (M0 == M1) {
962 ret |= TYPE_UNIFORM_SCALE;
963 } else {
964 ret |= TYPE_GENERAL_SCALE;
965 }
966 } else {
967 // Both scaling factors negative - 180 degree rotation
968 if (M0 != M1) {
969 ret |= (TYPE_QUADRANT_ROTATION | TYPE_GENERAL_SCALE);
970 } else if (M0 != -1.0) {
971 ret |= (TYPE_QUADRANT_ROTATION | TYPE_UNIFORM_SCALE);
972 } else {
973 ret |= TYPE_QUADRANT_ROTATION;
974 }
975 }
976 } else {
977 // Scaling factor signs different - flip about some axis
978 if (M0 == -M1) {
979 if (M0 == 1.0 || M0 == -1.0) {
980 ret |= TYPE_FLIP;
981 } else {
982 ret |= (TYPE_FLIP | TYPE_UNIFORM_SCALE);
983 }
984 } else {
985 ret |= (TYPE_FLIP | TYPE_GENERAL_SCALE);
986 }
987 }
988 break;
989 case (APPLY_TRANSLATE):
990 ret = TYPE_TRANSLATION;
991 break;
992 case (APPLY_IDENTITY):
993 break;
994 }
995 this.type = ret;
996 }
997
998 /**
999 * Returns the determinant of the matrix representation of the transform.
1000 * The determinant is useful both to determine if the transform can
1001 * be inverted and to get a single value representing the
1002 * combined X and Y scaling of the transform.
1003 * <p>
1004 * If the determinant is non-zero, then this transform is
1005 * invertible and the various methods that depend on the inverse
1006 * transform do not need to throw a
1007 * {@link NoninvertibleTransformException}.
1008 * If the determinant is zero then this transform can not be
1009 * inverted since the transform maps all input coordinates onto
1010 * a line or a point.
1011 * If the determinant is near enough to zero then inverse transform
1012 * operations might not carry enough precision to produce meaningful
1013 * results.
1014 * <p>
1015 * If this transform represents a uniform scale, as indicated by
1016 * the <code>getType</code> method then the determinant also
1017 * represents the square of the uniform scale factor by which all of
1018 * the points are expanded from or contracted towards the origin.
1019 * If this transform represents a non-uniform scale or more general
1020 * transform then the determinant is not likely to represent a
1021 * value useful for any purpose other than determining if inverse
1022 * transforms are possible.
1023 * <p>
1024 * Mathematically, the determinant is calculated using the formula:
1025 * <pre>
1026 * | m00 m01 m02 |
1027 * | m10 m11 m12 | = m00 * m11 - m01 * m10
1028 * | 0 0 1 |
1029 * </pre>
1030 *
1031 * @return the determinant of the matrix used to transform the
1032 * coordinates.
1033 * @see #getType
1034 * @see #createInverse
1035 * @see #inverseTransform
1036 * @see #TYPE_UNIFORM_SCALE
1037 * @since 1.2
1038 */
1039 public double getDeterminant() {
1040 switch (state) {
1041 default:
1042 stateError();
1043 /* NOTREACHED */
1044 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1045 case (APPLY_SHEAR | APPLY_SCALE):
1046 return m00 * m11 - m01 * m10;
1047 case (APPLY_SHEAR | APPLY_TRANSLATE):
1048 case (APPLY_SHEAR):
1049 return -(m01 * m10);
1050 case (APPLY_SCALE | APPLY_TRANSLATE):
1051 case (APPLY_SCALE):
1052 return m00 * m11;
1053 case (APPLY_TRANSLATE):
1054 case (APPLY_IDENTITY):
1055 return 1.0;
1056 }
1057 }
1058
1059 /**
1060 * Manually recalculates the state of the transform when the matrix
1061 * changes too much to predict the effects on the state.
1062 * The following table specifies what the various settings of the
1063 * state field say about the values of the corresponding matrix
1064 * element fields.
1065 * Note that the rules governing the SCALE fields are slightly
1066 * different depending on whether the SHEAR flag is also set.
1067 * <pre>
1068 * SCALE SHEAR TRANSLATE
1069 * m00/m11 m01/m10 m02/m12
1070 *
1071 * IDENTITY 1.0 0.0 0.0
1072 * TRANSLATE (TR) 1.0 0.0 not both 0.0
1073 * SCALE (SC) not both 1.0 0.0 0.0
1074 * TR | SC not both 1.0 0.0 not both 0.0
1075 * SHEAR (SH) 0.0 not both 0.0 0.0
1076 * TR | SH 0.0 not both 0.0 not both 0.0
1077 * SC | SH not both 0.0 not both 0.0 0.0
1078 * TR | SC | SH not both 0.0 not both 0.0 not both 0.0
1079 * </pre>
1080 */
1081 void updateState() {
1082 if (m01 == 0.0 && m10 == 0.0) {
1083 if (m00 == 1.0 && m11 == 1.0) {
1084 if (m02 == 0.0 && m12 == 0.0) {
1085 state = APPLY_IDENTITY;
1086 type = TYPE_IDENTITY;
1087 } else {
1088 state = APPLY_TRANSLATE;
1089 type = TYPE_TRANSLATION;
1090 }
1091 } else {
1092 if (m02 == 0.0 && m12 == 0.0) {
1093 state = APPLY_SCALE;
1094 type = TYPE_UNKNOWN;
1095 } else {
1096 state = (APPLY_SCALE | APPLY_TRANSLATE);
1097 type = TYPE_UNKNOWN;
1098 }
1099 }
1100 } else {
1101 if (m00 == 0.0 && m11 == 0.0) {
1102 if (m02 == 0.0 && m12 == 0.0) {
1103 state = APPLY_SHEAR;
1104 type = TYPE_UNKNOWN;
1105 } else {
1106 state = (APPLY_SHEAR | APPLY_TRANSLATE);
1107 type = TYPE_UNKNOWN;
1108 }
1109 } else {
1110 if (m02 == 0.0 && m12 == 0.0) {
1111 state = (APPLY_SHEAR | APPLY_SCALE);
1112 type = TYPE_UNKNOWN;
1113 } else {
1114 state = (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE);
1115 type = TYPE_UNKNOWN;
1116 }
1117 }
1118 }
1119 }
1120
1121 /*
1122 * Convenience method used internally to throw exceptions when
1123 * a case was forgotten in a switch statement.
1124 */
1125 private void stateError() {
1126 throw new InternalError("missing case in transform state switch");
1127 }
1128
1129 /**
1130 * Retrieves the 6 specifiable values in the 3x3 affine transformation
1131 * matrix and places them into an array of double precisions values.
1132 * The values are stored in the array as
1133 * { m00 m10 m01 m11 m02 m12 }.
1134 * An array of 4 doubles can also be specified, in which case only the
1135 * first four elements representing the non-transform
1136 * parts of the array are retrieved and the values are stored into
1137 * the array as { m00 m10 m01 m11 }
1138 * @param flatmatrix the double array used to store the returned
1139 * values.
1140 * @see #getScaleX
1141 * @see #getScaleY
1142 * @see #getShearX
1143 * @see #getShearY
1144 * @see #getTranslateX
1145 * @see #getTranslateY
1146 * @since 1.2
1147 */
1148 public void getMatrix(double[] flatmatrix) {
1149 flatmatrix[0] = m00;
1150 flatmatrix[1] = m10;
1151 flatmatrix[2] = m01;
1152 flatmatrix[3] = m11;
1153 if (flatmatrix.length > 5) {
1154 flatmatrix[4] = m02;
1155 flatmatrix[5] = m12;
1156 }
1157 }
1158
1159 /**
1160 * Returns the X coordinate scaling element (m00) of the 3x3
1161 * affine transformation matrix.
1162 * @return a double value that is the X coordinate of the scaling
1163 * element of the affine transformation matrix.
1164 * @see #getMatrix
1165 * @since 1.2
1166 */
1167 public double getScaleX() {
1168 return m00;
1169 }
1170
1171 /**
1172 * Returns the Y coordinate scaling element (m11) of the 3x3
1173 * affine transformation matrix.
1174 * @return a double value that is the Y coordinate of the scaling
1175 * element of the affine transformation matrix.
1176 * @see #getMatrix
1177 * @since 1.2
1178 */
1179 public double getScaleY() {
1180 return m11;
1181 }
1182
1183 /**
1184 * Returns the X coordinate shearing element (m01) of the 3x3
1185 * affine transformation matrix.
1186 * @return a double value that is the X coordinate of the shearing
1187 * element of the affine transformation matrix.
1188 * @see #getMatrix
1189 * @since 1.2
1190 */
1191 public double getShearX() {
1192 return m01;
1193 }
1194
1195 /**
1196 * Returns the Y coordinate shearing element (m10) of the 3x3
1197 * affine transformation matrix.
1198 * @return a double value that is the Y coordinate of the shearing
1199 * element of the affine transformation matrix.
1200 * @see #getMatrix
1201 * @since 1.2
1202 */
1203 public double getShearY() {
1204 return m10;
1205 }
1206
1207 /**
1208 * Returns the X coordinate of the translation element (m02) of the
1209 * 3x3 affine transformation matrix.
1210 * @return a double value that is the X coordinate of the translation
1211 * element of the affine transformation matrix.
1212 * @see #getMatrix
1213 * @since 1.2
1214 */
1215 public double getTranslateX() {
1216 return m02;
1217 }
1218
1219 /**
1220 * Returns the Y coordinate of the translation element (m12) of the
1221 * 3x3 affine transformation matrix.
1222 * @return a double value that is the Y coordinate of the translation
1223 * element of the affine transformation matrix.
1224 * @see #getMatrix
1225 * @since 1.2
1226 */
1227 public double getTranslateY() {
1228 return m12;
1229 }
1230
1231 /**
1232 * Concatenates this transform with a translation transformation.
1233 * This is equivalent to calling concatenate(T), where T is an
1234 * <code>AffineTransform</code> represented by the following matrix:
1235 * <pre>
1236 * [ 1 0 tx ]
1237 * [ 0 1 ty ]
1238 * [ 0 0 1 ]
1239 * </pre>
1240 * @param tx the distance by which coordinates are translated in the
1241 * X axis direction
1242 * @param ty the distance by which coordinates are translated in the
1243 * Y axis direction
1244 * @since 1.2
1245 */
1246 public void translate(double tx, double ty) {
1247 switch (state) {
1248 default:
1249 stateError();
1250 /* NOTREACHED */
1251 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1252 m02 = tx * m00 + ty * m01 + m02;
1253 m12 = tx * m10 + ty * m11 + m12;
1254 if (m02 == 0.0 && m12 == 0.0) {
1255 state = APPLY_SHEAR | APPLY_SCALE;
1256 if (type != TYPE_UNKNOWN) {
1257 type -= TYPE_TRANSLATION;
1258 }
1259 }
1260 return;
1261 case (APPLY_SHEAR | APPLY_SCALE):
1262 m02 = tx * m00 + ty * m01;
1263 m12 = tx * m10 + ty * m11;
1264 if (m02 != 0.0 || m12 != 0.0) {
1265 state = APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE;
1266 type |= TYPE_TRANSLATION;
1267 }
1268 return;
1269 case (APPLY_SHEAR | APPLY_TRANSLATE):
1270 m02 = ty * m01 + m02;
1271 m12 = tx * m10 + m12;
1272 if (m02 == 0.0 && m12 == 0.0) {
1273 state = APPLY_SHEAR;
1274 if (type != TYPE_UNKNOWN) {
1275 type -= TYPE_TRANSLATION;
1276 }
1277 }
1278 return;
1279 case (APPLY_SHEAR):
1280 m02 = ty * m01;
1281 m12 = tx * m10;
1282 if (m02 != 0.0 || m12 != 0.0) {
1283 state = APPLY_SHEAR | APPLY_TRANSLATE;
1284 type |= TYPE_TRANSLATION;
1285 }
1286 return;
1287 case (APPLY_SCALE | APPLY_TRANSLATE):
1288 m02 = tx * m00 + m02;
1289 m12 = ty * m11 + m12;
1290 if (m02 == 0.0 && m12 == 0.0) {
1291 state = APPLY_SCALE;
1292 if (type != TYPE_UNKNOWN) {
1293 type -= TYPE_TRANSLATION;
1294 }
1295 }
1296 return;
1297 case (APPLY_SCALE):
1298 m02 = tx * m00;
1299 m12 = ty * m11;
1300 if (m02 != 0.0 || m12 != 0.0) {
1301 state = APPLY_SCALE | APPLY_TRANSLATE;
1302 type |= TYPE_TRANSLATION;
1303 }
1304 return;
1305 case (APPLY_TRANSLATE):
1306 m02 = tx + m02;
1307 m12 = ty + m12;
1308 if (m02 == 0.0 && m12 == 0.0) {
1309 state = APPLY_IDENTITY;
1310 type = TYPE_IDENTITY;
1311 }
1312 return;
1313 case (APPLY_IDENTITY):
1314 m02 = tx;
1315 m12 = ty;
1316 if (tx != 0.0 || ty != 0.0) {
1317 state = APPLY_TRANSLATE;
1318 type = TYPE_TRANSLATION;
1319 }
1320 return;
1321 }
1322 }
1323
1324 // Utility methods to optimize rotate methods.
1325 // These tables translate the flags during predictable quadrant
1326 // rotations where the shear and scale values are swapped and negated.
1327 private static final int rot90conversion[] = {
1328 /* IDENTITY => */ APPLY_SHEAR,
1329 /* TRANSLATE (TR) => */ APPLY_SHEAR | APPLY_TRANSLATE,
1330 /* SCALE (SC) => */ APPLY_SHEAR,
1331 /* SC | TR => */ APPLY_SHEAR | APPLY_TRANSLATE,
1332 /* SHEAR (SH) => */ APPLY_SCALE,
1333 /* SH | TR => */ APPLY_SCALE | APPLY_TRANSLATE,
1334 /* SH | SC => */ APPLY_SHEAR | APPLY_SCALE,
1335 /* SH | SC | TR => */ APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE,
1336 };
1337 private final void rotate90() {
1338 double M0 = m00;
1339 m00 = m01;
1340 m01 = -M0;
1341 M0 = m10;
1342 m10 = m11;
1343 m11 = -M0;
1344 int state = rot90conversion[this.state];
1345 if ((state & (APPLY_SHEAR | APPLY_SCALE)) == APPLY_SCALE &&
1346 m00 == 1.0 && m11 == 1.0)
1347 {
1348 state -= APPLY_SCALE;
1349 }
1350 this.state = state;
1351 type = TYPE_UNKNOWN;
1352 }
1353 private final void rotate180() {
1354 m00 = -m00;
1355 m11 = -m11;
1356 int state = this.state;
1357 if ((state & (APPLY_SHEAR)) != 0) {
1358 // If there was a shear, then this rotation has no
1359 // effect on the state.
1360 m01 = -m01;
1361 m10 = -m10;
1362 } else {
1363 // No shear means the SCALE state may toggle when
1364 // m00 and m11 are negated.
1365 if (m00 == 1.0 && m11 == 1.0) {
1366 this.state = state & ~APPLY_SCALE;
1367 } else {
1368 this.state = state | APPLY_SCALE;
1369 }
1370 }
1371 type = TYPE_UNKNOWN;
1372 }
1373 private final void rotate270() {
1374 double M0 = m00;
1375 m00 = -m01;
1376 m01 = M0;
1377 M0 = m10;
1378 m10 = -m11;
1379 m11 = M0;
1380 int state = rot90conversion[this.state];
1381 if ((state & (APPLY_SHEAR | APPLY_SCALE)) == APPLY_SCALE &&
1382 m00 == 1.0 && m11 == 1.0)
1383 {
1384 state -= APPLY_SCALE;
1385 }
1386 this.state = state;
1387 type = TYPE_UNKNOWN;
1388 }
1389
1390 /**
1391 * Concatenates this transform with a rotation transformation.
1392 * This is equivalent to calling concatenate(R), where R is an
1393 * <code>AffineTransform</code> represented by the following matrix:
1394 * <pre>
1395 * [ cos(theta) -sin(theta) 0 ]
1396 * [ sin(theta) cos(theta) 0 ]
1397 * [ 0 0 1 ]
1398 * </pre>
1399 * Rotating by a positive angle theta rotates points on the positive
1400 * X axis toward the positive Y axis.
1401 * Note also the discussion of
1402 * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
1403 * above.
1404 * @param theta the angle of rotation measured in radians
1405 * @since 1.2
1406 */
1407 public void rotate(double theta) {
1408 double sin = Math.sin(theta);
1409 if (sin == 1.0) {
1410 rotate90();
1411 } else if (sin == -1.0) {
1412 rotate270();
1413 } else {
1414 double cos = Math.cos(theta);
1415 if (cos == -1.0) {
1416 rotate180();
1417 } else if (cos != 1.0) {
1418 double M0, M1;
1419 M0 = m00;
1420 M1 = m01;
1421 m00 = cos * M0 + sin * M1;
1422 m01 = -sin * M0 + cos * M1;
1423 M0 = m10;
1424 M1 = m11;
1425 m10 = cos * M0 + sin * M1;
1426 m11 = -sin * M0 + cos * M1;
1427 updateState();
1428 }
1429 }
1430 }
1431
1432 /**
1433 * Concatenates this transform with a transform that rotates
1434 * coordinates around an anchor point.
1435 * This operation is equivalent to translating the coordinates so
1436 * that the anchor point is at the origin (S1), then rotating them
1437 * about the new origin (S2), and finally translating so that the
1438 * intermediate origin is restored to the coordinates of the original
1439 * anchor point (S3).
1440 * <p>
1441 * This operation is equivalent to the following sequence of calls:
1442 * <pre>
1443 * translate(anchorx, anchory); // S3: final translation
1444 * rotate(theta); // S2: rotate around anchor
1445 * translate(-anchorx, -anchory); // S1: translate anchor to origin
1446 * </pre>
1447 * Rotating by a positive angle theta rotates points on the positive
1448 * X axis toward the positive Y axis.
1449 * Note also the discussion of
1450 * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
1451 * above.
1452 *
1453 * @param theta the angle of rotation measured in radians
1454 * @param anchorx the X coordinate of the rotation anchor point
1455 * @param anchory the Y coordinate of the rotation anchor point
1456 * @since 1.2
1457 */
1458 public void rotate(double theta, double anchorx, double anchory) {
1459 // REMIND: Simple for now - optimize later
1460 translate(anchorx, anchory);
1461 rotate(theta);
1462 translate(-anchorx, -anchory);
1463 }
1464
1465 /**
1466 * Concatenates this transform with a transform that rotates
1467 * coordinates according to a rotation vector.
1468 * All coordinates rotate about the origin by the same amount.
1469 * The amount of rotation is such that coordinates along the former
1470 * positive X axis will subsequently align with the vector pointing
1471 * from the origin to the specified vector coordinates.
1472 * If both <code>vecx</code> and <code>vecy</code> are 0.0,
1473 * no additional rotation is added to this transform.
1474 * This operation is equivalent to calling:
1475 * <pre>
1476 * rotate(Math.atan2(vecy, vecx));
1477 * </pre>
1478 *
1479 * @param vecx the X coordinate of the rotation vector
1480 * @param vecy the Y coordinate of the rotation vector
1481 * @since 1.6
1482 */
1483 public void rotate(double vecx, double vecy) {
1484 if (vecy == 0.0) {
1485 if (vecx < 0.0) {
1486 rotate180();
1487 }
1488 // If vecx > 0.0 - no rotation
1489 // If vecx == 0.0 - undefined rotation - treat as no rotation
1490 } else if (vecx == 0.0) {
1491 if (vecy > 0.0) {
1492 rotate90();
1493 } else { // vecy must be < 0.0
1494 rotate270();
1495 }
1496 } else {
1497 double len = Math.sqrt(vecx * vecx + vecy * vecy);
1498 double sin = vecy / len;
1499 double cos = vecx / len;
1500 double M0, M1;
1501 M0 = m00;
1502 M1 = m01;
1503 m00 = cos * M0 + sin * M1;
1504 m01 = -sin * M0 + cos * M1;
1505 M0 = m10;
1506 M1 = m11;
1507 m10 = cos * M0 + sin * M1;
1508 m11 = -sin * M0 + cos * M1;
1509 updateState();
1510 }
1511 }
1512
1513 /**
1514 * Concatenates this transform with a transform that rotates
1515 * coordinates around an anchor point according to a rotation
1516 * vector.
1517 * All coordinates rotate about the specified anchor coordinates
1518 * by the same amount.
1519 * The amount of rotation is such that coordinates along the former
1520 * positive X axis will subsequently align with the vector pointing
1521 * from the origin to the specified vector coordinates.
1522 * If both <code>vecx</code> and <code>vecy</code> are 0.0,
1523 * the transform is not modified in any way.
1524 * This method is equivalent to calling:
1525 * <pre>
1526 * rotate(Math.atan2(vecy, vecx), anchorx, anchory);
1527 * </pre>
1528 *
1529 * @param vecx the X coordinate of the rotation vector
1530 * @param vecy the Y coordinate of the rotation vector
1531 * @param anchorx the X coordinate of the rotation anchor point
1532 * @param anchory the Y coordinate of the rotation anchor point
1533 * @since 1.6
1534 */
1535 public void rotate(double vecx, double vecy,
1536 double anchorx, double anchory)
1537 {
1538 // REMIND: Simple for now - optimize later
1539 translate(anchorx, anchory);
1540 rotate(vecx, vecy);
1541 translate(-anchorx, -anchory);
1542 }
1543
1544 /**
1545 * Concatenates this transform with a transform that rotates
1546 * coordinates by the specified number of quadrants.
1547 * This is equivalent to calling:
1548 * <pre>
1549 * rotate(numquadrants * Math.PI / 2.0);
1550 * </pre>
1551 * Rotating by a positive number of quadrants rotates points on
1552 * the positive X axis toward the positive Y axis.
1553 * @param numquadrants the number of 90 degree arcs to rotate by
1554 * @since 1.6
1555 */
1556 public void quadrantRotate(int numquadrants) {
1557 switch (numquadrants & 3) {
1558 case 0:
1559 break;
1560 case 1:
1561 rotate90();
1562 break;
1563 case 2:
1564 rotate180();
1565 break;
1566 case 3:
1567 rotate270();
1568 break;
1569 }
1570 }
1571
1572 /**
1573 * Concatenates this transform with a transform that rotates
1574 * coordinates by the specified number of quadrants around
1575 * the specified anchor point.
1576 * This method is equivalent to calling:
1577 * <pre>
1578 * rotate(numquadrants * Math.PI / 2.0, anchorx, anchory);
1579 * </pre>
1580 * Rotating by a positive number of quadrants rotates points on
1581 * the positive X axis toward the positive Y axis.
1582 *
1583 * @param numquadrants the number of 90 degree arcs to rotate by
1584 * @param anchorx the X coordinate of the rotation anchor point
1585 * @param anchory the Y coordinate of the rotation anchor point
1586 * @since 1.6
1587 */
1588 public void quadrantRotate(int numquadrants,
1589 double anchorx, double anchory)
1590 {
1591 switch (numquadrants & 3) {
1592 case 0:
1593 return;
1594 case 1:
1595 m02 += anchorx * (m00 - m01) + anchory * (m01 + m00);
1596 m12 += anchorx * (m10 - m11) + anchory * (m11 + m10);
1597 rotate90();
1598 break;
1599 case 2:
1600 m02 += anchorx * (m00 + m00) + anchory * (m01 + m01);
1601 m12 += anchorx * (m10 + m10) + anchory * (m11 + m11);
1602 rotate180();
1603 break;
1604 case 3:
1605 m02 += anchorx * (m00 + m01) + anchory * (m01 - m00);
1606 m12 += anchorx * (m10 + m11) + anchory * (m11 - m10);
1607 rotate270();
1608 break;
1609 }
1610 if (m02 == 0.0 && m12 == 0.0) {
1611 state &= ~APPLY_TRANSLATE;
1612 } else {
1613 state |= APPLY_TRANSLATE;
1614 }
1615 }
1616
1617 /**
1618 * Concatenates this transform with a scaling transformation.
1619 * This is equivalent to calling concatenate(S), where S is an
1620 * <code>AffineTransform</code> represented by the following matrix:
1621 * <pre>
1622 * [ sx 0 0 ]
1623 * [ 0 sy 0 ]
1624 * [ 0 0 1 ]
1625 * </pre>
1626 * @param sx the factor by which coordinates are scaled along the
1627 * X axis direction
1628 * @param sy the factor by which coordinates are scaled along the
1629 * Y axis direction
1630 * @since 1.2
1631 */
1632 public void scale(double sx, double sy) {
1633 int state = this.state;
1634 switch (state) {
1635 default:
1636 stateError();
1637 /* NOTREACHED */
1638 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1639 case (APPLY_SHEAR | APPLY_SCALE):
1640 m00 *= sx;
1641 m11 *= sy;
1642 /* NOBREAK */
1643 case (APPLY_SHEAR | APPLY_TRANSLATE):
1644 case (APPLY_SHEAR):
1645 m01 *= sy;
1646 m10 *= sx;
1647 if (m01 == 0 && m10 == 0) {
1648 state &= APPLY_TRANSLATE;
1649 if (m00 == 1.0 && m11 == 1.0) {
1650 this.type = (state == APPLY_IDENTITY
1651 ? TYPE_IDENTITY
1652 : TYPE_TRANSLATION);
1653 } else {
1654 state |= APPLY_SCALE;
1655 this.type = TYPE_UNKNOWN;
1656 }
1657 this.state = state;
1658 }
1659 return;
1660 case (APPLY_SCALE | APPLY_TRANSLATE):
1661 case (APPLY_SCALE):
1662 m00 *= sx;
1663 m11 *= sy;
1664 if (m00 == 1.0 && m11 == 1.0) {
1665 this.state = (state &= APPLY_TRANSLATE);
1666 this.type = (state == APPLY_IDENTITY
1667 ? TYPE_IDENTITY
1668 : TYPE_TRANSLATION);
1669 } else {
1670 this.type = TYPE_UNKNOWN;
1671 }
1672 return;
1673 case (APPLY_TRANSLATE):
1674 case (APPLY_IDENTITY):
1675 m00 = sx;
1676 m11 = sy;
1677 if (sx != 1.0 || sy != 1.0) {
1678 this.state = state | APPLY_SCALE;
1679 this.type = TYPE_UNKNOWN;
1680 }
1681 return;
1682 }
1683 }
1684
1685 /**
1686 * Concatenates this transform with a shearing transformation.
1687 * This is equivalent to calling concatenate(SH), where SH is an
1688 * <code>AffineTransform</code> represented by the following matrix:
1689 * <pre>
1690 * [ 1 shx 0 ]
1691 * [ shy 1 0 ]
1692 * [ 0 0 1 ]
1693 * </pre>
1694 * @param shx the multiplier by which coordinates are shifted in the
1695 * direction of the positive X axis as a factor of their Y coordinate
1696 * @param shy the multiplier by which coordinates are shifted in the
1697 * direction of the positive Y axis as a factor of their X coordinate
1698 * @since 1.2
1699 */
1700 public void shear(double shx, double shy) {
1701 int state = this.state;
1702 switch (state) {
1703 default:
1704 stateError();
1705 /* NOTREACHED */
1706 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1707 case (APPLY_SHEAR | APPLY_SCALE):
1708 double M0, M1;
1709 M0 = m00;
1710 M1 = m01;
1711 m00 = M0 + M1 * shy;
1712 m01 = M0 * shx + M1;
1713
1714 M0 = m10;
1715 M1 = m11;
1716 m10 = M0 + M1 * shy;
1717 m11 = M0 * shx + M1;
1718 updateState();
1719 return;
1720 case (APPLY_SHEAR | APPLY_TRANSLATE):
1721 case (APPLY_SHEAR):
1722 m00 = m01 * shy;
1723 m11 = m10 * shx;
1724 if (m00 != 0.0 || m11 != 0.0) {
1725 this.state = state | APPLY_SCALE;
1726 }
1727 this.type = TYPE_UNKNOWN;
1728 return;
1729 case (APPLY_SCALE | APPLY_TRANSLATE):
1730 case (APPLY_SCALE):
1731 m01 = m00 * shx;
1732 m10 = m11 * shy;
1733 if (m01 != 0.0 || m10 != 0.0) {
1734 this.state = state | APPLY_SHEAR;
1735 }
1736 this.type = TYPE_UNKNOWN;
1737 return;
1738 case (APPLY_TRANSLATE):
1739 case (APPLY_IDENTITY):
1740 m01 = shx;
1741 m10 = shy;
1742 if (m01 != 0.0 || m10 != 0.0) {
1743 this.state = state | APPLY_SCALE | APPLY_SHEAR;
1744 this.type = TYPE_UNKNOWN;
1745 }
1746 return;
1747 }
1748 }
1749
1750 /**
1751 * Resets this transform to the Identity transform.
1752 * @since 1.2
1753 */
1754 public void setToIdentity() {
1755 m00 = m11 = 1.0;
1756 m10 = m01 = m02 = m12 = 0.0;
1757 state = APPLY_IDENTITY;
1758 type = TYPE_IDENTITY;
1759 }
1760
1761 /**
1762 * Sets this transform to a translation transformation.
1763 * The matrix representing this transform becomes:
1764 * <pre>
1765 * [ 1 0 tx ]
1766 * [ 0 1 ty ]
1767 * [ 0 0 1 ]
1768 * </pre>
1769 * @param tx the distance by which coordinates are translated in the
1770 * X axis direction
1771 * @param ty the distance by which coordinates are translated in the
1772 * Y axis direction
1773 * @since 1.2
1774 */
1775 public void setToTranslation(double tx, double ty) {
1776 m00 = 1.0;
1777 m10 = 0.0;
1778 m01 = 0.0;
1779 m11 = 1.0;
1780 m02 = tx;
1781 m12 = ty;
1782 if (tx != 0.0 || ty != 0.0) {
1783 state = APPLY_TRANSLATE;
1784 type = TYPE_TRANSLATION;
1785 } else {
1786 state = APPLY_IDENTITY;
1787 type = TYPE_IDENTITY;
1788 }
1789 }
1790
1791 /**
1792 * Sets this transform to a rotation transformation.
1793 * The matrix representing this transform becomes:
1794 * <pre>
1795 * [ cos(theta) -sin(theta) 0 ]
1796 * [ sin(theta) cos(theta) 0 ]
1797 * [ 0 0 1 ]
1798 * </pre>
1799 * Rotating by a positive angle theta rotates points on the positive
1800 * X axis toward the positive Y axis.
1801 * Note also the discussion of
1802 * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
1803 * above.
1804 * @param theta the angle of rotation measured in radians
1805 * @since 1.2
1806 */
1807 public void setToRotation(double theta) {
1808 double sin = Math.sin(theta);
1809 double cos;
1810 if (sin == 1.0 || sin == -1.0) {
1811 cos = 0.0;
1812 state = APPLY_SHEAR;
1813 type = TYPE_QUADRANT_ROTATION;
1814 } else {
1815 cos = Math.cos(theta);
1816 if (cos == -1.0) {
1817 sin = 0.0;
1818 state = APPLY_SCALE;
1819 type = TYPE_QUADRANT_ROTATION;
1820 } else if (cos == 1.0) {
1821 sin = 0.0;
1822 state = APPLY_IDENTITY;
1823 type = TYPE_IDENTITY;
1824 } else {
1825 state = APPLY_SHEAR | APPLY_SCALE;
1826 type = TYPE_GENERAL_ROTATION;
1827 }
1828 }
1829 m00 = cos;
1830 m10 = sin;
1831 m01 = -sin;
1832 m11 = cos;
1833 m02 = 0.0;
1834 m12 = 0.0;
1835 }
1836
1837 /**
1838 * Sets this transform to a translated rotation transformation.
1839 * This operation is equivalent to translating the coordinates so
1840 * that the anchor point is at the origin (S1), then rotating them
1841 * about the new origin (S2), and finally translating so that the
1842 * intermediate origin is restored to the coordinates of the original
1843 * anchor point (S3).
1844 * <p>
1845 * This operation is equivalent to the following sequence of calls:
1846 * <pre>
1847 * setToTranslation(anchorx, anchory); // S3: final translation
1848 * rotate(theta); // S2: rotate around anchor
1849 * translate(-anchorx, -anchory); // S1: translate anchor to origin
1850 * </pre>
1851 * The matrix representing this transform becomes:
1852 * <pre>
1853 * [ cos(theta) -sin(theta) x-x*cos+y*sin ]
1854 * [ sin(theta) cos(theta) y-x*sin-y*cos ]
1855 * [ 0 0 1 ]
1856 * </pre>
1857 * Rotating by a positive angle theta rotates points on the positive
1858 * X axis toward the positive Y axis.
1859 * Note also the discussion of
1860 * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
1861 * above.
1862 *
1863 * @param theta the angle of rotation measured in radians
1864 * @param anchorx the X coordinate of the rotation anchor point
1865 * @param anchory the Y coordinate of the rotation anchor point
1866 * @since 1.2
1867 */
1868 public void setToRotation(double theta, double anchorx, double anchory) {
1869 setToRotation(theta);
1870 double sin = m10;
1871 double oneMinusCos = 1.0 - m00;
1872 m02 = anchorx * oneMinusCos + anchory * sin;
1873 m12 = anchory * oneMinusCos - anchorx * sin;
1874 if (m02 != 0.0 || m12 != 0.0) {
1875 state |= APPLY_TRANSLATE;
1876 type |= TYPE_TRANSLATION;
1877 }
1878 }
1879
1880 /**
1881 * Sets this transform to a rotation transformation that rotates
1882 * coordinates according to a rotation vector.
1883 * All coordinates rotate about the origin by the same amount.
1884 * The amount of rotation is such that coordinates along the former
1885 * positive X axis will subsequently align with the vector pointing
1886 * from the origin to the specified vector coordinates.
1887 * If both <code>vecx</code> and <code>vecy</code> are 0.0,
1888 * the transform is set to an identity transform.
1889 * This operation is equivalent to calling:
1890 * <pre>
1891 * setToRotation(Math.atan2(vecy, vecx));
1892 * </pre>
1893 *
1894 * @param vecx the X coordinate of the rotation vector
1895 * @param vecy the Y coordinate of the rotation vector
1896 * @since 1.6
1897 */
1898 public void setToRotation(double vecx, double vecy) {
1899 double sin, cos;
1900 if (vecy == 0) {
1901 sin = 0.0;
1902 if (vecx < 0.0) {
1903 cos = -1.0;
1904 state = APPLY_SCALE;
1905 type = TYPE_QUADRANT_ROTATION;
1906 } else {
1907 cos = 1.0;
1908 state = APPLY_IDENTITY;
1909 type = TYPE_IDENTITY;
1910 }
1911 } else if (vecx == 0) {
1912 cos = 0.0;
1913 sin = (vecy > 0.0) ? 1.0 : -1.0;
1914 state = APPLY_SHEAR;
1915 type = TYPE_QUADRANT_ROTATION;
1916 } else {
1917 double len = Math.sqrt(vecx * vecx + vecy * vecy);
1918 cos = vecx / len;
1919 sin = vecy / len;
1920 state = APPLY_SHEAR | APPLY_SCALE;
1921 type = TYPE_GENERAL_ROTATION;
1922 }
1923 m00 = cos;
1924 m10 = sin;
1925 m01 = -sin;
1926 m11 = cos;
1927 m02 = 0.0;
1928 m12 = 0.0;
1929 }
1930
1931 /**
1932 * Sets this transform to a rotation transformation that rotates
1933 * coordinates around an anchor point according to a rotation
1934 * vector.
1935 * All coordinates rotate about the specified anchor coordinates
1936 * by the same amount.
1937 * The amount of rotation is such that coordinates along the former
1938 * positive X axis will subsequently align with the vector pointing
1939 * from the origin to the specified vector coordinates.
1940 * If both <code>vecx</code> and <code>vecy</code> are 0.0,
1941 * the transform is set to an identity transform.
1942 * This operation is equivalent to calling:
1943 * <pre>
1944 * setToTranslation(Math.atan2(vecy, vecx), anchorx, anchory);
1945 * </pre>
1946 *
1947 * @param vecx the X coordinate of the rotation vector
1948 * @param vecy the Y coordinate of the rotation vector
1949 * @param anchorx the X coordinate of the rotation anchor point
1950 * @param anchory the Y coordinate of the rotation anchor point
1951 * @since 1.6
1952 */
1953 public void setToRotation(double vecx, double vecy,
1954 double anchorx, double anchory)
1955 {
1956 setToRotation(vecx, vecy);
1957 double sin = m10;
1958 double oneMinusCos = 1.0 - m00;
1959 m02 = anchorx * oneMinusCos + anchory * sin;
1960 m12 = anchory * oneMinusCos - anchorx * sin;
1961 if (m02 != 0.0 || m12 != 0.0) {
1962 state |= APPLY_TRANSLATE;
1963 type |= TYPE_TRANSLATION;
1964 }
1965 }
1966
1967 /**
1968 * Sets this transform to a rotation transformation that rotates
1969 * coordinates by the specified number of quadrants.
1970 * This operation is equivalent to calling:
1971 * <pre>
1972 * setToRotation(numquadrants * Math.PI / 2.0);
1973 * </pre>
1974 * Rotating by a positive number of quadrants rotates points on
1975 * the positive X axis toward the positive Y axis.
1976 * @param numquadrants the number of 90 degree arcs to rotate by
1977 * @since 1.6
1978 */
1979 public void setToQuadrantRotation(int numquadrants) {
1980 switch (numquadrants & 3) {
1981 case 0:
1982 m00 = 1.0;
1983 m10 = 0.0;
1984 m01 = 0.0;
1985 m11 = 1.0;
1986 m02 = 0.0;
1987 m12 = 0.0;
1988 state = APPLY_IDENTITY;
1989 type = TYPE_IDENTITY;
1990 break;
1991 case 1:
1992 m00 = 0.0;
1993 m10 = 1.0;
1994 m01 = -1.0;
1995 m11 = 0.0;
1996 m02 = 0.0;
1997 m12 = 0.0;
1998 state = APPLY_SHEAR;
1999 type = TYPE_QUADRANT_ROTATION;
2000 break;
2001 case 2:
2002 m00 = -1.0;
2003 m10 = 0.0;
2004 m01 = 0.0;
2005 m11 = -1.0;
2006 m02 = 0.0;
2007 m12 = 0.0;
2008 state = APPLY_SCALE;
2009 type = TYPE_QUADRANT_ROTATION;
2010 break;
2011 case 3:
2012 m00 = 0.0;
2013 m10 = -1.0;
2014 m01 = 1.0;
2015 m11 = 0.0;
2016 m02 = 0.0;
2017 m12 = 0.0;
2018 state = APPLY_SHEAR;
2019 type = TYPE_QUADRANT_ROTATION;
2020 break;
2021 }
2022 }
2023
2024 /**
2025 * Sets this transform to a translated rotation transformation
2026 * that rotates coordinates by the specified number of quadrants
2027 * around the specified anchor point.
2028 * This operation is equivalent to calling:
2029 * <pre>
2030 * setToRotation(numquadrants * Math.PI / 2.0, anchorx, anchory);
2031 * </pre>
2032 * Rotating by a positive number of quadrants rotates points on
2033 * the positive X axis toward the positive Y axis.
2034 *
2035 * @param numquadrants the number of 90 degree arcs to rotate by
2036 * @param anchorx the X coordinate of the rotation anchor point
2037 * @param anchory the Y coordinate of the rotation anchor point
2038 * @since 1.6
2039 */
2040 public void setToQuadrantRotation(int numquadrants,
2041 double anchorx, double anchory)
2042 {
2043 switch (numquadrants & 3) {
2044 case 0:
2045 m00 = 1.0;
2046 m10 = 0.0;
2047 m01 = 0.0;
2048 m11 = 1.0;
2049 m02 = 0.0;
2050 m12 = 0.0;
2051 state = APPLY_IDENTITY;
2052 type = TYPE_IDENTITY;
2053 break;
2054 case 1:
2055 m00 = 0.0;
2056 m10 = 1.0;
2057 m01 = -1.0;
2058 m11 = 0.0;
2059 m02 = anchorx + anchory;
2060 m12 = anchory - anchorx;
2061 if (m02 == 0.0 && m12 == 0.0) {
2062 state = APPLY_SHEAR;
2063 type = TYPE_QUADRANT_ROTATION;
2064 } else {
2065 state = APPLY_SHEAR | APPLY_TRANSLATE;
2066 type = TYPE_QUADRANT_ROTATION | TYPE_TRANSLATION;
2067 }
2068 break;
2069 case 2:
2070 m00 = -1.0;
2071 m10 = 0.0;
2072 m01 = 0.0;
2073 m11 = -1.0;
2074 m02 = anchorx + anchorx;
2075 m12 = anchory + anchory;
2076 if (m02 == 0.0 && m12 == 0.0) {
2077 state = APPLY_SCALE;
2078 type = TYPE_QUADRANT_ROTATION;
2079 } else {
2080 state = APPLY_SCALE | APPLY_TRANSLATE;
2081 type = TYPE_QUADRANT_ROTATION | TYPE_TRANSLATION;
2082 }
2083 break;
2084 case 3:
2085 m00 = 0.0;
2086 m10 = -1.0;
2087 m01 = 1.0;
2088 m11 = 0.0;
2089 m02 = anchorx - anchory;
2090 m12 = anchory + anchorx;
2091 if (m02 == 0.0 && m12 == 0.0) {
2092 state = APPLY_SHEAR;
2093 type = TYPE_QUADRANT_ROTATION;
2094 } else {
2095 state = APPLY_SHEAR | APPLY_TRANSLATE;
2096 type = TYPE_QUADRANT_ROTATION | TYPE_TRANSLATION;
2097 }
2098 break;
2099 }
2100 }
2101
2102 /**
2103 * Sets this transform to a scaling transformation.
2104 * The matrix representing this transform becomes:
2105 * <pre>
2106 * [ sx 0 0 ]
2107 * [ 0 sy 0 ]
2108 * [ 0 0 1 ]
2109 * </pre>
2110 * @param sx the factor by which coordinates are scaled along the
2111 * X axis direction
2112 * @param sy the factor by which coordinates are scaled along the
2113 * Y axis direction
2114 * @since 1.2
2115 */
2116 public void setToScale(double sx, double sy) {
2117 m00 = sx;
2118 m10 = 0.0;
2119 m01 = 0.0;
2120 m11 = sy;
2121 m02 = 0.0;
2122 m12 = 0.0;
2123 if (sx != 1.0 || sy != 1.0) {
2124 state = APPLY_SCALE;
2125 type = TYPE_UNKNOWN;
2126 } else {
2127 state = APPLY_IDENTITY;
2128 type = TYPE_IDENTITY;
2129 }
2130 }
2131
2132 /**
2133 * Sets this transform to a shearing transformation.
2134 * The matrix representing this transform becomes:
2135 * <pre>
2136 * [ 1 shx 0 ]
2137 * [ shy 1 0 ]
2138 * [ 0 0 1 ]
2139 * </pre>
2140 * @param shx the multiplier by which coordinates are shifted in the
2141 * direction of the positive X axis as a factor of their Y coordinate
2142 * @param shy the multiplier by which coordinates are shifted in the
2143 * direction of the positive Y axis as a factor of their X coordinate
2144 * @since 1.2
2145 */
2146 public void setToShear(double shx, double shy) {
2147 m00 = 1.0;
2148 m01 = shx;
2149 m10 = shy;
2150 m11 = 1.0;
2151 m02 = 0.0;
2152 m12 = 0.0;
2153 if (shx != 0.0 || shy != 0.0) {
2154 state = (APPLY_SHEAR | APPLY_SCALE);
2155 type = TYPE_UNKNOWN;
2156 } else {
2157 state = APPLY_IDENTITY;
2158 type = TYPE_IDENTITY;
2159 }
2160 }
2161
2162 /**
2163 * Sets this transform to a copy of the transform in the specified
2164 * <code>AffineTransform</code> object.
2165 * @param Tx the <code>AffineTransform</code> object from which to
2166 * copy the transform
2167 * @since 1.2
2168 */
2169 public void setTransform(AffineTransform Tx) {
2170 this.m00 = Tx.m00;
2171 this.m10 = Tx.m10;
2172 this.m01 = Tx.m01;
2173 this.m11 = Tx.m11;
2174 this.m02 = Tx.m02;
2175 this.m12 = Tx.m12;
2176 this.state = Tx.state;
2177 this.type = Tx.type;
2178 }
2179
2180 /**
2181 * Sets this transform to the matrix specified by the 6
2182 * double precision values.
2183 *
2184 * @param m00 the X coordinate scaling element of the 3x3 matrix
2185 * @param m10 the Y coordinate shearing element of the 3x3 matrix
2186 * @param m01 the X coordinate shearing element of the 3x3 matrix
2187 * @param m11 the Y coordinate scaling element of the 3x3 matrix
2188 * @param m02 the X coordinate translation element of the 3x3 matrix
2189 * @param m12 the Y coordinate translation element of the 3x3 matrix
2190 * @since 1.2
2191 */
2192 public void setTransform(double m00, double m10,
2193 double m01, double m11,
2194 double m02, double m12) {
2195 this.m00 = m00;
2196 this.m10 = m10;
2197 this.m01 = m01;
2198 this.m11 = m11;
2199 this.m02 = m02;
2200 this.m12 = m12;
2201 updateState();
2202 }
2203
2204 /**
2205 * Concatenates an <code>AffineTransform</code> <code>Tx</code> to
2206 * this <code>AffineTransform</code> Cx in the most commonly useful
2207 * way to provide a new user space
2208 * that is mapped to the former user space by <code>Tx</code>.
2209 * Cx is updated to perform the combined transformation.
2210 * Transforming a point p by the updated transform Cx' is
2211 * equivalent to first transforming p by <code>Tx</code> and then
2212 * transforming the result by the original transform Cx like this:
2213 * Cx'(p) = Cx(Tx(p))
2214 * In matrix notation, if this transform Cx is
2215 * represented by the matrix [this] and <code>Tx</code> is represented
2216 * by the matrix [Tx] then this method does the following:
2217 * <pre>
2218 * [this] = [this] x [Tx]
2219 * </pre>
2220 * @param Tx the <code>AffineTransform</code> object to be
2221 * concatenated with this <code>AffineTransform</code> object.
2222 * @see #preConcatenate
2223 * @since 1.2
2224 */
2225 public void concatenate(AffineTransform Tx) {
2226 double M0, M1;
2227 double T00, T01, T10, T11;
2228 double T02, T12;
2229 int mystate = state;
2230 int txstate = Tx.state;
2231 switch ((txstate << HI_SHIFT) | mystate) {
2232
2233 /* ---------- Tx == IDENTITY cases ---------- */
2234 case (HI_IDENTITY | APPLY_IDENTITY):
2235 case (HI_IDENTITY | APPLY_TRANSLATE):
2236 case (HI_IDENTITY | APPLY_SCALE):
2237 case (HI_IDENTITY | APPLY_SCALE | APPLY_TRANSLATE):
2238 case (HI_IDENTITY | APPLY_SHEAR):
2239 case (HI_IDENTITY | APPLY_SHEAR | APPLY_TRANSLATE):
2240 case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE):
2241 case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2242 return;
2243
2244 /* ---------- this == IDENTITY cases ---------- */
2245 case (HI_SHEAR | HI_SCALE | HI_TRANSLATE | APPLY_IDENTITY):
2246 m01 = Tx.m01;
2247 m10 = Tx.m10;
2248 /* NOBREAK */
2249 case (HI_SCALE | HI_TRANSLATE | APPLY_IDENTITY):
2250 m00 = Tx.m00;
2251 m11 = Tx.m11;
2252 /* NOBREAK */
2253 case (HI_TRANSLATE | APPLY_IDENTITY):
2254 m02 = Tx.m02;
2255 m12 = Tx.m12;
2256 state = txstate;
2257 type = Tx.type;
2258 return;
2259 case (HI_SHEAR | HI_SCALE | APPLY_IDENTITY):
2260 m01 = Tx.m01;
2261 m10 = Tx.m10;
2262 /* NOBREAK */
2263 case (HI_SCALE | APPLY_IDENTITY):
2264 m00 = Tx.m00;
2265 m11 = Tx.m11;
2266 state = txstate;
2267 type = Tx.type;
2268 return;
2269 case (HI_SHEAR | HI_TRANSLATE | APPLY_IDENTITY):
2270 m02 = Tx.m02;
2271 m12 = Tx.m12;
2272 /* NOBREAK */
2273 case (HI_SHEAR | APPLY_IDENTITY):
2274 m01 = Tx.m01;
2275 m10 = Tx.m10;
2276 m00 = m11 = 0.0;
2277 state = txstate;
2278 type = Tx.type;
2279 return;
2280
2281 /* ---------- Tx == TRANSLATE cases ---------- */
2282 case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2283 case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE):
2284 case (HI_TRANSLATE | APPLY_SHEAR | APPLY_TRANSLATE):
2285 case (HI_TRANSLATE | APPLY_SHEAR):
2286 case (HI_TRANSLATE | APPLY_SCALE | APPLY_TRANSLATE):
2287 case (HI_TRANSLATE | APPLY_SCALE):
2288 case (HI_TRANSLATE | APPLY_TRANSLATE):
2289 translate(Tx.m02, Tx.m12);
2290 return;
2291
2292 /* ---------- Tx == SCALE cases ---------- */
2293 case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2294 case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE):
2295 case (HI_SCALE | APPLY_SHEAR | APPLY_TRANSLATE):
2296 case (HI_SCALE | APPLY_SHEAR):
2297 case (HI_SCALE | APPLY_SCALE | APPLY_TRANSLATE):
2298 case (HI_SCALE | APPLY_SCALE):
2299 case (HI_SCALE | APPLY_TRANSLATE):
2300 scale(Tx.m00, Tx.m11);
2301 return;
2302
2303 /* ---------- Tx == SHEAR cases ---------- */
2304 case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2305 case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE):
2306 T01 = Tx.m01; T10 = Tx.m10;
2307 M0 = m00;
2308 m00 = m01 * T10;
2309 m01 = M0 * T01;
2310 M0 = m10;
2311 m10 = m11 * T10;
2312 m11 = M0 * T01;
2313 type = TYPE_UNKNOWN;
2314 return;
2315 case (HI_SHEAR | APPLY_SHEAR | APPLY_TRANSLATE):
2316 case (HI_SHEAR | APPLY_SHEAR):
2317 m00 = m01 * Tx.m10;
2318 m01 = 0.0;
2319 m11 = m10 * Tx.m01;
2320 m10 = 0.0;
2321 state = mystate ^ (APPLY_SHEAR | APPLY_SCALE);
2322 type = TYPE_UNKNOWN;
2323 return;
2324 case (HI_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2325 case (HI_SHEAR | APPLY_SCALE):
2326 m01 = m00 * Tx.m01;
2327 m00 = 0.0;
2328 m10 = m11 * Tx.m10;
2329 m11 = 0.0;
2330 state = mystate ^ (APPLY_SHEAR | APPLY_SCALE);
2331 type = TYPE_UNKNOWN;
2332 return;
2333 case (HI_SHEAR | APPLY_TRANSLATE):
2334 m00 = 0.0;
2335 m01 = Tx.m01;
2336 m10 = Tx.m10;
2337 m11 = 0.0;
2338 state = APPLY_TRANSLATE | APPLY_SHEAR;
2339 type = TYPE_UNKNOWN;
2340 return;
2341 }
2342 // If Tx has more than one attribute, it is not worth optimizing
2343 // all of those cases...
2344 T00 = Tx.m00; T01 = Tx.m01; T02 = Tx.m02;
2345 T10 = Tx.m10; T11 = Tx.m11; T12 = Tx.m12;
2346 switch (mystate) {
2347 default:
2348 stateError();
2349 /* NOTREACHED */
2350 case (APPLY_SHEAR | APPLY_SCALE):
2351 state = mystate | txstate;
2352 /* NOBREAK */
2353 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2354 M0 = m00;
2355 M1 = m01;
2356 m00 = T00 * M0 + T10 * M1;
2357 m01 = T01 * M0 + T11 * M1;
2358 m02 += T02 * M0 + T12 * M1;
2359
2360 M0 = m10;
2361 M1 = m11;
2362 m10 = T00 * M0 + T10 * M1;
2363 m11 = T01 * M0 + T11 * M1;
2364 m12 += T02 * M0 + T12 * M1;
2365 type = TYPE_UNKNOWN;
2366 return;
2367
2368 case (APPLY_SHEAR | APPLY_TRANSLATE):
2369 case (APPLY_SHEAR):
2370 M0 = m01;
2371 m00 = T10 * M0;
2372 m01 = T11 * M0;
2373 m02 += T12 * M0;
2374
2375 M0 = m10;
2376 m10 = T00 * M0;
2377 m11 = T01 * M0;
2378 m12 += T02 * M0;
2379 break;
2380
2381 case (APPLY_SCALE | APPLY_TRANSLATE):
2382 case (APPLY_SCALE):
2383 M0 = m00;
2384 m00 = T00 * M0;
2385 m01 = T01 * M0;
2386 m02 += T02 * M0;
2387
2388 M0 = m11;
2389 m10 = T10 * M0;
2390 m11 = T11 * M0;
2391 m12 += T12 * M0;
2392 break;
2393
2394 case (APPLY_TRANSLATE):
2395 m00 = T00;
2396 m01 = T01;
2397 m02 += T02;
2398
2399 m10 = T10;
2400 m11 = T11;
2401 m12 += T12;
2402 state = txstate | APPLY_TRANSLATE;
2403 type = TYPE_UNKNOWN;
2404 return;
2405 }
2406 updateState();
2407 }
2408
2409 /**
2410 * Concatenates an <code>AffineTransform</code> <code>Tx</code> to
2411 * this <code>AffineTransform</code> Cx
2412 * in a less commonly used way such that <code>Tx</code> modifies the
2413 * coordinate transformation relative to the absolute pixel
2414 * space rather than relative to the existing user space.
2415 * Cx is updated to perform the combined transformation.
2416 * Transforming a point p by the updated transform Cx' is
2417 * equivalent to first transforming p by the original transform
2418 * Cx and then transforming the result by
2419 * <code>Tx</code> like this:
2420 * Cx'(p) = Tx(Cx(p))
2421 * In matrix notation, if this transform Cx
2422 * is represented by the matrix [this] and <code>Tx</code> is
2423 * represented by the matrix [Tx] then this method does the
2424 * following:
2425 * <pre>
2426 * [this] = [Tx] x [this]
2427 * </pre>
2428 * @param Tx the <code>AffineTransform</code> object to be
2429 * concatenated with this <code>AffineTransform</code> object.
2430 * @see #concatenate
2431 * @since 1.2
2432 */
2433 public void preConcatenate(AffineTransform Tx) {
2434 double M0, M1;
2435 double T00, T01, T10, T11;
2436 double T02, T12;
2437 int mystate = state;
2438 int txstate = Tx.state;
2439 switch ((txstate << HI_SHIFT) | mystate) {
2440 case (HI_IDENTITY | APPLY_IDENTITY):
2441 case (HI_IDENTITY | APPLY_TRANSLATE):
2442 case (HI_IDENTITY | APPLY_SCALE):
2443 case (HI_IDENTITY | APPLY_SCALE | APPLY_TRANSLATE):
2444 case (HI_IDENTITY | APPLY_SHEAR):
2445 case (HI_IDENTITY | APPLY_SHEAR | APPLY_TRANSLATE):
2446 case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE):
2447 case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2448 // Tx is IDEN