Package org.geotools.renderer.lite.gridcoverage2d

Source Code of org.geotools.renderer.lite.gridcoverage2d.ColorMapNode

/*
*    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.awt.Color;
import java.awt.image.DataBuffer;
import java.awt.image.RenderedImage;
import java.awt.image.renderable.ParameterBlock;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.media.jai.JAI;
import javax.media.jai.OperationDescriptor;
import javax.media.jai.RenderedOp;

import org.geotools.coverage.GridSampleDimension;
import org.geotools.coverage.TypeMap;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.factory.Hints;
import org.geotools.referencing.piecewise.Domain1D;
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.ColorMap;
import org.geotools.styling.ColorMapEntry;
import org.geotools.styling.StyleVisitor;
import org.geotools.util.SimpleInternationalString;
import org.geotools.util.logging.Logging;
import org.opengis.coverage.SampleDimensionType;
import org.opengis.coverage.grid.GridCoverage;
import org.opengis.util.InternationalString;

/**
* This           {@link CoverageProcessingNode}           is responsible for visiting the supplied          {@link ColorMapTransform}           and applying it to the source           {@link GridCoverage2D}          . <p> <strong>What we support and how do we implement it</strong> <p> A ColorMapTransform is created in order to map categories to colors on a single band coverage (or on the visible band of multiband coverage). <p> In this implementation we allow users to use either 256 or 65536 colors via the creation of a paletted image with s suitable palette derived from the single           {@link ColorMapEntry}           that make up the           {@link ColorMapTransform}          .
* @author           Simone Giannecchini, GeoSolutions
* @see  ColorMapTransform
*/
class ColorMapNode extends StyleVisitorCoverageProcessingNodeAdapter implements
    StyleVisitor, CoverageProcessingNode {

  /*
   * (non-Javadoc)
   * @see CoverageProcessingNode#getName()
   */
  public InternationalString getName() {
    return Vocabulary.formatInternational(VocabularyKeys.COLOR_MAP);
  }

  /** {@link Logger} for this class. */
  private final static Logger LOGGER = Logging.getLogger(ColorMapNode.class.getName());
  static {
    try {
      if (JAI.getDefaultInstance().getOperationRegistry().getDescriptor(
          OperationDescriptor.class, RasterClassifier.OPERATION_NAME) == null)
        RasterClassifier.register(JAI.getDefaultInstance());
    } catch (Exception e) {
      LOGGER.log(Level.SEVERE, e.getLocalizedMessage(), e);
    }
  }

  /**
   * Stores the type of {@link ColorMapTransform} we want to use for this node.
   *
   *
   * <p>
   * Possible types are
   * <ol>
   * <li>TYPE_RAMP which will build a ramp f colors using linear
   * interpolation</li>
   * <li>TYPE_INTERVALS which would do classifications, i.e. would map
   * intervals to colors</li>
   * <li>TYPE_VALUES, which would do single value slicing</li>
   * </ol>
   *
   */
  private int type;

  /**
   * The {@link Domain1D} that we build while parsing the various
   * {@link ColorMapEntry}s provided by the {@link ColorMapTransform} we visit. This
   * {@link LinearColorMap} we'll help us buld the colormapped
   * image.
   */
  private LinearColorMap colorMapTransform;

  /**
     * Do we want 16 bits or 8 bits colormap?
     * @uml.property  name="extendedColors"
     */
  private boolean extendedColors;

  /**
   * Visits the provided {@link ColorMapTransform} and build up a {@link Domain1D}
   * for later creation of a palette rendering for this coverage.
   */
  public void visit(ColorMap colorMap) {
    // //
    //
    // This allows this node to work in store-and-forward way in case we had
    // nothing to do
    //
    // //
    if (colorMap == null)
      return;

    // /////////////////////////////////////////////////////////////////////
    //
    // Get the type and check it. In case the type or the entries are
    // invalid we skip this node.
    //
    // /////////////////////////////////////////////////////////////////////
    this.type = colorMap.getType();
    this.extendedColors = colorMap.getExtendedColors();
    final ColorMapEntry[] cmEntries = colorMap.getColorMapEntries();
    if (cmEntries != null && cmEntries.length > 0) {

      // /////////////////////////////////////////////////////////////////////
      //
      // Check the source coverage and, if it has more than one band
      // reduce it to 1 band using the visible band.
      //
      // If do not manage to do so, let's throw an exception since as per
      // Craig Bruce email it is an error to apply a ColoMap to a
      // multiband coverage.
      //
      // /////////////////////////////////////////////////////////////////////
      final CoverageProcessingNode source=getSource(0);
      GridCoverageRendererUtilities.ensureSourceNotNull(source, "ColorMapNode");
      final GridCoverage2D sourceCoverage = (GridCoverage2D) source.getOutput();
      GridCoverageRendererUtilities.ensureSourceNotNull(sourceCoverage, "ColorMapNode");
      final int numSD = sourceCoverage.getNumSampleDimensions();
      if (numSD>1)
        throw new IllegalArgumentException(
            Errors.format(ErrorKeys.BAD_BAND_NUMBER_$1,Integer.valueOf(numSD)));
      // /////////////////////////////////////////////////////////////////////
      //
      // Check the sample dimension we are going to use for NoData
      // categories.
      //
      // It is important to have such categories since we might have holes
      // in the categories we are going to build hence it is important to
      // have a valid NoDataValue that we can use.
      //
      // /////////////////////////////////////////////////////////////////////
      final GridSampleDimension candidateSD = (GridSampleDimension) sourceCoverage.getSampleDimension(0);
      double[] candidateNoDataValues = preparaNoDataValues(candidateSD);

      // /////////////////////////////////////////////////////////////////////
      //
      // Main Loop
      //
      // /////////////////////////////////////////////////////////////////////
      //TODO MAKE THE COLORS CONFIGURABLE
      final SLDColorMapBuilder builder = new SLDColorMapBuilder();
      builder.setExtendedColors(this.extendedColors)
          .setLinearColorMapType(this.type)
          .setNumberColorMapEntries(cmEntries.length)
          .setColorForValuesToPreserve(new Color(0, 0, 0, 0))
          .setGapsColor(new Color(0, 0, 0, 0));
      for (int i = 0; i < cmEntries.length; i++) {
        builder.addColorMapEntry(cmEntries[i]);

      }



      // /////////////////////////////////////////////////////////////////////
      //
      // Create the list of no data colorMapTransform domain elements. Note that all of them
      //
      // /////////////////////////////////////////////////////////////////////
      if(candidateNoDataValues!=null&&candidateNoDataValues.length>0){
        final LinearColorMapElement noDataCategories[] = new LinearColorMapElement[candidateNoDataValues.length];
        for (int i = 0; i < noDataCategories.length; i++) {
          builder.addValueToPreserve(candidateNoDataValues[i]);
        }
      }

      // /////////////////////////////////////////////////////////////////////
      //
      // Create the list of colorMapTransform categories
      //
      // /////////////////////////////////////////////////////////////////////
      colorMapTransform = builder.buildLinearColorMap();

    } else
      this.type = -1;

  }

    /**
     * @param candidateSD
     * @return
     * @throws IllegalStateException
     */
    private static double[] preparaNoDataValues(final GridSampleDimension candidateSD)
            throws IllegalStateException {
        double[] candidateNoDataValues = candidateSD.getNoDataValues();
        // if no nodata categories are ready we'll add a fictitious one
        // @todo TODO make this code configurable
        if (candidateNoDataValues == null)
        {
            candidateNoDataValues= new double[1];
            final SampleDimensionType sdType = candidateSD.getSampleDimensionType();
            final int dataBufferType=TypeMap.getDataBufferType(sdType);
            switch(dataBufferType){
            case DataBuffer.TYPE_SHORT:
                candidateNoDataValues[0]=Short.MIN_VALUE;
                break;
            case DataBuffer.TYPE_INT:
                candidateNoDataValues[0]=Integer.MIN_VALUE;
                break;  
            case DataBuffer.TYPE_FLOAT:
                candidateNoDataValues[0]=Float.NaN;
                break;
            case DataBuffer.TYPE_DOUBLE:case DataBuffer.TYPE_UNDEFINED:
                candidateNoDataValues[0]=Double.NaN;
                break;
            default://BYTE, USHORT
              candidateNoDataValues=null;
            break;
           }
        }
        return candidateNoDataValues;
    }

  /**
   * Default constructor for the {@link ColorMapNode} processing node.
   */
  public ColorMapNode() {
    this(null);
  }
 
  /**
   * Default constructor for the {@link ColorMapNode} processing node.
   */
  public ColorMapNode(Hints hints) {
    super(
        1,
        hints,
        SimpleInternationalString.wrap("ColorMapNode"),
        SimpleInternationalString
            .wrap("Node which applies a ColorMapTransform following SLD 1.0 spec."));
  }


  /**
   * Note that the color map can be applied only to a single band hence, in
   * principle, applying the {@link ColorMapTransform} element to a coverage with more
   * than one band is an error.
   */
  protected GridCoverage2D execute() {
      ///////////////////////////////////////////////////////////////////
      //
      //get the source for this node and ensure it is correct
      //
      ///////////////////////////////////////////////////////////////////
      final CoverageProcessingNode sourceNode = getSource(0);
      GridCoverageRendererUtilities.ensureSourceNotNull(sourceNode, this.getName().toString());
      final GridCoverage2D sourceCoverage = (GridCoverage2D) sourceNode.getOutput();
      GridCoverageRendererUtilities.ensureSourceNotNull(sourceCoverage, this.getName().toString());
     
      ///////////////////////////////////////////////////////////////////
            //
      //now apply the colormap if one exists
      //
            ///////////////////////////////////////////////////////////////////
      if (colorMapTransform != null) {
          //get input image
          final RenderedImage sourceImage = sourceCoverage.getRenderedImage();
          GridCoverageRendererUtilities.ensureSourceNotNull(sourceImage, this.getName().toString());
          //prepare the colorMapTransform operation
          final ParameterBlock pbj = new ParameterBlock();
          pbj.addSource(sourceImage).add(colorMapTransform);
          final RenderedOp classified = JAI.create(RasterClassifier.OPERATION_NAME,pbj);

          ////
          //
          // prepare the output coverage by specifying its bands
          //
          ////
          final int outputChannels=classified.getColorModel().getNumComponents();
                final int numBands=classified.getSampleModel().getNumBands();
                assert outputChannels==1||outputChannels==3||outputChannels==4;
                final GridSampleDimension [] sd= new GridSampleDimension[numBands];
                for(int i=0;i<numBands;i++)
            sd[i]= new GridSampleDimension(TypeMap.getColorInterpretation(classified.getColorModel(), i).name());
         
          ////
                //
                // Create the the output coverage by preserving its gridgeometry and its bands
                //
                ////
    return getCoverageFactory().create(
            "color_mapped_"+sourceCoverage.getName().toString(),
            classified,
            sourceCoverage.getGridGeometry(),
            sd,
            new GridCoverage[]{sourceCoverage},
            sourceCoverage.getProperties()
            );
      }
      return sourceCoverage; 


  }

  /**
     * It tells me whether or not we are using extended colors for this colormap.
     * @return       the extendedColors
     * @uml.property  name="extendedColors"
     */
  public boolean isExtendedColors() {
    return extendedColors;
  }

}
TOP

Related Classes of org.geotools.renderer.lite.gridcoverage2d.ColorMapNode

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.