Class AffineTransform2D

All Implemented Interfaces:
Serializable, Cloneable, LinearTransform2D, Parameterized, LinearTransform, LenientComparable, org.opengis.referencing.operation.MathTransform, org.opengis.referencing.operation.MathTransform2D
Direct Known Subclasses:
ParameterizedAffine

public class AffineTransform2D extends ImmutableAffineTransform implements LinearTransform2D, LenientComparable, Parameterized
Transforms two-dimensional coordinate tuples using an affine transform. This class both extends AffineTransform and implements MathTransform2D, so it can be used as a bridge between Java2D and the referencing module. Note that this bridge role involves a tricky issue with the equals method, hopefully to occur only in exceptional corner cases.
Since:
0.5
Version:
1.3
See Also:
  • Field Details

    • serialVersionUID

      private static final long serialVersionUID
      Serial number for inter-operability with different versions.
      See Also:
    • matrix

      private AffineMatrix matrix
      The matrix, or null if not yet computed.

      This field is also used for determining if the affine transform is mutable. If this field is null (which should be a temporary state), then this means that this affine transform is still under construction. This field must be set to a non-null value before an AffineTransform2D instance is published.

      See Also:
    • inverse

      private transient volatile AffineTransform2D inverse
      The inverse transform. This field will be computed only when needed.
      See Also:
  • Constructor Details

    • AffineTransform2D

      public AffineTransform2D(AffineTransform transform)
      Creates a new affine transform with the same coefficients than the specified transform.
      Parameters:
      transform - the affine transform to copy.
    • AffineTransform2D

      public AffineTransform2D(double[] elements)
      Creates a new transform from an array of values representing either the 4 non-translation entries or the 6 specifiable entries of the 3×3 matrix.
      Parameters:
      elements - the matrix elements in an array of length 4 or 6.
    • AffineTransform2D

      public AffineTransform2D(ExtendedPrecisionMatrix matrix)
      Creates a new AffineTransform2D from the 9 or 18 values of the given matrix.
      Parameters:
      matrix - the matrix from which to get the (potentially extended) elements.
    • AffineTransform2D

      @Workaround(library="JDK", version="1.7") private AffineTransform2D(ExtendedPrecisionMatrix m, double[] elements)
      Work around for RFE #4093999 in Sun's bug database ("Relax constraint on placement of this()/super() call in constructors").
    • AffineTransform2D

      public AffineTransform2D(double m00, double m10, double m01, double m11, double m02, double m12)
      Creates a new AffineTransform2D from 6 values representing the 6 specifiable entries of the 3×3 transformation matrix. Those values are given unchanged to the super class constructor, except for negative zeros that are replaced by positive zeros.
      Parameters:
      m00 - the X coordinate scaling.
      m10 - the Y coordinate shearing.
      m01 - the X coordinate shearing.
      m11 - the Y coordinate scaling.
      m02 - the X coordinate translation.
      m12 - the Y coordinate translation.
    • AffineTransform2D

      public AffineTransform2D(double m00, double m10, double m01, double m11, double m02, double m12, boolean modifiable)
      Creates a potentially modifiable transform initialized to the 6 specifiable entries. Caller shall invoke freeze() before to publish this transform.
      Parameters:
      m00 - the X coordinate scaling.
      m10 - the Y coordinate shearing.
      m01 - the X coordinate shearing.
      m11 - the Y coordinate scaling.
      m02 - the X coordinate translation.
      m12 - the Y coordinate translation.
      modifiable - whether the transform should be modifiable.
  • Method Details

    • pz

      @Workaround(library="JDK", version="8", fixed="20") private static double pz(double value)
      Makes sure that the zero is positive. We do that in order to workaround a JDK 6 to 8 bug, where AffineTransform.hashCode() is inconsistent with AffineTransform.equals(Object) if there is zeros of opposite sign.

      The inconsistency is in the use of Double.doubleToLongBits(double) for hash code and == for testing equality. The former is sensitive to the sign of 0 while the latter is not.

      JDK-8290973
    • freeze

      public final void freeze()
      Ensures that this transform contains only positive zeros, then marks this transform as unmodifiable.
    • checkPermission

      protected final void checkPermission() throws UnsupportedOperationException
      Throws an UnsupportedOperationException when a mutable method is invoked, since AffineTransform2D must be immutable.
      Overrides:
      checkPermission in class ImmutableAffineTransform
      Throws:
      UnsupportedOperationException - always thrown.
    • isAffine

      public final boolean isAffine()
      Returns true since this transform is affine.
      Specified by:
      isAffine in interface LinearTransform
      Returns:
      true if this transform is affine.
      See Also:
    • getParameterDescriptors

      public org.opengis.parameter.ParameterDescriptorGroup getParameterDescriptors()
      Returns the parameter descriptors for this math transform.
      Specified by:
      getParameterDescriptors in interface Parameterized
      Returns:
      the parameter descriptors for this object, or null.
    • getParameterValues

      public org.opengis.parameter.ParameterValueGroup getParameterValues()
      Returns the matrix elements as a group of parameter values. The number of parameters depends on the matrix size. Only matrix elements different from their default value will be included in this group.
      Specified by:
      getParameterValues in interface Parameterized
      Returns:
      the parameter values for this object, or null if unknown.
    • getSourceDimensions

      public final int getSourceDimensions()
      Gets the dimension of input points, which is fixed to 2.
      Specified by:
      getSourceDimensions in interface org.opengis.referencing.operation.MathTransform
    • getTargetDimensions

      public final int getTargetDimensions()
      Gets the dimension of output points, which is fixed to 2.
      Specified by:
      getTargetDimensions in interface org.opengis.referencing.operation.MathTransform
    • transform

      public final org.opengis.geometry.DirectPosition transform(org.opengis.geometry.DirectPosition ptSrc, org.opengis.geometry.DirectPosition ptDst)
      Transforms the specified ptSrc and stores the result in ptDst.
      Specified by:
      transform in interface org.opengis.referencing.operation.MathTransform
    • createTransformedShape

      public final Shape createTransformedShape(Shape shape)
      Transforms the specified shape. This method creates a simpler shape then the default super-class implementation. For example if the given shape is a rectangle and this affine transform has no scale or shear, then the returned shape will be an instance of Rectangle2D.
      Specified by:
      createTransformedShape in interface org.opengis.referencing.operation.MathTransform2D
      Overrides:
      createTransformedShape in class AffineTransform
      Parameters:
      shape - shape to transform.
      Returns:
      transformed shape, or shape if this transform is the identity transform.
    • getMatrix

      public final org.opengis.referencing.operation.Matrix getMatrix()
      Returns this transform as an affine transform matrix.
      Specified by:
      getMatrix in interface LinearTransform
      Returns:
      the coefficients of this linear transform as a matrix.
      See Also:
    • derivative

      public final org.opengis.referencing.operation.Matrix derivative(Point2D point)
      Gets the derivative of this transform at a point. For an affine transform, the derivative is the same everywhere.
      Specified by:
      derivative in interface org.opengis.referencing.operation.MathTransform2D
    • derivative

      public final org.opengis.referencing.operation.Matrix derivative(org.opengis.geometry.DirectPosition point)
      Gets the derivative of this transform at a point. For an affine transform, the derivative is the same everywhere.
      Specified by:
      derivative in interface org.opengis.referencing.operation.MathTransform
    • inverse

      public final AffineTransform2D inverse() throws org.opengis.referencing.operation.NoninvertibleTransformException
      Creates the inverse transform of this object.
      Specified by:
      inverse in interface LinearTransform
      Specified by:
      inverse in interface LinearTransform2D
      Specified by:
      inverse in interface org.opengis.referencing.operation.MathTransform
      Specified by:
      inverse in interface org.opengis.referencing.operation.MathTransform2D
      Returns:
      the inverse transform.
      Throws:
      org.opengis.referencing.operation.NoninvertibleTransformException - if this transform cannot be inverted.
      See Also:
    • equals

      public boolean equals(Object object, ComparisonMode mode)
      Compares this affine transform with the given object for equality. This method behaves as documented in the LenientComparable.equals(…) method, except for the following case: if the given mode is ComparisonMode.STRICT, then this method delegates to equals(Object). The latter method has different rules than the ones documented in the LenientComparable interface, because of the AffineTransform inheritance.
      Specified by:
      equals in interface LenientComparable
      Parameters:
      object - the object to compare to this.
      mode - the strictness level of the comparison.
      Returns:
      true if both objects are equal.
      See Also:
    • equals

      public boolean equals(Object object)
      Compares this affine transform with the given object for equality. The comparison is performed in the same way than AffineTransform.equals(Object) with one additional rule: if the other object is also an instance of AffineTransform2D, then the two objects must be of the exact same class.

      Most SIS implementations require that the objects being compared are unconditionally of the same class in order to be considered equal. However, many JDK implementations, including AffineTransform, do not have this requirement. Consequently, the above condition (i.e. require the same class only if the given object is an AffineTransform2D or a subclass) is necessary in order to preserve the symmetricity contract of Object.equals(Object).

      A side-effect of this implementation is that the transitivity contract of Object.equals(Object) may be broken is some corner cases. This contract said:

      a.equals(b) and b.equals(c) implies a.equals(c)
      Assuming that a, b and c are instances of AffineTransform (where "instance of T" means T or any subclass of T), then the transitivity contract is broken if and only if exactly two of those objects are instance of AffineTransform2D and those two objects are not of the same class. Note that this implies that at least one subclass of AffineTransform2D is used.

      In the vast majority of cases, the transitivity contract is not broken and the users can ignore this documentation. The transitivity contract is typically not broken either because we usually don't subclass AffineTransform2D, or because we don't mix AffineTransform with AffineTransform2D subclasses in the same collection.

      This special case exists in order to allow developers to attach additional information to their own subclass of AffineTransform2D, and still distinguish their specialized subclass from ordinary affine transforms in a pool of MathTransform instances. The main application is the Equirectangular map projection, which can be simplified to an affine transform but still needs to remember the projection parameters.

      Specified by:
      equals in interface LenientComparable
      Overrides:
      equals in class AffineTransform
      Parameters:
      object - the object to compare with this affine transform for equality.
      Returns:
      true if the given object is of appropriate class (as explained in the above documentation) and the affine transform coefficients are the same.
      See Also:
    • clone

      public AffineTransform clone()
      Returns a new affine transform which is a modifiable copy of this transform. This implementation always returns an instance of AffineTransform, not AffineTransform2D, because the latter is unmodifiable and cloning it make little sense.
      Overrides:
      clone in class AffineTransform
      Returns:
      a modifiable copy of this affine transform.
    • toWKT

      public String toWKT()
      Returns the WKT for this transform.
      Specified by:
      toWKT in interface org.opengis.referencing.operation.MathTransform
    • toString

      public String toString()
      Returns a string representation of this transform as a matrix, for consistency with other LinearTransform implementations in Apache SIS.
      Overrides:
      toString in class AffineTransform