001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2003-2006, Geotools Project Managment Committee (PMC)
005: * (C) 2002, Institut de Recherche pour le Développement
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: */
017: package org.geotools.referencing.operation.transform;
018:
019: // J2SE dependencies
020: import java.util.Random;
021:
022: // JUnit dependencies
023: import junit.framework.Test;
024: import junit.framework.TestCase;
025: import junit.framework.TestSuite;
026:
027: // OpenGIS dependencies
028: import org.opengis.referencing.operation.TransformException;
029:
030: /**
031: * Test the {@link LocalizationGrid} implementation.
032: *
033: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/test/java/org/geotools/referencing/operation/transform/LocalizationGridTest.java $
034: * @version $Id: LocalizationGridTest.java 27848 2007-11-12 13:10:32Z desruisseaux $
035: * @author Remi Eve
036: * @author Martin Desruisseaux
037: */
038: public final class LocalizationGridTest extends TestCase {
039: /**
040: * Random number generator for this test.
041: */
042: private static final Random random = new Random(78421369762L);
043:
044: /**
045: * The grid of localization to test.
046: */
047: private LocalizationGrid grid;
048:
049: /**
050: * The "real world" coordinates of the image.
051: */
052: private static final double[][] GRID_DATA = {
053: { 74.273440, -37.882812, /* First line. */
054: 72.695310, -38.375000, 71.382810, -38.765625, 70.250000,
055: -39.085938, 69.257810, -39.359375, 68.375000,
056: -39.585938 },
057: { 74.273440, -37.875000, /* Second line. */
058: 72.695310, -38.367188, 71.375000, -38.757812, 70.250000,
059: -39.078125, 69.257810, -39.343750, 68.367190,
060: -39.578125 },
061: { 74.265625, -37.867188, /* third line. */
062: 72.687500, -38.359375, 71.375000, -38.750000, 70.242190,
063: -39.070312, 69.250000, -39.335938, 68.367190,
064: -39.570312 },
065: { 74.257810, -37.859375, /* fourth line. */
066: 72.687500, -38.351562, 71.367190, -38.742188, 70.234375,
067: -39.062500, 69.242190, -39.328125, 68.359375,
068: -39.562500 },
069: { 74.257810, -37.851562, /* fifth line. */
070: 72.679690, -38.343750, 71.359375, -38.734375, 70.234375,
071: -39.054688, 69.242190, -39.320312, 68.359375,
072: -39.546875 },
073: { 74.250000, -37.843750, /* sixth line. */
074: 72.671875, -38.335938, 71.359375, -38.726562, 70.226560,
075: -39.039062, 69.234375, -39.312500, 68.351560,
076: -39.539062 } };
077:
078: /**
079: * Maximal error between expected "real world" and computed "real world"
080: * coordinates when direct transformation is used.
081: */
082: private static final double EPS = 1E-9;
083:
084: /**
085: * Maximal error between expected "real world" and computed "real world"
086: * coordinates when the fitted affine transformation is used.
087: */
088: private static final double FIT_TOLERANCE = 0.4;
089:
090: /**
091: * Run the suite from the command line.
092: */
093: public static void main(final String[] args) {
094: org.geotools.util.logging.Logging.GEOTOOLS
095: .forceMonolineConsoleOutput();
096: junit.textui.TestRunner.run(suite());
097: }
098:
099: /**
100: * Returns the test suite.
101: */
102: public static Test suite() {
103: return new TestSuite(LocalizationGridTest.class);
104: }
105:
106: /**
107: * Constructs a test case with the given name.
108: */
109: public LocalizationGridTest(final String name) {
110: super (name);
111: }
112:
113: /**
114: * Set up common objects used for all tests.
115: * This implementation construct a default localization grid.
116: */
117: protected void setUp() throws Exception {
118: super .setUp();
119: final int width = GRID_DATA[0].length / 2;
120: final int height = GRID_DATA.length;
121: grid = new LocalizationGrid(width, height);
122: for (int j = 0; j < height; j++) {
123: final double[] line = GRID_DATA[j];
124: assertEquals("Grid is not square", width * 2, line.length);
125: int offset = 0;
126: for (int i = 0; i < width; i++) {
127: grid.setLocalizationPoint(i, j, line[offset++],
128: line[offset++]);
129: }
130: }
131: }
132:
133: /**
134: * Test some grid properties.
135: */
136: public void testProperties() {
137: assertTrue(grid.isMonotonic(false));
138: assertTrue(!grid.isMonotonic(true));
139: assertTrue(!grid.isNaN());
140: }
141:
142: /**
143: * Returns an array with grid or "real world" coordinates.
144: *
145: * @param real <code>true</code> to gets the "real world" coordinates,
146: * or <code>false</code> to gets the grid coordinates.
147: */
148: private double[] getGridCoordinates(final boolean real) {
149: final int width = GRID_DATA[0].length / 2;
150: final int height = GRID_DATA.length;
151: final double[] array = new double[width * height * 2];
152: int offset = 0;
153: for (int j = 0; j < height; j++) {
154: final double[] line = GRID_DATA[j];
155: assertEquals("Grid is not square", width * 2, line.length);
156: for (int i = 0; i < width; i++) {
157: array[offset++] = (real) ? line[i * 2 + 0] : i;
158: array[offset++] = (real) ? line[i * 2 + 1] : j;
159: }
160: }
161: assertEquals("Grid is not square", width * height * 2, offset);
162: return array;
163: }
164:
165: /**
166: * Compare a transformed array with the expected grid or "real world" coordinates.
167: *
168: * @param array The array to compare.
169: * @param real <code>true</code> to compare with the "real world" coordinates,
170: * or <code>false</code> to compare with the grid coordinates.
171: * @param eps The maximal error accepted in comparaisons.
172: */
173: private void compare(final double[] array, final boolean real,
174: final double eps) {
175: final int width = GRID_DATA[0].length / 2;
176: final int height = GRID_DATA.length;
177: int offset = 0;
178: for (int j = 0; j < height; j++) {
179: final double[] line = GRID_DATA[j];
180: assertEquals("Grid is not square", width * 2, line.length);
181: for (int i = 0; i < width; i++) {
182: assertEquals(real ? line[i * 2 + 0] : i,
183: array[offset++], eps);
184: assertEquals(real ? line[i * 2 + 1] : j,
185: array[offset++], eps);
186: }
187: }
188: assertEquals("Grid is not square", width * height * 2, offset);
189: }
190:
191: /**
192: * Test direct transformation from grid coordinates to "real world"
193: * coordinates using the localization grid.
194: */
195: public void testDirectTransform() throws TransformException {
196: final double[] array = getGridCoordinates(false);
197: grid.getMathTransform().transform(array, 0, array, 0,
198: array.length / 2);
199: compare(array, true, EPS);
200: }
201:
202: /**
203: * Test affine tranformation for the whole grid by comparing the
204: * expected "real world" to the approximated coordinates. Since
205: * the affine transform is fitted using least-squares method, the
206: * transformation is approximative.
207: */
208: public void testAffineTransform() {
209: final double[] array = getGridCoordinates(false);
210: grid.getAffineTransform().transform(array, 0, array, 0,
211: array.length / 2);
212: compare(array, true, FIT_TOLERANCE);
213: }
214:
215: /**
216: * Test inverse transformation from "real world" coordinates
217: * to grid coordinates coordinate using the localization grid.
218: */
219: public void testInverseTransform() throws TransformException {
220: final double[] array = getGridCoordinates(true);
221: grid.getMathTransform().inverse().transform(array, 0, array, 0,
222: array.length / 2);
223: compare(array, false, EPS);
224: }
225:
226: /**
227: * Test some mathematical identities used if {@link LocalizationGrid#fitPlane}.
228: */
229: public void testMathematicalIdentities() {
230: int sum_x = 0;
231: int sum_y = 0;
232: int sum_xx = 0;
233: int sum_yy = 0;
234: int sum_xy = 0;
235:
236: final int width = random.nextInt(100) + 5;
237: final int height = random.nextInt(100) + 5;
238: for (int y = 0; y < height; y++) {
239: for (int x = 0; x < width; x++) {
240: sum_x += x;
241: sum_y += y;
242: sum_xx += x * x;
243: sum_yy += y * y;
244: sum_xy += x * y;
245: }
246: }
247: final int n = width * height;
248: assertEquals("sum_x", (n * (width - 1)) / 2, sum_x);
249: assertEquals("sum_y", (n * (height - 1)) / 2, sum_y);
250: assertEquals("sum_xy", (n * (width - 1) * (height - 1)) / 4,
251: sum_xy);
252: assertEquals("sum_xx", (n * (width - 0.5) * (width - 1)) / 3,
253: sum_xx, 1E-6);
254: assertEquals("sum_yy", (n * (height - 0.5) * (height - 1)) / 3,
255: sum_yy, 1E-6);
256: }
257: }
|