/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2005-2008, 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.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.Point2D;
import java.awt.geom.AffineTransform;
import java.util.Random;
import javax.media.jai.Warp;
import javax.media.jai.WarpAffine;
import javax.media.jai.WarpQuadratic;
import javax.media.jai.WarpPolynomial;
import org.opengis.referencing.operation.TransformException;
import org.geotools.resources.Classes;
import org.junit.*;
import static org.junit.Assert.*;
/**
* Tests the {@link WarpTransform2D} and {@link WarpAdapter} classes.
*
* @source $URL$
* @version $Id$
* @author Martin Desruisseaux
*/
public final class WarpTransformTest {
/**
* Width and height of a pseudo-image source image.
*/
private static final int WIDTH=1000, HEIGHT=2000;
/**
* 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).
*/
private static WarpPolynomial executeTest(final Formula formula, final int degree, final float EPS)
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);
final WarpTransform2D 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 WarpTransform2D inverse = (WarpTransform2D) transform.inverse();
assertNotNull("WKT formatting test", transform.toString());
/*
* Checks Warp properties.
*/
final Warp warp = transform.getWarp();
assertTrue("Expected a polynomial warp but got " + Classes.getShortClassName(warp),
warp instanceof WarpPolynomial);
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, transform.transform(computed, computed));
assertEquals(message, expected.x, computed.getX(), EPS*expected.x);
assertEquals(message, expected.y, computed.getY(), EPS*expected.y);
//
// Try 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], EPS*expected.x);
assertEquals(message, expected.y, array[1], EPS*expected.y);
}
//
// Try 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], EPS*expected.x);
assertEquals(message, expected.y, array[1], EPS*expected.y);
}
//
// Tests inverse transform
//
if (degree == 1) {
computed.setLocation(expected.x, expected.y);
assertSame (message, computed, inverse.transform(computed, computed));
assertEquals(message, source.x, computed.getX(), EPS*expected.x);
assertEquals(message, source.y, computed.getY(), EPS*expected.y);
}
}
return poly;
}
/**
* Tests an affine warp.
*/
@Test
public void testAffine() throws TransformException {
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() {
public String message() {
return "WarpAffine[" + scaleX + ',' + scaleY + ']';
}
public void transform(final Point point) {
point.x *= scaleX;
point.y *= scaleY;
}
}, 1, 1E-5f);
assertTrue("Expected an affine warp but got " + Classes.getShortClassName(warp),
warp instanceof WarpAffine);
}
}
/**
* Tests a quadratic warp.
*/
@Test
public void testQuadratic() throws TransformException {
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() {
public String message() {
return "WarpQuadratic[" + scaleX + ',' + scaleY + ']';
}
public void transform(final Point point) {
point.x *= scaleX*point.x;
point.y *= scaleY;
}
}, 2, 1E-2f);
assertTrue("Expected a quatratic warp but got " + Classes.getShortClassName(warp),
warp instanceof WarpQuadratic);
}
}
/**
* Tests the {@link WarpAdapter} class using an affine transform.
*/
@Test
public void testAdapter() {
final AffineTransform atr = AffineTransform.getScaleInstance(0.25, 0.5);
atr.translate(4, 2);
final AffineTransform2D transform = new AffineTransform2D(atr);
final WarpAffine warp = new WarpAffine (atr);
final WarpAdapter adapter = new WarpAdapter("test", transform);
final Random random = new Random(-854734760285695284L);
for (int i=0; i<200; i++) {
Point2D source = new Point2D.Double(random.nextDouble()*100, random.nextDouble()*100);
Point2D expected = warp .mapDestPoint(source);
Point2D computed = adapter.mapDestPoint(source);
assertEquals("X", expected.getX(), computed.getX(), 1E-5);
assertEquals("Y", expected.getY(), computed.getY(), 1E-5);
// Try inverse transform.
expected = warp .mapSourcePoint(source);
computed = adapter.mapSourcePoint(source);
assertEquals("X", expected.getX(), computed.getX(), 1E-5);
assertEquals("Y", expected.getY(), computed.getY(), 1E-5);
// Try warpPoint
final float[] exp = warp .warpPoint((int)source.getX(), (int)source.getY(), null);
final float[] com = adapter.warpPoint((int)source.getX(), (int)source.getY(), null);
assertEquals("X", exp[0], com[0], 1E-5);
assertEquals("Y", exp[1], com[1], 1E-5);
}
}
}