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