< prev index next >
modules/graphics/src/main/java/javafx/scene/transform/Transform.java
Print this page
@@ -33,14 +33,13 @@
import javafx.scene.Node;
import com.sun.javafx.util.WeakReferenceQueue;
import com.sun.javafx.binding.ExpressionHelper;
import com.sun.javafx.event.EventHandlerManager;
-import com.sun.javafx.geom.transform.Affine2D;
import com.sun.javafx.geom.transform.Affine3D;
-import com.sun.javafx.geom.transform.AffineBase;
import com.sun.javafx.geom.transform.BaseTransform;
+import com.sun.javafx.scene.transform.TransformHelper;
import com.sun.javafx.scene.transform.TransformUtils;
import java.lang.ref.SoftReference;
import javafx.beans.InvalidationListener;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyBooleanProperty;
@@ -48,11 +47,10 @@
import javafx.beans.value.ChangeListener;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.event.EventTarget;
import javafx.event.EventType;
-import javafx.geometry.BoundingBox;
import javafx.geometry.Bounds;
import javafx.geometry.Point2D;
import javafx.geometry.Point3D;
// PENDING_DOC_REVIEW of this whole class
@@ -70,10 +68,66 @@
* </code></pre>
* @since JavaFX 2.0
*/
public abstract class Transform implements Cloneable, EventTarget {
+ static {
+ // This is used by classes in different packages to get access to
+ // private and package private methods.
+ TransformHelper.setTransformAccessor(new TransformHelper.TransformAccessor() {
+
+ @Override
+ public void add(Transform transform, Node node) {
+ transform.add(node);
+ }
+
+ @Override
+ public void remove(Transform transform, Node node) {
+ transform.remove(node);
+ }
+
+ @Override
+ public void apply(Transform transform, Affine3D affine3D) {
+ transform.apply(affine3D);
+ }
+
+ @Override
+ public BaseTransform derive(Transform transform, BaseTransform baseTransform) {
+ return transform.derive(baseTransform);
+ }
+
+ @Override
+ public Transform createImmutableTransform() {
+ return Transform.createImmutableTransform();
+ }
+
+ @Override
+ public Transform createImmutableTransform(
+ double mxx, double mxy, double mxz, double tx,
+ double myx, double myy, double myz, double ty,
+ double mzx, double mzy, double mzz, double tz) {
+ return Transform.createImmutableTransform(mxx, mxy, mxz, tx,
+ myx, myy, myz, ty, mzx, mzy, mzz, tz);
+ }
+
+ @Override
+ public Transform createImmutableTransform(Transform transform,
+ double mxx, double mxy, double mxz, double tx,
+ double myx, double myy, double myz, double ty,
+ double mzx, double mzy, double mzz, double tz) {
+ return Transform.createImmutableTransform(transform,
+ mxx, mxy, mxz, tx, myx, myy, myz, ty, mzx, mzy, mzz, tz);
+ }
+
+ @Override
+ public Transform createImmutableTransform(Transform transform,
+ Transform left, Transform right) {
+ return Transform.createImmutableTransform(transform, left, right);
+ }
+ });
+ }
+
/* *************************************************************************
* *
* Factories *
* *
**************************************************************************/
@@ -1989,39 +2043,19 @@
getMxx(); getMxy(); getMxz(); getTx();
getMyx(); getMyy(); getMyz(); getTy();
getMzx(); getMzy(); getMzz(); getTz();
}
- /**
- * @treatAsPrivate implementation detail
- * @deprecated This is an internal API that is not intended for use and will be removed in the next version
- */
- @Deprecated
- public abstract void impl_apply(Affine3D t);
+ abstract void apply(Affine3D t);
- /**
- * @treatAsPrivate implementation detail
- * @deprecated This is an internal API that is not intended for use and will be removed in the next version
- */
- @Deprecated
- public abstract BaseTransform impl_derive(BaseTransform t);
+ abstract BaseTransform derive(BaseTransform t);
- /**
- * @treatAsPrivate implementation detail
- * @deprecated This is an internal API that is not intended for use and will be removed in the next version
- */
- @Deprecated
- public void impl_add(final Node node) {
+ private void add(final Node node) {
nodes.add(node);
}
- /**
- * @treatAsPrivate implementation detail
- * @deprecated This is an internal API that is not intended for use and will be removed in the next version
- */
- @Deprecated
- public void impl_remove(final Node node) {
+ private void remove(final Node node) {
nodes.remove(node);
}
/**
* This method must be called by all transforms whenever any of their
@@ -2109,6 +2143,780 @@
void clearInverseCache() {
if (inverseCache != null) {
inverseCache.clear();
}
}
+
+ /**************************************************************************
+ * ImmutableTransform Class and supporting methods
+ **************************************************************************/
+
+ static Transform createImmutableTransform() {
+ return new ImmutableTransform();
+ }
+
+ static Transform createImmutableTransform(
+ double mxx, double mxy, double mxz, double tx,
+ double myx, double myy, double myz, double ty,
+ double mzx, double mzy, double mzz, double tz) {
+ return new ImmutableTransform(
+ mxx, mxy, mxz, tx,
+ myx, myy, myz, ty,
+ mzx, mzy, mzz, tz);
+ }
+
+ static Transform createImmutableTransform(Transform transform,
+ double mxx, double mxy, double mxz, double tx,
+ double myx, double myy, double myz, double ty,
+ double mzx, double mzy, double mzz, double tz) {
+ if (transform == null) {
+ return createImmutableTransform(
+ mxx, mxy, mxz, tx,
+ myx, myy, myz, ty,
+ mzx, mzy, mzz, tz);
+ }
+ ((Transform.ImmutableTransform) transform).setToTransform(
+ mxx, mxy, mxz, tx,
+ myx, myy, myz, ty,
+ mzx, mzy, mzz, tz);
+ return transform;
+ }
+
+ static Transform createImmutableTransform(Transform transform,
+ Transform left, Transform right) {
+ if (transform == null) {
+ transform = createImmutableTransform();
+ }
+ ((Transform.ImmutableTransform) transform).setToConcatenation(
+ (ImmutableTransform) left, (ImmutableTransform) right);
+ return transform;
+ }
+
+ /**
+ * Immutable transformation with performance optimizations based on Affine.
+ *
+ * From user's perspective, this transform is immutable. However, we can
+ * modify it internally. This allows for reusing instances that were
+ * not handed to users. The caller is responsible for not modifying
+ * user-visible instances.
+ *
+ * Note: can't override Transform's package private methods so they cannot
+ * be optimized. Currently not a big deal.
+ */
+ static class ImmutableTransform extends Transform {
+
+ private static final int APPLY_IDENTITY = 0;
+ private static final int APPLY_TRANSLATE = 1;
+ private static final int APPLY_SCALE = 2;
+ private static final int APPLY_SHEAR = 4;
+ private static final int APPLY_NON_3D = 0;
+ private static final int APPLY_3D_COMPLEX = 4;
+ private transient int state2d;
+ private transient int state3d;
+
+ private double xx;
+ private double xy;
+ private double xz;
+ private double yx;
+ private double yy;
+ private double yz;
+ private double zx;
+ private double zy;
+ private double zz;
+ private double xt;
+ private double yt;
+ private double zt;
+
+ ImmutableTransform() {
+ xx = yy = zz = 1.0;
+ }
+
+ ImmutableTransform(Transform transform) {
+ this(transform.getMxx(), transform.getMxy(), transform.getMxz(),
+ transform.getTx(),
+ transform.getMyx(), transform.getMyy(), transform.getMyz(),
+ transform.getTy(),
+ transform.getMzx(), transform.getMzy(), transform.getMzz(),
+ transform.getTz());
+ }
+
+ ImmutableTransform(double mxx, double mxy, double mxz, double tx,
+ double myx, double myy, double myz, double ty,
+ double mzx, double mzy, double mzz, double tz) {
+ xx = mxx;
+ xy = mxy;
+ xz = mxz;
+ xt = tx;
+
+ yx = myx;
+ yy = myy;
+ yz = myz;
+ yt = ty;
+
+ zx = mzx;
+ zy = mzy;
+ zz = mzz;
+ zt = tz;
+
+ updateState();
+ }
+
+ // Beware: this is modifying immutable transform!
+ // It is private and it is there just for the purpose of reusing
+ // instances not given to users
+ private void setToTransform(double mxx, double mxy, double mxz, double tx,
+ double myx, double myy, double myz, double ty,
+ double mzx, double mzy, double mzz, double tz)
+ {
+ xx = mxx;
+ xy = mxy;
+ xz = mxz;
+ xt = tx;
+ yx = myx;
+ yy = myy;
+ yz = myz;
+ yt = ty;
+ zx = mzx;
+ zy = mzy;
+ zz = mzz;
+ zt = tz;
+ updateState();
+ }
+
+ // Beware: this is modifying immutable transform!
+ // It is private and it is there just for the purpose of reusing
+ // instances not given to users
+ private void setToConcatenation(ImmutableTransform left, ImmutableTransform right) {
+ if (left.state3d == APPLY_NON_3D && right.state3d == APPLY_NON_3D) {
+ xx = left.xx * right.xx + left.xy * right.yx;
+ xy = left.xx * right.xy + left.xy * right.yy;
+ xt = left.xx * right.xt + left.xy * right.yt + left.xt;
+ yx = left.yx * right.xx + left.yy * right.yx;
+ yy = left.yx * right.xy + left.yy * right.yy;
+ yt = left.yx * right.xt + left.yy * right.yt + left.yt;
+ if (state3d != APPLY_NON_3D) {
+ xz = yz = zx = zy = zt = 0.0;
+ zz = 1.0;
+ state3d = APPLY_NON_3D;
+ }
+ updateState2D();
+ } else {
+ xx = left.xx * right.xx + left.xy * right.yx + left.xz * right.zx;
+ xy = left.xx * right.xy + left.xy * right.yy + left.xz * right.zy;
+ xz = left.xx * right.xz + left.xy * right.yz + left.xz * right.zz;
+ xt = left.xx * right.xt + left.xy * right.yt + left.xz * right.zt + left.xt;
+ yx = left.yx * right.xx + left.yy * right.yx + left.yz * right.zx;
+ yy = left.yx * right.xy + left.yy * right.yy + left.yz * right.zy;
+ yz = left.yx * right.xz + left.yy * right.yz + left.yz * right.zz;
+ yt = left.yx * right.xt + left.yy * right.yt + left.yz * right.zt + left.yt;
+ zx = left.zx * right.xx + left.zy * right.yx + left.zz * right.zx;
+ zy = left.zx * right.xy + left.zy * right.yy + left.zz * right.zy;
+ zz = left.zx * right.xz + left.zy * right.yz + left.zz * right.zz;
+ zt = left.zx * right.xt + left.zy * right.yt + left.zz * right.zt + left.zt;
+ updateState();
+ }
+ // could be further optimized using the states, but that would
+ // require a lot of code (see Affine and all its append* methods)
+ }
+
+ @Override
+ public double getMxx() {
+ return xx;
+ }
+
+ @Override
+ public double getMxy() {
+ return xy;
+ }
+
+ @Override
+ public double getMxz() {
+ return xz;
+ }
+
+ @Override
+ public double getTx() {
+ return xt;
+ }
+
+ @Override
+ public double getMyx() {
+ return yx;
+ }
+
+ @Override
+ public double getMyy() {
+ return yy;
+ }
+
+ @Override
+ public double getMyz() {
+ return yz;
+ }
+
+ @Override
+ public double getTy() {
+ return yt;
+ }
+
+ @Override
+ public double getMzx() {
+ return zx;
+ }
+
+ @Override
+ public double getMzy() {
+ return zy;
+ }
+
+ @Override
+ public double getMzz() {
+ return zz;
+ }
+
+ @Override
+ public double getTz() {
+ return zt;
+ }
+
+ /* *************************************************************************
+ * *
+ * State getters *
+ * *
+ **************************************************************************/
+
+ @Override
+ public double determinant() {
+ switch(state3d) {
+ default:
+ stateError();
+ // cannot reach
+ case APPLY_NON_3D:
+ switch (state2d) {
+ default:
+ stateError();
+ // cannot reach
+ case APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE:
+ case APPLY_SHEAR | APPLY_SCALE:
+ return xx * yy - xy * yx;
+ case APPLY_SHEAR | APPLY_TRANSLATE:
+ case APPLY_SHEAR:
+ return -(xy* yx);
+ case APPLY_SCALE | APPLY_TRANSLATE:
+ case APPLY_SCALE:
+ return xx * yy;
+ case APPLY_TRANSLATE:
+ case APPLY_IDENTITY:
+ return 1.0;
+ }
+ case APPLY_TRANSLATE:
+ return 1.0;
+ case APPLY_SCALE:
+ case APPLY_SCALE | APPLY_TRANSLATE:
+ return xx * yy * zz;
+ case APPLY_3D_COMPLEX:
+ return (xx* (yy * zz - zy * yz) +
+ xy* (yz * zx - zz * yx) +
+ xz* (yx * zy - zx * yy));
+ }
+ }
+
+ @Override
+ public Transform createConcatenation(Transform transform) {
+ javafx.scene.transform.Affine a = new Affine(this);
+ a.append(transform);
+ return a;
+ }
+
+ @Override
+ public javafx.scene.transform.Affine createInverse() throws NonInvertibleTransformException {
+ javafx.scene.transform.Affine t = new Affine(this);
+ t.invert();
+ return t;
+ }
+
+ @Override
+ public Transform clone() {
+ return new ImmutableTransform(this);
+ }
+
+ /* *************************************************************************
+ * *
+ * Transform, Inverse Transform *
+ * *
+ **************************************************************************/
+
+ @Override
+ public Point2D transform(double x, double y) {
+ ensureCanTransform2DPoint();
+
+ switch (state2d) {
+ default:
+ stateError();
+ // cannot reach
+ case APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE:
+ return new Point2D(
+ xx * x + xy * y + xt,
+ yx * x + yy * y + yt);
+ case APPLY_SHEAR | APPLY_SCALE:
+ return new Point2D(
+ xx * x + xy * y,
+ yx * x + yy * y);
+ case APPLY_SHEAR | APPLY_TRANSLATE:
+ return new Point2D(
+ xy * y + xt,
+ yx * x + yt);
+ case APPLY_SHEAR:
+ return new Point2D(xy * y, yx * x);
+ case APPLY_SCALE | APPLY_TRANSLATE:
+ return new Point2D(
+ xx * x + xt,
+ yy * y + yt);
+ case APPLY_SCALE:
+ return new Point2D(xx * x, yy * y);
+ case APPLY_TRANSLATE:
+ return new Point2D(x + xt, y + yt);
+ case APPLY_IDENTITY:
+ return new Point2D(x, y);
+ }
+ }
+
+ @Override
+ public Point3D transform(double x, double y, double z) {
+ switch (state3d) {
+ default:
+ stateError();
+ // cannot reach
+ case APPLY_NON_3D:
+ switch (state2d) {
+ default:
+ stateError();
+ // cannot reach
+ case APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE:
+ return new Point3D(
+ xx * x + xy * y + xt,
+ yx * x + yy * y + yt, z);
+ case APPLY_SHEAR | APPLY_SCALE:
+ return new Point3D(
+ xx * x + xy * y,
+ yx * x + yy * y, z);
+ case APPLY_SHEAR | APPLY_TRANSLATE:
+ return new Point3D(
+ xy * y + xt, yx * x + yt,
+ z);
+ case APPLY_SHEAR:
+ return new Point3D(xy * y, yx * x, z);
+ case APPLY_SCALE | APPLY_TRANSLATE:
+ return new Point3D(
+ xx * x + xt, yy * y + yt,
+ z);
+ case APPLY_SCALE:
+ return new Point3D(xx * x, yy * y, z);
+ case APPLY_TRANSLATE:
+ return new Point3D(x + xt, y + yt, z);
+ case APPLY_IDENTITY:
+ return new Point3D(x, y, z);
+ }
+ case APPLY_TRANSLATE:
+ return new Point3D(x + xt, y + yt, z + zt);
+ case APPLY_SCALE:
+ return new Point3D(xx * x, yy * y, zz * z);
+ case APPLY_SCALE | APPLY_TRANSLATE:
+ return new Point3D(
+ xx * x + xt,
+ yy * y + yt,
+ zz * z + zt);
+ case APPLY_3D_COMPLEX:
+ return new Point3D(
+ xx * x + xy * y + xz * z + xt,
+ yx * x + yy * y + yz * z + yt,
+ zx * x + zy * y + zz * z + zt);
+ }
+ }
+
+ @Override
+ public Point2D deltaTransform(double x, double y) {
+ ensureCanTransform2DPoint();
+
+ switch (state2d) {
+ default:
+ stateError();
+ // cannot reach
+ case APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE:
+ case APPLY_SHEAR | APPLY_SCALE:
+ return new Point2D(
+ xx * x + xy * y,
+ yx * x + yy * y);
+ case APPLY_SHEAR | APPLY_TRANSLATE:
+ case APPLY_SHEAR:
+ return new Point2D(xy * y, yx * x);
+ case APPLY_SCALE | APPLY_TRANSLATE:
+ case APPLY_SCALE:
+ return new Point2D(xx * x, yy * y);
+ case APPLY_TRANSLATE:
+ case APPLY_IDENTITY:
+ return new Point2D(x, y);
+ }
+ }
+
+ @Override
+ public Point3D deltaTransform(double x, double y, double z) {
+ switch (state3d) {
+ default:
+ stateError();
+ // cannot reach
+ case APPLY_NON_3D:
+ switch (state2d) {
+ default:
+ stateError();
+ // cannot reach
+ case APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE:
+ case APPLY_SHEAR | APPLY_SCALE:
+ return new Point3D(
+ xx * x + xy * y,
+ yx * x + yy * y, z);
+ case APPLY_SHEAR | APPLY_TRANSLATE:
+ case APPLY_SHEAR:
+ return new Point3D(xy * y, yx * x, z);
+ case APPLY_SCALE | APPLY_TRANSLATE:
+ case APPLY_SCALE:
+ return new Point3D(xx * x, yy * y, z);
+ case APPLY_TRANSLATE:
+ case APPLY_IDENTITY:
+ return new Point3D(x, y, z);
+ }
+ case APPLY_TRANSLATE:
+ return new Point3D(x, y, z);
+ case APPLY_SCALE:
+ case APPLY_SCALE | APPLY_TRANSLATE:
+ return new Point3D(xx * x, yy * y, zz * z);
+ case APPLY_3D_COMPLEX:
+ return new Point3D(
+ xx * x + xy * y + xz * z,
+ yx * x + yy * y + yz * z,
+ zx * x + zy * y + zz * z);
+ }
+ }
+
+ @Override
+ public Point2D inverseTransform(double x, double y)
+ throws NonInvertibleTransformException {
+ ensureCanTransform2DPoint();
+
+ switch (state2d) {
+ default:
+ return super.inverseTransform(x, y);
+ case APPLY_SHEAR | APPLY_TRANSLATE:
+ if (xy == 0.0 || yx == 0.0) {
+ throw new NonInvertibleTransformException("Determinant is 0");
+ }
+ return new Point2D(
+ (1.0 / yx) * y - yt / yx,
+ (1.0 / xy) * x - xt / xy);
+ case APPLY_SHEAR:
+ if (xy == 0.0 || yx == 0.0) {
+ throw new NonInvertibleTransformException("Determinant is 0");
+ }
+ return new Point2D((1.0 / yx) * y, (1.0 / xy) * x);
+ case APPLY_SCALE | APPLY_TRANSLATE:
+ if (xx == 0.0 || yy == 0.0) {
+ throw new NonInvertibleTransformException("Determinant is 0");
+ }
+ return new Point2D(
+ (1.0 / xx) * x - xt / xx,
+ (1.0 / yy) * y - yt / yy);
+ case APPLY_SCALE:
+ if (xx == 0.0 || yy == 0.0) {
+ throw new NonInvertibleTransformException("Determinant is 0");
+ }
+ return new Point2D((1.0 / xx) * x, (1.0 / yy) * y);
+ case APPLY_TRANSLATE:
+ return new Point2D(x - xt, y - yt);
+ case APPLY_IDENTITY:
+ return new Point2D(x, y);
+ }
+ }
+
+ @Override
+ public Point3D inverseTransform(double x, double y, double z)
+ throws NonInvertibleTransformException {
+ switch(state3d) {
+ default:
+ stateError();
+ // cannot reach
+ case APPLY_NON_3D:
+ switch (state2d) {
+ default:
+ return super.inverseTransform(x, y, z);
+ case APPLY_SHEAR | APPLY_TRANSLATE:
+ if (xy == 0.0 || yx == 0.0) {
+ throw new NonInvertibleTransformException(
+ "Determinant is 0");
+ }
+ return new Point3D(
+ (1.0 / yx) * y - yt / yx,
+ (1.0 / xy) * x - xt / xy, z);
+ case APPLY_SHEAR:
+ if (xy == 0.0 || yx == 0.0) {
+ throw new NonInvertibleTransformException(
+ "Determinant is 0");
+ }
+ return new Point3D(
+ (1.0 / yx) * y,
+ (1.0 / xy) * x, z);
+ case APPLY_SCALE | APPLY_TRANSLATE:
+ if (xx == 0.0 || yy == 0.0) {
+ throw new NonInvertibleTransformException(
+ "Determinant is 0");
+ }
+ return new Point3D(
+ (1.0 / xx) * x - xt / xx,
+ (1.0 / yy) * y - yt / yy, z);
+ case APPLY_SCALE:
+ if (xx == 0.0 || yy == 0.0) {
+ throw new NonInvertibleTransformException(
+ "Determinant is 0");
+ }
+ return new Point3D((1.0 / xx) * x, (1.0 / yy) * y, z);
+ case APPLY_TRANSLATE:
+ return new Point3D(x - xt, y - yt, z);
+ case APPLY_IDENTITY:
+ return new Point3D(x, y, z);
+ }
+ case APPLY_TRANSLATE:
+ return new Point3D(x - xt, y - yt, z - zt);
+ case APPLY_SCALE:
+ if (xx == 0.0 || yy == 0.0 || zz == 0.0) {
+ throw new NonInvertibleTransformException("Determinant is 0");
+ }
+ return new Point3D(
+ (1.0 / xx) * x,
+ (1.0 / yy) * y,
+ (1.0 / zz) * z);
+ case APPLY_SCALE | APPLY_TRANSLATE:
+ if (xx == 0.0 || yy == 0.0 || zz == 0.0) {
+ throw new NonInvertibleTransformException("Determinant is 0");
+ }
+ return new Point3D(
+ (1.0 / xx) * x - xt / xx,
+ (1.0 / yy) * y - yt / yy,
+ (1.0 / zz) * z - zt / zz);
+ case APPLY_3D_COMPLEX:
+ return super.inverseTransform(x, y, z);
+ }
+ }
+
+ @Override
+ public Point2D inverseDeltaTransform(double x, double y)
+ throws NonInvertibleTransformException {
+ ensureCanTransform2DPoint();
+
+ switch (state2d) {
+ default:
+ return super.inverseDeltaTransform(x, y);
+ case APPLY_SHEAR | APPLY_TRANSLATE:
+ case APPLY_SHEAR:
+ if (xy == 0.0 || yx == 0.0) {
+ throw new NonInvertibleTransformException("Determinant is 0");
+ }
+ return new Point2D((1.0 / yx) * y, (1.0 / xy) * x);
+ case APPLY_SCALE | APPLY_TRANSLATE:
+ case APPLY_SCALE:
+ if (xx == 0.0 || yy == 0.0) {
+ throw new NonInvertibleTransformException("Determinant is 0");
+ }
+ return new Point2D((1.0 / xx) * x, (1.0 / yy) * y);
+ case APPLY_TRANSLATE:
+ case APPLY_IDENTITY:
+ return new Point2D(x, y);
+ }
+ }
+
+ @Override
+ public Point3D inverseDeltaTransform(double x, double y, double z)
+ throws NonInvertibleTransformException {
+ switch(state3d) {
+ default:
+ stateError();
+ // cannot reach
+ case APPLY_NON_3D:
+ switch (state2d) {
+ default:
+ return super.inverseDeltaTransform(x, y, z);
+ case APPLY_SHEAR | APPLY_TRANSLATE:
+ case APPLY_SHEAR:
+ if (xy == 0.0 || yx == 0.0) {
+ throw new NonInvertibleTransformException(
+ "Determinant is 0");
+ }
+ return new Point3D(
+ (1.0 / yx) * y,
+ (1.0 / xy) * x, z);
+ case APPLY_SCALE | APPLY_TRANSLATE:
+ case APPLY_SCALE:
+ if (xx == 0.0 || yy == 0.0) {
+ throw new NonInvertibleTransformException(
+ "Determinant is 0");
+ }
+ return new Point3D(
+ (1.0 / xx) * x,
+ (1.0 / yy) * y, z);
+ case APPLY_TRANSLATE:
+ case APPLY_IDENTITY:
+ return new Point3D(x, y, z);
+ }
+
+ case APPLY_TRANSLATE:
+ return new Point3D(x, y, z);
+ case APPLY_SCALE | APPLY_TRANSLATE:
+ case APPLY_SCALE:
+ if (xx == 0.0 || yy == 0.0 || zz == 0.0) {
+ throw new NonInvertibleTransformException("Determinant is 0");
+ }
+ return new Point3D(
+ (1.0 / xx) * x,
+ (1.0 / yy) * y,
+ (1.0 / zz) * z);
+ case APPLY_3D_COMPLEX:
+ return super.inverseDeltaTransform(x, y, z);
+ }
+ }
+
+ /* *************************************************************************
+ * *
+ * Other API *
+ * *
+ **************************************************************************/
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("Transform [\n");
+
+ sb.append("\t").append(xx);
+ sb.append(", ").append(xy);
+ sb.append(", ").append(xz);
+ sb.append(", ").append(xt);
+ sb.append('\n');
+ sb.append("\t").append(yx);
+ sb.append(", ").append(yy);
+ sb.append(", ").append(yz);
+ sb.append(", ").append(yt);
+ sb.append('\n');
+ sb.append("\t").append(zx);
+ sb.append(", ").append(zy);
+ sb.append(", ").append(zz);
+ sb.append(", ").append(zt);
+
+ return sb.append("\n]").toString();
+ }
+
+ /* *************************************************************************
+ * *
+ * Internal implementation stuff *
+ * *
+ **************************************************************************/
+
+ private void updateState() {
+ updateState2D();
+
+ state3d = APPLY_NON_3D;
+
+ if (xz != 0.0 ||
+ yz != 0.0 ||
+ zx != 0.0 ||
+ zy != 0.0)
+ {
+ state3d = APPLY_3D_COMPLEX;
+ } else {
+ if ((state2d & APPLY_SHEAR) == 0) {
+ if (zt != 0.0) {
+ state3d |= APPLY_TRANSLATE;
+ }
+ if (zz != 1.0) {
+ state3d |= APPLY_SCALE;
+ }
+ if (state3d != APPLY_NON_3D) {
+ state3d |= (state2d & (APPLY_SCALE | APPLY_TRANSLATE));
+ }
+ } else {
+ if (zz != 1.0 || zt != 0.0) {
+ state3d = APPLY_3D_COMPLEX;
+ }
+ }
+ }
+ }
+
+ private void updateState2D() {
+ if (xy == 0.0 && yx == 0.0) {
+ if (xx == 1.0 && yy == 1.0) {
+ if (xt == 0.0 && yt == 0.0) {
+ state2d = APPLY_IDENTITY;
+ } else {
+ state2d = APPLY_TRANSLATE;
+ }
+ } else {
+ if (xt == 0.0 && yt == 0.0) {
+ state2d = APPLY_SCALE;
+ } else {
+ state2d = (APPLY_SCALE | APPLY_TRANSLATE);
+ }
+ }
+ } else {
+ if (xx == 0.0 && yy == 0.0) {
+ if (xt == 0.0 && yt == 0.0) {
+ state2d = APPLY_SHEAR;
+ } else {
+ state2d = (APPLY_SHEAR | APPLY_TRANSLATE);
+ }
+ } else {
+ if (xt == 0.0 && yt == 0.0) {
+ state2d = (APPLY_SHEAR | APPLY_SCALE);
+ } else {
+ state2d = (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE);
+ }
+ }
+ }
+ }
+
+ void ensureCanTransform2DPoint() throws IllegalStateException {
+ if (state3d != APPLY_NON_3D) {
+ throw new IllegalStateException("Cannot transform 2D point "
+ + "with a 3D transform");
+ }
+ }
+
+ private static void stateError() {
+ throw new InternalError("missing case in a switch");
+ }
+
+
+ @Override
+ void apply(final Affine3D trans) {
+ trans.concatenate(xx, xy, xz, xt,
+ yx, yy, yz, yt,
+ zx, zy, zz, zt);
+ }
+
+ @Override
+ BaseTransform derive(final BaseTransform trans) {
+ return trans.deriveWithConcatenation(xx, xy, xz, xt,
+ yx, yy, yz, yt,
+ zx, zy, zz, zt);
+ }
+
+ /**
+ * Used only by tests to check the 2d matrix state
+ */
+ int getState2d() {
+ return state2d;
+ }
+
+ /**
+ * Used only by tests to check the 3d matrix state
+ */
+ int getState3d() {
+ return state3d;
+ }
+
+ }
+
}
< prev index next >