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