1 /* 2 * $RCSfile: PerspectiveTransform.java,v $ 3 * 4 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. 5 * 6 * Use is subject to license terms. 7 * 8 * $Revision: 1.1 $ 9 * $Date: 2005/02/11 04:57:15 $ 10 * $State: Exp $ 11 */ 12 package com.lightcrafts.mediax.jai; 13 import java.awt.geom.AffineTransform; 14 import java.awt.geom.Point2D; 15 import java.awt.geom.NoninvertibleTransformException; 16 import java.io.Serializable; 17 18 19 /** 20 * A 2D perspective (or projective) transform, used by various OpImages. 21 * 22 * <p> A perspective transformation is capable of mapping an arbitrary 23 * quadrilateral into another arbitrary quadrilateral, while 24 * preserving the straightness of lines. Unlike an affine 25 * transformation, the parallelism of lines in the source is not 26 * necessarily preserved in the output. 27 * 28 * <p> Such a coordinate transformation can be represented by a 3x3 29 * matrix which transforms homogenous source coordinates 30 * <code>(x, y, 1)</code> into destination coordinates 31 * <code>(x', y', w)</code>. To convert back into non-homogenous 32 * coordinates (X, Y), <code>x'</code> and <code>y'</code> are divided by 33 * <code>w</code>. 34 * 35 * <pre> 36 * [ x'] [ m00 m01 m02 ] [ x ] [ m00x + m01y + m02 ] 37 * [ y'] = [ m10 m11 m12 ] [ y ] = [ m10x + m11y + m12 ] 38 * [ w ] [ m20 m21 m22 ] [ 1 ] [ m20x + m21y + m22 ] 39 * 40 * x' = (m00x + m01y + m02) 41 * y' = (m10x + m11y + m12) 42 * 43 * w = (m20x + m21y + m22) 44 * 45 * X = x' / w 46 * Y = y' / w 47 * </pre> 48 */ 49 public final class PerspectiveTransform implements Cloneable, Serializable { 50 51 private static final double PERSPECTIVE_DIVIDE_EPSILON = 1.0e-10; 52 53 /** An element of the transform matrix. */ 54 double m00, m01, m02, m10, m11, m12, m20, m21, m22; 55 56 /** Constructs an identity PerspectiveTransform. */ PerspectiveTransform()57 public PerspectiveTransform() { 58 m00 = m11 = m22 = 1.0; 59 m01 = m02 = m10 = m12 = m20 = m21 = 0.0; 60 } 61 62 /** 63 * Constructs a new PerspectiveTransform from 9 floats. 64 * @deprecated as of JAI 1.1 Use PerspectiveTransform(double[][]) instead. 65 */ PerspectiveTransform(float m00, float m01, float m02, float m10, float m11, float m12, float m20, float m21, float m22)66 public PerspectiveTransform(float m00, float m01, float m02, 67 float m10, float m11, float m12, 68 float m20, float m21, float m22) { 69 this.m00 = m00; 70 this.m01 = m01; 71 this.m02 = m02; 72 this.m10 = m10; 73 this.m11 = m11; 74 this.m12 = m12; 75 this.m20 = m20; 76 this.m21 = m21; 77 this.m22 = m22; 78 } 79 80 /** 81 * Constructs a new PerspectiveTransform from 9 doubles. 82 * @deprecated as of JAI 1.1 Use PerspectiveTransform(double[][]) instead. 83 */ PerspectiveTransform(double m00, double m01, double m02, double m10, double m11, double m12, double m20, double m21, double m22)84 public PerspectiveTransform(double m00, double m01, double m02, 85 double m10, double m11, double m12, 86 double m20, double m21, double m22) { 87 this.m00 = m00; 88 this.m01 = m01; 89 this.m02 = m02; 90 this.m10 = m10; 91 this.m11 = m11; 92 this.m12 = m12; 93 this.m20 = m20; 94 this.m21 = m21; 95 this.m22 = m22; 96 } 97 98 /** 99 * Constructs a new PerspectiveTransform from a one-dimensional 100 * array of 9 floats, in row-major order. 101 * The values in the array are assumed to be 102 * { m00 m01 m02 m10 m11 m12 m20 m21 m22 }. 103 * @throws IllegalArgumentException if flatmatrix is null 104 * @throws ArrayIndexOutOfBoundsException if flatmatrix is too small 105 * @deprecated as of JAI 1.1 Use PerspectiveTransform(double[][]) instead. 106 */ PerspectiveTransform(float[] flatmatrix)107 public PerspectiveTransform(float[] flatmatrix) { 108 if ( flatmatrix == null ) { 109 throw new IllegalArgumentException(JaiI18N.getString("Generic0")); 110 } 111 112 m00 = flatmatrix[0]; 113 m01 = flatmatrix[1]; 114 m02 = flatmatrix[2]; 115 m10 = flatmatrix[3]; 116 m11 = flatmatrix[4]; 117 m12 = flatmatrix[5]; 118 m20 = flatmatrix[6]; 119 m21 = flatmatrix[7]; 120 m22 = flatmatrix[8]; 121 } 122 123 /** 124 * Constructs a new PerspectiveTransform from a two-dimensional 125 * array of floats. 126 * @throws IllegalArgumentException if matrix is null 127 * @throws ArrayIndexOutOfBoundsException if matrix is too small 128 * 129 * @deprecated as of JAI 1.1 Use PerspectiveTransform(double[][]) instead. 130 */ PerspectiveTransform(float[][] matrix)131 public PerspectiveTransform(float[][] matrix) { 132 if ( matrix == null ) { 133 throw new IllegalArgumentException(JaiI18N.getString("Generic0")); 134 } 135 136 m00 = matrix[0][0]; 137 m01 = matrix[0][1]; 138 m02 = matrix[0][2]; 139 m10 = matrix[1][0]; 140 m11 = matrix[1][1]; 141 m12 = matrix[1][2]; 142 m20 = matrix[2][0]; 143 m21 = matrix[2][1]; 144 m22 = matrix[2][2]; 145 } 146 147 /** 148 * Constructs a new PerspectiveTransform from a one-dimensional 149 * array of 9 doubles, in row-major order. 150 * The values in the array are assumed to be 151 * { m00 m01 m02 m10 m11 m12 m20 m21 m22 }. 152 * @throws IllegalArgumentException if flatmatrix is null 153 * @throws ArrayIndexOutOfBoundsException if flatmatrix is too small 154 * 155 * @deprecated as of JAI 1.1 Use PerspectiveTransform(double[][]) instead. 156 */ PerspectiveTransform(double[] flatmatrix)157 public PerspectiveTransform(double[] flatmatrix) { 158 if ( flatmatrix == null ) { 159 throw new IllegalArgumentException(JaiI18N.getString("Generic0")); 160 } 161 162 m00 = flatmatrix[0]; 163 m01 = flatmatrix[1]; 164 m02 = flatmatrix[2]; 165 m10 = flatmatrix[3]; 166 m11 = flatmatrix[4]; 167 m12 = flatmatrix[5]; 168 m20 = flatmatrix[6]; 169 m21 = flatmatrix[7]; 170 m22 = flatmatrix[8]; 171 } 172 173 /** 174 * Constructs a new PerspectiveTransform from a two-dimensional 175 * array of doubles. 176 * @throws IllegalArgumentException if matrix is null 177 * @throws ArrayIndexOutOfBoundsException if matrix is too small 178 */ PerspectiveTransform(double[][] matrix)179 public PerspectiveTransform(double[][] matrix) { 180 if ( matrix == null ) { 181 throw new IllegalArgumentException(JaiI18N.getString("Generic0")); 182 } 183 184 m00 = matrix[0][0]; 185 m01 = matrix[0][1]; 186 m02 = matrix[0][2]; 187 m10 = matrix[1][0]; 188 m11 = matrix[1][1]; 189 m12 = matrix[1][2]; 190 m20 = matrix[2][0]; 191 m21 = matrix[2][1]; 192 m22 = matrix[2][2]; 193 } 194 195 /** 196 * Constructs a new PerspectiveTransform with the same effect 197 * as an existing AffineTransform. 198 * @throws IllegalArgumentException if transform is null 199 */ PerspectiveTransform(AffineTransform transform)200 public PerspectiveTransform(AffineTransform transform) { 201 if ( transform == null ) { 202 throw new IllegalArgumentException(JaiI18N.getString("Generic0")); 203 } 204 205 m00 = transform.getScaleX(); 206 m01 = transform.getShearX(); 207 m02 = transform.getTranslateX(); 208 m10 = transform.getShearY(); 209 m11 = transform.getScaleY(); 210 m12 = transform.getTranslateY(); 211 m20 = 0.0; 212 m21 = 0.0; 213 m22 = 1.0; 214 } 215 216 /** 217 * Replaces the matrix with its adjoint. 218 */ makeAdjoint()219 private final void makeAdjoint() { 220 double m00p = m11*m22 - m12*m21; 221 double m01p = m12*m20 - m10*m22; // flipped sign 222 double m02p = m10*m21 - m11*m20; 223 double m10p = m02*m21 - m01*m22; // flipped sign 224 double m11p = m00*m22 - m02*m20; 225 double m12p = m01*m20 - m00*m21; // flipped sign 226 double m20p = m01*m12 - m02*m11; 227 double m21p = m02*m10 - m00*m12; // flipped sign 228 double m22p = m00*m11 - m01*m10; 229 230 // Transpose and copy sub-determinants 231 m00 = m00p; 232 m01 = m10p; 233 m02 = m20p; 234 m10 = m01p; 235 m11 = m11p; 236 m12 = m21p; 237 m20 = m02p; 238 m21 = m12p; 239 m22 = m22p; 240 } 241 242 /** 243 * Scales the matrix elements so m22 is equal to 1.0. 244 * m22 must not be equal to 0. 245 */ normalize()246 private final void normalize() { 247 double invscale = 1.0/m22; 248 m00 *= invscale; 249 m01 *= invscale; 250 m02 *= invscale; 251 m10 *= invscale; 252 m11 *= invscale; 253 m12 *= invscale; 254 m20 *= invscale; 255 m21 *= invscale; 256 m22 = 1.0; 257 } 258 getSquareToQuad(double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3, PerspectiveTransform tx)259 private static final void getSquareToQuad(double x0, double y0, 260 double x1, double y1, 261 double x2, double y2, 262 double x3, double y3, 263 PerspectiveTransform tx) { 264 double dx3 = x0 - x1 + x2 - x3; 265 double dy3 = y0 - y1 + y2 - y3; 266 267 tx.m22 = 1.0F; 268 269 if ((dx3 == 0.0F) && (dy3 == 0.0F)) { // to do: use tolerance 270 tx.m00 = x1 - x0; 271 tx.m01 = x2 - x1; 272 tx.m02 = x0; 273 tx.m10 = y1 - y0; 274 tx.m11 = y2 - y1; 275 tx.m12 = y0; 276 tx.m20 = 0.0F; 277 tx.m21 = 0.0F; 278 } else { 279 double dx1 = x1 - x2; 280 double dy1 = y1 - y2; 281 double dx2 = x3 - x2; 282 double dy2 = y3 - y2; 283 284 double invdet = 1.0F/(dx1*dy2 - dx2*dy1); 285 tx.m20 = (dx3*dy2 - dx2*dy3)*invdet; 286 tx.m21 = (dx1*dy3 - dx3*dy1)*invdet; 287 tx.m00 = x1 - x0 + tx.m20*x1; 288 tx.m01 = x3 - x0 + tx.m21*x3; 289 tx.m02 = x0; 290 tx.m10 = y1 - y0 + tx.m20*y1; 291 tx.m11 = y3 - y0 + tx.m21*y3; 292 tx.m12 = y0; 293 } 294 } 295 296 /** 297 * Creates a PerspectiveTransform that maps the unit square 298 * onto an arbitrary quadrilateral. 299 * 300 * <pre> 301 * (0, 0) -> (x0, y0) 302 * (1, 0) -> (x1, y1) 303 * (1, 1) -> (x2, y2) 304 * (0, 1) -> (x3, y3) 305 * </pre> 306 */ getSquareToQuad(double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3)307 public static PerspectiveTransform getSquareToQuad(double x0, double y0, 308 double x1, double y1, 309 double x2, double y2, 310 double x3, double y3) { 311 PerspectiveTransform tx = new PerspectiveTransform(); 312 getSquareToQuad(x0, y0, x1, y1, x2, y2, x3, y3, tx); 313 return tx; 314 } 315 316 317 /** 318 * Creates a PerspectiveTransform that maps the unit square 319 * onto an arbitrary quadrilateral. 320 * 321 * <pre> 322 * (0, 0) -> (x0, y0) 323 * (1, 0) -> (x1, y1) 324 * (1, 1) -> (x2, y2) 325 * (0, 1) -> (x3, y3) 326 * </pre> 327 */ getSquareToQuad(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3)328 public static PerspectiveTransform getSquareToQuad(float x0, float y0, 329 float x1, float y1, 330 float x2, float y2, 331 float x3, float y3) { 332 return getSquareToQuad((double)x0, (double)y0, 333 (double)x1, (double)y1, 334 (double)x2, (double)y2, 335 (double)x3, (double)y3); 336 } 337 338 339 /** 340 * Creates a PerspectiveTransform that maps an arbitrary 341 * quadrilateral onto the unit square. 342 * 343 * <pre> 344 * (x0, y0) -> (0, 0) 345 * (x1, y1) -> (1, 0) 346 * (x2, y2) -> (1, 1) 347 * (x3, y3) -> (0, 1) 348 * </pre> 349 */ getQuadToSquare(double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3)350 public static PerspectiveTransform getQuadToSquare(double x0, double y0, 351 double x1, double y1, 352 double x2, double y2, 353 double x3, double y3) { 354 PerspectiveTransform tx = new PerspectiveTransform(); 355 getSquareToQuad(x0, y0, x1, y1, x2, y2, x3, y3, tx); 356 tx.makeAdjoint(); 357 return tx; 358 } 359 360 /** 361 * Creates a PerspectiveTransform that maps an arbitrary 362 * quadrilateral onto the unit square. 363 * 364 * <pre> 365 * (x0, y0) -> (0, 0) 366 * (x1, y1) -> (1, 0) 367 * (x2, y2) -> (1, 1) 368 * (x3, y3) -> (0, 1) 369 * </pre> 370 */ getQuadToSquare(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3)371 public static PerspectiveTransform getQuadToSquare(float x0, float y0, 372 float x1, float y1, 373 float x2, float y2, 374 float x3, float y3) { 375 return getQuadToSquare((double)x0, (double)y0, 376 (double)x1, (double)y1, 377 (double)x2, (double)y2, 378 (double)x3, (double)y3); 379 } 380 381 /** 382 * Creates a PerspectiveTransform that maps an arbitrary 383 * quadrilateral onto another arbitrary quadrilateral. 384 * 385 * <pre> 386 * (x0, y0) -> (x0p, y0p) 387 * (x1, y1) -> (x1p, y1p) 388 * (x2, y2) -> (x2p, y2p) 389 * (x3, y3) -> (x3p, y3p) 390 * </pre> 391 */ getQuadToQuad(double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3, double x0p, double y0p, double x1p, double y1p, double x2p, double y2p, double x3p, double y3p)392 public static PerspectiveTransform getQuadToQuad(double x0, double y0, 393 double x1, double y1, 394 double x2, double y2, 395 double x3, double y3, 396 double x0p, double y0p, 397 double x1p, double y1p, 398 double x2p, double y2p, 399 double x3p, double y3p) { 400 PerspectiveTransform tx1 = 401 getQuadToSquare(x0, y0, x1, y1, x2, y2, x3, y3); 402 403 PerspectiveTransform tx2 = 404 getSquareToQuad(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p); 405 406 tx1.concatenate(tx2); 407 return tx1; 408 } 409 410 411 /** 412 * Creates a PerspectiveTransform that maps an arbitrary 413 * quadrilateral onto another arbitrary quadrilateral. 414 * 415 * <pre> 416 * (x0, y0) -> (x0p, y0p) 417 * (x1, y1) -> (x1p, y1p) 418 * (x2, y2) -> (x2p, y2p) 419 * (x3, y3) -> (x3p, y3p) 420 * </pre> 421 */ getQuadToQuad(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float x0p, float y0p, float x1p, float y1p, float x2p, float y2p, float x3p, float y3p)422 public static PerspectiveTransform getQuadToQuad(float x0, float y0, 423 float x1, float y1, 424 float x2, float y2, 425 float x3, float y3, 426 float x0p, float y0p, 427 float x1p, float y1p, 428 float x2p, float y2p, 429 float x3p, float y3p) { 430 return getQuadToQuad((double)x0, (double)y0, 431 (double)x1, (double)y1, 432 (double)x2, (double)y2, 433 (double)x3, (double)y3, 434 (double)x0p, (double)y0p, 435 (double)x1p, (double)y1p, 436 (double)x2p, (double)y2p, 437 (double)x3p, (double)y3p); 438 } 439 440 /** 441 * Returns the determinant of the matrix representation of the 442 * transform. 443 */ getDeterminant()444 public double getDeterminant() { 445 return ( (m00 * ((m11 * m22) - (m12 * m21))) - 446 (m01 * ((m10 * m22) - (m12 * m20))) + 447 (m02 * ((m10 * m21) - (m11 * m20))) ); 448 449 } 450 451 /** 452 * Retrieves the 9 specifiable values in the 3x3 affine 453 * transformation matrix into an array of double precision values. 454 * The values are stored into the array as 455 * { m00 m01 m02 m10 m11 m12 m20 m21 m22 }. 456 * 457 * @param flatmatrix The double array used to store the returned 458 * values. The length of the array is assumed to be at 459 * least 9. 460 * @throws ArrayIndexOutOfBoundsException if flatmatrix is too small 461 * @deprecated as of JAI 1.1 Use double[][] getMatrix(double[][] matrix) instead. 462 */ getMatrix(double[] flatmatrix)463 public double[] getMatrix(double[] flatmatrix) { 464 if (flatmatrix == null) { 465 flatmatrix = new double[9]; 466 } 467 468 flatmatrix[0] = m00; 469 flatmatrix[1] = m01; 470 flatmatrix[2] = m02; 471 flatmatrix[3] = m10; 472 flatmatrix[4] = m11; 473 flatmatrix[5] = m12; 474 flatmatrix[6] = m20; 475 flatmatrix[7] = m21; 476 flatmatrix[8] = m22; 477 478 return flatmatrix; 479 } 480 481 /** 482 * Retrieves the 9 specifiable values in the 3x3 affine 483 * transformation matrix into a 2-dimensional array of double 484 * precision values. The values are stored into the 2-dimensional 485 * array using the row index as the first subscript and the column 486 * index as the second. 487 * 488 * @param matrix The 2-dimensional double array to store the 489 * returned values. The array is assumed to be at least 3x3. 490 * @throws ArrayIndexOutOfBoundsException if matrix is too small 491 */ getMatrix(double[][] matrix)492 public double[][] getMatrix(double[][] matrix) { 493 if (matrix == null) { 494 matrix = new double[3][3]; 495 } 496 497 matrix[0][0] = m00; 498 matrix[0][1] = m01; 499 matrix[0][2] = m02; 500 matrix[1][0] = m10; 501 matrix[1][1] = m11; 502 matrix[1][2] = m12; 503 matrix[2][0] = m20; 504 matrix[2][1] = m21; 505 matrix[2][2] = m22; 506 507 return matrix; 508 } 509 510 /** 511 * Concatenates this transform with a translation transformation. 512 * This is equivalent to calling concatenate(T), where T is an 513 * PerspectiveTransform represented by the following matrix: 514 * <pre> 515 * [ 1 0 tx ] 516 * [ 0 1 ty ] 517 * [ 0 0 1 ] 518 * </pre> 519 */ translate(double tx, double ty)520 public void translate(double tx, double ty) { 521 PerspectiveTransform Tx = new PerspectiveTransform(); 522 Tx.setToTranslation(tx, ty); 523 concatenate(Tx); 524 } 525 526 /** 527 * Concatenates this transform with a rotation transformation. 528 * This is equivalent to calling concatenate(R), where R is an 529 * PerspectiveTransform represented by the following matrix: 530 * <pre> 531 * [ cos(theta) -sin(theta) 0 ] 532 * [ sin(theta) cos(theta) 0 ] 533 * [ 0 0 1 ] 534 * </pre> 535 * Rotating with a positive angle theta rotates points on the positive 536 * X axis toward the positive Y axis. 537 * 538 * @param theta The angle of rotation in radians. 539 */ rotate(double theta)540 public void rotate(double theta) { 541 PerspectiveTransform Tx = new PerspectiveTransform(); 542 Tx.setToRotation(theta); 543 concatenate(Tx); 544 } 545 546 /** 547 * Concatenates this transform with a translated rotation transformation. 548 * This is equivalent to the following sequence of calls: 549 * <pre> 550 * translate(x, y); 551 * rotate(theta); 552 * translate(-x, -y); 553 * </pre> 554 * Rotating with a positive angle theta rotates points on the positive 555 * X axis toward the positive Y axis. 556 * 557 * @param theta The angle of rotation in radians. 558 * @param x The X coordinate of the origin of the rotation 559 * @param y The Y coordinate of the origin of the rotation 560 */ rotate(double theta, double x, double y)561 public void rotate(double theta, double x, double y) { 562 PerspectiveTransform Tx = new PerspectiveTransform(); 563 Tx.setToRotation(theta, x, y); 564 concatenate(Tx); 565 } 566 567 /** 568 * Concatenates this transform with a scaling transformation. 569 * This is equivalent to calling concatenate(S), where S is an 570 * PerspectiveTransform represented by the following matrix: 571 * <pre> 572 * [ sx 0 0 ] 573 * [ 0 sy 0 ] 574 * [ 0 0 1 ] 575 * </pre> 576 * 577 * @param sx The X axis scale factor. 578 * @param sy The Y axis scale factor. 579 */ scale(double sx, double sy)580 public void scale(double sx, double sy) { 581 PerspectiveTransform Tx = new PerspectiveTransform(); 582 Tx.setToScale(sx, sy); 583 concatenate(Tx); 584 } 585 586 /** 587 * Concatenates this transform with a shearing transformation. 588 * This is equivalent to calling concatenate(SH), where SH is an 589 * PerspectiveTransform represented by the following matrix: 590 * <pre> 591 * [ 1 shx 0 ] 592 * [ shy 1 0 ] 593 * [ 0 0 1 ] 594 * </pre> 595 * 596 * @param shx The factor by which coordinates are shifted towards 597 * the positive X axis direction according to their Y 598 * coordinate. 599 * @param shy The factor by which coordinates are shifted towards 600 * the positive Y axis direction according to their X 601 * coordinate. 602 */ shear(double shx, double shy)603 public void shear(double shx, double shy) { 604 PerspectiveTransform Tx = new PerspectiveTransform(); 605 Tx.setToShear(shx, shy); 606 concatenate(Tx); 607 } 608 609 /** 610 * Resets this transform to the Identity transform. 611 */ setToIdentity()612 public void setToIdentity() { 613 m00 = m11 = m22 = 1.0; 614 m01 = m10 = m02 = m20 = m12 = m21 = 0.0; 615 } 616 617 /** 618 * Sets this transform to a translation transformation. 619 * The matrix representing this transform becomes: 620 * <pre> 621 * [ 1 0 tx ] 622 * [ 0 1 ty ] 623 * [ 0 0 1 ] 624 * </pre> 625 * @param tx The distance by which coordinates are translated in the 626 * X axis direction 627 * @param ty The distance by which coordinates are translated in the 628 * Y axis direction 629 */ setToTranslation(double tx, double ty)630 public void setToTranslation(double tx, double ty) { 631 m00 = 1.0; 632 m01 = 0.0; 633 m02 = tx; 634 m10 = 0.0; 635 m11 = 1.0; 636 m12 = ty; 637 m20 = 0.0; 638 m21 = 0.0; 639 m22 = 1.0; 640 } 641 642 /** 643 * Sets this transform to a rotation transformation. 644 * The matrix representing this transform becomes: 645 * <pre> 646 * [ cos(theta) -sin(theta) 0 ] 647 * [ sin(theta) cos(theta) 0 ] 648 * [ 0 0 1 ] 649 * </pre> 650 * Rotating with a positive angle theta rotates points on the positive 651 * X axis toward the positive Y axis. 652 * @param theta The angle of rotation in radians. 653 */ setToRotation(double theta)654 public void setToRotation(double theta) { 655 m00 = Math.cos(theta); 656 m01 = -Math.sin(theta); 657 m02 = 0.0; 658 m10 = - m01; // Math.sin(theta); 659 m11 = m00; // Math.cos(theta); 660 m12 = 0.0; 661 m20 = 0.0; 662 m21 = 0.0; 663 m22 = 1.0; 664 } 665 666 /** 667 * Sets this transform to a rotation transformation 668 * about a specified point (x, y). This is equivalent 669 * to the following sequence of calls: 670 * 671 * <pre> 672 * setToTranslate(x, y); 673 * rotate(theta); 674 * translate(-x, -y); 675 * </pre> 676 * 677 * Rotating with a positive angle theta rotates points on the positive 678 * X axis toward the positive Y axis. 679 * 680 * @param theta The angle of rotation in radians. 681 * @param x The X coordinate of the origin of the rotation 682 * @param y The Y coordinate of the origin of the rotation 683 */ setToRotation(double theta, double x, double y)684 public void setToRotation(double theta, double x, double y) { 685 setToRotation(theta); 686 double sin = m10; 687 double oneMinusCos = 1.0 - m00; 688 m02 = x * oneMinusCos + y * sin; 689 m12 = y * oneMinusCos - x * sin; 690 } 691 692 /** 693 * Sets this transform to a scale transformation 694 * with scale factors sx and sy. 695 * The matrix representing this transform becomes: 696 * <pre> 697 * [ sx 0 0 ] 698 * [ 0 sy 0 ] 699 * [ 0 0 1 ] 700 * </pre> 701 * 702 * @param sx The X axis scale factor. 703 * @param sy The Y axis scale factor. 704 */ setToScale(double sx, double sy)705 public void setToScale(double sx, double sy) { 706 m00 = sx; 707 m01 = 0.0; 708 m02 = 0.0; 709 m10 = 0.0; 710 m11 = sy; 711 m12 = 0.0; 712 m20 = 0.0; 713 m21 = 0.0; 714 m22 = 1.0; 715 } 716 717 /** 718 * Sets this transform to a shearing transformation 719 * with shear factors sx and sy. 720 * The matrix representing this transform becomes: 721 * <pre> 722 * [ 1 shx 0 ] 723 * [ shy 1 0 ] 724 * [ 0 0 1 ] 725 * </pre> 726 * 727 * @param shx The factor by which coordinates are shifted towards 728 * the positive X axis direction according to their Y 729 * coordinate. 730 * @param shy The factor by which coordinates are shifted towards 731 * the positive Y axis direction according to their X 732 * coordinate. 733 */ setToShear(double shx, double shy)734 public void setToShear(double shx, double shy) { 735 m00 = 1.0; 736 m01 = shx; 737 m02 = 0.0; 738 m10 = shy; 739 m11 = 1.0; 740 m12 = 0.0; 741 m20 = 0.0; 742 m21 = 0.0; 743 m22 = 1.0; 744 } 745 746 /** 747 * Sets this transform to a given AffineTransform. 748 * @throws IllegalArgumentException if Tx is null 749 */ setTransform(AffineTransform Tx)750 public void setTransform(AffineTransform Tx) { 751 if ( Tx == null ) { 752 throw new IllegalArgumentException(JaiI18N.getString("Generic0")); 753 } 754 755 m00 = Tx.getScaleX(); 756 m01 = Tx.getShearX(); 757 m02 = Tx.getTranslateX(); 758 m10 = Tx.getShearY(); 759 m11 = Tx.getScaleY(); 760 m12 = Tx.getTranslateY(); 761 m20 = 0.0; 762 m21 = 0.0; 763 m22 = 1.0; 764 } 765 766 /** 767 * Sets this transform to a given PerspectiveTransform. 768 * @throws IllegalArgumentException if Tx is null 769 */ setTransform(PerspectiveTransform Tx)770 public void setTransform(PerspectiveTransform Tx) { 771 if ( Tx == null ) { 772 throw new IllegalArgumentException(JaiI18N.getString("Generic0")); 773 } 774 775 m00 = Tx.m00; 776 m01 = Tx.m01; 777 m02 = Tx.m02; 778 m10 = Tx.m10; 779 m11 = Tx.m11; 780 m12 = Tx.m12; 781 m20 = Tx.m20; 782 m21 = Tx.m21; 783 m22 = Tx.m22; 784 } 785 786 /** 787 * Sets this transform to a given PerspectiveTransform, 788 * expressed by the elements of its matrix. <i>Important Note: The 789 * matrix elements in the argument list are in column-major order 790 * unlike those of the constructor, which are in row-major order.</i> 791 * @deprecated as of JAI 1.1 Use double[][] getMatrix(double[][] matrix) instead. 792 */ setTransform(float m00, float m10, float m20, float m01, float m11, float m21, float m02, float m12, float m22)793 public void setTransform(float m00, float m10, float m20, 794 float m01, float m11, float m21, 795 float m02, float m12, float m22) { 796 this.m00 = (double)m00; 797 this.m01 = (double)m01; 798 this.m02 = (double)m02; 799 this.m10 = (double)m10; 800 this.m11 = (double)m11; 801 this.m12 = (double)m12; 802 this.m20 = (double)m20; 803 this.m21 = (double)m21; 804 this.m22 = (double)m22; 805 } 806 807 /** 808 * Sets this transform using a two-dimensional array of double precision 809 * values. The row index is first, and the column index is second. 810 * 811 * @param matrix The 2D double array to be used for setting this transform. 812 * The array is assumed to be at least 3x3. 813 * @throws IllegalArgumentException if matrix is null 814 * @throws ArrayIndexOutOfBoundsException if matrix is too small 815 * @since JAI 1.1 816 */ setTransform(double[][] matrix)817 public void setTransform(double[][] matrix) { 818 if ( matrix == null ) { 819 throw new IllegalArgumentException(JaiI18N.getString("Generic0")); 820 } 821 822 m00 = matrix[0][0]; 823 m01 = matrix[0][1]; 824 m02 = matrix[0][2]; 825 m10 = matrix[1][0]; 826 m11 = matrix[1][1]; 827 m12 = matrix[1][2]; 828 m20 = matrix[2][0]; 829 m21 = matrix[2][1]; 830 m22 = matrix[2][2]; 831 } 832 833 /** 834 * Post-concatenates a given AffineTransform to this transform. 835 * @throws IllegalArgumentException if Tx is null 836 */ concatenate(AffineTransform Tx)837 public void concatenate(AffineTransform Tx) { 838 if ( Tx == null ) { 839 throw new IllegalArgumentException(JaiI18N.getString("Generic0")); 840 } 841 842 // Extend Tx: Tx.m20 = 0, Tx.m21 = 0, Tx.m22 = 1 843 844 double tx_m00 = Tx.getScaleX(); 845 double tx_m01 = Tx.getShearX(); 846 double tx_m02 = Tx.getTranslateX(); 847 double tx_m10 = Tx.getShearY(); 848 double tx_m11 = Tx.getScaleY(); 849 double tx_m12 = Tx.getTranslateY(); 850 851 double m00p = m00*tx_m00 + m10*tx_m01 + m20*tx_m02; 852 double m01p = m01*tx_m00 + m11*tx_m01 + m21*tx_m02; 853 double m02p = m02*tx_m00 + m12*tx_m01 + m22*tx_m02; 854 double m10p = m00*tx_m10 + m10*tx_m11 + m20*tx_m12; 855 double m11p = m01*tx_m10 + m11*tx_m11 + m21*tx_m12; 856 double m12p = m02*tx_m10 + m12*tx_m11 + m22*tx_m12; 857 double m20p = m20; 858 double m21p = m21; 859 double m22p = m22; 860 861 m00 = m00p; 862 m10 = m10p; 863 m20 = m20p; 864 m01 = m01p; 865 m11 = m11p; 866 m21 = m21p; 867 m02 = m02p; 868 m12 = m12p; 869 m22 = m22p; 870 } 871 872 /** 873 * Post-concatenates a given PerspectiveTransform to this transform. 874 * @throws IllegalArgumentException if Tx is null 875 */ concatenate(PerspectiveTransform Tx)876 public void concatenate(PerspectiveTransform Tx) { 877 if ( Tx == null ) { 878 throw new IllegalArgumentException(JaiI18N.getString("Generic0")); 879 } 880 881 double m00p = m00*Tx.m00 + m10*Tx.m01 + m20*Tx.m02; 882 double m10p = m00*Tx.m10 + m10*Tx.m11 + m20*Tx.m12; 883 double m20p = m00*Tx.m20 + m10*Tx.m21 + m20*Tx.m22; 884 double m01p = m01*Tx.m00 + m11*Tx.m01 + m21*Tx.m02; 885 double m11p = m01*Tx.m10 + m11*Tx.m11 + m21*Tx.m12; 886 double m21p = m01*Tx.m20 + m11*Tx.m21 + m21*Tx.m22; 887 double m02p = m02*Tx.m00 + m12*Tx.m01 + m22*Tx.m02; 888 double m12p = m02*Tx.m10 + m12*Tx.m11 + m22*Tx.m12; 889 double m22p = m02*Tx.m20 + m12*Tx.m21 + m22*Tx.m22; 890 891 m00 = m00p; 892 m10 = m10p; 893 m20 = m20p; 894 m01 = m01p; 895 m11 = m11p; 896 m21 = m21p; 897 m02 = m02p; 898 m12 = m12p; 899 m22 = m22p; 900 } 901 902 /** 903 * Pre-concatenates a given AffineTransform to this transform. 904 * @throws IllegalArgumentException if Tx is null 905 */ preConcatenate(AffineTransform Tx)906 public void preConcatenate(AffineTransform Tx) { 907 if ( Tx == null ) { 908 throw new IllegalArgumentException(JaiI18N.getString("Generic0")); 909 } 910 911 // Extend Tx: Tx.m20 = 0, Tx.m21 = 0, Tx.m22 = 1 912 913 double tx_m00 = Tx.getScaleX(); 914 double tx_m01 = Tx.getShearX(); 915 double tx_m02 = Tx.getTranslateX(); 916 double tx_m10 = Tx.getShearY(); 917 double tx_m11 = Tx.getScaleY(); 918 double tx_m12 = Tx.getTranslateY(); 919 920 double m00p = tx_m00*m00 + tx_m10*m01; 921 double m01p = tx_m01*m00 + tx_m11*m01; 922 double m02p = tx_m02*m00 + tx_m12*m01 + m02; 923 double m10p = tx_m00*m10 + tx_m10*m11; 924 double m11p = tx_m01*m10 + tx_m11*m11; 925 double m12p = tx_m02*m10 + tx_m12*m11 + m12; 926 double m20p = tx_m00*m20 + tx_m10*m21; 927 double m21p = tx_m01*m20 + tx_m11*m21; 928 double m22p = tx_m02*m20 + tx_m12*m21 + m22; 929 930 m00 = m00p; 931 m10 = m10p; 932 m20 = m20p; 933 m01 = m01p; 934 m11 = m11p; 935 m21 = m21p; 936 m02 = m02p; 937 m12 = m12p; 938 m22 = m22p; 939 } 940 941 /** 942 * Pre-concatenates a given PerspectiveTransform to this transform. 943 * @throws IllegalArgumentException if Tx is null 944 */ preConcatenate(PerspectiveTransform Tx)945 public void preConcatenate(PerspectiveTransform Tx) { 946 if ( Tx == null ) { 947 throw new IllegalArgumentException(JaiI18N.getString("Generic0")); 948 } 949 950 double m00p = Tx.m00*m00 + Tx.m10*m01 + Tx.m20*m02; 951 double m10p = Tx.m00*m10 + Tx.m10*m11 + Tx.m20*m12; 952 double m20p = Tx.m00*m20 + Tx.m10*m21 + Tx.m20*m22; 953 double m01p = Tx.m01*m00 + Tx.m11*m01 + Tx.m21*m02; 954 double m11p = Tx.m01*m10 + Tx.m11*m11 + Tx.m21*m12; 955 double m21p = Tx.m01*m20 + Tx.m11*m21 + Tx.m21*m22; 956 double m02p = Tx.m02*m00 + Tx.m12*m01 + Tx.m22*m02; 957 double m12p = Tx.m02*m10 + Tx.m12*m11 + Tx.m22*m12; 958 double m22p = Tx.m02*m20 + Tx.m12*m21 + Tx.m22*m22; 959 960 m00 = m00p; 961 m10 = m10p; 962 m20 = m20p; 963 m01 = m01p; 964 m11 = m11p; 965 m21 = m21p; 966 m02 = m02p; 967 m12 = m12p; 968 m22 = m22p; 969 } 970 971 /** 972 * Returns a new PerpectiveTransform that is the inverse 973 * of the current transform. 974 * @throws NoninvertibleTransformException if transform cannot be inverted 975 */ createInverse()976 public PerspectiveTransform createInverse() 977 throws NoninvertibleTransformException, CloneNotSupportedException { 978 979 PerspectiveTransform tx = (PerspectiveTransform)clone(); 980 tx.makeAdjoint(); 981 if (Math.abs(tx.m22) < PERSPECTIVE_DIVIDE_EPSILON) { 982 throw new NoninvertibleTransformException(JaiI18N.getString("PerspectiveTransform0")); 983 } 984 tx.normalize(); 985 return tx; 986 } 987 988 /** 989 * Returns a new PerpectiveTransform that is the adjoint, 990 * of the current transform. The adjoint is defined as 991 * the matrix of cofactors, which in turn are the determinants 992 * of the submatrices defined by removing the row and column 993 * of each element from the original matrix in turn. 994 * 995 * <p> The adjoint is a scalar multiple of the inverse matrix. 996 * Because points to be transformed are converted into homogeneous 997 * coordinates, where scalar factors are irrelevant, the adjoint 998 * may be used in place of the true inverse. Since it is unnecessary 999 * to normalize the adjoint, it is both faster to compute and more 1000 * numerically stable than the true inverse. 1001 */ createAdjoint()1002 public PerspectiveTransform createAdjoint() 1003 throws CloneNotSupportedException{ 1004 1005 PerspectiveTransform tx = (PerspectiveTransform)clone(); 1006 tx.makeAdjoint(); 1007 return tx; 1008 } 1009 1010 /** 1011 * Transforms the specified ptSrc and stores the result in ptDst. 1012 * If ptDst is null, a new Point2D object will be allocated before 1013 * storing. In either case, ptDst containing the transformed point 1014 * is returned for convenience. 1015 * Note that ptSrc and ptDst can the same. In this case, the input 1016 * point will be overwritten with the transformed point. 1017 * 1018 * @param ptSrc The array containing the source point objects. 1019 * @param ptDst The array where the transform point objects are returned. 1020 * @throws IllegalArgumentException if ptSrc is null 1021 */ transform(Point2D ptSrc, Point2D ptDst)1022 public Point2D transform(Point2D ptSrc, Point2D ptDst) { 1023 if ( ptSrc == null ) { 1024 throw new IllegalArgumentException(JaiI18N.getString("Generic0")); 1025 } 1026 1027 if (ptDst == null) { 1028 if (ptSrc instanceof Point2D.Double) { 1029 ptDst = new Point2D.Double(); 1030 } else { 1031 ptDst = new Point2D.Float(); 1032 } 1033 } 1034 1035 double x = ptSrc.getX(); 1036 double y = ptSrc.getY(); 1037 double w = m20 * x + m21 * y + m22; 1038 ptDst.setLocation((m00 * x + m01 * y + m02) / w, 1039 (m10 * x + m11 * y + m12) / w); 1040 1041 return ptDst; 1042 } 1043 1044 /** 1045 * Transforms an array of point objects by this transform. 1046 * @param ptSrc The array containing the source point objects. 1047 * @param ptDst The array where the transform point objects are returned. 1048 * @param srcOff The offset to the first point object to be transformed 1049 * in the source array. 1050 * @param dstOff The offset to the location where the first transformed 1051 * point object is stored in the destination array. 1052 * @param numPts The number of point objects to be transformed. 1053 * @throws IllegalArgumentException if ptSrc is null 1054 * @throws IllegalArgumentException if ptDst is null 1055 * @throws ArrayIndexOutOfBoundsException if ptSrc is too small 1056 */ transform(Point2D[] ptSrc, int srcOff, Point2D[] ptDst, int dstOff, int numPts)1057 public void transform(Point2D[] ptSrc, int srcOff, 1058 Point2D[] ptDst, int dstOff, 1059 int numPts) { 1060 1061 if ( ptSrc == null || ptDst == null ) { 1062 throw new IllegalArgumentException(JaiI18N.getString("Generic0")); 1063 } 1064 1065 while (numPts-- > 0) { 1066 /* Copy source coords into local variables in case src == dst. */ 1067 Point2D src = ptSrc[srcOff++]; 1068 Point2D dst = ptDst[dstOff++]; 1069 if (dst == null) { 1070 if (src instanceof Point2D.Double) { 1071 dst = new Point2D.Double(); 1072 } else { 1073 dst = new Point2D.Float(); 1074 } 1075 ptDst[dstOff - 1] = dst; 1076 } 1077 1078 double x = src.getX(); 1079 double y = src.getY(); 1080 double w = m20 * x + m21 * y + m22; 1081 1082 if (w == 0) { 1083 dst.setLocation(x, y); 1084 } else { 1085 dst.setLocation((m00 * x + m01 * y + m02) / w, 1086 (m10 * x + m11 * y + m12) / w); 1087 } 1088 } 1089 } 1090 1091 /** 1092 * Transforms an array of floating point coordinates by this transform. 1093 * @param srcPts The array containing the source point coordinates. 1094 * Each point is stored as a pair of x,y coordinates. 1095 * @param srcOff The offset to the first point to be transformed 1096 * in the source array. 1097 * @param dstPts The array where the transformed point coordinates are 1098 * returned. Each point is stored as a pair of x,y coordinates. 1099 * @param dstOff The offset to the location where the first transformed 1100 * point is stored in the destination array. 1101 * @param numPts The number of points to be transformed. 1102 * @throws IllegalArgumentException if srcPts is null 1103 * @throws ArrayIndexOutOfBoundsException if srcPts is too small 1104 */ transform(float[] srcPts, int srcOff, float[] dstPts, int dstOff, int numPts)1105 public void transform(float[] srcPts, int srcOff, 1106 float[] dstPts, int dstOff, 1107 int numPts) { 1108 1109 if ( srcPts == null ) { 1110 throw new IllegalArgumentException(JaiI18N.getString("Generic0")); 1111 } 1112 1113 if (dstPts == null) { 1114 dstPts = new float[numPts * 2 + dstOff]; 1115 } 1116 1117 while (numPts-- > 0) { 1118 float x = srcPts[srcOff++]; 1119 float y = srcPts[srcOff++]; 1120 double w = m20 * x + m21 * y + m22; 1121 1122 if (w == 0) { 1123 dstPts[dstOff++] = x; 1124 dstPts[dstOff++] = y; 1125 } else { 1126 dstPts[dstOff++] = (float)((m00 * x + m01 * y + m02) / w); 1127 dstPts[dstOff++] = (float)((m10 * x + m11 * y + m12) / w); 1128 } 1129 } 1130 } 1131 1132 /** 1133 * Transforms an array of double precision coordinates by this transform. 1134 * @param srcPts The array containing the source point coordinates. 1135 * Each point is stored as a pair of x,y coordinates. 1136 * @param dstPts The array where the transformed point coordinates are 1137 * returned. Each point is stored as a pair of x,y coordinates. 1138 * @param srcOff The offset to the first point to be transformed 1139 * in the source array. 1140 * @param dstOff The offset to the location where the first transformed 1141 * point is stored in the destination array. 1142 * @param numPts The number of point objects to be transformed. 1143 * @throws IllegalArgumentException if srcPts is null 1144 * @throws ArrayIndexOutOfBoundsException if srcPts is too small 1145 */ transform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, int numPts)1146 public void transform(double[] srcPts, int srcOff, 1147 double[] dstPts, int dstOff, 1148 int numPts) { 1149 1150 if ( srcPts == null ) { 1151 throw new IllegalArgumentException(JaiI18N.getString("Generic0")); 1152 } 1153 1154 if (dstPts == null) { 1155 dstPts = new double[numPts * 2 + dstOff]; 1156 } 1157 1158 while (numPts-- > 0) { 1159 double x = srcPts[srcOff++]; 1160 double y = srcPts[srcOff++]; 1161 double w = m20 * x + m21 * y + m22; 1162 1163 if (w == 0) { 1164 dstPts[dstOff++] = x; 1165 dstPts[dstOff++] = y; 1166 } else { 1167 dstPts[dstOff++] = (m00 * x + m01 * y + m02) / w; 1168 dstPts[dstOff++] = (m10 * x + m11 * y + m12) / w; 1169 } 1170 } 1171 } 1172 1173 /** 1174 * Transforms an array of floating point coordinates by this transform, 1175 * storing the results into an array of doubles. 1176 * @param srcPts The array containing the source point coordinates. 1177 * Each point is stored as a pair of x,y coordinates. 1178 * @param srcOff The offset to the first point to be transformed 1179 * in the source array. 1180 * @param dstPts The array where the transformed point coordinates are 1181 * returned. Each point is stored as a pair of x,y coordinates. 1182 * @param dstOff The offset to the location where the first transformed 1183 * point is stored in the destination array. 1184 * @param numPts The number of points to be transformed. 1185 * @throws IllegalArgumentException if srcPts is null 1186 * @throws ArrayIndexOutOfBoundsException if srcPts is too small 1187 */ transform(float[] srcPts, int srcOff, double[] dstPts, int dstOff, int numPts)1188 public void transform(float[] srcPts, int srcOff, 1189 double[] dstPts, int dstOff, 1190 int numPts) { 1191 1192 if ( srcPts == null ) { 1193 throw new IllegalArgumentException(JaiI18N.getString("Generic0")); 1194 } 1195 1196 if (dstPts == null) { 1197 dstPts = new double[numPts * 2 + dstOff]; 1198 } 1199 1200 while (numPts-- > 0) { 1201 float x = srcPts[srcOff++]; 1202 float y = srcPts[srcOff++]; 1203 double w = m20 * x + m21 * y + m22; 1204 1205 if (w == 0) { 1206 dstPts[dstOff++] = x; 1207 dstPts[dstOff++] = y; 1208 } else { 1209 dstPts[dstOff++] = (m00 * x + m01 * y + m02) / w; 1210 dstPts[dstOff++] = (m10 * x + m11 * y + m12) / w; 1211 } 1212 } 1213 } 1214 1215 /** 1216 * Transforms an array of double precision coordinates by this transform, 1217 * storing the results into an array of floats. 1218 * @param srcPts The array containing the source point coordinates. 1219 * Each point is stored as a pair of x,y coordinates. 1220 * @param dstPts The array where the transformed point coordinates are 1221 * returned. Each point is stored as a pair of x,y coordinates. 1222 * @param srcOff The offset to the first point to be transformed 1223 * in the source array. 1224 * @param dstOff The offset to the location where the first transformed 1225 * point is stored in the destination array. 1226 * @param numPts The number of point objects to be transformed. 1227 * @throws IllegalArgumentException if srcPts is null 1228 * @throws ArrayIndexOutOfBoundsException if srcPts is too small 1229 */ transform(double[] srcPts, int srcOff, float[] dstPts, int dstOff, int numPts)1230 public void transform(double[] srcPts, int srcOff, 1231 float[] dstPts, int dstOff, 1232 int numPts) { 1233 1234 if ( srcPts == null ) { 1235 throw new IllegalArgumentException(JaiI18N.getString("Generic0")); 1236 } 1237 1238 if (dstPts == null) { 1239 dstPts = new float[numPts * 2 + dstOff]; 1240 } 1241 1242 while (numPts-- > 0) { 1243 double x = srcPts[srcOff++]; 1244 double y = srcPts[srcOff++]; 1245 double w = m20 * x + m21 * y + m22; 1246 1247 if (w == 0) { 1248 dstPts[dstOff++] = (float)x; 1249 dstPts[dstOff++] = (float)y; 1250 } else { 1251 dstPts[dstOff++] = (float)((m00 * x + m01 * y + m02) / w); 1252 dstPts[dstOff++] = (float)((m10 * x + m11 * y + m12) / w); 1253 } 1254 } 1255 } 1256 1257 /** 1258 * Inverse transforms the specified ptSrc and stores the result in ptDst. 1259 * If ptDst is null, a new Point2D object will be allocated before 1260 * storing. In either case, ptDst containing the transformed point 1261 * is returned for convenience. 1262 * Note that ptSrc and ptDst can the same. In this case, the input 1263 * point will be overwritten with the transformed point. 1264 * @param ptSrc The point to be inverse transformed. 1265 * @param ptDst The resulting transformed point. 1266 * @throws NoninvertibleTransformException if the matrix cannot be 1267 * inverted. 1268 * @throws IllegalArgumentException if ptSrc is null 1269 */ inverseTransform(Point2D ptSrc, Point2D ptDst)1270 public Point2D inverseTransform(Point2D ptSrc, Point2D ptDst) 1271 throws NoninvertibleTransformException 1272 { 1273 if ( ptSrc == null ) { 1274 throw new IllegalArgumentException(JaiI18N.getString("Generic0")); 1275 } 1276 1277 if (ptDst == null) { 1278 if (ptSrc instanceof Point2D.Double) { 1279 ptDst = new Point2D.Double(); 1280 } else { 1281 ptDst = new Point2D.Float(); 1282 } 1283 } 1284 // Copy source coords into local variables in case src == dst 1285 double x = ptSrc.getX(); 1286 double y = ptSrc.getY(); 1287 1288 double tmp_x = (m11*m22 - m12*m21) * x + 1289 (m02*m21 - m01*m22) * y + 1290 (m01*m12 - m02*m11); 1291 double tmp_y = (m12*m20 - m10*m22) * x + 1292 (m00*m22 - m02*m20) * y + 1293 (m02*m10 - m00*m12); 1294 double w = (m10*m21 - m11*m20) * x + 1295 (m01*m20 - m00*m21) * y + 1296 (m00*m11 - m01*m10); 1297 1298 double wabs = w; 1299 if (w < 0) { 1300 wabs = - w; 1301 } 1302 if (wabs < PERSPECTIVE_DIVIDE_EPSILON) { 1303 throw new 1304 NoninvertibleTransformException( 1305 JaiI18N.getString("PerspectiveTransform1")); 1306 } 1307 1308 ptDst.setLocation(tmp_x/w, tmp_y/w); 1309 1310 return ptDst; 1311 } 1312 1313 /** 1314 * Inverse transforms an array of double precision coordinates by 1315 * this transform. 1316 * @param srcPts The array containing the source point coordinates. 1317 * Each point is stored as a pair of x,y coordinates. 1318 * @param dstPts The array where the transformed point coordinates are 1319 * returned. Each point is stored as a pair of x,y coordinates. 1320 * @param srcOff The offset to the first point to be transformed 1321 * in the source array. 1322 * @param dstOff The offset to the location where the first transformed 1323 * point is stored in the destination array. 1324 * @param numPts The number of point objects to be transformed. 1325 * @throws NoninvertibleTransformException if the matrix cannot be 1326 * inverted. 1327 * @throws IllegalArgumentException if srcPts is null 1328 * @throws ArrayIndexOutOfBoundsException if srcPts is too small 1329 * @throws NoninvertibleTransformException transform cannot be inverted 1330 */ inverseTransform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, int numPts)1331 public void inverseTransform(double[] srcPts, int srcOff, 1332 double[] dstPts, int dstOff, 1333 int numPts) 1334 throws NoninvertibleTransformException 1335 { 1336 if ( srcPts == null ) { 1337 throw new IllegalArgumentException(JaiI18N.getString("Generic0")); 1338 } 1339 1340 if (dstPts == null) { 1341 dstPts = new double[numPts * 2 + dstOff]; 1342 } 1343 1344 while (numPts-- > 0) { 1345 double x = srcPts[srcOff++]; 1346 double y = srcPts[srcOff++]; 1347 1348 double tmp_x = (m11*m22 - m12*m21) * x + 1349 (m02*m21 - m01*m22) * y + 1350 (m01*m12 - m02*m11); 1351 double tmp_y = (m12*m20 - m10*m22) * x + 1352 (m00*m22 - m02*m20) * y + 1353 (m02*m10 - m00*m12); 1354 double w = (m10*m21 - m11*m20) * x + 1355 (m01*m20 - m00*m21) * y + 1356 (m00*m11 - m01*m10); 1357 1358 double wabs = w; 1359 if (w < 0) { 1360 wabs = - w; 1361 } 1362 if (wabs < PERSPECTIVE_DIVIDE_EPSILON) { 1363 throw new NoninvertibleTransformException( 1364 JaiI18N.getString("PerspectiveTransform1")); 1365 } 1366 1367 dstPts[dstOff++] = tmp_x / w; 1368 dstPts[dstOff++] = tmp_y / w; 1369 } 1370 } 1371 1372 /** 1373 * Returns a String that represents the value of this Object. 1374 */ toString()1375 public String toString() { 1376 StringBuffer sb = new StringBuffer(); 1377 sb.append("Perspective transform matrix\n"); 1378 sb.append(this.m00); 1379 sb.append("\t"); 1380 sb.append(this.m01); 1381 sb.append("\t"); 1382 sb.append(this.m02); 1383 sb.append("\n"); 1384 sb.append(this.m10); 1385 sb.append("\t"); 1386 sb.append(this.m11); 1387 sb.append("\t"); 1388 sb.append(this.m12); 1389 sb.append("\n"); 1390 sb.append(this.m20); 1391 sb.append("\t"); 1392 sb.append(this.m21); 1393 sb.append("\t"); 1394 sb.append(this.m22); 1395 sb.append("\n"); 1396 return new String(sb); 1397 } 1398 1399 /** 1400 * Returns the boolean true value if this PerspectiveTransform is an 1401 * identity transform. Returns false otherwise. 1402 */ isIdentity()1403 public boolean isIdentity() { 1404 return m01 == 0.0 && m02 == 0.0 && 1405 m10 == 0.0 && m12 == 0.0 && 1406 m20 == 0.0 && m21 == 0.0 && 1407 m22 != 0.0 && m00/m22 == 1.0 && m11/m22 == 1.0; 1408 } 1409 1410 /** 1411 * Returns a copy of this PerspectiveTransform object. 1412 */ clone()1413 public Object clone() { 1414 try { 1415 return super.clone(); 1416 } catch (CloneNotSupportedException e) { 1417 // this shouldn't happen, since we are Cloneable 1418 throw new InternalError(); 1419 } 1420 } 1421 1422 1423 /** 1424 * Tests if this PerspectiveTransform equals a supplied one. 1425 * 1426 * @param obj The PerspectiveTransform to be compared to this one. 1427 */ equals(Object obj)1428 public boolean equals(Object obj) { 1429 if (!(obj instanceof PerspectiveTransform)) { 1430 return false; 1431 } 1432 1433 PerspectiveTransform a = (PerspectiveTransform)obj; 1434 1435 return ((m00 == a.m00) && (m10 == a.m10) && (m20 == a.m20) && 1436 (m01 == a.m01) && (m11 == a.m11) && (m21 == a.m21) && 1437 (m02 == a.m02) && (m12 == a.m12) && (m22 == a.m22)); 1438 } 1439 } 1440