/*
* Copyright (C) 2010 Brockmann Consult GmbH (info@brockmann-consult.de)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at your option)
* any later version.
* This program 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 General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see http://www.gnu.org/licenses/
*/
package org.esa.snap.ui.product;
import com.bc.ceres.binding.PropertySet;
import com.bc.ceres.core.ProgressMonitor;
import com.bc.ceres.glayer.CollectionLayer;
import com.bc.ceres.glayer.Layer;
import com.bc.ceres.glayer.LayerFilter;
import com.bc.ceres.glayer.LayerType;
import com.bc.ceres.glayer.LayerTypeRegistry;
import com.bc.ceres.glayer.support.ImageLayer;
import com.bc.ceres.glayer.support.LayerUtils;
import org.esa.snap.core.datamodel.ImageInfo;
import org.esa.snap.core.datamodel.Mask;
import org.esa.snap.core.datamodel.Product;
import org.esa.snap.core.datamodel.ProductNode;
import org.esa.snap.core.datamodel.ProductNodeGroup;
import org.esa.snap.core.datamodel.RasterDataNode;
import org.esa.snap.core.datamodel.VectorDataNode;
import org.esa.snap.core.image.ColoredBandImageMultiLevelSource;
import org.esa.snap.core.layer.GraticuleLayer;
import org.esa.snap.core.layer.GraticuleLayerType;
import org.esa.snap.core.layer.MaskCollectionLayerType;
import org.esa.snap.core.layer.MaskLayerType;
import org.esa.snap.core.layer.NoDataLayerType;
import org.esa.snap.core.layer.ProductLayerContext;
import org.esa.snap.core.layer.RasterImageLayerType;
import org.esa.snap.core.layer.RgbImageLayerType;
import org.esa.snap.core.util.PropertyMap;
import java.awt.Color;
import java.awt.geom.AffineTransform;
public class ProductSceneImage implements ProductLayerContext {
private static final ImageLayerFilter IMAGE_LAYER_FILTER = new ImageLayerFilter();
private final String name;
private final PropertyMap configuration;
private RasterDataNode[] rasters;
private Layer rootLayer;
private ColoredBandImageMultiLevelSource coloredBandImageMultiLevelSource;
/**
* Creates a color indexed product scene for the given product raster.
*
* @param raster the product raster, must not be null
* @param configuration a configuration
* @param pm a monitor to inform the user about progress @return a color indexed product scene image
*/
public ProductSceneImage(RasterDataNode raster, PropertyMap configuration, ProgressMonitor pm) {
this(raster.getDisplayName(),
new RasterDataNode[]{raster},
configuration);
coloredBandImageMultiLevelSource = ColoredBandImageMultiLevelSource.create(raster, pm);
initRootLayer();
}
/**
* Creates a new scene image for an existing view.
*
* @param raster The product raster.
* @param view An existing view.
*/
public ProductSceneImage(RasterDataNode raster, ProductSceneView view) {
this(raster.getDisplayName(),
new RasterDataNode[]{raster},
view.getSceneImage().getConfiguration());
coloredBandImageMultiLevelSource = view.getSceneImage().getColoredBandImageMultiLevelSource();
initRootLayer();
}
/**
* Creates an RGB product scene for the given raster datasets.
*
* @param name the name of the scene view
* @param redRaster the product raster used for the red color component, must not be null
* @param greenRaster the product raster used for the green color component, must not be null
* @param blueRaster the product raster used for the blue color component, must not be null
* @param configuration a configuration
* @param pm a monitor to inform the user about progress @return an RGB product scene image @throws java.io.IOException if the image creation failed due to an I/O problem
*/
public ProductSceneImage(String name, RasterDataNode redRaster,
RasterDataNode greenRaster,
RasterDataNode blueRaster,
PropertyMap configuration,
ProgressMonitor pm) {
this(name, new RasterDataNode[]{redRaster, greenRaster, blueRaster}, configuration);
coloredBandImageMultiLevelSource = ColoredBandImageMultiLevelSource.create(rasters, pm);
initRootLayer();
}
private ProductSceneImage(String name, RasterDataNode[] rasters, PropertyMap configuration) {
this.name = name;
this.rasters = rasters;
this.configuration = configuration;
}
public PropertyMap getConfiguration() {
return configuration;
}
public String getName() {
return name;
}
public ImageInfo getImageInfo() {
return coloredBandImageMultiLevelSource.getImageInfo();
}
public void setImageInfo(ImageInfo imageInfo) {
coloredBandImageMultiLevelSource.setImageInfo(imageInfo);
}
public RasterDataNode[] getRasters() {
return rasters;
}
public void setRasters(RasterDataNode[] rasters) {
this.rasters = rasters;
}
@Override
public Object getCoordinateReferenceSystem() {
return getProduct().getSceneCRS();
}
@Override
public Layer getRootLayer() {
return rootLayer;
}
Layer getLayer(String id) {
return LayerUtils.getChildLayerById(getRootLayer(), id);
}
void addLayer(int index, Layer layer) {
rootLayer.getChildren().add(index, layer);
}
int getFirstImageLayerIndex() {
return LayerUtils.getChildLayerIndex(getRootLayer(), LayerUtils.SEARCH_DEEP, 0, IMAGE_LAYER_FILTER);
}
ImageLayer getBaseImageLayer() {
return (ImageLayer) getLayer(ProductSceneView.BASE_IMAGE_LAYER_ID);
}
Layer getNoDataLayer(boolean create) {
Layer layer = getLayer(ProductSceneView.NO_DATA_LAYER_ID);
if (layer == null && create) {
layer = createNoDataLayer();
addLayer(getFirstImageLayerIndex(), layer);
}
return layer;
}
Layer getVectorDataCollectionLayer(boolean create) {
Layer layer = getLayer(ProductSceneView.VECTOR_DATA_LAYER_ID);
if (layer == null && create) {
layer = createVectorDataCollectionLayer();
addLayer(getFirstImageLayerIndex(), layer);
}
return layer;
}
Layer getMaskCollectionLayer(boolean create) {
Layer layer = getLayer(ProductSceneView.MASKS_LAYER_ID);
if (layer == null && create) {
layer = createMaskCollectionLayer();
addLayer(getFirstImageLayerIndex(), layer);
}
return layer;
}
GraticuleLayer getGraticuleLayer(boolean create) {
GraticuleLayer layer = (GraticuleLayer) getLayer(ProductSceneView.GRATICULE_LAYER_ID);
if (layer == null && create) {
layer = createGraticuleLayer(getImageToModelTransform());
addLayer(0, layer);
}
return layer;
}
Layer getGcpLayer(boolean create) {
final Product product = getProduct();
if (product != null) {
final VectorDataNode vectorDataNode = product.getGcpGroup().getVectorDataNode();
final Layer vectorDataCollectionLayer = getVectorDataCollectionLayer(create);
if (vectorDataCollectionLayer != null) {
return LayerUtils.getChildLayer(getRootLayer(),
LayerUtils.SEARCH_DEEP,
VectorDataLayerFilterFactory.createNodeFilter(vectorDataNode));
}
}
return null;
}
Layer getPinLayer(boolean create) {
final Product product = getProduct();
if (product != null) {
final VectorDataNode vectorDataNode = product.getPinGroup().getVectorDataNode();
final Layer vectorDataCollectionLayer = getVectorDataCollectionLayer(create);
if (vectorDataCollectionLayer != null) {
return LayerUtils.getChildLayer(getRootLayer(),
LayerUtils.SEARCH_DEEP,
VectorDataLayerFilterFactory.createNodeFilter(vectorDataNode));
}
}
return null;
}
private RasterDataNode getRaster() {
return rasters[0];
}
private void initRootLayer() {
rootLayer = new CollectionLayer();
addLayer(0, createBaseImageLayer());
}
public void initVectorDataCollectionLayer() {
if (mustEnableVectorDataCollectionLayer()) {
getVectorDataCollectionLayer(true);
}
}
public void initMaskCollectionLayer() {
if (mustEnableMaskCollectionLayer()) {
getMaskCollectionLayer(true);
}
}
private boolean mustEnableVectorDataCollectionLayer() {
return getRaster().getProduct().getVectorDataGroup().getNodeCount() > 0;
}
private boolean mustEnableMaskCollectionLayer() {
return getRaster().getOverlayMaskGroup().getNodeCount() > 0;
}
private AffineTransform getImageToModelTransform() {
return coloredBandImageMultiLevelSource.getModel().getImageToModelTransform(0);
}
private Layer createBaseImageLayer() {
final Layer layer;
if (getRasters().length == 1) {
final RasterImageLayerType type = LayerTypeRegistry.getLayerType(RasterImageLayerType.class);
layer = type.createLayer(getRaster(), coloredBandImageMultiLevelSource);
} else {
final RgbImageLayerType type = LayerTypeRegistry.getLayerType(RgbImageLayerType.class);
layer = type.createLayer(getRasters(), coloredBandImageMultiLevelSource);
}
layer.setName(getName());
layer.setVisible(true);
layer.setId(ProductSceneView.BASE_IMAGE_LAYER_ID);
applyBaseImageLayerStyle(configuration, layer);
return layer;
}
static void applyBaseImageLayerStyle(PropertyMap configuration, Layer layer) {
final boolean borderShown = configuration.getPropertyBool("image.border.shown",
ImageLayer.DEFAULT_BORDER_SHOWN);
final double borderWidth = configuration.getPropertyDouble("image.border.size",
ImageLayer.DEFAULT_BORDER_WIDTH);
final Color borderColor = configuration.getPropertyColor("image.border.color",
ImageLayer.DEFAULT_BORDER_COLOR);
final boolean pixelBorderShown = configuration.getPropertyBool("pixel.border.shown",
ImageLayer.DEFAULT_PIXEL_BORDER_SHOWN);
final double pixelBorderWidth = configuration.getPropertyDouble("pixel.border.size",
ImageLayer.DEFAULT_PIXEL_BORDER_WIDTH);
final Color pixelBorderColor = configuration.getPropertyColor("pixel.border.color",
ImageLayer.DEFAULT_PIXEL_BORDER_COLOR);
final PropertySet layerConfiguration = layer.getConfiguration();
layerConfiguration.setValue(ImageLayer.PROPERTY_NAME_BORDER_SHOWN, borderShown);
layerConfiguration.setValue(ImageLayer.PROPERTY_NAME_BORDER_WIDTH, borderWidth);
layerConfiguration.setValue(ImageLayer.PROPERTY_NAME_BORDER_COLOR, borderColor);
layerConfiguration.setValue(ImageLayer.PROPERTY_NAME_PIXEL_BORDER_SHOWN, pixelBorderShown);
layerConfiguration.setValue(ImageLayer.PROPERTY_NAME_PIXEL_BORDER_WIDTH, pixelBorderWidth);
layerConfiguration.setValue(ImageLayer.PROPERTY_NAME_PIXEL_BORDER_COLOR, pixelBorderColor);
}
private Layer createNoDataLayer() {
final LayerType noDataType = LayerTypeRegistry.getLayerType(NoDataLayerType.class);
final PropertySet configTemplate = noDataType.createLayerConfig(null);
final Color color = configuration.getPropertyColor("noDataOverlay.color", Color.ORANGE);
configTemplate.setValue(NoDataLayerType.PROPERTY_NAME_COLOR, color);
configTemplate.setValue(NoDataLayerType.PROPERTY_NAME_RASTER, getRaster());
final Layer layer = noDataType.createLayer(this, configTemplate);
final double transparency = configuration.getPropertyDouble("noDataOverlay.transparency", 0.3);
layer.setTransparency(transparency);
return layer;
}
private synchronized Layer createVectorDataCollectionLayer() {
final LayerType collectionLayerType = LayerTypeRegistry.getLayerType(VectorDataCollectionLayerType.class);
final Layer collectionLayer = collectionLayerType.createLayer(this, collectionLayerType.createLayerConfig(this));
final ProductNodeGroup<VectorDataNode> vectorDataGroup = getRaster().getProduct().getVectorDataGroup();
final VectorDataNode[] vectorDataNodes = vectorDataGroup.toArray(new VectorDataNode[vectorDataGroup.getNodeCount()]);
for (final VectorDataNode vectorDataNode : vectorDataNodes) {
final Layer layer = VectorDataLayerType.createLayer(this, vectorDataNode);
collectionLayer.getChildren().add(layer);
}
return collectionLayer;
}
private synchronized Layer createMaskCollectionLayer() {
final LayerType maskCollectionType = LayerTypeRegistry.getLayerType(MaskCollectionLayerType.class);
final PropertySet layerConfig = maskCollectionType.createLayerConfig(null);
layerConfig.setValue(MaskCollectionLayerType.PROPERTY_NAME_RASTER, getRaster());
final Layer maskCollectionLayer = maskCollectionType.createLayer(this, layerConfig);
ProductNodeGroup<Mask> productNodeGroup = getRaster().getProduct().getMaskGroup();
final RasterDataNode raster = getRaster();
for (int i = 0; i < productNodeGroup.getNodeCount(); i++) {
final Mask mask = productNodeGroup.get(i);
//todo add all mask layers as soon as the masks have been scaled to fit the raster
if (raster.getRasterSize().equals(mask.getRasterSize())) {
Layer layer = MaskLayerType.createLayer(raster, mask);
maskCollectionLayer.getChildren().add(layer);
}
}
return maskCollectionLayer;
}
static void applyNoDataLayerStyle(PropertyMap configuration, Layer layer) {
final PropertySet layerConfiguration = layer.getConfiguration();
final Color color = configuration.getPropertyColor("noDataOverlay.color", NoDataLayerType.DEFAULT_COLOR);
layerConfiguration.setValue(NoDataLayerType.PROPERTY_NAME_COLOR, color);
final double transparency = configuration.getPropertyDouble("noDataOverlay.transparency", 0.3);
layer.setTransparency(transparency);
}
static void applyFigureLayerStyle(PropertyMap configuration, Layer layer) {
final PropertySet layerConfiguration = layer.getConfiguration();
/*
layerConfiguration.setValue(VectorDataLayer.PROPERTY_NAME_SHAPE_OUTLINED,
configuration.getPropertyBool(VectorDataLayer.PROPERTY_NAME_SHAPE_OUTLINED,
VectorDataLayer.DEFAULT_SHAPE_OUTLINED));
layerConfiguration.setValue(VectorDataLayer.PROPERTY_NAME_SHAPE_OUTL_COLOR,
configuration.getPropertyColor(VectorDataLayer.PROPERTY_NAME_SHAPE_OUTL_COLOR,
VectorDataLayer.DEFAULT_SHAPE_OUTL_COLOR));
layerConfiguration.setValue(VectorDataLayer.PROPERTY_NAME_SHAPE_OUTL_TRANSPARENCY,
configuration.getPropertyDouble(
VectorDataLayer.PROPERTY_NAME_SHAPE_OUTL_TRANSPARENCY,
VectorDataLayer.DEFAULT_SHAPE_OUTL_TRANSPARENCY));
layerConfiguration.setValue(VectorDataLayer.PROPERTY_NAME_SHAPE_OUTL_WIDTH,
configuration.getPropertyDouble(VectorDataLayer.PROPERTY_NAME_SHAPE_OUTL_WIDTH,
VectorDataLayer.DEFAULT_SHAPE_OUTL_WIDTH));
layerConfiguration.setValue(VectorDataLayer.PROPERTY_NAME_SHAPE_FILLED,
configuration.getPropertyBool(VectorDataLayer.PROPERTY_NAME_SHAPE_FILLED,
VectorDataLayer.DEFAULT_SHAPE_FILLED));
layerConfiguration.setValue(VectorDataLayer.PROPERTY_NAME_SHAPE_FILL_COLOR,
configuration.getPropertyColor(VectorDataLayer.PROPERTY_NAME_SHAPE_FILL_COLOR,
VectorDataLayer.DEFAULT_SHAPE_FILL_COLOR));
layerConfiguration.setValue(VectorDataLayer.PROPERTY_NAME_SHAPE_FILL_TRANSPARENCY,
configuration.getPropertyDouble(
VectorDataLayer.PROPERTY_NAME_SHAPE_FILL_TRANSPARENCY,
VectorDataLayer.DEFAULT_SHAPE_FILL_TRANSPARENCY));
*/
}
private GraticuleLayer createGraticuleLayer(AffineTransform i2mTransform) {
final LayerType layerType = LayerTypeRegistry.getLayerType(GraticuleLayerType.class);
final PropertySet template = layerType.createLayerConfig(null);
template.setValue(GraticuleLayerType.PROPERTY_NAME_RASTER, getRaster());
final GraticuleLayer graticuleLayer = (GraticuleLayer) layerType.createLayer(null, template);
graticuleLayer.setId(ProductSceneView.GRATICULE_LAYER_ID);
graticuleLayer.setVisible(false);
graticuleLayer.setName("Graticule");
applyGraticuleLayerStyle(configuration, graticuleLayer);
return graticuleLayer;
}
static void applyGraticuleLayerStyle(PropertyMap configuration, Layer layer) {
final PropertySet layerConfiguration = layer.getConfiguration();
layerConfiguration.setValue(GraticuleLayerType.PROPERTY_NAME_RES_AUTO,
configuration.getPropertyBool(GraticuleLayerType.PROPERTY_NAME_RES_AUTO,
GraticuleLayerType.DEFAULT_RES_AUTO));
layerConfiguration.setValue(GraticuleLayerType.PROPERTY_NAME_RES_PIXELS,
configuration.getPropertyInt(GraticuleLayerType.PROPERTY_NAME_RES_PIXELS,
GraticuleLayerType.DEFAULT_RES_PIXELS));
layerConfiguration.setValue(GraticuleLayerType.PROPERTY_NAME_RES_LAT,
configuration.getPropertyDouble(GraticuleLayerType.PROPERTY_NAME_RES_LAT,
GraticuleLayerType.DEFAULT_RES_LAT));
layerConfiguration.setValue(GraticuleLayerType.PROPERTY_NAME_RES_LON,
configuration.getPropertyDouble(GraticuleLayerType.PROPERTY_NAME_RES_LON,
GraticuleLayerType.DEFAULT_RES_LON));
layerConfiguration.setValue(GraticuleLayerType.PROPERTY_NAME_LINE_COLOR,
configuration.getPropertyColor(GraticuleLayerType.PROPERTY_NAME_LINE_COLOR,
GraticuleLayerType.DEFAULT_LINE_COLOR));
layerConfiguration.setValue(GraticuleLayerType.PROPERTY_NAME_LINE_WIDTH,
configuration.getPropertyDouble(GraticuleLayerType.PROPERTY_NAME_LINE_WIDTH,
GraticuleLayerType.DEFAULT_LINE_WIDTH));
layerConfiguration.setValue(GraticuleLayerType.PROPERTY_NAME_LINE_TRANSPARENCY,
configuration.getPropertyDouble(
GraticuleLayerType.PROPERTY_NAME_LINE_TRANSPARENCY,
GraticuleLayerType.DEFAULT_LINE_TRANSPARENCY));
layerConfiguration.setValue(GraticuleLayerType.PROPERTY_NAME_TEXT_ENABLED,
configuration.getPropertyBool(GraticuleLayerType.PROPERTY_NAME_TEXT_ENABLED,
GraticuleLayerType.DEFAULT_TEXT_ENABLED));
layerConfiguration.setValue(GraticuleLayerType.PROPERTY_NAME_TEXT_FG_COLOR,
configuration.getPropertyColor(GraticuleLayerType.PROPERTY_NAME_TEXT_FG_COLOR,
GraticuleLayerType.DEFAULT_TEXT_FG_COLOR));
layerConfiguration.setValue(GraticuleLayerType.PROPERTY_NAME_TEXT_BG_COLOR,
configuration.getPropertyColor(GraticuleLayerType.PROPERTY_NAME_TEXT_BG_COLOR,
GraticuleLayerType.DEFAULT_TEXT_BG_COLOR));
layerConfiguration.setValue(GraticuleLayerType.PROPERTY_NAME_TEXT_BG_TRANSPARENCY,
configuration.getPropertyDouble(
GraticuleLayerType.PROPERTY_NAME_TEXT_BG_TRANSPARENCY,
GraticuleLayerType.DEFAULT_TEXT_BG_TRANSPARENCY));
}
private ColoredBandImageMultiLevelSource getColoredBandImageMultiLevelSource() {
return coloredBandImageMultiLevelSource;
}
@Override
public Product getProduct() {
return getRaster().getProduct();
}
@Override
public ProductNode getProductNode() {
return getRaster();
}
private static class ImageLayerFilter implements LayerFilter {
@Override
public boolean accept(Layer layer) {
return layer instanceof ImageLayer;
}
}
}