0001: /*
0002: * $RCSfile: PerspectiveTransform.java,v $
0003: *
0004: * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * Use is subject to license terms.
0007: *
0008: * $Revision: 1.1 $
0009: * $Date: 2005/02/11 04:57:15 $
0010: * $State: Exp $
0011: */
0012: package javax.media.jai;
0013:
0014: import java.awt.geom.AffineTransform;
0015: import java.awt.geom.Point2D;
0016: import java.awt.geom.NoninvertibleTransformException;
0017: import java.io.Serializable;
0018:
0019: /**
0020: * A 2D perspective (or projective) transform, used by various OpImages.
0021: *
0022: * <p> A perspective transformation is capable of mapping an arbitrary
0023: * quadrilateral into another arbitrary quadrilateral, while
0024: * preserving the straightness of lines. Unlike an affine
0025: * transformation, the parallelism of lines in the source is not
0026: * necessarily preserved in the output.
0027: *
0028: * <p> Such a coordinate transformation can be represented by a 3x3
0029: * matrix which transforms homogenous source coordinates
0030: * <code>(x, y, 1)</code> into destination coordinates
0031: * <code>(x', y', w)</code>. To convert back into non-homogenous
0032: * coordinates (X, Y), <code>x'</code> and <code>y'</code> are divided by
0033: * <code>w</code>.
0034: *
0035: * <pre>
0036: * [ x'] [ m00 m01 m02 ] [ x ] [ m00x + m01y + m02 ]
0037: * [ y'] = [ m10 m11 m12 ] [ y ] = [ m10x + m11y + m12 ]
0038: * [ w ] [ m20 m21 m22 ] [ 1 ] [ m20x + m21y + m22 ]
0039: *
0040: * x' = (m00x + m01y + m02)
0041: * y' = (m10x + m11y + m12)
0042: *
0043: * w = (m20x + m21y + m22)
0044: *
0045: * X = x' / w
0046: * Y = y' / w
0047: * </pre>
0048: */
0049: public final class PerspectiveTransform implements Cloneable,
0050: Serializable {
0051:
0052: private static final double PERSPECTIVE_DIVIDE_EPSILON = 1.0e-10;
0053:
0054: /** An element of the transform matrix. */
0055: double m00, m01, m02, m10, m11, m12, m20, m21, m22;
0056:
0057: /** Constructs an identity PerspectiveTransform. */
0058: public PerspectiveTransform() {
0059: m00 = m11 = m22 = 1.0;
0060: m01 = m02 = m10 = m12 = m20 = m21 = 0.0;
0061: }
0062:
0063: /**
0064: * Constructs a new PerspectiveTransform from 9 floats.
0065: * @deprecated as of JAI 1.1 Use PerspectiveTransform(double[][]) instead.
0066: */
0067: public PerspectiveTransform(float m00, float m01, float m02,
0068: float m10, float m11, float m12, float m20, float m21,
0069: float m22) {
0070: this .m00 = m00;
0071: this .m01 = m01;
0072: this .m02 = m02;
0073: this .m10 = m10;
0074: this .m11 = m11;
0075: this .m12 = m12;
0076: this .m20 = m20;
0077: this .m21 = m21;
0078: this .m22 = m22;
0079: }
0080:
0081: /**
0082: * Constructs a new PerspectiveTransform from 9 doubles.
0083: * @deprecated as of JAI 1.1 Use PerspectiveTransform(double[][]) instead.
0084: */
0085: public PerspectiveTransform(double m00, double m01, double m02,
0086: double m10, double m11, double m12, double m20, double m21,
0087: double m22) {
0088: this .m00 = m00;
0089: this .m01 = m01;
0090: this .m02 = m02;
0091: this .m10 = m10;
0092: this .m11 = m11;
0093: this .m12 = m12;
0094: this .m20 = m20;
0095: this .m21 = m21;
0096: this .m22 = m22;
0097: }
0098:
0099: /**
0100: * Constructs a new PerspectiveTransform from a one-dimensional
0101: * array of 9 floats, in row-major order.
0102: * The values in the array are assumed to be
0103: * { m00 m01 m02 m10 m11 m12 m20 m21 m22 }.
0104: * @throws IllegalArgumentException if flatmatrix is null
0105: * @throws ArrayIndexOutOfBoundsException if flatmatrix is too small
0106: * @deprecated as of JAI 1.1 Use PerspectiveTransform(double[][]) instead.
0107: */
0108: public PerspectiveTransform(float[] flatmatrix) {
0109: if (flatmatrix == null) {
0110: throw new IllegalArgumentException(JaiI18N
0111: .getString("Generic0"));
0112: }
0113:
0114: m00 = flatmatrix[0];
0115: m01 = flatmatrix[1];
0116: m02 = flatmatrix[2];
0117: m10 = flatmatrix[3];
0118: m11 = flatmatrix[4];
0119: m12 = flatmatrix[5];
0120: m20 = flatmatrix[6];
0121: m21 = flatmatrix[7];
0122: m22 = flatmatrix[8];
0123: }
0124:
0125: /**
0126: * Constructs a new PerspectiveTransform from a two-dimensional
0127: * array of floats.
0128: * @throws IllegalArgumentException if matrix is null
0129: * @throws ArrayIndexOutOfBoundsException if matrix is too small
0130: *
0131: * @deprecated as of JAI 1.1 Use PerspectiveTransform(double[][]) instead.
0132: */
0133: public PerspectiveTransform(float[][] matrix) {
0134: if (matrix == null) {
0135: throw new IllegalArgumentException(JaiI18N
0136: .getString("Generic0"));
0137: }
0138:
0139: m00 = matrix[0][0];
0140: m01 = matrix[0][1];
0141: m02 = matrix[0][2];
0142: m10 = matrix[1][0];
0143: m11 = matrix[1][1];
0144: m12 = matrix[1][2];
0145: m20 = matrix[2][0];
0146: m21 = matrix[2][1];
0147: m22 = matrix[2][2];
0148: }
0149:
0150: /**
0151: * Constructs a new PerspectiveTransform from a one-dimensional
0152: * array of 9 doubles, in row-major order.
0153: * The values in the array are assumed to be
0154: * { m00 m01 m02 m10 m11 m12 m20 m21 m22 }.
0155: * @throws IllegalArgumentException if flatmatrix is null
0156: * @throws ArrayIndexOutOfBoundsException if flatmatrix is too small
0157: *
0158: * @deprecated as of JAI 1.1 Use PerspectiveTransform(double[][]) instead.
0159: */
0160: public PerspectiveTransform(double[] flatmatrix) {
0161: if (flatmatrix == null) {
0162: throw new IllegalArgumentException(JaiI18N
0163: .getString("Generic0"));
0164: }
0165:
0166: m00 = flatmatrix[0];
0167: m01 = flatmatrix[1];
0168: m02 = flatmatrix[2];
0169: m10 = flatmatrix[3];
0170: m11 = flatmatrix[4];
0171: m12 = flatmatrix[5];
0172: m20 = flatmatrix[6];
0173: m21 = flatmatrix[7];
0174: m22 = flatmatrix[8];
0175: }
0176:
0177: /**
0178: * Constructs a new PerspectiveTransform from a two-dimensional
0179: * array of doubles.
0180: * @throws IllegalArgumentException if matrix is null
0181: * @throws ArrayIndexOutOfBoundsException if matrix is too small
0182: */
0183: public PerspectiveTransform(double[][] matrix) {
0184: if (matrix == null) {
0185: throw new IllegalArgumentException(JaiI18N
0186: .getString("Generic0"));
0187: }
0188:
0189: m00 = matrix[0][0];
0190: m01 = matrix[0][1];
0191: m02 = matrix[0][2];
0192: m10 = matrix[1][0];
0193: m11 = matrix[1][1];
0194: m12 = matrix[1][2];
0195: m20 = matrix[2][0];
0196: m21 = matrix[2][1];
0197: m22 = matrix[2][2];
0198: }
0199:
0200: /**
0201: * Constructs a new PerspectiveTransform with the same effect
0202: * as an existing AffineTransform.
0203: * @throws IllegalArgumentException if transform is null
0204: */
0205: public PerspectiveTransform(AffineTransform transform) {
0206: if (transform == null) {
0207: throw new IllegalArgumentException(JaiI18N
0208: .getString("Generic0"));
0209: }
0210:
0211: m00 = transform.getScaleX();
0212: m01 = transform.getShearX();
0213: m02 = transform.getTranslateX();
0214: m10 = transform.getShearY();
0215: m11 = transform.getScaleY();
0216: m12 = transform.getTranslateY();
0217: m20 = 0.0;
0218: m21 = 0.0;
0219: m22 = 1.0;
0220: }
0221:
0222: /**
0223: * Replaces the matrix with its adjoint.
0224: */
0225: private final void makeAdjoint() {
0226: double m00p = m11 * m22 - m12 * m21;
0227: double m01p = m12 * m20 - m10 * m22; // flipped sign
0228: double m02p = m10 * m21 - m11 * m20;
0229: double m10p = m02 * m21 - m01 * m22; // flipped sign
0230: double m11p = m00 * m22 - m02 * m20;
0231: double m12p = m01 * m20 - m00 * m21; // flipped sign
0232: double m20p = m01 * m12 - m02 * m11;
0233: double m21p = m02 * m10 - m00 * m12; // flipped sign
0234: double m22p = m00 * m11 - m01 * m10;
0235:
0236: // Transpose and copy sub-determinants
0237: m00 = m00p;
0238: m01 = m10p;
0239: m02 = m20p;
0240: m10 = m01p;
0241: m11 = m11p;
0242: m12 = m21p;
0243: m20 = m02p;
0244: m21 = m12p;
0245: m22 = m22p;
0246: }
0247:
0248: /**
0249: * Scales the matrix elements so m22 is equal to 1.0.
0250: * m22 must not be equal to 0.
0251: */
0252: private final void normalize() {
0253: double invscale = 1.0 / m22;
0254: m00 *= invscale;
0255: m01 *= invscale;
0256: m02 *= invscale;
0257: m10 *= invscale;
0258: m11 *= invscale;
0259: m12 *= invscale;
0260: m20 *= invscale;
0261: m21 *= invscale;
0262: m22 = 1.0;
0263: }
0264:
0265: private static final void getSquareToQuad(double x0, double y0,
0266: double x1, double y1, double x2, double y2, double x3,
0267: double y3, PerspectiveTransform tx) {
0268: double dx3 = x0 - x1 + x2 - x3;
0269: double dy3 = y0 - y1 + y2 - y3;
0270:
0271: tx.m22 = 1.0F;
0272:
0273: if ((dx3 == 0.0F) && (dy3 == 0.0F)) { // to do: use tolerance
0274: tx.m00 = x1 - x0;
0275: tx.m01 = x2 - x1;
0276: tx.m02 = x0;
0277: tx.m10 = y1 - y0;
0278: tx.m11 = y2 - y1;
0279: tx.m12 = y0;
0280: tx.m20 = 0.0F;
0281: tx.m21 = 0.0F;
0282: } else {
0283: double dx1 = x1 - x2;
0284: double dy1 = y1 - y2;
0285: double dx2 = x3 - x2;
0286: double dy2 = y3 - y2;
0287:
0288: double invdet = 1.0F / (dx1 * dy2 - dx2 * dy1);
0289: tx.m20 = (dx3 * dy2 - dx2 * dy3) * invdet;
0290: tx.m21 = (dx1 * dy3 - dx3 * dy1) * invdet;
0291: tx.m00 = x1 - x0 + tx.m20 * x1;
0292: tx.m01 = x3 - x0 + tx.m21 * x3;
0293: tx.m02 = x0;
0294: tx.m10 = y1 - y0 + tx.m20 * y1;
0295: tx.m11 = y3 - y0 + tx.m21 * y3;
0296: tx.m12 = y0;
0297: }
0298: }
0299:
0300: /**
0301: * Creates a PerspectiveTransform that maps the unit square
0302: * onto an arbitrary quadrilateral.
0303: *
0304: * <pre>
0305: * (0, 0) -> (x0, y0)
0306: * (1, 0) -> (x1, y1)
0307: * (1, 1) -> (x2, y2)
0308: * (0, 1) -> (x3, y3)
0309: * </pre>
0310: */
0311: public static PerspectiveTransform getSquareToQuad(double x0,
0312: double y0, double x1, double y1, double x2, double y2,
0313: double x3, double y3) {
0314: PerspectiveTransform tx = new PerspectiveTransform();
0315: getSquareToQuad(x0, y0, x1, y1, x2, y2, x3, y3, tx);
0316: return tx;
0317: }
0318:
0319: /**
0320: * Creates a PerspectiveTransform that maps the unit square
0321: * onto an arbitrary quadrilateral.
0322: *
0323: * <pre>
0324: * (0, 0) -> (x0, y0)
0325: * (1, 0) -> (x1, y1)
0326: * (1, 1) -> (x2, y2)
0327: * (0, 1) -> (x3, y3)
0328: * </pre>
0329: */
0330: public static PerspectiveTransform getSquareToQuad(float x0,
0331: float y0, float x1, float y1, float x2, float y2, float x3,
0332: float y3) {
0333: return getSquareToQuad((double) x0, (double) y0, (double) x1,
0334: (double) y1, (double) x2, (double) y2, (double) x3,
0335: (double) y3);
0336: }
0337:
0338: /**
0339: * Creates a PerspectiveTransform that maps an arbitrary
0340: * quadrilateral onto the unit square.
0341: *
0342: * <pre>
0343: * (x0, y0) -> (0, 0)
0344: * (x1, y1) -> (1, 0)
0345: * (x2, y2) -> (1, 1)
0346: * (x3, y3) -> (0, 1)
0347: * </pre>
0348: */
0349: public static PerspectiveTransform getQuadToSquare(double x0,
0350: double y0, double x1, double y1, double x2, double y2,
0351: double x3, double y3) {
0352: PerspectiveTransform tx = new PerspectiveTransform();
0353: getSquareToQuad(x0, y0, x1, y1, x2, y2, x3, y3, tx);
0354: tx.makeAdjoint();
0355: return tx;
0356: }
0357:
0358: /**
0359: * Creates a PerspectiveTransform that maps an arbitrary
0360: * quadrilateral onto the unit square.
0361: *
0362: * <pre>
0363: * (x0, y0) -> (0, 0)
0364: * (x1, y1) -> (1, 0)
0365: * (x2, y2) -> (1, 1)
0366: * (x3, y3) -> (0, 1)
0367: * </pre>
0368: */
0369: public static PerspectiveTransform getQuadToSquare(float x0,
0370: float y0, float x1, float y1, float x2, float y2, float x3,
0371: float y3) {
0372: return getQuadToSquare((double) x0, (double) y0, (double) x1,
0373: (double) y1, (double) x2, (double) y2, (double) x3,
0374: (double) y3);
0375: }
0376:
0377: /**
0378: * Creates a PerspectiveTransform that maps an arbitrary
0379: * quadrilateral onto another arbitrary quadrilateral.
0380: *
0381: * <pre>
0382: * (x0, y0) -> (x0p, y0p)
0383: * (x1, y1) -> (x1p, y1p)
0384: * (x2, y2) -> (x2p, y2p)
0385: * (x3, y3) -> (x3p, y3p)
0386: * </pre>
0387: */
0388: public static PerspectiveTransform getQuadToQuad(double x0,
0389: double y0, double x1, double y1, double x2, double y2,
0390: double x3, double y3, double x0p, double y0p, double x1p,
0391: double y1p, double x2p, double y2p, double x3p, double y3p) {
0392: PerspectiveTransform tx1 = getQuadToSquare(x0, y0, x1, y1, x2,
0393: y2, x3, y3);
0394:
0395: PerspectiveTransform tx2 = getSquareToQuad(x0p, y0p, x1p, y1p,
0396: x2p, y2p, x3p, y3p);
0397:
0398: tx1.concatenate(tx2);
0399: return tx1;
0400: }
0401:
0402: /**
0403: * Creates a PerspectiveTransform that maps an arbitrary
0404: * quadrilateral onto another arbitrary quadrilateral.
0405: *
0406: * <pre>
0407: * (x0, y0) -> (x0p, y0p)
0408: * (x1, y1) -> (x1p, y1p)
0409: * (x2, y2) -> (x2p, y2p)
0410: * (x3, y3) -> (x3p, y3p)
0411: * </pre>
0412: */
0413: public static PerspectiveTransform getQuadToQuad(float x0,
0414: float y0, float x1, float y1, float x2, float y2, float x3,
0415: float y3, float x0p, float y0p, float x1p, float y1p,
0416: float x2p, float y2p, float x3p, float y3p) {
0417: return getQuadToQuad((double) x0, (double) y0, (double) x1,
0418: (double) y1, (double) x2, (double) y2, (double) x3,
0419: (double) y3, (double) x0p, (double) y0p, (double) x1p,
0420: (double) y1p, (double) x2p, (double) y2p, (double) x3p,
0421: (double) y3p);
0422: }
0423:
0424: /**
0425: * Returns the determinant of the matrix representation of the
0426: * transform.
0427: */
0428: public double getDeterminant() {
0429: return ((m00 * ((m11 * m22) - (m12 * m21)))
0430: - (m01 * ((m10 * m22) - (m12 * m20))) + (m02 * ((m10 * m21) - (m11 * m20))));
0431:
0432: }
0433:
0434: /**
0435: * Retrieves the 9 specifiable values in the 3x3 affine
0436: * transformation matrix into an array of double precision values.
0437: * The values are stored into the array as
0438: * { m00 m01 m02 m10 m11 m12 m20 m21 m22 }.
0439: *
0440: * @param flatmatrix The double array used to store the returned
0441: * values. The length of the array is assumed to be at
0442: * least 9.
0443: * @throws ArrayIndexOutOfBoundsException if flatmatrix is too small
0444: * @deprecated as of JAI 1.1 Use double[][] getMatrix(double[][] matrix) instead.
0445: */
0446: public double[] getMatrix(double[] flatmatrix) {
0447: if (flatmatrix == null) {
0448: flatmatrix = new double[9];
0449: }
0450:
0451: flatmatrix[0] = m00;
0452: flatmatrix[1] = m01;
0453: flatmatrix[2] = m02;
0454: flatmatrix[3] = m10;
0455: flatmatrix[4] = m11;
0456: flatmatrix[5] = m12;
0457: flatmatrix[6] = m20;
0458: flatmatrix[7] = m21;
0459: flatmatrix[8] = m22;
0460:
0461: return flatmatrix;
0462: }
0463:
0464: /**
0465: * Retrieves the 9 specifiable values in the 3x3 affine
0466: * transformation matrix into a 2-dimensional array of double
0467: * precision values. The values are stored into the 2-dimensional
0468: * array using the row index as the first subscript and the column
0469: * index as the second.
0470: *
0471: * @param matrix The 2-dimensional double array to store the
0472: * returned values. The array is assumed to be at least 3x3.
0473: * @throws ArrayIndexOutOfBoundsException if matrix is too small
0474: */
0475: public double[][] getMatrix(double[][] matrix) {
0476: if (matrix == null) {
0477: matrix = new double[3][3];
0478: }
0479:
0480: matrix[0][0] = m00;
0481: matrix[0][1] = m01;
0482: matrix[0][2] = m02;
0483: matrix[1][0] = m10;
0484: matrix[1][1] = m11;
0485: matrix[1][2] = m12;
0486: matrix[2][0] = m20;
0487: matrix[2][1] = m21;
0488: matrix[2][2] = m22;
0489:
0490: return matrix;
0491: }
0492:
0493: /**
0494: * Concatenates this transform with a translation transformation.
0495: * This is equivalent to calling concatenate(T), where T is an
0496: * PerspectiveTransform represented by the following matrix:
0497: * <pre>
0498: * [ 1 0 tx ]
0499: * [ 0 1 ty ]
0500: * [ 0 0 1 ]
0501: * </pre>
0502: */
0503: public void translate(double tx, double ty) {
0504: PerspectiveTransform Tx = new PerspectiveTransform();
0505: Tx.setToTranslation(tx, ty);
0506: concatenate(Tx);
0507: }
0508:
0509: /**
0510: * Concatenates this transform with a rotation transformation.
0511: * This is equivalent to calling concatenate(R), where R is an
0512: * PerspectiveTransform represented by the following matrix:
0513: * <pre>
0514: * [ cos(theta) -sin(theta) 0 ]
0515: * [ sin(theta) cos(theta) 0 ]
0516: * [ 0 0 1 ]
0517: * </pre>
0518: * Rotating with a positive angle theta rotates points on the positive
0519: * X axis toward the positive Y axis.
0520: *
0521: * @param theta The angle of rotation in radians.
0522: */
0523: public void rotate(double theta) {
0524: PerspectiveTransform Tx = new PerspectiveTransform();
0525: Tx.setToRotation(theta);
0526: concatenate(Tx);
0527: }
0528:
0529: /**
0530: * Concatenates this transform with a translated rotation transformation.
0531: * This is equivalent to the following sequence of calls:
0532: * <pre>
0533: * translate(x, y);
0534: * rotate(theta);
0535: * translate(-x, -y);
0536: * </pre>
0537: * Rotating with a positive angle theta rotates points on the positive
0538: * X axis toward the positive Y axis.
0539: *
0540: * @param theta The angle of rotation in radians.
0541: * @param x The X coordinate of the origin of the rotation
0542: * @param y The Y coordinate of the origin of the rotation
0543: */
0544: public void rotate(double theta, double x, double y) {
0545: PerspectiveTransform Tx = new PerspectiveTransform();
0546: Tx.setToRotation(theta, x, y);
0547: concatenate(Tx);
0548: }
0549:
0550: /**
0551: * Concatenates this transform with a scaling transformation.
0552: * This is equivalent to calling concatenate(S), where S is an
0553: * PerspectiveTransform represented by the following matrix:
0554: * <pre>
0555: * [ sx 0 0 ]
0556: * [ 0 sy 0 ]
0557: * [ 0 0 1 ]
0558: * </pre>
0559: *
0560: * @param sx The X axis scale factor.
0561: * @param sy The Y axis scale factor.
0562: */
0563: public void scale(double sx, double sy) {
0564: PerspectiveTransform Tx = new PerspectiveTransform();
0565: Tx.setToScale(sx, sy);
0566: concatenate(Tx);
0567: }
0568:
0569: /**
0570: * Concatenates this transform with a shearing transformation.
0571: * This is equivalent to calling concatenate(SH), where SH is an
0572: * PerspectiveTransform represented by the following matrix:
0573: * <pre>
0574: * [ 1 shx 0 ]
0575: * [ shy 1 0 ]
0576: * [ 0 0 1 ]
0577: * </pre>
0578: *
0579: * @param shx The factor by which coordinates are shifted towards
0580: * the positive X axis direction according to their Y
0581: * coordinate.
0582: * @param shy The factor by which coordinates are shifted towards
0583: * the positive Y axis direction according to their X
0584: * coordinate.
0585: */
0586: public void shear(double shx, double shy) {
0587: PerspectiveTransform Tx = new PerspectiveTransform();
0588: Tx.setToShear(shx, shy);
0589: concatenate(Tx);
0590: }
0591:
0592: /**
0593: * Resets this transform to the Identity transform.
0594: */
0595: public void setToIdentity() {
0596: m00 = m11 = m22 = 1.0;
0597: m01 = m10 = m02 = m20 = m12 = m21 = 0.0;
0598: }
0599:
0600: /**
0601: * Sets this transform to a translation transformation.
0602: * The matrix representing this transform becomes:
0603: * <pre>
0604: * [ 1 0 tx ]
0605: * [ 0 1 ty ]
0606: * [ 0 0 1 ]
0607: * </pre>
0608: * @param tx The distance by which coordinates are translated in the
0609: * X axis direction
0610: * @param ty The distance by which coordinates are translated in the
0611: * Y axis direction
0612: */
0613: public void setToTranslation(double tx, double ty) {
0614: m00 = 1.0;
0615: m01 = 0.0;
0616: m02 = tx;
0617: m10 = 0.0;
0618: m11 = 1.0;
0619: m12 = ty;
0620: m20 = 0.0;
0621: m21 = 0.0;
0622: m22 = 1.0;
0623: }
0624:
0625: /**
0626: * Sets this transform to a rotation transformation.
0627: * The matrix representing this transform becomes:
0628: * <pre>
0629: * [ cos(theta) -sin(theta) 0 ]
0630: * [ sin(theta) cos(theta) 0 ]
0631: * [ 0 0 1 ]
0632: * </pre>
0633: * Rotating with a positive angle theta rotates points on the positive
0634: * X axis toward the positive Y axis.
0635: * @param theta The angle of rotation in radians.
0636: */
0637: public void setToRotation(double theta) {
0638: m00 = Math.cos(theta);
0639: m01 = -Math.sin(theta);
0640: m02 = 0.0;
0641: m10 = -m01; // Math.sin(theta);
0642: m11 = m00; // Math.cos(theta);
0643: m12 = 0.0;
0644: m20 = 0.0;
0645: m21 = 0.0;
0646: m22 = 1.0;
0647: }
0648:
0649: /**
0650: * Sets this transform to a rotation transformation
0651: * about a specified point (x, y). This is equivalent
0652: * to the following sequence of calls:
0653: *
0654: * <pre>
0655: * setToTranslate(x, y);
0656: * rotate(theta);
0657: * translate(-x, -y);
0658: * </pre>
0659: *
0660: * Rotating with a positive angle theta rotates points on the positive
0661: * X axis toward the positive Y axis.
0662: *
0663: * @param theta The angle of rotation in radians.
0664: * @param x The X coordinate of the origin of the rotation
0665: * @param y The Y coordinate of the origin of the rotation
0666: */
0667: public void setToRotation(double theta, double x, double y) {
0668: setToRotation(theta);
0669: double sin = m10;
0670: double oneMinusCos = 1.0 - m00;
0671: m02 = x * oneMinusCos + y * sin;
0672: m12 = y * oneMinusCos - x * sin;
0673: }
0674:
0675: /**
0676: * Sets this transform to a scale transformation
0677: * with scale factors sx and sy.
0678: * The matrix representing this transform becomes:
0679: * <pre>
0680: * [ sx 0 0 ]
0681: * [ 0 sy 0 ]
0682: * [ 0 0 1 ]
0683: * </pre>
0684: *
0685: * @param sx The X axis scale factor.
0686: * @param sy The Y axis scale factor.
0687: */
0688: public void setToScale(double sx, double sy) {
0689: m00 = sx;
0690: m01 = 0.0;
0691: m02 = 0.0;
0692: m10 = 0.0;
0693: m11 = sy;
0694: m12 = 0.0;
0695: m20 = 0.0;
0696: m21 = 0.0;
0697: m22 = 1.0;
0698: }
0699:
0700: /**
0701: * Sets this transform to a shearing transformation
0702: * with shear factors sx and sy.
0703: * The matrix representing this transform becomes:
0704: * <pre>
0705: * [ 1 shx 0 ]
0706: * [ shy 1 0 ]
0707: * [ 0 0 1 ]
0708: * </pre>
0709: *
0710: * @param shx The factor by which coordinates are shifted towards
0711: * the positive X axis direction according to their Y
0712: * coordinate.
0713: * @param shy The factor by which coordinates are shifted towards
0714: * the positive Y axis direction according to their X
0715: * coordinate.
0716: */
0717: public void setToShear(double shx, double shy) {
0718: m00 = 1.0;
0719: m01 = shx;
0720: m02 = 0.0;
0721: m10 = shy;
0722: m11 = 1.0;
0723: m12 = 0.0;
0724: m20 = 0.0;
0725: m21 = 0.0;
0726: m22 = 1.0;
0727: }
0728:
0729: /**
0730: * Sets this transform to a given AffineTransform.
0731: * @throws IllegalArgumentException if Tx is null
0732: */
0733: public void setTransform(AffineTransform Tx) {
0734: if (Tx == null) {
0735: throw new IllegalArgumentException(JaiI18N
0736: .getString("Generic0"));
0737: }
0738:
0739: m00 = Tx.getScaleX();
0740: m01 = Tx.getShearX();
0741: m02 = Tx.getTranslateX();
0742: m10 = Tx.getShearY();
0743: m11 = Tx.getScaleY();
0744: m12 = Tx.getTranslateY();
0745: m20 = 0.0;
0746: m21 = 0.0;
0747: m22 = 1.0;
0748: }
0749:
0750: /**
0751: * Sets this transform to a given PerspectiveTransform.
0752: * @throws IllegalArgumentException if Tx is null
0753: */
0754: public void setTransform(PerspectiveTransform Tx) {
0755: if (Tx == null) {
0756: throw new IllegalArgumentException(JaiI18N
0757: .getString("Generic0"));
0758: }
0759:
0760: m00 = Tx.m00;
0761: m01 = Tx.m01;
0762: m02 = Tx.m02;
0763: m10 = Tx.m10;
0764: m11 = Tx.m11;
0765: m12 = Tx.m12;
0766: m20 = Tx.m20;
0767: m21 = Tx.m21;
0768: m22 = Tx.m22;
0769: }
0770:
0771: /**
0772: * Sets this transform to a given PerspectiveTransform,
0773: * expressed by the elements of its matrix. <i>Important Note: The
0774: * matrix elements in the argument list are in column-major order
0775: * unlike those of the constructor, which are in row-major order.</i>
0776: * @deprecated as of JAI 1.1 Use double[][] getMatrix(double[][] matrix) instead.
0777: */
0778: public void setTransform(float m00, float m10, float m20,
0779: float m01, float m11, float m21, float m02, float m12,
0780: float m22) {
0781: this .m00 = (double) m00;
0782: this .m01 = (double) m01;
0783: this .m02 = (double) m02;
0784: this .m10 = (double) m10;
0785: this .m11 = (double) m11;
0786: this .m12 = (double) m12;
0787: this .m20 = (double) m20;
0788: this .m21 = (double) m21;
0789: this .m22 = (double) m22;
0790: }
0791:
0792: /**
0793: * Sets this transform using a two-dimensional array of double precision
0794: * values. The row index is first, and the column index is second.
0795: *
0796: * @param matrix The 2D double array to be used for setting this transform.
0797: * The array is assumed to be at least 3x3.
0798: * @throws IllegalArgumentException if matrix is null
0799: * @throws ArrayIndexOutOfBoundsException if matrix is too small
0800: * @since JAI 1.1
0801: */
0802: public void setTransform(double[][] matrix) {
0803: if (matrix == null) {
0804: throw new IllegalArgumentException(JaiI18N
0805: .getString("Generic0"));
0806: }
0807:
0808: m00 = matrix[0][0];
0809: m01 = matrix[0][1];
0810: m02 = matrix[0][2];
0811: m10 = matrix[1][0];
0812: m11 = matrix[1][1];
0813: m12 = matrix[1][2];
0814: m20 = matrix[2][0];
0815: m21 = matrix[2][1];
0816: m22 = matrix[2][2];
0817: }
0818:
0819: /**
0820: * Post-concatenates a given AffineTransform to this transform.
0821: * @throws IllegalArgumentException if Tx is null
0822: */
0823: public void concatenate(AffineTransform Tx) {
0824: if (Tx == null) {
0825: throw new IllegalArgumentException(JaiI18N
0826: .getString("Generic0"));
0827: }
0828:
0829: // Extend Tx: Tx.m20 = 0, Tx.m21 = 0, Tx.m22 = 1
0830:
0831: double tx_m00 = Tx.getScaleX();
0832: double tx_m01 = Tx.getShearX();
0833: double tx_m02 = Tx.getTranslateX();
0834: double tx_m10 = Tx.getShearY();
0835: double tx_m11 = Tx.getScaleY();
0836: double tx_m12 = Tx.getTranslateY();
0837:
0838: double m00p = m00 * tx_m00 + m10 * tx_m01 + m20 * tx_m02;
0839: double m01p = m01 * tx_m00 + m11 * tx_m01 + m21 * tx_m02;
0840: double m02p = m02 * tx_m00 + m12 * tx_m01 + m22 * tx_m02;
0841: double m10p = m00 * tx_m10 + m10 * tx_m11 + m20 * tx_m12;
0842: double m11p = m01 * tx_m10 + m11 * tx_m11 + m21 * tx_m12;
0843: double m12p = m02 * tx_m10 + m12 * tx_m11 + m22 * tx_m12;
0844: double m20p = m20;
0845: double m21p = m21;
0846: double m22p = m22;
0847:
0848: m00 = m00p;
0849: m10 = m10p;
0850: m20 = m20p;
0851: m01 = m01p;
0852: m11 = m11p;
0853: m21 = m21p;
0854: m02 = m02p;
0855: m12 = m12p;
0856: m22 = m22p;
0857: }
0858:
0859: /**
0860: * Post-concatenates a given PerspectiveTransform to this transform.
0861: * @throws IllegalArgumentException if Tx is null
0862: */
0863: public void concatenate(PerspectiveTransform Tx) {
0864: if (Tx == null) {
0865: throw new IllegalArgumentException(JaiI18N
0866: .getString("Generic0"));
0867: }
0868:
0869: double m00p = m00 * Tx.m00 + m10 * Tx.m01 + m20 * Tx.m02;
0870: double m10p = m00 * Tx.m10 + m10 * Tx.m11 + m20 * Tx.m12;
0871: double m20p = m00 * Tx.m20 + m10 * Tx.m21 + m20 * Tx.m22;
0872: double m01p = m01 * Tx.m00 + m11 * Tx.m01 + m21 * Tx.m02;
0873: double m11p = m01 * Tx.m10 + m11 * Tx.m11 + m21 * Tx.m12;
0874: double m21p = m01 * Tx.m20 + m11 * Tx.m21 + m21 * Tx.m22;
0875: double m02p = m02 * Tx.m00 + m12 * Tx.m01 + m22 * Tx.m02;
0876: double m12p = m02 * Tx.m10 + m12 * Tx.m11 + m22 * Tx.m12;
0877: double m22p = m02 * Tx.m20 + m12 * Tx.m21 + m22 * Tx.m22;
0878:
0879: m00 = m00p;
0880: m10 = m10p;
0881: m20 = m20p;
0882: m01 = m01p;
0883: m11 = m11p;
0884: m21 = m21p;
0885: m02 = m02p;
0886: m12 = m12p;
0887: m22 = m22p;
0888: }
0889:
0890: /**
0891: * Pre-concatenates a given AffineTransform to this transform.
0892: * @throws IllegalArgumentException if Tx is null
0893: */
0894: public void preConcatenate(AffineTransform Tx) {
0895: if (Tx == null) {
0896: throw new IllegalArgumentException(JaiI18N
0897: .getString("Generic0"));
0898: }
0899:
0900: // Extend Tx: Tx.m20 = 0, Tx.m21 = 0, Tx.m22 = 1
0901:
0902: double tx_m00 = Tx.getScaleX();
0903: double tx_m01 = Tx.getShearX();
0904: double tx_m02 = Tx.getTranslateX();
0905: double tx_m10 = Tx.getShearY();
0906: double tx_m11 = Tx.getScaleY();
0907: double tx_m12 = Tx.getTranslateY();
0908:
0909: double m00p = tx_m00 * m00 + tx_m10 * m01;
0910: double m01p = tx_m01 * m00 + tx_m11 * m01;
0911: double m02p = tx_m02 * m00 + tx_m12 * m01 + m02;
0912: double m10p = tx_m00 * m10 + tx_m10 * m11;
0913: double m11p = tx_m01 * m10 + tx_m11 * m11;
0914: double m12p = tx_m02 * m10 + tx_m12 * m11 + m12;
0915: double m20p = tx_m00 * m20 + tx_m10 * m21;
0916: double m21p = tx_m01 * m20 + tx_m11 * m21;
0917: double m22p = tx_m02 * m20 + tx_m12 * m21 + m22;
0918:
0919: m00 = m00p;
0920: m10 = m10p;
0921: m20 = m20p;
0922: m01 = m01p;
0923: m11 = m11p;
0924: m21 = m21p;
0925: m02 = m02p;
0926: m12 = m12p;
0927: m22 = m22p;
0928: }
0929:
0930: /**
0931: * Pre-concatenates a given PerspectiveTransform to this transform.
0932: * @throws IllegalArgumentException if Tx is null
0933: */
0934: public void preConcatenate(PerspectiveTransform Tx) {
0935: if (Tx == null) {
0936: throw new IllegalArgumentException(JaiI18N
0937: .getString("Generic0"));
0938: }
0939:
0940: double m00p = Tx.m00 * m00 + Tx.m10 * m01 + Tx.m20 * m02;
0941: double m10p = Tx.m00 * m10 + Tx.m10 * m11 + Tx.m20 * m12;
0942: double m20p = Tx.m00 * m20 + Tx.m10 * m21 + Tx.m20 * m22;
0943: double m01p = Tx.m01 * m00 + Tx.m11 * m01 + Tx.m21 * m02;
0944: double m11p = Tx.m01 * m10 + Tx.m11 * m11 + Tx.m21 * m12;
0945: double m21p = Tx.m01 * m20 + Tx.m11 * m21 + Tx.m21 * m22;
0946: double m02p = Tx.m02 * m00 + Tx.m12 * m01 + Tx.m22 * m02;
0947: double m12p = Tx.m02 * m10 + Tx.m12 * m11 + Tx.m22 * m12;
0948: double m22p = Tx.m02 * m20 + Tx.m12 * m21 + Tx.m22 * m22;
0949:
0950: m00 = m00p;
0951: m10 = m10p;
0952: m20 = m20p;
0953: m01 = m01p;
0954: m11 = m11p;
0955: m21 = m21p;
0956: m02 = m02p;
0957: m12 = m12p;
0958: m22 = m22p;
0959: }
0960:
0961: /**
0962: * Returns a new PerpectiveTransform that is the inverse
0963: * of the current transform.
0964: * @throws NoninvertibleTransformException if transform cannot be inverted
0965: */
0966: public PerspectiveTransform createInverse()
0967: throws NoninvertibleTransformException,
0968: CloneNotSupportedException {
0969:
0970: PerspectiveTransform tx = (PerspectiveTransform) clone();
0971: tx.makeAdjoint();
0972: if (Math.abs(tx.m22) < PERSPECTIVE_DIVIDE_EPSILON) {
0973: throw new NoninvertibleTransformException(JaiI18N
0974: .getString("PerspectiveTransform0"));
0975: }
0976: tx.normalize();
0977: return tx;
0978: }
0979:
0980: /**
0981: * Returns a new PerpectiveTransform that is the adjoint,
0982: * of the current transform. The adjoint is defined as
0983: * the matrix of cofactors, which in turn are the determinants
0984: * of the submatrices defined by removing the row and column
0985: * of each element from the original matrix in turn.
0986: *
0987: * <p> The adjoint is a scalar multiple of the inverse matrix.
0988: * Because points to be transformed are converted into homogeneous
0989: * coordinates, where scalar factors are irrelevant, the adjoint
0990: * may be used in place of the true inverse. Since it is unnecessary
0991: * to normalize the adjoint, it is both faster to compute and more
0992: * numerically stable than the true inverse.
0993: */
0994: public PerspectiveTransform createAdjoint()
0995: throws CloneNotSupportedException {
0996:
0997: PerspectiveTransform tx = (PerspectiveTransform) clone();
0998: tx.makeAdjoint();
0999: return tx;
1000: }
1001:
1002: /**
1003: * Transforms the specified ptSrc and stores the result in ptDst.
1004: * If ptDst is null, a new Point2D object will be allocated before
1005: * storing. In either case, ptDst containing the transformed point
1006: * is returned for convenience.
1007: * Note that ptSrc and ptDst can the same. In this case, the input
1008: * point will be overwritten with the transformed point.
1009: *
1010: * @param ptSrc The array containing the source point objects.
1011: * @param ptDst The array where the transform point objects are returned.
1012: * @throws IllegalArgumentException if ptSrc is null
1013: */
1014: public Point2D transform(Point2D ptSrc, Point2D ptDst) {
1015: if (ptSrc == null) {
1016: throw new IllegalArgumentException(JaiI18N
1017: .getString("Generic0"));
1018: }
1019:
1020: if (ptDst == null) {
1021: if (ptSrc instanceof Point2D.Double) {
1022: ptDst = new Point2D.Double();
1023: } else {
1024: ptDst = new Point2D.Float();
1025: }
1026: }
1027:
1028: double x = ptSrc.getX();
1029: double y = ptSrc.getY();
1030: double w = m20 * x + m21 * y + m22;
1031: ptDst.setLocation((m00 * x + m01 * y + m02) / w, (m10 * x + m11
1032: * y + m12)
1033: / w);
1034:
1035: return ptDst;
1036: }
1037:
1038: /**
1039: * Transforms an array of point objects by this transform.
1040: * @param ptSrc The array containing the source point objects.
1041: * @param ptDst The array where the transform point objects are returned.
1042: * @param srcOff The offset to the first point object to be transformed
1043: * in the source array.
1044: * @param dstOff The offset to the location where the first transformed
1045: * point object is stored in the destination array.
1046: * @param numPts The number of point objects to be transformed.
1047: * @throws IllegalArgumentException if ptSrc is null
1048: * @throws IllegalArgumentException if ptDst is null
1049: * @throws ArrayIndexOutOfBoundsException if ptSrc is too small
1050: */
1051: public void transform(Point2D[] ptSrc, int srcOff, Point2D[] ptDst,
1052: int dstOff, int numPts) {
1053:
1054: if (ptSrc == null || ptDst == null) {
1055: throw new IllegalArgumentException(JaiI18N
1056: .getString("Generic0"));
1057: }
1058:
1059: while (numPts-- > 0) {
1060: /* Copy source coords into local variables in case src == dst. */
1061: Point2D src = ptSrc[srcOff++];
1062: Point2D dst = ptDst[dstOff++];
1063: if (dst == null) {
1064: if (src instanceof Point2D.Double) {
1065: dst = new Point2D.Double();
1066: } else {
1067: dst = new Point2D.Float();
1068: }
1069: ptDst[dstOff - 1] = dst;
1070: }
1071:
1072: double x = src.getX();
1073: double y = src.getY();
1074: double w = m20 * x + m21 * y + m22;
1075:
1076: if (w == 0) {
1077: dst.setLocation(x, y);
1078: } else {
1079: dst.setLocation((m00 * x + m01 * y + m02) / w, (m10 * x
1080: + m11 * y + m12)
1081: / w);
1082: }
1083: }
1084: }
1085:
1086: /**
1087: * Transforms an array of floating point coordinates by this transform.
1088: * @param srcPts The array containing the source point coordinates.
1089: * Each point is stored as a pair of x,y coordinates.
1090: * @param srcOff The offset to the first point to be transformed
1091: * in the source array.
1092: * @param dstPts The array where the transformed point coordinates are
1093: * returned. Each point is stored as a pair of x,y coordinates.
1094: * @param dstOff The offset to the location where the first transformed
1095: * point is stored in the destination array.
1096: * @param numPts The number of points to be transformed.
1097: * @throws IllegalArgumentException if srcPts is null
1098: * @throws ArrayIndexOutOfBoundsException if srcPts is too small
1099: */
1100: public void transform(float[] srcPts, int srcOff, float[] dstPts,
1101: int dstOff, int numPts) {
1102:
1103: if (srcPts == null) {
1104: throw new IllegalArgumentException(JaiI18N
1105: .getString("Generic0"));
1106: }
1107:
1108: if (dstPts == null) {
1109: dstPts = new float[numPts * 2 + dstOff];
1110: }
1111:
1112: while (numPts-- > 0) {
1113: float x = srcPts[srcOff++];
1114: float y = srcPts[srcOff++];
1115: double w = m20 * x + m21 * y + m22;
1116:
1117: if (w == 0) {
1118: dstPts[dstOff++] = x;
1119: dstPts[dstOff++] = y;
1120: } else {
1121: dstPts[dstOff++] = (float) ((m00 * x + m01 * y + m02) / w);
1122: dstPts[dstOff++] = (float) ((m10 * x + m11 * y + m12) / w);
1123: }
1124: }
1125: }
1126:
1127: /**
1128: * Transforms an array of double precision coordinates by this transform.
1129: * @param srcPts The array containing the source point coordinates.
1130: * Each point is stored as a pair of x,y coordinates.
1131: * @param dstPts The array where the transformed point coordinates are
1132: * returned. Each point is stored as a pair of x,y coordinates.
1133: * @param srcOff The offset to the first point to be transformed
1134: * in the source array.
1135: * @param dstOff The offset to the location where the first transformed
1136: * point is stored in the destination array.
1137: * @param numPts The number of point objects to be transformed.
1138: * @throws IllegalArgumentException if srcPts is null
1139: * @throws ArrayIndexOutOfBoundsException if srcPts is too small
1140: */
1141: public void transform(double[] srcPts, int srcOff, double[] dstPts,
1142: int dstOff, int numPts) {
1143:
1144: if (srcPts == null) {
1145: throw new IllegalArgumentException(JaiI18N
1146: .getString("Generic0"));
1147: }
1148:
1149: if (dstPts == null) {
1150: dstPts = new double[numPts * 2 + dstOff];
1151: }
1152:
1153: while (numPts-- > 0) {
1154: double x = srcPts[srcOff++];
1155: double y = srcPts[srcOff++];
1156: double w = m20 * x + m21 * y + m22;
1157:
1158: if (w == 0) {
1159: dstPts[dstOff++] = x;
1160: dstPts[dstOff++] = y;
1161: } else {
1162: dstPts[dstOff++] = (m00 * x + m01 * y + m02) / w;
1163: dstPts[dstOff++] = (m10 * x + m11 * y + m12) / w;
1164: }
1165: }
1166: }
1167:
1168: /**
1169: * Transforms an array of floating point coordinates by this transform,
1170: * storing the results into an array of doubles.
1171: * @param srcPts The array containing the source point coordinates.
1172: * Each point is stored as a pair of x,y coordinates.
1173: * @param srcOff The offset to the first point to be transformed
1174: * in the source array.
1175: * @param dstPts The array where the transformed point coordinates are
1176: * returned. Each point is stored as a pair of x,y coordinates.
1177: * @param dstOff The offset to the location where the first transformed
1178: * point is stored in the destination array.
1179: * @param numPts The number of points to be transformed.
1180: * @throws IllegalArgumentException if srcPts is null
1181: * @throws ArrayIndexOutOfBoundsException if srcPts is too small
1182: */
1183: public void transform(float[] srcPts, int srcOff, double[] dstPts,
1184: int dstOff, int numPts) {
1185:
1186: if (srcPts == null) {
1187: throw new IllegalArgumentException(JaiI18N
1188: .getString("Generic0"));
1189: }
1190:
1191: if (dstPts == null) {
1192: dstPts = new double[numPts * 2 + dstOff];
1193: }
1194:
1195: while (numPts-- > 0) {
1196: float x = srcPts[srcOff++];
1197: float y = srcPts[srcOff++];
1198: double w = m20 * x + m21 * y + m22;
1199:
1200: if (w == 0) {
1201: dstPts[dstOff++] = x;
1202: dstPts[dstOff++] = y;
1203: } else {
1204: dstPts[dstOff++] = (m00 * x + m01 * y + m02) / w;
1205: dstPts[dstOff++] = (m10 * x + m11 * y + m12) / w;
1206: }
1207: }
1208: }
1209:
1210: /**
1211: * Transforms an array of double precision coordinates by this transform,
1212: * storing the results into an array of floats.
1213: * @param srcPts The array containing the source point coordinates.
1214: * Each point is stored as a pair of x,y coordinates.
1215: * @param dstPts The array where the transformed point coordinates are
1216: * returned. Each point is stored as a pair of x,y coordinates.
1217: * @param srcOff The offset to the first point to be transformed
1218: * in the source array.
1219: * @param dstOff The offset to the location where the first transformed
1220: * point is stored in the destination array.
1221: * @param numPts The number of point objects to be transformed.
1222: * @throws IllegalArgumentException if srcPts is null
1223: * @throws ArrayIndexOutOfBoundsException if srcPts is too small
1224: */
1225: public void transform(double[] srcPts, int srcOff, float[] dstPts,
1226: int dstOff, int numPts) {
1227:
1228: if (srcPts == null) {
1229: throw new IllegalArgumentException(JaiI18N
1230: .getString("Generic0"));
1231: }
1232:
1233: if (dstPts == null) {
1234: dstPts = new float[numPts * 2 + dstOff];
1235: }
1236:
1237: while (numPts-- > 0) {
1238: double x = srcPts[srcOff++];
1239: double y = srcPts[srcOff++];
1240: double w = m20 * x + m21 * y + m22;
1241:
1242: if (w == 0) {
1243: dstPts[dstOff++] = (float) x;
1244: dstPts[dstOff++] = (float) y;
1245: } else {
1246: dstPts[dstOff++] = (float) ((m00 * x + m01 * y + m02) / w);
1247: dstPts[dstOff++] = (float) ((m10 * x + m11 * y + m12) / w);
1248: }
1249: }
1250: }
1251:
1252: /**
1253: * Inverse transforms the specified ptSrc and stores the result in ptDst.
1254: * If ptDst is null, a new Point2D object will be allocated before
1255: * storing. In either case, ptDst containing the transformed point
1256: * is returned for convenience.
1257: * Note that ptSrc and ptDst can the same. In this case, the input
1258: * point will be overwritten with the transformed point.
1259: * @param ptSrc The point to be inverse transformed.
1260: * @param ptDst The resulting transformed point.
1261: * @throws NoninvertibleTransformException if the matrix cannot be
1262: * inverted.
1263: * @throws IllegalArgumentException if ptSrc is null
1264: */
1265: public Point2D inverseTransform(Point2D ptSrc, Point2D ptDst)
1266: throws NoninvertibleTransformException {
1267: if (ptSrc == null) {
1268: throw new IllegalArgumentException(JaiI18N
1269: .getString("Generic0"));
1270: }
1271:
1272: if (ptDst == null) {
1273: if (ptSrc instanceof Point2D.Double) {
1274: ptDst = new Point2D.Double();
1275: } else {
1276: ptDst = new Point2D.Float();
1277: }
1278: }
1279: // Copy source coords into local variables in case src == dst
1280: double x = ptSrc.getX();
1281: double y = ptSrc.getY();
1282:
1283: double tmp_x = (m11 * m22 - m12 * m21) * x
1284: + (m02 * m21 - m01 * m22) * y + (m01 * m12 - m02 * m11);
1285: double tmp_y = (m12 * m20 - m10 * m22) * x
1286: + (m00 * m22 - m02 * m20) * y + (m02 * m10 - m00 * m12);
1287: double w = (m10 * m21 - m11 * m20) * x
1288: + (m01 * m20 - m00 * m21) * y + (m00 * m11 - m01 * m10);
1289:
1290: double wabs = w;
1291: if (w < 0) {
1292: wabs = -w;
1293: }
1294: if (wabs < PERSPECTIVE_DIVIDE_EPSILON) {
1295: throw new NoninvertibleTransformException(JaiI18N
1296: .getString("PerspectiveTransform1"));
1297: }
1298:
1299: ptDst.setLocation(tmp_x / w, tmp_y / w);
1300:
1301: return ptDst;
1302: }
1303:
1304: /**
1305: * Inverse transforms an array of double precision coordinates by
1306: * this transform.
1307: * @param srcPts The array containing the source point coordinates.
1308: * Each point is stored as a pair of x,y coordinates.
1309: * @param dstPts The array where the transformed point coordinates are
1310: * returned. Each point is stored as a pair of x,y coordinates.
1311: * @param srcOff The offset to the first point to be transformed
1312: * in the source array.
1313: * @param dstOff The offset to the location where the first transformed
1314: * point is stored in the destination array.
1315: * @param numPts The number of point objects to be transformed.
1316: * @throws NoninvertibleTransformException if the matrix cannot be
1317: * inverted.
1318: * @throws IllegalArgumentException if srcPts is null
1319: * @throws ArrayIndexOutOfBoundsException if srcPts is too small
1320: * @throws NoninvertibleTransformException transform cannot be inverted
1321: */
1322: public void inverseTransform(double[] srcPts, int srcOff,
1323: double[] dstPts, int dstOff, int numPts)
1324: throws NoninvertibleTransformException {
1325: if (srcPts == null) {
1326: throw new IllegalArgumentException(JaiI18N
1327: .getString("Generic0"));
1328: }
1329:
1330: if (dstPts == null) {
1331: dstPts = new double[numPts * 2 + dstOff];
1332: }
1333:
1334: while (numPts-- > 0) {
1335: double x = srcPts[srcOff++];
1336: double y = srcPts[srcOff++];
1337:
1338: double tmp_x = (m11 * m22 - m12 * m21) * x
1339: + (m02 * m21 - m01 * m22) * y
1340: + (m01 * m12 - m02 * m11);
1341: double tmp_y = (m12 * m20 - m10 * m22) * x
1342: + (m00 * m22 - m02 * m20) * y
1343: + (m02 * m10 - m00 * m12);
1344: double w = (m10 * m21 - m11 * m20) * x
1345: + (m01 * m20 - m00 * m21) * y
1346: + (m00 * m11 - m01 * m10);
1347:
1348: double wabs = w;
1349: if (w < 0) {
1350: wabs = -w;
1351: }
1352: if (wabs < PERSPECTIVE_DIVIDE_EPSILON) {
1353: throw new NoninvertibleTransformException(JaiI18N
1354: .getString("PerspectiveTransform1"));
1355: }
1356:
1357: dstPts[dstOff++] = tmp_x / w;
1358: dstPts[dstOff++] = tmp_y / w;
1359: }
1360: }
1361:
1362: /**
1363: * Returns a String that represents the value of this Object.
1364: */
1365: public String toString() {
1366: StringBuffer sb = new StringBuffer();
1367: sb.append("Perspective transform matrix\n");
1368: sb.append(this .m00);
1369: sb.append("\t");
1370: sb.append(this .m01);
1371: sb.append("\t");
1372: sb.append(this .m02);
1373: sb.append("\n");
1374: sb.append(this .m10);
1375: sb.append("\t");
1376: sb.append(this .m11);
1377: sb.append("\t");
1378: sb.append(this .m12);
1379: sb.append("\n");
1380: sb.append(this .m20);
1381: sb.append("\t");
1382: sb.append(this .m21);
1383: sb.append("\t");
1384: sb.append(this .m22);
1385: sb.append("\n");
1386: return new String(sb);
1387: }
1388:
1389: /**
1390: * Returns the boolean true value if this PerspectiveTransform is an
1391: * identity transform. Returns false otherwise.
1392: */
1393: public boolean isIdentity() {
1394: return m01 == 0.0 && m02 == 0.0 && m10 == 0.0 && m12 == 0.0
1395: && m20 == 0.0 && m21 == 0.0 && m22 != 0.0
1396: && m00 / m22 == 1.0 && m11 / m22 == 1.0;
1397: }
1398:
1399: /**
1400: * Returns a copy of this PerspectiveTransform object.
1401: */
1402: public Object clone() {
1403: try {
1404: return super .clone();
1405: } catch (CloneNotSupportedException e) {
1406: // this shouldn't happen, since we are Cloneable
1407: throw new InternalError();
1408: }
1409: }
1410:
1411: /**
1412: * Tests if this PerspectiveTransform equals a supplied one.
1413: *
1414: * @param obj The PerspectiveTransform to be compared to this one.
1415: */
1416: public boolean equals(Object obj) {
1417: if (!(obj instanceof PerspectiveTransform)) {
1418: return false;
1419: }
1420:
1421: PerspectiveTransform a = (PerspectiveTransform) obj;
1422:
1423: return ((m00 == a.m00) && (m10 == a.m10) && (m20 == a.m20)
1424: && (m01 == a.m01) && (m11 == a.m11) && (m21 == a.m21)
1425: && (m02 == a.m02) && (m12 == a.m12) && (m22 == a.m22));
1426: }
1427: }
|