Matrix.java revision 3a58ec108bb430b81a328adb2062035f860159b4
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.graphics; 18 19import java.io.PrintWriter; 20 21 22/** 23 * The Matrix class holds a 3x3 matrix for transforming coordinates. 24 * Matrix does not have a constructor, so it must be explicitly initialized 25 * using either reset() - to construct an identity matrix, or one of the set..() 26 * functions (e.g. setTranslate, setRotate, etc.). 27 */ 28public class Matrix { 29 30 public static final int MSCALE_X = 0; //!< use with getValues/setValues 31 public static final int MSKEW_X = 1; //!< use with getValues/setValues 32 public static final int MTRANS_X = 2; //!< use with getValues/setValues 33 public static final int MSKEW_Y = 3; //!< use with getValues/setValues 34 public static final int MSCALE_Y = 4; //!< use with getValues/setValues 35 public static final int MTRANS_Y = 5; //!< use with getValues/setValues 36 public static final int MPERSP_0 = 6; //!< use with getValues/setValues 37 public static final int MPERSP_1 = 7; //!< use with getValues/setValues 38 public static final int MPERSP_2 = 8; //!< use with getValues/setValues 39 40 /** 41 * @hide 42 */ 43 public int native_instance; 44 45 /** 46 * Create an identity matrix 47 */ 48 public Matrix() { 49 native_instance = native_create(0); 50 } 51 52 /** 53 * Create a matrix that is a (deep) copy of src 54 * @param src The matrix to copy into this matrix 55 */ 56 public Matrix(Matrix src) { 57 native_instance = native_create(src != null ? src.native_instance : 0); 58 } 59 60 /** 61 * Returns true if the matrix is identity. 62 * This maybe faster than testing if (getType() == 0) 63 */ 64 public boolean isIdentity() { 65 return native_isIdentity(native_instance); 66 } 67 68 /** 69 * Returns true if will map a rectangle to another rectangle. This can be 70 * true if the matrix is identity, scale-only, or rotates a multiple of 90 71 * degrees. 72 */ 73 public boolean rectStaysRect() { 74 return native_rectStaysRect(native_instance); 75 } 76 77 /** 78 * (deep) copy the src matrix into this matrix. If src is null, reset this 79 * matrix to the identity matrix. 80 */ 81 public void set(Matrix src) { 82 if (src == null) { 83 reset(); 84 } else { 85 native_set(native_instance, src.native_instance); 86 } 87 } 88 89 /** Returns true iff obj is a Matrix and its values equal our values. 90 */ 91 public boolean equals(Object obj) { 92 return obj != null && 93 obj instanceof Matrix && 94 native_equals(native_instance, ((Matrix)obj).native_instance); 95 } 96 97 /** Set the matrix to identity */ 98 public void reset() { 99 native_reset(native_instance); 100 } 101 102 /** Set the matrix to translate by (dx, dy). */ 103 public void setTranslate(float dx, float dy) { 104 native_setTranslate(native_instance, dx, dy); 105 } 106 107 /** 108 * Set the matrix to scale by sx and sy, with a pivot point at (px, py). 109 * The pivot point is the coordinate that should remain unchanged by the 110 * specified transformation. 111 */ 112 public void setScale(float sx, float sy, float px, float py) { 113 native_setScale(native_instance, sx, sy, px, py); 114 } 115 116 /** Set the matrix to scale by sx and sy. */ 117 public void setScale(float sx, float sy) { 118 native_setScale(native_instance, sx, sy); 119 } 120 121 /** 122 * Set the matrix to rotate by the specified number of degrees, with a pivot 123 * point at (px, py). The pivot point is the coordinate that should remain 124 * unchanged by the specified transformation. 125 */ 126 public void setRotate(float degrees, float px, float py) { 127 native_setRotate(native_instance, degrees, px, py); 128 } 129 130 /** 131 * Set the matrix to rotate about (0,0) by the specified number of degrees. 132 */ 133 public void setRotate(float degrees) { 134 native_setRotate(native_instance, degrees); 135 } 136 137 /** 138 * Set the matrix to rotate by the specified sine and cosine values, with a 139 * pivot point at (px, py). The pivot point is the coordinate that should 140 * remain unchanged by the specified transformation. 141 */ 142 public void setSinCos(float sinValue, float cosValue, float px, float py) { 143 native_setSinCos(native_instance, sinValue, cosValue, px, py); 144 } 145 146 /** Set the matrix to rotate by the specified sine and cosine values. */ 147 public void setSinCos(float sinValue, float cosValue) { 148 native_setSinCos(native_instance, sinValue, cosValue); 149 } 150 151 /** 152 * Set the matrix to skew by sx and sy, with a pivot point at (px, py). 153 * The pivot point is the coordinate that should remain unchanged by the 154 * specified transformation. 155 */ 156 public void setSkew(float kx, float ky, float px, float py) { 157 native_setSkew(native_instance, kx, ky, px, py); 158 } 159 160 /** Set the matrix to skew by sx and sy. */ 161 public void setSkew(float kx, float ky) { 162 native_setSkew(native_instance, kx, ky); 163 } 164 165 /** 166 * Set the matrix to the concatenation of the two specified matrices, 167 * returning true if the the result can be represented. Either of the two 168 * matrices may also be the target matrix. this = a * b 169 */ 170 public boolean setConcat(Matrix a, Matrix b) { 171 return native_setConcat(native_instance, a.native_instance, 172 b.native_instance); 173 } 174 175 /** 176 * Preconcats the matrix with the specified translation. 177 * M' = M * T(dx, dy) 178 */ 179 public boolean preTranslate(float dx, float dy) { 180 return native_preTranslate(native_instance, dx, dy); 181 } 182 183 /** 184 * Preconcats the matrix with the specified scale. 185 * M' = M * S(sx, sy, px, py) 186 */ 187 public boolean preScale(float sx, float sy, float px, float py) { 188 return native_preScale(native_instance, sx, sy, px, py); 189 } 190 191 /** 192 * Preconcats the matrix with the specified scale. 193 * M' = M * S(sx, sy) 194 */ 195 public boolean preScale(float sx, float sy) { 196 return native_preScale(native_instance, sx, sy); 197 } 198 199 /** 200 * Preconcats the matrix with the specified rotation. 201 * M' = M * R(degrees, px, py) 202 */ 203 public boolean preRotate(float degrees, float px, float py) { 204 return native_preRotate(native_instance, degrees, px, py); 205 } 206 207 /** 208 * Preconcats the matrix with the specified rotation. 209 * M' = M * R(degrees) 210 */ 211 public boolean preRotate(float degrees) { 212 return native_preRotate(native_instance, degrees); 213 } 214 215 /** 216 * Preconcats the matrix with the specified skew. 217 * M' = M * K(kx, ky, px, py) 218 */ 219 public boolean preSkew(float kx, float ky, float px, float py) { 220 return native_preSkew(native_instance, kx, ky, px, py); 221 } 222 223 /** 224 * Preconcats the matrix with the specified skew. 225 * M' = M * K(kx, ky) 226 */ 227 public boolean preSkew(float kx, float ky) { 228 return native_preSkew(native_instance, kx, ky); 229 } 230 231 /** 232 * Preconcats the matrix with the specified matrix. 233 * M' = M * other 234 */ 235 public boolean preConcat(Matrix other) { 236 return native_preConcat(native_instance, other.native_instance); 237 } 238 239 /** 240 * Postconcats the matrix with the specified translation. 241 * M' = T(dx, dy) * M 242 */ 243 public boolean postTranslate(float dx, float dy) { 244 return native_postTranslate(native_instance, dx, dy); 245 } 246 247 /** 248 * Postconcats the matrix with the specified scale. 249 * M' = S(sx, sy, px, py) * M 250 */ 251 public boolean postScale(float sx, float sy, float px, float py) { 252 return native_postScale(native_instance, sx, sy, px, py); 253 } 254 255 /** 256 * Postconcats the matrix with the specified scale. 257 * M' = S(sx, sy) * M 258 */ 259 public boolean postScale(float sx, float sy) { 260 return native_postScale(native_instance, sx, sy); 261 } 262 263 /** 264 * Postconcats the matrix with the specified rotation. 265 * M' = R(degrees, px, py) * M 266 */ 267 public boolean postRotate(float degrees, float px, float py) { 268 return native_postRotate(native_instance, degrees, px, py); 269 } 270 271 /** 272 * Postconcats the matrix with the specified rotation. 273 * M' = R(degrees) * M 274 */ 275 public boolean postRotate(float degrees) { 276 return native_postRotate(native_instance, degrees); 277 } 278 279 /** 280 * Postconcats the matrix with the specified skew. 281 * M' = K(kx, ky, px, py) * M 282 */ 283 public boolean postSkew(float kx, float ky, float px, float py) { 284 return native_postSkew(native_instance, kx, ky, px, py); 285 } 286 287 /** 288 * Postconcats the matrix with the specified skew. 289 * M' = K(kx, ky) * M 290 */ 291 public boolean postSkew(float kx, float ky) { 292 return native_postSkew(native_instance, kx, ky); 293 } 294 295 /** 296 * Postconcats the matrix with the specified matrix. 297 * M' = other * M 298 */ 299 public boolean postConcat(Matrix other) { 300 return native_postConcat(native_instance, other.native_instance); 301 } 302 303 /** Controlls how the src rect should align into the dst rect for 304 setRectToRect(). 305 */ 306 public enum ScaleToFit { 307 /** 308 * Scale in X and Y independently, so that src matches dst exactly. 309 * This may change the aspect ratio of the src. 310 */ 311 FILL (0), 312 /** 313 * Compute a scale that will maintain the original src aspect ratio, 314 * but will also ensure that src fits entirely inside dst. At least one 315 * axis (X or Y) will fit exactly. START aligns the result to the 316 * left and top edges of dst. 317 */ 318 START (1), 319 /** 320 * Compute a scale that will maintain the original src aspect ratio, 321 * but will also ensure that src fits entirely inside dst. At least one 322 * axis (X or Y) will fit exactly. The result is centered inside dst. 323 */ 324 CENTER (2), 325 /** 326 * Compute a scale that will maintain the original src aspect ratio, 327 * but will also ensure that src fits entirely inside dst. At least one 328 * axis (X or Y) will fit exactly. END aligns the result to the 329 * right and bottom edges of dst. 330 */ 331 END (3); 332 333 // the native values must match those in SkMatrix.h 334 ScaleToFit(int nativeInt) { 335 this.nativeInt = nativeInt; 336 } 337 final int nativeInt; 338 } 339 340 /** 341 * Set the matrix to the scale and translate values that map the source 342 * rectangle to the destination rectangle, returning true if the the result 343 * can be represented. 344 * 345 * @param src the source rectangle to map from. 346 * @param dst the destination rectangle to map to. 347 * @param stf the ScaleToFit option 348 * @return true if the matrix can be represented by the rectangle mapping. 349 */ 350 public boolean setRectToRect(RectF src, RectF dst, ScaleToFit stf) { 351 if (dst == null || src == null) { 352 throw new NullPointerException(); 353 } 354 return native_setRectToRect(native_instance, src, dst, stf.nativeInt); 355 } 356 357 // private helper to perform range checks on arrays of "points" 358 private static void checkPointArrays(float[] src, int srcIndex, 359 float[] dst, int dstIndex, 360 int pointCount) { 361 // check for too-small and too-big indices 362 int srcStop = srcIndex + (pointCount << 1); 363 int dstStop = dstIndex + (pointCount << 1); 364 if ((pointCount | srcIndex | dstIndex | srcStop | dstStop) < 0 || 365 srcStop > src.length || dstStop > dst.length) { 366 throw new ArrayIndexOutOfBoundsException(); 367 } 368 } 369 370 /** 371 * Set the matrix such that the specified src points would map to the 372 * specified dst points. The "points" are represented as an array of floats, 373 * order [x0, y0, x1, y1, ...], where each "point" is 2 float values. 374 * 375 * @param src The array of src [x,y] pairs (points) 376 * @param srcIndex Index of the first pair of src values 377 * @param dst The array of dst [x,y] pairs (points) 378 * @param dstIndex Index of the first pair of dst values 379 * @param pointCount The number of pairs/points to be used. Must be [0..4] 380 * @return true if the matrix was set to the specified transformation 381 */ 382 public boolean setPolyToPoly(float[] src, int srcIndex, 383 float[] dst, int dstIndex, 384 int pointCount) { 385 if (pointCount > 4) { 386 throw new IllegalArgumentException(); 387 } 388 checkPointArrays(src, srcIndex, dst, dstIndex, pointCount); 389 return native_setPolyToPoly(native_instance, src, srcIndex, 390 dst, dstIndex, pointCount); 391 } 392 393 /** 394 * If this matrix can be inverted, return true and if inverse is not null, 395 * set inverse to be the inverse of this matrix. If this matrix cannot be 396 * inverted, ignore inverse and return false. 397 */ 398 public boolean invert(Matrix inverse) { 399 return native_invert(native_instance, inverse.native_instance); 400 } 401 402 /** 403 * Apply this matrix to the array of 2D points specified by src, and write 404 * the transformed points into the array of points specified by dst. The 405 * two arrays represent their "points" as pairs of floats [x, y]. 406 * 407 * @param dst The array of dst points (x,y pairs) 408 * @param dstIndex The index of the first [x,y] pair of dst floats 409 * @param src The array of src points (x,y pairs) 410 * @param srcIndex The index of the first [x,y] pair of src floats 411 * @param pointCount The number of points (x,y pairs) to transform 412 */ 413 public void mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex, 414 int pointCount) { 415 checkPointArrays(src, srcIndex, dst, dstIndex, pointCount); 416 native_mapPoints(native_instance, dst, dstIndex, src, srcIndex, 417 pointCount, true); 418 } 419 420 /** 421 * Apply this matrix to the array of 2D vectors specified by src, and write 422 * the transformed vectors into the array of vectors specified by dst. The 423 * two arrays represent their "vectors" as pairs of floats [x, y]. 424 * 425 * Note: this method does not apply the translation associated with the matrix. Use 426 * {@link Matrix#mapPoints(float[], int, float[], int, int)} if you want the translation 427 * to be applied. 428 * 429 * @param dst The array of dst vectors (x,y pairs) 430 * @param dstIndex The index of the first [x,y] pair of dst floats 431 * @param src The array of src vectors (x,y pairs) 432 * @param srcIndex The index of the first [x,y] pair of src floats 433 * @param vectorCount The number of vectors (x,y pairs) to transform 434 */ 435 public void mapVectors(float[] dst, int dstIndex, float[] src, int srcIndex, 436 int vectorCount) { 437 checkPointArrays(src, srcIndex, dst, dstIndex, vectorCount); 438 native_mapPoints(native_instance, dst, dstIndex, src, srcIndex, 439 vectorCount, false); 440 } 441 442 /** 443 * Apply this matrix to the array of 2D points specified by src, and write 444 * the transformed points into the array of points specified by dst. The 445 * two arrays represent their "points" as pairs of floats [x, y]. 446 * 447 * @param dst The array of dst points (x,y pairs) 448 * @param src The array of src points (x,y pairs) 449 */ 450 public void mapPoints(float[] dst, float[] src) { 451 if (dst.length != src.length) { 452 throw new ArrayIndexOutOfBoundsException(); 453 } 454 mapPoints(dst, 0, src, 0, dst.length >> 1); 455 } 456 457 /** 458 * Apply this matrix to the array of 2D vectors specified by src, and write 459 * the transformed vectors into the array of vectors specified by dst. The 460 * two arrays represent their "vectors" as pairs of floats [x, y]. 461 * 462 * Note: this method does not apply the translation associated with the matrix. Use 463 * {@link Matrix#mapPoints(float[], float[])} if you want the translation to be applied. 464 * 465 * @param dst The array of dst vectors (x,y pairs) 466 * @param src The array of src vectors (x,y pairs) 467 */ 468 public void mapVectors(float[] dst, float[] src) { 469 if (dst.length != src.length) { 470 throw new ArrayIndexOutOfBoundsException(); 471 } 472 mapVectors(dst, 0, src, 0, dst.length >> 1); 473 } 474 475 /** 476 * Apply this matrix to the array of 2D points, and write the transformed 477 * points back into the array 478 * 479 * @param pts The array [x0, y0, x1, y1, ...] of points to transform. 480 */ 481 public void mapPoints(float[] pts) { 482 mapPoints(pts, 0, pts, 0, pts.length >> 1); 483 } 484 485 /** 486 * Apply this matrix to the array of 2D vectors, and write the transformed 487 * vectors back into the array. 488 * 489 * Note: this method does not apply the translation associated with the matrix. Use 490 * {@link Matrix#mapPoints(float[])} if you want the translation to be applied. 491 * 492 * @param vecs The array [x0, y0, x1, y1, ...] of vectors to transform. 493 */ 494 public void mapVectors(float[] vecs) { 495 mapVectors(vecs, 0, vecs, 0, vecs.length >> 1); 496 } 497 498 /** 499 * Apply this matrix to the src rectangle, and write the transformed 500 * rectangle into dst. This is accomplished by transforming the 4 corners of 501 * src, and then setting dst to the bounds of those points. 502 * 503 * @param dst Where the transformed rectangle is written. 504 * @param src The original rectangle to be transformed. 505 * @return the result of calling rectStaysRect() 506 */ 507 public boolean mapRect(RectF dst, RectF src) { 508 if (dst == null || src == null) { 509 throw new NullPointerException(); 510 } 511 return native_mapRect(native_instance, dst, src); 512 } 513 514 /** 515 * Apply this matrix to the rectangle, and write the transformed rectangle 516 * back into it. This is accomplished by transforming the 4 corners of rect, 517 * and then setting it to the bounds of those points 518 * 519 * @param rect The rectangle to transform. 520 * @return the result of calling rectStaysRect() 521 */ 522 public boolean mapRect(RectF rect) { 523 return mapRect(rect, rect); 524 } 525 526 /** 527 * Return the mean radius of a circle after it has been mapped by 528 * this matrix. NOTE: in perspective this value assumes the circle 529 * has its center at the origin. 530 */ 531 public float mapRadius(float radius) { 532 return native_mapRadius(native_instance, radius); 533 } 534 535 /** Copy 9 values from the matrix into the array. 536 */ 537 public void getValues(float[] values) { 538 if (values.length < 9) { 539 throw new ArrayIndexOutOfBoundsException(); 540 } 541 native_getValues(native_instance, values); 542 } 543 544 /** Copy 9 values from the array into the matrix. 545 Depending on the implementation of Matrix, these may be 546 transformed into 16.16 integers in the Matrix, such that 547 a subsequent call to getValues() will not yield exactly 548 the same values. 549 */ 550 public void setValues(float[] values) { 551 if (values.length < 9) { 552 throw new ArrayIndexOutOfBoundsException(); 553 } 554 native_setValues(native_instance, values); 555 } 556 557 public String toString() { 558 StringBuilder sb = new StringBuilder(64); 559 sb.append("Matrix{"); 560 toShortString(sb); 561 sb.append('}'); 562 return sb.toString(); 563 564 } 565 566 public String toShortString() { 567 StringBuilder sb = new StringBuilder(64); 568 toShortString(sb); 569 return sb.toString(); 570 } 571 572 /** 573 * @hide 574 */ 575 public void toShortString(StringBuilder sb) { 576 float[] values = new float[9]; 577 getValues(values); 578 sb.append('['); 579 sb.append(values[0]); sb.append(", "); sb.append(values[1]); sb.append(", "); 580 sb.append(values[2]); sb.append("]["); 581 sb.append(values[3]); sb.append(", "); sb.append(values[4]); sb.append(", "); 582 sb.append(values[5]); sb.append("]["); 583 sb.append(values[6]); sb.append(", "); sb.append(values[7]); sb.append(", "); 584 sb.append(values[8]); sb.append(']'); 585 } 586 587 /** 588 * Print short string, to optimize dumping. 589 * @hide 590 */ 591 public void printShortString(PrintWriter pw) { 592 float[] values = new float[9]; 593 getValues(values); 594 pw.print('['); 595 pw.print(values[0]); pw.print(", "); pw.print(values[1]); pw.print(", "); 596 pw.print(values[2]); pw.print("]["); 597 pw.print(values[3]); pw.print(", "); pw.print(values[4]); pw.print(", "); 598 pw.print(values[5]); pw.print("]["); 599 pw.print(values[6]); pw.print(", "); pw.print(values[7]); pw.print(", "); 600 pw.print(values[8]); pw.print(']'); 601 602 } 603 604 protected void finalize() throws Throwable { 605 finalizer(native_instance); 606 } 607 608 /*package*/ final int ni() { 609 return native_instance; 610 } 611 612 private static native int native_create(int native_src_or_zero); 613 private static native boolean native_isIdentity(int native_object); 614 private static native boolean native_rectStaysRect(int native_object); 615 private static native void native_reset(int native_object); 616 private static native void native_set(int native_object, int other); 617 private static native void native_setTranslate(int native_object, 618 float dx, float dy); 619 private static native void native_setScale(int native_object, 620 float sx, float sy, float px, float py); 621 private static native void native_setScale(int native_object, 622 float sx, float sy); 623 private static native void native_setRotate(int native_object, 624 float degrees, float px, float py); 625 private static native void native_setRotate(int native_object, 626 float degrees); 627 private static native void native_setSinCos(int native_object, 628 float sinValue, float cosValue, float px, float py); 629 private static native void native_setSinCos(int native_object, 630 float sinValue, float cosValue); 631 private static native void native_setSkew(int native_object, 632 float kx, float ky, float px, float py); 633 private static native void native_setSkew(int native_object, 634 float kx, float ky); 635 private static native boolean native_setConcat(int native_object, 636 int a, int b); 637 private static native boolean native_preTranslate(int native_object, 638 float dx, float dy); 639 private static native boolean native_preScale(int native_object, 640 float sx, float sy, float px, float py); 641 private static native boolean native_preScale(int native_object, 642 float sx, float sy); 643 private static native boolean native_preRotate(int native_object, 644 float degrees, float px, float py); 645 private static native boolean native_preRotate(int native_object, 646 float degrees); 647 private static native boolean native_preSkew(int native_object, 648 float kx, float ky, float px, float py); 649 private static native boolean native_preSkew(int native_object, 650 float kx, float ky); 651 private static native boolean native_preConcat(int native_object, 652 int other_matrix); 653 private static native boolean native_postTranslate(int native_object, 654 float dx, float dy); 655 private static native boolean native_postScale(int native_object, 656 float sx, float sy, float px, float py); 657 private static native boolean native_postScale(int native_object, 658 float sx, float sy); 659 private static native boolean native_postRotate(int native_object, 660 float degrees, float px, float py); 661 private static native boolean native_postRotate(int native_object, 662 float degrees); 663 private static native boolean native_postSkew(int native_object, 664 float kx, float ky, float px, float py); 665 private static native boolean native_postSkew(int native_object, 666 float kx, float ky); 667 private static native boolean native_postConcat(int native_object, 668 int other_matrix); 669 private static native boolean native_setRectToRect(int native_object, 670 RectF src, RectF dst, int stf); 671 private static native boolean native_setPolyToPoly(int native_object, 672 float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount); 673 private static native boolean native_invert(int native_object, int inverse); 674 private static native void native_mapPoints(int native_object, 675 float[] dst, int dstIndex, float[] src, int srcIndex, 676 int ptCount, boolean isPts); 677 private static native boolean native_mapRect(int native_object, 678 RectF dst, RectF src); 679 private static native float native_mapRadius(int native_object, 680 float radius); 681 private static native void native_getValues(int native_object, 682 float[] values); 683 private static native void native_setValues(int native_object, 684 float[] values); 685 private static native boolean native_equals(int native_a, int native_b); 686 private static native void finalizer(int native_instance); 687} 688