/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2005-2016, 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.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import org.geotools.metadata.iso.citation.Citations;
import org.geotools.parameter.DefaultParameterDescriptor;
import org.geotools.referencing.NamedIdentifier;
import org.geotools.referencing.operation.MathTransformProvider;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.parameter.ParameterNotFoundException;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.Transformation;
/**
* The provider for the {@link WarpTransform2D}. This provider constructs a JAI
* {@linkplain WarpPolynomial image warp} from a set of polynomial coefficients,
* and wrap it in a {@link WarpTransform2D} object.
*
* @version $Id$
* @author Martin Desruisseaux
*/
public class WarpTransform2DProvider extends MathTransformProvider {
/** Serial number for interoperability with different versions. */
private static final long serialVersionUID = -7949539694656719923L;
/** Descriptor for the "{@link WarpPolynomial#getDegree degree}" parameter value. */
public static final ParameterDescriptor<Integer> DEGREE = DefaultParameterDescriptor.create(
"degree", 2, 1, WarpTransform2D.MAX_DEGREE);
/** Descriptor for the "{@link WarpPolynomial#getXCoeffs xCoeffs}" parameter value. */
@SuppressWarnings({ "rawtypes", "unchecked" })
public static final ParameterDescriptor<?> X_COEFFS = new DefaultParameterDescriptor(
"xCoeffs", float[].class, null, null);
/** Descriptor for the "{@link WarpPolynomial#getYCoeffs yCoeffs}" parameter value. */
@SuppressWarnings({ "rawtypes", "unchecked" })
public static final ParameterDescriptor<?> Y_COEFFS = new DefaultParameterDescriptor(
"yCoeffs", float[].class, null, null);
/** Descriptor for the "{@link WarpPolynomial#getPreScaleX preScaleX}" parameter value. */
public static final ParameterDescriptor<Float> PRE_SCALE_X;
/** Descriptor for the "{@link WarpPolynomial#getPreScaleY preScaleY}" parameter value. */
public static final ParameterDescriptor<Float> PRE_SCALE_Y;
/** Descriptor for the "{@link WarpPolynomial#getPostScaleX postScaleX}" parameter value. */
public static final ParameterDescriptor<Float> POST_SCALE_X;
/** Descriptor for the "{@link WarpPolynomial#getPostScaleY postScaleY}" parameter value. */
public static final ParameterDescriptor<Float> POST_SCALE_Y;
static {
final Float ONE = 1f;
PRE_SCALE_X = DefaultParameterDescriptor.create( "preScaleX",null, Float.class, ONE, false);
PRE_SCALE_Y = DefaultParameterDescriptor.create( "preScaleY", null, Float.class, ONE, false);
POST_SCALE_X = DefaultParameterDescriptor.create("postScaleX", null, Float.class, ONE, false);
POST_SCALE_Y = DefaultParameterDescriptor.create("postScaleY", null, Float.class, ONE, false);
}
/**
* The parameters group.
*/
static final ParameterDescriptorGroup PARAMETERS = createDescriptorGroup(new NamedIdentifier[] {
new NamedIdentifier(Citations.GEOTOOLS, "WarpPolynomial")
}, new ParameterDescriptor[] {
DEGREE, X_COEFFS, Y_COEFFS, PRE_SCALE_X, PRE_SCALE_Y, POST_SCALE_X, POST_SCALE_Y
});
/**
* Create a provider for warp transforms.
*/
public WarpTransform2DProvider() {
super(2, 2, PARAMETERS);
}
/**
* Returns the operation type.
*/
@Override
public Class<Transformation> getOperationType() {
return Transformation.class;
}
/**
* Creates a warp transform from the specified group of parameter values.
*
* @param values The group of parameter values.
* @return The created math transform.
* @throws ParameterNotFoundException if a required parameter was not found.
*/
protected MathTransform createMathTransform(final ParameterValueGroup values)
throws ParameterNotFoundException
{
final int degree = intValue(DEGREE, values);
final float[] xCoeffs = (float[]) value(X_COEFFS, values);
final float[] yCoeffs = (float[]) value(Y_COEFFS, values);
final float preScaleX = scale( PRE_SCALE_X, values);
final float preScaleY = scale( PRE_SCALE_Y, values);
final float postScaleX = scale(POST_SCALE_X, values);
final float postScaleY = scale(POST_SCALE_Y, values);
try {
final Object warp;
switch (degree) {
case 1: warp = createWarp("javax.media.jai.WarpAffine",
xCoeffs, yCoeffs, preScaleX, preScaleY, postScaleX, postScaleY); break;
case 2: warp = createWarp("javax.media.jai.WarpQuadratic",
xCoeffs, yCoeffs, preScaleX, preScaleY, postScaleX, postScaleY); break;
case 3: warp = createWarp("javax.media.jai.WarpCubic",
xCoeffs, yCoeffs, preScaleX, preScaleY, postScaleX, postScaleY); break;
default: warp = createWarp("javax.media.jai.WarpGeneralPolynomial",
xCoeffs, yCoeffs, preScaleX, preScaleY, postScaleX, postScaleY); break;
}
Class<? extends MathTransform> transformClass;
transformClass = (Class<? extends MathTransform>) Class.forName("org.geotools.referencing.operation.transform.WarpTransform2D");
Class warpClass = Class.forName("javax.media.jai.Warp");
Constructor<? extends MathTransform> createTransform = transformClass.getConstructor( new Class[]{warpClass,warpClass});
return createTransform.newInstance( warp, null );
} catch (Exception jaiUnavailable) {
throw new UnsupportedOperationException("WarpTransform2D requires Java Advanced Imaging extension");
}
}
private Object createWarp(String warpName, final float[] xCoeffs, final float[] yCoeffs,
final float preScaleX, final float preScaleY, final float postScaleX,
final float postScaleY) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Class warpClass = Class.forName(warpName);
Class[] params = new Class[]{float[].class,float[].class,float.class,float.class,float.class,float.class,float.class};
Constructor<?> constrctor = warpClass.getConstructor(params);
return constrctor.newInstance( xCoeffs, yCoeffs, preScaleX, preScaleY, postScaleX, postScaleY);
}
/**
* Returns the parameter value for the specified operation parameter.
*
* @param param The parameter to look for.
* @param group The parameter value group to search into.
* @return The requested parameter value, or {@code 1} if none.
*/
private static float scale(final ParameterDescriptor param,
final ParameterValueGroup group)
throws ParameterNotFoundException
{
final Object value = value(param, group);
return (value!=null) ? ((Number) value).floatValue() : 1;
}
}