/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2002-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.coverage;
import java.awt.image.RenderedImage;
import java.awt.geom.AffineTransform;
import javax.media.jai.iterator.RectIter;
import javax.media.jai.iterator.RectIterFactory;
import org.opengis.geometry.Envelope;
import org.opengis.coverage.Coverage;
import org.opengis.coverage.grid.GridCoverage;
import org.opengis.coverage.grid.GridGeometry;
import org.opengis.referencing.operation.MathTransform;
import org.geotools.test.TestData;
import org.geotools.geometry.GeneralEnvelope;
import org.geotools.coverage.grid.Viewer;
import org.geotools.coverage.grid.ViewType;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.referencing.operation.matrix.XAffineTransform;
import static org.junit.Assert.*;
/**
* Base class for tests on {@link AbstractCoverage} subclasses.
*
* @source $URL$
* @version $Id$
* @author Martin Desruisseaux (IRD)
*/
public class CoverageTestBase {
/**
* {@code true} if the result of coverage operations should be displayed.
* This is sometime useful for debugging purpose.
*/
protected static boolean SHOW = TestData.isInteractiveTest();
/**
* Small value for comparaison of sample values. Since most grid coverage implementations in
* Geotools 2 store geophysics values as {@code float} numbers, this {@code EPS} value must
* be of the order of {@code float} relative precision, not {@code double}.
*/
protected static final float EPS = 1E-5f;
/**
* Returns the "Sample to geophysics" transform as an affine transform, or {@code null}
* if none. Note that the returned instance may be an immutable one, not necessarly the
* default Java2D implementation.
*
* @param coverage The coverage for which to get the "grid to CRS" affine transform.
* @return The "grid to CRS" affine transform of the given coverage, or {@code null}
* if none or if the transform is not affine.
*/
protected static AffineTransform getAffineTransform(final Coverage coverage) {
if (coverage instanceof GridCoverage) {
final GridGeometry geometry = ((GridCoverage) coverage).getGridGeometry();
if (geometry != null) {
final MathTransform gridToCRS;
if (geometry instanceof GridGeometry2D) {
gridToCRS = ((GridGeometry2D) geometry).getGridToCRS();
} else {
gridToCRS = geometry.getGridToCRS();
}
if (gridToCRS instanceof AffineTransform) {
return (AffineTransform) gridToCRS;
}
}
}
return null;
}
/**
* Returns the scale of the "grid to CRS" transform, or {@link Double#NaN} if unknown.
*
* @param coverage The coverage for which to get the "grid to CRS" scale, or {@code null}.
* @return The "grid to CRS" scale, or {@code NaN} if none or if the transform is not affine.
*/
protected static double getScale(final Coverage coverage) {
final AffineTransform gridToCRS = getAffineTransform(coverage);
return (gridToCRS != null) ? XAffineTransform.getScale(gridToCRS) : Double.NaN;
}
/**
* Returns the envelope of the given coverage as a {@link GeneralEnvelope} implementation.
*
* @param coverage The coverage for which to get the envelope.
* @return The envelope of the given coverage (never {@code null}).
*/
protected static GeneralEnvelope getGeneralEnvelope(final Coverage coverage) {
final Envelope envelope = coverage.getEnvelope();
assertNotNull(envelope);
assertEquals(coverage.getCoordinateReferenceSystem(),
envelope.getCoordinateReferenceSystem());
if (coverage instanceof GeneralEnvelope) {
return (GeneralEnvelope) envelope;
} else {
return new GeneralEnvelope(envelope);
}
}
/**
* Compares the envelopes of two coverages for equality using the smallest
* scale factor of their "grid to world" transform as the tolerance.
*
* @param expected The coverage having the expected envelope.
* @param actual The coverage having the actual envelope.
*/
protected static void assertEnvelopeEquals(Coverage expected, Coverage actual) {
final double scaleA = getScale(expected);
final double scaleB = getScale(actual);
final double tolerance;
if (scaleA <= scaleB) {
tolerance = scaleA;
} else if (!Double.isNaN(scaleB)) {
tolerance = scaleB;
} else {
tolerance = EPS;
}
assertTrue(getGeneralEnvelope(expected).equals(actual.getEnvelope(), tolerance, false));
}
/**
* Compares two affine transforms for equality.
*
* @param expected The expected affine transform.
* @param actual The actual affine transform.
*/
protected static void assertTransformEquals(AffineTransform expected, AffineTransform actual) {
assertEquals("scaleX", expected.getScaleX(), actual.getScaleX(), EPS);
assertEquals("scaleY", expected.getScaleY(), actual.getScaleY(), EPS);
assertEquals("shearX", expected.getShearX(), actual.getShearX(), EPS);
assertEquals("shearY", expected.getShearY(), actual.getShearY(), EPS);
assertEquals("translateX", expected.getTranslateX(), actual.getTranslateX(), EPS);
assertEquals("translateY", expected.getTranslateY(), actual.getTranslateY(), EPS);
}
/**
* Compares the rendered view of two coverages for equality.
*
* @param expected The coverage containing the expected pixel values.
* @param actual The coverage containing the actual pixel values.
*/
protected static void assertRasterEquals(final Coverage expected, final Coverage actual) {
assertRasterEquals(expected.getRenderableImage(0,1).createDefaultRendering(),
actual.getRenderableImage(0,1).createDefaultRendering());
}
/**
* Compares two rasters for equality.
*
* @param expected The image containing the expected pixel values.
* @param actual The image containing the actual pixel values.
*/
protected static void assertRasterEquals(final RenderedImage expected, final RenderedImage actual) {
final RectIter e = RectIterFactory.create(expected, null);
final RectIter a = RectIterFactory.create(actual, null);
if (!e.finishedLines()) do {
assertFalse(a.finishedLines());
if (!e.finishedPixels()) do {
assertFalse(a.finishedPixels());
if (!e.finishedBands()) do {
assertFalse(a.finishedBands());
final float pe = e.getSampleFloat();
final float pa = a.getSampleFloat();
assertEquals(pe, pa, EPS);
a.nextBand();
} while (!e.nextBandDone());
assertTrue(a.finishedBands());
a.nextPixel();
a.startBands();
e.startBands();
} while (!e.nextPixelDone());
assertTrue(a.finishedPixels());
a.nextLine();
a.startPixels();
e.startPixels();
} while (!e.nextLineDone());
assertTrue(a.finishedLines());
}
/**
* Show the default rendering of the specified coverage.
* This is used for debugging only.
*
* @param coverage The coverage to display.
*/
protected static void show(Coverage coverage) {
if (coverage instanceof GridCoverage2D) {
coverage = ((GridCoverage2D) coverage).view(ViewType.PACKED);
}
final RenderedImage image = coverage.getRenderableImage(0,1).createDefaultRendering();
try {
Class.forName("org.geotools.gui.swing.OperationTreeBrowser")
.getMethod("show", new Class[]{RenderedImage.class})
.invoke(null, new Object[]{image});
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
/*
* The OperationTreeBrowser is not part of Geotools's core. It is optional and this
* class should not fails if it is not presents. This is only a helper for debugging.
*/
if (coverage instanceof GridCoverage2D) {
Viewer.show((GridCoverage2D) coverage);
} else {
Viewer.show(image);
}
}
}
}