1. /*
  2. * @(#)AffineTransform.java 1.71 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.awt.geom;
  8. import java.awt.Shape;
  9. /**
  10. * The <code>AffineTransform</code> class represents a 2D affine transform
  11. * that performs a linear mapping from 2D coordinates to other 2D
  12. * coordinates that preserves the "straightness" and
  13. * "parallelness" of lines. Affine transformations can be constructed
  14. * using sequences of translations, scales, flips, rotations, and shears.
  15. * <p>
  16. * Such a coordinate transformation can be represented by a 3 row by
  17. * 3 column matrix with an implied last row of [ 0 0 1 ]. This matrix
  18. * transforms source coordinates <code>(x, y)</code> into
  19. * destination coordinates <code>(x', y')</code> by considering
  20. * them to be a column vector and multiplying the coordinate vector
  21. * by the matrix according to the following process:
  22. * <pre>
  23. * [ x'] [ m00 m01 m02 ] [ x ] [ m00x + m01y + m02 ]
  24. * [ y'] = [ m10 m11 m12 ] [ y ] = [ m10x + m11y + m12 ]
  25. * [ 1 ] [ 0 0 1 ] [ 1 ] [ 1 ]
  26. * </pre>
  27. *
  28. * @version 1.71, 12/19/03
  29. * @author Jim Graham
  30. */
  31. public class AffineTransform implements Cloneable, java.io.Serializable {
  32. /*
  33. * This constant is only useful for the cached type field.
  34. * It indicates that the type has been decached and must be recalculated.
  35. */
  36. private static final int TYPE_UNKNOWN = -1;
  37. /**
  38. * This constant indicates that the transform defined by this object
  39. * is an identity transform.
  40. * An identity transform is one in which the output coordinates are
  41. * always the same as the input coordinates.
  42. * If this transform is anything other than the identity transform,
  43. * the type will either be the constant GENERAL_TRANSFORM or a
  44. * combination of the appropriate flag bits for the various coordinate
  45. * conversions that this transform performs.
  46. * @see #TYPE_TRANSLATION
  47. * @see #TYPE_UNIFORM_SCALE
  48. * @see #TYPE_GENERAL_SCALE
  49. * @see #TYPE_FLIP
  50. * @see #TYPE_QUADRANT_ROTATION
  51. * @see #TYPE_GENERAL_ROTATION
  52. * @see #TYPE_GENERAL_TRANSFORM
  53. * @see #getType
  54. */
  55. public static final int TYPE_IDENTITY = 0;
  56. /**
  57. * This flag bit indicates that the transform defined by this object
  58. * performs a translation in addition to the conversions indicated
  59. * by other flag bits.
  60. * A translation moves the coordinates by a constant amount in x
  61. * and y without changing the length or angle of vectors.
  62. * @see #TYPE_IDENTITY
  63. * @see #TYPE_UNIFORM_SCALE
  64. * @see #TYPE_GENERAL_SCALE
  65. * @see #TYPE_FLIP
  66. * @see #TYPE_QUADRANT_ROTATION
  67. * @see #TYPE_GENERAL_ROTATION
  68. * @see #TYPE_GENERAL_TRANSFORM
  69. * @see #getType
  70. */
  71. public static final int TYPE_TRANSLATION = 1;
  72. /**
  73. * This flag bit indicates that the transform defined by this object
  74. * performs a uniform scale in addition to the conversions indicated
  75. * by other flag bits.
  76. * A uniform scale multiplies the length of vectors by the same amount
  77. * in both the x and y directions without changing the angle between
  78. * vectors.
  79. * This flag bit is mutually exclusive with the TYPE_GENERAL_SCALE flag.
  80. * @see #TYPE_IDENTITY
  81. * @see #TYPE_TRANSLATION
  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_UNIFORM_SCALE = 2;
  90. /**
  91. * This flag bit indicates that the transform defined by this object
  92. * performs a general scale in addition to the conversions indicated
  93. * by other flag bits.
  94. * A general scale multiplies the length of vectors by different
  95. * amounts in the x and y directions without changing the angle
  96. * between perpendicular vectors.
  97. * This flag bit is mutually exclusive with the TYPE_UNIFORM_SCALE flag.
  98. * @see #TYPE_IDENTITY
  99. * @see #TYPE_TRANSLATION
  100. * @see #TYPE_UNIFORM_SCALE
  101. * @see #TYPE_FLIP
  102. * @see #TYPE_QUADRANT_ROTATION
  103. * @see #TYPE_GENERAL_ROTATION
  104. * @see #TYPE_GENERAL_TRANSFORM
  105. * @see #getType
  106. */
  107. public static final int TYPE_GENERAL_SCALE = 4;
  108. /**
  109. * This constant is a bit mask for any of the scale flag bits.
  110. * @see #TYPE_UNIFORM_SCALE
  111. * @see #TYPE_GENERAL_SCALE
  112. */
  113. public static final int TYPE_MASK_SCALE = (TYPE_UNIFORM_SCALE |
  114. TYPE_GENERAL_SCALE);
  115. /**
  116. * This flag bit indicates that the transform defined by this object
  117. * performs a mirror image flip about some axis which changes the
  118. * normally right handed coordinate system into a left handed
  119. * system in addition to the conversions indicated by other flag bits.
  120. * A right handed coordinate system is one where the positive X
  121. * axis rotates counterclockwise to overlay the positive Y axis
  122. * similar to the direction that the fingers on your right hand
  123. * curl when you stare end on at your thumb.
  124. * A left handed coordinate system is one where the positive X
  125. * axis rotates clockwise to overlay the positive Y axis similar
  126. * to the direction that the fingers on your left hand curl.
  127. * There is no mathematical way to determine the angle of the
  128. * original flipping or mirroring transformation since all angles
  129. * of flip are identical given an appropriate adjusting rotation.
  130. * @see #TYPE_IDENTITY
  131. * @see #TYPE_TRANSLATION
  132. * @see #TYPE_UNIFORM_SCALE
  133. * @see #TYPE_GENERAL_SCALE
  134. * @see #TYPE_QUADRANT_ROTATION
  135. * @see #TYPE_GENERAL_ROTATION
  136. * @see #TYPE_GENERAL_TRANSFORM
  137. * @see #getType
  138. */
  139. public static final int TYPE_FLIP = 64;
  140. /* NOTE: TYPE_FLIP was added after GENERAL_TRANSFORM was in public
  141. * circulation and the flag bits could no longer be conveniently
  142. * renumbered without introducing binary incompatibility in outside
  143. * code.
  144. */
  145. /**
  146. * This flag bit indicates that the transform defined by this object
  147. * performs a quadrant rotation by some multiple of 90 degrees in
  148. * addition to the conversions indicated by other flag bits.
  149. * A rotation changes the angles of vectors by the same amount
  150. * regardless of the original direction of the vector and without
  151. * changing the length of the vector.
  152. * This flag bit is mutually exclusive with the TYPE_GENERAL_ROTATION flag.
  153. * @see #TYPE_IDENTITY
  154. * @see #TYPE_TRANSLATION
  155. * @see #TYPE_UNIFORM_SCALE
  156. * @see #TYPE_GENERAL_SCALE
  157. * @see #TYPE_FLIP
  158. * @see #TYPE_GENERAL_ROTATION
  159. * @see #TYPE_GENERAL_TRANSFORM
  160. * @see #getType
  161. */
  162. public static final int TYPE_QUADRANT_ROTATION = 8;
  163. /**
  164. * This flag bit indicates that the transform defined by this object
  165. * performs a rotation by an arbitrary angle in addition to the
  166. * conversions indicated by other flag bits.
  167. * A rotation changes the angles of vectors by the same amount
  168. * regardless of the original direction of the vector and without
  169. * changing the length of the vector.
  170. * This flag bit is mutually exclusive with the
  171. * TYPE_QUADRANT_ROTATION flag.
  172. * @see #TYPE_IDENTITY
  173. * @see #TYPE_TRANSLATION
  174. * @see #TYPE_UNIFORM_SCALE
  175. * @see #TYPE_GENERAL_SCALE
  176. * @see #TYPE_FLIP
  177. * @see #TYPE_QUADRANT_ROTATION
  178. * @see #TYPE_GENERAL_TRANSFORM
  179. * @see #getType
  180. */
  181. public static final int TYPE_GENERAL_ROTATION = 16;
  182. /**
  183. * This constant is a bit mask for any of the rotation flag bits.
  184. * @see #TYPE_QUADRANT_ROTATION
  185. * @see #TYPE_GENERAL_ROTATION
  186. */
  187. public static final int TYPE_MASK_ROTATION = (TYPE_QUADRANT_ROTATION |
  188. TYPE_GENERAL_ROTATION);
  189. /**
  190. * This constant indicates that the transform defined by this object
  191. * performs an arbitrary conversion of the input coordinates.
  192. * If this transform can be classified by any of the above constants,
  193. * the type will either be the constant TYPE_IDENTITY or a
  194. * combination of the appropriate flag bits for the various coordinate
  195. * conversions that this transform performs.
  196. * @see #TYPE_IDENTITY
  197. * @see #TYPE_TRANSLATION
  198. * @see #TYPE_UNIFORM_SCALE
  199. * @see #TYPE_GENERAL_SCALE
  200. * @see #TYPE_FLIP
  201. * @see #TYPE_QUADRANT_ROTATION
  202. * @see #TYPE_GENERAL_ROTATION
  203. * @see #getType
  204. */
  205. public static final int TYPE_GENERAL_TRANSFORM = 32;
  206. /**
  207. * This constant is used for the internal state variable to indicate
  208. * that no calculations need to be performed and that the source
  209. * coordinates only need to be copied to their destinations to
  210. * complete the transformation equation of this transform.
  211. * @see #APPLY_TRANSLATE
  212. * @see #APPLY_SCALE
  213. * @see #APPLY_SHEAR
  214. * @see #state
  215. */
  216. static final int APPLY_IDENTITY = 0;
  217. /**
  218. * This constant is used for the internal state variable to indicate
  219. * that the translation components of the matrix (m02 and m12) need
  220. * to be added to complete the transformation equation of this transform.
  221. * @see #APPLY_IDENTITY
  222. * @see #APPLY_SCALE
  223. * @see #APPLY_SHEAR
  224. * @see #state
  225. */
  226. static final int APPLY_TRANSLATE = 1;
  227. /**
  228. * This constant is used for the internal state variable to indicate
  229. * that the scaling components of the matrix (m00 and m11) need
  230. * to be factored in to complete the transformation equation of
  231. * this transform. If the APPLY_SHEAR bit is also set then it
  232. * indicates that the scaling components are not both 0.0. If the
  233. * APPLY_SHEAR bit is not also set then it indicates that the
  234. * scaling components are not both 1.0. If neither the APPLY_SHEAR
  235. * nor the APPLY_SCALE bits are set then the scaling components
  236. * are both 1.0, which means that the x and y components contribute
  237. * to the transformed coordinate, but they are not multiplied by
  238. * any scaling factor.
  239. * @see #APPLY_IDENTITY
  240. * @see #APPLY_TRANSLATE
  241. * @see #APPLY_SHEAR
  242. * @see #state
  243. */
  244. static final int APPLY_SCALE = 2;
  245. /**
  246. * This constant is used for the internal state variable to indicate
  247. * that the shearing components of the matrix (m01 and m10) need
  248. * to be factored in to complete the transformation equation of this
  249. * transform. The presence of this bit in the state variable changes
  250. * the interpretation of the APPLY_SCALE bit as indicated in its
  251. * documentation.
  252. * @see #APPLY_IDENTITY
  253. * @see #APPLY_TRANSLATE
  254. * @see #APPLY_SCALE
  255. * @see #state
  256. */
  257. static final int APPLY_SHEAR = 4;
  258. /*
  259. * For methods which combine together the state of two separate
  260. * transforms and dispatch based upon the combination, these constants
  261. * specify how far to shift one of the states so that the two states
  262. * are mutually non-interfering and provide constants for testing the
  263. * bits of the shifted (HI) state. The methods in this class use
  264. * the convention that the state of "this" transform is unshifted and
  265. * the state of the "other" or "argument" transform is shifted (HI).
  266. */
  267. private static final int HI_SHIFT = 3;
  268. private static final int HI_IDENTITY = APPLY_IDENTITY << HI_SHIFT;
  269. private static final int HI_TRANSLATE = APPLY_TRANSLATE << HI_SHIFT;
  270. private static final int HI_SCALE = APPLY_SCALE << HI_SHIFT;
  271. private static final int HI_SHEAR = APPLY_SHEAR << HI_SHIFT;
  272. /**
  273. * The X coordinate scaling element of the 3x3
  274. * affine transformation matrix.
  275. *
  276. * @serial
  277. */
  278. double m00;
  279. /**
  280. * The Y coordinate shearing element of the 3x3
  281. * affine transformation matrix.
  282. *
  283. * @serial
  284. */
  285. double m10;
  286. /**
  287. * The X coordinate shearing element of the 3x3
  288. * affine transformation matrix.
  289. *
  290. * @serial
  291. */
  292. double m01;
  293. /**
  294. * The Y coordinate scaling element of the 3x3
  295. * affine transformation matrix.
  296. *
  297. * @serial
  298. */
  299. double m11;
  300. /**
  301. * The X coordinate of the translation element of the
  302. * 3x3 affine transformation matrix.
  303. *
  304. * @serial
  305. */
  306. double m02;
  307. /**
  308. * The Y coordinate of the translation element of the
  309. * 3x3 affine transformation matrix.
  310. *
  311. * @serial
  312. */
  313. double m12;
  314. /**
  315. * This field keeps track of which components of the matrix need to
  316. * be applied when performing a transformation.
  317. * @see #APPLY_IDENTITY
  318. * @see #APPLY_TRANSLATE
  319. * @see #APPLY_SCALE
  320. * @see #APPLY_SHEAR
  321. */
  322. transient int state;
  323. /**
  324. * This field caches the current transformation type of the matrix.
  325. * @see #TYPE_IDENTITY
  326. * @see #TYPE_TRANSLATION
  327. * @see #TYPE_UNIFORM_SCALE
  328. * @see #TYPE_GENERAL_SCALE
  329. * @see #TYPE_FLIP
  330. * @see #TYPE_QUADRANT_ROTATION
  331. * @see #TYPE_GENERAL_ROTATION
  332. * @see #TYPE_GENERAL_TRANSFORM
  333. * @see #TYPE_UNKNOWN
  334. * @see #getType
  335. */
  336. private transient int type;
  337. private AffineTransform(double m00, double m10,
  338. double m01, double m11,
  339. double m02, double m12,
  340. int state) {
  341. this.m00 = m00;
  342. this.m10 = m10;
  343. this.m01 = m01;
  344. this.m11 = m11;
  345. this.m02 = m02;
  346. this.m12 = m12;
  347. this.state = state;
  348. this.type = TYPE_UNKNOWN;
  349. }
  350. /**
  351. * Constructs a new <code>AffineTransform</code> representing the
  352. * Identity transformation.
  353. */
  354. public AffineTransform() {
  355. m00 = m11 = 1.0;
  356. // m01 = m10 = m02 = m12 = 0.0; /* Not needed. */
  357. // state = APPLY_IDENTITY; /* Not needed. */
  358. // type = TYPE_IDENTITY; /* Not needed. */
  359. }
  360. /**
  361. * Constructs a new <code>AffineTransform</code> that is a copy of
  362. * the specified <code>AffineTransform</code> object.
  363. * @param Tx the <code>AffineTransform</code> object to copy
  364. */
  365. public AffineTransform(AffineTransform Tx) {
  366. this.m00 = Tx.m00;
  367. this.m10 = Tx.m10;
  368. this.m01 = Tx.m01;
  369. this.m11 = Tx.m11;
  370. this.m02 = Tx.m02;
  371. this.m12 = Tx.m12;
  372. this.state = Tx.state;
  373. this.type = Tx.type;
  374. }
  375. /**
  376. * Constructs a new <code>AffineTransform</code> from 6 floating point
  377. * values representing the 6 specifiable entries of the 3x3
  378. * transformation matrix.
  379. * @param m00, m01, m02, m10, m11, m12 the
  380. * 6 floating point values that compose the 3x3 transformation matrix
  381. */
  382. public AffineTransform(float m00, float m10,
  383. float m01, float m11,
  384. float m02, float m12) {
  385. this.m00 = m00;
  386. this.m10 = m10;
  387. this.m01 = m01;
  388. this.m11 = m11;
  389. this.m02 = m02;
  390. this.m12 = m12;
  391. updateState();
  392. }
  393. /**
  394. * Constructs a new <code>AffineTransform</code> from an array of
  395. * floating point values representing either the 4 non-translation
  396. * enries or the 6 specifiable entries of the 3x3 transformation
  397. * matrix. The values are retrieved from the array as
  398. * { m00 m10 m01 m11 [m02 m12]}.
  399. * @param flatmatrix the float array containing the values to be set
  400. * in the new <code>AffineTransform</code> object. The length of the
  401. * array is assumed to be at least 4. If the length of the array is
  402. * less than 6, only the first 4 values are taken. If the length of
  403. * the array is greater than 6, the first 6 values are taken.
  404. */
  405. public AffineTransform(float[] flatmatrix) {
  406. m00 = flatmatrix[0];
  407. m10 = flatmatrix[1];
  408. m01 = flatmatrix[2];
  409. m11 = flatmatrix[3];
  410. if (flatmatrix.length > 5) {
  411. m02 = flatmatrix[4];
  412. m12 = flatmatrix[5];
  413. }
  414. updateState();
  415. }
  416. /**
  417. * Constructs a new <code>AffineTransform</code> from 6 double
  418. * precision values representing the 6 specifiable entries of the 3x3
  419. * transformation matrix.
  420. * @param m00, m01, m02, m10, m11, m12 the
  421. * 6 floating point values that compose the 3x3 transformation matrix
  422. */
  423. public AffineTransform(double m00, double m10,
  424. double m01, double m11,
  425. double m02, double m12) {
  426. this.m00 = m00;
  427. this.m10 = m10;
  428. this.m01 = m01;
  429. this.m11 = m11;
  430. this.m02 = m02;
  431. this.m12 = m12;
  432. updateState();
  433. }
  434. /**
  435. * Constructs a new <code>AffineTransform</code> from an array of
  436. * double precision values representing either the 4 non-translation
  437. * entries or the 6 specifiable entries of the 3x3 transformation
  438. * matrix. The values are retrieved from the array as
  439. * { m00 m10 m01 m11 [m02 m12]}.
  440. * @param flatmatrix the double array containing the values to be set
  441. * in the new <code>AffineTransform</code> object. The length of the
  442. * array is assumed to be at least 4. If the length of the array is
  443. * less than 6, only the first 4 values are taken. If the length of
  444. * the array is greater than 6, the first 6 values are taken.
  445. */
  446. public AffineTransform(double[] flatmatrix) {
  447. m00 = flatmatrix[0];
  448. m10 = flatmatrix[1];
  449. m01 = flatmatrix[2];
  450. m11 = flatmatrix[3];
  451. if (flatmatrix.length > 5) {
  452. m02 = flatmatrix[4];
  453. m12 = flatmatrix[5];
  454. }
  455. updateState();
  456. }
  457. /**
  458. * Returns a transform representing a translation transformation.
  459. * The matrix representing the returned transform is:
  460. * <pre>
  461. * [ 1 0 tx ]
  462. * [ 0 1 ty ]
  463. * [ 0 0 1 ]
  464. * </pre>
  465. * @param tx the distance by which coordinates are translated in the
  466. * X axis direction
  467. * @param ty the distance by which coordinates are translated in the
  468. * Y axis direction
  469. * @return an <code>AffineTransform</code> object that represents a
  470. * translation transformation, created with the specified vector.
  471. */
  472. public static AffineTransform getTranslateInstance(double tx, double ty) {
  473. AffineTransform Tx = new AffineTransform();
  474. Tx.setToTranslation(tx, ty);
  475. return Tx;
  476. }
  477. /**
  478. * Returns a transform representing a rotation transformation.
  479. * The matrix representing the returned transform is:
  480. * <pre>
  481. * [ cos(theta) -sin(theta) 0 ]
  482. * [ sin(theta) cos(theta) 0 ]
  483. * [ 0 0 1 ]
  484. * </pre>
  485. * Rotating with a positive angle theta rotates points on the positive
  486. * x axis toward the positive y axis.
  487. * @param theta the angle of rotation in radians
  488. * @return an <code>AffineTransform</code> object that is a rotation
  489. * transformation, created with the specified angle of rotation.
  490. */
  491. public static AffineTransform getRotateInstance(double theta) {
  492. AffineTransform Tx = new AffineTransform();
  493. Tx.setToRotation(theta);
  494. return Tx;
  495. }
  496. /**
  497. * Returns a transform that rotates coordinates around an anchor point.
  498. * This operation is equivalent to translating the coordinates so
  499. * that the anchor point is at the origin (S1), then rotating them
  500. * about the new origin (S2), and finally translating so that the
  501. * intermediate origin is restored to the coordinates of the original
  502. * anchor point (S3).
  503. * <p>
  504. * This operation is equivalent to the following sequence of calls:
  505. * <pre>
  506. * AffineTransform Tx = new AffineTransform();
  507. * Tx.setToTranslation(x, y); // S3: final translation
  508. * Tx.rotate(theta); // S2: rotate around anchor
  509. * Tx.translate(-x, -y); // S1: translate anchor to origin
  510. * </pre>
  511. * The matrix representing the returned transform is:
  512. * <pre>
  513. * [ cos(theta) -sin(theta) x-x*cos+y*sin ]
  514. * [ sin(theta) cos(theta) y-x*sin-y*cos ]
  515. * [ 0 0 1 ]
  516. * </pre>
  517. * Rotating with a positive angle theta rotates points on the positive
  518. * x axis toward the positive y axis.
  519. * @param theta the angle of rotation in radians
  520. * @param x, y the coordinates of the anchor point of the
  521. * rotation
  522. * @return an <code>AffineTransform</code> object that rotates
  523. * coordinates around the specified point by the specified angle of
  524. * rotation.
  525. */
  526. public static AffineTransform getRotateInstance(double theta,
  527. double x, double y) {
  528. AffineTransform Tx = new AffineTransform();
  529. Tx.setToRotation(theta, x, y);
  530. return Tx;
  531. }
  532. /**
  533. * Returns a transform representing a scaling transformation.
  534. * The matrix representing the returned transform is:
  535. * <pre>
  536. * [ sx 0 0 ]
  537. * [ 0 sy 0 ]
  538. * [ 0 0 1 ]
  539. * </pre>
  540. * @param sx the factor by which coordinates are scaled along the
  541. * X axis direction
  542. * @param sy the factor by which coordinates are scaled along the
  543. * Y axis direction
  544. * @return an <code>AffineTransform</code> object that scales
  545. * coordinates by the specified factors.
  546. */
  547. public static AffineTransform getScaleInstance(double sx, double sy) {
  548. AffineTransform Tx = new AffineTransform();
  549. Tx.setToScale(sx, sy);
  550. return Tx;
  551. }
  552. /**
  553. * Returns a transform representing a shearing transformation.
  554. * The matrix representing the returned transform is:
  555. * <pre>
  556. * [ 1 shx 0 ]
  557. * [ shy 1 0 ]
  558. * [ 0 0 1 ]
  559. * </pre>
  560. * @param shx the multiplier by which coordinates are shifted in the
  561. * direction of the positive X axis as a factor of their Y coordinate
  562. * @param shy the multiplier by which coordinates are shifted in the
  563. * direction of the positive Y axis as a factor of their X coordinate
  564. * @return an <code>AffineTransform</code> object that shears
  565. * coordinates by the specified multipliers.
  566. */
  567. public static AffineTransform getShearInstance(double shx, double shy) {
  568. AffineTransform Tx = new AffineTransform();
  569. Tx.setToShear(shx, shy);
  570. return Tx;
  571. }
  572. /**
  573. * Retrieves the flag bits describing the conversion properties of
  574. * this transform.
  575. * The return value is either one of the constants TYPE_IDENTITY
  576. * or TYPE_GENERAL_TRANSFORM, or a combination of the
  577. * appriopriate flag bits.
  578. * A valid combination of flag bits is an exclusive OR operation
  579. * that can combine
  580. * the TYPE_TRANSLATION flag bit
  581. * in addition to either of the
  582. * TYPE_UNIFORM_SCALE or TYPE_GENERAL_SCALE flag bits
  583. * as well as either of the
  584. * TYPE_QUADRANT_ROTATION or TYPE_GENERAL_ROTATION flag bits.
  585. * @return the OR combination of any of the indicated flags that
  586. * apply to this transform
  587. * @see #TYPE_IDENTITY
  588. * @see #TYPE_TRANSLATION
  589. * @see #TYPE_UNIFORM_SCALE
  590. * @see #TYPE_GENERAL_SCALE
  591. * @see #TYPE_QUADRANT_ROTATION
  592. * @see #TYPE_GENERAL_ROTATION
  593. * @see #TYPE_GENERAL_TRANSFORM
  594. */
  595. public int getType() {
  596. if (type == TYPE_UNKNOWN) {
  597. calculateType();
  598. }
  599. return type;
  600. }
  601. /**
  602. * This is the utility function to calculate the flag bits when
  603. * they have not been cached.
  604. * @see #getType
  605. */
  606. private void calculateType() {
  607. int ret = TYPE_IDENTITY;
  608. boolean sgn0, sgn1;
  609. double M0, M1, M2, M3;
  610. updateState();
  611. switch (state) {
  612. default:
  613. stateError();
  614. /* NOTREACHED */
  615. case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
  616. ret = TYPE_TRANSLATION;
  617. /* NOBREAK */
  618. case (APPLY_SHEAR | APPLY_SCALE):
  619. if ((M0 = m00) * (M2 = m01) + (M3 = m10) * (M1 = m11) != 0) {
  620. // Transformed unit vectors are not perpendicular...
  621. this.type = TYPE_GENERAL_TRANSFORM;
  622. return;
  623. }
  624. sgn0 = (M0 >= 0.0);
  625. sgn1 = (M1 >= 0.0);
  626. if (sgn0 == sgn1) {
  627. // sgn(M0) == sgn(M1) therefore sgn(M2) == -sgn(M3)
  628. // This is the "unflipped" (right-handed) state
  629. if (M0 != M1 || M2 != -M3) {
  630. ret |= (TYPE_GENERAL_ROTATION | TYPE_GENERAL_SCALE);
  631. } else if (M0 * M1 - M2 * M3 != 1.0) {
  632. ret |= (TYPE_GENERAL_ROTATION | TYPE_UNIFORM_SCALE);
  633. } else {
  634. ret |= TYPE_GENERAL_ROTATION;
  635. }
  636. } else {
  637. // sgn(M0) == -sgn(M1) therefore sgn(M2) == sgn(M3)
  638. // This is the "flipped" (left-handed) state
  639. if (M0 != -M1 || M2 != M3) {
  640. ret |= (TYPE_GENERAL_ROTATION |
  641. TYPE_FLIP |
  642. TYPE_GENERAL_SCALE);
  643. } else if (M0 * M1 - M2 * M3 != 1.0) {
  644. ret |= (TYPE_GENERAL_ROTATION |
  645. TYPE_FLIP |
  646. TYPE_UNIFORM_SCALE);
  647. } else {
  648. ret |= (TYPE_GENERAL_ROTATION | TYPE_FLIP);
  649. }
  650. }
  651. break;
  652. case (APPLY_SHEAR | APPLY_TRANSLATE):
  653. ret = TYPE_TRANSLATION;
  654. /* NOBREAK */
  655. case (APPLY_SHEAR):
  656. sgn0 = ((M0 = m01) >= 0.0);
  657. sgn1 = ((M1 = m10) >= 0.0);
  658. if (sgn0 != sgn1) {
  659. // Different signs - simple 90 degree rotation
  660. if (M0 != -M1) {
  661. ret |= (TYPE_QUADRANT_ROTATION | TYPE_GENERAL_SCALE);
  662. } else if (M0 != 1.0 && M0 != -1.0) {
  663. ret |= (TYPE_QUADRANT_ROTATION | TYPE_UNIFORM_SCALE);
  664. } else {
  665. ret |= TYPE_QUADRANT_ROTATION;
  666. }
  667. } else {
  668. // Same signs - 90 degree rotation plus an axis flip too
  669. if (M0 == M1) {
  670. ret |= (TYPE_QUADRANT_ROTATION |
  671. TYPE_FLIP |
  672. TYPE_UNIFORM_SCALE);
  673. } else {
  674. ret |= (TYPE_QUADRANT_ROTATION |
  675. TYPE_FLIP |
  676. TYPE_GENERAL_SCALE);
  677. }
  678. }
  679. break;
  680. case (APPLY_SCALE | APPLY_TRANSLATE):
  681. ret = TYPE_TRANSLATION;
  682. /* NOBREAK */
  683. case (APPLY_SCALE):
  684. sgn0 = ((M0 = m00) >= 0.0);
  685. sgn1 = ((M1 = m11) >= 0.0);
  686. if (sgn0 == sgn1) {
  687. if (sgn0) {
  688. // Both scaling factors non-negative - simple scale
  689. // Note: APPLY_SCALE implies M0, M1 are not both 1
  690. if (M0 == M1) {
  691. ret |= TYPE_UNIFORM_SCALE;
  692. } else {
  693. ret |= TYPE_GENERAL_SCALE;
  694. }
  695. } else {
  696. // Both scaling factors negative - 180 degree rotation
  697. if (M0 != M1) {
  698. ret |= (TYPE_QUADRANT_ROTATION | TYPE_GENERAL_SCALE);
  699. } else if (M0 != -1.0) {
  700. ret |= (TYPE_QUADRANT_ROTATION | TYPE_UNIFORM_SCALE);
  701. } else {
  702. ret |= TYPE_QUADRANT_ROTATION;
  703. }
  704. }
  705. } else {
  706. // Scaling factor signs different - flip about some axis
  707. if (M0 == -M1) {
  708. if (M0 == 1.0 || M0 == -1.0) {
  709. ret |= TYPE_FLIP;
  710. } else {
  711. ret |= (TYPE_FLIP | TYPE_UNIFORM_SCALE);
  712. }
  713. } else {
  714. ret |= (TYPE_FLIP | TYPE_GENERAL_SCALE);
  715. }
  716. }
  717. break;
  718. case (APPLY_TRANSLATE):
  719. ret = TYPE_TRANSLATION;
  720. break;
  721. case (APPLY_IDENTITY):
  722. break;
  723. }
  724. this.type = ret;
  725. }
  726. /**
  727. * Returns the determinant of the matrix representation of the transform.
  728. * The determinant is useful both to determine if the transform can
  729. * be inverted and to get a single value representing the
  730. * combined X and Y scaling of the transform.
  731. * <p>
  732. * If the determinant is non-zero, then this transform is
  733. * invertible and the various methods that depend on the inverse
  734. * transform do not need to throw a
  735. * {@link NoninvertibleTransformException}.
  736. * If the determinant is zero then this transform can not be
  737. * inverted since the transform maps all input coordinates onto
  738. * a line or a point.
  739. * If the determinant is near enough to zero then inverse transform
  740. * operations might not carry enough precision to produce meaningful
  741. * results.
  742. * <p>
  743. * If this transform represents a uniform scale, as indicated by
  744. * the <code>getType</code> method then the determinant also
  745. * represents the square of the uniform scale factor by which all of
  746. * the points are expanded from or contracted towards the origin.
  747. * If this transform represents a non-uniform scale or more general
  748. * transform then the determinant is not likely to represent a
  749. * value useful for any purpose other than determining if inverse
  750. * transforms are possible.
  751. * <p>
  752. * Mathematically, the determinant is calculated using the formula:
  753. * <pre>
  754. * | m00 m01 m02 |
  755. * | m10 m11 m12 | = m00 * m11 - m01 * m10
  756. * | 0 0 1 |
  757. * </pre>
  758. *
  759. * @return the determinant of the matrix used to transform the
  760. * coordinates.
  761. * @see #getType
  762. * @see #createInverse
  763. * @see #inverseTransform
  764. * @see #TYPE_UNIFORM_SCALE
  765. */
  766. public double getDeterminant() {
  767. switch (state) {
  768. default:
  769. stateError();
  770. /* NOTREACHED */
  771. case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
  772. case (APPLY_SHEAR | APPLY_SCALE):
  773. return m00 * m11 - m01 * m10;
  774. case (APPLY_SHEAR | APPLY_TRANSLATE):
  775. case (APPLY_SHEAR):
  776. return -(m01 * m10);
  777. case (APPLY_SCALE | APPLY_TRANSLATE):
  778. case (APPLY_SCALE):
  779. return m00 * m11;
  780. case (APPLY_TRANSLATE):
  781. case (APPLY_IDENTITY):
  782. return 1.0;
  783. }
  784. }
  785. /**
  786. * Manually recalculates the state of the transform when the matrix
  787. * changes too much to predict the effects on the state.
  788. * The following table specifies what the various settings of the
  789. * state field say about the values of the corresponding matrix
  790. * element fields.
  791. * Note that the rules governing the SCALE fields are slightly
  792. * different depending on whether the SHEAR flag is also set.
  793. * <pre>
  794. * SCALE SHEAR TRANSLATE
  795. * m00/m11 m01/m10 m02/m12
  796. *
  797. * IDENTITY 1.0 0.0 0.0
  798. * TRANSLATE (TR) 1.0 0.0 not both 0.0
  799. * SCALE (SC) not both 1.0 0.0 0.0
  800. * TR | SC not both 1.0 0.0 not both 0.0
  801. * SHEAR (SH) 0.0 not both 0.0 0.0
  802. * TR | SH 0.0 not both 0.0 not both 0.0
  803. * SC | SH not both 0.0 not both 0.0 0.0
  804. * TR | SC | SH not both 0.0 not both 0.0 not both 0.0
  805. * </pre>
  806. */
  807. void updateState() {
  808. if (m01 == 0.0 && m10 == 0.0) {
  809. if (m00 == 1.0 && m11 == 1.0) {
  810. if (m02 == 0.0 && m12 == 0.0) {
  811. state = APPLY_IDENTITY;
  812. type = TYPE_IDENTITY;
  813. } else {
  814. state = APPLY_TRANSLATE;
  815. type = TYPE_TRANSLATION;
  816. }
  817. } else {
  818. if (m02 == 0.0 && m12 == 0.0) {
  819. state = APPLY_SCALE;
  820. type = TYPE_UNKNOWN;
  821. } else {
  822. state = (APPLY_SCALE | APPLY_TRANSLATE);
  823. type = TYPE_UNKNOWN;
  824. }
  825. }
  826. } else {
  827. if (m00 == 0.0 && m11 == 0.0) {
  828. if (m02 == 0.0 && m12 == 0.0) {
  829. state = APPLY_SHEAR;
  830. type = TYPE_UNKNOWN;
  831. } else {
  832. state = (APPLY_SHEAR | APPLY_TRANSLATE);
  833. type = TYPE_UNKNOWN;
  834. }
  835. } else {
  836. if (m02 == 0.0 && m12 == 0.0) {
  837. state = (APPLY_SHEAR | APPLY_SCALE);
  838. type = TYPE_UNKNOWN;
  839. } else {
  840. state = (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE);
  841. type = TYPE_UNKNOWN;
  842. }
  843. }
  844. }
  845. }
  846. /*
  847. * Convenience method used internally to throw exceptions when
  848. * a case was forgotten in a switch statement.
  849. */
  850. private void stateError() {
  851. throw new InternalError("missing case in transform state switch");
  852. }
  853. /**
  854. * Retrieves the 6 specifiable values in the 3x3 affine transformation
  855. * matrix and places them into an array of double precisions values.
  856. * The values are stored in the array as
  857. * { m00 m10 m01 m11 m02 m12 }.
  858. * An array of 4 doubles can also be specified, in which case only the
  859. * first four elements representing the non-transform
  860. * parts of the array are retrieved and the values are stored into
  861. * the array as { m00 m10 m01 m11 }
  862. * @param flatmatrix the double array used to store the returned
  863. * values.
  864. * @see #getScaleX
  865. * @see #getScaleY
  866. * @see #getShearX
  867. * @see #getShearY
  868. * @see #getTranslateX
  869. * @see #getTranslateY
  870. */
  871. public void getMatrix(double[] flatmatrix) {
  872. flatmatrix[0] = m00;
  873. flatmatrix[1] = m10;
  874. flatmatrix[2] = m01;
  875. flatmatrix[3] = m11;
  876. if (flatmatrix.length > 5) {
  877. flatmatrix[4] = m02;
  878. flatmatrix[5] = m12;
  879. }
  880. }
  881. /**
  882. * Returns the X coordinate scaling element (m00) of the 3x3
  883. * affine transformation matrix.
  884. * @return a double value that is the X coordinate of the scaling
  885. * element of the affine transformation matrix.
  886. * @see #getMatrix
  887. */
  888. public double getScaleX() {
  889. return m00;
  890. }
  891. /**
  892. * Returns the Y coordinate scaling element (m11) of the 3x3
  893. * affine transformation matrix.
  894. * @return a double value that is the Y coordinate of the scaling
  895. * element of the affine transformation matrix.
  896. * @see #getMatrix
  897. */
  898. public double getScaleY() {
  899. return m11;
  900. }
  901. /**
  902. * Returns the X coordinate shearing element (m01) of the 3x3
  903. * affine transformation matrix.
  904. * @return a double value that is the X coordinate of the shearing
  905. * element of the affine transformation matrix.
  906. * @see #getMatrix
  907. */
  908. public double getShearX() {
  909. return m01;
  910. }
  911. /**
  912. * Returns the Y coordinate shearing element (m10) of the 3x3
  913. * affine transformation matrix.
  914. * @return a double value that is the Y coordinate of the shearing
  915. * element of the affine transformation matrix.
  916. * @see #getMatrix
  917. */
  918. public double getShearY() {
  919. return m10;
  920. }
  921. /**
  922. * Returns the X coordinate of the translation element (m02) of the
  923. * 3x3 affine transformation matrix.
  924. * @return a double value that is the X coordinate of the translation
  925. * element of the affine transformation matrix.
  926. * @see #getMatrix
  927. */
  928. public double getTranslateX() {
  929. return m02;
  930. }
  931. /**
  932. * Returns the Y coordinate of the translation element (m12) of the
  933. * 3x3 affine transformation matrix.
  934. * @return a double value that is the Y coordinate of the translation
  935. * element of the affine transformation matrix.
  936. * @see #getMatrix
  937. */
  938. public double getTranslateY() {
  939. return m12;
  940. }
  941. /**
  942. * Concatenates this transform with a translation transformation.
  943. * This is equivalent to calling concatenate(T), where T is an
  944. * <code>AffineTransform</code> represented by the following matrix:
  945. * <pre>
  946. * [ 1 0 tx ]
  947. * [ 0 1 ty ]
  948. * [ 0 0 1 ]
  949. * </pre>
  950. * @param tx the distance by which coordinates are translated in the
  951. * X axis direction
  952. * @param ty the distance by which coordinates are translated in the
  953. * Y axis direction
  954. */
  955. public void translate(double tx, double ty) {
  956. switch (state) {
  957. default:
  958. stateError();
  959. /* NOTREACHED */
  960. case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
  961. m02 = tx * m00 + ty * m01 + m02;
  962. m12 = tx * m10 + ty * m11 + m12;
  963. if (m02 == 0.0 && m12 == 0.0) {
  964. state = APPLY_SHEAR | APPLY_SCALE;
  965. if (type != TYPE_UNKNOWN) {
  966. type -= TYPE_TRANSLATION;
  967. }
  968. }
  969. return;
  970. case (APPLY_SHEAR | APPLY_SCALE):
  971. m02 = tx * m00 + ty * m01;
  972. m12 = tx * m10 + ty * m11;
  973. if (m02 != 0.0 || m12 != 0.0) {
  974. state = APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE;
  975. type |= TYPE_TRANSLATION;
  976. }
  977. return;
  978. case (APPLY_SHEAR | APPLY_TRANSLATE):
  979. m02 = ty * m01 + m02;
  980. m12 = tx * m10 + m12;
  981. if (m02 == 0.0 && m12 == 0.0) {
  982. state = APPLY_SHEAR;
  983. if (type != TYPE_UNKNOWN) {
  984. type -= TYPE_TRANSLATION;
  985. }
  986. }
  987. return;
  988. case (APPLY_SHEAR):
  989. m02 = ty * m01;
  990. m12 = tx * m10;
  991. if (m02 != 0.0 || m12 != 0.0) {
  992. state = APPLY_SHEAR | APPLY_TRANSLATE;
  993. type |= TYPE_TRANSLATION;
  994. }
  995. return;
  996. case (APPLY_SCALE | APPLY_TRANSLATE):
  997. m02 = tx * m00 + m02;
  998. m12 = ty * m11 + m12;
  999. if (m02 == 0.0 && m12 == 0.0) {
  1000. state = APPLY_SCALE;
  1001. if (type != TYPE_UNKNOWN) {
  1002. type -= TYPE_TRANSLATION;
  1003. }
  1004. }
  1005. return;
  1006. case (APPLY_SCALE):
  1007. m02 = tx * m00;
  1008. m12 = ty * m11;
  1009. if (m02 != 0.0 || m12 != 0.0) {
  1010. state = APPLY_SCALE | APPLY_TRANSLATE;
  1011. type |= TYPE_TRANSLATION;
  1012. }
  1013. return;
  1014. case (APPLY_TRANSLATE):
  1015. m02 = tx + m02;
  1016. m12 = ty + m12;
  1017. if (m02 == 0.0 && m12 == 0.0) {
  1018. state = APPLY_IDENTITY;
  1019. type = TYPE_IDENTITY;
  1020. }
  1021. return;
  1022. case (APPLY_IDENTITY):
  1023. m02 = tx;
  1024. m12 = ty;
  1025. if (tx != 0.0 || ty != 0.0) {
  1026. state = APPLY_TRANSLATE;
  1027. type = TYPE_TRANSLATION;
  1028. }
  1029. return;
  1030. }
  1031. }
  1032. /**
  1033. * Concatenates this transform with a rotation transformation.
  1034. * This is equivalent to calling concatenate(R), where R is an
  1035. * <code>AffineTransform</code> represented by the following matrix:
  1036. * <pre>
  1037. * [ cos(theta) -sin(theta) 0 ]
  1038. * [ sin(theta) cos(theta) 0 ]
  1039. * [ 0 0 1 ]
  1040. * </pre>
  1041. * Rotating with a positive angle theta rotates points on the positive
  1042. * x axis toward the positive y axis.
  1043. * @param theta the angle of rotation in radians
  1044. */
  1045. public void rotate(double theta) {
  1046. double sin = Math.sin(theta);
  1047. double cos = Math.cos(theta);
  1048. if (Math.abs(sin) < 1E-15) {
  1049. if (cos < 0.0) {
  1050. m00 = -m00;
  1051. m11 = -m11;
  1052. int state = this.state;
  1053. if ((state & (APPLY_SHEAR)) != 0) {
  1054. // If there was a shear, then this rotation has no
  1055. // effect on the state.
  1056. m01 = -m01;
  1057. m10 = -m10;
  1058. } else {
  1059. // No shear means the SCALE state may toggle when
  1060. // m00 and m11 are negated.
  1061. if (m00 == 1.0 && m11 == 1.0) {
  1062. this.state = state & ~APPLY_SCALE;
  1063. } else {
  1064. this.state = state | APPLY_SCALE;
  1065. }
  1066. }
  1067. type = TYPE_UNKNOWN;
  1068. }
  1069. return;
  1070. }
  1071. if (Math.abs(cos) < 1E-15) {
  1072. if (sin < 0.0) {
  1073. double M0 = m00;
  1074. m00 = -m01;
  1075. m01 = M0;
  1076. M0 = m10;
  1077. m10 = -m11;
  1078. m11 = M0;
  1079. } else {
  1080. double M0 = m00;
  1081. m00 = m01;
  1082. m01 = -M0;
  1083. M0 = m10;
  1084. m10 = m11;
  1085. m11 = -M0;
  1086. }
  1087. int state = rot90conversion[this.state];
  1088. if ((state & (APPLY_SHEAR | APPLY_SCALE)) == APPLY_SCALE &&
  1089. m00 == 1.0 && m11 == 1.0)
  1090. {
  1091. state -= APPLY_SCALE;
  1092. }
  1093. this.state = state;
  1094. type = TYPE_UNKNOWN;
  1095. return;
  1096. }
  1097. double M0, M1;
  1098. M0 = m00;
  1099. M1 = m01;
  1100. m00 = cos * M0 + sin * M1;
  1101. m01 = -sin * M0 + cos * M1;
  1102. M0 = m10;
  1103. M1 = m11;
  1104. m10 = cos * M0 + sin * M1;
  1105. m11 = -sin * M0 + cos * M1;
  1106. updateState();
  1107. }
  1108. private static int rot90conversion[] = {
  1109. APPLY_SHEAR, APPLY_SHEAR | APPLY_TRANSLATE,
  1110. APPLY_SHEAR, APPLY_SHEAR | APPLY_TRANSLATE,
  1111. APPLY_SCALE, APPLY_SCALE | APPLY_TRANSLATE,
  1112. APPLY_SHEAR | APPLY_SCALE,
  1113. APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE,
  1114. };
  1115. /**
  1116. * Concatenates this transform with a transform that rotates
  1117. * coordinates around an anchor point.
  1118. * This operation is equivalent to translating the coordinates so
  1119. * that the anchor point is at the origin (S1), then rotating them
  1120. * about the new origin (S2), and finally translating so that the
  1121. * intermediate origin is restored to the coordinates of the original
  1122. * anchor point (S3).
  1123. * <p>
  1124. * This operation is equivalent to the following sequence of calls:
  1125. * <pre>
  1126. * translate(x, y); // S3: final translation
  1127. * rotate(theta); // S2: rotate around anchor
  1128. * translate(-x, -y); // S1: translate anchor to origin
  1129. * </pre>
  1130. * Rotating with a positive angle theta rotates points on the positive
  1131. * x axis toward the positive y axis.
  1132. * @param theta the angle of rotation in radians
  1133. * @param x, y the coordinates of the anchor point of the
  1134. * rotation
  1135. */
  1136. public void rotate(double theta, double x, double y) {
  1137. // REMIND: Simple for now - optimize later
  1138. translate(x, y);
  1139. rotate(theta);
  1140. translate(-x, -y);
  1141. }
  1142. /**
  1143. * Concatenates this transform with a scaling transformation.
  1144. * This is equivalent to calling concatenate(S), where S is an
  1145. * <code>AffineTransform</code> represented by the following matrix:
  1146. * <pre>
  1147. * [ sx 0 0 ]
  1148. * [ 0 sy 0 ]
  1149. * [ 0 0 1 ]
  1150. * </pre>
  1151. * @param sx the factor by which coordinates are scaled along the
  1152. * X axis direction
  1153. * @param sy the factor by which coordinates are scaled along the
  1154. * Y axis direction
  1155. */
  1156. public void scale(double sx, double sy) {
  1157. int state = this.state;
  1158. switch (state) {
  1159. default:
  1160. stateError();
  1161. /* NOTREACHED */
  1162. case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
  1163. case (APPLY_SHEAR | APPLY_SCALE):
  1164. m00 *= sx;
  1165. m11 *= sy;
  1166. /* NOBREAK */
  1167. case (APPLY_SHEAR | APPLY_TRANSLATE):
  1168. case (APPLY_SHEAR):
  1169. m01 *= sy;
  1170. m10 *= sx;
  1171. if (m01 == 0 && m10 == 0) {
  1172. this.state = state - APPLY_SHEAR;
  1173. // REMIND: Is it possible for m00 and m11 to be both 1.0?
  1174. }
  1175. this.type = TYPE_UNKNOWN;
  1176. return;
  1177. case (APPLY_SCALE | APPLY_TRANSLATE):
  1178. case (APPLY_SCALE):
  1179. m00 *= sx;
  1180. m11 *= sy;
  1181. if (m00 == 1.0 && m11 == 1.0) {
  1182. this.state = (state &= APPLY_TRANSLATE);
  1183. this.type = (state == APPLY_IDENTITY
  1184. ? TYPE_IDENTITY
  1185. : TYPE_TRANSLATION);
  1186. } else {
  1187. this.type = TYPE_UNKNOWN;
  1188. }
  1189. return;
  1190. case (APPLY_TRANSLATE):
  1191. case (APPLY_IDENTITY):
  1192. m00 = sx;
  1193. m11 = sy;
  1194. if (sx != 1.0 || sy != 1.0) {
  1195. this.state = state | APPLY_SCALE;
  1196. this.type = TYPE_UNKNOWN;
  1197. }
  1198. return;
  1199. }
  1200. }
  1201. /**
  1202. * Concatenates this transform with a shearing transformation.
  1203. * This is equivalent to calling concatenate(SH), where SH is an
  1204. * <code>AffineTransform</code> represented by the following matrix:
  1205. * <pre>
  1206. * [ 1 shx 0 ]
  1207. * [ shy 1 0 ]
  1208. * [ 0 0 1 ]
  1209. * </pre>
  1210. * @param shx the multiplier by which coordinates are shifted in the
  1211. * direction of the positive X axis as a factor of their Y coordinate
  1212. * @param shy the multiplier by which coordinates are shifted in the
  1213. * direction of the positive Y axis as a factor of their X coordinate
  1214. */
  1215. public void shear(double shx, double shy) {
  1216. int state = this.state;
  1217. switch (state) {
  1218. default:
  1219. stateError();
  1220. /* NOTREACHED */
  1221. case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
  1222. case (APPLY_SHEAR | APPLY_SCALE):
  1223. double M0, M1;
  1224. M0 = m00;
  1225. M1 = m01;
  1226. m00 = M0 + M1 * shy;
  1227. m01 = M0 * shx + M1;
  1228. M0 = m10;
  1229. M1 = m11;
  1230. m10 = M0 + M1 * shy;
  1231. m11 = M0 * shx + M1;
  1232. updateState();
  1233. return;
  1234. case (APPLY_SHEAR | APPLY_TRANSLATE):
  1235. case (APPLY_SHEAR):
  1236. m00 = m01 * shy;
  1237. m11 = m10 * shx;
  1238. if (m00 != 0.0 || m11 != 0.0) {
  1239. this.state = state | APPLY_SCALE;
  1240. }
  1241. this.type = TYPE_UNKNOWN;
  1242. return;
  1243. case (APPLY_SCALE | APPLY_TRANSLATE):
  1244. case (APPLY_SCALE):
  1245. m01 = m00 * shx;
  1246. m10 = m11 * shy;
  1247. if (m01 != 0.0 || m10 != 0.0) {
  1248. this.state = state | APPLY_SHEAR;
  1249. }
  1250. this.type = TYPE_UNKNOWN;
  1251. return;
  1252. case (APPLY_TRANSLATE):
  1253. case (APPLY_IDENTITY):
  1254. m01 = shx;
  1255. m10 = shy;
  1256. if (m01 != 0.0 || m10 != 0.0) {
  1257. this.state = state | APPLY_SCALE | APPLY_SHEAR;
  1258. this.type = TYPE_UNKNOWN;
  1259. }
  1260. return;
  1261. }
  1262. }
  1263. /**
  1264. * Resets this transform to the Identity transform.
  1265. */
  1266. public void setToIdentity() {
  1267. m00 = m11 = 1.0;
  1268. m10 = m01 = m02 = m12 = 0.0;
  1269. state = APPLY_IDENTITY;
  1270. type = TYPE_IDENTITY;
  1271. }
  1272. /**
  1273. * Sets this transform to a translation transformation.
  1274. * The matrix representing this transform becomes:
  1275. * <pre>
  1276. * [ 1 0 tx ]
  1277. * [ 0 1 ty ]
  1278. * [ 0 0 1 ]
  1279. * </pre>
  1280. * @param tx the distance by which coordinates are translated in the
  1281. * X axis direction
  1282. * @param ty the distance by which coordinates are translated in the
  1283. * Y axis direction
  1284. */
  1285. public void setToTranslation(double tx, double ty) {
  1286. m00 = 1.0;
  1287. m10 = 0.0;
  1288. m01 = 0.0;
  1289. m11 = 1.0;
  1290. m02 = tx;
  1291. m12 = ty;
  1292. if (tx != 0.0 || ty != 0.0) {
  1293. state = APPLY_TRANSLATE;
  1294. type = TYPE_TRANSLATION;
  1295. } else {
  1296. state = APPLY_IDENTITY;
  1297. type = TYPE_IDENTITY;
  1298. }
  1299. }
  1300. /**
  1301. * Sets this transform to a rotation transformation.
  1302. * The matrix representing this transform becomes:
  1303. * <pre>
  1304. * [ cos(theta) -sin(theta) 0 ]
  1305. * [ sin(theta) cos(theta) 0 ]
  1306. * [ 0 0 1 ]
  1307. * </pre>
  1308. * Rotating with a positive angle theta rotates points on the positive
  1309. * x axis toward the positive y axis.
  1310. * @param theta the angle of rotation in radians
  1311. */
  1312. public void setToRotation(double theta) {
  1313. m02 = 0.0;
  1314. m12 = 0.0;
  1315. double sin = Math.sin(theta);
  1316. double cos = Math.cos(theta);
  1317. if (Math.abs(sin) < 1E-15) {
  1318. m01 = m10 = 0.0;
  1319. if (cos < 0) {
  1320. m00 = m11 = -1.0;
  1321. state = APPLY_SCALE;
  1322. type = TYPE_QUADRANT_ROTATION;
  1323. } else {
  1324. m00 = m11 = 1.0;
  1325. state = APPLY_IDENTITY;
  1326. type = TYPE_IDENTITY;
  1327. }
  1328. return;
  1329. }
  1330. if (Math.abs(cos) < 1E-15) {
  1331. m00 = m11 = 0.0;
  1332. if (sin < 0.0) {
  1333. m01 = 1.0;
  1334. m10 = -1.0;
  1335. } else {
  1336. m01 = -1.0;
  1337. m10 = 1.0;
  1338. }
  1339. state = APPLY_SHEAR;
  1340. type = TYPE_QUADRANT_ROTATION;
  1341. return;
  1342. }
  1343. m00 = cos;
  1344. m01 = -sin;
  1345. m10 = sin;
  1346. m11 = cos;
  1347. state = APPLY_SHEAR | APPLY_SCALE;
  1348. type = TYPE_GENERAL_ROTATION;
  1349. return;
  1350. }
  1351. /**
  1352. * Sets this transform to a translated rotation transformation.
  1353. * This operation is equivalent to translating the coordinates so
  1354. * that the anchor point is at the origin (S1), then rotating them
  1355. * about the new origin (S2), and finally translating so that the
  1356. * intermediate origin is restored to the coordinates of the original
  1357. * anchor point (S3).
  1358. * <p>
  1359. * This operation is equivalent to the following sequence of calls:
  1360. * <pre>
  1361. * setToTranslation(x, y); // S3: final translation
  1362. * rotate(theta); // S2: rotate around anchor
  1363. * translate(-x, -y); // S1: translate anchor to origin
  1364. * </pre>
  1365. * The matrix representing this transform becomes:
  1366. * <pre>
  1367. * [ cos(theta) -sin(theta) x-x*cos+y*sin ]
  1368. * [ sin(theta) cos(theta) y-x*sin-y*cos ]
  1369. * [ 0 0 1 ]
  1370. * </pre>
  1371. * Rotating with a positive angle theta rotates points on the positive
  1372. * x axis toward the positive y axis.
  1373. * @param theta the angle of rotation in radians
  1374. * @param x, y the coordinates of the anchor point of the
  1375. * rotation
  1376. */
  1377. public void setToRotation(double theta, double x, double y) {
  1378. setToRotation(theta);
  1379. double sin = m10;
  1380. double oneMinusCos = 1.0 - m00;
  1381. m02 = x * oneMinusCos + y * sin;
  1382. m12 = y * oneMinusCos - x * sin;
  1383. if (m02 != 0.0 || m12 != 0.0) {
  1384. state |= APPLY_TRANSLATE;
  1385. type |= TYPE_TRANSLATION;
  1386. }
  1387. return;
  1388. }
  1389. /**
  1390. * Sets this transform to a scaling transformation.
  1391. * The matrix representing this transform becomes:
  1392. * <pre>
  1393. * [ sx 0 0 ]
  1394. * [ 0 sy 0 ]
  1395. * [ 0 0 1 ]
  1396. * </pre>
  1397. * @param sx the factor by which coordinates are scaled along the
  1398. * X axis direction
  1399. * @param sy the factor by which coordinates are scaled along the
  1400. * Y axis direction
  1401. */
  1402. public void setToScale(double sx, double sy) {
  1403. m00 = sx;
  1404. m10 = 0.0;
  1405. m01 = 0.0;
  1406. m11 = sy;
  1407. m02 = 0.0;
  1408. m12 = 0.0;
  1409. if (sx != 1.0 || sy != 1.0) {
  1410. state = APPLY_SCALE;
  1411. type = TYPE_UNKNOWN;
  1412. } else {
  1413. state = APPLY_IDENTITY;
  1414. type = TYPE_IDENTITY;
  1415. }
  1416. }
  1417. /**
  1418. * Sets this transform to a shearing transformation.
  1419. * The matrix representing this transform becomes:
  1420. * <pre>
  1421. * [ 1 shx 0 ]
  1422. * [ shy 1 0 ]
  1423. * [ 0 0 1 ]
  1424. * </pre>
  1425. * @param shx the multiplier by which coordinates are shifted in the
  1426. * direction of the positive X axis as a factor of their Y coordinate
  1427. * @param shy the multiplier by which coordinates are shifted in the
  1428. * direction of the positive Y axis as a factor of their X coordinate
  1429. */
  1430. public void setToShear(double shx, double shy) {
  1431. m00 = 1.0;
  1432. m01 = shx;
  1433. m10 = shy;
  1434. m11 = 1.0;
  1435. m02 = 0.0;
  1436. m12 = 0.0;
  1437. if (shx != 0.0 || shy != 0.0) {
  1438. state = (APPLY_SHEAR | APPLY_SCALE);
  1439. type = TYPE_UNKNOWN;
  1440. } else {
  1441. state = APPLY_IDENTITY;
  1442. type = TYPE_IDENTITY;
  1443. }
  1444. }
  1445. /**
  1446. * Sets this transform to a copy of the transform in the specified
  1447. * <code>AffineTransform</code> object.
  1448. * @param Tx the <code>AffineTransform</code> object from which to
  1449. * copy the transform
  1450. */
  1451. public void setTransform(AffineTransform Tx) {
  1452. this.m00 = Tx.m00;
  1453. this.m10 = Tx.m10;
  1454. this.m01 = Tx.m01;
  1455. this.m11 = Tx.m11;
  1456. this.m02 = Tx.m02;
  1457. this.m12 = Tx.m12;
  1458. this.state = Tx.state;
  1459. this.type = Tx.type;
  1460. }
  1461. /**
  1462. * Sets this transform to the matrix specified by the 6
  1463. * double precision values.
  1464. * @param m00, m01, m02, m10, m11, m12 the
  1465. * 6 floating point values that compose the 3x3 transformation matrix
  1466. */
  1467. public void setTransform(double m00, double m10,
  1468. double m01, double m11,
  1469. double m02, double m12) {
  1470. this.m00 = m00;
  1471. this.m10 = m10;
  1472. this.m01 = m01;
  1473. this.m11 = m11;
  1474. this.m02 = m02;
  1475. this.m12 = m12;
  1476. updateState();
  1477. }
  1478. /**
  1479. * Concatenates an <code>AffineTransform</code> <code>Tx</code> to
  1480. * this <code>AffineTransform</code> Cx in the most commonly useful
  1481. * way to provide a new user space
  1482. * that is mapped to the former user space by <code>Tx</code>.
  1483. * Cx is updated to perform the combined transformation.
  1484. * Transforming a point p by the updated transform Cx' is
  1485. * equivalent to first transforming p by <code>Tx</code> and then
  1486. * transforming the result by the original transform Cx like this:
  1487. * Cx'(p) = Cx(Tx(p))
  1488. * In matrix notation, if this transform Cx is
  1489. * represented by the matrix [this] and <code>Tx</code> is represented
  1490. * by the matrix [Tx] then this method does the following:
  1491. * <pre>
  1492. * [this] = [this] x [Tx]
  1493. * </pre>
  1494. * @param Tx the <code>AffineTransform</code> object to be
  1495. * concatenated with this <code>AffineTransform</code> object.
  1496. * @see #preConcatenate
  1497. */
  1498. public void concatenate(AffineTransform Tx) {
  1499. double M0, M1;
  1500. double T00, T01, T10, T11;
  1501. double T02, T12;
  1502. int mystate = state;
  1503. int txstate = Tx.state;
  1504. switch ((txstate << HI_SHIFT) | mystate) {
  1505. /* ---------- Tx == IDENTITY cases ---------- */
  1506. case (HI_IDENTITY | APPLY_IDENTITY):
  1507. case (HI_IDENTITY | APPLY_TRANSLATE):
  1508. case (HI_IDENTITY | APPLY_SCALE):
  1509. case (HI_IDENTITY | APPLY_SCALE | APPLY_TRANSLATE):
  1510. case (HI_IDENTITY | APPLY_SHEAR):
  1511. case (HI_IDENTITY | APPLY_SHEAR | APPLY_TRANSLATE):
  1512. case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE):
  1513. case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
  1514. return;
  1515. /* ---------- this == IDENTITY cases ---------- */
  1516. case (HI_SHEAR | HI_SCALE | HI_TRANSLATE | APPLY_IDENTITY):
  1517. m01 = Tx.m01;
  1518. m10 = Tx.m10;
  1519. /* NOBREAK */
  1520. case (HI_SCALE | HI_TRANSLATE | APPLY_IDENTITY):
  1521. m00 = Tx.m00;
  1522. m11 = Tx.m11;
  1523. /* NOBREAK */
  1524. case (HI_TRANSLATE | APPLY_IDENTITY):
  1525. m02 = Tx.m02;
  1526. m12 = Tx.m12;
  1527. state = txstate;
  1528. type = Tx.type;
  1529. return;
  1530. case (HI_SHEAR | HI_SCALE | APPLY_IDENTITY):
  1531. m01 = Tx.m01;
  1532. m10 = Tx.m10;
  1533. /* NOBREAK */
  1534. case (HI_SCALE | APPLY_IDENTITY):
  1535. m00 = Tx.m00;
  1536. m11 = Tx.m11;
  1537. state = txstate;
  1538. type = Tx.type;
  1539. return;
  1540. case (HI_SHEAR | HI_TRANSLATE | APPLY_IDENTITY):
  1541. m02 = Tx.m02;
  1542. m12 = Tx.m12;
  1543. /* NOBREAK */
  1544. case (HI_SHEAR | APPLY_IDENTITY):
  1545. m01 = Tx.m01;
  1546. m10 = Tx.m10;
  1547. m00 = m11 = 0.0;
  1548. state = txstate;
  1549. type = Tx.type;
  1550. return;
  1551. /* ---------- Tx == TRANSLATE cases ---------- */
  1552. case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
  1553. case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE):
  1554. case (HI_TRANSLATE | APPLY_SHEAR | APPLY_TRANSLATE):
  1555. case (HI_TRANSLATE | APPLY_SHEAR):
  1556. case (HI_TRANSLATE | APPLY_SCALE | APPLY_TRANSLATE):
  1557. case (HI_TRANSLATE | APPLY_SCALE):
  1558. case (HI_TRANSLATE | APPLY_TRANSLATE):
  1559. translate(Tx.m02, Tx.m12);
  1560. return;
  1561. /* ---------- Tx == SCALE cases ---------- */
  1562. case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
  1563. case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE):
  1564. case (HI_SCALE | APPLY_SHEAR | APPLY_TRANSLATE):
  1565. case (HI_SCALE | APPLY_SHEAR):
  1566. case (HI_SCALE | APPLY_SCALE | APPLY_TRANSLATE):
  1567. case (HI_SCALE | APPLY_SCALE):
  1568. case (HI_SCALE | APPLY_TRANSLATE):
  1569. scale(Tx.m00, Tx.m11);
  1570. return;
  1571. /* ---------- Tx == SHEAR cases ---------- */
  1572. case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
  1573. case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE):
  1574. T01 = Tx.m01; T10 = Tx.m10;
  1575. M0 = m00;
  1576. m00 = m01 * T10;
  1577. m01 = M0 * T01;
  1578. M0 = m10;
  1579. m10 = m11 * T10;
  1580. m11 = M0 * T01;
  1581. type = TYPE_UNKNOWN;
  1582. return;
  1583. case (HI_SHEAR | APPLY_SHEAR | APPLY_TRANSLATE):
  1584. case (HI_SHEAR | APPLY_SHEAR):
  1585. m00 = m01 * Tx.m10;
  1586. m01 = 0.0;
  1587. m11 = m10 * Tx.m01;
  1588. m10 = 0.0;
  1589. state = mystate ^ (APPLY_SHEAR | APPLY_SCALE);
  1590. type = TYPE_UNKNOWN;
  1591. return;
  1592. case (HI_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
  1593. case (HI_SHEAR | APPLY_SCALE):
  1594. m01 = m00 * Tx.m01;
  1595. m00 = 0.0;
  1596. m10 = m11 * Tx.m10;
  1597. m11 = 0.0;
  1598. state = mystate ^ (APPLY_SHEAR | APPLY_SCALE);
  1599. type = TYPE_UNKNOWN;
  1600. return;
  1601. case (HI_SHEAR | APPLY_TRANSLATE):
  1602. m00 = 0.0;
  1603. m01 = Tx.m01;
  1604. m10 = Tx.m10;
  1605. m11 = 0.0;
  1606. state = APPLY_TRANSLATE | APPLY_SHEAR;
  1607. type = TYPE_UNKNOWN;
  1608. return;
  1609. }
  1610. // If Tx has more than one attribute, it is not worth optimizing
  1611. // all of those cases...
  1612. T00 = Tx.m00; T01 = Tx.m01; T02 = Tx.m02;
  1613. T10 = Tx.m10; T11 = Tx.m11; T12 = Tx.m12;
  1614. switch (mystate) {
  1615. default:
  1616. stateError();
  1617. /* NOTREACHED */
  1618. case (APPLY_SHEAR | APPLY_SCALE):
  1619. state = mystate | txstate;
  1620. /* NOBREAK */
  1621. case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
  1622. M0 = m00;
  1623. M1 = m01;
  1624. m00 = T00 * M0 + T10 * M1;
  1625. m01 = T01 * M0 + T11 * M1;
  1626. m02 += T02 * M0 + T12 * M1;
  1627. M0 = m10;
  1628. M1 = m11;
  1629. m10 = T00 * M0 + T10 * M1;
  1630. m11 = T01 * M0 + T11 * M1;
  1631. m12 += T02 * M0 + T12 * M1;
  1632. type = TYPE_UNKNOWN;
  1633. return;
  1634. case (APPLY_SHEAR | APPLY_TRANSLATE):
  1635. case (APPLY_SHEAR):
  1636. M0 = m01;
  1637. m00 = T10 * M0;
  1638. m01 = T11 * M0;
  1639. m02 += T12 * M0;
  1640. M0 = m10;
  1641. m10 = T00 * M0;
  1642. m11 = T01 * M0;
  1643. m12 += T02 * M0;
  1644. break;
  1645. case (APPLY_SCALE | APPLY_TRANSLATE):
  1646. case (APPLY_SCALE):
  1647. M0 = m00;
  1648. m00 = T00 * M0;
  1649. m01 = T01 * M0;
  1650. m02 += T02 * M0;
  1651. M0 = m11;
  1652. m10 = T10 * M0;
  1653. m11 = T11 * M0;
  1654. m12 += T12 * M0;
  1655. break;
  1656. case (APPLY_TRANSLATE):
  1657. m00 = T00;
  1658. m01 = T01;
  1659. m02 += T02;
  1660. m10 = T10;
  1661. m11 = T11;
  1662. m12 += T12;
  1663. state = txstate | APPLY_TRANSLATE;
  1664. type = TYPE_UNKNOWN;
  1665. return;
  1666. }
  1667. updateState();
  1668. }
  1669. /**
  1670. * Concatenates an <code>AffineTransform</code> <code>Tx</code> to
  1671. * this <code>AffineTransform</code> Cx
  1672. * in a less commonly used way such that <code>Tx</code> modifies the
  1673. * coordinate transformation relative to the absolute pixel
  1674. * space rather than relative to the existing user space.
  1675. * Cx is updated to perform the combined transformation.
  1676. * Transforming a point p by the updated transform Cx' is
  1677. * equivalent to first transforming p by the original transform
  1678. * Cx and then transforming the result by
  1679. * <code>Tx</code> like this:
  1680. * Cx'(p) = Tx(Cx(p))
  1681. * In matrix notation, if this transform Cx
  1682. * is represented by the matrix [this] and <code>Tx</code> is
  1683. * represented by the matrix [Tx] then this method does the
  1684. * following:
  1685. * <pre>
  1686. * [this] = [Tx] x [this]
  1687. * </pre>
  1688. * @param Tx the <code>AffineTransform</code> object to be
  1689. * concatenated with this <code>AffineTransform</code> object.
  1690. * @see #concatenate
  1691. */
  1692. public void preConcatenate(AffineTransform Tx) {
  1693. double M0, M1;
  1694. double T00, T01, T10, T11;
  1695. double T02, T12;
  1696. int mystate = state;
  1697. int txstate = Tx.state;
  1698. switch ((txstate << HI_SHIFT) | mystate) {
  1699. case (HI_IDENTITY | APPLY_IDENTITY):
  1700. case (HI_IDENTITY | APPLY_TRANSLATE):
  1701. case (HI_IDENTITY | APPLY_SCALE):
  1702. case (HI_IDENTITY | APPLY_SCALE | APPLY_TRANSLATE):
  1703. case (HI_IDENTITY | APPLY_SHEAR):
  1704. case (HI_IDENTITY | APPLY_SHEAR | APPLY_TRANSLATE):
  1705. case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE):
  1706. case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
  1707. // Tx is IDENTITY...
  1708. return;
  1709. case (HI_TRANSLATE | APPLY_IDENTITY):
  1710. case (HI_TRANSLATE | APPLY_SCALE):
  1711. case (HI_TRANSLATE | APPLY_SHEAR):
  1712. case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE):
  1713. // Tx is TRANSLATE, this has no TRANSLATE
  1714. m02 = Tx.m02;
  1715. m12 = Tx.m12;
  1716. state = mystate | APPLY_TRANSLATE;
  1717. type |= TYPE_TRANSLATION;
  1718. return;
  1719. case (HI_TRANSLATE | APPLY_TRANSLATE):
  1720. case (HI_TRANSLATE | APPLY_SCALE | APPLY_TRANSLATE):
  1721. case (HI_TRANSLATE | APPLY_SHEAR | APPLY_TRANSLATE):
  1722. case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
  1723. // Tx is TRANSLATE, this has one too
  1724. m02 = m02 + Tx.m02;
  1725. m12 = m12 + Tx.m12;
  1726. return;
  1727. case (HI_SCALE | APPLY_TRANSLATE):
  1728. case (HI_SCALE | APPLY_IDENTITY):
  1729. // Only these two existing states need a new state
  1730. state = mystate | APPLY_SCALE;
  1731. /* NOBREAK */
  1732. case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
  1733. case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE):
  1734. case (HI_SCALE | APPLY_SHEAR | APPLY_TRANSLATE):
  1735. case (HI_SCALE | APPLY_SHEAR):
  1736. case (HI_SCALE | APPLY_SCALE | APPLY_TRANSLATE):
  1737. case (HI_SCALE | APPLY_SCALE):
  1738. // Tx is SCALE, this is anything
  1739. T00 = Tx.m00;
  1740. T11 = Tx.m11;
  1741. if ((mystate & APPLY_SHEAR) != 0) {
  1742. m01 = m01 * T00;
  1743. m10 = m10 * T11;
  1744. if ((mystate & APPLY_SCALE) != 0) {
  1745. m00 = m00 * T00;
  1746. m11 = m11 * T11;
  1747. }
  1748. } else {
  1749. m00 = m00 * T00;
  1750. m11 = m11 * T11;
  1751. }
  1752. if ((mystate & APPLY_TRANSLATE) != 0) {
  1753. m02 = m02 * T00;
  1754. m12 = m12 * T11;
  1755. }
  1756. type = TYPE_UNKNOWN;
  1757. return;
  1758. case (HI_SHEAR | APPLY_SHEAR | APPLY_TRANSLATE):
  1759. case (HI_SHEAR | APPLY_SHEAR):
  1760. mystate = mystate | APPLY_SCALE;
  1761. /* NOBREAK */
  1762. case (HI_SHEAR | APPLY_TRANSLATE):
  1763. case (HI_SHEAR | APPLY_IDENTITY):
  1764. case (HI_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
  1765. case (HI_SHEAR | APPLY_SCALE):
  1766. state = mystate ^ APPLY_SHEAR;
  1767. /* NOBREAK */
  1768. case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
  1769. case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE):
  1770. // Tx is SHEAR, this is anything
  1771. T01 = Tx.m01;
  1772. T10 = Tx.m10;
  1773. M0 = m00;
  1774. m00 = m10 * T01;
  1775. m10 = M0 * T10;
  1776. M0 = m01;
  1777. m01 = m11 * T01;
  1778. m11 = M0 * T10;
  1779. M0 = m02;
  1780. m02 = m12 * T01;
  1781. m12 = M0 * T10;
  1782. type = TYPE_UNKNOWN;
  1783. return;
  1784. }
  1785. // If Tx has more than one attribute, it is not worth optimizing
  1786. // all of those cases...
  1787. T00 = Tx.m00; T01 = Tx.m01; T02 = Tx.m02;
  1788. T10 = Tx.m10; T11 = Tx.m11; T12 = Tx.m12;
  1789. switch (mystate) {
  1790. default:
  1791. stateError();
  1792. /* NOTREACHED */
  1793. case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
  1794. M0 = m02;
  1795. M1 = m12;
  1796. T02 += M0 * T00 + M1 * T01;
  1797. T12 += M0 * T10 + M1 * T11;
  1798. /* NOBREAK */
  1799. case (APPLY_SHEAR | APPLY_SCALE):
  1800. m02 = T02;
  1801. m12 = T12;
  1802. M0 = m00;
  1803. M1 = m10;
  1804. m00 = M0 * T00 + M1 * T01;
  1805. m10 = M0 * T10 + M1 * T11;
  1806. M0 = m01;
  1807. M1 = m11;
  1808. m01 = M0 * T00 + M1 * T01;
  1809. m11 = M0 * T10 + M1 * T11;
  1810. break;
  1811. case (APPLY_SHEAR | APPLY_TRANSLATE):
  1812. M0 = m02;
  1813. M1 = m12;
  1814. T02 += M0 * T00 + M1 * T01;
  1815. T12 += M0 * T10 + M1 * T11;
  1816. /* NOBREAK */
  1817. case (APPLY_SHEAR):
  1818. m02 = T02;
  1819. m12 = T12;
  1820. M0 = m10;
  1821. m00 = M0 * T01;
  1822. m10 = M0 * T11;
  1823. M0 = m01;
  1824. m01 = M0 * T00;
  1825. m11 = M0 * T10;
  1826. break;
  1827. case (APPLY_SCALE | APPLY_TRANSLATE):
  1828. M0 = m02;
  1829. M1 = m12;
  1830. T02 += M0 * T00 + M1 * T01;
  1831. T12 += M0 * T10 + M1 * T11;
  1832. /* NOBREAK */
  1833. case (APPLY_SCALE):
  1834. m02 = T02;
  1835. m12 = T12;
  1836. M0 = m00;
  1837. m00 = M0 * T00;
  1838. m10 = M0 * T10;
  1839. M0 = m11;
  1840. m01 = M0 * T01;
  1841. m11 = M0 * T11;
  1842. break;
  1843. case (APPLY_TRANSLATE):
  1844. M0 = m02;
  1845. M1 = m12;
  1846. T02 += M0 * T00 + M1 * T01;
  1847. T12 += M0 * T10 + M1 * T11;
  1848. /* NOBREAK */
  1849. case (APPLY_IDENTITY):
  1850. m02 = T02;
  1851. m12 = T12;
  1852. m00 = T00;
  1853. m10 = T10;
  1854. m01 = T01;
  1855. m11 = T11;
  1856. state = mystate | txstate;
  1857. type = TYPE_UNKNOWN;
  1858. return;
  1859. }
  1860. updateState();
  1861. }
  1862. /**
  1863. * Returns an <code>AffineTransform</code> object representing the
  1864. * inverse transformation.
  1865. * The inverse transform Tx' of this transform Tx
  1866. * maps coordinates transformed by Tx back
  1867. * to their original coordinates.
  1868. * In other words, Tx'(Tx(p)) = p = Tx(Tx'(p)).
  1869. * <p>
  1870. * If this transform maps all coordinates onto a point or a line
  1871. * then it will not have an inverse, since coordinates that do
  1872. * not lie on the destination point or line will not have an inverse
  1873. * mapping.
  1874. * The <code>getDeterminant</code> method can be used to determine if this
  1875. * transform has no inverse, in which case an exception will be
  1876. * thrown if the <code>createInverse</code> method is called.
  1877. * @return a new <code>AffineTransform</code> object representing the
  1878. * inverse transformation.
  1879. * @see #getDeterminant
  1880. * @exception NoninvertibleTransformException
  1881. * if the matrix cannot be inverted.
  1882. */
  1883. public AffineTransform createInverse()
  1884. throws NoninvertibleTransformException
  1885. {
  1886. double det;
  1887. switch (state) {
  1888. default:
  1889. stateError();
  1890. /* NOTREACHED */
  1891. case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
  1892. det = m00 * m11 - m01 * m10;
  1893. if (Math.abs(det) <= Double.MIN_VALUE) {
  1894. throw new NoninvertibleTransformException("Determinant is "+
  1895. det);
  1896. }
  1897. return new AffineTransform( m11 / det, -m10 / det,
  1898. -m01 / det, m00 / det,
  1899. (m01 * m12 - m11 * m02) / det,
  1900. (m10 * m02 - m00 * m12) / det,
  1901. (APPLY_SHEAR |
  1902. APPLY_SCALE |
  1903. APPLY_TRANSLATE));
  1904. case (APPLY_SHEAR | APPLY_SCALE):
  1905. det = m00 * m11 - m01 * m10;
  1906. if (Math.abs(det) <= Double.MIN_VALUE) {
  1907. throw new NoninvertibleTransformException("Determinant is "+
  1908. det);
  1909. }
  1910. return new AffineTransform( m11 / det, -m10 / det,
  1911. -m01 / det, m00 / det,
  1912. 0.0, 0.0,
  1913. (APPLY_SHEAR | APPLY_SCALE));
  1914. case (APPLY_SHEAR | APPLY_TRANSLATE):
  1915. if (m01 == 0.0 || m10 == 0.0) {
  1916. throw new NoninvertibleTransformException("Determinant is 0");
  1917. }
  1918. return new AffineTransform( 0.0, 1.0 / m01,
  1919. 1.0 / m10, 0.0,
  1920. -m12 / m10, -m02 / m01,
  1921. (APPLY_SHEAR | APPLY_TRANSLATE));
  1922. case (APPLY_SHEAR):
  1923. if (m01 == 0.0 || m10 == 0.0) {
  1924. throw new NoninvertibleTransformException("Determinant is 0");
  1925. }
  1926. return new AffineTransform(0.0, 1.0 / m01,
  1927. 1.0 / m10, 0.0,
  1928. 0.0, 0.0,
  1929. (APPLY_SHEAR));
  1930. case (APPLY_SCALE | APPLY_TRANSLATE):
  1931. if (m00 == 0.0 || m11 == 0.0) {
  1932. throw new NoninvertibleTransformException("Determinant is 0");
  1933. }
  1934. return new AffineTransform( 1.0 / m00, 0.0,
  1935. 0.0, 1.0 / m11,
  1936. -m02 / m00, -m12 / m11,
  1937. (APPLY_SCALE | APPLY_TRANSLATE));
  1938. case (APPLY_SCALE):
  1939. if (m00 == 0.0 || m11 == 0.0) {
  1940. throw new NoninvertibleTransformException("Determinant is 0");
  1941. }
  1942. return new AffineTransform(1.0 / m00, 0.0,
  1943. 0.0, 1.0 / m11,
  1944. 0.0, 0.0,
  1945. (APPLY_SCALE));
  1946. case (APPLY_TRANSLATE):
  1947. return new AffineTransform( 1.0, 0.0,
  1948. 0.0, 1.0,
  1949. -m02, -m12,
  1950. (APPLY_TRANSLATE));
  1951. case (APPLY_IDENTITY):
  1952. return new AffineTransform();
  1953. }
  1954. /* NOTREACHED */
  1955. }
  1956. /**
  1957. * Transforms the specified <code>ptSrc</code> and stores the result
  1958. * in <code>ptDst</code>.
  1959. * If <code>ptDst</code> is <code>null</code>, a new {@link Point2D}
  1960. * object is allocated and then the result of the transformation is
  1961. * stored in this object.
  1962. * In either case, <code>ptDst</code>, which contains the
  1963. * transformed point, is returned for convenience.
  1964. * If <code>ptSrc</code> and <code>ptDst</code> are the same
  1965. * object, the input point is correctly overwritten with
  1966. * the transformed point.
  1967. * @param ptSrc the specified <code>Point2D</code> to be transformed
  1968. * @param ptDst the specified <code>Point2D</code> that stores the
  1969. * result of transforming <code>ptSrc</code>
  1970. * @return the <code>ptDst</code> after transforming
  1971. * <code>ptSrc</code> and stroring the result in <code>ptDst</code>.
  1972. */
  1973. public Point2D transform(Point2D ptSrc, Point2D ptDst) {
  1974. if (ptDst == null) {
  1975. if (ptSrc instanceof Point2D.Double) {
  1976. ptDst = new Point2D.Double();
  1977. } else {
  1978. ptDst = new Point2D.Float();
  1979. }
  1980. }
  1981. // Copy source coords into local variables in case src == dst
  1982. double x = ptSrc.getX();
  1983. double y = ptSrc.getY();
  1984. switch (state) {
  1985. default:
  1986. stateError();
  1987. /* NOTREACHED */
  1988. case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
  1989. ptDst.setLocation(x * m00 + y * m01 + m02,
  1990. x * m10 + y * m11 + m12);
  1991. return ptDst;
  1992. case (APPLY_SHEAR | APPLY_SCALE):
  1993. ptDst.setLocation(x * m00 + y * m01, x * m10 + y * m11);
  1994. return ptDst;
  1995. case (APPLY_SHEAR | APPLY_TRANSLATE):
  1996. ptDst.setLocation(y * m01 + m02, x * m10 + m12);
  1997. return ptDst;
  1998. case (APPLY_SHEAR):
  1999. ptDst.setLocation(y * m01, x * m10);
  2000. return ptDst;
  2001. case (APPLY_SCALE | APPLY_TRANSLATE):
  2002. ptDst.setLocation(x * m00 + m02, y * m11 + m12);
  2003. return ptDst;
  2004. case (APPLY_SCALE):
  2005. ptDst.setLocation(x * m00, y * m11);
  2006. return ptDst;
  2007. case (APPLY_TRANSLATE):
  2008. ptDst.setLocation(x + m02, y + m12);
  2009. return ptDst;
  2010. case (APPLY_IDENTITY):
  2011. ptDst.setLocation(x, y);
  2012. return ptDst;
  2013. }
  2014. /* NOTREACHED */
  2015. }
  2016. /**
  2017. * Transforms an array of point objects by this transform.
  2018. * If any element of the <code>ptDst</code> array is
  2019. * <code>null</code>, a new <code>Point2D</code> object is allocated
  2020. * and stored into that element before storing the results of the
  2021. * transformation.
  2022. * <p>
  2023. * Note that this method does not take any precautions to
  2024. * avoid problems caused by storing results into <code>Point2D</code>
  2025. * objects that will be used as the source for calculations
  2026. * further down the source array.
  2027. * This method does guarantee that if a specified <code>Point2D</code>
  2028. * object is both the source and destination for the same single point
  2029. * transform operation then the results will not be stored until
  2030. * the calculations are complete to avoid storing the results on
  2031. * top of the operands.
  2032. * If, however, the destination <code>Point2D</code> object for one
  2033. * operation is the same object as the source <code>Point2D</code>
  2034. * object for another operation further down the source array then
  2035. * the original coordinates in that point are overwritten before
  2036. * they can be converted.
  2037. * @param ptSrc the array containing the source point objects
  2038. * @param ptDst the array into which the transform point objects are
  2039. * returned
  2040. * @param srcOff the offset to the first point object to be
  2041. * transformed in the source array
  2042. * @param dstOff the offset to the location of the first
  2043. * transformed point object that is stored in the destination array
  2044. * @param numPts the number of point objects to be transformed
  2045. */
  2046. public void transform(Point2D[] ptSrc, int srcOff,
  2047. Point2D[] ptDst, int dstOff,
  2048. int numPts) {
  2049. int state = this.state;
  2050. while (--numPts >= 0) {
  2051. // Copy source coords into local variables in case src == dst
  2052. Point2D src = ptSrc[srcOff++];
  2053. double x = src.getX();
  2054. double y = src.getY();
  2055. Point2D dst = ptDst[dstOff++];
  2056. if (dst == null) {
  2057. if (src instanceof Point2D.Double) {
  2058. dst = new Point2D.Double();
  2059. } else {
  2060. dst = new Point2D.Float();
  2061. }
  2062. ptDst[dstOff - 1] = dst;
  2063. }
  2064. switch (state) {
  2065. default:
  2066. stateError();
  2067. /* NOTREACHED */
  2068. case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
  2069. dst.setLocation(x * m00 + y * m01 + m02,
  2070. x * m10 + y * m11 + m12);
  2071. break;
  2072. case (APPLY_SHEAR | APPLY_SCALE):
  2073. dst.setLocation(x * m00 + y * m01, x * m10 + y * m11);
  2074. break;
  2075. case (APPLY_SHEAR | APPLY_TRANSLATE):
  2076. dst.setLocation(y * m01 + m02, x * m10 + m12);
  2077. break;
  2078. case (APPLY_SHEAR):
  2079. dst.setLocation(y * m01, x * m10);
  2080. break;
  2081. case (APPLY_SCALE | APPLY_TRANSLATE):
  2082. dst.setLocation(x * m00 + m02, y * m11 + m12);
  2083. break;
  2084. case (APPLY_SCALE):
  2085. dst.setLocation(x * m00, y * m11);
  2086. break;
  2087. case (APPLY_TRANSLATE):
  2088. dst.setLocation(x + m02, y + m12);
  2089. break;
  2090. case (APPLY_IDENTITY):
  2091. dst.setLocation(x, y);
  2092. break;
  2093. }
  2094. }
  2095. /* NOTREACHED */
  2096. }
  2097. /**
  2098. * Transforms an array of floating point coordinates by this transform.
  2099. * The two coordinate array sections can be exactly the same or
  2100. * can be overlapping sections of the same array without affecting the
  2101. * validity of the results.
  2102. * This method ensures that no source coordinates are overwritten by a
  2103. * previous operation before they can be transformed.
  2104. * The coordinates are stored in the arrays starting at the specified
  2105. * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
  2106. * @param srcPts the array containing the source point coordinates.
  2107. * Each point is stored as a pair of x, y coordinates.
  2108. * @param dstPts the array into which the transformed point coordinates
  2109. * are returned. Each point is stored as a pair of x, y
  2110. * coordinates.
  2111. * @param srcOff the offset to the first point to be transformed
  2112. * in the source array
  2113. * @param dstOff the offset to the location of the first
  2114. * transformed point that is stored in the destination array
  2115. * @param numPts the number of points to be transformed
  2116. */
  2117. public void transform(float[] srcPts, int srcOff,
  2118. float[] dstPts, int dstOff,
  2119. int numPts) {
  2120. double M00, M01, M02, M10, M11, M12; // For caching
  2121. if (dstPts == srcPts &&
  2122. dstOff > srcOff && dstOff < srcOff + numPts * 2)
  2123. {
  2124. // If the arrays overlap partially with the destination higher
  2125. // than the source and we transform the coordinates normally
  2126. // we would overwrite some of the later source coordinates
  2127. // with results of previous transformations.
  2128. // To get around this we use arraycopy to copy the points
  2129. // to their final destination with correct overwrite
  2130. // handling and then transform them in place in the new
  2131. // safer location.
  2132. System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts * 2);
  2133. // srcPts = dstPts; // They are known to be equal.
  2134. srcOff = dstOff;
  2135. }
  2136. switch (state) {
  2137. default:
  2138. stateError();
  2139. /* NOTREACHED */
  2140. case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
  2141. M00 = m00; M01 = m01; M02 = m02;
  2142. M10 = m10; M11 = m11; M12 = m12;
  2143. while (--numPts >= 0) {
  2144. double x = srcPts[srcOff++];
  2145. double y = srcPts[srcOff++];
  2146. dstPts[dstOff++] = (float) (M00 * x + M01 * y + M02);
  2147. dstPts[dstOff++] = (float) (M10 * x + M11 * y + M12);
  2148. }
  2149. return;
  2150. case (APPLY_SHEAR | APPLY_SCALE):
  2151. M00 = m00; M01 = m01;
  2152. M10 = m10; M11 = m11;
  2153. while (--numPts >= 0) {
  2154. double x = srcPts[srcOff++];
  2155. double y = srcPts[srcOff++];
  2156. dstPts[dstOff++] = (float) (M00 * x + M01 * y);
  2157. dstPts[dstOff++] = (float) (M10 * x + M11 * y);
  2158. }
  2159. return;
  2160. case (APPLY_SHEAR | APPLY_TRANSLATE):
  2161. M01 = m01; M02 = m02;
  2162. M10 = m10; M12 = m12;
  2163. while (--numPts >= 0) {
  2164. double x = srcPts[srcOff++];
  2165. dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++] + M02);
  2166. dstPts[dstOff++] = (float) (M10 * x + M12);
  2167. }
  2168. return;
  2169. case (APPLY_SHEAR):
  2170. M01 = m01; M10 = m10;
  2171. while (--numPts >= 0) {
  2172. double x = srcPts[srcOff++];
  2173. dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++]);
  2174. dstPts[dstOff++] = (float) (M10 * x);
  2175. }
  2176. return;
  2177. case (APPLY_SCALE | APPLY_TRANSLATE):
  2178. M00 = m00; M02 = m02;
  2179. M11 = m11; M12 = m12;
  2180. while (--numPts >= 0) {
  2181. dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++] + M02);
  2182. dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++] + M12);
  2183. }
  2184. return;
  2185. case (APPLY_SCALE):
  2186. M00 = m00; M11 = m11;
  2187. while (--numPts >= 0) {
  2188. dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++]);
  2189. dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++]);
  2190. }
  2191. return;
  2192. case (APPLY_TRANSLATE):
  2193. M02 = m02; M12 = m12;
  2194. while (--numPts >= 0) {
  2195. dstPts[dstOff++] = (float) (srcPts[srcOff++] + M02);
  2196. dstPts[dstOff++] = (float) (srcPts[srcOff++] + M12);
  2197. }
  2198. return;
  2199. case (APPLY_IDENTITY):
  2200. if (srcPts != dstPts || srcOff != dstOff) {
  2201. System.arraycopy(srcPts, srcOff, dstPts, dstOff,
  2202. numPts * 2);
  2203. }
  2204. return;
  2205. }
  2206. /* NOTREACHED */
  2207. }
  2208. /**
  2209. * Transforms an array of double precision coordinates by this transform.
  2210. * The two coordinate array sections can be exactly the same or
  2211. * can be overlapping sections of the same array without affecting the
  2212. * validity of the results.
  2213. * This method ensures that no source coordinates are
  2214. * overwritten by a previous operation before they can be transformed.
  2215. * The coordinates are stored in the arrays starting at the indicated
  2216. * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
  2217. * @param srcPts the array containing the source point coordinates.
  2218. * Each point is stored as a pair of x, y coordinates.
  2219. * @param dstPts the array into which the transformed point
  2220. * coordinates are returned. Each point is stored as a pair of
  2221. * x, y coordinates.
  2222. * @param srcOff the offset to the first point to be transformed
  2223. * in the source array
  2224. * @param dstOff the offset to the location of the first
  2225. * transformed point that is stored in the destination array
  2226. * @param numPts the number of point objects to be transformed
  2227. */
  2228. public void transform(double[] srcPts, int srcOff,
  2229. double[] dstPts, int dstOff,
  2230. int numPts) {
  2231. double M00, M01, M02, M10, M11, M12; // For caching
  2232. if (dstPts == srcPts &&
  2233. dstOff > srcOff && dstOff < srcOff + numPts * 2)
  2234. {
  2235. // If the arrays overlap partially with the destination higher
  2236. // than the source and we transform the coordinates normally
  2237. // we would overwrite some of the later source coordinates
  2238. // with results of previous transformations.
  2239. // To get around this we use arraycopy to copy the points
  2240. // to their final destination with correct overwrite
  2241. // handling and then transform them in place in the new
  2242. // safer location.
  2243. System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts * 2);
  2244. // srcPts = dstPts; // They are known to be equal.
  2245. srcOff = dstOff;
  2246. }
  2247. switch (state) {
  2248. default:
  2249. stateError();
  2250. /* NOTREACHED */
  2251. case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
  2252. M00 = m00; M01 = m01; M02 = m02;
  2253. M10 = m10; M11 = m11; M12 = m12;
  2254. while (--numPts >= 0) {
  2255. double x = srcPts[srcOff++];
  2256. double y = srcPts[srcOff++];
  2257. dstPts[dstOff++] = M00 * x + M01 * y + M02;
  2258. dstPts[dstOff++] = M10 * x + M11 * y + M12;
  2259. }
  2260. return;
  2261. case (APPLY_SHEAR | APPLY_SCALE):
  2262. M00 = m00; M01 = m01;
  2263. M10 = m10; M11 = m11;
  2264. while (--numPts >= 0) {
  2265. double x = srcPts[srcOff++];
  2266. double y = srcPts[srcOff++];
  2267. dstPts[dstOff++] = M00 * x + M01 * y;
  2268. dstPts[dstOff++] = M10 * x + M11 * y;
  2269. }
  2270. return;
  2271. case (APPLY_SHEAR | APPLY_TRANSLATE):
  2272. M01 = m01; M02 = m02;
  2273. M10 = m10; M12 = m12;
  2274. while (--numPts >= 0) {
  2275. double x = srcPts[srcOff++];
  2276. dstPts[dstOff++] = M01 * srcPts[srcOff++] + M02;
  2277. dstPts[dstOff++] = M10 * x + M12;
  2278. }
  2279. return;
  2280. case (APPLY_SHEAR):
  2281. M01 = m01; M10 = m10;
  2282. while (--numPts >= 0) {
  2283. double x = srcPts[srcOff++];
  2284. dstPts[dstOff++] = M01 * srcPts[srcOff++];
  2285. dstPts[dstOff++] = M10 * x;
  2286. }
  2287. return;
  2288. case (APPLY_SCALE | APPLY_TRANSLATE):
  2289. M00 = m00; M02 = m02;
  2290. M11 = m11; M12 = m12;
  2291. while (--numPts >= 0) {
  2292. dstPts[dstOff++] = M00 * srcPts[srcOff++] + M02;
  2293. dstPts[dstOff++] = M11 * srcPts[srcOff++] + M12;
  2294. }
  2295. return;
  2296. case (APPLY_SCALE):
  2297. M00 = m00; M11 = m11;
  2298. while (--numPts >= 0) {
  2299. dstPts[dstOff++] = M00 * srcPts[srcOff++];
  2300. dstPts[dstOff++] = M11 * srcPts[srcOff++];
  2301. }
  2302. return;
  2303. case (APPLY_TRANSLATE):
  2304. M02 = m02; M12 = m12;
  2305. while (--numPts >= 0) {
  2306. dstPts[dstOff++] = srcPts[srcOff++] + M02;
  2307. dstPts[dstOff++] = srcPts[srcOff++] + M12;
  2308. }
  2309. return;
  2310. case (APPLY_IDENTITY):
  2311. if (srcPts != dstPts || srcOff != dstOff) {
  2312. System.arraycopy(srcPts, srcOff, dstPts, dstOff,
  2313. numPts * 2);
  2314. }
  2315. return;
  2316. }
  2317. /* NOTREACHED */
  2318. }
  2319. /**
  2320. * Transforms an array of floating point coordinates by this transform
  2321. * and stores the results into an array of doubles.
  2322. * The coordinates are stored in the arrays starting at the specified
  2323. * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
  2324. * @param srcPts the array containing the source point coordinates.
  2325. * Each point is stored as a pair of x, y coordinates.
  2326. * @param dstPts the array into which the transformed point coordinates
  2327. * are returned. Each point is stored as a pair of x, y
  2328. * coordinates.
  2329. * @param srcOff the offset to the first point to be transformed
  2330. * in the source array
  2331. * @param dstOff the offset to the location of the first
  2332. * transformed point that is stored in the destination array
  2333. * @param numPts the number of points to be transformed
  2334. */
  2335. public void transform(float[] srcPts, int srcOff,
  2336. double[] dstPts, int dstOff,
  2337. int numPts) {
  2338. double M00, M01, M02, M10, M11, M12; // For caching
  2339. switch (state) {
  2340. default:
  2341. stateError();
  2342. /* NOTREACHED */
  2343. case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
  2344. M00 = m00; M01 = m01; M02 = m02;
  2345. M10 = m10; M11 = m11; M12 = m12;
  2346. while (--numPts >= 0) {
  2347. double x = srcPts[srcOff++];
  2348. double y = srcPts[srcOff++];
  2349. dstPts[dstOff++] = M00 * x + M01 * y + M02;
  2350. dstPts[dstOff++] = M10 * x + M11 * y + M12;
  2351. }
  2352. return;
  2353. case (APPLY_SHEAR | APPLY_SCALE):
  2354. M00 = m00; M01 = m01;
  2355. M10 = m10; M11 = m11;
  2356. while (--numPts >= 0) {
  2357. double x = srcPts[srcOff++];
  2358. double y = srcPts[srcOff++];
  2359. dstPts[dstOff++] = M00 * x + M01 * y;
  2360. dstPts[dstOff++] = M10 * x + M11 * y;
  2361. }
  2362. return;
  2363. case (APPLY_SHEAR | APPLY_TRANSLATE):
  2364. M01 = m01; M02 = m02;
  2365. M10 = m10; M12 = m12;
  2366. while (--numPts >= 0) {
  2367. double x = srcPts[srcOff++];
  2368. dstPts[dstOff++] = M01 * srcPts[srcOff++] + M02;
  2369. dstPts[dstOff++] = M10 * x + M12;
  2370. }
  2371. return;
  2372. case (APPLY_SHEAR):
  2373. M01 = m01; M10 = m10;
  2374. while (--numPts >= 0) {
  2375. double x = srcPts[srcOff++];
  2376. dstPts[dstOff++] = M01 * srcPts[srcOff++];
  2377. dstPts[dstOff++] = M10 * x;
  2378. }
  2379. return;
  2380. case (APPLY_SCALE | APPLY_TRANSLATE):
  2381. M00 = m00; M02 = m02;
  2382. M11 = m11; M12 = m12;
  2383. while (--numPts >= 0) {
  2384. dstPts[dstOff++] = M00 * srcPts[srcOff++] + M02;
  2385. dstPts[dstOff++] = M11 * srcPts[srcOff++] + M12;
  2386. }
  2387. return;
  2388. case (APPLY_SCALE):
  2389. M00 = m00; M11 = m11;
  2390. while (--numPts >= 0) {
  2391. dstPts[dstOff++] = M00 * srcPts[srcOff++];
  2392. dstPts[dstOff++] = M11 * srcPts[srcOff++];
  2393. }
  2394. return;
  2395. case (APPLY_TRANSLATE):
  2396. M02 = m02; M12 = m12;
  2397. while (--numPts >= 0) {
  2398. dstPts[dstOff++] = srcPts[srcOff++] + M02;
  2399. dstPts[dstOff++] = srcPts[srcOff++] + M12;
  2400. }
  2401. return;
  2402. case (APPLY_IDENTITY):
  2403. while (--numPts >= 0) {
  2404. dstPts[dstOff++] = srcPts[srcOff++];
  2405. dstPts[dstOff++] = srcPts[srcOff++];
  2406. }
  2407. return;
  2408. }
  2409. /* NOTREACHED */
  2410. }
  2411. /**
  2412. * Transforms an array of double precision coordinates by this transform
  2413. * and stores the results into an array of floats.
  2414. * The coordinates are stored in the arrays starting at the specified
  2415. * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
  2416. * @param srcPts the array containing the source point coordinates.
  2417. * Each point is stored as a pair of x, y coordinates.
  2418. * @param dstPts the array into which the transformed point
  2419. * coordinates are returned. Each point is stored as a pair of
  2420. * x, y coordinates.
  2421. * @param srcOff the offset to the first point to be transformed
  2422. * in the source array
  2423. * @param dstOff the offset to the location of the first
  2424. * transformed point that is stored in the destination array
  2425. * @param numPts the number of point objects to be transformed
  2426. */
  2427. public void transform(double[] srcPts, int srcOff,
  2428. float[] dstPts, int dstOff,
  2429. int numPts) {
  2430. double M00, M01, M02, M10, M11, M12; // For caching
  2431. switch (state) {
  2432. default:
  2433. stateError();
  2434. /* NOTREACHED */
  2435. case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
  2436. M00 = m00; M01 = m01; M02 = m02;
  2437. M10 = m10; M11 = m11; M12 = m12;
  2438. while (--numPts >= 0) {
  2439. double x = srcPts[srcOff++];
  2440. double y = srcPts[srcOff++];
  2441. dstPts[dstOff++] = (float) (M00 * x + M01 * y + M02);
  2442. dstPts[dstOff++] = (float) (M10 * x + M11 * y + M12);
  2443. }
  2444. return;
  2445. case (APPLY_SHEAR | APPLY_SCALE):
  2446. M00 = m00; M01 = m01;
  2447. M10 = m10; M11 = m11;
  2448. while (--numPts >= 0) {
  2449. double x = srcPts[srcOff++];
  2450. double y = srcPts[srcOff++];
  2451. dstPts[dstOff++] = (float) (M00 * x + M01 * y);
  2452. dstPts[dstOff++] = (float) (M10 * x + M11 * y);
  2453. }
  2454. return;
  2455. case (APPLY_SHEAR | APPLY_TRANSLATE):
  2456. M01 = m01; M02 = m02;
  2457. M10 = m10; M12 = m12;
  2458. while (--numPts >= 0) {
  2459. double x = srcPts[srcOff++];
  2460. dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++] + M02);
  2461. dstPts[dstOff++] = (float) (M10 * x + M12);
  2462. }
  2463. return;
  2464. case (APPLY_SHEAR):
  2465. M01 = m01; M10 = m10;
  2466. while (--numPts >= 0) {
  2467. double x = srcPts[srcOff++];
  2468. dstPts[dstOff++] = (float) (M01 * srcPts[srcOff++]);
  2469. dstPts[dstOff++] = (float) (M10 * x);
  2470. }
  2471. return;
  2472. case (APPLY_SCALE | APPLY_TRANSLATE):
  2473. M00 = m00; M02 = m02;
  2474. M11 = m11; M12 = m12;
  2475. while (--numPts >= 0) {
  2476. dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++] + M02);
  2477. dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++] + M12);
  2478. }
  2479. return;
  2480. case (APPLY_SCALE):
  2481. M00 = m00; M11 = m11;
  2482. while (--numPts >= 0) {
  2483. dstPts[dstOff++] = (float) (M00 * srcPts[srcOff++]);
  2484. dstPts[dstOff++] = (float) (M11 * srcPts[srcOff++]);
  2485. }
  2486. return;
  2487. case (APPLY_TRANSLATE):
  2488. M02 = m02; M12 = m12;
  2489. while (--numPts >= 0) {
  2490. dstPts[dstOff++] = (float) (srcPts[srcOff++] + M02);
  2491. dstPts[dstOff++] = (float) (srcPts[srcOff++] + M12);
  2492. }
  2493. return;
  2494. case (APPLY_IDENTITY):
  2495. while (--numPts >= 0) {
  2496. dstPts[dstOff++] = (float) (srcPts[srcOff++]);
  2497. dstPts[dstOff++] = (float) (srcPts[srcOff++]);
  2498. }
  2499. return;
  2500. }
  2501. /* NOTREACHED */
  2502. }
  2503. /**
  2504. * Inverse transforms the specified <code>ptSrc</code> and stores the
  2505. * result in <code>ptDst</code>.
  2506. * If <code>ptDst</code> is <code>null</code>, a new
  2507. * <code>Point2D</code> object is allocated and then the result of the
  2508. * transform is stored in this object.
  2509. * In either case, <code>ptDst</code>, which contains the transformed
  2510. * point, is returned for convenience.
  2511. * If <code>ptSrc</code> and <code>ptDst</code> are the same
  2512. * object, the input point is correctly overwritten with the
  2513. * transformed point.
  2514. * @param ptSrc the point to be inverse transformed
  2515. * @param ptDst the resulting transformed point
  2516. * @return <code>ptDst</code>, which contains the result of the
  2517. * inverse transform.
  2518. * @exception NoninvertibleTransformException if the matrix cannot be
  2519. * inverted.
  2520. */
  2521. public Point2D inverseTransform(Point2D ptSrc, Point2D ptDst)
  2522. throws NoninvertibleTransformException
  2523. {
  2524. if (ptDst == null) {
  2525. if (ptSrc instanceof Point2D.Double) {
  2526. ptDst = new Point2D.Double();
  2527. } else {
  2528. ptDst = new Point2D.Float();
  2529. }
  2530. }
  2531. // Copy source coords into local variables in case src == dst
  2532. double x = ptSrc.getX();
  2533. double y = ptSrc.getY();
  2534. switch (state) {
  2535. default:
  2536. stateError();
  2537. /* NOTREACHED */
  2538. case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
  2539. x -= m02;
  2540. y -= m12;
  2541. /* NOBREAK */
  2542. case (APPLY_SHEAR | APPLY_SCALE):
  2543. double det = m00 * m11 - m01 * m10;
  2544. if (Math.abs(det) <= Double.MIN_VALUE) {
  2545. throw new NoninvertibleTransformException("Determinant is "+
  2546. det);
  2547. }
  2548. ptDst.setLocation((x * m11 - y * m01) / det,
  2549. (y * m00 - x * m10) / det);
  2550. return ptDst;
  2551. case (APPLY_SHEAR | APPLY_TRANSLATE):
  2552. x -= m02;
  2553. y -= m12;
  2554. /* NOBREAK */
  2555. case (APPLY_SHEAR):
  2556. if (m01 == 0.0 || m10 == 0.0) {
  2557. throw new NoninvertibleTransformException("Determinant is 0");
  2558. }
  2559. ptDst.setLocation(y / m10, x / m01);
  2560. return ptDst;
  2561. case (APPLY_SCALE | APPLY_TRANSLATE):
  2562. x -= m02;
  2563. y -= m12;
  2564. /* NOBREAK */
  2565. case (APPLY_SCALE):
  2566. if (m00 == 0.0 || m11 == 0.0) {
  2567. throw new NoninvertibleTransformException("Determinant is 0");
  2568. }
  2569. ptDst.setLocation(x / m00, y / m11);
  2570. return ptDst;
  2571. case (APPLY_TRANSLATE):
  2572. ptDst.setLocation(x - m02, y - m12);
  2573. return ptDst;
  2574. case (APPLY_IDENTITY):
  2575. ptDst.setLocation(x, y);
  2576. return ptDst;
  2577. }
  2578. /* NOTREACHED */
  2579. }
  2580. /**
  2581. * Inverse transforms an array of double precision coordinates by
  2582. * this transform.
  2583. * The two coordinate array sections can be exactly the same or
  2584. * can be overlapping sections of the same array without affecting the
  2585. * validity of the results.
  2586. * This method ensures that no source coordinates are
  2587. * overwritten by a previous operation before they can be transformed.
  2588. * The coordinates are stored in the arrays starting at the specified
  2589. * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
  2590. * @param srcPts the array containing the source point coordinates.
  2591. * Each point is stored as a pair of x, y coordinates.
  2592. * @param dstPts the array into which the transformed point
  2593. * coordinates are returned. Each point is stored as a pair of
  2594. * x, y coordinates.
  2595. * @param srcOff the offset to the first point to be transformed
  2596. * in the source array
  2597. * @param dstOff the offset to the location of the first
  2598. * transformed point that is stored in the destination array
  2599. * @param numPts the number of point objects to be transformed
  2600. * @exception NoninvertibleTransformException if the matrix cannot be
  2601. * inverted.
  2602. */
  2603. public void inverseTransform(double[] srcPts, int srcOff,
  2604. double[] dstPts, int dstOff,
  2605. int numPts)
  2606. throws NoninvertibleTransformException
  2607. {
  2608. double M00, M01, M02, M10, M11, M12; // For caching
  2609. double det;
  2610. if (dstPts == srcPts &&
  2611. dstOff > srcOff && dstOff < srcOff + numPts * 2)
  2612. {
  2613. // If the arrays overlap partially with the destination higher
  2614. // than the source and we transform the coordinates normally
  2615. // we would overwrite some of the later source coordinates
  2616. // with results of previous transformations.
  2617. // To get around this we use arraycopy to copy the points
  2618. // to their final destination with correct overwrite
  2619. // handling and then transform them in place in the new
  2620. // safer location.
  2621. System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts * 2);
  2622. // srcPts = dstPts; // They are known to be equal.
  2623. srcOff = dstOff;
  2624. }
  2625. switch (state) {
  2626. default:
  2627. stateError();
  2628. /* NOTREACHED */
  2629. case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
  2630. M00 = m00; M01 = m01; M02 = m02;
  2631. M10 = m10; M11 = m11; M12 = m12;
  2632. det = M00 * M11 - M01 * M10;
  2633. if (Math.abs(det) <= Double.MIN_VALUE) {
  2634. throw new NoninvertibleTransformException("Determinant is "+
  2635. det);
  2636. }
  2637. while (--numPts >= 0) {
  2638. double x = srcPts[srcOff++] - M02;
  2639. double y = srcPts[srcOff++] - M12;
  2640. dstPts[dstOff++] = (x * M11 - y * M01) / det;
  2641. dstPts[dstOff++] = (y * M00 - x * M10) / det;
  2642. }
  2643. return;
  2644. case (APPLY_SHEAR | APPLY_SCALE):
  2645. M00 = m00; M01 = m01;
  2646. M10 = m10; M11 = m11;
  2647. det = M00 * M11 - M01 * M10;
  2648. if (Math.abs(det) <= Double.MIN_VALUE) {
  2649. throw new NoninvertibleTransformException("Determinant is "+
  2650. det);
  2651. }
  2652. while (--numPts >= 0) {
  2653. double x = srcPts[srcOff++];
  2654. double y = srcPts[srcOff++];
  2655. dstPts[dstOff++] = (x * M11 - y * M01) / det;
  2656. dstPts[dstOff++] = (y * M00 - x * M10) / det;
  2657. }
  2658. return;
  2659. case (APPLY_SHEAR | APPLY_TRANSLATE):
  2660. M01 = m01; M02 = m02;
  2661. M10 = m10; M12 = m12;
  2662. if (M01 == 0.0 || M10 == 0.0) {
  2663. throw new NoninvertibleTransformException("Determinant is 0");
  2664. }
  2665. while (--numPts >= 0) {
  2666. double x = srcPts[srcOff++] - M02;
  2667. dstPts[dstOff++] = (srcPts[srcOff++] - M12) / M10;
  2668. dstPts[dstOff++] = x / M01;
  2669. }
  2670. return;
  2671. case (APPLY_SHEAR):
  2672. M01 = m01; M10 = m10;
  2673. if (M01 == 0.0 || M10 == 0.0) {
  2674. throw new NoninvertibleTransformException("Determinant is 0");
  2675. }
  2676. while (--numPts >= 0) {
  2677. double x = srcPts[srcOff++];
  2678. dstPts[dstOff++] = srcPts[srcOff++] / M10;
  2679. dstPts[dstOff++] = x / M01;
  2680. }
  2681. return;
  2682. case (APPLY_SCALE | APPLY_TRANSLATE):
  2683. M00 = m00; M02 = m02;
  2684. M11 = m11; M12 = m12;
  2685. if (M00 == 0.0 || M11 == 0.0) {
  2686. throw new NoninvertibleTransformException("Determinant is 0");
  2687. }
  2688. while (--numPts >= 0) {
  2689. dstPts[dstOff++] = (srcPts[srcOff++] - M02) / M00;
  2690. dstPts[dstOff++] = (srcPts[srcOff++] - M12) / M11;
  2691. }
  2692. return;
  2693. case (APPLY_SCALE):
  2694. M00 = m00; M11 = m11;
  2695. if (M00 == 0.0 || M11 == 0.0) {
  2696. throw new NoninvertibleTransformException("Determinant is 0");
  2697. }
  2698. while (--numPts >= 0) {
  2699. dstPts[dstOff++] = srcPts[srcOff++] / M00;
  2700. dstPts[dstOff++] = srcPts[srcOff++] / M11;
  2701. }
  2702. return;
  2703. case (APPLY_TRANSLATE):
  2704. M02 = m02; M12 = m12;
  2705. while (--numPts >= 0) {
  2706. dstPts[dstOff++] = srcPts[srcOff++] - M02;
  2707. dstPts[dstOff++] = srcPts[srcOff++] - M12;
  2708. }
  2709. return;
  2710. case (APPLY_IDENTITY):
  2711. if (srcPts != dstPts || srcOff != dstOff) {
  2712. System.arraycopy(srcPts, srcOff, dstPts, dstOff,
  2713. numPts * 2);
  2714. }
  2715. return;
  2716. }
  2717. /* NOTREACHED */
  2718. }
  2719. /**
  2720. * Transforms the relative distance vector specified by
  2721. * <code>ptSrc</code> and stores the result in <code>ptDst</code>.
  2722. * A relative distance vector is transformed without applying the
  2723. * translation components of the affine transformation matrix
  2724. * using the following equations:
  2725. * <pre>
  2726. * [ x' ] [ m00 m01 (m02) ] [ x ] [ m00x + m01y ]
  2727. * [ y' ] = [ m10 m11 (m12) ] [ y ] = [ m10x + m11y ]
  2728. * [ (1) ] [ (0) (0) ( 1 ) ] [ (1) ] [ (1) ]
  2729. * </pre>
  2730. * If <code>ptDst</code> is <code>null</code>, a new
  2731. * <code>Point2D</code> object is allocated and then the result of the
  2732. * transform is stored in this object.
  2733. * In either case, <code>ptDst</code>, which contains the
  2734. * transformed point, is returned for convenience.
  2735. * If <code>ptSrc</code> and <code>ptDst</code> are the same object,
  2736. * the input point is correctly overwritten with the transformed
  2737. * point.
  2738. * @param ptSrc the distance vector to be delta transformed
  2739. * @param ptDst the resulting transformed distance vector
  2740. * @return <code>ptDst</code>, which contains the result of the
  2741. * transformation.
  2742. */
  2743. public Point2D deltaTransform(Point2D ptSrc, Point2D ptDst) {
  2744. if (ptDst == null) {
  2745. if (ptSrc instanceof Point2D.Double) {
  2746. ptDst = new Point2D.Double();
  2747. } else {
  2748. ptDst = new Point2D.Float();
  2749. }
  2750. }
  2751. // Copy source coords into local variables in case src == dst
  2752. double x = ptSrc.getX();
  2753. double y = ptSrc.getY();
  2754. switch (state) {
  2755. default:
  2756. stateError();
  2757. /* NOTREACHED */
  2758. case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
  2759. case (APPLY_SHEAR | APPLY_SCALE):
  2760. ptDst.setLocation(x * m00 + y * m01, x * m10 + y * m11);
  2761. return ptDst;
  2762. case (APPLY_SHEAR | APPLY_TRANSLATE):
  2763. case (APPLY_SHEAR):
  2764. ptDst.setLocation(y * m01, x * m10);
  2765. return ptDst;
  2766. case (APPLY_SCALE | APPLY_TRANSLATE):
  2767. case (APPLY_SCALE):
  2768. ptDst.setLocation(x * m00, y * m11);
  2769. return ptDst;
  2770. case (APPLY_TRANSLATE):
  2771. case (APPLY_IDENTITY):
  2772. ptDst.setLocation(x, y);
  2773. return ptDst;
  2774. }
  2775. /* NOTREACHED */
  2776. }
  2777. /**
  2778. * Transforms an array of relative distance vectors by this
  2779. * transform.
  2780. * A relative distance vector is transformed without applying the
  2781. * translation components of the affine transformation matrix
  2782. * using the following equations:
  2783. * <pre>
  2784. * [ x' ] [ m00 m01 (m02) ] [ x ] [ m00x + m01y ]
  2785. * [ y' ] = [ m10 m11 (m12) ] [ y ] = [ m10x + m11y ]
  2786. * [ (1) ] [ (0) (0) ( 1 ) ] [ (1) ] [ (1) ]
  2787. * </pre>
  2788. * The two coordinate array sections can be exactly the same or
  2789. * can be overlapping sections of the same array without affecting the
  2790. * validity of the results.
  2791. * This method ensures that no source coordinates are
  2792. * overwritten by a previous operation before they can be transformed.
  2793. * The coordinates are stored in the arrays starting at the indicated
  2794. * offset in the order <code>[x0, y0, x1, y1, ..., xn, yn]</code>.
  2795. * @param srcPts the array containing the source distance vectors.
  2796. * Each vector is stored as a pair of relative x, y coordinates.
  2797. * @param dstPts the array into which the transformed distance vectors
  2798. * are returned. Each vector is stored as a pair of relative
  2799. * x, y coordinates.
  2800. * @param srcOff the offset to the first vector to be transformed
  2801. * in the source array
  2802. * @param dstOff the offset to the location of the first
  2803. * transformed vector that is stored in the destination array
  2804. * @param numPts the number of vector coordinate pairs to be
  2805. * transformed
  2806. */
  2807. public void deltaTransform(double[] srcPts, int srcOff,
  2808. double[] dstPts, int dstOff,
  2809. int numPts) {
  2810. double M00, M01, M10, M11; // For caching
  2811. if (dstPts == srcPts &&
  2812. dstOff > srcOff && dstOff < srcOff + numPts * 2)
  2813. {
  2814. // If the arrays overlap partially with the destination higher
  2815. // than the source and we transform the coordinates normally
  2816. // we would overwrite some of the later source coordinates
  2817. // with results of previous transformations.
  2818. // To get around this we use arraycopy to copy the points
  2819. // to their final destination with correct overwrite
  2820. // handling and then transform them in place in the new
  2821. // safer location.
  2822. System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts * 2);
  2823. // srcPts = dstPts; // They are known to be equal.
  2824. srcOff = dstOff;
  2825. }
  2826. switch (state) {
  2827. default:
  2828. stateError();
  2829. /* NOTREACHED */
  2830. case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
  2831. case (APPLY_SHEAR | APPLY_SCALE):
  2832. M00 = m00; M01 = m01;
  2833. M10 = m10; M11 = m11;
  2834. while (--numPts >= 0) {
  2835. double x = srcPts[srcOff++];
  2836. double y = srcPts[srcOff++];
  2837. dstPts[dstOff++] = x * M00 + y * M01;
  2838. dstPts[dstOff++] = x * M10 + y * M11;
  2839. }
  2840. return;
  2841. case (APPLY_SHEAR | APPLY_TRANSLATE):
  2842. case (APPLY_SHEAR):
  2843. M01 = m01; M10 = m10;
  2844. while (--numPts >= 0) {
  2845. double x = srcPts[srcOff++];
  2846. dstPts[dstOff++] = srcPts[srcOff++] * M01;
  2847. dstPts[dstOff++] = x * M10;
  2848. }
  2849. return;
  2850. case (APPLY_SCALE | APPLY_TRANSLATE):
  2851. case (APPLY_SCALE):
  2852. M00 = m00; M11 = m11;
  2853. while (--numPts >= 0) {
  2854. dstPts[dstOff++] = srcPts[srcOff++] * M00;
  2855. dstPts[dstOff++] = srcPts[srcOff++] * M11;
  2856. }
  2857. return;
  2858. case (APPLY_TRANSLATE):
  2859. case (APPLY_IDENTITY):
  2860. if (srcPts != dstPts || srcOff != dstOff) {
  2861. System.arraycopy(srcPts, srcOff, dstPts, dstOff,
  2862. numPts * 2);
  2863. }
  2864. return;
  2865. }
  2866. /* NOTREACHED */
  2867. }
  2868. /**
  2869. * Returns a new {@link Shape} object defined by the geometry of the
  2870. * specified <code>Shape</code> after it has been transformed by
  2871. * this transform.
  2872. * @param pSrc the specified <code>Shape</code> object to be
  2873. * transformed by this transform.
  2874. * @return a new <code>Shape</code> object that defines the geometry
  2875. * of the transformed <code>Shape</code>.
  2876. */
  2877. public Shape createTransformedShape(Shape pSrc) {
  2878. if (pSrc == null) {
  2879. return null;
  2880. }
  2881. if (pSrc instanceof GeneralPath) {
  2882. return ((GeneralPath)pSrc).createTransformedShape(this);
  2883. } else {
  2884. PathIterator pi = pSrc.getPathIterator(this);
  2885. GeneralPath gp = new GeneralPath(pi.getWindingRule());
  2886. gp.append(pi, false);
  2887. return gp;
  2888. }
  2889. /* NOTREACHED */
  2890. }
  2891. // Round values to sane precision for printing
  2892. // Note that Math.sin(Math.PI) has an error of about 10^-16
  2893. private static double _matround(double matval) {
  2894. return Math.rint(matval * 1E15) / 1E15;
  2895. }
  2896. /**
  2897. * Returns a <code>String</code> that represents the value of this
  2898. * {@link Object}.
  2899. * @return a <code>String</code> representing the value of this
  2900. * <code>Object</code>.
  2901. */
  2902. public String toString() {
  2903. return ("AffineTransform[["
  2904. + _matround(m00) + ", "
  2905. + _matround(m01) + ", "
  2906. + _matround(m02) + "], ["
  2907. + _matround(m10) + ", "
  2908. + _matround(m11) + ", "
  2909. + _matround(m12) + "]]");
  2910. }
  2911. /**
  2912. * Returns <code>true</code> if this <code>AffineTransform</code> is
  2913. * an identity transform.
  2914. * @return <code>true</code> if this <code>AffineTransform</code> is
  2915. * an identity transform; <code>false</code> otherwise.
  2916. */
  2917. public boolean isIdentity() {
  2918. return (state == APPLY_IDENTITY || (getType() == TYPE_IDENTITY));
  2919. }
  2920. /**
  2921. * Returns a copy of this <code>AffineTransform</code> object.
  2922. * @return an <code>Object</code> that is a copy of this
  2923. * <code>AffineTransform</code> object.
  2924. */
  2925. public Object clone() {
  2926. try {
  2927. return super.clone();
  2928. } catch (CloneNotSupportedException e) {
  2929. // this shouldn't happen, since we are Cloneable
  2930. throw new InternalError();
  2931. }
  2932. }
  2933. /**
  2934. * Returns the hashcode for this transform.
  2935. * @return a hash code for this transform.
  2936. */
  2937. public int hashCode() {
  2938. long bits = Double.doubleToLongBits(m00);
  2939. bits = bits * 31 + Double.doubleToLongBits(m01);
  2940. bits = bits * 31 + Double.doubleToLongBits(m02);
  2941. bits = bits * 31 + Double.doubleToLongBits(m10);
  2942. bits = bits * 31 + Double.doubleToLongBits(m11);
  2943. bits = bits * 31 + Double.doubleToLongBits(m12);
  2944. return (((int) bits) ^ ((int) (bits >> 32)));
  2945. }
  2946. /**
  2947. * Returns <code>true</code> if this <code>AffineTransform</code>
  2948. * represents the same affine coordinate transform as the specified
  2949. * argument.
  2950. * @param obj the <code>Object</code> to test for equality with this
  2951. * <code>AffineTransform</code>
  2952. * @return <code>true</code> if <code>obj</code> equals this
  2953. * <code>AffineTransform</code> object; <code>false</code> otherwise.
  2954. */
  2955. public boolean equals(Object obj) {
  2956. if (!(obj instanceof AffineTransform)) {
  2957. return false;
  2958. }
  2959. AffineTransform a = (AffineTransform)obj;
  2960. return ((m00 == a.m00) && (m01 == a.m01) && (m02 == a.m02) &&
  2961. (m10 == a.m10) && (m11 == a.m11) && (m12 == a.m12));
  2962. }
  2963. /* Serialization support. A readObject method is neccessary because
  2964. * the state field is part of the implementation of this particular
  2965. * AffineTransform and not part of the public specification. The
  2966. * state variable's value needs to be recalculated on the fly by the
  2967. * readObject method as it is in the 6-argument matrix constructor.
  2968. */
  2969. private void writeObject(java.io.ObjectOutputStream s)
  2970. throws java.lang.ClassNotFoundException, java.io.IOException
  2971. {
  2972. s.defaultWriteObject();
  2973. }
  2974. private void readObject(java.io.ObjectInputStream s)
  2975. throws java.lang.ClassNotFoundException, java.io.IOException
  2976. {
  2977. s.defaultReadObject();
  2978. updateState();
  2979. }
  2980. }