/******************************************************************************* * Copyright 2012 Geoscience Australia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package au.gov.ga.earthsci.worldwind.common.layers.model.gdal; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import gov.nasa.worldwind.geom.Position; import gov.nasa.worldwind.util.gdal.GDALUtils; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.List; import org.gdal.gdal.gdalJNI; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.jmock.Expectations; import org.jmock.Mockery; import org.junit.Assume; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import au.gov.ga.earthsci.worldwind.common.layers.Bounds; import au.gov.ga.earthsci.worldwind.common.layers.model.ModelLayer; import au.gov.ga.earthsci.worldwind.common.render.fastshape.FastShape; import au.gov.ga.earthsci.worldwind.test.util.TestUtils; /** * Unit tests for the {@link GDALRasterModelProvider} * * @author James Navin (james.navin@ga.gov.au) */ public class GDALRasterModelProviderTest { private GDALRasterModelProvider classUnderTest; private Mockery mockContext; private ModelLayer modelLayer; private FastShapeMatcher matcher; // Test raster properties (in WGS84 lat/lon) private static final List<RasterProperties> TEST_RASTERS = new ArrayList<RasterProperties>(); static { TEST_RASTERS.add(new RasterProperties() { { { name = "testgrid.tif"; testBand = 1; maxLat = -25.5230437; minLat = -27.6117002; minLon = 141.7329060; maxLon = 144.7855579; xCellSize = 0.040166471522998; yCellSize = -0.040166471522998; width = 76; height = 52; minValue = -2558.0; maxValue = -699.0; } } }); TEST_RASTERS.add(new RasterProperties() { { { name = "testgrid.asc"; testBand = 1; maxLat = 300; minLat = 0; minLon = 0; maxLon = 200; xCellSize = 50.0; yCellSize = 50.0; width = 4; height = 6; minValue = 100; maxValue = 1; } } }); } @BeforeClass public static void init() { // IMPORTANT: This fixes resolution of GDAL path in GDALUtils for the case when // tests are executed from Ant scripts other than Common try { String userdir = new File(System.getProperty("user.dir")).getCanonicalPath(); System.setProperty("user.dir", userdir); } catch (IOException e) { } } @Before public void setup() { classUnderTest = new GDALRasterModelProvider(); mockContext = new Mockery(); modelLayer = mockContext.mock(ModelLayer.class); } @Test public void testConstructWithNull() { classUnderTest = new GDALRasterModelProvider(null); // Expect default parameters GDALRasterModelParameters defaults = new GDALRasterModelParameters(); GDALRasterModelParameters actuals = classUnderTest.getModelParameters(); assertEquals(defaults.getBand(), actuals.getBand()); assertEquals(defaults.getDefaultColor(), actuals.getDefaultColor()); assertEquals(defaults.getColorMap(), actuals.getColorMap()); assertEquals(defaults.getMaxVariance(), actuals.getMaxVariance(), 0.001); } @Test public void testLoadWithNullUrl() { try { classUnderTest.doLoadData(null, modelLayer); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException e) { // pass } } @Test public void testLoadWithNullLayer() { try { URL url = TestUtils.resolveFileURL(getClass().getResource("testgrid.tif")); classUnderTest.doLoadData(url, null); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException e) { // pass } } @Test public void testLoadValidUrl() throws Exception { RasterProperties testRaster = TEST_RASTERS.get(0); URL url = setupTestWithRaster(testRaster); //TODO fix GDAL loading within Eclipse plugin test Assume.assumeTrue(gdalJNI.isAvailable()); Assume.assumeTrue(GDALUtils.canOpen(url)); boolean dataLoaded = classUnderTest.doLoadData(url, modelLayer); FastShape shape = matcher.shape; assertTrue("Data did not load as expected", dataLoaded); assertNotNull("Shape is null", shape); assertTrue("Force sorted primitives is not true", shape.isForceSortedPrimitives()); assertTrue("Shape is not lighted", shape.isLighted()); assertTrue("Two-sided lighting is not enabled", shape.isTwoSidedLighting()); assertTrue(shape.isCalculateNormals()); // With MaxVariance = 0 we expect every pixel to have a corresponding position List<Position> positions = shape.getPositions(); assertNotNull(positions); assertEquals(testRaster.width * testRaster.height, positions.size()); // Colour buffer should have a 4 element entry per-point assertEquals(4, shape.getColorBufferElementSize()); float[] colourBuffer = shape.getColorBuffer(); assertNotNull(colourBuffer); assertEquals(testRaster.width * testRaster.height * 4, colourBuffer.length); // Sector will be sampled from 'bottom-left' corners of cells Bounds bounds = shape.getBounds(); assertNotNull(bounds); assertEquals(testRaster.minLon, bounds.minimum.longitude.degrees, 0.0001); assertEquals(testRaster.maxLon - testRaster.xCellSize, bounds.maximum.longitude.degrees, 0.0001); assertEquals(testRaster.minLat - testRaster.yCellSize, bounds.minimum.latitude.degrees, 0.0001); assertEquals(testRaster.maxLat, bounds.maximum.latitude.degrees, 0.0001); } @Test public void testOffset() { final float scale = 1.0f; final float offset = -100f; doScaleOffsetTest(scale, offset); } @Test public void testScale() { final float scale = 10.0f; final float offset = 0f; doScaleOffsetTest(scale, offset); } @Test public void testScaleWithOffset() { final float scale = 10.0f; final float offset = -100f; doScaleOffsetTest(scale, offset); } private void doScaleOffsetTest(final float scale, final float offset) { RasterProperties testRaster = TEST_RASTERS.get(1); URL url = setupTestWithRaster(testRaster); //TODO fix GDAL loading within Eclipse plugin test Assume.assumeTrue(gdalJNI.isAvailable()); Assume.assumeTrue(GDALUtils.canOpen(url)); GDALRasterModelParameters params = new GDALRasterModelParameters(); params.setCoordinateSystem("EPSG:4326"); params.setOffset((double) offset); params.setScaleFactor((double) scale); classUnderTest = new GDALRasterModelProvider(params); boolean dataLoaded = classUnderTest.doLoadData(url, modelLayer); FastShape shape = matcher.shape; assertTrue("Data did not load as expected", dataLoaded); assertNotNull("Shape is null", shape); // With MaxVariance = 0 we expect every pixel to have a corresponding position List<Position> positions = shape.getPositions(); assertNotNull(positions); assertEquals(testRaster.width * testRaster.height, positions.size()); // Expected behaviour: // - NODATA values will be set to last 'good' value // - Elevation values will be offset by offset amount (-100) float[] raw = { -9999, -9999, 5, 2, 2, 20, 100, 36, 3, 8, 35, 10, 32, 42, 50, 6, 88, 75, 27, 9, 13, 5, 1, 1, }; float[] expected = adjustRawValue(raw, offset, scale); assertElevationsAsExpected(positions, expected, testRaster); } private void assertElevationsAsExpected(List<Position> positions, float[] expected, RasterProperties testRaster) { for (int v = 0; v < testRaster.height; v++) { for (int u = 0; u < testRaster.width; u++) { Position p = positions.get(v * testRaster.width + u); Float e = expected[v * testRaster.width + u]; assertEquals(e, p.elevation, 0.001); } } } private float[] adjustRawValue(float[] raw, float offset, float scale) { float[] result = new float[raw.length]; for (int i = 0; i < result.length; i++) { result[i] = offset + (scale * raw[i]); } return result; } private URL setupTestWithRaster(RasterProperties raster) { URL url = TestUtils.resolveFileURL(getClass().getResource(raster.name)); matcher = new FastShapeMatcher(); mockContext.checking(new Expectations() { { { allowing(modelLayer).addShape(with(matcher)); } } }); return url; } /** A simple properties class that holds raster details for use in tests */ private static class RasterProperties { String name; int testBand = 1; double minLat; double minLon; double maxLat; double maxLon; double xCellSize; double yCellSize; int width; int height; double minValue; double maxValue; } /** * A matcher that accepts any FastShape, and provides access for later * inspection */ private static class FastShapeMatcher extends BaseMatcher<FastShape> { public FastShape shape; @Override public boolean matches(Object item) { this.shape = (FastShape) item; return true; } @Override public void describeTo(Description description) { } } }