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.coverage;
018:
019: // J2SE and JAI dependencies
020: import java.util.Arrays;
021: import java.util.Random;
022: import javax.media.jai.util.Range;
023:
024: // JUnit dependencies
025: import junit.framework.Test;
026: import junit.framework.TestCase;
027: import junit.framework.TestSuite;
028:
029: // OpenGIS dependencies
030: import org.opengis.referencing.operation.TransformException;
031:
032: // Geotools dependencies
033: import org.geotools.resources.XArray;
034:
035: /**
036: * Test the {@link CategoryList} implementation.
037: *
038: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/coverage/src/test/java/org/geotools/coverage/CategoryListTest.java $
039: * @version $Id: CategoryListTest.java 27848 2007-11-12 13:10:32Z desruisseaux $
040: * @author Martin Desruisseaux
041: */
042: public class CategoryListTest extends TestCase {
043: /**
044: * Set to <code>true</code> in order to print diagnostic messages.
045: */
046: private static final boolean PRINT = false;
047:
048: /**
049: * Small value for comparaisons.
050: */
051: private static final double EPS = 1E-9;
052:
053: /**
054: * Random number generator for this test.
055: */
056: private static final Random random = new Random(
057: 1471753385855374101L);
058:
059: /**
060: * Run the suite from the command line.
061: */
062: public static void main(String[] args) {
063: org.geotools.util.logging.Logging.GEOTOOLS
064: .forceMonolineConsoleOutput();
065: junit.textui.TestRunner.run(suite());
066: }
067:
068: /**
069: * Returns the test suite.
070: */
071: public static Test suite() {
072: return new TestSuite(CategoryListTest.class);
073: }
074:
075: /**
076: * Constructs a test case with the given name.
077: */
078: public CategoryListTest(final String name) {
079: super (name);
080: }
081:
082: /**
083: * Returns the specified value as an hexadecimal string. Usefull
084: * for comparing NaN values.
085: */
086: private static String toHexString(final double value) {
087: return Integer.toHexString(Float
088: .floatToRawIntBits((float) value));
089: }
090:
091: /**
092: * Test the {@link CategoryList#binarySearch} method.
093: */
094: public void testBinarySearch() {
095: for (int pass = 0; pass < 50; pass++) {
096: final double[] array = new double[64];
097: for (int i = 0; i < array.length; i++) {
098: array[i] = (random.nextInt(100) - 50) / 10;
099: }
100: Arrays.sort(array);
101: for (int i = 0; i < 300; i++) {
102: final double searchFor = (random.nextInt(150) - 75) / 10;
103: assertEquals("binarySearch", Arrays.binarySearch(array,
104: searchFor), CategoryList.binarySearch(array,
105: searchFor));
106: }
107: /*
108: * Previous test didn't tested NaN values (which is the main difference
109: * between binarySearch method in Arrays and CategoryList). Now test it.
110: */
111: final Category[] categories = new Category[array.length];
112: for (int i = 0; i < categories.length; i++) {
113: categories[i] = new Category(String.valueOf(i), null,
114: random.nextInt(100)).inverse;
115: }
116: Arrays.sort(categories, new CategoryList(new Category[0],
117: null));
118: assertTrue("isSorted", CategoryList.isSorted(categories));
119: for (int i = 0; i < categories.length; i++) {
120: array[i] = categories[i].inverse.minimum;
121: }
122: for (int i = 0; i < categories.length; i++) {
123: final double expected = categories[i].inverse.minimum;
124: final int foundAt = CategoryList.binarySearch(array,
125: expected);
126: final double actual = categories[foundAt].inverse.minimum;
127: assertEquals("binarySearch", toHexString(expected),
128: toHexString(actual));
129: }
130: }
131: }
132:
133: /**
134: * Test the {@link CategoryList} constructor.
135: */
136: public void testArgumentChecks() {
137: Category[] categories;
138: categories = new Category[] { new Category("No data", null, 0),
139: new Category("Land", null, 10),
140: new Category("Clouds", null, 2),
141: new Category("Land again", null, 10) // Range overlaps.
142: };
143: try {
144: new CategoryList(categories, null);
145: fail("Argument check");
146: } catch (IllegalArgumentException exception) {
147: if (PRINT) {
148: System.out.println(exception.getLocalizedMessage());
149: // This is the expected exception.
150: }
151: }
152: for (int i = 0; i < categories.length; i++) {
153: final Category cat = categories[i];
154: assertSame(cat, cat.geophysics(true).geophysics(false));
155: categories[i] = cat.geophysics(true);
156: }
157: try {
158: new CategoryList(categories, null);
159: fail("Argument check");
160: } catch (IllegalArgumentException exception) {
161: if (PRINT) {
162: System.out.println(exception.getLocalizedMessage());
163: // This is the expected exception.
164: }
165: }
166: // Remove the wrong category. Now, construction should succed.
167: categories = (Category[]) XArray.resize(categories,
168: categories.length - 1);
169: new CategoryList(categories, null);
170: }
171:
172: /**
173: * Test the {@link CategoryList#getCategory} method and a
174: * limited set of {@link CategoryList#transform} calls.
175: */
176: public void testGetCategory() throws TransformException {
177: final Category[] categories = new Category[] {
178: /*[0]*/new Category("No data", null, 0),
179: /*[1]*/new Category("Land", null, 7),
180: /*[2]*/new Category("Clouds", null, 3),
181: /*[3]*/new Category("Temperature", null, 10, 100, 0.1, 5),
182: /*[4]*/new Category("Foo", null, 100, 120, -1, 3) };
183: CategoryList list;
184: boolean searchNearest = false;
185: do {
186: list = new CategoryList(categories, null, searchNearest,
187: null);
188: assertTrue("containsAll", list.containsAll(Arrays
189: .asList(categories)));
190: assertSame(list.geophysics(true), list.inverse());
191: assertSame(list.geophysics(true).geophysics(false), list);
192: assertSame(list.geophysics(false), list);
193:
194: final Range range = list.getRange();
195: assertEquals("min", 0, ((Number) range.getMinValue())
196: .doubleValue(), 0);
197: assertEquals("max", 120, ((Number) range.getMaxValue())
198: .doubleValue(), 0);
199: assertTrue("min included", range.isMinIncluded() == true);
200: assertTrue("max included", range.isMaxIncluded() == false);
201: /*
202: * Check category search.
203: */
204: assertSame("0", list.getCategory(0), categories[0]);
205: assertSame("7", list.getCategory(7), categories[1]);
206: assertSame("3", list.getCategory(3), categories[2]);
207: assertSame(" 10", list.getCategory(10), categories[3]);
208: assertSame(" 50", list.getCategory(50), categories[3]);
209: assertSame("100", list.getCategory(100), categories[4]);
210: assertSame("110", list.getCategory(110), categories[4]);
211: if (searchNearest) {
212: assertSame("-1", list.getCategory(-1), categories[0]); // Nearest sample is 0.
213: assertSame("2", list.getCategory(2), categories[2]); // Nearest sample is 3.
214: assertSame("4", list.getCategory(4), categories[2]); // Nearest sample is 3.
215: assertSame("9", list.getCategory(9), categories[3]); // Nearest sample is 10.
216: assertSame("120", list.getCategory(120), categories[4]); // Nearest sample is 119
217: assertSame("200", list.getCategory(200), categories[4]); // Nearest sample is 119
218: } else {
219: assertNull("-1", list.getCategory(-1));
220: assertNull("2", list.getCategory(2));
221: assertNull("4", list.getCategory(4));
222: assertNull("9", list.getCategory(9));
223: assertNull("120", list.getCategory(120));
224: assertNull("200", list.getCategory(200));
225: }
226: /*
227: * Check transformations.
228: */
229: assertTrue("0", Double.isNaN(list.transform(0)));
230: assertTrue("7", Double.isNaN(list.transform(7)));
231: assertTrue("3", Double.isNaN(list.transform(3)));
232: assertEquals("10", 6, list.transform(10), EPS);
233: assertEquals("50", 10, list.transform(50), EPS);
234: assertEquals("100", -97, list.transform(100), EPS);
235: assertEquals("110", -107, list.transform(110), EPS);
236: try {
237: assertEquals("9", searchNearest ? 6 : 5.9, list
238: .transform(9), EPS);
239: if (!searchNearest) {
240: fail();
241: }
242: } catch (TransformException exception) {
243: if (searchNearest) {
244: throw exception;
245: }
246: }
247: } while ((searchNearest = !searchNearest) == true);
248: /*
249: * Test transformation using methods working on arrays.
250: * We assume that the 'transform(double)' version can
251: * be used as a reference.
252: */
253: final double[] input = new double[512];
254: final double[] output0 = new double[input.length];
255: final double[] output1 = new double[input.length];
256: for (int i = 0; i < input.length; i++) {
257: input[i] = random.nextInt(130) - 5;
258: output0[i] = list.transform(input[i]);
259: }
260: list.transform(input, 0, output1, 0, input.length);
261: compare(output0, output1, EPS);
262: /*
263: * Test the transform using overlapping array.
264: */
265: System.arraycopy(input, 0, output1, 3, input.length - 3);
266: list.transform(output1, 3, output1, 0, input.length - 3);
267: System.arraycopy(output0, input.length - 3, output1,
268: input.length - 3, 3);
269: compare(output0, output1, EPS);
270: // Implementation will do the following transform in reverse direction.
271: System.arraycopy(input, 3, output1, 0, input.length - 3);
272: list.transform(output1, 0, output1, 3, input.length - 3);
273: System.arraycopy(output0, 0, output1, 0, 3);
274: compare(output0, output1, EPS);
275: // Test inverse transform
276: list.inverse()
277: .transform(output0, 0, output0, 0, output0.length);
278: for (int i = 0; i < output0.length; i++) {
279: final double expected = input[i];
280: if (expected >= 10 && expected < 120) {
281: // Values outside this range have been clamped.
282: // They would usually not be equal.
283: assertEquals("inverse", expected, output0[i], EPS);
284: }
285: }
286: }
287:
288: /**
289: * Compare two arrays. Special comparaison is performed for NaN values.
290: */
291: public static void compare(final double[] output0,
292: final double[] output1, final double eps) {
293: assertEquals("length", output0.length, output1.length);
294: for (int i = 0; i < output0.length; i++) {
295: final double expected = output0[i];
296: final double actual = output1[i];
297: final String name = "transform[" + i + ']';
298: if (Double.isNaN(expected)) {
299: final String hex1 = Integer.toHexString(Float
300: .floatToRawIntBits((float) expected));
301: final String hex2 = Integer.toHexString(Float
302: .floatToRawIntBits((float) actual));
303: assertEquals(name, hex1, hex2);
304: continue;
305: }
306: assertEquals(name, expected, actual, eps);
307: }
308: }
309: }
|