/*
* Geotools 2 - OpenSource mapping toolkit
* (C) 2003, Geotools Project Managment Committee (PMC)
* (C) 2001, Institut de Recherche pour le Développement
*
* 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; either
* version 2.1 of the License, or (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.geotools.ct;
// OpenGIS dependencies
import java.io.Serializable;
import org.geotools.pt.CoordinatePoint;
import org.geotools.pt.Matrix;
import org.geotools.resources.Utilities;
import org.geotools.resources.i18n.Errors;
import org.geotools.resources.i18n.ErrorKeys;
import org.opengis.referencing.operation.NoninvertibleTransformException;
import org.opengis.referencing.operation.TransformException;
import org.opengis.spatialschema.geometry.MismatchedDimensionException;
/**
* Transform which passes through a subset of ordinates to another transform.
* This allows transforms to operate on a subset of ordinates. For example,
* if you have (latitude,longitude,height)
* coordinates, then you may wish to convert the height values from feet to
* meters without affecting the latitude and longitude values.
*
* @source $URL$
* @version 1.00
* @author Martin Desruisseaux
*
* @deprecated Replaced by {@link org.geotools.referencing.operation.transform.PassThroughTransform}
* in the org.geotools.referencing.operation.transform
package.
*/
final class PassThroughTransform extends AbstractMathTransform implements Serializable {
/**
* Serial number for interoperability with different versions.
*/
private static final long serialVersionUID = -1673997634240223449L;
/**
* Index of the first affected ordinate.
*/
protected final int firstAffectedOrdinate;
/**
* Number of unaffected ordinates after the affected ones.
* Always 0 when used through the strict OpenGIS API.
*/
protected final int numTrailingOrdinates;
/**
* The sub transform.
*/
protected final MathTransform transform;
/**
* The inverse transform. This field
* will be computed only when needed.
*/
private transient PassThroughTransform inverse;
/**
* Create a pass through transform.
*
* @param firstAffectedOrdinate Index of the first affected ordinate.
* @param transform The sub transform.
* @param numTrailingOrdinates Number of trailing ordinates to pass through.
* Affected ordinates will range from firstAffectedOrdinate
* inclusive to dimTarget-numTrailingOrdinates
exclusive.
*/
public PassThroughTransform(final int firstAffectedOrdinate,
final MathTransform transform,
final int numTrailingOrdinates)
{
if (transform instanceof PassThroughTransform) {
final PassThroughTransform passThrough = (PassThroughTransform) transform;
this.firstAffectedOrdinate = passThrough.firstAffectedOrdinate + firstAffectedOrdinate;
this.numTrailingOrdinates = passThrough.numTrailingOrdinates + numTrailingOrdinates;
this.transform = passThrough.transform;
} else {
this.firstAffectedOrdinate = firstAffectedOrdinate;
this.numTrailingOrdinates = numTrailingOrdinates;
this.transform = transform;
}
}
/**
* Gets the dimension of input points.
*/
public int getDimSource() {
return firstAffectedOrdinate + transform.getDimSource() + numTrailingOrdinates;
}
/**
* Gets the dimension of output points.
*/
public int getDimTarget() {
return firstAffectedOrdinate + transform.getDimTarget() + numTrailingOrdinates;
}
/**
* Tests whether this transform does not move any points.
*/
public boolean isIdentity() {
return transform.isIdentity();
}
/**
* Transforms a list of coordinate point ordinal values.
*/
public void transform(final float[] srcPts, int srcOff,
final float[] dstPts, int dstOff, int numPts)
throws TransformException
{
final int subDimSource = transform.getDimSource();
final int subDimTarget = transform.getDimTarget();
int srcStep = numTrailingOrdinates;
int dstStep = numTrailingOrdinates;
if (srcPts==dstPts && srcOff= 0) {
System.arraycopy (srcPts, srcOff, dstPts, dstOff, firstAffectedOrdinate);
transform.transform(srcPts, srcOff+=firstAffectedOrdinate, dstPts, dstOff+=firstAffectedOrdinate, 1);
System.arraycopy (srcPts, srcOff+=subDimSource, dstPts, dstOff+=subDimTarget, numTrailingOrdinates);
srcOff += srcStep;
dstOff += dstStep;
}
}
/**
* Transforms a list of coordinate point ordinal values.
*/
public void transform(final double[] srcPts, int srcOff,
final double[] dstPts, int dstOff, int numPts)
throws TransformException
{
final int subDimSource = transform.getDimSource();
final int subDimTarget = transform.getDimTarget();
int srcStep = numTrailingOrdinates;
int dstStep = numTrailingOrdinates;
if (srcPts==dstPts && srcOff= 0) {
System.arraycopy (srcPts, srcOff, dstPts, dstOff, firstAffectedOrdinate);
transform.transform(srcPts, srcOff+=firstAffectedOrdinate, dstPts, dstOff+=firstAffectedOrdinate, 1);
System.arraycopy (srcPts, srcOff+=subDimSource, dstPts, dstOff+=subDimTarget, numTrailingOrdinates);
srcOff += srcStep;
dstOff += dstStep;
}
}
/**
* Gets the derivative of this transform at a point.
*/
public Matrix derivative(final CoordinatePoint point) throws TransformException {
final int nSkipped = firstAffectedOrdinate + numTrailingOrdinates;
final int transDim = transform.getDimSource();
final int pointDim = point.getDimension();
if (pointDim != transDim+nSkipped) {
throw new MismatchedDimensionException(Errors.format(
ErrorKeys.MISMATCHED_DIMENSION_$2,
new Integer(pointDim), new Integer(transDim+nSkipped)));
}
final CoordinatePoint subPoint = new CoordinatePoint(transDim);
System.arraycopy(point.ord, firstAffectedOrdinate, subPoint.ord, 0, transDim);
return expand(transform.derivative(subPoint),
firstAffectedOrdinate, numTrailingOrdinates, 0);
}
/**
* Create a pass through transform from a matrix. This method is invoked when the
* sub-transform can be express as a matrix. It is also invoked for computing the
* matrix returned by {@link #derivative}.
*
* @param subMatrix The sub-transform as a matrix.
* @param firstAffectedOrdinate Index of the first affected ordinate.
* @param numTrailingOrdinates Number of trailing ordinates to pass through.
* @param affine 0 if the matrix do not contains translation terms, or 1 if
* the matrix is an affine transform with translation terms.
*/
static Matrix expand(final Matrix subMatrix,
final int firstAffectedOrdinate,
final int numTrailingOrdinates,
final int affine)
{
final int nSkipped = firstAffectedOrdinate + numTrailingOrdinates;
final int numRow = subMatrix.getNumRow() - affine;
final int numCol = subMatrix.getNumCol() - affine;
final Matrix matrix = new Matrix(numRow + nSkipped + affine,
numCol + nSkipped + affine);
matrix.setZero();
// Set UL part to 1: [ 1 0 ]
// [ 0 1 ]
// [ ]
// [ ]
// [ ]
for (int j=0; j