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