/*
* Geotoolkit.org - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2001-2012, Open Source Geospatial Foundation (OSGeo)
* (C) 2009-2012, Geomatys
*
* 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.geotoolkit.referencing.operation.transform;
import org.opengis.util.FactoryException;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
import org.geotoolkit.internal.referencing.SeparableTransform;
import org.apache.sis.referencing.operation.transform.PassThroughTransform;
import org.apache.sis.referencing.operation.transform.TransformSeparator;
/**
* A utility class for the separation of {@linkplain ConcatenatedTransform concatenation} of
* {@linkplain PassThroughTransform pass through transforms}. Given an arbitrary
* {@linkplain MathTransform math transform}, this utility class will returns a new math transform
* that operates only of a given set of source dimensions. For example if the supplied
* {@code transform} has (<var>x</var>, <var>y</var>, <var>z</var>) inputs and
* (<var>longitude</var>, <var>latitude</var>, <var>height</var>) outputs, then
* the following code:
*
* {@preformat java
* addSourceDimensionRange(0, 2);
* MathTransform mt = separate(transform);
* }
*
* will returns a transform with (<var>x</var>, <var>y</var>) inputs and (probably)
* (<var>longitude</var>, <var>latitude</var>) outputs. The later can be verified with
* a call to {@link #getTargetDimensions}.
*
* @author Martin Desruisseaux (IRD)
* @author Simone Giannecchini (Geosolutions)
* @version 3.00
*
* @todo This class contains a set of static methods that could be factored out in
* some kind of {@code org.geotoolkit.util.SortedIntegerSet} implementation.
*
* @todo Consider providing a {@code subTransform(DimensionFilter)} method in
* {@link AbstractMathTransform}, and move some {@code DimensionFilter}
* code in {@code AbstractMathTransform} sub-classes. This would allow us
* to separate transforms that are defined in downstream modules, like NetCDF.
*
* @since 2.1
* @module
*
* @deprecated Moved to Apache SIS as {@link TransformSeparator}.
*/
@Deprecated
public class DimensionFilter extends TransformSeparator {
public DimensionFilter(MathTransform transform) {
super(transform);
}
public DimensionFilter(MathTransform transform, MathTransformFactory factory) {
super(transform, factory);
}
/**
* Adds an input dimension to keep. The {@code dimension} applies to the source dimensions
* of the transform to be given to <code>{@linkplain #separate separate}(transform)</code>.
* The number must be in the range 0 inclusive to
* <code>transform.{@linkplain MathTransform#getSourceDimensions getSourceDimensions()}</code>
* exclusive.
*
* @param dimension The dimension to add.
* @throws IllegalArgumentException if {@code dimension} is negative.
*/
public void addSourceDimension(final int dimension) throws IllegalArgumentException {
addSourceDimensions(dimension);
}
/**
* Adds an output dimension to keep. The {@code dimension} applies to the target dimensions
* of the transform to be given to <code>{@linkplain #separate separate}(transform)</code>.
* The number must be in the range 0 inclusive to
* <code>transform.{@linkplain MathTransform#getTargetDimensions getTargetDimensions()}</code>
* exclusive.
*
* @param dimension The dimension to add.
* @throws IllegalArgumentException if {@code dimension} is negative.
*/
public void addTargetDimension(final int dimension) throws IllegalArgumentException {
addTargetDimensions(dimension);
}
/**
* Separates the specified math transform. This method returns a math transform that uses
* only the specified {@linkplain #getSourceDimensions source dimensions} and returns only
* the specified {@linkplain #getTargetDimensions target dimensions}. Special case:
* <p>
* <ul>
* <li><p>If {@linkplain #getSourceDimensions source dimensions} are unspecified, then the
* returned transform will expects all source dimensions as input but will produces only
* the specified {@linkplain #getTargetDimensions target dimensions} as output.</p></li>
*
* <li><p>If {@linkplain #getTargetDimensions target dimensions} are unspecified, then the
* returned transform will expects only the specified {@linkplain #getSourceDimensions
* source dimensions} as input, and the target dimensions will be inferred
* automatically.</p></li>
* </ul>
*
* @return The separated math transform.
* @throws FactoryException if the transform can't be separated.
*/
@Override
public MathTransform separate() throws FactoryException {
/*
* -------- HACK BEGINS --------
* Special case for NetCDF transforms. Actually we should generalize the approach used
* here by providing an abstract protected method in AbstractMathTransform which expect
* a DimensionFilter (maybe to be renamed) in argument. The default implementation would
* check for the trivial case allowing to return 'this', and throw an exception for non-
* trivial cases. Appropriate subclasses (PassthroughTransform, ConcatenatedTransform,
* etc.) should implement that method.
*/
if (transform instanceof SeparableTransform) {
final MathTransform candidate = ((SeparableTransform) transform).subTransform(sourceDimensions, targetDimensions);
if (candidate != null) {
// BAD HACK - Presume that source and target dimensions are the same.
// This is often the case with NetCDF files, but is not garanteed.
if (sourceDimensions == null) sourceDimensions = targetDimensions;
if (targetDimensions == null) targetDimensions = sourceDimensions;
return candidate;
}
}
/*
* -------- END OF HACK --------
*/
return super.separate();
}
/**
* Separates the math transform on the basis of {@linkplain #sourceDimensions input dimensions}.
* The remaining {@linkplain #targetDimensions output dimensions} will be selected automatically
* according the specified input dimensions.
*
* @param step The transform to reduces.
* @return A transform expecting only the specified input dimensions.
* @throws FactoryException if the transform is not separable.
*/
@Override
protected MathTransform filterSourceDimensions(final MathTransform step, final int[] dimensions) throws FactoryException {
/*
* -------- HACK BEGINS -------- (same than in 'separate(...)')
*/
if (step instanceof SeparableTransform) {
final MathTransform candidate = ((SeparableTransform) step).subTransform(sourceDimensions, targetDimensions);
if (candidate != null) {
if (sourceDimensions == null) sourceDimensions = targetDimensions;
if (targetDimensions == null) targetDimensions = sourceDimensions;
return candidate;
}
}
/*
* -------- END OF HACK --------
*/
return super.filterSourceDimensions(step, dimensions);
}
}