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

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [libjava/] [classpath/] [java/] [awt/] [geom/] [AffineTransform.java] - Blame information for rev 14

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 jlechner
/* 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.setToTranslation(tx, ty);
418
    return t;
419
  }
420
 
421
  /**
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>
429
   *
430
   * @param theta the rotation angle
431
   * @return the rotating transform
432
   */
433
  public static AffineTransform getRotateInstance(double theta)
434
  {
435
    AffineTransform t = new AffineTransform();
436
    t.setToRotation(theta);
437
    return t;
438
  }
439
 
440
  /**
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>
450
   *
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>
457
   *
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
462
   */
463
  public static AffineTransform getRotateInstance(double theta,
464
                                                  double x, double y)
465
  {
466
    AffineTransform t = new AffineTransform();
467
    t.setToTranslation(x, y);
468
    t.rotate(theta);
469
    t.translate(-x, -y);
470
    return t;
471
  }
472
 
473
  /**
474
   * Returns a scaling transform:
475
   * <pre>
476
   * [ sx 0  0 ]
477
   * [ 0  sy 0 ]
478
   * [ 0  0  1 ]
479
   * </pre>
480
   *
481
   * @param sx the x scaling factor
482
   * @param sy the y scaling factor
483
   * @return the scaling transform
484
   */
485
  public static AffineTransform getScaleInstance(double sx, double sy)
486
  {
487
    AffineTransform t = new AffineTransform();
488
    t.setToScale(sx, sy);
489
    return t;
490
  }
491
 
492
  /**
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>
501
   *
502
   * @param shx the x shearing factor
503
   * @param shy the y shearing factor
504
   * @return the shearing transform
505
   */
506
  public static AffineTransform getShearInstance(double shx, double shy)
507
  {
508
    AffineTransform t = new AffineTransform();
509
    t.setToShear(shx, shy);
510
    return t;
511
  }
512
 
513
  /**
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.
520
   *
521
   * @return The type.
522
   *
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
530
   */
531
  public int getType()
532
  {
533
    return type;
534
  }
535
 
536
  /**
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.
542
   *
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>
551
   *
552
   * @return the determinant
553
   * @see #createInverse()
554
   */
555
  public double getDeterminant()
556
  {
557
    return m00 * m11 - m01 * m10;
558
  }
559
 
560
  /**
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>
570
   *
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
574
   */
575
  public void getMatrix(double[] d)
576
  {
577
    d[0] = m00;
578
    d[1] = m10;
579
    d[2] = m01;
580
    d[3] = m11;
581
    if (d.length >= 6)
582
      {
583
        d[4] = m02;
584
        d[5] = m12;
585
      }
586
  }
587
 
588
  /**
589
   * Returns the X coordinate scaling factor of the matrix.
590
   *
591
   * @return m00
592
   * @see #getMatrix(double[])
593
   */
594
  public double getScaleX()
595
  {
596
    return m00;
597
  }
598
 
599
  /**
600
   * Returns the Y coordinate scaling factor of the matrix.
601
   *
602
   * @return m11
603
   * @see #getMatrix(double[])
604
   */
605
  public double getScaleY()
606
  {
607
    return m11;
608
  }
609
 
610
  /**
611
   * Returns the X coordinate shearing factor of the matrix.
612
   *
613
   * @return m01
614
   * @see #getMatrix(double[])
615
   */
616
  public double getShearX()
617
  {
618
    return m01;
619
  }
620
 
621
  /**
622
   * Returns the Y coordinate shearing factor of the matrix.
623
   *
624
   * @return m10
625
   * @see #getMatrix(double[])
626
   */
627
  public double getShearY()
628
  {
629
    return m10;
630
  }
631
 
632
  /**
633
   * Returns the X coordinate translation factor of the matrix.
634
   *
635
   * @return m02
636
   * @see #getMatrix(double[])
637
   */
638
  public double getTranslateX()
639
  {
640
    return m02;
641
  }
642
 
643
  /**
644
   * Returns the Y coordinate translation factor of the matrix.
645
   *
646
   * @return m12
647
   * @see #getMatrix(double[])
648
   */
649
  public double getTranslateY()
650
  {
651
    return m12;
652
  }
653
 
654
  /**
655
   * Concatenate a translation onto this transform. This is equivalent, but
656
   * more efficient than
657
   * <code>concatenate(AffineTransform.getTranslateInstance(tx, ty))</code>.
658
   *
659
   * @param tx the x translation distance
660
   * @param ty the y translation distance
661
   * @see #getTranslateInstance(double, double)
662
   * @see #concatenate(AffineTransform)
663
   */
664
  public void translate(double tx, double ty)
