/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2006-2015, 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.io.netcdf;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.geom.Point2D;
import java.awt.image.DataBuffer;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.TimeZone;
import java.util.logging.Logger;
import javax.media.jai.ImageLayout;
import javax.media.jai.PlanarImage;
import javax.swing.JFrame;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridEnvelope2D;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;
import org.geotools.coverage.grid.io.AbstractGridFormat;
import org.geotools.coverage.grid.io.GranuleSource;
import org.geotools.coverage.grid.io.HarvestedSource;
import org.geotools.data.DataUtilities;
import org.geotools.data.Query;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.factory.Hints;
import org.geotools.gce.imagemosaic.ImageMosaicFormat;
import org.geotools.gce.imagemosaic.ImageMosaicReader;
import org.geotools.gce.imagemosaic.Utils.Prop;
import org.geotools.geometry.GeneralEnvelope;
import org.geotools.imageio.netcdf.NetCDFImageReader;
import org.geotools.imageio.netcdf.NetCDFImageReaderSpi;
import org.geotools.referencing.CRS;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.resources.image.ImageUtilities;
import org.geotools.test.TestData;
import org.geotools.util.logging.Logging;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.sort.SortBy;
import org.opengis.filter.sort.SortOrder;
import org.opengis.geometry.DirectPosition;
import org.opengis.parameter.GeneralParameterValue;
import org.opengis.parameter.InvalidParameterValueException;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterValue;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.NoSuchAuthorityCodeException;
import it.geosolutions.imageio.utilities.ImageIOUtilities;
import junit.framework.JUnit4TestAdapter;
import junit.textui.TestRunner;
import ucar.nc2.Variable;
/**
* Testing {@link ImageMosaicReader}.
*
* @author Simone Giannecchini, GeoSolutions
* @author Stefan Alfons Krueger (alfonx), Wikisquare.de
* @since 2.3
*
*
*
* @source $URL$
*/
public class NetCDFMosaicReaderTest extends Assert {
private final static Logger LOGGER = Logging.getLogger(NetCDFMosaicReaderTest.class.toString());
public static junit.framework.Test suite() {
return new JUnit4TestAdapter(NetCDFMosaicReaderTest.class);
}
@Test
public void testHarvestAddTime() throws IOException {
// prepare a "mosaic" with just one NetCDF
File nc1 = TestData.file(this,"polyphemus_20130301_test.nc");
File mosaic = new File(TestData.file(this,"."),"nc_harvest1");
if(mosaic.exists()) {
FileUtils.deleteDirectory(mosaic);
}
assertTrue(mosaic.mkdirs());
FileUtils.copyFileToDirectory(nc1, mosaic);
// The indexer
String indexer = "TimeAttribute=time\n" +
"Schema=the_geom:Polygon,location:String,imageindex:Integer,time:java.util.Date\n";
FileUtils.writeStringToFile(new File(mosaic, "indexer.properties"), indexer);
// the datastore.properties file is also mandatory...
File dsp = TestData.file(this,"datastore.properties");
FileUtils.copyFileToDirectory(dsp, mosaic);
// have the reader harvest it
ImageMosaicFormat format = new ImageMosaicFormat();
ImageMosaicReader reader = format.getReader(mosaic);
SimpleFeatureIterator it = null;
assertNotNull(reader);
try {
String[] names = reader.getGridCoverageNames();
assertEquals(1, names.length);
assertEquals("O3", names[0]);
// check we have the two granules we expect
GranuleSource source = reader.getGranules("O3", true);
FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();
Query q = new Query(Query.ALL);
q.setSortBy(new SortBy[] {ff.sort("time", SortOrder.ASCENDING)});
SimpleFeatureCollection granules = source.getGranules(q);
assertEquals(2, granules.size());
it = granules.features();
assertTrue(it.hasNext());
SimpleFeature f = it.next();
assertEquals("polyphemus_20130301_test.nc", f.getAttribute("location"));
assertEquals(0, f.getAttribute("imageindex"));
assertEquals("2013-03-01T00:00:00.000Z", ConvertersHack.convert(f.getAttribute("time"), String.class));
assertTrue(it.hasNext());
f = it.next();
assertEquals("polyphemus_20130301_test.nc", f.getAttribute("location"));
assertEquals(1, f.getAttribute("imageindex"));
assertEquals("2013-03-01T01:00:00.000Z", ConvertersHack.convert(f.getAttribute("time"), String.class));
it.close();
// now add another netcdf and harvest it
File nc2 = TestData.file(this,"polyphemus_20130302_test.nc");
FileUtils.copyFileToDirectory(nc2, mosaic);
File fileToHarvest = new File(mosaic, "polyphemus_20130302_test.nc");
List<HarvestedSource> harvestSummary = reader.harvest(null, fileToHarvest, null);
assertEquals(1, harvestSummary.size());
HarvestedSource hf = harvestSummary.get(0);
assertEquals("polyphemus_20130302_test.nc", ((File) hf.getSource()).getName());
assertTrue(hf.success());
assertEquals(1, reader.getGridCoverageNames().length);
// check that we have four times now
granules = source.getGranules(q);
assertEquals(4, granules.size());
it = granules.features();
f = it.next();
assertEquals("polyphemus_20130301_test.nc", f.getAttribute("location"));
assertEquals(0, f.getAttribute("imageindex"));
assertEquals("2013-03-01T00:00:00.000Z", ConvertersHack.convert(f.getAttribute("time"), String.class));
assertTrue(it.hasNext());
f = it.next();
assertEquals("polyphemus_20130301_test.nc", f.getAttribute("location"));
assertEquals(1, f.getAttribute("imageindex"));
assertEquals("2013-03-01T01:00:00.000Z", ConvertersHack.convert(f.getAttribute("time"), String.class));
f = it.next();
assertEquals("polyphemus_20130302_test.nc", f.getAttribute("location"));
assertEquals(0, f.getAttribute("imageindex"));
assertEquals("2013-03-02T00:00:00.000Z", ConvertersHack.convert(f.getAttribute("time"), String.class));
assertTrue(it.hasNext());
f = it.next();
assertEquals("polyphemus_20130302_test.nc", f.getAttribute("location"));
assertEquals(1, f.getAttribute("imageindex"));
assertEquals("2013-03-02T01:00:00.000Z", ConvertersHack.convert(f.getAttribute("time"), String.class));
it.close();
ImageLayout layout = reader.getImageLayout();
SampleModel sampleModel = layout.getSampleModel(null);
assertEquals(DataBuffer.TYPE_FLOAT, sampleModel.getDataType());
} finally {
if(it != null) {
it.close();
}
reader.dispose();
}
}
@Test
public void testHeterogeneous() throws IOException, InvalidParameterValueException, ParseException {
// prepare a "mosaic" with just one NetCDF
File nc1 = TestData.file(this,"polyphemus_20130301_test.nc");
File mosaic = new File(TestData.file(this,"."),"nc_poly_hetero");
if(mosaic.exists()) {
FileUtils.deleteDirectory(mosaic);
}
assertTrue(mosaic.mkdirs());
FileUtils.copyFileToDirectory(nc1, mosaic);
// The indexer
String indexer = "TimeAttribute=time\n" +
"Schema=the_geom:Polygon,location:String,imageindex:Integer,time:java.util.Date\n";
FileUtils.writeStringToFile(new File(mosaic, "indexer.properties"), indexer);
// the datastore.properties file is also mandatory...
File dsp = TestData.file(this,"datastore.properties");
FileUtils.copyFileToDirectory(dsp, mosaic);
// have the reader harvest it
ImageMosaicFormat format = new ImageMosaicFormat();
ImageMosaicReader reader = format.getReader(mosaic);
assertNotNull(reader);
reader.dispose();
// now force heterogeneous interpretation
Properties mosaicProps = new Properties();
File mosaicPropsFile = new File(mosaic, "O3.properties");
try(FileInputStream fis = new FileInputStream(mosaicPropsFile)) {
mosaicProps.load(fis);
}
mosaicProps.put("Heterogeneous", "true");
try(FileOutputStream fos = new FileOutputStream(mosaicPropsFile)) {
mosaicProps.store(fos, "Now with hetero flag up");
}
// load two different times, make sure we actually read two different slices
String t1 = "2013-03-01T00:00:00.000Z";
String t2 = "2013-03-01T01:00:00.000Z";
reader = format.getReader(mosaic);
try {
// prepare params
final ParameterValue<Boolean> useJai = AbstractGridFormat.USE_JAI_IMAGEREAD.createValue();
useJai.setValue(false);
ParameterValue<List> time = ImageMosaicFormat.TIME.createValue();
time.setValue(Arrays.asList(parseTimeStamp(t1)));
GeneralParameterValue[] params = new GeneralParameterValue[] { useJai, time };
// read first
GridCoverage2D coverage1 = reader.read(params);
time.setValue(Arrays.asList(parseTimeStamp(t2)));
GridCoverage2D coverage2 = reader.read(params);
DirectPosition center = reader.getOriginalEnvelope().getMedian();
float[] v1 = (float[]) coverage1.evaluate(center);
float[] v2 = (float[]) coverage2.evaluate(center);
assertNotEquals(v1[0], v2[0], 0f);
} finally {
reader.dispose();
}
}
@Test
public void testCustomTimeAttribute() throws IOException {
File nc1 = TestData.file(this,"polyphemus_20130301_NO2_time2.nc");
File mosaic = new File(TestData.file(this,"."),"nc_time2");
if (mosaic.exists()) {
FileUtils.deleteDirectory(mosaic);
}
assertTrue(mosaic.mkdirs());
FileUtils.copyFileToDirectory(nc1, mosaic);
// The indexer
String indexer = "TimeAttribute=time\n" +
"Schema=the_geom:Polygon,location:String,imageindex:Integer,time:java.util.Date\n";
final String auxiliaryFilePath = mosaic.getAbsolutePath() + File.separatorChar + ".polyphemus_20130301_NO2_time2";
final File auxiliaryFileDir = new File(auxiliaryFilePath);
assertTrue(auxiliaryFileDir.mkdirs());
File nc1Aux = TestData.file(this,"polyphemus_20130301_NO2_time2.xml");
FileUtils.copyFileToDirectory(nc1Aux, auxiliaryFileDir);
FileUtils.writeStringToFile(new File(mosaic, "indexer.properties"), indexer);
File dsp = TestData.file(this,"datastore.properties");
FileUtils.copyFileToDirectory(dsp, mosaic);
ImageMosaicFormat format = new ImageMosaicFormat();
ImageMosaicReader reader = format.getReader(mosaic);
NetCDFImageReader imageReader = null;
SimpleFeatureIterator it = null;
assertNotNull(reader);
try {
String[] names = reader.getGridCoverageNames();
assertEquals(1, names.length);
assertEquals("NO2", names[0]);
// check we have the two granules we expect
GranuleSource source = reader.getGranules("NO2", true);
FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();
Query q = new Query(Query.ALL);
q.setSortBy(new SortBy[] {ff.sort("time", SortOrder.ASCENDING)});
SimpleFeatureCollection granules = source.getGranules(q);
assertEquals(2, granules.size());
it = granules.features();
assertTrue(it.hasNext());
SimpleFeature f = it.next();
assertEquals("polyphemus_20130301_NO2_time2.nc", f.getAttribute("location"));
SimpleFeatureType featureType = f.getType();
// check the underlying data has a time2 dimension
imageReader = (NetCDFImageReader) new NetCDFImageReaderSpi().createReaderInstance();
imageReader.setInput(nc1);
Variable var = imageReader.getVariableByName("NO2");
String dimensions = var.getDimensionsString();
assertTrue(dimensions.contains("time2"));
// check I'm getting a "time" attribute instead of "time2" due to the
// uniqueTimeAttribute remap
assertNotNull(featureType.getDescriptor("time"));
} finally {
if (it != null) {
it.close();
}
if (reader != null) {
try {
reader.dispose();
} catch (Exception e) {
// Ignore exception on dispose
}
}
if (imageReader != null) {
try {
imageReader.dispose();
} catch (Exception e) {
// Ignore exception on dispose
}
}
}
}
@Test
public void testReHarvest() throws Exception {
// prepare a "mosaic" with just one NetCDF
File nc1 = TestData.file(this,"polyphemus_20130301_test.nc");
File mosaic = new File(TestData.file(this,"."),"nc_harvest4");
if(mosaic.exists()) {
FileUtils.deleteDirectory(mosaic);
}
assertTrue(mosaic.mkdirs());
FileUtils.copyFileToDirectory(nc1, mosaic);
// The indexer
String indexer = "TimeAttribute=time\n" +
"Schema=the_geom:Polygon,location:String,imageindex:Integer,time:java.util.Date\n";
FileUtils.writeStringToFile(new File(mosaic, "indexer.properties"), indexer);
// the datastore.properties file is also mandatory...
File dsp =TestData.file(this,"datastore.properties");
FileUtils.copyFileToDirectory(dsp, mosaic);
// have the reader harvest it
ImageMosaicFormat format = new ImageMosaicFormat();
ImageMosaicReader reader = format.getReader(mosaic);
SimpleFeatureIterator it = null;
assertNotNull(reader);
try {
String[] names = reader.getGridCoverageNames();
assertEquals(1, names.length);
assertEquals("O3", names[0]);
// check we have the two granules we expect
GranuleSource source = reader.getGranules("O3", true);
FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();
Query q = new Query(Query.ALL);
q.setSortBy(new SortBy[] {ff.sort("time", SortOrder.ASCENDING)});
SimpleFeatureCollection granules = source.getGranules(q);
assertEquals(2, granules.size());
it = granules.features();
assertTrue(it.hasNext());
SimpleFeature f = it.next();
assertEquals("polyphemus_20130301_test.nc", f.getAttribute("location"));
assertEquals(0, f.getAttribute("imageindex"));
assertEquals("2013-03-01T00:00:00.000Z", ConvertersHack.convert(f.getAttribute("time"), String.class));
assertTrue(it.hasNext());
f = it.next();
assertEquals("polyphemus_20130301_test.nc", f.getAttribute("location"));
assertEquals(1, f.getAttribute("imageindex"));
assertEquals("2013-03-01T01:00:00.000Z", ConvertersHack.convert(f.getAttribute("time"), String.class));
it.close();
// close the reader and re-open it
reader.dispose();
reader = format.getReader(mosaic);
source = reader.getGranules("O3", true);
// wait a bit, we have to make sure the old indexes are recognized as old
Thread.sleep(1000);
// now replace the netcdf file with a more up to date version of the same
File nc2 = TestData.file(this,"polyphemus_20130301_test_more_times.nc");
File target = new File(mosaic, "polyphemus_20130301_test.nc");
FileUtils.copyFile(nc2, target, false);
File fileToHarvest = new File(mosaic, "polyphemus_20130301_test.nc");
List<HarvestedSource> harvestSummary = reader.harvest(null, fileToHarvest, null);
assertEquals(1, harvestSummary.size());
HarvestedSource hf = harvestSummary.get(0);
assertEquals("polyphemus_20130301_test.nc", ((File) hf.getSource()).getName());
assertTrue(hf.success());
assertEquals(1, reader.getGridCoverageNames().length);
// check that we have four times now
source = reader.getGranules("O3", true);
granules = source.getGranules(q);
assertEquals(4, granules.size());
it = granules.features();
f = it.next();
assertEquals("polyphemus_20130301_test.nc", f.getAttribute("location"));
assertEquals(0, f.getAttribute("imageindex"));
assertEquals("2013-03-01T00:00:00.000Z", ConvertersHack.convert(f.getAttribute("time"), String.class));
assertTrue(it.hasNext());
f = it.next();
assertEquals("polyphemus_20130301_test.nc", f.getAttribute("location"));
assertEquals(1, f.getAttribute("imageindex"));
assertEquals("2013-03-01T01:00:00.000Z", ConvertersHack.convert(f.getAttribute("time"), String.class));
f = it.next();
assertEquals("polyphemus_20130301_test.nc", f.getAttribute("location"));
assertEquals(2, f.getAttribute("imageindex"));
assertEquals("2013-03-01T02:00:00.000Z", ConvertersHack.convert(f.getAttribute("time"), String.class));
assertTrue(it.hasNext());
f = it.next();
assertEquals("polyphemus_20130301_test.nc", f.getAttribute("location"));
assertEquals(3, f.getAttribute("imageindex"));
assertEquals("2013-03-01T03:00:00.000Z", ConvertersHack.convert(f.getAttribute("time"), String.class));
it.close();
} finally {
if(it != null) {
it.close();
}
reader.dispose();
}
}
@Test
public void testHarvestHDF5Data() throws IOException {
File nc1 = TestData.file(this,"2DLatLonCoverage.nc");
File nc2 = TestData.file(this,"2DLatLonCoverage2.nc");
File mosaic = new File(TestData.file(this,"."),"simpleMosaic");
if(mosaic.exists()) {
FileUtils.deleteDirectory(mosaic);
}
assertTrue(mosaic.mkdirs());
FileUtils.copyFileToDirectory(nc1, mosaic);
FileUtils.copyFileToDirectory(nc2, mosaic);
// the datastore.properties file is also mandatory...
File dsp = TestData.file(this,"datastore.properties");
FileUtils.copyFileToDirectory(dsp, mosaic);
File xml = TestData.file(this,"hdf5Coverage2D.xml");
FileUtils.copyFileToDirectory(xml, mosaic);
// The indexer
String indexer = "TimeAttribute=time\n"
+ "Schema=the_geom:Polygon,location:String,imageindex:Integer,time:java.util.Date\n";
// + "PropertyCollectors=TimestampFileNameExtractorSPI[timeregex](time)\n";
indexer += Prop.AUXILIARY_FILE + "=" + "hdf5Coverage2D.xml";
FileUtils.writeStringToFile(new File(mosaic, "indexer.properties"), indexer);
//simply test if the mosaic can be read without exceptions
ImageMosaicFormat format = new ImageMosaicFormat();
ImageMosaicReader reader = format.getReader(mosaic);
reader.read("L1_V2",null);
}
@Test
public void testHarvestAddVariable() throws IOException {
// prepare a "mosaic" with just one NetCDF
File nc1 = TestData.file(this,"polyphemus_20130301_test.nc");
File mosaic = new File(TestData.file(this,"."),"nc_harvest2");
if(mosaic.exists()) {
FileUtils.deleteDirectory(mosaic);
}
assertTrue(mosaic.mkdirs());
FileUtils.copyFileToDirectory(nc1, mosaic);
// The indexer
String indexer = "TimeAttribute=time\n" +
"Schema=the_geom:Polygon,location:String,imageindex:Integer,time:java.util.Date\n";
FileUtils.writeStringToFile(new File(mosaic, "indexer.properties"), indexer);
// the datastore.properties file is also mandatory...
File dsp = TestData.file(this,"datastore.properties");
FileUtils.copyFileToDirectory(dsp, mosaic);
// have the reader harvest it
ImageMosaicFormat format = new ImageMosaicFormat();
ImageMosaicReader reader = format.getReader(mosaic);
SimpleFeatureIterator it = null;
assertNotNull(reader);
try {
String[] names = reader.getGridCoverageNames();
assertEquals(1, names.length);
assertEquals("O3", names[0]);
// check we have the two granules we expect
GranuleSource source = reader.getGranules("O3", true);
FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();
Query q = new Query(Query.ALL);
q.setSortBy(new SortBy[] {ff.sort("time", SortOrder.ASCENDING)});
SimpleFeatureCollection granules = source.getGranules(q);
assertEquals(2, granules.size());
it = granules.features();
assertTrue(it.hasNext());
SimpleFeature f = it.next();
assertEquals("polyphemus_20130301_test.nc", f.getAttribute("location"));
assertEquals(0, f.getAttribute("imageindex"));
assertEquals("2013-03-01T00:00:00.000Z", ConvertersHack.convert(f.getAttribute("time"), String.class));
assertTrue(it.hasNext());
f = it.next();
assertEquals("polyphemus_20130301_test.nc", f.getAttribute("location"));
assertEquals(1, f.getAttribute("imageindex"));
assertEquals("2013-03-01T01:00:00.000Z", ConvertersHack.convert(f.getAttribute("time"), String.class));
it.close();
// now add another netcdf and harvest it
File nc2 = TestData.file(this,"polyphemus_20130301_NO2.nc");
FileUtils.copyFileToDirectory(nc2, mosaic);
File fileToHarvest = new File(mosaic, "polyphemus_20130301_NO2.nc");
List<HarvestedSource> harvestSummary = reader.harvest(null, fileToHarvest, null);
assertEquals(1, harvestSummary.size());
HarvestedSource hf = harvestSummary.get(0);
assertEquals("polyphemus_20130301_NO2.nc", ((File) hf.getSource()).getName());
assertTrue(hf.success());
// check we have two coverages now
names = reader.getGridCoverageNames();
Arrays.sort(names);
assertEquals(2, names.length);
assertEquals("NO2", names[0]);
assertEquals("O3", names[1]);
// test the newly ingested granules, which are in a separate coverage
q.setTypeName("NO2");
granules = source.getGranules(q);
assertEquals(2, granules.size());
it = granules.features();
f = it.next();
assertEquals("polyphemus_20130301_NO2.nc", f.getAttribute("location"));
assertEquals(0, f.getAttribute("imageindex"));
assertEquals("2013-03-01T00:00:00.000Z", ConvertersHack.convert(f.getAttribute("time"), String.class));
assertTrue(it.hasNext());
f = it.next();
assertEquals("polyphemus_20130301_NO2.nc", f.getAttribute("location"));
assertEquals(1, f.getAttribute("imageindex"));
assertEquals("2013-03-01T01:00:00.000Z", ConvertersHack.convert(f.getAttribute("time"), String.class));
it.close();
} finally {
if(it != null) {
it.close();
}
reader.dispose();
}
}
@Test
public void testMultipleGranules() throws IOException, ParseException {
// prepare a "mosaic" with just one NetCDF
File nc1 = TestData.file(this, "20130101.METOPA.GOME2.NO2.DUMMY_new.nc");
File nc2 = TestData.file(this, "20130108.METOPA.GOME2.NO2.DUMMY_new.nc");
File mosaic = new File(TestData.file(this, "."), "nc_heterogen");
if (mosaic.exists()) {
FileUtils.deleteDirectory(mosaic);
}
assertTrue(mosaic.mkdirs());
FileUtils.copyFileToDirectory(nc1, mosaic);
FileUtils.copyFileToDirectory(nc2, mosaic);
File xml = TestData.file(this, "GOME2.NO2_new.xml");
FileUtils.copyFileToDirectory(xml, mosaic);
// The indexer
String indexer = "TimeAttribute=time\n"
+ "Schema=the_geom:Polygon,location:String,imageindex:Integer,time:java.util.Date\n"
+ "PropertyCollectors=TimestampFileNameExtractorSPI[timeregex](time)\n";
indexer += Prop.AUXILIARY_FILE + "=" + "GOME2.NO2_new.xml";
FileUtils.writeStringToFile(new File(mosaic, "indexer.properties"), indexer);
String timeregex = "regex=[0-9]{8}";
FileUtils.writeStringToFile(new File(mosaic, "timeregex.properties"), timeregex);
// the datastore.properties file is also mandatory...
File dsp = TestData.file(this, "datastore.properties");
FileUtils.copyFileToDirectory(dsp, mosaic);
// have the reader harvest it
ImageMosaicFormat format = new ImageMosaicFormat();
ImageMosaicReader reader = format.getReader(mosaic);
SimpleFeatureIterator it = null;
assertNotNull(reader);
try {
// use imageio with defined tiles
final ParameterValue<Boolean> useJai = AbstractGridFormat.USE_JAI_IMAGEREAD
.createValue();
useJai.setValue(false);
// specify time
ParameterValue<List> time = ImageMosaicFormat.TIME.createValue();
final Date timeD = parseTimeStamp("2013-01-01T00:00:00.000");
time.setValue(new ArrayList() {
{
add(timeD);
}
});
GeneralParameterValue[] params = new GeneralParameterValue[] { useJai, time };
GridCoverage2D coverage1 = reader.read(params);
// Specify a new time (Check if two times returns two different coverages)
final Date timeD2 = parseTimeStamp("2013-01-08T00:00:00.000");
time.setValue(new ArrayList() {
{
add(timeD2);
}
});
params = new GeneralParameterValue[] { useJai, time };
GridCoverage2D coverage2 = reader.read(params);
// Ensure that the two images are different (different location)
String property = (String) coverage1.getProperty("OriginalFileSource");
String property2 = (String) coverage2.getProperty("OriginalFileSource");
assertNotEquals(property, property2);
// Ensure that only one coverage is present
String[] names = reader.getGridCoverageNames();
assertEquals(1, names.length);
assertEquals("NO2", names[0]);
} finally {
if (it != null) {
it.close();
}
reader.dispose();
}
}
@Test
public void testHarvest3Gome() throws IOException {
// prepare a "mosaic" with just one NetCDF
File nc1 = TestData.file(this,"20130101.METOPA.GOME2.NO2.DUMMY.nc");
File mosaic = new File(TestData.file(this,"."),"nc_harvest");
if (mosaic.exists()) {
FileUtils.deleteDirectory(mosaic);
}
assertTrue(mosaic.mkdirs());
FileUtils.copyFileToDirectory(nc1, mosaic);
File xml = TestData.file(this,".DUMMY.GOME2.NO2.PGL/GOME2.NO2.xml");
FileUtils.copyFileToDirectory(xml, mosaic);
// The indexer
String indexer = "TimeAttribute=time\n"
+ "Schema=the_geom:Polygon,location:String,imageindex:Integer,time:java.util.Date\n"
+ "PropertyCollectors=TimestampFileNameExtractorSPI[timeregex](time)\n";
indexer += Prop.AUXILIARY_FILE + "=" + "GOME2.NO2.xml";
FileUtils.writeStringToFile(new File(mosaic, "indexer.properties"), indexer);
String timeregex = "regex=[0-9]{8}";
FileUtils.writeStringToFile(new File(mosaic, "timeregex.properties"), timeregex);
// the datastore.properties file is also mandatory...
File dsp = TestData.file(this,"datastore.properties");
FileUtils.copyFileToDirectory(dsp, mosaic);
// have the reader harvest it
ImageMosaicFormat format = new ImageMosaicFormat();
ImageMosaicReader reader = format.getReader(mosaic);
SimpleFeatureIterator it = null;
assertNotNull(reader);
try {
String[] names = reader.getGridCoverageNames();
assertEquals(1, names.length);
assertEquals("NO2", names[0]);
// check we have the two granules we expect
GranuleSource source = reader.getGranules("NO2", true);
FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();
Query q = new Query(Query.ALL);
q.setSortBy(new SortBy[] { ff.sort("time", SortOrder.DESCENDING) });
SimpleFeatureCollection granules = source.getGranules(q);
assertEquals(1, granules.size());
it = granules.features();
assertTrue(it.hasNext());
SimpleFeature f = it.next();
assertEquals("20130101.METOPA.GOME2.NO2.DUMMY.nc", f.getAttribute("location"));
assertEquals(0, f.getAttribute("imageindex"));
assertEquals("2013-01-01T00:00:00.000Z",
ConvertersHack.convert(f.getAttribute("time"), String.class));
it.close();
// now add another netcdf and harvest it
File nc2 = TestData.file(this,"20130116.METOPA.GOME2.NO2.DUMMY.nc");
FileUtils.copyFileToDirectory(nc2, mosaic);
File fileToHarvest = new File(mosaic, "20130116.METOPA.GOME2.NO2.DUMMY.nc");
List<HarvestedSource> harvestSummary = reader.harvest("NO2", fileToHarvest, null);
assertEquals(1, harvestSummary.size());
granules = source.getGranules(q);
assertEquals(2, granules.size());
HarvestedSource hf = harvestSummary.get(0);
assertEquals("20130116.METOPA.GOME2.NO2.DUMMY.nc", ((File) hf.getSource()).getName());
assertTrue(hf.success());
assertEquals(1, reader.getGridCoverageNames().length);
File nc3 = TestData.file(this,"20130108.METOPA.GOME2.NO2.DUMMY.nc");
FileUtils.copyFileToDirectory(nc3, mosaic);
fileToHarvest = new File(mosaic, "20130108.METOPA.GOME2.NO2.DUMMY.nc");
harvestSummary = reader.harvest("NO2", fileToHarvest, null);
assertEquals(1, harvestSummary.size());
hf = harvestSummary.get(0);
assertEquals("20130108.METOPA.GOME2.NO2.DUMMY.nc", ((File) hf.getSource()).getName());
assertTrue(hf.success());
assertEquals(1, reader.getGridCoverageNames().length);
// check that we have 2 times now
granules = source.getGranules(q);
assertEquals(3, granules.size());
it = granules.features();
f = it.next();
assertEquals("20130116.METOPA.GOME2.NO2.DUMMY.nc", f.getAttribute("location"));
assertEquals(0, f.getAttribute("imageindex"));
assertEquals("2013-01-16T00:00:00.000Z",
ConvertersHack.convert(f.getAttribute("time"), String.class));
assertTrue(it.hasNext());
f = it.next();
assertEquals("20130108.METOPA.GOME2.NO2.DUMMY.nc", f.getAttribute("location"));
assertEquals(0, f.getAttribute("imageindex"));
assertEquals("2013-01-08T00:00:00.000Z",
ConvertersHack.convert(f.getAttribute("time"), String.class));
f = it.next();
assertEquals("20130101.METOPA.GOME2.NO2.DUMMY.nc", f.getAttribute("location"));
assertEquals(0, f.getAttribute("imageindex"));
assertEquals("2013-01-01T00:00:00.000Z",
ConvertersHack.convert(f.getAttribute("time"), String.class));
it.close();
} finally {
if (it != null) {
it.close();
}
reader.dispose();
}
}
@Test
public void testReadCoverageGome() throws IOException {
// prepare a "mosaic" with just one NetCDF
File nc1 = TestData.file(this,"20130101.METOPA.GOME2.NO2.DUMMY.nc");
File mosaic = new File(TestData.file(this,"."),"nc_harvest3");
if (mosaic.exists()) {
FileUtils.deleteDirectory(mosaic);
}
assertTrue(mosaic.mkdirs());
FileUtils.copyFileToDirectory(nc1, mosaic);
File xml = TestData.file(this,".DUMMY.GOME2.NO2.PGL/GOME2.NO2.xml");
FileUtils.copyFileToDirectory(xml, mosaic);
// The indexer
String indexer = "TimeAttribute=time\n"
+ "Schema=the_geom:Polygon,location:String,imageindex:Integer,time:java.util.Date\n"
+ "PropertyCollectors=TimestampFileNameExtractorSPI[timeregex](time)\n";
indexer += Prop.AUXILIARY_FILE + "=" + "GOME2.NO2.xml";
FileUtils.writeStringToFile(new File(mosaic, "indexer.properties"), indexer);
String timeregex = "regex=[0-9]{8}";
FileUtils.writeStringToFile(new File(mosaic, "timeregex.properties"), timeregex);
// the datastore.properties file is also mandatory...
File dsp = TestData.file(this,"datastore.properties");
FileUtils.copyFileToDirectory(dsp, mosaic);
// have the reader harvest it
ImageMosaicFormat format = new ImageMosaicFormat();
ImageMosaicReader reader = format.getReader(mosaic);
GridCoverage2D coverage = null;
assertNotNull(reader);
try {
String[] names = reader.getGridCoverageNames();
assertEquals(1, names.length);
assertEquals("NO2", names[0]);
GranuleSource source = reader.getGranules("NO2", true);
SimpleFeatureCollection granules = source.getGranules(Query.ALL);
assertEquals(1, granules.size());
assertTrue(CRS.equalsIgnoreMetadata(DefaultGeographicCRS.WGS84, reader.getCoordinateReferenceSystem()));
GeneralEnvelope envelope = reader.getOriginalEnvelope("NO2");
assertEquals(-360, envelope.getMinimum(0), 0d);
assertEquals(360, envelope.getMaximum(0), 0d);
assertEquals(-180, envelope.getMinimum(1), 0d);
assertEquals(180, envelope.getMaximum(1), 0d);
// check we can read a coverage out of it
coverage = reader.read(null);
reader.dispose();
// Checking we can read again from the coverage once it has been configured.
reader = format.getReader(mosaic);
coverage = reader.read(null);
assertNotNull(coverage);
} finally {
if(coverage != null) {
ImageUtilities.disposePlanarImageChain((PlanarImage) coverage.getRenderedImage());
coverage.dispose(true);
}
reader.dispose();
}
}
@Test
public void testAuxiliaryFileHasRelativePath() throws IOException {
// prepare a "mosaic" with just one NetCDF
File nc1 = TestData.file(this, "20130101.METOPA.GOME2.NO2.DUMMY.nc");
File mosaic = new File(TestData.file(this, "."), "nc_harvestRP");
if (mosaic.exists()) {
FileUtils.deleteDirectory(mosaic);
}
assertTrue(mosaic.mkdirs());
FileUtils.copyFileToDirectory(nc1, mosaic);
final String auxFileName = "GOME2.NO2.xml";
File xml = TestData.file(this, ".DUMMY.GOME2.NO2.PGL/" + auxFileName);
FileUtils.copyFileToDirectory(xml, mosaic);
// The indexer
String indexer = "TimeAttribute=time\n"
+ "Schema=the_geom:Polygon,location:String,imageindex:Integer,time:java.util.Date\n"
+ "PropertyCollectors=TimestampFileNameExtractorSPI[timeregex](time)\n";
indexer += Prop.AUXILIARY_FILE + "=" + "GOME2.NO2.xml\n";
// Setting RelativePath behavior
indexer += Prop.ABSOLUTE_PATH + "=" + "false";
FileUtils.writeStringToFile(new File(mosaic, "indexer.properties"), indexer);
String timeregex = "regex=[0-9]{8}";
FileUtils.writeStringToFile(new File(mosaic, "timeregex.properties"), timeregex);
// the datastore.properties file is also mandatory...
File dsp = TestData.file(this, "datastore.properties");
FileUtils.copyFileToDirectory(dsp, mosaic);
// have the reader harvest it
ImageMosaicFormat format = new ImageMosaicFormat();
ImageMosaicReader reader = format.getReader(mosaic);
InputStream inStream = null;
assertNotNull(reader);
try {
String[] names = reader.getGridCoverageNames();
assertEquals(1, names.length);
assertEquals("NO2", names[0]);
GranuleSource source = reader.getGranules("NO2", true);
SimpleFeatureCollection granules = source.getGranules(Query.ALL);
assertEquals(1, granules.size());
Properties props = new Properties();
final File file = new File(mosaic, "nc_harvestRP.properties");
inStream = new FileInputStream(file);
props.load(inStream);
// Before the fix, the AuxiliaryFile was always an absolute path
assertEquals(auxFileName, (String) props.getProperty(Prop.AUXILIARY_FILE));
} finally {
if (inStream != null) {
IOUtils.closeQuietly(inStream);
}
if (reader != null) {
try {
reader.dispose();
} catch (Throwable t) {
// Ignore exception on close attempt
}
}
}
}
@Test
public void testDeleteCoverageGome() throws IOException {
// prepare a "mosaic" with just one NetCDF
File nc1 = TestData.file(this,"O3-NO2.nc");
File mosaic = new File(TestData.file(this,"."),"nc_deleteCoverage");
if (mosaic.exists()) {
FileUtils.deleteDirectory(mosaic);
}
assertTrue(mosaic.mkdirs());
FileUtils.copyFileToDirectory(nc1, mosaic);
File xml = TestData.file(this,".O3-NO2/O3-NO2.xml");
FileUtils.copyFileToDirectory(xml, mosaic);
// The indexer
String indexer = "TimeAttribute=time\n"
+ "Schema=the_geom:Polygon,location:String,imageindex:Integer,time:java.util.Date\n";
indexer += Prop.AUXILIARY_FILE + "=" + "O3-NO2.xml";
FileUtils.writeStringToFile(new File(mosaic, "indexer.properties"), indexer);
// the datastore.properties file is also mandatory...
File dsp = TestData.file(this,"datastore.properties");
FileUtils.copyFileToDirectory(dsp, mosaic);
// have the reader harvest it
ImageMosaicFormat format = new ImageMosaicFormat();
ImageMosaicReader reader = format.getReader(mosaic);
GridCoverage2D coverage = null;
assertNotNull(reader);
try {
assertEquals(2, reader.getGridCoverageNames().length);
File[] files = mosaic.listFiles();
assertEquals(15, files.length);
reader.dispose();
reader = format.getReader(mosaic);
reader.delete(false);
files = mosaic.listFiles();
assertEquals(1, files.length);
} finally {
if(coverage != null) {
ImageUtilities.disposePlanarImageChain((PlanarImage) coverage.getRenderedImage());
coverage.dispose(true);
}
reader.dispose();
}
}
@Test
public void testReadCoverageGome2Names() throws IOException {
// prepare a "mosaic" with just one NetCDF
File nc1 = TestData.file(this,"20130101.METOPA.GOME2.NO2.DUMMY.nc");
File mosaic = new File(TestData.file(this,"."),"nc_gome2");
if (mosaic.exists()) {
FileUtils.deleteDirectory(mosaic);
}
assertTrue(mosaic.mkdirs());
FileUtils.copyFileToDirectory(nc1, mosaic);
nc1 = TestData.file(this,"20130101.METOPA.GOME2.BrO.DUMMY.nc");
FileUtils.copyFileToDirectory(nc1, mosaic);
File xml = TestData.file(this,"DUMMYGOME2.xml");
FileUtils.copyFileToDirectory(xml, mosaic);
// The indexer
String indexer = "TimeAttribute=time\n"
+ "Schema=the_geom:Polygon,location:String,imageindex:Integer,time:java.util.Date\n"
+ "PropertyCollectors=TimestampFileNameExtractorSPI[timeregex](time)\n";
indexer += Prop.AUXILIARY_FILE + "=" + "DUMMYGOME2.xml";
FileUtils.writeStringToFile(new File(mosaic, "indexer.properties"), indexer);
String timeregex = "regex=[0-9]{8}";
FileUtils.writeStringToFile(new File(mosaic, "timeregex.properties"), timeregex);
// the datastore.properties file is also mandatory...
File dsp = TestData.file(this,"datastore.properties");
FileUtils.copyFileToDirectory(dsp, mosaic);
// have the reader harvest it
ImageMosaicFormat format = new ImageMosaicFormat();
ImageMosaicReader reader = format.getReader(mosaic);
GridCoverage2D coverage = null;
assertNotNull(reader);
try {
String[] names = reader.getGridCoverageNames();
assertEquals(2, names.length);
assertEquals("NO2", names[0]);
assertEquals("BrO", names[1]);
GranuleSource source = reader.getGranules("NO2", true);
SimpleFeatureCollection granules = source.getGranules(Query.ALL);
assertEquals(1, granules.size());
assertTrue(CRS.equalsIgnoreMetadata(DefaultGeographicCRS.WGS84, reader.getCoordinateReferenceSystem("NO2")));
GeneralEnvelope envelope = reader.getOriginalEnvelope("NO2");
assertEquals(-360, envelope.getMinimum(0), 0d);
assertEquals(360, envelope.getMaximum(0), 0d);
assertEquals(-180, envelope.getMinimum(1), 0d);
assertEquals(180, envelope.getMaximum(1), 0d);
// check we can read a coverage out of it
coverage = reader.read("NO2", null);
reader.dispose();
// Checking we can read again from the coverage (using a different name this time) once it has been configured.
reader = format.getReader(mosaic);
coverage = reader.read("BrO", null);
assertNotNull(coverage);
} finally {
if(coverage != null) {
ImageUtilities.disposePlanarImageChain((PlanarImage) coverage.getRenderedImage());
coverage.dispose(true);
}
reader.dispose();
}
}
@Test
public void testCheckDifferentSampleImages() throws IOException {
// prepare a "mosaic" with just one NetCDF
File nc1 = TestData.file(this,"20130101.METOPA.GOME2.NO2.DUMMY.nc");
File mosaic =new File(TestData.file(this,"."),"nc_sampleimages");
if (mosaic.exists()) {
FileUtils.deleteDirectory(mosaic);
}
assertTrue(mosaic.mkdirs());
FileUtils.copyFileToDirectory(nc1, mosaic);
nc1 = TestData.file(this,"20130101.METOPA.GOME2.BrO.DUMMY.nc");
FileUtils.copyFileToDirectory(nc1, mosaic);
File xml = TestData.file(this,"DUMMYGOME2.xml");
FileUtils.copyFileToDirectory(xml, mosaic);
// The indexer
String indexer = "TimeAttribute=time\n"
+ "Schema=the_geom:Polygon,location:String,imageindex:Integer,time:java.util.Date\n"
+ "PropertyCollectors=TimestampFileNameExtractorSPI[timeregex](time)\n";
indexer += Prop.AUXILIARY_FILE + "=" + "DUMMYGOME2.xml";
FileUtils.writeStringToFile(new File(mosaic, "indexer.properties"), indexer);
String timeregex = "regex=[0-9]{8}";
FileUtils.writeStringToFile(new File(mosaic, "timeregex.properties"), timeregex);
// the datastore.properties file is also mandatory...
File dsp = TestData.file(this,"datastore.properties");
FileUtils.copyFileToDirectory(dsp, mosaic);
// have the reader harvest it
ImageMosaicFormat format = new ImageMosaicFormat();
ImageMosaicReader reader = format.getReader(mosaic);
assertNotNull(reader);
// Checking whether different sample images have been created
final File sampleImage1 = new File(TestData.file(this,"."),"nc_sampleimages/BrOsample_image.dat");
final File sampleImage2 = new File(TestData.file(this,"."),"nc_sampleimages/NO2sample_image.dat");
assertTrue(sampleImage1.exists());
assertTrue(sampleImage2.exists());
reader.dispose();
}
@Test
@Ignore
public void oracle() throws IOException, ParseException, NoSuchAuthorityCodeException, FactoryException {
final File workDir=new File("C:\\data\\dlr\\ascatL1_mosaic");
final AbstractGridFormat format = new ImageMosaicFormat();
assertNotNull(format);
ImageMosaicReader reader = (ImageMosaicReader) format.getReader(workDir.toURI().toURL());
assertNotNull(format);
String[] names = reader.getGridCoverageNames();
String name = names[1];
final String[] metadataNames = reader.getMetadataNames(name);
assertNotNull(metadataNames);
assertEquals(metadataNames.length, 18);
assertEquals("false", reader.getMetadataValue(name, "HAS_TIME_DOMAIN"));
assertEquals("true", reader.getMetadataValue(name, "HAS_NUMSIGMA_DOMAIN"));
assertEquals("0,1,2",reader.getMetadataValue(name, "NUMSIGMA_DOMAIN"));
assertEquals("java.lang.Integer", reader.getMetadataValue(name, "NUMSIGMA_DOMAIN_DATATYPE"));
assertEquals("true", reader.getMetadataValue(name, "HAS_RUNTIME_DOMAIN"));
assertEquals("false", reader.getMetadataValue(name, "HAS_ELEVATION_DOMAIN"));
assertEquals("false", reader.getMetadataValue(name, "HAS_XX_DOMAIN"));
assertEquals("20110620020000", reader.getMetadataValue(name, "RUNTIME_DOMAIN"));
assertEquals("java.lang.String", reader.getMetadataValue(name, "RUNTIME_DOMAIN_DATATYPE"));
// limit yourself to reading just a bit of it
final ParameterValue<GridGeometry2D> gg = AbstractGridFormat.READ_GRIDGEOMETRY2D.createValue();
final GeneralEnvelope envelope = reader.getOriginalEnvelope(name);
final Dimension dim= new Dimension();
dim.setSize(reader.getOriginalGridRange(name).getSpan(0)/2.0, reader.getOriginalGridRange(name).getSpan(1)/2.0);
final Rectangle rasterArea=(( GridEnvelope2D)reader.getOriginalGridRange(name));
rasterArea.setSize(dim);
final GridEnvelope2D range= new GridEnvelope2D(rasterArea);
gg.setValue(new GridGeometry2D(range,envelope));
final ParameterValue<Boolean> direct= ImageMosaicFormat.USE_JAI_IMAGEREAD.createValue();
direct.setValue(false);
final ParameterValue<double[]> bkg = ImageMosaicFormat.BACKGROUND_VALUES.createValue();
bkg.setValue(new double[]{-9999.0});
ParameterValue<List<String>> dateValue = null;
ParameterValue<List<String>> sigmaValue = null;
final String selectedSigma = "1";
final String selectedRuntime = "20110620020000";
Set<ParameterDescriptor<List>> params = reader.getDynamicParameters(name);
for (ParameterDescriptor param : params) {
if (param.getName().getCode().equalsIgnoreCase("RUNTIME")) {
dateValue = param.createValue();
dateValue.setValue(new ArrayList<String>() {
{
add(selectedRuntime);
}
});
} else if (param.getName().getCode().equalsIgnoreCase("NUMSIGMA")) {
sigmaValue = param.createValue();
sigmaValue.setValue(new ArrayList<String>() {
{
add(selectedSigma);
}
});
}
}
// Test the output coverage
GridCoverage2D coverage = reader.read(name, new GeneralParameterValue[] {gg, bkg, direct, sigmaValue, dateValue});
assertNotNull(coverage);
}
/**
* Test that expected data values can be read from an ImageMosaic of multi-coverage NetCDF files.
*
* @throws Exception
*/
@Test
public void testMultiCoverage() throws Exception {
File testDir = new File("target", "multi-coverage");
URL testUrl = DataUtilities.fileToURL(testDir);
if (testDir.exists()) {
FileUtils.deleteDirectory(testDir);
}
FileUtils.copyDirectory(TestData.file(this, "multi-coverage"), testDir);
ImageMosaicReader reader = null;
try {
reader = new ImageMosaicReader(testUrl);
assertNotNull(reader);
checkMultiCoverage(reader, "air_temperature", -85, 26, "2017-02-06T00:00:00.000", 295);
checkMultiCoverage(reader, "sea_surface_temperature", -85, 26, "2017-02-06T00:00:00.000", 296);
checkMultiCoverage(reader, "air_temperature", -85, 26, "2017-02-06T12:00:00.000", 296);
checkMultiCoverage(reader, "sea_surface_temperature", -85, 26, "2017-02-06T12:00:00.000", 295);
} finally {
if (reader != null) {
reader.dispose();
}
}
}
/**
* Check that reading a single data value from an ImageMosaic of multi-coverage NetCDF files yields the expected value.
*
* @param reader
* @param coverageName
* @param longitude
* @param latitude
* @param timestamp
* @param expected
* @throws Exception
*/
private void checkMultiCoverage(ImageMosaicReader reader, String coverageName, double longitude,
double latitude, String timestamp, double expected) throws Exception {
ParameterValue<Boolean> useJai = AbstractGridFormat.USE_JAI_IMAGEREAD.createValue();
useJai.setValue(false);
@SuppressWarnings("rawtypes")
ParameterValue<List> time = ImageMosaicFormat.TIME.createValue();
time.setValue(Arrays.asList(new Date[] { parseTimeStamp(timestamp) }));
GeneralParameterValue[] params = new GeneralParameterValue[] { useJai, time };
GridCoverage2D coverage = reader.read(coverageName, params);
assertNotNull(coverage);
// delta is zero because an exact match is expected
assertEquals(expected,
coverage.evaluate(new Point2D.Double(longitude, latitude), (double[]) null)[0], 0);
}
private Date parseTimeStamp(String timeStamp) throws ParseException {
final SimpleDateFormat formatD = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
formatD.setTimeZone(TimeZone.getTimeZone("Zulu"));
return formatD.parse(timeStamp);
}
/**
* Shows the provided {@link RenderedImage} ina {@link JFrame} using the provided <code>title</code> as the frame's title.
*
* @param image to show.
* @param title to use.
*/
static void show(RenderedImage image, String title) {
ImageIOUtilities.visualize(image, title);
}
/**
* @param args
*/
public static void main(String[] args) {
TestRunner.run(NetCDFMosaicReaderTest.suite());
}
@Before
public void init() {
// make sure CRS ordering is correct
System.setProperty("org.geotools.referencing.forceXY", "true");
System.setProperty("user.timezone", "GMT");
System.setProperty("org.geotools.shapefile.datetime", "true");
CRS.reset("all");
}
@AfterClass
public static void close() {
System.clearProperty("org.geotools.referencing.forceXY");
System.clearProperty("user.timezone");
System.clearProperty("org.geotools.shapefile.datetime");
CRS.reset("all");
}
/**
* returns an {@link AbstractGridCoverage2DReader} for the provided {@link URL} and for the providede {@link AbstractGridFormat}.
*
* @param testURL points to a valid object to create an {@link AbstractGridCoverage2DReader} for.
* @param format to use for instantiating such a reader.
* @return a suitable {@link ImageMosaicReader}.
* @throws FactoryException
* @throws NoSuchAuthorityCodeException
*/
static ImageMosaicReader getReader(URL testURL, final AbstractGridFormat format)
throws NoSuchAuthorityCodeException, FactoryException {
// final Hints hints= new Hints(Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM, CRS.decode("EPSG:4326", true));
return getReader(testURL, format, null);
}
static ImageMosaicReader getReader(URL testURL, final AbstractGridFormat format, Hints hints) {
// Get a reader
final ImageMosaicReader reader = (ImageMosaicReader) format.getReader(testURL, hints);
Assert.assertNotNull(reader);
return reader;
}
}