| 1 7 8 package java.awt.geom; 9 10 import java.awt.Shape ; 11 12 34 public class AffineTransform implements Cloneable , java.io.Serializable { 35 39 private static final int TYPE_UNKNOWN = -1; 40 41 59 public static final int TYPE_IDENTITY = 0; 60 61 76 public static final int TYPE_TRANSLATION = 1; 77 78 95 public static final int TYPE_UNIFORM_SCALE = 2; 96 97 114 public static final int TYPE_GENERAL_SCALE = 4; 115 116 121 public static final int TYPE_MASK_SCALE = (TYPE_UNIFORM_SCALE | 122 TYPE_GENERAL_SCALE); 123 124 148 public static final int TYPE_FLIP = 64; 149 154 155 172 public static final int TYPE_QUADRANT_ROTATION = 8; 173 174 192 public static final int TYPE_GENERAL_ROTATION = 16; 193 194 199 public static final int TYPE_MASK_ROTATION = (TYPE_QUADRANT_ROTATION | 200 TYPE_GENERAL_ROTATION); 201 202 218 public static final int TYPE_GENERAL_TRANSFORM = 32; 219 220 230 static final int APPLY_IDENTITY = 0; 231 232 241 static final int APPLY_TRANSLATE = 1; 242 243 260 static final int APPLY_SCALE = 2; 261 262 274 static final int APPLY_SHEAR = 4; 275 276 285 private static final int HI_SHIFT = 3; 286 private static final int HI_IDENTITY = APPLY_IDENTITY << HI_SHIFT; 287 private static final int HI_TRANSLATE = APPLY_TRANSLATE << HI_SHIFT; 288 private static final int HI_SCALE = APPLY_SCALE << HI_SHIFT; 289 private static final int HI_SHEAR = APPLY_SHEAR << HI_SHIFT; 290 291 297 double m00; 298 299 305 double m10; 306 307 313 double m01; 314 315 321 double m11; 322 323 329 double m02; 330 331 337 double m12; 338 339 347 transient int state; 348 349 362 private transient int type; 363 364 private AffineTransform(double m00, double m10, 365 double m01, double m11, 366 double m02, double m12, 367 int state) { 368 this.m00 = m00; 369 this.m10 = m10; 370 this.m01 = m01; 371 this.m11 = m11; 372 this.m02 = m02; 373 this.m12 = m12; 374 this.state = state; 375 this.type = TYPE_UNKNOWN; 376 } 377 378 382 public AffineTransform() { 383 m00 = m11 = 1.0; 384 } 388 389 394 public AffineTransform(AffineTransform Tx) { 395 this.m00 = Tx.m00; 396 this.m10 = Tx.m10; 397 this.m01 = Tx.m01; 398 this.m11 = Tx.m11; 399 this.m02 = Tx.m02; 400 this.m12 = Tx.m12; 401 this.state = Tx.state; 402 this.type = Tx.type; 403 } 404 405 412 public AffineTransform(float m00, float m10, 413 float m01, float m11, 414 float m02, float m12) { 415 this.m00 = m00; 416 this.m10 = m10; 417 this.m01 = m01; 418 this.m11 = m11; 419 this.m02 = m02; 420 this.m12 = m12; 421 updateState(); 422 } 423 424 436 public AffineTransform(float[] flatmatrix) { 437 m00 = flatmatrix[0]; 438 m10 = flatmatrix[1]; 439 m01 = flatmatrix[2]; 440 m11 = flatmatrix[3]; 441 if (flatmatrix.length > 5) { 442 m02 = flatmatrix[4]; 443 m12 = flatmatrix[5]; 444 } 445 updateState(); 446 } 447 448 455 public AffineTransform(double m00, double m10, 456 double m01, double m11, 457 double m02, double m12) { 458 this.m00 = m00; 459 this.m10 = m10; 460 this.m01 = m01; 461 this.m11 = m11; 462 this.m02 = m02; 463 this.m12 = m12; 464 updateState(); 465 } 466 467 479 public AffineTransform(double[] flatmatrix) { 480 m00 = flatmatrix[0]; 481 m10 = flatmatrix[1]; 482 m01 = flatmatrix[2]; 483 m11 = flatmatrix[3]; 484 if (flatmatrix.length > 5) { 485 m02 = flatmatrix[4]; 486 m12 = flatmatrix[5]; 487 } 488 updateState(); 489 } 490 491 506 public static AffineTransform getTranslateInstance(double tx, double ty) { 507 AffineTransform Tx = new AffineTransform (); 508 Tx.setToTranslation(tx, ty); 509 return Tx; 510 } 511 512 526 public static AffineTransform getRotateInstance(double theta) { 527 AffineTransform Tx = new AffineTransform (); 528 Tx.setToRotation(theta); 529 return Tx; 530 } 531 532 562 public static AffineTransform getRotateInstance(double theta, 563 double x, double y) { 564 AffineTransform Tx = new AffineTransform (); 565 Tx.setToRotation(theta, x, y); 566 return Tx; 567 } 568 569 584 public static AffineTransform getScaleInstance(double sx, double sy) { 585 AffineTransform Tx = new AffineTransform (); 586 Tx.setToScale(sx, sy); 587 return Tx; 588 } 589 590 605 public static AffineTransform getShearInstance(double shx, double shy) { 606 AffineTransform Tx = new AffineTransform (); 607 Tx.setToShear(shx, shy); 608 return Tx; 609 } 610 611 634 public int getType() { 635 if (type == TYPE_UNKNOWN) { 636 calculateType(); 637 } 638 return type; 639 } 640 641 646 private void calculateType() { 647 int ret = TYPE_IDENTITY; 648 boolean sgn0, sgn1; 649 double M0, M1, M2, M3; 650 updateState(); 651 switch (state) { 652 default: 653 stateError(); 654 655 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 656 ret = TYPE_TRANSLATION; 657 658 case (APPLY_SHEAR | APPLY_SCALE): 659 if ((M0 = m00) * (M2 = m01) + (M3 = m10) * (M1 = m11) != 0) { 660 this.type = TYPE_GENERAL_TRANSFORM; 662 return; 663 } 664 sgn0 = (M0 >= 0.0); 665 sgn1 = (M1 >= 0.0); 666 if (sgn0 == sgn1) { 667 if (M0 != M1 || M2 != -M3) { 670 ret |= (TYPE_GENERAL_ROTATION | TYPE_GENERAL_SCALE); 671 } else if (M0 * M1 - M2 * M3 != 1.0) { 672 ret |= (TYPE_GENERAL_ROTATION | TYPE_UNIFORM_SCALE); 673 } else { 674 ret |= TYPE_GENERAL_ROTATION; 675 } 676 } else { 677 if (M0 != -M1 || M2 != M3) { 680 ret |= (TYPE_GENERAL_ROTATION | 681 TYPE_FLIP | 682 TYPE_GENERAL_SCALE); 683 } else if (M0 * M1 - M2 * M3 != 1.0) { 684 ret |= (TYPE_GENERAL_ROTATION | 685 TYPE_FLIP | 686 TYPE_UNIFORM_SCALE); 687 } else { 688 ret |= (TYPE_GENERAL_ROTATION | TYPE_FLIP); 689 } 690 } 691 break; 692 case (APPLY_SHEAR | APPLY_TRANSLATE): 693 ret = TYPE_TRANSLATION; 694 695 case (APPLY_SHEAR): 696 sgn0 = ((M0 = m01) >= 0.0); 697 sgn1 = ((M1 = m10) >= 0.0); 698 if (sgn0 != sgn1) { 699 if (M0 != -M1) { 701 ret |= (TYPE_QUADRANT_ROTATION | TYPE_GENERAL_SCALE); 702 } else if (M0 != 1.0 && M0 != -1.0) { 703 ret |= (TYPE_QUADRANT_ROTATION | TYPE_UNIFORM_SCALE); 704 } else { 705 ret |= TYPE_QUADRANT_ROTATION; 706 } 707 } else { 708 if (M0 == M1) { 710 ret |= (TYPE_QUADRANT_ROTATION | 711 TYPE_FLIP | 712 TYPE_UNIFORM_SCALE); 713 } else { 714 ret |= (TYPE_QUADRANT_ROTATION | 715 TYPE_FLIP | 716 TYPE_GENERAL_SCALE); 717 } 718 } 719 break; 720 case (APPLY_SCALE | APPLY_TRANSLATE): 721 ret = TYPE_TRANSLATION; 722 723 case (APPLY_SCALE): 724 sgn0 = ((M0 = m00) >= 0.0); 725 sgn1 = ((M1 = m11) >= 0.0); 726 if (sgn0 == sgn1) { 727 if (sgn0) { 728 if (M0 == M1) { 731 ret |= TYPE_UNIFORM_SCALE; 732 } else { 733 ret |= TYPE_GENERAL_SCALE; 734 } 735 } else { 736 if (M0 != M1) { 738 ret |= (TYPE_QUADRANT_ROTATION | TYPE_GENERAL_SCALE); 739 } else if (M0 != -1.0) { 740 ret |= (TYPE_QUADRANT_ROTATION | TYPE_UNIFORM_SCALE); 741 } else { 742 ret |= TYPE_QUADRANT_ROTATION; 743 } 744 } 745 } else { 746 if (M0 == -M1) { 748 if (M0 == 1.0 || M0 == -1.0) { 749 ret |= TYPE_FLIP; 750 } else { 751 ret |= (TYPE_FLIP | TYPE_UNIFORM_SCALE); 752 } 753 } else { 754 ret |= (TYPE_FLIP | TYPE_GENERAL_SCALE); 755 } 756 } 757 break; 758 case (APPLY_TRANSLATE): 759 ret = TYPE_TRANSLATION; 760 break; 761 case (APPLY_IDENTITY): 762 break; 763 } 764 this.type = ret; 765 } 766 767 807 public double getDeterminant() { 808 switch (state) { 809 default: 810 stateError(); 811 812 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 813 case (APPLY_SHEAR | APPLY_SCALE): 814 return m00 * m11 - m01 * m10; 815 case (APPLY_SHEAR | APPLY_TRANSLATE): 816 case (APPLY_SHEAR): 817 return -(m01 * m10); 818 case (APPLY_SCALE | APPLY_TRANSLATE): 819 case (APPLY_SCALE): 820 return m00 * m11; 821 case (APPLY_TRANSLATE): 822 case (APPLY_IDENTITY): 823 return 1.0; 824 } 825 } 826 827 849 void updateState() { 850 if (m01 == 0.0 && m10 == 0.0) { 851 if (m00 == 1.0 && m11 == 1.0) { 852 if (m02 == 0.0 && m12 == 0.0) { 853 state = APPLY_IDENTITY; 854 type = TYPE_IDENTITY; 855 } else { 856 state = APPLY_TRANSLATE; 857 type = TYPE_TRANSLATION; 858 } 859 } else { 860 if (m02 == 0.0 && m12 == 0.0) { 861 state = APPLY_SCALE; 862 type = TYPE_UNKNOWN; 863 } else { 864 state = (APPLY_SCALE | APPLY_TRANSLATE); 865 type = TYPE_UNKNOWN; 866 } 867 } 868 } else { 869 if (m00 == 0.0 && m11 == 0.0) { 870 if (m02 == 0.0 && m12 == 0.0) { 871 state = APPLY_SHEAR; 872 type = TYPE_UNKNOWN; 873 } else { 874 state = (APPLY_SHEAR | APPLY_TRANSLATE); 875 type = TYPE_UNKNOWN; 876 } 877 } else { 878 if (m02 == 0.0 && m12 == 0.0) { 879 state = (APPLY_SHEAR | APPLY_SCALE); 880 type = TYPE_UNKNOWN; 881 } else { 882 state = (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE); 883 type = TYPE_UNKNOWN; 884 } 885 } 886 } 887 } 888 889 893 private void stateError() { 894 throw new InternalError ("missing case in transform state switch"); 895 } 896 897 915 public void getMatrix(double[] flatmatrix) { 916 flatmatrix[0] = m00; 917 flatmatrix[1] = m10; 918 flatmatrix[2] = m01; 919 flatmatrix[3] = m11; 920 if (flatmatrix.length > 5) { 921 flatmatrix[4] = m02; 922 flatmatrix[5] = m12; 923 } 924 } 925 926 933 public double getScaleX() { 934 return m00; 935 } 936 937 944 public double getScaleY() { 945 return m11; 946 } 947 948 955 public double getShearX() { 956 return m01; 957 } 958 959 966 public double getShearY() { 967 return m10; 968 } 969 970 977 public double getTranslateX() { 978 return m02; 979 } 980 981 988 public double getTranslateY() { 989 return m12; 990 } 991 992 1006 public void translate(double tx, double ty) { 1007 switch (state) { 1008 default: 1009 stateError(); 1010 1011 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 1012 m02 = tx * m00 + ty * m01 + m02; 1013 m12 = tx * m10 + ty * m11 + m12; 1014 if (m02 == 0.0 && m12 == 0.0) { 1015 state = APPLY_SHEAR | APPLY_SCALE; 1016 if (type != TYPE_UNKNOWN) { 1017 type -= TYPE_TRANSLATION; 1018 } 1019 } 1020 return; 1021 case (APPLY_SHEAR | APPLY_SCALE): 1022 m02 = tx * m00 + ty * m01; 1023 m12 = tx * m10 + ty * m11; 1024 if (m02 != 0.0 || m12 != 0.0) { 1025 state = APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE; 1026 type |= TYPE_TRANSLATION; 1027 } 1028 return; 1029 case (APPLY_SHEAR | APPLY_TRANSLATE): 1030 &
|