2003-12-26 Guilhem Lavaux <guilhem@kaffe.org>
[official-gcc.git] / libjava / java / awt / geom / AffineTransform.java
blobd479763be8ca29e541dd9cea8fdf1db61d5fb63e
1 /* AffineTransform.java -- transform coordinates between two 2-D spaces
2 Copyright (C) 2000, 2001, 2002 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 toString) by "[[m00, m01, m02], [m10, m11, m12]]".
62 * @author Tom Tromey <tromey@cygnus.com>
63 * @author Eric Blake <ebb9@email.byu.edu>
64 * @since 1.2
65 * @status partially updated to 1.4, still has some problems
67 public class AffineTransform implements Cloneable, Serializable
69 /**
70 * Compatible with JDK 1.2+.
72 private static final long serialVersionUID = 1330973210523860834L;
74 /**
75 * The transformation is the identity (x' = x, y' = y). All other transforms
76 * have either a combination of the appropriate transform flag bits for
77 * their type, or the type GENERAL_TRANSFORM.
79 * @see #TYPE_TRANSLATION
80 * @see #TYPE_UNIFORM_SCALE
81 * @see #TYPE_GENERAL_SCALE
82 * @see #TYPE_FLIP
83 * @see #TYPE_QUADRANT_ROTATION
84 * @see #TYPE_GENERAL_ROTATION
85 * @see #TYPE_GENERAL_TRANSFORM
86 * @see #getType()
88 public static final int TYPE_IDENTITY = 0;
90 /**
91 * The transformation includes a translation - shifting in the x or y
92 * direction without changing length or angles.
94 * @see #TYPE_IDENTITY
95 * @see #TYPE_UNIFORM_SCALE
96 * @see #TYPE_GENERAL_SCALE
97 * @see #TYPE_FLIP
98 * @see #TYPE_QUADRANT_ROTATION
99 * @see #TYPE_GENERAL_ROTATION
100 * @see #TYPE_GENERAL_TRANSFORM
101 * @see #getType()
103 public static final int TYPE_TRANSLATION = 1;
106 * The transformation includes a uniform scale - length is scaled in both
107 * the x and y directions by the same amount, without affecting angles.
108 * This is mutually exclusive with TYPE_GENERAL_SCALE.
110 * @see #TYPE_IDENTITY
111 * @see #TYPE_TRANSLATION
112 * @see #TYPE_GENERAL_SCALE
113 * @see #TYPE_FLIP
114 * @see #TYPE_QUADRANT_ROTATION
115 * @see #TYPE_GENERAL_ROTATION
116 * @see #TYPE_GENERAL_TRANSFORM
117 * @see #TYPE_MASK_SCALE
118 * @see #getType()
120 public static final int TYPE_UNIFORM_SCALE = 2;
123 * The transformation includes a general scale - length is scaled in either
124 * or both the x and y directions, but by different amounts; without
125 * affecting angles. This is mutually exclusive with TYPE_UNIFORM_SCALE.
127 * @see #TYPE_IDENTITY
128 * @see #TYPE_TRANSLATION
129 * @see #TYPE_UNIFORM_SCALE
130 * @see #TYPE_FLIP
131 * @see #TYPE_QUADRANT_ROTATION
132 * @see #TYPE_GENERAL_ROTATION
133 * @see #TYPE_GENERAL_TRANSFORM
134 * @see #TYPE_MASK_SCALE
135 * @see #getType()
137 public static final int TYPE_GENERAL_SCALE = 4;
140 * This constant checks if either variety of scale transform is performed.
142 * @see #TYPE_UNIFORM_SCALE
143 * @see #TYPE_GENERAL_SCALE
145 public static final int TYPE_MASK_SCALE = 6;
148 * The transformation includes a flip about an axis, swapping between
149 * right-handed and left-handed coordinate systems. In a right-handed
150 * system, the positive x-axis rotates counter-clockwise to the positive
151 * y-axis; in a left-handed system it rotates clockwise.
153 * @see #TYPE_IDENTITY
154 * @see #TYPE_TRANSLATION
155 * @see #TYPE_UNIFORM_SCALE
156 * @see #TYPE_GENERAL_SCALE
157 * @see #TYPE_QUADRANT_ROTATION
158 * @see #TYPE_GENERAL_ROTATION
159 * @see #TYPE_GENERAL_TRANSFORM
160 * @see #getType()
162 public static final int TYPE_FLIP = 64;
165 * The transformation includes a rotation of a multiple of 90 degrees (PI/2
166 * radians). Angles are rotated, but length is preserved. This is mutually
167 * exclusive with TYPE_GENERAL_ROTATION.
169 * @see #TYPE_IDENTITY
170 * @see #TYPE_TRANSLATION
171 * @see #TYPE_UNIFORM_SCALE
172 * @see #TYPE_GENERAL_SCALE
173 * @see #TYPE_FLIP
174 * @see #TYPE_GENERAL_ROTATION
175 * @see #TYPE_GENERAL_TRANSFORM
176 * @see #TYPE_MASK_ROTATION
177 * @see #getType()
179 public static final int TYPE_QUADRANT_ROTATION = 8;
182 * The transformation includes a rotation by an arbitrary angle. Angles are
183 * rotated, but length is preserved. This is mutually exclusive with
184 * TYPE_QUADRANT_ROTATION.
186 * @see #TYPE_IDENTITY
187 * @see #TYPE_TRANSLATION
188 * @see #TYPE_UNIFORM_SCALE
189 * @see #TYPE_GENERAL_SCALE
190 * @see #TYPE_FLIP
191 * @see #TYPE_QUADRANT_ROTATION
192 * @see #TYPE_GENERAL_TRANSFORM
193 * @see #TYPE_MASK_ROTATION
194 * @see #getType()
196 public static final int TYPE_GENERAL_ROTATION = 16;
199 * This constant checks if either variety of rotation is performed.
201 * @see #TYPE_QUADRANT_ROTATION
202 * @see #TYPE_GENERAL_ROTATION
204 public static final int TYPE_MASK_ROTATION = 24;
207 * The transformation is an arbitrary conversion of coordinates which
208 * could not be decomposed into the other TYPEs.
210 * @see #TYPE_IDENTITY
211 * @see #TYPE_TRANSLATION
212 * @see #TYPE_UNIFORM_SCALE
213 * @see #TYPE_GENERAL_SCALE
214 * @see #TYPE_FLIP
215 * @see #TYPE_QUADRANT_ROTATION
216 * @see #TYPE_GENERAL_ROTATION
217 * @see #getType()
219 public static final int TYPE_GENERAL_TRANSFORM = 32;
222 * The X coordinate scaling element of the transform matrix.
224 * @serial matrix[0,0]
226 private double m00;
229 * The Y coordinate scaling element of the transform matrix.
231 * @serial matrix[1,0]
233 private double m10;
236 * The X coordinate shearing element of the transform matrix.
238 * @serial matrix[0,1]
240 private double m01;
243 * The Y coordinate shearing element of the transform matrix.
245 * @serial matrix[1,1]
247 private double m11;
250 * The X coordinate translation element of the transform matrix.
252 * @serial matrix[0,2]
254 private double m02;
257 * The Y coordinate translation element of the transform matrix.
259 * @serial matrix[1,2]
261 private double m12;
263 /** The type of this transform. */
264 private transient int type;
267 * Construct a new identity transform:
268 * <pre>
269 * [ 1 0 0 ]
270 * [ 0 1 0 ]
271 * [ 0 0 1 ]
272 * </pre>
274 public AffineTransform()
276 m00 = m11 = 1;
280 * Create a new transform which copies the given one.
282 * @param tx the transform to copy
283 * @throws NullPointerException if tx is null
285 public AffineTransform(AffineTransform tx)
287 setTransform(tx);
291 * Construct a transform with the given matrix entries:
292 * <pre>
293 * [ m00 m01 m02 ]
294 * [ m10 m11 m12 ]
295 * [ 0 0 1 ]
296 * </pre>
298 * @param m00 the x scaling component
299 * @param m10 the y shearing component
300 * @param m01 the x shearing component
301 * @param m11 the y scaling component
302 * @param m02 the x translation component
303 * @param m12 the y translation component
305 public AffineTransform(float m00, float m10,
306 float m01, float m11,
307 float m02, float m12)
309 this.m00 = m00;
310 this.m10 = m10;
311 this.m01 = m01;
312 this.m11 = m11;
313 this.m02 = m02;
314 this.m12 = m12;
315 updateType();
319 * Construct a transform from a sequence of float entries. The array must
320 * have at least 4 entries, which has a translation factor of 0; or 6
321 * entries, for specifying all parameters:
322 * <pre>
323 * [ f[0] f[2] (f[4]) ]
324 * [ f[1] f[3] (f[5]) ]
325 * [ 0 0 1 ]
326 * </pre>
328 * @param f the matrix to copy from, with at least 4 (6) entries
329 * @throws NullPointerException if f is null
330 * @throws ArrayIndexOutOfBoundsException if f is too small
332 public AffineTransform(float[] f)
334 m00 = f[0];
335 m10 = f[1];
336 m01 = f[2];
337 m11 = f[3];
338 if (f.length >= 6)
340 m02 = f[4];
341 m12 = f[5];
343 updateType();
347 * Construct a transform with the given matrix entries:
348 * <pre>
349 * [ m00 m01 m02 ]
350 * [ m10 m11 m12 ]
351 * [ 0 0 1 ]
352 * </pre>
354 * @param m00 the x scaling component
355 * @param m10 the y shearing component
356 * @param m01 the x shearing component
357 * @param m11 the y scaling component
358 * @param m02 the x translation component
359 * @param m12 the y translation component
361 public AffineTransform(double m00, double m10, double m01,
362 double m11, double m02, double m12)
364 this.m00 = m00;
365 this.m10 = m10;
366 this.m01 = m01;
367 this.m11 = m11;
368 this.m02 = m02;
369 this.m12 = m12;
370 updateType();
374 * Construct a transform from a sequence of double entries. The array must
375 * have at least 4 entries, which has a translation factor of 0; or 6
376 * entries, for specifying all parameters:
377 * <pre>
378 * [ d[0] d[2] (d[4]) ]
379 * [ d[1] d[3] (d[5]) ]
380 * [ 0 0 1 ]
381 * </pre>
383 * @param d the matrix to copy from, with at least 4 (6) entries
384 * @throws NullPointerException if d is null
385 * @throws ArrayIndexOutOfBoundsException if d is too small
387 public AffineTransform(double[] d)
389 m00 = d[0];
390 m10 = d[1];
391 m01 = d[2];
392 m11 = d[3];
393 if (d.length >= 6)
395 m02 = d[4];
396 m12 = d[5];
398 updateType();
402 * Returns a translation transform:
403 * <pre>
404 * [ 1 0 tx ]
405 * [ 0 1 ty ]
406 * [ 0 0 1 ]
407 * </pre>
409 * @param tx the x translation distance
410 * @param ty the y translation distance
411 * @return the translating transform
413 public static AffineTransform getTranslateInstance(double tx, double ty)
415 AffineTransform t = new AffineTransform();
416 t.setToTranslation(tx, ty);
417 return t;
421 * Returns a rotation transform. A positive angle (in radians) rotates
422 * the positive x-axis to the positive y-axis:
423 * <pre>
424 * [ cos(theta) -sin(theta) 0 ]
425 * [ sin(theta) cos(theta) 0 ]
426 * [ 0 0 1 ]
427 * </pre>
429 * @param theta the rotation angle
430 * @return the rotating transform
432 public static AffineTransform getRotateInstance(double theta)
434 AffineTransform t = new AffineTransform();
435 t.setToRotation(theta);
436 return t;
440 * Returns a rotation transform about a point. A positive angle (in radians)
441 * rotates the positive x-axis to the positive y-axis. This is the same
442 * as calling:
443 * <pre>
444 * AffineTransform tx = new AffineTransform();
445 * tx.setToTranslation(x, y);
446 * tx.rotate(theta);
447 * tx.translate(-x, -y);
448 * </pre>
450 * <p>The resulting matrix is:
451 * <pre>
452 * [ cos(theta) -sin(theta) x-x*cos+y*sin ]
453 * [ sin(theta) cos(theta) y-x*sin-y*cos ]
454 * [ 0 0 1 ]
455 * </pre>
457 * @param theta the rotation angle
458 * @param x the x coordinate of the pivot point
459 * @param y the y coordinate of the pivot point
460 * @return the rotating transform
462 public static AffineTransform getRotateInstance(double theta,
463 double x, double y)
465 AffineTransform t = new AffineTransform();
466 t.setToTranslation(x, y);
467 t.rotate(theta);
468 t.translate(-x, -y);
469 return t;
473 * Returns a scaling transform:
474 * <pre>
475 * [ sx 0 0 ]
476 * [ 0 sy 0 ]
477 * [ 0 0 1 ]
478 * </pre>
480 * @param sx the x scaling factor
481 * @param sy the y scaling factor
482 * @return the scaling transform
484 public static AffineTransform getScaleInstance(double sx, double sy)
486 AffineTransform t = new AffineTransform();
487 t.setToScale(sx, sy);
488 return t;
492 * Returns a shearing transform (points are shifted in the x direction based
493 * on a factor of their y coordinate, and in the y direction as a factor of
494 * their x coordinate):
495 * <pre>
496 * [ 1 shx 0 ]
497 * [ shy 1 0 ]
498 * [ 0 0 1 ]
499 * </pre>
501 * @param shx the x shearing factor
502 * @param shy the y shearing factor
503 * @return the shearing transform
505 public static AffineTransform getShearInstance(double shx, double shy)
507 AffineTransform t = new AffineTransform();
508 t.setToShear(shx, shy);
509 return t;
513 * Returns the type of this transform. The result is always valid, although
514 * it may not be the simplest interpretation (in other words, there are
515 * sequences of transforms which reduce to something simpler, which this
516 * does not always detect). The result is either TYPE_GENERAL_TRANSFORM,
517 * or a bit-wise combination of TYPE_TRANSLATION, the mutually exclusive
518 * TYPE_*_ROTATIONs, and the mutually exclusive TYPE_*_SCALEs.
520 * @see #TYPE_IDENTITY
521 * @see #TYPE_TRANSLATION
522 * @see #TYPE_UNIFORM_SCALE
523 * @see #TYPE_GENERAL_SCALE
524 * @see #TYPE_QUADRANT_ROTATION
525 * @see #TYPE_GENERAL_ROTATION
526 * @see #TYPE_GENERAL_TRANSFORM
528 public int getType()
530 return type;
534 * Return the determinant of this transform matrix. If the determinant is
535 * non-zero, the transform is invertible; otherwise operations which require
536 * an inverse throw a NoninvertibleTransformException. A result very near
537 * zero, due to rounding errors, may indicate that inversion results do not
538 * carry enough precision to be meaningful.
540 * <p>If this is a uniform scale transformation, the determinant also
541 * represents the squared value of the scale. Otherwise, it carries little
542 * additional meaning. The determinant is calculated as:
543 * <pre>
544 * | m00 m01 m02 |
545 * | m10 m11 m12 | = m00 * m11 - m01 * m10
546 * | 0 0 1 |
547 * </pre>
549 * @return the determinant
550 * @see #createInverse()
552 public double getDeterminant()
554 return m00 * m11 - m01 * m10;
558 * Return the matrix of values used in this transform. If the matrix has
559 * fewer than 6 entries, only the scale and shear factors are returned;
560 * otherwise the translation factors are copied as well. The resulting
561 * values are:
562 * <pre>
563 * [ d[0] d[2] (d[4]) ]
564 * [ d[1] d[3] (d[5]) ]
565 * [ 0 0 1 ]
566 * </pre>
568 * @param d the matrix to store the results into; with 4 (6) entries
569 * @throws NullPointerException if d is null
570 * @throws ArrayIndexOutOfBoundsException if d is too small
572 public void getMatrix(double[] d)
574 d[0] = m00;
575 d[1] = m10;
576 d[2] = m01;
577 d[3] = m11;
578 if (d.length >= 6)
580 d[4] = m02;
581 d[5] = m12;
586 * Returns the X coordinate scaling factor of the matrix.
588 * @return m00
589 * @see #getMatrix(double[])
591 public double getScaleX()
593 return m00;
597 * Returns the Y coordinate scaling factor of the matrix.
599 * @return m11
600 * @see #getMatrix(double[])
602 public double getScaleY()
604 return m11;
608 * Returns the X coordinate shearing factor of the matrix.
610 * @return m01
611 * @see #getMatrix(double[])
613 public double getShearX()
615 return m01;
619 * Returns the Y coordinate shearing factor of the matrix.
621 * @return m10
622 * @see #getMatrix(double[])
624 public double getShearY()
626 return m10;
630 * Returns the X coordinate translation factor of the matrix.
632 * @return m02
633 * @see #getMatrix(double[])
635 public double getTranslateX()
637 return m02;
641 * Returns the Y coordinate translation factor of the matrix.
643 * @return m12
644 * @see #getMatrix(double[])
646 public double getTranslateY()
648 return m12;
652 * Concatenate a translation onto this transform. This is equivalent, but
653 * more efficient than
654 * <code>concatenate(AffineTransform.getTranslateInstance(tx, ty))</code>.
656 * @param tx the x translation distance
657 * @param ty the y translation distance
658 * @see #getTranslateInstance(double, double)
659 * @see #concatenate(AffineTransform)
661 public void translate(double tx, double ty)
663 m02 += tx * m00 + ty * m01;
664 m12 += tx * m10 + ty * m11;
665 updateType();
669 * Concatenate a rotation onto this transform. This is equivalent, but
670 * more efficient than
671 * <code>concatenate(AffineTransform.getRotateInstance(theta))</code>.
673 * @param theta the rotation angle
674 * @see #getRotateInstance(double)
675 * @see #concatenate(AffineTransform)
677 public void rotate(double theta)
679 double c = Math.cos(theta);
680 double s = Math.sin(theta);
681 double n00 = m00 * c + m01 * s;
682 double n01 = m00 * -s + m01 * c;
683 double n10 = m10 * c + m11 * s;
684 double n11 = m10 * -s + m11 * c;
685 m00 = n00;
686 m01 = n01;
687 m10 = n10;
688 m11 = n11;
689 updateType();
693 * Concatenate a rotation about a point onto this transform. This is
694 * equivalent, but more efficient than
695 * <code>concatenate(AffineTransform.getRotateInstance(theta, x, y))</code>.
697 * @param theta the rotation angle
698 * @param x the x coordinate of the pivot point
699 * @param y the y coordinate of the pivot point
700 * @see #getRotateInstance(double, double, double)
701 * @see #concatenate(AffineTransform)
703 public void rotate(double theta, double x, double y)
705 translate(x, y);
706 rotate(theta);
707 translate(-x, -y);
711 * Concatenate a scale onto this transform. This is equivalent, but more
712 * efficient than
713 * <code>concatenate(AffineTransform.getScaleInstance(sx, sy))</code>.
715 * @param sx the x scaling factor
716 * @param sy the y scaling factor
717 * @see #getScaleInstance(double, double)
718 * @see #concatenate(AffineTransform)
720 public void scale(double sx, double sy)
722 m00 *= sx;
723 m01 *= sy;
724 m10 *= sx;
725 m11 *= sy;
726 updateType();
730 * Concatenate a shearing onto this transform. This is equivalent, but more
731 * efficient than
732 * <code>concatenate(AffineTransform.getShearInstance(sx, sy))</code>.
734 * @param shx the x shearing factor
735 * @param shy the y shearing factor
736 * @see #getShearInstance(double, double)
737 * @see #concatenate(AffineTransform)
739 public void shear(double shx, double shy)
741 double n00 = m00 + shx * m01;
742 double n01 = shx * m00 + m01;
743 double n10 = m10 * shy + m11;
744 double n11 = shx * m10 + m11;
745 m00 = n00;
746 m01 = n01;
747 m10 = n10;
748 m11 = n11;
749 updateType();
753 * Reset this transform to the identity (no transformation):
754 * <pre>
755 * [ 1 0 0 ]
756 * [ 0 1 0 ]
757 * [ 0 0 1 ]
758 * </pre>
760 public void setToIdentity()
762 m00 = m11 = 1;
763 m01 = m02 = m10 = m12 = 0;
764 type = TYPE_IDENTITY;
768 * Set this transform to a translation:
769 * <pre>
770 * [ 1 0 tx ]
771 * [ 0 1 ty ]
772 * [ 0 0 1 ]
773 * </pre>
775 * @param tx the x translation distance
776 * @param ty the y translation distance
778 public void setToTranslation(double tx, double ty)
780 m00 = m11 = 1;
781 m01 = m10 = 0;
782 m02 = tx;
783 m12 = ty;
784 type = (tx == 0 && ty == 0) ? TYPE_UNIFORM_SCALE : TYPE_TRANSLATION;
788 * Set this transform to a rotation. A positive angle (in radians) rotates
789 * the positive x-axis to the positive y-axis:
790 * <pre>
791 * [ cos(theta) -sin(theta) 0 ]
792 * [ sin(theta) cos(theta) 0 ]
793 * [ 0 0 1 ]
794 * </pre>
796 * @param theta the rotation angle
798 public void setToRotation(double theta)
800 double c = Math.cos(theta);
801 double s = Math.sin(theta);
802 m00 = c;
803 m01 = -s;
804 m02 = 0;
805 m10 = s;
806 m11 = c;
807 m12 = 0;
808 type = (c == 1 ? TYPE_IDENTITY
809 : c == 0 || c == -1 ? TYPE_QUADRANT_ROTATION
810 : TYPE_GENERAL_ROTATION);
814 * Set this transform to a rotation about a point. A positive angle (in
815 * radians) rotates the positive x-axis to the positive y-axis. This is the
816 * same as calling:
817 * <pre>
818 * tx.setToTranslation(x, y);
819 * tx.rotate(theta);
820 * tx.translate(-x, -y);
821 * </pre>
823 * <p>The resulting matrix is:
824 * <pre>
825 * [ cos(theta) -sin(theta) x-x*cos+y*sin ]
826 * [ sin(theta) cos(theta) y-x*sin-y*cos ]
827 * [ 0 0 1 ]
828 * </pre>
830 * @param theta the rotation angle
831 * @param x the x coordinate of the pivot point
832 * @param y the y coordinate of the pivot point
834 public void setToRotation(double theta, double x, double y)
836 double c = Math.cos(theta);
837 double s = Math.sin(theta);
838 m00 = c;
839 m01 = -s;
840 m02 = x - x * c + y * s;
841 m10 = s;
842 m11 = c;
843 m12 = y - x * s - y * c;
844 updateType();
848 * Set this transform to a scale:
849 * <pre>
850 * [ sx 0 0 ]
851 * [ 0 sy 0 ]
852 * [ 0 0 1 ]
853 * </pre>
855 * @param sx the x scaling factor
856 * @param sy the y scaling factor
858 public void setToScale(double sx, double sy)
860 m00 = sx;
861 m01 = m02 = m10 = m12 = 0;
862 m11 = sy;
863 type = (sx != sy ? TYPE_GENERAL_SCALE
864 : sx == 1 ? TYPE_IDENTITY : TYPE_UNIFORM_SCALE);
868 * Set this transform to a shear (points are shifted in the x direction based
869 * on a factor of their y coordinate, and in the y direction as a factor of
870 * their x coordinate):
871 * <pre>
872 * [ 1 shx 0 ]
873 * [ shy 1 0 ]
874 * [ 0 0 1 ]
875 * </pre>
877 * @param shx the x shearing factor
878 * @param shy the y shearing factor
880 public void setToShear(double shx, double shy)
882 m00 = m11 = 1;
883 m01 = shx;
884 m10 = shy;
885 m02 = m12 = 0;
886 updateType();
890 * Set this transform to a copy of the given one.
892 * @param tx the transform to copy
893 * @throws NullPointerException if tx is null
895 public void setTransform(AffineTransform tx)
897 m00 = tx.m00;
898 m01 = tx.m01;
899 m02 = tx.m02;
900 m10 = tx.m10;
901 m11 = tx.m11;
902 m12 = tx.m12;
903 type = tx.type;
907 * Set this transform to the given values:
908 * <pre>
909 * [ m00 m01 m02 ]
910 * [ m10 m11 m12 ]
911 * [ 0 0 1 ]
912 * </pre>
914 * @param m00 the x scaling component
915 * @param m10 the y shearing component
916 * @param m01 the x shearing component
917 * @param m11 the y scaling component
918 * @param m02 the x translation component
919 * @param m12 the y translation component
921 public void setTransform(double m00, double m10, double m01,
922 double m11, double m02, double m12)
924 this.m00 = m00;
925 this.m10 = m10;
926 this.m01 = m01;
927 this.m11 = m11;
928 this.m02 = m02;
929 this.m12 = m12;
930 updateType();
934 * Set this transform to the result of performing the original version of
935 * this followed by tx. This is commonly used when chaining transformations
936 * from one space to another. In matrix form:
937 * <pre>
938 * [ this ] = [ this ] x [ tx ]
939 * </pre>
941 * @param tx the transform to concatenate
942 * @throws NullPointerException if tx is null
943 * @see #preConcatenate(AffineTransform)
945 public void concatenate(AffineTransform tx)
947 double n00 = m00 * tx.m00 + m01 * tx.m10;
948 double n01 = m00 * tx.m01 + m01 * tx.m11;
949 double n02 = m00 * tx.m02 + m01 * tx.m12 + m02;
950 double n10 = m10 * tx.m00 + m11 * tx.m10;
951 double n11 = m10 * tx.m01 + m11 * tx.m11;
952 double n12 = m10 * tx.m02 + m11 * tx.m12 + m12;
953 m00 = n00;
954 m01 = n01;
955 m02 = n02;
956 m10 = n10;
957 m11 = n11;
958 m12 = n12;
959 updateType();
963 * Set this transform to the result of performing tx followed by the
964 * original version of this. This is less common than normal concatenation,
965 * but can still be used to chain transformations from one space to another.
966 * In matrix form:
967 * <pre>
968 * [ this ] = [ tx ] x [ this ]
969 * </pre>
971 * @param tx the transform to concatenate
972 * @throws NullPointerException if tx is null
973 * @see #concatenate(AffineTransform)
975 public void preConcatenate(AffineTransform tx)
977 double n00 = tx.m00 * m00 + tx.m01 * m10;
978 double n01 = tx.m00 * m01 + tx.m01 * m11;
979 double n02 = tx.m00 * m02 + tx.m01 * m12 + tx.m02;
980 double n10 = tx.m10 * m00 + tx.m11 * m10;
981 double n11 = tx.m10 * m01 + tx.m11 * m11;
982 double n12 = tx.m10 * m02 + tx.m11 * m12 + tx.m12;
983 m00 = n00;
984 m01 = n01;
985 m02 = n02;
986 m10 = n10;
987 m11 = n11;
988 m12 = n12;
989 updateType();
993 * Returns a transform, which if concatenated to this one, will result in
994 * the identity transform. This is useful for undoing transformations, but
995 * is only possible if the original transform has an inverse (ie. does not
996 * map multiple points to the same line or point). A transform exists only
997 * if getDeterminant() has a non-zero value.
999 * @return a new inverse transform
1000 * @throws NoninvertibleTransformException if inversion is not possible
1001 * @see #getDeterminant()
1003 public AffineTransform createInverse()
1004 throws NoninvertibleTransformException
1006 double det = getDeterminant();
1007 if (det == 0)
1008 throw new NoninvertibleTransformException("can't invert transform");
1009 return new AffineTransform(m11 / det, -m10 / det, m01 / det, -m00 / det,
1010 -m02, -m12);
1014 * Perform this transformation on the given source point, and store the
1015 * result in the destination (creating it if necessary). It is safe for
1016 * src and dst to be the same.
1018 * @param src the source point
1019 * @param dst the destination, or null
1020 * @return the transformation of src, in dst if it was non-null
1021 * @throws NullPointerException if src is null
1023 public Point2D transform(Point2D src, Point2D dst)
1025 if (dst == null)
1026 dst = new Point2D.Double();
1027 double x = src.getX();
1028 double y = src.getY();
1029 double nx = m00 * x + m01 * y + m02;
1030 double ny = m10 * x + m11 * y + m12;
1031 dst.setLocation(nx, ny);
1032 return dst;
1036 * Perform this transformation on an array of points, storing the results
1037 * in another (possibly same) array. This will not create a destination
1038 * array, but will create points for the null entries of the destination.
1039 * The transformation is done sequentially. While having a single source
1040 * and destination point be the same is safe, you should be aware that
1041 * duplicate references to the same point in the source, and having the
1042 * source overlap the destination, may result in your source points changing
1043 * from a previous transform before it is their turn to be evaluated.
1045 * @param src the array of source points
1046 * @param srcOff the starting offset into src
1047 * @param dst the array of destination points (may have null entries)
1048 * @param dstOff the starting offset into dst
1049 * @param num the number of points to transform
1050 * @throws NullPointerException if src or dst is null, or src has null
1051 * entries
1052 * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded
1053 * @throws ArrayStoreException if new points are incompatible with dst
1055 public void transform(Point2D[] src, int srcOff,
1056 Point2D[] dst, int dstOff, int num)
1058 while (--num >= 0)
1059 dst[dstOff] = transform(src[srcOff++], dst[dstOff++]);
1063 * Perform this transformation on an array of points, in (x,y) pairs,
1064 * storing the results in another (possibly same) array. This will not
1065 * create a destination array. All sources are copied before the
1066 * transformation, so that no result will overwrite a point that has not yet
1067 * been evaluated.
1069 * @param src the array of source points
1070 * @param srcOff the starting offset into src
1071 * @param dst the array of destination points
1072 * @param dstOff the starting offset into dst
1073 * @param num the number of points to transform
1074 * @throws NullPointerException if src or dst is null
1075 * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded
1077 public void transform(float[] srcPts, int srcOff,
1078 float[] dstPts, int dstOff, int num)
1080 if (srcPts == dstPts && dstOff > srcOff
1081 && num > 1 && srcOff + 2 * num > dstOff)
1083 float[] f = new float[2 * num];
1084 System.arraycopy(srcPts, srcOff, f, 0, 2 * num);
1085 srcPts = f;
1087 while (--num >= 0)
1089 float x = srcPts[srcOff++];
1090 float y = srcPts[srcOff++];
1091 dstPts[dstOff++] = (float) (m00 * x + m01 * y + m02);
1092 dstPts[dstOff++] = (float) (m10 * x + m11 * y + m12);
1097 * Perform this transformation on an array of points, in (x,y) pairs,
1098 * storing the results in another (possibly same) array. This will not
1099 * create a destination array. All sources are copied before the
1100 * transformation, so that no result will overwrite a point that has not yet
1101 * been evaluated.
1103 * @param src the array of source points
1104 * @param srcOff the starting offset into src
1105 * @param dst the array of destination points
1106 * @param dstOff the starting offset into dst
1107 * @param num the number of points to transform
1108 * @throws NullPointerException if src or dst is null
1109 * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded
1111 public void transform(double[] srcPts, int srcOff,
1112 double[] dstPts, int dstOff, int num)
1114 if (srcPts == dstPts && dstOff > srcOff
1115 && num > 1 && srcOff + 2 * num > dstOff)
1117 double[] d = new double[2 * num];
1118 System.arraycopy(srcPts, srcOff, d, 0, 2 * num);
1119 srcPts = d;
1121 while (--num >= 0)
1123 double x = srcPts[srcOff++];
1124 double y = srcPts[srcOff++];
1125 dstPts[dstOff++] = m00 * x + m01 * y + m02;
1126 dstPts[dstOff++] = m10 * x + m11 * y + m12;
1131 * Perform this transformation on an array of points, in (x,y) pairs,
1132 * storing the results in another array. This will not create a destination
1133 * array.
1135 * @param src the array of source points
1136 * @param srcOff the starting offset into src
1137 * @param dst the array of destination points
1138 * @param dstOff the starting offset into dst
1139 * @param num the number of points to transform
1140 * @throws NullPointerException if src or dst is null
1141 * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded
1143 public void transform(float[] srcPts, int srcOff,
1144 double[] dstPts, int dstOff, int num)
1146 while (--num >= 0)
1148 float x = srcPts[srcOff++];
1149 float y = srcPts[srcOff++];
1150 dstPts[dstOff++] = m00 * x + m01 * y + m02;
1151 dstPts[dstOff++] = m10 * x + m11 * y + m12;
1156 * Perform this transformation on an array of points, in (x,y) pairs,
1157 * storing the results in another array. This will not create a destination
1158 * array.
1160 * @param src the array of source points
1161 * @param srcOff the starting offset into src
1162 * @param dst the array of destination points
1163 * @param dstOff the starting offset into dst
1164 * @param num the number of points to transform
1165 * @throws NullPointerException if src or dst is null
1166 * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded
1168 public void transform(double[] srcPts, int srcOff,
1169 float[] dstPts, int dstOff, int num)
1171 while (--num >= 0)
1173 double x = srcPts[srcOff++];
1174 double y = srcPts[srcOff++];
1175 dstPts[dstOff++] = (float) (m00 * x + m01 * y + m02);
1176 dstPts[dstOff++] = (float) (m10 * x + m11 * y + m12);
1181 * Perform the inverse of this transformation on the given source point,
1182 * and store the result in the destination (creating it if necessary). It
1183 * is safe for src and dst to be the same.
1185 * @param src the source point
1186 * @param dst the destination, or null
1187 * @return the inverse transformation of src, in dst if it was non-null
1188 * @throws NullPointerException if src is null
1189 * @throws NoninvertibleTransformException if the inverse does not exist
1190 * @see #getDeterminant()
1192 public Point2D inverseTransform(Point2D src, Point2D dst)
1193 throws NoninvertibleTransformException
1195 double det = getDeterminant();
1196 if (det == 0)
1197 throw new NoninvertibleTransformException("couldn't invert transform");
1198 if (dst == null)
1199 dst = new Point2D.Double();
1200 double x = src.getX();
1201 double y = src.getY();
1202 double nx = (m11 * x + -m10 * y) / det - m02;
1203 double ny = (m01 * x + -m00 * y) / det - m12;
1204 dst.setLocation(nx, ny);
1205 return dst;
1209 * Perform the inverse of this transformation on an array of points, in
1210 * (x,y) pairs, storing the results in another (possibly same) array. This
1211 * will not create a destination array. All sources are copied before the
1212 * transformation, so that no result will overwrite a point that has not yet
1213 * been evaluated.
1215 * @param src the array of source points
1216 * @param srcOff the starting offset into src
1217 * @param dst the array of destination points
1218 * @param dstOff the starting offset into dst
1219 * @param num the number of points to transform
1220 * @throws NullPointerException if src or dst is null
1221 * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded
1222 * @throws NoninvertibleTransformException if the inverse does not exist
1223 * @see #getDeterminant()
1225 public void inverseTransform(double[] srcPts, int srcOff,
1226 double[] dstPts, int dstOff, int num)
1227 throws NoninvertibleTransformException
1229 double det = getDeterminant();
1230 if (det == 0)
1231 throw new NoninvertibleTransformException("couldn't invert transform");
1232 if (srcPts == dstPts && dstOff > srcOff
1233 && num > 1 && srcOff + 2 * num > dstOff)
1235 double[] d = new double[2 * num];
1236 System.arraycopy(srcPts, srcOff, d, 0, 2 * num);
1237 srcPts = d;
1239 while (--num >= 0)
1241 double x = srcPts[srcOff++];
1242 double y = srcPts[srcOff++];
1243 dstPts[dstOff++] = (m11 * x + -m10 * y) / det - m02;
1244 dstPts[dstOff++] = (m01 * x + -m00 * y) / det - m12;
1249 * Perform this transformation, less any translation, on the given source
1250 * point, and store the result in the destination (creating it if
1251 * necessary). It is safe for src and dst to be the same. The reduced
1252 * transform is equivalent to:
1253 * <pre>
1254 * [ x' ] = [ m00 m01 ] [ x ] = [ m00 * x + m01 * y ]
1255 * [ y' ] [ m10 m11 ] [ y ] = [ m10 * x + m11 * y ]
1256 * </pre>
1258 * @param src the source point
1259 * @param dst the destination, or null
1260 * @return the delta transformation of src, in dst if it was non-null
1261 * @throws NullPointerException if src is null
1263 public Point2D deltaTransform(Point2D src, Point2D dst)
1265 if (dst == null)
1266 dst = new Point2D.Double();
1267 double x = src.getX();
1268 double y = src.getY();
1269 double nx = m00 * x + m01 * y;
1270 double ny = m10 * x + m11 * y;
1271 dst.setLocation(nx, ny);
1272 return dst;
1276 * Perform this transformation, less any translation, on an array of points,
1277 * in (x,y) pairs, storing the results in another (possibly same) array.
1278 * This will not create a destination array. All sources are copied before
1279 * the transformation, so that no result will overwrite a point that has
1280 * not yet been evaluated. The reduced transform is equivalent to:
1281 * <pre>
1282 * [ x' ] = [ m00 m01 ] [ x ] = [ m00 * x + m01 * y ]
1283 * [ y' ] [ m10 m11 ] [ y ] = [ m10 * x + m11 * y ]
1284 * </pre>
1286 * @param src the array of source points
1287 * @param srcOff the starting offset into src
1288 * @param dst the array of destination points
1289 * @param dstOff the starting offset into dst
1290 * @param num the number of points to transform
1291 * @throws NullPointerException if src or dst is null
1292 * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded
1294 public void deltaTransform(double[] srcPts, int srcOff,
1295 double[] dstPts, int dstOff,
1296 int num)
1298 if (srcPts == dstPts && dstOff > srcOff
1299 && num > 1 && srcOff + 2 * num > dstOff)
1301 double[] d = new double[2 * num];
1302 System.arraycopy(srcPts, srcOff, d, 0, 2 * num);
1303 srcPts = d;
1305 while (--num >= 0)
1307 double x = srcPts[srcOff++];
1308 double y = srcPts[srcOff++];
1309 dstPts[dstOff++] = m00 * x + m01 * y;
1310 dstPts[dstOff++] = m10 * x + m11 * y;
1315 * Return a new Shape, based on the given one, where the path of the shape
1316 * has been transformed by this transform. Notice that this uses GeneralPath,
1317 * which only stores points in float precision.
1319 * @param src the shape source to transform
1320 * @return the shape, transformed by this
1321 * @throws NullPointerException if src is null
1322 * @see GeneralPath#transform(AffineTransform)
1324 public Shape createTransformedShape(Shape src)
1326 GeneralPath p = new GeneralPath(src);
1327 p.transform(this);
1328 return p;
1332 * Returns a string representation of the transform, in the format:
1333 * <code>"AffineTransform[[" + m00 + ", " + m01 + ", " + m02 + "], ["
1334 * + m10 + ", " + m11 + ", " + m12 + "]]"</code>.
1336 * @return the string representation
1338 public String toString()
1340 return "AffineTransform[[" + m00 + ", " + m01 + ", " + m02 + "], ["
1341 + m10 + ", " + m11 + ", " + m12 + "]]";
1345 * Tests if this transformation is the identity:
1346 * <pre>
1347 * [ 1 0 0 ]
1348 * [ 0 1 0 ]
1349 * [ 0 0 1 ]
1350 * </pre>
1352 * @return true if this is the identity transform
1354 public boolean isIdentity()
1356 // Rather than rely on type, check explicitly.
1357 return (m00 == 1 && m01 == 0 && m02 == 0
1358 && m10 == 0 && m11 == 1 && m12 == 0);
1362 * Create a new transform of the same run-time type, with the same
1363 * transforming properties as this one.
1365 * @return the clone
1367 public Object clone()
1371 return super.clone();
1373 catch (CloneNotSupportedException e)
1375 throw (Error) new InternalError().initCause(e); // Impossible
1380 * Return the hashcode for this transformation. The formula is not
1381 * documented, but appears to be the same as:
1382 * <pre>
1383 * long l = Double.doubleToLongBits(getScaleX());
1384 * l = l * 31 + Double.doubleToLongBits(getShearY());
1385 * l = l * 31 + Double.doubleToLongBits(getShearX());
1386 * l = l * 31 + Double.doubleToLongBits(getScaleY());
1387 * l = l * 31 + Double.doubleToLongBits(getTranslateX());
1388 * l = l * 31 + Double.doubleToLongBits(getTranslateY());
1389 * return (int) ((l >> 32) ^ l);
1390 * </pre>
1392 * @return the hashcode
1394 public int hashCode()
1396 long l = Double.doubleToLongBits(m00);
1397 l = l * 31 + Double.doubleToLongBits(m10);
1398 l = l * 31 + Double.doubleToLongBits(m01);
1399 l = l * 31 + Double.doubleToLongBits(m11);
1400 l = l * 31 + Double.doubleToLongBits(m02);
1401 l = l * 31 + Double.doubleToLongBits(m12);
1402 return (int) ((l >> 32) ^ l);
1406 * Compares two transforms for equality. This returns true if they have the
1407 * same matrix values.
1409 * @param o the transform to compare
1410 * @return true if it is equal
1412 public boolean equals(Object obj)
1414 if (! (obj instanceof AffineTransform))
1415 return false;
1416 AffineTransform t = (AffineTransform) obj;
1417 return (m00 == t.m00 && m01 == t.m01 && m02 == t.m02
1418 && m10 == t.m10 && m11 == t.m11 && m12 == t.m12);
1422 * Helper to decode the type from the matrix. This is not guaranteed
1423 * to find the optimal type, but at least it will be valid.
1425 private void updateType()
1427 double det = getDeterminant();
1428 if (det == 0)
1430 type = TYPE_GENERAL_TRANSFORM;
1431 return;
1433 // Scale (includes rotation by PI) or translation.
1434 if (m01 == 0 && m10 == 0)
1436 if (m00 == m11)
1437 type = m00 == 1 ? TYPE_IDENTITY : TYPE_UNIFORM_SCALE;
1438 else
1439 type = TYPE_GENERAL_SCALE;
1440 if (m02 != 0 || m12 != 0)
1441 type |= TYPE_TRANSLATION;
1443 // Rotation.
1444 else if (m00 == m11 && m01 == -m10)
1446 type = m00 == 0 ? TYPE_QUADRANT_ROTATION : TYPE_GENERAL_ROTATION;
1447 if (det != 1)
1448 type |= TYPE_UNIFORM_SCALE;
1449 if (m02 != 0 || m12 != 0)
1450 type |= TYPE_TRANSLATION;
1452 else
1453 type = TYPE_GENERAL_TRANSFORM;
1457 * Reads a transform from an object stream.
1459 * @param s the stream to read from
1460 * @throws ClassNotFoundException if there is a problem deserializing
1461 * @throws IOException if there is a problem deserializing
1463 private void readObject(ObjectInputStream s)
1464 throws ClassNotFoundException, IOException
1466 s.defaultReadObject();
1467 updateType();
1469 } // class AffineTransform