/**
   * Calculates the inverse of this transform.
   *
   * @return the inverted transform
   */
  public CCTransform invert() {
    CCTransform result = new CCTransform();

    if (_myIsIdentity) {
      result.setIdentity();
      return result;
    }

    result._myMatrix.set(_myMatrix);
    if (_myIsRotationMatrix) {
      if (_myIsUniformScale) {
        final double sx = _myScale.x;
        result._myMatrix.transposeLocal();
        if (sx != 1.0) {
          result._myMatrix.multiplyLocal(1.0f / sx);
        }
      } else {
        result._myMatrix.set(result._myMatrix.multiplyDiagonalPost(_myScale).invertLocal());
      }
    } else {
      result._myMatrix.invertLocal();
    }

    result._myTranslation.set(result._myMatrix.applyPost(_myTranslation).negateLocal());
    result.updateFlags(_myIsRotationMatrix);

    return result;
  }
 /**
  * @param o the object to compare for equality
  * @return true if this transform and the provided transform have the exact same double values.
  */
 public boolean strictEquals(final Object o) {
   if (this == o) {
     return true;
   }
   if (!(o instanceof CCTransform)) {
     return false;
   }
   final CCTransform comp = (CCTransform) o;
   return _myMatrix.strictEquals(comp.getMatrix())
       && _myScale.equals(comp.scale())
       && _myTranslation.equals(comp.translation());
 }
  /**
   * Check a transform... if it is null or one of its members are invalid, return false. Else return
   * true.
   *
   * @param transform the transform to check
   * @return true or false as stated above.
   */
  public static boolean isValid(final CCTransform transform) {
    if (transform == null) {
      return false;
    }
    if (!CCVector3.isValid(transform.scale())
        || !CCVector3.isValid(transform.translation())
        || !CCMatrix3x3.isValid(transform.getMatrix())) {
      return false;
    }

    return true;
  }
  /**
   * Constructs a new Transform object from the information stored in the given source Transform.
   *
   * @param theSource
   * @throws NullPointerException if source is null.
   */
  public CCTransform(final CCTransform theSource) {
    _myMatrix.set(theSource.getMatrix());
    _myScale.set(theSource.scale());
    _myTranslation.set(theSource.translation());

    _myIsIdentity = theSource.isIdentity();
    _myIsRotationMatrix = theSource.isRotationMatrix();
    _myIsUniformScale = theSource.isUniformScale();
  }
  /**
   * Copies the given transform values into this transform object.
   *
   * @param source
   * @return this transform for chaining.
   * @throws NullPointerException if source is null.
   */
  public CCTransform set(final CCTransform source) {
    if (source.isIdentity()) {
      setIdentity();
    } else {
      _myMatrix.set(source.getMatrix());
      _myScale.set(source.scale());
      _myTranslation.set(source.translation());

      _myIsIdentity = false;
      _myIsRotationMatrix = source.isRotationMatrix();
      _myIsUniformScale = source.isUniformScale();
    }
    return this;
  }
 /**
  * @param o the object to compare for equality
  * @return true if this transform and the provided transform have the same values.
  */
 @Override
 public boolean equals(final Object o) {
   if (this == o) {
     return true;
   }
   if (!(o instanceof CCTransform)) {
     return false;
   }
   final CCTransform comp = (CCTransform) o;
   return _myMatrix.equals(comp.getMatrix())
       && Math.abs(_myTranslation.x - comp.translation().x) < CCTransform.ALLOWED_DEVIANCE
       && Math.abs(_myTranslation.y - comp.translation().y) < CCTransform.ALLOWED_DEVIANCE
       && Math.abs(_myTranslation.z - comp.translation().z) < CCTransform.ALLOWED_DEVIANCE
       && Math.abs(_myScale.x - comp.scale().x) < CCTransform.ALLOWED_DEVIANCE
       && Math.abs(_myScale.y - comp.scale().y) < CCTransform.ALLOWED_DEVIANCE
       && Math.abs(_myScale.z - comp.scale().z) < CCTransform.ALLOWED_DEVIANCE;
 }
  /**
   * Calculates the product of this transform with the given "transformBy" transform (P = this * T)
   * and stores this in store.
   *
   * @param transformBy
   * @return the product
   * @throws NullPointerException if transformBy is null.
   */
  public CCTransform multiply(final CCTransform transformBy, CCTransform theStore) {
    if (theStore == null) theStore = new CCTransform();

    if (_myIsIdentity) {
      return theStore.set(transformBy);
    }

    if (transformBy.isIdentity()) {
      return theStore.set(this);
    }

    if (_myIsRotationMatrix && transformBy.isRotationMatrix() && _myIsUniformScale) {
      theStore._myIsRotationMatrix = true;
      theStore._myMatrix.set(_myMatrix).multiplyLocal(transformBy.getMatrix());

      theStore._myTranslation.set(transformBy.translation());
      theStore._myTranslation.set(_myMatrix.applyPost(theStore._myTranslation));
      // uniform scale, so just use X.
      theStore._myTranslation.multiplyLocal(_myScale.x);
      theStore._myTranslation.addLocal(_myTranslation);

      if (transformBy.isUniformScale()) {
        theStore.scale(_myScale.x * transformBy.scale().x);
      } else {
        final CCVector3 scale = theStore._myScale.set(transformBy.scale());
        scale.multiplyLocal(_myScale.x);
      }

      // update our flags in one place.
      theStore.updateFlags(true);

      return theStore;
    }

    // In all remaining cases, the matrix cannot be written as R*S*X+T.
    final CCMatrix3x3 matrixA =
        isRotationMatrix() ? _myMatrix.multiplyDiagonalPost(_myScale) : _myMatrix;

    final CCMatrix3x3 matrixB =
        transformBy.isRotationMatrix()
            ? transformBy.getMatrix().multiplyDiagonalPost(transformBy.scale())
            : transformBy.getMatrix();

    final CCMatrix3x3 newMatrix = theStore._myMatrix;
    newMatrix.set(matrixA).multiplyLocal(matrixB);

    theStore._myTranslation.set(
        matrixA.applyPost(transformBy.translation()).addLocal(translation()));

    // prevent scale bleeding since we don't set it.
    theStore._myScale.set(1.0f, 1.0f, 1.0f);

    // update our flags in one place.
    theStore.updateFlags(false);

    return theStore;
  }