package org.esa.snap.rcp.util; import org.esa.snap.core.dataio.ProductSubsetDef; import org.esa.snap.core.datamodel.AbstractGeoCoding; import org.esa.snap.core.datamodel.Band; import org.esa.snap.core.datamodel.CrsGeoCoding; import org.esa.snap.core.datamodel.GeoPos; import org.esa.snap.core.datamodel.MetadataElement; import org.esa.snap.core.datamodel.PixelPos; import org.esa.snap.core.datamodel.Product; import org.esa.snap.core.datamodel.ProductData; import org.esa.snap.core.datamodel.Scene; import org.esa.snap.core.datamodel.TiePointGrid; import org.esa.snap.core.datamodel.VirtualBand; import org.esa.snap.core.dataop.maptransf.Datum; import org.esa.snap.core.transform.AffineTransform2D; import org.geotools.referencing.crs.DefaultGeographicCRS; import org.opengis.referencing.FactoryException; import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.TransformException; import javax.media.jai.operator.ConstantDescriptor; import java.awt.Color; import java.awt.geom.AffineTransform; import java.awt.geom.NoninvertibleTransformException; import java.awt.geom.Point2D; import java.util.Random; /** * Creates product instances for testing. * * @author Norman Fomferra */ public class TestProducts { public static Product[] createProducts() { return new Product[]{createProduct1(), createProduct2(), createProduct3(), createProduct4(), createProduct5(), createProduct6() }; } public static Product createProduct1() { Product product = new Product("Test_Product_1", "Test_Type_1", 2048, 1024); product.addTiePointGrid(new TiePointGrid("Grid_A", 32, 16, 0, 0, 2048f / 32, 1024f / 16, createRandomPoints(32 * 16))); product.addTiePointGrid(new TiePointGrid("Grid_B", 32, 16, 0, 0, 2048f / 32, 1024f / 16, createRandomPoints(32 * 16))); product.addBand("Band_A", "sin(4 * PI * sqrt( sq(X/1000.0 - 1) + sq(Y/500.0 - 1) ))"); product.addBand("Band_B", "sin(4 * PI * sqrt( 2.0 * abs(X/1000.0 * Y/500.0) ))"); product.addMask("Mask_A", "Band_A > 0.5", "I am Mask A", Color.ORANGE, 0.5); product.addMask("Mask_B", "Band_B < 0.0", "I am Mask B", Color.RED, 0.5); product.getMetadataRoot().addElement(new MetadataElement("Global_Attributes")); product.getMetadataRoot().addElement(new MetadataElement("Local_Attributes")); product.setModified(false); double sx = 40.0 / product.getSceneRasterWidth(); AffineTransform at = new AffineTransform(); at.translate(-80, -30); at.rotate(0.3, 20.0, 10.0); at.scale(sx, sx); product.setSceneGeoCoding(new ATGeoCoding(at)); return product; } public static Product createProduct2() { Product product = new Product("Test_Product_2", "Test_Type_2", 1024, 2048); product.addTiePointGrid(new TiePointGrid("Grid_1", 16, 32, 0, 0, 1024f / 16, 2048f / 32, createRandomPoints(32 * 16))); product.addTiePointGrid(new TiePointGrid("Grid_2", 16, 32, 0, 0, 1024f / 16, 2048f / 32, createRandomPoints(32 * 16))); product.addBand("Band_1", "cos(X/100)-sin(Y/100)"); product.addBand("Band_2", "sin(X/100)+cos(Y/100)"); product.addBand("Band_3", "cos(X/100)*cos(Y/100)"); product.addBand("Band_1_Unc", "cos(3*X/100)-sin(3*Y/100)"); product.addBand("Band_2_Unc", "sin(3*X/100)+cos(3*Y/100)"); product.addBand("Band_3_Unc", "cos(3*X/100)*cos(3*Y/100)"); product.getBand("Band_1").addAncillaryVariable(product.getBand("Band_1_Unc"), "uncertainty"); product.getBand("Band_2").addAncillaryVariable(product.getBand("Band_2_Unc"), "uncertainty"); product.getBand("Band_3").addAncillaryVariable(product.getBand("Band_3_Unc"), "uncertainty"); product.addMask("Mask_1", "Band_1 > 0.5", "I am Mask 1", Color.GREEN, 0.5); product.addMask("Mask_2", "Band_2 < 0.0", "I am Mask 2", Color.CYAN, 0.5); product.addMask("Mask_3", "Band_3 > -0.1 && Band_3 < 0.1", "I am Mask 3", Color.BLUE, 0.5); product.getMetadataRoot().addElement(new MetadataElement("Global_Attributes")); product.getMetadataRoot().addElement(new MetadataElement("Local_Attributes")); product.setModified(false); double sx = 20.0 / product.getSceneRasterWidth(); AffineTransform at = new AffineTransform(); at.scale(sx, sx); at.rotate(-0.2, 10.0, 10.0); product.setSceneGeoCoding(new ATGeoCoding(at)); product.addBand("A", "Band_1"); product.addBand("B", "Band_1 + Band_2 + Band_3"); product.addBand("C", "Band_1 / (2.3 + Band_2 + Band_3)"); product.addBand("D", "pow(Band_1, 3) / (pow(Band_1, 3) + pow(Band_3, 3))"); return product; } public static Product createProduct3() { int size = 10 * 1024; Product product = new Product("Test_Product_3", "Test_Type_3", size, size); product.setPreferredTileSize(512, 512); Band band1 = new Band("Big_Band_1", ProductData.TYPE_FLOAT64, product.getSceneRasterWidth(), product.getSceneRasterHeight()); Band band2 = new Band("Big_Band_2", ProductData.TYPE_FLOAT64, product.getSceneRasterWidth(), product.getSceneRasterHeight()); Band band3 = new Band("Big_Band_3", ProductData.TYPE_FLOAT64, product.getSceneRasterWidth(), product.getSceneRasterHeight()); Band band4 = new Band("Big_Band_4", ProductData.TYPE_FLOAT64, product.getSceneRasterWidth(), product.getSceneRasterHeight()); Band band5 = new Band("Big_Band_5", ProductData.TYPE_FLOAT64, product.getSceneRasterWidth(), product.getSceneRasterHeight()); band1.setSourceImage(ConstantDescriptor.create(1f * size, 1F * size, new Double[]{1.0}, null)); band2.setSourceImage(ConstantDescriptor.create(1f * size, 1F * size, new Double[]{2.0}, null)); band3.setSourceImage(ConstantDescriptor.create(1f * size, 1F * size, new Double[]{3.0}, null)); band4.setSourceImage(ConstantDescriptor.create(1f * size, 1F * size, new Double[]{4.0}, null)); band5.setSourceImage(ConstantDescriptor.create(1f * size, 1F * size, new Double[]{5.0}, null)); product.addBand(band1); product.addBand(band2); product.addBand(band3); product.addBand(band4); product.addBand(band5); product.setModified(true); double sx = 30.0 / product.getSceneRasterWidth(); AffineTransform at = new AffineTransform(); at.translate(100, 0.0); at.rotate(0.1, 15.0, 15.0); at.scale(sx, sx); product.setSceneGeoCoding(new ATGeoCoding(at)); return product; } public static Product createProduct4() { Product product = new Product("Test_Product_4", "Test_Type_4", 512, 512); product.getMetadataRoot().addElement(new MetadataElement("Global_Attributes")); product.getMetadataRoot().addElement(new MetadataElement("Local_Attributes")); product.setModified(false); double sx = 10.0 / product.getSceneRasterWidth(); VirtualBand band4 = new VirtualBand("Band_4", ProductData.TYPE_FLOAT64, 512, 512, "cos(ampl((X-256)/100, (Y-256)/100))"); product.addBand(band4); AffineTransform at4 = new AffineTransform(); at4.scale(0.5 * sx, 0.5 * sx); at4.rotate(-0.2, 5.0, 5.0); at4.translate(256, 256); product.setSceneGeoCoding(new ATGeoCoding(at4)); return product; } public static Product createProduct5() { try { Product product = new Product("Test_Product_5_CRS", "Test_Type_5_CRS", 512, 512); product.getMetadataRoot().addElement(new MetadataElement("Global_Attributes")); product.getMetadataRoot().addElement(new MetadataElement("Local_Attributes")); product.setModified(false); product.addBand("Band_A", "sin(4 * PI * sqrt( sq(X/1000.0 - 1) + sq(Y/500.0 - 1) ))"); product.setSceneGeoCoding(new CrsGeoCoding(DefaultGeographicCRS.WGS84, 512, 512, 0, 10, 1, 1)); final String b_expression = "sin(4 * PI * sqrt( 2.0 * abs(X/1000.0 * Y/500.0) ))"; final VirtualBand band_b = new VirtualBand("Band_B", ProductData.TYPE_FLOAT32, 1024, 256, b_expression); band_b.setGeoCoding(new CrsGeoCoding(DefaultGeographicCRS.WGS84, 1024, 256, 0, 10, 0.5, 2.0)); band_b.setNoDataValueUsed(true); product.addBand(band_b); return product; } catch (FactoryException | TransformException e) { return null; } } public static Product createProduct6() { try { Product product = new Product("Test_Product_6_SceneRasterTransforms", "Test_Type_6_SceneRasterTransforms", 512, 512); product.getMetadataRoot().addElement(new MetadataElement("Global_Attributes")); product.getMetadataRoot().addElement(new MetadataElement("Local_Attributes")); product.setModified(false); final String a_expression = "sin(4 * PI * sqrt( sq(X/1000.0 - 1) + sq(Y/500.0 - 1) ))"; final Band band_a = new VirtualBand("Band_A", ProductData.TYPE_FLOAT32, 2048, 1024, a_expression); final AffineTransform a_forward = new AffineTransform(); a_forward.scale(0.25, 0.5); final AffineTransform a_inverse = a_forward.createInverse(); band_a.setModelToSceneTransform(new AffineTransform2D(a_forward)); band_a.setSceneToModelTransform(new AffineTransform2D(a_inverse)); product.addBand(band_a); final String b_expression = "sin(4 * PI * sqrt( 2.0 * abs(X/1000.0 * Y/500.0) ))"; final VirtualBand band_b = new VirtualBand("Band_B", ProductData.TYPE_FLOAT32, 128, 256, b_expression); final AffineTransform b_forward = new AffineTransform(); b_forward.scale(2.0, 2.0); b_forward.translate(128, 0); final AffineTransform b_inverse = b_forward.createInverse(); band_b.setModelToSceneTransform(new AffineTransform2D(b_forward)); band_b.setSceneToModelTransform(new AffineTransform2D(b_inverse)); band_b.setNoDataValue(Double.NaN); band_b.setNoDataValueUsed(true); product.addBand(band_b); return product; } catch (NoninvertibleTransformException e) { return null; } } // public static Product createProduct7() { // Product product = new Product("Test_Product_3_different_tie_point_geocodings", "Test_Type_3_different_tie_point_geocodings", 1024, 2048); // product.addTiePointGrid(new TiePointGrid("Grid_1", 16, 32, 0, 0, 1024f / 16, 2048f / 32, createRandomPoints(32 * 16))); // product.addTiePointGrid(new TiePointGrid("Grid_2", 16, 32, 0, 0, 1024f / 16, 2048f / 32, createRandomPoints(32 * 16))); // product.addBand("Band_1", "cos(X/100)-sin(Y/100)"); // product.addMask("Mask_1", "Band_1 > 0.5", "I am Mask 1", Color.GREEN, 0.5); // product.getMetadataRoot().addElement(new MetadataElement("Global_Attributes")); // product.getMetadataRoot().addElement(new MetadataElement("Local_Attributes")); // product.setModified(false); // double sx = 20.0 / product.getSceneRasterWidth(); // AffineTransform at = new AffineTransform(); // at.scale(sx, sx); // at.rotate(-0.2, 10.0, 10.0); // product.setSceneGeoCoding(new ATGeoCoding(at)); // // Band band2 = new Band("Band_2", ProductData.TYPE_FLOAT64, 512, 512); // final VirtualBandOpImage image = VirtualBandOpImage. // builder("cos(ampl((X-256)/100, (Y-256)/100))", product). // sourceSize(band2.getRasterSize()). // dataType(band2.getDataType()). // create(); // // AffineTransform at_model_2 = new AffineTransform(); // at_model_2.scale(0.5, 0.5); // at_model_2.translate(128, 128); // final DefaultMultiLevelModel targetModel = new DefaultMultiLevelModel(at_model_2, 512, 512); // final DefaultMultiLevelModel targetModel = new DefaultMultiLevelModel(at2, 512, 512); // final DefaultMultiLevelModel targetModel = new DefaultMultiLevelModel(new AffineTransform(), 512, 512); // final DefaultMultiLevelSource targetMultiLevelSource = new DefaultMultiLevelSource(image, targetModel); // band2.setSourceImage(new DefaultMultiLevelImage(targetMultiLevelSource)); // product.addBand(band2); // AffineTransform at2 = new AffineTransform(); // at2.scale(0.5 * sx, 0.5 * sx); // at2.scale(0.5, 0.5); // at2.rotate(-0.2, 5.0, 5.0); // at2.translate(256, 256); // band2.setGeoCoding(new ATGeoCoding(at2)); // band2.setNoDataValue(-1.0); // band2.setNoDataValueUsed(true); // return product; // } private static float[] createRandomPoints(int n) { Random random = new Random(); float[] pnts = new float[n]; for (int i = 0; i < pnts.length; i++) { pnts[i] = (float) random.nextGaussian(); } return pnts; } private static class ATGeoCoding extends AbstractGeoCoding { private static final PixelPos INVALID_PIXEL_POS = new PixelPos(Double.NaN, Double.NaN); private final AffineTransform affineTransform; public ATGeoCoding(AffineTransform affineTransform) { this.affineTransform = affineTransform; } @Override public boolean transferGeoCoding(Scene srcScene, Scene destScene, ProductSubsetDef subsetDef) { return false; } @Override public boolean isCrossingMeridianAt180() { return false; } @Override public boolean canGetPixelPos() { return true; } @Override public boolean canGetGeoPos() { return true; } @Override public PixelPos getPixelPos(GeoPos geoPos, PixelPos pixelPos) { try { Point2D p = affineTransform.inverseTransform(new Point2D.Double(geoPos.lon, geoPos.lat), null); if (pixelPos == null) { pixelPos = new PixelPos(); } pixelPos.x = p.getX(); pixelPos.y = p.getY(); return pixelPos; } catch (NoninvertibleTransformException e) { return INVALID_PIXEL_POS; } } @Override public GeoPos getGeoPos(PixelPos pixelPos, GeoPos geoPos) { Point2D point2D = affineTransform.transform(pixelPos, null); if (geoPos == null) { geoPos = new GeoPos(); } geoPos.lon = point2D.getX(); geoPos.lat = point2D.getY(); return geoPos; } @Override public Datum getDatum() { return Datum.WGS_84; } @Override public MathTransform getImageToMapTransform() { return new AffineTransform2D(affineTransform); } @Override public void dispose() { } } }