665
  {
666
    m02 += tx * m00 + ty * m01;
667
    m12 += tx * m10 + ty * m11;
668
    updateType();
669
  }
670
 
671
  /**
672
   * Concatenate a rotation onto this transform. This is equivalent, but
673
   * more efficient than
674
   * <code>concatenate(AffineTransform.getRotateInstance(theta))</code>.
675
   *
676
   * @param theta the rotation angle
677
   * @see #getRotateInstance(double)
678
   * @see #concatenate(AffineTransform)
679
   */
680
  public void rotate(double theta)
681
  {
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();
693
  }
694
 
695
  /**
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>.
699
   *
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)
705
   */
706
  public void rotate(double theta, double x, double y)
707
  {
708
    translate(x, y);
709
    rotate(theta);
710
    translate(-x, -y);
711
  }
712
 
713
  /**
714
   * Concatenate a scale onto this transform. This is equivalent, but more
715
   * efficient than
716
   * <code>concatenate(AffineTransform.getScaleInstance(sx, sy))</code>.
717
   *
718
   * @param sx the x scaling factor
719
   * @param sy the y scaling factor
720
   * @see #getScaleInstance(double, double)
721
   * @see #concatenate(AffineTransform)
722
   */
723
  public void scale(double sx, double sy)
724
  {
725
    m00 *= sx;
726
    m01 *= sy;
727
    m10 *= sx;
728
    m11 *= sy;
729
    updateType();
730
  }
731
 
732
  /**
733
   * Concatenate a shearing onto this transform. This is equivalent, but more
734
   * efficient than
735
   * <code>concatenate(AffineTransform.getShearInstance(sx, sy))</code>.
736
   *
737
   * @param shx the x shearing factor
738
   * @param shy the y shearing factor
739
   * @see #getShearInstance(double, double)
740
   * @see #concatenate(AffineTransform)
741
   */
742
  public void shear(double shx, double shy)
743
  {
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();
753
  }
754
 
755
  /**
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>
762
   */
763
  public void setToIdentity()
764
  {
765
    m00 = m11 = 1;
766
    m01 = m02 = m10 = m12 = 0;
767
    type = TYPE_IDENTITY;
768
  }
769
 
770
  /**
771
   * Set this transform to a translation:
772
   * <pre>
773
   * [ 1 0 tx ]
774
   * [ 0 1 ty ]
775
   * [ 0 0 1  ]
776
   * </pre>
777
   *
778
   * @param tx the x translation distance
779
   * @param ty the y translation distance
780
   */
781
  public void setToTranslation(double tx, double ty)
782
  {
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;
788
  }
789
 
790
  /**
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>
798
   *
799
   * @param theta the rotation angle
800
   */
801
  public void setToRotation(double theta)
802
  {
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);
814
  }
815
 
816
  /**
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>
825
   *
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>
832
   *
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
836
   */
837
  public void setToRotation(double theta, double x, double y)
838
  {
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();
848
  }
849
 
850
  /**
851
   * Set this transform to a scale:
852
   * <pre>
853
   * [ sx 0  0 ]
854
   * [ 0  sy 0 ]
855
   * [ 0  0  1 ]
856
   * </pre>
857
   *
858
   * @param sx the x scaling factor
859
   * @param sy the y scaling factor
860
   */
861
  public void setToScale(double sx, double sy)
862
  {
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);
868
  }
869
 
870
  /**
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>
879
   *
880
   * @param shx the x shearing factor
881
   * @param shy the y shearing factor
882
   */
883
  public void setToShear(double shx, double shy)
884
  {
885
    m00 = m11 = 1;
886
    m01 = shx;
887
    m10 = shy;
888
    m02 = m12 = 0;
889
    updateType();
890
  }
891
 
892
  /**
893
   * Set this transform to a copy of the given one.
894
   *
895
   * @param tx the transform to copy
896
   * @throws NullPointerException if tx is null
897
   */
898
  public void setTransform(AffineTransform tx)
899
  {
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;
907
  }
908
 
909
  /**
910
   * Set this transform to the given values:
911
   * <pre>
912
   * [ m00 m01 m02 ]
913
   * [ m10 m11 m12 ]
914
   * [  0   0   1  ]
915
   * </pre>
916
   *
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
923
   */
924
  public void setTransform(double m00, double m10, double m01,
925
                           double m11, double m02, double m12)
926
  {
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();
934
  }
935
 
936
  /**
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>
943
   *
944
   * @param tx the transform to concatenate
945
   * @throws NullPointerException if tx is null
946
   * @see #preConcatenate(AffineTransform)
947
   */
948
  public void concatenate(AffineTransform tx)
949
  {
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();
963
  }
964
 
