/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2005-2008, 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.renderer.lite.gridcoverage2d;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.factory.Hints;
import org.geotools.renderer.i18n.ErrorKeys;
import org.geotools.renderer.i18n.Errors;
import org.geotools.renderer.i18n.Vocabulary;
import org.geotools.renderer.i18n.VocabularyKeys;
import org.geotools.styling.ChannelSelection;
import org.geotools.styling.SelectedChannelType;
import org.geotools.styling.StyleVisitor;
import org.geotools.util.SimpleInternationalString;
import org.opengis.util.InternationalString;
/**
* {@link CoverageProcessingNode} that actually implement a
* {@link ChannelSelection} operation as stated in SLD 1.0 spec from OGC.
* <p>
* This node internally creates a small chain that does all that�'s needed to
* satisfy a {@link ChannelSelection} element.
*
* @author Simone Giannecchini, GeoSolutions
*/
class ChannelSelectionNode extends SubchainStyleVisitorCoverageProcessingAdapter
implements StyleVisitor, CoverageProcessingNode {
/** Logger for this class. */
private final static Logger LOGGER = Logger.getLogger(ChannelSelectionNode.class.getName());
/*
* (non-Javadoc)
* @see CoverageProcessingNode#getName()
*/
public InternationalString getName() {
return Vocabulary.formatInternational(VocabularyKeys.CHANNEL_SELECTION);
}
/**
* Default Constructor
*/
public ChannelSelectionNode() {
this(null);
}
/**
* Constructor with support for {@link Hints}
*
* @param hints
* control the internal machinery for factories.
*/
public ChannelSelectionNode(Hints hints) {
super(
3,
hints,
SimpleInternationalString.wrap("ChannelSelectionNode"),
SimpleInternationalString.wrap("Node which applies a ChannelSelection following SLD 1.0 spec."));
}
/*
* (non-Javadoc)
*
* @see org.geotools.renderer.lite.gridcoverage2d.StyleVisitorAdapter#visit(org.geotools.styling.ChannelSelection)
*/
public synchronized void visit(final ChannelSelection cs) {
// /////////////////////////////////////////////////////////////////////
//
// Ensure that the ChannelSelection is not null and that the source is
// not null
//
// /////////////////////////////////////////////////////////////////////
final List <CoverageProcessingNode>localSources = getSources();
final int length = localSources.size();
if (length == 0)
throw new IllegalArgumentException(Errors.format(
ErrorKeys.SOURCE_CANT_BE_NULL_$1, "ChannelSelectionNode"));
final GridCoverage2D source = (GridCoverage2D) getSource(0).getOutput();
ensureSourceNotNull(source, this.getName().toString());
// /////////////////////////////////////////////////////////////////////
//
// Get the channel selection and parse it in order to create the
// subchain
//
// /////////////////////////////////////////////////////////////////////
//creating a new separate chain
final RootNode chainSource = new RootNode(source, getHints());
final BandMergeNode subChainSink = new BandMergeNode(getHints());
//anchoring the chain for later disposal
setSink(subChainSink);
final SelectedChannelType[] rgb=cs.getRGBChannels();
final SelectedChannelType gray=cs.getGrayChannel();
// both of them are set?
if((rgb!=null&&rgb[0]!=null&&rgb[1]!=null&&rgb[2]!=null)&&(gray!=null))
throw new IllegalArgumentException(Errors.format(
ErrorKeys.ILLEGAL_ARGUMENT_$1, "Both gray and rgb channel selection are valid!"));
final SelectedChannelType[] sc = gray==null?rgb:new SelectedChannelType[]{gray};
// If we do not really select any bands from the original coverage, we try to entirely skip this operation
// this means that either we have to select 1 real band, or we have to select 3 real bands
// Notice that we also try to be as resilient as possible since
if (sc != null && ((sc.length ==1 &&sc[0]!=null)||(sc.length ==3 &&sc[0]!=null&&sc[1]!=null&&sc[2]!=null))) {
// //
//
// Note that we can either select 1 (GRAY) or 3 (RGB) bands.
//
// //
if (sc.length != 3 && sc.length != 1)
throw new IllegalArgumentException(Errors.format(
ErrorKeys.BAD_BAND_NUMBER_$1, Integer.valueOf(sc.length)));
for (int i = 0; i < sc.length; i++) {
// get the channel element
final SelectedChannelType channel = sc[i];
if(LOGGER.isLoggable(Level.FINE))
LOGGER.fine("Channel "+i+" was "+ channel.getChannelName());
// //
//
// BAND SELECTION
//
// //
final BandSelectionNode bandSelectionNode = new BandSelectionNode();
bandSelectionNode.addSource(chainSource);
bandSelectionNode.visit(channel);
// //
//
// CONTRAST ENHANCEMENT
//
// //
final ContrastEnhancementNode contrastenhancementNode = new ContrastEnhancementNode();
contrastenhancementNode.addSource(bandSelectionNode);
bandSelectionNode.addSink(contrastenhancementNode);
contrastenhancementNode.visit(channel != null ? channel.getContrastEnhancement() : null);
// //
//
// BAND MERGE
//
// //
contrastenhancementNode.addSink(subChainSink);
subChainSink.addSource(contrastenhancementNode);
}
return;
}
// no band selection, just forward this node
subChainSink.addSource(chainSource);
}
}