Merge from mainline (gomp-merge-2005-02-26).
[official-gcc.git] / libjava / java / awt / geom / AffineTransform.java
blob21eacae7409df32176c5f197a6e49e02df3e2195
1 /* AffineTransform.java -- transform coordinates between two 2-D spaces
2 Copyright (C) 2000, 2001, 2002, 2004 Free Software Foundation
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package java.awt.geom;
41 import java.awt.Shape;
42 import java.io.IOException;
43 import java.io.ObjectInputStream;
44 import java.io.Serializable;
46 /**
47 * This class represents an affine transformation between two coordinate
48 * spaces in 2 dimensions. Such a transform preserves the "straightness"
49 * and "parallelness" of lines. The transform is built from a sequence of
50 * translations, scales, flips, rotations, and shears.
52 * <p>The transformation can be represented using matrix math on a 3x3 array.
53 * Given (x,y), the transformation (x',y') can be found by:
54 * <pre>
55 * [ x'] [ m00 m01 m02 ] [ x ] [ m00*x + m01*y + m02 ]
56 * [ y'] = [ m10 m11 m12 ] [ y ] = [ m10*x + m11*y + m12 ]
57 * [ 1 ] [ 0 0 1 ] [ 1 ] [ 1 ]
58 * </pre>
59 * The bottom row of the matrix is constant, so a transform can be uniquely
60 * represented (as in {@link #toString()}) by
61 * "[[m00, m01, m02], [m10, m11, m12]]".
63 * @author Tom Tromey (tromey@cygnus.com)
64 * @author Eric Blake (ebb9@email.byu.edu)
65 * @since 1.2
66 * @status partially updated to 1.4, still has some problems
68 public class AffineTransform implements Cloneable, Serializable
70 /**
71 * Compatible with JDK 1.2+.
73 private static final long serialVersionUID = 1330973210523860834L;
75 /**
76 * The transformation is the identity (x' = x, y' = y). All other transforms
77 * have either a combination of the appropriate transform flag bits for
78 * their type, or the type GENERAL_TRANSFORM.
80 * @see #TYPE_TRANSLATION
81 * @see #TYPE_UNIFORM_SCALE
82 * @see #TYPE_GENERAL_SCALE
83 * @see #TYPE_FLIP
84 * @see #TYPE_QUADRANT_ROTATION
85 * @see #TYPE_GENERAL_ROTATION
86 * @see #TYPE_GENERAL_TRANSFORM
87 * @see #getType()
89 public static final int TYPE_IDENTITY = 0;
91 /**
92 * The transformation includes a translation - shifting in the x or y
93 * direction without changing length or angles.
95 * @see #TYPE_IDENTITY
96 * @see #TYPE_UNIFORM_SCALE
97 * @see #TYPE_GENERAL_SCALE
98 * @see #TYPE_FLIP
99 * @see #TYPE_QUADRANT_ROTATION
100 * @see #TYPE_GENERAL_ROTATION
101 * @see #TYPE_GENERAL_TRANSFORM
102 * @see #getType()
104 public static final int TYPE_TRANSLATION = 1;
107 * The transformation includes a uniform scale - length is scaled in both
108 * the x and y directions by the same amount, without affecting angles.
109 * This is mutually exclusive with TYPE_GENERAL_SCALE.
111 * @see #TYPE_IDENTITY
112 * @see #TYPE_TRANSLATION
113 * @see #TYPE_GENERAL_SCALE
114 * @see #TYPE_FLIP
115 * @see #TYPE_QUADRANT_ROTATION
116 * @see #TYPE_GENERAL_ROTATION
117 * @see #TYPE_GENERAL_TRANSFORM
118 * @see #TYPE_MASK_SCALE
119 * @see #getType()
121 public static final int TYPE_UNIFORM_SCALE = 2;
124 * The transformation includes a general scale - length is scaled in either
125 * or both the x and y directions, but by different amounts; without
126 * affecting angles. This is mutually exclusive with TYPE_UNIFORM_SCALE.
128 * @see #TYPE_IDENTITY
129 * @see #TYPE_TRANSLATION
130 * @see #TYPE_UNIFORM_SCALE
131 * @see #TYPE_FLIP
132 * @see #TYPE_QUADRANT_ROTATION
133 * @see #TYPE_GENERAL_ROTATION
134 * @see #TYPE_GENERAL_TRANSFORM
135 * @see #TYPE_MASK_SCALE
136 * @see #getType()
138 public static final int TYPE_GENERAL_SCALE = 4;
141 * This constant checks if either variety of scale transform is performed.
143 * @see #TYPE_UNIFORM_SCALE
144 * @see #TYPE_GENERAL_SCALE
146 public static final int TYPE_MASK_SCALE = 6;
149 * The transformation includes a flip about an axis, swapping between
150 * right-handed and left-handed coordinate systems. In a right-handed
151 * system, the positive x-axis rotates counter-clockwise to the positive
152 * y-axis; in a left-handed system it rotates clockwise.
154 * @see #TYPE_IDENTITY
155 * @see #TYPE_TRANSLATION
156 * @see #TYPE_UNIFORM_SCALE
157 * @see #TYPE_GENERAL_SCALE
158 * @see #TYPE_QUADRANT_ROTATION
159 * @see #TYPE_GENERAL_ROTATION
160 * @see #TYPE_GENERAL_TRANSFORM
161 * @see #getType()
163 public static final int TYPE_FLIP = 64;
166 * The transformation includes a rotation of a multiple of 90 degrees (PI/2
167 * radians). Angles are rotated, but length is preserved. This is mutually
168 * exclusive with TYPE_GENERAL_ROTATION.
170 * @see #TYPE_IDENTITY
171 * @see #TYPE_TRANSLATION
172 * @see #TYPE_UNIFORM_SCALE
173 * @see #TYPE_GENERAL_SCALE
174 * @see #TYPE_FLIP
175 * @see #TYPE_GENERAL_ROTATION
176 * @see #TYPE_GENERAL_TRANSFORM
177 * @see #TYPE_MASK_ROTATION
178 * @see #getType()
180 public static final int TYPE_QUADRANT_ROTATION = 8;
183 * The transformation includes a rotation by an arbitrary angle. Angles are
184 * rotated, but length is preserved. This is mutually exclusive with
185 * TYPE_QUADRANT_ROTATION.
187 * @see #TYPE_IDENTITY
188 * @see #TYPE_TRANSLATION
189 * @see #TYPE_UNIFORM_SCALE
190 * @see #TYPE_GENERAL_SCALE
191 * @see #TYPE_FLIP
192 * @see #TYPE_QUADRANT_ROTATION
193 * @see #TYPE_GENERAL_TRANSFORM
194 * @see #TYPE_MASK_ROTATION
195 * @see #getType()
197 public static final int TYPE_GENERAL_ROTATION = 16;
200 * This constant checks if either variety of rotation is performed.
202 * @see #TYPE_QUADRANT_ROTATION
203 * @see #TYPE_GENERAL_ROTATION
205 public static final int TYPE_MASK_ROTATION = 24;
208 * The transformation is an arbitrary conversion of coordinates which
209 * could not be decomposed into the other TYPEs.
211 * @see #TYPE_IDENTITY
212 * @see #TYPE_TRANSLATION
213 * @see #TYPE_UNIFORM_SCALE
214 * @see #TYPE_GENERAL_SCALE
215 * @see #TYPE_FLIP
216 * @see #TYPE_QUADRANT_ROTATION
217 * @see #TYPE_GENERAL_ROTATION
218 * @see #getType()
220 public static final int TYPE_GENERAL_TRANSFORM = 32;
223 * The X coordinate scaling element of the transform matrix.
225 * @serial matrix[0,0]
227 private double m00;
230 * The Y coordinate shearing element of the transform matrix.
232 * @serial matrix[1,0]
234 private double m10;
237 * The X coordinate shearing element of the transform matrix.
239 * @serial matrix[0,1]
241 private double m01;
244 * The Y coordinate scaling element of the transform matrix.
246 * @serial matrix[1,1]
248 private double m11;
251 * The X coordinate translation element of the transform matrix.
253 * @serial matrix[0,2]
255 private double m02;
258 * The Y coordinate translation element of the transform matrix.
260 * @serial matrix[1,2]
262 private double m12;
264 /** The type of this transform. */
265 private transient int type;
268 * Construct a new identity transform:
269 * <pre>
270 * [ 1 0 0 ]
271 * [ 0 1 0 ]
272 * [ 0 0 1 ]
273 * </pre>
275 public AffineTransform()
277 m00 = m11 = 1;
281 * Create a new transform which copies the given one.
283 * @param tx the transform to copy
284 * @throws NullPointerException if tx is null
286 public AffineTransform(AffineTransform tx)
288 setTransform(tx);
292 * Construct a transform with the given matrix entries:
293 * <pre>
294 * [ m00 m01 m02 ]
295 * [ m10 m11 m12 ]
296 * [ 0 0 1 ]
297 * </pre>
299 * @param m00 the x scaling component
300 * @param m10 the y shearing component
301 * @param m01 the x shearing component
302 * @param m11 the y scaling component
303 * @param m02 the x translation component
304 * @param m12 the y translation component
306 public AffineTransform(float m00, float m10,
307 float m01, float m11,
308 float m02, float m12)
310 this.m00 = m00;
311 this.m10 = m10;
312 this.m01 = m01;
313 this.m11 = m11;
314 this.m02 = m02;
315 this.m12 = m12;
316 updateType();
320 * Construct a transform from a sequence of float entries. The array must
321 * have at least 4 entries, which has a translation factor of 0; or 6
322 * entries, for specifying all parameters:
323 * <pre>
324 * [ f[0] f[2] (f[4]) ]
325 * [ f[1] f[3] (f[5]) ]
326 * [ 0 0 1 ]
327 * </pre>
329 * @param f the matrix to copy from, with at least 4 (6) entries
330 * @throws NullPointerException if f is null
331 * @throws ArrayIndexOutOfBoundsException if f is too small
333 public AffineTransform(float[] f)
335 m00 = f[0];
336 m10 = f[1];
337 m01 = f[2];
338 m11 = f[3];
339 if (f.length >= 6)
341 m02 = f[4];
342 m12 = f[5];
344 updateType();
348 * Construct a transform with the given matrix entries:
349 * <pre>
350 * [ m00 m01 m02 ]
351 * [ m10 m11 m12 ]
352 * [ 0 0 1 ]
353 * </pre>
355 * @param m00 the x scaling component
356 * @param m10 the y shearing component
357 * @param m01 the x shearing component
358 * @param m11 the y scaling component
359 * @param m02 the x translation component
360 * @param m12 the y translation component
362 public AffineTransform(double m00, double m10, double m01,
363 double m11, double m02, double m12)
365 this.m00 = m00;
366 this.m10 = m10;
367 this.m01 = m01;
368 this.m11 = m11;
369 this.m02 = m02;
370 this.m12 = m12;
371 updateType();
375 * Construct a transform from a sequence of double entries. The array must
376 * have at least 4 entries, which has a translation factor of 0; or 6
377 * entries, for specifying all parameters:
378 * <pre>
379 * [ d[0] d[2] (d[4]) ]
380 * [ d[1] d[3] (d[5]) ]
381 * [ 0 0 1 ]
382 * </pre>
384 * @param d the matrix to copy from, with at least 4 (6) entries
385 * @throws NullPointerException if d is null
386 * @throws ArrayIndexOutOfBoundsException if d is too small
388 public AffineTransform(double[] d)
390 m00 = d[0];
391 m10 = d[1];
392 m01 = d[2];
393 m11 = d[3];
394 if (d.length >= 6)
396 m02 = d[4];
397 m12 = d[5];
399 updateType();
403 * Returns a translation transform:
404 * <pre>
405 * [ 1 0 tx ]
406 * [ 0 1 ty ]
407 * [ 0 0 1 ]
408 * </pre>
410 * @param tx the x translation distance
411 * @param ty the y translation distance
412 * @return the translating transform
414 public static AffineTransform getTranslateInstance(double tx, double ty)
416 AffineTransform t = new AffineTransform();
417 t.setToTranslation(tx, ty);
418 return t;
422 * Returns a rotation transform. A positive angle (in radians) rotates
423 * the positive x-axis to the positive y-axis:
424 * <pre>
425 * [ cos(theta) -sin(theta) 0 ]
426 * [ sin(theta) cos(theta) 0 ]
427 * [ 0 0 1 ]
428 * </pre>
430 * @param theta the rotation angle
431 * @return the rotating transform
433 public static AffineTransform getRotateInstance(double theta)
435 AffineTransform t = new AffineTransform();
436 t.setToRotation(theta);
437 return t;
441 * Returns a rotation transform about a point. A positive angle (in radians)
442 * rotates the positive x-axis to the positive y-axis. This is the same
443 * as calling:
444 * <pre>
445 * AffineTransform tx = new AffineTransform();
446 * tx.setToTranslation(x, y);
447 * tx.rotate(theta);
448 * tx.translate(-x, -y);
449 * </pre>
451 * <p>The resulting matrix is:
452 * <pre>
453 * [ cos(theta) -sin(theta) x-x*cos+y*sin ]
454 * [ sin(theta) cos(theta) y-x*sin-y*cos ]
455 * [ 0 0 1 ]
456 * </pre>
458 * @param theta the rotation angle
459 * @param x the x coordinate of the pivot point
460 * @param y the y coordinate of the pivot point
461 * @return the rotating transform
463 public static AffineTransform getRotateInstance(double theta,
464 double x, double y)
466 AffineTransform t = new AffineTransform();
467 t.setToTranslation(x, y);
468 t.rotate(theta);
469 t.translate(-x, -y);
470 return t;
474 * Returns a scaling transform:
475 * <pre>
476 * [ sx 0 0 ]
477 * [ 0 sy 0 ]
478 * [ 0 0 1 ]
479 * </pre>
481 * @param sx the x scaling factor
482 * @param sy the y scaling factor
483 * @return the scaling transform
485 public static AffineTransform getScaleInstance(double sx, double sy)
487 AffineTransform t = new AffineTransform();
488 t.setToScale(sx, sy);
489 return t;
493 * Returns a shearing transform (points are shifted in the x direction based
494 * on a factor of their y coordinate, and in the y direction as a factor of
495 * their x coordinate):
496 * <pre>
497 * [ 1 shx 0 ]
498 * [ shy 1 0 ]
499 * [ 0 0 1 ]
500 * </pre>
502 * @param shx the x shearing factor
503 * @param shy the y shearing factor
504 * @return the shearing transform
506 public static AffineTransform getShearInstance(double shx, double shy)
508 AffineTransform t = new AffineTransform();
509 t.setToShear(shx, shy);
510 return t;
514 * Returns the type of this transform. The result is always valid, although
515 * it may not be the simplest interpretation (in other words, there are
516 * sequences of transforms which reduce to something simpler, which this
517 * does not always detect). The result is either TYPE_GENERAL_TRANSFORM,
518 * or a bit-wise combination of TYPE_TRANSLATION, the mutually exclusive
519 * TYPE_*_ROTATIONs, and the mutually exclusive TYPE_*_SCALEs.
521 * @return The type.
523 * @see #TYPE_IDENTITY
524 * @see #TYPE_TRANSLATION
525 * @see #TYPE_UNIFORM_SCALE
526 * @see #TYPE_GENERAL_SCALE
527 * @see #TYPE_QUADRANT_ROTATION
528 * @see #TYPE_GENERAL_ROTATION
529 * @see #TYPE_GENERAL_TRANSFORM
531 public int getType()
533 return type;
537 * Return the determinant of this transform matrix. If the determinant is
538 * non-zero, the transform is invertible; otherwise operations which require
539 * an inverse throw a NoninvertibleTransformException. A result very near
540 * zero, due to rounding errors, may indicate that inversion results do not
541 * carry enough precision to be meaningful.
543 * <p>If this is a uniform scale transformation, the determinant also
544 * represents the squared value of the scale. Otherwise, it carries little
545 * additional meaning. The determinant is calculated as:
546 * <pre>
547 * | m00 m01 m02 |
548 * | m10 m11 m12 | = m00 * m11 - m01 * m10
549 * | 0 0 1 |
550 * </pre>
552 * @return the determinant
553 * @see #createInverse()
555 public double getDeterminant()
557 return m00 * m11 - m01 * m10;
561 * Return the matrix of values used in this transform. If the matrix has
562 * fewer than 6 entries, only the scale and shear factors are returned;
563 * otherwise the translation factors are copied as well. The resulting
564 * values are:
565 * <pre>
566 * [ d[0] d[2] (d[4]) ]
567 * [ d[1] d[3] (d[5]) ]
568 * [ 0 0 1 ]
569 * </pre>
571 * @param d the matrix to store the results into; with 4 (6) entries
572 * @throws NullPointerException if d is null
573 * @throws ArrayIndexOutOfBoundsException if d is too small
575 public void getMatrix(double[] d)
577 d[0] = m00;
578 d[1] = m10;
579 d[2] = m01;
580 d[3] = m11;
581 if (d.length >= 6)
583 d[4] = m02;
584 d[5] = m12;
589 * Returns the X coordinate scaling factor of the matrix.
591 * @return m00
592 * @see #getMatrix(double[])
594 public double getScaleX()
596 return m00;
600 * Returns the Y coordinate scaling factor of the matrix.
602 * @return m11
603 * @see #getMatrix(double[])
605 public double getScaleY()
607 return m11;
611 * Returns the X coordinate shearing factor of the matrix.
613 * @return m01
614 * @see #getMatrix(double[])
616 public double getShearX()
618 return m01;
622 * Returns the Y coordinate shearing factor of the matrix.
624 * @return m10
625 * @see #getMatrix(double[])
627 public double getShearY()
629 return m10;
633 * Returns the X coordinate translation factor of the matrix.
635 * @return m02
636 * @see #getMatrix(double[])
638 public double getTranslateX()
640 return m02;
644 * Returns the Y coordinate translation factor of the matrix.
646 * @return m12
647 * @see #getMatrix(double[])
649 public double getTranslateY()
651 return m12;
655 * Concatenate a translation onto this transform. This is equivalent, but
656 * more efficient than
657 * <code>concatenate(AffineTransform.getTranslateInstance(tx, ty))</code>.
659 * @param tx the x translation distance
660 * @param ty the y translation distance
661 * @see #getTranslateInstance(double, double)
662 * @see #concatenate(AffineTransform)
664 public void translate(double tx, double ty)
666 m02 += tx * m00 + ty * m01;
667 m12 += tx * m10 + ty * m11;
668 updateType();
672 * Concatenate a rotation onto this transform. This is equivalent, but
673 * more efficient than
674 * <code>concatenate(AffineTransform.getRotateInstance(theta))</code>.
676 * @param theta the rotation angle
677 * @see #getRotateInstance(double)
678 * @see #concatenate(AffineTransform)
680 public void rotate(double theta)
682 double c = Math.cos(theta);
683 double s = Math.sin(theta);
684 double n00 = m00 * c + m01 * s;
685 double n01 = m00 * -s + m01 * c;
686 double n10 = m10 * c + m11 * s;
687 double n11 = m10 * -s + m11 * c;
688 m00 = n00;
689 m01 = n01;
690 m10 = n10;
691 m11 = n11;
692 updateType();
696 * Concatenate a rotation about a point onto this transform. This is
697 * equivalent, but more efficient than
698 * <code>concatenate(AffineTransform.getRotateInstance(theta, x, y))</code>.
700 * @param theta the rotation angle
701 * @param x the x coordinate of the pivot point
702 * @param y the y coordinate of the pivot point
703 * @see #getRotateInstance(double, double, double)
704 * @see #concatenate(AffineTransform)
706 public void rotate(double theta, double x, double y)
708 translate(x, y);
709 rotate(theta);
710 translate(-x, -y);
714 * Concatenate a scale onto this transform. This is equivalent, but more
715 * efficient than
716 * <code>concatenate(AffineTransform.getScaleInstance(sx, sy))</code>.
718 * @param sx the x scaling factor
719 * @param sy the y scaling factor
720 * @see #getScaleInstance(double, double)
721 * @see #concatenate(AffineTransform)
723 public void scale(double sx, double sy)
725 m00 *= sx;
726 m01 *= sy;
727 m10 *= sx;
728 m11 *= sy;
729 updateType();
733 * Concatenate a shearing onto this transform. This is equivalent, but more
734 * efficient than
735 * <code>concatenate(AffineTransform.getShearInstance(sx, sy))</code>.
737 * @param shx the x shearing factor
738 * @param shy the y shearing factor
739 * @see #getShearInstance(double, double)
740 * @see #concatenate(AffineTransform)
742 public void shear(double shx, double shy)
744 double n00 = m00 + (shy * m01);
745 double n01 = m01 + (shx * m00);
746 double n10 = m10 + (shy * m11);
747 double n11 = m11 + (shx * m10);
748 m00 = n00;
749 m01 = n01;
750 m10 = n10;
751 m11 = n11;
752 updateType();
756 * Reset this transform to the identity (no transformation):
757 * <pre>
758 * [ 1 0 0 ]
759 * [ 0 1 0 ]
760 * [ 0 0 1 ]
761 * </pre>
763 public void setToIdentity()
765 m00 = m11 = 1;
766 m01 = m02 = m10 = m12 = 0;
767 type = TYPE_IDENTITY;
771 * Set this transform to a translation:
772 * <pre>
773 * [ 1 0 tx ]
774 * [ 0 1 ty ]
775 * [ 0 0 1 ]
776 * </pre>
778 * @param tx the x translation distance
779 * @param ty the y translation distance
781 public void setToTranslation(double tx, double ty)
783 m00 = m11 = 1;
784 m01 = m10 = 0;
785 m02 = tx;
786 m12 = ty;
787 type = (tx == 0 && ty == 0) ? TYPE_UNIFORM_SCALE : TYPE_TRANSLATION;
791 * Set this transform to a rotation. A positive angle (in radians) rotates
792 * the positive x-axis to the positive y-axis:
793 * <pre>
794 * [ cos(theta) -sin(theta) 0 ]
795 * [ sin(theta) cos(theta) 0 ]
796 * [ 0 0 1 ]
797 * </pre>
799 * @param theta the rotation angle
801 public void setToRotation(double theta)
803 double c = Math.cos(theta);
804 double s = Math.sin(theta);
805 m00 = c;
806 m01 = -s;
807 m02 = 0;
808 m10 = s;
809 m11 = c;
810 m12 = 0;
811 type = (c == 1 ? TYPE_IDENTITY
812 : c == 0 || c == -1 ? TYPE_QUADRANT_ROTATION
813 : TYPE_GENERAL_ROTATION);
817 * Set this transform to a rotation about a point. A positive angle (in
818 * radians) rotates the positive x-axis to the positive y-axis. This is the
819 * same as calling:
820 * <pre>
821 * tx.setToTranslation(x, y);
822 * tx.rotate(theta);
823 * tx.translate(-x, -y);
824 * </pre>
826 * <p>The resulting matrix is:
827 * <pre>
828 * [ cos(theta) -sin(theta) x-x*cos+y*sin ]
829 * [ sin(theta) cos(theta) y-x*sin-y*cos ]
830 * [ 0 0 1 ]
831 * </pre>
833 * @param theta the rotation angle
834 * @param x the x coordinate of the pivot point
835 * @param y the y coordinate of the pivot point
837 public void setToRotation(double theta, double x, double y)
839 double c = Math.cos(theta);
840 double s = Math.sin(theta);
841 m00 = c;
842 m01 = -s;
843 m02 = x - x * c + y * s;
844 m10 = s;
845 m11 = c;
846 m12 = y - x * s - y * c;
847 updateType();
851 * Set this transform to a scale:
852 * <pre>
853 * [ sx 0 0 ]
854 * [ 0 sy 0 ]
855 * [ 0 0 1 ]
856 * </pre>
858 * @param sx the x scaling factor
859 * @param sy the y scaling factor
861 public void setToScale(double sx, double sy)
863 m00 = sx;
864 m01 = m02 = m10 = m12 = 0;
865 m11 = sy;
866 type = (sx != sy ? TYPE_GENERAL_SCALE
867 : sx == 1 ? TYPE_IDENTITY : TYPE_UNIFORM_SCALE);
871 * Set this transform to a shear (points are shifted in the x direction based
872 * on a factor of their y coordinate, and in the y direction as a factor of
873 * their x coordinate):
874 * <pre>
875 * [ 1 shx 0 ]
876 * [ shy 1 0 ]
877 * [ 0 0 1 ]
878 * </pre>
880 * @param shx the x shearing factor
881 * @param shy the y shearing factor
883 public void setToShear(double shx, double shy)
885 m00 = m11 = 1;
886 m01 = shx;
887 m10 = shy;
888 m02 = m12 = 0;
889 updateType();
893 * Set this transform to a copy of the given one.
895 * @param tx the transform to copy
896 * @throws NullPointerException if tx is null
898 public void setTransform(AffineTransform tx)
900 m00 = tx.m00;
901 m01 = tx.m01;
902 m02 = tx.m02;
903 m10 = tx.m10;
904 m11 = tx.m11;
905 m12 = tx.m12;
906 type = tx.type;
910 * Set this transform to the given values:
911 * <pre>
912 * [ m00 m01 m02 ]
913 * [ m10 m11 m12 ]
914 * [ 0 0 1 ]
915 * </pre>
917 * @param m00 the x scaling component
918 * @param m10 the y shearing component
919 * @param m01 the x shearing component
920 * @param m11 the y scaling component
921 * @param m02 the x translation component
922 * @param m12 the y translation component
924 public void setTransform(double m00, double m10, double m01,
925 double m11, double m02, double m12)
927 this.m00 = m00;
928 this.m10 = m10;
929 this.m01 = m01;
930 this.m11 = m11;
931 this.m02 = m02;
932 this.m12 = m12;
933 updateType();
937 * Set this transform to the result of performing the original version of
938 * this followed by tx. This is commonly used when chaining transformations
939 * from one space to another. In matrix form:
940 * <pre>
941 * [ this ] = [ this ] x [ tx ]
942 * </pre>
944 * @param tx the transform to concatenate
945 * @throws NullPointerException if tx is null
946 * @see #preConcatenate(AffineTransform)
948 public void concatenate(AffineTransform tx)
950 double n00 = m00 * tx.m00 + m01 * tx.m10;
951 double n01 = m00 * tx.m01 + m01 * tx.m11;
952 double n02 = m00 * tx.m02 + m01 * tx.m12 + m02;
953 double n10 = m10 * tx.m00 + m11 * tx.m10;
954 double n11 = m10 * tx.m01 + m11 * tx.m11;
955 double n12 = m10 * tx.m02 + m11 * tx.m12 + m12;
956 m00 = n00;
957 m01 = n01;
958 m02 = n02;
959 m10 = n10;
960 m11 = n11;
961 m12 = n12;
962 updateType();
966 * Set this transform to the result of performing tx followed by the
967 * original version of this. This is less common than normal concatenation,
968 * but can still be used to chain transformations from one space to another.
969 * In matrix form:
970 * <pre>
971 * [ this ] = [ tx ] x [ this ]
972 * </pre>
974 * @param tx the transform to concatenate
975 * @throws NullPointerException if tx is null
976 * @see #concatenate(AffineTransform)
978 public void preConcatenate(AffineTransform tx)
980 double n00 = tx.m00 * m00 + tx.m01 * m10;
981 double n01 = tx.m00 * m01 + tx.m01 * m11;
982 double n02 = tx.m00 * m02 + tx.m01 * m12 + tx.m02;
983 double n10 = tx.m10 * m00 + tx.m11 * m10;
984 double n11 = tx.m10 * m01 + tx.m11 * m11;
985 double n12 = tx.m10 * m02 + tx.m11 * m12 + tx.m12;
986 m00 = n00;
987 m01 = n01;
988 m02 = n02;
989 m10 = n10;
990 m11 = n11;
991 m12 = n12;
992 updateType();
996 * Returns a transform, which if concatenated to this one, will result in
997 * the identity transform. This is useful for undoing transformations, but
998 * is only possible if the original transform has an inverse (ie. does not
999 * map multiple points to the same line or point). A transform exists only
1000 * if getDeterminant() has a non-zero value.
1002 * The inverse is calculated as:
1004 * <pre>
1006 * Let A be the matrix for which we want to find the inverse:
1008 * A = [ m00 m01 m02 ]
1009 * [ m10 m11 m12 ]
1010 * [ 0 0 1 ]
1013 * 1
1014 * inverse (A) = --- x adjoint(A)
1015 * det
1019 * = 1 [ m11 -m01 m01*m12-m02*m11 ]
1020 * --- x [ -m10 m00 -m00*m12+m10*m02 ]
1021 * det [ 0 0 m00*m11-m10*m01 ]
1025 * = [ m11/det -m01/det m01*m12-m02*m11/det ]
1026 * [ -m10/det m00/det -m00*m12+m10*m02/det ]
1027 * [ 0 0 1 ]
1030 * </pre>
1034 * @return a new inverse transform
1035 * @throws NoninvertibleTransformException if inversion is not possible
1036 * @see #getDeterminant()
1038 public AffineTransform createInverse()
1039 throws NoninvertibleTransformException
1041 double det = getDeterminant();
1042 if (det == 0)
1043 throw new NoninvertibleTransformException("can't invert transform");
1045 double im00 = m11 / det;
1046 double im10 = -m10 / det;
1047 double im01 = -m01 / det;
1048 double im11 = m00 / det;
1049 double im02 = (m01 * m12 - m02 * m11) / det;
1050 double im12 = (-m00 * m12 + m10 * m02) / det;
1052 return new AffineTransform (im00, im10, im01, im11, im02, im12);
1056 * Perform this transformation on the given source point, and store the
1057 * result in the destination (creating it if necessary). It is safe for
1058 * src and dst to be the same.
1060 * @param src the source point
1061 * @param dst the destination, or null
1062 * @return the transformation of src, in dst if it was non-null
1063 * @throws NullPointerException if src is null
1065 public Point2D transform(Point2D src, Point2D dst)
1067 if (dst == null)
1068 dst = new Point2D.Double();
1069 double x = src.getX();
1070 double y = src.getY();
1071 double nx = m00 * x + m01 * y + m02;
1072 double ny = m10 * x + m11 * y + m12;
1073 dst.setLocation(nx, ny);
1074 return dst;
1078 * Perform this transformation on an array of points, storing the results
1079 * in another (possibly same) array. This will not create a destination
1080 * array, but will create points for the null entries of the destination.
1081 * The transformation is done sequentially. While having a single source
1082 * and destination point be the same is safe, you should be aware that
1083 * duplicate references to the same point in the source, and having the
1084 * source overlap the destination, may result in your source points changing
1085 * from a previous transform before it is their turn to be evaluated.
1087 * @param src the array of source points
1088 * @param srcOff the starting offset into src
1089 * @param dst the array of destination points (may have null entries)
1090 * @param dstOff the starting offset into dst
1091 * @param num the number of points to transform
1092 * @throws NullPointerException if src or dst is null, or src has null
1093 * entries
1094 * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded
1095 * @throws ArrayStoreException if new points are incompatible with dst
1097 public void transform(Point2D[] src, int srcOff,
1098 Point2D[] dst, int dstOff, int num)
1100 while (--num >= 0)
1101 dst[dstOff] = transform(src[srcOff++], dst[dstOff++]);
1105 * Perform this transformation on an array of points, in (x,y) pairs,
1106 * storing the results in another (possibly same) array. This will not
1107 * create a destination array. All sources are copied before the
1108 * transformation, so that no result will overwrite a point that has not yet
1109 * been evaluated.
1111 * @param srcPts the array of source points
1112 * @param srcOff the starting offset into src
1113 * @param dstPts the array of destination points
1114 * @param dstOff the starting offset into dst
1115 * @param num the number of points to transform
1116 * @throws NullPointerException if src or dst is null
1117 * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded
1119 public void transform(float[] srcPts, int srcOff,
1120 float[] dstPts, int dstOff, int num)
1122 if (srcPts == dstPts && dstOff > srcOff
1123 && num > 1 && srcOff + 2 * num > dstOff)
1125 float[] f = new float[2 * num];
1126 System.arraycopy(srcPts, srcOff, f, 0, 2 * num);
1127 srcPts = f;
1129 while (--num >= 0)
1131 float x = srcPts[srcOff++];
1132 float y = srcPts[srcOff++];
1133 dstPts[dstOff++] = (float) (m00 * x + m01 * y + m02);
1134 dstPts[dstOff++] = (float) (m10 * x + m11 * y + m12);
1139 * Perform this transformation on an array of points, in (x,y) pairs,
1140 * storing the results in another (possibly same) array. This will not
1141 * create a destination array. All sources are copied before the
1142 * transformation, so that no result will overwrite a point that has not yet
1143 * been evaluated.
1145 * @param srcPts the array of source points
1146 * @param srcOff the starting offset into src
1147 * @param dstPts the array of destination points
1148 * @param dstOff the starting offset into dst
1149 * @param num the number of points to transform
1150 * @throws NullPointerException if src or dst is null
1151 * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded
1153 public void transform(double[] srcPts, int srcOff,
1154 double[] dstPts, int dstOff, int num)
1156 if (srcPts == dstPts && dstOff > srcOff
1157 && num > 1 && srcOff + 2 * num > dstOff)
1159 double[] d = new double[2 * num];
1160 System.arraycopy(srcPts, srcOff, d, 0, 2 * num);
1161 srcPts = d;
1163 while (--num >= 0)
1165 double x = srcPts[srcOff++];
1166 double y = srcPts[srcOff++];
1167 dstPts[dstOff++] = m00 * x + m01 * y + m02;
1168 dstPts[dstOff++] = m10 * x + m11 * y + m12;
1173 * Perform this transformation on an array of points, in (x,y) pairs,
1174 * storing the results in another array. This will not create a destination
1175 * array.
1177 * @param srcPts the array of source points
1178 * @param srcOff the starting offset into src
1179 * @param dstPts the array of destination points
1180 * @param dstOff the starting offset into dst
1181 * @param num the number of points to transform
1182 * @throws NullPointerException if src or dst is null
1183 * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded
1185 public void transform(float[] srcPts, int srcOff,
1186 double[] dstPts, int dstOff, int num)
1188 while (--num >= 0)
1190 float x = srcPts[srcOff++];
1191 float y = srcPts[srcOff++];
1192 dstPts[dstOff++] = m00 * x + m01 * y + m02;
1193 dstPts[dstOff++] = m10 * x + m11 * y + m12;
1198 * Perform this transformation on an array of points, in (x,y) pairs,
1199 * storing the results in another array. This will not create a destination
1200 * array.
1202 * @param srcPts the array of source points
1203 * @param srcOff the starting offset into src
1204 * @param dstPts the array of destination points
1205 * @param dstOff the starting offset into dst
1206 * @param num the number of points to transform
1207 * @throws NullPointerException if src or dst is null
1208 * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded
1210 public void transform(double[] srcPts, int srcOff,
1211 float[] dstPts, int dstOff, int num)
1213 while (--num >= 0)
1215 double x = srcPts[srcOff++];
1216 double y = srcPts[srcOff++];
1217 dstPts[dstOff++] = (float) (m00 * x + m01 * y + m02);
1218 dstPts[dstOff++] = (float) (m10 * x + m11 * y + m12);
1223 * Perform the inverse of this transformation on the given source point,
1224 * and store the result in the destination (creating it if necessary). It
1225 * is safe for src and dst to be the same.
1227 * @param src the source point
1228 * @param dst the destination, or null
1229 * @return the inverse transformation of src, in dst if it was non-null
1230 * @throws NullPointerException if src is null
1231 * @throws NoninvertibleTransformException if the inverse does not exist
1232 * @see #getDeterminant()
1234 public Point2D inverseTransform(Point2D src, Point2D dst)
1235 throws NoninvertibleTransformException
1237 return createInverse().transform(src, dst);
1241 * Perform the inverse of this transformation on an array of points, in
1242 * (x,y) pairs, storing the results in another (possibly same) array. This
1243 * will not create a destination array. All sources are copied before the
1244 * transformation, so that no result will overwrite a point that has not yet
1245 * been evaluated.
1247 * @param srcPts the array of source points
1248 * @param srcOff the starting offset into src
1249 * @param dstPts the array of destination points
1250 * @param dstOff the starting offset into dst
1251 * @param num the number of points to transform
1252 * @throws NullPointerException if src or dst is null
1253 * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded
1254 * @throws NoninvertibleTransformException if the inverse does not exist
1255 * @see #getDeterminant()
1257 public void inverseTransform(double[] srcPts, int srcOff,
1258 double[] dstPts, int dstOff, int num)
1259 throws NoninvertibleTransformException
1261 createInverse().transform(srcPts, srcOff, dstPts, dstOff, num);
1265 * Perform this transformation, less any translation, on the given source
1266 * point, and store the result in the destination (creating it if
1267 * necessary). It is safe for src and dst to be the same. The reduced
1268 * transform is equivalent to:
1269 * <pre>
1270 * [ x' ] = [ m00 m01 ] [ x ] = [ m00 * x + m01 * y ]
1271 * [ y' ] [ m10 m11 ] [ y ] = [ m10 * x + m11 * y ]
1272 * </pre>
1274 * @param src the source point
1275 * @param dst the destination, or null
1276 * @return the delta transformation of src, in dst if it was non-null
1277 * @throws NullPointerException if src is null
1279 public Point2D deltaTransform(Point2D src, Point2D dst)
1281 if (dst == null)
1282 dst = new Point2D.Double();
1283 double x = src.getX();
1284 double y = src.getY();
1285 double nx = m00 * x + m01 * y;
1286 double ny = m10 * x + m11 * y;
1287 dst.setLocation(nx, ny);
1288 return dst;
1292 * Perform this transformation, less any translation, on an array of points,
1293 * in (x,y) pairs, storing the results in another (possibly same) array.
1294 * This will not create a destination array. All sources are copied before
1295 * the transformation, so that no result will overwrite a point that has
1296 * not yet been evaluated. The reduced transform is equivalent to:
1297 * <pre>
1298 * [ x' ] = [ m00 m01 ] [ x ] = [ m00 * x + m01 * y ]
1299 * [ y' ] [ m10 m11 ] [ y ] = [ m10 * x + m11 * y ]
1300 * </pre>
1302 * @param srcPts the array of source points
1303 * @param srcOff the starting offset into src
1304 * @param dstPts the array of destination points
1305 * @param dstOff the starting offset into dst
1306 * @param num the number of points to transform
1307 * @throws NullPointerException if src or dst is null
1308 * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded
1310 public void deltaTransform(double[] srcPts, int srcOff,
1311 double[] dstPts, int dstOff,
1312 int num)
1314 if (srcPts == dstPts && dstOff > srcOff
1315 && num > 1 && srcOff + 2 * num > dstOff)
1317 double[] d = new double[2 * num];
1318 System.arraycopy(srcPts, srcOff, d, 0, 2 * num);
1319 srcPts = d;
1321 while (--num >= 0)
1323 double x = srcPts[srcOff++];
1324 double y = srcPts[srcOff++];
1325 dstPts[dstOff++] = m00 * x + m01 * y;
1326 dstPts[dstOff++] = m10 * x + m11 * y;
1331 * Return a new Shape, based on the given one, where the path of the shape
1332 * has been transformed by this transform. Notice that this uses GeneralPath,
1333 * which only stores points in float precision.
1335 * @param src the shape source to transform
1336 * @return the shape, transformed by this, <code>null</code> if src is
1337 * <code>null</code>.
1338 * @see GeneralPath#transform(AffineTransform)
1340 public Shape createTransformedShape(Shape src)
1342 if(src == null)
1343 return null;
1344 GeneralPath p = new GeneralPath(src);
1345 p.transform(this);
1346 return p;
1350 * Returns a string representation of the transform, in the format:
1351 * <code>"AffineTransform[[" + m00 + ", " + m01 + ", " + m02 + "], ["
1352 * + m10 + ", " + m11 + ", " + m12 + "]]"</code>.
1354 * @return the string representation
1356 public String toString()
1358 return "AffineTransform[[" + m00 + ", " + m01 + ", " + m02 + "], ["
1359 + m10 + ", " + m11 + ", " + m12 + "]]";
1363 * Tests if this transformation is the identity:
1364 * <pre>
1365 * [ 1 0 0 ]
1366 * [ 0 1 0 ]
1367 * [ 0 0 1 ]
1368 * </pre>
1370 * @return true if this is the identity transform
1372 public boolean isIdentity()
1374 // Rather than rely on type, check explicitly.
1375 return (m00 == 1 && m01 == 0 && m02 == 0
1376 && m10 == 0 && m11 == 1 && m12 == 0);
1380 * Create a new transform of the same run-time type, with the same
1381 * transforming properties as this one.
1383 * @return the clone
1385 public Object clone()
1389 return super.clone();
1391 catch (CloneNotSupportedException e)
1393 throw (Error) new InternalError().initCause(e); // Impossible
1398 * Return the hashcode for this transformation. The formula is not
1399 * documented, but appears to be the same as:
1400 * <pre>
1401 * long l = Double.doubleToLongBits(getScaleX());
1402 * l = l * 31 + Double.doubleToLongBits(getShearY());
1403 * l = l * 31 + Double.doubleToLongBits(getShearX());
1404 * l = l * 31 + Double.doubleToLongBits(getScaleY());
1405 * l = l * 31 + Double.doubleToLongBits(getTranslateX());
1406 * l = l * 31 + Double.doubleToLongBits(getTranslateY());
1407 * return (int) ((l >> 32) ^ l);
1408 * </pre>
1410 * @return the hashcode
1412 public int hashCode()
1414 long l = Double.doubleToLongBits(m00);
1415 l = l * 31 + Double.doubleToLongBits(m10);
1416 l = l * 31 + Double.doubleToLongBits(m01);
1417 l = l * 31 + Double.doubleToLongBits(m11);
1418 l = l * 31 + Double.doubleToLongBits(m02);
1419 l = l * 31 + Double.doubleToLongBits(m12);
1420 return (int) ((l >> 32) ^ l);
1424 * Compares two transforms for equality. This returns true if they have the
1425 * same matrix values.
1427 * @param obj the transform to compare
1428 * @return true if it is equal
1430 public boolean equals(Object obj)
1432 if (! (obj instanceof AffineTransform))
1433 return false;
1434 AffineTransform t = (AffineTransform) obj;
1435 return (m00 == t.m00 && m01 == t.m01 && m02 == t.m02
1436 && m10 == t.m10 && m11 == t.m11 && m12 == t.m12);
1440 * Helper to decode the type from the matrix. This is not guaranteed
1441 * to find the optimal type, but at least it will be valid.
1443 private void updateType()
1445 double det = getDeterminant();
1446 if (det == 0)
1448 type = TYPE_GENERAL_TRANSFORM;
1449 return;
1451 // Scale (includes rotation by PI) or translation.
1452 if (m01 == 0 && m10 == 0)
1454 if (m00 == m11)
1455 type = m00 == 1 ? TYPE_IDENTITY : TYPE_UNIFORM_SCALE;
1456 else
1457 type = TYPE_GENERAL_SCALE;
1458 if (m02 != 0 || m12 != 0)
1459 type |= TYPE_TRANSLATION;
1461 // Rotation.
1462 else if (m00 == m11 && m01 == -m10)
1464 type = m00 == 0 ? TYPE_QUADRANT_ROTATION : TYPE_GENERAL_ROTATION;
1465 if (det != 1)
1466 type |= TYPE_UNIFORM_SCALE;
1467 if (m02 != 0 || m12 != 0)
1468 type |= TYPE_TRANSLATION;
1470 else
1471 type = TYPE_GENERAL_TRANSFORM;
1475 * Reads a transform from an object stream.
1477 * @param s the stream to read from
1478 * @throws ClassNotFoundException if there is a problem deserializing
1479 * @throws IOException if there is a problem deserializing
1481 private void readObject(ObjectInputStream s)
1482 throws ClassNotFoundException, IOException
1484 s.defaultReadObject();
1485 updateType();
1487 } // class AffineTransform