/*
* Geotoolkit.org - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2005-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 java.util.Random;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.Point2D;
import javax.media.jai.Warp;
import javax.media.jai.WarpAffine;
import javax.media.jai.WarpQuadratic;
import javax.media.jai.WarpPolynomial;
import org.opengis.util.Factory;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransform2D;
import org.opengis.referencing.operation.TransformException;
import org.opengis.test.referencing.TransformTestCase;
import org.junit.*;
import static org.opengis.test.Assert.*;
/**
* Tests the {@link WarpTransform2D} class.
*
* @author Martin Desruisseaux (IRD, Geomatys)
* @version 3.15
*
* @since 2.1
*/
public final strictfp class WarpTransformTest extends TransformTestCase {
/**
* Width and height of a pseudo-image source image.
*/
private static final int WIDTH = 1000, HEIGHT = 2000;
/**
* Creates a new test case without factory.
*/
public WarpTransformTest() {
super(new Factory[0]);
}
/**
* Transforms in place a point. This is used for testing
* affine, quadratic and cubic warp from know formulas.
*/
private static interface Formula {
String message();
void transform(Point point);
}
/**
* Constructs a warp and tests the transformations.
* Coefficients will be tested later (by the caller).
*
* @param formula The formula to use for generating points.
* @param degree The polynomial degree for the wrap transform to be created.
* @return The created warp transform, returned for information purpose.
*/
private WarpPolynomial executeTest(final Formula formula, final int degree)
throws TransformException
{
/*
* Creates a set of points and transform them according the formula supplied in argument.
*/
final Random random = new Random(-854734760285695284L);
final Point[] sources = new Point[100];
final Point[] dest = new Point[sources.length];
for (int i=0; i<dest.length; i++) {
Point p;
sources[i] = p = new Point(random.nextInt(WIDTH), random.nextInt(HEIGHT));
dest [i] = p = new Point(p);
formula.transform(p);
}
/*
* Gets the transform. We specify a bounding box which contains all points.
*/
final Point ext = new Point(WIDTH, HEIGHT);
formula.transform(ext);
transform = new WarpTransform2D(
new Rectangle(0, 0, WIDTH, HEIGHT), sources, 0,
new Rectangle(0, 0, ext.x, ext.y), dest, 0,
sources.length, degree);
final MathTransform inverse = transform.inverse();
final String wkt = transform.toString();
assertNotNull("WKT formatting test", wkt);
/*
* Checks Warp properties.
*/
final Warp warp = ((WarpTransform2D) transform).getWarp();
assertInstanceOf("Expected a polynomial warp.", WarpPolynomial.class, warp);
final WarpPolynomial poly = (WarpPolynomial) warp;
/*
* Compares transformations to the expected points.
*/
for (int i=0; i<sources.length; i++) {
final String message = formula.message() + " Point #" + i;
final Point source = sources[i];
final Point expected = dest [i];
final Point2D computed = new Point2D.Double(source.x, source.y);
assertSame (message, computed, ((MathTransform2D) transform).transform(computed, computed));
assertEquals(message, expected.x, computed.getX(), tolerance*expected.x);
assertEquals(message, expected.y, computed.getY(), tolerance*expected.y);
//
// Tries using transform(float[], ...)
//
if (true) {
final float[] array = new float[] {source.x, source.y};
transform.transform(array, 0, array, 0, 1);
assertEquals(message, expected.x, array[0], (float) (tolerance*expected.x));
assertEquals(message, expected.y, array[1], (float) (tolerance*expected.y));
}
//
// Tries using transform(double[], ...)
//
if (true) {
final double[] array = new double[] {source.x, source.y};
transform.transform(array, 0, array, 0, 1);
assertEquals(message, expected.x, array[0], tolerance*expected.x);
assertEquals(message, expected.y, array[1], tolerance*expected.y);
}
//
// Tests inverse transform
//
if (degree == 1) {
computed.setLocation(expected.x, expected.y);
assertSame (message, computed, ((MathTransform2D) inverse).transform(computed, computed));
assertEquals(message, source.x, computed.getX(), tolerance*expected.x);
assertEquals(message, source.y, computed.getY(), tolerance*expected.y);
}
}
return poly;
}
/**
* Tests an affine warp.
*
* @throws TransformException Should never happen.
*/
@Test
@Ignore("MathTransformFactory not found for unknown reason. Will be revisited in Apache SIS.")
public void testAffine() throws TransformException {
tolerance = 1E-5;
final int[] scalesX = {1,2,3,4,5,6, 2,7,3,1,8};
final int[] scalesY = {1,2,3,4,5,6, 6,2,5,9,1};
for (int i=0; i<scalesX.length; i++) {
final int scaleX = scalesX[i];
final int scaleY = scalesY[i];
final WarpPolynomial warp = executeTest(new Formula() {
@Override public String message() {
return "WarpAffine[" + scaleX + ',' + scaleY + ']';
}
@Override public void transform(final Point point) {
point.x *= scaleX;
point.y *= scaleY;
}
}, 1);
assertInstanceOf("Expected an affine warp.", WarpAffine.class, warp);
}
}
/**
* Tests a quadratic warp.
*
* @throws TransformException Should never happen.
*/
@Test
@Ignore("MathTransformFactory not found for unknown reason. Will be revisited in Apache SIS.")
public void testQuadratic() throws TransformException {
tolerance = 1E-2;
final int[] scalesX = {1,2,3,4,5,6, 2,7,3,1,8};
final int[] scalesY = {1,2,3,4,5,6, 6,2,5,9,1};
for (int i=0; i<scalesX.length; i++) {
final int scaleX = scalesX[i];
final int scaleY = scalesY[i];
final WarpPolynomial warp = executeTest(new Formula() {
@Override public String message() {
return "WarpQuadratic[" + scaleX + ',' + scaleY + ']';
}
@Override public void transform(final Point point) {
point.x *= scaleX*point.x;
point.y *= scaleY;
}
}, 2);
assertInstanceOf("Expected a quatratic warp.", WarpQuadratic.class, warp);
}
}
}