/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2011, 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.process.raster.gs;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.LineString;
import org.geotools.coverage.CoverageFactoryFinder;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridCoverageFactory;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.opengis.feature.simple.SimpleFeature;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Unit tests for ContourProcess.
*
* @author Michael Bedward
* @since 8.0
*
* @source $URL$
* @version $Id$
*/
public class ContourProcessTest {
private static final double TOL = 1.0e-6;
private static final GridCoverageFactory covFactory = CoverageFactoryFinder.getGridCoverageFactory(null);
private ContourProcess process;
@Before
public void setup() {
process = new ContourProcess();
}
/**
* Creates a coverage with just two rows where values are constant within rows
* and differ between rows, then checks for correctly generated single contour
* between rows.
*/
@Test
public void singleContourInVerticalGradient() {
final int COVERAGE_COLS = 10;
final int COVERAGE_ROWS = 2;
final double CELL_SIZE = 100;
final ReferencedEnvelope WORLD = new ReferencedEnvelope(
1000, 1000 + COVERAGE_COLS * CELL_SIZE,
5000, 5000 + COVERAGE_ROWS * CELL_SIZE, null);
final float DATA_MIN = 100;
final float DATA_MAX = 200;
GridCoverage2D cov = createVerticalGradient(
COVERAGE_ROWS, COVERAGE_COLS, WORLD, DATA_MIN, DATA_MAX);
final double levelValue = (DATA_MIN + DATA_MAX) / 2;
SimpleFeatureCollection fc = process.execute(
cov, 0, new double[] {levelValue}, null, null, null, null, null);
// Should be a single contour
assertEquals(1, fc.size());
SimpleFeatureIterator iter = fc.features();
SimpleFeature feature = null;
try {
feature = iter.next();
} finally {
iter.close();
}
// Check contour value
Double value = (Double) feature.getAttribute("value");
assertEquals(levelValue, value, TOL);
LineString contour = (LineString) feature.getDefaultGeometry();
Coordinate[] coords = contour.getCoordinates();
// Contour should have had co-linear vertices removed by default
assertEquals(2, coords.length);
// Contour end-point X ordinates should be within half cell-width of
// coverage X extrema
double minX = Math.min(coords[0].x, coords[1].x);
assertEquals(WORLD.getMinX(), minX, CELL_SIZE / 2 + TOL);
double maxX = Math.max(coords[0].x, coords[1].x);
assertEquals(WORLD.getMaxX(), maxX, CELL_SIZE / 2 + TOL);
// Contour Y ordinate should be at mid-Y of coverage and
// contour should be horizontal
double expectedY = (WORLD.getMinY() + WORLD.getMaxY()) / 2;
assertEquals(expectedY, coords[0].y, TOL);
assertEquals(expectedY, coords[1].y, TOL);
}
/**
* Tests that the process doesn't blow up when there are no
* contours to return
*/
@Test
public void noContours() {
// Coverage with values in range [0, 10]
GridCoverage2D cov = createVerticalGradient(10, 10, null, 0, 10);
// Run process asking for contours at level = 20
SimpleFeatureCollection fc = process.execute(cov, 0, new double[20], null, null, null, null, null);
assertNotNull(fc);
assertTrue(fc.isEmpty());
}
private GridCoverage2D createVerticalGradient(
final int dataRows, final int dataCols,
ReferencedEnvelope worldEnv,
final float startValue, final float endValue) {
if (dataRows < 2) {
throw new IllegalArgumentException("dataRows must be >= 2");
}
if (dataCols < 1) {
throw new IllegalArgumentException("dataCols must be positive");
}
if (worldEnv == null) {
worldEnv = new ReferencedEnvelope(0, dataCols, 0, dataRows, null);
}
float[][] DATA = new float[dataRows][dataCols];
float delta = (endValue - startValue) / (dataRows - 1);
for (int iy = 0; iy < dataRows; iy++) {
float value = startValue + iy * delta;
for (int ix = 0; ix < dataCols; ix++) {
DATA[iy][ix] = value;
}
value += delta;
}
return covFactory.create("coverage", DATA, worldEnv);
}
}