/*---------------- FILE HEADER ------------------------------------------
This file is part of deegree.
Copyright (C) 2001 by:
EXSE, Department of Geography, University of Bonn
http://www.giub.uni-bonn.de/exse/
lat/lon GmbH
http://www.lat-lon.de
It has been implemented within SEAGIS - An OpenSource implementation of OpenGIS specification
(C) 2001, Institut de Recherche pour le D�veloppement (http://sourceforge.net/projects/seagis/)
SEAGIS Contacts: Surveillance de l'Environnement Assist�e par Satellite
Institut de Recherche pour le D�veloppement / US-Espace
mailto:seasnet@teledetection.fr
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
Contact:
Andreas Poth
lat/lon GmbH
Aennchenstr. 19
53115 Bonn
Germany
E-Mail: poth@lat-lon.de
Klaus Greve
Department of Geography
University of Bonn
Meckenheimer Allee 166
53115 Bonn
Germany
E-Mail: klaus.greve@uni-bonn.de
---------------------------------------------------------------------------*/
package org.deegree.model.csct.ct;
// OpenGIS dependencies (SEAGIS)
import java.io.Serializable;
import org.deegree.model.csct.pt.CoordinatePoint;
import org.deegree.model.csct.pt.Matrix;
import org.deegree.model.csct.pt.MismatchedDimensionException;
import org.deegree.model.csct.resources.Utilities;
/**
* 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 (<var>latitude</var>,<var>longitude</var>,<var>height</var>)
* coordinates, then you may wish to convert the height values from feet to
* meters without affecting the latitude and longitude values.
*
* @version 1.00
* @author OpenGIS (www.opengis.org)
* @author Martin Desruisseaux
*/
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 <code>firstAffectedOrdinate</code>
* inclusive to <code>dimTarget-numTrailingOrdinates</code> 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<dstOff)
{
final int dimSource = getDimSource();
final int dimTarget = getDimTarget();
srcOff += numPts * dimSource;
dstOff += numPts * dimTarget;
srcStep -= 2*dimSource;
dstStep -= 2*dimTarget;
}
while (--numPts >= 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<dstOff)
{
final int dimSource = getDimSource();
final int dimTarget = getDimTarget();
srcOff += numPts * dimSource;
dstOff += numPts * dimTarget;
srcStep -= 2*dimSource;
dstStep -= 2*dimTarget;
}
while (--numPts >= 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(pointDim, transDim+nSkipped);
}
final CoordinatePoint subPoint = new CoordinatePoint(transDim);
System.arraycopy(point.ord, firstAffectedOrdinate, subPoint.ord, 0, transDim);
final Matrix subMatrix = transform.derivative(subPoint);
final int numRow = subMatrix.getNumRow();
final int numCol = subMatrix.getNumCol();
final Matrix matrix = new Matrix(nSkipped+numRow, nSkipped+numCol);
matrix.setZero();
// Set UL part to 1: [ 1 0 ]
// [ 0 1 ]
// [ ]
// [ ]
// [ ]
for (int j=0; j<firstAffectedOrdinate; j++)
matrix.setElement(j,j,1);
// Set central part: [ 1 0 0 0 0 0 ]
// [ 0 1 0 0 0 0 ]
// [ 0 0 ? ? ? 0 ]
// [ 0 0 ? ? ? 0 ]
// [ ]
subMatrix.copySubMatrix(0,0,numRow,numCol,firstAffectedOrdinate,firstAffectedOrdinate, matrix);
// Set LR part to 1: [ 1 0 0 0 0 0 ]
// [ 0 1 0 0 0 0 ]
// [ 0 0 ? ? ? 0 ]
// [ 0 0 ? ? ? 0 ]
// [ 0 0 0 0 0 1 ]
final int offset = numCol-numRow;
for (int j=pointDim-numTrailingOrdinates; j<pointDim; j++)
matrix.setElement(j, j+offset, 1);
return matrix;
}
/**
* Creates the inverse transform of this object.
*/
public synchronized MathTransform inverse() throws NoninvertibleTransformException
{
if (inverse==null)
{
inverse = new PassThroughTransform(firstAffectedOrdinate, transform.inverse(), numTrailingOrdinates);
inverse.inverse = this;
}
return inverse;
}
/**
* Compares the specified object with
* this math transform for equality.
*/
public boolean equals(final Object object)
{
if (object==this) return true;
if (super.equals(object))
{
final PassThroughTransform that = (PassThroughTransform) object;
return this.firstAffectedOrdinate == that.firstAffectedOrdinate &&
this.numTrailingOrdinates == that.numTrailingOrdinates &&
Utilities.equals(this.transform, that.transform);
}
return false;
}
/**
* Returns the WKT for this math transform.
*/
public String toString()
{
final StringBuffer buffer = new StringBuffer("PASSTHROUGH_MT[");
buffer.append(firstAffectedOrdinate);
buffer.append(',');
if (numTrailingOrdinates!=0)
{
// TODO: This parameter is not part of OpenGIS specification!
// We should returns a more complex WKT here, using an
// affine transform to change the coordinates order.
buffer.append(numTrailingOrdinates);
buffer.append(',');
}
buffer.append(transform);
buffer.append(']');
return buffer.toString();
}
}