OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [java/] [awt/] [geom/] [AffineTransform.java] - Blame information for rev 771

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 771 jeremybenn
/* AffineTransform.java -- transform coordinates between two 2-D spaces
2
   Copyright (C) 2000, 2001, 2002, 2004 Free Software Foundation
3
 
4
This file is part of GNU Classpath.
5
 
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.
10
 
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.
15
 
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., 51 Franklin Street, Fifth Floor, Boston, MA
19
02110-1301 USA.
20
 
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.
25
 
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. */
37
 
38
 
39
package java.awt.geom;
40
 
41
import java.awt.Shape;
42
import java.io.IOException;
43
import java.io.ObjectInputStream;
44
import java.io.Serializable;
45
 
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.
51
 *
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]]".
62
 *
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
67
 */
68
public class AffineTransform implements Cloneable, Serializable
69
{
70
  /**
71
   * Compatible with JDK 1.2+.
72
   */
73
  private static final long serialVersionUID = 1330973210523860834L;
74
 
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.
79
   *
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()
88
   */
89
  public static final int TYPE_IDENTITY = 0;
90
 
91
  /**
92
   * The transformation includes a translation - shifting in the x or y
93
   * direction without changing length or angles.
94
   *
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()
103
   */
104
  public static final int TYPE_TRANSLATION = 1;
105
 
106
  /**
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.
110
   *
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()
120
   */
121
  public static final int TYPE_UNIFORM_SCALE = 2;
122
 
123
  /**
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.
127
   *
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()
137
   */
138
  public static final int TYPE_GENERAL_SCALE = 4;
139
 
140
  /**
141
   * This constant checks if either variety of scale transform is performed.
142
   *
143
   * @see #TYPE_UNIFORM_SCALE
144
   * @see #TYPE_GENERAL_SCALE
145
   */
146
  public static final int TYPE_MASK_SCALE = 6;
147
 
148
  /**
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.
153
   *
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()
162
   */
163
  public static final int TYPE_FLIP = 64;
164
 
165
  /**
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.
169
   *
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()
179
   */
180
  public static final int TYPE_QUADRANT_ROTATION = 8;
181
 
182
  /**
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.
186
   *
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()
196
   */
197
  public static final int TYPE_GENERAL_ROTATION = 16;
198
 
199
  /**
200
   * This constant checks if either variety of rotation is performed.
201
   *
202
   * @see #TYPE_QUADRANT_ROTATION
203
   * @see #TYPE_GENERAL_ROTATION
204
   */
205
  public static final int TYPE_MASK_ROTATION = 24;
206
 
207
  /**
208
   * The transformation is an arbitrary conversion of coordinates which
209
   * could not be decomposed into the other TYPEs.
210
   *
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()
219
   */
220
  public static final int TYPE_GENERAL_TRANSFORM = 32;
221
 
222
  /**
223
   * The X coordinate scaling element of the transform matrix.
224
   *
225
   * @serial matrix[0,0]
226
   */
227
  private double m00;
228
 
229
  /**
230
   * The Y coordinate shearing element of the transform matrix.
231
   *
232
   * @serial matrix[1,0]
233
   */
234
  private double m10;
235
 
236
  /**
237
   * The X coordinate shearing element of the transform matrix.
238
   *
239
   * @serial matrix[0,1]
240
   */
241
  private double m01;
242
 
243
  /**
244
   * The Y coordinate scaling element of the transform matrix.
245
   *
246
   * @serial matrix[1,1]
247
   */
248
  private double m11;
249
 
250
  /**
251
   * The X coordinate translation element of the transform matrix.
252
   *
253
   * @serial matrix[0,2]
254
   */
255
  private double m02;
256
 
257
  /**
258
   * The Y coordinate translation element of the transform matrix.
259
   *
260
   * @serial matrix[1,2]
261
   */
262
  private double m12;
263
 
264
  /** The type of this transform. */
265
  private transient int type;
266
 
267
  /**
268
   * Construct a new identity transform:
269
   * <pre>
270
   * [ 1 0 0 ]
271
   * [ 0 1 0 ]
272
   * [ 0 0 1 ]
273
   * </pre>
274
   */
275
  public AffineTransform()
276
  {
277
    m00 = m11 = 1;
278
  }
279
 
280
  /**
281
   * Create a new transform which copies the given one.
282
   *
283
   * @param tx the transform to copy
284
   * @throws NullPointerException if tx is null
285
   */
286
  public AffineTransform(AffineTransform tx)
287
  {
288
    setTransform(tx);
289
  }
290
 
291
  /**
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>
298
   *
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
305
   */
306
  public AffineTransform(float m00, float m10,
307
                         float m01, float m11,
308
                         float m02, float m12)
309
  {
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();
317
  }
318
 
319
  /**
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>
328
   *
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
332
   */
333
  public AffineTransform(float[] f)
334
  {
335
    m00 = f[0];
336
    m10 = f[1];
337
    m01 = f[2];
338
    m11 = f[3];
339
    if (f.length >= 6)
340
      {
341
        m02 = f[4];
342
        m12 = f[5];
343
      }
344
    updateType();
345
  }
346
 
347
  /**
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>
354
   *
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
361
   */
362
  public AffineTransform(double m00, double m10, double m01,
363
                         double m11, double m02, double m12)
364
  {
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();
372
  }
373
 
374
  /**
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>
383
   *
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
387
   */
388
  public AffineTransform(double[] d)
389
  {
390
    m00 = d[0];
391
    m10 = d[1];
392
    m01 = d[2];
393
    m11 = d[3];
394
    if (d.length >= 6)
395
      {
396
        m02 = d[4];
397
        m12 = d[5];
398
      }
399
    updateType();
400
  }
401
 
402
  /**
403
   * Returns a translation transform:
404
   * <pre>
405
   * [ 1 0 tx ]
406
   * [ 0 1 ty ]
407
   * [ 0 0 1  ]
408
   * </pre>
409
   *
410
   * @param tx the x translation distance
411
   * @param ty the y translation distance
412
   * @return the translating transform
413
   */
414
  public static AffineTransform getTranslateInstance(double tx, double ty)
415
  {
416
    AffineTransform t = new AffineTransform();
417
    t.m02 = tx;
418
    t.m12 = ty;
419
    t.type = (tx == 0 && ty == 0) ? TYPE_UNIFORM_SCALE : TYPE_TRANSLATION;
420
    return t;
421
  }
422
 
423
  /**
424
   * Returns a rotation transform. A positive angle (in radians) rotates
425
   * the positive x-axis to the positive y-axis:
426
   * <pre>
427
   * [ cos(theta) -sin(theta) 0 ]
428
   * [ sin(theta)  cos(theta) 0 ]
429
   * [     0           0      1 ]
430
   * </pre>
431
   *
432
   * @param theta the rotation angle
433
   * @return the rotating transform
434
   */
435
  public static AffineTransform getRotateInstance(double theta)
436
  {
437
    AffineTransform t = new AffineTransform();
438
    t.setToRotation(theta);
439
    return t;
440
  }
441
 
442
  /**
443
   * Returns a rotation transform about a point. A positive angle (in radians)
444
   * rotates the positive x-axis to the positive y-axis. This is the same
445
   * as calling:
446
   * <pre>
447
   * AffineTransform tx = new AffineTransform();
448
   * tx.setToTranslation(x, y);
449
   * tx.rotate(theta);
450
   * tx.translate(-x, -y);
451
   * </pre>
452
   *
453
   * <p>The resulting matrix is:
454
   * <pre>
455
   * [ cos(theta) -sin(theta) x-x*cos+y*sin ]
456
   * [ sin(theta)  cos(theta) y-x*sin-y*cos ]
457
   * [     0           0            1       ]
458
   * </pre>
459
   *
460
   * @param theta the rotation angle
461
   * @param x the x coordinate of the pivot point
462
   * @param y the y coordinate of the pivot point
463
   * @return the rotating transform
464
   */
465
  public static AffineTransform getRotateInstance(double theta,
466
                                                  double x, double y)
467
  {
468
    AffineTransform t = new AffineTransform();
469
    t.setToTranslation(x, y);
470
    t.rotate(theta);
471
    t.translate(-x, -y);
472
    return t;
473
  }
474
 
475
  /**
476
   * Returns a scaling transform:
477
   * <pre>
478
   * [ sx 0  0 ]
479
   * [ 0  sy 0 ]
480
   * [ 0  0  1 ]
481
   * </pre>
482
   *
483
   * @param sx the x scaling factor
484
   * @param sy the y scaling factor
485
   * @return the scaling transform
486
   */
487
  public static AffineTransform getScaleInstance(double sx, double sy)
488
  {
489
    AffineTransform t = new AffineTransform();
490
    t.setToScale(sx, sy);
491
    return t;
492
  }
493
 
494
  /**
495
   * Returns a shearing transform (points are shifted in the x direction based
496
   * on a factor of their y coordinate, and in the y direction as a factor of
497
   * their x coordinate):
498
   * <pre>
499
   * [  1  shx 0 ]
500
   * [ shy  1  0 ]
501
   * [  0   0  1 ]
502
   * </pre>
503
   *
504
   * @param shx the x shearing factor
505
   * @param shy the y shearing factor
506
   * @return the shearing transform
507
   */
508
  public static AffineTransform getShearInstance(double shx, double shy)
509
  {
510
    AffineTransform t = new AffineTransform();
511
    t.setToShear(shx, shy);
512
    return t;
513
  }
514
 
515
  /**
516
   * Returns the type of this transform. The result is always valid, although
517
   * it may not be the simplest interpretation (in other words, there are
518
   * sequences of transforms which reduce to something simpler, which this
519
   * does not always detect). The result is either TYPE_GENERAL_TRANSFORM,
520
   * or a bit-wise combination of TYPE_TRANSLATION, the mutually exclusive
521
   * TYPE_*_ROTATIONs, and the mutually exclusive TYPE_*_SCALEs.
522
   *
523
   * @return The type.
524
   *
525
   * @see #TYPE_IDENTITY
526
   * @see #TYPE_TRANSLATION
527
   * @see #TYPE_UNIFORM_SCALE
528
   * @see #TYPE_GENERAL_SCALE
529
   * @see #TYPE_QUADRANT_ROTATION
530
   * @see #TYPE_GENERAL_ROTATION
531
   * @see #TYPE_GENERAL_TRANSFORM
532
   */
533
  public int getType()
534
  {
535
    return type;
536
  }
537
 
538
  /**
539
   * Return the determinant of this transform matrix. If the determinant is
540
   * non-zero, the transform is invertible; otherwise operations which require
541
   * an inverse throw a NoninvertibleTransformException. A result very near
542
   * zero, due to rounding errors, may indicate that inversion results do not
543
   * carry enough precision to be meaningful.
544
   *
545
   * <p>If this is a uniform scale transformation, the determinant also
546
   * represents the squared value of the scale. Otherwise, it carries little
547
   * additional meaning. The determinant is calculated as:
548
   * <pre>
549
   * | m00 m01 m02 |
550
   * | m10 m11 m12 | = m00 * m11 - m01 * m10
551
   * |  0   0   1  |
552
   * </pre>
553
   *
554
   * @return the determinant
555
   * @see #createInverse()
556
   */
557
  public double getDeterminant()
558
  {
559
    return m00 * m11 - m01 * m10;
560
  }
561
 
562
  /**
563
   * Return the matrix of values used in this transform. If the matrix has
564
   * fewer than 6 entries, only the scale and shear factors are returned;
565
   * otherwise the translation factors are copied as well. The resulting
566
   * values are:
567
   * <pre>
568
   * [ d[0] d[2] (d[4]) ]
569
   * [ d[1] d[3] (d[5]) ]
570
   * [  0     0    1    ]
571
   * </pre>
572
   *
573
   * @param d the matrix to store the results into; with 4 (6) entries
574
   * @throws NullPointerException if d is null
575
   * @throws ArrayIndexOutOfBoundsException if d is too small
576
   */
577
  public void getMatrix(double[] d)
578
  {
579
    d[0] = m00;
580
    d[1] = m10;
581
    d[2] = m01;
582
    d[3] = m11;
583
    if (d.length >= 6)
584
      {
585
        d[4] = m02;
586
        d[5] = m12;
587
      }
588
  }
589
 
590
  /**
591
   * Returns the X coordinate scaling factor of the matrix.
592
   *
593
   * @return m00
594
   * @see #getMatrix(double[])
595
   */
596
  public double getScaleX()
597
  {
598
    return m00;
599
  }
600
 
601
  /**
602
   * Returns the Y coordinate scaling factor of the matrix.
603
   *
604
   * @return m11
605
   * @see #getMatrix(double[])
606
   */
607
  public double getScaleY()
608
  {
609
    return m11;
610
  }
611
 
612
  /**
613
   * Returns the X coordinate shearing factor of the matrix.
614
   *
615
   * @return m01
616
   * @see #getMatrix(double[])
617
   */
618
  public double getShearX()
619
  {
620
    return m01;
621
  }
622
 
623
  /**
624
   * Returns the Y coordinate shearing factor of the matrix.
625
   *
626
   * @return m10
627
   * @see #getMatrix(double[])
628
   */
629
  public double getShearY()
630
  {
631
    return m10;
632
  }
633
 
634
  /**
635
   * Returns the X coordinate translation factor of the matrix.
636
   *
637
   * @return m02
638
   * @see #getMatrix(double[])
639
   */
640
  public double getTranslateX()
641
  {
642
    return m02;
643
  }
644
 
645
  /**
646
   * Returns the Y coordinate translation factor of the matrix.
647
   *
648
   * @return m12
649
   * @see #getMatrix(double[])
650
   */
651
  public double getTranslateY()
652
  {
653
    return m12;
654
  }
655
 
656
  /**
657
   * Concatenate a translation onto this transform. This is equivalent, but
658
   * more efficient than
659
   * <code>concatenate(AffineTransform.getTranslateInstance(tx, ty))</code>.
660
   *
661
   * @param tx the x translation distance
662
   * @param ty the y translation distance
663
   * @see #getTranslateInstance(double, double)
664
   * @see #concatenate(AffineTransform)
665
   */
666
  public void translate(double tx, double ty)
667
  {
668
    m02 += tx * m00 + ty * m01;
669
    m12 += tx * m10 + ty * m11;
670
    updateType();
671
  }
672
 
673
  /**
674
   * Concatenate a rotation onto this transform. This is equivalent, but
675
   * more efficient than
676
   * <code>concatenate(AffineTransform.getRotateInstance(theta))</code>.
677
   *
678
   * @param theta the rotation angle
679
   * @see #getRotateInstance(double)
680
   * @see #concatenate(AffineTransform)
681
   */
682
  public void rotate(double theta)
683
  {
684
    double c = Math.cos(theta);
685
    double s = Math.sin(theta);
686
    double n00 = m00 *  c + m01 * s;
687
    double n01 = m00 * -s + m01 * c;
688
    double n10 = m10 *  c + m11 * s;
689
    double n11 = m10 * -s + m11 * c;
690
    m00 = n00;
691
    m01 = n01;
692
    m10 = n10;
693
    m11 = n11;
694
    updateType();
695
  }
696
 
697
  /**
698
   * Concatenate a rotation about a point onto this transform. This is
699
   * equivalent, but more efficient than
700
   * <code>concatenate(AffineTransform.getRotateInstance(theta, x, y))</code>.
701
   *
702
   * @param theta the rotation angle
703
   * @param x the x coordinate of the pivot point
704
   * @param y the y coordinate of the pivot point
705
   * @see #getRotateInstance(double, double, double)
706
   * @see #concatenate(AffineTransform)
707
   */
708
  public void rotate(double theta, double x, double y)
709
  {
710
    translate(x, y);
711
    rotate(theta);
712
    translate(-x, -y);
713
  }
714
 
715
  /**
716
   * Concatenate a scale onto this transform. This is equivalent, but more
717
   * efficient than
718
   * <code>concatenate(AffineTransform.getScaleInstance(sx, sy))</code>.
719
   *
720
   * @param sx the x scaling factor
721
   * @param sy the y scaling factor
722
   * @see #getScaleInstance(double, double)
723
   * @see #concatenate(AffineTransform)
724
   */
725
  public void scale(double sx, double sy)
726
  {
727
    m00 *= sx;
728
    m01 *= sy;
729
    m10 *= sx;
730
    m11 *= sy;
731
    updateType();
732
  }
733
 
734
  /**
735
   * Concatenate a shearing onto this transform. This is equivalent, but more
736
   * efficient than
737
   * <code>concatenate(AffineTransform.getShearInstance(sx, sy))</code>.
738
   *
739
   * @param shx the x shearing factor
740
   * @param shy the y shearing factor
741
   * @see #getShearInstance(double, double)
742
   * @see #concatenate(AffineTransform)
743
   */
744
  public void shear(double shx, double shy)
745
  {
746
    double n00 = m00 + (shy * m01);
747
    double n01 = m01 + (shx * m00);
748
    double n10 = m10 + (shy * m11);
749
    double n11 = m11 + (shx * m10);
750
    m00 = n00;
751
    m01 = n01;
752
    m10 = n10;
753
    m11 = n11;
754
    updateType();
755
  }
756
 
757
  /**
758
   * Reset this transform to the identity (no transformation):
759
   * <pre>
760
   * [ 1 0 0 ]
761
   * [ 0 1 0 ]
762
   * [ 0 0 1 ]
763
   * </pre>
764
   */
765
  public void setToIdentity()
766
  {
767
    m00 = m11 = 1;
768
    m01 = m02 = m10 = m12 = 0;
769
    type = TYPE_IDENTITY;
770
  }
771
 
772
  /**
773
   * Set this transform to a translation:
774
   * <pre>
775
   * [ 1 0 tx ]
776
   * [ 0 1 ty ]
777
   * [ 0 0 1  ]
778
   * </pre>
779
   *
780
   * @param tx the x translation distance
781
   * @param ty the y translation distance
782
   */
783
  public void setToTranslation(double tx, double ty)
784
  {
785
    m00 = m11 = 1;
786
    m01 = m10 = 0;
787
    m02 = tx;
788
    m12 = ty;
789
    type = (tx == 0 && ty == 0) ? TYPE_UNIFORM_SCALE : TYPE_TRANSLATION;
790
  }
791
 
792
  /**
793
   * Set this transform to a rotation. A positive angle (in radians) rotates
794
   * the positive x-axis to the positive y-axis:
795
   * <pre>
796
   * [ cos(theta) -sin(theta) 0 ]
797
   * [ sin(theta)  cos(theta) 0 ]
798
   * [     0           0      1 ]
799
   * </pre>
800
   *
801
   * @param theta the rotation angle
802
   */
803
  public void setToRotation(double theta)
804
  {
805
    double c = Math.cos(theta);
806
    double s = Math.sin(theta);
807
    m00 = c;
808
    m01 = -s;
809
    m02 = 0;
810
    m10 = s;
811
    m11 = c;
812
    m12 = 0;
813
    type = (c == 1 ? TYPE_IDENTITY
814
            : c == 0 || c == -1 ? TYPE_QUADRANT_ROTATION
815
            : TYPE_GENERAL_ROTATION);
816
  }
817
 
818
  /**
819
   * Set this transform to a rotation about a point. A positive angle (in
820
   * radians) rotates the positive x-axis to the positive y-axis. This is the
821
   * same as calling:
822
   * <pre>
823
   * tx.setToTranslation(x, y);
824
   * tx.rotate(theta);
825
   * tx.translate(-x, -y);
826
   * </pre>
827
   *
828
   * <p>The resulting matrix is:
829
   * <pre>
830
   * [ cos(theta) -sin(theta) x-x*cos+y*sin ]
831
   * [ sin(theta)  cos(theta) y-x*sin-y*cos ]
832
   * [     0           0            1       ]
833
   * </pre>
834
   *
835
   * @param theta the rotation angle
836
   * @param x the x coordinate of the pivot point
837
   * @param y the y coordinate of the pivot point
838
   */
839
  public void setToRotation(double theta, double x, double y)
840
  {
841
    double c = Math.cos(theta);
842
    double s = Math.sin(theta);
843
    m00 = c;
844
    m01 = -s;
845
    m02 = x - x * c + y * s;
846
    m10 = s;
847
    m11 = c;
848
    m12 = y - x * s - y * c;
849
    updateType();
850
  }
851
 
852
  /**
853
   * Set this transform to a scale:
854
   * <pre>
855
   * [ sx 0  0 ]
856
   * [ 0  sy 0 ]
857
   * [ 0  0  1 ]
858
   * </pre>
859
   *
860
   * @param sx the x scaling factor
861
   * @param sy the y scaling factor
862
   */
863
  public void setToScale(double sx, double sy)
864
  {
865
    m00 = sx;
866
    m01 = m02 = m10 = m12 = 0;
867
    m11 = sy;
868
    type = (sx != sy ? TYPE_GENERAL_SCALE
869
            : sx == 1 ? TYPE_IDENTITY : TYPE_UNIFORM_SCALE);
870
  }
871
 
872
  /**
873
   * Set this transform to a shear (points are shifted in the x direction based
874
   * on a factor of their y coordinate, and in the y direction as a factor of
875
   * their x coordinate):
876
   * <pre>
877
   * [  1  shx 0 ]
878
   * [ shy  1  0 ]
879
   * [  0   0  1 ]
880
   * </pre>
881
   *
882
   * @param shx the x shearing factor
883
   * @param shy the y shearing factor
884
   */
885
  public void setToShear(double shx, double shy)
886
  {
887
    m00 = m11 = 1;
888
    m01 = shx;
889
    m10 = shy;
890
    m02 = m12 = 0;
891
    updateType();
892
  }
893
 
894
  /**
895
   * Set this transform to a copy of the given one.
896
   *
897
   * @param tx the transform to copy
898
   * @throws NullPointerException if tx is null
899
   */
900
  public void setTransform(AffineTransform tx)
901
  {
902
    m00 = tx.m00;
903
    m01 = tx.m01;
904
    m02 = tx.m02;
905
    m10 = tx.m10;
906
    m11 = tx.m11;
907
    m12 = tx.m12;
908
    type = tx.type;
909
  }
910
 
911
  /**
912
   * Set this transform to the given values:
913
   * <pre>
914
   * [ m00 m01 m02 ]
915
   * [ m10 m11 m12 ]
916
   * [  0   0   1  ]
917
   * </pre>
918
   *
919
   * @param m00 the x scaling component
920
   * @param m10 the y shearing component
921
   * @param m01 the x shearing component
922
   * @param m11 the y scaling component
923
   * @param m02 the x translation component
924
   * @param m12 the y translation component
925
   */
926
  public void setTransform(double m00, double m10, double m01,
927
                           double m11, double m02, double m12)
928
  {
929
    this.m00 = m00;
930
    this.m10 = m10;
931
    this.m01 = m01;
932
    this.m11 = m11;
933
    this.m02 = m02;
934
    this.m12 = m12;
935
    updateType();
936
  }
937
 
938
  /**
939
   * Set this transform to the result of performing the original version of
940
   * this followed by tx. This is commonly used when chaining transformations
941
   * from one space to another. In matrix form:
942
   * <pre>
943
   * [ this ] = [ this ] x [ tx ]
944
   * </pre>
945
   *
946
   * @param tx the transform to concatenate
947
   * @throws NullPointerException if tx is null
948
   * @see #preConcatenate(AffineTransform)
949
   */
950
  public void concatenate(AffineTransform tx)
951
  {
952
    double n00 = m00 * tx.m00 + m01 * tx.m10;
953
    double n01 = m00 * tx.m01 + m01 * tx.m11;
954
    double n02 = m00 * tx.m02 + m01 * tx.m12 + m02;
955
    double n10 = m10 * tx.m00 + m11 * tx.m10;
956
    double n11 = m10 * tx.m01 + m11 * tx.m11;
957
    double n12 = m10 * tx.m02 + m11 * tx.m12 + m12;
958
    m00 = n00;
959
    m01 = n01;
960
    m02 = n02;
961
    m10 = n10;
962
    m11 = n11;
963
    m12 = n12;
964
    updateType();
965
  }
966
 
967
  /**
968
   * Set this transform to the result of performing tx followed by the
969
   * original version of this. This is less common than normal concatenation,
970
   * but can still be used to chain transformations from one space to another.
971
   * In matrix form:
972
   * <pre>
973
   * [ this ] = [ tx ] x [ this ]
974
   * </pre>
975
   *
976
   * @param tx the transform to concatenate
977
   * @throws NullPointerException if tx is null
978
   * @see #concatenate(AffineTransform)
979
   */
980
  public void preConcatenate(AffineTransform tx)
981
  {
982
    double n00 = tx.m00 * m00 + tx.m01 * m10;
983
    double n01 = tx.m00 * m01 + tx.m01 * m11;
984
    double n02 = tx.m00 * m02 + tx.m01 * m12 + tx.m02;
985
    double n10 = tx.m10 * m00 + tx.m11 * m10;
986
    double n11 = tx.m10 * m01 + tx.m11 * m11;
987
    double n12 = tx.m10 * m02 + tx.m11 * m12 + tx.m12;
988
    m00 = n00;
989
    m01 = n01;
990
    m02 = n02;
991
    m10 = n10;
992
    m11 = n11;
993
    m12 = n12;
994
    updateType();
995
  }
996
 
997
  /**
998
   * Returns a transform, which if concatenated to this one, will result in
999
   * the identity transform. This is useful for undoing transformations, but
1000
   * is only possible if the original transform has an inverse (ie. does not
1001
   * map multiple points to the same line or point). A transform exists only
1002
   * if getDeterminant() has a non-zero value.
1003
   *
1004
   * The inverse is calculated as:
1005
   *
1006
   * <pre>
1007
   *
1008
   * Let A be the matrix for which we want to find the inverse:
1009
   *
1010
   * A = [ m00 m01 m02 ]
1011
   *     [ m10 m11 m12 ]
1012
   *     [ 0   0   1   ]
1013
   *
1014
   *
1015
   *                 1
1016
   * inverse (A) =  ---   x  adjoint(A)
1017
   *                det
1018
   *
1019
   *
1020
   *
1021
   *             =   1       [  m11  -m01   m01*m12-m02*m11  ]
1022
   *                ---   x  [ -m10   m00  -m00*m12+m10*m02  ]
1023
   *                det      [  0     0     m00*m11-m10*m01  ]
1024
   *
1025
   *
1026
   *
1027
   *             = [  m11/det  -m01/det   m01*m12-m02*m11/det ]
1028
   *               [ -m10/det   m00/det  -m00*m12+m10*m02/det ]
1029
   *               [   0           0          1               ]
1030
   *
1031
   *
1032
   * </pre>
1033
   *
1034
   *
1035
   *
1036
   * @return a new inverse transform
1037
   * @throws NoninvertibleTransformException if inversion is not possible
1038
   * @see #getDeterminant()
1039
   */
1040
  public AffineTransform createInverse()
1041
    throws NoninvertibleTransformException
1042
  {
1043
    double det = getDeterminant();
1044
    if (det == 0)
1045
      throw new NoninvertibleTransformException("can't invert transform");
1046
 
1047
    double im00 = m11 / det;
1048
    double im10 = -m10 / det;
1049
    double im01 = -m01 / det;
1050
    double im11 = m00 / det;
1051
    double im02 = (m01 * m12 - m02 * m11) / det;
1052
    double im12 = (-m00 * m12 + m10 * m02) / det;
1053
 
1054
    return new AffineTransform (im00, im10, im01, im11, im02, im12);
1055
  }
1056
 
1057
  /**
1058
   * Perform this transformation on the given source point, and store the
1059
   * result in the destination (creating it if necessary). It is safe for
1060
   * src and dst to be the same.
1061
   *
1062
   * @param src the source point
1063
   * @param dst the destination, or null
1064
   * @return the transformation of src, in dst if it was non-null
1065
   * @throws NullPointerException if src is null
1066
   */
1067
  public Point2D transform(Point2D src, Point2D dst)
1068
  {
1069
    if (dst == null)
1070
      dst = new Point2D.Double();
1071
    double x = src.getX();
1072
    double y = src.getY();
1073
    double nx = m00 * x + m01 * y + m02;
1074
    double ny = m10 * x + m11 * y + m12;
1075
    dst.setLocation(nx, ny);
1076
    return dst;
1077
  }
1078
 
1079
  /**
1080
   * Perform this transformation on an array of points, storing the results
1081
   * in another (possibly same) array. This will not create a destination
1082
   * array, but will create points for the null entries of the destination.
1083
   * The transformation is done sequentially. While having a single source
1084
   * and destination point be the same is safe, you should be aware that
1085
   * duplicate references to the same point in the source, and having the
1086
   * source overlap the destination, may result in your source points changing
1087
   * from a previous transform before it is their turn to be evaluated.
1088
   *
1089
   * @param src the array of source points
1090
   * @param srcOff the starting offset into src
1091
   * @param dst the array of destination points (may have null entries)
1092
   * @param dstOff the starting offset into dst
1093
   * @param num the number of points to transform
1094
   * @throws NullPointerException if src or dst is null, or src has null
1095
   *         entries
1096
   * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded
1097
   * @throws ArrayStoreException if new points are incompatible with dst
1098
   */
1099
  public void transform(Point2D[] src, int srcOff,
1100
                        Point2D[] dst, int dstOff, int num)
1101
  {
1102
    while (--num >= 0)
1103
      dst[dstOff] = transform(src[srcOff++], dst[dstOff++]);
1104
  }
1105
 
1106
  /**
1107
   * Perform this transformation on an array of points, in (x,y) pairs,
1108
   * storing the results in another (possibly same) array. This will not
1109
   * create a destination array. All sources are copied before the
1110
   * transformation, so that no result will overwrite a point that has not yet
1111
   * been evaluated.
1112
   *
1113
   * @param srcPts the array of source points
1114
   * @param srcOff the starting offset into src
1115
   * @param dstPts the array of destination points
1116
   * @param dstOff the starting offset into dst
1117
   * @param num the number of points to transform
1118
   * @throws NullPointerException if src or dst is null
1119
   * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded
1120
   */
1121
  public void transform(float[] srcPts, int srcOff,
1122
                        float[] dstPts, int dstOff, int num)
1123
  {
1124
    if (srcPts == dstPts && dstOff > srcOff
1125
        && num > 1 && srcOff + 2 * num > dstOff)
1126
      {
1127
        float[] f = new float[2 * num];
1128
        System.arraycopy(srcPts, srcOff, f, 0, 2 * num);
1129
        srcPts = f;
1130
      }
1131
    while (--num >= 0)
1132
      {
1133
        float x = srcPts[srcOff++];
1134
        float y = srcPts[srcOff++];
1135
        dstPts[dstOff++] = (float) (m00 * x + m01 * y + m02);
1136
        dstPts[dstOff++] = (float) (m10 * x + m11 * y + m12);
1137
      }
1138
  }
1139
 
1140
  /**
1141
   * Perform this transformation on an array of points, in (x,y) pairs,
1142
   * storing the results in another (possibly same) array. This will not
1143
   * create a destination array. All sources are copied before the
1144
   * transformation, so that no result will overwrite a point that has not yet
1145
   * been evaluated.
1146
   *
1147
   * @param srcPts the array of source points
1148
   * @param srcOff the starting offset into src
1149
   * @param dstPts the array of destination points
1150
   * @param dstOff the starting offset into dst
1151
   * @param num the number of points to transform
1152
   * @throws NullPointerException if src or dst is null
1153
   * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded
1154
   */
1155
  public void transform(double[] srcPts, int srcOff,
1156
                        double[] dstPts, int dstOff, int num)
1157
  {
1158
    if (srcPts == dstPts && dstOff > srcOff
1159
        && num > 1 && srcOff + 2 * num > dstOff)
1160
      {
1161
        double[] d = new double[2 * num];
1162
        System.arraycopy(srcPts, srcOff, d, 0, 2 * num);
1163
        srcPts = d;
1164
      }
1165
    while (--num >= 0)
1166
      {
1167
        double x = srcPts[srcOff++];
1168
        double y = srcPts[srcOff++];
1169
        dstPts[dstOff++] = m00 * x + m01 * y + m02;
1170
        dstPts[dstOff++] = m10 * x + m11 * y + m12;
1171
      }
1172
  }
1173
 
1174
  /**
1175
   * Perform this transformation on an array of points, in (x,y) pairs,
1176
   * storing the results in another array. This will not create a destination
1177
   * array.
1178
   *
1179
   * @param srcPts the array of source points
1180
   * @param srcOff the starting offset into src
1181
   * @param dstPts the array of destination points
1182
   * @param dstOff the starting offset into dst
1183
   * @param num the number of points to transform
1184
   * @throws NullPointerException if src or dst is null
1185
   * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded
1186
   */
1187
  public void transform(float[] srcPts, int srcOff,
1188
                        double[] dstPts, int dstOff, int num)
1189
  {
1190
    while (--num >= 0)
1191
      {
1192
        float x = srcPts[srcOff++];
1193
        float y = srcPts[srcOff++];
1194
        dstPts[dstOff++] = m00 * x + m01 * y + m02;
1195
        dstPts[dstOff++] = m10 * x + m11 * y + m12;
1196
      }
1197
  }
1198
 
1199
  /**
1200
   * Perform this transformation on an array of points, in (x,y) pairs,
1201
   * storing the results in another array. This will not create a destination
1202
   * array.
1203
   *
1204
   * @param srcPts the array of source points
1205
   * @param srcOff the starting offset into src
1206
   * @param dstPts the array of destination points
1207
   * @param dstOff the starting offset into dst
1208
   * @param num the number of points to transform
1209
   * @throws NullPointerException if src or dst is null
1210
   * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded
1211
   */
1212
  public void transform(double[] srcPts, int srcOff,
1213
                        float[] dstPts, int dstOff, int num)
1214
  {
1215
    while (--num >= 0)
1216
      {
1217
        double x = srcPts[srcOff++];
1218
        double y = srcPts[srcOff++];
1219
        dstPts[dstOff++] = (float) (m00 * x + m01 * y + m02);
1220
        dstPts[dstOff++] = (float) (m10 * x + m11 * y + m12);
1221
      }
1222
  }
1223
 
1224
  /**
1225
   * Perform the inverse of this transformation on the given source point,
1226
   * and store the result in the destination (creating it if necessary). It
1227
   * is safe for src and dst to be the same.
1228
   *
1229
   * @param src the source point
1230
   * @param dst the destination, or null
1231
   * @return the inverse transformation of src, in dst if it was non-null
1232
   * @throws NullPointerException if src is null
1233
   * @throws NoninvertibleTransformException if the inverse does not exist
1234
   * @see #getDeterminant()
1235
   */
1236
  public Point2D inverseTransform(Point2D src, Point2D dst)
1237
    throws NoninvertibleTransformException
1238
  {
1239
    return createInverse().transform(src, dst);
1240
  }
1241
 
1242
  /**
1243
   * Perform the inverse of this transformation on an array of points, in
1244
   * (x,y) pairs, storing the results in another (possibly same) array. This
1245
   * will not create a destination array. All sources are copied before the
1246
   * transformation, so that no result will overwrite a point that has not yet
1247
   * been evaluated.
1248
   *
1249
   * @param srcPts the array of source points
1250
   * @param srcOff the starting offset into src
1251
   * @param dstPts the array of destination points
1252
   * @param dstOff the starting offset into dst
1253
   * @param num the number of points to transform
1254
   * @throws NullPointerException if src or dst is null
1255
   * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded
1256
   * @throws NoninvertibleTransformException if the inverse does not exist
1257
   * @see #getDeterminant()
1258
   */
1259
  public void inverseTransform(double[] srcPts, int srcOff,
1260
                               double[] dstPts, int dstOff, int num)
1261
    throws NoninvertibleTransformException
1262
  {
1263
    createInverse().transform(srcPts, srcOff, dstPts, dstOff, num);
1264
  }
1265
 
1266
  /**
1267
   * Perform this transformation, less any translation, on the given source
1268
   * point, and store the result in the destination (creating it if
1269
   * necessary). It is safe for src and dst to be the same. The reduced
1270
   * transform is equivalent to:
1271
   * <pre>
1272
   * [ x' ] = [ m00 m01 ] [ x ] = [ m00 * x + m01 * y ]
1273
   * [ y' ]   [ m10 m11 ] [ y ] = [ m10 * x + m11 * y ]
1274
   * </pre>
1275
   *
1276
   * @param src the source point
1277
   * @param dst the destination, or null
1278
   * @return the delta transformation of src, in dst if it was non-null
1279
   * @throws NullPointerException if src is null
1280
   */
1281
  public Point2D deltaTransform(Point2D src, Point2D dst)
1282
  {
1283
    if (dst == null)
1284
      dst = new Point2D.Double();
1285
    double x = src.getX();
1286
    double y = src.getY();
1287
    double nx = m00 * x + m01 * y;
1288
    double ny = m10 * x + m11 * y;
1289
    dst.setLocation(nx, ny);
1290
    return dst;
1291
  }
1292
 
1293
  /**
1294
   * Perform this transformation, less any translation, on an array of points,
1295
   * in (x,y) pairs, storing the results in another (possibly same) array.
1296
   * This will not create a destination array. All sources are copied before
1297
   * the transformation, so that no result will overwrite a point that has
1298
   * not yet been evaluated. The reduced transform is equivalent to:
1299
   * <pre>
1300
   * [ x' ] = [ m00 m01 ] [ x ] = [ m00 * x + m01 * y ]
1301
   * [ y' ]   [ m10 m11 ] [ y ] = [ m10 * x + m11 * y ]
1302
   * </pre>
1303
   *
1304
   * @param srcPts the array of source points
1305
   * @param srcOff the starting offset into src
1306
   * @param dstPts the array of destination points
1307
   * @param dstOff the starting offset into dst
1308
   * @param num the number of points to transform
1309
   * @throws NullPointerException if src or dst is null
1310
   * @throws ArrayIndexOutOfBoundsException if array bounds are exceeded
1311
   */
1312
  public void deltaTransform(double[] srcPts, int srcOff,
1313
                              double[] dstPts, int dstOff,
1314
                              int num)
1315
  {
1316
    if (srcPts == dstPts && dstOff > srcOff
1317
        && num > 1 && srcOff + 2 * num > dstOff)
1318
      {
1319
        double[] d = new double[2 * num];
1320
        System.arraycopy(srcPts, srcOff, d, 0, 2 * num);
1321
        srcPts = d;
1322
      }
1323
    while (--num >= 0)
1324
      {
1325
        double x = srcPts[srcOff++];
1326
        double y = srcPts[srcOff++];
1327
        dstPts[dstOff++] = m00 * x + m01 * y;
1328
        dstPts[dstOff++] = m10 * x + m11 * y;
1329
      }
1330
  }
1331
 
1332
  /**
1333
   * Return a new Shape, based on the given one, where the path of the shape
1334
   * has been transformed by this transform. Notice that this uses GeneralPath,
1335
   * which only stores points in float precision.
1336
   *
1337
   * @param src the shape source to transform
1338
   * @return the shape, transformed by this, <code>null</code> if src is
1339
   * <code>null</code>.
1340
   * @see GeneralPath#transform(AffineTransform)
1341
   */
1342
  public Shape createTransformedShape(Shape src)
1343
  {
1344
    if(src == null)
1345
      return null;
1346
    GeneralPath p = new GeneralPath(src);
1347
    p.transform(this);
1348
    return p;
1349
  }
1350
 
1351
  /**
1352
   * Returns a string representation of the transform, in the format:
1353
   * <code>"AffineTransform[[" + m00 + ", " + m01 + ", " + m02 + "], ["
1354
   *   + m10 + ", " + m11 + ", " + m12 + "]]"</code>.
1355
   *
1356
   * @return the string representation
1357
   */
1358
  public String toString()
1359
  {
1360
    return "AffineTransform[[" + m00 + ", " + m01 + ", " + m02 + "], ["
1361
      + m10 + ", " + m11 + ", " + m12 + "]]";
1362
  }
1363
 
1364
  /**
1365
   * Tests if this transformation is the identity:
1366
   * <pre>
1367
   * [ 1 0 0 ]
1368
   * [ 0 1 0 ]
1369
   * [ 0 0 1 ]
1370
   * </pre>
1371
   *
1372
   * @return true if this is the identity transform
1373
   */
1374
  public boolean isIdentity()
1375
  {
1376
    // Rather than rely on type, check explicitly.
1377
    return (m00 == 1 && m01 == 0 && m02 == 0
1378
            && m10 == 0 && m11 == 1 && m12 == 0);
1379
  }
1380
 
1381
  /**
1382
   * Create a new transform of the same run-time type, with the same
1383
   * transforming properties as this one.
1384
   *
1385
   * @return the clone
1386
   */
1387
  public Object clone()
1388
  {
1389
    try
1390
      {
1391
        return super.clone();
1392
      }
1393
    catch (CloneNotSupportedException e)
1394
      {
1395
        throw (Error) new InternalError().initCause(e); // Impossible
1396
      }
1397
  }
1398
 
1399
  /**
1400
   * Return the hashcode for this transformation. The formula is not
1401
   * documented, but appears to be the same as:
1402
   * <pre>
1403
   * long l = Double.doubleToLongBits(getScaleX());
1404
   * l = l * 31 + Double.doubleToLongBits(getShearX());
1405
   * l = l * 31 + Double.doubleToLongBits(getTranslateX());
1406
   * l = l * 31 + Double.doubleToLongBits(getShearY());
1407
   * l = l * 31 + Double.doubleToLongBits(getScaleY());
1408
   * l = l * 31 + Double.doubleToLongBits(getTranslateY());
1409
   * return (int) ((l >> 32) ^ l);
1410
   * </pre>
1411
   *
1412
   * @return the hashcode
1413
   */
1414
  public int hashCode()
1415
  {
1416
    long l = Double.doubleToLongBits(m00);
1417
    l = l * 31 + Double.doubleToLongBits(m01);
1418
    l = l * 31 + Double.doubleToLongBits(m02);
1419
    l = l * 31 + Double.doubleToLongBits(m10);
1420
    l = l * 31 + Double.doubleToLongBits(m11);
1421
    l = l * 31 + Double.doubleToLongBits(m12);
1422
    return (int) ((l >> 32) ^ l);
1423
  }
1424
 
1425
  /**
1426
   * Compares two transforms for equality. This returns true if they have the
1427
   * same matrix values.
1428
   *
1429
   * @param obj the transform to compare
1430
   * @return true if it is equal
1431
   */
1432
  public boolean equals(Object obj)
1433
  {
1434
    if (! (obj instanceof AffineTransform))
1435
      return false;
1436
    AffineTransform t = (AffineTransform) obj;
1437
    return (m00 == t.m00 && m01 == t.m01 && m02 == t.m02
1438
            && m10 == t.m10 && m11 == t.m11 && m12 == t.m12);
1439
  }
1440
 
1441
  /**
1442
   * Helper to decode the type from the matrix. This is not guaranteed
1443
   * to find the optimal type, but at least it will be valid.
1444
   */
1445
  private void updateType()
1446
  {
1447
    double det = getDeterminant();
1448
    if (det == 0)
1449
      {
1450
        type = TYPE_GENERAL_TRANSFORM;
1451
        return;
1452
      }
1453
    // Scale (includes rotation by PI) or translation.
1454
    if (m01 == 0 && m10 == 0)
1455
      {
1456
        if (m00 == m11)
1457
          type = m00 == 1 ? TYPE_IDENTITY : TYPE_UNIFORM_SCALE;
1458
        else
1459
          type = TYPE_GENERAL_SCALE;
1460
        if (m02 != 0 || m12 != 0)
1461
          type |= TYPE_TRANSLATION;
1462
      }
1463
    // Rotation.
1464
    else if (m00 == m11 && m01 == -m10)
1465
      {
1466
        type = m00 == 0 ? TYPE_QUADRANT_ROTATION : TYPE_GENERAL_ROTATION;
1467
        if (det != 1)
1468
          type |= TYPE_UNIFORM_SCALE;
1469
        if (m02 != 0 || m12 != 0)
1470
          type |= TYPE_TRANSLATION;
1471
      }
1472
    else
1473
      type = TYPE_GENERAL_TRANSFORM;
1474
  }
1475
 
1476
  /**
1477
   * Reads a transform from an object stream.
1478
   *
1479
   * @param s the stream to read from
1480
   * @throws ClassNotFoundException if there is a problem deserializing
1481
   * @throws IOException if there is a problem deserializing
1482
   */
1483
  private void readObject(ObjectInputStream s)
1484
    throws ClassNotFoundException, IOException
1485
  {
1486
    s.defaultReadObject();
1487
    updateType();
1488
  }
1489
} // class AffineTransform

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.