0001 /*
0002 * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved.
0003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004 *
0005 * This code is free software; you can redistribute it and/or modify it
0006 * under the terms of the GNU General Public License version 2 only, as
0007 * published by the Free Software Foundation. Sun designates this
0008 * particular file as subject to the "Classpath" exception as provided
0009 * by Sun in the LICENSE file that accompanied this code.
0010 *
0011 * This code is distributed in the hope that it will be useful, but WITHOUT
0012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014 * version 2 for more details (a copy is included in the LICENSE file that
0015 * accompanied this code).
0016 *
0017 * You should have received a copy of the GNU General Public License version
0018 * 2 along with this work; if not, write to the Free Software Foundation,
0019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020 *
0021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022 * CA 95054 USA or visit www.sun.com if you need additional information or
0023 * have any questions.
0024 */
0025
0026 package java.awt.geom;
0027
0028 import java.awt.Shape;
0029
0030 /**
0031 * The <code>AffineTransform</code> class represents a 2D affine transform
0032 * that performs a linear mapping from 2D coordinates to other 2D
0033 * coordinates that preserves the "straightness" and
0034 * "parallelness" of lines. Affine transformations can be constructed
0035 * using sequences of translations, scales, flips, rotations, and shears.
0036 * <p>
0037 * Such a coordinate transformation can be represented by a 3 row by
0038 * 3 column matrix with an implied last row of [ 0 0 1 ]. This matrix
0039 * transforms source coordinates {@code (x,y)} into
0040 * destination coordinates {@code (x',y')} by considering
0041 * them to be a column vector and multiplying the coordinate vector
0042 * by the matrix according to the following process:
0043 * <pre>
0044 * [ x'] [ m00 m01 m02 ] [ x ] [ m00x + m01y + m02 ]
0045 * [ y'] = [ m10 m11 m12 ] [ y ] = [ m10x + m11y + m12 ]
0046 * [ 1 ] [ 0 0 1 ] [ 1 ] [ 1 ]
0047 * </pre>
0048 * <p>
0049 * <a name="quadrantapproximation"><h4>Handling 90-Degree Rotations</h4></a>
0050 * <p>
0051 * In some variations of the <code>rotate</code> methods in the
0052 * <code>AffineTransform</code> class, a double-precision argument
0053 * specifies the angle of rotation in radians.
0054 * These methods have special handling for rotations of approximately
0055 * 90 degrees (including multiples such as 180, 270, and 360 degrees),
0056 * so that the common case of quadrant rotation is handled more
0057 * efficiently.
0058 * This special handling can cause angles very close to multiples of
0059 * 90 degrees to be treated as if they were exact multiples of
0060 * 90 degrees.
0061 * For small multiples of 90 degrees the range of angles treated
0062 * as a quadrant rotation is approximately 0.00000121 degrees wide.
0063 * This section explains why such special care is needed and how
0064 * it is implemented.
0065 * <p>
0066 * Since 90 degrees is represented as <code>PI/2</code> in radians,
0067 * and since PI is a transcendental (and therefore irrational) number,
0068 * it is not possible to exactly represent a multiple of 90 degrees as
0069 * an exact double precision value measured in radians.
0070 * As a result it is theoretically impossible to describe quadrant
0071 * rotations (90, 180, 270 or 360 degrees) using these values.
0072 * Double precision floating point values can get very close to
0073 * non-zero multiples of <code>PI/2</code> but never close enough
0074 * for the sine or cosine to be exactly 0.0, 1.0 or -1.0.
0075 * The implementations of <code>Math.sin()</code> and
0076 * <code>Math.cos()</code> correspondingly never return 0.0
0077 * for any case other than <code>Math.sin(0.0)</code>.
0078 * These same implementations do, however, return exactly 1.0 and
0079 * -1.0 for some range of numbers around each multiple of 90
0080 * degrees since the correct answer is so close to 1.0 or -1.0 that
0081 * the double precision significand cannot represent the difference
0082 * as accurately as it can for numbers that are near 0.0.
0083 * <p>
0084 * The net result of these issues is that if the
0085 * <code>Math.sin()</code> and <code>Math.cos()</code> methods
0086 * are used to directly generate the values for the matrix modifications
0087 * during these radian-based rotation operations then the resulting
0088 * transform is never strictly classifiable as a quadrant rotation
0089 * even for a simple case like <code>rotate(Math.PI/2.0)</code>,
0090 * due to minor variations in the matrix caused by the non-0.0 values
0091 * obtained for the sine and cosine.
0092 * If these transforms are not classified as quadrant rotations then
0093 * subsequent code which attempts to optimize further operations based
0094 * upon the type of the transform will be relegated to its most general
0095 * implementation.
0096 * <p>
0097 * Because quadrant rotations are fairly common,
0098 * this class should handle these cases reasonably quickly, both in
0099 * applying the rotations to the transform and in applying the resulting
0100 * transform to the coordinates.
0101 * To facilitate this optimal handling, the methods which take an angle
0102 * of rotation measured in radians attempt to detect angles that are
0103 * intended to be quadrant rotations and treat them as such.
0104 * These methods therefore treat an angle <em>theta</em> as a quadrant
0105 * rotation if either <code>Math.sin(<em>theta</em>)</code> or
0106 * <code>Math.cos(<em>theta</em>)</code> returns exactly 1.0 or -1.0.
0107 * As a rule of thumb, this property holds true for a range of
0108 * approximately 0.0000000211 radians (or 0.00000121 degrees) around
0109 * small multiples of <code>Math.PI/2.0</code>.
0110 *
0111 * @version 1.83, 05/05/07
0112 * @author Jim Graham
0113 * @since 1.2
0114 */
0115 public class AffineTransform implements Cloneable, java.io.Serializable {
0116
0117 /*
0118 * This constant is only useful for the cached type field.
0119 * It indicates that the type has been decached and must be recalculated.
0120 */
0121 private static final int TYPE_UNKNOWN = -1;
0122
0123 /**
0124 * This constant indicates that the transform defined by this object
0125 * is an identity transform.
0126 * An identity transform is one in which the output coordinates are
0127 * always the same as the input coordinates.
0128 * If this transform is anything other than the identity transform,
0129 * the type will either be the constant GENERAL_TRANSFORM or a
0130 * combination of the appropriate flag bits for the various coordinate
0131 * conversions that this transform performs.
0132 * @see #TYPE_TRANSLATION
0133 * @see #TYPE_UNIFORM_SCALE
0134 * @see #TYPE_GENERAL_SCALE
0135 * @see #TYPE_FLIP
0136 * @see #TYPE_QUADRANT_ROTATION
0137 * @see #TYPE_GENERAL_ROTATION
0138 * @see #TYPE_GENERAL_TRANSFORM
0139 * @see #getType
0140 * @since 1.2
0141 */
0142 public static final int TYPE_IDENTITY = 0;
0143
0144 /**
0145 * This flag bit indicates that the transform defined by this object
0146 * performs a translation in addition to the conversions indicated
0147 * by other flag bits.
0148 * A translation moves the coordinates by a constant amount in x
0149 * and y without changing the length or angle of vectors.
0150 * @see #TYPE_IDENTITY
0151 * @see #TYPE_UNIFORM_SCALE
0152 * @see #TYPE_GENERAL_SCALE
0153 * @see #TYPE_FLIP
0154 * @see #TYPE_QUADRANT_ROTATION
0155 * @see #TYPE_GENERAL_ROTATION
0156 * @see #TYPE_GENERAL_TRANSFORM
0157 * @see #getType
0158 * @since 1.2
0159 */
0160 public static final int TYPE_TRANSLATION = 1;
0161
0162 /**
0163 * This flag bit indicates that the transform defined by this object
0164 * performs a uniform scale in addition to the conversions indicated
0165 * by other flag bits.
0166 * A uniform scale multiplies the length of vectors by the same amount
0167 * in both the x and y directions without changing the angle between
0168 * vectors.
0169 * This flag bit is mutually exclusive with the TYPE_GENERAL_SCALE flag.
0170 * @see #TYPE_IDENTITY
0171 * @see #TYPE_TRANSLATION
0172 * @see #TYPE_GENERAL_SCALE
0173 * @see #TYPE_FLIP
0174 * @see #TYPE_QUADRANT_ROTATION
0175 * @see #TYPE_GENERAL_ROTATION
0176 * @see #TYPE_GENERAL_TRANSFORM
0177 * @see #getType
0178 * @since 1.2
0179 */
0180 public static final int TYPE_UNIFORM_SCALE = 2;
0181
0182 /**
0183 * This flag bit indicates that the transform defined by this object
0184 * performs a general scale in addition to the conversions indicated
0185 * by other flag bits.
0186 * A general scale multiplies the length of vectors by different
0187 * amounts in the x and y directions without changing the angle
0188 * between perpendicular vectors.
0189 * This flag bit is mutually exclusive with the TYPE_UNIFORM_SCALE flag.
0190 * @see #TYPE_IDENTITY
0191 * @see #TYPE_TRANSLATION
0192 * @see #TYPE_UNIFORM_SCALE
0193 * @see #TYPE_FLIP
0194 * @see #TYPE_QUADRANT_ROTATION
0195 * @see #TYPE_GENERAL_ROTATION
0196 * @see #TYPE_GENERAL_TRANSFORM
0197 * @see #getType
0198 * @since 1.2
0199 */
0200 public static final int TYPE_GENERAL_SCALE = 4;
0201
0202 /**
0203 * This constant is a bit mask for any of the scale flag bits.
0204 * @see #TYPE_UNIFORM_SCALE
0205 * @see #TYPE_GENERAL_SCALE
0206 * @since 1.2
0207 */
0208 public static final int TYPE_MASK_SCALE = (TYPE_UNIFORM_SCALE | TYPE_GENERAL_SCALE);
0209
0210 /**
0211 * This flag bit indicates that the transform defined by this object
0212 * performs a mirror image flip about some axis which changes the
0213 * normally right handed coordinate system into a left handed
0214 * system in addition to the conversions indicated by other flag bits.
0215 * A right handed coordinate system is one where the positive X
0216 * axis rotates counterclockwise to overlay the positive Y axis
0217 * similar to the direction that the fingers on your right hand
0218 * curl when you stare end on at your thumb.
0219 * A left handed coordinate system is one where the positive X
0220 * axis rotates clockwise to overlay the positive Y axis similar
0221 * to the direction that the fingers on your left hand curl.
0222 * There is no mathematical way to determine the angle of the
0223 * original flipping or mirroring transformation since all angles
0224 * of flip are identical given an appropriate adjusting rotation.
0225 * @see #TYPE_IDENTITY
0226 * @see #TYPE_TRANSLATION
0227 * @see #TYPE_UNIFORM_SCALE
0228 * @see #TYPE_GENERAL_SCALE
0229 * @see #TYPE_QUADRANT_ROTATION
0230 * @see #TYPE_GENERAL_ROTATION
0231 * @see #TYPE_GENERAL_TRANSFORM
0232 * @see #getType
0233 * @since 1.2
0234 */
0235 public static final int TYPE_FLIP = 64;
0236 /* NOTE: TYPE_FLIP was added after GENERAL_TRANSFORM was in public
0237 * circulation and the flag bits could no longer be conveniently
0238 * renumbered without introducing binary incompatibility in outside
0239 * code.
0240 */
0241
0242 /**
0243 * This flag bit indicates that the transform defined by this object
0244 * performs a quadrant rotation by some multiple of 90 degrees in
0245 * addition to the conversions indicated by other flag bits.
0246 * A rotation changes the angles of vectors by the same amount
0247 * regardless of the original direction of the vector and without
0248 * changing the length of the vector.
0249 * This flag bit is mutually exclusive with the TYPE_GENERAL_ROTATION flag.
0250 * @see #TYPE_IDENTITY
0251 * @see #TYPE_TRANSLATION
0252 * @see #TYPE_UNIFORM_SCALE
0253 * @see #TYPE_GENERAL_SCALE
0254 * @see #TYPE_FLIP
0255 * @see #TYPE_GENERAL_ROTATION
0256 * @see #TYPE_GENERAL_TRANSFORM
0257 * @see #getType
0258 * @since 1.2
0259 */
0260 public static final int TYPE_QUADRANT_ROTATION = 8;
0261
0262 /**
0263 * This flag bit indicates that the transform defined by this object
0264 * performs a rotation by an arbitrary angle in addition to the
0265 * conversions indicated by other flag bits.
0266 * A rotation changes the angles of vectors by the same amount
0267 * regardless of the original direction of the vector and without
0268 * changing the length of the vector.
0269 * This flag bit is mutually exclusive with the
0270 * TYPE_QUADRANT_ROTATION flag.
0271 * @see #TYPE_IDENTITY
0272 * @see #TYPE_TRANSLATION
0273 * @see #TYPE_UNIFORM_SCALE
0274 * @see #TYPE_GENERAL_SCALE
0275 * @see #TYPE_FLIP
0276 * @see #TYPE_QUADRANT_ROTATION
0277 * @see #TYPE_GENERAL_TRANSFORM
0278 * @see #getType
0279 * @since 1.2
0280 */
0281 public static final int TYPE_GENERAL_ROTATION = 16;
0282
0283 /**
0284 * This constant is a bit mask for any of the rotation flag bits.
0285 * @see #TYPE_QUADRANT_ROTATION
0286 * @see #TYPE_GENERAL_ROTATION
0287 * @since 1.2
0288 */
0289 public static final int TYPE_MASK_ROTATION = (TYPE_QUADRANT_ROTATION | TYPE_GENERAL_ROTATION);
0290
0291 /**
0292 * This constant indicates that the transform defined by this object
0293 * performs an arbitrary conversion of the input coordinates.
0294 * If this transform can be classified by any of the above constants,
0295 * the type will either be the constant TYPE_IDENTITY or a
0296 * combination of the appropriate flag bits for the various coordinate
0297 * conversions that this transform performs.
0298 * @see #TYPE_IDENTITY
0299 * @see #TYPE_TRANSLATION
0300 * @see #TYPE_UNIFORM_SCALE
0301 * @see #TYPE_GENERAL_SCALE
0302 * @see #TYPE_FLIP
0303 * @see #TYPE_QUADRANT_ROTATION
0304 * @see #TYPE_GENERAL_ROTATION
0305 * @see #getType
0306 * @since 1.2
0307 */
0308 public static final int TYPE_GENERAL_TRANSFORM = 32;
0309
0310 /**
0311 * This constant is used for the internal state variable to indicate
0312 * that no calculations need to be performed and that the source
0313 * coordinates only need to be copied to their destinations to
0314 * complete the transformation equation of this transform.
0315 * @see #APPLY_TRANSLATE
0316 * @see #APPLY_SCALE
0317 * @see #APPLY_SHEAR
0318 * @see #state
0319 */
0320 static final int APPLY_IDENTITY = 0;
0321
0322 /**
0323 * This constant is used for the internal state variable to indicate
0324 * that the translation components of the matrix (m02 and m12) need
0325 * to be added to complete the transformation equation of this transform.
0326 * @see #APPLY_IDENTITY
0327 * @see #APPLY_SCALE
0328 * @see #APPLY_SHEAR
0329 * @see #state
0330 */
0331 static final int APPLY_TRANSLATE = 1;
0332
0333 /**
0334 * This constant is used for the internal state variable to indicate
0335 * that the scaling components of the matrix (m00 and m11) need
0336 * to be factored in to complete the transformation equation of
0337 * this transform. If the APPLY_SHEAR bit is also set then it
0338 * indicates that the scaling components are not both 0.0. If the
0339 * APPLY_SHEAR bit is not also set then it indicates that the
0340 * scaling components are not both 1.0. If neither the APPLY_SHEAR
0341 * nor the APPLY_SCALE bits are set then the scaling components
0342 * are both 1.0, which means that the x and y components contribute
0343 * to the transformed coordinate, but they are not multiplied by
0344 * any scaling factor.
0345 * @see #APPLY_IDENTITY
0346 * @see #APPLY_TRANSLATE
0347 * @see #APPLY_SHEAR
0348 * @see #state
0349 */
0350 static final int APPLY_SCALE = 2;
0351
0352 /**
0353 * This constant is used for the internal state variable to indicate
0354 * that the shearing components of the matrix (m01 and m10) need
0355 * to be factored in to complete the transformation equation of this
0356 * transform. The presence of this bit in the state variable changes
0357 * the interpretation of the APPLY_SCALE bit as indicated in its
0358 * documentation.
0359 * @see #APPLY_IDENTITY
0360 * @see #APPLY_TRANSLATE
0361 * @see #APPLY_SCALE
0362 * @see #state
0363 */
0364 static final int APPLY_SHEAR = 4;
0365
0366 /*
0367 * For methods which combine together the state of two separate
0368 * transforms and dispatch based upon the combination, these constants
0369 * specify how far to shift one of the states so that the two states
0370 * are mutually non-interfering and provide constants for testing the
0371 * bits of the shifted (HI) state. The methods in this class use
0372 * the convention that the state of "this" transform is unshifted and
0373 * the state of the "other" or "argument" transform is shifted (HI).
0374 */
0375 private static final int HI_SHIFT = 3;
0376 private static final int HI_IDENTITY = APPLY_IDENTITY << HI_SHIFT;
0377 private static final int HI_TRANSLATE = APPLY_TRANSLATE << HI_SHIFT;
0378 private static final int HI_SCALE = APPLY_SCALE << HI_SHIFT;
0379 private static final int HI_SHEAR = APPLY_SHEAR << HI_SHIFT;
0380
0381 /**
0382 * The X coordinate scaling element of the 3x3
0383 * affine transformation matrix.
0384 *
0385 * @serial
0386 */
0387 double m00;
0388
0389 /**
0390 * The Y coordinate shearing element of the 3x3
0391 * affine transformation matrix.
0392 *
0393 * @serial
0394 */
0395 double m10;
0396
0397 /**
0398 * The X coordinate shearing element of the 3x3
0399 * affine transformation matrix.
0400 *
0401 * @serial
0402 */
0403 double m01;
0404
0405 /**
0406 * The Y coordinate scaling element of the 3x3
0407 * affine transformation matrix.
0408 *
0409 * @serial
0410 */
0411 double m11;
0412
0413 /**
0414 * The X coordinate of the translation element of the
0415 * 3x3 affine transformation matrix.
0416 *
0417 * @serial
0418 */
0419 double m02;
0420
0421 /**
0422 * The Y coordinate of the translation element of the
0423 * 3x3 affine transformation matrix.
0424 *
0425 * @serial
0426 */
0427 double m12;
0428
0429 /**
0430 * This field keeps track of which components of the matrix need to
0431 * be applied when performing a transformation.
0432 * @see #APPLY_IDENTITY
0433 * @see #APPLY_TRANSLATE
0434 * @see #APPLY_SCALE
0435 * @see #APPLY_SHEAR
0436 */
0437 transient int state;
0438
0439 /**
0440 * This field caches the current transformation type of the matrix.
0441 * @see #TYPE_IDENTITY
0442 * @see #TYPE_TRANSLATION
0443 * @see #TYPE_UNIFORM_SCALE
0444 * @see #TYPE_GENERAL_SCALE
0445 * @see #TYPE_FLIP
0446 * @see #TYPE_QUADRANT_ROTATION
0447 * @see #TYPE_GENERAL_ROTATION
0448 * @see #TYPE_GENERAL_TRANSFORM
0449 * @see #TYPE_UNKNOWN
0450 * @see #getType
0451 */
0452 private transient int type;
0453
0454 private AffineTransform(double m00, double m10, double m01,
0455 double m11, double m02, double m12, int state) {
0456 this .m00 = m00;
0457 this .m10 = m10;
0458 this .m01 = m01;
0459 this .m11 = m11;
0460 this .m02 = m02;
0461 this .m12 = m12;
0462 this .state = state;
0463 this .type = TYPE_UNKNOWN;
0464 }
0465
0466 /**
0467 * Constructs a new <code>AffineTransform</code> representing the
0468 * Identity transformation.
0469 * @since 1.2
0470 */
0471 public AffineTransform() {
0472 m00 = m11 = 1.0;
0473 // m01 = m10 = m02 = m12 = 0.0; /* Not needed. */
0474 // state = APPLY_IDENTITY; /* Not needed. */
0475 // type = TYPE_IDENTITY; /* Not needed. */
0476 }
0477
0478 /**
0479 * Constructs a new <code>AffineTransform</code> that is a copy of
0480 * the specified <code>AffineTransform</code> object.
0481 * @param Tx the <code>AffineTransform</code> object to copy
0482 * @since 1.2
0483 */
0484 public AffineTransform(AffineTransform Tx) {
0485 this .m00 = Tx.m00;
0486 this .m10 = Tx.m10;
0487 this .m01 = Tx.m01;
0488 this .m11 = Tx.m11;
0489 this .m02 = Tx.m02;
0490 this .m12 = Tx.m12;
0491 this .state = Tx.state;
0492 this .type = Tx.type;
0493 }
0494
0495 /**
0496 * Constructs a new <code>AffineTransform</code> from 6 floating point
0497 * values representing the 6 specifiable entries of the 3x3
0498 * transformation matrix.
0499 *
0500 * @param m00 the X coordinate scaling element of the 3x3 matrix
0501 * @param m10 the Y coordinate shearing element of the 3x3 matrix
0502 * @param m01 the X coordinate shearing element of the 3x3 matrix
0503 * @param m11 the Y coordinate scaling element of the 3x3 matrix
0504 * @param m02 the X coordinate translation element of the 3x3 matrix
0505 * @param m12 the Y coordinate translation element of the 3x3 matrix
0506 * @since 1.2
0507 */
0508 public AffineTransform(float m00, float m10, float m01, float m11,
0509 float m02, float m12) {
0510 this .m00 = m00;
0511 this .m10 = m10;
0512 this .m01 = m01;
0513 this .m11 = m11;
0514 this .m02 = m02;
0515 this .m12 = m12;
0516 updateState();
0517 }
0518
0519 /**
0520 * Constructs a new <code>AffineTransform</code> from an array of
0521 * floating point values representing either the 4 non-translation
0522 * enries or the 6 specifiable entries of the 3x3 transformation
0523 * matrix. The values are retrieved from the array as
0524 * { m00 m10 m01 m11 [m02 m12]}.
0525 * @param flatmatrix the float array containing the values to be set
0526 * in the new <code>AffineTransform</code> object. The length of the
0527 * array is assumed to be at least 4. If the length of the array is
0528 * less than 6, only the first 4 values are taken. If the length of
0529 * the array is greater than 6, the first 6 values are taken.
0530 * @since 1.2
0531 */
0532 public AffineTransform(float[] flatmatrix) {
0533 m00 = flatmatrix[0];
0534 m10 = flatmatrix[1];
0535 m01 = flatmatrix[2];
0536 m11 = flatmatrix[3];
0537 if (flatmatrix.length > 5) {
0538 m02 = flatmatrix[4];
0539 m12 = flatmatrix[5];
0540 }
0541 updateState();
0542 }
0543
0544 /**
0545 * Constructs a new <code>AffineTransform</code> from 6 double
0546 * precision values representing the 6 specifiable entries of the 3x3
0547 * transformation matrix.
0548 *
0549 * @param m00 the X coordinate scaling element of the 3x3 matrix
0550 * @param m10 the Y coordinate shearing element of the 3x3 matrix
0551 * @param m01 the X coordinate shearing element of the 3x3 matrix
0552 * @param m11 the Y coordinate scaling element of the 3x3 matrix
0553 * @param m02 the X coordinate translation element of the 3x3 matrix
0554 * @param m12 the Y coordinate translation element of the 3x3 matrix
0555 * @since 1.2
0556 */
0557 public AffineTransform(double m00, double m10, double m01,
0558 double m11, double m02, double m12) {
0559 this .m00 = m00;
0560 this .m10 = m10;
0561 this .m01 = m01;
0562 this .m11 = m11;
0563 this .m02 = m02;
0564 this .m12 = m12;
0565 updateState();
0566 }
0567
0568 /**
0569 * Constructs a new <code>AffineTransform</code> from an array of
0570 * double precision values representing either the 4 non-translation
0571 * entries or the 6 specifiable entries of the 3x3 transformation
0572 * matrix. The values are retrieved from the array as
0573 * { m00 m10 m01 m11 [m02 m12]}.
0574 * @param flatmatrix the double array containing the values to be set
0575 * in the new <code>AffineTransform</code> object. The length of the
0576 * array is assumed to be at least 4. If the length of the array is
0577 * less than 6, only the first 4 values are taken. If the length of
0578 * the array is greater than 6, the first 6 values are taken.
0579 * @since 1.2
0580 */
0581 public AffineTransform(double[] flatmatrix) {
0582 m00 = flatmatrix[0];
0583 m10 = flatmatrix[1];
0584 m01 = flatmatrix[2];
0585 m11 = flatmatrix[3];
0586 if (flatmatrix.length > 5) {
0587 m02 = flatmatrix[4];
0588 m12 = flatmatrix[5];
0589 }
0590 updateState();
0591 }
0592
0593 /**
0594 * Returns a transform representing a translation transformation.
0595 * The matrix representing the returned transform is:
0596 * <pre>
0597 * [ 1 0 tx ]
0598 * [ 0 1 ty ]
0599 * [ 0 0 1 ]
0600 * </pre>
0601 * @param tx the distance by which coordinates are translated in the
0602 * X axis direction
0603 * @param ty the distance by which coordinates are translated in the
0604 * Y axis direction
0605 * @return an <code>AffineTransform</code> object that represents a
0606 * translation transformation, created with the specified vector.
0607 * @since 1.2
0608 */
0609 public static AffineTransform getTranslateInstance(double tx,
0610 double ty) {
0611 AffineTransform Tx = new AffineTransform();
0612 Tx.setToTranslation(tx, ty);
0613 return Tx;
0614 }
0615
0616 /**
0617 * Returns a transform representing a rotation transformation.
0618 * The matrix representing the returned transform is:
0619 * <pre>
0620 * [ cos(theta) -sin(theta) 0 ]
0621 * [ sin(theta) cos(theta) 0 ]
0622 * [ 0 0 1 ]
0623 * </pre>
0624 * Rotating by a positive angle theta rotates points on the positive
0625 * X axis toward the positive Y axis.
0626 * Note also the discussion of
0627 * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
0628 * above.
0629 * @param theta the angle of rotation measured in radians
0630 * @return an <code>AffineTransform</code> object that is a rotation
0631 * transformation, created with the specified angle of rotation.
0632 * @since 1.2
0633 */
0634 public static AffineTransform getRotateInstance(double theta) {
0635 AffineTransform Tx = new AffineTransform();
0636 Tx.setToRotation(theta);
0637 return Tx;
0638 }
0639
0640 /**
0641 * Returns a transform that rotates coordinates around an anchor point.
0642 * This operation is equivalent to translating the coordinates so
0643 * that the anchor point is at the origin (S1), then rotating them
0644 * about the new origin (S2), and finally translating so that the
0645 * intermediate origin is restored to the coordinates of the original
0646 * anchor point (S3).
0647 * <p>
0648 * This operation is equivalent to the following sequence of calls:
0649 * <pre>
0650 * AffineTransform Tx = new AffineTransform();
0651 * Tx.translate(anchorx, anchory); // S3: final translation
0652 * Tx.rotate(theta); // S2: rotate around anchor
0653 * Tx.translate(-anchorx, -anchory); // S1: translate anchor to origin
0654 * </pre>
0655 * The matrix representing the returned transform is:
0656 * <pre>
0657 * [ cos(theta) -sin(theta) x-x*cos+y*sin ]
0658 * [ sin(theta) cos(theta) y-x*sin-y*cos ]
0659 * [ 0 0 1 ]
0660 * </pre>
0661 * Rotating by a positive angle theta rotates points on the positive
0662 * X axis toward the positive Y axis.
0663 * Note also the discussion of
0664 * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
0665 * above.
0666 *
0667 * @param theta the angle of rotation measured in radians
0668 * @param anchorx the X coordinate of the rotation anchor point
0669 * @param anchory the Y coordinate of the rotation anchor point
0670 * @return an <code>AffineTransform</code> object that rotates
0671 * coordinates around the specified point by the specified angle of
0672 * rotation.
0673 * @since 1.2
0674 */
0675 public static AffineTransform getRotateInstance(double theta,
0676 double anchorx, double anchory) {
0677 AffineTransform Tx = new AffineTransform();
0678 Tx.setToRotation(theta, anchorx, anchory);
0679 return Tx;
0680 }
0681
0682 /**
0683 * Returns a transform that rotates coordinates according to
0684 * a rotation vector.
0685 * All coordinates rotate about the origin by the same amount.
0686 * The amount of rotation is such that coordinates along the former
0687 * positive X axis will subsequently align with the vector pointing
0688 * from the origin to the specified vector coordinates.
0689 * If both <code>vecx</code> and <code>vecy</code> are 0.0,
0690 * an identity transform is returned.
0691 * This operation is equivalent to calling:
0692 * <pre>
0693 * AffineTransform.getRotateInstance(Math.atan2(vecy, vecx));
0694 * </pre>
0695 *
0696 * @param vecx the X coordinate of the rotation vector
0697 * @param vecy the Y coordinate of the rotation vector
0698 * @return an <code>AffineTransform</code> object that rotates
0699 * coordinates according to the specified rotation vector.
0700 * @since 1.6
0701 */
0702 public static AffineTransform getRotateInstance(double vecx,
0703 double vecy) {
0704 AffineTransform Tx = new AffineTransform();
0705 Tx.setToRotation(vecx, vecy);
0706 return Tx;
0707 }
0708
0709 /**
0710 * Returns a transform that rotates coordinates around an anchor
0711 * point accordinate to a rotation vector.
0712 * All coordinates rotate about the specified anchor coordinates
0713 * by the same amount.
0714 * The amount of rotation is such that coordinates along the former
0715 * positive X axis will subsequently align with the vector pointing
0716 * from the origin to the specified vector coordinates.
0717 * If both <code>vecx</code> and <code>vecy</code> are 0.0,
0718 * an identity transform is returned.
0719 * This operation is equivalent to calling:
0720 * <pre>
0721 * AffineTransform.getRotateInstance(Math.atan2(vecy, vecx),
0722 * anchorx, anchory);
0723 * </pre>
0724 *
0725 * @param vecx the X coordinate of the rotation vector
0726 * @param vecy the Y coordinate of the rotation vector
0727 * @param anchorx the X coordinate of the rotation anchor point
0728 * @param anchory the Y coordinate of the rotation anchor point
0729 * @return an <code>AffineTransform</code> object that rotates
0730 * coordinates around the specified point according to the
0731 * specified rotation vector.
0732 * @since 1.6
0733 */
0734 public static AffineTransform getRotateInstance(double vecx,
0735 double vecy, double anchorx, double anchory) {
0736 AffineTransform Tx = new AffineTransform();
0737 Tx.setToRotation(vecx, vecy, anchorx, anchory);
0738 return Tx;
0739 }
0740
0741 /**
0742 * Returns a transform that rotates coordinates by the specified
0743 * number of quadrants.
0744 * This operation is equivalent to calling:
0745 * <pre>
0746 * AffineTransform.getRotateInstance(numquadrants * Math.PI / 2.0);
0747 * </pre>
0748 * Rotating by a positive number of quadrants rotates points on
0749 * the positive X axis toward the positive Y axis.
0750 * @param numquadrants the number of 90 degree arcs to rotate by
0751 * @return an <code>AffineTransform</code> object that rotates
0752 * coordinates by the specified number of quadrants.
0753 * @since 1.6
0754 */
0755 public static AffineTransform getQuadrantRotateInstance(
0756 int numquadrants) {
0757 AffineTransform Tx = new AffineTransform();
0758 Tx.setToQuadrantRotation(numquadrants);
0759 return Tx;
0760 }
0761
0762 /**
0763 * Returns a transform that rotates coordinates by the specified
0764 * number of quadrants around the specified anchor point.
0765 * This operation is equivalent to calling:
0766 * <pre>
0767 * AffineTransform.getRotateInstance(numquadrants * Math.PI / 2.0,
0768 * anchorx, anchory);
0769 * </pre>
0770 * Rotating by a positive number of quadrants rotates points on
0771 * the positive X axis toward the positive Y axis.
0772 *
0773 * @param numquadrants the number of 90 degree arcs to rotate by
0774 * @param anchorx the X coordinate of the rotation anchor point
0775 * @param anchory the Y coordinate of the rotation anchor point
0776 * @return an <code>AffineTransform</code> object that rotates
0777 * coordinates by the specified number of quadrants around the
0778 * specified anchor point.
0779 * @since 1.6
0780 */
0781 public static AffineTransform getQuadrantRotateInstance(
0782 int numquadrants, double anchorx, double anchory) {
0783 AffineTransform Tx = new AffineTransform();
0784 Tx.setToQuadrantRotation(numquadrants, anchorx, anchory);
0785 return Tx;
0786 }
0787
0788 /**
0789 * Returns a transform representing a scaling transformation.
0790 * The matrix representing the returned transform is:
0791 * <pre>
0792 * [ sx 0 0 ]
0793 * [ 0 sy 0 ]
0794 * [ 0 0 1 ]
0795 * </pre>
0796 * @param sx the factor by which coordinates are scaled along the
0797 * X axis direction
0798 * @param sy the factor by which coordinates are scaled along the
0799 * Y axis direction
0800 * @return an <code>AffineTransform</code> object that scales
0801 * coordinates by the specified factors.
0802 * @since 1.2
0803 */
0804 public static AffineTransform getScaleInstance(double sx, double sy) {
0805 AffineTransform Tx = new AffineTransform();
0806 Tx.setToScale(sx, sy);
0807 return Tx;
0808 }
0809
0810 /**
0811 * Returns a transform representing a shearing transformation.
0812 * The matrix representing the returned transform is:
0813 * <pre>
0814 * [ 1 shx 0 ]
0815 * [ shy 1 0 ]
0816 * [ 0 0 1 ]
0817 * </pre>
0818 * @param shx the multiplier by which coordinates are shifted in the
0819 * direction of the positive X axis as a factor of their Y coordinate
0820 * @param shy the multiplier by which coordinates are shifted in the
0821 * direction of the positive Y axis as a factor of their X coordinate
0822 * @return an <code>AffineTransform</code> object that shears
0823 * coordinates by the specified multipliers.
0824 * @since 1.2
0825 */
0826 public static AffineTransform getShearInstance(double shx,
0827 double shy) {
0828 AffineTransform Tx = new AffineTransform();
0829 Tx.setToShear(shx, shy);
0830 return Tx;
0831 }
0832
0833 /**
0834 * Retrieves the flag bits describing the conversion properties of
0835 * this transform.
0836 * The return value is either one of the constants TYPE_IDENTITY
0837 * or TYPE_GENERAL_TRANSFORM, or a combination of the
0838 * appriopriate flag bits.
0839 * A valid combination of flag bits is an exclusive OR operation
0840 * that can combine
0841 * the TYPE_TRANSLATION flag bit
0842 * in addition to either of the
0843 * TYPE_UNIFORM_SCALE or TYPE_GENERAL_SCALE flag bits
0844 * as well as either of the
0845 * TYPE_QUADRANT_ROTATION or TYPE_GENERAL_ROTATION flag bits.
0846 * @return the OR combination of any of the indicated flags that
0847 * apply to this transform
0848 * @see #TYPE_IDENTITY
0849 * @see #TYPE_TRANSLATION
0850 * @see #TYPE_UNIFORM_SCALE
0851 * @see #TYPE_GENERAL_SCALE
0852 * @see #TYPE_QUADRANT_ROTATION
0853 * @see #TYPE_GENERAL_ROTATION
0854 * @see #TYPE_GENERAL_TRANSFORM
0855 * @since 1.2
0856 */
0857 public int getType() {
0858 if (type == TYPE_UNKNOWN) {
0859 calculateType();
0860 }
0861 return type;
0862 }
0863
0864 /**
0865 * This is the utility function to calculate the flag bits when
0866 * they have not been cached.
0867 * @see #getType
0868 */
0869 private void calculateType() {
0870 int ret = TYPE_IDENTITY;
0871 boolean sgn0, sgn1;
0872 double M0, M1, M2, M3;
0873 updateState();
0874 switch (state) {
0875 default:
0876 stateError();
0877 /* NOTREACHED */
0878 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
0879 ret = TYPE_TRANSLATION;
0880 /* NOBREAK */
0881 case (APPLY_SHEAR | APPLY_SCALE):
0882 if ((M0 = m00) * (M2 = m01) + (M3 = m10) * (M1 = m11) != 0) {
0883 // Transformed unit vectors are not perpendicular...
0884 this .type = TYPE_GENERAL_TRANSFORM;
0885 return;
0886 }
0887 sgn0 = (M0 >= 0.0);
0888 sgn1 = (M1 >= 0.0);
0889 if (sgn0 == sgn1) {
0890 // sgn(M0) == sgn(M1) therefore sgn(M2) == -sgn(M3)
0891 // This is the "unflipped" (right-handed) state
0892 if (M0 != M1 || M2 != -M3) {
0893 ret |= (TYPE_GENERAL_ROTATION | TYPE_GENERAL_SCALE);
0894 } else if (M0 * M1 - M2 * M3 != 1.0) {
0895 ret |= (TYPE_GENERAL_ROTATION | TYPE_UNIFORM_SCALE);
0896 } else {
0897 ret |= TYPE_GENERAL_ROTATION;
0898 }
0899 } else {
0900 // sgn(M0) == -sgn(M1) therefore sgn(M2) == sgn(M3)
0901 // This is the "flipped" (left-handed) state
0902 if (M0 != -M1 || M2 != M3) {
0903 ret |= (TYPE_GENERAL_ROTATION | TYPE_FLIP | TYPE_GENERAL_SCALE);
0904 } else if (M0 * M1 - M2 * M3 != 1.0) {
0905 ret |= (TYPE_GENERAL_ROTATION | TYPE_FLIP | TYPE_UNIFORM_SCALE);
0906 } else {
0907 ret |= (TYPE_GENERAL_ROTATION | TYPE_FLIP);
0908 }
0909 }
0910 break;
0911 case (APPLY_SHEAR | APPLY_TRANSLATE):
0912 ret = TYPE_TRANSLATION;
0913 /* NOBREAK */
0914 case (APPLY_SHEAR):
0915 sgn0 = ((M0 = m01) >= 0.0);
0916 sgn1 = ((M1 = m10) >= 0.0);
0917 if (sgn0 != sgn1) {
0918 // Different signs - simple 90 degree rotation
0919 if (M0 != -M1) {
0920 ret |= (TYPE_QUADRANT_ROTATION | TYPE_GENERAL_SCALE);
0921 } else if (M0 != 1.0 && M0 != -1.0) {
0922 ret |= (TYPE_QUADRANT_ROTATION | TYPE_UNIFORM_SCALE);
0923 } else {
0924 ret |= TYPE_QUADRANT_ROTATION;
0925 }
0926 } else {
0927 // Same signs - 90 degree rotation plus an axis flip too
0928 if (M0 == M1) {
0929 ret |= (TYPE_QUADRANT_ROTATION | TYPE_FLIP | TYPE_UNIFORM_SCALE);
0930 } else {
0931 ret |= (TYPE_QUADRANT_ROTATION | TYPE_FLIP | TYPE_GENERAL_SCALE);
0932 }
0933 }
0934 break;
0935 case (APPLY_SCALE | APPLY_TRANSLATE):
0936 ret = TYPE_TRANSLATION;
0937 /* NOBREAK */
0938 case (APPLY_SCALE):
0939 sgn0 = ((M0 = m00) >= 0.0);
0940 sgn1 = ((M1 = m11) >= 0.0);
0941 if (sgn0 == sgn1) {
0942 if (sgn0) {
0943 // Both scaling factors non-negative - simple scale
0944 // Note: APPLY_SCALE implies M0, M1 are not both 1
0945 if (M0 == M1) {
0946 ret |= TYPE_UNIFORM_SCALE;
0947 } else {
0948 ret |= TYPE_GENERAL_SCALE;
0949 }
0950 } else {
0951 // Both scaling factors negative - 180 degree rotation
0952 if (M0 != M1) {
0953 ret |= (TYPE_QUADRANT_ROTATION | TYPE_GENERAL_SCALE);
0954 } else if (M0 != -1.0) {
0955 ret |= (TYPE_QUADRANT_ROTATION | TYPE_UNIFORM_SCALE);
0956 } else {
0957 ret |= TYPE_QUADRANT_ROTATION;
0958 }
0959 }
0960 } else {
0961 // Scaling factor signs different - flip about some axis
0962 if (M0 == -M1) {
0963 if (M0 == 1.0 || M0 == -1.0) {
0964 ret |= TYPE_FLIP;
0965 } else {
0966 ret |= (TYPE_FLIP | TYPE_UNIFORM_SCALE);
0967 }
0968 } else {
0969 ret |= (TYPE_FLIP | TYPE_GENERAL_SCALE);
0970 }
0971 }
0972 break;
0973 case (APPLY_TRANSLATE):
0974 ret = TYPE_TRANSLATION;
0975 break;
0976 case (APPLY_IDENTITY):
0977 break;
0978 }
0979 this .type = ret;
0980 }
0981
0982 /**
0983 * Returns the determinant of the matrix representation of the transform.
0984 * The determinant is useful both to determine if the transform can
0985 * be inverted and to get a single value representing the
0986 * combined X and Y scaling of the transform.
0987 * <p>
0988 * If the determinant is non-zero, then this transform is
0989 * invertible and the various methods that depend on the inverse
0990 * transform do not need to throw a
0991 * {@link NoninvertibleTransformException}.
0992 * If the determinant is zero then this transform can not be
0993 * inverted since the transform maps all input coordinates onto
0994 * a line or a point.
0995 * If the determinant is near enough to zero then inverse transform
0996 * operations might not carry enough precision to produce meaningful
0997 * results.
0998 * <p>
0999 * If this transform represents a uniform scale, as indicated by
1000 * the <code>getType</code> method then the determinant also
1001 * represents the square of the uniform scale factor by which all of
1002 * the points are expanded from or contracted towards the origin.
1003 * If this transform represents a non-uniform scale or more general
1004 * transform then the determinant is not likely to represent a
1005 * value useful for any purpose other than determining if inverse
1006 * transforms are possible.
1007 * <p>
1008 * Mathematically, the determinant is calculated using the formula:
1009 * <pre>
1010 * | m00 m01 m02 |
1011 * | m10 m11 m12 | = m00 * m11 - m01 * m10
1012 * | 0 0 1 |
1013 * </pre>
1014 *
1015 * @return the determinant of the matrix used to transform the
1016 * coordinates.
1017 * @see #getType
1018 * @see #createInverse
1019 * @see #inverseTransform
1020 * @see #TYPE_UNIFORM_SCALE
1021 * @since 1.2
1022 */
1023 public double getDeterminant() {
1024 switch (state) {
1025 default:
1026 stateError();
1027 /* NOTREACHED */
1028 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1029 case (APPLY_SHEAR | APPLY_SCALE):
1030 return m00 * m11 - m01 * m10;
1031 case (APPLY_SHEAR | APPLY_TRANSLATE):
1032 case (APPLY_SHEAR):
1033 return -(m01 * m10);
1034 case (APPLY_SCALE | APPLY_TRANSLATE):
1035 case (APPLY_SCALE):
1036 return m00 * m11;
1037 case (APPLY_TRANSLATE):
1038 case (APPLY_IDENTITY):
1039 return 1.0;
1040 }
1041 }
1042
1043 /**
1044 * Manually recalculates the state of the transform when the matrix
1045 * changes too much to predict the effects on the state.
1046 * The following table specifies what the various settings of the
1047 * state field say about the values of the corresponding matrix
1048 * element fields.
1049 * Note that the rules governing the SCALE fields are slightly
1050 * different depending on whether the SHEAR flag is also set.
1051 * <pre>
1052 * SCALE SHEAR TRANSLATE
1053 * m00/m11 m01/m10 m02/m12
1054 *
1055 * IDENTITY 1.0 0.0 0.0
1056 * TRANSLATE (TR) 1.0 0.0 not both 0.0
1057 * SCALE (SC) not both 1.0 0.0 0.0
1058 * TR | SC not both 1.0 0.0 not both 0.0
1059 * SHEAR (SH) 0.0 not both 0.0 0.0
1060 * TR | SH 0.0 not both 0.0 not both 0.0
1061 * SC | SH not both 0.0 not both 0.0 0.0
1062 * TR | SC | SH not both 0.0 not both 0.0 not both 0.0
1063 * </pre>
1064 */
1065 void updateState() {
1066 if (m01 == 0.0 && m10 == 0.0) {
1067 if (m00 == 1.0 && m11 == 1.0) {
1068 if (m02 == 0.0 && m12 == 0.0) {
1069 state = APPLY_IDENTITY;
1070 type = TYPE_IDENTITY;
1071 } else {
1072 state = APPLY_TRANSLATE;
1073 type = TYPE_TRANSLATION;
1074 }
1075 } else {
1076 if (m02 == 0.0 && m12 == 0.0) {
1077 state = APPLY_SCALE;
1078 type = TYPE_UNKNOWN;
1079 } else {
1080 state = (APPLY_SCALE | APPLY_TRANSLATE);
1081 type = TYPE_UNKNOWN;
1082 }
1083 }
1084 } else {
1085 if (m00 == 0.0 && m11 == 0.0) {
1086 if (m02 == 0.0 && m12 == 0.0) {
1087 state = APPLY_SHEAR;
1088 type = TYPE_UNKNOWN;
1089 } else {
1090 state = (APPLY_SHEAR | APPLY_TRANSLATE);
1091 type = TYPE_UNKNOWN;
1092 }
1093 } else {
1094 if (m02 == 0.0 && m12 == 0.0) {
1095 state = (APPLY_SHEAR | APPLY_SCALE);
1096 type = TYPE_UNKNOWN;
1097 } else {
1098 state = (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE);
1099 type = TYPE_UNKNOWN;
1100 }
1101 }
1102 }
1103 }
1104
1105 /*
1106 * Convenience method used internally to throw exceptions when
1107 * a case was forgotten in a switch statement.
1108 */
1109 private void stateError() {
1110 throw new InternalError(
1111 "missing case in transform state switch");
1112 }
1113
1114 /**
1115 * Retrieves the 6 specifiable values in the 3x3 affine transformation
1116 * matrix and places them into an array of double precisions values.
1117 * The values are stored in the array as
1118 * { m00 m10 m01 m11 m02 m12 }.
1119 * An array of 4 doubles can also be specified, in which case only the
1120 * first four elements representing the non-transform
1121 * parts of the array are retrieved and the values are stored into
1122 * the array as { m00 m10 m01 m11 }
1123 * @param flatmatrix the double array used to store the returned
1124 * values.
1125 * @see #getScaleX
1126 * @see #getScaleY
1127 * @see #getShearX
1128 * @see #getShearY
1129 * @see #getTranslateX
1130 * @see #getTranslateY
1131 * @since 1.2
1132 */
1133 public void getMatrix(double[] flatmatrix) {
1134 flatmatrix[0] = m00;
1135 flatmatrix[1] = m10;
1136 flatmatrix[2] = m01;
1137 flatmatrix[3] = m11;
1138 if (flatmatrix.length > 5) {
1139 flatmatrix[4] = m02;
1140 flatmatrix[5] = m12;
1141 }
1142 }
1143
1144 /**
1145 * Returns the X coordinate scaling element (m00) of the 3x3
1146 * affine transformation matrix.
1147 * @return a double value that is the X coordinate of the scaling
1148 * element of the affine transformation matrix.
1149 * @see #getMatrix
1150 * @since 1.2
1151 */
1152 public double getScaleX() {
1153 return m00;
1154 }
1155
1156 /**
1157 * Returns the Y coordinate scaling element (m11) of the 3x3
1158 * affine transformation matrix.
1159 * @return a double value that is the Y coordinate of the scaling
1160 * element of the affine transformation matrix.
1161 * @see #getMatrix
1162 * @since 1.2
1163 */
1164 public double getScaleY() {
1165 return m11;
1166 }
1167
1168 /**
1169 * Returns the X coordinate shearing element (m01) of the 3x3
1170 * affine transformation matrix.
1171 * @return a double value that is the X coordinate of the shearing
1172 * element of the affine transformation matrix.
1173 * @see #getMatrix
1174 * @since 1.2
1175 */
1176 public double getShearX() {
1177 return m01;
1178 }
1179
1180 /**
1181 * Returns the Y coordinate shearing element (m10) of the 3x3
1182 * affine transformation matrix.
1183 * @return a double value that is the Y coordinate of the shearing
1184 * element of the affine transformation matrix.
1185 * @see #getMatrix
1186 * @since 1.2
1187 */
1188 public double getShearY() {
1189 return m10;
1190 }
1191
1192 /**
1193 * Returns the X coordinate of the translation element (m02) of the
1194 * 3x3 affine transformation matrix.
1195 * @return a double value that is the X coordinate of the translation
1196 * element of the affine transformation matrix.
1197 * @see #getMatrix
1198 * @since 1.2
1199 */
1200 public double getTranslateX() {
1201 return m02;
1202 }
1203
1204 /**
1205 * Returns the Y coordinate of the translation element (m12) of the
1206 * 3x3 affine transformation matrix.
1207 * @return a double value that is the Y coordinate of the translation
1208 * element of the affine transformation matrix.
1209 * @see #getMatrix
1210 * @since 1.2
1211 */
1212 public double getTranslateY() {
1213 return m12;
1214 }
1215
1216 /**
1217 * Concatenates this transform with a translation transformation.
1218 * This is equivalent to calling concatenate(T), where T is an
1219 * <code>AffineTransform</code> represented by the following matrix:
1220 * <pre>
1221 * [ 1 0 tx ]
1222 * [ 0 1 ty ]
1223 * [ 0 0 1 ]
1224 * </pre>
1225 * @param tx the distance by which coordinates are translated in the
1226 * X axis direction
1227 * @param ty the distance by which coordinates are translated in the
1228 * Y axis direction
1229 * @since 1.2
1230 */
1231 public void translate(double tx, double ty) {
1232 switch (state) {
1233 default:
1234 stateError();
1235 /* NOTREACHED */
1236 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1237 m02 = tx * m00 + ty * m01 + m02;
1238 m12 = tx * m10 + ty * m11 + m12;
1239 if (m02 == 0.0 && m12 == 0.0) {
1240 state = APPLY_SHEAR | APPLY_SCALE;
1241 if (type != TYPE_UNKNOWN) {
1242 type -= TYPE_TRANSLATION;
1243 }
1244 }
1245 return;
1246 case (APPLY_SHEAR | APPLY_SCALE):
1247 m02 = tx * m00 + ty * m01;
1248 m12 = tx * m10 + ty * m11;
1249 if (m02 != 0.0 || m12 != 0.0) {
1250 state = APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE;
1251 type |= TYPE_TRANSLATION;
1252 }
1253 return;
1254 case (APPLY_SHEAR | APPLY_TRANSLATE):
1255 m02 = ty * m01 + m02;
1256 m12 = tx * m10 + m12;
1257 if (m02 == 0.0 && m12 == 0.0) {
1258 state = APPLY_SHEAR;
1259 if (type != TYPE_UNKNOWN) {
1260 type -= TYPE_TRANSLATION;
1261 }
1262 }
1263 return;
1264 case (APPLY_SHEAR):
1265 m02 = ty * m01;
1266 m12 = tx * m10;
1267 if (m02 != 0.0 || m12 != 0.0) {
1268 state = APPLY_SHEAR | APPLY_TRANSLATE;
1269 type |= TYPE_TRANSLATION;
1270 }
1271 return;
1272 case (APPLY_SCALE | APPLY_TRANSLATE):
1273 m02 = tx * m00 + m02;
1274 m12 = ty * m11 + m12;
1275 if (m02 == 0.0 && m12 == 0.0) {
1276 state = APPLY_SCALE;
1277 if (type != TYPE_UNKNOWN) {
1278 type -= TYPE_TRANSLATION;
1279 }
1280 }
1281 return;
1282 case (APPLY_SCALE):
1283 m02 = tx * m00;
1284 m12 = ty * m11;
1285 if (m02 != 0.0 || m12 != 0.0) {
1286 state = APPLY_SCALE | APPLY_TRANSLATE;
1287 type |= TYPE_TRANSLATION;
1288 }
1289 return;
1290 case (APPLY_TRANSLATE):
1291 m02 = tx + m02;
1292 m12 = ty + m12;
1293 if (m02 == 0.0 && m12 == 0.0) {
1294 state = APPLY_IDENTITY;
1295 type = TYPE_IDENTITY;
1296 }
1297 return;
1298 case (APPLY_IDENTITY):
1299 m02 = tx;
1300 m12 = ty;
1301 if (tx != 0.0 || ty != 0.0) {
1302 state = APPLY_TRANSLATE;
1303 type = TYPE_TRANSLATION;
1304 }
1305 return;
1306 }
1307 }
1308
1309 // Utility methods to optimize rotate methods.
1310 // These tables translate the flags during predictable quadrant
1311 // rotations where the shear and scale values are swapped and negated.
1312 private static final int rot90conversion[] = {
1313 /* IDENTITY => */APPLY_SHEAR,
1314 /* TRANSLATE (TR) => */APPLY_SHEAR | APPLY_TRANSLATE,
1315 /* SCALE (SC) => */APPLY_SHEAR,
1316 /* SC | TR => */APPLY_SHEAR | APPLY_TRANSLATE,
1317 /* SHEAR (SH) => */APPLY_SCALE,
1318 /* SH | TR => */APPLY_SCALE | APPLY_TRANSLATE,
1319 /* SH | SC => */APPLY_SHEAR | APPLY_SCALE,
1320 /* SH | SC | TR => */APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE, };
1321
1322 private final void rotate90() {
1323 double M0 = m00;
1324 m00 = m01;
1325 m01 = -M0;
1326 M0 = m10;
1327 m10 = m11;
1328 m11 = -M0;
1329 int state = rot90conversion[this .state];
1330 if ((state & (APPLY_SHEAR | APPLY_SCALE)) == APPLY_SCALE
1331 && m00 == 1.0 && m11 == 1.0) {
1332 state -= APPLY_SCALE;
1333 }
1334 this .state = state;
1335 type = TYPE_UNKNOWN;
1336 }
1337
1338 private final void rotate180() {
1339 m00 = -m00;
1340 m11 = -m11;
1341 int state = this .state;
1342 if ((state & (APPLY_SHEAR)) != 0) {
1343 // If there was a shear, then this rotation has no
1344 // effect on the state.
1345 m01 = -m01;
1346 m10 = -m10;
1347 } else {
1348 // No shear means the SCALE state may toggle when
1349 // m00 and m11 are negated.
1350 if (m00 == 1.0 && m11 == 1.0) {
1351 this .state = state & ~APPLY_SCALE;
1352 } else {
1353 this .state = state | APPLY_SCALE;
1354 }
1355 }
1356 type = TYPE_UNKNOWN;
1357 }
1358
1359 private final void rotate270() {
1360 double M0 = m00;
1361 m00 = -m01;
1362 m01 = M0;
1363 M0 = m10;
1364 m10 = -m11;
1365 m11 = M0;
1366 int state = rot90conversion[this .state];
1367 if ((state & (APPLY_SHEAR | APPLY_SCALE)) == APPLY_SCALE
1368 && m00 == 1.0 && m11 == 1.0) {
1369 state -= APPLY_SCALE;
1370 }
1371 this .state = state;
1372 type = TYPE_UNKNOWN;
1373 }
1374
1375 /**
1376 * Concatenates this transform with a rotation transformation.
1377 * This is equivalent to calling concatenate(R), where R is an
1378 * <code>AffineTransform</code> represented by the following matrix:
1379 * <pre>
1380 * [ cos(theta) -sin(theta) 0 ]
1381 * [ sin(theta) cos(theta) 0 ]
1382 * [ 0 0 1 ]
1383 * </pre>
1384 * Rotating by a positive angle theta rotates points on the positive
1385 * X axis toward the positive Y axis.
1386 * Note also the discussion of
1387 * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
1388 * above.
1389 * @param theta the angle of rotation measured in radians
1390 * @since 1.2
1391 */
1392 public void rotate(double theta) {
1393 double sin = Math.sin(theta);
1394 if (sin == 1.0) {
1395 rotate90();
1396 } else if (sin == -1.0) {
1397 rotate270();
1398 } else {
1399 double cos = Math.cos(theta);
1400 if (cos == -1.0) {
1401 rotate180();
1402 } else if (cos != 1.0) {
1403 double M0, M1;
1404 M0 = m00;
1405 M1 = m01;
1406 m00 = cos * M0 + sin * M1;
1407 m01 = -sin * M0 + cos * M1;
1408 M0 = m10;
1409 M1 = m11;
1410 m10 = cos * M0 + sin * M1;
1411 m11 = -sin * M0 + cos * M1;
1412 updateState();
1413 }
1414 }
1415 }
1416
1417 /**
1418 * Concatenates this transform with a transform that rotates
1419 * coordinates around an anchor point.
1420 * This operation is equivalent to translating the coordinates so
1421 * that the anchor point is at the origin (S1), then rotating them
1422 * about the new origin (S2), and finally translating so that the
1423 * intermediate origin is restored to the coordinates of the original
1424 * anchor point (S3).
1425 * <p>
1426 * This operation is equivalent to the following sequence of calls:
1427 * <pre>
1428 * translate(anchorx, anchory); // S3: final translation
1429 * rotate(theta); // S2: rotate around anchor
1430 * translate(-anchorx, -anchory); // S1: translate anchor to origin
1431 * </pre>
1432 * Rotating by a positive angle theta rotates points on the positive
1433 * X axis toward the positive Y axis.
1434 * Note also the discussion of
1435 * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
1436 * above.
1437 *
1438 * @param theta the angle of rotation measured in radians
1439 * @param anchorx the X coordinate of the rotation anchor point
1440 * @param anchory the Y coordinate of the rotation anchor point
1441 * @since 1.2
1442 */
1443 public void rotate(double theta, double anchorx, double anchory) {
1444 // REMIND: Simple for now - optimize later
1445 translate(anchorx, anchory);
1446 rotate(theta);
1447 translate(-anchorx, -anchory);
1448 }
1449
1450 /**
1451 * Concatenates this transform with a transform that rotates
1452 * coordinates according to a rotation vector.
1453 * All coordinates rotate about the origin by the same amount.
1454 * The amount of rotation is such that coordinates along the former
1455 * positive X axis will subsequently align with the vector pointing
1456 * from the origin to the specified vector coordinates.
1457 * If both <code>vecx</code> and <code>vecy</code> are 0.0,
1458 * no additional rotation is added to this transform.
1459 * This operation is equivalent to calling:
1460 * <pre>
1461 * rotate(Math.atan2(vecy, vecx));
1462 * </pre>
1463 *
1464 * @param vecx the X coordinate of the rotation vector
1465 * @param vecy the Y coordinate of the rotation vector
1466 * @since 1.6
1467 */
1468 public void rotate(double vecx, double vecy) {
1469 if (vecy == 0.0) {
1470 if (vecx < 0.0) {
1471 rotate180();
1472 }
1473 // If vecx > 0.0 - no rotation
1474 // If vecx == 0.0 - undefined rotation - treat as no rotation
1475 } else if (vecx == 0.0) {
1476 if (vecy > 0.0) {
1477 rotate90();
1478 } else { // vecy must be < 0.0
1479 rotate270();
1480 }
1481 } else {
1482 double len = Math.sqrt(vecx * vecx + vecy * vecy);
1483 double sin = vecy / len;
1484 double cos = vecx / len;
1485 double M0, M1;
1486 M0 = m00;
1487 M1 = m01;
1488 m00 = cos * M0 + sin * M1;
1489 m01 = -sin * M0 + cos * M1;
1490 M0 = m10;
1491 M1 = m11;
1492 m10 = cos * M0 + sin * M1;
1493 m11 = -sin * M0 + cos * M1;
1494 updateState();
1495 }
1496 }
1497
1498 /**
1499 * Concatenates this transform with a transform that rotates
1500 * coordinates around an anchor point according to a rotation
1501 * vector.
1502 * All coordinates rotate about the specified anchor coordinates
1503 * by the same amount.
1504 * The amount of rotation is such that coordinates along the former
1505 * positive X axis will subsequently align with the vector pointing
1506 * from the origin to the specified vector coordinates.
1507 * If both <code>vecx</code> and <code>vecy</code> are 0.0,
1508 * the transform is not modified in any way.
1509 * This method is equivalent to calling:
1510 * <pre>
1511 * rotate(Math.atan2(vecy, vecx), anchorx, anchory);
1512 * </pre>
1513 *
1514 * @param vecx the X coordinate of the rotation vector
1515 * @param vecy the Y coordinate of the rotation vector
1516 * @param anchorx the X coordinate of the rotation anchor point
1517 * @param anchory the Y coordinate of the rotation anchor point
1518 * @since 1.6
1519 */
1520 public void rotate(double vecx, double vecy, double anchorx,
1521 double anchory) {
1522 // REMIND: Simple for now - optimize later
1523 translate(anchorx, anchory);
1524 rotate(vecx, vecy);
1525 translate(-anchorx, -anchory);
1526 }
1527
1528 /**
1529 * Concatenates this transform with a transform that rotates
1530 * coordinates by the specified number of quadrants.
1531 * This is equivalent to calling:
1532 * <pre>
1533 * rotate(numquadrants * Math.PI / 2.0);
1534 * </pre>
1535 * Rotating by a positive number of quadrants rotates points on
1536 * the positive X axis toward the positive Y axis.
1537 * @param numquadrants the number of 90 degree arcs to rotate by
1538 * @since 1.6
1539 */
1540 public void quadrantRotate(int numquadrants) {
1541 switch (numquadrants & 3) {
1542 case 0:
1543 break;
1544 case 1:
1545 rotate90();
1546 break;
1547 case 2:
1548 rotate180();
1549 break;
1550 case 3:
1551 rotate270();
1552 break;
1553 }
1554 }
1555
1556 /**
1557 * Concatenates this transform with a transform that rotates
1558 * coordinates by the specified number of quadrants around
1559 * the specified anchor point.
1560 * This method is equivalent to calling:
1561 * <pre>
1562 * rotate(numquadrants * Math.PI / 2.0, anchorx, anchory);
1563 * </pre>
1564 * Rotating by a positive number of quadrants rotates points on
1565 * the positive X axis toward the positive Y axis.
1566 *
1567 * @param numquadrants the number of 90 degree arcs to rotate by
1568 * @param anchorx the X coordinate of the rotation anchor point
1569 * @param anchory the Y coordinate of the rotation anchor point
1570 * @since 1.6
1571 */
1572 public void quadrantRotate(int numquadrants, double anchorx,
1573 double anchory) {
1574 switch (numquadrants & 3) {
1575 case 0:
1576 return;
1577 case 1:
1578 m02 += anchorx * (m00 - m01) + anchory * (m01 + m00);
1579 m12 += anchorx * (m10 - m11) + anchory * (m11 + m10);
1580 rotate90();
1581 break;
1582 case 2:
1583 m02 += anchorx * (m00 + m00) + anchory * (m01 + m01);
1584 m12 += anchorx * (m10 + m10) + anchory * (m11 + m11);
1585 rotate180();
1586 break;
1587 case 3:
1588 m02 += anchorx * (m00 + m01) + anchory * (m01 - m00);
1589 m12 += anchorx * (m10 + m11) + anchory * (m11 - m10);
1590 rotate270();
1591 break;
1592 }
1593 if (m02 == 0.0 && m12 == 0.0) {
1594 state &= ~APPLY_TRANSLATE;
1595 } else {
1596 state |= APPLY_TRANSLATE;
1597 }
1598 }
1599
1600 /**
1601 * Concatenates this transform with a scaling transformation.
1602 * This is equivalent to calling concatenate(S), where S is an
1603 * <code>AffineTransform</code> represented by the following matrix:
1604 * <pre>
1605 * [ sx 0 0 ]
1606 * [ 0 sy 0 ]
1607 * [ 0 0 1 ]
1608 * </pre>
1609 * @param sx the factor by which coordinates are scaled along the
1610 * X axis direction
1611 * @param sy the factor by which coordinates are scaled along the
1612 * Y axis direction
1613 * @since 1.2
1614 */
1615 public void scale(double sx, double sy) {
1616 int state = this .state;
1617 switch (state) {
1618 default:
1619 stateError();
1620 /* NOTREACHED */
1621 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1622 case (APPLY_SHEAR | APPLY_SCALE):
1623 m00 *= sx;
1624 m11 *= sy;
1625 /* NOBREAK */
1626 case (APPLY_SHEAR | APPLY_TRANSLATE):
1627 case (APPLY_SHEAR):
1628 m01 *= sy;
1629 m10 *= sx;
1630 if (m01 == 0 && m10 == 0) {
1631 state &= APPLY_TRANSLATE;
1632 if (m00 == 1.0 && m11 == 1.0) {
1633 this .type = (state == APPLY_IDENTITY ? TYPE_IDENTITY
1634 : TYPE_TRANSLATION);
1635 } else {
1636 state |= APPLY_SCALE;
1637 this .type = TYPE_UNKNOWN;
1638 }
1639 this .state = state;
1640 }
1641 return;
1642 case (APPLY_SCALE | APPLY_TRANSLATE):
1643 case (APPLY_SCALE):
1644 m00 *= sx;
1645 m11 *= sy;
1646 if (m00 == 1.0 && m11 == 1.0) {
1647 this .state = (state &= APPLY_TRANSLATE);
1648 this .type = (state == APPLY_IDENTITY ? TYPE_IDENTITY
1649 : TYPE_TRANSLATION);
1650 } else {
1651 this .type = TYPE_UNKNOWN;
1652 }
1653 return;
1654 case (APPLY_TRANSLATE):
1655 case (APPLY_IDENTITY):
1656 m00 = sx;
1657 m11 = sy;
1658 if (sx != 1.0 || sy != 1.0) {
1659 this .state = state | APPLY_SCALE;
1660 this .type = TYPE_UNKNOWN;
1661 }
1662 return;
1663 }
1664 }
1665
1666 /**
1667 * Concatenates this transform with a shearing transformation.
1668 * This is equivalent to calling concatenate(SH), where SH is an
1669 * <code>AffineTransform</code> represented by the following matrix:
1670 * <pre>
1671 * [ 1 shx 0 ]
1672 * [ shy 1 0 ]
1673 * [ 0 0 1 ]
1674 * </pre>
1675 * @param shx the multiplier by which coordinates are shifted in the
1676 * direction of the positive X axis as a factor of their Y coordinate
1677 * @param shy the multiplier by which coordinates are shifted in the
1678 * direction of the positive Y axis as a factor of their X coordinate
1679 * @since 1.2
1680 */
1681 public void shear(double shx, double shy) {
1682 int state = this .state;
1683 switch (state) {
1684 default:
1685 stateError();
1686 /* NOTREACHED */
1687 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
1688 case (APPLY_SHEAR | APPLY_SCALE):
1689 double M0,
1690 M1;
1691 M0 = m00;
1692 M1 = m01;
1693 m00 = M0 + M1 * shy;
1694 m01 = M0 * shx + M1;
1695
1696 M0 = m10;
1697 M1 = m11;
1698 m10 = M0 + M1 * shy;
1699 m11 = M0 * shx + M1;
1700 updateState();
1701 return;
1702 case (APPLY_SHEAR | APPLY_TRANSLATE):
1703 case (APPLY_SHEAR):
1704 m00 = m01 * shy;
1705 m11 = m10 * shx;
1706 if (m00 != 0.0 || m11 != 0.0) {
1707 this .state = state | APPLY_SCALE;
1708 }
1709 this .type = TYPE_UNKNOWN;
1710 return;
1711 case (APPLY_SCALE | APPLY_TRANSLATE):
1712 case (APPLY_SCALE):
1713 m01 = m00 * shx;
1714 m10 = m11 * shy;
1715 if (m01 != 0.0 || m10 != 0.0) {
1716 this .state = state | APPLY_SHEAR;
1717 }
1718 this .type = TYPE_UNKNOWN;
1719 return;
1720 case (APPLY_TRANSLATE):
1721 case (APPLY_IDENTITY):
1722 m01 = shx;
1723 m10 = shy;
1724 if (m01 != 0.0 || m10 != 0.0) {
1725 this .state = state | APPLY_SCALE | APPLY_SHEAR;
1726 this .type = TYPE_UNKNOWN;
1727 }
1728 return;
1729 }
1730 }
1731
1732 /**
1733 * Resets this transform to the Identity transform.
1734 * @since 1.2
1735 */
1736 public void setToIdentity() {
1737 m00 = m11 = 1.0;
1738 m10 = m01 = m02 = m12 = 0.0;
1739 state = APPLY_IDENTITY;
1740 type = TYPE_IDENTITY;
1741 }
1742
1743 /**
1744 * Sets this transform to a translation transformation.
1745 * The matrix representing this transform becomes:
1746 * <pre>
1747 * [ 1 0 tx ]
1748 * [ 0 1 ty ]
1749 * [ 0 0 1 ]
1750 * </pre>
1751 * @param tx the distance by which coordinates are translated in the
1752 * X axis direction
1753 * @param ty the distance by which coordinates are translated in the
1754 * Y axis direction
1755 * @since 1.2
1756 */
1757 public void setToTranslation(double tx, double ty) {
1758 m00 = 1.0;
1759 m10 = 0.0;
1760 m01 = 0.0;
1761 m11 = 1.0;
1762 m02 = tx;
1763 m12 = ty;
1764 if (tx != 0.0 || ty != 0.0) {
1765 state = APPLY_TRANSLATE;
1766 type = TYPE_TRANSLATION;
1767 } else {
1768 state = APPLY_IDENTITY;
1769 type = TYPE_IDENTITY;
1770 }
1771 }
1772
1773 /**
1774 * Sets this transform to a rotation transformation.
1775 * The matrix representing this transform becomes:
1776 * <pre>
1777 * [ cos(theta) -sin(theta) 0 ]
1778 * [ sin(theta) cos(theta) 0 ]
1779 * [ 0 0 1 ]
1780 * </pre>
1781 * Rotating by a positive angle theta rotates points on the positive
1782 * X axis toward the positive Y axis.
1783 * Note also the discussion of
1784 * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
1785 * above.
1786 * @param theta the angle of rotation measured in radians
1787 * @since 1.2
1788 */
1789 public void setToRotation(double theta) {
1790 double sin = Math.sin(theta);
1791 double cos;
1792 if (sin == 1.0 || sin == -1.0) {
1793 cos = 0.0;
1794 state = APPLY_SHEAR;
1795 type = TYPE_QUADRANT_ROTATION;
1796 } else {
1797 cos = Math.cos(theta);
1798 if (cos == -1.0) {
1799 sin = 0.0;
1800 state = APPLY_SCALE;
1801 type = TYPE_QUADRANT_ROTATION;
1802 } else if (cos == 1.0) {
1803 sin = 0.0;
1804 state = APPLY_IDENTITY;
1805 type = TYPE_IDENTITY;
1806 } else {
1807 state = APPLY_SHEAR | APPLY_SCALE;
1808 type = TYPE_GENERAL_ROTATION;
1809 }
1810 }
1811 m00 = cos;
1812 m10 = sin;
1813 m01 = -sin;
1814 m11 = cos;
1815 m02 = 0.0;
1816 m12 = 0.0;
1817 }
1818
1819 /**
1820 * Sets this transform to a translated rotation transformation.
1821 * This operation is equivalent to translating the coordinates so
1822 * that the anchor point is at the origin (S1), then rotating them
1823 * about the new origin (S2), and finally translating so that the
1824 * intermediate origin is restored to the coordinates of the original
1825 * anchor point (S3).
1826 * <p>
1827 * This operation is equivalent to the following sequence of calls:
1828 * <pre>
1829 * setToTranslation(anchorx, anchory); // S3: final translation
1830 * rotate(theta); // S2: rotate around anchor
1831 * translate(-anchorx, -anchory); // S1: translate anchor to origin
1832 * </pre>
1833 * The matrix representing this transform becomes:
1834 * <pre>
1835 * [ cos(theta) -sin(theta) x-x*cos+y*sin ]
1836 * [ sin(theta) cos(theta) y-x*sin-y*cos ]
1837 * [ 0 0 1 ]
1838 * </pre>
1839 * Rotating by a positive angle theta rotates points on the positive
1840 * X axis toward the positive Y axis.
1841 * Note also the discussion of
1842 * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
1843 * above.
1844 *
1845 * @param theta the angle of rotation measured in radians
1846 * @param anchorx the X coordinate of the rotation anchor point
1847 * @param anchory the Y coordinate of the rotation anchor point
1848 * @since 1.2
1849 */
1850 public void setToRotation(double theta, double anchorx,
1851 double anchory) {
1852 setToRotation(theta);
1853 double sin = m10;
1854 double oneMinusCos = 1.0 - m00;
1855 m02 = anchorx * oneMinusCos + anchory * sin;
1856 m12 = anchory * oneMinusCos - anchorx * sin;
1857 if (m02 != 0.0 || m12 != 0.0) {
1858 state |= APPLY_TRANSLATE;
1859 type |= TYPE_TRANSLATION;
1860 }
1861 }
1862
1863 /**
1864 * Sets this transform to a rotation transformation that rotates
1865 * coordinates according to a rotation vector.
1866 * All coordinates rotate about the origin by the same amount.
1867 * The amount of rotation is such that coordinates along the former
1868 * positive X axis will subsequently align with the vector pointing
1869 * from the origin to the specified vector coordinates.
1870 * If both <code>vecx</code> and <code>vecy</code> are 0.0,
1871 * the transform is set to an identity transform.
1872 * This operation is equivalent to calling:
1873 * <pre>
1874 * setToRotation(Math.atan2(vecy, vecx));
1875 * </pre>
1876 *
1877 * @param vecx the X coordinate of the rotation vector
1878 * @param vecy the Y coordinate of the rotation vector
1879 * @since 1.6
1880 */
1881 public void setToRotation(double vecx, double vecy) {
1882 double sin, cos;
1883 if (vecy == 0) {
1884 sin = 0.0;
1885 if (vecx < 0.0) {
1886 cos = -1.0;
1887 state = APPLY_SCALE;
1888 type = TYPE_QUADRANT_ROTATION;
1889 } else {
1890 cos = 1.0;
1891 state = APPLY_IDENTITY;
1892 type = TYPE_IDENTITY;
1893 }
1894 } else if (vecx == 0) {
1895 cos = 0.0;
1896 sin = (vecy > 0.0) ? 1.0 : -1.0;
1897 state = APPLY_SHEAR;
1898 type = TYPE_QUADRANT_ROTATION;
1899 } else {
1900 double len = Math.sqrt(vecx * vecx + vecy * vecy);
1901 cos = vecx / len;
1902 sin = vecy / len;
1903 state = APPLY_SHEAR | APPLY_SCALE;
1904 type = TYPE_GENERAL_ROTATION;
1905 }
1906 m00 = cos;
1907 m10 = sin;
1908 m01 = -sin;
1909 m11 = cos;
1910 m02 = 0.0;
1911 m12 = 0.0;
1912 }
1913
1914 /**
1915 * Sets this transform to a rotation transformation that rotates
1916 * coordinates around an anchor point according to a rotation
1917 * vector.
1918 * All coordinates rotate about the specified anchor coordinates
1919 * by the same amount.
1920 * The amount of rotation is such that coordinates along the former
1921 * positive X axis will subsequently align with the vector pointing
1922 * from the origin to the specified vector coordinates.
1923 * If both <code>vecx</code> and <code>vecy</code> are 0.0,
1924 * the transform is set to an identity transform.
1925 * This operation is equivalent to calling:
1926 * <pre>
1927 * setToTranslation(Math.atan2(vecy, vecx), anchorx, anchory);
1928 * </pre>
1929 *
1930 * @param vecx the X coordinate of the rotation vector
1931 * @param vecy the Y coordinate of the rotation vector
1932 * @param anchorx the X coordinate of the rotation anchor point
1933 * @param anchory the Y coordinate of the rotation anchor point
1934 * @since 1.6
1935 */
1936 public void setToRotation(double vecx, double vecy, double anchorx,
1937 double anchory) {
1938 setToRotation(vecx, vecy);
1939 double sin = m10;
1940 double oneMinusCos = 1.0 - m00;
1941 m02 = anchorx * oneMinusCos + anchory * sin;
1942 m12 = anchory * oneMinusCos - anchorx * sin;
1943 if (m02 != 0.0 || m12 != 0.0) {
1944 state |= APPLY_TRANSLATE;
1945 type |= TYPE_TRANSLATION;
1946 }
1947 }
1948
1949 /**
1950 * Sets this transform to a rotation transformation that rotates
1951 * coordinates by the specified number of quadrants.
1952 * This operation is equivalent to calling:
1953 * <pre>
1954 * setToRotation(numquadrants * Math.PI / 2.0);
1955 * </pre>
1956 * Rotating by a positive number of quadrants rotates points on
1957 * the positive X axis toward the positive Y axis.
1958 * @param numquadrants the number of 90 degree arcs to rotate by
1959 * @since 1.6
1960 */
1961 public void setToQuadrantRotation(int numquadrants) {
1962 switch (numquadrants & 3) {
1963 case 0:
1964 m00 = 1.0;
1965 m10 = 0.0;
1966 m01 = 0.0;
1967 m11 = 1.0;
1968 m02 = 0.0;
1969 m12 = 0.0;
1970 state = APPLY_IDENTITY;
1971 type = TYPE_IDENTITY;
1972 break;
1973 case 1:
1974 m00 = 0.0;
1975 m10 = 1.0;
1976 m01 = -1.0;
1977 m11 = 0.0;
1978 m02 = 0.0;
1979 m12 = 0.0;
1980 state = APPLY_SHEAR;
1981 type = TYPE_QUADRANT_ROTATION;
1982 break;
1983 case 2:
1984 m00 = -1.0;
1985 m10 = 0.0;
1986 m01 = 0.0;
1987 m11 = -1.0;
1988 m02 = 0.0;
1989 m12 = 0.0;
1990 state = APPLY_SCALE;
1991 type = TYPE_QUADRANT_ROTATION;
1992 break;
1993 case 3:
1994 m00 = 0.0;
1995 m10 = -1.0;
1996 m01 = 1.0;
1997 m11 = 0.0;
1998 m02 = 0.0;
1999 m12 = 0.0;
2000 state = APPLY_SHEAR;
2001 type = TYPE_QUADRANT_ROTATION;
2002 break;
2003 }
2004 }
2005
2006 /**
2007 * Sets this transform to a translated rotation transformation
2008 * that rotates coordinates by the specified number of quadrants
2009 * around the specified anchor point.
2010 * This operation is equivalent to calling:
2011 * <pre>
2012 * setToRotation(numquadrants * Math.PI / 2.0, anchorx, anchory);
2013 * </pre>
2014 * Rotating by a positive number of quadrants rotates points on
2015 * the positive X axis toward the positive Y axis.
2016 *
2017 * @param numquadrants the number of 90 degree arcs to rotate by
2018 * @param anchorx the X coordinate of the rotation anchor point
2019 * @param anchory the Y coordinate of the rotation anchor point
2020 * @since 1.6
2021 */
2022 public void setToQuadrantRotation(int numquadrants, double anchorx,
2023 double anchory) {
2024 switch (numquadrants & 3) {
2025 case 0:
2026 m00 = 1.0;
2027 m10 = 0.0;
2028 m01 = 0.0;
2029 m11 = 1.0;
2030 m02 = 0.0;
2031 m12 = 0.0;
2032 state = APPLY_IDENTITY;
2033 type = TYPE_IDENTITY;
2034 break;
2035 case 1:
2036 m00 = 0.0;
2037 m10 = 1.0;
2038 m01 = -1.0;
2039 m11 = 0.0;
2040 m02 = anchorx + anchory;
2041 m12 = anchory - anchorx;
2042 if (m02 == 0.0 && m12 == 0.0) {
2043 state = APPLY_SHEAR;
2044 type = TYPE_QUADRANT_ROTATION;
2045 } else {
2046 state = APPLY_SHEAR | APPLY_TRANSLATE;
2047 type = TYPE_QUADRANT_ROTATION | TYPE_TRANSLATION;
2048 }
2049 break;
2050 case 2:
2051 m00 = -1.0;
2052 m10 = 0.0;
2053 m01 = 0.0;
2054 m11 = -1.0;
2055 m02 = anchorx + anchorx;
2056 m12 = anchory + anchory;
2057 if (m02 == 0.0 && m12 == 0.0) {
2058 state = APPLY_SCALE;
2059 type = TYPE_QUADRANT_ROTATION;
2060 } else {
2061 state = APPLY_SCALE | APPLY_TRANSLATE;
2062 type = TYPE_QUADRANT_ROTATION | TYPE_TRANSLATION;
2063 }
2064 break;
2065 case 3:
2066 m00 = 0.0;
2067 m10 = -1.0;
2068 m01 = 1.0;
2069 m11 = 0.0;
2070 m02 = anchorx - anchory;
2071 m12 = anchory + anchorx;
2072 if (m02 == 0.0 && m12 == 0.0) {
2073 state = APPLY_SHEAR;
2074 type = TYPE_QUADRANT_ROTATION;
2075 } else {
2076 state = APPLY_SHEAR | APPLY_TRANSLATE;
2077 type = TYPE_QUADRANT_ROTATION | TYPE_TRANSLATION;
2078 }
2079 break;
2080 }
2081 }
2082
2083 /**
2084 * Sets this transform to a scaling transformation.
2085 * The matrix representing this transform becomes:
2086 * <pre>
2087 * [ sx 0 0 ]
2088 * [ 0 sy 0 ]
2089 * [ 0 0 1 ]
2090 * </pre>
2091 * @param sx the factor by which coordinates are scaled along the
2092 * X axis direction
2093 * @param sy the factor by which coordinates are scaled along the
2094 * Y axis direction
2095 * @since 1.2
2096 */
2097 public void setToScale(double sx, double sy) {
2098 m00 = sx;
2099 m10 = 0.0;
2100 m01 = 0.0;
2101 m11 = sy;
2102 m02 = 0.0;
2103 m12 = 0.0;
2104 if (sx != 1.0 || sy != 1.0) {
2105 state = APPLY_SCALE;
2106 type = TYPE_UNKNOWN;
2107 } else {
2108 state = APPLY_IDENTITY;
2109 type = TYPE_IDENTITY;
2110 }
2111 }
2112
2113 /**
2114 * Sets this transform to a shearing transformation.
2115 * The matrix representing this transform becomes:
2116 * <pre>
2117 * [ 1 shx 0 ]
2118 * [ shy 1 0 ]
2119 * [ 0 0 1 ]
2120 * </pre>
2121 * @param shx the multiplier by which coordinates are shifted in the
2122 * direction of the positive X axis as a factor of their Y coordinate
2123 * @param shy the multiplier by which coordinates are shifted in the
2124 * direction of the positive Y axis as a factor of their X coordinate
2125 * @since 1.2
2126 */
2127 public void setToShear(double shx, double shy) {
2128 m00 = 1.0;
2129 m01 = shx;
2130 m10 = shy;
2131 m11 = 1.0;
2132 m02 = 0.0;
2133 m12 = 0.0;
2134 if (shx != 0.0 || shy != 0.0) {
2135 state = (APPLY_SHEAR | APPLY_SCALE);
2136 type = TYPE_UNKNOWN;
2137 } else {
2138 state = APPLY_IDENTITY;
2139 type = TYPE_IDENTITY;
2140 }
2141 }
2142
2143 /**
2144 * Sets this transform to a copy of the transform in the specified
2145 * <code>AffineTransform</code> object.
2146 * @param Tx the <code>AffineTransform</code> object from which to
2147 * copy the transform
2148 * @since 1.2
2149 */
2150 public void setTransform(AffineTransform Tx) {
2151 this .m00 = Tx.m00;
2152 this .m10 = Tx.m10;
2153 this .m01 = Tx.m01;
2154 this .m11 = Tx.m11;
2155 this .m02 = Tx.m02;
2156 this .m12 = Tx.m12;
2157 this .state = Tx.state;
2158 this .type = Tx.type;
2159 }
2160
2161 /**
2162 * Sets this transform to the matrix specified by the 6
2163 * double precision values.
2164 *
2165 * @param m00 the X coordinate scaling element of the 3x3 matrix
2166 * @param m10 the Y coordinate shearing element of the 3x3 matrix
2167 * @param m01 the X coordinate shearing element of the 3x3 matrix
2168 * @param m11 the Y coordinate scaling element of the 3x3 matrix
2169 * @param m02 the X coordinate translation element of the 3x3 matrix
2170 * @param m12 the Y coordinate translation element of the 3x3 matrix
2171 * @since 1.2
2172 */
2173 public void setTransform(double m00, double m10, double m01,
2174 double m11, double m02, double m12) {
2175 this .m00 = m00;
2176 this .m10 = m10;
2177 this .m01 = m01;
2178 this .m11 = m11;
2179 this .m02 = m02;
2180 this .m12 = m12;
2181 updateState();
2182 }
2183
2184 /**
2185 * Concatenates an <code>AffineTransform</code> <code>Tx</code> to
2186 * this <code>AffineTransform</code> Cx in the most commonly useful
2187 * way to provide a new user space
2188 * that is mapped to the former user space by <code>Tx</code>.
2189 * Cx is updated to perform the combined transformation.
2190 * Transforming a point p by the updated transform Cx' is
2191 * equivalent to first transforming p by <code>Tx</code> and then
2192 * transforming the result by the original transform Cx like this:
2193 * Cx'(p) = Cx(Tx(p))
2194 * In matrix notation, if this transform Cx is
2195 * represented by the matrix [this] and <code>Tx</code> is represented
2196 * by the matrix [Tx] then this method does the following:
2197 * <pre>
2198 * [this] = [this] x [Tx]
2199 * </pre>
2200 * @param Tx the <code>AffineTransform</code> object to be
2201 * concatenated with this <code>AffineTransform</code> object.
2202 * @see #preConcatenate
2203 * @since 1.2
2204 */
2205 public void concatenate(AffineTransform Tx) {
2206 double M0, M1;
2207 double T00, T01, T10, T11;
2208 double T02, T12;
2209 int mystate = state;
2210 int txstate = Tx.state;
2211 switch ((txstate << HI_SHIFT) | mystate) {
2212
2213 /* ---------- Tx == IDENTITY cases ---------- */
2214 case (HI_IDENTITY | APPLY_IDENTITY):
2215 case (HI_IDENTITY | APPLY_TRANSLATE):
2216 case (HI_IDENTITY | APPLY_SCALE):
2217 case (HI_IDENTITY | APPLY_SCALE | APPLY_TRANSLATE):
2218 case (HI_IDENTITY | APPLY_SHEAR):
2219 case (HI_IDENTITY | APPLY_SHEAR | APPLY_TRANSLATE):
2220 case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE):
2221 case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2222 return;
2223
2224 /* ---------- this == IDENTITY cases ---------- */
2225 case (HI_SHEAR | HI_SCALE | HI_TRANSLATE | APPLY_IDENTITY):
2226 m01 = Tx.m01;
2227 m10 = Tx.m10;
2228 /* NOBREAK */
2229 case (HI_SCALE | HI_TRANSLATE | APPLY_IDENTITY):
2230 m00 = Tx.m00;
2231 m11 = Tx.m11;
2232 /* NOBREAK */
2233 case (HI_TRANSLATE | APPLY_IDENTITY):
2234 m02 = Tx.m02;
2235 m12 = Tx.m12;
2236 state = txstate;
2237 type = Tx.type;
2238 return;
2239 case (HI_SHEAR | HI_SCALE | APPLY_IDENTITY):
2240 m01 = Tx.m01;
2241 m10 = Tx.m10;
2242 /* NOBREAK */
2243 case (HI_SCALE | APPLY_IDENTITY):
2244 m00 = Tx.m00;
2245 m11 = Tx.m11;
2246 state = txstate;
2247 type = Tx.type;
2248 return;
2249 case (HI_SHEAR | HI_TRANSLATE | APPLY_IDENTITY):
2250 m02 = Tx.m02;
2251 m12 = Tx.m12;
2252 /* NOBREAK */
2253 case (HI_SHEAR | APPLY_IDENTITY):
2254 m01 = Tx.m01;
2255 m10 = Tx.m10;
2256 m00 = m11 = 0.0;
2257 state = txstate;
2258 type = Tx.type;
2259 return;
2260
2261 /* ---------- Tx == TRANSLATE cases ---------- */
2262 case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2263 case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE):
2264 case (HI_TRANSLATE | APPLY_SHEAR | APPLY_TRANSLATE):
2265 case (HI_TRANSLATE | APPLY_SHEAR):
2266 case (HI_TRANSLATE | APPLY_SCALE | APPLY_TRANSLATE):
2267 case (HI_TRANSLATE | APPLY_SCALE):
2268 case (HI_TRANSLATE | APPLY_TRANSLATE):
2269 translate(Tx.m02, Tx.m12);
2270 return;
2271
2272 /* ---------- Tx == SCALE cases ---------- */
2273 case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2274 case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE):
2275 case (HI_SCALE | APPLY_SHEAR | APPLY_TRANSLATE):
2276 case (HI_SCALE | APPLY_SHEAR):
2277 case (HI_SCALE | APPLY_SCALE | APPLY_TRANSLATE):
2278 case (HI_SCALE | APPLY_SCALE):
2279 case (HI_SCALE | APPLY_TRANSLATE):
2280 scale(Tx.m00, Tx.m11);
2281 return;
2282
2283 /* ---------- Tx == SHEAR cases ---------- */
2284 case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2285 case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE):
2286 T01 = Tx.m01;
2287 T10 = Tx.m10;
2288 M0 = m00;
2289 m00 = m01 * T10;
2290 m01 = M0 * T01;
2291 M0 = m10;
2292 m10 = m11 * T10;
2293 m11 = M0 * T01;
2294 type = TYPE_UNKNOWN;
2295 return;
2296 case (HI_SHEAR | APPLY_SHEAR | APPLY_TRANSLATE):
2297 case (HI_SHEAR | APPLY_SHEAR):
2298 m00 = m01 * Tx.m10;
2299 m01 = 0.0;
2300 m11 = m10 * Tx.m01;
2301 m10 = 0.0;
2302 state = mystate ^ (APPLY_SHEAR | APPLY_SCALE);
2303 type = TYPE_UNKNOWN;
2304 return;
2305 case (HI_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2306 case (HI_SHEAR | APPLY_SCALE):
2307 m01 = m00 * Tx.m01;
2308 m00 = 0.0;
2309 m10 = m11 * Tx.m10;
2310 m11 = 0.0;
2311 state = mystate ^ (APPLY_SHEAR | APPLY_SCALE);
2312 type = TYPE_UNKNOWN;
2313 return;
2314 case (HI_SHEAR | APPLY_TRANSLATE):
2315 m00 = 0.0;
2316 m01 = Tx.m01;
2317 m10 = Tx.m10;
2318 m11 = 0.0;
2319 state = APPLY_TRANSLATE | APPLY_SHEAR;
2320 type = TYPE_UNKNOWN;
2321 return;
2322 }
2323 // If Tx has more than one attribute, it is not worth optimizing
2324 // all of those cases...
2325 T00 = Tx.m00;
2326 T01 = Tx.m01;
2327 T02 = Tx.m02;
2328 T10 = Tx.m10;
2329 T11 = Tx.m11;
2330 T12 = Tx.m12;
2331 switch (mystate) {
2332 default:
2333 stateError();
2334 /* NOTREACHED */
2335 case (APPLY_SHEAR | APPLY_SCALE):
2336 state = mystate | txstate;
2337 /* NOBREAK */
2338 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2339 M0 = m00;
2340 M1 = m01;
2341 m00 = T00 * M0 + T10 * M1;
2342 m01 = T01 * M0 + T11 * M1;
2343 m02 += T02 * M0 + T12 * M1;
2344
2345 M0 = m10;
2346 M1 = m11;
2347 m10 = T00 * M0 + T10 * M1;
2348 m11 = T01 * M0 + T11 * M1;
2349 m12 += T02 * M0 + T12 * M1;
2350 type = TYPE_UNKNOWN;
2351 return;
2352
2353 case (APPLY_SHEAR | APPLY_TRANSLATE):
2354 case (APPLY_SHEAR):
2355 M0 = m01;
2356 m00 = T10 * M0;
2357 m01 = T11 * M0;
2358 m02 += T12 * M0;
2359
2360 M0 = m10;
2361 m10 = T00 * M0;
2362 m11 = T01 * M0;
2363 m12 += T02 * M0;
2364 break;
2365
2366 case (APPLY_SCALE | APPLY_TRANSLATE):
2367 case (APPLY_SCALE):
2368 M0 = m00;
2369 m00 = T00 * M0;
2370 m01 = T01 * M0;
2371 m02 += T02 * M0;
2372
2373 M0 = m11;
2374 m10 = T10 * M0;
2375 m11 = T11 * M0;
2376 m12 += T12 * M0;
2377 break;
2378
2379 case (APPLY_TRANSLATE):
2380 m00 = T00;
2381 m01 = T01;
2382 m02 += T02;
2383
2384 m10 = T10;
2385 m11 = T11;
2386 m12 += T12;
2387 state = txstate | APPLY_TRANSLATE;
2388 type = TYPE_UNKNOWN;
2389 return;
2390 }
2391 updateState();
2392 }
2393
2394 /**
2395 * Concatenates an <code>AffineTransform</code> <code>Tx</code> to
2396 * this <code>AffineTransform</code> Cx
2397 * in a less commonly used way such that <code>Tx</code> modifies the
2398 * coordinate transformation relative to the absolute pixel
2399 * space rather than relative to the existing user space.
2400 * Cx is updated to perform the combined transformation.
2401 * Transforming a point p by the updated transform Cx' is
2402 * equivalent to first transforming p by the original transform
2403 * Cx and then transforming the result by
2404 * <code>Tx</code> like this:
2405 * Cx'(p) = Tx(Cx(p))
2406 * In matrix notation, if this transform Cx
2407 * is represented by the matrix [this] and <code>Tx</code> is
2408 * represented by the matrix [Tx] then this method does the
2409 * following:
2410 * <pre>
2411 * [this] = [Tx] x [this]
2412 * </pre>
2413 * @param Tx the <code>AffineTransform</code> object to be
2414 * concatenated with this <code>AffineTransform</code> object.
2415 * @see #concatenate
2416 * @since 1.2
2417 */
2418 public void preConcatenate(AffineTransform Tx) {
2419 double M0, M1;
2420 double T00, T01, T10, T11;
2421 double T02, T12;
2422 int mystate = state;
2423 int txstate = Tx.state;
2424 switch ((txstate << HI_SHIFT) | mystate) {
2425 case (HI_IDENTITY | APPLY_IDENTITY):
2426 case (HI_IDENTITY | APPLY_TRANSLATE):
2427 case (HI_IDENTITY | APPLY_SCALE):
2428 case (HI_IDENTITY | APPLY_SCALE | APPLY_TRANSLATE):
2429 case (HI_IDENTITY | APPLY_SHEAR):
2430 case (HI_IDENTITY | APPLY_SHEAR | APPLY_TRANSLATE):
2431 case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE):
2432 case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2433 // Tx is IDENTITY...
2434 return;
2435
2436 case (HI_TRANSLATE | APPLY_IDENTITY):
2437 case (HI_TRANSLATE | APPLY_SCALE):
2438 case (HI_TRANSLATE | APPLY_SHEAR):
2439 case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE):
2440 // Tx is TRANSLATE, this has no TRANSLATE
2441 m02 = Tx.m02;
2442 m12 = Tx.m12;
2443 state = mystate | APPLY_TRANSLATE;
2444 type |= TYPE_TRANSLATION;
2445 return;
2446
2447 case (HI_TRANSLATE | APPLY_TRANSLATE):
2448 case (HI_TRANSLATE | APPLY_SCALE | APPLY_TRANSLATE):
2449 case (HI_TRANSLATE | APPLY_SHEAR | APPLY_TRANSLATE):
2450 case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2451 // Tx is TRANSLATE, this has one too
2452 m02 = m02 + Tx.m02;
2453 m12 = m12 + Tx.m12;
2454 return;
2455
2456 case (HI_SCALE | APPLY_TRANSLATE):
2457 case (HI_SCALE | APPLY_IDENTITY):
2458 // Only these two existing states need a new state
2459 state = mystate | APPLY_SCALE;
2460 /* NOBREAK */
2461 case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2462 case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE):
2463 case (HI_SCALE | APPLY_SHEAR | APPLY_TRANSLATE):
2464 case (HI_SCALE | APPLY_SHEAR):
2465 case (HI_SCALE | APPLY_SCALE | APPLY_TRANSLATE):
2466 case (HI_SCALE | APPLY_SCALE):
2467 // Tx is SCALE, this is anything
2468 T00 = Tx.m00;
2469 T11 = Tx.m11;
2470 if ((mystate & APPLY_SHEAR) != 0) {
2471 m01 = m01 * T00;
2472 m10 = m10 * T11;
2473 if ((mystate & APPLY_SCALE) != 0) {
2474 m00 = m00 * T00;
2475 m11 = m11 * T11;
2476 }
2477 } else {
2478 m00 = m00 * T00;
2479 m11 = m11 * T11;
2480 }
2481 if ((mystate & APPLY_TRANSLATE) != 0) {
2482 m02 = m02 * T00;
2483 m12 = m12 * T11;
2484 }
2485 type = TYPE_UNKNOWN;
2486 return;
2487 case (HI_SHEAR | APPLY_SHEAR | APPLY_TRANSLATE):
2488 case (HI_SHEAR | APPLY_SHEAR):
2489 mystate = mystate | APPLY_SCALE;
2490 /* NOBREAK */
2491 case (HI_SHEAR | APPLY_TRANSLATE):
2492 case (HI_SHEAR | APPLY_IDENTITY):
2493 case (HI_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2494 case (HI_SHEAR | APPLY_SCALE):
2495 state = mystate ^ APPLY_SHEAR;
2496 /* NOBREAK */
2497 case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2498 case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE):
2499 // Tx is SHEAR, this is anything
2500 T01 = Tx.m01;
2501 T10 = Tx.m10;
2502
2503 M0 = m00;
2504 m00 = m10 * T01;
2505 m10 = M0 * T10;
2506
2507 M0 = m01;
2508 m01 = m11 * T01;
2509 m11 = M0 * T10;
2510
2511 M0 = m02;
2512 m02 = m12 * T01;
2513 m12 = M0 * T10;
2514 type = TYPE_UNKNOWN;
2515 return;
2516 }
2517 // If Tx has more than one attribute, it is not worth optimizing
2518 // all of those cases...
2519 T00 = Tx.m00;
2520 T01 = Tx.m01;
2521 T02 = Tx.m02;
2522 T10 = Tx.m10;
2523 T11 = Tx.m11;
2524 T12 = Tx.m12;
2525 switch (mystate) {
2526 default:
2527 stateError();
2528 /* NOTREACHED */
2529 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2530 M0 = m02;
2531 M1 = m12;
2532 T02 += M0 * T00 + M1 * T01;
2533 T12 += M0 * T10 + M1 * T11;
2534
2535 /* NOBREAK */
2536 case (APPLY_SHEAR | APPLY_SCALE):
2537 m02 = T02;
2538 m12 = T12;
2539
2540 M0 = m00;
2541 M1 = m10;
2542 m00 = M0 * T00 + M1 * T01;
2543 m10 = M0 * T10 + M1 * T11;
2544
2545 M0 = m01;
2546 M1 = m11;
2547 m01 = M0 * T00 + M1 * T01;
2548 m11 = M0 * T10 + M1 * T11;
2549 break;
2550
2551 case (APPLY_SHEAR | APPLY_TRANSLATE):
2552 M0 = m02;
2553 M1 = m12;
2554 T02 += M0 * T00 + M1 * T01;
2555 T12 += M0 * T10 + M1 * T11;
2556
2557 /* NOBREAK */
2558 case (APPLY_SHEAR):
2559 m02 = T02;
2560 m12 = T12;
2561
2562 M0 = m10;
2563 m00 = M0 * T01;
2564 m10 = M0 * T11;
2565
2566 M0 = m01;
2567 m01 = M0 * T00;
2568 m11 = M0 * T10;
2569 break;
2570
2571 case (APPLY_SCALE | APPLY_TRANSLATE):
2572 M0 = m02;
2573 M1 = m12;
2574 T02 += M0 * T00 + M1 * T01;
2575 T12 += M0 * T10 + M1 * T11;
2576
2577 /* NOBREAK */
2578 case (APPLY_SCALE):
2579 m02 = T02;
2580 m12 = T12;
2581
2582 M0 = m00;
2583 m00 = M0 * T00;
2584 m10 = M0 * T10;
2585
2586 M0 = m11;
2587 m01 = M0 * T01;
2588 m11 = M0 * T11;
2589 break;
2590
2591 case (APPLY_TRANSLATE):
2592 M0 = m02;
2593 M1 = m12;
2594 T02 += M0 * T00 + M1 * T01;
2595 T12 += M0 * T10 + M1 * T11;
2596
2597 /* NOBREAK */
2598 case (APPLY_IDENTITY):
2599 m02 = T02;
2600 m12 = T12;
2601
2602 m00 = T00;
2603 m10 = T10;
2604
2605 m01 = T01;
2606 m11 = T11;
2607
2608 state = mystate | txstate;
2609 type = TYPE_UNKNOWN;
2610 return;
2611 }
2612 updateState();
2613 }
2614
2615 /**
2616 * Returns an <code>AffineTransform</code> object representing the
2617 * inverse transformation.
2618 * The inverse transform Tx' of this transform Tx
2619 * maps coordinates transformed by Tx back
2620 * to their original coordinates.
2621 * In other words, Tx'(Tx(p)) = p = Tx(Tx'(p)).
2622 * <p>
2623 * If this transform maps all coordinates onto a point or a line
2624 * then it will not have an inverse, since coordinates that do
2625 * not lie on the destination point or line will not have an inverse
2626 * mapping.
2627 * The <code>getDeterminant</code> method can be used to determine if this
2628 * transform has no inverse, in which case an exception will be
2629 * thrown if the <code>createInverse</code> method is called.
2630 * @return a new <code>AffineTransform</code> object representing the
2631 * inverse transformation.
2632 * @see #getDeterminant
2633 * @exception NoninvertibleTransformException
2634 * if the matrix cannot be inverted.
2635 * @since 1.2
2636 */
2637 public AffineTransform createInverse()
2638 throws NoninvertibleTransformException {
2639 double det;
2640 switch (state) {
2641 default:
2642 stateError();
2643 /* NOTREACHED */
2644 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2645 det = m00 * m11 - m01 * m10;
2646 if (Math.abs(det) <= Double.MIN_VALUE) {
2647 throw new NoninvertibleTransformException(
2648 "Determinant is " + det);
2649 }
2650 return new AffineTransform(m11 / det, -m10 / det, -m01
2651 / det, m00 / det, (m01 * m12 - m11 * m02) / det,
2652 (m10 * m02 - m00 * m12) / det, (APPLY_SHEAR
2653 | APPLY_SCALE | APPLY_TRANSLATE));
2654 case (APPLY_SHEAR | APPLY_SCALE):
2655 det = m00 * m11 - m01 * m10;
2656 if (Math.abs(det) <= Double.MIN_VALUE) {
2657 throw new NoninvertibleTransformException(
2658 "Determinant is " + det);
2659 }
2660 return new AffineTransform(m11 / det, -m10 / det, -m01
2661 / det, m00 / det, 0.0, 0.0,
2662 (APPLY_SHEAR | APPLY_SCALE));
2663 case (APPLY_SHEAR | APPLY_TRANSLATE):
2664 if (m01 == 0.0 || m10 == 0.0) {
2665 throw new NoninvertibleTransformException(
2666 "Determinant is 0");
2667 }
2668 return new AffineTransform(0.0, 1.0 / m01, 1.0 / m10, 0.0,
2669 -m12 / m10, -m02 / m01,
2670 (APPLY_SHEAR | APPLY_TRANSLATE));
2671 case (APPLY_SHEAR):
2672 if (m01 == 0.0 || m10 == 0.0) {
2673 throw new NoninvertibleTransformException(
2674 "Determinant is 0");
2675 }
2676 return new AffineTransform(0.0, 1.0 / m01, 1.0 / m10, 0.0,
2677 0.0, 0.0, (APPLY_SHEAR));
2678 case (APPLY_SCALE | APPLY_TRANSLATE):
2679 if (m00 == 0.0 || m11 == 0.0) {
2680 throw new NoninvertibleTransformException(
2681 "Determinant is 0");
2682 }
2683 return new AffineTransform(1.0 / m00, 0.0, 0.0, 1.0 / m11,
2684 -m02 / m00, -m12 / m11,
2685 (APPLY_SCALE | APPLY_TRANSLATE));
2686 case (APPLY_SCALE):
2687 if (m00 == 0.0 || m11 == 0.0) {
2688 throw new NoninvertibleTransformException(
2689 "Determinant is 0");
2690 }
2691 return new AffineTransform(1.0 / m00, 0.0, 0.0, 1.0 / m11,
2692 0.0, 0.0, (APPLY_SCALE));
2693 case (APPLY_TRANSLATE):
2694 return new AffineTransform(1.0, 0.0, 0.0, 1.0, -m02, -m12,
2695 (APPLY_TRANSLATE));
2696 case (APPLY_IDENTITY):
2697 return new AffineTransform();
2698 }
2699
2700 /* NOTREACHED */
2701 }
2702
2703 /**
2704 * Sets this transform to the inverse of itself.
2705 * The inverse transform Tx' of this transform Tx
2706 * maps coordinates transformed by Tx back
2707 * to their original coordinates.
2708 * In other words, Tx'(Tx(p)) = p = Tx(Tx'(p)).
2709 * <p>
2710 * If this transform maps all coordinates onto a point or a line
2711 * then it will not have an inverse, since coordinates that do
2712 * not lie on the destination point or line will not have an inverse
2713 * mapping.
2714 * The <code>getDeterminant</code> method can be used to determine if this
2715 * transform has no inverse, in which case an exception will be
2716 * thrown if the <code>invert</code> method is called.
2717 * @see #getDeterminant
2718 * @exception NoninvertibleTransformException
2719 * if the matrix cannot be inverted.
2720 * @since 1.6
2721 */
2722 public void invert() throws NoninvertibleTransformException {
2723 double M00, M01, M02;
2724 double M10, M11, M12;
2725 double det;
2726 switch (state) {
2727 default:
2728 stateError();
2729 /* NOTREACHED */
2730 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2731 M00 = m00;
2732 M01 = m01;
2733 M02 = m02;
2734 M10 = m10;
2735 M11 = m11;
2736 M12 = m12;
2737 det = M00 * M11 - M01 * M10;
2738 if (Math.abs(det) <= Double.MIN_VALUE) {
2739 throw new NoninvertibleTransformException(
2740 "Determinant is " + det);
2741 }
2742 m00 = M11 / det;
2743 m10 = -M10 / det;
2744 m01 = -M01 / det;
2745 m11 = M00 / det;
2746 m02 = (M01 * M12 - M11 * M02) / det;
2747 m12 = (M10 * M02 - M00 * M12) / det;
2748 break;
2749 case (APPLY_SHEAR | APPLY_SCALE):
2750 M00 = m00;
2751 M01 = m01;
2752 M10 = m10;
2753 M11 = m11;
2754 det = M00 * M11 - M01 * M10;
2755 if (Math.abs(det) <= Double.MIN_VALUE) {
2756 throw new NoninvertibleTransformException(
2757 "Determinant is " + det);
2758 }
2759 m00 = M11 / det;
2760 m10 = -M10 / det;
2761 m01 = -M01 / det;
2762 m11 = M00 / det;
2763 // m02 = 0.0;
2764 // m12 = 0.0;
2765 break;
2766 case (APPLY_SHEAR | APPLY_TRANSLATE):
2767 M01 = m01;
2768 M02 = m02;
2769 M10 = m10;
2770 M12 = m12;
2771 if (M01 == 0.0 || M10 == 0.0) {
2772 throw new NoninvertibleTransformException(
2773 "Determinant is 0");
2774 }
2775 // m00 = 0.0;
2776 m10 = 1.0 / M01;
2777 m01 = 1.0 / M10;
2778 // m11 = 0.0;
2779 m02 = -M12 / M10;
2780 m12 = -M02 / M01;
2781 break;
2782 case (APPLY_SHEAR):
2783 M01 = m01;
2784 M10 = m10;
2785 if (M01 == 0.0 || M10 == 0.0) {
2786 throw new NoninvertibleTransformException(
2787 "Determinant is 0");
2788 }
2789 // m00 = 0.0;
2790 m10 = 1.0 / M01;
2791 m01 = 1.0 / M10;
2792 // m11 = 0.0;
2793 // m02 = 0.0;
2794 // m12 = 0.0;
2795 break;
2796 case (APPLY_SCALE | APPLY_TRANSLATE):
2797 M00 = m00;
2798 M02 = m02;
2799 M11 = m11;
2800 M12 = m12;
2801 if (M00 == 0.0 || M11 == 0.0) {
2802 throw new NoninvertibleTransformException(
2803 "Determinant is 0");
2804 }
2805 m00 = 1.0 / M00;
2806 // m10 = 0.0;
2807 // m01 = 0.0;
2808 m11 = 1.0 / M11;
2809 m02 = -M02 / M00;
2810 m12 = -M12 / M11;
2811 break;
2812 case (APPLY_SCALE):
2813 M00 = m00;
2814 M11 = m11;
2815 if (M00 == 0.0 || M11 == 0.0) {
2816 throw new NoninvertibleTransformException(
2817 "Determinant is 0");
2818 }
2819 m00 = 1.0 / M00;
2820 // m10 = 0.0;
2821 // m01 = 0.0;
2822 m11 = 1.0 / M11;
2823 // m02 = 0.0;
2824 // m12 = 0.0;
2825 break;
2826 case (APPLY_TRANSLATE):
2827 // m00 = 1.0;
2828 // m10 = 0.0;
2829 // m01 = 0.0;
2830 // m11 = 1.0;
2831 m02 = -m02;
2832 m12 = -m12;
2833 break;
2834 case (APPLY_IDENTITY):
2835 // m00 = 1.0;
2836 // m10 = 0.0;
2837 // m01 = 0.0;
2838 // m11 = 1.0;
2839 // m02 = 0.0;
2840 // m12 = 0.0;
2841 break;
2842 }
2843 }
2844
2845 /**
2846 * Transforms the specified <code>ptSrc</code> and stores the result
2847 * in <code>ptDst</code>.
2848 * If <code>ptDst</code> is <code>null</code>, a new {@link Point2D}
2849 * object is allocated and then the result of the transformation is
2850 * stored in this object.
2851 * In either case, <code>ptDst</code>, which contains the
2852 * transformed point, is returned for convenience.
2853 * If <code>ptSrc</code> and <code>ptDst</code> are the same
2854 * object, the input point is correctly overwritten with
2855 * the transformed point.
2856 * @param ptSrc the specified <code>Point2D</code> to be transformed
2857 * @param ptDst the specified <code>Point2D</code> that stores the
2858 * result of transforming <code>ptSrc</code>
2859 * @return the <code>ptDst</code> after transforming
2860 * <code>ptSrc</code> and stroring the result in <code>ptDst</code>.
2861 * @since 1.2
2862 */
2863 public Point2D transform(Point2D ptSrc, Point2D ptDst) {
2864 if (ptDst == null) {
2865 if (ptSrc instanceof Point2D.Double) {
2866 ptDst = new Point2D.Double();
2867 } else {
2868 ptDst = new Point2D.Float();
2869 }
2870 }
2871 // Copy source coords into local variables in case src == dst
2872 double x = ptSrc.getX();
2873 double y = ptSrc.getY();
2874 switch (state) {
2875 default:
2876 stateError();
2877 /* NOTREACHED */
2878 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2879 ptDst.setLocation(x * m00 + y * m01 + m02, x * m10 + y
2880 * m11 + m12);
2881 return ptDst;
2882 case (APPLY_SHEAR | APPLY_SCALE):
2883 ptDst.setLocation(x * m00 + y * m01, x * m10 + y * m11);
2884 return ptDst;
2885 case (APPLY_SHEAR | APPLY_TRANSLATE):
2886 ptDst.setLocation(y * m01 + m02, x * m10 + m12);
2887 return ptDst;
2888 case (APPLY_SHEAR):
2889 ptDst.setLocation(y * m01, x * m10);
2890 return ptDst;
2891 case (APPLY_SCALE | APPLY_TRANSLATE):
2892 ptDst.setLocation(x * m00 + m02, y * m11 + m12);
2893 return ptDst;
2894 case (APPLY_SCALE):
2895 ptDst.setLocation(x * m00, y * m11);
2896 return ptDst;
2897 case (APPLY_TRANSLATE):
2898 ptDst.setLocation(x + m02, y + m12);
2899 return ptDst;
2900 case (APPLY_IDENTITY):
2901 ptDst.setLocation(x, y);
2902 return ptDst;
2903 }
2904
2905 /* NOTREACHED */
2906 }
2907
2908 /**
2909 * Transforms an array of point objects by this transform.
2910 * If any element of the <code>ptDst</code> array is
2911 * <code>null</code>, a new <code>Point2D</code> object is allocated
2912 * and stored into that element before storing the results of the
2913 * transformation.
2914 * <p>
2915 * Note that this method does not take any precautions to
2916 * avoid problems caused by storing results into <code>Point2D</code>
2917 * objects that will be used as the source for calculations
2918 * further down the source array.
2919 * This method does guarantee that if a specified <code>Point2D</code>
2920 * object is both the source and destination for the same single point
2921 * transform operation then the results will not be stored until
2922 * the calculations are complete to avoid storing the results on
2923 * top of the operands.
2924 * If, however, the destination <code>Point2D</code> object for one
2925 * operation is the same object as the source <code>Point2D</code>
2926 * object for another operation further down the source array then
2927 * the original coordinates in that point are overwritten before
2928 * they can be converted.
2929 * @param ptSrc the array containing the source point objects
2930 * @param ptDst the array into which the transform point objects are
2931 * returned
2932 * @param srcOff the offset to the first point object to be
2933 * transformed in the source array
2934 * @param dstOff the offset to the location of the first
2935 * transformed point object that is stored in the destination array
2936 * @param numPts the number of point objects to be transformed
2937 * @since 1.2
2938 */
2939 public void transform(Point2D[] ptSrc, int srcOff, Point2D[] ptDst,
2940 int dstOff, int numPts) {
2941 int state = this .state;
2942 while (--numPts >= 0) {
2943 // Copy source coords into local variables in case src == dst
2944 Point2D src = ptSrc[srcOff++];
2945 double x = src.getX();
2946 double y = src.getY();
2947 Point2D dst = ptDst[dstOff++];
2948 if (dst == null) {
2949 if (src instanceof Point2D.Double) {
2950 dst = new Point2D.Double();
2951 } else {
2952 dst = new Point2D.Float();
2953 }
2954 ptDst[dstOff - 1] = dst;
2955 }
2956 switch (state) {
2957 default:
2958 stateError();
2959 /* NOTREACHED */
2960 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
2961 dst.setLocation(x * m00 + y * m01 + m02, x * m10 + y
2962 * m11 + m12);
2963 break;
2964 case (APPLY_SHEAR | APPLY_SCALE):
2965 dst.setLocation(x * m00 + y * m01, x * m10 + y * m11);
2966 break;
2967 case (APPLY_SHEAR | APPLY_TRANSLATE):
2968 dst.setLocation(y * m01 + m02, x * m10 + m12);
2969 break;
2970 case (APPLY_SHEAR):
2971 dst.setLocation(y * m01, x * m10);
2972 break;
2973 case (APPLY_SCALE | APPLY_TRANSLATE):
2974 dst.setLocation(x * m00 + m02, y * m11 + m12);
2975 break;
2976 case (APPLY_SCALE):
2977 dst.setLocation(x * m00, y * m11);
2978 break;
2979 case (APPLY_TRANSLATE):
2980 dst.setLocation(x + m02, y + m12);
2981 break;
2982 case (APPLY_IDENTITY):
2983 dst.setLocation(x, y);
2984 break;
2985 }
2986 }
2987
2988 /* NOTREACHED */
2989 }
2990
2991 /**
2992 * Transforms an array of floating point coordinates by this transform.
2993 * The two coordinate array sections can be exactly the same or
2994 * can be overlapping sections of the same array without affecting the
2995 * validity of the results.
2996 * This method ensures that no source coordinates are overwritten by a
2997 * previous operation before they can be transformed.
2998 * The coordinates are stored in the arrays starting at the specified
2999 * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3000 * @param srcPts the array containing the source point coordinates.
3001 * Each point is stored as a pair of x, y coordinates.
3002 * @param dstPts the array into which the transformed point coordinates
3003 * are returned. Each point is stored as a pair of x, y
3004 * coordinates.
3005 * @param srcOff the offset to the first point to be transformed
3006 * in the source array
3007 * @param dstOff the offset to the location of the first
3008 * transformed point that is stored in the destination array
3009 * @param numPts the number of points to be transformed
3010 * @since 1.2
3011 */
3012 public void transform(float[] srcPts, int srcOff, float[] dstPts,
3013 int dstOff, int numPts) {
3014 double M00, M01, M02, M10, M11, M12; // For caching
3015 if (dstPts == srcPts && dstOff > srcOff
3016 && dstOff < srcOff + numPts * 2) {
3017 // If the arrays overlap partially with the destination higher
3018 // than the source and we transform the coordinates normally
3019 // we would overwrite some of the later source coordinates
3020 // with results of previous transformations.
3021 // To get around this we use arraycopy to copy the points
3022 // to their final destination with correct overwrite
3023 // handling and then transform them in place in the new
3024 // safer location.
3025 System
3026 .arraycopy(srcPts, srcOff, dstPts, dstOff,
3027 numPts * 2);
3028 // srcPts = dstPts; // They are known to be equal.
3029 srcOff = dstOff;
3030 }
3031 switch (state) {
3032 default:
3033 stateError();
3034 /* NOTREACHED */
3035 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3036 M00 = m00;
3037 M01 = m01;
3038 M02 = m02;
3039 M10 = m10;
3040 M11 = m11;
3041 M12 = m12;
3042 while (--numPts >= 0) {
3043 double x = srcPts[srcOff++];
3044 double y = srcPts[srcOff++];
3045 dstPts[dstOff++] = (float) (M00 * x + M01 * y + M02);
3046 dstPts[dstOff++] = (float) (M10 * x + M11 * y + M12);
3047 }
3048 return;
3049 case (APPLY_SHEAR | APPLY_SCALE):
3050 M00 = m00;
3051 M01 = m01;
3052 M10 = m10;
3053 M11 = m11;
3054 while (--numPts >= 0) {
3055 double x = srcPts[srcOff++];
3056 double y = srcPts[srcOff++];
3057 dstPts[dstOff++] = (float) (M00 * x + M01 * y);
3058 dstPts[dstOff++] = (float) (M10 * x + M11 * y);
3059 }
3060 return;
3061 case (APPLY_SHEAR | APPLY_TRANSLATE):
3062 M01 = m01;
3063 M02 = m02;
3064 M10 = m10;
3065 M12 = m12;
3066 while (--numPts >= 0) {
3067 double x = srcPts[srcOff++];
3068 dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++] + M02);
3069 dstPts[dstOff++] = (float) (M10 * x + M12);
3070 }
3071 return;
3072 case (APPLY_SHEAR):
3073 M01 = m01;
3074 M10 = m10;
3075 while (--numPts >= 0) {
3076 double x = srcPts[srcOff++];
3077 dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++]);
3078 dstPts[dstOff++] = (float) (M10 * x);
3079 }
3080 return;
3081 case (APPLY_SCALE | APPLY_TRANSLATE):
3082 M00 = m00;
3083 M02 = m02;
3084 M11 = m11;
3085 M12 = m12;
3086 while (--numPts >= 0) {
3087 dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++] + M02);
3088 dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++] + M12);
3089 }
3090 return;
3091 case (APPLY_SCALE):
3092 M00 = m00;
3093 M11 = m11;
3094 while (--numPts >= 0) {
3095 dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++]);
3096 dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++]);
3097 }
3098 return;
3099 case (APPLY_TRANSLATE):
3100 M02 = m02;
3101 M12 = m12;
3102 while (--numPts >= 0) {
3103 dstPts[dstOff++] = (float) (srcPts[srcOff++] + M02);
3104 dstPts[dstOff++] = (float) (srcPts[srcOff++] + M12);
3105 }
3106 return;
3107 case (APPLY_IDENTITY):
3108 if (srcPts != dstPts || srcOff != dstOff) {
3109 System.arraycopy(srcPts, srcOff, dstPts, dstOff,
3110 numPts * 2);
3111 }
3112 return;
3113 }
3114
3115 /* NOTREACHED */
3116 }
3117
3118 /**
3119 * Transforms an array of double precision coordinates by this transform.
3120 * The two coordinate array sections can be exactly the same or
3121 * can be overlapping sections of the same array without affecting the
3122 * validity of the results.
3123 * This method ensures that no source coordinates are
3124 * overwritten by a previous operation before they can be transformed.
3125 * The coordinates are stored in the arrays starting at the indicated
3126 * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3127 * @param srcPts the array containing the source point coordinates.
3128 * Each point is stored as a pair of x, y coordinates.
3129 * @param dstPts the array into which the transformed point
3130 * coordinates are returned. Each point is stored as a pair of
3131 * x, y coordinates.
3132 * @param srcOff the offset to the first point to be transformed
3133 * in the source array
3134 * @param dstOff the offset to the location of the first
3135 * transformed point that is stored in the destination array
3136 * @param numPts the number of point objects to be transformed
3137 * @since 1.2
3138 */
3139 public void transform(double[] srcPts, int srcOff, double[] dstPts,
3140 int dstOff, int numPts) {
3141 double M00, M01, M02, M10, M11, M12; // For caching
3142 if (dstPts == srcPts && dstOff > srcOff
3143 && dstOff < srcOff + numPts * 2) {
3144 // If the arrays overlap partially with the destination higher
3145 // than the source and we transform the coordinates normally
3146 // we would overwrite some of the later source coordinates
3147 // with results of previous transformations.
3148 // To get around this we use arraycopy to copy the points
3149 // to their final destination with correct overwrite
3150 // handling and then transform them in place in the new
3151 // safer location.
3152 System
3153 .arraycopy(srcPts, srcOff, dstPts, dstOff,
3154 numPts * 2);
3155 // srcPts = dstPts; // They are known to be equal.
3156 srcOff = dstOff;
3157 }
3158 switch (state) {
3159 default:
3160 stateError();
3161 /* NOTREACHED */
3162 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3163 M00 = m00;
3164 M01 = m01;
3165 M02 = m02;
3166 M10 = m10;
3167 M11 = m11;
3168 M12 = m12;
3169 while (--numPts >= 0) {
3170 double x = srcPts[srcOff++];
3171 double y = srcPts[srcOff++];
3172 dstPts[dstOff++] = M00 * x + M01 * y + M02;
3173 dstPts[dstOff++] = M10 * x + M11 * y + M12;
3174 }
3175 return;
3176 case (APPLY_SHEAR | APPLY_SCALE):
3177 M00 = m00;
3178 M01 = m01;
3179 M10 = m10;
3180 M11 = m11;
3181 while (--numPts >= 0) {
3182 double x = srcPts[srcOff++];
3183 double y = srcPts[srcOff++];
3184 dstPts[dstOff++] = M00 * x + M01 * y;
3185 dstPts[dstOff++] = M10 * x + M11 * y;
3186 }
3187 return;
3188 case (APPLY_SHEAR | APPLY_TRANSLATE):
3189 M01 = m01;
3190 M02 = m02;
3191 M10 = m10;
3192 M12 = m12;
3193 while (--numPts >= 0) {
3194 double x = srcPts[srcOff++];
3195 dstPts[dstOff++] = M01 * srcPts[srcOff++] + M02;
3196 dstPts[dstOff++] = M10 * x + M12;
3197 }
3198 return;
3199 case (APPLY_SHEAR):
3200 M01 = m01;
3201 M10 = m10;
3202 while (--numPts >= 0) {
3203 double x = srcPts[srcOff++];
3204 dstPts[dstOff++] = M01 * srcPts[srcOff++];
3205 dstPts[dstOff++] = M10 * x;
3206 }
3207 return;
3208 case (APPLY_SCALE | APPLY_TRANSLATE):
3209 M00 = m00;
3210 M02 = m02;
3211 M11 = m11;
3212 M12 = m12;
3213 while (--numPts >= 0) {
3214 dstPts[dstOff++] = M00 * srcPts[srcOff++] + M02;
3215 dstPts[dstOff++] = M11 * srcPts[srcOff++] + M12;
3216 }
3217 return;
3218 case (APPLY_SCALE):
3219 M00 = m00;
3220 M11 = m11;
3221 while (--numPts >= 0) {
3222 dstPts[dstOff++] = M00 * srcPts[srcOff++];
3223 dstPts[dstOff++] = M11 * srcPts[srcOff++];
3224 }
3225 return;
3226 case (APPLY_TRANSLATE):
3227 M02 = m02;
3228 M12 = m12;
3229 while (--numPts >= 0) {
3230 dstPts[dstOff++] = srcPts[srcOff++] + M02;
3231 dstPts[dstOff++] = srcPts[srcOff++] + M12;
3232 }
3233 return;
3234 case (APPLY_IDENTITY):
3235 if (srcPts != dstPts || srcOff != dstOff) {
3236 System.arraycopy(srcPts, srcOff, dstPts, dstOff,
3237 numPts * 2);
3238 }
3239 return;
3240 }
3241
3242 /* NOTREACHED */
3243 }
3244
3245 /**
3246 * Transforms an array of floating point coordinates by this transform
3247 * and stores the results into an array of doubles.
3248 * The coordinates are stored in the arrays starting at the specified
3249 * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3250 * @param srcPts the array containing the source point coordinates.
3251 * Each point is stored as a pair of x, y coordinates.
3252 * @param dstPts the array into which the transformed point coordinates
3253 * are returned. Each point is stored as a pair of x, y
3254 * coordinates.
3255 * @param srcOff the offset to the first point to be transformed
3256 * in the source array
3257 * @param dstOff the offset to the location of the first
3258 * transformed point that is stored in the destination array
3259 * @param numPts the number of points to be transformed
3260 * @since 1.2
3261 */
3262 public void transform(float[] srcPts, int srcOff, double[] dstPts,
3263 int dstOff, int numPts) {
3264 double M00, M01, M02, M10, M11, M12; // For caching
3265 switch (state) {
3266 default:
3267 stateError();
3268 /* NOTREACHED */
3269 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3270 M00 = m00;
3271 M01 = m01;
3272 M02 = m02;
3273 M10 = m10;
3274 M11 = m11;
3275 M12 = m12;
3276 while (--numPts >= 0) {
3277 double x = srcPts[srcOff++];
3278 double y = srcPts[srcOff++];
3279 dstPts[dstOff++] = M00 * x + M01 * y + M02;
3280 dstPts[dstOff++] = M10 * x + M11 * y + M12;
3281 }
3282 return;
3283 case (APPLY_SHEAR | APPLY_SCALE):
3284 M00 = m00;
3285 M01 = m01;
3286 M10 = m10;
3287 M11 = m11;
3288 while (--numPts >= 0) {
3289 double x = srcPts[srcOff++];
3290 double y = srcPts[srcOff++];
3291 dstPts[dstOff++] = M00 * x + M01 * y;
3292 dstPts[dstOff++] = M10 * x + M11 * y;
3293 }
3294 return;
3295 case (APPLY_SHEAR | APPLY_TRANSLATE):
3296 M01 = m01;
3297 M02 = m02;
3298 M10 = m10;
3299 M12 = m12;
3300 while (--numPts >= 0) {
3301 double x = srcPts[srcOff++];
3302 dstPts[dstOff++] = M01 * srcPts[srcOff++] + M02;
3303 dstPts[dstOff++] = M10 * x + M12;
3304 }
3305 return;
3306 case (APPLY_SHEAR):
3307 M01 = m01;
3308 M10 = m10;
3309 while (--numPts >= 0) {
3310 double x = srcPts[srcOff++];
3311 dstPts[dstOff++] = M01 * srcPts[srcOff++];
3312 dstPts[dstOff++] = M10 * x;
3313 }
3314 return;
3315 case (APPLY_SCALE | APPLY_TRANSLATE):
3316 M00 = m00;
3317 M02 = m02;
3318 M11 = m11;
3319 M12 = m12;
3320 while (--numPts >= 0) {
3321 dstPts[dstOff++] = M00 * srcPts[srcOff++] + M02;
3322 dstPts[dstOff++] = M11 * srcPts[srcOff++] + M12;
3323 }
3324 return;
3325 case (APPLY_SCALE):
3326 M00 = m00;
3327 M11 = m11;
3328 while (--numPts >= 0) {
3329 dstPts[dstOff++] = M00 * srcPts[srcOff++];
3330 dstPts[dstOff++] = M11 * srcPts[srcOff++];
3331 }
3332 return;
3333 case (APPLY_TRANSLATE):
3334 M02 = m02;
3335 M12 = m12;
3336 while (--numPts >= 0) {
3337 dstPts[dstOff++] = srcPts[srcOff++] + M02;
3338 dstPts[dstOff++] = srcPts[srcOff++] + M12;
3339 }
3340 return;
3341 case (APPLY_IDENTITY):
3342 while (--numPts >= 0) {
3343 dstPts[dstOff++] = srcPts[srcOff++];
3344 dstPts[dstOff++] = srcPts[srcOff++];
3345 }
3346 return;
3347 }
3348
3349 /* NOTREACHED */
3350 }
3351
3352 /**
3353 * Transforms an array of double precision coordinates by this transform
3354 * and stores the results into an array of floats.
3355 * The coordinates are stored in the arrays starting at the specified
3356 * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3357 * @param srcPts the array containing the source point coordinates.
3358 * Each point is stored as a pair of x, y coordinates.
3359 * @param dstPts the array into which the transformed point
3360 * coordinates are returned. Each point is stored as a pair of
3361 * x, y coordinates.
3362 * @param srcOff the offset to the first point to be transformed
3363 * in the source array
3364 * @param dstOff the offset to the location of the first
3365 * transformed point that is stored in the destination array
3366 * @param numPts the number of point objects to be transformed
3367 * @since 1.2
3368 */
3369 public void transform(double[] srcPts, int srcOff, float[] dstPts,
3370 int dstOff, int numPts) {
3371 double M00, M01, M02, M10, M11, M12; // For caching
3372 switch (state) {
3373 default:
3374 stateError();
3375 /* NOTREACHED */
3376 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3377 M00 = m00;
3378 M01 = m01;
3379 M02 = m02;
3380 M10 = m10;
3381 M11 = m11;
3382 M12 = m12;
3383 while (--numPts >= 0) {
3384 double x = srcPts[srcOff++];
3385 double y = srcPts[srcOff++];
3386 dstPts[dstOff++] = (float) (M00 * x + M01 * y + M02);
3387 dstPts[dstOff++] = (float) (M10 * x + M11 * y + M12);
3388 }
3389 return;
3390 case (APPLY_SHEAR | APPLY_SCALE):
3391 M00 = m00;
3392 M01 = m01;
3393 M10 = m10;
3394 M11 = m11;
3395 while (--numPts >= 0) {
3396 double x = srcPts[srcOff++];
3397 double y = srcPts[srcOff++];
3398 dstPts[dstOff++] = (float) (M00 * x + M01 * y);
3399 dstPts[dstOff++] = (float) (M10 * x + M11 * y);
3400 }
3401 return;
3402 case (APPLY_SHEAR | APPLY_TRANSLATE):
3403 M01 = m01;
3404 M02 = m02;
3405 M10 = m10;
3406 M12 = m12;
3407 while (--numPts >= 0) {
3408 double x = srcPts[srcOff++];
3409 dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++] + M02);
3410 dstPts[dstOff++] = (float) (M10 * x + M12);
3411 }
3412 return;
3413 case (APPLY_SHEAR):
3414 M01 = m01;
3415 M10 = m10;
3416 while (--numPts >= 0) {
3417 double x = srcPts[srcOff++];
3418 dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++]);
3419 dstPts[dstOff++] = (float) (M10 * x);
3420 }
3421 return;
3422 case (APPLY_SCALE | APPLY_TRANSLATE):
3423 M00 = m00;
3424 M02 = m02;
3425 M11 = m11;
3426 M12 = m12;
3427 while (--numPts >= 0) {
3428 dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++] + M02);
3429 dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++] + M12);
3430 }
3431 return;
3432 case (APPLY_SCALE):
3433 M00 = m00;
3434 M11 = m11;
3435 while (--numPts >= 0) {
3436 dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++]);
3437 dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++]);
3438 }
3439 return;
3440 case (APPLY_TRANSLATE):
3441 M02 = m02;
3442 M12 = m12;
3443 while (--numPts >= 0) {
3444 dstPts[dstOff++] = (float) (srcPts[srcOff++] + M02);
3445 dstPts[dstOff++] = (float) (srcPts[srcOff++] + M12);
3446 }
3447 return;
3448 case (APPLY_IDENTITY):
3449 while (--numPts >= 0) {
3450 dstPts[dstOff++] = (float) (srcPts[srcOff++]);
3451 dstPts[dstOff++] = (float) (srcPts[srcOff++]);
3452 }
3453 return;
3454 }
3455
3456 /* NOTREACHED */
3457 }
3458
3459 /**
3460 * Inverse transforms the specified <code>ptSrc</code> and stores the
3461 * result in <code>ptDst</code>.
3462 * If <code>ptDst</code> is <code>null</code>, a new
3463 * <code>Point2D</code> object is allocated and then the result of the
3464 * transform is stored in this object.
3465 * In either case, <code>ptDst</code>, which contains the transformed
3466 * point, is returned for convenience.
3467 * If <code>ptSrc</code> and <code>ptDst</code> are the same
3468 * object, the input point is correctly overwritten with the
3469 * transformed point.
3470 * @param ptSrc the point to be inverse transformed
3471 * @param ptDst the resulting transformed point
3472 * @return <code>ptDst</code>, which contains the result of the
3473 * inverse transform.
3474 * @exception NoninvertibleTransformException if the matrix cannot be
3475 * inverted.
3476 * @since 1.2
3477 */
3478 public Point2D inverseTransform(Point2D ptSrc, Point2D ptDst)
3479 throws NoninvertibleTransformException {
3480 if (ptDst == null) {
3481 if (ptSrc instanceof Point2D.Double) {
3482 ptDst = new Point2D.Double();
3483 } else {
3484 ptDst = new Point2D.Float();
3485 }
3486 }
3487 // Copy source coords into local variables in case src == dst
3488 double x = ptSrc.getX();
3489 double y = ptSrc.getY();
3490 switch (state) {
3491 default:
3492 stateError();
3493 /* NOTREACHED */
3494 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3495 x -= m02;
3496 y -= m12;
3497 /* NOBREAK */
3498 case (APPLY_SHEAR | APPLY_SCALE):
3499 double det = m00 * m11 - m01 * m10;
3500 if (Math.abs(det) <= Double.MIN_VALUE) {
3501 throw new NoninvertibleTransformException(
3502 "Determinant is " + det);
3503 }
3504 ptDst.setLocation((x * m11 - y * m01) / det, (y * m00 - x
3505 * m10)
3506 / det);
3507 return ptDst;
3508 case (APPLY_SHEAR | APPLY_TRANSLATE):
3509 x -= m02;
3510 y -= m12;
3511 /* NOBREAK */
3512 case (APPLY_SHEAR):
3513 if (m01 == 0.0 || m10 == 0.0) {
3514 throw new NoninvertibleTransformException(
3515 "Determinant is 0");
3516 }
3517 ptDst.setLocation(y / m10, x / m01);
3518 return ptDst;
3519 case (APPLY_SCALE | APPLY_TRANSLATE):
3520 x -= m02;
3521 y -= m12;
3522 /* NOBREAK */
3523 case (APPLY_SCALE):
3524 if (m00 == 0.0 || m11 == 0.0) {
3525 throw new NoninvertibleTransformException(
3526 "Determinant is 0");
3527 }
3528 ptDst.setLocation(x / m00, y / m11);
3529 return ptDst;
3530 case (APPLY_TRANSLATE):
3531 ptDst.setLocation(x - m02, y - m12);
3532 return ptDst;
3533 case (APPLY_IDENTITY):
3534 ptDst.setLocation(x, y);
3535 return ptDst;
3536 }
3537
3538 /* NOTREACHED */
3539 }
3540
3541 /**
3542 * Inverse transforms an array of double precision coordinates by
3543 * this transform.
3544 * The two coordinate array sections can be exactly the same or
3545 * can be overlapping sections of the same array without affecting the
3546 * validity of the results.
3547 * This method ensures that no source coordinates are
3548 * overwritten by a previous operation before they can be transformed.
3549 * The coordinates are stored in the arrays starting at the specified
3550 * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3551 * @param srcPts the array containing the source point coordinates.
3552 * Each point is stored as a pair of x, y coordinates.
3553 * @param dstPts the array into which the transformed point
3554 * coordinates are returned. Each point is stored as a pair of
3555 * x, y coordinates.
3556 * @param srcOff the offset to the first point to be transformed
3557 * in the source array
3558 * @param dstOff the offset to the location of the first
3559 * transformed point that is stored in the destination array
3560 * @param numPts the number of point objects to be transformed
3561 * @exception NoninvertibleTransformException if the matrix cannot be
3562 * inverted.
3563 * @since 1.2
3564 */
3565 public void inverseTransform(double[] srcPts, int srcOff,
3566 double[] dstPts, int dstOff, int numPts)
3567 throws NoninvertibleTransformException {
3568 double M00, M01, M02, M10, M11, M12; // For caching
3569 double det;
3570 if (dstPts == srcPts && dstOff > srcOff
3571 && dstOff < srcOff + numPts * 2) {
3572 // If the arrays overlap partially with the destination higher
3573 // than the source and we transform the coordinates normally
3574 // we would overwrite some of the later source coordinates
3575 // with results of previous transformations.
3576 // To get around this we use arraycopy to copy the points
3577 // to their final destination with correct overwrite
3578 // handling and then transform them in place in the new
3579 // safer location.
3580 System
3581 .arraycopy(srcPts, srcOff, dstPts, dstOff,
3582 numPts * 2);
3583 // srcPts = dstPts; // They are known to be equal.
3584 srcOff = dstOff;
3585 }
3586 switch (state) {
3587 default:
3588 stateError();
3589 /* NOTREACHED */
3590 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3591 M00 = m00;
3592 M01 = m01;
3593 M02 = m02;
3594 M10 = m10;
3595 M11 = m11;
3596 M12 = m12;
3597 det = M00 * M11 - M01 * M10;
3598 if (Math.abs(det) <= Double.MIN_VALUE) {
3599 throw new NoninvertibleTransformException(
3600 "Determinant is " + det);
3601 }
3602 while (--numPts >= 0) {
3603 double x = srcPts[srcOff++] - M02;
3604 double y = srcPts[srcOff++] - M12;
3605 dstPts[dstOff++] = (x * M11 - y * M01) / det;
3606 dstPts[dstOff++] = (y * M00 - x * M10) / det;
3607 }
3608 return;
3609 case (APPLY_SHEAR | APPLY_SCALE):
3610 M00 = m00;
3611 M01 = m01;
3612 M10 = m10;
3613 M11 = m11;
3614 det = M00 * M11 - M01 * M10;
3615 if (Math.abs(det) <= Double.MIN_VALUE) {
3616 throw new NoninvertibleTransformException(
3617 "Determinant is " + det);
3618 }
3619 while (--numPts >= 0) {
3620 double x = srcPts[srcOff++];
3621 double y = srcPts[srcOff++];
3622 dstPts[dstOff++] = (x * M11 - y * M01) / det;
3623 dstPts[dstOff++] = (y * M00 - x * M10) / det;
3624 }
3625 return;
3626 case (APPLY_SHEAR | APPLY_TRANSLATE):
3627 M01 = m01;
3628 M02 = m02;
3629 M10 = m10;
3630 M12 = m12;
3631 if (M01 == 0.0 || M10 == 0.0) {
3632 throw new NoninvertibleTransformException(
3633 "Determinant is 0");
3634 }
3635 while (--numPts >= 0) {
3636 double x = srcPts[srcOff++] - M02;
3637 dstPts[dstOff++] = (srcPts[srcOff++] - M12) / M10;
3638 dstPts[dstOff++] = x / M01;
3639 }
3640 return;
3641 case (APPLY_SHEAR):
3642 M01 = m01;
3643 M10 = m10;
3644 if (M01 == 0.0 || M10 == 0.0) {
3645 throw new NoninvertibleTransformException(
3646 "Determinant is 0");
3647 }
3648 while (--numPts >= 0) {
3649 double x = srcPts[srcOff++];
3650 dstPts[dstOff++] = srcPts[srcOff++] / M10;
3651 dstPts[dstOff++] = x / M01;
3652 }
3653 return;
3654 case (APPLY_SCALE | APPLY_TRANSLATE):
3655 M00 = m00;
3656 M02 = m02;
3657 M11 = m11;
3658 M12 = m12;
3659 if (M00 == 0.0 || M11 == 0.0) {
3660 throw new NoninvertibleTransformException(
3661 "Determinant is 0");
3662 }
3663 while (--numPts >= 0) {
3664 dstPts[dstOff++] = (srcPts[srcOff++] - M02) / M00;
3665 dstPts[dstOff++] = (srcPts[srcOff++] - M12) / M11;
3666 }
3667 return;
3668 case (APPLY_SCALE):
3669 M00 = m00;
3670 M11 = m11;
3671 if (M00 == 0.0 || M11 == 0.0) {
3672 throw new NoninvertibleTransformException(
3673 "Determinant is 0");
3674 }
3675 while (--numPts >= 0) {
3676 dstPts[dstOff++] = srcPts[srcOff++] / M00;
3677 dstPts[dstOff++] = srcPts[srcOff++] / M11;
3678 }
3679 return;
3680 case (APPLY_TRANSLATE):
3681 M02 = m02;
3682 M12 = m12;
3683 while (--numPts >= 0) {
3684 dstPts[dstOff++] = srcPts[srcOff++] - M02;
3685 dstPts[dstOff++] = srcPts[srcOff++] - M12;
3686 }
3687 return;
3688 case (APPLY_IDENTITY):
3689 if (srcPts != dstPts || srcOff != dstOff) {
3690 System.arraycopy(srcPts, srcOff, dstPts, dstOff,
3691 numPts * 2);
3692 }
3693 return;
3694 }
3695
3696 /* NOTREACHED */
3697 }
3698
3699 /**
3700 * Transforms the relative distance vector specified by
3701 * <code>ptSrc</code> and stores the result in <code>ptDst</code>.
3702 * A relative distance vector is transformed without applying the
3703 * translation components of the affine transformation matrix
3704 * using the following equations:
3705 * <pre>
3706 * [ x' ] [ m00 m01 (m02) ] [ x ] [ m00x + m01y ]
3707 * [ y' ] = [ m10 m11 (m12) ] [ y ] = [ m10x + m11y ]
3708 * [ (1) ] [ (0) (0) ( 1 ) ] [ (1) ] [ (1) ]
3709 * </pre>
3710 * If <code>ptDst</code> is <code>null</code>, a new
3711 * <code>Point2D</code> object is allocated and then the result of the
3712 * transform is stored in this object.
3713 * In either case, <code>ptDst</code>, which contains the
3714 * transformed point, is returned for convenience.
3715 * If <code>ptSrc</code> and <code>ptDst</code> are the same object,
3716 * the input point is correctly overwritten with the transformed
3717 * point.
3718 * @param ptSrc the distance vector to be delta transformed
3719 * @param ptDst the resulting transformed distance vector
3720 * @return <code>ptDst</code>, which contains the result of the
3721 * transformation.
3722 * @since 1.2
3723 */
3724 public Point2D deltaTransform(Point2D ptSrc, Point2D ptDst) {
3725 if (ptDst == null) {
3726 if (ptSrc instanceof Point2D.Double) {
3727 ptDst = new Point2D.Double();
3728 } else {
3729 ptDst = new Point2D.Float();
3730 }
3731 }
3732 // Copy source coords into local variables in case src == dst
3733 double x = ptSrc.getX();
3734 double y = ptSrc.getY();
3735 switch (state) {
3736 default:
3737 stateError();
3738 /* NOTREACHED */
3739 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3740 case (APPLY_SHEAR | APPLY_SCALE):
3741 ptDst.setLocation(x * m00 + y * m01, x * m10 + y * m11);
3742 return ptDst;
3743 case (APPLY_SHEAR | APPLY_TRANSLATE):
3744 case (APPLY_SHEAR):
3745 ptDst.setLocation(y * m01, x * m10);
3746 return ptDst;
3747 case (APPLY_SCALE | APPLY_TRANSLATE):
3748 case (APPLY_SCALE):
3749 ptDst.setLocation(x * m00, y * m11);
3750 return ptDst;
3751 case (APPLY_TRANSLATE):
3752 case (APPLY_IDENTITY):
3753 ptDst.setLocation(x, y);
3754 return ptDst;
3755 }
3756
3757 /* NOTREACHED */
3758 }
3759
3760 /**
3761 * Transforms an array of relative distance vectors by this
3762 * transform.
3763 * A relative distance vector is transformed without applying the
3764 * translation components of the affine transformation matrix
3765 * using the following equations:
3766 * <pre>
3767 * [ x' ] [ m00 m01 (m02) ] [ x ] [ m00x + m01y ]
3768 * [ y' ] = [ m10 m11 (m12) ] [ y ] = [ m10x + m11y ]
3769 * [ (1) ] [ (0) (0) ( 1 ) ] [ (1) ] [ (1) ]
3770 * </pre>
3771 * The two coordinate array sections can be exactly the same or
3772 * can be overlapping sections of the same array without affecting the
3773 * validity of the results.
3774 * This method ensures that no source coordinates are
3775 * overwritten by a previous operation before they can be transformed.
3776 * The coordinates are stored in the arrays starting at the indicated
3777 * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
3778 * @param srcPts the array containing the source distance vectors.
3779 * Each vector is stored as a pair of relative x, y coordinates.
3780 * @param dstPts the array into which the transformed distance vectors
3781 * are returned. Each vector is stored as a pair of relative
3782 * x, y coordinates.
3783 * @param srcOff the offset to the first vector to be transformed
3784 * in the source array
3785 * @param dstOff the offset to the location of the first
3786 * transformed vector that is stored in the destination array
3787 * @param numPts the number of vector coordinate pairs to be
3788 * transformed
3789 * @since 1.2
3790 */
3791 public void deltaTransform(double[] srcPts, int srcOff,
3792 double[] dstPts, int dstOff, int numPts) {
3793 double M00, M01, M10, M11; // For caching
3794 if (dstPts == srcPts && dstOff > srcOff
3795 && dstOff < srcOff + numPts * 2) {
3796 // If the arrays overlap partially with the destination higher
3797 // than the source and we transform the coordinates normally
3798 // we would overwrite some of the later source coordinates
3799 // with results of previous transformations.
3800 // To get around this we use arraycopy to copy the points
3801 // to their final destination with correct overwrite
3802 // handling and then transform them in place in the new
3803 // safer location.
3804 System
3805 .arraycopy(srcPts, srcOff, dstPts, dstOff,
3806 numPts * 2);
3807 // srcPts = dstPts; // They are known to be equal.
3808 srcOff = dstOff;
3809 }
3810 switch (state) {
3811 default:
3812 stateError();
3813 /* NOTREACHED */
3814 case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
3815 case (APPLY_SHEAR | APPLY_SCALE):
3816 M00 = m00;
3817 M01 = m01;
3818 M10 = m10;
3819 M11 = m11;
3820 while (--numPts >= 0) {
3821 double x = srcPts[srcOff++];
3822 double y = srcPts[srcOff++];
3823 dstPts[dstOff++] = x * M00 + y * M01;
3824 dstPts[dstOff++] = x * M10 + y * M11;
3825 }
3826 return;
3827 case (APPLY_SHEAR | APPLY_TRANSLATE):
3828 case (APPLY_SHEAR):
3829 M01 = m01;
3830 M10 = m10;
3831 while (--numPts >= 0) {
3832 double x = srcPts[srcOff++];
3833 dstPts[dstOff++] = srcPts[srcOff++] * M01;
3834 dstPts[dstOff++] = x * M10;
3835 }
3836 return;
3837 case (APPLY_SCALE | APPLY_TRANSLATE):
3838 case (APPLY_SCALE):
3839 M00 = m00;
3840 M11 = m11;
3841 while (--numPts >= 0) {
3842 dstPts[dstOff++] = srcPts[srcOff++] * M00;
3843 dstPts[dstOff++] = srcPts[srcOff++] * M11;
3844 }
3845 return;
3846 case (APPLY_TRANSLATE):
3847 case (APPLY_IDENTITY):
3848 if (srcPts != dstPts || srcOff != dstOff) {
3849 System.arraycopy(srcPts, srcOff, dstPts, dstOff,
3850 numPts * 2);
3851 }
3852 return;
3853 }
3854
3855 /* NOTREACHED */
3856 }
3857
3858 /**
3859 * Returns a new {@link Shape} object defined by the geometry of the
3860 * specified <code>Shape</code> after it has been transformed by
3861 * this transform.
3862 * @param pSrc the specified <code>Shape</code> object to be
3863 * transformed by this transform.
3864 * @return a new <code>Shape</code> object that defines the geometry
3865 * of the transformed <code>Shape</code>, or null if {@code pSrc} is null.
3866 * @since 1.2
3867 */
3868 public Shape createTransformedShape(Shape pSrc) {
3869 if (pSrc == null) {
3870 return null;
3871 }
3872 return new Path2D.Double(pSrc, this );
3873 }
3874
3875 // Round values to sane precision for printing
3876 // Note that Math.sin(Math.PI) has an error of about 10^-16
3877 private static double _matround(double matval) {
3878 return Math.rint(matval * 1E15) / 1E15;
3879 }
3880
3881 /**
3882 * Returns a <code>String</code> that represents the value of this
3883 * {@link Object}.
3884 * @return a <code>String</code> representing the value of this
3885 * <code>Object</code>.
3886 * @since 1.2
3887 */
3888 public String toString() {
3889 return ("AffineTransform[[" + _matround(m00) + ", "
3890 + _matround(m01) + ", " + _matround(m02) + "], ["
3891 + _matround(m10) + ", " + _matround(m11) + ", "
3892 + _matround(m12) + "]]");
3893 }
3894
3895 /**
3896 * Returns <code>true</code> if this <code>AffineTransform</code> is
3897 * an identity transform.
3898 * @return <code>true</code> if this <code>AffineTransform</code> is
3899 * an identity transform; <code>false</code> otherwise.
3900 * @since 1.2
3901 */
3902 public boolean isIdentity() {
3903 return (state == APPLY_IDENTITY || (getType() == TYPE_IDENTITY));
3904 }
3905
3906 /**
3907 * Returns a copy of this <code>AffineTransform</code> object.
3908 * @return an <code>Object</code> that is a copy of this
3909 * <code>AffineTransform</code> object.
3910 * @since 1.2
3911 */
3912 public Object clone() {
3913 try {
3914 return super .clone();
3915 } catch (CloneNotSupportedException e) {
3916 // this shouldn't happen, since we are Cloneable
3917 throw new InternalError();
3918 }
3919 }
3920
3921 /**
3922 * Returns the hashcode for this transform.
3923 * @return a hash code for this transform.
3924 * @since 1.2
3925 */
3926 public int hashCode() {
3927 long bits = Double.doubleToLongBits(m00);
3928 bits = bits * 31 + Double.doubleToLongBits(m01);
3929 bits = bits * 31 + Double.doubleToLongBits(m02);
3930 bits = bits * 31 + Double.doubleToLongBits(m10);
3931 bits = bits * 31 + Double.doubleToLongBits(m11);
3932 bits = bits * 31 + Double.doubleToLongBits(m12);
3933 return (((int) bits) ^ ((int) (bits >> 32)));
3934 }
3935
3936 /**
3937 * Returns <code>true</code> if this <code>AffineTransform</code>
3938 * represents the same affine coordinate transform as the specified
3939 * argument.
3940 * @param obj the <code>Object</code> to test for equality with this
3941 * <code>AffineTransform</code>
3942 * @return <code>true</code> if <code>obj</code> equals this
3943 * <code>AffineTransform</code> object; <code>false</code> otherwise.
3944 * @since 1.2
3945 */
3946 public boolean equals(Object obj) {
3947 if (!(obj instanceof AffineTransform)) {
3948 return false;
3949 }
3950
3951 AffineTransform a = (AffineTransform) obj;
3952
3953 return ((m00 == a.m00) && (m01 == a.m01) && (m02 == a.m02)
3954 && (m10 == a.m10) && (m11 == a.m11) && (m12 == a.m12));
3955 }
3956
3957 /* Serialization support. A readObject method is neccessary because
3958 * the state field is part of the implementation of this particular
3959 * AffineTransform and not part of the public specification. The
3960 * state variable's value needs to be recalculated on the fly by the
3961 * readObject method as it is in the 6-argument matrix constructor.
3962 */
3963
3964 /*
3965 * JDK 1.2 serialVersionUID
3966 */
3967 private static final long serialVersionUID = 1330973210523860834L;
3968
3969 private void writeObject(java.io.ObjectOutputStream s)
3970 throws java.lang.ClassNotFoundException,
3971 java.io.IOException {
3972 s.defaultWriteObject();
3973 }
3974
3975 private void readObject(java.io.ObjectInputStream s)
3976 throws java.lang.ClassNotFoundException,
3977 java.io.IOException {
3978 s.defaultReadObject();
3979 updateState();
3980 }
3981 }
|