package com.android.droidgraph.scene; import com.android.droidgraph.geom.BoundingBox; import com.android.droidgraph.geom.Bounds; import com.android.droidgraph.geom.Transform3D; import com.android.droidgraph.vecmath.Point3f; import com.android.droidgraph.vecmath.Vector3f; /** * */ public abstract class SGTransform extends SGFilter { /** * This class provides factory methods to create specific subclasses of the * {@link SGTransform} class for various common affine transformations. * * @see Translate * @see Scale * @see Rotate * @see Shear * @see Affine * */ static abstract class Factory { /** Creates a new instance of TransformFactory */ Factory() { } abstract Translate makeTranslate(float tx, float ty, float tz, SGNode node); abstract Scale makeScale(float sx, float sy, float sz, SGNode node); abstract Rotate makeRotate(float thetax, float thetay, float thetaz, SGNode node); abstract Shear makeShear(float shx, float shy, float shz, SGNode node); abstract Affine makeAffine(Transform3D at, SGNode node); } static Factory theFactory; static { // REMIND: This should be switch selectable theFactory = new DesktopSGTransformFactory(); } /** * Returns an instance of {@link Translate} which translates points by the * specified amounts. * * @param tx * the initial {@code X} translation for the filter * @param ty * the initial {@code Y} translation for the filter * @param tz * the initial {@code Z} translation for the filter * @param child * an optional child for the filter * @return a {@code Translate} object */ public static Translate createTranslation(float tx, float ty, float tz, SGNode child) { Translate t = theFactory.makeTranslate(tx, ty, tz, child); if (child != null) { t.setChild(child); } return t; } /** * Returns an instance of {@link Scale} which scales points by the specified * amounts. * * @param sx * the initial {@code X} scale for the filter * @param sy * the initial {@code Y} scale for the filter * @param sz * the initial {@code Z} scale for the filter * @param child * an optional child for the filter * @return a {@code Scale} object */ public static Scale createScale(float sx, float sy, float sz, SGNode child) { Scale s = theFactory.makeScale(sx, sy, sz, child); if (child != null) { s.setChild(child); } return s; } /** * Returns an instance of {@link Rotate} which rotates points by the * specified angle, measured in radians. * * @param theta * the initial rotation for the filter * @param child * an optional child for the filter * @return a {@code Rotate} object */ public static Rotate createRotation(float thetax, float thetay, float thetaz, SGNode child) { Rotate r = theFactory.makeRotate(thetax, thetay, thetaz, child); if (child != null) { r.setChild(child); } return r; } /** * Returns an instance of {@link Shear} which shears points by the specified * amounts. * * @param shx * the initial {@code X} shear for the filter * @param shy * the initial {@code Y} shear for the filter * @param child * an optional child for the filter * @return a {@code Shear} object */ public static Shear createShear(float shx, float shy, float shz, SGNode child) { Shear s = theFactory.makeShear(shx, shy, shz, child); if (child != null) { s.setChild(child); } return s; } /** * Returns an instance of {@link Affine} which transforms points by the * specified generalized affine transformation. If the * {@link Transform3D} parameter is null then an identity transform is * used initially. * * @param at * an optional initial transform for the filter * @param child * an optional child for the filter * @return an {@code Affine} object */ public static Affine createAffine(Transform3D at, SGNode child) { Affine a = theFactory.makeAffine(at, child); if (child != null) { a.setChild(child); } return a; } /** Creates a new instance of SGTransform */ SGTransform() { } /** * Transforms a single input point specified by a {@link Point2D} object * into an optionally specified output point and returns the object used to * store the results. The {@code dst} argument may be null in which case a * new {@code Point2D} object will be created for the return value, * otherwise the specified object will be used to store the point and * returned from the method. * * @param src * the input point to be transformed * @param dst * an optional output point for storing the result * @return the {@code Point2D} object used to store the result */ public abstract Point3f transform(Point3f src, Point3f dst); /** * Untransforms (transforms by the inverse of this transform) a single input * point specified by a {@link Point2D} object into an optionally specified * output point and returns the object used to store the results. The * {@code dst} argument may be null in which case a new {@code Point2D} * object will be created for the return value, otherwise the specified * object will be used to store the point and returned from the method. * <p> * Note that this method does not throw a * <code>NoninvertibleTransformException</code> as similar methods in the * {@link Transform3D} class do. The subclasses will make a * "best effort" to inverse transform the coordinates of the point depending * on what pieces of the inverse calculations can be performed and may * return the original {@code src} location if necessary. The forgiving * nature of this method should reduce or eliminate unnecessary * {@code catch} clauses without reducing its utility. If desired, the * associated transform can be retrieved and queried for invertibility. * * @param src * the input point to be inverse transformed * @param dst * an optional output point for storing the result * @return the {@code Point2D} object used to store the result */ public abstract Point3f inverseTransform(Point3f src, Point3f dst); /** * Applies the simple transform operation of this {@code Transform} to a * more general {@link Transform3D} object. The transform operation of * this object is appended to the existing transform operations already * represented in the {@code Transform3D} object as if by appending a * new matrix. * * @param at * the {@code Transform3D} object to append this transform to */ public abstract void concatenateInto(Transform3D at); /** * Sets the {@link Transform3D} object to represent the same transform * as the simple transform of this {@code Transform}. The transform * operation of this object replaces the existing transform operations that * may have been representd in the {@code Transform3D} object. * * @param at * the {@code Transform3D} object to store this transform * into */ public abstract void getTransform(Transform3D at); /** * Creates a new Transform3D representing the same transform operation * as this object. * * @return a new {@code Transform3D} object representing this transform. */ public Transform3D createAffine() { Transform3D at = new Transform3D(); getTransform(at); return at; } /** * Resets this transform node to an identity operation which has no effect * on the input points. */ public abstract void reset(); protected void invalidateTransform() { // log.pl("right here", this); } @Override public boolean canSkipRendering() { return true; } /** * Calculates the accumulated product of all transforms back to the root of * the tree. The inherited implementation simply returns a shared value from * the parent, but SGTransform nodes must append their individual transform * to a copy of that inherited object. */ @Override final Transform3D calculateCumulativeTransform() { Transform3D xform = super.calculateCumulativeTransform(); xform = new Transform3D(xform); concatenateInto(xform); return xform; } @Override public Bounds getBounds(Transform3D transform) { SGNode child = getChild(); if (child == null) { // just an empty rectangle return new BoundingBox(); } else { Transform3D childTx = createAffine(); if (childTx != null && childTx.getType() != Transform3D.IDENTITY) { if (transform != null && transform.getType() != Transform3D.IDENTITY) { /////////////// // AffineTransforms' preConcatenate converted for Transform3D childTx.mul(childTx, transform); ////////////// } transform = childTx; } return child.getBounds(transform); } } /** * A subclass of {@link SGTransform} that applies a simple translation * transform. A translation transform simply adds a constant value to the * {@code X} and {@code Y} coordinates of the source coordinates. The * transform {@code x',y'} of a source point {@code x,y} is represented by * the equations: * * <pre> * x' = x + transx; * y' = y + transy; * </pre> * * Instances of this class can only be created by calling the * {@link SGTransform#createTranslation} factory method. * * @author Flar */ public static abstract class Translate extends SGTransform { /** Creates a new instance of Translate */ Translate() { } /** * Returns the translation offset applied to the {@code X} coordinates. * * @return the {@code} X translation */ public abstract float getTranslateX(); /** * Returns the translation offset applied to the {@code Y} coordinates. * * @return the {@code} Y translation */ public abstract float getTranslateY(); /** * Returns the translation offset applied to the {@code Z} coordinates. * * @return the {@code} Z translation */ public abstract float getTranslateZ(); /** * Sets the translation offset applied to the {@code X} coordinates. * * @param tx * the new {@code} X translation */ public abstract void setTranslateX(float tx); /** * Sets the translation offset applied to the {@code Y} coordinates. * * @param ty * the new {@code} Y translation */ public abstract void setTranslateY(float ty); /** * Sets the translation offset applied to the {@code Z} coordinates. * * @param tz * the new {@code} Z translation */ public abstract void setTranslateZ(float tz); /** * Sets the {@code X} and {@code Y} translation offets to the specified * new values. * * @param tx * the new X translation offset * @param ty * the new Y translation offset */ public abstract void setTranslation(float tx, float ty, float tz); /** * Offsets the {@code X} and {@code Y} translation offets by the * specified additional offset values. This method is equivalent to: * * <pre> * tt.setTranslation(tt.getTranslateX() + tx, tt.getTranslateY() + ty); * </pre> * * @param tx * the additional X translation offset * @param ty * the additional Y translation offset */ public abstract void translateBy(float tx, float ty, float tz); @Override public void reset() { setTranslation(0, 0, 0); } } /** * This class implements a basic 2 Dimensional scale transform. All input * points are scaled independently in the {@code X} and {@code Y} directions * by the {@code ScaleX} and {@code ScaleY} values. The transform * {@code x',y'} of a source point {@code x,y} is represented by the * equations: * * <pre> * x' = x * scalex; * y' = y * scaley; * z' = z * scalez; * </pre> * * Instances of this class can only be created by calling the * {@link SGTransform#createScale} factory method. * * @author Flar */ public static abstract class Scale extends SGTransform { /** Creates a new instance of Scale */ Scale() { } /** * Returns the scale factor for the {@code X} coordinates. * * @return the {@code X} scale factor */ public abstract float getScaleX(); /** * Returns the scale factor for the {@code Y} coordinates. * * @return the {@code Y} scale factor */ public abstract float getScaleY(); /** * Returns the scale factor for the {@code Z} coordinates. * * @return the {@code Z} scale factor */ public abstract float getScaleZ(); /** * Sets the scale factor for the {@code X} coordinates. * * @param sx * the new {@code X} scale factor */ public abstract void setScaleX(float sx); /** * Sets the scale factor for the {@code Y} coordinates. * * @param sy * the new {@code Y} scale factor */ public abstract void setScaleY(float sy); /** * Sets the scale factor for the {@code Z} coordinates. * * @param sz * the new {@code Z} scale factor */ public abstract void setScaleZ(float sz); /** * Sets the scale factors for the {@code X} and {@code Y} coordinates. * * @param sx * the new {@code X} scale factor * @param sy * the new {@code Y} scale factor */ public abstract void setScale(float sx, float sy, float sz); /** * Scales (multiplies) the scale factors for the {@code X} and {@code Y} * coordinates by additional scale factors. This method is equivalent * to: * * <pre> * st.setScale(st.getScaleX() * sx, st.getScaleY() * sy, st.getScaleZ() * sz); * </pre> * * @param sx * the new {@code X} scale factor * @param sy * the new {@code Y} scale factor * @param sz * the new {@code Z} scale factor */ public abstract void scaleBy(float sx, float sy, float sz); @Override public void reset() { setScale(1, 1, 1); } } /** */ public static abstract class Rotate extends SGTransform { /** Creates a new instance of Rotate */ Rotate() { } /** * Returns the angle, measured in radians, by which the source points * are rotated around the origin. The direction of rotation for positive * angles will rotate the positive {@code X} axis towards the positive * {@code Y} axis. * * @return the angle, measured in radians */ public abstract Vector3f getRotation(); public abstract float getRotationX(); public abstract float getRotationY(); public abstract float getRotationZ(); /** * Sets the angle, measured in radians, by which the source points are * rotated around the origin. The direction of rotation for positive * angles will rotate the positive {@code X} axis towards the positive * {@code Y} axis. * * @param theta * the angle, measured in radians */ public abstract void setRotation(float thetax, float thetay, float thetaz); /** * Adjusts the angle, measured in radians, by which the source points * are rotated around the origin. The direction of rotation for positive * angles will rotate the positive {@code X} axis towards the positive * {@code Y} axis. This method is equivalent to: * * <pre> * rt.setRotation(rt.getRotation() + theta); * </pre> * * @param theta * the angle to be added, measured in radians */ public abstract void rotateBy(Vector3f v); public abstract void rotateXBy(float thetax); public abstract void rotateYBy(float thetay); public abstract void rotateZBy(float thetaz); @Override public void reset() { setRotation(0, 0, 0); } } /** * This class implements a simple 2 Dimensional shearing transform. Input * points are slanted by applying a scaling factor perpendicular to each * axis and that increases linearly along the axes such that points near the * origin are not moved at all, but positive coordinates far from the origin * are moved by ever increasing distances perpendicular to the axes. * Negative coordinates are moved in the opposite direction as positive * coordinates. The transform {@code x',y'} of a source point {@code x,y} is * represented by the equations: * * <pre> * x' = x + y * shearx; * y' = y + x * sheary; * z' = z + x * shearz; * </pre> * * Instances of this class can only be created by calling the * {@link SGTransform#createShear} factory method. * * @author Flar */ public static abstract class Shear extends SGTransform { /** Creates a new instance of Shear */ Shear() { } /** * Returns the factor by which positive {@code X} coordinates are moved * in the direction of the positive {@code Y} axis. Negative coordinates * are moved similarly in the opposite direction. * * @return the {@code X} shearing factor */ public abstract float getShearX(); /** * Returns the factor by which positive {@code Y} coordinates are moved * in the direction of the positive {@code X} axis. Negative coordinates * are moved similarly in the opposite direction. * * @return the {@code Y} shearing factor */ public abstract float getShearY(); /** * Returns the factor by which positive {@code Z} coordinates are moved * in the direction of the positive {@code X} axis. Negative coordinates * are moved similarly in the opposite direction. * * @return the {@code Z} shearing factor */ public abstract float getShearZ(); /** * Sets the factor by which positive {@code X} coordinates are moved in * the direction of the positive {@code Y} axis. Negative coordinates * are moved similarly in the opposite direction. * * @param shx * the new {@code X} shearing factor */ public abstract void setShearX(float shx); /** * Sets the factor by which positive {@code Y} coordinates are moved in * the direction of the positive {@code X} axis. Negative coordinates * are moved similarly in the opposite direction. * * @param shy * the new {@code Y} shearing factor */ public abstract void setShearY(float shy); /** * Sets the factor by which positive {@code Z} coordinates are moved in * the direction of the positive {@code X} axis. Negative coordinates * are moved similarly in the opposite direction. * * @param shy * the new {@code Z} shearing factor */ public abstract void setShearZ(float shz); /** * Sets the {@code X} and {@code Y} shearing factors to new values. * * @param shx * the new {@code X} shearing factor * @param shy * the new {@code Y} shearing factor */ public abstract void setShear(float shx, float shy, float shz); /** * Scales the {@code X} and {@code Y} shearing factors by the specified * factors. This method is equivalent to: * * <pre> * st.setShear(st.getShearX() * shx, st.getShearY() * shy); * </pre> * * @param shx * the scale applied to the {@code X} shearing factor * @param shy * the scale applied to the {@code Y} shearing factor */ public abstract void shearBy(float shx, float shy, float shz); @Override public void reset() { setShear(0, 0, 0); } } /** * This class implements a general 2 Dimensional affine transform. Input * points are transformed by applying the generalized affine transform * specified by an {@link Transform3D} object. * * Instances of this class can only be created by calling the * {@link SGTransform#createAffine} factory method. * * @author Flar */ public static abstract class Affine extends SGTransform { /** Creates a new instance of Affine */ Affine() { } /** * Returns the {@link Transform3D} object which controls how * coordinates are transformed by this node. * * @return the {@code Transform3D} object */ public abstract Transform3D getAffine(); /** * Sets the {@link Transform3D} object which controls how * coordinates are transformed by this node. * * @param at * the {@code Transform3D} object */ public abstract void setAffine(Transform3D at); /** * Concatenates the existing transform with an additional * {@link Transform3D} object as per the implementation of * {@link Transform3D#concatenate}. * * @param at * the {@code Transform3D} to be concatenated */ public abstract void transformBy(Transform3D at); } }