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