965
  /**
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>
973
   *
974
   * @param tx the transform to concatenate
975
   * @throws NullPointerException if tx is null
976
   * @see #concatenate(AffineTransform)
977
   */
978
  public void preConcatenate(AffineTransform tx)
979
  {
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();
993
  }
994
 
995
  /**
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.
1001
   *
1002
   * The inverse is calculated as:
1003
   *
1004
   * <pre>
1005
   *
1006
   * Let A be the matrix for which we want to find the inverse:
1007
   *
1008
   * A = [ m00 m01 m02 ]
1009
   *     [ m10 m11 m12 ]
1010
   *     [ 0   0   1   ]
1011
   *
1012
   *
1013
   *                 1
1014
   * inverse (A) =  ---   x  adjoint(A)
1015
   *                det
1016
   *
1017
   *
1018
   *
1019
   *             =   1       [  m11  -m01   m01*m12-m02*m11  ]
1020
   *                ---   x  [ -m10   m00  -m00*m12+m10*m02  ]
1021
   *                det      [  0     0     m00*m11-m10*m01  ]
1022
   *
1023
   *
1024
   *
1025
   *             = [  m11/det  -m01/det   m01*m12-m02*m11/det ]
1026
   *               [ -m10/det   m00/det  -m00*m12+m10*m02/det ]
1027
   *               [   0           0          1               ]
1028
   *
1029
   *
1030
   * </pre>
1031
   *
1032
   *
1033
   *
1034
   * @return a new inverse transform
1035
   * @throws NoninvertibleTransformException if inversion is not possible
1036
   * @see #getDeterminant()
1037
   */
1038
  public AffineTransform createInverse()
1039
    throws NoninvertibleTransformException
1040
  {
1041
    double det = getDeterminant();
1042
    if (det == 0)
1043
      throw new NoninvertibleTransformException("can't invert transform");
1044
 
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;
1051
 
1052
    return new AffineTransform (im00, im10, im01, im11, im02, im12);
1053
  }
1054
 
1055
  /**
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.
1059
   *
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
1064
   */
1065
  public Point2D transform(Point2D src, Point2D dst)
1066
  {
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;
1075
  }
1076
 
1077
  /**
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.
1086
   *
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
1096
   */
1097
  public void transform(Point2D[] src, int srcOff,
1098
                        Point2D[] dst, int dstOff, int num)
1099
  {
1100
    while (--num >= 0)
1101
      dst[dstOff] = transform(src[srcOff++], dst[dstOff++]);
1102
  }
1103
 
1104
  /**
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.
1110
   *
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
1118
   */
1119
  public void transform(float[] srcPts, int srcOff,
1120
                        float[] dstPts, int dstOff, int num)
1121
  {
1122
    if (srcPts == dstPts && dstOff > srcOff
1123
        && num > 1 && srcOff + 2 * num > dstOff)
1124
      {
1125
        float[] f = new float[2 * num];
1126
        System.arraycopy(srcPts, srcOff, f, 0, 2 * num);
1127
        srcPts = f;
1128
      }
1129
    while (--num >= 0)
1130
      {
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);
1135
      }
1136
  }
1137
 
1138
  /**
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.
1144
   *
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
1152
   */
1153
  public void transform(double[] srcPts, int srcOff,
1154
                        double[] dstPts, int dstOff, int num)
1155
  {
1156
    if (srcPts == dstPts && dstOff > srcOff
1157
        && num > 1 && srcOff + 2 * num > dstOff)
1158
      {
1159
        double[] d = new double[2 * num];
1160
        System.arraycopy(srcPts, srcOff, d, 0, 2 * num);
1161
        srcPts = d;
1162
      }
1163
    while (--num >= 0)
1164
      {
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;
1169
      }
1170
  }
1171
 
1172
  /**
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.
1176
   *
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
1184
   */
1185
  public void transform(float[] srcPts, int srcOff,
1186
                        double[] dstPts, int dstOff, int num)
1187
  {
1188
    while (--num >= 0)
1189
      {
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;
1194
      }
1195
  }
1196
 
1197
  /**
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.
1201
   *
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
1209
   */
1210
  public void transform(double[] srcPts, int srcOff,
1211
                        float[] dstPts, int dstOff, int num)
1212
  {
1213
    while (--num >= 0)
1214
      {
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);
1219
      }
1220
  }
1221
 
1222
  /**
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.
1226
   *
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()
1233
   */
1234
  public Point2D inverseTransform(Point2D src, Point2D dst)
1235
    throws NoninvertibleTransformException
1236
  {
1237
    return createInverse().transform(src, dst);
1238
  }
1239
 
1240
  /**
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.
1246
   *
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()
1256
   */
1257
  public void inverseTransform(double[] srcPts, int srcOff,
1258
                               double[] dstPts, int dstOff, int num)
