1 /* 2 * Copyright (c) 1996, 2013, 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</code> class represents a 2D affine transform 33 * that performs a linear mapping from 2D coordinates to other 2D 34 * coordinates that preserves the "straightness" and 35 * "parallelness" of lines. Affine transformations can be constructed 36 * using sequences of translations, scales, flips, rotations, and shears. 37 * <p> 38 * Such a coordinate transformation can be represented by a 3 row by 39 * 3 column matrix with an implied last row of [ 0 0 1 ]. This matrix 40 * transforms source coordinates {@code (x,y)} into 41 * destination coordinates {@code (x',y')} by considering 42 * them to be a column vector and multiplying the coordinate vector 43 * by the matrix according to the following process: 44 * <pre> 45 * [ x'] [ m00 m01 m02 ] [ x ] [ m00x + m01y + m02 ] 46 * [ y'] = [ m10 m11 m12 ] [ y ] = [ m10x + m11y + m12 ] 47 * [ 1 ] [ 0 0 1 ] [ 1 ] [ 1 ] 48 * </pre> 49 * <h3><a name="quadrantapproximation">Handling 90-Degree Rotations</a></h3> 50 * <p> 51 * In some variations of the <code>rotate</code> methods in the 52 * <code>AffineTransform</code> class, a double-precision argument 53 * specifies the angle of rotation in radians. 54 * These methods have special handling for rotations of approximately 55 * 90 degrees (including multiples such as 180, 270, and 360 degrees), 56 * so that the common case of quadrant rotation is handled more 57 * efficiently. 58 * This special handling can cause angles very close to multiples of 59 * 90 degrees to be treated as if they were exact multiples of 60 * 90 degrees. 61 * For small multiples of 90 degrees the range of angles treated 62 * as a quadrant rotation is approximately 0.00000121 degrees wide. 63 * This section explains why such special care is needed and how 64 * it is implemented. 65 * <p> 66 * Since 90 degrees is represented as <code>PI/2</code> in radians, 67 * and since PI is a transcendental (and therefore irrational) number, 68 * it is not possible to exactly represent a multiple of 90 degrees as 69 * an exact double precision value measured in radians. 70 * As a result it is theoretically impossible to describe quadrant 71 * rotations (90, 180, 270 or 360 degrees) using these values. 72 * Double precision floating point values can get very close to 73 * non-zero multiples of <code>PI/2</code> but never close enough 74 * for the sine or cosine to be exactly 0.0, 1.0 or -1.0. 75 * The implementations of <code>Math.sin()</code> and 76 * <code>Math.cos()</code> correspondingly never return 0.0 77 * for any case other than <code>Math.sin(0.0)</code>. 78 * These same implementations do, however, return exactly 1.0 and 79 * -1.0 for some range of numbers around each multiple of 90 80 * degrees since the correct answer is so close to 1.0 or -1.0 that 81 * the double precision significand cannot represent the difference 82 * as accurately as it can for numbers that are near 0.0. 83 * <p> 84 * The net result of these issues is that if the 85 * <code>Math.sin()</code> and <code>Math.cos()</code> methods 86 * are used to directly generate the values for the matrix modifications 87 * during these radian-based rotation operations then the resulting 88 * transform is never strictly classifiable as a quadrant rotation 89 * even for a simple case like <code>rotate(Math.PI/2.0)</code>, 90 * due to minor variations in the matrix caused by the non-0.0 values 91 * obtained for the sine and cosine. 92 * If these transforms are not classified as quadrant rotations then 93 * subsequent code which attempts to optimize further operations based 94 * upon the type of the transform will be relegated to its most general 95 * implementation. 96 * <p> 97 * Because quadrant rotations are fairly common, 98 * this class should handle these cases reasonably quickly, both in 99 * applying the rotations to the transform and in applying the resulting 100 * transform to the coordinates. 101 * To facilitate this optimal handling, the methods which take an angle 102 * of rotation measured in radians attempt to detect angles that are 103 * intended to be quadrant rotations and treat them as such. 104 * These methods therefore treat an angle <em>theta</em> as a quadrant 105 * rotation if either <code>Math.sin(<em>theta</em>)</code> or 106 * <code>Math.cos(<em>theta</em>)</code> returns exactly 1.0 or -1.0. 107 * As a rule of thumb, this property holds true for a range of 108 * approximately 0.0000000211 radians (or 0.00000121 degrees) around 109 * small multiples of <code>Math.PI/2.0</code>. 110 * 111 * @author Jim Graham 112 * @since 1.2 113 */ 114 public class AffineTransform implements Cloneable, java.io.Serializable { 115 116 /* 117 * This constant is only useful for the cached type field. 118 * It indicates that the type has been decached and must be recalculated. 119 */ 120 private static final int TYPE_UNKNOWN = -1; 121 122 /** 123 * This constant indicates that the transform defined by this object 124 * is an identity transform. 125 * An identity transform is one in which the output coordinates are 126 * always the same as the input coordinates. 127 * If this transform is anything other than the identity transform, 128 * the type will either be the constant GENERAL_TRANSFORM or a 129 * combination of the appropriate flag bits for the various coordinate 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</code> 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</code> that is a copy of 483 * the specified <code>AffineTransform</code> object. 484 * @param Tx the <code>AffineTransform</code> object to copy 485 * @since 1.2 486 */ 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</code> from 6 floating point 500 * values representing the 6 specifiable entries of the 3x3 501 * transformation matrix. 502 * 503 * @param m00 the X coordinate scaling element of the 3x3 matrix 504 * @param m10 the Y coordinate shearing element of the 3x3 matrix 505 * @param m01 the X coordinate shearing element of the 3x3 matrix 506 * @param m11 the Y coordinate scaling element of the 3x3 matrix 507 * @param m02 the X coordinate translation element of the 3x3 matrix 508 * @param m12 the Y coordinate translation element of the 3x3 matrix 509 * @since 1.2 510 */ 511 @ConstructorProperties({ "scaleX", "shearY", "shearX", "scaleY", "translateX", "translateY" }) 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</code> from an array of 526 * floating point values representing either the 4 non-translation 527 * entries or the 6 specifiable entries of the 3x3 transformation 528 * matrix. The values are retrieved from the array as 529 * { m00 m10 m01 m11 [m02 m12]}. 530 * @param flatmatrix the float array containing the values to be set 531 * in the new <code>AffineTransform</code> object. The length of the 532 * array is assumed to be at least 4. If the length of the array is 533 * less than 6, only the first 4 values are taken. If the length of 534 * the array is greater than 6, the first 6 values are taken. 535 * @since 1.2 536 */ 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</code> from 6 double 551 * precision values representing the 6 specifiable entries of the 3x3 552 * transformation matrix. 553 * 554 * @param m00 the X coordinate scaling element of the 3x3 matrix 555 * @param m10 the Y coordinate shearing element of the 3x3 matrix 556 * @param m01 the X coordinate shearing element of the 3x3 matrix 557 * @param m11 the Y coordinate scaling element of the 3x3 matrix 558 * @param m02 the X coordinate translation element of the 3x3 matrix 559 * @param m12 the Y coordinate translation element of the 3x3 matrix 560 * @since 1.2 561 */ 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</code> from an array of 576 * double precision values representing either the 4 non-translation 577 * entries or the 6 specifiable entries of the 3x3 transformation 578 * matrix. The values are retrieved from the array as 579 * { m00 m10 m01 m11 [m02 m12]}. 580 * @param flatmatrix the double array containing the values to be set 581 * in the new <code>AffineTransform</code> object. The length of the 582 * array is assumed to be at least 4. If the length of the array is 583 * less than 6, only the first 4 values are taken. If the length of 584 * the array is greater than 6, the first 6 values are taken. 585 * @since 1.2 586 */ 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</code> 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</code> 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</code> 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</code> and <code>vecy</code> are 0.0, 697 * an identity transform is returned. 698 * This operation is equivalent to calling: 699 * <pre> 700 * AffineTransform.getRotateInstance(Math.atan2(vecy, vecx)); 701 * </pre> 702 * 703 * @param vecx the X coordinate of the rotation vector 704 * @param vecy the Y coordinate of the rotation vector 705 * @return an <code>AffineTransform</code> object that rotates 706 * coordinates according to the specified rotation vector. 707 * @since 1.6 708 */ 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</code> and <code>vecy</code> are 0.0, 724 * an identity transform is returned. 725 * This operation is equivalent to calling: 726 * <pre> 727 * AffineTransform.getRotateInstance(Math.atan2(vecy, vecx), 728 * anchorx, anchory); 729 * </pre> 730 * 731 * @param vecx the X coordinate of the rotation vector 732 * @param vecy the Y coordinate of the rotation vector 733 * @param anchorx the X coordinate of the rotation anchor point 734 * @param anchory the Y coordinate of the rotation anchor point 735 * @return an <code>AffineTransform</code> object that rotates 736 * coordinates around the specified point according to the 737 * specified rotation vector. 738 * @since 1.6 739 */ 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</code> 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</code> 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</code> 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</code> 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</code> method then the determinant also 1019 * represents the square of the uniform scale factor by which all of 1020 * the points are expanded from or contracted towards the origin. 1021 * If this transform represents a non-uniform scale or more general 1022 * transform then the determinant is not likely to represent a 1023 * value useful for any purpose other than determining if inverse 1024 * transforms are possible. 1025 * <p> 1026 * Mathematically, the determinant is calculated using the formula: 1027 * <pre> 1028 * | m00 m01 m02 | 1029 * | m10 m11 m12 | = m00 * m11 - m01 * m10 1030 * | 0 0 1 | 1031 * </pre> 1032 * 1033 * @return the determinant of the matrix used to transform the 1034 * coordinates. 1035 * @see #getType 1036 * @see #createInverse 1037 * @see #inverseTransform 1038 * @see #TYPE_UNIFORM_SCALE 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 X coordinate scaling element (m00) of the 3x3 1164 * affine transformation matrix. 1165 * @return a double value that is the X coordinate of the scaling 1166 * element of the affine transformation matrix. 1167 * @see #getMatrix 1168 * @since 1.2 1169 */ getScaleX()1170 public double getScaleX() { 1171 return m00; 1172 } 1173 1174 /** 1175 * Returns the Y coordinate scaling element (m11) of the 3x3 1176 * affine transformation matrix. 1177 * @return a double value that is the Y coordinate of the scaling 1178 * element of the affine transformation matrix. 1179 * @see #getMatrix 1180 * @since 1.2 1181 */ getScaleY()1182 public double getScaleY() { 1183 return m11; 1184 } 1185 1186 /** 1187 * Returns the X coordinate shearing element (m01) of the 3x3 1188 * affine transformation matrix. 1189 * @return a double value that is the X coordinate of the shearing 1190 * element of the affine transformation matrix. 1191 * @see #getMatrix 1192 * @since 1.2 1193 */ getShearX()1194 public double getShearX() { 1195 return m01; 1196 } 1197 1198 /** 1199 * Returns the Y coordinate shearing element (m10) of the 3x3 1200 * affine transformation matrix. 1201 * @return a double value that is the Y coordinate of the shearing 1202 * element of the affine transformation matrix. 1203 * @see #getMatrix 1204 * @since 1.2 1205 */ getShearY()1206 public double getShearY() { 1207 return m10; 1208 } 1209 1210 /** 1211 * Returns the X coordinate of the translation element (m02) of the 1212 * 3x3 affine transformation matrix. 1213 * @return a double value that is the X coordinate of the translation 1214 * element of the affine transformation matrix. 1215 * @see #getMatrix 1216 * @since 1.2 1217 */ getTranslateX()1218 public double getTranslateX() { 1219 return m02; 1220 } 1221 1222 /** 1223 * Returns the Y coordinate of the translation element (m12) of the 1224 * 3x3 affine transformation matrix. 1225 * @return a double value that is the Y coordinate of the translation 1226 * element of the affine transformation matrix. 1227 * @see #getMatrix 1228 * @since 1.2 1229 */ getTranslateY()1230 public double getTranslateY() { 1231 return m12; 1232 } 1233 1234 /** 1235 * Concatenates this transform with a translation transformation. 1236 * This is equivalent to calling concatenate(T), where T is an 1237 * <code>AffineTransform</code> represented by the following matrix: 1238 * <pre> 1239 * [ 1 0 tx ] 1240 * [ 0 1 ty ] 1241 * [ 0 0 1 ] 1242 * </pre> 1243 * @param tx the distance by which coordinates are translated in the 1244 * X axis direction 1245 * @param ty the distance by which coordinates are translated in the 1246 * Y axis direction 1247 * @since 1.2 1248 */ translate(double tx, double ty)1249 public void translate(double tx, double ty) { 1250 switch (state) { 1251 default: 1252 stateError(); 1253 /* NOTREACHED */ 1254 return; 1255 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 1256 m02 = tx * m00 + ty * m01 + m02; 1257 m12 = tx * m10 + ty * m11 + m12; 1258 if (m02 == 0.0 && m12 == 0.0) { 1259 state = APPLY_SHEAR | APPLY_SCALE; 1260 if (type != TYPE_UNKNOWN) { 1261 type -= TYPE_TRANSLATION; 1262 } 1263 } 1264 return; 1265 case (APPLY_SHEAR | APPLY_SCALE): 1266 m02 = tx * m00 + ty * m01; 1267 m12 = tx * m10 + ty * m11; 1268 if (m02 != 0.0 || m12 != 0.0) { 1269 state = APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE; 1270 type |= TYPE_TRANSLATION; 1271 } 1272 return; 1273 case (APPLY_SHEAR | APPLY_TRANSLATE): 1274 m02 = ty * m01 + m02; 1275 m12 = tx * m10 + m12; 1276 if (m02 == 0.0 && m12 == 0.0) { 1277 state = APPLY_SHEAR; 1278 if (type != TYPE_UNKNOWN) { 1279 type -= TYPE_TRANSLATION; 1280 } 1281 } 1282 return; 1283 case (APPLY_SHEAR): 1284 m02 = ty * m01; 1285 m12 = tx * m10; 1286 if (m02 != 0.0 || m12 != 0.0) { 1287 state = APPLY_SHEAR | APPLY_TRANSLATE; 1288 type |= TYPE_TRANSLATION; 1289 } 1290 return; 1291 case (APPLY_SCALE | APPLY_TRANSLATE): 1292 m02 = tx * m00 + m02; 1293 m12 = ty * m11 + m12; 1294 if (m02 == 0.0 && m12 == 0.0) { 1295 state = APPLY_SCALE; 1296 if (type != TYPE_UNKNOWN) { 1297 type -= TYPE_TRANSLATION; 1298 } 1299 } 1300 return; 1301 case (APPLY_SCALE): 1302 m02 = tx * m00; 1303 m12 = ty * m11; 1304 if (m02 != 0.0 || m12 != 0.0) { 1305 state = APPLY_SCALE | APPLY_TRANSLATE; 1306 type |= TYPE_TRANSLATION; 1307 } 1308 return; 1309 case (APPLY_TRANSLATE): 1310 m02 = tx + m02; 1311 m12 = ty + m12; 1312 if (m02 == 0.0 && m12 == 0.0) { 1313 state = APPLY_IDENTITY; 1314 type = TYPE_IDENTITY; 1315 } 1316 return; 1317 case (APPLY_IDENTITY): 1318 m02 = tx; 1319 m12 = ty; 1320 if (tx != 0.0 || ty != 0.0) { 1321 state = APPLY_TRANSLATE; 1322 type = TYPE_TRANSLATION; 1323 } 1324 return; 1325 } 1326 } 1327 1328 // Utility methods to optimize rotate methods. 1329 // These tables translate the flags during predictable quadrant 1330 // rotations where the shear and scale values are swapped and negated. 1331 private static final int rot90conversion[] = { 1332 /* IDENTITY => */ APPLY_SHEAR, 1333 /* TRANSLATE (TR) => */ APPLY_SHEAR | APPLY_TRANSLATE, 1334 /* SCALE (SC) => */ APPLY_SHEAR, 1335 /* SC | TR => */ APPLY_SHEAR | APPLY_TRANSLATE, 1336 /* SHEAR (SH) => */ APPLY_SCALE, 1337 /* SH | TR => */ APPLY_SCALE | APPLY_TRANSLATE, 1338 /* SH | SC => */ APPLY_SHEAR | APPLY_SCALE, 1339 /* SH | SC | TR => */ APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE, 1340 }; rotate90()1341 private final void rotate90() { 1342 double M0 = m00; 1343 m00 = m01; 1344 m01 = -M0; 1345 M0 = m10; 1346 m10 = m11; 1347 m11 = -M0; 1348 int state = rot90conversion[this.state]; 1349 if ((state & (APPLY_SHEAR | APPLY_SCALE)) == APPLY_SCALE && 1350 m00 == 1.0 && m11 == 1.0) 1351 { 1352 state -= APPLY_SCALE; 1353 } 1354 this.state = state; 1355 type = TYPE_UNKNOWN; 1356 } rotate180()1357 private final void rotate180() { 1358 m00 = -m00; 1359 m11 = -m11; 1360 int state = this.state; 1361 if ((state & (APPLY_SHEAR)) != 0) { 1362 // If there was a shear, then this rotation has no 1363 // effect on the state. 1364 m01 = -m01; 1365 m10 = -m10; 1366 } else { 1367 // No shear means the SCALE state may toggle when 1368 // m00 and m11 are negated. 1369 if (m00 == 1.0 && m11 == 1.0) { 1370 this.state = state & ~APPLY_SCALE; 1371 } else { 1372 this.state = state | APPLY_SCALE; 1373 } 1374 } 1375 type = TYPE_UNKNOWN; 1376 } rotate270()1377 private final void rotate270() { 1378 double M0 = m00; 1379 m00 = -m01; 1380 m01 = M0; 1381 M0 = m10; 1382 m10 = -m11; 1383 m11 = M0; 1384 int state = rot90conversion[this.state]; 1385 if ((state & (APPLY_SHEAR | APPLY_SCALE)) == APPLY_SCALE && 1386 m00 == 1.0 && m11 == 1.0) 1387 { 1388 state -= APPLY_SCALE; 1389 } 1390 this.state = state; 1391 type = TYPE_UNKNOWN; 1392 } 1393 1394 /** 1395 * Concatenates this transform with a rotation transformation. 1396 * This is equivalent to calling concatenate(R), where R is an 1397 * <code>AffineTransform</code> represented by the following matrix: 1398 * <pre> 1399 * [ cos(theta) -sin(theta) 0 ] 1400 * [ sin(theta) cos(theta) 0 ] 1401 * [ 0 0 1 ] 1402 * </pre> 1403 * Rotating by a positive angle theta rotates points on the positive 1404 * X axis toward the positive Y axis. 1405 * Note also the discussion of 1406 * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a> 1407 * above. 1408 * @param theta the angle of rotation measured in radians 1409 * @since 1.2 1410 */ rotate(double theta)1411 public void rotate(double theta) { 1412 double sin = Math.sin(theta); 1413 if (sin == 1.0) { 1414 rotate90(); 1415 } else if (sin == -1.0) { 1416 rotate270(); 1417 } else { 1418 double cos = Math.cos(theta); 1419 if (cos == -1.0) { 1420 rotate180(); 1421 } else if (cos != 1.0) { 1422 double M0, M1; 1423 M0 = m00; 1424 M1 = m01; 1425 m00 = cos * M0 + sin * M1; 1426 m01 = -sin * M0 + cos * M1; 1427 M0 = m10; 1428 M1 = m11; 1429 m10 = cos * M0 + sin * M1; 1430 m11 = -sin * M0 + cos * M1; 1431 updateState(); 1432 } 1433 } 1434 } 1435 1436 /** 1437 * Concatenates this transform with a transform that rotates 1438 * coordinates around an anchor point. 1439 * This operation is equivalent to translating the coordinates so 1440 * that the anchor point is at the origin (S1), then rotating them 1441 * about the new origin (S2), and finally translating so that the 1442 * intermediate origin is restored to the coordinates of the original 1443 * anchor point (S3). 1444 * <p> 1445 * This operation is equivalent to the following sequence of calls: 1446 * <pre> 1447 * translate(anchorx, anchory); // S3: final translation 1448 * rotate(theta); // S2: rotate around anchor 1449 * translate(-anchorx, -anchory); // S1: translate anchor to origin 1450 * </pre> 1451 * Rotating by a positive angle theta rotates points on the positive 1452 * X axis toward the positive Y axis. 1453 * Note also the discussion of 1454 * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a> 1455 * above. 1456 * 1457 * @param theta the angle of rotation measured in radians 1458 * @param anchorx the X coordinate of the rotation anchor point 1459 * @param anchory the Y coordinate of the rotation anchor point 1460 * @since 1.2 1461 */ rotate(double theta, double anchorx, double anchory)1462 public void rotate(double theta, double anchorx, double anchory) { 1463 // REMIND: Simple for now - optimize later 1464 translate(anchorx, anchory); 1465 rotate(theta); 1466 translate(-anchorx, -anchory); 1467 } 1468 1469 /** 1470 * Concatenates this transform with a transform that rotates 1471 * coordinates according to a rotation vector. 1472 * All coordinates rotate about the origin by the same amount. 1473 * The amount of rotation is such that coordinates along the former 1474 * positive X axis will subsequently align with the vector pointing 1475 * from the origin to the specified vector coordinates. 1476 * If both <code>vecx</code> and <code>vecy</code> are 0.0, 1477 * no additional rotation is added to this transform. 1478 * This operation is equivalent to calling: 1479 * <pre> 1480 * rotate(Math.atan2(vecy, vecx)); 1481 * </pre> 1482 * 1483 * @param vecx the X coordinate of the rotation vector 1484 * @param vecy the Y coordinate of the rotation vector 1485 * @since 1.6 1486 */ rotate(double vecx, double vecy)1487 public void rotate(double vecx, double vecy) { 1488 if (vecy == 0.0) { 1489 if (vecx < 0.0) { 1490 rotate180(); 1491 } 1492 // If vecx > 0.0 - no rotation 1493 // If vecx == 0.0 - undefined rotation - treat as no rotation 1494 } else if (vecx == 0.0) { 1495 if (vecy > 0.0) { 1496 rotate90(); 1497 } else { // vecy must be < 0.0 1498 rotate270(); 1499 } 1500 } else { 1501 double len = Math.sqrt(vecx * vecx + vecy * vecy); 1502 double sin = vecy / len; 1503 double cos = vecx / len; 1504 double M0, M1; 1505 M0 = m00; 1506 M1 = m01; 1507 m00 = cos * M0 + sin * M1; 1508 m01 = -sin * M0 + cos * M1; 1509 M0 = m10; 1510 M1 = m11; 1511 m10 = cos * M0 + sin * M1; 1512 m11 = -sin * M0 + cos * M1; 1513 updateState(); 1514 } 1515 } 1516 1517 /** 1518 * Concatenates this transform with a transform that rotates 1519 * coordinates around an anchor point according to a rotation 1520 * vector. 1521 * All coordinates rotate about the specified anchor coordinates 1522 * by the same amount. 1523 * The amount of rotation is such that coordinates along the former 1524 * positive X axis will subsequently align with the vector pointing 1525 * from the origin to the specified vector coordinates. 1526 * If both <code>vecx</code> and <code>vecy</code> are 0.0, 1527 * the transform is not modified in any way. 1528 * This method is equivalent to calling: 1529 * <pre> 1530 * rotate(Math.atan2(vecy, vecx), anchorx, anchory); 1531 * </pre> 1532 * 1533 * @param vecx the X coordinate of the rotation vector 1534 * @param vecy the Y coordinate of the rotation vector 1535 * @param anchorx the X coordinate of the rotation anchor point 1536 * @param anchory the Y coordinate of the rotation anchor point 1537 * @since 1.6 1538 */ rotate(double vecx, double vecy, double anchorx, double anchory)1539 public void rotate(double vecx, double vecy, 1540 double anchorx, double anchory) 1541 { 1542 // REMIND: Simple for now - optimize later 1543 translate(anchorx, anchory); 1544 rotate(vecx, vecy); 1545 translate(-anchorx, -anchory); 1546 } 1547 1548 /** 1549 * Concatenates this transform with a transform that rotates 1550 * coordinates by the specified number of quadrants. 1551 * This is equivalent to calling: 1552 * <pre> 1553 * rotate(numquadrants * Math.PI / 2.0); 1554 * </pre> 1555 * Rotating by a positive number of quadrants rotates points on 1556 * the positive X axis toward the positive Y axis. 1557 * @param numquadrants the number of 90 degree arcs to rotate by 1558 * @since 1.6 1559 */ quadrantRotate(int numquadrants)1560 public void quadrantRotate(int numquadrants) { 1561 switch (numquadrants & 3) { 1562 case 0: 1563 break; 1564 case 1: 1565 rotate90(); 1566 break; 1567 case 2: 1568 rotate180(); 1569 break; 1570 case 3: 1571 rotate270(); 1572 break; 1573 } 1574 } 1575 1576 /** 1577 * Concatenates this transform with a transform that rotates 1578 * coordinates by the specified number of quadrants around 1579 * the specified anchor point. 1580 * This method is equivalent to calling: 1581 * <pre> 1582 * rotate(numquadrants * Math.PI / 2.0, anchorx, anchory); 1583 * </pre> 1584 * Rotating by a positive number of quadrants rotates points on 1585 * the positive X axis toward the positive Y axis. 1586 * 1587 * @param numquadrants the number of 90 degree arcs to rotate by 1588 * @param anchorx the X coordinate of the rotation anchor point 1589 * @param anchory the Y coordinate of the rotation anchor point 1590 * @since 1.6 1591 */ quadrantRotate(int numquadrants, double anchorx, double anchory)1592 public void quadrantRotate(int numquadrants, 1593 double anchorx, double anchory) 1594 { 1595 switch (numquadrants & 3) { 1596 case 0: 1597 return; 1598 case 1: 1599 m02 += anchorx * (m00 - m01) + anchory * (m01 + m00); 1600 m12 += anchorx * (m10 - m11) + anchory * (m11 + m10); 1601 rotate90(); 1602 break; 1603 case 2: 1604 m02 += anchorx * (m00 + m00) + anchory * (m01 + m01); 1605 m12 += anchorx * (m10 + m10) + anchory * (m11 + m11); 1606 rotate180(); 1607 break; 1608 case 3: 1609 m02 += anchorx * (m00 + m01) + anchory * (m01 - m00); 1610 m12 += anchorx * (m10 + m11) + anchory * (m11 - m10); 1611 rotate270(); 1612 break; 1613 } 1614 if (m02 == 0.0 && m12 == 0.0) { 1615 state &= ~APPLY_TRANSLATE; 1616 } else { 1617 state |= APPLY_TRANSLATE; 1618 } 1619 } 1620 1621 /** 1622 * Concatenates this transform with a scaling transformation. 1623 * This is equivalent to calling concatenate(S), where S is an 1624 * <code>AffineTransform</code> represented by the following matrix: 1625 * <pre> 1626 * [ sx 0 0 ] 1627 * [ 0 sy 0 ] 1628 * [ 0 0 1 ] 1629 * </pre> 1630 * @param sx the factor by which coordinates are scaled along the 1631 * X axis direction 1632 * @param sy the factor by which coordinates are scaled along the 1633 * Y axis direction 1634 * @since 1.2 1635 */ 1636 @SuppressWarnings("fallthrough") scale(double sx, double sy)1637 public void scale(double sx, double sy) { 1638 int state = this.state; 1639 switch (state) { 1640 default: 1641 stateError(); 1642 /* NOTREACHED */ 1643 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 1644 case (APPLY_SHEAR | APPLY_SCALE): 1645 m00 *= sx; 1646 m11 *= sy; 1647 /* NOBREAK */ 1648 case (APPLY_SHEAR | APPLY_TRANSLATE): 1649 case (APPLY_SHEAR): 1650 m01 *= sy; 1651 m10 *= sx; 1652 if (m01 == 0 && m10 == 0) { 1653 state &= APPLY_TRANSLATE; 1654 if (m00 == 1.0 && m11 == 1.0) { 1655 this.type = (state == APPLY_IDENTITY 1656 ? TYPE_IDENTITY 1657 : TYPE_TRANSLATION); 1658 } else { 1659 state |= APPLY_SCALE; 1660 this.type = TYPE_UNKNOWN; 1661 } 1662 this.state = state; 1663 } 1664 return; 1665 case (APPLY_SCALE | APPLY_TRANSLATE): 1666 case (APPLY_SCALE): 1667 m00 *= sx; 1668 m11 *= sy; 1669 if (m00 == 1.0 && m11 == 1.0) { 1670 this.state = (state &= APPLY_TRANSLATE); 1671 this.type = (state == APPLY_IDENTITY 1672 ? TYPE_IDENTITY 1673 : TYPE_TRANSLATION); 1674 } else { 1675 this.type = TYPE_UNKNOWN; 1676 } 1677 return; 1678 case (APPLY_TRANSLATE): 1679 case (APPLY_IDENTITY): 1680 m00 = sx; 1681 m11 = sy; 1682 if (sx != 1.0 || sy != 1.0) { 1683 this.state = state | APPLY_SCALE; 1684 this.type = TYPE_UNKNOWN; 1685 } 1686 return; 1687 } 1688 } 1689 1690 /** 1691 * Concatenates this transform with a shearing transformation. 1692 * This is equivalent to calling concatenate(SH), where SH is an 1693 * <code>AffineTransform</code> represented by the following matrix: 1694 * <pre> 1695 * [ 1 shx 0 ] 1696 * [ shy 1 0 ] 1697 * [ 0 0 1 ] 1698 * </pre> 1699 * @param shx the multiplier by which coordinates are shifted in the 1700 * direction of the positive X axis as a factor of their Y coordinate 1701 * @param shy the multiplier by which coordinates are shifted in the 1702 * direction of the positive Y axis as a factor of their X coordinate 1703 * @since 1.2 1704 */ shear(double shx, double shy)1705 public void shear(double shx, double shy) { 1706 int state = this.state; 1707 switch (state) { 1708 default: 1709 stateError(); 1710 /* NOTREACHED */ 1711 return; 1712 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 1713 case (APPLY_SHEAR | APPLY_SCALE): 1714 double M0, M1; 1715 M0 = m00; 1716 M1 = m01; 1717 m00 = M0 + M1 * shy; 1718 m01 = M0 * shx + M1; 1719 1720 M0 = m10; 1721 M1 = m11; 1722 m10 = M0 + M1 * shy; 1723 m11 = M0 * shx + M1; 1724 updateState(); 1725 return; 1726 case (APPLY_SHEAR | APPLY_TRANSLATE): 1727 case (APPLY_SHEAR): 1728 m00 = m01 * shy; 1729 m11 = m10 * shx; 1730 if (m00 != 0.0 || m11 != 0.0) { 1731 this.state = state | APPLY_SCALE; 1732 } 1733 this.type = TYPE_UNKNOWN; 1734 return; 1735 case (APPLY_SCALE | APPLY_TRANSLATE): 1736 case (APPLY_SCALE): 1737 m01 = m00 * shx; 1738 m10 = m11 * shy; 1739 if (m01 != 0.0 || m10 != 0.0) { 1740 this.state = state | APPLY_SHEAR; 1741 } 1742 this.type = TYPE_UNKNOWN; 1743 return; 1744 case (APPLY_TRANSLATE): 1745 case (APPLY_IDENTITY): 1746 m01 = shx; 1747 m10 = shy; 1748 if (m01 != 0.0 || m10 != 0.0) { 1749 this.state = state | APPLY_SCALE | APPLY_SHEAR; 1750 this.type = TYPE_UNKNOWN; 1751 } 1752 return; 1753 } 1754 } 1755 1756 /** 1757 * Resets this transform to the Identity transform. 1758 * @since 1.2 1759 */ setToIdentity()1760 public void setToIdentity() { 1761 m00 = m11 = 1.0; 1762 m10 = m01 = m02 = m12 = 0.0; 1763 state = APPLY_IDENTITY; 1764 type = TYPE_IDENTITY; 1765 } 1766 1767 /** 1768 * Sets this transform to a translation transformation. 1769 * The matrix representing this transform becomes: 1770 * <pre> 1771 * [ 1 0 tx ] 1772 * [ 0 1 ty ] 1773 * [ 0 0 1 ] 1774 * </pre> 1775 * @param tx the distance by which coordinates are translated in the 1776 * X axis direction 1777 * @param ty the distance by which coordinates are translated in the 1778 * Y axis direction 1779 * @since 1.2 1780 */ setToTranslation(double tx, double ty)1781 public void setToTranslation(double tx, double ty) { 1782 m00 = 1.0; 1783 m10 = 0.0; 1784 m01 = 0.0; 1785 m11 = 1.0; 1786 m02 = tx; 1787 m12 = ty; 1788 if (tx != 0.0 || ty != 0.0) { 1789 state = APPLY_TRANSLATE; 1790 type = TYPE_TRANSLATION; 1791 } else { 1792 state = APPLY_IDENTITY; 1793 type = TYPE_IDENTITY; 1794 } 1795 } 1796 1797 /** 1798 * Sets this transform to a rotation transformation. 1799 * The matrix representing this transform becomes: 1800 * <pre> 1801 * [ cos(theta) -sin(theta) 0 ] 1802 * [ sin(theta) cos(theta) 0 ] 1803 * [ 0 0 1 ] 1804 * </pre> 1805 * Rotating by a positive angle theta rotates points on the positive 1806 * X axis toward the positive Y axis. 1807 * Note also the discussion of 1808 * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a> 1809 * above. 1810 * @param theta the angle of rotation measured in radians 1811 * @since 1.2 1812 */ setToRotation(double theta)1813 public void setToRotation(double theta) { 1814 double sin = Math.sin(theta); 1815 double cos; 1816 if (sin == 1.0 || sin == -1.0) { 1817 cos = 0.0; 1818 state = APPLY_SHEAR; 1819 type = TYPE_QUADRANT_ROTATION; 1820 } else { 1821 cos = Math.cos(theta); 1822 if (cos == -1.0) { 1823 sin = 0.0; 1824 state = APPLY_SCALE; 1825 type = TYPE_QUADRANT_ROTATION; 1826 } else if (cos == 1.0) { 1827 sin = 0.0; 1828 state = APPLY_IDENTITY; 1829 type = TYPE_IDENTITY; 1830 } else { 1831 state = APPLY_SHEAR | APPLY_SCALE; 1832 type = TYPE_GENERAL_ROTATION; 1833 } 1834 } 1835 m00 = cos; 1836 m10 = sin; 1837 m01 = -sin; 1838 m11 = cos; 1839 m02 = 0.0; 1840 m12 = 0.0; 1841 } 1842 1843 /** 1844 * Sets this transform to a translated rotation transformation. 1845 * This operation is equivalent to translating the coordinates so 1846 * that the anchor point is at the origin (S1), then rotating them 1847 * about the new origin (S2), and finally translating so that the 1848 * intermediate origin is restored to the coordinates of the original 1849 * anchor point (S3). 1850 * <p> 1851 * This operation is equivalent to the following sequence of calls: 1852 * <pre> 1853 * setToTranslation(anchorx, anchory); // S3: final translation 1854 * rotate(theta); // S2: rotate around anchor 1855 * translate(-anchorx, -anchory); // S1: translate anchor to origin 1856 * </pre> 1857 * The matrix representing this transform becomes: 1858 * <pre> 1859 * [ cos(theta) -sin(theta) x-x*cos+y*sin ] 1860 * [ sin(theta) cos(theta) y-x*sin-y*cos ] 1861 * [ 0 0 1 ] 1862 * </pre> 1863 * Rotating by a positive angle theta rotates points on the positive 1864 * X axis toward the positive Y axis. 1865 * Note also the discussion of 1866 * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a> 1867 * above. 1868 * 1869 * @param theta the angle of rotation measured in radians 1870 * @param anchorx the X coordinate of the rotation anchor point 1871 * @param anchory the Y coordinate of the rotation anchor point 1872 * @since 1.2 1873 */ setToRotation(double theta, double anchorx, double anchory)1874 public void setToRotation(double theta, double anchorx, double anchory) { 1875 setToRotation(theta); 1876 double sin = m10; 1877 double oneMinusCos = 1.0 - m00; 1878 m02 = anchorx * oneMinusCos + anchory * sin; 1879 m12 = anchory * oneMinusCos - anchorx * sin; 1880 if (m02 != 0.0 || m12 != 0.0) { 1881 state |= APPLY_TRANSLATE; 1882 type |= TYPE_TRANSLATION; 1883 } 1884 } 1885 1886 /** 1887 * Sets this transform to a rotation transformation that rotates 1888 * coordinates according to a rotation vector. 1889 * All coordinates rotate about the origin by the same amount. 1890 * The amount of rotation is such that coordinates along the former 1891 * positive X axis will subsequently align with the vector pointing 1892 * from the origin to the specified vector coordinates. 1893 * If both <code>vecx</code> and <code>vecy</code> are 0.0, 1894 * the transform is set to an identity transform. 1895 * This operation is equivalent to calling: 1896 * <pre> 1897 * setToRotation(Math.atan2(vecy, vecx)); 1898 * </pre> 1899 * 1900 * @param vecx the X coordinate of the rotation vector 1901 * @param vecy the Y coordinate of the rotation vector 1902 * @since 1.6 1903 */ setToRotation(double vecx, double vecy)1904 public void setToRotation(double vecx, double vecy) { 1905 double sin, cos; 1906 if (vecy == 0) { 1907 sin = 0.0; 1908 if (vecx < 0.0) { 1909 cos = -1.0; 1910 state = APPLY_SCALE; 1911 type = TYPE_QUADRANT_ROTATION; 1912 } else { 1913 cos = 1.0; 1914 state = APPLY_IDENTITY; 1915 type = TYPE_IDENTITY; 1916 } 1917 } else if (vecx == 0) { 1918 cos = 0.0; 1919 sin = (vecy > 0.0) ? 1.0 : -1.0; 1920 state = APPLY_SHEAR; 1921 type = TYPE_QUADRANT_ROTATION; 1922 } else { 1923 double len = Math.sqrt(vecx * vecx + vecy * vecy); 1924 cos = vecx / len; 1925 sin = vecy / len; 1926 state = APPLY_SHEAR | APPLY_SCALE; 1927 type = TYPE_GENERAL_ROTATION; 1928 } 1929 m00 = cos; 1930 m10 = sin; 1931 m01 = -sin; 1932 m11 = cos; 1933 m02 = 0.0; 1934 m12 = 0.0; 1935 } 1936 1937 /** 1938 * Sets this transform to a rotation transformation that rotates 1939 * coordinates around an anchor point according to a rotation 1940 * vector. 1941 * All coordinates rotate about the specified anchor coordinates 1942 * by the same amount. 1943 * The amount of rotation is such that coordinates along the former 1944 * positive X axis will subsequently align with the vector pointing 1945 * from the origin to the specified vector coordinates. 1946 * If both <code>vecx</code> and <code>vecy</code> are 0.0, 1947 * the transform is set to an identity transform. 1948 * This operation is equivalent to calling: 1949 * <pre> 1950 * setToTranslation(Math.atan2(vecy, vecx), anchorx, anchory); 1951 * </pre> 1952 * 1953 * @param vecx the X coordinate of the rotation vector 1954 * @param vecy the Y coordinate of the rotation vector 1955 * @param anchorx the X coordinate of the rotation anchor point 1956 * @param anchory the Y coordinate of the rotation anchor point 1957 * @since 1.6 1958 */ setToRotation(double vecx, double vecy, double anchorx, double anchory)1959 public void setToRotation(double vecx, double vecy, 1960 double anchorx, double anchory) 1961 { 1962 setToRotation(vecx, vecy); 1963 double sin = m10; 1964 double oneMinusCos = 1.0 - m00; 1965 m02 = anchorx * oneMinusCos + anchory * sin; 1966 m12 = anchory * oneMinusCos - anchorx * sin; 1967 if (m02 != 0.0 || m12 != 0.0) { 1968 state |= APPLY_TRANSLATE; 1969 type |= TYPE_TRANSLATION; 1970 } 1971 } 1972 1973 /** 1974 * Sets this transform to a rotation transformation that rotates 1975 * coordinates by the specified number of quadrants. 1976 * This operation is equivalent to calling: 1977 * <pre> 1978 * setToRotation(numquadrants * Math.PI / 2.0); 1979 * </pre> 1980 * Rotating by a positive number of quadrants rotates points on 1981 * the positive X axis toward the positive Y axis. 1982 * @param numquadrants the number of 90 degree arcs to rotate by 1983 * @since 1.6 1984 */ setToQuadrantRotation(int numquadrants)1985 public void setToQuadrantRotation(int numquadrants) { 1986 switch (numquadrants & 3) { 1987 case 0: 1988 m00 = 1.0; 1989 m10 = 0.0; 1990 m01 = 0.0; 1991 m11 = 1.0; 1992 m02 = 0.0; 1993 m12 = 0.0; 1994 state = APPLY_IDENTITY; 1995 type = TYPE_IDENTITY; 1996 break; 1997 case 1: 1998 m00 = 0.0; 1999 m10 = 1.0; 2000 m01 = -1.0; 2001 m11 = 0.0; 2002 m02 = 0.0; 2003 m12 = 0.0; 2004 state = APPLY_SHEAR; 2005 type = TYPE_QUADRANT_ROTATION; 2006 break; 2007 case 2: 2008 m00 = -1.0; 2009 m10 = 0.0; 2010 m01 = 0.0; 2011 m11 = -1.0; 2012 m02 = 0.0; 2013 m12 = 0.0; 2014 state = APPLY_SCALE; 2015 type = TYPE_QUADRANT_ROTATION; 2016 break; 2017 case 3: 2018 m00 = 0.0; 2019 m10 = -1.0; 2020 m01 = 1.0; 2021 m11 = 0.0; 2022 m02 = 0.0; 2023 m12 = 0.0; 2024 state = APPLY_SHEAR; 2025 type = TYPE_QUADRANT_ROTATION; 2026 break; 2027 } 2028 } 2029 2030 /** 2031 * Sets this transform to a translated rotation transformation 2032 * that rotates coordinates by the specified number of quadrants 2033 * around the specified anchor point. 2034 * This operation is equivalent to calling: 2035 * <pre> 2036 * setToRotation(numquadrants * Math.PI / 2.0, anchorx, anchory); 2037 * </pre> 2038 * Rotating by a positive number of quadrants rotates points on 2039 * the positive X axis toward the positive Y axis. 2040 * 2041 * @param numquadrants the number of 90 degree arcs to rotate by 2042 * @param anchorx the X coordinate of the rotation anchor point 2043 * @param anchory the Y coordinate of the rotation anchor point 2044 * @since 1.6 2045 */ setToQuadrantRotation(int numquadrants, double anchorx, double anchory)2046 public void setToQuadrantRotation(int numquadrants, 2047 double anchorx, double anchory) 2048 { 2049 switch (numquadrants & 3) { 2050 case 0: 2051 m00 = 1.0; 2052 m10 = 0.0; 2053 m01 = 0.0; 2054 m11 = 1.0; 2055 m02 = 0.0; 2056 m12 = 0.0; 2057 state = APPLY_IDENTITY; 2058 type = TYPE_IDENTITY; 2059 break; 2060 case 1: 2061 m00 = 0.0; 2062 m10 = 1.0; 2063 m01 = -1.0; 2064 m11 = 0.0; 2065 m02 = anchorx + anchory; 2066 m12 = anchory - anchorx; 2067 if (m02 == 0.0 && m12 == 0.0) { 2068 state = APPLY_SHEAR; 2069 type = TYPE_QUADRANT_ROTATION; 2070 } else { 2071 state = APPLY_SHEAR | APPLY_TRANSLATE; 2072 type = TYPE_QUADRANT_ROTATION | TYPE_TRANSLATION; 2073 } 2074 break; 2075 case 2: 2076 m00 = -1.0; 2077 m10 = 0.0; 2078 m01 = 0.0; 2079 m11 = -1.0; 2080 m02 = anchorx + anchorx; 2081 m12 = anchory + anchory; 2082 if (m02 == 0.0 && m12 == 0.0) { 2083 state = APPLY_SCALE; 2084 type = TYPE_QUADRANT_ROTATION; 2085 } else { 2086 state = APPLY_SCALE | APPLY_TRANSLATE; 2087 type = TYPE_QUADRANT_ROTATION | TYPE_TRANSLATION; 2088 } 2089 break; 2090 case 3: 2091 m00 = 0.0; 2092 m10 = -1.0; 2093 m01 = 1.0; 2094 m11 = 0.0; 2095 m02 = anchorx - anchory; 2096 m12 = anchory + anchorx; 2097 if (m02 == 0.0 && m12 == 0.0) { 2098 state = APPLY_SHEAR; 2099 type = TYPE_QUADRANT_ROTATION; 2100 } else { 2101 state = APPLY_SHEAR | APPLY_TRANSLATE; 2102 type = TYPE_QUADRANT_ROTATION | TYPE_TRANSLATION; 2103 } 2104 break; 2105 } 2106 } 2107 2108 /** 2109 * Sets this transform to a scaling transformation. 2110 * The matrix representing this transform becomes: 2111 * <pre> 2112 * [ sx 0 0 ] 2113 * [ 0 sy 0 ] 2114 * [ 0 0 1 ] 2115 * </pre> 2116 * @param sx the factor by which coordinates are scaled along the 2117 * X axis direction 2118 * @param sy the factor by which coordinates are scaled along the 2119 * Y axis direction 2120 * @since 1.2 2121 */ setToScale(double sx, double sy)2122 public void setToScale(double sx, double sy) { 2123 m00 = sx; 2124 m10 = 0.0; 2125 m01 = 0.0; 2126 m11 = sy; 2127 m02 = 0.0; 2128 m12 = 0.0; 2129 if (sx != 1.0 || sy != 1.0) { 2130 state = APPLY_SCALE; 2131 type = TYPE_UNKNOWN; 2132 } else { 2133 state = APPLY_IDENTITY; 2134 type = TYPE_IDENTITY; 2135 } 2136 } 2137 2138 /** 2139 * Sets this transform to a shearing transformation. 2140 * The matrix representing this transform becomes: 2141 * <pre> 2142 * [ 1 shx 0 ] 2143 * [ shy 1 0 ] 2144 * [ 0 0 1 ] 2145 * </pre> 2146 * @param shx the multiplier by which coordinates are shifted in the 2147 * direction of the positive X axis as a factor of their Y coordinate 2148 * @param shy the multiplier by which coordinates are shifted in the 2149 * direction of the positive Y axis as a factor of their X coordinate 2150 * @since 1.2 2151 */ setToShear(double shx, double shy)2152 public void setToShear(double shx, double shy) { 2153 m00 = 1.0; 2154 m01 = shx; 2155 m10 = shy; 2156 m11 = 1.0; 2157 m02 = 0.0; 2158 m12 = 0.0; 2159 if (shx != 0.0 || shy != 0.0) { 2160 state = (APPLY_SHEAR | APPLY_SCALE); 2161 type = TYPE_UNKNOWN; 2162 } else { 2163 state = APPLY_IDENTITY; 2164 type = TYPE_IDENTITY; 2165 } 2166 } 2167 2168 /** 2169 * Sets this transform to a copy of the transform in the specified 2170 * <code>AffineTransform</code> object. 2171 * @param Tx the <code>AffineTransform</code> object from which to 2172 * copy the transform 2173 * @since 1.2 2174 */ setTransform(AffineTransform Tx)2175 public void setTransform(AffineTransform Tx) { 2176 this.m00 = Tx.m00; 2177 this.m10 = Tx.m10; 2178 this.m01 = Tx.m01; 2179 this.m11 = Tx.m11; 2180 this.m02 = Tx.m02; 2181 this.m12 = Tx.m12; 2182 this.state = Tx.state; 2183 this.type = Tx.type; 2184 } 2185 2186 /** 2187 * Sets this transform to the matrix specified by the 6 2188 * double precision values. 2189 * 2190 * @param m00 the X coordinate scaling element of the 3x3 matrix 2191 * @param m10 the Y coordinate shearing element of the 3x3 matrix 2192 * @param m01 the X coordinate shearing element of the 3x3 matrix 2193 * @param m11 the Y coordinate scaling element of the 3x3 matrix 2194 * @param m02 the X coordinate translation element of the 3x3 matrix 2195 * @param m12 the Y coordinate translation element of the 3x3 matrix 2196 * @since 1.2 2197 */ setTransform(double m00, double m10, double m01, double m11, double m02, double m12)2198 public void setTransform(double m00, double m10, 2199 double m01, double m11, 2200 double m02, double m12) { 2201 this.m00 = m00; 2202 this.m10 = m10; 2203 this.m01 = m01; 2204 this.m11 = m11; 2205 this.m02 = m02; 2206 this.m12 = m12; 2207 updateState(); 2208 } 2209 2210 /** 2211 * Concatenates an <code>AffineTransform</code> <code>Tx</code> to 2212 * this <code>AffineTransform</code> Cx in the most commonly useful 2213 * way to provide a new user space 2214 * that is mapped to the former user space by <code>Tx</code>. 2215 * Cx is updated to perform the combined transformation. 2216 * Transforming a point p by the updated transform Cx' is 2217 * equivalent to first transforming p by <code>Tx</code> and then 2218 * transforming the result by the original transform Cx like this: 2219 * Cx'(p) = Cx(Tx(p)) 2220 * In matrix notation, if this transform Cx is 2221 * represented by the matrix [this] and <code>Tx</code> is represented 2222 * by the matrix [Tx] then this method does the following: 2223 * <pre> 2224 * [this] = [this] x [Tx] 2225 * </pre> 2226 * @param Tx the <code>AffineTransform</code> object to be 2227 * concatenated with this <code>AffineTransform</code> object. 2228 * @see #preConcatenate 2229 * @since 1.2 2230 */ 2231 @SuppressWarnings("fallthrough") concatenate(AffineTransform Tx)2232 public void concatenate(AffineTransform Tx) { 2233 double M0, M1; 2234 double T00, T01, T10, T11; 2235 double T02, T12; 2236 int mystate = state; 2237 int txstate = Tx.state; 2238 switch ((txstate << HI_SHIFT) | mystate) { 2239 2240 /* ---------- Tx == IDENTITY cases ---------- */ 2241 case (HI_IDENTITY | APPLY_IDENTITY): 2242 case (HI_IDENTITY | APPLY_TRANSLATE): 2243 case (HI_IDENTITY | APPLY_SCALE): 2244 case (HI_IDENTITY | APPLY_SCALE | APPLY_TRANSLATE): 2245 case (HI_IDENTITY | APPLY_SHEAR): 2246 case (HI_IDENTITY | APPLY_SHEAR | APPLY_TRANSLATE): 2247 case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE): 2248 case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2249 return; 2250 2251 /* ---------- this == IDENTITY cases ---------- */ 2252 case (HI_SHEAR | HI_SCALE | HI_TRANSLATE | APPLY_IDENTITY): 2253 m01 = Tx.m01; 2254 m10 = Tx.m10; 2255 /* NOBREAK */ 2256 case (HI_SCALE | HI_TRANSLATE | APPLY_IDENTITY): 2257 m00 = Tx.m00; 2258 m11 = Tx.m11; 2259 /* NOBREAK */ 2260 case (HI_TRANSLATE | APPLY_IDENTITY): 2261 m02 = Tx.m02; 2262 m12 = Tx.m12; 2263 state = txstate; 2264 type = Tx.type; 2265 return; 2266 case (HI_SHEAR | HI_SCALE | APPLY_IDENTITY): 2267 m01 = Tx.m01; 2268 m10 = Tx.m10; 2269 /* NOBREAK */ 2270 case (HI_SCALE | APPLY_IDENTITY): 2271 m00 = Tx.m00; 2272 m11 = Tx.m11; 2273 state = txstate; 2274 type = Tx.type; 2275 return; 2276 case (HI_SHEAR | HI_TRANSLATE | APPLY_IDENTITY): 2277 m02 = Tx.m02; 2278 m12 = Tx.m12; 2279 /* NOBREAK */ 2280 case (HI_SHEAR | APPLY_IDENTITY): 2281 m01 = Tx.m01; 2282 m10 = Tx.m10; 2283 m00 = m11 = 0.0; 2284 state = txstate; 2285 type = Tx.type; 2286 return; 2287 2288 /* ---------- Tx == TRANSLATE cases ---------- */ 2289 case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2290 case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE): 2291 case (HI_TRANSLATE | APPLY_SHEAR | APPLY_TRANSLATE): 2292 case (HI_TRANSLATE | APPLY_SHEAR): 2293 case (HI_TRANSLATE | APPLY_SCALE | APPLY_TRANSLATE): 2294 case (HI_TRANSLATE | APPLY_SCALE): 2295 case (HI_TRANSLATE | APPLY_TRANSLATE): 2296 translate(Tx.m02, Tx.m12); 2297 return; 2298 2299 /* ---------- Tx == SCALE cases ---------- */ 2300 case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2301 case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE): 2302 case (HI_SCALE | APPLY_SHEAR | APPLY_TRANSLATE): 2303 case (HI_SCALE | APPLY_SHEAR): 2304 case (HI_SCALE | APPLY_SCALE | APPLY_TRANSLATE): 2305 case (HI_SCALE | APPLY_SCALE): 2306 case (HI_SCALE | APPLY_TRANSLATE): 2307 scale(Tx.m00, Tx.m11); 2308 return; 2309 2310 /* ---------- Tx == SHEAR cases ---------- */ 2311 case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2312 case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE): 2313 T01 = Tx.m01; T10 = Tx.m10; 2314 M0 = m00; 2315 m00 = m01 * T10; 2316 m01 = M0 * T01; 2317 M0 = m10; 2318 m10 = m11 * T10; 2319 m11 = M0 * T01; 2320 type = TYPE_UNKNOWN; 2321 return; 2322 case (HI_SHEAR | APPLY_SHEAR | APPLY_TRANSLATE): 2323 case (HI_SHEAR | APPLY_SHEAR): 2324 m00 = m01 * Tx.m10; 2325 m01 = 0.0; 2326 m11 = m10 * Tx.m01; 2327 m10 = 0.0; 2328 state = mystate ^ (APPLY_SHEAR | APPLY_SCALE); 2329 type = TYPE_UNKNOWN; 2330 return; 2331 case (HI_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2332 case (HI_SHEAR | APPLY_SCALE): 2333 m01 = m00 * Tx.m01; 2334 m00 = 0.0; 2335 m10 = m11 * Tx.m10; 2336 m11 = 0.0; 2337 state = mystate ^ (APPLY_SHEAR | APPLY_SCALE); 2338 type = TYPE_UNKNOWN; 2339 return; 2340 case (HI_SHEAR | APPLY_TRANSLATE): 2341 m00 = 0.0; 2342 m01 = Tx.m01; 2343 m10 = Tx.m10; 2344 m11 = 0.0; 2345 state = APPLY_TRANSLATE | APPLY_SHEAR; 2346 type = TYPE_UNKNOWN; 2347 return; 2348 } 2349 // If Tx has more than one attribute, it is not worth optimizing 2350 // all of those cases... 2351 T00 = Tx.m00; T01 = Tx.m01; T02 = Tx.m02; 2352 T10 = Tx.m10; T11 = Tx.m11; T12 = Tx.m12; 2353 switch (mystate) { 2354 default: 2355 stateError(); 2356 /* NOTREACHED */ 2357 case (APPLY_SHEAR | APPLY_SCALE): 2358 state = mystate | txstate; 2359 /* NOBREAK */ 2360 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2361 M0 = m00; 2362 M1 = m01; 2363 m00 = T00 * M0 + T10 * M1; 2364 m01 = T01 * M0 + T11 * M1; 2365 m02 += T02 * M0 + T12 * M1; 2366 2367 M0 = m10; 2368 M1 = m11; 2369 m10 = T00 * M0 + T10 * M1; 2370 m11 = T01 * M0 + T11 * M1; 2371 m12 += T02 * M0 + T12 * M1; 2372 type = TYPE_UNKNOWN; 2373 return; 2374 2375 case (APPLY_SHEAR | APPLY_TRANSLATE): 2376 case (APPLY_SHEAR): 2377 M0 = m01; 2378 m00 = T10 * M0; 2379 m01 = T11 * M0; 2380 m02 += T12 * M0; 2381 2382 M0 = m10; 2383 m10 = T00 * M0; 2384 m11 = T01 * M0; 2385 m12 += T02 * M0; 2386 break; 2387 2388 case (APPLY_SCALE | APPLY_TRANSLATE): 2389 case (APPLY_SCALE): 2390 M0 = m00; 2391 m00 = T00 * M0; 2392 m01 = T01 * M0; 2393 m02 += T02 * M0; 2394 2395 M0 = m11; 2396 m10 = T10 * M0; 2397 m11 = T11 * M0; 2398 m12 += T12 * M0; 2399 break; 2400 2401 case (APPLY_TRANSLATE): 2402 m00 = T00; 2403 m01 = T01; 2404 m02 += T02; 2405 2406 m10 = T10; 2407 m11 = T11; 2408 m12 += T12; 2409 state = txstate | APPLY_TRANSLATE; 2410 type = TYPE_UNKNOWN; 2411 return; 2412 } 2413 updateState(); 2414 } 2415 2416 /** 2417 * Concatenates an <code>AffineTransform</code> <code>Tx</code> to 2418 * this <code>AffineTransform</code> Cx 2419 * in a less commonly used way such that <code>Tx</code> modifies the 2420 * coordinate transformation relative to the absolute pixel 2421 * space rather than relative to the existing user space. 2422 * Cx is updated to perform the combined transformation. 2423 * Transforming a point p by the updated transform Cx' is 2424 * equivalent to first transforming p by the original transform 2425 * Cx and then transforming the result by 2426 * <code>Tx</code> like this: 2427 * Cx'(p) = Tx(Cx(p)) 2428 * In matrix notation, if this transform Cx 2429 * is represented by the matrix [this] and <code>Tx</code> is 2430 * represented by the matrix [Tx] then this method does the 2431 * following: 2432 * <pre> 2433 * [this] = [Tx] x [this] 2434 * </pre> 2435 * @param Tx the <code>AffineTransform</code> object to be 2436 * concatenated with this <code>AffineTransform</code> object. 2437 * @see #concatenate 2438 * @since 1.2 2439 */ 2440 @SuppressWarnings("fallthrough") preConcatenate(AffineTransform Tx)2441 public void preConcatenate(AffineTransform Tx) { 2442 double M0, M1; 2443 double T00, T01, T10, T11; 2444 double T02, T12; 2445 int mystate = state; 2446 int txstate = Tx.state; 2447 switch ((txstate << HI_SHIFT) | mystate) { 2448 case (HI_IDENTITY | APPLY_IDENTITY): 2449 case (HI_IDENTITY | APPLY_TRANSLATE): 2450 case (HI_IDENTITY | APPLY_SCALE): 2451 case (HI_IDENTITY | APPLY_SCALE | APPLY_TRANSLATE): 2452 case (HI_IDENTITY | APPLY_SHEAR): 2453 case (HI_IDENTITY | APPLY_SHEAR | APPLY_TRANSLATE): 2454 case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE): 2455 case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2456 // Tx is IDENTITY... 2457 return; 2458 2459 case (HI_TRANSLATE | APPLY_IDENTITY): 2460 case (HI_TRANSLATE | APPLY_SCALE): 2461 case (HI_TRANSLATE | APPLY_SHEAR): 2462 case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE): 2463 // Tx is TRANSLATE, this has no TRANSLATE 2464 m02 = Tx.m02; 2465 m12 = Tx.m12; 2466 state = mystate | APPLY_TRANSLATE; 2467 type |= TYPE_TRANSLATION; 2468 return; 2469 2470 case (HI_TRANSLATE | APPLY_TRANSLATE): 2471 case (HI_TRANSLATE | APPLY_SCALE | APPLY_TRANSLATE): 2472 case (HI_TRANSLATE | APPLY_SHEAR | APPLY_TRANSLATE): 2473 case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2474 // Tx is TRANSLATE, this has one too 2475 m02 = m02 + Tx.m02; 2476 m12 = m12 + Tx.m12; 2477 return; 2478 2479 case (HI_SCALE | APPLY_TRANSLATE): 2480 case (HI_SCALE | APPLY_IDENTITY): 2481 // Only these two existing states need a new state 2482 state = mystate | APPLY_SCALE; 2483 /* NOBREAK */ 2484 case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2485 case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE): 2486 case (HI_SCALE | APPLY_SHEAR | APPLY_TRANSLATE): 2487 case (HI_SCALE | APPLY_SHEAR): 2488 case (HI_SCALE | APPLY_SCALE | APPLY_TRANSLATE): 2489 case (HI_SCALE | APPLY_SCALE): 2490 // Tx is SCALE, this is anything 2491 T00 = Tx.m00; 2492 T11 = Tx.m11; 2493 if ((mystate & APPLY_SHEAR) != 0) { 2494 m01 = m01 * T00; 2495 m10 = m10 * T11; 2496 if ((mystate & APPLY_SCALE) != 0) { 2497 m00 = m00 * T00; 2498 m11 = m11 * T11; 2499 } 2500 } else { 2501 m00 = m00 * T00; 2502 m11 = m11 * T11; 2503 } 2504 if ((mystate & APPLY_TRANSLATE) != 0) { 2505 m02 = m02 * T00; 2506 m12 = m12 * T11; 2507 } 2508 type = TYPE_UNKNOWN; 2509 return; 2510 case (HI_SHEAR | APPLY_SHEAR | APPLY_TRANSLATE): 2511 case (HI_SHEAR | APPLY_SHEAR): 2512 mystate = mystate | APPLY_SCALE; 2513 /* NOBREAK */ 2514 case (HI_SHEAR | APPLY_TRANSLATE): 2515 case (HI_SHEAR | APPLY_IDENTITY): 2516 case (HI_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2517 case (HI_SHEAR | APPLY_SCALE): 2518 state = mystate ^ APPLY_SHEAR; 2519 /* NOBREAK */ 2520 case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2521 case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE): 2522 // Tx is SHEAR, this is anything 2523 T01 = Tx.m01; 2524 T10 = Tx.m10; 2525 2526 M0 = m00; 2527 m00 = m10 * T01; 2528 m10 = M0 * T10; 2529 2530 M0 = m01; 2531 m01 = m11 * T01; 2532 m11 = M0 * T10; 2533 2534 M0 = m02; 2535 m02 = m12 * T01; 2536 m12 = M0 * T10; 2537 type = TYPE_UNKNOWN; 2538 return; 2539 } 2540 // If Tx has more than one attribute, it is not worth optimizing 2541 // all of those cases... 2542 T00 = Tx.m00; T01 = Tx.m01; T02 = Tx.m02; 2543 T10 = Tx.m10; T11 = Tx.m11; T12 = Tx.m12; 2544 switch (mystate) { 2545 default: 2546 stateError(); 2547 /* NOTREACHED */ 2548 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2549 M0 = m02; 2550 M1 = m12; 2551 T02 += M0 * T00 + M1 * T01; 2552 T12 += M0 * T10 + M1 * T11; 2553 2554 /* NOBREAK */ 2555 case (APPLY_SHEAR | APPLY_SCALE): 2556 m02 = T02; 2557 m12 = T12; 2558 2559 M0 = m00; 2560 M1 = m10; 2561 m00 = M0 * T00 + M1 * T01; 2562 m10 = M0 * T10 + M1 * T11; 2563 2564 M0 = m01; 2565 M1 = m11; 2566 m01 = M0 * T00 + M1 * T01; 2567 m11 = M0 * T10 + M1 * T11; 2568 break; 2569 2570 case (APPLY_SHEAR | APPLY_TRANSLATE): 2571 M0 = m02; 2572 M1 = m12; 2573 T02 += M0 * T00 + M1 * T01; 2574 T12 += M0 * T10 + M1 * T11; 2575 2576 /* NOBREAK */ 2577 case (APPLY_SHEAR): 2578 m02 = T02; 2579 m12 = T12; 2580 2581 M0 = m10; 2582 m00 = M0 * T01; 2583 m10 = M0 * T11; 2584 2585 M0 = m01; 2586 m01 = M0 * T00; 2587 m11 = M0 * T10; 2588 break; 2589 2590 case (APPLY_SCALE | APPLY_TRANSLATE): 2591 M0 = m02; 2592 M1 = m12; 2593 T02 += M0 * T00 + M1 * T01; 2594 T12 += M0 * T10 + M1 * T11; 2595 2596 /* NOBREAK */ 2597 case (APPLY_SCALE): 2598 m02 = T02; 2599 m12 = T12; 2600 2601 M0 = m00; 2602 m00 = M0 * T00; 2603 m10 = M0 * T10; 2604 2605 M0 = m11; 2606 m01 = M0 * T01; 2607 m11 = M0 * T11; 2608 break; 2609 2610 case (APPLY_TRANSLATE): 2611 M0 = m02; 2612 M1 = m12; 2613 T02 += M0 * T00 + M1 * T01; 2614 T12 += M0 * T10 + M1 * T11; 2615 2616 /* NOBREAK */ 2617 case (APPLY_IDENTITY): 2618 m02 = T02; 2619 m12 = T12; 2620 2621 m00 = T00; 2622 m10 = T10; 2623 2624 m01 = T01; 2625 m11 = T11; 2626 2627 state = mystate | txstate; 2628 type = TYPE_UNKNOWN; 2629 return; 2630 } 2631 updateState(); 2632 } 2633 2634 /** 2635 * Returns an <code>AffineTransform</code> object representing the 2636 * inverse transformation. 2637 * The inverse transform Tx' of this transform Tx 2638 * maps coordinates transformed by Tx back 2639 * to their original coordinates. 2640 * In other words, Tx'(Tx(p)) = p = Tx(Tx'(p)). 2641 * <p> 2642 * If this transform maps all coordinates onto a point or a line 2643 * then it will not have an inverse, since coordinates that do 2644 * not lie on the destination point or line will not have an inverse 2645 * mapping. 2646 * The <code>getDeterminant</code> method can be used to determine if this 2647 * transform has no inverse, in which case an exception will be 2648 * thrown if the <code>createInverse</code> method is called. 2649 * @return a new <code>AffineTransform</code> object representing the 2650 * inverse transformation. 2651 * @see #getDeterminant 2652 * @exception NoninvertibleTransformException 2653 * if the matrix cannot be inverted. 2654 * @since 1.2 2655 */ createInverse()2656 public AffineTransform createInverse() 2657 throws NoninvertibleTransformException 2658 { 2659 double det; 2660 switch (state) { 2661 default: 2662 stateError(); 2663 /* NOTREACHED */ 2664 return null; 2665 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2666 det = m00 * m11 - m01 * m10; 2667 if (Math.abs(det) <= Double.MIN_VALUE) { 2668 throw new NoninvertibleTransformException("Determinant is "+ 2669 det); 2670 } 2671 return new AffineTransform( m11 / det, -m10 / det, 2672 -m01 / det, m00 / det, 2673 (m01 * m12 - m11 * m02) / det, 2674 (m10 * m02 - m00 * m12) / det, 2675 (APPLY_SHEAR | 2676 APPLY_SCALE | 2677 APPLY_TRANSLATE)); 2678 case (APPLY_SHEAR | APPLY_SCALE): 2679 det = m00 * m11 - m01 * m10; 2680 if (Math.abs(det) <= Double.MIN_VALUE) { 2681 throw new NoninvertibleTransformException("Determinant is "+ 2682 det); 2683 } 2684 return new AffineTransform( m11 / det, -m10 / det, 2685 -m01 / det, m00 / det, 2686 0.0, 0.0, 2687 (APPLY_SHEAR | APPLY_SCALE)); 2688 case (APPLY_SHEAR | APPLY_TRANSLATE): 2689 if (m01 == 0.0 || m10 == 0.0) { 2690 throw new NoninvertibleTransformException("Determinant is 0"); 2691 } 2692 return new AffineTransform( 0.0, 1.0 / m01, 2693 1.0 / m10, 0.0, 2694 -m12 / m10, -m02 / m01, 2695 (APPLY_SHEAR | APPLY_TRANSLATE)); 2696 case (APPLY_SHEAR): 2697 if (m01 == 0.0 || m10 == 0.0) { 2698 throw new NoninvertibleTransformException("Determinant is 0"); 2699 } 2700 return new AffineTransform(0.0, 1.0 / m01, 2701 1.0 / m10, 0.0, 2702 0.0, 0.0, 2703 (APPLY_SHEAR)); 2704 case (APPLY_SCALE | APPLY_TRANSLATE): 2705 if (m00 == 0.0 || m11 == 0.0) { 2706 throw new NoninvertibleTransformException("Determinant is 0"); 2707 } 2708 return new AffineTransform( 1.0 / m00, 0.0, 2709 0.0, 1.0 / m11, 2710 -m02 / m00, -m12 / m11, 2711 (APPLY_SCALE | APPLY_TRANSLATE)); 2712 case (APPLY_SCALE): 2713 if (m00 == 0.0 || m11 == 0.0) { 2714 throw new NoninvertibleTransformException("Determinant is 0"); 2715 } 2716 return new AffineTransform(1.0 / m00, 0.0, 2717 0.0, 1.0 / m11, 2718 0.0, 0.0, 2719 (APPLY_SCALE)); 2720 case (APPLY_TRANSLATE): 2721 return new AffineTransform( 1.0, 0.0, 2722 0.0, 1.0, 2723 -m02, -m12, 2724 (APPLY_TRANSLATE)); 2725 case (APPLY_IDENTITY): 2726 return new AffineTransform(); 2727 } 2728 2729 /* NOTREACHED */ 2730 } 2731 2732 /** 2733 * Sets this transform to the inverse of itself. 2734 * The inverse transform Tx' of this transform Tx 2735 * maps coordinates transformed by Tx back 2736 * to their original coordinates. 2737 * In other words, Tx'(Tx(p)) = p = Tx(Tx'(p)). 2738 * <p> 2739 * If this transform maps all coordinates onto a point or a line 2740 * then it will not have an inverse, since coordinates that do 2741 * not lie on the destination point or line will not have an inverse 2742 * mapping. 2743 * The <code>getDeterminant</code> method can be used to determine if this 2744 * transform has no inverse, in which case an exception will be 2745 * thrown if the <code>invert</code> method is called. 2746 * @see #getDeterminant 2747 * @exception NoninvertibleTransformException 2748 * if the matrix cannot be inverted. 2749 * @since 1.6 2750 */ invert()2751 public void invert() 2752 throws NoninvertibleTransformException 2753 { 2754 double M00, M01, M02; 2755 double M10, M11, M12; 2756 double det; 2757 switch (state) { 2758 default: 2759 stateError(); 2760 /* NOTREACHED */ 2761 return; 2762 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2763 M00 = m00; M01 = m01; M02 = m02; 2764 M10 = m10; M11 = m11; M12 = m12; 2765 det = M00 * M11 - M01 * M10; 2766 if (Math.abs(det) <= Double.MIN_VALUE) { 2767 throw new NoninvertibleTransformException("Determinant is "+ 2768 det); 2769 } 2770 m00 = M11 / det; 2771 m10 = -M10 / det; 2772 m01 = -M01 / det; 2773 m11 = M00 / det; 2774 m02 = (M01 * M12 - M11 * M02) / det; 2775 m12 = (M10 * M02 - M00 * M12) / det; 2776 break; 2777 case (APPLY_SHEAR | APPLY_SCALE): 2778 M00 = m00; M01 = m01; 2779 M10 = m10; M11 = m11; 2780 det = M00 * M11 - M01 * M10; 2781 if (Math.abs(det) <= Double.MIN_VALUE) { 2782 throw new NoninvertibleTransformException("Determinant is "+ 2783 det); 2784 } 2785 m00 = M11 / det; 2786 m10 = -M10 / det; 2787 m01 = -M01 / det; 2788 m11 = M00 / det; 2789 // m02 = 0.0; 2790 // m12 = 0.0; 2791 break; 2792 case (APPLY_SHEAR | APPLY_TRANSLATE): 2793 M01 = m01; M02 = m02; 2794 M10 = m10; M12 = m12; 2795 if (M01 == 0.0 || M10 == 0.0) { 2796 throw new NoninvertibleTransformException("Determinant is 0"); 2797 } 2798 // m00 = 0.0; 2799 m10 = 1.0 / M01; 2800 m01 = 1.0 / M10; 2801 // m11 = 0.0; 2802 m02 = -M12 / M10; 2803 m12 = -M02 / M01; 2804 break; 2805 case (APPLY_SHEAR): 2806 M01 = m01; 2807 M10 = m10; 2808 if (M01 == 0.0 || M10 == 0.0) { 2809 throw new NoninvertibleTransformException("Determinant is 0"); 2810 } 2811 // m00 = 0.0; 2812 m10 = 1.0 / M01; 2813 m01 = 1.0 / M10; 2814 // m11 = 0.0; 2815 // m02 = 0.0; 2816 // m12 = 0.0; 2817 break; 2818 case (APPLY_SCALE | APPLY_TRANSLATE): 2819 M00 = m00; M02 = m02; 2820 M11 = m11; M12 = m12; 2821 if (M00 == 0.0 || M11 == 0.0) { 2822 throw new NoninvertibleTransformException("Determinant is 0"); 2823 } 2824 m00 = 1.0 / M00; 2825 // m10 = 0.0; 2826 // m01 = 0.0; 2827 m11 = 1.0 / M11; 2828 m02 = -M02 / M00; 2829 m12 = -M12 / M11; 2830 break; 2831 case (APPLY_SCALE): 2832 M00 = m00; 2833 M11 = m11; 2834 if (M00 == 0.0 || M11 == 0.0) { 2835 throw new NoninvertibleTransformException("Determinant is 0"); 2836 } 2837 m00 = 1.0 / M00; 2838 // m10 = 0.0; 2839 // m01 = 0.0; 2840 m11 = 1.0 / M11; 2841 // m02 = 0.0; 2842 // m12 = 0.0; 2843 break; 2844 case (APPLY_TRANSLATE): 2845 // m00 = 1.0; 2846 // m10 = 0.0; 2847 // m01 = 0.0; 2848 // m11 = 1.0; 2849 m02 = -m02; 2850 m12 = -m12; 2851 break; 2852 case (APPLY_IDENTITY): 2853 // m00 = 1.0; 2854 // m10 = 0.0; 2855 // m01 = 0.0; 2856 // m11 = 1.0; 2857 // m02 = 0.0; 2858 // m12 = 0.0; 2859 break; 2860 } 2861 } 2862 2863 /** 2864 * Transforms the specified <code>ptSrc</code> and stores the result 2865 * in <code>ptDst</code>. 2866 * If <code>ptDst</code> is <code>null</code>, a new {@link Point2D} 2867 * object is allocated and then the result of the transformation is 2868 * stored in this object. 2869 * In either case, <code>ptDst</code>, which contains the 2870 * transformed point, is returned for convenience. 2871 * If <code>ptSrc</code> and <code>ptDst</code> are the same 2872 * object, the input point is correctly overwritten with 2873 * the transformed point. 2874 * @param ptSrc the specified <code>Point2D</code> to be transformed 2875 * @param ptDst the specified <code>Point2D</code> that stores the 2876 * result of transforming <code>ptSrc</code> 2877 * @return the <code>ptDst</code> after transforming 2878 * <code>ptSrc</code> and storing the result in <code>ptDst</code>. 2879 * @since 1.2 2880 */ transform(Point2D ptSrc, Point2D ptDst)2881 public Point2D transform(Point2D ptSrc, Point2D ptDst) { 2882 if (ptDst == null) { 2883 if (ptSrc instanceof Point2D.Double) { 2884 ptDst = new Point2D.Double(); 2885 } else { 2886 ptDst = new Point2D.Float(); 2887 } 2888 } 2889 // Copy source coords into local variables in case src == dst 2890 double x = ptSrc.getX(); 2891 double y = ptSrc.getY(); 2892 switch (state) { 2893 default: 2894 stateError(); 2895 /* NOTREACHED */ 2896 return null; 2897 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2898 ptDst.setLocation(x * m00 + y * m01 + m02, 2899 x * m10 + y * m11 + m12); 2900 return ptDst; 2901 case (APPLY_SHEAR | APPLY_SCALE): 2902 ptDst.setLocation(x * m00 + y * m01, x * m10 + y * m11); 2903 return ptDst; 2904 case (APPLY_SHEAR | APPLY_TRANSLATE): 2905 ptDst.setLocation(y * m01 + m02, x * m10 + m12); 2906 return ptDst; 2907 case (APPLY_SHEAR): 2908 ptDst.setLocation(y * m01, x * m10); 2909 return ptDst; 2910 case (APPLY_SCALE | APPLY_TRANSLATE): 2911 ptDst.setLocation(x * m00 + m02, y * m11 + m12); 2912 return ptDst; 2913 case (APPLY_SCALE): 2914 ptDst.setLocation(x * m00, y * m11); 2915 return ptDst; 2916 case (APPLY_TRANSLATE): 2917 ptDst.setLocation(x + m02, y + m12); 2918 return ptDst; 2919 case (APPLY_IDENTITY): 2920 ptDst.setLocation(x, y); 2921 return ptDst; 2922 } 2923 2924 /* NOTREACHED */ 2925 } 2926 2927 /** 2928 * Transforms an array of point objects by this transform. 2929 * If any element of the <code>ptDst</code> array is 2930 * <code>null</code>, a new <code>Point2D</code> object is allocated 2931 * and stored into that element before storing the results of the 2932 * transformation. 2933 * <p> 2934 * Note that this method does not take any precautions to 2935 * avoid problems caused by storing results into <code>Point2D</code> 2936 * objects that will be used as the source for calculations 2937 * further down the source array. 2938 * This method does guarantee that if a specified <code>Point2D</code> 2939 * object is both the source and destination for the same single point 2940 * transform operation then the results will not be stored until 2941 * the calculations are complete to avoid storing the results on 2942 * top of the operands. 2943 * If, however, the destination <code>Point2D</code> object for one 2944 * operation is the same object as the source <code>Point2D</code> 2945 * object for another operation further down the source array then 2946 * the original coordinates in that point are overwritten before 2947 * they can be converted. 2948 * @param ptSrc the array containing the source point objects 2949 * @param ptDst the array into which the transform point objects are 2950 * returned 2951 * @param srcOff the offset to the first point object to be 2952 * transformed in the source array 2953 * @param dstOff the offset to the location of the first 2954 * transformed point object that is stored in the destination array 2955 * @param numPts the number of point objects to be transformed 2956 * @since 1.2 2957 */ transform(Point2D[] ptSrc, int srcOff, Point2D[] ptDst, int dstOff, int numPts)2958 public void transform(Point2D[] ptSrc, int srcOff, 2959 Point2D[] ptDst, int dstOff, 2960 int numPts) { 2961 int state = this.state; 2962 while (--numPts >= 0) { 2963 // Copy source coords into local variables in case src == dst 2964 Point2D src = ptSrc[srcOff++]; 2965 double x = src.getX(); 2966 double y = src.getY(); 2967 Point2D dst = ptDst[dstOff++]; 2968 if (dst == null) { 2969 if (src instanceof Point2D.Double) { 2970 dst = new Point2D.Double(); 2971 } else { 2972 dst = new Point2D.Float(); 2973 } 2974 ptDst[dstOff - 1] = dst; 2975 } 2976 switch (state) { 2977 default: 2978 stateError(); 2979 /* NOTREACHED */ 2980 return; 2981 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 2982 dst.setLocation(x * m00 + y * m01 + m02, 2983 x * m10 + y * m11 + m12); 2984 break; 2985 case (APPLY_SHEAR | APPLY_SCALE): 2986 dst.setLocation(x * m00 + y * m01, x * m10 + y * m11); 2987 break; 2988 case (APPLY_SHEAR | APPLY_TRANSLATE): 2989 dst.setLocation(y * m01 + m02, x * m10 + m12); 2990 break; 2991 case (APPLY_SHEAR): 2992 dst.setLocation(y * m01, x * m10); 2993 break; 2994 case (APPLY_SCALE | APPLY_TRANSLATE): 2995 dst.setLocation(x * m00 + m02, y * m11 + m12); 2996 break; 2997 case (APPLY_SCALE): 2998 dst.setLocation(x * m00, y * m11); 2999 break; 3000 case (APPLY_TRANSLATE): 3001 dst.setLocation(x + m02, y + m12); 3002 break; 3003 case (APPLY_IDENTITY): 3004 dst.setLocation(x, y); 3005 break; 3006 } 3007 } 3008 3009 /* NOTREACHED */ 3010 } 3011 3012 /** 3013 * Transforms an array of floating point coordinates by this transform. 3014 * The two coordinate array sections can be exactly the same or 3015 * can be overlapping sections of the same array without affecting the 3016 * validity of the results. 3017 * This method ensures that no source coordinates are overwritten by a 3018 * previous operation before they can be transformed. 3019 * The coordinates are stored in the arrays starting at the specified 3020 * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>. 3021 * @param srcPts the array containing the source point coordinates. 3022 * Each point is stored as a pair of x, y coordinates. 3023 * @param dstPts the array into which the transformed point coordinates 3024 * are returned. Each point is stored as a pair of x, y 3025 * coordinates. 3026 * @param srcOff the offset to the first point to be transformed 3027 * in the source array 3028 * @param dstOff the offset to the location of the first 3029 * transformed point that is stored in the destination array 3030 * @param numPts the number of points to be transformed 3031 * @since 1.2 3032 */ transform(float[] srcPts, int srcOff, float[] dstPts, int dstOff, int numPts)3033 public void transform(float[] srcPts, int srcOff, 3034 float[] dstPts, int dstOff, 3035 int numPts) { 3036 double M00, M01, M02, M10, M11, M12; // For caching 3037 if (dstPts == srcPts && 3038 dstOff > srcOff && dstOff < srcOff + numPts * 2) 3039 { 3040 // If the arrays overlap partially with the destination higher 3041 // than the source and we transform the coordinates normally 3042 // we would overwrite some of the later source coordinates 3043 // with results of previous transformations. 3044 // To get around this we use arraycopy to copy the points 3045 // to their final destination with correct overwrite 3046 // handling and then transform them in place in the new 3047 // safer location. 3048 System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts * 2); 3049 // srcPts = dstPts; // They are known to be equal. 3050 srcOff = dstOff; 3051 } 3052 switch (state) { 3053 default: 3054 stateError(); 3055 /* NOTREACHED */ 3056 return; 3057 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 3058 M00 = m00; M01 = m01; M02 = m02; 3059 M10 = m10; M11 = m11; M12 = m12; 3060 while (--numPts >= 0) { 3061 double x = srcPts[srcOff++]; 3062 double y = srcPts[srcOff++]; 3063 dstPts[dstOff++] = (float) (M00 * x + M01 * y + M02); 3064 dstPts[dstOff++] = (float) (M10 * x + M11 * y + M12); 3065 } 3066 return; 3067 case (APPLY_SHEAR | APPLY_SCALE): 3068 M00 = m00; M01 = m01; 3069 M10 = m10; M11 = m11; 3070 while (--numPts >= 0) { 3071 double x = srcPts[srcOff++]; 3072 double y = srcPts[srcOff++]; 3073 dstPts[dstOff++] = (float) (M00 * x + M01 * y); 3074 dstPts[dstOff++] = (float) (M10 * x + M11 * y); 3075 } 3076 return; 3077 case (APPLY_SHEAR | APPLY_TRANSLATE): 3078 M01 = m01; M02 = m02; 3079 M10 = m10; M12 = m12; 3080 while (--numPts >= 0) { 3081 double x = srcPts[srcOff++]; 3082 dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++] + M02); 3083 dstPts[dstOff++] = (float) (M10 * x + M12); 3084 } 3085 return; 3086 case (APPLY_SHEAR): 3087 M01 = m01; M10 = m10; 3088 while (--numPts >= 0) { 3089 double x = srcPts[srcOff++]; 3090 dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++]); 3091 dstPts[dstOff++] = (float) (M10 * x); 3092 } 3093 return; 3094 case (APPLY_SCALE | APPLY_TRANSLATE): 3095 M00 = m00; M02 = m02; 3096 M11 = m11; M12 = m12; 3097 while (--numPts >= 0) { 3098 dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++] + M02); 3099 dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++] + M12); 3100 } 3101 return; 3102 case (APPLY_SCALE): 3103 M00 = m00; M11 = m11; 3104 while (--numPts >= 0) { 3105 dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++]); 3106 dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++]); 3107 } 3108 return; 3109 case (APPLY_TRANSLATE): 3110 M02 = m02; M12 = m12; 3111 while (--numPts >= 0) { 3112 dstPts[dstOff++] = (float) (srcPts[srcOff++] + M02); 3113 dstPts[dstOff++] = (float) (srcPts[srcOff++] + M12); 3114 } 3115 return; 3116 case (APPLY_IDENTITY): 3117 if (srcPts != dstPts || srcOff != dstOff) { 3118 System.arraycopy(srcPts, srcOff, dstPts, dstOff, 3119 numPts * 2); 3120 } 3121 return; 3122 } 3123 3124 /* NOTREACHED */ 3125 } 3126 3127 /** 3128 * Transforms an array of double precision coordinates by this transform. 3129 * The two coordinate array sections can be exactly the same or 3130 * can be overlapping sections of the same array without affecting the 3131 * validity of the results. 3132 * This method ensures that no source coordinates are 3133 * overwritten by a previous operation before they can be transformed. 3134 * The coordinates are stored in the arrays starting at the indicated 3135 * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>. 3136 * @param srcPts the array containing the source point coordinates. 3137 * Each point is stored as a pair of x, y coordinates. 3138 * @param dstPts the array into which the transformed point 3139 * coordinates are returned. Each point is stored as a pair of 3140 * x, y coordinates. 3141 * @param srcOff the offset to the first point to be transformed 3142 * in the source array 3143 * @param dstOff the offset to the location of the first 3144 * transformed point that is stored in the destination array 3145 * @param numPts the number of point objects to be transformed 3146 * @since 1.2 3147 */ transform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, int numPts)3148 public void transform(double[] srcPts, int srcOff, 3149 double[] dstPts, int dstOff, 3150 int numPts) { 3151 double M00, M01, M02, M10, M11, M12; // For caching 3152 if (dstPts == srcPts && 3153 dstOff > srcOff && dstOff < srcOff + numPts * 2) 3154 { 3155 // If the arrays overlap partially with the destination higher 3156 // than the source and we transform the coordinates normally 3157 // we would overwrite some of the later source coordinates 3158 // with results of previous transformations. 3159 // To get around this we use arraycopy to copy the points 3160 // to their final destination with correct overwrite 3161 // handling and then transform them in place in the new 3162 // safer location. 3163 System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts * 2); 3164 // srcPts = dstPts; // They are known to be equal. 3165 srcOff = dstOff; 3166 } 3167 switch (state) { 3168 default: 3169 stateError(); 3170 /* NOTREACHED */ 3171 return; 3172 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 3173 M00 = m00; M01 = m01; M02 = m02; 3174 M10 = m10; M11 = m11; M12 = m12; 3175 while (--numPts >= 0) { 3176 double x = srcPts[srcOff++]; 3177 double y = srcPts[srcOff++]; 3178 dstPts[dstOff++] = M00 * x + M01 * y + M02; 3179 dstPts[dstOff++] = M10 * x + M11 * y + M12; 3180 } 3181 return; 3182 case (APPLY_SHEAR | APPLY_SCALE): 3183 M00 = m00; M01 = m01; 3184 M10 = m10; M11 = m11; 3185 while (--numPts >= 0) { 3186 double x = srcPts[srcOff++]; 3187 double y = srcPts[srcOff++]; 3188 dstPts[dstOff++] = M00 * x + M01 * y; 3189 dstPts[dstOff++] = M10 * x + M11 * y; 3190 } 3191 return; 3192 case (APPLY_SHEAR | APPLY_TRANSLATE): 3193 M01 = m01; M02 = m02; 3194 M10 = m10; M12 = m12; 3195 while (--numPts >= 0) { 3196 double x = srcPts[srcOff++]; 3197 dstPts[dstOff++] = M01 * srcPts[srcOff++] + M02; 3198 dstPts[dstOff++] = M10 * x + M12; 3199 } 3200 return; 3201 case (APPLY_SHEAR): 3202 M01 = m01; M10 = m10; 3203 while (--numPts >= 0) { 3204 double x = srcPts[srcOff++]; 3205 dstPts[dstOff++] = M01 * srcPts[srcOff++]; 3206 dstPts[dstOff++] = M10 * x; 3207 } 3208 return; 3209 case (APPLY_SCALE | APPLY_TRANSLATE): 3210 M00 = m00; M02 = m02; 3211 M11 = m11; M12 = m12; 3212 while (--numPts >= 0) { 3213 dstPts[dstOff++] = M00 * srcPts[srcOff++] + M02; 3214 dstPts[dstOff++] = M11 * srcPts[srcOff++] + M12; 3215 } 3216 return; 3217 case (APPLY_SCALE): 3218 M00 = m00; M11 = m11; 3219 while (--numPts >= 0) { 3220 dstPts[dstOff++] = M00 * srcPts[srcOff++]; 3221 dstPts[dstOff++] = M11 * srcPts[srcOff++]; 3222 } 3223 return; 3224 case (APPLY_TRANSLATE): 3225 M02 = m02; M12 = m12; 3226 while (--numPts >= 0) { 3227 dstPts[dstOff++] = srcPts[srcOff++] + M02; 3228 dstPts[dstOff++] = srcPts[srcOff++] + M12; 3229 } 3230 return; 3231 case (APPLY_IDENTITY): 3232 if (srcPts != dstPts || srcOff != dstOff) { 3233 System.arraycopy(srcPts, srcOff, dstPts, dstOff, 3234 numPts * 2); 3235 } 3236 return; 3237 } 3238 3239 /* NOTREACHED */ 3240 } 3241 3242 /** 3243 * Transforms an array of floating point coordinates by this transform 3244 * and stores the results into an array of doubles. 3245 * The coordinates are stored in the arrays starting at the specified 3246 * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>. 3247 * @param srcPts the array containing the source point coordinates. 3248 * Each point is stored as a pair of x, y coordinates. 3249 * @param dstPts the array into which the transformed point coordinates 3250 * are returned. Each point is stored as a pair of x, y 3251 * coordinates. 3252 * @param srcOff the offset to the first point to be transformed 3253 * in the source array 3254 * @param dstOff the offset to the location of the first 3255 * transformed point that is stored in the destination array 3256 * @param numPts the number of points to be transformed 3257 * @since 1.2 3258 */ transform(float[] srcPts, int srcOff, double[] dstPts, int dstOff, int numPts)3259 public void transform(float[] srcPts, int srcOff, 3260 double[] dstPts, int dstOff, 3261 int numPts) { 3262 double M00, M01, M02, M10, M11, M12; // For caching 3263 switch (state) { 3264 default: 3265 stateError(); 3266 /* NOTREACHED */ 3267 return; 3268 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 3269 M00 = m00; M01 = m01; M02 = m02; 3270 M10 = m10; M11 = m11; M12 = m12; 3271 while (--numPts >= 0) { 3272 double x = srcPts[srcOff++]; 3273 double y = srcPts[srcOff++]; 3274 dstPts[dstOff++] = M00 * x + M01 * y + M02; 3275 dstPts[dstOff++] = M10 * x + M11 * y + M12; 3276 } 3277 return; 3278 case (APPLY_SHEAR | APPLY_SCALE): 3279 M00 = m00; M01 = m01; 3280 M10 = m10; M11 = m11; 3281 while (--numPts >= 0) { 3282 double x = srcPts[srcOff++]; 3283 double y = srcPts[srcOff++]; 3284 dstPts[dstOff++] = M00 * x + M01 * y; 3285 dstPts[dstOff++] = M10 * x + M11 * y; 3286 } 3287 return; 3288 case (APPLY_SHEAR | APPLY_TRANSLATE): 3289 M01 = m01; M02 = m02; 3290 M10 = m10; M12 = m12; 3291 while (--numPts >= 0) { 3292 double x = srcPts[srcOff++]; 3293 dstPts[dstOff++] = M01 * srcPts[srcOff++] + M02; 3294 dstPts[dstOff++] = M10 * x + M12; 3295 } 3296 return; 3297 case (APPLY_SHEAR): 3298 M01 = m01; M10 = m10; 3299 while (--numPts >= 0) { 3300 double x = srcPts[srcOff++]; 3301 dstPts[dstOff++] = M01 * srcPts[srcOff++]; 3302 dstPts[dstOff++] = M10 * x; 3303 } 3304 return; 3305 case (APPLY_SCALE | APPLY_TRANSLATE): 3306 M00 = m00; M02 = m02; 3307 M11 = m11; M12 = m12; 3308 while (--numPts >= 0) { 3309 dstPts[dstOff++] = M00 * srcPts[srcOff++] + M02; 3310 dstPts[dstOff++] = M11 * srcPts[srcOff++] + M12; 3311 } 3312 return; 3313 case (APPLY_SCALE): 3314 M00 = m00; M11 = m11; 3315 while (--numPts >= 0) { 3316 dstPts[dstOff++] = M00 * srcPts[srcOff++]; 3317 dstPts[dstOff++] = M11 * srcPts[srcOff++]; 3318 } 3319 return; 3320 case (APPLY_TRANSLATE): 3321 M02 = m02; M12 = m12; 3322 while (--numPts >= 0) { 3323 dstPts[dstOff++] = srcPts[srcOff++] + M02; 3324 dstPts[dstOff++] = srcPts[srcOff++] + M12; 3325 } 3326 return; 3327 case (APPLY_IDENTITY): 3328 while (--numPts >= 0) { 3329 dstPts[dstOff++] = srcPts[srcOff++]; 3330 dstPts[dstOff++] = srcPts[srcOff++]; 3331 } 3332 return; 3333 } 3334 3335 /* NOTREACHED */ 3336 } 3337 3338 /** 3339 * Transforms an array of double precision coordinates by this transform 3340 * and stores the results into an array of floats. 3341 * The coordinates are stored in the arrays starting at the specified 3342 * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>. 3343 * @param srcPts the array containing the source point coordinates. 3344 * Each point is stored as a pair of x, y coordinates. 3345 * @param dstPts the array into which the transformed point 3346 * coordinates are returned. Each point is stored as a pair of 3347 * x, y coordinates. 3348 * @param srcOff the offset to the first point to be transformed 3349 * in the source array 3350 * @param dstOff the offset to the location of the first 3351 * transformed point that is stored in the destination array 3352 * @param numPts the number of point objects to be transformed 3353 * @since 1.2 3354 */ transform(double[] srcPts, int srcOff, float[] dstPts, int dstOff, int numPts)3355 public void transform(double[] srcPts, int srcOff, 3356 float[] dstPts, int dstOff, 3357 int numPts) { 3358 double M00, M01, M02, M10, M11, M12; // For caching 3359 switch (state) { 3360 default: 3361 stateError(); 3362 /* NOTREACHED */ 3363 return; 3364 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 3365 M00 = m00; M01 = m01; M02 = m02; 3366 M10 = m10; M11 = m11; M12 = m12; 3367 while (--numPts >= 0) { 3368 double x = srcPts[srcOff++]; 3369 double y = srcPts[srcOff++]; 3370 dstPts[dstOff++] = (float) (M00 * x + M01 * y + M02); 3371 dstPts[dstOff++] = (float) (M10 * x + M11 * y + M12); 3372 } 3373 return; 3374 case (APPLY_SHEAR | APPLY_SCALE): 3375 M00 = m00; M01 = m01; 3376 M10 = m10; M11 = m11; 3377 while (--numPts >= 0) { 3378 double x = srcPts[srcOff++]; 3379 double y = srcPts[srcOff++]; 3380 dstPts[dstOff++] = (float) (M00 * x + M01 * y); 3381 dstPts[dstOff++] = (float) (M10 * x + M11 * y); 3382 } 3383 return; 3384 case (APPLY_SHEAR | APPLY_TRANSLATE): 3385 M01 = m01; M02 = m02; 3386 M10 = m10; M12 = m12; 3387 while (--numPts >= 0) { 3388 double x = srcPts[srcOff++]; 3389 dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++] + M02); 3390 dstPts[dstOff++] = (float) (M10 * x + M12); 3391 } 3392 return; 3393 case (APPLY_SHEAR): 3394 M01 = m01; M10 = m10; 3395 while (--numPts >= 0) { 3396 double x = srcPts[srcOff++]; 3397 dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++]); 3398 dstPts[dstOff++] = (float) (M10 * x); 3399 } 3400 return; 3401 case (APPLY_SCALE | APPLY_TRANSLATE): 3402 M00 = m00; M02 = m02; 3403 M11 = m11; M12 = m12; 3404 while (--numPts >= 0) { 3405 dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++] + M02); 3406 dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++] + M12); 3407 } 3408 return; 3409 case (APPLY_SCALE): 3410 M00 = m00; M11 = m11; 3411 while (--numPts >= 0) { 3412 dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++]); 3413 dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++]); 3414 } 3415 return; 3416 case (APPLY_TRANSLATE): 3417 M02 = m02; M12 = m12; 3418 while (--numPts >= 0) { 3419 dstPts[dstOff++] = (float) (srcPts[srcOff++] + M02); 3420 dstPts[dstOff++] = (float) (srcPts[srcOff++] + M12); 3421 } 3422 return; 3423 case (APPLY_IDENTITY): 3424 while (--numPts >= 0) { 3425 dstPts[dstOff++] = (float) (srcPts[srcOff++]); 3426 dstPts[dstOff++] = (float) (srcPts[srcOff++]); 3427 } 3428 return; 3429 } 3430 3431 /* NOTREACHED */ 3432 } 3433 3434 /** 3435 * Inverse transforms the specified <code>ptSrc</code> and stores the 3436 * result in <code>ptDst</code>. 3437 * If <code>ptDst</code> is <code>null</code>, a new 3438 * <code>Point2D</code> object is allocated and then the result of the 3439 * transform is stored in this object. 3440 * In either case, <code>ptDst</code>, which contains the transformed 3441 * point, is returned for convenience. 3442 * If <code>ptSrc</code> and <code>ptDst</code> are the same 3443 * object, the input point is correctly overwritten with the 3444 * transformed point. 3445 * @param ptSrc the point to be inverse transformed 3446 * @param ptDst the resulting transformed point 3447 * @return <code>ptDst</code>, which contains the result of the 3448 * inverse transform. 3449 * @exception NoninvertibleTransformException if the matrix cannot be 3450 * inverted. 3451 * @since 1.2 3452 */ 3453 @SuppressWarnings("fallthrough") inverseTransform(Point2D ptSrc, Point2D ptDst)3454 public Point2D inverseTransform(Point2D ptSrc, Point2D ptDst) 3455 throws NoninvertibleTransformException 3456 { 3457 if (ptDst == null) { 3458 if (ptSrc instanceof Point2D.Double) { 3459 ptDst = new Point2D.Double(); 3460 } else { 3461 ptDst = new Point2D.Float(); 3462 } 3463 } 3464 // Copy source coords into local variables in case src == dst 3465 double x = ptSrc.getX(); 3466 double y = ptSrc.getY(); 3467 switch (state) { 3468 default: 3469 stateError(); 3470 /* NOTREACHED */ 3471 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 3472 x -= m02; 3473 y -= m12; 3474 /* NOBREAK */ 3475 case (APPLY_SHEAR | APPLY_SCALE): 3476 double det = m00 * m11 - m01 * m10; 3477 if (Math.abs(det) <= Double.MIN_VALUE) { 3478 throw new NoninvertibleTransformException("Determinant is "+ 3479 det); 3480 } 3481 ptDst.setLocation((x * m11 - y * m01) / det, 3482 (y * m00 - x * m10) / det); 3483 return ptDst; 3484 case (APPLY_SHEAR | APPLY_TRANSLATE): 3485 x -= m02; 3486 y -= m12; 3487 /* NOBREAK */ 3488 case (APPLY_SHEAR): 3489 if (m01 == 0.0 || m10 == 0.0) { 3490 throw new NoninvertibleTransformException("Determinant is 0"); 3491 } 3492 ptDst.setLocation(y / m10, x / m01); 3493 return ptDst; 3494 case (APPLY_SCALE | APPLY_TRANSLATE): 3495 x -= m02; 3496 y -= m12; 3497 /* NOBREAK */ 3498 case (APPLY_SCALE): 3499 if (m00 == 0.0 || m11 == 0.0) { 3500 throw new NoninvertibleTransformException("Determinant is 0"); 3501 } 3502 ptDst.setLocation(x / m00, y / m11); 3503 return ptDst; 3504 case (APPLY_TRANSLATE): 3505 ptDst.setLocation(x - m02, y - m12); 3506 return ptDst; 3507 case (APPLY_IDENTITY): 3508 ptDst.setLocation(x, y); 3509 return ptDst; 3510 } 3511 3512 /* NOTREACHED */ 3513 } 3514 3515 /** 3516 * Inverse transforms an array of double precision coordinates by 3517 * this transform. 3518 * The two coordinate array sections can be exactly the same or 3519 * can be overlapping sections of the same array without affecting the 3520 * validity of the results. 3521 * This method ensures that no source coordinates are 3522 * overwritten by a previous operation before they can be transformed. 3523 * The coordinates are stored in the arrays starting at the specified 3524 * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>. 3525 * @param srcPts the array containing the source point coordinates. 3526 * Each point is stored as a pair of x, y coordinates. 3527 * @param dstPts the array into which the transformed point 3528 * coordinates are returned. Each point is stored as a pair of 3529 * x, y coordinates. 3530 * @param srcOff the offset to the first point to be transformed 3531 * in the source array 3532 * @param dstOff the offset to the location of the first 3533 * transformed point that is stored in the destination array 3534 * @param numPts the number of point objects to be transformed 3535 * @exception NoninvertibleTransformException if the matrix cannot be 3536 * inverted. 3537 * @since 1.2 3538 */ inverseTransform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, int numPts)3539 public void inverseTransform(double[] srcPts, int srcOff, 3540 double[] dstPts, int dstOff, 3541 int numPts) 3542 throws NoninvertibleTransformException 3543 { 3544 double M00, M01, M02, M10, M11, M12; // For caching 3545 double det; 3546 if (dstPts == srcPts && 3547 dstOff > srcOff && dstOff < srcOff + numPts * 2) 3548 { 3549 // If the arrays overlap partially with the destination higher 3550 // than the source and we transform the coordinates normally 3551 // we would overwrite some of the later source coordinates 3552 // with results of previous transformations. 3553 // To get around this we use arraycopy to copy the points 3554 // to their final destination with correct overwrite 3555 // handling and then transform them in place in the new 3556 // safer location. 3557 System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts * 2); 3558 // srcPts = dstPts; // They are known to be equal. 3559 srcOff = dstOff; 3560 } 3561 switch (state) { 3562 default: 3563 stateError(); 3564 /* NOTREACHED */ 3565 return; 3566 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 3567 M00 = m00; M01 = m01; M02 = m02; 3568 M10 = m10; M11 = m11; M12 = m12; 3569 det = M00 * M11 - M01 * M10; 3570 if (Math.abs(det) <= Double.MIN_VALUE) { 3571 throw new NoninvertibleTransformException("Determinant is "+ 3572 det); 3573 } 3574 while (--numPts >= 0) { 3575 double x = srcPts[srcOff++] - M02; 3576 double y = srcPts[srcOff++] - M12; 3577 dstPts[dstOff++] = (x * M11 - y * M01) / det; 3578 dstPts[dstOff++] = (y * M00 - x * M10) / det; 3579 } 3580 return; 3581 case (APPLY_SHEAR | APPLY_SCALE): 3582 M00 = m00; M01 = m01; 3583 M10 = m10; M11 = m11; 3584 det = M00 * M11 - M01 * M10; 3585 if (Math.abs(det) <= Double.MIN_VALUE) { 3586 throw new NoninvertibleTransformException("Determinant is "+ 3587 det); 3588 } 3589 while (--numPts >= 0) { 3590 double x = srcPts[srcOff++]; 3591 double y = srcPts[srcOff++]; 3592 dstPts[dstOff++] = (x * M11 - y * M01) / det; 3593 dstPts[dstOff++] = (y * M00 - x * M10) / det; 3594 } 3595 return; 3596 case (APPLY_SHEAR | APPLY_TRANSLATE): 3597 M01 = m01; M02 = m02; 3598 M10 = m10; M12 = m12; 3599 if (M01 == 0.0 || M10 == 0.0) { 3600 throw new NoninvertibleTransformException("Determinant is 0"); 3601 } 3602 while (--numPts >= 0) { 3603 double x = srcPts[srcOff++] - M02; 3604 dstPts[dstOff++] = (srcPts[srcOff++] - M12) / M10; 3605 dstPts[dstOff++] = x / M01; 3606 } 3607 return; 3608 case (APPLY_SHEAR): 3609 M01 = m01; M10 = m10; 3610 if (M01 == 0.0 || M10 == 0.0) { 3611 throw new NoninvertibleTransformException("Determinant is 0"); 3612 } 3613 while (--numPts >= 0) { 3614 double x = srcPts[srcOff++]; 3615 dstPts[dstOff++] = srcPts[srcOff++] / M10; 3616 dstPts[dstOff++] = x / M01; 3617 } 3618 return; 3619 case (APPLY_SCALE | APPLY_TRANSLATE): 3620 M00 = m00; M02 = m02; 3621 M11 = m11; M12 = m12; 3622 if (M00 == 0.0 || M11 == 0.0) { 3623 throw new NoninvertibleTransformException("Determinant is 0"); 3624 } 3625 while (--numPts >= 0) { 3626 dstPts[dstOff++] = (srcPts[srcOff++] - M02) / M00; 3627 dstPts[dstOff++] = (srcPts[srcOff++] - M12) / M11; 3628 } 3629 return; 3630 case (APPLY_SCALE): 3631 M00 = m00; M11 = m11; 3632 if (M00 == 0.0 || M11 == 0.0) { 3633 throw new NoninvertibleTransformException("Determinant is 0"); 3634 } 3635 while (--numPts >= 0) { 3636 dstPts[dstOff++] = srcPts[srcOff++] / M00; 3637 dstPts[dstOff++] = srcPts[srcOff++] / M11; 3638 } 3639 return; 3640 case (APPLY_TRANSLATE): 3641 M02 = m02; M12 = m12; 3642 while (--numPts >= 0) { 3643 dstPts[dstOff++] = srcPts[srcOff++] - M02; 3644 dstPts[dstOff++] = srcPts[srcOff++] - M12; 3645 } 3646 return; 3647 case (APPLY_IDENTITY): 3648 if (srcPts != dstPts || srcOff != dstOff) { 3649 System.arraycopy(srcPts, srcOff, dstPts, dstOff, 3650 numPts * 2); 3651 } 3652 return; 3653 } 3654 3655 /* NOTREACHED */ 3656 } 3657 3658 /** 3659 * Transforms the relative distance vector specified by 3660 * <code>ptSrc</code> and stores the result in <code>ptDst</code>. 3661 * A relative distance vector is transformed without applying the 3662 * translation components of the affine transformation matrix 3663 * using the following equations: 3664 * <pre> 3665 * [ x' ] [ m00 m01 (m02) ] [ x ] [ m00x + m01y ] 3666 * [ y' ] = [ m10 m11 (m12) ] [ y ] = [ m10x + m11y ] 3667 * [ (1) ] [ (0) (0) ( 1 ) ] [ (1) ] [ (1) ] 3668 * </pre> 3669 * If <code>ptDst</code> is <code>null</code>, a new 3670 * <code>Point2D</code> object is allocated and then the result of the 3671 * transform is stored in this object. 3672 * In either case, <code>ptDst</code>, which contains the 3673 * transformed point, is returned for convenience. 3674 * If <code>ptSrc</code> and <code>ptDst</code> are the same object, 3675 * the input point is correctly overwritten with the transformed 3676 * point. 3677 * @param ptSrc the distance vector to be delta transformed 3678 * @param ptDst the resulting transformed distance vector 3679 * @return <code>ptDst</code>, which contains the result of the 3680 * transformation. 3681 * @since 1.2 3682 */ deltaTransform(Point2D ptSrc, Point2D ptDst)3683 public Point2D deltaTransform(Point2D ptSrc, Point2D ptDst) { 3684 if (ptDst == null) { 3685 if (ptSrc instanceof Point2D.Double) { 3686 ptDst = new Point2D.Double(); 3687 } else { 3688 ptDst = new Point2D.Float(); 3689 } 3690 } 3691 // Copy source coords into local variables in case src == dst 3692 double x = ptSrc.getX(); 3693 double y = ptSrc.getY(); 3694 switch (state) { 3695 default: 3696 stateError(); 3697 /* NOTREACHED */ 3698 return null; 3699 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 3700 case (APPLY_SHEAR | APPLY_SCALE): 3701 ptDst.setLocation(x * m00 + y * m01, x * m10 + y * m11); 3702 return ptDst; 3703 case (APPLY_SHEAR | APPLY_TRANSLATE): 3704 case (APPLY_SHEAR): 3705 ptDst.setLocation(y * m01, x * m10); 3706 return ptDst; 3707 case (APPLY_SCALE | APPLY_TRANSLATE): 3708 case (APPLY_SCALE): 3709 ptDst.setLocation(x * m00, y * m11); 3710 return ptDst; 3711 case (APPLY_TRANSLATE): 3712 case (APPLY_IDENTITY): 3713 ptDst.setLocation(x, y); 3714 return ptDst; 3715 } 3716 3717 /* NOTREACHED */ 3718 } 3719 3720 /** 3721 * Transforms an array of relative distance vectors by this 3722 * transform. 3723 * A relative distance vector is transformed without applying the 3724 * translation components of the affine transformation matrix 3725 * using the following equations: 3726 * <pre> 3727 * [ x' ] [ m00 m01 (m02) ] [ x ] [ m00x + m01y ] 3728 * [ y' ] = [ m10 m11 (m12) ] [ y ] = [ m10x + m11y ] 3729 * [ (1) ] [ (0) (0) ( 1 ) ] [ (1) ] [ (1) ] 3730 * </pre> 3731 * The two coordinate array sections can be exactly the same or 3732 * can be overlapping sections of the same array without affecting the 3733 * validity of the results. 3734 * This method ensures that no source coordinates are 3735 * overwritten by a previous operation before they can be transformed. 3736 * The coordinates are stored in the arrays starting at the indicated 3737 * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>. 3738 * @param srcPts the array containing the source distance vectors. 3739 * Each vector is stored as a pair of relative x, y coordinates. 3740 * @param dstPts the array into which the transformed distance vectors 3741 * are returned. Each vector is stored as a pair of relative 3742 * x, y coordinates. 3743 * @param srcOff the offset to the first vector to be transformed 3744 * in the source array 3745 * @param dstOff the offset to the location of the first 3746 * transformed vector that is stored in the destination array 3747 * @param numPts the number of vector coordinate pairs to be 3748 * transformed 3749 * @since 1.2 3750 */ deltaTransform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, int numPts)3751 public void deltaTransform(double[] srcPts, int srcOff, 3752 double[] dstPts, int dstOff, 3753 int numPts) { 3754 double M00, M01, M10, M11; // For caching 3755 if (dstPts == srcPts && 3756 dstOff > srcOff && dstOff < srcOff + numPts * 2) 3757 { 3758 // If the arrays overlap partially with the destination higher 3759 // than the source and we transform the coordinates normally 3760 // we would overwrite some of the later source coordinates 3761 // with results of previous transformations. 3762 // To get around this we use arraycopy to copy the points 3763 // to their final destination with correct overwrite 3764 // handling and then transform them in place in the new 3765 // safer location. 3766 System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts * 2); 3767 // srcPts = dstPts; // They are known to be equal. 3768 srcOff = dstOff; 3769 } 3770 switch (state) { 3771 default: 3772 stateError(); 3773 /* NOTREACHED */ 3774 return; 3775 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): 3776 case (APPLY_SHEAR | APPLY_SCALE): 3777 M00 = m00; M01 = m01; 3778 M10 = m10; M11 = m11; 3779 while (--numPts >= 0) { 3780 double x = srcPts[srcOff++]; 3781 double y = srcPts[srcOff++]; 3782 dstPts[dstOff++] = x * M00 + y * M01; 3783 dstPts[dstOff++] = x * M10 + y * M11; 3784 } 3785 return; 3786 case (APPLY_SHEAR | APPLY_TRANSLATE): 3787 case (APPLY_SHEAR): 3788 M01 = m01; M10 = m10; 3789 while (--numPts >= 0) { 3790 double x = srcPts[srcOff++]; 3791 dstPts[dstOff++] = srcPts[srcOff++] * M01; 3792 dstPts[dstOff++] = x * M10; 3793 } 3794 return; 3795 case (APPLY_SCALE | APPLY_TRANSLATE): 3796 case (APPLY_SCALE): 3797 M00 = m00; M11 = m11; 3798 while (--numPts >= 0) { 3799 dstPts[dstOff++] = srcPts[srcOff++] * M00; 3800 dstPts[dstOff++] = srcPts[srcOff++] * M11; 3801 } 3802 return; 3803 case (APPLY_TRANSLATE): 3804 case (APPLY_IDENTITY): 3805 if (srcPts != dstPts || srcOff != dstOff) { 3806 System.arraycopy(srcPts, srcOff, dstPts, dstOff, 3807 numPts * 2); 3808 } 3809 return; 3810 } 3811 3812 /* NOTREACHED */ 3813 } 3814 3815 /** 3816 * Returns a new {@link Shape} object defined by the geometry of the 3817 * specified <code>Shape</code> after it has been transformed by 3818 * this transform. 3819 * @param pSrc the specified <code>Shape</code> object to be 3820 * transformed by this transform. 3821 * @return a new <code>Shape</code> object that defines the geometry 3822 * of the transformed <code>Shape</code>, or null if {@code pSrc} is null. 3823 * @since 1.2 3824 */ createTransformedShape(Shape pSrc)3825 public Shape createTransformedShape(Shape pSrc) { 3826 if (pSrc == null) { 3827 return null; 3828 } 3829 return new Path2D.Double(pSrc, this); 3830 } 3831 3832 // Round values to sane precision for printing 3833 // Note that Math.sin(Math.PI) has an error of about 10^-16 _matround(double matval)3834 private static double _matround(double matval) { 3835 return Math.rint(matval * 1E15) / 1E15; 3836 } 3837 3838 /** 3839 * Returns a <code>String</code> that represents the value of this 3840 * {@link Object}. 3841 * @return a <code>String</code> representing the value of this 3842 * <code>Object</code>. 3843 * @since 1.2 3844 */ toString()3845 public String toString() { 3846 return ("AffineTransform[[" 3847 + _matround(m00) + ", " 3848 + _matround(m01) + ", " 3849 + _matround(m02) + "], [" 3850 + _matround(m10) + ", " 3851 + _matround(m11) + ", " 3852 + _matround(m12) + "]]"); 3853 } 3854 3855 /** 3856 * Returns <code>true</code> if this <code>AffineTransform</code> is 3857 * an identity transform. 3858 * @return <code>true</code> if this <code>AffineTransform</code> is 3859 * an identity transform; <code>false</code> otherwise. 3860 * @since 1.2 3861 */ isIdentity()3862 public boolean isIdentity() { 3863 return (state == APPLY_IDENTITY || (getType() == TYPE_IDENTITY)); 3864 } 3865 3866 /** 3867 * Returns a copy of this <code>AffineTransform</code> object. 3868 * @return an <code>Object</code> that is a copy of this 3869 * <code>AffineTransform</code> object. 3870 * @since 1.2 3871 */ clone()3872 public Object clone() { 3873 try { 3874 return super.clone(); 3875 } catch (CloneNotSupportedException e) { 3876 // this shouldn't happen, since we are Cloneable 3877 throw new InternalError(e); 3878 } 3879 } 3880 3881 /** 3882 * Returns the hashcode for this transform. 3883 * @return a hash code for this transform. 3884 * @since 1.2 3885 */ hashCode()3886 public int hashCode() { 3887 long bits = Double.doubleToLongBits(m00); 3888 bits = bits * 31 + Double.doubleToLongBits(m01); 3889 bits = bits * 31 + Double.doubleToLongBits(m02); 3890 bits = bits * 31 + Double.doubleToLongBits(m10); 3891 bits = bits * 31 + Double.doubleToLongBits(m11); 3892 bits = bits * 31 + Double.doubleToLongBits(m12); 3893 return (((int) bits) ^ ((int) (bits >> 32))); 3894 } 3895 3896 /** 3897 * Returns <code>true</code> if this <code>AffineTransform</code> 3898 * represents the same affine coordinate transform as the specified 3899 * argument. 3900 * @param obj the <code>Object</code> to test for equality with this 3901 * <code>AffineTransform</code> 3902 * @return <code>true</code> if <code>obj</code> equals this 3903 * <code>AffineTransform</code> object; <code>false</code> otherwise. 3904 * @since 1.2 3905 */ equals(Object obj)3906 public boolean equals(Object obj) { 3907 if (!(obj instanceof AffineTransform)) { 3908 return false; 3909 } 3910 3911 AffineTransform a = (AffineTransform)obj; 3912 3913 return ((m00 == a.m00) && (m01 == a.m01) && (m02 == a.m02) && 3914 (m10 == a.m10) && (m11 == a.m11) && (m12 == a.m12)); 3915 } 3916 3917 /* Serialization support. A readObject method is neccessary because 3918 * the state field is part of the implementation of this particular 3919 * AffineTransform and not part of the public specification. The 3920 * state variable's value needs to be recalculated on the fly by the 3921 * readObject method as it is in the 6-argument matrix constructor. 3922 */ 3923 3924 /* 3925 * JDK 1.2 serialVersionUID 3926 */ 3927 private static final long serialVersionUID = 1330973210523860834L; 3928 writeObject(java.io.ObjectOutputStream s)3929 private void writeObject(java.io.ObjectOutputStream s) 3930 throws java.lang.ClassNotFoundException, java.io.IOException 3931 { 3932 s.defaultWriteObject(); 3933 } 3934 readObject(java.io.ObjectInputStream s)3935 private void readObject(java.io.ObjectInputStream s) 3936 throws java.lang.ClassNotFoundException, java.io.IOException 3937 { 3938 s.defaultReadObject(); 3939 updateState(); 3940 } 3941 } 3942