Spec-Zone .ru
спецификации, руководства, описания, API
|
001/* 002 * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025 026package javafx.scene.transform; 027 028import javafx.beans.property.DoubleProperty; 029import javafx.beans.property.DoublePropertyBase; 030import javafx.beans.property.ObjectProperty; 031import javafx.beans.property.ObjectPropertyBase; 032import javafx.geometry.Point3D; 033 034import com.sun.javafx.geom.transform.Affine3D; 035import javafx.geometry.Point2D; 036 037 038/** 039 * This class represents an {@code Affine} object that rotates coordinates 040 * around an anchor point. This operation is equivalent to translating the 041 * coordinates so that the anchor point is at the origin (S1), then rotating them 042 * about the new origin (S2), and finally translating so that the 043 * intermediate origin is restored to the coordinates of the original 044 * anchor point (S3). 045 * <p/> 046 * For example, the matrix representing the returned transform of 047 * new Rotate (theta, x, y, z) around the Z-axis 048 * 049 * is : 050 * <pre> 051 * [ cos(theta) -sin(theta) 0 x-x*cos+y*sin ] 052 * [ sin(theta) cos(theta) 0 y-x*sin-y*cos ] 053 * [ 0 0 1 z ] 054 * </pre> 055 * <p> 056 * For example, to rotate a text 30 degrees around the Z-axis at 057 * anchor point of (50,30): 058 * <pre><code> 059 * Text text = new Text("This is a test"); 060 * text.setX(10); 061 * text.setY(50); 062 * text.setFont(new Font(20)); 063 * 064 * text.getTransforms().add(new Rotate(30, 50, 30)); 065 * </code></pre> 066 * </p> 067 */ 068 069public class Rotate extends Transform { 070 071 /** 072 * Specifies the X-axis as the axis of rotation. 073 */ 074 public static final Point3D X_AXIS = new Point3D(1,0,0); 075 076 /** 077 * Specifies the Y-axis as the axis of rotation. 078 */ 079 public static final Point3D Y_AXIS = new Point3D(0,1,0); 080 081 /** 082 * Specifies the Z-axis as the axis of rotation. 083 */ 084 public static final Point3D Z_AXIS = new Point3D(0,0,1); 085 086 /** 087 * Avoids lot of repeated computation. 088 * @see #MatrixCache 089 */ 090 private MatrixCache cache; 091 092 /** 093 * Avoids lot of repeated computation. 094 * @see #MatrixCache 095 */ 096 private MatrixCache inverseCache; 097 098 /** 099 * Creates a default Rotate transform (identity). 100 */ 101 public Rotate() { 102 } 103 104 /** 105 * Creates a two-dimensional Rotate transform. 106 * @param angle the angle of rotation measured in degrees 107 */ 108 public Rotate(double angle) { 109 setAngle(angle); 110 } 111 112 /** 113 * Creates a three-dimensional Rotate transform. 114 * @param angle the angle of rotation measured in degrees 115 * @param axis the axis of rotation 116 */ 117 public Rotate(double angle, Point3D axis) { 118 setAngle(angle); 119 setAxis(axis); 120 } 121 122 /** 123 * Creates a two-dimensional Rotate transform with pivot. 124 * @param angle the angle of rotation measured in degrees 125 * @param pivotX the X coordinate of the rotation pivot point 126 * @param pivotY the Y coordinate of the rotation pivot point 127 */ 128 public Rotate(double angle, double pivotX, double pivotY) { 129 setAngle(angle); 130 setPivotX(pivotX); 131 setPivotY(pivotY); 132 } 133 134 /** 135 * Creates a simple Rotate transform with three-dimensional pivot. 136 * @param angle the angle of rotation measured in degrees 137 * @param pivotX the X coordinate of the rotation pivot point 138 * @param pivotY the Y coordinate of the rotation pivot point 139 * @param pivotZ the Z coordinate of the rotation pivot point 140 */ 141 public Rotate(double angle, double pivotX, double pivotY, double pivotZ) { 142 this(angle, pivotX, pivotY); 143 setPivotZ(pivotZ); 144 } 145 146 /** 147 * Creates a three-dimensional Rotate transform with pivot. 148 * @param angle the angle of rotation measured in degrees 149 * @param pivotX the X coordinate of the rotation pivot point 150 * @param pivotY the Y coordinate of the rotation pivot point 151 * @param pivotZ the Z coordinate of the rotation pivot point 152 * @param axis the axis of rotation 153 */ 154 public Rotate(double angle, double pivotX, double pivotY, double pivotZ, Point3D axis) { 155 this(angle, pivotX, pivotY); 156 setPivotZ(pivotZ); 157 setAxis(axis); 158 } 159 160 /** 161 * Defines the angle of rotation measured in degrees. 162 */ 163 private DoubleProperty angle; 164 165 166 public final void setAngle(double value) { 167 angleProperty().set(value); 168 } 169 170 public final double getAngle() { 171 return angle == null ? 0.0 : angle.get(); 172 } 173 174 public final DoubleProperty angleProperty() { 175 if (angle == null) { 176 angle = new DoublePropertyBase() { 177 178 @Override 179 public void invalidated() { 180 transformChanged(); 181 } 182 183 @Override 184 public Object getBean() { 185 return Rotate.this; 186 } 187 188 @Override 189 public String getName() { 190 return "angle"; 191 } 192 }; 193 } 194 return angle; 195 } 196 197 /** 198 * Defines the X coordinate of the rotation pivot point. 199 */ 200 private DoubleProperty pivotX; 201 202 203 public final void setPivotX(double value) { 204 pivotXProperty().set(value); 205 } 206 207 public final double getPivotX() { 208 return pivotX == null ? 0.0 : pivotX.get(); 209 } 210 211 public final DoubleProperty pivotXProperty() { 212 if (pivotX == null) { 213 pivotX = new DoublePropertyBase() { 214 215 @Override 216 public void invalidated() { 217 transformChanged(); 218 } 219 220 @Override 221 public Object getBean() { 222 return Rotate.this; 223 } 224 225 @Override 226 public String getName() { 227 return "pivotX"; 228 } 229 }; 230 } 231 return pivotX; 232 } 233 234 /** 235 * Defines the Y coordinate of the rotation pivot point. 236 */ 237 private DoubleProperty pivotY; 238 239 240 public final void setPivotY(double value) { 241 pivotYProperty().set(value); 242 } 243 244 public final double getPivotY() { 245 return pivotY == null ? 0.0 : pivotY.get(); 246 } 247 248 public final DoubleProperty pivotYProperty() { 249 if (pivotY == null) { 250 pivotY = new DoublePropertyBase() { 251 252 @Override 253 public void invalidated() { 254 transformChanged(); 255 } 256 257 @Override 258 public Object getBean() { 259 return Rotate.this; 260 } 261 262 @Override 263 public String getName() { 264 return "pivotY"; 265 } 266 }; 267 } 268 return pivotY; 269 } 270 271 /** 272 * Defines the Z coordinate of the rotation pivot point. 273 */ 274 private DoubleProperty pivotZ; 275 276 277 public final void setPivotZ(double value) { 278 pivotZProperty().set(value); 279 } 280 281 public final double getPivotZ() { 282 return pivotZ == null ? 0.0 : pivotZ.get(); 283 } 284 285 public final DoubleProperty pivotZProperty() { 286 if (pivotZ == null) { 287 pivotZ = new DoublePropertyBase() { 288 289 @Override 290 public void invalidated() { 291 transformChanged(); 292 } 293 294 @Override 295 public Object getBean() { 296 return Rotate.this; 297 } 298 299 @Override 300 public String getName() { 301 return "pivotZ"; 302 } 303 }; 304 } 305 return pivotZ; 306 } 307 308 /** 309 * Defines the axis of rotation at the pivot point. 310 */ 311 private ObjectProperty<Point3D> axis; 312 313 314 public final void setAxis(Point3D value) { 315 axisProperty().set(value); 316 } 317 318 public final Point3D getAxis() { 319 return axis == null ? Z_AXIS : axis.get(); 320 } 321 322 public final ObjectProperty<Point3D> axisProperty() { 323 if (axis == null) { 324 axis = new ObjectPropertyBase<Point3D>(Z_AXIS) { 325 326 @Override 327 public void invalidated() { 328 transformChanged(); 329 } 330 331 @Override 332 public Object getBean() { 333 return Rotate.this; 334 } 335 336 @Override 337 public String getName() { 338 return "axis"; 339 } 340 }; 341 } 342 return axis; 343 } 344 345 /* ************************************************************************* 346 * * 347 * Element getters * 348 * * 349 **************************************************************************/ 350 351 @Override 352 public double getMxx() { 353 updateCache(); 354 return cache.mxx; 355 } 356 357 @Override 358 public double getMxy() { 359 updateCache(); 360 return cache.mxy; 361 } 362 363 @Override 364 public double getMxz() { 365 updateCache(); 366 return cache.mxz; 367 } 368 369 @Override 370 public double getTx() { 371 updateCache(); 372 return cache.tx; 373 } 374 375 @Override 376 public double getMyx() { 377 updateCache(); 378 return cache.myx; 379 } 380 381 @Override 382 public double getMyy() { 383 updateCache(); 384 return cache.myy; 385 } 386 387 @Override 388 public double getMyz() { 389 updateCache(); 390 return cache.myz; 391 } 392 393 @Override 394 public double getTy() { 395 updateCache(); 396 return cache.ty; 397 } 398 399 @Override 400 public double getMzx() { 401 updateCache(); 402 return cache.mzx; 403 } 404 405 @Override 406 public double getMzy() { 407 updateCache(); 408 return cache.mzy; 409 } 410 411 @Override 412 public double getMzz() { 413 updateCache(); 414 return cache.mzz; 415 } 416 417 @Override 418 public double getTz() { 419 updateCache(); 420 return cache.tz; 421 } 422 423 /* ************************************************************************* 424 * * 425 * State getters * 426 * * 427 **************************************************************************/ 428 429 @Override 430 boolean computeIs2D() { 431 final Point3D a = getAxis(); 432 return (a.getX() == 0.0 && a.getY() == 0.0) || getAngle() == 0; 433 } 434 435 @Override 436 boolean computeIsIdentity() { 437 if (getAngle() == 0.0) { 438 return true; 439 } 440 441 final Point3D a = getAxis(); 442 return a.getX() == 0 && a.getY() == 0 && a.getZ() == 0.0; 443 } 444 445 /* ************************************************************************* 446 * * 447 * Array getters * 448 * * 449 **************************************************************************/ 450 451 @Override 452 void fill2DArray(double[] array) { 453 updateCache(); 454 array[0] = cache.mxx; 455 array[1] = cache.mxy; 456 array[2] = cache.tx; 457 array[3] = cache.myx; 458 array[4] = cache.myy; 459 array[5] = cache.ty; 460 } 461 462 @Override 463 void fill3DArray(double[] array) { 464 updateCache(); 465 array[0] = cache.mxx; 466 array[1] = cache.mxy; 467 array[2] = cache.mxz; 468 array[3] = cache.tx; 469 array[4] = cache.myx; 470 array[5] = cache.myy; 471 array[6] = cache.myz; 472 array[7] = cache.ty; 473 array[8] = cache.mzx; 474 array[9] = cache.mzy; 475 array[10] = cache.mzz; 476 array[11] = cache.tz; 477 return; 478 } 479 480 /* ************************************************************************* 481 * * 482 * Transform creators * 483 * * 484 **************************************************************************/ 485 486 @Override 487 public Transform createConcatenation(Transform transform) { 488 if (transform instanceof Rotate) { 489 Rotate r = (Rotate) transform; 490 final double px = getPivotX(); 491 final double py = getPivotY(); 492 final double pz = getPivotZ(); 493 494 if ((r.getAxis() == getAxis() || 495 r.getAxis().normalize().equals(getAxis().normalize())) && 496 px == r.getPivotX() && 497 py == r.getPivotY() && 498 pz == r.getPivotZ()) { 499 return new Rotate(getAngle() + r.getAngle(), px, py, pz, getAxis()); 500 } 501 } 502 503 if (transform instanceof Affine) { 504 Affine a = (Affine) transform.clone(); 505 a.prepend(this); 506 return a; 507 } 508 509 return super.createConcatenation(transform); 510 } 511 512 @Override 513 public Transform createInverse() throws NonInvertibleTransformException { 514 return new Rotate(-getAngle(), getPivotX(), getPivotY(), getPivotZ(), 515 getAxis()); 516 } 517 518 @Override 519 public Rotate clone() { 520 return new Rotate(getAngle(), getPivotX(), getPivotY(), getPivotZ(), 521 getAxis()); 522 } 523 524 /* ************************************************************************* 525 * * 526 * Transform, Inverse Transform * 527 * * 528 **************************************************************************/ 529 530 @Override 531 public Point2D transform(double x, double y) { 532 ensureCanTransform2DPoint(); 533 534 updateCache(); 535 536 return new Point2D( 537 cache.mxx * x + cache.mxy * y + cache.tx, 538 cache.myx * x + cache.myy * y + cache.ty); 539 } 540 541 @Override 542 public Point3D transform(double x, double y, double z) { 543 updateCache(); 544 545 return new Point3D( 546 cache.mxx * x + cache.mxy * y + cache.mxz * z + cache.tx, 547 cache.myx * x + cache.myy * y + cache.myz * z + cache.ty, 548 cache.mzx * x + cache.mzy * y + cache.mzz * z + cache.tz); 549 } 550 551 @Override 552 void transform2DPointsImpl(double[] srcPts, int srcOff, 553 double[] dstPts, int dstOff, int numPts) { 554 updateCache(); 555 556 while (--numPts >= 0) { 557 final double x = srcPts[srcOff++]; 558 final double y = srcPts[srcOff++]; 559 560 dstPts[dstOff++] = cache.mxx * x + cache.mxy * y + cache.tx; 561 dstPts[dstOff++] = cache.myx * x + cache.myy * y + cache.ty; 562 } 563 } 564 565 @Override 566 void transform3DPointsImpl(double[] srcPts, int srcOff, 567 double[] dstPts, int dstOff, int numPts) { 568 569 updateCache(); 570 571 while (--numPts >= 0) { 572 final double x = srcPts[srcOff++]; 573 final double y = srcPts[srcOff++]; 574 final double z = srcPts[srcOff++]; 575 576 dstPts[dstOff++] = cache.mxx * x + cache.mxy * y + cache.mxz * z + cache.tx; 577 dstPts[dstOff++] = cache.myx * x + cache.myy * y + cache.myz * z + cache.ty; 578 dstPts[dstOff++] = cache.mzx * x + cache.mzy * y + cache.mzz * z + cache.tz; 579 } 580 } 581 582 @Override 583 public Point2D deltaTransform(double x, double y) { 584 ensureCanTransform2DPoint(); 585 586 updateCache(); 587 588 return new Point2D( 589 cache.mxx * x + cache.mxy * y, 590 cache.myx * x + cache.myy * y); 591 } 592 593 @Override 594 public Point3D deltaTransform(double x, double y, double z) { 595 updateCache(); 596 597 return new Point3D( 598 cache.mxx * x + cache.mxy * y + cache.mxz * z, 599 cache.myx * x + cache.myy * y + cache.myz * z, 600 cache.mzx * x + cache.mzy * y + cache.mzz * z); 601 } 602 603 @Override 604 public Point2D inverseTransform(double x, double y) { 605 ensureCanTransform2DPoint(); 606 607 updateInverseCache(); 608 609 return new Point2D( 610 inverseCache.mxx * x + inverseCache.mxy * y + inverseCache.tx, 611 inverseCache.myx * x + inverseCache.myy * y + inverseCache.ty); 612 } 613 614 @Override 615 public Point3D inverseTransform(double x, double y, double z) { 616 updateInverseCache(); 617 618 return new Point3D( 619 inverseCache.mxx * x + inverseCache.mxy * y + inverseCache.mxz * z 620 + inverseCache.tx, 621 inverseCache.myx * x + inverseCache.myy * y + inverseCache.myz * z 622 + inverseCache.ty, 623 inverseCache.mzx * x + inverseCache.mzy * y + inverseCache.mzz * z 624 + inverseCache.tz); 625 } 626 627 @Override 628 void inverseTransform2DPointsImpl(double[] srcPts, int srcOff, 629 double[] dstPts, int dstOff, int numPts) { 630 updateInverseCache(); 631 632 while (--numPts >= 0) { 633 final double x = srcPts[srcOff++]; 634 final double y = srcPts[srcOff++]; 635 636 dstPts[dstOff++] = inverseCache.mxx * x + inverseCache.mxy * y 637 + inverseCache.tx; 638 dstPts[dstOff++] = inverseCache.myx * x + inverseCache.myy * y 639 + inverseCache.ty; 640 } 641 } 642 643 @Override 644 void inverseTransform3DPointsImpl(double[] srcPts, int srcOff, 645 double[] dstPts, int dstOff, int numPts) { 646 647 updateInverseCache(); 648 649 while (--numPts >= 0) { 650 final double x = srcPts[srcOff++]; 651 final double y = srcPts[srcOff++]; 652 final double z = srcPts[srcOff++]; 653 654 dstPts[dstOff++] = inverseCache.mxx * x + inverseCache.mxy * y 655 + inverseCache.mxz * z + inverseCache.tx; 656 dstPts[dstOff++] = inverseCache.myx * x + inverseCache.myy * y 657 + inverseCache.myz * z + inverseCache.ty; 658 dstPts[dstOff++] = inverseCache.mzx * x + inverseCache.mzy * y 659 + inverseCache.mzz * z + inverseCache.tz; 660 } 661 } 662 663 @Override 664 public Point2D inverseDeltaTransform(double x, double y) { 665 ensureCanTransform2DPoint(); 666 667 updateInverseCache(); 668 669 return new Point2D( 670 inverseCache.mxx * x + inverseCache.mxy * y, 671 inverseCache.myx * x + inverseCache.myy * y); 672 } 673 674 @Override 675 public Point3D inverseDeltaTransform(double x, double y, double z) { 676 updateInverseCache(); 677 678 return new Point3D( 679 inverseCache.mxx * x + inverseCache.mxy * y + inverseCache.mxz * z, 680 inverseCache.myx * x + inverseCache.myy * y + inverseCache.myz * z, 681 inverseCache.mzx * x + inverseCache.mzy * y + inverseCache.mzz * z); 682 } 683 684 /* ************************************************************************* 685 * * 686 * Other API * 687 * * 688 **************************************************************************/ 689 690 /** 691 * Returns a string representation of this {@code Rotate} object. 692 * @return a string representation of this {@code Rotate} object. 693 */ 694 @Override 695 public String toString() { 696 final StringBuilder sb = new StringBuilder("Rotate ["); 697 698 sb.append("angle=").append(getAngle()); 699 sb.append(", pivotX=").append(getPivotX()); 700 sb.append(", pivotY=").append(getPivotY()); 701 sb.append(", pivotZ=").append(getPivotZ()); 702 sb.append(", axis=").append(getAxis()); 703 704 return sb.append("]").toString(); 705 } 706 707 /* ************************************************************************* 708 * * 709 * Internal implementation stuff * 710 * * 711 **************************************************************************/ 712 713 /** 714 * @treatAsPrivate implementation detail 715 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 716 */ 717 @Deprecated 718 @Override 719 public void impl_apply(final Affine3D trans) { 720 double localPivotX = getPivotX(); 721 double localPivotY = getPivotY(); 722 double localPivotZ = getPivotZ(); 723 double localAngle = getAngle(); 724 725 if (localPivotX != 0 || localPivotY != 0 || localPivotZ != 0) { 726 trans.translate(localPivotX, localPivotY, localPivotZ); 727 trans.rotate(Math.toRadians(localAngle), 728 getAxis().getX(),getAxis().getY(), getAxis().getZ()); 729 trans.translate(-localPivotX, -localPivotY, -localPivotZ); 730 } else { 731 trans.rotate(Math.toRadians(localAngle), 732 getAxis().getX(), getAxis().getY(), getAxis().getZ()); 733 } 734 } 735 736 @Override 737 void validate() { 738 getAxis(); 739 getAngle(); 740 getPivotX(); 741 getPivotY(); 742 getPivotZ(); 743 } 744 745 @Override 746 protected void transformChanged() { 747 if (cache != null) { 748 cache.invalidate(); 749 } 750 super.transformChanged(); 751 } 752 753 @Override 754 void appendTo(Affine a) { 755 a.appendRotation(getAngle(), getPivotX(), getPivotY(), getPivotZ(), 756 getAxis()); 757 } 758 759 @Override 760 void prependTo(Affine a) { 761 a.prependRotation(getAngle(), getPivotX(), getPivotY(), getPivotZ(), 762 getAxis()); 763 } 764 765 /** 766 * Updates the matrix cache 767 */ 768 private void updateCache() { 769 if (cache == null) { 770 cache = new MatrixCache(); 771 } 772 773 if (!cache.valid) { 774 cache.update(getAngle(), getAxis(), 775 getPivotX(), getPivotY(), getPivotZ()); 776 } 777 } 778 779 /** 780 * Updates the inverse matrix cache 781 */ 782 private void updateInverseCache() { 783 if (inverseCache == null) { 784 inverseCache = new MatrixCache(); 785 } 786 787 if (!inverseCache.valid) { 788 inverseCache.update(-getAngle(), getAxis(), 789 getPivotX(), getPivotY(), getPivotZ()); 790 } 791 } 792 793 /** 794 * Matrix cache. Computing single transformation matrix elements for 795 * a general rotation is quite expensive. Also each of those partial 796 * computations need some common operations to be made (compute sin 797 * and cos, normalize axis). Therefore with the direct element computations 798 * if all the getters for the elements are called to get the matrix, 799 * the result is slow. 800 * 801 * If a matrix element is asked for, we can reasonably anticipate that 802 * some other elements will be asked for as well. So when any element 803 * needs to be computed, we compute the entire matrix, cache it, 804 * and use the stored values until the transform changes. 805 */ 806 private static class MatrixCache { 807 boolean valid = false; 808 boolean is3D = false; 809 810 double mxx, mxy, mxz, tx, 811 myx, myy, myz, ty, 812 mzx, mzy, mzz, tz; 813 814 public MatrixCache() { 815 // to have the 3D part right when using 2D-only 816 mzz = 1.0; 817 } 818 819 public void update(double angle, Point3D axis, 820 double px, double py, double pz) { 821 822 final double rads = Math.toRadians(angle); 823 final double sin = Math.sin(rads); 824 final double cos = Math.cos(rads); 825 826 if (axis == Z_AXIS || 827 (axis.getX() == 0.0 && 828 axis.getY() == 0.0 && 829 axis.getZ() > 0.0)) { 830 // 2D case 831 mxx = cos; 832 mxy = -sin; 833 tx = px * (1 - cos) + py * sin; 834 myx = sin; 835 myy = cos; 836 ty = py * (1 - cos) - px * sin; 837 838 if (is3D) { 839 // Was 3D, needs to set the 3D values 840 mxz = 0.0; 841 myz = 0.0; 842 mzx = 0.0; 843 mzy = 0.0; 844 mzz = 1.0; 845 tz = 0.0; 846 is3D = false; 847 } 848 valid = true; 849 return; 850 } 851 // 3D case 852 is3D = true; 853 854 double axisX, axisY, axisZ; 855 856 if (axis == X_AXIS || axis == Y_AXIS || axis == Z_AXIS) { 857 axisX = axis.getX(); 858 axisY = axis.getY(); 859 axisZ = axis.getZ(); 860 } else { 861 // normalize 862 final double mag = Math.sqrt(axis.getX() * axis.getX() + 863 axis.getY() * axis.getY() + axis.getZ() * axis.getZ()); 864 865 if (mag == 0.0) { 866 mxx = 1; mxy = 0; mxz = 0; tx = 0; 867 myx = 0; myy = 1; myz = 0; ty = 0; 868 mzx = 0; mzy = 0; mzz = 1; tz = 0; 869 valid = true; 870 return; 871 } else { 872 axisX = axis.getX() / mag; 873 axisY = axis.getY() / mag; 874 axisZ = axis.getZ() / mag; 875 } 876 } 877 878 mxx = cos + axisX * axisX * (1 - cos); 879 mxy = axisX * axisY * (1 - cos) - axisZ * sin; 880 mxz = axisX * axisZ * (1 - cos) + axisY * sin; 881 tx = px * (1 - mxx) - py * mxy - pz * mxz; 882 883 myx = axisY * axisX * (1 - cos) + axisZ * sin; 884 myy = cos + axisY * axisY * (1 - cos); 885 myz = axisY * axisZ * (1 - cos) - axisX * sin; 886 ty = py * (1 - myy) - px * myx - pz * myz; 887 888 mzx = axisZ * axisX * (1 - cos) - axisY * sin; 889 mzy = axisZ * axisY * (1 - cos) + axisX * sin; 890 mzz = cos + axisZ * axisZ * (1 - cos); 891 tz = pz * (1 - mzz) - px * mzx - py * mzy; 892 893 valid = true; 894 } 895 896 public void invalidate() { 897 valid = false; 898 } 899 } 900}