/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2002-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.referencing.operation.transform;
import java.awt.geom.AffineTransform;
import java.io.Serializable;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.referencing.operation.Matrix;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import org.opengis.geometry.DirectPosition;
import org.geotools.geometry.GeneralDirectPosition;
import org.geotools.referencing.operation.LinearTransform;
import org.geotools.referencing.operation.matrix.MatrixFactory;
/**
* The identity transform. The data are only copied without any transformation. This class is
* used for identity transform of dimension greater than 2. For 1D and 2D identity transforms,
* {@link LinearTransform1D} and {@link java.awt.geom.AffineTransform} already provide their
* own optimisations.
*
* @since 2.0
*
* @source $URL$
* @version $Id$
* @author Martin Desruisseaux (IRD)
*/
public class IdentityTransform extends AbstractMathTransform
implements LinearTransform, Serializable
{
/**
* Serial number for interoperability with different versions.
*/
private static final long serialVersionUID = -5339040282922138164L;
/**
* The input and output dimension.
*/
private final int dimension;
/**
* Identity transforms for dimensions ranging from to 0 to 7.
* Elements in this array will be created only when first requested.
*/
private static final LinearTransform[] POOL = new LinearTransform[8];
/**
* Constructs an identity transform of the specified dimension.
*/
protected IdentityTransform(final int dimension) {
this.dimension = dimension;
}
/**
* Constructs an identity transform of the specified dimension.
*/
public static synchronized LinearTransform create(final int dimension) {
LinearTransform candidate;
if (dimension < POOL.length) {
candidate = POOL[dimension];
if (candidate != null) {
return candidate;
}
}
switch (dimension) {
case 1: candidate = LinearTransform1D.IDENTITY; break;
case 2: candidate = new AffineTransform2D(new AffineTransform()); break;
default: candidate = new IdentityTransform(dimension); break;
}
if (dimension < POOL.length) {
POOL[dimension] = candidate;
}
return candidate;
}
/**
* Tests whether this transform does not move any points.
* This implementation always returns {@code true}.
*/
@Override
public boolean isIdentity() {
return true;
}
/**
* Tests whether this transform does not move any points.
* This implementation always returns {@code true}.
*/
public boolean isIdentity(double tolerance) {
return true;
}
/**
* Gets the dimension of input points.
*/
public int getSourceDimensions() {
return dimension;
}
/**
* Gets the dimension of output points.
*/
public int getTargetDimensions() {
return dimension;
}
/**
* Returns the parameter descriptors for this math transform.
*/
@Override
public ParameterDescriptorGroup getParameterDescriptors() {
return ProjectiveTransform.ProviderAffine.PARAMETERS;
}
/**
* Returns the matrix elements as a group of parameters values.
*
* @return A copy of the parameter values for this math transform.
*/
@Override
public ParameterValueGroup getParameterValues() {
return ProjectiveTransform.getParameterValues(getMatrix());
}
/**
* Returns a copy of the identity matrix.
*/
public Matrix getMatrix() {
return MatrixFactory.create(dimension+1);
}
/**
* Gets the derivative of this transform at a point. For an identity transform,
* the derivative is the same everywhere.
*/
@Override
public Matrix derivative(final DirectPosition point) {
return MatrixFactory.create(dimension);
}
/**
* Copies the values from {@code ptSrc} to {@code ptDst}.
* Overrides the super-class method for performance reason.
*
* @since 2.2
*/
@Override
public DirectPosition transform(final DirectPosition ptSrc, final DirectPosition ptDst) {
if (ptSrc.getDimension() == dimension) {
if (ptDst == null) {
return new GeneralDirectPosition(ptSrc);
}
if (ptDst.getDimension() == dimension) {
for (int i=0; i<dimension; i++) {
ptDst.setOrdinate(i, ptSrc.getOrdinate(i));
}
return ptDst;
}
}
try {
// The super class will take care of throwing the MismatchedDimensionException.
return super.transform(ptSrc, ptDst);
} catch (TransformException e) {
throw new AssertionError(e); // Should never happen.
}
}
/**
* Transforms an array of floating point coordinates by this transform.
*/
@Override
public void transform(final float[] srcPts, int srcOff,
final float[] dstPts, int dstOff, int numPts)
{
System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts*dimension);
}
/**
* Transforms an array of floating point coordinates by this transform.
*/
public void transform(final double[] srcPts, int srcOff,
final double[] dstPts, int dstOff, int numPts)
{
System.arraycopy(srcPts, srcOff, dstPts, dstOff, numPts*dimension);
}
/**
* Returns the inverse transform of this object, which
* is this transform itself
*/
@Override
public MathTransform inverse() {
return this;
}
/**
* Returns a hash value for this transform.
* This value need not remain consistent between
* different implementations of the same class.
*/
@Override
public int hashCode() {
return (int)serialVersionUID + dimension;
}
/**
* Compares the specified object with
* this math transform for equality.
*/
@Override
public boolean equals(final Object object) {
if (object == this) {
// Slight optimization
return true;
}
if (super.equals(object)) {
final IdentityTransform that = (IdentityTransform) object;
return this.dimension == that.dimension;
}
return false;
}
}