12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.awt.geom;
27
28 import java.awt.Shape;
29 import java.beans.ConstructorProperties;
30
31 /**
32 * The <code>AffineTransform</code> class represents a 2D affine transform
33 * that performs a linear mapping from 2D coordinates to other 2D
34 * coordinates that preserves the "straightness" and
35 * "parallelness" of lines. Affine transformations can be constructed
36 * using sequences of translations, scales, flips, rotations, and shears.
37 * <p>
38 * Such a coordinate transformation can be represented by a 3 row by
39 * 3 column matrix with an implied last row of [ 0 0 1 ]. This matrix
40 * transforms source coordinates {@code (x,y)} into
41 * destination coordinates {@code (x',y')} by considering
42 * them to be a column vector and multiplying the coordinate vector
43 * by the matrix according to the following process:
44 * <pre>
45 * [ x'] [ m00 m01 m02 ] [ x ] [ m00x + m01y + m02 ]
46 * [ y'] = [ m10 m11 m12 ] [ y ] = [ m10x + m11y + m12 ]
47 * [ 1 ] [ 0 0 1 ] [ 1 ] [ 1 ]
48 * </pre>
49 * <h3><a name="quadrantapproximation">Handling 90-Degree Rotations</a></h3>
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
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 @ConstructorProperties({ "scaleX", "shearY", "shearX", "scaleY", "translateX", "translateY" })
512 public AffineTransform(float m00, float m10,
513 float m01, float m11,
514 float m02, float m12) {
515 this.m00 = m00;
516 this.m10 = m10;
517 this.m01 = m01;
518 this.m11 = m11;
519 this.m02 = m02;
520 this.m12 = m12;
521 updateState();
522 }
523
524 /**
525 * Constructs a new <code>AffineTransform</code> from an array of
526 * floating point values representing either the 4 non-translation
527 * entries or the 6 specifiable entries of the 3x3 transformation
528 * matrix. The values are retrieved from the array as
529 * { m00 m10 m01 m11 [m02 m12]}.
530 * @param flatmatrix the float array containing the values to be set
531 * in the new <code>AffineTransform</code> object. The length of the
532 * array is assumed to be at least 4. If the length of the array is
533 * less than 6, only the first 4 values are taken. If the length of
534 * the array is greater than 6, the first 6 values are taken.
535 * @since 1.2
536 */
537 public AffineTransform(float[] flatmatrix) {
538 m00 = flatmatrix[0];
539 m10 = flatmatrix[1];
540 m01 = flatmatrix[2];
541 m11 = flatmatrix[3];
542 if (flatmatrix.length > 5) {
543 m02 = flatmatrix[4];
544 m12 = flatmatrix[5];
545 }
546 updateState();
547 }
548
549 /**
550 * Constructs a new <code>AffineTransform</code> from 6 double
551 * precision values representing the 6 specifiable entries of the 3x3
552 * transformation matrix.
553 *
554 * @param m00 the X coordinate scaling element of the 3x3 matrix
555 * @param m10 the Y coordinate shearing element of the 3x3 matrix
556 * @param m01 the X coordinate shearing element of the 3x3 matrix
557 * @param m11 the Y coordinate scaling element of the 3x3 matrix
558 * @param m02 the X coordinate translation element of the 3x3 matrix
559 * @param m12 the Y coordinate translation element of the 3x3 matrix
560 * @since 1.2
561 */
562 public AffineTransform(double m00, double m10,
563 double m01, double m11,
564 double m02, double m12) {
565 this.m00 = m00;
566 this.m10 = m10;
567 this.m01 = m01;
568 this.m11 = m11;
569 this.m02 = m02;
570 this.m12 = m12;
571 updateState();
572 }
573
574 /**
575 * Constructs a new <code>AffineTransform</code> from an array of
576 * double precision values representing either the 4 non-translation
577 * entries or the 6 specifiable entries of the 3x3 transformation
578 * matrix. The values are retrieved from the array as
579 * { m00 m10 m01 m11 [m02 m12]}.
580 * @param flatmatrix the double array containing the values to be set
581 * in the new <code>AffineTransform</code> object. The length of the
582 * array is assumed to be at least 4. If the length of the array is
583 * less than 6, only the first 4 values are taken. If the length of
584 * the array is greater than 6, the first 6 values are taken.
585 * @since 1.2
586 */
587 public AffineTransform(double[] flatmatrix) {
588 m00 = flatmatrix[0];
589 m10 = flatmatrix[1];
590 m01 = flatmatrix[2];
591 m11 = flatmatrix[3];
592 if (flatmatrix.length > 5) {
593 m02 = flatmatrix[4];
594 m12 = flatmatrix[5];
595 }
596 updateState();
597 }
598
599 /**
600 * Returns a transform representing a translation transformation.
601 * The matrix representing the returned transform is:
602 * <pre>
603 * [ 1 0 tx ]
604 * [ 0 1 ty ]
605 * [ 0 0 1 ]
606 * </pre>
607 * @param tx the distance by which coordinates are translated in the
608 * X axis direction
609 * @param ty the distance by which coordinates are translated in the
610 * Y axis direction
611 * @return an <code>AffineTransform</code> object that represents a
612 * translation transformation, created with the specified vector.
613 * @since 1.2
614 */
615 public static AffineTransform getTranslateInstance(double tx, double ty) {
616 AffineTransform Tx = new AffineTransform();
617 Tx.setToTranslation(tx, ty);
618 return Tx;
619 }
620
621 /**
622 * Returns a transform representing a rotation transformation.
623 * The matrix representing the returned transform is:
624 * <pre>
625 * [ cos(theta) -sin(theta) 0 ]
626 * [ sin(theta) cos(theta) 0 ]
627 * [ 0 0 1 ]
628 * </pre>
629 * Rotating by a positive angle theta rotates points on the positive
630 * X axis toward the positive Y axis.
631 * Note also the discussion of
632 * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
633 * above.
634 * @param theta the angle of rotation measured in radians
635 * @return an <code>AffineTransform</code> object that is a rotation
636 * transformation, created with the specified angle of rotation.
637 * @since 1.2
638 */
639 public static AffineTransform getRotateInstance(double theta) {
640 AffineTransform Tx = new AffineTransform();
641 Tx.setToRotation(theta);
642 return Tx;
643 }
644
645 /**
646 * Returns a transform that rotates coordinates around an anchor point.
647 * This operation is equivalent to translating the coordinates so
648 * that the anchor point is at the origin (S1), then rotating them
649 * about the new origin (S2), and finally translating so that the
650 * intermediate origin is restored to the coordinates of the original
651 * anchor point (S3).
652 * <p>
653 * This operation is equivalent to the following sequence of calls:
654 * <pre>
655 * AffineTransform Tx = new AffineTransform();
656 * Tx.translate(anchorx, anchory); // S3: final translation
657 * Tx.rotate(theta); // S2: rotate around anchor
658 * Tx.translate(-anchorx, -anchory); // S1: translate anchor to origin
659 * </pre>
660 * The matrix representing the returned transform is:
661 * <pre>
662 * [ cos(theta) -sin(theta) x-x*cos+y*sin ]
663 * [ sin(theta) cos(theta) y-x*sin-y*cos ]
664 * [ 0 0 1 ]
665 * </pre>
666 * Rotating by a positive angle theta rotates points on the positive
667 * X axis toward the positive Y axis.
668 * Note also the discussion of
669 * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
670 * above.
671 *
672 * @param theta the angle of rotation measured in radians
673 * @param anchorx the X coordinate of the rotation anchor point
674 * @param anchory the Y coordinate of the rotation anchor point
675 * @return an <code>AffineTransform</code> object that rotates
676 * coordinates around the specified point by the specified angle of
677 * rotation.
678 * @since 1.2
679 */
680 public static AffineTransform getRotateInstance(double theta,
681 double anchorx,
682 double anchory)
683 {
684 AffineTransform Tx = new AffineTransform();
685 Tx.setToRotation(theta, anchorx, anchory);
686 return Tx;
687 }
688
689 /**
690 * Returns a transform that rotates coordinates according to
691 * a rotation vector.
692 * All coordinates rotate about the origin by the same amount.
693 * The amount of rotation is such that coordinates along the former
694 * positive X axis will subsequently align with the vector pointing
695 * from the origin to the specified vector coordinates.
696 * If both <code>vecx</code> and <code>vecy</code> are 0.0,
697 * an identity transform is returned.
698 * This operation is equivalent to calling:
699 * <pre>
700 * AffineTransform.getRotateInstance(Math.atan2(vecy, vecx));
701 * </pre>
702 *
703 * @param vecx the X coordinate of the rotation vector
704 * @param vecy the Y coordinate of the rotation vector
705 * @return an <code>AffineTransform</code> object that rotates
706 * coordinates according to the specified rotation vector.
707 * @since 1.6
708 */
709 public static AffineTransform getRotateInstance(double vecx, double vecy) {
710 AffineTransform Tx = new AffineTransform();
711 Tx.setToRotation(vecx, vecy);
712 return Tx;
713 }
714
715 /**
716 * Returns a transform that rotates coordinates around an anchor
717 * point according to a rotation vector.
718 * All coordinates rotate about the specified anchor coordinates
719 * by the same amount.
720 * The amount of rotation is such that coordinates along the former
721 * positive X axis will subsequently align with the vector pointing
722 * from the origin to the specified vector coordinates.
723 * If both <code>vecx</code> and <code>vecy</code> are 0.0,
724 * an identity transform is returned.
725 * This operation is equivalent to calling:
726 * <pre>
727 * AffineTransform.getRotateInstance(Math.atan2(vecy, vecx),
728 * anchorx, anchory);
729 * </pre>
730 *
731 * @param vecx the X coordinate of the rotation vector
732 * @param vecy the Y coordinate of the rotation vector
733 * @param anchorx the X coordinate of the rotation anchor point
734 * @param anchory the Y coordinate of the rotation anchor point
735 * @return an <code>AffineTransform</code> object that rotates
736 * coordinates around the specified point according to the
737 * specified rotation vector.
738 * @since 1.6
739 */
740 public static AffineTransform getRotateInstance(double vecx,
741 double vecy,
742 double anchorx,
743 double anchory)
744 {
745 AffineTransform Tx = new AffineTransform();
746 Tx.setToRotation(vecx, vecy, anchorx, anchory);
747 return Tx;
748 }
749
750 /**
751 * Returns a transform that rotates coordinates by the specified
752 * number of quadrants.
753 * This operation is equivalent to calling:
754 * <pre>
755 * AffineTransform.getRotateInstance(numquadrants * Math.PI / 2.0);
756 * </pre>
757 * Rotating by a positive number of quadrants rotates points on
758 * the positive X axis toward the positive Y axis.
759 * @param numquadrants the number of 90 degree arcs to rotate by
760 * @return an <code>AffineTransform</code> object that rotates
761 * coordinates by the specified number of quadrants.
762 * @since 1.6
763 */
764 public static AffineTransform getQuadrantRotateInstance(int numquadrants) {
765 AffineTransform Tx = new AffineTransform();
766 Tx.setToQuadrantRotation(numquadrants);
767 return Tx;
768 }
769
770 /**
771 * Returns a transform that rotates coordinates by the specified
772 * number of quadrants around the specified anchor point.
773 * This operation is equivalent to calling:
774 * <pre>
775 * AffineTransform.getRotateInstance(numquadrants * Math.PI / 2.0,
776 * anchorx, anchory);
777 * </pre>
778 * Rotating by a positive number of quadrants rotates points on
779 * the positive X axis toward the positive Y axis.
780 *
781 * @param numquadrants the number of 90 degree arcs to rotate by
782 * @param anchorx the X coordinate of the rotation anchor point
783 * @param anchory the Y coordinate of the rotation anchor point
784 * @return an <code>AffineTransform</code> object that rotates
785 * coordinates by the specified number of quadrants around the
786 * specified anchor point.
787 * @since 1.6
788 */
789 public static AffineTransform getQuadrantRotateInstance(int numquadrants,
790 double anchorx,
791 double anchory)
792 {
793 AffineTransform Tx = new AffineTransform();
794 Tx.setToQuadrantRotation(numquadrants, anchorx, anchory);
795 return Tx;
796 }
797
798 /**
799 * Returns a transform representing a scaling transformation.
800 * The matrix representing the returned transform is:
801 * <pre>
802 * [ sx 0 0 ]
803 * [ 0 sy 0 ]
804 * [ 0 0 1 ]
805 * </pre>
806 * @param sx the factor by which coordinates are scaled along the
807 * X axis direction
808 * @param sy the factor by which coordinates are scaled along the
809 * Y axis direction
810 * @return an <code>AffineTransform</code> object that scales
811 * coordinates by the specified factors.
812 * @since 1.2
813 */
814 public static AffineTransform getScaleInstance(double sx, double sy) {
815 AffineTransform Tx = new AffineTransform();
816 Tx.setToScale(sx, sy);
817 return Tx;
818 }
819
820 /**
821 * Returns a transform representing a shearing transformation.
822 * The matrix representing the returned transform is:
823 * <pre>
824 * [ 1 shx 0 ]
825 * [ shy 1 0 ]
826 * [ 0 0 1 ]
827 * </pre>
828 * @param shx the multiplier by which coordinates are shifted in the
829 * direction of the positive X axis as a factor of their Y coordinate
830 * @param shy the multiplier by which coordinates are shifted in the
831 * direction of the positive Y axis as a factor of their X coordinate
832 * @return an <code>AffineTransform</code> object that shears
833 * coordinates by the specified multipliers.
834 * @since 1.2
835 */
836 public static AffineTransform getShearInstance(double shx, double shy) {
837 AffineTransform Tx = new AffineTransform();
838 Tx.setToShear(shx, shy);
839 return Tx;
840 }
841
842 /**
843 * Retrieves the flag bits describing the conversion properties of
844 * this transform.
845 * The return value is either one of the constants TYPE_IDENTITY
846 * or TYPE_GENERAL_TRANSFORM, or a combination of the
847 * appropriate flag bits.
848 * A valid combination of flag bits is an exclusive OR operation
849 * that can combine
850 * the TYPE_TRANSLATION flag bit
851 * in addition to either of the
852 * TYPE_UNIFORM_SCALE or TYPE_GENERAL_SCALE flag bits
998 }
999
1000 /**
1001 * Returns the determinant of the matrix representation of the transform.
1002 * The determinant is useful both to determine if the transform can
1003 * be inverted and to get a single value representing the
1004 * combined X and Y scaling of the transform.
1005 * <p>
1006 * If the determinant is non-zero, then this transform is
1007 * invertible and the various methods that depend on the inverse
1008 * transform do not need to throw a
1009 * {@link NoninvertibleTransformException}.
1010 * If the determinant is zero then this transform can not be
1011 * inverted since the transform maps all input coordinates onto
1012 * a line or a point.
1013 * If the determinant is near enough to zero then inverse transform
1014 * operations might not carry enough precision to produce meaningful
1015 * results.
1016 * <p>
1017 * If this transform represents a uniform scale, as indicated by
1018 * the <code>getType</code> method then the determinant also
1019 * represents the square of the uniform scale factor by which all of
1020 * the points are expanded from or contracted towards the origin.
1021 * If this transform represents a non-uniform scale or more general
1022 * transform then the determinant is not likely to represent a
1023 * value useful for any purpose other than determining if inverse
1024 * transforms are possible.
1025 * <p>
1026 * Mathematically, the determinant is calculated using the formula:
1027 * <pre>
1028 * | m00 m01 m02 |
1029 * | m10 m11 m12 | = m00 * m11 - m01 * m10
1030 * | 0 0 1 |
1031 * </pre>
1032 *
1033 * @return the determinant of the matrix used to transform the
1034 * coordinates.
1035 * @see #getType
1036 * @see #createInverse
1037 * @see #inverseTransform
1038 * @see #TYPE_UNIFORM_SCALE
1217 */
1218 public double getTranslateX() {
1219 return m02;
1220 }
1221
1222 /**
1223 * Returns the Y coordinate of the translation element (m12) of the
1224 * 3x3 affine transformation matrix.
1225 * @return a double value that is the Y coordinate of the translation
1226 * element of the affine transformation matrix.
1227 * @see #getMatrix
1228 * @since 1.2
1229 */
1230 public double getTranslateY() {
1231 return m12;
1232 }
1233
1234 /**
1235 * Concatenates this transform with a translation transformation.
1236 * This is equivalent to calling concatenate(T), where T is an
1237 * <code>AffineTransform</code> represented by the following matrix:
1238 * <pre>
1239 * [ 1 0 tx ]
1240 * [ 0 1 ty ]
1241 * [ 0 0 1 ]
1242 * </pre>
1243 * @param tx the distance by which coordinates are translated in the
1244 * X axis direction
1245 * @param ty the distance by which coordinates are translated in the
1246 * Y axis direction
1247 * @since 1.2
1248 */
1249 public void translate(double tx, double ty) {
1250 switch (state) {
1251 default:
1252 stateError();
1253 /* NOTREACHED */
1254 return;
1255 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1256 m02 = tx * m00 + ty * m01 + m02;
1257 m12 = tx * m10 + ty * m11 + m12;
1377 private final void rotate270() {
1378 double M0 = m00;
1379 m00 = -m01;
1380 m01 = M0;
1381 M0 = m10;
1382 m10 = -m11;
1383 m11 = M0;
1384 int state = rot90conversion[this.state];
1385 if ((state & (APPLY_SHEAR | APPLY_SCALE)) == APPLY_SCALE &&
1386 m00 == 1.0 && m11 == 1.0)
1387 {
1388 state -= APPLY_SCALE;
1389 }
1390 this.state = state;
1391 type = TYPE_UNKNOWN;
1392 }
1393
1394 /**
1395 * Concatenates this transform with a rotation transformation.
1396 * This is equivalent to calling concatenate(R), where R is an
1397 * <code>AffineTransform</code> represented by the following matrix:
1398 * <pre>
1399 * [ cos(theta) -sin(theta) 0 ]
1400 * [ sin(theta) cos(theta) 0 ]
1401 * [ 0 0 1 ]
1402 * </pre>
1403 * Rotating by a positive angle theta rotates points on the positive
1404 * X axis toward the positive Y axis.
1405 * Note also the discussion of
1406 * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
1407 * above.
1408 * @param theta the angle of rotation measured in radians
1409 * @since 1.2
1410 */
1411 public void rotate(double theta) {
1412 double sin = Math.sin(theta);
1413 if (sin == 1.0) {
1414 rotate90();
1415 } else if (sin == -1.0) {
1416 rotate270();
1417 } else {
1456 *
1457 * @param theta the angle of rotation measured in radians
1458 * @param anchorx the X coordinate of the rotation anchor point
1459 * @param anchory the Y coordinate of the rotation anchor point
1460 * @since 1.2
1461 */
1462 public void rotate(double theta, double anchorx, double anchory) {
1463 // REMIND: Simple for now - optimize later
1464 translate(anchorx, anchory);
1465 rotate(theta);
1466 translate(-anchorx, -anchory);
1467 }
1468
1469 /**
1470 * Concatenates this transform with a transform that rotates
1471 * coordinates according to a rotation vector.
1472 * All coordinates rotate about the origin by the same amount.
1473 * The amount of rotation is such that coordinates along the former
1474 * positive X axis will subsequently align with the vector pointing
1475 * from the origin to the specified vector coordinates.
1476 * If both <code>vecx</code> and <code>vecy</code> are 0.0,
1477 * no additional rotation is added to this transform.
1478 * This operation is equivalent to calling:
1479 * <pre>
1480 * rotate(Math.atan2(vecy, vecx));
1481 * </pre>
1482 *
1483 * @param vecx the X coordinate of the rotation vector
1484 * @param vecy the Y coordinate of the rotation vector
1485 * @since 1.6
1486 */
1487 public void rotate(double vecx, double vecy) {
1488 if (vecy == 0.0) {
1489 if (vecx < 0.0) {
1490 rotate180();
1491 }
1492 // If vecx > 0.0 - no rotation
1493 // If vecx == 0.0 - undefined rotation - treat as no rotation
1494 } else if (vecx == 0.0) {
1495 if (vecy > 0.0) {
1496 rotate90();
1506 M1 = m01;
1507 m00 = cos * M0 + sin * M1;
1508 m01 = -sin * M0 + cos * M1;
1509 M0 = m10;
1510 M1 = m11;
1511 m10 = cos * M0 + sin * M1;
1512 m11 = -sin * M0 + cos * M1;
1513 updateState();
1514 }
1515 }
1516
1517 /**
1518 * Concatenates this transform with a transform that rotates
1519 * coordinates around an anchor point according to a rotation
1520 * vector.
1521 * All coordinates rotate about the specified anchor coordinates
1522 * by the same amount.
1523 * The amount of rotation is such that coordinates along the former
1524 * positive X axis will subsequently align with the vector pointing
1525 * from the origin to the specified vector coordinates.
1526 * If both <code>vecx</code> and <code>vecy</code> are 0.0,
1527 * the transform is not modified in any way.
1528 * This method is equivalent to calling:
1529 * <pre>
1530 * rotate(Math.atan2(vecy, vecx), anchorx, anchory);
1531 * </pre>
1532 *
1533 * @param vecx the X coordinate of the rotation vector
1534 * @param vecy the Y coordinate of the rotation vector
1535 * @param anchorx the X coordinate of the rotation anchor point
1536 * @param anchory the Y coordinate of the rotation anchor point
1537 * @since 1.6
1538 */
1539 public void rotate(double vecx, double vecy,
1540 double anchorx, double anchory)
1541 {
1542 // REMIND: Simple for now - optimize later
1543 translate(anchorx, anchory);
1544 rotate(vecx, vecy);
1545 translate(-anchorx, -anchory);
1546 }
1604 m02 += anchorx * (m00 + m00) + anchory * (m01 + m01);
1605 m12 += anchorx * (m10 + m10) + anchory * (m11 + m11);
1606 rotate180();
1607 break;
1608 case 3:
1609 m02 += anchorx * (m00 + m01) + anchory * (m01 - m00);
1610 m12 += anchorx * (m10 + m11) + anchory * (m11 - m10);
1611 rotate270();
1612 break;
1613 }
1614 if (m02 == 0.0 && m12 == 0.0) {
1615 state &= ~APPLY_TRANSLATE;
1616 } else {
1617 state |= APPLY_TRANSLATE;
1618 }
1619 }
1620
1621 /**
1622 * Concatenates this transform with a scaling transformation.
1623 * This is equivalent to calling concatenate(S), where S is an
1624 * <code>AffineTransform</code> represented by the following matrix:
1625 * <pre>
1626 * [ sx 0 0 ]
1627 * [ 0 sy 0 ]
1628 * [ 0 0 1 ]
1629 * </pre>
1630 * @param sx the factor by which coordinates are scaled along the
1631 * X axis direction
1632 * @param sy the factor by which coordinates are scaled along the
1633 * Y axis direction
1634 * @since 1.2
1635 */
1636 @SuppressWarnings("fallthrough")
1637 public void scale(double sx, double sy) {
1638 int state = this.state;
1639 switch (state) {
1640 default:
1641 stateError();
1642 /* NOTREACHED */
1643 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1644 case (APPLY_SHEAR | APPLY_SCALE):
1673 : TYPE_TRANSLATION);
1674 } else {
1675 this.type = TYPE_UNKNOWN;
1676 }
1677 return;
1678 case (APPLY_TRANSLATE):
1679 case (APPLY_IDENTITY):
1680 m00 = sx;
1681 m11 = sy;
1682 if (sx != 1.0 || sy != 1.0) {
1683 this.state = state | APPLY_SCALE;
1684 this.type = TYPE_UNKNOWN;
1685 }
1686 return;
1687 }
1688 }
1689
1690 /**
1691 * Concatenates this transform with a shearing transformation.
1692 * This is equivalent to calling concatenate(SH), where SH is an
1693 * <code>AffineTransform</code> represented by the following matrix:
1694 * <pre>
1695 * [ 1 shx 0 ]
1696 * [ shy 1 0 ]
1697 * [ 0 0 1 ]
1698 * </pre>
1699 * @param shx the multiplier by which coordinates are shifted in the
1700 * direction of the positive X axis as a factor of their Y coordinate
1701 * @param shy the multiplier by which coordinates are shifted in the
1702 * direction of the positive Y axis as a factor of their X coordinate
1703 * @since 1.2
1704 */
1705 public void shear(double shx, double shy) {
1706 int state = this.state;
1707 switch (state) {
1708 default:
1709 stateError();
1710 /* NOTREACHED */
1711 return;
1712 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1713 case (APPLY_SHEAR | APPLY_SCALE):
1873 */
1874 public void setToRotation(double theta, double anchorx, double anchory) {
1875 setToRotation(theta);
1876 double sin = m10;
1877 double oneMinusCos = 1.0 - m00;
1878 m02 = anchorx * oneMinusCos + anchory * sin;
1879 m12 = anchory * oneMinusCos - anchorx * sin;
1880 if (m02 != 0.0 || m12 != 0.0) {
1881 state |= APPLY_TRANSLATE;
1882 type |= TYPE_TRANSLATION;
1883 }
1884 }
1885
1886 /**
1887 * Sets this transform to a rotation transformation that rotates
1888 * coordinates according to a rotation vector.
1889 * All coordinates rotate about the origin by the same amount.
1890 * The amount of rotation is such that coordinates along the former
1891 * positive X axis will subsequently align with the vector pointing
1892 * from the origin to the specified vector coordinates.
1893 * If both <code>vecx</code> and <code>vecy</code> are 0.0,
1894 * the transform is set to an identity transform.
1895 * This operation is equivalent to calling:
1896 * <pre>
1897 * setToRotation(Math.atan2(vecy, vecx));
1898 * </pre>
1899 *
1900 * @param vecx the X coordinate of the rotation vector
1901 * @param vecy the Y coordinate of the rotation vector
1902 * @since 1.6
1903 */
1904 public void setToRotation(double vecx, double vecy) {
1905 double sin, cos;
1906 if (vecy == 0) {
1907 sin = 0.0;
1908 if (vecx < 0.0) {
1909 cos = -1.0;
1910 state = APPLY_SCALE;
1911 type = TYPE_QUADRANT_ROTATION;
1912 } else {
1913 cos = 1.0;
1926 state = APPLY_SHEAR | APPLY_SCALE;
1927 type = TYPE_GENERAL_ROTATION;
1928 }
1929 m00 = cos;
1930 m10 = sin;
1931 m01 = -sin;
1932 m11 = cos;
1933 m02 = 0.0;
1934 m12 = 0.0;
1935 }
1936
1937 /**
1938 * Sets this transform to a rotation transformation that rotates
1939 * coordinates around an anchor point according to a rotation
1940 * vector.
1941 * All coordinates rotate about the specified anchor coordinates
1942 * by the same amount.
1943 * The amount of rotation is such that coordinates along the former
1944 * positive X axis will subsequently align with the vector pointing
1945 * from the origin to the specified vector coordinates.
1946 * If both <code>vecx</code> and <code>vecy</code> are 0.0,
1947 * the transform is set to an identity transform.
1948 * This operation is equivalent to calling:
1949 * <pre>
1950 * setToTranslation(Math.atan2(vecy, vecx), anchorx, anchory);
1951 * </pre>
1952 *
1953 * @param vecx the X coordinate of the rotation vector
1954 * @param vecy the Y coordinate of the rotation vector
1955 * @param anchorx the X coordinate of the rotation anchor point
1956 * @param anchory the Y coordinate of the rotation anchor point
1957 * @since 1.6
1958 */
1959 public void setToRotation(double vecx, double vecy,
1960 double anchorx, double anchory)
1961 {
1962 setToRotation(vecx, vecy);
1963 double sin = m10;
1964 double oneMinusCos = 1.0 - m00;
1965 m02 = anchorx * oneMinusCos + anchory * sin;
1966 m12 = anchory * oneMinusCos - anchorx * sin;
2150 * @since 1.2
2151 */
2152 public void setToShear(double shx, double shy) {
2153 m00 = 1.0;
2154 m01 = shx;
2155 m10 = shy;
2156 m11 = 1.0;
2157 m02 = 0.0;
2158 m12 = 0.0;
2159 if (shx != 0.0 || shy != 0.0) {
2160 state = (APPLY_SHEAR | APPLY_SCALE);
2161 type = TYPE_UNKNOWN;
2162 } else {
2163 state = APPLY_IDENTITY;
2164 type = TYPE_IDENTITY;
2165 }
2166 }
2167
2168 /**
2169 * Sets this transform to a copy of the transform in the specified
2170 * <code>AffineTransform</code> object.
2171 * @param Tx the <code>AffineTransform</code> object from which to
2172 * copy the transform
2173 * @since 1.2
2174 */
2175 public void setTransform(AffineTransform Tx) {
2176 this.m00 = Tx.m00;
2177 this.m10 = Tx.m10;
2178 this.m01 = Tx.m01;
2179 this.m11 = Tx.m11;
2180 this.m02 = Tx.m02;
2181 this.m12 = Tx.m12;
2182 this.state = Tx.state;
2183 this.type = Tx.type;
2184 }
2185
2186 /**
2187 * Sets this transform to the matrix specified by the 6
2188 * double precision values.
2189 *
2190 * @param m00 the X coordinate scaling element of the 3x3 matrix
2191 * @param m10 the Y coordinate shearing element of the 3x3 matrix
2192 * @param m01 the X coordinate shearing element of the 3x3 matrix
2193 * @param m11 the Y coordinate scaling element of the 3x3 matrix
2194 * @param m02 the X coordinate translation element of the 3x3 matrix
2195 * @param m12 the Y coordinate translation element of the 3x3 matrix
2196 * @since 1.2
2197 */
2198 public void setTransform(double m00, double m10,
2199 double m01, double m11,
2200 double m02, double m12) {
2201 this.m00 = m00;
2202 this.m10 = m10;
2203 this.m01 = m01;
2204 this.m11 = m11;
2205 this.m02 = m02;
2206 this.m12 = m12;
2207 updateState();
2208 }
2209
2210 /**
2211 * Concatenates an <code>AffineTransform</code> <code>Tx</code> to
2212 * this <code>AffineTransform</code> Cx in the most commonly useful
2213 * way to provide a new user space
2214 * that is mapped to the former user space by <code>Tx</code>.
2215 * Cx is updated to perform the combined transformation.
2216 * Transforming a point p by the updated transform Cx' is
2217 * equivalent to first transforming p by <code>Tx</code> and then
2218 * transforming the result by the original transform Cx like this:
2219 * Cx'(p) = Cx(Tx(p))
2220 * In matrix notation, if this transform Cx is
2221 * represented by the matrix [this] and <code>Tx</code> is represented
2222 * by the matrix [Tx] then this method does the following:
2223 * <pre>
2224 * [this] = [this] x [Tx]
2225 * </pre>
2226 * @param Tx the <code>AffineTransform</code> object to be
2227 * concatenated with this <code>AffineTransform</code> object.
2228 * @see #preConcatenate
2229 * @since 1.2
2230 */
2231 @SuppressWarnings("fallthrough")
2232 public void concatenate(AffineTransform Tx) {
2233 double M0, M1;
2234 double T00, T01, T10, T11;
2235 double T02, T12;
2236 int mystate = state;
2237 int txstate = Tx.state;
2238 switch ((txstate << HI_SHIFT) | mystate) {
2239
2240 /* ---------- Tx == IDENTITY cases ---------- */
2241 case (HI_IDENTITY | APPLY_IDENTITY):
2242 case (HI_IDENTITY | APPLY_TRANSLATE):
2243 case (HI_IDENTITY | APPLY_SCALE):
2244 case (HI_IDENTITY | APPLY_SCALE | APPLY_TRANSLATE):
2245 case (HI_IDENTITY | APPLY_SHEAR):
2246 case (HI_IDENTITY | APPLY_SHEAR | APPLY_TRANSLATE):
2247 case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE):
2397 m11 = T11 * M0;
2398 m12 += T12 * M0;
2399 break;
2400
2401 case (APPLY_TRANSLATE):
2402 m00 = T00;
2403 m01 = T01;
2404 m02 += T02;
2405
2406 m10 = T10;
2407 m11 = T11;
2408 m12 += T12;
2409 state = txstate | APPLY_TRANSLATE;
2410 type = TYPE_UNKNOWN;
2411 return;
2412 }
2413 updateState();
2414 }
2415
2416 /**
2417 * Concatenates an <code>AffineTransform</code> <code>Tx</code> to
2418 * this <code>AffineTransform</code> Cx
2419 * in a less commonly used way such that <code>Tx</code> modifies the
2420 * coordinate transformation relative to the absolute pixel
2421 * space rather than relative to the existing user space.
2422 * Cx is updated to perform the combined transformation.
2423 * Transforming a point p by the updated transform Cx' is
2424 * equivalent to first transforming p by the original transform
2425 * Cx and then transforming the result by
2426 * <code>Tx</code> like this:
2427 * Cx'(p) = Tx(Cx(p))
2428 * In matrix notation, if this transform Cx
2429 * is represented by the matrix [this] and <code>Tx</code> is
2430 * represented by the matrix [Tx] then this method does the
2431 * following:
2432 * <pre>
2433 * [this] = [Tx] x [this]
2434 * </pre>
2435 * @param Tx the <code>AffineTransform</code> object to be
2436 * concatenated with this <code>AffineTransform</code> object.
2437 * @see #concatenate
2438 * @since 1.2
2439 */
2440 @SuppressWarnings("fallthrough")
2441 public void preConcatenate(AffineTransform Tx) {
2442 double M0, M1;
2443 double T00, T01, T10, T11;
2444 double T02, T12;
2445 int mystate = state;
2446 int txstate = Tx.state;
2447 switch ((txstate << HI_SHIFT) | mystate) {
2448 case (HI_IDENTITY | APPLY_IDENTITY):
2449 case (HI_IDENTITY | APPLY_TRANSLATE):
2450 case (HI_IDENTITY | APPLY_SCALE):
2451 case (HI_IDENTITY | APPLY_SCALE | APPLY_TRANSLATE):
2452 case (HI_IDENTITY | APPLY_SHEAR):
2453 case (HI_IDENTITY | APPLY_SHEAR | APPLY_TRANSLATE):
2454 case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE):
2455 case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2456 // Tx is IDENTITY...
2615
2616 /* NOBREAK */
2617 case (APPLY_IDENTITY):
2618 m02 = T02;
2619 m12 = T12;
2620
2621 m00 = T00;
2622 m10 = T10;
2623
2624 m01 = T01;
2625 m11 = T11;
2626
2627 state = mystate | txstate;
2628 type = TYPE_UNKNOWN;
2629 return;
2630 }
2631 updateState();
2632 }
2633
2634 /**
2635 * Returns an <code>AffineTransform</code> object representing the
2636 * inverse transformation.
2637 * The inverse transform Tx' of this transform Tx
2638 * maps coordinates transformed by Tx back
2639 * to their original coordinates.
2640 * In other words, Tx'(Tx(p)) = p = Tx(Tx'(p)).
2641 * <p>
2642 * If this transform maps all coordinates onto a point or a line
2643 * then it will not have an inverse, since coordinates that do
2644 * not lie on the destination point or line will not have an inverse
2645 * mapping.
2646 * The <code>getDeterminant</code> method can be used to determine if this
2647 * transform has no inverse, in which case an exception will be
2648 * thrown if the <code>createInverse</code> method is called.
2649 * @return a new <code>AffineTransform</code> object representing the
2650 * inverse transformation.
2651 * @see #getDeterminant
2652 * @exception NoninvertibleTransformException
2653 * if the matrix cannot be inverted.
2654 * @since 1.2
2655 */
2656 public AffineTransform createInverse()
2657 throws NoninvertibleTransformException
2658 {
2659 double det;
2660 switch (state) {
2661 default:
2662 stateError();
2663 /* NOTREACHED */
2664 return null;
2665 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2666 det = m00 * m11 - m01 * m10;
2667 if (Math.abs(det) <= Double.MIN_VALUE) {
2668 throw new NoninvertibleTransformException("Determinant is "+
2669 det);
2723 -m02, -m12,
2724 (APPLY_TRANSLATE));
2725 case (APPLY_IDENTITY):
2726 return new AffineTransform();
2727 }
2728
2729 /* NOTREACHED */
2730 }
2731
2732 /**
2733 * Sets this transform to the inverse of itself.
2734 * The inverse transform Tx' of this transform Tx
2735 * maps coordinates transformed by Tx back
2736 * to their original coordinates.
2737 * In other words, Tx'(Tx(p)) = p = Tx(Tx'(p)).
2738 * <p>
2739 * If this transform maps all coordinates onto a point or a line
2740 * then it will not have an inverse, since coordinates that do
2741 * not lie on the destination point or line will not have an inverse
2742 * mapping.
2743 * The <code>getDeterminant</code> method can be used to determine if this
2744 * transform has no inverse, in which case an exception will be
2745 * thrown if the <code>invert</code> method is called.
2746 * @see #getDeterminant
2747 * @exception NoninvertibleTransformException
2748 * if the matrix cannot be inverted.
2749 * @since 1.6
2750 */
2751 public void invert()
2752 throws NoninvertibleTransformException
2753 {
2754 double M00, M01, M02;
2755 double M10, M11, M12;
2756 double det;
2757 switch (state) {
2758 default:
2759 stateError();
2760 /* NOTREACHED */
2761 return;
2762 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2763 M00 = m00; M01 = m01; M02 = m02;
2764 M10 = m10; M11 = m11; M12 = m12;
2765 det = M00 * M11 - M01 * M10;
2844 case (APPLY_TRANSLATE):
2845 // m00 = 1.0;
2846 // m10 = 0.0;
2847 // m01 = 0.0;
2848 // m11 = 1.0;
2849 m02 = -m02;
2850 m12 = -m12;
2851 break;
2852 case (APPLY_IDENTITY):
2853 // m00 = 1.0;
2854 // m10 = 0.0;
2855 // m01 = 0.0;
2856 // m11 = 1.0;
2857 // m02 = 0.0;
2858 // m12 = 0.0;
2859 break;
2860 }
2861 }
2862
2863 /**
2864 * Transforms the specified <code>ptSrc</code> and stores the result
2865 * in <code>ptDst</code>.
2866 * If <code>ptDst</code> is <code>null</code>, a new {@link Point2D}
2867 * object is allocated and then the result of the transformation is
2868 * stored in this object.
2869 * In either case, <code>ptDst</code>, which contains the
2870 * transformed point, is returned for convenience.
2871 * If <code>ptSrc</code> and <code>ptDst</code> are the same
2872 * object, the input point is correctly overwritten with
2873 * the transformed point.
2874 * @param ptSrc the specified <code>Point2D</code> to be transformed
2875 * @param ptDst the specified <code>Point2D</code> that stores the
2876 * result of transforming <code>ptSrc</code>
2877 * @return the <code>ptDst</code> after transforming
2878 * <code>ptSrc</code> and storing the result in <code>ptDst</code>.
2879 * @since 1.2
2880 */
2881 public Point2D transform(Point2D ptSrc, Point2D ptDst) {
2882 if (ptDst == null) {
2883 if (ptSrc instanceof Point2D.Double) {
2884 ptDst = new Point2D.Double();
2885 } else {
2886 ptDst = new Point2D.Float();
2887 }
2888 }
2889 // Copy source coords into local variables in case src == dst
2890 double x = ptSrc.getX();
2891 double y = ptSrc.getY();
2892 switch (state) {
2893 default:
2894 stateError();
2895 /* NOTREACHED */
2896 return null;
2897 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2898 ptDst.setLocation(x * m00 + y * m01 + m02,
2909 return ptDst;
2910 case (APPLY_SCALE | APPLY_TRANSLATE):
2911 ptDst.setLocation(x * m00 + m02, y * m11 + m12);
2912 return ptDst;
2913 case (APPLY_SCALE):
2914 ptDst.setLocation(x * m00, y * m11);
2915 return ptDst;
2916 case (APPLY_TRANSLATE):
2917 ptDst.setLocation(x + m02, y + m12);
2918 return ptDst;
2919 case (APPLY_IDENTITY):
2920 ptDst.setLocation(x, y);
2921 return ptDst;
2922 }
2923
2924 /* NOTREACHED */
2925 }
2926
2927 /**
2928 * Transforms an array of point objects by this transform.
2929 * If any element of the <code>ptDst</code> array is
2930 * <code>null</code>, a new <code>Point2D</code> object is allocated
2931 * and stored into that element before storing the results of the
2932 * transformation.
2933 * <p>
2934 * Note that this method does not take any precautions to
2935 * avoid problems caused by storing results into <code>Point2D</code>
2936 * objects that will be used as the source for calculations
2937 * further down the source array.
2938 * This method does guarantee that if a specified <code>Point2D</code>
2939 * object is both the source and destination for the same single point
2940 * transform operation then the results will not be stored until
2941 * the calculations are complete to avoid storing the results on
2942 * top of the operands.
2943 * If, however, the destination <code>Point2D</code> object for one
2944 * operation is the same object as the source <code>Point2D</code>
2945 * object for another operation further down the source array then
2946 * the original coordinates in that point are overwritten before
2947 * they can be converted.
2948 * @param ptSrc the array containing the source point objects
2949 * @param ptDst the array into which the transform point objects are
2950 * returned
2951 * @param srcOff the offset to the first point object to be
2952 * transformed in the source array
2953 * @param dstOff the offset to the location of the first
2954 * transformed point object that is stored in the destination array
2955 * @param numPts the number of point objects to be transformed
2956 * @since 1.2
2957 */
2958 public void transform(Point2D[] ptSrc, int srcOff,
2959 Point2D[] ptDst, int dstOff,
2960 int numPts) {
2961 int state = this.state;
2962 while (--numPts >= 0) {
2963 // Copy source coords into local variables in case src == dst
2964 Point2D src = ptSrc[srcOff++];
3000 case (APPLY_TRANSLATE):
3001 dst.setLocation(x + m02, y + m12);
3002 break;
3003 case (APPLY_IDENTITY):
3004 dst.setLocation(x, y);
3005 break;
3006 }
3007 }
3008
3009 /* NOTREACHED */
3010 }
3011
3012 /**
3013 * Transforms an array of floating point coordinates by this transform.
3014 * The two coordinate array sections can be exactly the same or
3015 * can be overlapping sections of the same array without affecting the
3016 * validity of the results.
3017 * This method ensures that no source coordinates are overwritten by a
3018 * previous operation before they can be transformed.
3019 * The coordinates are stored in the arrays starting at the specified
3020 * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3021 * @param srcPts the array containing the source point coordinates.
3022 * Each point is stored as a pair of x, y coordinates.
3023 * @param dstPts the array into which the transformed point coordinates
3024 * are returned. Each point is stored as a pair of x, y
3025 * coordinates.
3026 * @param srcOff the offset to the first point to be transformed
3027 * in the source array
3028 * @param dstOff the offset to the location of the first
3029 * transformed point that is stored in the destination array
3030 * @param numPts the number of points to be transformed
3031 * @since 1.2
3032 */
3033 public void transform(float[] srcPts, int srcOff,
3034 float[] dstPts, int dstOff,
3035 int numPts) {
3036 double M00, M01, M02, M10, M11, M12; // For caching
3037 if (dstPts == srcPts &&
3038 dstOff > srcOff && dstOff < srcOff + numPts * 2)
3039 {
3040 // If the arrays overlap partially with the destination higher
3115 return;
3116 case (APPLY_IDENTITY):
3117 if (srcPts != dstPts || srcOff != dstOff) {
3118 System.arraycopy(srcPts, srcOff, dstPts, dstOff,
3119 numPts * 2);
3120 }
3121 return;
3122 }
3123
3124 /* NOTREACHED */
3125 }
3126
3127 /**
3128 * Transforms an array of double precision coordinates by this transform.
3129 * The two coordinate array sections can be exactly the same or
3130 * can be overlapping sections of the same array without affecting the
3131 * validity of the results.
3132 * This method ensures that no source coordinates are
3133 * overwritten by a previous operation before they can be transformed.
3134 * The coordinates are stored in the arrays starting at the indicated
3135 * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3136 * @param srcPts the array containing the source point coordinates.
3137 * Each point is stored as a pair of x, y coordinates.
3138 * @param dstPts the array into which the transformed point
3139 * coordinates are returned. Each point is stored as a pair of
3140 * x, y coordinates.
3141 * @param srcOff the offset to the first point to be transformed
3142 * in the source array
3143 * @param dstOff the offset to the location of the first
3144 * transformed point that is stored in the destination array
3145 * @param numPts the number of point objects to be transformed
3146 * @since 1.2
3147 */
3148 public void transform(double[] srcPts, int srcOff,
3149 double[] dstPts, int dstOff,
3150 int numPts) {
3151 double M00, M01, M02, M10, M11, M12; // For caching
3152 if (dstPts == srcPts &&
3153 dstOff > srcOff && dstOff < srcOff + numPts * 2)
3154 {
3155 // If the arrays overlap partially with the destination higher
3226 while (--numPts >= 0) {
3227 dstPts[dstOff++] = srcPts[srcOff++] + M02;
3228 dstPts[dstOff++] = srcPts[srcOff++] + M12;
3229 }
3230 return;
3231 case (APPLY_IDENTITY):
3232 if (srcPts != dstPts || srcOff != dstOff) {
3233 System.arraycopy(srcPts, srcOff, dstPts, dstOff,
3234 numPts * 2);
3235 }
3236 return;
3237 }
3238
3239 /* NOTREACHED */
3240 }
3241
3242 /**
3243 * Transforms an array of floating point coordinates by this transform
3244 * and stores the results into an array of doubles.
3245 * The coordinates are stored in the arrays starting at the specified
3246 * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3247 * @param srcPts the array containing the source point coordinates.
3248 * Each point is stored as a pair of x, y coordinates.
3249 * @param dstPts the array into which the transformed point coordinates
3250 * are returned. Each point is stored as a pair of x, y
3251 * coordinates.
3252 * @param srcOff the offset to the first point to be transformed
3253 * in the source array
3254 * @param dstOff the offset to the location of the first
3255 * transformed point that is stored in the destination array
3256 * @param numPts the number of points to be transformed
3257 * @since 1.2
3258 */
3259 public void transform(float[] srcPts, int srcOff,
3260 double[] dstPts, int dstOff,
3261 int numPts) {
3262 double M00, M01, M02, M10, M11, M12; // For caching
3263 switch (state) {
3264 default:
3265 stateError();
3266 /* NOTREACHED */
3322 while (--numPts >= 0) {
3323 dstPts[dstOff++] = srcPts[srcOff++] + M02;
3324 dstPts[dstOff++] = srcPts[srcOff++] + M12;
3325 }
3326 return;
3327 case (APPLY_IDENTITY):
3328 while (--numPts >= 0) {
3329 dstPts[dstOff++] = srcPts[srcOff++];
3330 dstPts[dstOff++] = srcPts[srcOff++];
3331 }
3332 return;
3333 }
3334
3335 /* NOTREACHED */
3336 }
3337
3338 /**
3339 * Transforms an array of double precision coordinates by this transform
3340 * and stores the results into an array of floats.
3341 * The coordinates are stored in the arrays starting at the specified
3342 * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3343 * @param srcPts the array containing the source point coordinates.
3344 * Each point is stored as a pair of x, y coordinates.
3345 * @param dstPts the array into which the transformed point
3346 * coordinates are returned. Each point is stored as a pair of
3347 * x, y coordinates.
3348 * @param srcOff the offset to the first point to be transformed
3349 * in the source array
3350 * @param dstOff the offset to the location of the first
3351 * transformed point that is stored in the destination array
3352 * @param numPts the number of point objects to be transformed
3353 * @since 1.2
3354 */
3355 public void transform(double[] srcPts, int srcOff,
3356 float[] dstPts, int dstOff,
3357 int numPts) {
3358 double M00, M01, M02, M10, M11, M12; // For caching
3359 switch (state) {
3360 default:
3361 stateError();
3362 /* NOTREACHED */
3415 return;
3416 case (APPLY_TRANSLATE):
3417 M02 = m02; M12 = m12;
3418 while (--numPts >= 0) {
3419 dstPts[dstOff++] = (float) (srcPts[srcOff++] + M02);
3420 dstPts[dstOff++] = (float) (srcPts[srcOff++] + M12);
3421 }
3422 return;
3423 case (APPLY_IDENTITY):
3424 while (--numPts >= 0) {
3425 dstPts[dstOff++] = (float) (srcPts[srcOff++]);
3426 dstPts[dstOff++] = (float) (srcPts[srcOff++]);
3427 }
3428 return;
3429 }
3430
3431 /* NOTREACHED */
3432 }
3433
3434 /**
3435 * Inverse transforms the specified <code>ptSrc</code> and stores the
3436 * result in <code>ptDst</code>.
3437 * If <code>ptDst</code> is <code>null</code>, a new
3438 * <code>Point2D</code> object is allocated and then the result of the
3439 * transform is stored in this object.
3440 * In either case, <code>ptDst</code>, which contains the transformed
3441 * point, is returned for convenience.
3442 * If <code>ptSrc</code> and <code>ptDst</code> are the same
3443 * object, the input point is correctly overwritten with the
3444 * transformed point.
3445 * @param ptSrc the point to be inverse transformed
3446 * @param ptDst the resulting transformed point
3447 * @return <code>ptDst</code>, which contains the result of the
3448 * inverse transform.
3449 * @exception NoninvertibleTransformException if the matrix cannot be
3450 * inverted.
3451 * @since 1.2
3452 */
3453 @SuppressWarnings("fallthrough")
3454 public Point2D inverseTransform(Point2D ptSrc, Point2D ptDst)
3455 throws NoninvertibleTransformException
3456 {
3457 if (ptDst == null) {
3458 if (ptSrc instanceof Point2D.Double) {
3459 ptDst = new Point2D.Double();
3460 } else {
3461 ptDst = new Point2D.Float();
3462 }
3463 }
3464 // Copy source coords into local variables in case src == dst
3465 double x = ptSrc.getX();
3466 double y = ptSrc.getY();
3467 switch (state) {
3504 case (APPLY_TRANSLATE):
3505 ptDst.setLocation(x - m02, y - m12);
3506 return ptDst;
3507 case (APPLY_IDENTITY):
3508 ptDst.setLocation(x, y);
3509 return ptDst;
3510 }
3511
3512 /* NOTREACHED */
3513 }
3514
3515 /**
3516 * Inverse transforms an array of double precision coordinates by
3517 * this transform.
3518 * The two coordinate array sections can be exactly the same or
3519 * can be overlapping sections of the same array without affecting the
3520 * validity of the results.
3521 * This method ensures that no source coordinates are
3522 * overwritten by a previous operation before they can be transformed.
3523 * The coordinates are stored in the arrays starting at the specified
3524 * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3525 * @param srcPts the array containing the source point coordinates.
3526 * Each point is stored as a pair of x, y coordinates.
3527 * @param dstPts the array into which the transformed point
3528 * coordinates are returned. Each point is stored as a pair of
3529 * x, y coordinates.
3530 * @param srcOff the offset to the first point to be transformed
3531 * in the source array
3532 * @param dstOff the offset to the location of the first
3533 * transformed point that is stored in the destination array
3534 * @param numPts the number of point objects to be transformed
3535 * @exception NoninvertibleTransformException if the matrix cannot be
3536 * inverted.
3537 * @since 1.2
3538 */
3539 public void inverseTransform(double[] srcPts, int srcOff,
3540 double[] dstPts, int dstOff,
3541 int numPts)
3542 throws NoninvertibleTransformException
3543 {
3544 double M00, M01, M02, M10, M11, M12; // For caching
3640 case (APPLY_TRANSLATE):
3641 M02 = m02; M12 = m12;
3642 while (--numPts >= 0) {
3643 dstPts[dstOff++] = srcPts[srcOff++] - M02;
3644 dstPts[dstOff++] = srcPts[srcOff++] - M12;
3645 }
3646 return;
3647 case (APPLY_IDENTITY):
3648 if (srcPts != dstPts || srcOff != dstOff) {
3649 System.arraycopy(srcPts, srcOff, dstPts, dstOff,
3650 numPts * 2);
3651 }
3652 return;
3653 }
3654
3655 /* NOTREACHED */
3656 }
3657
3658 /**
3659 * Transforms the relative distance vector specified by
3660 * <code>ptSrc</code> and stores the result in <code>ptDst</code>.
3661 * A relative distance vector is transformed without applying the
3662 * translation components of the affine transformation matrix
3663 * using the following equations:
3664 * <pre>
3665 * [ x' ] [ m00 m01 (m02) ] [ x ] [ m00x + m01y ]
3666 * [ y' ] = [ m10 m11 (m12) ] [ y ] = [ m10x + m11y ]
3667 * [ (1) ] [ (0) (0) ( 1 ) ] [ (1) ] [ (1) ]
3668 * </pre>
3669 * If <code>ptDst</code> is <code>null</code>, a new
3670 * <code>Point2D</code> object is allocated and then the result of the
3671 * transform is stored in this object.
3672 * In either case, <code>ptDst</code>, which contains the
3673 * transformed point, is returned for convenience.
3674 * If <code>ptSrc</code> and <code>ptDst</code> are the same object,
3675 * the input point is correctly overwritten with the transformed
3676 * point.
3677 * @param ptSrc the distance vector to be delta transformed
3678 * @param ptDst the resulting transformed distance vector
3679 * @return <code>ptDst</code>, which contains the result of the
3680 * transformation.
3681 * @since 1.2
3682 */
3683 public Point2D deltaTransform(Point2D ptSrc, Point2D ptDst) {
3684 if (ptDst == null) {
3685 if (ptSrc instanceof Point2D.Double) {
3686 ptDst = new Point2D.Double();
3687 } else {
3688 ptDst = new Point2D.Float();
3689 }
3690 }
3691 // Copy source coords into local variables in case src == dst
3692 double x = ptSrc.getX();
3693 double y = ptSrc.getY();
3694 switch (state) {
3695 default:
3696 stateError();
3697 /* NOTREACHED */
3698 return null;
3699 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3717 /* NOTREACHED */
3718 }
3719
3720 /**
3721 * Transforms an array of relative distance vectors by this
3722 * transform.
3723 * A relative distance vector is transformed without applying the
3724 * translation components of the affine transformation matrix
3725 * using the following equations:
3726 * <pre>
3727 * [ x' ] [ m00 m01 (m02) ] [ x ] [ m00x + m01y ]
3728 * [ y' ] = [ m10 m11 (m12) ] [ y ] = [ m10x + m11y ]
3729 * [ (1) ] [ (0) (0) ( 1 ) ] [ (1) ] [ (1) ]
3730 * </pre>
3731 * The two coordinate array sections can be exactly the same or
3732 * can be overlapping sections of the same array without affecting the
3733 * validity of the results.
3734 * This method ensures that no source coordinates are
3735 * overwritten by a previous operation before they can be transformed.
3736 * The coordinates are stored in the arrays starting at the indicated
3737 * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3738 * @param srcPts the array containing the source distance vectors.
3739 * Each vector is stored as a pair of relative x, y coordinates.
3740 * @param dstPts the array into which the transformed distance vectors
3741 * are returned. Each vector is stored as a pair of relative
3742 * x, y coordinates.
3743 * @param srcOff the offset to the first vector to be transformed
3744 * in the source array
3745 * @param dstOff the offset to the location of the first
3746 * transformed vector that is stored in the destination array
3747 * @param numPts the number of vector coordinate pairs to be
3748 * transformed
3749 * @since 1.2
3750 */
3751 public void deltaTransform(double[] srcPts, int srcOff,
3752 double[] dstPts, int dstOff,
3753 int numPts) {
3754 double M00, M01, M10, M11; // For caching
3755 if (dstPts == srcPts &&
3756 dstOff > srcOff && dstOff < srcOff + numPts * 2)
3757 {
3797 M00 = m00; M11 = m11;
3798 while (--numPts >= 0) {
3799 dstPts[dstOff++] = srcPts[srcOff++] * M00;
3800 dstPts[dstOff++] = srcPts[srcOff++] * M11;
3801 }
3802 return;
3803 case (APPLY_TRANSLATE):
3804 case (APPLY_IDENTITY):
3805 if (srcPts != dstPts || srcOff != dstOff) {
3806 System.arraycopy(srcPts, srcOff, dstPts, dstOff,
3807 numPts * 2);
3808 }
3809 return;
3810 }
3811
3812 /* NOTREACHED */
3813 }
3814
3815 /**
3816 * Returns a new {@link Shape} object defined by the geometry of the
3817 * specified <code>Shape</code> after it has been transformed by
3818 * this transform.
3819 * @param pSrc the specified <code>Shape</code> object to be
3820 * transformed by this transform.
3821 * @return a new <code>Shape</code> object that defines the geometry
3822 * of the transformed <code>Shape</code>, or null if {@code pSrc} is null.
3823 * @since 1.2
3824 */
3825 public Shape createTransformedShape(Shape pSrc) {
3826 if (pSrc == null) {
3827 return null;
3828 }
3829 return new Path2D.Double(pSrc, this);
3830 }
3831
3832 // Round values to sane precision for printing
3833 // Note that Math.sin(Math.PI) has an error of about 10^-16
3834 private static double _matround(double matval) {
3835 return Math.rint(matval * 1E15) / 1E15;
3836 }
3837
3838 /**
3839 * Returns a <code>String</code> that represents the value of this
3840 * {@link Object}.
3841 * @return a <code>String</code> representing the value of this
3842 * <code>Object</code>.
3843 * @since 1.2
3844 */
3845 public String toString() {
3846 return ("AffineTransform[["
3847 + _matround(m00) + ", "
3848 + _matround(m01) + ", "
3849 + _matround(m02) + "], ["
3850 + _matround(m10) + ", "
3851 + _matround(m11) + ", "
3852 + _matround(m12) + "]]");
3853 }
3854
3855 /**
3856 * Returns <code>true</code> if this <code>AffineTransform</code> is
3857 * an identity transform.
3858 * @return <code>true</code> if this <code>AffineTransform</code> is
3859 * an identity transform; <code>false</code> otherwise.
3860 * @since 1.2
3861 */
3862 public boolean isIdentity() {
3863 return (state == APPLY_IDENTITY || (getType() == TYPE_IDENTITY));
3864 }
3865
3866 /**
3867 * Returns a copy of this <code>AffineTransform</code> object.
3868 * @return an <code>Object</code> that is a copy of this
3869 * <code>AffineTransform</code> object.
3870 * @since 1.2
3871 */
3872 public Object clone() {
3873 try {
3874 return super.clone();
3875 } catch (CloneNotSupportedException e) {
3876 // this shouldn't happen, since we are Cloneable
3877 throw new InternalError(e);
3878 }
3879 }
3880
3881 /**
3882 * Returns the hashcode for this transform.
3883 * @return a hash code for this transform.
3884 * @since 1.2
3885 */
3886 public int hashCode() {
3887 long bits = Double.doubleToLongBits(m00);
3888 bits = bits * 31 + Double.doubleToLongBits(m01);
3889 bits = bits * 31 + Double.doubleToLongBits(m02);
3890 bits = bits * 31 + Double.doubleToLongBits(m10);
3891 bits = bits * 31 + Double.doubleToLongBits(m11);
3892 bits = bits * 31 + Double.doubleToLongBits(m12);
3893 return (((int) bits) ^ ((int) (bits >> 32)));
3894 }
3895
3896 /**
3897 * Returns <code>true</code> if this <code>AffineTransform</code>
3898 * represents the same affine coordinate transform as the specified
3899 * argument.
3900 * @param obj the <code>Object</code> to test for equality with this
3901 * <code>AffineTransform</code>
3902 * @return <code>true</code> if <code>obj</code> equals this
3903 * <code>AffineTransform</code> object; <code>false</code> otherwise.
3904 * @since 1.2
3905 */
3906 public boolean equals(Object obj) {
3907 if (!(obj instanceof AffineTransform)) {
3908 return false;
3909 }
3910
3911 AffineTransform a = (AffineTransform)obj;
3912
3913 return ((m00 == a.m00) && (m01 == a.m01) && (m02 == a.m02) &&
3914 (m10 == a.m10) && (m11 == a.m11) && (m12 == a.m12));
3915 }
3916
3917 /* Serialization support. A readObject method is neccessary because
3918 * the state field is part of the implementation of this particular
3919 * AffineTransform and not part of the public specification. The
3920 * state variable's value needs to be recalculated on the fly by the
3921 * readObject method as it is in the 6-argument matrix constructor.
3922 */
3923
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.awt.geom;
27
28 import java.awt.Shape;
29 import java.beans.ConstructorProperties;
30
31 /**
32 * The {@code AffineTransform} class represents a 2D affine transform
33 * that performs a linear mapping from 2D coordinates to other 2D
34 * coordinates that preserves the "straightness" and
35 * "parallelness" of lines. Affine transformations can be constructed
36 * using sequences of translations, scales, flips, rotations, and shears.
37 * <p>
38 * Such a coordinate transformation can be represented by a 3 row by
39 * 3 column matrix with an implied last row of [ 0 0 1 ]. This matrix
40 * transforms source coordinates {@code (x,y)} into
41 * destination coordinates {@code (x',y')} by considering
42 * them to be a column vector and multiplying the coordinate vector
43 * by the matrix according to the following process:
44 * <pre>
45 * [ x'] [ m00 m01 m02 ] [ x ] [ m00x + m01y + m02 ]
46 * [ y'] = [ m10 m11 m12 ] [ y ] = [ m10x + m11y + m12 ]
47 * [ 1 ] [ 0 0 1 ] [ 1 ] [ 1 ]
48 * </pre>
49 * <h3><a name="quadrantapproximation">Handling 90-Degree Rotations</a></h3>
50 * <p>
51 * In some variations of the {@code rotate} methods in the
52 * {@code AffineTransform} 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} 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} 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()} and
76 * {@code Math.cos()} correspondingly never return 0.0
77 * for any case other than {@code Math.sin(0.0)}.
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()} and {@code Math.cos()} 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)},
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}.
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
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} 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} that is a copy of
483 * the specified {@code AffineTransform} object.
484 * @param Tx the {@code AffineTransform} 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} 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 @ConstructorProperties({ "scaleX", "shearY", "shearX", "scaleY", "translateX", "translateY" })
512 public AffineTransform(float m00, float m10,
513 float m01, float m11,
514 float m02, float m12) {
515 this.m00 = m00;
516 this.m10 = m10;
517 this.m01 = m01;
518 this.m11 = m11;
519 this.m02 = m02;
520 this.m12 = m12;
521 updateState();
522 }
523
524 /**
525 * Constructs a new {@code AffineTransform} from an array of
526 * floating point values representing either the 4 non-translation
527 * entries or the 6 specifiable entries of the 3x3 transformation
528 * matrix. The values are retrieved from the array as
529 * { m00 m10 m01 m11 [m02 m12]}.
530 * @param flatmatrix the float array containing the values to be set
531 * in the new {@code AffineTransform} object. The length of the
532 * array is assumed to be at least 4. If the length of the array is
533 * less than 6, only the first 4 values are taken. If the length of
534 * the array is greater than 6, the first 6 values are taken.
535 * @since 1.2
536 */
537 public AffineTransform(float[] flatmatrix) {
538 m00 = flatmatrix[0];
539 m10 = flatmatrix[1];
540 m01 = flatmatrix[2];
541 m11 = flatmatrix[3];
542 if (flatmatrix.length > 5) {
543 m02 = flatmatrix[4];
544 m12 = flatmatrix[5];
545 }
546 updateState();
547 }
548
549 /**
550 * Constructs a new {@code AffineTransform} from 6 double
551 * precision values representing the 6 specifiable entries of the 3x3
552 * transformation matrix.
553 *
554 * @param m00 the X coordinate scaling element of the 3x3 matrix
555 * @param m10 the Y coordinate shearing element of the 3x3 matrix
556 * @param m01 the X coordinate shearing element of the 3x3 matrix
557 * @param m11 the Y coordinate scaling element of the 3x3 matrix
558 * @param m02 the X coordinate translation element of the 3x3 matrix
559 * @param m12 the Y coordinate translation element of the 3x3 matrix
560 * @since 1.2
561 */
562 public AffineTransform(double m00, double m10,
563 double m01, double m11,
564 double m02, double m12) {
565 this.m00 = m00;
566 this.m10 = m10;
567 this.m01 = m01;
568 this.m11 = m11;
569 this.m02 = m02;
570 this.m12 = m12;
571 updateState();
572 }
573
574 /**
575 * Constructs a new {@code AffineTransform} from an array of
576 * double precision values representing either the 4 non-translation
577 * entries or the 6 specifiable entries of the 3x3 transformation
578 * matrix. The values are retrieved from the array as
579 * { m00 m10 m01 m11 [m02 m12]}.
580 * @param flatmatrix the double array containing the values to be set
581 * in the new {@code AffineTransform} object. The length of the
582 * array is assumed to be at least 4. If the length of the array is
583 * less than 6, only the first 4 values are taken. If the length of
584 * the array is greater than 6, the first 6 values are taken.
585 * @since 1.2
586 */
587 public AffineTransform(double[] flatmatrix) {
588 m00 = flatmatrix[0];
589 m10 = flatmatrix[1];
590 m01 = flatmatrix[2];
591 m11 = flatmatrix[3];
592 if (flatmatrix.length > 5) {
593 m02 = flatmatrix[4];
594 m12 = flatmatrix[5];
595 }
596 updateState();
597 }
598
599 /**
600 * Returns a transform representing a translation transformation.
601 * The matrix representing the returned transform is:
602 * <pre>
603 * [ 1 0 tx ]
604 * [ 0 1 ty ]
605 * [ 0 0 1 ]
606 * </pre>
607 * @param tx the distance by which coordinates are translated in the
608 * X axis direction
609 * @param ty the distance by which coordinates are translated in the
610 * Y axis direction
611 * @return an {@code AffineTransform} object that represents a
612 * translation transformation, created with the specified vector.
613 * @since 1.2
614 */
615 public static AffineTransform getTranslateInstance(double tx, double ty) {
616 AffineTransform Tx = new AffineTransform();
617 Tx.setToTranslation(tx, ty);
618 return Tx;
619 }
620
621 /**
622 * Returns a transform representing a rotation transformation.
623 * The matrix representing the returned transform is:
624 * <pre>
625 * [ cos(theta) -sin(theta) 0 ]
626 * [ sin(theta) cos(theta) 0 ]
627 * [ 0 0 1 ]
628 * </pre>
629 * Rotating by a positive angle theta rotates points on the positive
630 * X axis toward the positive Y axis.
631 * Note also the discussion of
632 * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
633 * above.
634 * @param theta the angle of rotation measured in radians
635 * @return an {@code AffineTransform} object that is a rotation
636 * transformation, created with the specified angle of rotation.
637 * @since 1.2
638 */
639 public static AffineTransform getRotateInstance(double theta) {
640 AffineTransform Tx = new AffineTransform();
641 Tx.setToRotation(theta);
642 return Tx;
643 }
644
645 /**
646 * Returns a transform that rotates coordinates around an anchor point.
647 * This operation is equivalent to translating the coordinates so
648 * that the anchor point is at the origin (S1), then rotating them
649 * about the new origin (S2), and finally translating so that the
650 * intermediate origin is restored to the coordinates of the original
651 * anchor point (S3).
652 * <p>
653 * This operation is equivalent to the following sequence of calls:
654 * <pre>
655 * AffineTransform Tx = new AffineTransform();
656 * Tx.translate(anchorx, anchory); // S3: final translation
657 * Tx.rotate(theta); // S2: rotate around anchor
658 * Tx.translate(-anchorx, -anchory); // S1: translate anchor to origin
659 * </pre>
660 * The matrix representing the returned transform is:
661 * <pre>
662 * [ cos(theta) -sin(theta) x-x*cos+y*sin ]
663 * [ sin(theta) cos(theta) y-x*sin-y*cos ]
664 * [ 0 0 1 ]
665 * </pre>
666 * Rotating by a positive angle theta rotates points on the positive
667 * X axis toward the positive Y axis.
668 * Note also the discussion of
669 * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
670 * above.
671 *
672 * @param theta the angle of rotation measured in radians
673 * @param anchorx the X coordinate of the rotation anchor point
674 * @param anchory the Y coordinate of the rotation anchor point
675 * @return an {@code AffineTransform} object that rotates
676 * coordinates around the specified point by the specified angle of
677 * rotation.
678 * @since 1.2
679 */
680 public static AffineTransform getRotateInstance(double theta,
681 double anchorx,
682 double anchory)
683 {
684 AffineTransform Tx = new AffineTransform();
685 Tx.setToRotation(theta, anchorx, anchory);
686 return Tx;
687 }
688
689 /**
690 * Returns a transform that rotates coordinates according to
691 * a rotation vector.
692 * All coordinates rotate about the origin by the same amount.
693 * The amount of rotation is such that coordinates along the former
694 * positive X axis will subsequently align with the vector pointing
695 * from the origin to the specified vector coordinates.
696 * If both {@code vecx} and {@code vecy} are 0.0,
697 * an identity transform is returned.
698 * This operation is equivalent to calling:
699 * <pre>
700 * AffineTransform.getRotateInstance(Math.atan2(vecy, vecx));
701 * </pre>
702 *
703 * @param vecx the X coordinate of the rotation vector
704 * @param vecy the Y coordinate of the rotation vector
705 * @return an {@code AffineTransform} object that rotates
706 * coordinates according to the specified rotation vector.
707 * @since 1.6
708 */
709 public static AffineTransform getRotateInstance(double vecx, double vecy) {
710 AffineTransform Tx = new AffineTransform();
711 Tx.setToRotation(vecx, vecy);
712 return Tx;
713 }
714
715 /**
716 * Returns a transform that rotates coordinates around an anchor
717 * point according to a rotation vector.
718 * All coordinates rotate about the specified anchor coordinates
719 * by the same amount.
720 * The amount of rotation is such that coordinates along the former
721 * positive X axis will subsequently align with the vector pointing
722 * from the origin to the specified vector coordinates.
723 * If both {@code vecx} and {@code vecy} are 0.0,
724 * an identity transform is returned.
725 * This operation is equivalent to calling:
726 * <pre>
727 * AffineTransform.getRotateInstance(Math.atan2(vecy, vecx),
728 * anchorx, anchory);
729 * </pre>
730 *
731 * @param vecx the X coordinate of the rotation vector
732 * @param vecy the Y coordinate of the rotation vector
733 * @param anchorx the X coordinate of the rotation anchor point
734 * @param anchory the Y coordinate of the rotation anchor point
735 * @return an {@code AffineTransform} object that rotates
736 * coordinates around the specified point according to the
737 * specified rotation vector.
738 * @since 1.6
739 */
740 public static AffineTransform getRotateInstance(double vecx,
741 double vecy,
742 double anchorx,
743 double anchory)
744 {
745 AffineTransform Tx = new AffineTransform();
746 Tx.setToRotation(vecx, vecy, anchorx, anchory);
747 return Tx;
748 }
749
750 /**
751 * Returns a transform that rotates coordinates by the specified
752 * number of quadrants.
753 * This operation is equivalent to calling:
754 * <pre>
755 * AffineTransform.getRotateInstance(numquadrants * Math.PI / 2.0);
756 * </pre>
757 * Rotating by a positive number of quadrants rotates points on
758 * the positive X axis toward the positive Y axis.
759 * @param numquadrants the number of 90 degree arcs to rotate by
760 * @return an {@code AffineTransform} object that rotates
761 * coordinates by the specified number of quadrants.
762 * @since 1.6
763 */
764 public static AffineTransform getQuadrantRotateInstance(int numquadrants) {
765 AffineTransform Tx = new AffineTransform();
766 Tx.setToQuadrantRotation(numquadrants);
767 return Tx;
768 }
769
770 /**
771 * Returns a transform that rotates coordinates by the specified
772 * number of quadrants around the specified anchor point.
773 * This operation is equivalent to calling:
774 * <pre>
775 * AffineTransform.getRotateInstance(numquadrants * Math.PI / 2.0,
776 * anchorx, anchory);
777 * </pre>
778 * Rotating by a positive number of quadrants rotates points on
779 * the positive X axis toward the positive Y axis.
780 *
781 * @param numquadrants the number of 90 degree arcs to rotate by
782 * @param anchorx the X coordinate of the rotation anchor point
783 * @param anchory the Y coordinate of the rotation anchor point
784 * @return an {@code AffineTransform} object that rotates
785 * coordinates by the specified number of quadrants around the
786 * specified anchor point.
787 * @since 1.6
788 */
789 public static AffineTransform getQuadrantRotateInstance(int numquadrants,
790 double anchorx,
791 double anchory)
792 {
793 AffineTransform Tx = new AffineTransform();
794 Tx.setToQuadrantRotation(numquadrants, anchorx, anchory);
795 return Tx;
796 }
797
798 /**
799 * Returns a transform representing a scaling transformation.
800 * The matrix representing the returned transform is:
801 * <pre>
802 * [ sx 0 0 ]
803 * [ 0 sy 0 ]
804 * [ 0 0 1 ]
805 * </pre>
806 * @param sx the factor by which coordinates are scaled along the
807 * X axis direction
808 * @param sy the factor by which coordinates are scaled along the
809 * Y axis direction
810 * @return an {@code AffineTransform} object that scales
811 * coordinates by the specified factors.
812 * @since 1.2
813 */
814 public static AffineTransform getScaleInstance(double sx, double sy) {
815 AffineTransform Tx = new AffineTransform();
816 Tx.setToScale(sx, sy);
817 return Tx;
818 }
819
820 /**
821 * Returns a transform representing a shearing transformation.
822 * The matrix representing the returned transform is:
823 * <pre>
824 * [ 1 shx 0 ]
825 * [ shy 1 0 ]
826 * [ 0 0 1 ]
827 * </pre>
828 * @param shx the multiplier by which coordinates are shifted in the
829 * direction of the positive X axis as a factor of their Y coordinate
830 * @param shy the multiplier by which coordinates are shifted in the
831 * direction of the positive Y axis as a factor of their X coordinate
832 * @return an {@code AffineTransform} object that shears
833 * coordinates by the specified multipliers.
834 * @since 1.2
835 */
836 public static AffineTransform getShearInstance(double shx, double shy) {
837 AffineTransform Tx = new AffineTransform();
838 Tx.setToShear(shx, shy);
839 return Tx;
840 }
841
842 /**
843 * Retrieves the flag bits describing the conversion properties of
844 * this transform.
845 * The return value is either one of the constants TYPE_IDENTITY
846 * or TYPE_GENERAL_TRANSFORM, or a combination of the
847 * appropriate flag bits.
848 * A valid combination of flag bits is an exclusive OR operation
849 * that can combine
850 * the TYPE_TRANSLATION flag bit
851 * in addition to either of the
852 * TYPE_UNIFORM_SCALE or TYPE_GENERAL_SCALE flag bits
998 }
999
1000 /**
1001 * Returns the determinant of the matrix representation of the transform.
1002 * The determinant is useful both to determine if the transform can
1003 * be inverted and to get a single value representing the
1004 * combined X and Y scaling of the transform.
1005 * <p>
1006 * If the determinant is non-zero, then this transform is
1007 * invertible and the various methods that depend on the inverse
1008 * transform do not need to throw a
1009 * {@link NoninvertibleTransformException}.
1010 * If the determinant is zero then this transform can not be
1011 * inverted since the transform maps all input coordinates onto
1012 * a line or a point.
1013 * If the determinant is near enough to zero then inverse transform
1014 * operations might not carry enough precision to produce meaningful
1015 * results.
1016 * <p>
1017 * If this transform represents a uniform scale, as indicated by
1018 * the {@code getType} method then the determinant also
1019 * represents the square of the uniform scale factor by which all of
1020 * the points are expanded from or contracted towards the origin.
1021 * If this transform represents a non-uniform scale or more general
1022 * transform then the determinant is not likely to represent a
1023 * value useful for any purpose other than determining if inverse
1024 * transforms are possible.
1025 * <p>
1026 * Mathematically, the determinant is calculated using the formula:
1027 * <pre>
1028 * | m00 m01 m02 |
1029 * | m10 m11 m12 | = m00 * m11 - m01 * m10
1030 * | 0 0 1 |
1031 * </pre>
1032 *
1033 * @return the determinant of the matrix used to transform the
1034 * coordinates.
1035 * @see #getType
1036 * @see #createInverse
1037 * @see #inverseTransform
1038 * @see #TYPE_UNIFORM_SCALE
1217 */
1218 public double getTranslateX() {
1219 return m02;
1220 }
1221
1222 /**
1223 * Returns the Y coordinate of the translation element (m12) of the
1224 * 3x3 affine transformation matrix.
1225 * @return a double value that is the Y coordinate of the translation
1226 * element of the affine transformation matrix.
1227 * @see #getMatrix
1228 * @since 1.2
1229 */
1230 public double getTranslateY() {
1231 return m12;
1232 }
1233
1234 /**
1235 * Concatenates this transform with a translation transformation.
1236 * This is equivalent to calling concatenate(T), where T is an
1237 * {@code AffineTransform} represented by the following matrix:
1238 * <pre>
1239 * [ 1 0 tx ]
1240 * [ 0 1 ty ]
1241 * [ 0 0 1 ]
1242 * </pre>
1243 * @param tx the distance by which coordinates are translated in the
1244 * X axis direction
1245 * @param ty the distance by which coordinates are translated in the
1246 * Y axis direction
1247 * @since 1.2
1248 */
1249 public void translate(double tx, double ty) {
1250 switch (state) {
1251 default:
1252 stateError();
1253 /* NOTREACHED */
1254 return;
1255 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1256 m02 = tx * m00 + ty * m01 + m02;
1257 m12 = tx * m10 + ty * m11 + m12;
1377 private final void rotate270() {
1378 double M0 = m00;
1379 m00 = -m01;
1380 m01 = M0;
1381 M0 = m10;
1382 m10 = -m11;
1383 m11 = M0;
1384 int state = rot90conversion[this.state];
1385 if ((state & (APPLY_SHEAR | APPLY_SCALE)) == APPLY_SCALE &&
1386 m00 == 1.0 && m11 == 1.0)
1387 {
1388 state -= APPLY_SCALE;
1389 }
1390 this.state = state;
1391 type = TYPE_UNKNOWN;
1392 }
1393
1394 /**
1395 * Concatenates this transform with a rotation transformation.
1396 * This is equivalent to calling concatenate(R), where R is an
1397 * {@code AffineTransform} represented by the following matrix:
1398 * <pre>
1399 * [ cos(theta) -sin(theta) 0 ]
1400 * [ sin(theta) cos(theta) 0 ]
1401 * [ 0 0 1 ]
1402 * </pre>
1403 * Rotating by a positive angle theta rotates points on the positive
1404 * X axis toward the positive Y axis.
1405 * Note also the discussion of
1406 * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
1407 * above.
1408 * @param theta the angle of rotation measured in radians
1409 * @since 1.2
1410 */
1411 public void rotate(double theta) {
1412 double sin = Math.sin(theta);
1413 if (sin == 1.0) {
1414 rotate90();
1415 } else if (sin == -1.0) {
1416 rotate270();
1417 } else {
1456 *
1457 * @param theta the angle of rotation measured in radians
1458 * @param anchorx the X coordinate of the rotation anchor point
1459 * @param anchory the Y coordinate of the rotation anchor point
1460 * @since 1.2
1461 */
1462 public void rotate(double theta, double anchorx, double anchory) {
1463 // REMIND: Simple for now - optimize later
1464 translate(anchorx, anchory);
1465 rotate(theta);
1466 translate(-anchorx, -anchory);
1467 }
1468
1469 /**
1470 * Concatenates this transform with a transform that rotates
1471 * coordinates according to a rotation vector.
1472 * All coordinates rotate about the origin by the same amount.
1473 * The amount of rotation is such that coordinates along the former
1474 * positive X axis will subsequently align with the vector pointing
1475 * from the origin to the specified vector coordinates.
1476 * If both {@code vecx} and {@code vecy} are 0.0,
1477 * no additional rotation is added to this transform.
1478 * This operation is equivalent to calling:
1479 * <pre>
1480 * rotate(Math.atan2(vecy, vecx));
1481 * </pre>
1482 *
1483 * @param vecx the X coordinate of the rotation vector
1484 * @param vecy the Y coordinate of the rotation vector
1485 * @since 1.6
1486 */
1487 public void rotate(double vecx, double vecy) {
1488 if (vecy == 0.0) {
1489 if (vecx < 0.0) {
1490 rotate180();
1491 }
1492 // If vecx > 0.0 - no rotation
1493 // If vecx == 0.0 - undefined rotation - treat as no rotation
1494 } else if (vecx == 0.0) {
1495 if (vecy > 0.0) {
1496 rotate90();
1506 M1 = m01;
1507 m00 = cos * M0 + sin * M1;
1508 m01 = -sin * M0 + cos * M1;
1509 M0 = m10;
1510 M1 = m11;
1511 m10 = cos * M0 + sin * M1;
1512 m11 = -sin * M0 + cos * M1;
1513 updateState();
1514 }
1515 }
1516
1517 /**
1518 * Concatenates this transform with a transform that rotates
1519 * coordinates around an anchor point according to a rotation
1520 * vector.
1521 * All coordinates rotate about the specified anchor coordinates
1522 * by the same amount.
1523 * The amount of rotation is such that coordinates along the former
1524 * positive X axis will subsequently align with the vector pointing
1525 * from the origin to the specified vector coordinates.
1526 * If both {@code vecx} and {@code vecy} are 0.0,
1527 * the transform is not modified in any way.
1528 * This method is equivalent to calling:
1529 * <pre>
1530 * rotate(Math.atan2(vecy, vecx), anchorx, anchory);
1531 * </pre>
1532 *
1533 * @param vecx the X coordinate of the rotation vector
1534 * @param vecy the Y coordinate of the rotation vector
1535 * @param anchorx the X coordinate of the rotation anchor point
1536 * @param anchory the Y coordinate of the rotation anchor point
1537 * @since 1.6
1538 */
1539 public void rotate(double vecx, double vecy,
1540 double anchorx, double anchory)
1541 {
1542 // REMIND: Simple for now - optimize later
1543 translate(anchorx, anchory);
1544 rotate(vecx, vecy);
1545 translate(-anchorx, -anchory);
1546 }
1604 m02 += anchorx * (m00 + m00) + anchory * (m01 + m01);
1605 m12 += anchorx * (m10 + m10) + anchory * (m11 + m11);
1606 rotate180();
1607 break;
1608 case 3:
1609 m02 += anchorx * (m00 + m01) + anchory * (m01 - m00);
1610 m12 += anchorx * (m10 + m11) + anchory * (m11 - m10);
1611 rotate270();
1612 break;
1613 }
1614 if (m02 == 0.0 && m12 == 0.0) {
1615 state &= ~APPLY_TRANSLATE;
1616 } else {
1617 state |= APPLY_TRANSLATE;
1618 }
1619 }
1620
1621 /**
1622 * Concatenates this transform with a scaling transformation.
1623 * This is equivalent to calling concatenate(S), where S is an
1624 * {@code AffineTransform} represented by the following matrix:
1625 * <pre>
1626 * [ sx 0 0 ]
1627 * [ 0 sy 0 ]
1628 * [ 0 0 1 ]
1629 * </pre>
1630 * @param sx the factor by which coordinates are scaled along the
1631 * X axis direction
1632 * @param sy the factor by which coordinates are scaled along the
1633 * Y axis direction
1634 * @since 1.2
1635 */
1636 @SuppressWarnings("fallthrough")
1637 public void scale(double sx, double sy) {
1638 int state = this.state;
1639 switch (state) {
1640 default:
1641 stateError();
1642 /* NOTREACHED */
1643 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1644 case (APPLY_SHEAR | APPLY_SCALE):
1673 : TYPE_TRANSLATION);
1674 } else {
1675 this.type = TYPE_UNKNOWN;
1676 }
1677 return;
1678 case (APPLY_TRANSLATE):
1679 case (APPLY_IDENTITY):
1680 m00 = sx;
1681 m11 = sy;
1682 if (sx != 1.0 || sy != 1.0) {
1683 this.state = state | APPLY_SCALE;
1684 this.type = TYPE_UNKNOWN;
1685 }
1686 return;
1687 }
1688 }
1689
1690 /**
1691 * Concatenates this transform with a shearing transformation.
1692 * This is equivalent to calling concatenate(SH), where SH is an
1693 * {@code AffineTransform} represented by the following matrix:
1694 * <pre>
1695 * [ 1 shx 0 ]
1696 * [ shy 1 0 ]
1697 * [ 0 0 1 ]
1698 * </pre>
1699 * @param shx the multiplier by which coordinates are shifted in the
1700 * direction of the positive X axis as a factor of their Y coordinate
1701 * @param shy the multiplier by which coordinates are shifted in the
1702 * direction of the positive Y axis as a factor of their X coordinate
1703 * @since 1.2
1704 */
1705 public void shear(double shx, double shy) {
1706 int state = this.state;
1707 switch (state) {
1708 default:
1709 stateError();
1710 /* NOTREACHED */
1711 return;
1712 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1713 case (APPLY_SHEAR | APPLY_SCALE):
1873 */
1874 public void setToRotation(double theta, double anchorx, double anchory) {
1875 setToRotation(theta);
1876 double sin = m10;
1877 double oneMinusCos = 1.0 - m00;
1878 m02 = anchorx * oneMinusCos + anchory * sin;
1879 m12 = anchory * oneMinusCos - anchorx * sin;
1880 if (m02 != 0.0 || m12 != 0.0) {
1881 state |= APPLY_TRANSLATE;
1882 type |= TYPE_TRANSLATION;
1883 }
1884 }
1885
1886 /**
1887 * Sets this transform to a rotation transformation that rotates
1888 * coordinates according to a rotation vector.
1889 * All coordinates rotate about the origin by the same amount.
1890 * The amount of rotation is such that coordinates along the former
1891 * positive X axis will subsequently align with the vector pointing
1892 * from the origin to the specified vector coordinates.
1893 * If both {@code vecx} and {@code vecy} are 0.0,
1894 * the transform is set to an identity transform.
1895 * This operation is equivalent to calling:
1896 * <pre>
1897 * setToRotation(Math.atan2(vecy, vecx));
1898 * </pre>
1899 *
1900 * @param vecx the X coordinate of the rotation vector
1901 * @param vecy the Y coordinate of the rotation vector
1902 * @since 1.6
1903 */
1904 public void setToRotation(double vecx, double vecy) {
1905 double sin, cos;
1906 if (vecy == 0) {
1907 sin = 0.0;
1908 if (vecx < 0.0) {
1909 cos = -1.0;
1910 state = APPLY_SCALE;
1911 type = TYPE_QUADRANT_ROTATION;
1912 } else {
1913 cos = 1.0;
1926 state = APPLY_SHEAR | APPLY_SCALE;
1927 type = TYPE_GENERAL_ROTATION;
1928 }
1929 m00 = cos;
1930 m10 = sin;
1931 m01 = -sin;
1932 m11 = cos;
1933 m02 = 0.0;
1934 m12 = 0.0;
1935 }
1936
1937 /**
1938 * Sets this transform to a rotation transformation that rotates
1939 * coordinates around an anchor point according to a rotation
1940 * vector.
1941 * All coordinates rotate about the specified anchor coordinates
1942 * by the same amount.
1943 * The amount of rotation is such that coordinates along the former
1944 * positive X axis will subsequently align with the vector pointing
1945 * from the origin to the specified vector coordinates.
1946 * If both {@code vecx} and {@code vecy} are 0.0,
1947 * the transform is set to an identity transform.
1948 * This operation is equivalent to calling:
1949 * <pre>
1950 * setToTranslation(Math.atan2(vecy, vecx), anchorx, anchory);
1951 * </pre>
1952 *
1953 * @param vecx the X coordinate of the rotation vector
1954 * @param vecy the Y coordinate of the rotation vector
1955 * @param anchorx the X coordinate of the rotation anchor point
1956 * @param anchory the Y coordinate of the rotation anchor point
1957 * @since 1.6
1958 */
1959 public void setToRotation(double vecx, double vecy,
1960 double anchorx, double anchory)
1961 {
1962 setToRotation(vecx, vecy);
1963 double sin = m10;
1964 double oneMinusCos = 1.0 - m00;
1965 m02 = anchorx * oneMinusCos + anchory * sin;
1966 m12 = anchory * oneMinusCos - anchorx * sin;
2150 * @since 1.2
2151 */
2152 public void setToShear(double shx, double shy) {
2153 m00 = 1.0;
2154 m01 = shx;
2155 m10 = shy;
2156 m11 = 1.0;
2157 m02 = 0.0;
2158 m12 = 0.0;
2159 if (shx != 0.0 || shy != 0.0) {
2160 state = (APPLY_SHEAR | APPLY_SCALE);
2161 type = TYPE_UNKNOWN;
2162 } else {
2163 state = APPLY_IDENTITY;
2164 type = TYPE_IDENTITY;
2165 }
2166 }
2167
2168 /**
2169 * Sets this transform to a copy of the transform in the specified
2170 * {@code AffineTransform} object.
2171 * @param Tx the {@code AffineTransform} object from which to
2172 * copy the transform
2173 * @since 1.2
2174 */
2175 public void setTransform(AffineTransform Tx) {
2176 this.m00 = Tx.m00;
2177 this.m10 = Tx.m10;
2178 this.m01 = Tx.m01;
2179 this.m11 = Tx.m11;
2180 this.m02 = Tx.m02;
2181 this.m12 = Tx.m12;
2182 this.state = Tx.state;
2183 this.type = Tx.type;
2184 }
2185
2186 /**
2187 * Sets this transform to the matrix specified by the 6
2188 * double precision values.
2189 *
2190 * @param m00 the X coordinate scaling element of the 3x3 matrix
2191 * @param m10 the Y coordinate shearing element of the 3x3 matrix
2192 * @param m01 the X coordinate shearing element of the 3x3 matrix
2193 * @param m11 the Y coordinate scaling element of the 3x3 matrix
2194 * @param m02 the X coordinate translation element of the 3x3 matrix
2195 * @param m12 the Y coordinate translation element of the 3x3 matrix
2196 * @since 1.2
2197 */
2198 public void setTransform(double m00, double m10,
2199 double m01, double m11,
2200 double m02, double m12) {
2201 this.m00 = m00;
2202 this.m10 = m10;
2203 this.m01 = m01;
2204 this.m11 = m11;
2205 this.m02 = m02;
2206 this.m12 = m12;
2207 updateState();
2208 }
2209
2210 /**
2211 * Concatenates an {@code AffineTransform Tx} to
2212 * this {@code AffineTransform} Cx in the most commonly useful
2213 * way to provide a new user space
2214 * that is mapped to the former user space by {@code Tx}.
2215 * Cx is updated to perform the combined transformation.
2216 * Transforming a point p by the updated transform Cx' is
2217 * equivalent to first transforming p by {@code Tx} and then
2218 * transforming the result by the original transform Cx like this:
2219 * Cx'(p) = Cx(Tx(p))
2220 * In matrix notation, if this transform Cx is
2221 * represented by the matrix [this] and {@code Tx} is represented
2222 * by the matrix [Tx] then this method does the following:
2223 * <pre>
2224 * [this] = [this] x [Tx]
2225 * </pre>
2226 * @param Tx the {@code AffineTransform} object to be
2227 * concatenated with this {@code AffineTransform} object.
2228 * @see #preConcatenate
2229 * @since 1.2
2230 */
2231 @SuppressWarnings("fallthrough")
2232 public void concatenate(AffineTransform Tx) {
2233 double M0, M1;
2234 double T00, T01, T10, T11;
2235 double T02, T12;
2236 int mystate = state;
2237 int txstate = Tx.state;
2238 switch ((txstate << HI_SHIFT) | mystate) {
2239
2240 /* ---------- Tx == IDENTITY cases ---------- */
2241 case (HI_IDENTITY | APPLY_IDENTITY):
2242 case (HI_IDENTITY | APPLY_TRANSLATE):
2243 case (HI_IDENTITY | APPLY_SCALE):
2244 case (HI_IDENTITY | APPLY_SCALE | APPLY_TRANSLATE):
2245 case (HI_IDENTITY | APPLY_SHEAR):
2246 case (HI_IDENTITY | APPLY_SHEAR | APPLY_TRANSLATE):
2247 case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE):
2397 m11 = T11 * M0;
2398 m12 += T12 * M0;
2399 break;
2400
2401 case (APPLY_TRANSLATE):
2402 m00 = T00;
2403 m01 = T01;
2404 m02 += T02;
2405
2406 m10 = T10;
2407 m11 = T11;
2408 m12 += T12;
2409 state = txstate | APPLY_TRANSLATE;
2410 type = TYPE_UNKNOWN;
2411 return;
2412 }
2413 updateState();
2414 }
2415
2416 /**
2417 * Concatenates an {@code AffineTransform Tx} to
2418 * this {@code AffineTransform} Cx
2419 * in a less commonly used way such that {@code Tx} modifies the
2420 * coordinate transformation relative to the absolute pixel
2421 * space rather than relative to the existing user space.
2422 * Cx is updated to perform the combined transformation.
2423 * Transforming a point p by the updated transform Cx' is
2424 * equivalent to first transforming p by the original transform
2425 * Cx and then transforming the result by
2426 * {@code Tx} like this:
2427 * Cx'(p) = Tx(Cx(p))
2428 * In matrix notation, if this transform Cx
2429 * is represented by the matrix [this] and {@code Tx} is
2430 * represented by the matrix [Tx] then this method does the
2431 * following:
2432 * <pre>
2433 * [this] = [Tx] x [this]
2434 * </pre>
2435 * @param Tx the {@code AffineTransform} object to be
2436 * concatenated with this {@code AffineTransform} object.
2437 * @see #concatenate
2438 * @since 1.2
2439 */
2440 @SuppressWarnings("fallthrough")
2441 public void preConcatenate(AffineTransform Tx) {
2442 double M0, M1;
2443 double T00, T01, T10, T11;
2444 double T02, T12;
2445 int mystate = state;
2446 int txstate = Tx.state;
2447 switch ((txstate << HI_SHIFT) | mystate) {
2448 case (HI_IDENTITY | APPLY_IDENTITY):
2449 case (HI_IDENTITY | APPLY_TRANSLATE):
2450 case (HI_IDENTITY | APPLY_SCALE):
2451 case (HI_IDENTITY | APPLY_SCALE | APPLY_TRANSLATE):
2452 case (HI_IDENTITY | APPLY_SHEAR):
2453 case (HI_IDENTITY | APPLY_SHEAR | APPLY_TRANSLATE):
2454 case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE):
2455 case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2456 // Tx is IDENTITY...
2615
2616 /* NOBREAK */
2617 case (APPLY_IDENTITY):
2618 m02 = T02;
2619 m12 = T12;
2620
2621 m00 = T00;
2622 m10 = T10;
2623
2624 m01 = T01;
2625 m11 = T11;
2626
2627 state = mystate | txstate;
2628 type = TYPE_UNKNOWN;
2629 return;
2630 }
2631 updateState();
2632 }
2633
2634 /**
2635 * Returns an {@code AffineTransform} object representing the
2636 * inverse transformation.
2637 * The inverse transform Tx' of this transform Tx
2638 * maps coordinates transformed by Tx back
2639 * to their original coordinates.
2640 * In other words, Tx'(Tx(p)) = p = Tx(Tx'(p)).
2641 * <p>
2642 * If this transform maps all coordinates onto a point or a line
2643 * then it will not have an inverse, since coordinates that do
2644 * not lie on the destination point or line will not have an inverse
2645 * mapping.
2646 * The {@code getDeterminant} method can be used to determine if this
2647 * transform has no inverse, in which case an exception will be
2648 * thrown if the {@code createInverse} method is called.
2649 * @return a new {@code AffineTransform} object representing the
2650 * inverse transformation.
2651 * @see #getDeterminant
2652 * @exception NoninvertibleTransformException
2653 * if the matrix cannot be inverted.
2654 * @since 1.2
2655 */
2656 public AffineTransform createInverse()
2657 throws NoninvertibleTransformException
2658 {
2659 double det;
2660 switch (state) {
2661 default:
2662 stateError();
2663 /* NOTREACHED */
2664 return null;
2665 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2666 det = m00 * m11 - m01 * m10;
2667 if (Math.abs(det) <= Double.MIN_VALUE) {
2668 throw new NoninvertibleTransformException("Determinant is "+
2669 det);
2723 -m02, -m12,
2724 (APPLY_TRANSLATE));
2725 case (APPLY_IDENTITY):
2726 return new AffineTransform();
2727 }
2728
2729 /* NOTREACHED */
2730 }
2731
2732 /**
2733 * Sets this transform to the inverse of itself.
2734 * The inverse transform Tx' of this transform Tx
2735 * maps coordinates transformed by Tx back
2736 * to their original coordinates.
2737 * In other words, Tx'(Tx(p)) = p = Tx(Tx'(p)).
2738 * <p>
2739 * If this transform maps all coordinates onto a point or a line
2740 * then it will not have an inverse, since coordinates that do
2741 * not lie on the destination point or line will not have an inverse
2742 * mapping.
2743 * The {@code getDeterminant} method can be used to determine if this
2744 * transform has no inverse, in which case an exception will be
2745 * thrown if the {@code invert} method is called.
2746 * @see #getDeterminant
2747 * @exception NoninvertibleTransformException
2748 * if the matrix cannot be inverted.
2749 * @since 1.6
2750 */
2751 public void invert()
2752 throws NoninvertibleTransformException
2753 {
2754 double M00, M01, M02;
2755 double M10, M11, M12;
2756 double det;
2757 switch (state) {
2758 default:
2759 stateError();
2760 /* NOTREACHED */
2761 return;
2762 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2763 M00 = m00; M01 = m01; M02 = m02;
2764 M10 = m10; M11 = m11; M12 = m12;
2765 det = M00 * M11 - M01 * M10;
2844 case (APPLY_TRANSLATE):
2845 // m00 = 1.0;
2846 // m10 = 0.0;
2847 // m01 = 0.0;
2848 // m11 = 1.0;
2849 m02 = -m02;
2850 m12 = -m12;
2851 break;
2852 case (APPLY_IDENTITY):
2853 // m00 = 1.0;
2854 // m10 = 0.0;
2855 // m01 = 0.0;
2856 // m11 = 1.0;
2857 // m02 = 0.0;
2858 // m12 = 0.0;
2859 break;
2860 }
2861 }
2862
2863 /**
2864 * Transforms the specified {@code ptSrc} and stores the result
2865 * in {@code ptDst}.
2866 * If {@code ptDst} is {@code null}, a new {@link Point2D}
2867 * object is allocated and then the result of the transformation is
2868 * stored in this object.
2869 * In either case, {@code ptDst}, which contains the
2870 * transformed point, is returned for convenience.
2871 * If {@code ptSrc} and {@code ptDst} are the same
2872 * object, the input point is correctly overwritten with
2873 * the transformed point.
2874 * @param ptSrc the specified {@code Point2D} to be transformed
2875 * @param ptDst the specified {@code Point2D} that stores the
2876 * result of transforming {@code ptSrc}
2877 * @return the {@code ptDst} after transforming
2878 * {@code ptSrc} and storing the result in {@code ptDst}.
2879 * @since 1.2
2880 */
2881 public Point2D transform(Point2D ptSrc, Point2D ptDst) {
2882 if (ptDst == null) {
2883 if (ptSrc instanceof Point2D.Double) {
2884 ptDst = new Point2D.Double();
2885 } else {
2886 ptDst = new Point2D.Float();
2887 }
2888 }
2889 // Copy source coords into local variables in case src == dst
2890 double x = ptSrc.getX();
2891 double y = ptSrc.getY();
2892 switch (state) {
2893 default:
2894 stateError();
2895 /* NOTREACHED */
2896 return null;
2897 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2898 ptDst.setLocation(x * m00 + y * m01 + m02,
2909 return ptDst;
2910 case (APPLY_SCALE | APPLY_TRANSLATE):
2911 ptDst.setLocation(x * m00 + m02, y * m11 + m12);
2912 return ptDst;
2913 case (APPLY_SCALE):
2914 ptDst.setLocation(x * m00, y * m11);
2915 return ptDst;
2916 case (APPLY_TRANSLATE):
2917 ptDst.setLocation(x + m02, y + m12);
2918 return ptDst;
2919 case (APPLY_IDENTITY):
2920 ptDst.setLocation(x, y);
2921 return ptDst;
2922 }
2923
2924 /* NOTREACHED */
2925 }
2926
2927 /**
2928 * Transforms an array of point objects by this transform.
2929 * If any element of the {@code ptDst} array is
2930 * {@code null}, a new {@code Point2D} object is allocated
2931 * and stored into that element before storing the results of the
2932 * transformation.
2933 * <p>
2934 * Note that this method does not take any precautions to
2935 * avoid problems caused by storing results into {@code Point2D}
2936 * objects that will be used as the source for calculations
2937 * further down the source array.
2938 * This method does guarantee that if a specified {@code Point2D}
2939 * object is both the source and destination for the same single point
2940 * transform operation then the results will not be stored until
2941 * the calculations are complete to avoid storing the results on
2942 * top of the operands.
2943 * If, however, the destination {@code Point2D} object for one
2944 * operation is the same object as the source {@code Point2D}
2945 * object for another operation further down the source array then
2946 * the original coordinates in that point are overwritten before
2947 * they can be converted.
2948 * @param ptSrc the array containing the source point objects
2949 * @param ptDst the array into which the transform point objects are
2950 * returned
2951 * @param srcOff the offset to the first point object to be
2952 * transformed in the source array
2953 * @param dstOff the offset to the location of the first
2954 * transformed point object that is stored in the destination array
2955 * @param numPts the number of point objects to be transformed
2956 * @since 1.2
2957 */
2958 public void transform(Point2D[] ptSrc, int srcOff,
2959 Point2D[] ptDst, int dstOff,
2960 int numPts) {
2961 int state = this.state;
2962 while (--numPts >= 0) {
2963 // Copy source coords into local variables in case src == dst
2964 Point2D src = ptSrc[srcOff++];
3000 case (APPLY_TRANSLATE):
3001 dst.setLocation(x + m02, y + m12);
3002 break;
3003 case (APPLY_IDENTITY):
3004 dst.setLocation(x, y);
3005 break;
3006 }
3007 }
3008
3009 /* NOTREACHED */
3010 }
3011
3012 /**
3013 * Transforms an array of floating point coordinates by this transform.
3014 * The two coordinate array sections can be exactly the same or
3015 * can be overlapping sections of the same array without affecting the
3016 * validity of the results.
3017 * This method ensures that no source coordinates are overwritten by a
3018 * previous operation before they can be transformed.
3019 * The coordinates are stored in the arrays starting at the specified
3020 * offset in the order {@code [x0, y0, x1, y1, ..., xn, yn]}.
3021 * @param srcPts the array containing the source point coordinates.
3022 * Each point is stored as a pair of x, y coordinates.
3023 * @param dstPts the array into which the transformed point coordinates
3024 * are returned. Each point is stored as a pair of x, y
3025 * coordinates.
3026 * @param srcOff the offset to the first point to be transformed
3027 * in the source array
3028 * @param dstOff the offset to the location of the first
3029 * transformed point that is stored in the destination array
3030 * @param numPts the number of points to be transformed
3031 * @since 1.2
3032 */
3033 public void transform(float[] srcPts, int srcOff,
3034 float[] dstPts, int dstOff,
3035 int numPts) {
3036 double M00, M01, M02, M10, M11, M12; // For caching
3037 if (dstPts == srcPts &&
3038 dstOff > srcOff && dstOff < srcOff + numPts * 2)
3039 {
3040 // If the arrays overlap partially with the destination higher
3115 return;
3116 case (APPLY_IDENTITY):
3117 if (srcPts != dstPts || srcOff != dstOff) {
3118 System.arraycopy(srcPts, srcOff, dstPts, dstOff,
3119 numPts * 2);
3120 }
3121 return;
3122 }
3123
3124 /* NOTREACHED */
3125 }
3126
3127 /**
3128 * Transforms an array of double precision coordinates by this transform.
3129 * The two coordinate array sections can be exactly the same or
3130 * can be overlapping sections of the same array without affecting the
3131 * validity of the results.
3132 * This method ensures that no source coordinates are
3133 * overwritten by a previous operation before they can be transformed.
3134 * The coordinates are stored in the arrays starting at the indicated
3135 * offset in the order {@code [x0, y0, x1, y1, ..., xn, yn]}.
3136 * @param srcPts the array containing the source point coordinates.
3137 * Each point is stored as a pair of x, y coordinates.
3138 * @param dstPts the array into which the transformed point
3139 * coordinates are returned. Each point is stored as a pair of
3140 * x, y coordinates.
3141 * @param srcOff the offset to the first point to be transformed
3142 * in the source array
3143 * @param dstOff the offset to the location of the first
3144 * transformed point that is stored in the destination array
3145 * @param numPts the number of point objects to be transformed
3146 * @since 1.2
3147 */
3148 public void transform(double[] srcPts, int srcOff,
3149 double[] dstPts, int dstOff,
3150 int numPts) {
3151 double M00, M01, M02, M10, M11, M12; // For caching
3152 if (dstPts == srcPts &&
3153 dstOff > srcOff && dstOff < srcOff + numPts * 2)
3154 {
3155 // If the arrays overlap partially with the destination higher
3226 while (--numPts >= 0) {
3227 dstPts[dstOff++] = srcPts[srcOff++] + M02;
3228 dstPts[dstOff++] = srcPts[srcOff++] + M12;
3229 }
3230 return;
3231 case (APPLY_IDENTITY):
3232 if (srcPts != dstPts || srcOff != dstOff) {
3233 System.arraycopy(srcPts, srcOff, dstPts, dstOff,
3234 numPts * 2);
3235 }
3236 return;
3237 }
3238
3239 /* NOTREACHED */
3240 }
3241
3242 /**
3243 * Transforms an array of floating point coordinates by this transform
3244 * and stores the results into an array of doubles.
3245 * The coordinates are stored in the arrays starting at the specified
3246 * offset in the order {@code [x0, y0, x1, y1, ..., xn, yn]}.
3247 * @param srcPts the array containing the source point coordinates.
3248 * Each point is stored as a pair of x, y coordinates.
3249 * @param dstPts the array into which the transformed point coordinates
3250 * are returned. Each point is stored as a pair of x, y
3251 * coordinates.
3252 * @param srcOff the offset to the first point to be transformed
3253 * in the source array
3254 * @param dstOff the offset to the location of the first
3255 * transformed point that is stored in the destination array
3256 * @param numPts the number of points to be transformed
3257 * @since 1.2
3258 */
3259 public void transform(float[] srcPts, int srcOff,
3260 double[] dstPts, int dstOff,
3261 int numPts) {
3262 double M00, M01, M02, M10, M11, M12; // For caching
3263 switch (state) {
3264 default:
3265 stateError();
3266 /* NOTREACHED */
3322 while (--numPts >= 0) {
3323 dstPts[dstOff++] = srcPts[srcOff++] + M02;
3324 dstPts[dstOff++] = srcPts[srcOff++] + M12;
3325 }
3326 return;
3327 case (APPLY_IDENTITY):
3328 while (--numPts >= 0) {
3329 dstPts[dstOff++] = srcPts[srcOff++];
3330 dstPts[dstOff++] = srcPts[srcOff++];
3331 }
3332 return;
3333 }
3334
3335 /* NOTREACHED */
3336 }
3337
3338 /**
3339 * Transforms an array of double precision coordinates by this transform
3340 * and stores the results into an array of floats.
3341 * The coordinates are stored in the arrays starting at the specified
3342 * offset in the order {@code [x0, y0, x1, y1, ..., xn, yn]}.
3343 * @param srcPts the array containing the source point coordinates.
3344 * Each point is stored as a pair of x, y coordinates.
3345 * @param dstPts the array into which the transformed point
3346 * coordinates are returned. Each point is stored as a pair of
3347 * x, y coordinates.
3348 * @param srcOff the offset to the first point to be transformed
3349 * in the source array
3350 * @param dstOff the offset to the location of the first
3351 * transformed point that is stored in the destination array
3352 * @param numPts the number of point objects to be transformed
3353 * @since 1.2
3354 */
3355 public void transform(double[] srcPts, int srcOff,
3356 float[] dstPts, int dstOff,
3357 int numPts) {
3358 double M00, M01, M02, M10, M11, M12; // For caching
3359 switch (state) {
3360 default:
3361 stateError();
3362 /* NOTREACHED */
3415 return;
3416 case (APPLY_TRANSLATE):
3417 M02 = m02; M12 = m12;
3418 while (--numPts >= 0) {
3419 dstPts[dstOff++] = (float) (srcPts[srcOff++] + M02);
3420 dstPts[dstOff++] = (float) (srcPts[srcOff++] + M12);
3421 }
3422 return;
3423 case (APPLY_IDENTITY):
3424 while (--numPts >= 0) {
3425 dstPts[dstOff++] = (float) (srcPts[srcOff++]);
3426 dstPts[dstOff++] = (float) (srcPts[srcOff++]);
3427 }
3428 return;
3429 }
3430
3431 /* NOTREACHED */
3432 }
3433
3434 /**
3435 * Inverse transforms the specified {@code ptSrc} and stores the
3436 * result in {@code ptDst}.
3437 * If {@code ptDst} is {@code null}, a new
3438 * {@code Point2D} object is allocated and then the result of the
3439 * transform is stored in this object.
3440 * In either case, {@code ptDst}, which contains the transformed
3441 * point, is returned for convenience.
3442 * If {@code ptSrc} and {@code ptDst} are the same
3443 * object, the input point is correctly overwritten with the
3444 * transformed point.
3445 * @param ptSrc the point to be inverse transformed
3446 * @param ptDst the resulting transformed point
3447 * @return {@code ptDst}, which contains the result of the
3448 * inverse transform.
3449 * @exception NoninvertibleTransformException if the matrix cannot be
3450 * inverted.
3451 * @since 1.2
3452 */
3453 @SuppressWarnings("fallthrough")
3454 public Point2D inverseTransform(Point2D ptSrc, Point2D ptDst)
3455 throws NoninvertibleTransformException
3456 {
3457 if (ptDst == null) {
3458 if (ptSrc instanceof Point2D.Double) {
3459 ptDst = new Point2D.Double();
3460 } else {
3461 ptDst = new Point2D.Float();
3462 }
3463 }
3464 // Copy source coords into local variables in case src == dst
3465 double x = ptSrc.getX();
3466 double y = ptSrc.getY();
3467 switch (state) {
3504 case (APPLY_TRANSLATE):
3505 ptDst.setLocation(x - m02, y - m12);
3506 return ptDst;
3507 case (APPLY_IDENTITY):
3508 ptDst.setLocation(x, y);
3509 return ptDst;
3510 }
3511
3512 /* NOTREACHED */
3513 }
3514
3515 /**
3516 * Inverse transforms an array of double precision coordinates by
3517 * this transform.
3518 * The two coordinate array sections can be exactly the same or
3519 * can be overlapping sections of the same array without affecting the
3520 * validity of the results.
3521 * This method ensures that no source coordinates are
3522 * overwritten by a previous operation before they can be transformed.
3523 * The coordinates are stored in the arrays starting at the specified
3524 * offset in the order {@code [x0, y0, x1, y1, ..., xn, yn]}.
3525 * @param srcPts the array containing the source point coordinates.
3526 * Each point is stored as a pair of x, y coordinates.
3527 * @param dstPts the array into which the transformed point
3528 * coordinates are returned. Each point is stored as a pair of
3529 * x, y coordinates.
3530 * @param srcOff the offset to the first point to be transformed
3531 * in the source array
3532 * @param dstOff the offset to the location of the first
3533 * transformed point that is stored in the destination array
3534 * @param numPts the number of point objects to be transformed
3535 * @exception NoninvertibleTransformException if the matrix cannot be
3536 * inverted.
3537 * @since 1.2
3538 */
3539 public void inverseTransform(double[] srcPts, int srcOff,
3540 double[] dstPts, int dstOff,
3541 int numPts)
3542 throws NoninvertibleTransformException
3543 {
3544 double M00, M01, M02, M10, M11, M12; // For caching
3640 case (APPLY_TRANSLATE):
3641 M02 = m02; M12 = m12;
3642 while (--numPts >= 0) {
3643 dstPts[dstOff++] = srcPts[srcOff++] - M02;
3644 dstPts[dstOff++] = srcPts[srcOff++] - M12;
3645 }
3646 return;
3647 case (APPLY_IDENTITY):
3648 if (srcPts != dstPts || srcOff != dstOff) {
3649 System.arraycopy(srcPts, srcOff, dstPts, dstOff,
3650 numPts * 2);
3651 }
3652 return;
3653 }
3654
3655 /* NOTREACHED */
3656 }
3657
3658 /**
3659 * Transforms the relative distance vector specified by
3660 * {@code ptSrc} and stores the result in {@code ptDst}.
3661 * A relative distance vector is transformed without applying the
3662 * translation components of the affine transformation matrix
3663 * using the following equations:
3664 * <pre>
3665 * [ x' ] [ m00 m01 (m02) ] [ x ] [ m00x + m01y ]
3666 * [ y' ] = [ m10 m11 (m12) ] [ y ] = [ m10x + m11y ]
3667 * [ (1) ] [ (0) (0) ( 1 ) ] [ (1) ] [ (1) ]
3668 * </pre>
3669 * If {@code ptDst} is {@code null}, a new
3670 * {@code Point2D} object is allocated and then the result of the
3671 * transform is stored in this object.
3672 * In either case, {@code ptDst}, which contains the
3673 * transformed point, is returned for convenience.
3674 * If {@code ptSrc} and {@code ptDst} are the same object,
3675 * the input point is correctly overwritten with the transformed
3676 * point.
3677 * @param ptSrc the distance vector to be delta transformed
3678 * @param ptDst the resulting transformed distance vector
3679 * @return {@code ptDst}, which contains the result of the
3680 * transformation.
3681 * @since 1.2
3682 */
3683 public Point2D deltaTransform(Point2D ptSrc, Point2D ptDst) {
3684 if (ptDst == null) {
3685 if (ptSrc instanceof Point2D.Double) {
3686 ptDst = new Point2D.Double();
3687 } else {
3688 ptDst = new Point2D.Float();
3689 }
3690 }
3691 // Copy source coords into local variables in case src == dst
3692 double x = ptSrc.getX();
3693 double y = ptSrc.getY();
3694 switch (state) {
3695 default:
3696 stateError();
3697 /* NOTREACHED */
3698 return null;
3699 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3717 /* NOTREACHED */
3718 }
3719
3720 /**
3721 * Transforms an array of relative distance vectors by this
3722 * transform.
3723 * A relative distance vector is transformed without applying the
3724 * translation components of the affine transformation matrix
3725 * using the following equations:
3726 * <pre>
3727 * [ x' ] [ m00 m01 (m02) ] [ x ] [ m00x + m01y ]
3728 * [ y' ] = [ m10 m11 (m12) ] [ y ] = [ m10x + m11y ]
3729 * [ (1) ] [ (0) (0) ( 1 ) ] [ (1) ] [ (1) ]
3730 * </pre>
3731 * The two coordinate array sections can be exactly the same or
3732 * can be overlapping sections of the same array without affecting the
3733 * validity of the results.
3734 * This method ensures that no source coordinates are
3735 * overwritten by a previous operation before they can be transformed.
3736 * The coordinates are stored in the arrays starting at the indicated
3737 * offset in the order {@code [x0, y0, x1, y1, ..., xn, yn]}.
3738 * @param srcPts the array containing the source distance vectors.
3739 * Each vector is stored as a pair of relative x, y coordinates.
3740 * @param dstPts the array into which the transformed distance vectors
3741 * are returned. Each vector is stored as a pair of relative
3742 * x, y coordinates.
3743 * @param srcOff the offset to the first vector to be transformed
3744 * in the source array
3745 * @param dstOff the offset to the location of the first
3746 * transformed vector that is stored in the destination array
3747 * @param numPts the number of vector coordinate pairs to be
3748 * transformed
3749 * @since 1.2
3750 */
3751 public void deltaTransform(double[] srcPts, int srcOff,
3752 double[] dstPts, int dstOff,
3753 int numPts) {
3754 double M00, M01, M10, M11; // For caching
3755 if (dstPts == srcPts &&
3756 dstOff > srcOff && dstOff < srcOff + numPts * 2)
3757 {
3797 M00 = m00; M11 = m11;
3798 while (--numPts >= 0) {
3799 dstPts[dstOff++] = srcPts[srcOff++] * M00;
3800 dstPts[dstOff++] = srcPts[srcOff++] * M11;
3801 }
3802 return;
3803 case (APPLY_TRANSLATE):
3804 case (APPLY_IDENTITY):
3805 if (srcPts != dstPts || srcOff != dstOff) {
3806 System.arraycopy(srcPts, srcOff, dstPts, dstOff,
3807 numPts * 2);
3808 }
3809 return;
3810 }
3811
3812 /* NOTREACHED */
3813 }
3814
3815 /**
3816 * Returns a new {@link Shape} object defined by the geometry of the
3817 * specified {@code Shape} after it has been transformed by
3818 * this transform.
3819 * @param pSrc the specified {@code Shape} object to be
3820 * transformed by this transform.
3821 * @return a new {@code Shape} object that defines the geometry
3822 * of the transformed {@code Shape}, or null if {@code pSrc} is null.
3823 * @since 1.2
3824 */
3825 public Shape createTransformedShape(Shape pSrc) {
3826 if (pSrc == null) {
3827 return null;
3828 }
3829 return new Path2D.Double(pSrc, this);
3830 }
3831
3832 // Round values to sane precision for printing
3833 // Note that Math.sin(Math.PI) has an error of about 10^-16
3834 private static double _matround(double matval) {
3835 return Math.rint(matval * 1E15) / 1E15;
3836 }
3837
3838 /**
3839 * Returns a {@code String} that represents the value of this
3840 * {@link Object}.
3841 * @return a {@code String} representing the value of this
3842 * {@code Object}.
3843 * @since 1.2
3844 */
3845 public String toString() {
3846 return ("AffineTransform[["
3847 + _matround(m00) + ", "
3848 + _matround(m01) + ", "
3849 + _matround(m02) + "], ["
3850 + _matround(m10) + ", "
3851 + _matround(m11) + ", "
3852 + _matround(m12) + "]]");
3853 }
3854
3855 /**
3856 * Returns {@code true} if this {@code AffineTransform} is
3857 * an identity transform.
3858 * @return {@code true} if this {@code AffineTransform} is
3859 * an identity transform; {@code false} otherwise.
3860 * @since 1.2
3861 */
3862 public boolean isIdentity() {
3863 return (state == APPLY_IDENTITY || (getType() == TYPE_IDENTITY));
3864 }
3865
3866 /**
3867 * Returns a copy of this {@code AffineTransform} object.
3868 * @return an {@code Object} that is a copy of this
3869 * {@code AffineTransform} object.
3870 * @since 1.2
3871 */
3872 public Object clone() {
3873 try {
3874 return super.clone();
3875 } catch (CloneNotSupportedException e) {
3876 // this shouldn't happen, since we are Cloneable
3877 throw new InternalError(e);
3878 }
3879 }
3880
3881 /**
3882 * Returns the hashcode for this transform.
3883 * @return a hash code for this transform.
3884 * @since 1.2
3885 */
3886 public int hashCode() {
3887 long bits = Double.doubleToLongBits(m00);
3888 bits = bits * 31 + Double.doubleToLongBits(m01);
3889 bits = bits * 31 + Double.doubleToLongBits(m02);
3890 bits = bits * 31 + Double.doubleToLongBits(m10);
3891 bits = bits * 31 + Double.doubleToLongBits(m11);
3892 bits = bits * 31 + Double.doubleToLongBits(m12);
3893 return (((int) bits) ^ ((int) (bits >> 32)));
3894 }
3895
3896 /**
3897 * Returns {@code true} if this {@code AffineTransform}
3898 * represents the same affine coordinate transform as the specified
3899 * argument.
3900 * @param obj the {@code Object} to test for equality with this
3901 * {@code AffineTransform}
3902 * @return {@code true} if {@code obj} equals this
3903 * {@code AffineTransform} object; {@code false} otherwise.
3904 * @since 1.2
3905 */
3906 public boolean equals(Object obj) {
3907 if (!(obj instanceof AffineTransform)) {
3908 return false;
3909 }
3910
3911 AffineTransform a = (AffineTransform)obj;
3912
3913 return ((m00 == a.m00) && (m01 == a.m01) && (m02 == a.m02) &&
3914 (m10 == a.m10) && (m11 == a.m11) && (m12 == a.m12));
3915 }
3916
3917 /* Serialization support. A readObject method is neccessary because
3918 * the state field is part of the implementation of this particular
3919 * AffineTransform and not part of the public specification. The
3920 * state variable's value needs to be recalculated on the fly by the
3921 * readObject method as it is in the 6-argument matrix constructor.
3922 */
3923
|