/* * Geotoolkit.org - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 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.processing.coverage.mathcalc; import java.awt.Dimension; import java.awt.image.BufferedImage; import java.awt.image.DataBuffer; import java.awt.image.Raster; import java.awt.image.RenderedImage; import java.awt.image.WritableRaster; import java.util.*; import org.apache.sis.geometry.GeneralDirectPosition; import org.apache.sis.internal.referencing.GeodeticObjectBuilder; import org.apache.sis.referencing.CommonCRS; import org.apache.sis.storage.DataStoreException; import org.geotoolkit.storage.coverage.CoverageStore; import org.geotoolkit.coverage.GridCoverageStack; import org.geotoolkit.storage.coverage.GridMosaic; import org.geotoolkit.coverage.GridSampleDimension; import org.geotoolkit.storage.coverage.Pyramid; import org.geotoolkit.storage.coverage.PyramidalCoverageReference; import org.geotoolkit.coverage.grid.GridCoverage2D; import org.geotoolkit.coverage.grid.GridCoverageBuilder; import org.geotoolkit.coverage.grid.ViewType; import org.geotoolkit.coverage.io.GridCoverageReader; import org.geotoolkit.coverage.memory.MPCoverageStore; import org.geotoolkit.util.NamesExt; import org.opengis.util.GenericName; import org.apache.sis.geometry.GeneralEnvelope; import org.geotoolkit.image.BufferedImages; import org.junit.Assert; import org.junit.Test; import org.opengis.coverage.Coverage; import org.opengis.coverage.grid.GridCoverage; import org.opengis.geometry.Envelope; import org.opengis.referencing.crs.CoordinateReferenceSystem; /** * * @author Johann Sorel (Geomatys) */ public class MathCalcTest extends org.geotoolkit.test.TestBase { private static final float DELTA = 0.000000001f; /** * This test is expected to copy values from one coverage to the other. */ @Test public void passthroughtTest() throws Exception{ final int width = 512; final int height = 300; final CoordinateReferenceSystem crs = CommonCRS.WGS84.defaultGeographic(); final GeneralEnvelope env = new GeneralEnvelope(crs); env.setRange(0, 0, 51.2); env.setRange(1, 0, 30.0); //create base coverage final GridCoverage2D baseCoverage = createCoverage2D(env, width, height, 15.5f, -3.0f); //create output coverage ref final GenericName n = NamesExt.create("test"); final MPCoverageStore store = new MPCoverageStore(); final PyramidalCoverageReference outRef = (PyramidalCoverageReference) store.create(n); outRef.setPackMode(ViewType.GEOPHYSICS); outRef.setSampleDimensions(Collections.singletonList(new GridSampleDimension("data"))); outRef.setSampleModel(baseCoverage.getRenderedImage().getSampleModel()); outRef.setColorModel(baseCoverage.getRenderedImage().getColorModel()); final Pyramid pyramid = outRef.createPyramid(crs); final GeneralDirectPosition corner = new GeneralDirectPosition(crs); corner.setCoordinate(env.getMinimum(0), env.getMaximum(1)); outRef.createMosaic(pyramid.getId(), new Dimension(1, 1), new Dimension(width, height), corner, 0.1); //run math calc process final MathCalcProcess process = new MathCalcProcess( new Coverage[]{baseCoverage}, "A", new String[]{"A"}, outRef); process.call(); final GridCoverageReader reader = outRef.acquireReader(); final GridCoverage2D result = (GridCoverage2D)reader.read(0, null); outRef.recycle(reader); final Raster resultRaster = result.getRenderedImage().getData(); for(int x=0;x<width;x++){ for(int y=0;y<height;y++){ float v = resultRaster.getSampleFloat(x, y, 0); Assert.assertEquals("at ("+x+" "+y+")", (y<height/2) ? 15.5f : -3.0f, v, DELTA); } } } /** * This test is expected to copy values with and addition from one coverage to the other. */ @Test public void incrementTest() throws Exception{ final int width = 512; final int height = 300; final CoordinateReferenceSystem crs = CommonCRS.WGS84.defaultGeographic(); final GeneralEnvelope env = new GeneralEnvelope(crs); env.setRange(0, 0, 51.2); env.setRange(1, 0, 30.0); //create base coverage final GridCoverage2D baseCoverage = createCoverage2D(env, width, height, 15.5f, -2.0f); //create output coverage ref final GenericName n = NamesExt.create("test"); final MPCoverageStore store = new MPCoverageStore(); final PyramidalCoverageReference outRef = (PyramidalCoverageReference) store.create(n); outRef.setPackMode(ViewType.GEOPHYSICS); outRef.setSampleDimensions(Collections.singletonList(new GridSampleDimension("data"))); outRef.setSampleModel(baseCoverage.getRenderedImage().getSampleModel()); outRef.setColorModel(baseCoverage.getRenderedImage().getColorModel()); final Pyramid pyramid = outRef.createPyramid(crs); final GeneralDirectPosition corner = new GeneralDirectPosition(crs); corner.setCoordinate(env.getMinimum(0), env.getMaximum(1)); outRef.createMosaic(pyramid.getId(), new Dimension(1, 1), new Dimension(width, height), corner, 0.1); //run math calc process final MathCalcProcess process = new MathCalcProcess( new Coverage[]{baseCoverage}, "A+10", new String[]{"A"}, outRef); process.call(); final GridCoverageReader reader = outRef.acquireReader(); final GridCoverage2D result = (GridCoverage2D)reader.read(0, null); outRef.recycle(reader); final Raster resultRaster = result.getRenderedImage().getData(); for(int x=0;x<width;x++){ for(int y=0;y<height;y++){ float v = resultRaster.getSampleFloat(x, y, 0); Assert.assertEquals( (y<height/2) ? 25.5f : 8.0f, v, DELTA); } } } /** * This test is expected to copy values with and addition from one coverage to the other. */ @Test public void expression2CoverageTest() throws Exception{ final int width = 512; final int height = 300; final CoordinateReferenceSystem crs = CommonCRS.WGS84.defaultGeographic(); final GeneralEnvelope env = new GeneralEnvelope(crs); env.setRange(0, 0, 51.2); env.setRange(1, 0, 30.0); //create base coverage final GridCoverage2D baseCoverage1 = createCoverage2D(env, width, height, 15.5f, 3.0f); final GridCoverage2D baseCoverage2 = createCoverage2D(env, width, height, -9.0f, 20.0f); //create output coverage ref final GenericName n = NamesExt.create("test"); final MPCoverageStore store = new MPCoverageStore(); final PyramidalCoverageReference outRef = (PyramidalCoverageReference) store.create(n); outRef.setPackMode(ViewType.GEOPHYSICS); outRef.setSampleDimensions(Collections.singletonList(new GridSampleDimension("data"))); outRef.setSampleModel(baseCoverage1.getRenderedImage().getSampleModel()); outRef.setColorModel(baseCoverage1.getRenderedImage().getColorModel()); final Pyramid pyramid = outRef.createPyramid(crs); final GeneralDirectPosition corner = new GeneralDirectPosition(crs); corner.setCoordinate(env.getMinimum(0), env.getMaximum(1)); outRef.createMosaic(pyramid.getId(), new Dimension(1, 1), new Dimension(width, height), corner, 0.1); //run math calc process final MathCalcProcess process = new MathCalcProcess( new Coverage[]{baseCoverage1, baseCoverage2}, "(A+B)*5", new String[]{"A","B"}, outRef); process.call(); final GridCoverageReader reader = outRef.acquireReader(); final GridCoverage2D result = (GridCoverage2D)reader.read(0, null); outRef.recycle(reader); final Raster resultRaster = result.getRenderedImage().getData(); for(int x=0;x<width;x++){ for(int y=0;y<height;y++){ float v = resultRaster.getSampleFloat(x, y, 0); Assert.assertEquals( (y<height/2) ? 32.5f : 115.0f, v, DELTA); } } } /** * 4D calc test * @throws Exception */ @Test public void coverage4DTest() throws Exception{ //create a small pyramid final CoverageStore store = new MPCoverageStore(); final CoordinateReferenceSystem horizontal = CommonCRS.defaultGeographic(); final CoordinateReferenceSystem vertical = CommonCRS.Vertical.ELLIPSOIDAL.crs(); final CoordinateReferenceSystem temporal = CommonCRS.Temporal.JAVA.crs(); Map<String, Object> props = new HashMap<>(); props.put("name", "4dcrs"); final CoordinateReferenceSystem crs = new GeodeticObjectBuilder().addName("4dcrs") .createCompoundCRS(horizontal, vertical, temporal); final int width = 28; final int height = 13; final PyramidalCoverageReference ref1 = (PyramidalCoverageReference) store.create(NamesExt.create("test1")); create4DPyramid(ref1, crs, width, height, new double[][]{ {-5,-9, 12}, {-5, 0, -7}, {-5,21, 51}, {62,-9, -3}, {62, 0, 5}, {62,21, 17}, }); final PyramidalCoverageReference ref2 = (PyramidalCoverageReference) store.create(NamesExt.create("test2")); create4DPyramid(ref2, crs, width, height, new double[][]{ {-5,-9, -4}, {-5, 0, 32}, {-5,21, 90}, {62,-9, -87}, {62, 0, -6}, {62,21, 41}, }); final PyramidalCoverageReference outRef = (PyramidalCoverageReference) store.create(NamesExt.create("result")); create4DPyramid(outRef, crs, width, height, new double[][]{ {-5,-9, 0}, {-5, 0, 0}, {-5,21, 0}, {62,-9, 0}, {62, 0, 0}, {62,21, 0}, }); //create base coverage final GridCoverageReader reader1 = ref1.acquireReader(); final GridCoverageReader reader2 = ref2.acquireReader(); final GridCoverage baseCoverage1 = reader1.read(0, null); final GridCoverage baseCoverage2 = reader2.read(0, null); ref1.recycle(reader1); ref2.recycle(reader2); outRef.setSampleModel(createRenderedImage(1,1,0,0).getSampleModel()); outRef.setColorModel(createRenderedImage(1,1,0,0).getColorModel()); //run math calc process final MathCalcProcess process = new MathCalcProcess( new Coverage[]{baseCoverage1, baseCoverage2}, "(A+B)*5", new String[]{"A","B"}, outRef); process.call(); final GridCoverageReader outReader = outRef.acquireReader(); final GridCoverage result = outReader.read(0, null); outRef.recycle(outReader); Assert.assertTrue(result instanceof GridCoverageStack); final GridCoverageStack stackT = (GridCoverageStack) result; final GridCoverageStack stackT0 = (GridCoverageStack) stackT.coveragesAt(-9).get(0); final GridCoverageStack stackT1 = (GridCoverageStack) stackT.coveragesAt( 0).get(0); final GridCoverageStack stackT2 = (GridCoverageStack) stackT.coveragesAt(21).get(0); final GridCoverage2D stackT0Z0 = (GridCoverage2D) stackT0.coveragesAt(-5).get(0); final GridCoverage2D stackT0Z1 = (GridCoverage2D) stackT0.coveragesAt(62).get(0); final GridCoverage2D stackT1Z0 = (GridCoverage2D) stackT1.coveragesAt(-5).get(0); final GridCoverage2D stackT1Z1 = (GridCoverage2D) stackT1.coveragesAt(62).get(0); final GridCoverage2D stackT2Z0 = (GridCoverage2D) stackT2.coveragesAt(-5).get(0); final GridCoverage2D stackT2Z1 = (GridCoverage2D) stackT2.coveragesAt(62).get(0); testImageContent(stackT0Z0.getRenderedImage(), width, height, 40, 40); // (12 - 4)*5 testImageContent(stackT1Z0.getRenderedImage(), width, height, 125, 125); // (-7 + 32)*5 testImageContent(stackT2Z0.getRenderedImage(), width, height, 705, 705); // (51 + 90)*5 testImageContent(stackT0Z1.getRenderedImage(), width, height,-450,-450); // (-3 - 87)*5 testImageContent(stackT1Z1.getRenderedImage(), width, height, -5, -5); // ( 5 - 6)*5 testImageContent(stackT2Z1.getRenderedImage(), width, height, 290, 290); // (17 + 41)*5 } /** * * @param ref * @param crs * @param geovalues [0...n slices][Z coord, T coord, sample value] */ private static void create4DPyramid(PyramidalCoverageReference ref, CoordinateReferenceSystem crs, int width, int height, double[][] geovalues) throws DataStoreException { final List<GridSampleDimension> dimensions = new ArrayList<GridSampleDimension>(); final GridSampleDimension dim = new GridSampleDimension("samples"); dimensions.add(dim); final Pyramid pyramid = ref.createPyramid(crs); ref.setSampleDimensions(dimensions); final Dimension gridSize = new Dimension(4, 3); final Dimension tilePixelSize = new Dimension(width, height); for(double[] slice : geovalues){ final GeneralDirectPosition upperLeft = new GeneralDirectPosition(crs); upperLeft.setCoordinate(-50, 60, slice[0], slice[1]); final GridMosaic mosaic = ref.createMosaic(pyramid.getId(), gridSize, tilePixelSize, upperLeft, 1); final float sample = (float)slice[2]; for(int x=0;x<gridSize.width;x++){ for(int y=0;y<gridSize.height;y++){ ref.writeTile(pyramid.getId(), mosaic.getId(), x, y, createRenderedImage( tilePixelSize.width, tilePixelSize.height, sample, sample)); } } } } /** * * @param env * @param width * @param height * @param fillValue1 value used in first vertical half of the image * @param fillValue2 value used in secong vertical half of the image * @return */ private static GridCoverage2D createCoverage2D(Envelope env, int width, int height, float fillValue1, float fillValue2){ final BufferedImage baseImage = createRenderedImage(width, height, fillValue1, fillValue2); final GridCoverageBuilder baseGcb1 = new GridCoverageBuilder(); baseGcb1.setName("base"); baseGcb1.setRenderedImage(baseImage); baseGcb1.setEnvelope(env); return baseGcb1.getGridCoverage2D(); } private static BufferedImage createRenderedImage(int width, int height, float fillValue1, float fillValue2){ final BufferedImage baseImage = BufferedImages.createImage(width, height, 1 , DataBuffer.TYPE_FLOAT); final WritableRaster baseRaster1 = baseImage.getRaster(); for(int x=0;x<width;x++){ for(int y=0;y<height;y++){ baseRaster1.setSample(x, y, 0, (y<height/2) ? fillValue1 : fillValue2 ); } } return baseImage; } private static void testImageContent(RenderedImage image, int width, int height, float value1, float value2){ final Raster resultRaster = image.getData(); for(int x=0;x<width;x++){ for(int y=0;y<height;y++){ float v = resultRaster.getSampleFloat(x, y, 0); Assert.assertEquals( (y<height/2) ? value1 : value2, v, DELTA); } } } }