1 /*
   2  * Copyright (c) 2009, 2015, Oracle and/or its affiliates.
   3  * All rights reserved. Use is subject to license terms.
   4  *
   5  * This file is available and licensed under the following license:
   6  *
   7  * Redistribution and use in source and binary forms, with or without
   8  * modification, are permitted provided that the following conditions
   9  * are met:
  10  *
  11  *  - Redistributions of source code must retain the above copyright
  12  *    notice, this list of conditions and the following disclaimer.
  13  *  - Redistributions in binary form must reproduce the above copyright
  14  *    notice, this list of conditions and the following disclaimer in
  15  *    the documentation and/or other materials provided with the distribution.
  16  *  - Neither the name of Oracle Corporation nor the names of its
  17  *    contributors may be used to endorse or promote products derived
  18  *    from this software without specific prior written permission.
  19  *
  20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31  */
  32 
  33 package com.javafx.experiments.utils3d.geom.transform;
  34 
  35 import com.javafx.experiments.utils3d.geom.*;
  36 
  37 /**
  38  *
  39  */
  40 public abstract class BaseTransform implements CanTransformVec3d {
  41     public static final BaseTransform IDENTITY_TRANSFORM = new Identity();
  42 
  43     public static enum Degree {
  44         IDENTITY,
  45         TRANSLATE_2D,
  46         AFFINE_2D,
  47         TRANSLATE_3D,
  48         AFFINE_3D,
  49     }
  50 
  51     /*
  52      * This constant is only useful for a cached type field.
  53      * It indicates that the type has been decached and must be recalculated.
  54      */
  55     protected static final int TYPE_UNKNOWN = -1;
  56 
  57     /**
  58      * This constant indicates that the transform defined by this object
  59      * is an identity transform.
  60      * An identity transform is one in which the output coordinates are
  61      * always the same as the input coordinates.
  62      * If this transform is anything other than the identity transform,
  63      * the type will either be the constant GENERAL_TRANSFORM or a
  64      * combination of the appropriate flag bits for the various coordinate
  65      * conversions that this transform performs.
  66      * @see #TYPE_TRANSLATION
  67      * @see #TYPE_UNIFORM_SCALE
  68      * @see #TYPE_GENERAL_SCALE
  69      * @see #TYPE_FLIP
  70      * @see #TYPE_QUADRANT_ROTATION
  71      * @see #TYPE_GENERAL_ROTATION
  72      * @see #TYPE_GENERAL_TRANSFORM
  73      * @see #getType
  74      */
  75     public static final int TYPE_IDENTITY = 0;
  76 
  77     /**
  78      * This flag bit indicates that the transform defined by this object
  79      * performs a translation in addition to the conversions indicated
  80      * by other flag bits.
  81      * A translation moves the coordinates by a constant amount in x
  82      * and y without changing the length or angle of vectors.
  83      * @see #TYPE_IDENTITY
  84      * @see #TYPE_UNIFORM_SCALE
  85      * @see #TYPE_GENERAL_SCALE
  86      * @see #TYPE_FLIP
  87      * @see #TYPE_QUADRANT_ROTATION
  88      * @see #TYPE_GENERAL_ROTATION
  89      * @see #TYPE_GENERAL_TRANSFORM
  90      * @see #getType
  91      */
  92     public static final int TYPE_TRANSLATION = 1;
  93 
  94     /**
  95      * This flag bit indicates that the transform defined by this object
  96      * performs a uniform scale in addition to the conversions indicated
  97      * by other flag bits.
  98      * A uniform scale multiplies the length of vectors by the same amount
  99      * in both the x and y directions without changing the angle between
 100      * vectors.
 101      * This flag bit is mutually exclusive with the TYPE_GENERAL_SCALE flag.
 102      * @see #TYPE_IDENTITY
 103      * @see #TYPE_TRANSLATION
 104      * @see #TYPE_GENERAL_SCALE
 105      * @see #TYPE_FLIP
 106      * @see #TYPE_QUADRANT_ROTATION
 107      * @see #TYPE_GENERAL_ROTATION
 108      * @see #TYPE_GENERAL_TRANSFORM
 109      * @see #getType
 110      */
 111     public static final int TYPE_UNIFORM_SCALE = 2;
 112 
 113     /**
 114      * This flag bit indicates that the transform defined by this object
 115      * performs a general scale in addition to the conversions indicated
 116      * by other flag bits.
 117      * A general scale multiplies the length of vectors by different
 118      * amounts in the x and y directions without changing the angle
 119      * between perpendicular vectors.
 120      * This flag bit is mutually exclusive with the TYPE_UNIFORM_SCALE flag.
 121      * @see #TYPE_IDENTITY
 122      * @see #TYPE_TRANSLATION
 123      * @see #TYPE_UNIFORM_SCALE
 124      * @see #TYPE_FLIP
 125      * @see #TYPE_QUADRANT_ROTATION
 126      * @see #TYPE_GENERAL_ROTATION
 127      * @see #TYPE_GENERAL_TRANSFORM
 128      * @see #getType
 129      */
 130     public static final int TYPE_GENERAL_SCALE = 4;
 131 
 132     /**
 133      * This constant is a bit mask for any of the scale flag bits.
 134      * @see #TYPE_UNIFORM_SCALE
 135      * @see #TYPE_GENERAL_SCALE
 136      */
 137     public static final int TYPE_MASK_SCALE = (TYPE_UNIFORM_SCALE |
 138                            TYPE_GENERAL_SCALE);
 139 
 140     /**
 141      * This flag bit indicates that the transform defined by this object
 142      * performs a mirror image flip about some axis which changes the
 143      * normally right handed coordinate system into a left handed
 144      * system in addition to the conversions indicated by other flag bits.
 145      * A right handed coordinate system is one where the positive X
 146      * axis rotates counterclockwise to overlay the positive Y axis
 147      * similar to the direction that the fingers on your right hand
 148      * curl when you stare end on at your thumb.
 149      * A left handed coordinate system is one where the positive X
 150      * axis rotates clockwise to overlay the positive Y axis similar
 151      * to the direction that the fingers on your left hand curl.
 152      * There is no mathematical way to determine the angle of the
 153      * original flipping or mirroring transformation since all angles
 154      * of flip are identical given an appropriate adjusting rotation.
 155      * @see #TYPE_IDENTITY
 156      * @see #TYPE_TRANSLATION
 157      * @see #TYPE_UNIFORM_SCALE
 158      * @see #TYPE_GENERAL_SCALE
 159      * @see #TYPE_QUADRANT_ROTATION
 160      * @see #TYPE_GENERAL_ROTATION
 161      * @see #TYPE_GENERAL_TRANSFORM
 162      * @see #getType
 163      */
 164     public static final int TYPE_FLIP = 64;
 165     /* NOTE: TYPE_FLIP was added after GENERAL_TRANSFORM was in public
 166      * circulation and the flag bits could no longer be conveniently
 167      * renumbered without introducing binary incompatibility in outside
 168      * code.
 169      */
 170 
 171     /**
 172      * This flag bit indicates that the transform defined by this object
 173      * performs a quadrant rotation by some multiple of 90 degrees in
 174      * addition to the conversions indicated by other flag bits.
 175      * A rotation changes the angles of vectors by the same amount
 176      * regardless of the original direction of the vector and without
 177      * changing the length of the vector.
 178      * This flag bit is mutually exclusive with the TYPE_GENERAL_ROTATION flag.
 179      * @see #TYPE_IDENTITY
 180      * @see #TYPE_TRANSLATION
 181      * @see #TYPE_UNIFORM_SCALE
 182      * @see #TYPE_GENERAL_SCALE
 183      * @see #TYPE_FLIP
 184      * @see #TYPE_GENERAL_ROTATION
 185      * @see #TYPE_GENERAL_TRANSFORM
 186      * @see #getType
 187      */
 188     public static final int TYPE_QUADRANT_ROTATION = 8;
 189 
 190     /**
 191      * This flag bit indicates that the transform defined by this object
 192      * performs a rotation by an arbitrary angle in addition to the
 193      * conversions indicated by other flag bits.
 194      * A rotation changes the angles of vectors by the same amount
 195      * regardless of the original direction of the vector and without
 196      * changing the length of the vector.
 197      * This flag bit is mutually exclusive with the
 198      * TYPE_QUADRANT_ROTATION flag.
 199      * @see #TYPE_IDENTITY
 200      * @see #TYPE_TRANSLATION
 201      * @see #TYPE_UNIFORM_SCALE
 202      * @see #TYPE_GENERAL_SCALE
 203      * @see #TYPE_FLIP
 204      * @see #TYPE_QUADRANT_ROTATION
 205      * @see #TYPE_GENERAL_TRANSFORM
 206      * @see #getType
 207      */
 208     public static final int TYPE_GENERAL_ROTATION = 16;
 209 
 210     /**
 211      * This constant is a bit mask for any of the rotation flag bits.
 212      * @see #TYPE_QUADRANT_ROTATION
 213      * @see #TYPE_GENERAL_ROTATION
 214      */
 215     public static final int TYPE_MASK_ROTATION = (TYPE_QUADRANT_ROTATION |
 216                           TYPE_GENERAL_ROTATION);
 217 
 218     /**
 219      * This constant indicates that the transform defined by this object
 220      * performs an arbitrary conversion of the input coordinates.
 221      * If this transform can be classified by any of the above constants,
 222      * the type will either be the constant TYPE_IDENTITY or a
 223      * combination of the appropriate flag bits for the various coordinate
 224      * conversions that this transform performs.
 225      * @see #TYPE_IDENTITY
 226      * @see #TYPE_TRANSLATION
 227      * @see #TYPE_UNIFORM_SCALE
 228      * @see #TYPE_GENERAL_SCALE
 229      * @see #TYPE_FLIP
 230      * @see #TYPE_QUADRANT_ROTATION
 231      * @see #TYPE_GENERAL_ROTATION
 232      * @see #getType
 233      */
 234     public static final int TYPE_GENERAL_TRANSFORM = 32;
 235 
 236     public static final int TYPE_AFFINE2D_MASK =
 237             (TYPE_TRANSLATION |
 238              TYPE_UNIFORM_SCALE |
 239              TYPE_GENERAL_SCALE |
 240              TYPE_QUADRANT_ROTATION |
 241              TYPE_GENERAL_ROTATION |
 242              TYPE_GENERAL_TRANSFORM |
 243              TYPE_FLIP);
 244 
 245     public static final int TYPE_AFFINE_3D = 128;
 246 
 247     /*
 248      * Convenience method used internally to throw exceptions when
 249      * an operation of degree higher than AFFINE_2D is attempted.
 250      */
 251     static void degreeError(Degree maxSupported) {
 252         throw new InternalError("does not support higher than "+
 253                                 maxSupported+" operations");
 254     }
 255 
 256     public static BaseTransform getInstance(BaseTransform tx) {
 257         if (tx.isIdentity()) {
 258             return IDENTITY_TRANSFORM;
 259         } else if (tx.isTranslateOrIdentity()) {
 260             return new Translate2D(tx);
 261         } else if (tx.is2D()) {
 262             return new Affine2D(tx);
 263         }
 264         return new Affine3D(tx);
 265     }
 266 
 267     public static BaseTransform getInstance(double mxx, double mxy, double mxz, double mxt,
 268                                             double myx, double myy, double myz, double myt,
 269                                             double mzx, double mzy, double mzz, double mzt)
 270     {
 271         if (mxz == 0.0 && myz == 0.0 &&
 272             mzx == 0.0 && mzy == 0.0 && mzz == 1.0 && mzt == 0.0)
 273         {
 274             return getInstance(mxx, myx, mxy, myy, mxt, myt);
 275         } else {
 276             return new Affine3D(mxx, mxy, mxz, mxt,
 277                                 myx, myy, myz, myt,
 278                                 mzx, mzy, mzz, mzt);
 279         }
 280     }
 281 
 282     public static BaseTransform getInstance(double mxx, double myx,
 283                                             double mxy, double myy,
 284                                             double mxt, double myt)
 285     {
 286         if (mxx == 1.0 && myx == 0.0 && mxy == 0.0 && myy == 1.0) {
 287             return getTranslateInstance(mxt, myt);
 288         } else {
 289             return new Affine2D(mxx, myx, mxy, myy, mxt, myt);
 290         }
 291     }
 292 
 293     public static BaseTransform getTranslateInstance(double mxt, double myt) {
 294         if (mxt == 0.0 && myt == 0.0) {
 295             return IDENTITY_TRANSFORM;
 296         } else {
 297             return new Translate2D(mxt, myt);
 298         }
 299     }
 300 
 301     public static BaseTransform getScaleInstance(double mxx, double myy) {
 302         return getInstance(mxx, 0, 0, myy, 0, 0);
 303     }
 304 
 305     public static BaseTransform getRotateInstance(double theta, double x, double y) {
 306         Affine2D a = new Affine2D();
 307         a.setToRotation(theta, x, y);
 308         return a;
 309     }
 310 
 311     public abstract Degree getDegree();
 312 
 313     /**
 314      * Retrieves the flag bits describing the conversion properties of
 315      * this transform.
 316      * The return value is either one of the constants TYPE_IDENTITY
 317      * or TYPE_GENERAL_TRANSFORM, or a combination of the
 318      * appriopriate flag bits.
 319      * A valid combination of flag bits is an exclusive OR operation
 320      * that can combine
 321      * the TYPE_TRANSLATION flag bit
 322      * in addition to either of the
 323      * TYPE_UNIFORM_SCALE or TYPE_GENERAL_SCALE flag bits
 324      * as well as either of the
 325      * TYPE_QUADRANT_ROTATION or TYPE_GENERAL_ROTATION flag bits.
 326      * @return the OR combination of any of the indicated flags that
 327      * apply to this transform
 328      * @see #TYPE_IDENTITY
 329      * @see #TYPE_TRANSLATION
 330      * @see #TYPE_UNIFORM_SCALE
 331      * @see #TYPE_GENERAL_SCALE
 332      * @see #TYPE_QUADRANT_ROTATION
 333      * @see #TYPE_GENERAL_ROTATION
 334      * @see #TYPE_GENERAL_TRANSFORM
 335      */
 336     public abstract int getType();
 337 
 338     public abstract boolean isIdentity();
 339     public abstract boolean isTranslateOrIdentity();
 340     public abstract boolean is2D();
 341 
 342     public abstract double getDeterminant();
 343 
 344     public double getMxx() { return 1.0; }
 345     public double getMxy() { return 0.0; }
 346     public double getMxz() { return 0.0; }
 347     public double getMxt() { return 0.0; }
 348     public double getMyx() { return 0.0; }
 349     public double getMyy() { return 1.0; }
 350     public double getMyz() { return 0.0; }
 351     public double getMyt() { return 0.0; }
 352     public double getMzx() { return 0.0; }
 353     public double getMzy() { return 0.0; }
 354     public double getMzz() { return 1.0; }
 355     public double getMzt() { return 0.0; }
 356 
 357     public abstract Point2D transform(Point2D src, Point2D dst);
 358     public abstract Point2D inverseTransform(Point2D src, Point2D dst)
 359         throws NoninvertibleTransformException;
 360     public abstract Vec3d transform(Vec3d src, Vec3d dst);
 361     public abstract Vec3d deltaTransform(Vec3d src, Vec3d dst);
 362     public abstract Vec3d inverseTransform(Vec3d src, Vec3d dst)
 363         throws NoninvertibleTransformException;
 364     public abstract Vec3d inverseDeltaTransform(Vec3d src, Vec3d dst)
 365         throws NoninvertibleTransformException;
 366 
 367     public abstract void transform(float[] srcPts, int srcOff,
 368                                    float[] dstPts, int dstOff,
 369                                    int numPts);
 370     public abstract void transform(double[] srcPts, int srcOff,
 371                                    double[] dstPts, int dstOff,
 372                                    int numPts);
 373     public abstract void transform(float[] srcPts, int srcOff,
 374                                    double[] dstPts, int dstOff,
 375                                    int numPts);
 376     public abstract void transform(double[] srcPts, int srcOff,
 377                                    float[] dstPts, int dstOff,
 378                                    int numPts);
 379     public abstract void deltaTransform(float[] srcPts, int srcOff,
 380                                         float[] dstPts, int dstOff,
 381                                         int numPts);
 382     public abstract void deltaTransform(double[] srcPts, int srcOff,
 383                                         double[] dstPts, int dstOff,
 384                                         int numPts);
 385     public abstract void inverseTransform(float[] srcPts, int srcOff,
 386                                           float[] dstPts, int dstOff,
 387                                           int numPts)
 388         throws NoninvertibleTransformException;
 389     public abstract void inverseDeltaTransform(float[] srcPts, int srcOff,
 390                                                float[] dstPts, int dstOff,
 391                                                int numPts)
 392         throws NoninvertibleTransformException;
 393     public abstract void inverseTransform(double[] srcPts, int srcOff,
 394                                           double[] dstPts, int dstOff,
 395                                           int numPts)
 396         throws NoninvertibleTransformException;
 397 
 398     public abstract BaseBounds transform(BaseBounds bounds, BaseBounds result);
 399     public abstract void transform(Rectangle rect, Rectangle result);
 400     public abstract BaseBounds inverseTransform(BaseBounds bounds, BaseBounds result)
 401         throws NoninvertibleTransformException;
 402     public abstract void inverseTransform(Rectangle rect, Rectangle result)
 403         throws NoninvertibleTransformException;
 404 
 405     public abstract void setToIdentity();
 406     public abstract void setTransform(BaseTransform xform);
 407 
 408     /**
 409      * This function inverts the {@code BaseTransform} in place.  All
 410      * current implementations can support their own inverted form, and
 411      * that should likely remain true in the future as well.
 412      */
 413     public abstract void invert() throws NoninvertibleTransformException;
 414 
 415     /**
 416      * This function is only guaranteed to succeed if the transform is
 417      * of degree AFFINE2D or less and the matrix
 418      * parameters specified came from this same instance.  In practice,
 419      * they will also tend to succeed if they specify a transform of
 420      * Degree less than or equal to the Degree of this instance as well,
 421      * but the intent of this method is to restore the transform that
 422      * had been read out of this transform into local variables.
 423      */
 424     public abstract void restoreTransform(double mxx, double myx,
 425                                           double mxy, double myy,
 426                                           double mxt, double myt);
 427 
 428     /**
 429      * This function is only guaranteed to succeed if the matrix
 430      * parameters specified came from this same instance.  In practice,
 431      * they will also tend to succeed if they specify a transform of
 432      * Degree less than or equal to the Degree of this instance as well,
 433      * but the intent of this method is to restore the transform that
 434      * had been read out of this transform into local variables.
 435      */
 436     public abstract void restoreTransform(double mxx, double mxy, double mxz, double mxt,
 437                                           double myx, double myy, double myz, double myt,
 438                                           double mzx, double mzy, double mzz, double mzt);
 439 
 440     public abstract BaseTransform deriveWithTranslation(double mxt, double myt);
 441     public abstract BaseTransform deriveWithTranslation(double mxt, double myt, double mzt);
 442     public abstract BaseTransform deriveWithScale(double mxx, double myy, double mzz);
 443     public abstract BaseTransform deriveWithRotation(double theta, double axisX, double axisY, double axisZ);
 444     public abstract BaseTransform deriveWithPreTranslation(double mxt, double myt);
 445     public abstract BaseTransform deriveWithConcatenation(double mxx, double myx,
 446                                                           double mxy, double myy,
 447                                                           double mxt, double myt);
 448     public abstract BaseTransform deriveWithConcatenation(
 449             double mxx, double mxy, double mxz, double mxt,
 450             double myx, double myy, double myz, double myt,
 451             double mzx, double mzy, double mzz, double mzt);
 452     public abstract BaseTransform deriveWithPreConcatenation(BaseTransform transform);
 453     public abstract BaseTransform deriveWithConcatenation(BaseTransform tx);
 454     public abstract BaseTransform deriveWithNewTransform(BaseTransform tx);
 455 
 456     /**
 457      * This function always returns a new object, unless the transform
 458      * is an identity transform in which case it might return the
 459      * {@code Identity} singleton.
 460      * @return a new transform representing the inverse of this transform.
 461      */
 462     public abstract BaseTransform createInverse()
 463         throws NoninvertibleTransformException;
 464 
 465     public abstract BaseTransform copy();
 466 
 467     /**
 468      * Returns the hashcode for this transform.
 469      * @return      a hash code for this transform.
 470      */
 471     @Override
 472     public int hashCode() {
 473         if (isIdentity()) return 0;
 474         long bits = 0;
 475         bits = bits * 31 + Double.doubleToLongBits(getMzz());
 476         bits = bits * 31 + Double.doubleToLongBits(getMzy());
 477         bits = bits * 31 + Double.doubleToLongBits(getMzx());
 478         bits = bits * 31 + Double.doubleToLongBits(getMyz());
 479         bits = bits * 31 + Double.doubleToLongBits(getMxz());
 480         bits = bits * 31 + Double.doubleToLongBits(getMyy());
 481         bits = bits * 31 + Double.doubleToLongBits(getMyx());
 482         bits = bits * 31 + Double.doubleToLongBits(getMxy());
 483         bits = bits * 31 + Double.doubleToLongBits(getMxx());
 484         bits = bits * 31 + Double.doubleToLongBits(getMzt());
 485         bits = bits * 31 + Double.doubleToLongBits(getMyt());
 486         bits = bits * 31 + Double.doubleToLongBits(getMxt());
 487         return (((int) bits) ^ ((int) (bits >> 32)));
 488     }
 489 
 490     /**
 491      * Returns <code>true</code> if this <code>BaseTransform</code>
 492      * represents the same coordinate transform as the specified
 493      * argument.
 494      * @param obj the <code>Object</code> to test for equality with this
 495      * <code>BaseTransform</code>
 496      * @return <code>true</code> if <code>obj</code> equals this
 497      * <code>BaseTransform</code> object; <code>false</code> otherwise.
 498      */
 499     @Override
 500     public boolean equals(Object obj) {
 501         if (!(obj instanceof BaseTransform)) {
 502             return false;
 503         }
 504 
 505         BaseTransform a = (BaseTransform) obj;
 506 
 507         return (getMxx() == a.getMxx() &&
 508                 getMxy() == a.getMxy() &&
 509                 getMxz() == a.getMxz() &&
 510                 getMxt() == a.getMxt() &&
 511                 getMyx() == a.getMyx() &&
 512                 getMyy() == a.getMyy() &&
 513                 getMyz() == a.getMyz() &&
 514                 getMyt() == a.getMyt() &&
 515                 getMzx() == a.getMzx() &&
 516                 getMzy() == a.getMzy() &&
 517                 getMzz() == a.getMzz() &&
 518                 getMzt() == a.getMzt());
 519     }
 520 
 521     static Point2D makePoint(Point2D src, Point2D dst) {
 522         if (dst == null) {
 523             dst = new Point2D();
 524         }
 525         return dst;
 526     }
 527 
 528     static final double EPSILON_ABSOLUTE = 1.0e-5;
 529 
 530     public static boolean almostZero(double a) {
 531         return ((a < EPSILON_ABSOLUTE) && (a > -EPSILON_ABSOLUTE));
 532     }
 533 
 534     /**
 535      * Returns the matrix elements and degree of this transform as a string.
 536      * @return  the matrix elements and degree of this transform
 537      */
 538     @Override
 539     public String toString() {
 540         return "Matrix: degree " + getDegree() + "\n" +
 541                 getMxx() + ", " + getMxy() + ", " + getMxz() + ", " + getMxt() + "\n" +
 542                 getMyx() + ", " + getMyy() + ", " + getMyz() + ", " + getMyt() + "\n" +
 543                 getMzx() + ", " + getMzy() + ", " + getMzz() + ", " + getMzt() + "\n";
 544     }
 545 }