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