1 /* 2 * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact 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 id="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 130 * conversions that this transform performs. 131 * @see #TYPE_TRANSLATION 132 * @see #TYPE_UNIFORM_SCALE 133 * @see #TYPE_GENERAL_SCALE 134 * @see #TYPE_FLIP 135 * @see #TYPE_QUADRANT_ROTATION 136 * @see #TYPE_GENERAL_ROTATION 137 * @see #TYPE_GENERAL_TRANSFORM 138 * @see #getType 139 * @since 1.2 140 */ 141 public static final int TYPE_IDENTITY = 0; 142 143 /** 144 * This flag bit indicates that the transform defined by this object 145 * performs a translation in addition to the conversions indicated 146 * by other flag bits. 147 * A translation moves the coordinates by a constant amount in x 148 * and y without changing the length or angle of vectors. 149 * @see #TYPE_IDENTITY 150 * @see #TYPE_UNIFORM_SCALE 151 * @see #TYPE_GENERAL_SCALE 152 * @see #TYPE_FLIP 153 * @see #TYPE_QUADRANT_ROTATION 154 * @see #TYPE_GENERAL_ROTATION 155 * @see #TYPE_GENERAL_TRANSFORM 156 * @see #getType 157 * @since 1.2 158 */ 159 public static final int TYPE_TRANSLATION = 1; 160 161 /** 162 * This flag bit indicates that the transform defined by this object 163 * performs a uniform scale in addition to the conversions indicated 164 * by other flag bits. 165 * A uniform scale multiplies the length of vectors by the same amount 166 * in both the x and y directions without changing the angle between 167 * vectors. 168 * This flag bit is mutually exclusive with the TYPE_GENERAL_SCALE flag. 169 * @see #TYPE_IDENTITY 170 * @see #TYPE_TRANSLATION 171 * @see #TYPE_GENERAL_SCALE 172 * @see #TYPE_FLIP 173 * @see #TYPE_QUADRANT_ROTATION 174 * @see #TYPE_GENERAL_ROTATION 175 * @see #TYPE_GENERAL_TRANSFORM 176 * @see #getType 177 * @since 1.2 178 */ 179 public static final int TYPE_UNIFORM_SCALE = 2; 180 181 /** 182 * This flag bit indicates that the transform defined by this object 183 * performs a general scale in addition to the conversions indicated 184 * by other flag bits. 185 * A general scale multiplies the length of vectors by different 186 * amounts in the x and y directions without changing the angle 187 * between perpendicular vectors. 188 * This flag bit is mutually exclusive with the TYPE_UNIFORM_SCALE flag. 189 * @see #TYPE_IDENTITY 190 * @see #TYPE_TRANSLATION 191 * @see #TYPE_UNIFORM_SCALE 192 * @see #TYPE_FLIP 193 * @see #TYPE_QUADRANT_ROTATION 194 * @see #TYPE_GENERAL_ROTATION 195 * @see #TYPE_GENERAL_TRANSFORM 196 * @see #getType 197 * @since 1.2 198 */ 199 public static final int TYPE_GENERAL_SCALE = 4; 200 201 /** 202 * This constant is a bit mask for any of the scale flag bits. 203 * @see #TYPE_UNIFORM_SCALE 204 * @see #TYPE_GENERAL_SCALE 205 * @since 1.2 206 */ 207 public static final int TYPE_MASK_SCALE = (TYPE_UNIFORM_SCALE | 208 TYPE_GENERAL_SCALE); 209 210 /** 211 * This flag bit indicates that the transform defined by this object 212 * performs a mirror image flip about some axis which changes the 213 * normally right handed coordinate system into a left handed 214 * system in addition to the conversions indicated by other flag bits. 215 * A right handed coordinate system is one where the positive X 216 * axis rotates counterclockwise to overlay the positive Y axis 217 * similar to the direction that the fingers on your right hand 218 * curl when you stare end on at your thumb. 219 * A left handed coordinate system is one where the positive X 220 * axis rotates clockwise to overlay the positive Y axis similar 221 * to the direction that the fingers on your left hand curl. 222 * There is no mathematical way to determine the angle of the 223 * original flipping or mirroring transformation since all angles 224 * of flip are identical given an appropriate adjusting rotation. 225 * @see #TYPE_IDENTITY 226 * @see #TYPE_TRANSLATION 227 * @see #TYPE_UNIFORM_SCALE 228 * @see #TYPE_GENERAL_SCALE 229 * @see #TYPE_QUADRANT_ROTATION 230 * @see #TYPE_GENERAL_ROTATION 231 * @see #TYPE_GENERAL_TRANSFORM 232 * @see #getType 233 * @since 1.2 234 */ 235 public static final int TYPE_FLIP = 64; 236 /* NOTE: TYPE_FLIP was added after GENERAL_TRANSFORM was in public 237 * circulation and the flag bits could no longer be conveniently 238 * renumbered without introducing binary incompatibility in outside 239 * code. 240 */ 241 242 /** 243 * This flag bit indicates that the transform defined by this object 244 * performs a quadrant rotation by some multiple of 90 degrees in 245 * addition to the conversions indicated by other flag bits. 246 * A rotation changes the angles of vectors by the same amount 247 * regardless of the original direction of the vector and without 248 * changing the length of the vector. 249 * This flag bit is mutually exclusive with the TYPE_GENERAL_ROTATION flag. 250 * @see #TYPE_IDENTITY 251 * @see #TYPE_TRANSLATION 252 * @see #TYPE_UNIFORM_SCALE 253 * @see #TYPE_GENERAL_SCALE 254 * @see #TYPE_FLIP 255 * @see #TYPE_GENERAL_ROTATION 256 * @see #TYPE_GENERAL_TRANSFORM 257 * @see #getType 258 * @since 1.2 259 */ 260 public static final int TYPE_QUADRANT_ROTATION = 8; 261 262 /** 263 * This flag bit indicates that the transform defined by this object 264 * performs a rotation by an arbitrary angle in addition to the 265 * conversions indicated by other flag bits. 266 * A rotation changes the angles of vectors by the same amount 267 * regardless of the original direction of the vector and without 268 * changing the length of the vector. 269 * This flag bit is mutually exclusive with the 270 * TYPE_QUADRANT_ROTATION flag. 271 * @see #TYPE_IDENTITY 272 * @see #TYPE_TRANSLATION 273 * @see #TYPE_UNIFORM_SCALE 274 * @see #TYPE_GENERAL_SCALE 275 * @see #TYPE_FLIP 276 * @see #TYPE_QUADRANT_ROTATION 277 * @see #TYPE_GENERAL_TRANSFORM 278 * @see #getType 279 * @since 1.2 280 */ 281 public static final int TYPE_GENERAL_ROTATION = 16; 282 283 /** 284 * This constant is a bit mask for any of the rotation flag bits. 285 * @see #TYPE_QUADRANT_ROTATION 286 * @see #TYPE_GENERAL_ROTATION 287 * @since 1.2 288 */ 289 public static final int TYPE_MASK_ROTATION = (TYPE_QUADRANT_ROTATION | 290 TYPE_GENERAL_ROTATION); 291 292 /** 293 * This constant indicates that the transform defined by this object 294 * performs an arbitrary conversion of the input coordinates. 295 * If this transform can be classified by any of the above constants, 296 * the type will either be the constant TYPE_IDENTITY or a 297 * combination of the appropriate flag bits for the various coordinate 298 * conversions that this transform performs. 299 * @see #TYPE_IDENTITY 300 * @see #TYPE_TRANSLATION 301 * @see #TYPE_UNIFORM_SCALE 302 * @see #TYPE_GENERAL_SCALE 303 * @see #TYPE_FLIP 304 * @see #TYPE_QUADRANT_ROTATION 305 * @see #TYPE_GENERAL_ROTATION 306 * @see #getType 307 * @since 1.2 308 */ 309 public static final int TYPE_GENERAL_TRANSFORM = 32; 310 311 /** 312 * This constant is used for the internal state variable to indicate 313 * that no calculations need to be performed and that the source 314 * coordinates only need to be copied to their destinations to 315 * complete the transformation equation of this transform. 316 * @see #APPLY_TRANSLATE 317 * @see #APPLY_SCALE 318 * @see #APPLY_SHEAR 319 * @see #state 320 */ 321 static final int APPLY_IDENTITY = 0; 322 323 /** 324 * This constant is used for the internal state variable to indicate 325 * that the translation components of the matrix (m02 and m12) need 326 * to be added to complete the transformation equation of this transform. 327 * @see #APPLY_IDENTITY 328 * @see #APPLY_SCALE 329 * @see #APPLY_SHEAR 330 * @see #state 331 */ 332 static final int APPLY_TRANSLATE = 1; 333 334 /** 335 * This constant is used for the internal state variable to indicate 336 * that the scaling components of the matrix (m00 and m11) need 337 * to be factored in to complete the transformation equation of 338 * this transform. If the APPLY_SHEAR bit is also set then it 339 * indicates that the scaling components are not both 0.0. If the 340 * APPLY_SHEAR bit is not also set then it indicates that the 341 * scaling components are not both 1.0. If neither the APPLY_SHEAR 342 * nor the APPLY_SCALE bits are set then the scaling components 343 * are both 1.0, which means that the x and y components contribute 344 * to the transformed coordinate, but they are not multiplied by 345 * any scaling factor. 346 * @see #APPLY_IDENTITY 347 * @see #APPLY_TRANSLATE 348 * @see #APPLY_SHEAR 349 * @see #state 350 */ 351 static final int APPLY_SCALE = 2; 352 353 /** 354 * This constant is used for the internal state variable to indicate 355 * that the shearing components of the matrix (m01 and m10) need 356 * to be factored in to complete the transformation equation of this 357 * transform. The presence of this bit in the state variable changes 358 * the interpretation of the APPLY_SCALE bit as indicated in its 359 * documentation. 360 * @see #APPLY_IDENTITY 361 * @see #APPLY_TRANSLATE 362 * @see #APPLY_SCALE 363 * @see #state 364 */ 365 static final int APPLY_SHEAR = 4; 366 367 /* 368 * For methods which combine together the state of two separate 369 * transforms and dispatch based upon the combination, these constants 370 * specify how far to shift one of the states so that the two states 371 * are mutually non-interfering and provide constants for testing the 372 * bits of the shifted (HI) state. The methods in this class use 373 * the convention that the state of "this" transform is unshifted and 374 * the state of the "other" or "argument" transform is shifted (HI). 375 */ 376 private static final int HI_SHIFT = 3; 377 private static final int HI_IDENTITY = APPLY_IDENTITY << HI_SHIFT; 378 private static final int HI_TRANSLATE = APPLY_TRANSLATE << HI_SHIFT; 379 private static final int HI_SCALE = APPLY_SCALE << HI_SHIFT; 380 private static final int HI_SHEAR = APPLY_SHEAR << HI_SHIFT; 381 382 /** 383 * The X coordinate scaling element of the 3x3 384 * affine transformation matrix. 385 * 386 * @serial 387 */ 388 double m00; 389 390 /** 391 * The Y coordinate shearing element of the 3x3 392 * affine transformation matrix. 393 * 394 * @serial 395 */ 396 double m10; 397 398 /** 399 * The X coordinate shearing element of the 3x3 400 * affine transformation matrix. 401 * 402 * @serial 403 */ 404 double m01; 405 406 /** 407 * The Y coordinate scaling element of the 3x3 408 * affine transformation matrix. 409 * 410 * @serial 411 */ 412 double m11; 413 414 /** 415 * The X coordinate of the translation element of the 416 * 3x3 affine transformation matrix. 417 * 418 * @serial 419 */ 420 double m02; 421 422 /** 423 * The Y coordinate of the translation element of the 424 * 3x3 affine transformation matrix. 425 * 426 * @serial 427 */ 428 double m12; 429 430 /** 431 * This field keeps track of which components of the matrix need to 432 * be applied when performing a transformation. 433 * @see #APPLY_IDENTITY 434 * @see #APPLY_TRANSLATE 435 * @see #APPLY_SCALE 436 * @see #APPLY_SHEAR 437 */ 438 transient int state; 439 440 /** 441 * This field caches the current transformation type of the matrix. 442 * @see #TYPE_IDENTITY 443 * @see #TYPE_TRANSLATION 444 * @see #TYPE_UNIFORM_SCALE 445 * @see #TYPE_GENERAL_SCALE 446 * @see #TYPE_FLIP 447 * @see #TYPE_QUADRANT_ROTATION 448 * @see #TYPE_GENERAL_ROTATION 449 * @see #TYPE_GENERAL_TRANSFORM 450 * @see #TYPE_UNKNOWN 451 * @see #getType 452 */ 453 private transient int type; 454 AffineTransform(double m00, double m10, double m01, double m11, double m02, double m12, int state)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 */ AffineTransform()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 */ AffineTransform(AffineTransform Tx)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" }) AffineTransform(float m00, float m10, float m01, float m11, float m02, float m12)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 */ AffineTransform(float[] flatmatrix)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 */ AffineTransform(double m00, double m10, double m01, double m11, double m02, double m12)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 */ AffineTransform(double[] flatmatrix)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 */ getTranslateInstance(double tx, double ty)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 */ getRotateInstance(double theta)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 */ getRotateInstance(double theta, double anchorx, double anchory)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 */ getRotateInstance(double vecx, double vecy)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 */ getRotateInstance(double vecx, double vecy, double anchorx, double anchory)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 */ getQuadrantRotateInstance(int numquadrants)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 */ getQuadrantRotateInstance(int numquadrants, double anchorx, double anchory)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 */ getScaleInstance(double sx, double sy)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 */ getShearInstance(double shx, double shy)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 853 * as well as either of the 854 * TYPE_QUADRANT_ROTATION or TYPE_GENERAL_ROTATION flag bits. 855 * @return the OR combination of any of the indicated flags that 856 * apply to this transform 857 * @see #TYPE_IDENTITY 858 * @see #TYPE_TRANSLATION 859 * @see #TYPE_UNIFORM_SCALE 860 * @see #TYPE_GENERAL_SCALE 861 * @see #TYPE_QUADRANT_ROTATION 862 * @see #TYPE_GENERAL_ROTATION 863 * @see #TYPE_GENERAL_TRANSFORM 864 * @since 1.2 865 */ getType()866 public int getType() { 867 if (type == TYPE_UNKNOWN) { 868 calculateType(); 869 } 870 return type; 871 } 872 873 /** 874 * This is the utility function to calculate the flag bits when 875 * they have not been cached. 876 * @see #getType 877 */ 878 @SuppressWarnings("fallthrough") calculateType()879 private void calculateType() { 880 int ret = TYPE_IDENTITY; 881 boolean sgn0, sgn1; 882 double M0, M1, M2, M3; 883 updateState(); 884 switch (state) { 885 default: 886 stateError(); 887 /* NOTREACHED */ 888 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 889 ret = TYPE_TRANSLATION; 890 /* NOBREAK */ 891 case (APPLY_SHEAR | APPLY_SCALE): 892 if ((M0 = m00) * (M2 = m01) + (M3 = m10) * (M1 = m11) != 0) { 893 // Transformed unit vectors are not perpendicular... 894 this.type = TYPE_GENERAL_TRANSFORM; 895 return; 896 } 897 sgn0 = (M0 >= 0.0); 898 sgn1 = (M1 >= 0.0); 899 if (sgn0 == sgn1) { 900 // sgn(M0) == sgn(M1) therefore sgn(M2) == -sgn(M3) 901 // This is the "unflipped" (right-handed) state 902 if (M0 != M1 || M2 != -M3) { 903 ret |= (TYPE_GENERAL_ROTATION | TYPE_GENERAL_SCALE); 904 } else if (M0 * M1 - M2 * M3 != 1.0) { 905 ret |= (TYPE_GENERAL_ROTATION | TYPE_UNIFORM_SCALE); 906 } else { 907 ret |= TYPE_GENERAL_ROTATION; 908 } 909 } else { 910 // sgn(M0) == -sgn(M1) therefore sgn(M2) == sgn(M3) 911 // This is the "flipped" (left-handed) state 912 if (M0 != -M1 || M2 != M3) { 913 ret |= (TYPE_GENERAL_ROTATION | 914 TYPE_FLIP | 915 TYPE_GENERAL_SCALE); 916 } else if (M0 * M1 - M2 * M3 != 1.0) { 917 ret |= (TYPE_GENERAL_ROTATION | 918 TYPE_FLIP | 919 TYPE_UNIFORM_SCALE); 920 } else { 921 ret |= (TYPE_GENERAL_ROTATION | TYPE_FLIP); 922 } 923 } 924 break; 925 case (APPLY_SHEAR | APPLY_TRANSLATE): 926 ret = TYPE_TRANSLATION; 927 /* NOBREAK */ 928 case (APPLY_SHEAR): 929 sgn0 = ((M0 = m01) >= 0.0); 930 sgn1 = ((M1 = m10) >= 0.0); 931 if (sgn0 != sgn1) { 932 // Different signs - simple 90 degree rotation 933 if (M0 != -M1) { 934 ret |= (TYPE_QUADRANT_ROTATION | TYPE_GENERAL_SCALE); 935 } else if (M0 != 1.0 && M0 != -1.0) { 936 ret |= (TYPE_QUADRANT_ROTATION | TYPE_UNIFORM_SCALE); 937 } else { 938 ret |= TYPE_QUADRANT_ROTATION; 939 } 940 } else { 941 // Same signs - 90 degree rotation plus an axis flip too 942 if (M0 == M1) { 943 ret |= (TYPE_QUADRANT_ROTATION | 944 TYPE_FLIP | 945 TYPE_UNIFORM_SCALE); 946 } else { 947 ret |= (TYPE_QUADRANT_ROTATION | 948 TYPE_FLIP | 949 TYPE_GENERAL_SCALE); 950 } 951 } 952 break; 953 case (APPLY_SCALE | APPLY_TRANSLATE): 954 ret = TYPE_TRANSLATION; 955 /* NOBREAK */ 956 case (APPLY_SCALE): 957 sgn0 = ((M0 = m00) >= 0.0); 958 sgn1 = ((M1 = m11) >= 0.0); 959 if (sgn0 == sgn1) { 960 if (sgn0) { 961 // Both scaling factors non-negative - simple scale 962 // Note: APPLY_SCALE implies M0, M1 are not both 1 963 if (M0 == M1) { 964 ret |= TYPE_UNIFORM_SCALE; 965 } else { 966 ret |= TYPE_GENERAL_SCALE; 967 } 968 } else { 969 // Both scaling factors negative - 180 degree rotation 970 if (M0 != M1) { 971 ret |= (TYPE_QUADRANT_ROTATION | TYPE_GENERAL_SCALE); 972 } else if (M0 != -1.0) { 973 ret |= (TYPE_QUADRANT_ROTATION | TYPE_UNIFORM_SCALE); 974 } else { 975 ret |= TYPE_QUADRANT_ROTATION; 976 } 977 } 978 } else { 979 // Scaling factor signs different - flip about some axis 980 if (M0 == -M1) { 981 if (M0 == 1.0 || M0 == -1.0) { 982 ret |= TYPE_FLIP; 983 } else { 984 ret |= (TYPE_FLIP | TYPE_UNIFORM_SCALE); 985 } 986 } else { 987 ret |= (TYPE_FLIP | TYPE_GENERAL_SCALE); 988 } 989 } 990 break; 991 case (APPLY_TRANSLATE): 992 ret = TYPE_TRANSLATION; 993 break; 994 case (APPLY_IDENTITY): 995 break; 996 } 997 this.type = ret; 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 1039 * @since 1.2 1040 */ 1041 @SuppressWarnings("fallthrough") getDeterminant()1042 public double getDeterminant() { 1043 switch (state) { 1044 default: 1045 stateError(); 1046 /* NOTREACHED */ 1047 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 1048 case (APPLY_SHEAR | APPLY_SCALE): 1049 return m00 * m11 - m01 * m10; 1050 case (APPLY_SHEAR | APPLY_TRANSLATE): 1051 case (APPLY_SHEAR): 1052 return -(m01 * m10); 1053 case (APPLY_SCALE | APPLY_TRANSLATE): 1054 case (APPLY_SCALE): 1055 return m00 * m11; 1056 case (APPLY_TRANSLATE): 1057 case (APPLY_IDENTITY): 1058 return 1.0; 1059 } 1060 } 1061 1062 /** 1063 * Manually recalculates the state of the transform when the matrix 1064 * changes too much to predict the effects on the state. 1065 * The following table specifies what the various settings of the 1066 * state field say about the values of the corresponding matrix 1067 * element fields. 1068 * Note that the rules governing the SCALE fields are slightly 1069 * different depending on whether the SHEAR flag is also set. 1070 * <pre> 1071 * SCALE SHEAR TRANSLATE 1072 * m00/m11 m01/m10 m02/m12 1073 * 1074 * IDENTITY 1.0 0.0 0.0 1075 * TRANSLATE (TR) 1.0 0.0 not both 0.0 1076 * SCALE (SC) not both 1.0 0.0 0.0 1077 * TR | SC not both 1.0 0.0 not both 0.0 1078 * SHEAR (SH) 0.0 not both 0.0 0.0 1079 * TR | SH 0.0 not both 0.0 not both 0.0 1080 * SC | SH not both 0.0 not both 0.0 0.0 1081 * TR | SC | SH not both 0.0 not both 0.0 not both 0.0 1082 * </pre> 1083 */ updateState()1084 void updateState() { 1085 if (m01 == 0.0 && m10 == 0.0) { 1086 if (m00 == 1.0 && m11 == 1.0) { 1087 if (m02 == 0.0 && m12 == 0.0) { 1088 state = APPLY_IDENTITY; 1089 type = TYPE_IDENTITY; 1090 } else { 1091 state = APPLY_TRANSLATE; 1092 type = TYPE_TRANSLATION; 1093 } 1094 } else { 1095 if (m02 == 0.0 && m12 == 0.0) { 1096 state = APPLY_SCALE; 1097 type = TYPE_UNKNOWN; 1098 } else { 1099 state = (APPLY_SCALE | APPLY_TRANSLATE); 1100 type = TYPE_UNKNOWN; 1101 } 1102 } 1103 } else { 1104 if (m00 == 0.0 && m11 == 0.0) { 1105 if (m02 == 0.0 && m12 == 0.0) { 1106 state = APPLY_SHEAR; 1107 type = TYPE_UNKNOWN; 1108 } else { 1109 state = (APPLY_SHEAR | APPLY_TRANSLATE); 1110 type = TYPE_UNKNOWN; 1111 } 1112 } else { 1113 if (m02 == 0.0 && m12 == 0.0) { 1114 state = (APPLY_SHEAR | APPLY_SCALE); 1115 type = TYPE_UNKNOWN; 1116 } else { 1117 state = (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE); 1118 type = TYPE_UNKNOWN; 1119 } 1120 } 1121 } 1122 } 1123 1124 /* 1125 * Convenience method used internally to throw exceptions when 1126 * a case was forgotten in a switch statement. 1127 */ stateError()1128 private void stateError() { 1129 throw new InternalError("missing case in transform state switch"); 1130 } 1131 1132 /** 1133 * Retrieves the 6 specifiable values in the 3x3 affine transformation 1134 * matrix and places them into an array of double precisions values. 1135 * The values are stored in the array as 1136 * { m00 m10 m01 m11 m02 m12 }. 1137 * An array of 4 doubles can also be specified, in which case only the 1138 * first four elements representing the non-transform 1139 * parts of the array are retrieved and the values are stored into 1140 * the array as { m00 m10 m01 m11 } 1141 * @param flatmatrix the double array used to store the returned 1142 * values. 1143 * @see #getScaleX 1144 * @see #getScaleY 1145 * @see #getShearX 1146 * @see #getShearY 1147 * @see #getTranslateX 1148 * @see #getTranslateY 1149 * @since 1.2 1150 */ getMatrix(double[] flatmatrix)1151 public void getMatrix(double[] flatmatrix) { 1152 flatmatrix[0] = m00; 1153 flatmatrix[1] = m10; 1154 flatmatrix[2] = m01; 1155 flatmatrix[3] = m11; 1156 if (flatmatrix.length > 5) { 1157 flatmatrix[4] = m02; 1158 flatmatrix[5] = m12; 1159 } 1160 } 1161 1162 /** 1163 * Returns the {@code m00} element of the 3x3 affine transformation matrix. 1164 * This matrix factor determines how input X coordinates will affect output 1165 * X coordinates and is one element of the scale of the transform. 1166 * To measure the full amount by which X coordinates are stretched or 1167 * contracted by this transform, use the following code: 1168 * <pre> 1169 * Point2D p = new Point2D.Double(1, 0); 1170 * p = tx.deltaTransform(p, p); 1171 * double scaleX = p.distance(0, 0); 1172 * </pre> 1173 * @return a double value that is {@code m00} element of the 1174 * 3x3 affine transformation matrix. 1175 * @see #getMatrix 1176 * @since 1.2 1177 */ getScaleX()1178 public double getScaleX() { 1179 return m00; 1180 } 1181 1182 /** 1183 * Returns the {@code m11} element of the 3x3 affine transformation matrix. 1184 * This matrix factor determines how input Y coordinates will affect output 1185 * Y coordinates and is one element of the scale of the transform. 1186 * To measure the full amount by which Y coordinates are stretched or 1187 * contracted by this transform, use the following code: 1188 * <pre> 1189 * Point2D p = new Point2D.Double(0, 1); 1190 * p = tx.deltaTransform(p, p); 1191 * double scaleY = p.distance(0, 0); 1192 * </pre> 1193 * @return a double value that is {@code m11} element of the 1194 * 3x3 affine transformation matrix. 1195 * @see #getMatrix 1196 * @since 1.2 1197 */ getScaleY()1198 public double getScaleY() { 1199 return m11; 1200 } 1201 1202 /** 1203 * Returns the X coordinate shearing element (m01) of the 3x3 1204 * affine transformation matrix. 1205 * @return a double value that is the X coordinate of the shearing 1206 * element of the affine transformation matrix. 1207 * @see #getMatrix 1208 * @since 1.2 1209 */ getShearX()1210 public double getShearX() { 1211 return m01; 1212 } 1213 1214 /** 1215 * Returns the Y coordinate shearing element (m10) of the 3x3 1216 * affine transformation matrix. 1217 * @return a double value that is the Y coordinate of the shearing 1218 * element of the affine transformation matrix. 1219 * @see #getMatrix 1220 * @since 1.2 1221 */ getShearY()1222 public double getShearY() { 1223 return m10; 1224 } 1225 1226 /** 1227 * Returns the X coordinate of the translation element (m02) of the 1228 * 3x3 affine transformation matrix. 1229 * @return a double value that is the X coordinate of the translation 1230 * element of the affine transformation matrix. 1231 * @see #getMatrix 1232 * @since 1.2 1233 */ getTranslateX()1234 public double getTranslateX() { 1235 return m02; 1236 } 1237 1238 /** 1239 * Returns the Y coordinate of the translation element (m12) of the 1240 * 3x3 affine transformation matrix. 1241 * @return a double value that is the Y coordinate of the translation 1242 * element of the affine transformation matrix. 1243 * @see #getMatrix 1244 * @since 1.2 1245 */ getTranslateY()1246 public double getTranslateY() { 1247 return m12; 1248 } 1249 1250 /** 1251 * Concatenates this transform with a translation transformation. 1252 * This is equivalent to calling concatenate(T), where T is an 1253 * {@code AffineTransform} represented by the following matrix: 1254 * <pre> 1255 * [ 1 0 tx ] 1256 * [ 0 1 ty ] 1257 * [ 0 0 1 ] 1258 * </pre> 1259 * @param tx the distance by which coordinates are translated in the 1260 * X axis direction 1261 * @param ty the distance by which coordinates are translated in the 1262 * Y axis direction 1263 * @since 1.2 1264 */ translate(double tx, double ty)1265 public void translate(double tx, double ty) { 1266 switch (state) { 1267 default: 1268 stateError(); 1269 /* NOTREACHED */ 1270 return; 1271 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 1272 m02 = tx * m00 + ty * m01 + m02; 1273 m12 = tx * m10 + ty * m11 + m12; 1274 if (m02 == 0.0 && m12 == 0.0) { 1275 state = APPLY_SHEAR | APPLY_SCALE; 1276 if (type != TYPE_UNKNOWN) { 1277 type -= TYPE_TRANSLATION; 1278 } 1279 } 1280 return; 1281 case (APPLY_SHEAR | APPLY_SCALE): 1282 m02 = tx * m00 + ty * m01; 1283 m12 = tx * m10 + ty * m11; 1284 if (m02 != 0.0 || m12 != 0.0) { 1285 state = APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE; 1286 type |= TYPE_TRANSLATION; 1287 } 1288 return; 1289 case (APPLY_SHEAR | APPLY_TRANSLATE): 1290 m02 = ty * m01 + m02; 1291 m12 = tx * m10 + m12; 1292 if (m02 == 0.0 && m12 == 0.0) { 1293 state = APPLY_SHEAR; 1294 if (type != TYPE_UNKNOWN) { 1295 type -= TYPE_TRANSLATION; 1296 } 1297 } 1298 return; 1299 case (APPLY_SHEAR): 1300 m02 = ty * m01; 1301 m12 = tx * m10; 1302 if (m02 != 0.0 || m12 != 0.0) { 1303 state = APPLY_SHEAR | APPLY_TRANSLATE; 1304 type |= TYPE_TRANSLATION; 1305 } 1306 return; 1307 case (APPLY_SCALE | APPLY_TRANSLATE): 1308 m02 = tx * m00 + m02; 1309 m12 = ty * m11 + m12; 1310 if (m02 == 0.0 && m12 == 0.0) { 1311 state = APPLY_SCALE; 1312 if (type != TYPE_UNKNOWN) { 1313 type -= TYPE_TRANSLATION; 1314 } 1315 } 1316 return; 1317 case (APPLY_SCALE): 1318 m02 = tx * m00; 1319 m12 = ty * m11; 1320 if (m02 != 0.0 || m12 != 0.0) { 1321 state = APPLY_SCALE | APPLY_TRANSLATE; 1322 type |= TYPE_TRANSLATION; 1323 } 1324 return; 1325 case (APPLY_TRANSLATE): 1326 m02 = tx + m02; 1327 m12 = ty + m12; 1328 if (m02 == 0.0 && m12 == 0.0) { 1329 state = APPLY_IDENTITY; 1330 type = TYPE_IDENTITY; 1331 } 1332 return; 1333 case (APPLY_IDENTITY): 1334 m02 = tx; 1335 m12 = ty; 1336 if (tx != 0.0 || ty != 0.0) { 1337 state = APPLY_TRANSLATE; 1338 type = TYPE_TRANSLATION; 1339 } 1340 return; 1341 } 1342 } 1343 1344 // Utility methods to optimize rotate methods. 1345 // These tables translate the flags during predictable quadrant 1346 // rotations where the shear and scale values are swapped and negated. 1347 private static final int rot90conversion[] = { 1348 /* IDENTITY => */ APPLY_SHEAR, 1349 /* TRANSLATE (TR) => */ APPLY_SHEAR | APPLY_TRANSLATE, 1350 /* SCALE (SC) => */ APPLY_SHEAR, 1351 /* SC | TR => */ APPLY_SHEAR | APPLY_TRANSLATE, 1352 /* SHEAR (SH) => */ APPLY_SCALE, 1353 /* SH | TR => */ APPLY_SCALE | APPLY_TRANSLATE, 1354 /* SH | SC => */ APPLY_SHEAR | APPLY_SCALE, 1355 /* SH | SC | TR => */ APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE, 1356 }; rotate90()1357 private void rotate90() { 1358 double M0 = m00; 1359 m00 = m01; 1360 m01 = -M0; 1361 M0 = m10; 1362 m10 = m11; 1363 m11 = -M0; 1364 int state = rot90conversion[this.state]; 1365 if ((state & (APPLY_SHEAR | APPLY_SCALE)) == APPLY_SCALE && 1366 m00 == 1.0 && m11 == 1.0) 1367 { 1368 state -= APPLY_SCALE; 1369 } 1370 this.state = state; 1371 type = TYPE_UNKNOWN; 1372 } rotate180()1373 private void rotate180() { 1374 m00 = -m00; 1375 m11 = -m11; 1376 int state = this.state; 1377 if ((state & (APPLY_SHEAR)) != 0) { 1378 // If there was a shear, then this rotation has no 1379 // effect on the state. 1380 m01 = -m01; 1381 m10 = -m10; 1382 } else { 1383 // No shear means the SCALE state may toggle when 1384 // m00 and m11 are negated. 1385 if (m00 == 1.0 && m11 == 1.0) { 1386 this.state = state & ~APPLY_SCALE; 1387 } else { 1388 this.state = state | APPLY_SCALE; 1389 } 1390 } 1391 type = TYPE_UNKNOWN; 1392 } rotate270()1393 private void rotate270() { 1394 double M0 = m00; 1395 m00 = -m01; 1396 m01 = M0; 1397 M0 = m10; 1398 m10 = -m11; 1399 m11 = M0; 1400 int state = rot90conversion[this.state]; 1401 if ((state & (APPLY_SHEAR | APPLY_SCALE)) == APPLY_SCALE && 1402 m00 == 1.0 && m11 == 1.0) 1403 { 1404 state -= APPLY_SCALE; 1405 } 1406 this.state = state; 1407 type = TYPE_UNKNOWN; 1408 } 1409 1410 /** 1411 * Concatenates this transform with a rotation transformation. 1412 * This is equivalent to calling concatenate(R), where R is an 1413 * {@code AffineTransform} represented by the following matrix: 1414 * <pre> 1415 * [ cos(theta) -sin(theta) 0 ] 1416 * [ sin(theta) cos(theta) 0 ] 1417 * [ 0 0 1 ] 1418 * </pre> 1419 * Rotating by a positive angle theta rotates points on the positive 1420 * X axis toward the positive Y axis. 1421 * Note also the discussion of 1422 * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a> 1423 * above. 1424 * @param theta the angle of rotation measured in radians 1425 * @since 1.2 1426 */ rotate(double theta)1427 public void rotate(double theta) { 1428 double sin = Math.sin(theta); 1429 if (sin == 1.0) { 1430 rotate90(); 1431 } else if (sin == -1.0) { 1432 rotate270(); 1433 } else { 1434 double cos = Math.cos(theta); 1435 if (cos == -1.0) { 1436 rotate180(); 1437 } else if (cos != 1.0) { 1438 double M0, M1; 1439 M0 = m00; 1440 M1 = m01; 1441 m00 = cos * M0 + sin * M1; 1442 m01 = -sin * M0 + cos * M1; 1443 M0 = m10; 1444 M1 = m11; 1445 m10 = cos * M0 + sin * M1; 1446 m11 = -sin * M0 + cos * M1; 1447 updateState(); 1448 } 1449 } 1450 } 1451 1452 /** 1453 * Concatenates this transform with a transform that rotates 1454 * coordinates around an anchor point. 1455 * This operation is equivalent to translating the coordinates so 1456 * that the anchor point is at the origin (S1), then rotating them 1457 * about the new origin (S2), and finally translating so that the 1458 * intermediate origin is restored to the coordinates of the original 1459 * anchor point (S3). 1460 * <p> 1461 * This operation is equivalent to the following sequence of calls: 1462 * <pre> 1463 * translate(anchorx, anchory); // S3: final translation 1464 * rotate(theta); // S2: rotate around anchor 1465 * translate(-anchorx, -anchory); // S1: translate anchor to origin 1466 * </pre> 1467 * Rotating by a positive angle theta rotates points on the positive 1468 * X axis toward the positive Y axis. 1469 * Note also the discussion of 1470 * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a> 1471 * above. 1472 * 1473 * @param theta the angle of rotation measured in radians 1474 * @param anchorx the X coordinate of the rotation anchor point 1475 * @param anchory the Y coordinate of the rotation anchor point 1476 * @since 1.2 1477 */ rotate(double theta, double anchorx, double anchory)1478 public void rotate(double theta, double anchorx, double anchory) { 1479 // REMIND: Simple for now - optimize later 1480 translate(anchorx, anchory); 1481 rotate(theta); 1482 translate(-anchorx, -anchory); 1483 } 1484 1485 /** 1486 * Concatenates this transform with a transform that rotates 1487 * coordinates according to a rotation vector. 1488 * All coordinates rotate about the origin by the same amount. 1489 * The amount of rotation is such that coordinates along the former 1490 * positive X axis will subsequently align with the vector pointing 1491 * from the origin to the specified vector coordinates. 1492 * If both {@code vecx} and {@code vecy} are 0.0, 1493 * no additional rotation is added to this transform. 1494 * This operation is equivalent to calling: 1495 * <pre> 1496 * rotate(Math.atan2(vecy, vecx)); 1497 * </pre> 1498 * 1499 * @param vecx the X coordinate of the rotation vector 1500 * @param vecy the Y coordinate of the rotation vector 1501 * @since 1.6 1502 */ rotate(double vecx, double vecy)1503 public void rotate(double vecx, double vecy) { 1504 if (vecy == 0.0) { 1505 if (vecx < 0.0) { 1506 rotate180(); 1507 } 1508 // If vecx > 0.0 - no rotation 1509 // If vecx == 0.0 - undefined rotation - treat as no rotation 1510 } else if (vecx == 0.0) { 1511 if (vecy > 0.0) { 1512 rotate90(); 1513 } else { // vecy must be < 0.0 1514 rotate270(); 1515 } 1516 } else { 1517 double len = Math.sqrt(vecx * vecx + vecy * vecy); 1518 double sin = vecy / len; 1519 double cos = vecx / len; 1520 double M0, M1; 1521 M0 = m00; 1522 M1 = m01; 1523 m00 = cos * M0 + sin * M1; 1524 m01 = -sin * M0 + cos * M1; 1525 M0 = m10; 1526 M1 = m11; 1527 m10 = cos * M0 + sin * M1; 1528 m11 = -sin * M0 + cos * M1; 1529 updateState(); 1530 } 1531 } 1532 1533 /** 1534 * Concatenates this transform with a transform that rotates 1535 * coordinates around an anchor point according to a rotation 1536 * vector. 1537 * All coordinates rotate about the specified anchor coordinates 1538 * by the same amount. 1539 * The amount of rotation is such that coordinates along the former 1540 * positive X axis will subsequently align with the vector pointing 1541 * from the origin to the specified vector coordinates. 1542 * If both {@code vecx} and {@code vecy} are 0.0, 1543 * the transform is not modified in any way. 1544 * This method is equivalent to calling: 1545 * <pre> 1546 * rotate(Math.atan2(vecy, vecx), anchorx, anchory); 1547 * </pre> 1548 * 1549 * @param vecx the X coordinate of the rotation vector 1550 * @param vecy the Y coordinate of the rotation vector 1551 * @param anchorx the X coordinate of the rotation anchor point 1552 * @param anchory the Y coordinate of the rotation anchor point 1553 * @since 1.6 1554 */ rotate(double vecx, double vecy, double anchorx, double anchory)1555 public void rotate(double vecx, double vecy, 1556 double anchorx, double anchory) 1557 { 1558 // REMIND: Simple for now - optimize later 1559 translate(anchorx, anchory); 1560 rotate(vecx, vecy); 1561 translate(-anchorx, -anchory); 1562 } 1563 1564 /** 1565 * Concatenates this transform with a transform that rotates 1566 * coordinates by the specified number of quadrants. 1567 * This is equivalent to calling: 1568 * <pre> 1569 * rotate(numquadrants * Math.PI / 2.0); 1570 * </pre> 1571 * Rotating by a positive number of quadrants rotates points on 1572 * the positive X axis toward the positive Y axis. 1573 * @param numquadrants the number of 90 degree arcs to rotate by 1574 * @since 1.6 1575 */ quadrantRotate(int numquadrants)1576 public void quadrantRotate(int numquadrants) { 1577 switch (numquadrants & 3) { 1578 case 0: 1579 break; 1580 case 1: 1581 rotate90(); 1582 break; 1583 case 2: 1584 rotate180(); 1585 break; 1586 case 3: 1587 rotate270(); 1588 break; 1589 } 1590 } 1591 1592 /** 1593 * Concatenates this transform with a transform that rotates 1594 * coordinates by the specified number of quadrants around 1595 * the specified anchor point. 1596 * This method is equivalent to calling: 1597 * <pre> 1598 * rotate(numquadrants * Math.PI / 2.0, anchorx, anchory); 1599 * </pre> 1600 * Rotating by a positive number of quadrants rotates points on 1601 * the positive X axis toward the positive Y axis. 1602 * 1603 * @param numquadrants the number of 90 degree arcs to rotate by 1604 * @param anchorx the X coordinate of the rotation anchor point 1605 * @param anchory the Y coordinate of the rotation anchor point 1606 * @since 1.6 1607 */ quadrantRotate(int numquadrants, double anchorx, double anchory)1608 public void quadrantRotate(int numquadrants, 1609 double anchorx, double anchory) 1610 { 1611 switch (numquadrants & 3) { 1612 case 0: 1613 return; 1614 case 1: 1615 m02 += anchorx * (m00 - m01) + anchory * (m01 + m00); 1616 m12 += anchorx * (m10 - m11) + anchory * (m11 + m10); 1617 rotate90(); 1618 break; 1619 case 2: 1620 m02 += anchorx * (m00 + m00) + anchory * (m01 + m01); 1621 m12 += anchorx * (m10 + m10) + anchory * (m11 + m11); 1622 rotate180(); 1623 break; 1624 case 3: 1625 m02 += anchorx * (m00 + m01) + anchory * (m01 - m00); 1626 m12 += anchorx * (m10 + m11) + anchory * (m11 - m10); 1627 rotate270(); 1628 break; 1629 } 1630 if (m02 == 0.0 && m12 == 0.0) { 1631 state &= ~APPLY_TRANSLATE; 1632 } else { 1633 state |= APPLY_TRANSLATE; 1634 } 1635 } 1636 1637 /** 1638 * Concatenates this transform with a scaling transformation. 1639 * This is equivalent to calling concatenate(S), where S is an 1640 * {@code AffineTransform} represented by the following matrix: 1641 * <pre> 1642 * [ sx 0 0 ] 1643 * [ 0 sy 0 ] 1644 * [ 0 0 1 ] 1645 * </pre> 1646 * @param sx the factor by which coordinates are scaled along the 1647 * X axis direction 1648 * @param sy the factor by which coordinates are scaled along the 1649 * Y axis direction 1650 * @since 1.2 1651 */ 1652 @SuppressWarnings("fallthrough") scale(double sx, double sy)1653 public void scale(double sx, double sy) { 1654 int state = this.state; 1655 switch (state) { 1656 default: 1657 stateError(); 1658 /* NOTREACHED */ 1659 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 1660 case (APPLY_SHEAR | APPLY_SCALE): 1661 m00 *= sx; 1662 m11 *= sy; 1663 /* NOBREAK */ 1664 case (APPLY_SHEAR | APPLY_TRANSLATE): 1665 case (APPLY_SHEAR): 1666 m01 *= sy; 1667 m10 *= sx; 1668 if (m01 == 0 && m10 == 0) { 1669 state &= APPLY_TRANSLATE; 1670 if (m00 == 1.0 && m11 == 1.0) { 1671 this.type = (state == APPLY_IDENTITY 1672 ? TYPE_IDENTITY 1673 : TYPE_TRANSLATION); 1674 } else { 1675 state |= APPLY_SCALE; 1676 this.type = TYPE_UNKNOWN; 1677 } 1678 this.state = state; 1679 } 1680 return; 1681 case (APPLY_SCALE | APPLY_TRANSLATE): 1682 case (APPLY_SCALE): 1683 m00 *= sx; 1684 m11 *= sy; 1685 if (m00 == 1.0 && m11 == 1.0) { 1686 this.state = (state &= APPLY_TRANSLATE); 1687 this.type = (state == APPLY_IDENTITY 1688 ? TYPE_IDENTITY 1689 : TYPE_TRANSLATION); 1690 } else { 1691 this.type = TYPE_UNKNOWN; 1692 } 1693 return; 1694 case (APPLY_TRANSLATE): 1695 case (APPLY_IDENTITY): 1696 m00 = sx; 1697 m11 = sy; 1698 if (sx != 1.0 || sy != 1.0) { 1699 this.state = state | APPLY_SCALE; 1700 this.type = TYPE_UNKNOWN; 1701 } 1702 return; 1703 } 1704 } 1705 1706 /** 1707 * Concatenates this transform with a shearing transformation. 1708 * This is equivalent to calling concatenate(SH), where SH is an 1709 * {@code AffineTransform} represented by the following matrix: 1710 * <pre> 1711 * [ 1 shx 0 ] 1712 * [ shy 1 0 ] 1713 * [ 0 0 1 ] 1714 * </pre> 1715 * @param shx the multiplier by which coordinates are shifted in the 1716 * direction of the positive X axis as a factor of their Y coordinate 1717 * @param shy the multiplier by which coordinates are shifted in the 1718 * direction of the positive Y axis as a factor of their X coordinate 1719 * @since 1.2 1720 */ shear(double shx, double shy)1721 public void shear(double shx, double shy) { 1722 int state = this.state; 1723 switch (state) { 1724 default: 1725 stateError(); 1726 /* NOTREACHED */ 1727 return; 1728 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 1729 case (APPLY_SHEAR | APPLY_SCALE): 1730 double M0, M1; 1731 M0 = m00; 1732 M1 = m01; 1733 m00 = M0 + M1 * shy; 1734 m01 = M0 * shx + M1; 1735 1736 M0 = m10; 1737 M1 = m11; 1738 m10 = M0 + M1 * shy; 1739 m11 = M0 * shx + M1; 1740 updateState(); 1741 return; 1742 case (APPLY_SHEAR | APPLY_TRANSLATE): 1743 case (APPLY_SHEAR): 1744 m00 = m01 * shy; 1745 m11 = m10 * shx; 1746 if (m00 != 0.0 || m11 != 0.0) { 1747 this.state = state | APPLY_SCALE; 1748 } 1749 this.type = TYPE_UNKNOWN; 1750 return; 1751 case (APPLY_SCALE | APPLY_TRANSLATE): 1752 case (APPLY_SCALE): 1753 m01 = m00 * shx; 1754 m10 = m11 * shy; 1755 if (m01 != 0.0 || m10 != 0.0) { 1756 this.state = state | APPLY_SHEAR; 1757 } 1758 this.type = TYPE_UNKNOWN; 1759 return; 1760 case (APPLY_TRANSLATE): 1761 case (APPLY_IDENTITY): 1762 m01 = shx; 1763 m10 = shy; 1764 if (m01 != 0.0 || m10 != 0.0) { 1765 this.state = state | APPLY_SCALE | APPLY_SHEAR; 1766 this.type = TYPE_UNKNOWN; 1767 } 1768 return; 1769 } 1770 } 1771 1772 /** 1773 * Resets this transform to the Identity transform. 1774 * @since 1.2 1775 */ setToIdentity()1776 public void setToIdentity() { 1777 m00 = m11 = 1.0; 1778 m10 = m01 = m02 = m12 = 0.0; 1779 state = APPLY_IDENTITY; 1780 type = TYPE_IDENTITY; 1781 } 1782 1783 /** 1784 * Sets this transform to a translation transformation. 1785 * The matrix representing this transform becomes: 1786 * <pre> 1787 * [ 1 0 tx ] 1788 * [ 0 1 ty ] 1789 * [ 0 0 1 ] 1790 * </pre> 1791 * @param tx the distance by which coordinates are translated in the 1792 * X axis direction 1793 * @param ty the distance by which coordinates are translated in the 1794 * Y axis direction 1795 * @since 1.2 1796 */ setToTranslation(double tx, double ty)1797 public void setToTranslation(double tx, double ty) { 1798 m00 = 1.0; 1799 m10 = 0.0; 1800 m01 = 0.0; 1801 m11 = 1.0; 1802 m02 = tx; 1803 m12 = ty; 1804 if (tx != 0.0 || ty != 0.0) { 1805 state = APPLY_TRANSLATE; 1806 type = TYPE_TRANSLATION; 1807 } else { 1808 state = APPLY_IDENTITY; 1809 type = TYPE_IDENTITY; 1810 } 1811 } 1812 1813 /** 1814 * Sets this transform to a rotation transformation. 1815 * The matrix representing this transform becomes: 1816 * <pre> 1817 * [ cos(theta) -sin(theta) 0 ] 1818 * [ sin(theta) cos(theta) 0 ] 1819 * [ 0 0 1 ] 1820 * </pre> 1821 * Rotating by a positive angle theta rotates points on the positive 1822 * X axis toward the positive Y axis. 1823 * Note also the discussion of 1824 * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a> 1825 * above. 1826 * @param theta the angle of rotation measured in radians 1827 * @since 1.2 1828 */ setToRotation(double theta)1829 public void setToRotation(double theta) { 1830 double sin = Math.sin(theta); 1831 double cos; 1832 if (sin == 1.0 || sin == -1.0) { 1833 cos = 0.0; 1834 state = APPLY_SHEAR; 1835 type = TYPE_QUADRANT_ROTATION; 1836 } else { 1837 cos = Math.cos(theta); 1838 if (cos == -1.0) { 1839 sin = 0.0; 1840 state = APPLY_SCALE; 1841 type = TYPE_QUADRANT_ROTATION; 1842 } else if (cos == 1.0) { 1843 sin = 0.0; 1844 state = APPLY_IDENTITY; 1845 type = TYPE_IDENTITY; 1846 } else { 1847 state = APPLY_SHEAR | APPLY_SCALE; 1848 type = TYPE_GENERAL_ROTATION; 1849 } 1850 } 1851 m00 = cos; 1852 m10 = sin; 1853 m01 = -sin; 1854 m11 = cos; 1855 m02 = 0.0; 1856 m12 = 0.0; 1857 } 1858 1859 /** 1860 * Sets this transform to a translated rotation transformation. 1861 * This operation is equivalent to translating the coordinates so 1862 * that the anchor point is at the origin (S1), then rotating them 1863 * about the new origin (S2), and finally translating so that the 1864 * intermediate origin is restored to the coordinates of the original 1865 * anchor point (S3). 1866 * <p> 1867 * This operation is equivalent to the following sequence of calls: 1868 * <pre> 1869 * setToTranslation(anchorx, anchory); // S3: final translation 1870 * rotate(theta); // S2: rotate around anchor 1871 * translate(-anchorx, -anchory); // S1: translate anchor to origin 1872 * </pre> 1873 * The matrix representing this transform becomes: 1874 * <pre> 1875 * [ cos(theta) -sin(theta) x-x*cos+y*sin ] 1876 * [ sin(theta) cos(theta) y-x*sin-y*cos ] 1877 * [ 0 0 1 ] 1878 * </pre> 1879 * Rotating by a positive angle theta rotates points on the positive 1880 * X axis toward the positive Y axis. 1881 * Note also the discussion of 1882 * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a> 1883 * above. 1884 * 1885 * @param theta the angle of rotation measured in radians 1886 * @param anchorx the X coordinate of the rotation anchor point 1887 * @param anchory the Y coordinate of the rotation anchor point 1888 * @since 1.2 1889 */ setToRotation(double theta, double anchorx, double anchory)1890 public void setToRotation(double theta, double anchorx, double anchory) { 1891 setToRotation(theta); 1892 double sin = m10; 1893 double oneMinusCos = 1.0 - m00; 1894 m02 = anchorx * oneMinusCos + anchory * sin; 1895 m12 = anchory * oneMinusCos - anchorx * sin; 1896 if (m02 != 0.0 || m12 != 0.0) { 1897 state |= APPLY_TRANSLATE; 1898 type |= TYPE_TRANSLATION; 1899 } 1900 } 1901 1902 /** 1903 * Sets this transform to a rotation transformation that rotates 1904 * coordinates according to a rotation vector. 1905 * All coordinates rotate about the origin by the same amount. 1906 * The amount of rotation is such that coordinates along the former 1907 * positive X axis will subsequently align with the vector pointing 1908 * from the origin to the specified vector coordinates. 1909 * If both {@code vecx} and {@code vecy} are 0.0, 1910 * the transform is set to an identity transform. 1911 * This operation is equivalent to calling: 1912 * <pre> 1913 * setToRotation(Math.atan2(vecy, vecx)); 1914 * </pre> 1915 * 1916 * @param vecx the X coordinate of the rotation vector 1917 * @param vecy the Y coordinate of the rotation vector 1918 * @since 1.6 1919 */ setToRotation(double vecx, double vecy)1920 public void setToRotation(double vecx, double vecy) { 1921 double sin, cos; 1922 if (vecy == 0) { 1923 sin = 0.0; 1924 if (vecx < 0.0) { 1925 cos = -1.0; 1926 state = APPLY_SCALE; 1927 type = TYPE_QUADRANT_ROTATION; 1928 } else { 1929 cos = 1.0; 1930 state = APPLY_IDENTITY; 1931 type = TYPE_IDENTITY; 1932 } 1933 } else if (vecx == 0) { 1934 cos = 0.0; 1935 sin = (vecy > 0.0) ? 1.0 : -1.0; 1936 state = APPLY_SHEAR; 1937 type = TYPE_QUADRANT_ROTATION; 1938 } else { 1939 double len = Math.sqrt(vecx * vecx + vecy * vecy); 1940 cos = vecx / len; 1941 sin = vecy / len; 1942 state = APPLY_SHEAR | APPLY_SCALE; 1943 type = TYPE_GENERAL_ROTATION; 1944 } 1945 m00 = cos; 1946 m10 = sin; 1947 m01 = -sin; 1948 m11 = cos; 1949 m02 = 0.0; 1950 m12 = 0.0; 1951 } 1952 1953 /** 1954 * Sets this transform to a rotation transformation that rotates 1955 * coordinates around an anchor point according to a rotation 1956 * vector. 1957 * All coordinates rotate about the specified anchor coordinates 1958 * by the same amount. 1959 * The amount of rotation is such that coordinates along the former 1960 * positive X axis will subsequently align with the vector pointing 1961 * from the origin to the specified vector coordinates. 1962 * If both {@code vecx} and {@code vecy} are 0.0, 1963 * the transform is set to an identity transform. 1964 * This operation is equivalent to calling: 1965 * <pre> 1966 * setToTranslation(Math.atan2(vecy, vecx), anchorx, anchory); 1967 * </pre> 1968 * 1969 * @param vecx the X coordinate of the rotation vector 1970 * @param vecy the Y coordinate of the rotation vector 1971 * @param anchorx the X coordinate of the rotation anchor point 1972 * @param anchory the Y coordinate of the rotation anchor point 1973 * @since 1.6 1974 */ setToRotation(double vecx, double vecy, double anchorx, double anchory)1975 public void setToRotation(double vecx, double vecy, 1976 double anchorx, double anchory) 1977 { 1978 setToRotation(vecx, vecy); 1979 double sin = m10; 1980 double oneMinusCos = 1.0 - m00; 1981 m02 = anchorx * oneMinusCos + anchory * sin; 1982 m12 = anchory * oneMinusCos - anchorx * sin; 1983 if (m02 != 0.0 || m12 != 0.0) { 1984 state |= APPLY_TRANSLATE; 1985 type |= TYPE_TRANSLATION; 1986 } 1987 } 1988 1989 /** 1990 * Sets this transform to a rotation transformation that rotates 1991 * coordinates by the specified number of quadrants. 1992 * This operation is equivalent to calling: 1993 * <pre> 1994 * setToRotation(numquadrants * Math.PI / 2.0); 1995 * </pre> 1996 * Rotating by a positive number of quadrants rotates points on 1997 * the positive X axis toward the positive Y axis. 1998 * @param numquadrants the number of 90 degree arcs to rotate by 1999 * @since 1.6 2000 */ setToQuadrantRotation(int numquadrants)2001 public void setToQuadrantRotation(int numquadrants) { 2002 switch (numquadrants & 3) { 2003 case 0: 2004 m00 = 1.0; 2005 m10 = 0.0; 2006 m01 = 0.0; 2007 m11 = 1.0; 2008 m02 = 0.0; 2009 m12 = 0.0; 2010 state = APPLY_IDENTITY; 2011 type = TYPE_IDENTITY; 2012 break; 2013 case 1: 2014 m00 = 0.0; 2015 m10 = 1.0; 2016 m01 = -1.0; 2017 m11 = 0.0; 2018 m02 = 0.0; 2019 m12 = 0.0; 2020 state = APPLY_SHEAR; 2021 type = TYPE_QUADRANT_ROTATION; 2022 break; 2023 case 2: 2024 m00 = -1.0; 2025 m10 = 0.0; 2026 m01 = 0.0; 2027 m11 = -1.0; 2028 m02 = 0.0; 2029 m12 = 0.0; 2030 state = APPLY_SCALE; 2031 type = TYPE_QUADRANT_ROTATION; 2032 break; 2033 case 3: 2034 m00 = 0.0; 2035 m10 = -1.0; 2036 m01 = 1.0; 2037 m11 = 0.0; 2038 m02 = 0.0; 2039 m12 = 0.0; 2040 state = APPLY_SHEAR; 2041 type = TYPE_QUADRANT_ROTATION; 2042 break; 2043 } 2044 } 2045 2046 /** 2047 * Sets this transform to a translated rotation transformation 2048 * that rotates coordinates by the specified number of quadrants 2049 * around the specified anchor point. 2050 * This operation is equivalent to calling: 2051 * <pre> 2052 * setToRotation(numquadrants * Math.PI / 2.0, anchorx, anchory); 2053 * </pre> 2054 * Rotating by a positive number of quadrants rotates points on 2055 * the positive X axis toward the positive Y axis. 2056 * 2057 * @param numquadrants the number of 90 degree arcs to rotate by 2058 * @param anchorx the X coordinate of the rotation anchor point 2059 * @param anchory the Y coordinate of the rotation anchor point 2060 * @since 1.6 2061 */ setToQuadrantRotation(int numquadrants, double anchorx, double anchory)2062 public void setToQuadrantRotation(int numquadrants, 2063 double anchorx, double anchory) 2064 { 2065 switch (numquadrants & 3) { 2066 case 0: 2067 m00 = 1.0; 2068 m10 = 0.0; 2069 m01 = 0.0; 2070 m11 = 1.0; 2071 m02 = 0.0; 2072 m12 = 0.0; 2073 state = APPLY_IDENTITY; 2074 type = TYPE_IDENTITY; 2075 break; 2076 case 1: 2077 m00 = 0.0; 2078 m10 = 1.0; 2079 m01 = -1.0; 2080 m11 = 0.0; 2081 m02 = anchorx + anchory; 2082 m12 = anchory - anchorx; 2083 if (m02 == 0.0 && m12 == 0.0) { 2084 state = APPLY_SHEAR; 2085 type = TYPE_QUADRANT_ROTATION; 2086 } else { 2087 state = APPLY_SHEAR | APPLY_TRANSLATE; 2088 type = TYPE_QUADRANT_ROTATION | TYPE_TRANSLATION; 2089 } 2090 break; 2091 case 2: 2092 m00 = -1.0; 2093 m10 = 0.0; 2094 m01 = 0.0; 2095 m11 = -1.0; 2096 m02 = anchorx + anchorx; 2097 m12 = anchory + anchory; 2098 if (m02 == 0.0 && m12 == 0.0) { 2099 state = APPLY_SCALE; 2100 type = TYPE_QUADRANT_ROTATION; 2101 } else { 2102 state = APPLY_SCALE | APPLY_TRANSLATE; 2103 type = TYPE_QUADRANT_ROTATION | TYPE_TRANSLATION; 2104 } 2105 break; 2106 case 3: 2107 m00 = 0.0; 2108 m10 = -1.0; 2109 m01 = 1.0; 2110 m11 = 0.0; 2111 m02 = anchorx - anchory; 2112 m12 = anchory + anchorx; 2113 if (m02 == 0.0 && m12 == 0.0) { 2114 state = APPLY_SHEAR; 2115 type = TYPE_QUADRANT_ROTATION; 2116 } else { 2117 state = APPLY_SHEAR | APPLY_TRANSLATE; 2118 type = TYPE_QUADRANT_ROTATION | TYPE_TRANSLATION; 2119 } 2120 break; 2121 } 2122 } 2123 2124 /** 2125 * Sets this transform to a scaling transformation. 2126 * The matrix representing this transform becomes: 2127 * <pre> 2128 * [ sx 0 0 ] 2129 * [ 0 sy 0 ] 2130 * [ 0 0 1 ] 2131 * </pre> 2132 * @param sx the factor by which coordinates are scaled along the 2133 * X axis direction 2134 * @param sy the factor by which coordinates are scaled along the 2135 * Y axis direction 2136 * @since 1.2 2137 */ setToScale(double sx, double sy)2138 public void setToScale(double sx, double sy) { 2139 m00 = sx; 2140 m10 = 0.0; 2141 m01 = 0.0; 2142 m11 = sy; 2143 m02 = 0.0; 2144 m12 = 0.0; 2145 if (sx != 1.0 || sy != 1.0) { 2146 state = APPLY_SCALE; 2147 type = TYPE_UNKNOWN; 2148 } else { 2149 state = APPLY_IDENTITY; 2150 type = TYPE_IDENTITY; 2151 } 2152 } 2153 2154 /** 2155 * Sets this transform to a shearing transformation. 2156 * The matrix representing this transform becomes: 2157 * <pre> 2158 * [ 1 shx 0 ] 2159 * [ shy 1 0 ] 2160 * [ 0 0 1 ] 2161 * </pre> 2162 * @param shx the multiplier by which coordinates are shifted in the 2163 * direction of the positive X axis as a factor of their Y coordinate 2164 * @param shy the multiplier by which coordinates are shifted in the 2165 * direction of the positive Y axis as a factor of their X coordinate 2166 * @since 1.2 2167 */ setToShear(double shx, double shy)2168 public void setToShear(double shx, double shy) { 2169 m00 = 1.0; 2170 m01 = shx; 2171 m10 = shy; 2172 m11 = 1.0; 2173 m02 = 0.0; 2174 m12 = 0.0; 2175 if (shx != 0.0 || shy != 0.0) { 2176 state = (APPLY_SHEAR | APPLY_SCALE); 2177 type = TYPE_UNKNOWN; 2178 } else { 2179 state = APPLY_IDENTITY; 2180 type = TYPE_IDENTITY; 2181 } 2182 } 2183 2184 /** 2185 * Sets this transform to a copy of the transform in the specified 2186 * {@code AffineTransform} object. 2187 * @param Tx the {@code AffineTransform} object from which to 2188 * copy the transform 2189 * @since 1.2 2190 */ setTransform(AffineTransform Tx)2191 public void setTransform(AffineTransform Tx) { 2192 this.m00 = Tx.m00; 2193 this.m10 = Tx.m10; 2194 this.m01 = Tx.m01; 2195 this.m11 = Tx.m11; 2196 this.m02 = Tx.m02; 2197 this.m12 = Tx.m12; 2198 this.state = Tx.state; 2199 this.type = Tx.type; 2200 } 2201 2202 /** 2203 * Sets this transform to the matrix specified by the 6 2204 * double precision values. 2205 * 2206 * @param m00 the X coordinate scaling element of the 3x3 matrix 2207 * @param m10 the Y coordinate shearing element of the 3x3 matrix 2208 * @param m01 the X coordinate shearing element of the 3x3 matrix 2209 * @param m11 the Y coordinate scaling element of the 3x3 matrix 2210 * @param m02 the X coordinate translation element of the 3x3 matrix 2211 * @param m12 the Y coordinate translation element of the 3x3 matrix 2212 * @since 1.2 2213 */ setTransform(double m00, double m10, double m01, double m11, double m02, double m12)2214 public void setTransform(double m00, double m10, 2215 double m01, double m11, 2216 double m02, double m12) { 2217 this.m00 = m00; 2218 this.m10 = m10; 2219 this.m01 = m01; 2220 this.m11 = m11; 2221 this.m02 = m02; 2222 this.m12 = m12; 2223 updateState(); 2224 } 2225 2226 /** 2227 * Concatenates an {@code AffineTransform Tx} to 2228 * this {@code AffineTransform} Cx in the most commonly useful 2229 * way to provide a new user space 2230 * that is mapped to the former user space by {@code Tx}. 2231 * Cx is updated to perform the combined transformation. 2232 * Transforming a point p by the updated transform Cx' is 2233 * equivalent to first transforming p by {@code Tx} and then 2234 * transforming the result by the original transform Cx like this: 2235 * Cx'(p) = Cx(Tx(p)) 2236 * In matrix notation, if this transform Cx is 2237 * represented by the matrix [this] and {@code Tx} is represented 2238 * by the matrix [Tx] then this method does the following: 2239 * <pre> 2240 * [this] = [this] x [Tx] 2241 * </pre> 2242 * @param Tx the {@code AffineTransform} object to be 2243 * concatenated with this {@code AffineTransform} object. 2244 * @see #preConcatenate 2245 * @since 1.2 2246 */ 2247 @SuppressWarnings("fallthrough") concatenate(AffineTransform Tx)2248 public void concatenate(AffineTransform Tx) { 2249 double M0, M1; 2250 double T00, T01, T10, T11; 2251 double T02, T12; 2252 int mystate = state; 2253 int txstate = Tx.state; 2254 switch ((txstate << HI_SHIFT) | mystate) { 2255 2256 /* ---------- Tx == IDENTITY cases ---------- */ 2257 case (HI_IDENTITY | APPLY_IDENTITY): 2258 case (HI_IDENTITY | APPLY_TRANSLATE): 2259 case (HI_IDENTITY | APPLY_SCALE): 2260 case (HI_IDENTITY | APPLY_SCALE | APPLY_TRANSLATE): 2261 case (HI_IDENTITY | APPLY_SHEAR): 2262 case (HI_IDENTITY | APPLY_SHEAR | APPLY_TRANSLATE): 2263 case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE): 2264 case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2265 return; 2266 2267 /* ---------- this == IDENTITY cases ---------- */ 2268 case (HI_SHEAR | HI_SCALE | HI_TRANSLATE | APPLY_IDENTITY): 2269 m01 = Tx.m01; 2270 m10 = Tx.m10; 2271 /* NOBREAK */ 2272 case (HI_SCALE | HI_TRANSLATE | APPLY_IDENTITY): 2273 m00 = Tx.m00; 2274 m11 = Tx.m11; 2275 /* NOBREAK */ 2276 case (HI_TRANSLATE | APPLY_IDENTITY): 2277 m02 = Tx.m02; 2278 m12 = Tx.m12; 2279 state = txstate; 2280 type = Tx.type; 2281 return; 2282 case (HI_SHEAR | HI_SCALE | APPLY_IDENTITY): 2283 m01 = Tx.m01; 2284 m10 = Tx.m10; 2285 /* NOBREAK */ 2286 case (HI_SCALE | APPLY_IDENTITY): 2287 m00 = Tx.m00; 2288 m11 = Tx.m11; 2289 state = txstate; 2290 type = Tx.type; 2291 return; 2292 case (HI_SHEAR | HI_TRANSLATE | APPLY_IDENTITY): 2293 m02 = Tx.m02; 2294 m12 = Tx.m12; 2295 /* NOBREAK */ 2296 case (HI_SHEAR | APPLY_IDENTITY): 2297 m01 = Tx.m01; 2298 m10 = Tx.m10; 2299 m00 = m11 = 0.0; 2300 state = txstate; 2301 type = Tx.type; 2302 return; 2303 2304 /* ---------- Tx == TRANSLATE cases ---------- */ 2305 case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2306 case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE): 2307 case (HI_TRANSLATE | APPLY_SHEAR | APPLY_TRANSLATE): 2308 case (HI_TRANSLATE | APPLY_SHEAR): 2309 case (HI_TRANSLATE | APPLY_SCALE | APPLY_TRANSLATE): 2310 case (HI_TRANSLATE | APPLY_SCALE): 2311 case (HI_TRANSLATE | APPLY_TRANSLATE): 2312 translate(Tx.m02, Tx.m12); 2313 return; 2314 2315 /* ---------- Tx == SCALE cases ---------- */ 2316 case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2317 case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE): 2318 case (HI_SCALE | APPLY_SHEAR | APPLY_TRANSLATE): 2319 case (HI_SCALE | APPLY_SHEAR): 2320 case (HI_SCALE | APPLY_SCALE | APPLY_TRANSLATE): 2321 case (HI_SCALE | APPLY_SCALE): 2322 case (HI_SCALE | APPLY_TRANSLATE): 2323 scale(Tx.m00, Tx.m11); 2324 return; 2325 2326 /* ---------- Tx == SHEAR cases ---------- */ 2327 case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2328 case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE): 2329 T01 = Tx.m01; T10 = Tx.m10; 2330 M0 = m00; 2331 m00 = m01 * T10; 2332 m01 = M0 * T01; 2333 M0 = m10; 2334 m10 = m11 * T10; 2335 m11 = M0 * T01; 2336 type = TYPE_UNKNOWN; 2337 return; 2338 case (HI_SHEAR | APPLY_SHEAR | APPLY_TRANSLATE): 2339 case (HI_SHEAR | APPLY_SHEAR): 2340 m00 = m01 * Tx.m10; 2341 m01 = 0.0; 2342 m11 = m10 * Tx.m01; 2343 m10 = 0.0; 2344 state = mystate ^ (APPLY_SHEAR | APPLY_SCALE); 2345 type = TYPE_UNKNOWN; 2346 return; 2347 case (HI_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2348 case (HI_SHEAR | APPLY_SCALE): 2349 m01 = m00 * Tx.m01; 2350 m00 = 0.0; 2351 m10 = m11 * Tx.m10; 2352 m11 = 0.0; 2353 state = mystate ^ (APPLY_SHEAR | APPLY_SCALE); 2354 type = TYPE_UNKNOWN; 2355 return; 2356 case (HI_SHEAR | APPLY_TRANSLATE): 2357 m00 = 0.0; 2358 m01 = Tx.m01; 2359 m10 = Tx.m10; 2360 m11 = 0.0; 2361 state = APPLY_TRANSLATE | APPLY_SHEAR; 2362 type = TYPE_UNKNOWN; 2363 return; 2364 } 2365 // If Tx has more than one attribute, it is not worth optimizing 2366 // all of those cases... 2367 T00 = Tx.m00; T01 = Tx.m01; T02 = Tx.m02; 2368 T10 = Tx.m10; T11 = Tx.m11; T12 = Tx.m12; 2369 switch (mystate) { 2370 default: 2371 stateError(); 2372 /* NOTREACHED */ 2373 case (APPLY_SHEAR | APPLY_SCALE): 2374 state = mystate | txstate; 2375 /* NOBREAK */ 2376 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2377 M0 = m00; 2378 M1 = m01; 2379 m00 = T00 * M0 + T10 * M1; 2380 m01 = T01 * M0 + T11 * M1; 2381 m02 += T02 * M0 + T12 * M1; 2382 2383 M0 = m10; 2384 M1 = m11; 2385 m10 = T00 * M0 + T10 * M1; 2386 m11 = T01 * M0 + T11 * M1; 2387 m12 += T02 * M0 + T12 * M1; 2388 type = TYPE_UNKNOWN; 2389 return; 2390 2391 case (APPLY_SHEAR | APPLY_TRANSLATE): 2392 case (APPLY_SHEAR): 2393 M0 = m01; 2394 m00 = T10 * M0; 2395 m01 = T11 * M0; 2396 m02 += T12 * M0; 2397 2398 M0 = m10; 2399 m10 = T00 * M0; 2400 m11 = T01 * M0; 2401 m12 += T02 * M0; 2402 break; 2403 2404 case (APPLY_SCALE | APPLY_TRANSLATE): 2405 case (APPLY_SCALE): 2406 M0 = m00; 2407 m00 = T00 * M0; 2408 m01 = T01 * M0; 2409 m02 += T02 * M0; 2410 2411 M0 = m11; 2412 m10 = T10 * M0; 2413 m11 = T11 * M0; 2414 m12 += T12 * M0; 2415 break; 2416 2417 case (APPLY_TRANSLATE): 2418 m00 = T00; 2419 m01 = T01; 2420 m02 += T02; 2421 2422 m10 = T10; 2423 m11 = T11; 2424 m12 += T12; 2425 state = txstate | APPLY_TRANSLATE; 2426 type = TYPE_UNKNOWN; 2427 return; 2428 } 2429 updateState(); 2430 } 2431 2432 /** 2433 * Concatenates an {@code AffineTransform Tx} to 2434 * this {@code AffineTransform} Cx 2435 * in a less commonly used way such that {@code Tx} modifies the 2436 * coordinate transformation relative to the absolute pixel 2437 * space rather than relative to the existing user space. 2438 * Cx is updated to perform the combined transformation. 2439 * Transforming a point p by the updated transform Cx' is 2440 * equivalent to first transforming p by the original transform 2441 * Cx and then transforming the result by 2442 * {@code Tx} like this: 2443 * Cx'(p) = Tx(Cx(p)) 2444 * In matrix notation, if this transform Cx 2445 * is represented by the matrix [this] and {@code Tx} is 2446 * represented by the matrix [Tx] then this method does the 2447 * following: 2448 * <pre> 2449 * [this] = [Tx] x [this] 2450 * </pre> 2451 * @param Tx the {@code AffineTransform} object to be 2452 * concatenated with this {@code AffineTransform} object. 2453 * @see #concatenate 2454 * @since 1.2 2455 */ 2456 @SuppressWarnings("fallthrough") preConcatenate(AffineTransform Tx)2457 public void preConcatenate(AffineTransform Tx) { 2458 double M0, M1; 2459 double T00, T01, T10, T11; 2460 double T02, T12; 2461 int mystate = state; 2462 int txstate = Tx.state; 2463 switch ((txstate << HI_SHIFT) | mystate) { 2464 case (HI_IDENTITY | APPLY_IDENTITY): 2465 case (HI_IDENTITY | APPLY_TRANSLATE): 2466 case (HI_IDENTITY | APPLY_SCALE): 2467 case (HI_IDENTITY | APPLY_SCALE | APPLY_TRANSLATE): 2468 case (HI_IDENTITY | APPLY_SHEAR): 2469 case (HI_IDENTITY | APPLY_SHEAR | APPLY_TRANSLATE): 2470 case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE): 2471 case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2472 // Tx is IDENTITY... 2473 return; 2474 2475 case (HI_TRANSLATE | APPLY_IDENTITY): 2476 case (HI_TRANSLATE | APPLY_SCALE): 2477 case (HI_TRANSLATE | APPLY_SHEAR): 2478 case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE): 2479 // Tx is TRANSLATE, this has no TRANSLATE 2480 m02 = Tx.m02; 2481 m12 = Tx.m12; 2482 state = mystate | APPLY_TRANSLATE; 2483 type |= TYPE_TRANSLATION; 2484 return; 2485 2486 case (HI_TRANSLATE | APPLY_TRANSLATE): 2487 case (HI_TRANSLATE | APPLY_SCALE | APPLY_TRANSLATE): 2488 case (HI_TRANSLATE | APPLY_SHEAR | APPLY_TRANSLATE): 2489 case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2490 // Tx is TRANSLATE, this has one too 2491 m02 = m02 + Tx.m02; 2492 m12 = m12 + Tx.m12; 2493 return; 2494 2495 case (HI_SCALE | APPLY_TRANSLATE): 2496 case (HI_SCALE | APPLY_IDENTITY): 2497 // Only these two existing states need a new state 2498 state = mystate | APPLY_SCALE; 2499 /* NOBREAK */ 2500 case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2501 case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE): 2502 case (HI_SCALE | APPLY_SHEAR | APPLY_TRANSLATE): 2503 case (HI_SCALE | APPLY_SHEAR): 2504 case (HI_SCALE | APPLY_SCALE | APPLY_TRANSLATE): 2505 case (HI_SCALE | APPLY_SCALE): 2506 // Tx is SCALE, this is anything 2507 T00 = Tx.m00; 2508 T11 = Tx.m11; 2509 if ((mystate & APPLY_SHEAR) != 0) { 2510 m01 = m01 * T00; 2511 m10 = m10 * T11; 2512 if ((mystate & APPLY_SCALE) != 0) { 2513 m00 = m00 * T00; 2514 m11 = m11 * T11; 2515 } 2516 } else { 2517 m00 = m00 * T00; 2518 m11 = m11 * T11; 2519 } 2520 if ((mystate & APPLY_TRANSLATE) != 0) { 2521 m02 = m02 * T00; 2522 m12 = m12 * T11; 2523 } 2524 type = TYPE_UNKNOWN; 2525 return; 2526 case (HI_SHEAR | APPLY_SHEAR | APPLY_TRANSLATE): 2527 case (HI_SHEAR | APPLY_SHEAR): 2528 mystate = mystate | APPLY_SCALE; 2529 /* NOBREAK */ 2530 case (HI_SHEAR | APPLY_TRANSLATE): 2531 case (HI_SHEAR | APPLY_IDENTITY): 2532 case (HI_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2533 case (HI_SHEAR | APPLY_SCALE): 2534 state = mystate ^ APPLY_SHEAR; 2535 /* NOBREAK */ 2536 case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2537 case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE): 2538 // Tx is SHEAR, this is anything 2539 T01 = Tx.m01; 2540 T10 = Tx.m10; 2541 2542 M0 = m00; 2543 m00 = m10 * T01; 2544 m10 = M0 * T10; 2545 2546 M0 = m01; 2547 m01 = m11 * T01; 2548 m11 = M0 * T10; 2549 2550 M0 = m02; 2551 m02 = m12 * T01; 2552 m12 = M0 * T10; 2553 type = TYPE_UNKNOWN; 2554 return; 2555 } 2556 // If Tx has more than one attribute, it is not worth optimizing 2557 // all of those cases... 2558 T00 = Tx.m00; T01 = Tx.m01; T02 = Tx.m02; 2559 T10 = Tx.m10; T11 = Tx.m11; T12 = Tx.m12; 2560 switch (mystate) { 2561 default: 2562 stateError(); 2563 /* NOTREACHED */ 2564 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2565 M0 = m02; 2566 M1 = m12; 2567 T02 += M0 * T00 + M1 * T01; 2568 T12 += M0 * T10 + M1 * T11; 2569 2570 /* NOBREAK */ 2571 case (APPLY_SHEAR | APPLY_SCALE): 2572 m02 = T02; 2573 m12 = T12; 2574 2575 M0 = m00; 2576 M1 = m10; 2577 m00 = M0 * T00 + M1 * T01; 2578 m10 = M0 * T10 + M1 * T11; 2579 2580 M0 = m01; 2581 M1 = m11; 2582 m01 = M0 * T00 + M1 * T01; 2583 m11 = M0 * T10 + M1 * T11; 2584 break; 2585 2586 case (APPLY_SHEAR | APPLY_TRANSLATE): 2587 M0 = m02; 2588 M1 = m12; 2589 T02 += M0 * T00 + M1 * T01; 2590 T12 += M0 * T10 + M1 * T11; 2591 2592 /* NOBREAK */ 2593 case (APPLY_SHEAR): 2594 m02 = T02; 2595 m12 = T12; 2596 2597 M0 = m10; 2598 m00 = M0 * T01; 2599 m10 = M0 * T11; 2600 2601 M0 = m01; 2602 m01 = M0 * T00; 2603 m11 = M0 * T10; 2604 break; 2605 2606 case (APPLY_SCALE | APPLY_TRANSLATE): 2607 M0 = m02; 2608 M1 = m12; 2609 T02 += M0 * T00 + M1 * T01; 2610 T12 += M0 * T10 + M1 * T11; 2611 2612 /* NOBREAK */ 2613 case (APPLY_SCALE): 2614 m02 = T02; 2615 m12 = T12; 2616 2617 M0 = m00; 2618 m00 = M0 * T00; 2619 m10 = M0 * T10; 2620 2621 M0 = m11; 2622 m01 = M0 * T01; 2623 m11 = M0 * T11; 2624 break; 2625 2626 case (APPLY_TRANSLATE): 2627 M0 = m02; 2628 M1 = m12; 2629 T02 += M0 * T00 + M1 * T01; 2630 T12 += M0 * T10 + M1 * T11; 2631 2632 /* NOBREAK */ 2633 case (APPLY_IDENTITY): 2634 m02 = T02; 2635 m12 = T12; 2636 2637 m00 = T00; 2638 m10 = T10; 2639 2640 m01 = T01; 2641 m11 = T11; 2642 2643 state = mystate | txstate; 2644 type = TYPE_UNKNOWN; 2645 return; 2646 } 2647 updateState(); 2648 } 2649 2650 /** 2651 * Returns an {@code AffineTransform} object representing the 2652 * inverse transformation. 2653 * The inverse transform Tx' of this transform Tx 2654 * maps coordinates transformed by Tx back 2655 * to their original coordinates. 2656 * In other words, Tx'(Tx(p)) = p = Tx(Tx'(p)). 2657 * <p> 2658 * If this transform maps all coordinates onto a point or a line 2659 * then it will not have an inverse, since coordinates that do 2660 * not lie on the destination point or line will not have an inverse 2661 * mapping. 2662 * The {@code getDeterminant} method can be used to determine if this 2663 * transform has no inverse, in which case an exception will be 2664 * thrown if the {@code createInverse} method is called. 2665 * @return a new {@code AffineTransform} object representing the 2666 * inverse transformation. 2667 * @see #getDeterminant 2668 * @exception NoninvertibleTransformException 2669 * if the matrix cannot be inverted. 2670 * @since 1.2 2671 */ createInverse()2672 public AffineTransform createInverse() 2673 throws NoninvertibleTransformException 2674 { 2675 double det; 2676 switch (state) { 2677 default: 2678 stateError(); 2679 /* NOTREACHED */ 2680 return null; 2681 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2682 det = m00 * m11 - m01 * m10; 2683 if (Math.abs(det) <= Double.MIN_VALUE) { 2684 throw new NoninvertibleTransformException("Determinant is "+ 2685 det); 2686 } 2687 return new AffineTransform( m11 / det, -m10 / det, 2688 -m01 / det, m00 / det, 2689 (m01 * m12 - m11 * m02) / det, 2690 (m10 * m02 - m00 * m12) / det, 2691 (APPLY_SHEAR | 2692 APPLY_SCALE | 2693 APPLY_TRANSLATE)); 2694 case (APPLY_SHEAR | APPLY_SCALE): 2695 det = m00 * m11 - m01 * m10; 2696 if (Math.abs(det) <= Double.MIN_VALUE) { 2697 throw new NoninvertibleTransformException("Determinant is "+ 2698 det); 2699 } 2700 return new AffineTransform( m11 / det, -m10 / det, 2701 -m01 / det, m00 / det, 2702 0.0, 0.0, 2703 (APPLY_SHEAR | APPLY_SCALE)); 2704 case (APPLY_SHEAR | APPLY_TRANSLATE): 2705 if (m01 == 0.0 || m10 == 0.0) { 2706 throw new NoninvertibleTransformException("Determinant is 0"); 2707 } 2708 return new AffineTransform( 0.0, 1.0 / m01, 2709 1.0 / m10, 0.0, 2710 -m12 / m10, -m02 / m01, 2711 (APPLY_SHEAR | APPLY_TRANSLATE)); 2712 case (APPLY_SHEAR): 2713 if (m01 == 0.0 || m10 == 0.0) { 2714 throw new NoninvertibleTransformException("Determinant is 0"); 2715 } 2716 return new AffineTransform(0.0, 1.0 / m01, 2717 1.0 / m10, 0.0, 2718 0.0, 0.0, 2719 (APPLY_SHEAR)); 2720 case (APPLY_SCALE | APPLY_TRANSLATE): 2721 if (m00 == 0.0 || m11 == 0.0) { 2722 throw new NoninvertibleTransformException("Determinant is 0"); 2723 } 2724 return new AffineTransform( 1.0 / m00, 0.0, 2725 0.0, 1.0 / m11, 2726 -m02 / m00, -m12 / m11, 2727 (APPLY_SCALE | APPLY_TRANSLATE)); 2728 case (APPLY_SCALE): 2729 if (m00 == 0.0 || m11 == 0.0) { 2730 throw new NoninvertibleTransformException("Determinant is 0"); 2731 } 2732 return new AffineTransform(1.0 / m00, 0.0, 2733 0.0, 1.0 / m11, 2734 0.0, 0.0, 2735 (APPLY_SCALE)); 2736 case (APPLY_TRANSLATE): 2737 return new AffineTransform( 1.0, 0.0, 2738 0.0, 1.0, 2739 -m02, -m12, 2740 (APPLY_TRANSLATE)); 2741 case (APPLY_IDENTITY): 2742 return new AffineTransform(); 2743 } 2744 2745 /* NOTREACHED */ 2746 } 2747 2748 /** 2749 * Sets this transform to the inverse of itself. 2750 * The inverse transform Tx' of this transform Tx 2751 * maps coordinates transformed by Tx back 2752 * to their original coordinates. 2753 * In other words, Tx'(Tx(p)) = p = Tx(Tx'(p)). 2754 * <p> 2755 * If this transform maps all coordinates onto a point or a line 2756 * then it will not have an inverse, since coordinates that do 2757 * not lie on the destination point or line will not have an inverse 2758 * mapping. 2759 * The {@code getDeterminant} method can be used to determine if this 2760 * transform has no inverse, in which case an exception will be 2761 * thrown if the {@code invert} method is called. 2762 * @see #getDeterminant 2763 * @exception NoninvertibleTransformException 2764 * if the matrix cannot be inverted. 2765 * @since 1.6 2766 */ invert()2767 public void invert() 2768 throws NoninvertibleTransformException 2769 { 2770 double M00, M01, M02; 2771 double M10, M11, M12; 2772 double det; 2773 switch (state) { 2774 default: 2775 stateError(); 2776 /* NOTREACHED */ 2777 return; 2778 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2779 M00 = m00; M01 = m01; M02 = m02; 2780 M10 = m10; M11 = m11; M12 = m12; 2781 det = M00 * M11 - M01 * M10; 2782 if (Math.abs(det) <= Double.MIN_VALUE) { 2783 throw new NoninvertibleTransformException("Determinant is "+ 2784 det); 2785 } 2786 m00 = M11 / det; 2787 m10 = -M10 / det; 2788 m01 = -M01 / det; 2789 m11 = M00 / det; 2790 m02 = (M01 * M12 - M11 * M02) / det; 2791 m12 = (M10 * M02 - M00 * M12) / det; 2792 break; 2793 case (APPLY_SHEAR | APPLY_SCALE): 2794 M00 = m00; M01 = m01; 2795 M10 = m10; M11 = m11; 2796 det = M00 * M11 - M01 * M10; 2797 if (Math.abs(det) <= Double.MIN_VALUE) { 2798 throw new NoninvertibleTransformException("Determinant is "+ 2799 det); 2800 } 2801 m00 = M11 / det; 2802 m10 = -M10 / det; 2803 m01 = -M01 / det; 2804 m11 = M00 / det; 2805 // m02 = 0.0; 2806 // m12 = 0.0; 2807 break; 2808 case (APPLY_SHEAR | APPLY_TRANSLATE): 2809 M01 = m01; M02 = m02; 2810 M10 = m10; M12 = m12; 2811 if (M01 == 0.0 || M10 == 0.0) { 2812 throw new NoninvertibleTransformException("Determinant is 0"); 2813 } 2814 // m00 = 0.0; 2815 m10 = 1.0 / M01; 2816 m01 = 1.0 / M10; 2817 // m11 = 0.0; 2818 m02 = -M12 / M10; 2819 m12 = -M02 / M01; 2820 break; 2821 case (APPLY_SHEAR): 2822 M01 = m01; 2823 M10 = m10; 2824 if (M01 == 0.0 || M10 == 0.0) { 2825 throw new NoninvertibleTransformException("Determinant is 0"); 2826 } 2827 // m00 = 0.0; 2828 m10 = 1.0 / M01; 2829 m01 = 1.0 / M10; 2830 // m11 = 0.0; 2831 // m02 = 0.0; 2832 // m12 = 0.0; 2833 break; 2834 case (APPLY_SCALE | APPLY_TRANSLATE): 2835 M00 = m00; M02 = m02; 2836 M11 = m11; M12 = m12; 2837 if (M00 == 0.0 || M11 == 0.0) { 2838 throw new NoninvertibleTransformException("Determinant is 0"); 2839 } 2840 m00 = 1.0 / M00; 2841 // m10 = 0.0; 2842 // m01 = 0.0; 2843 m11 = 1.0 / M11; 2844 m02 = -M02 / M00; 2845 m12 = -M12 / M11; 2846 break; 2847 case (APPLY_SCALE): 2848 M00 = m00; 2849 M11 = m11; 2850 if (M00 == 0.0 || M11 == 0.0) { 2851 throw new NoninvertibleTransformException("Determinant is 0"); 2852 } 2853 m00 = 1.0 / M00; 2854 // m10 = 0.0; 2855 // m01 = 0.0; 2856 m11 = 1.0 / M11; 2857 // m02 = 0.0; 2858 // m12 = 0.0; 2859 break; 2860 case (APPLY_TRANSLATE): 2861 // m00 = 1.0; 2862 // m10 = 0.0; 2863 // m01 = 0.0; 2864 // m11 = 1.0; 2865 m02 = -m02; 2866 m12 = -m12; 2867 break; 2868 case (APPLY_IDENTITY): 2869 // m00 = 1.0; 2870 // m10 = 0.0; 2871 // m01 = 0.0; 2872 // m11 = 1.0; 2873 // m02 = 0.0; 2874 // m12 = 0.0; 2875 break; 2876 } 2877 } 2878 2879 /** 2880 * Transforms the specified {@code ptSrc} and stores the result 2881 * in {@code ptDst}. 2882 * If {@code ptDst} is {@code null}, a new {@link Point2D} 2883 * object is allocated and then the result of the transformation is 2884 * stored in this object. 2885 * In either case, {@code ptDst}, which contains the 2886 * transformed point, is returned for convenience. 2887 * If {@code ptSrc} and {@code ptDst} are the same 2888 * object, the input point is correctly overwritten with 2889 * the transformed point. 2890 * @param ptSrc the specified {@code Point2D} to be transformed 2891 * @param ptDst the specified {@code Point2D} that stores the 2892 * result of transforming {@code ptSrc} 2893 * @return the {@code ptDst} after transforming 2894 * {@code ptSrc} and storing the result in {@code ptDst}. 2895 * @since 1.2 2896 */ transform(Point2D ptSrc, Point2D ptDst)2897 public Point2D transform(Point2D ptSrc, Point2D ptDst) { 2898 if (ptDst == null) { 2899 if (ptSrc instanceof Point2D.Double) { 2900 ptDst = new Point2D.Double(); 2901 } else { 2902 ptDst = new Point2D.Float(); 2903 } 2904 } 2905 // Copy source coords into local variables in case src == dst 2906 double x = ptSrc.getX(); 2907 double y = ptSrc.getY(); 2908 switch (state) { 2909 default: 2910 stateError(); 2911 /* NOTREACHED */ 2912 return null; 2913 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2914 ptDst.setLocation(x * m00 + y * m01 + m02, 2915 x * m10 + y * m11 + m12); 2916 return ptDst; 2917 case (APPLY_SHEAR | APPLY_SCALE): 2918 ptDst.setLocation(x * m00 + y * m01, x * m10 + y * m11); 2919 return ptDst; 2920 case (APPLY_SHEAR | APPLY_TRANSLATE): 2921 ptDst.setLocation(y * m01 + m02, x * m10 + m12); 2922 return ptDst; 2923 case (APPLY_SHEAR): 2924 ptDst.setLocation(y * m01, x * m10); 2925 return ptDst; 2926 case (APPLY_SCALE | APPLY_TRANSLATE): 2927 ptDst.setLocation(x * m00 + m02, y * m11 + m12); 2928 return ptDst; 2929 case (APPLY_SCALE): 2930 ptDst.setLocation(x * m00, y * m11); 2931 return ptDst; 2932 case (APPLY_TRANSLATE): 2933 ptDst.setLocation(x + m02, y + m12); 2934 return ptDst; 2935 case (APPLY_IDENTITY): 2936 ptDst.setLocation(x, y); 2937 return ptDst; 2938 } 2939 2940 /* NOTREACHED */ 2941 } 2942 2943 /** 2944 * Transforms an array of point objects by this transform. 2945 * If any element of the {@code ptDst} array is 2946 * {@code null}, a new {@code Point2D} object is allocated 2947 * and stored into that element before storing the results of the 2948 * transformation. 2949 * <p> 2950 * Note that this method does not take any precautions to 2951 * avoid problems caused by storing results into {@code Point2D} 2952 * objects that will be used as the source for calculations 2953 * further down the source array. 2954 * This method does guarantee that if a specified {@code Point2D} 2955 * object is both the source and destination for the same single point 2956 * transform operation then the results will not be stored until 2957 * the calculations are complete to avoid storing the results on 2958 * top of the operands. 2959 * If, however, the destination {@code Point2D} object for one 2960 * operation is the same object as the source {@code Point2D} 2961 * object for another operation further down the source array then 2962 * the original coordinates in that point are overwritten before 2963 * they can be converted. 2964 * @param ptSrc the array containing the source point objects 2965 * @param ptDst the array into which the transform point objects are 2966 * returned 2967 * @param srcOff the offset to the first point object to be 2968 * transformed in the source array 2969 * @param dstOff the offset to the location of the first 2970 * transformed point object that is stored in the destination array 2971 * @param numPts the number of point objects to be transformed 2972 * @since 1.2 2973 */ transform(Point2D[] ptSrc, int srcOff, Point2D[] ptDst, int dstOff, int numPts)2974 public void transform(Point2D[] ptSrc, int srcOff, 2975 Point2D[] ptDst, int dstOff, 2976 int numPts) { 2977 int state = this.state; 2978 while (--numPts >= 0) { 2979 // Copy source coords into local variables in case src == dst 2980 Point2D src = ptSrc[srcOff++]; 2981 double x = src.getX(); 2982 double y = src.getY(); 2983 Point2D dst = ptDst[dstOff++]; 2984 if (dst == null) { 2985 if (src instanceof Point2D.Double) { 2986 dst = new Point2D.Double(); 2987 } else { 2988 dst = new Point2D.Float(); 2989 } 2990 ptDst[dstOff - 1] = dst; 2991 } 2992 switch (state) { 2993 default: 2994 stateError(); 2995 /* NOTREACHED */ 2996 return; 2997 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2998 dst.setLocation(x * m00 + y * m01 + m02, 2999 x * m10 + y * m11 + m12); 3000 break; 3001 case (APPLY_SHEAR | APPLY_SCALE): 3002 dst.setLocation(x * m00 + y * m01, x * m10 + y * m11); 3003 break; 3004 case (APPLY_SHEAR | APPLY_TRANSLATE): 3005 dst.setLocation(y * m01 + m02, x * m10 + m12); 3006 break; 3007 case (APPLY_SHEAR): 3008 dst.setLocation(y * m01, x * m10); 3009 break; 3010 case (APPLY_SCALE | APPLY_TRANSLATE): 3011 dst.setLocation(x * m00 + m02, y * m11 + m12); 3012 break; 3013 case (APPLY_SCALE): 3014 dst.setLocation(x * m00, y * m11); 3015 break; 3016 case (APPLY_TRANSLATE): 3017 dst.setLocation(x + m02, y + m12); 3018 break; 3019 case (APPLY_IDENTITY): 3020 dst.setLocation(x, y); 3021 break; 3022 } 3023 } 3024 3025 /* NOTREACHED */ 3026 } 3027 3028 /** 3029 * Transforms an array of floating point coordinates by this transform. 3030 * The two coordinate array sections can be exactly the same or 3031 * can be overlapping sections of the same array without affecting the 3032 * validity of the results. 3033 * This method ensures that no source coordinates are overwritten by a 3034 * previous operation before they can be transformed. 3035 * The coordinates are stored in the arrays starting at the specified 3036 * offset in the order {@code [x0, y0, x1, y1, ..., xn, yn]}. 3037 * @param srcPts the array containing the source point coordinates. 3038 * Each point is stored as a pair of x, y coordinates. 3039 * @param dstPts the array into which the transformed point coordinates 3040 * are returned. Each point is stored as a pair of x, y 3041 * coordinates. 3042 * @param srcOff the offset to the first point to be transformed 3043 * in the source array 3044 * @param dstOff the offset to the location of the first 3045 * transformed point that is stored in the destination array 3046 * @param numPts the number of points to be transformed 3047 * @since 1.2 3048 */ transform(float[] srcPts, int srcOff, float[] dstPts, int dstOff, int numPts)3049 public void transform(float[] srcPts, int srcOff, 3050 float[] dstPts, int dstOff, 3051 int numPts) { 3052 double M00, M01, M02, M10, M11, M12; // For caching 3053 if (dstPts == srcPts && 3054 dstOff > srcOff && dstOff < srcOff + numPts * 2) 3055 { 3056 // If the arrays overlap partially with the destination higher 3057 // than the source and we transform the coordinates normally 3058 // we would overwrite some of the later source coordinates 3059 // with results of previous transformations. 3060 // To get around this we use arraycopy to copy the points 3061 // to their final destination with correct overwrite 3062 // handling and then transform them in place in the new 3063 // safer location. 3064 System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts * 2); 3065 // srcPts = dstPts; // They are known to be equal. 3066 srcOff = dstOff; 3067 } 3068 switch (state) { 3069 default: 3070 stateError(); 3071 /* NOTREACHED */ 3072 return; 3073 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 3074 M00 = m00; M01 = m01; M02 = m02; 3075 M10 = m10; M11 = m11; M12 = m12; 3076 while (--numPts >= 0) { 3077 double x = srcPts[srcOff++]; 3078 double y = srcPts[srcOff++]; 3079 dstPts[dstOff++] = (float) (M00 * x + M01 * y + M02); 3080 dstPts[dstOff++] = (float) (M10 * x + M11 * y + M12); 3081 } 3082 return; 3083 case (APPLY_SHEAR | APPLY_SCALE): 3084 M00 = m00; M01 = m01; 3085 M10 = m10; M11 = m11; 3086 while (--numPts >= 0) { 3087 double x = srcPts[srcOff++]; 3088 double y = srcPts[srcOff++]; 3089 dstPts[dstOff++] = (float) (M00 * x + M01 * y); 3090 dstPts[dstOff++] = (float) (M10 * x + M11 * y); 3091 } 3092 return; 3093 case (APPLY_SHEAR | APPLY_TRANSLATE): 3094 M01 = m01; M02 = m02; 3095 M10 = m10; M12 = m12; 3096 while (--numPts >= 0) { 3097 double x = srcPts[srcOff++]; 3098 dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++] + M02); 3099 dstPts[dstOff++] = (float) (M10 * x + M12); 3100 } 3101 return; 3102 case (APPLY_SHEAR): 3103 M01 = m01; M10 = m10; 3104 while (--numPts >= 0) { 3105 double x = srcPts[srcOff++]; 3106 dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++]); 3107 dstPts[dstOff++] = (float) (M10 * x); 3108 } 3109 return; 3110 case (APPLY_SCALE | APPLY_TRANSLATE): 3111 M00 = m00; M02 = m02; 3112 M11 = m11; M12 = m12; 3113 while (--numPts >= 0) { 3114 dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++] + M02); 3115 dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++] + M12); 3116 } 3117 return; 3118 case (APPLY_SCALE): 3119 M00 = m00; M11 = m11; 3120 while (--numPts >= 0) { 3121 dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++]); 3122 dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++]); 3123 } 3124 return; 3125 case (APPLY_TRANSLATE): 3126 M02 = m02; M12 = m12; 3127 while (--numPts >= 0) { 3128 dstPts[dstOff++] = (float) (srcPts[srcOff++] + M02); 3129 dstPts[dstOff++] = (float) (srcPts[srcOff++] + M12); 3130 } 3131 return; 3132 case (APPLY_IDENTITY): 3133 if (srcPts != dstPts || srcOff != dstOff) { 3134 System.arraycopy(srcPts, srcOff, dstPts, dstOff, 3135 numPts * 2); 3136 } 3137 return; 3138 } 3139 3140 /* NOTREACHED */ 3141 } 3142 3143 /** 3144 * Transforms an array of double precision coordinates by this transform. 3145 * The two coordinate array sections can be exactly the same or 3146 * can be overlapping sections of the same array without affecting the 3147 * validity of the results. 3148 * This method ensures that no source coordinates are 3149 * overwritten by a previous operation before they can be transformed. 3150 * The coordinates are stored in the arrays starting at the indicated 3151 * offset in the order {@code [x0, y0, x1, y1, ..., xn, yn]}. 3152 * @param srcPts the array containing the source point coordinates. 3153 * Each point is stored as a pair of x, y coordinates. 3154 * @param dstPts the array into which the transformed point 3155 * coordinates are returned. Each point is stored as a pair of 3156 * x, y coordinates. 3157 * @param srcOff the offset to the first point to be transformed 3158 * in the source array 3159 * @param dstOff the offset to the location of the first 3160 * transformed point that is stored in the destination array 3161 * @param numPts the number of point objects to be transformed 3162 * @since 1.2 3163 */ transform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, int numPts)3164 public void transform(double[] srcPts, int srcOff, 3165 double[] dstPts, int dstOff, 3166 int numPts) { 3167 double M00, M01, M02, M10, M11, M12; // For caching 3168 if (dstPts == srcPts && 3169 dstOff > srcOff && dstOff < srcOff + numPts * 2) 3170 { 3171 // If the arrays overlap partially with the destination higher 3172 // than the source and we transform the coordinates normally 3173 // we would overwrite some of the later source coordinates 3174 // with results of previous transformations. 3175 // To get around this we use arraycopy to copy the points 3176 // to their final destination with correct overwrite 3177 // handling and then transform them in place in the new 3178 // safer location. 3179 System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts * 2); 3180 // srcPts = dstPts; // They are known to be equal. 3181 srcOff = dstOff; 3182 } 3183 switch (state) { 3184 default: 3185 stateError(); 3186 /* NOTREACHED */ 3187 return; 3188 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 3189 M00 = m00; M01 = m01; M02 = m02; 3190 M10 = m10; M11 = m11; M12 = m12; 3191 while (--numPts >= 0) { 3192 double x = srcPts[srcOff++]; 3193 double y = srcPts[srcOff++]; 3194 dstPts[dstOff++] = M00 * x + M01 * y + M02; 3195 dstPts[dstOff++] = M10 * x + M11 * y + M12; 3196 } 3197 return; 3198 case (APPLY_SHEAR | APPLY_SCALE): 3199 M00 = m00; M01 = m01; 3200 M10 = m10; M11 = m11; 3201 while (--numPts >= 0) { 3202 double x = srcPts[srcOff++]; 3203 double y = srcPts[srcOff++]; 3204 dstPts[dstOff++] = M00 * x + M01 * y; 3205 dstPts[dstOff++] = M10 * x + M11 * y; 3206 } 3207 return; 3208 case (APPLY_SHEAR | APPLY_TRANSLATE): 3209 M01 = m01; M02 = m02; 3210 M10 = m10; M12 = m12; 3211 while (--numPts >= 0) { 3212 double x = srcPts[srcOff++]; 3213 dstPts[dstOff++] = M01 * srcPts[srcOff++] + M02; 3214 dstPts[dstOff++] = M10 * x + M12; 3215 } 3216 return; 3217 case (APPLY_SHEAR): 3218 M01 = m01; M10 = m10; 3219 while (--numPts >= 0) { 3220 double x = srcPts[srcOff++]; 3221 dstPts[dstOff++] = M01 * srcPts[srcOff++]; 3222 dstPts[dstOff++] = M10 * x; 3223 } 3224 return; 3225 case (APPLY_SCALE | APPLY_TRANSLATE): 3226 M00 = m00; M02 = m02; 3227 M11 = m11; M12 = m12; 3228 while (--numPts >= 0) { 3229 dstPts[dstOff++] = M00 * srcPts[srcOff++] + M02; 3230 dstPts[dstOff++] = M11 * srcPts[srcOff++] + M12; 3231 } 3232 return; 3233 case (APPLY_SCALE): 3234 M00 = m00; M11 = m11; 3235 while (--numPts >= 0) { 3236 dstPts[dstOff++] = M00 * srcPts[srcOff++]; 3237 dstPts[dstOff++] = M11 * srcPts[srcOff++]; 3238 } 3239 return; 3240 case (APPLY_TRANSLATE): 3241 M02 = m02; M12 = m12; 3242 while (--numPts >= 0) { 3243 dstPts[dstOff++] = srcPts[srcOff++] + M02; 3244 dstPts[dstOff++] = srcPts[srcOff++] + M12; 3245 } 3246 return; 3247 case (APPLY_IDENTITY): 3248 if (srcPts != dstPts || srcOff != dstOff) { 3249 System.arraycopy(srcPts, srcOff, dstPts, dstOff, 3250 numPts * 2); 3251 } 3252 return; 3253 } 3254 3255 /* NOTREACHED */ 3256 } 3257 3258 /** 3259 * Transforms an array of floating point coordinates by this transform 3260 * and stores the results into an array of doubles. 3261 * The coordinates are stored in the arrays starting at the specified 3262 * offset in the order {@code [x0, y0, x1, y1, ..., xn, yn]}. 3263 * @param srcPts the array containing the source point coordinates. 3264 * Each point is stored as a pair of x, y coordinates. 3265 * @param dstPts the array into which the transformed point coordinates 3266 * are returned. Each point is stored as a pair of x, y 3267 * coordinates. 3268 * @param srcOff the offset to the first point to be transformed 3269 * in the source array 3270 * @param dstOff the offset to the location of the first 3271 * transformed point that is stored in the destination array 3272 * @param numPts the number of points to be transformed 3273 * @since 1.2 3274 */ transform(float[] srcPts, int srcOff, double[] dstPts, int dstOff, int numPts)3275 public void transform(float[] srcPts, int srcOff, 3276 double[] dstPts, int dstOff, 3277 int numPts) { 3278 double M00, M01, M02, M10, M11, M12; // For caching 3279 switch (state) { 3280 default: 3281 stateError(); 3282 /* NOTREACHED */ 3283 return; 3284 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 3285 M00 = m00; M01 = m01; M02 = m02; 3286 M10 = m10; M11 = m11; M12 = m12; 3287 while (--numPts >= 0) { 3288 double x = srcPts[srcOff++]; 3289 double y = srcPts[srcOff++]; 3290 dstPts[dstOff++] = M00 * x + M01 * y + M02; 3291 dstPts[dstOff++] = M10 * x + M11 * y + M12; 3292 } 3293 return; 3294 case (APPLY_SHEAR | APPLY_SCALE): 3295 M00 = m00; M01 = m01; 3296 M10 = m10; M11 = m11; 3297 while (--numPts >= 0) { 3298 double x = srcPts[srcOff++]; 3299 double y = srcPts[srcOff++]; 3300 dstPts[dstOff++] = M00 * x + M01 * y; 3301 dstPts[dstOff++] = M10 * x + M11 * y; 3302 } 3303 return; 3304 case (APPLY_SHEAR | APPLY_TRANSLATE): 3305 M01 = m01; M02 = m02; 3306 M10 = m10; M12 = m12; 3307 while (--numPts >= 0) { 3308 double x = srcPts[srcOff++]; 3309 dstPts[dstOff++] = M01 * srcPts[srcOff++] + M02; 3310 dstPts[dstOff++] = M10 * x + M12; 3311 } 3312 return; 3313 case (APPLY_SHEAR): 3314 M01 = m01; M10 = m10; 3315 while (--numPts >= 0) { 3316 double x = srcPts[srcOff++]; 3317 dstPts[dstOff++] = M01 * srcPts[srcOff++]; 3318 dstPts[dstOff++] = M10 * x; 3319 } 3320 return; 3321 case (APPLY_SCALE | APPLY_TRANSLATE): 3322 M00 = m00; M02 = m02; 3323 M11 = m11; M12 = m12; 3324 while (--numPts >= 0) { 3325 dstPts[dstOff++] = M00 * srcPts[srcOff++] + M02; 3326 dstPts[dstOff++] = M11 * srcPts[srcOff++] + M12; 3327 } 3328 return; 3329 case (APPLY_SCALE): 3330 M00 = m00; M11 = m11; 3331 while (--numPts >= 0) { 3332 dstPts[dstOff++] = M00 * srcPts[srcOff++]; 3333 dstPts[dstOff++] = M11 * srcPts[srcOff++]; 3334 } 3335 return; 3336 case (APPLY_TRANSLATE): 3337 M02 = m02; M12 = m12; 3338 while (--numPts >= 0) { 3339 dstPts[dstOff++] = srcPts[srcOff++] + M02; 3340 dstPts[dstOff++] = srcPts[srcOff++] + M12; 3341 } 3342 return; 3343 case (APPLY_IDENTITY): 3344 while (--numPts >= 0) { 3345 dstPts[dstOff++] = srcPts[srcOff++]; 3346 dstPts[dstOff++] = srcPts[srcOff++]; 3347 } 3348 return; 3349 } 3350 3351 /* NOTREACHED */ 3352 } 3353 3354 /** 3355 * Transforms an array of double precision coordinates by this transform 3356 * and stores the results into an array of floats. 3357 * The coordinates are stored in the arrays starting at the specified 3358 * offset in the order {@code [x0, y0, x1, y1, ..., xn, yn]}. 3359 * @param srcPts the array containing the source point coordinates. 3360 * Each point is stored as a pair of x, y coordinates. 3361 * @param dstPts the array into which the transformed point 3362 * coordinates are returned. Each point is stored as a pair of 3363 * x, y coordinates. 3364 * @param srcOff the offset to the first point to be transformed 3365 * in the source array 3366 * @param dstOff the offset to the location of the first 3367 * transformed point that is stored in the destination array 3368 * @param numPts the number of point objects to be transformed 3369 * @since 1.2 3370 */ transform(double[] srcPts, int srcOff, float[] dstPts, int dstOff, int numPts)3371 public void transform(double[] srcPts, int srcOff, 3372 float[] dstPts, int dstOff, 3373 int numPts) { 3374 double M00, M01, M02, M10, M11, M12; // For caching 3375 switch (state) { 3376 default: 3377 stateError(); 3378 /* NOTREACHED */ 3379 return; 3380 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 3381 M00 = m00; M01 = m01; M02 = m02; 3382 M10 = m10; M11 = m11; M12 = m12; 3383 while (--numPts >= 0) { 3384 double x = srcPts[srcOff++]; 3385 double y = srcPts[srcOff++]; 3386 dstPts[dstOff++] = (float) (M00 * x + M01 * y + M02); 3387 dstPts[dstOff++] = (float) (M10 * x + M11 * y + M12); 3388 } 3389 return; 3390 case (APPLY_SHEAR | APPLY_SCALE): 3391 M00 = m00; M01 = m01; 3392 M10 = m10; M11 = m11; 3393 while (--numPts >= 0) { 3394 double x = srcPts[srcOff++]; 3395 double y = srcPts[srcOff++]; 3396 dstPts[dstOff++] = (float) (M00 * x + M01 * y); 3397 dstPts[dstOff++] = (float) (M10 * x + M11 * y); 3398 } 3399 return; 3400 case (APPLY_SHEAR | APPLY_TRANSLATE): 3401 M01 = m01; M02 = m02; 3402 M10 = m10; M12 = m12; 3403 while (--numPts >= 0) { 3404 double x = srcPts[srcOff++]; 3405 dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++] + M02); 3406 dstPts[dstOff++] = (float) (M10 * x + M12); 3407 } 3408 return; 3409 case (APPLY_SHEAR): 3410 M01 = m01; M10 = m10; 3411 while (--numPts >= 0) { 3412 double x = srcPts[srcOff++]; 3413 dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++]); 3414 dstPts[dstOff++] = (float) (M10 * x); 3415 } 3416 return; 3417 case (APPLY_SCALE | APPLY_TRANSLATE): 3418 M00 = m00; M02 = m02; 3419 M11 = m11; M12 = m12; 3420 while (--numPts >= 0) { 3421 dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++] + M02); 3422 dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++] + M12); 3423 } 3424 return; 3425 case (APPLY_SCALE): 3426 M00 = m00; M11 = m11; 3427 while (--numPts >= 0) { 3428 dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++]); 3429 dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++]); 3430 } 3431 return; 3432 case (APPLY_TRANSLATE): 3433 M02 = m02; M12 = m12; 3434 while (--numPts >= 0) { 3435 dstPts[dstOff++] = (float) (srcPts[srcOff++] + M02); 3436 dstPts[dstOff++] = (float) (srcPts[srcOff++] + M12); 3437 } 3438 return; 3439 case (APPLY_IDENTITY): 3440 while (--numPts >= 0) { 3441 dstPts[dstOff++] = (float) (srcPts[srcOff++]); 3442 dstPts[dstOff++] = (float) (srcPts[srcOff++]); 3443 } 3444 return; 3445 } 3446 3447 /* NOTREACHED */ 3448 } 3449 3450 /** 3451 * Inverse transforms the specified {@code ptSrc} and stores the 3452 * result in {@code ptDst}. 3453 * If {@code ptDst} is {@code null}, a new 3454 * {@code Point2D} object is allocated and then the result of the 3455 * transform is stored in this object. 3456 * In either case, {@code ptDst}, which contains the transformed 3457 * point, is returned for convenience. 3458 * If {@code ptSrc} and {@code ptDst} are the same 3459 * object, the input point is correctly overwritten with the 3460 * transformed point. 3461 * @param ptSrc the point to be inverse transformed 3462 * @param ptDst the resulting transformed point 3463 * @return {@code ptDst}, which contains the result of the 3464 * inverse transform. 3465 * @exception NoninvertibleTransformException if the matrix cannot be 3466 * inverted. 3467 * @since 1.2 3468 */ 3469 @SuppressWarnings("fallthrough") inverseTransform(Point2D ptSrc, Point2D ptDst)3470 public Point2D inverseTransform(Point2D ptSrc, Point2D ptDst) 3471 throws NoninvertibleTransformException 3472 { 3473 if (ptDst == null) { 3474 if (ptSrc instanceof Point2D.Double) { 3475 ptDst = new Point2D.Double(); 3476 } else { 3477 ptDst = new Point2D.Float(); 3478 } 3479 } 3480 // Copy source coords into local variables in case src == dst 3481 double x = ptSrc.getX(); 3482 double y = ptSrc.getY(); 3483 switch (state) { 3484 default: 3485 stateError(); 3486 /* NOTREACHED */ 3487 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 3488 x -= m02; 3489 y -= m12; 3490 /* NOBREAK */ 3491 case (APPLY_SHEAR | APPLY_SCALE): 3492 double det = m00 * m11 - m01 * m10; 3493 if (Math.abs(det) <= Double.MIN_VALUE) { 3494 throw new NoninvertibleTransformException("Determinant is "+ 3495 det); 3496 } 3497 ptDst.setLocation((x * m11 - y * m01) / det, 3498 (y * m00 - x * m10) / det); 3499 return ptDst; 3500 case (APPLY_SHEAR | APPLY_TRANSLATE): 3501 x -= m02; 3502 y -= m12; 3503 /* NOBREAK */ 3504 case (APPLY_SHEAR): 3505 if (m01 == 0.0 || m10 == 0.0) { 3506 throw new NoninvertibleTransformException("Determinant is 0"); 3507 } 3508 ptDst.setLocation(y / m10, x / m01); 3509 return ptDst; 3510 case (APPLY_SCALE | APPLY_TRANSLATE): 3511 x -= m02; 3512 y -= m12; 3513 /* NOBREAK */ 3514 case (APPLY_SCALE): 3515 if (m00 == 0.0 || m11 == 0.0) { 3516 throw new NoninvertibleTransformException("Determinant is 0"); 3517 } 3518 ptDst.setLocation(x / m00, y / m11); 3519 return ptDst; 3520 case (APPLY_TRANSLATE): 3521 ptDst.setLocation(x - m02, y - m12); 3522 return ptDst; 3523 case (APPLY_IDENTITY): 3524 ptDst.setLocation(x, y); 3525 return ptDst; 3526 } 3527 3528 /* NOTREACHED */ 3529 } 3530 3531 /** 3532 * Inverse transforms an array of double precision coordinates by 3533 * this transform. 3534 * The two coordinate array sections can be exactly the same or 3535 * can be overlapping sections of the same array without affecting the 3536 * validity of the results. 3537 * This method ensures that no source coordinates are 3538 * overwritten by a previous operation before they can be transformed. 3539 * The coordinates are stored in the arrays starting at the specified 3540 * offset in the order {@code [x0, y0, x1, y1, ..., xn, yn]}. 3541 * @param srcPts the array containing the source point coordinates. 3542 * Each point is stored as a pair of x, y coordinates. 3543 * @param dstPts the array into which the transformed point 3544 * coordinates are returned. Each point is stored as a pair of 3545 * x, y coordinates. 3546 * @param srcOff the offset to the first point to be transformed 3547 * in the source array 3548 * @param dstOff the offset to the location of the first 3549 * transformed point that is stored in the destination array 3550 * @param numPts the number of point objects to be transformed 3551 * @exception NoninvertibleTransformException if the matrix cannot be 3552 * inverted. 3553 * @since 1.2 3554 */ inverseTransform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, int numPts)3555 public void inverseTransform(double[] srcPts, int srcOff, 3556 double[] dstPts, int dstOff, 3557 int numPts) 3558 throws NoninvertibleTransformException 3559 { 3560 double M00, M01, M02, M10, M11, M12; // For caching 3561 double det; 3562 if (dstPts == srcPts && 3563 dstOff > srcOff && dstOff < srcOff + numPts * 2) 3564 { 3565 // If the arrays overlap partially with the destination higher 3566 // than the source and we transform the coordinates normally 3567 // we would overwrite some of the later source coordinates 3568 // with results of previous transformations. 3569 // To get around this we use arraycopy to copy the points 3570 // to their final destination with correct overwrite 3571 // handling and then transform them in place in the new 3572 // safer location. 3573 System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts * 2); 3574 // srcPts = dstPts; // They are known to be equal. 3575 srcOff = dstOff; 3576 } 3577 switch (state) { 3578 default: 3579 stateError(); 3580 /* NOTREACHED */ 3581 return; 3582 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 3583 M00 = m00; M01 = m01; M02 = m02; 3584 M10 = m10; M11 = m11; M12 = m12; 3585 det = M00 * M11 - M01 * M10; 3586 if (Math.abs(det) <= Double.MIN_VALUE) { 3587 throw new NoninvertibleTransformException("Determinant is "+ 3588 det); 3589 } 3590 while (--numPts >= 0) { 3591 double x = srcPts[srcOff++] - M02; 3592 double y = srcPts[srcOff++] - M12; 3593 dstPts[dstOff++] = (x * M11 - y * M01) / det; 3594 dstPts[dstOff++] = (y * M00 - x * M10) / det; 3595 } 3596 return; 3597 case (APPLY_SHEAR | APPLY_SCALE): 3598 M00 = m00; M01 = m01; 3599 M10 = m10; M11 = m11; 3600 det = M00 * M11 - M01 * M10; 3601 if (Math.abs(det) <= Double.MIN_VALUE) { 3602 throw new NoninvertibleTransformException("Determinant is "+ 3603 det); 3604 } 3605 while (--numPts >= 0) { 3606 double x = srcPts[srcOff++]; 3607 double y = srcPts[srcOff++]; 3608 dstPts[dstOff++] = (x * M11 - y * M01) / det; 3609 dstPts[dstOff++] = (y * M00 - x * M10) / det; 3610 } 3611 return; 3612 case (APPLY_SHEAR | APPLY_TRANSLATE): 3613 M01 = m01; M02 = m02; 3614 M10 = m10; M12 = m12; 3615 if (M01 == 0.0 || M10 == 0.0) { 3616 throw new NoninvertibleTransformException("Determinant is 0"); 3617 } 3618 while (--numPts >= 0) { 3619 double x = srcPts[srcOff++] - M02; 3620 dstPts[dstOff++] = (srcPts[srcOff++] - M12) / M10; 3621 dstPts[dstOff++] = x / M01; 3622 } 3623 return; 3624 case (APPLY_SHEAR): 3625 M01 = m01; M10 = m10; 3626 if (M01 == 0.0 || M10 == 0.0) { 3627 throw new NoninvertibleTransformException("Determinant is 0"); 3628 } 3629 while (--numPts >= 0) { 3630 double x = srcPts[srcOff++]; 3631 dstPts[dstOff++] = srcPts[srcOff++] / M10; 3632 dstPts[dstOff++] = x / M01; 3633 } 3634 return; 3635 case (APPLY_SCALE | APPLY_TRANSLATE): 3636 M00 = m00; M02 = m02; 3637 M11 = m11; M12 = m12; 3638 if (M00 == 0.0 || M11 == 0.0) { 3639 throw new NoninvertibleTransformException("Determinant is 0"); 3640 } 3641 while (--numPts >= 0) { 3642 dstPts[dstOff++] = (srcPts[srcOff++] - M02) / M00; 3643 dstPts[dstOff++] = (srcPts[srcOff++] - M12) / M11; 3644 } 3645 return; 3646 case (APPLY_SCALE): 3647 M00 = m00; M11 = m11; 3648 if (M00 == 0.0 || M11 == 0.0) { 3649 throw new NoninvertibleTransformException("Determinant is 0"); 3650 } 3651 while (--numPts >= 0) { 3652 dstPts[dstOff++] = srcPts[srcOff++] / M00; 3653 dstPts[dstOff++] = srcPts[srcOff++] / M11; 3654 } 3655 return; 3656 case (APPLY_TRANSLATE): 3657 M02 = m02; M12 = m12; 3658 while (--numPts >= 0) { 3659 dstPts[dstOff++] = srcPts[srcOff++] - M02; 3660 dstPts[dstOff++] = srcPts[srcOff++] - M12; 3661 } 3662 return; 3663 case (APPLY_IDENTITY): 3664 if (srcPts != dstPts || srcOff != dstOff) { 3665 System.arraycopy(srcPts, srcOff, dstPts, dstOff, 3666 numPts * 2); 3667 } 3668 return; 3669 } 3670 3671 /* NOTREACHED */ 3672 } 3673 3674 /** 3675 * Transforms the relative distance vector specified by 3676 * {@code ptSrc} and stores the result in {@code ptDst}. 3677 * A relative distance vector is transformed without applying the 3678 * translation components of the affine transformation matrix 3679 * using the following equations: 3680 * <pre> 3681 * [ x' ] [ m00 m01 (m02) ] [ x ] [ m00x + m01y ] 3682 * [ y' ] = [ m10 m11 (m12) ] [ y ] = [ m10x + m11y ] 3683 * [ (1) ] [ (0) (0) ( 1 ) ] [ (1) ] [ (1) ] 3684 * </pre> 3685 * If {@code ptDst} is {@code null}, a new 3686 * {@code Point2D} object is allocated and then the result of the 3687 * transform is stored in this object. 3688 * In either case, {@code ptDst}, which contains the 3689 * transformed point, is returned for convenience. 3690 * If {@code ptSrc} and {@code ptDst} are the same object, 3691 * the input point is correctly overwritten with the transformed 3692 * point. 3693 * @param ptSrc the distance vector to be delta transformed 3694 * @param ptDst the resulting transformed distance vector 3695 * @return {@code ptDst}, which contains the result of the 3696 * transformation. 3697 * @since 1.2 3698 */ deltaTransform(Point2D ptSrc, Point2D ptDst)3699 public Point2D deltaTransform(Point2D ptSrc, Point2D ptDst) { 3700 if (ptDst == null) { 3701 if (ptSrc instanceof Point2D.Double) { 3702 ptDst = new Point2D.Double(); 3703 } else { 3704 ptDst = new Point2D.Float(); 3705 } 3706 } 3707 // Copy source coords into local variables in case src == dst 3708 double x = ptSrc.getX(); 3709 double y = ptSrc.getY(); 3710 switch (state) { 3711 default: 3712 stateError(); 3713 /* NOTREACHED */ 3714 return null; 3715 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 3716 case (APPLY_SHEAR | APPLY_SCALE): 3717 ptDst.setLocation(x * m00 + y * m01, x * m10 + y * m11); 3718 return ptDst; 3719 case (APPLY_SHEAR | APPLY_TRANSLATE): 3720 case (APPLY_SHEAR): 3721 ptDst.setLocation(y * m01, x * m10); 3722 return ptDst; 3723 case (APPLY_SCALE | APPLY_TRANSLATE): 3724 case (APPLY_SCALE): 3725 ptDst.setLocation(x * m00, y * m11); 3726 return ptDst; 3727 case (APPLY_TRANSLATE): 3728 case (APPLY_IDENTITY): 3729 ptDst.setLocation(x, y); 3730 return ptDst; 3731 } 3732 3733 /* NOTREACHED */ 3734 } 3735 3736 /** 3737 * Transforms an array of relative distance vectors by this 3738 * transform. 3739 * A relative distance vector is transformed without applying the 3740 * translation components of the affine transformation matrix 3741 * using the following equations: 3742 * <pre> 3743 * [ x' ] [ m00 m01 (m02) ] [ x ] [ m00x + m01y ] 3744 * [ y' ] = [ m10 m11 (m12) ] [ y ] = [ m10x + m11y ] 3745 * [ (1) ] [ (0) (0) ( 1 ) ] [ (1) ] [ (1) ] 3746 * </pre> 3747 * The two coordinate array sections can be exactly the same or 3748 * can be overlapping sections of the same array without affecting the 3749 * validity of the results. 3750 * This method ensures that no source coordinates are 3751 * overwritten by a previous operation before they can be transformed. 3752 * The coordinates are stored in the arrays starting at the indicated 3753 * offset in the order {@code [x0, y0, x1, y1, ..., xn, yn]}. 3754 * @param srcPts the array containing the source distance vectors. 3755 * Each vector is stored as a pair of relative x, y coordinates. 3756 * @param dstPts the array into which the transformed distance vectors 3757 * are returned. Each vector is stored as a pair of relative 3758 * x, y coordinates. 3759 * @param srcOff the offset to the first vector to be transformed 3760 * in the source array 3761 * @param dstOff the offset to the location of the first 3762 * transformed vector that is stored in the destination array 3763 * @param numPts the number of vector coordinate pairs to be 3764 * transformed 3765 * @since 1.2 3766 */ deltaTransform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, int numPts)3767 public void deltaTransform(double[] srcPts, int srcOff, 3768 double[] dstPts, int dstOff, 3769 int numPts) { 3770 double M00, M01, M10, M11; // For caching 3771 if (dstPts == srcPts && 3772 dstOff > srcOff && dstOff < srcOff + numPts * 2) 3773 { 3774 // If the arrays overlap partially with the destination higher 3775 // than the source and we transform the coordinates normally 3776 // we would overwrite some of the later source coordinates 3777 // with results of previous transformations. 3778 // To get around this we use arraycopy to copy the points 3779 // to their final destination with correct overwrite 3780 // handling and then transform them in place in the new 3781 // safer location. 3782 System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts * 2); 3783 // srcPts = dstPts; // They are known to be equal. 3784 srcOff = dstOff; 3785 } 3786 switch (state) { 3787 default: 3788 stateError(); 3789 /* NOTREACHED */ 3790 return; 3791 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 3792 case (APPLY_SHEAR | APPLY_SCALE): 3793 M00 = m00; M01 = m01; 3794 M10 = m10; M11 = m11; 3795 while (--numPts >= 0) { 3796 double x = srcPts[srcOff++]; 3797 double y = srcPts[srcOff++]; 3798 dstPts[dstOff++] = x * M00 + y * M01; 3799 dstPts[dstOff++] = x * M10 + y * M11; 3800 } 3801 return; 3802 case (APPLY_SHEAR | APPLY_TRANSLATE): 3803 case (APPLY_SHEAR): 3804 M01 = m01; M10 = m10; 3805 while (--numPts >= 0) { 3806 double x = srcPts[srcOff++]; 3807 dstPts[dstOff++] = srcPts[srcOff++] * M01; 3808 dstPts[dstOff++] = x * M10; 3809 } 3810 return; 3811 case (APPLY_SCALE | APPLY_TRANSLATE): 3812 case (APPLY_SCALE): 3813 M00 = m00; M11 = m11; 3814 while (--numPts >= 0) { 3815 dstPts[dstOff++] = srcPts[srcOff++] * M00; 3816 dstPts[dstOff++] = srcPts[srcOff++] * M11; 3817 } 3818 return; 3819 case (APPLY_TRANSLATE): 3820 case (APPLY_IDENTITY): 3821 if (srcPts != dstPts || srcOff != dstOff) { 3822 System.arraycopy(srcPts, srcOff, dstPts, dstOff, 3823 numPts * 2); 3824 } 3825 return; 3826 } 3827 3828 /* NOTREACHED */ 3829 } 3830 3831 /** 3832 * Returns a new {@link Shape} object defined by the geometry of the 3833 * specified {@code Shape} after it has been transformed by 3834 * this transform. 3835 * @param pSrc the specified {@code Shape} object to be 3836 * transformed by this transform. 3837 * @return a new {@code Shape} object that defines the geometry 3838 * of the transformed {@code Shape}, or null if {@code pSrc} is null. 3839 * @since 1.2 3840 */ createTransformedShape(Shape pSrc)3841 public Shape createTransformedShape(Shape pSrc) { 3842 if (pSrc == null) { 3843 return null; 3844 } 3845 return new Path2D.Double(pSrc, this); 3846 } 3847 3848 // Round values to sane precision for printing 3849 // Note that Math.sin(Math.PI) has an error of about 10^-16 _matround(double matval)3850 private static double _matround(double matval) { 3851 return Math.rint(matval * 1E15) / 1E15; 3852 } 3853 3854 /** 3855 * Returns a {@code String} that represents the value of this 3856 * {@link Object}. 3857 * @return a {@code String} representing the value of this 3858 * {@code Object}. 3859 * @since 1.2 3860 */ toString()3861 public String toString() { 3862 return ("AffineTransform[[" 3863 + _matround(m00) + ", " 3864 + _matround(m01) + ", " 3865 + _matround(m02) + "], [" 3866 + _matround(m10) + ", " 3867 + _matround(m11) + ", " 3868 + _matround(m12) + "]]"); 3869 } 3870 3871 /** 3872 * Returns {@code true} if this {@code AffineTransform} is 3873 * an identity transform. 3874 * @return {@code true} if this {@code AffineTransform} is 3875 * an identity transform; {@code false} otherwise. 3876 * @since 1.2 3877 */ isIdentity()3878 public boolean isIdentity() { 3879 return (state == APPLY_IDENTITY || (getType() == TYPE_IDENTITY)); 3880 } 3881 3882 /** 3883 * Returns a copy of this {@code AffineTransform} object. 3884 * @return an {@code Object} that is a copy of this 3885 * {@code AffineTransform} object. 3886 * @since 1.2 3887 */ clone()3888 public Object clone() { 3889 try { 3890 return super.clone(); 3891 } catch (CloneNotSupportedException e) { 3892 // this shouldn't happen, since we are Cloneable 3893 throw new InternalError(e); 3894 } 3895 } 3896 3897 /** 3898 * Returns the hashcode for this transform. 3899 * @return a hash code for this transform. 3900 * @since 1.2 3901 */ hashCode()3902 public int hashCode() { 3903 long bits = Double.doubleToLongBits(m00); 3904 bits = bits * 31 + Double.doubleToLongBits(m01); 3905 bits = bits * 31 + Double.doubleToLongBits(m02); 3906 bits = bits * 31 + Double.doubleToLongBits(m10); 3907 bits = bits * 31 + Double.doubleToLongBits(m11); 3908 bits = bits * 31 + Double.doubleToLongBits(m12); 3909 return (((int) bits) ^ ((int) (bits >> 32))); 3910 } 3911 3912 /** 3913 * Returns {@code true} if this {@code AffineTransform} 3914 * represents the same affine coordinate transform as the specified 3915 * argument. 3916 * @param obj the {@code Object} to test for equality with this 3917 * {@code AffineTransform} 3918 * @return {@code true} if {@code obj} equals this 3919 * {@code AffineTransform} object; {@code false} otherwise. 3920 * @since 1.2 3921 */ equals(Object obj)3922 public boolean equals(Object obj) { 3923 if (!(obj instanceof AffineTransform)) { 3924 return false; 3925 } 3926 3927 AffineTransform a = (AffineTransform)obj; 3928 3929 return ((m00 == a.m00) && (m01 == a.m01) && (m02 == a.m02) && 3930 (m10 == a.m10) && (m11 == a.m11) && (m12 == a.m12)); 3931 } 3932 3933 /* Serialization support. A readObject method is neccessary because 3934 * the state field is part of the implementation of this particular 3935 * AffineTransform and not part of the public specification. The 3936 * state variable's value needs to be recalculated on the fly by the 3937 * readObject method as it is in the 6-argument matrix constructor. 3938 */ 3939 3940 /* 3941 * JDK 1.2 serialVersionUID 3942 */ 3943 private static final long serialVersionUID = 1330973210523860834L; 3944 writeObject(java.io.ObjectOutputStream s)3945 private void writeObject(java.io.ObjectOutputStream s) 3946 throws java.lang.ClassNotFoundException, java.io.IOException 3947 { 3948 s.defaultWriteObject(); 3949 } 3950 readObject(java.io.ObjectInputStream s)3951 private void readObject(java.io.ObjectInputStream s) 3952 throws java.lang.ClassNotFoundException, java.io.IOException 3953 { 3954 s.defaultReadObject(); 3955 updateState(); 3956 } 3957 } 3958