1259
    throws NoninvertibleTransformException
1260
  {
1261
    createInverse().transform(srcPts, srcOff, dstPts, dstOff, num);
1262
  }
1263
 
1264
  /**
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>
1273
   *
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
1278
   */
1279
  public Point2D deltaTransform(Point2D src, Point2D dst)
1280
  {
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;
1289
  }
1290
 
1291
  /**
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>
1301
   *
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
1309
   */
1310
  public void deltaTransform(double[] srcPts, int srcOff,
1311
                              double[] dstPts, int dstOff,
1312
                              int num)
1313
  {
1314
    if (srcPts == dstPts && dstOff > srcOff
1315
        && num > 1 && srcOff + 2 * num > dstOff)
1316
      {
1317
        double[] d = new double[2 * num];
1318
        System.arraycopy(srcPts, srcOff, d, 0, 2 * num);
1319
        srcPts = d;
1320
      }
1321
    while (--num >= 0)
1322
      {
1323
        double x = srcPts[srcOff++];
1324
        double y = srcPts[srcOff++];
1325
        dstPts[dstOff++] = m00 * x + m01 * y;
1326
        dstPts[dstOff++] = m10 * x + m11 * y;
1327
      }
1328
  }
1329
 
1330
  /**
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.
1334
   *
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)
1339
   */
1340
  public Shape createTransformedShape(Shape src)
1341
  {
1342
    if(src == null)
1343
      return null;
1344
    GeneralPath p = new GeneralPath(src);
1345
    p.transform(this);
1346
    return p;
1347
  }
1348
 
1349
  /**
1350
   * Returns a string representation of the transform, in the format:
1351
   * <code>"AffineTransform[[" + m00 + ", " + m01 + ", " + m02 + "], ["
1352
   *   + m10 + ", " + m11 + ", " + m12 + "]]"</code>.
1353
   *
1354
   * @return the string representation
1355
   */
1356
  public String toString()
1357
  {
1358
    return "AffineTransform[[" + m00 + ", " + m01 + ", " + m02 + "], ["
1359
      + m10 + ", " + m11 + ", " + m12 + "]]";
1360
  }
1361
 
1362
  /**
1363
   * Tests if this transformation is the identity:
1364
   * <pre>
1365
   * [ 1 0 0 ]
1366
   * [ 0 1 0 ]
1367
   * [ 0 0 1 ]
1368
   * </pre>
1369
   *
1370
   * @return true if this is the identity transform
1371
   */
1372
  public boolean isIdentity()
1373
  {
1374
    // Rather than rely on type, check explicitly.
1375
    return (m00 == 1 && m01 == 0 && m02 == 0
1376
            && m10 == 0 && m11 == 1 && m12 == 0);
1377
  }
1378
 
1379
  /**
1380
   * Create a new transform of the same run-time type, with the same
1381
   * transforming properties as this one.
1382
   *
1383
   * @return the clone
1384
   */
1385
  public Object clone()
1386
  {
1387
    try
1388
      {
1389
        return super.clone();
1390
      }
1391
    catch (CloneNotSupportedException e)
1392
      {
1393
        throw (Error) new InternalError().initCause(e); // Impossible
1394
      }
1395
  }
1396
 
1397
  /**
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>
1409
   *
1410
   * @return the hashcode
1411
   */
1412
  public int hashCode()
1413
  {
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);
1421
  }
1422
 
1423
  /**
1424
   * Compares two transforms for equality. This returns true if they have the
1425
   * same matrix values.
1426
   *
1427
   * @param obj the transform to compare
1428
   * @return true if it is equal
1429
   */
1430
  public boolean equals(Object obj)
1431
  {
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);
1437
  }
1438
 
1439
  /**
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.
1442
   */
1443
  private void updateType()
1444
  {
1445
    double det = getDeterminant();
1446
    if (det == 0)
1447
      {
1448
        type = TYPE_GENERAL_TRANSFORM;
1449
        return;
1450
      }
1451
    // Scale (includes rotation by PI) or translation.
1452
    if (m01 == 0 && m10 == 0)
1453
      {
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;
1460
      }
1461
    // Rotation.
1462
    else if (m00 == m11 && m01 == -m10)
1463
      {
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;
1469
      }
1470
    else
1471
      type = TYPE_GENERAL_TRANSFORM;
1472
  }
1473
 
1474
  /**
1475
   * Reads a transform from an object stream.
1476
   *
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
1480
   */
1481
  private void readObject(ObjectInputStream s)
1482
    throws ClassNotFoundException, IOException
1483
  {
1484
    s.defaultReadObject();
1485
    updateType();
1486
  }
1487
} // class AffineTransform

powered by: WebSVN 2.1.0

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