Matrix_Delegate.java revision a6e51d549710d42f8ee4776fa5fefa08277c8e57
1/* 2 * Copyright (C) 2010 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 20import com.android.layoutlib.bridge.impl.DelegateManager; 21 22import android.graphics.Matrix.ScaleToFit; 23 24import java.awt.geom.AffineTransform; 25import java.awt.geom.NoninvertibleTransformException; 26 27/** 28 * Delegate implementing the native methods of android.graphics.Matrix 29 * 30 * Through the layoutlib_create tool, the original native methods of Matrix have been replaced 31 * by calls to methods of the same name in this delegate class. 32 * 33 * This class behaves like the original native implementation, but in Java, keeping previously 34 * native data into its own objects and mapping them to int that are sent back and forth between 35 * it and the original Matrix class. 36 * 37 * @see DelegateManager 38 * 39 */ 40public final class Matrix_Delegate { 41 42 private final static int MATRIX_SIZE = 9; 43 44 // ---- delegate manager ---- 45 private static final DelegateManager<Matrix_Delegate> sManager = 46 new DelegateManager<Matrix_Delegate>(); 47 48 // ---- delegate data ---- 49 private float mValues[] = new float[MATRIX_SIZE]; 50 51 // ---- Public Helper methods ---- 52 53 public static Matrix_Delegate getDelegate(int native_instance) { 54 return sManager.getDelegate(native_instance); 55 } 56 57 /** 58 * Returns an {@link AffineTransform} matching the given Matrix. 59 */ 60 public static AffineTransform getAffineTransform(Matrix m) { 61 Matrix_Delegate delegate = sManager.getDelegate(m.native_instance); 62 if (delegate == null) { 63 return null; 64 } 65 66 return delegate.getAffineTransform(); 67 } 68 69 public static boolean hasPerspective(Matrix m) { 70 Matrix_Delegate delegate = sManager.getDelegate(m.native_instance); 71 if (delegate == null) { 72 return false; 73 } 74 75 return delegate.hasPerspective(); 76 } 77 78 /** 79 * Sets the content of the matrix with the content of another matrix. 80 */ 81 public void set(Matrix_Delegate matrix) { 82 System.arraycopy(matrix.mValues, 0, mValues, 0, MATRIX_SIZE); 83 } 84 85 /** 86 * Resets the matrix to be the identity matrix. 87 */ 88 public void reset() { 89 reset(mValues); 90 } 91 92 /** 93 * Returns whether or not the matrix is identity. 94 */ 95 public boolean isIdentity() { 96 for (int i = 0, k = 0; i < 3; i++) { 97 for (int j = 0; j < 3; j++, k++) { 98 if (mValues[k] != ((i==j) ? 1 : 0)) { 99 return false; 100 } 101 } 102 } 103 104 return true; 105 } 106 107 public static Matrix_Delegate make(AffineTransform matrix) { 108 float[] values = new float[MATRIX_SIZE]; 109 values[0] = (float) matrix.getScaleX(); 110 values[1] = (float) matrix.getShearX(); 111 values[2] = (float) matrix.getTranslateX(); 112 values[3] = (float) matrix.getShearY(); 113 values[4] = (float) matrix.getScaleY(); 114 values[5] = (float) matrix.getTranslateY(); 115 values[6] = 0.f; 116 values[7] = 0.f; 117 values[8] = 1.f; 118 119 return new Matrix_Delegate(values); 120 } 121 122 public boolean mapRect(RectF dst, RectF src) { 123 // array with 4 corners 124 float[] corners = new float[] { 125 src.left, src.top, 126 src.right, src.top, 127 src.right, src.bottom, 128 src.left, src.bottom, 129 }; 130 131 // apply the transform to them. 132 mapPoints(corners); 133 134 // now put the result in the rect. We take the min/max of Xs and min/max of Ys 135 dst.left = Math.min(Math.min(corners[0], corners[2]), Math.min(corners[4], corners[6])); 136 dst.right = Math.max(Math.max(corners[0], corners[2]), Math.max(corners[4], corners[6])); 137 138 dst.top = Math.min(Math.min(corners[1], corners[3]), Math.min(corners[5], corners[7])); 139 dst.bottom = Math.max(Math.max(corners[1], corners[3]), Math.max(corners[5], corners[7])); 140 141 142 return (computeTypeMask() & kRectStaysRect_Mask) != 0; 143 } 144 145 146 /** 147 * Returns an {@link AffineTransform} matching the matrix. 148 */ 149 public AffineTransform getAffineTransform() { 150 return getAffineTransform(mValues); 151 } 152 153 public boolean hasPerspective() { 154 return (mValues[6] != 0 || mValues[7] != 0 || mValues[8] != 1); 155 } 156 157 158 159 // ---- native methods ---- 160 161 /*package*/ static int native_create(int native_src_or_zero) { 162 // create the delegate 163 Matrix_Delegate newDelegate = new Matrix_Delegate(); 164 165 // copy from values if needed. 166 if (native_src_or_zero > 0) { 167 Matrix_Delegate oldDelegate = sManager.getDelegate(native_src_or_zero); 168 if (oldDelegate != null) { 169 System.arraycopy( 170 oldDelegate.mValues, 0, 171 newDelegate.mValues, 0, 172 MATRIX_SIZE); 173 } 174 } 175 176 return sManager.addDelegate(newDelegate); 177 } 178 179 /*package*/ static boolean native_isIdentity(int native_object) { 180 Matrix_Delegate d = sManager.getDelegate(native_object); 181 if (d == null) { 182 return false; 183 } 184 185 return d.isIdentity(); 186 } 187 188 /*package*/ static boolean native_rectStaysRect(int native_object) { 189 Matrix_Delegate d = sManager.getDelegate(native_object); 190 if (d == null) { 191 return true; 192 } 193 194 return (d.computeTypeMask() & kRectStaysRect_Mask) != 0; 195 } 196 197 /*package*/ static void native_reset(int native_object) { 198 Matrix_Delegate d = sManager.getDelegate(native_object); 199 if (d == null) { 200 return; 201 } 202 203 reset(d.mValues); 204 } 205 206 /*package*/ static void native_set(int native_object, int other) { 207 Matrix_Delegate d = sManager.getDelegate(native_object); 208 if (d == null) { 209 return; 210 } 211 212 Matrix_Delegate src = sManager.getDelegate(other); 213 if (src == null) { 214 return; 215 } 216 217 System.arraycopy(src.mValues, 0, d.mValues, 0, MATRIX_SIZE); 218 } 219 220 /*package*/ static void native_setTranslate(int native_object, float dx, float dy) { 221 Matrix_Delegate d = sManager.getDelegate(native_object); 222 if (d == null) { 223 return; 224 } 225 226 setTranslate(d.mValues, dx, dy); 227 } 228 229 /*package*/ static void native_setScale(int native_object, float sx, float sy, 230 float px, float py) { 231 Matrix_Delegate d = sManager.getDelegate(native_object); 232 if (d == null) { 233 return; 234 } 235 236 d.mValues = getScale(sx, sy, px, py); 237 } 238 239 /*package*/ static void native_setScale(int native_object, float sx, float sy) { 240 Matrix_Delegate d = sManager.getDelegate(native_object); 241 if (d == null) { 242 return; 243 } 244 245 d.mValues[0] = sx; 246 d.mValues[1] = 0; 247 d.mValues[2] = 0; 248 d.mValues[3] = 0; 249 d.mValues[4] = sy; 250 d.mValues[5] = 0; 251 d.mValues[6] = 0; 252 d.mValues[7] = 0; 253 d.mValues[8] = 1; 254 } 255 256 /*package*/ static void native_setRotate(int native_object, float degrees, float px, float py) { 257 Matrix_Delegate d = sManager.getDelegate(native_object); 258 if (d == null) { 259 return; 260 } 261 262 d.mValues = getRotate(degrees, px, py); 263 } 264 265 /*package*/ static void native_setRotate(int native_object, float degrees) { 266 Matrix_Delegate d = sManager.getDelegate(native_object); 267 if (d == null) { 268 return; 269 } 270 271 setRotate(d.mValues, degrees); 272 } 273 274 /*package*/ static void native_setSinCos(int native_object, float sinValue, float cosValue, 275 float px, float py) { 276 Matrix_Delegate d = sManager.getDelegate(native_object); 277 if (d == null) { 278 return; 279 } 280 281 // TODO: do it in one pass 282 283 // translate so that the pivot is in 0,0 284 setTranslate(d.mValues, -px, -py); 285 286 // scale 287 d.postTransform(getRotate(sinValue, cosValue)); 288 // translate back the pivot 289 d.postTransform(getTranslate(px, py)); 290 } 291 292 /*package*/ static void native_setSinCos(int native_object, float sinValue, float cosValue) { 293 Matrix_Delegate d = sManager.getDelegate(native_object); 294 if (d == null) { 295 return; 296 } 297 298 setRotate(d.mValues, sinValue, cosValue); 299 } 300 301 /*package*/ static void native_setSkew(int native_object, float kx, float ky, 302 float px, float py) { 303 Matrix_Delegate d = sManager.getDelegate(native_object); 304 if (d == null) { 305 return; 306 } 307 308 d.mValues = getSkew(kx, ky, px, py); 309 } 310 311 /*package*/ static void native_setSkew(int native_object, float kx, float ky) { 312 Matrix_Delegate d = sManager.getDelegate(native_object); 313 if (d == null) { 314 return; 315 } 316 317 d.mValues[0] = 1; 318 d.mValues[1] = kx; 319 d.mValues[2] = -0; 320 d.mValues[3] = ky; 321 d.mValues[4] = 1; 322 d.mValues[5] = 0; 323 d.mValues[6] = 0; 324 d.mValues[7] = 0; 325 d.mValues[8] = 1; 326 } 327 328 /*package*/ static boolean native_setConcat(int native_object, int a, int b) { 329 if (a == native_object) { 330 return native_preConcat(native_object, b); 331 } else if (b == native_object) { 332 return native_postConcat(native_object, a); 333 } 334 335 Matrix_Delegate d = sManager.getDelegate(native_object); 336 if (d == null) { 337 return false; 338 } 339 340 Matrix_Delegate a_mtx = sManager.getDelegate(a); 341 if (a_mtx == null) { 342 return false; 343 } 344 345 Matrix_Delegate b_mtx = sManager.getDelegate(b); 346 if (b_mtx == null) { 347 return false; 348 } 349 350 multiply(d.mValues, a_mtx.mValues, b_mtx.mValues); 351 352 return true; 353 } 354 355 /*package*/ static boolean native_preTranslate(int native_object, float dx, float dy) { 356 Matrix_Delegate d = sManager.getDelegate(native_object); 357 if (d == null) { 358 return false; 359 } 360 361 d.preTransform(getTranslate(dx, dy)); 362 return true; 363 } 364 365 /*package*/ static boolean native_preScale(int native_object, float sx, float sy, 366 float px, float py) { 367 Matrix_Delegate d = sManager.getDelegate(native_object); 368 if (d == null) { 369 return false; 370 } 371 372 d.preTransform(getScale(sx, sy, px, py)); 373 return true; 374 } 375 376 /*package*/ static boolean native_preScale(int native_object, float sx, float sy) { 377 Matrix_Delegate d = sManager.getDelegate(native_object); 378 if (d == null) { 379 return false; 380 } 381 382 d.preTransform(getScale(sx, sy)); 383 return true; 384 } 385 386 /*package*/ static boolean native_preRotate(int native_object, float degrees, 387 float px, float py) { 388 Matrix_Delegate d = sManager.getDelegate(native_object); 389 if (d == null) { 390 return false; 391 } 392 393 d.preTransform(getRotate(degrees, px, py)); 394 return true; 395 } 396 397 /*package*/ static boolean native_preRotate(int native_object, float degrees) { 398 Matrix_Delegate d = sManager.getDelegate(native_object); 399 if (d == null) { 400 return false; 401 } 402 403 double rad = Math.toRadians(degrees); 404 float sin = (float)Math.sin(rad); 405 float cos = (float)Math.cos(rad); 406 407 d.preTransform(getRotate(sin, cos)); 408 return true; 409 } 410 411 /*package*/ static boolean native_preSkew(int native_object, float kx, float ky, 412 float px, float py) { 413 Matrix_Delegate d = sManager.getDelegate(native_object); 414 if (d == null) { 415 return false; 416 } 417 418 d.preTransform(getSkew(kx, ky, px, py)); 419 return true; 420 } 421 422 /*package*/ static boolean native_preSkew(int native_object, float kx, float ky) { 423 Matrix_Delegate d = sManager.getDelegate(native_object); 424 if (d == null) { 425 return false; 426 } 427 428 d.preTransform(getSkew(kx, ky)); 429 return true; 430 } 431 432 /*package*/ static boolean native_preConcat(int native_object, int other_matrix) { 433 Matrix_Delegate d = sManager.getDelegate(native_object); 434 if (d == null) { 435 return false; 436 } 437 438 Matrix_Delegate other = sManager.getDelegate(other_matrix); 439 if (d == null) { 440 return false; 441 } 442 443 d.preTransform(other.mValues); 444 return true; 445 } 446 447 /*package*/ static boolean native_postTranslate(int native_object, float dx, float dy) { 448 Matrix_Delegate d = sManager.getDelegate(native_object); 449 if (d == null) { 450 return false; 451 } 452 453 d.postTransform(getTranslate(dx, dy)); 454 return true; 455 } 456 457 /*package*/ static boolean native_postScale(int native_object, float sx, float sy, 458 float px, float py) { 459 Matrix_Delegate d = sManager.getDelegate(native_object); 460 if (d == null) { 461 return false; 462 } 463 464 d.postTransform(getScale(sx, sy, px, py)); 465 return true; 466 } 467 468 /*package*/ static boolean native_postScale(int native_object, float sx, float sy) { 469 Matrix_Delegate d = sManager.getDelegate(native_object); 470 if (d == null) { 471 return false; 472 } 473 474 d.postTransform(getScale(sx, sy)); 475 return true; 476 } 477 478 /*package*/ static boolean native_postRotate(int native_object, float degrees, 479 float px, float py) { 480 Matrix_Delegate d = sManager.getDelegate(native_object); 481 if (d == null) { 482 return false; 483 } 484 485 d.postTransform(getRotate(degrees, px, py)); 486 return true; 487 } 488 489 /*package*/ static boolean native_postRotate(int native_object, float degrees) { 490 Matrix_Delegate d = sManager.getDelegate(native_object); 491 if (d == null) { 492 return false; 493 } 494 495 d.postTransform(getRotate(degrees)); 496 return true; 497 } 498 499 /*package*/ static boolean native_postSkew(int native_object, float kx, float ky, 500 float px, float py) { 501 Matrix_Delegate d = sManager.getDelegate(native_object); 502 if (d == null) { 503 return false; 504 } 505 506 d.postTransform(getSkew(kx, ky, px, py)); 507 return true; 508 } 509 510 /*package*/ static boolean native_postSkew(int native_object, float kx, float ky) { 511 Matrix_Delegate d = sManager.getDelegate(native_object); 512 if (d == null) { 513 return false; 514 } 515 516 d.postTransform(getSkew(kx, ky)); 517 return true; 518 } 519 520 /*package*/ static boolean native_postConcat(int native_object, int other_matrix) { 521 Matrix_Delegate d = sManager.getDelegate(native_object); 522 if (d == null) { 523 return false; 524 } 525 526 Matrix_Delegate other = sManager.getDelegate(other_matrix); 527 if (d == null) { 528 return false; 529 } 530 531 d.postTransform(other.mValues); 532 return true; 533 } 534 535 /*package*/ static boolean native_setRectToRect(int native_object, RectF src, 536 RectF dst, int stf) { 537 Matrix_Delegate d = sManager.getDelegate(native_object); 538 if (d == null) { 539 return false; 540 } 541 542 if (src.isEmpty()) { 543 reset(d.mValues); 544 return false; 545 } 546 547 if (dst.isEmpty()) { 548 d.mValues[0] = d.mValues[1] = d.mValues[2] = d.mValues[3] = d.mValues[4] = d.mValues[5] 549 = d.mValues[6] = d.mValues[7] = 0; 550 d.mValues[8] = 1; 551 } else { 552 float tx, sx = dst.width() / src.width(); 553 float ty, sy = dst.height() / src.height(); 554 boolean xLarger = false; 555 556 if (stf != ScaleToFit.FILL.nativeInt) { 557 if (sx > sy) { 558 xLarger = true; 559 sx = sy; 560 } else { 561 sy = sx; 562 } 563 } 564 565 tx = dst.left - src.left * sx; 566 ty = dst.top - src.top * sy; 567 if (stf == ScaleToFit.CENTER.nativeInt || stf == ScaleToFit.END.nativeInt) { 568 float diff; 569 570 if (xLarger) { 571 diff = dst.width() - src.width() * sy; 572 } else { 573 diff = dst.height() - src.height() * sy; 574 } 575 576 if (stf == ScaleToFit.CENTER.nativeInt) { 577 diff = diff / 2; 578 } 579 580 if (xLarger) { 581 tx += diff; 582 } else { 583 ty += diff; 584 } 585 } 586 587 d.mValues[0] = sx; 588 d.mValues[4] = sy; 589 d.mValues[2] = tx; 590 d.mValues[5] = ty; 591 d.mValues[1] = d.mValues[3] = d.mValues[6] = d.mValues[7] = 0; 592 593 } 594 // shared cleanup 595 d.mValues[8] = 1; 596 return true; 597 } 598 599 /*package*/ static boolean native_setPolyToPoly(int native_object, float[] src, int srcIndex, 600 float[] dst, int dstIndex, int pointCount) { 601 // FIXME 602 throw new UnsupportedOperationException("Native delegate needed: Matrix_Delegate.native_setPolyToPoly"); 603 } 604 605 /*package*/ static boolean native_invert(int native_object, int inverse) { 606 Matrix_Delegate d = sManager.getDelegate(native_object); 607 if (d == null) { 608 return false; 609 } 610 611 Matrix_Delegate inv_mtx = sManager.getDelegate(inverse); 612 if (inv_mtx == null) { 613 return false; 614 } 615 616 try { 617 AffineTransform affineTransform = d.getAffineTransform(); 618 AffineTransform inverseTransform = affineTransform.createInverse(); 619 inv_mtx.mValues[0] = (float)inverseTransform.getScaleX(); 620 inv_mtx.mValues[1] = (float)inverseTransform.getShearX(); 621 inv_mtx.mValues[2] = (float)inverseTransform.getTranslateX(); 622 inv_mtx.mValues[3] = (float)inverseTransform.getScaleX(); 623 inv_mtx.mValues[4] = (float)inverseTransform.getShearY(); 624 inv_mtx.mValues[5] = (float)inverseTransform.getTranslateY(); 625 626 return true; 627 } catch (NoninvertibleTransformException e) { 628 return false; 629 } 630 } 631 632 /*package*/ static void native_mapPoints(int native_object, float[] dst, int dstIndex, 633 float[] src, int srcIndex, int ptCount, boolean isPts) { 634 Matrix_Delegate d = sManager.getDelegate(native_object); 635 if (d == null) { 636 return; 637 } 638 639 if (isPts) { 640 d.mapPoints(dst, dstIndex, src, srcIndex, ptCount); 641 } else { 642 // src is vectors 643 // FIXME 644 throw new UnsupportedOperationException("Native delegate needed: Matrix_Delegate.native_mapPoints"); 645 } 646 } 647 648 /*package*/ static boolean native_mapRect(int native_object, RectF dst, RectF src) { 649 Matrix_Delegate d = sManager.getDelegate(native_object); 650 if (d == null) { 651 return false; 652 } 653 654 return d.mapRect(dst, src); 655 } 656 657 /*package*/ static float native_mapRadius(int native_object, float radius) { 658 // FIXME 659 throw new UnsupportedOperationException("Native delegate needed: Matrix_Delegate.native_mapRadius"); 660 } 661 662 /*package*/ static void native_getValues(int native_object, float[] values) { 663 Matrix_Delegate d = sManager.getDelegate(native_object); 664 if (d == null) { 665 return; 666 } 667 668 System.arraycopy(d.mValues, 0, d.mValues, 0, MATRIX_SIZE); 669 } 670 671 /*package*/ static void native_setValues(int native_object, float[] values) { 672 Matrix_Delegate d = sManager.getDelegate(native_object); 673 if (d == null) { 674 return; 675 } 676 677 System.arraycopy(values, 0, d.mValues, 0, MATRIX_SIZE); 678 } 679 680 /*package*/ static boolean native_equals(int native_a, int native_b) { 681 Matrix_Delegate a = sManager.getDelegate(native_a); 682 if (a == null) { 683 return false; 684 } 685 686 Matrix_Delegate b = sManager.getDelegate(native_b); 687 if (b == null) { 688 return false; 689 } 690 691 for (int i = 0 ; i < MATRIX_SIZE ; i++) { 692 if (a.mValues[i] != b.mValues[i]) { 693 return false; 694 } 695 } 696 697 return true; 698 } 699 700 /*package*/ static void finalizer(int native_instance) { 701 sManager.removeDelegate(native_instance); 702 } 703 704 // ---- Private helper methods ---- 705 706 /*package*/ static AffineTransform getAffineTransform(float[] matrix) { 707 // the AffineTransform constructor takes the value in a different order 708 // for a matrix [ 0 1 2 ] 709 // [ 3 4 5 ] 710 // the order is 0, 3, 1, 4, 2, 5... 711 return new AffineTransform( 712 matrix[0], matrix[3], matrix[1], 713 matrix[4], matrix[2], matrix[5]); 714 } 715 716 /** 717 * Reset a matrix to the identity 718 */ 719 private static void reset(float[] mtx) { 720 for (int i = 0, k = 0; i < 3; i++) { 721 for (int j = 0; j < 3; j++, k++) { 722 mtx[k] = ((i==j) ? 1 : 0); 723 } 724 } 725 } 726 727 @SuppressWarnings("unused") 728 private final static int kIdentity_Mask = 0; 729 private final static int kTranslate_Mask = 0x01; //!< set if the matrix has translation 730 private final static int kScale_Mask = 0x02; //!< set if the matrix has X or Y scale 731 private final static int kAffine_Mask = 0x04; //!< set if the matrix skews or rotates 732 private final static int kPerspective_Mask = 0x08; //!< set if the matrix is in perspective 733 private final static int kRectStaysRect_Mask = 0x10; 734 @SuppressWarnings("unused") 735 private final static int kUnknown_Mask = 0x80; 736 737 @SuppressWarnings("unused") 738 private final static int kAllMasks = kTranslate_Mask | 739 kScale_Mask | 740 kAffine_Mask | 741 kPerspective_Mask | 742 kRectStaysRect_Mask; 743 744 // these guys align with the masks, so we can compute a mask from a variable 0/1 745 @SuppressWarnings("unused") 746 private final static int kTranslate_Shift = 0; 747 @SuppressWarnings("unused") 748 private final static int kScale_Shift = 1; 749 @SuppressWarnings("unused") 750 private final static int kAffine_Shift = 2; 751 @SuppressWarnings("unused") 752 private final static int kPerspective_Shift = 3; 753 private final static int kRectStaysRect_Shift = 4; 754 755 private int computeTypeMask() { 756 int mask = 0; 757 758 if (mValues[6] != 0. || mValues[7] != 0. || mValues[8] != 1.) { 759 mask |= kPerspective_Mask; 760 } 761 762 if (mValues[2] != 0. || mValues[5] != 0.) { 763 mask |= kTranslate_Mask; 764 } 765 766 float m00 = mValues[0]; 767 float m01 = mValues[1]; 768 float m10 = mValues[3]; 769 float m11 = mValues[4]; 770 771 if (m01 != 0. || m10 != 0.) { 772 mask |= kAffine_Mask; 773 } 774 775 if (m00 != 1. || m11 != 1.) { 776 mask |= kScale_Mask; 777 } 778 779 if ((mask & kPerspective_Mask) == 0) { 780 // map non-zero to 1 781 int im00 = m00 != 0 ? 1 : 0; 782 int im01 = m01 != 0 ? 1 : 0; 783 int im10 = m10 != 0 ? 1 : 0; 784 int im11 = m11 != 0 ? 1 : 0; 785 786 // record if the (p)rimary and (s)econdary diagonals are all 0 or 787 // all non-zero (answer is 0 or 1) 788 int dp0 = (im00 | im11) ^ 1; // true if both are 0 789 int dp1 = im00 & im11; // true if both are 1 790 int ds0 = (im01 | im10) ^ 1; // true if both are 0 791 int ds1 = im01 & im10; // true if both are 1 792 793 // return 1 if primary is 1 and secondary is 0 or 794 // primary is 0 and secondary is 1 795 mask |= ((dp0 & ds1) | (dp1 & ds0)) << kRectStaysRect_Shift; 796 } 797 798 return mask; 799 } 800 801 private Matrix_Delegate() { 802 reset(); 803 } 804 805 private Matrix_Delegate(float[] values) { 806 System.arraycopy(values, 0, mValues, 0, MATRIX_SIZE); 807 } 808 809 /** 810 * Adds the given transformation to the current Matrix 811 * <p/>This in effect does this = this*matrix 812 * @param matrix 813 */ 814 private void postTransform(float[] matrix) { 815 float[] tmp = new float[9]; 816 multiply(tmp, mValues, matrix); 817 mValues = tmp; 818 } 819 820 /** 821 * Adds the given transformation to the current Matrix 822 * <p/>This in effect does this = matrix*this 823 * @param matrix 824 */ 825 private void preTransform(float[] matrix) { 826 float[] tmp = new float[9]; 827 multiply(tmp, matrix, mValues); 828 mValues = tmp; 829 } 830 831 /** 832 * Apply this matrix to the array of 2D points specified by src, and write 833 * the transformed points into the array of points specified by dst. The 834 * two arrays represent their "points" as pairs of floats [x, y]. 835 * 836 * @param dst The array of dst points (x,y pairs) 837 * @param dstIndex The index of the first [x,y] pair of dst floats 838 * @param src The array of src points (x,y pairs) 839 * @param srcIndex The index of the first [x,y] pair of src floats 840 * @param pointCount The number of points (x,y pairs) to transform 841 */ 842 843 private void mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex, 844 int pointCount) { 845 //checkPointArrays(src, srcIndex, dst, dstIndex, pointCount); 846 847 float[] tmpDest = dst; 848 boolean inPlace = dst == src; 849 if (inPlace) { 850 tmpDest = new float[dstIndex + pointCount * 2]; 851 } 852 853 for (int i = 0 ; i < pointCount * 2 ; i += 2) { 854 // just in case we are doing in place, we better put this in temp vars 855 float x = mValues[0] * src[i + srcIndex] + 856 mValues[1] * src[i + srcIndex + 1] + 857 mValues[2]; 858 float y = mValues[3] * src[i + srcIndex] + 859 mValues[4] * src[i + srcIndex + 1] + 860 mValues[5]; 861 862 tmpDest[i + dstIndex] = x; 863 tmpDest[i + dstIndex + 1] = y; 864 } 865 866 if (inPlace) { 867 System.arraycopy(tmpDest, dstIndex, dst, dstIndex, pointCount * 2); 868 } 869 } 870 871 /** 872 * Apply this matrix to the array of 2D points, and write the transformed 873 * points back into the array 874 * 875 * @param pts The array [x0, y0, x1, y1, ...] of points to transform. 876 */ 877 878 private void mapPoints(float[] pts) { 879 mapPoints(pts, 0, pts, 0, pts.length >> 1); 880 } 881 882 /** 883 * multiply two matrices and store them in a 3rd. 884 * <p/>This in effect does dest = a*b 885 * dest cannot be the same as a or b. 886 */ 887 /*package*/ static void multiply(float dest[], float[] a, float[] b) { 888 // first row 889 dest[0] = b[0] * a[0] + b[1] * a[3] + b[2] * a[6]; 890 dest[1] = b[0] * a[1] + b[1] * a[4] + b[2] * a[7]; 891 dest[2] = b[0] * a[2] + b[1] * a[5] + b[2] * a[8]; 892 893 // 2nd row 894 dest[3] = b[3] * a[0] + b[4] * a[3] + b[5] * a[6]; 895 dest[4] = b[3] * a[1] + b[4] * a[4] + b[5] * a[7]; 896 dest[5] = b[3] * a[2] + b[4] * a[5] + b[5] * a[8]; 897 898 // 3rd row 899 dest[6] = b[6] * a[0] + b[7] * a[3] + b[8] * a[6]; 900 dest[7] = b[6] * a[1] + b[7] * a[4] + b[8] * a[7]; 901 dest[8] = b[6] * a[2] + b[7] * a[5] + b[8] * a[8]; 902 } 903 904 /** 905 * Returns a matrix that represents a given translate 906 * @param dx 907 * @param dy 908 * @return 909 */ 910 /*package*/ static float[] getTranslate(float dx, float dy) { 911 return setTranslate(new float[9], dx, dy); 912 } 913 914 /*package*/ static float[] setTranslate(float[] dest, float dx, float dy) { 915 dest[0] = 1; 916 dest[1] = 0; 917 dest[2] = dx; 918 dest[3] = 0; 919 dest[4] = 1; 920 dest[5] = dy; 921 dest[6] = 0; 922 dest[7] = 0; 923 dest[8] = 1; 924 return dest; 925 } 926 927 /*package*/ static float[] getScale(float sx, float sy) { 928 return new float[] { sx, 0, 0, 0, sy, 0, 0, 0, 1 }; 929 } 930 931 /** 932 * Returns a matrix that represents the given scale info. 933 * @param sx 934 * @param sy 935 * @param px 936 * @param py 937 */ 938 /*package*/ static float[] getScale(float sx, float sy, float px, float py) { 939 float[] tmp = new float[9]; 940 float[] tmp2 = new float[9]; 941 942 // TODO: do it in one pass 943 944 // translate tmp so that the pivot is in 0,0 945 setTranslate(tmp, -px, -py); 946 947 // scale into tmp2 948 multiply(tmp2, tmp, getScale(sx, sy)); 949 950 // translate back the pivot back into tmp 951 multiply(tmp, tmp2, getTranslate(px, py)); 952 953 return tmp; 954 } 955 956 957 /*package*/ static float[] getRotate(float degrees) { 958 double rad = Math.toRadians(degrees); 959 float sin = (float)Math.sin(rad); 960 float cos = (float)Math.cos(rad); 961 962 return getRotate(sin, cos); 963 } 964 965 /*package*/ static float[] getRotate(float sin, float cos) { 966 return setRotate(new float[9], sin, cos); 967 } 968 969 /*package*/ static float[] setRotate(float[] dest, float degrees) { 970 double rad = Math.toRadians(degrees); 971 float sin = (float)Math.sin(rad); 972 float cos = (float)Math.cos(rad); 973 974 return setRotate(dest, sin, cos); 975 } 976 977 /*package*/ static float[] setRotate(float[] dest, float sin, float cos) { 978 dest[0] = cos; 979 dest[1] = -sin; 980 dest[2] = 0; 981 dest[3] = sin; 982 dest[4] = cos; 983 dest[5] = 0; 984 dest[6] = 0; 985 dest[7] = 0; 986 dest[8] = 1; 987 return dest; 988 } 989 990 /*package*/ static float[] getRotate(float degrees, float px, float py) { 991 float[] tmp = new float[9]; 992 float[] tmp2 = new float[9]; 993 994 // TODO: do it in one pass 995 996 // translate so that the pivot is in 0,0 997 setTranslate(tmp, -px, -py); 998 999 // rotate into tmp2 1000 double rad = Math.toRadians(degrees); 1001 float cos = (float)Math.cos(rad); 1002 float sin = (float)Math.sin(rad); 1003 multiply(tmp2, tmp, getRotate(sin, cos)); 1004 1005 // translate back the pivot back into tmp 1006 multiply(tmp, tmp2, getTranslate(px, py)); 1007 1008 return tmp; 1009 } 1010 1011 /*package*/ static float[] getSkew(float kx, float ky) { 1012 return new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 }; 1013 } 1014 1015 /*package*/ static float[] getSkew(float kx, float ky, float px, float py) { 1016 float[] tmp = new float[9]; 1017 float[] tmp2 = new float[9]; 1018 1019 // TODO: do it in one pass 1020 1021 // translate so that the pivot is in 0,0 1022 setTranslate(tmp, -px, -py); 1023 1024 // skew into tmp2 1025 multiply(tmp2, tmp, new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 }); 1026 // translate back the pivot back into tmp 1027 multiply(tmp, tmp2, getTranslate(px, py)); 1028 1029 return tmp; 1030 } 1031} 1032