/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2013-2014, Geomatys
*
* 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.geotoolkit.coverage;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.util.List;
import org.opengis.coverage.Coverage;
import org.opengis.coverage.grid.GridCoverage;
import org.opengis.coverage.grid.GridEnvelope;
import org.opengis.coverage.grid.GridGeometry;
import org.opengis.geometry.Envelope;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.util.GenericName;
import org.apache.sis.geometry.GeneralDirectPosition;
import org.apache.sis.geometry.GeneralEnvelope;
import org.apache.sis.internal.referencing.GeodeticObjectBuilder;
import org.apache.sis.referencing.CommonCRS;
import org.apache.sis.util.Utilities;
import org.geotoolkit.coverage.grid.GridCoverage2D;
import org.geotoolkit.coverage.io.CoverageReader;
import org.geotoolkit.coverage.io.GridCoverageReadParam;
import org.geotoolkit.coverage.io.GridCoverageReader;
import org.geotoolkit.storage.coverage.CoverageStore;
import org.geotoolkit.storage.coverage.GridMosaic;
import org.geotoolkit.storage.coverage.Pyramid;
import org.geotoolkit.storage.coverage.PyramidalCoverageReference;
import org.geotoolkit.util.NamesExt;
import static org.junit.Assert.*;
import org.junit.Test;
/**
* Abstract pyramid store test.
*
* @author Johann Sorel (Geomatys)
* @module
*/
public abstract class PyramidalModelStoreNDTest extends org.geotoolkit.test.TestBase {
private static final double DELTA = 0.00000001;
private static final double corner_long = -180;
private static final double corner_lat = 90;
private static final double[] corner_v = {-15, 46.58};
// store an integer for each tile color, used as R,G,B
// vertical, scale, tile col, tile row
private final int[][][][] colors = new int[2][2][0][0];
private CoverageStore store;
private CoordinateReferenceSystem crs;
private PyramidalCoverageReference ref;
protected abstract CoverageStore createStore() throws Exception ;
private CoverageStore getCoverageStore() throws Exception {
if(store != null){
return store;
}
//create a small pyramid
store = createStore();
final CoordinateReferenceSystem horizontal = CommonCRS.WGS84.normalizedGeographic();
final CoordinateReferenceSystem vertical = CommonCRS.Vertical.ELLIPSOIDAL.crs();
crs = new GeodeticObjectBuilder().addName("3dcrs").createCompoundCRS(horizontal,vertical);
final GenericName name = NamesExt.create("test");
ref = (PyramidalCoverageReference) store.create(name);
//prepare expected colors
int color = 0;
for(int v=0;v<corner_v.length;v++){
colors[v][0] = new int[2][2];
colors[v][1] = new int[4][3];
colors[v][0][0][0] = color++;
colors[v][0][1][0] = color++;
colors[v][0][0][1] = color++;
colors[v][0][1][1] = color++;
colors[v][1][0][0] = color++;
colors[v][1][1][0] = color++;
colors[v][1][2][0] = color++;
colors[v][1][3][0] = color++;
colors[v][1][0][1] = color++;
colors[v][1][1][1] = color++;
colors[v][1][2][1] = color++;
colors[v][1][3][1] = color++;
colors[v][1][0][2] = color++;
colors[v][1][1][2] = color++;
colors[v][1][2][2] = color++;
colors[v][1][3][2] = color++;
}
final Pyramid pyramid = ref.createPyramid(crs);
for(int v=0;v<corner_v.length;v++){
final GridMosaic mosaic_s0 = ref.createMosaic(pyramid.getId(),
new Dimension(2, 2),new Dimension(10, 10) ,
createCorner(corner_long,corner_lat,corner_v[v]),1);
final GridMosaic mosaic_s1 = ref.createMosaic(pyramid.getId(),
new Dimension(4, 3),new Dimension(10, 10) ,
createCorner(corner_long,corner_lat,corner_v[v]),0.5);
//insert tiles
ref.writeTile(pyramid.getId(), mosaic_s0.getId(), 0, 0, createImage(colors[v][0][0][0]));
ref.writeTile(pyramid.getId(), mosaic_s0.getId(), 1, 0, createImage(colors[v][0][1][0]));
ref.writeTile(pyramid.getId(), mosaic_s0.getId(), 0, 1, createImage(colors[v][0][0][1]));
ref.writeTile(pyramid.getId(), mosaic_s0.getId(), 1, 1, createImage(colors[v][0][1][1]));
ref.writeTile(pyramid.getId(), mosaic_s1.getId(), 0, 0, createImage(colors[v][1][0][0]));
ref.writeTile(pyramid.getId(), mosaic_s1.getId(), 1, 0, createImage(colors[v][1][1][0]));
ref.writeTile(pyramid.getId(), mosaic_s1.getId(), 2, 0, createImage(colors[v][1][2][0]));
ref.writeTile(pyramid.getId(), mosaic_s1.getId(), 3, 0, createImage(colors[v][1][3][0]));
ref.writeTile(pyramid.getId(), mosaic_s1.getId(), 0, 1, createImage(colors[v][1][0][1]));
ref.writeTile(pyramid.getId(), mosaic_s1.getId(), 1, 1, createImage(colors[v][1][1][1]));
ref.writeTile(pyramid.getId(), mosaic_s1.getId(), 2, 1, createImage(colors[v][1][2][1]));
ref.writeTile(pyramid.getId(), mosaic_s1.getId(), 3, 1, createImage(colors[v][1][3][1]));
ref.writeTile(pyramid.getId(), mosaic_s1.getId(), 0, 2, createImage(colors[v][1][0][2]));
ref.writeTile(pyramid.getId(), mosaic_s1.getId(), 1, 2, createImage(colors[v][1][1][2]));
ref.writeTile(pyramid.getId(), mosaic_s1.getId(), 2, 2, createImage(colors[v][1][2][2]));
ref.writeTile(pyramid.getId(), mosaic_s1.getId(), 3, 2, createImage(colors[v][1][3][2]));
}
crs = pyramid.getCoordinateReferenceSystem();
return store;
}
private Envelope createEnvelope(double... coords){
final GeneralEnvelope env = new GeneralEnvelope(crs);
for(int i=0;i<coords.length;i+=2){
env.setRange(i/2, coords[i], coords[i+1]);
}
return env;
}
private GeneralDirectPosition createCorner(double... values) {
final GeneralDirectPosition corner = new GeneralDirectPosition(crs);
for (int i = 0; i < values.length; i++) {
corner.setOrdinate(i, values[i]);
}
return corner;
}
private static BufferedImage createImage(int color) {
color = color % 255;
final BufferedImage buffer = new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB);
final Graphics2D g = buffer.createGraphics();
g.setColor(new Color(color, color, color));
g.fillRect(0, 0, buffer.getWidth(), buffer.getHeight());
return buffer;
}
/**
* Read the full image.
* @throws Exception
*/
@Test
public void checkMetaTest() throws Exception{
//load the coverage store
getCoverageStore();
final GridCoverageReader reader = (GridCoverageReader) ref.acquireReader();
//check the image size
final GridGeometry gridGeom = reader.getGridGeometry(ref.getImageIndex());
final GridEnvelope gridEnv = gridGeom.getExtent();
assertEquals( 3, gridEnv.getDimension());
assertEquals( 0, gridEnv.getLow(0));
assertEquals(39, gridEnv.getHigh(0));
assertEquals( 0, gridEnv.getLow(1));
assertEquals(29, gridEnv.getHigh(1));
assertEquals( 0, gridEnv.getLow(2));
assertEquals( 1, gridEnv.getHigh(2));
final Envelope env = ref.getPyramidSet().getEnvelope();
assertEquals(-180, env.getMinimum(0), DELTA);
assertEquals(-180 +(4*10)*0.5, env.getMaximum(0), DELTA);
assertEquals( 90, env.getMaximum(1), DELTA);
assertEquals( 90 -(2*10)*1, env.getMinimum(1), DELTA);
assertEquals(corner_v[0], env.getMinimum(2), DELTA);
assertEquals(corner_v[1], env.getMaximum(2), DELTA);
ref.recycle(reader);
}
/**
* Read with no parameter, we should obtain the most accurate data
*/
@Test
public void readDefaultTest() throws Exception{
getCoverageStore();
final CoverageReader reader = ref.acquireReader();
//we expect a 3D coverage, with all slices
final GridCoverage coverage = (GridCoverage) reader.read(ref.getImageIndex(), null);
final Envelope env = coverage.getEnvelope();
assertTrue(Utilities.equalsIgnoreMetadata(crs, env.getCoordinateReferenceSystem()));
assertEquals(corner_long, env.getMinimum(0), DELTA);//-- -180
assertEquals( 75, env.getMinimum(1), DELTA);
assertEquals( corner_v[0], env.getMinimum(2), DELTA);//-- 15
assertEquals(-160, env.getMaximum(0), DELTA);
assertEquals( corner_lat, env.getMaximum(1), DELTA);//-- -90
assertEquals( 47.58, env.getMaximum(2), DELTA);
assertTrue(coverage instanceof GridCoverageStack);
final GridCoverageStack stack = (GridCoverageStack) coverage;
final List<Coverage> lowerCovs = stack.coveragesAt(-15);
final List<Coverage> upperCovs = stack.coveragesAt(46.58);
assertNotNull(lowerCovs);
assertNotNull(upperCovs);
assertEquals(1, lowerCovs.size());
assertEquals(1, upperCovs.size());
//expecting image from mosaic with min resolution and vertical -15
checkCoverage((GridCoverage2D)lowerCovs.get(0), 40, 30, colors[0][1], corner_long, -160, 75, corner_lat, corner_v[0], -14);
//expecting image from mosaic with min resolution and vertical 46.58
checkCoverage((GridCoverage2D)upperCovs.get(0), 40, 30, colors[1][1], corner_long, -160, 75, corner_lat, corner_v[1], 47.58);
ref.recycle(reader);
}
/**
* Read special scales and dimensions.
*/
@Test
public void readSlicesTest() throws Exception{
getCoverageStore();
final CoverageReader reader = ref.acquireReader();
final GridCoverageReadParam param = new GridCoverageReadParam();
//expecting image from mosaic with min resolution and vertical -15
param.setEnvelope(createEnvelope(corner_long, +180, //-- dim 0 (long)
-90, corner_lat, //-- dim 1 (lat)
corner_v[0], corner_v[0])); //-- dim 2 (vertical)
param.setResolution(0.5,
0.5,
1);
GridCoverage2D coverage = (GridCoverage2D) reader.read(ref.getImageIndex(), param);
checkCoverage(coverage, 40, 30, colors[0][1], corner_long, -160,
75, corner_lat,
corner_v[0], -14); //-- -14 = corner_v[0] - 1 unity.
ref.recycle(reader);
//expecting image from mosaic with max resolution and vertical -15
param.setEnvelope(createEnvelope(corner_long, +180,
-90, corner_lat,
corner_v[0], corner_v[0]));
param.setResolution(1,1,1);
coverage = (GridCoverage2D) reader.read(ref.getImageIndex(), param);
checkCoverage(coverage, 20, 20, colors[0][0], corner_long, -160,
70, corner_lat,
corner_v[0], -14);
ref.recycle(reader);
//expecting image from mosaic with min resolution and vertical 46.58
param.setEnvelope(createEnvelope(corner_long, +180,
-90, corner_lat,
corner_v[1], corner_v[1]));
param.setResolution(0.5,0.5,1);
coverage = (GridCoverage2D) reader.read(ref.getImageIndex(), param);
checkCoverage(coverage, 40, 30, colors[1][1], corner_long, -160,
75, corner_lat,
corner_v[1], 47.58);
ref.recycle(reader);
//expecting image from mosaic with max resolution and vertical 46.58
param.setEnvelope(createEnvelope(corner_long, +180,
-90, corner_lat,
corner_v[1], corner_v[1]));
param.setResolution(1,1,1);
coverage = (GridCoverage2D) reader.read(ref.getImageIndex(), param);
checkCoverage(coverage, 20, 20, colors[1][0], corner_long, -160,
70, corner_lat,
corner_v[1], 47.58);
ref.recycle(reader);
}
/**
*
* @param coverage coverage to test
* @param width expected image width
* @param height expected image height
* @param colors colors to be found in the image
* @param envelope expented envelope
*/
private void checkCoverage(GridCoverage2D coverage, int width, int height, int[][] colors, double... envelope){
assertTrue(Utilities.equalsApproximatively(crs, coverage.getCoordinateReferenceSystem()));
Envelope env = coverage.getEnvelope();
assertEquals(envelope[0], env.getMinimum(0), DELTA);
assertEquals(envelope[1], env.getMaximum(0), DELTA);
assertEquals(envelope[2], env.getMinimum(1), DELTA);
assertEquals(envelope[3], env.getMaximum(1), DELTA);
assertEquals(envelope[4], env.getMinimum(2), DELTA);
assertEquals(envelope[5], env.getMaximum(2), DELTA);
final RenderedImage img = coverage.getRenderedImage();
final Raster raster = img.getData();
assertEquals(width, img.getWidth());
assertEquals(height, img.getHeight());
//we should have a different color each 10pixel
final int[] buffer = new int[4];
for(int x=0;x<img.getWidth()/10;x++){
for(int y=0;y<img.getHeight()/10;y++){
raster.getPixel(x*10+5, y*10+5, buffer);
assertEquals(colors[x][y],buffer[0]);
}
}
}
}