/*---------------- 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.resources.Utilities; import org.deegree.model.csct.resources.css.ResourceKeys; import org.deegree.model.csct.resources.css.Resources; /** * Base class for concatened transform. Concatened transforms are * serializable if all their step transforms are serializables. * * @version 1.0 * @author Martin Desruisseaux */ class ConcatenedTransform extends AbstractMathTransform implements Serializable { /** * Serial number for interoperability with different versions. */ private static final long serialVersionUID = 5772066656987558634L; /** * The math transform factory that created this concatened transform. * Will be used for creating the inverse transform when needed. */ private MathTransformFactory provider; /** * The first math transform. */ protected final MathTransform transform1; /** * The second math transform. */ protected final MathTransform transform2; /** * The inverse transform. This field * will be computed only when needed. */ private transient MathTransform inverse; /** * Construct a concatenated transform. */ public ConcatenedTransform(final MathTransformFactory provider, final MathTransform transform1, final MathTransform transform2) { this.provider = provider; this.transform1 = transform1; this.transform2 = transform2; if (!isValid()) { throw new IllegalArgumentException(Resources.format(ResourceKeys.ERROR_CANT_CONCATENATE_CS_$2, getName(transform1), getName(transform2))); } } /** * Returns a name for the specified coordinate system. */ private static final String getName(final MathTransform transform) { if (transform instanceof AbstractMathTransform) { String name = ((AbstractMathTransform) transform).getName(null); if (name!=null && (name=name.trim()).length()!=0) return name; } return Utilities.getShortClassName(transform); } /** * Check if transforms are compatibles. The default * implementation check if transfert dimension match. */ protected boolean isValid() {return transform1.getDimTarget() == transform2.getDimSource();} /** * Gets the dimension of input points. */ public final int getDimSource() {return transform1.getDimSource();} /** * Gets the dimension of output points. */ public final int getDimTarget() {return transform2.getDimTarget();} /** * Transforms the specified <code>ptSrc</code> and stores the result in <code>ptDst</code>. */ public CoordinatePoint transform(final CoordinatePoint ptSrc, CoordinatePoint ptDst) throws TransformException { // Note: If we know that the transfert dimension is the same than source // and target dimension, then we don't need to use an intermediate // point. This optimization is done in ConcatenedTransformDirect. return transform2.transform(transform1.transform(ptSrc, null), ptDst); } /** * Transforms a list of coordinate point ordinal values. */ public void transform(final double[] srcPts, final int srcOff, final double[] dstPts, final int dstOff, final int numPts) throws TransformException { // Note: If we know that the transfert dimension is the same than source // and target dimension, then we don't need to use an intermediate // buffer. This optimization is done in ConcatenedTransformDirect. final double[] tmp = new double[numPts*transform1.getDimTarget()]; transform1.transform(srcPts, srcOff, tmp, 0, numPts); transform2.transform(tmp, 0, dstPts, dstOff, numPts); } /** * Transforms a list of coordinate point ordinal values. */ public void transform(final float[] srcPts, final int srcOff, final float[] dstPts, final int dstOff, final int numPts) throws TransformException { // Note: If we know that the transfert dimension is the same than source // and target dimension, then we don't need to use an intermediate // buffer. This optimization is done in ConcatenedTransformDirect. final float[] tmp = new float[numPts*transform1.getDimTarget()]; transform1.transform(srcPts, srcOff, tmp, 0, numPts); transform2.transform(tmp, 0, dstPts, dstOff, numPts); } /** * Creates the inverse transform of this object. */ public synchronized final MathTransform inverse() throws NoninvertibleTransformException { if (inverse==null) { if (provider == null) { provider = MathTransformFactory.getDefault(); } inverse = provider.createConcatenatedTransform(transform2.inverse(), transform1.inverse()); if (inverse instanceof ConcatenedTransform) { ((ConcatenedTransform) inverse).inverse = this; } } return inverse; } /** * Gets the derivative of this transform at a point. * * @param point The coordinate point where to evaluate the derivative. * @return The derivative at the specified point (never <code>null</code>). * @throws TransformException if the derivative can't be evaluated at the specified point. */ public Matrix derivative(final CoordinatePoint point) throws TransformException { final Matrix matrix1 = transform1.derivative(point); final Matrix matrix2 = transform2.derivative(transform1.transform(point, null)); // Compute "matrix = matrix2 * matrix1". Reuse an existing matrix object // if possible, which is always the case when both matrix are square. final int numRow = matrix2.getNumRow(); final int numCol = matrix1.getNumCol(); final Matrix matrix; if (numCol == matrix2.getNumCol()) { matrix = matrix2; matrix2.mul(matrix1); } else { matrix = new Matrix(numRow, numCol); matrix.mul(matrix2, matrix1); } return matrix; } /** * Tests whether this transform does not move any points. * Default implementation check if the two transforms are * identity. This a way too conservative aproach, but it * it doesn't hurt since ConcatenedTransform should not * have been created if it were to result in an identity * transform (this case should have been detected earlier). */ public final boolean isIdentity() {return transform1.isIdentity() && transform2.isIdentity();} /** * Returns a hash value for this transform. */ public final int hashCode() {return transform1.hashCode() + 37*transform2.hashCode();} /** * Compares the specified object with * this math transform for equality. */ public final boolean equals(final Object object) { if (object==this) return true; // Slight optimization if (super.equals(object)) { final ConcatenedTransform that = (ConcatenedTransform) object; return Utilities.equals(this.transform1, that.transform1) && Utilities.equals(this.transform2, that.transform2); } return false; } /** * Returns the WKT for this math transform. */ public final String toString() { final StringBuffer buffer = new StringBuffer("CONCAT_MT["); addWKT(buffer, this, true); buffer.append(']'); return buffer.toString(); } /** * Append to a string buffer the WKT * for the specified math transform. */ private static void addWKT(final StringBuffer buffer, final MathTransform transform, final boolean first) { if (transform instanceof ConcatenedTransform) { final ConcatenedTransform concat = (ConcatenedTransform) transform; addWKT(buffer, concat.transform1, first); addWKT(buffer, concat.transform2, false); } else { if (!first) buffer.append(", "); buffer.append(transform); } } }