Package org.geotools.gce

Source Code of org.geotools.gce.RasterLayerResponse$SimplifiedGridSampleDimension

/*
*    GeoTools - The Open Source Java GIS Toolkit
*    http://geotools.org
*
*    (C) 2007-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.gce;

import it.geosolutions.imageio.imageioimpl.EnhancedImageReadParam;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.ColorModel;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.measure.unit.Unit;
import javax.media.jai.JAI;
import javax.media.jai.PlanarImage;
import javax.media.jai.operator.ConstantDescriptor;
import javax.media.jai.operator.FormatDescriptor;
import javax.media.jai.util.ImagingException;

import org.geotools.coverage.Category;
import org.geotools.coverage.GridSampleDimension;
import org.geotools.coverage.TypeMap;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridCoverageFactory;
import org.geotools.coverage.grid.GridEnvelope2D;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.coverage.grid.io.OverviewPolicy;
import org.geotools.data.DataSourceException;
import org.geotools.factory.Hints;
import org.geotools.gce.OverviewsController.OverviewLevel;
import org.geotools.gce.RasterDescriptor.RasterLoadingResult;
import org.geotools.gce.geotiff.GeoTiffUtils;
import org.geotools.geometry.GeneralEnvelope;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.referencing.CRS;
import org.geotools.referencing.operation.transform.AffineTransform2D;
import org.geotools.resources.coverage.CoverageUtilities;
import org.geotools.resources.i18n.Vocabulary;
import org.geotools.resources.i18n.VocabularyKeys;
import org.geotools.resources.image.ImageUtilities;
import org.geotools.util.NumberRange;
import org.geotools.util.SimpleInternationalString;
import org.jaitools.imageutils.ImageLayout2;
import org.opengis.coverage.ColorInterpretation;
import org.opengis.coverage.SampleDimension;
import org.opengis.coverage.SampleDimensionType;
import org.opengis.coverage.grid.GridCoverage;
import org.opengis.geometry.BoundingBox;
import org.opengis.referencing.datum.PixelInCell;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransform1D;
import org.opengis.referencing.operation.MathTransform2D;
import org.opengis.referencing.operation.TransformException;
import org.opengis.util.InternationalString;

/**
* A RasterLayerResponse. An instance of this class is produced everytime a
* requestCoverage is called to a reader.
*
* @author Daniele Romagnoli, GeoSolutions
* @author Simone Giannecchini, GeoSolutions
*
*/
class RasterLayerResponse{
 
    private static final class SimplifiedGridSampleDimension extends GridSampleDimension implements SampleDimension{
       
          /**
           *
           */
          private static final long serialVersionUID = 2227219522016820587L;
       
       
          private double nodata;
          private double minimum;
          private double maximum;
          private double scale;
          private double offset;
          private Unit<?> unit;
          private SampleDimensionType type;
          private ColorInterpretation color;
          private Category bkg;
       
          public SimplifiedGridSampleDimension(
              CharSequence description,
              SampleDimensionType type,
              ColorInterpretation color,
              double nodata,
              double minimum,
              double maximum,
              double scale,
              double offset,
              Unit<?> unit) {
            super(description,!Double.isNaN(nodata)?
                new Category[]{new Category(Vocabulary
                              .formatInternational(VocabularyKeys.NODATA), new Color[]{new Color(0, 0, 0, 0)} , NumberRange
                              .create(nodata, nodata), NumberRange
                              .create(nodata, nodata))}:null,unit);
            this.nodata=nodata;
            this.minimum=minimum;
            this.maximum=maximum;
            this.scale=scale;
            this.offset=offset;
            this.unit=unit;
            this.type=type;
            this.color=color;
            this.bkg=new Category("Background", GeoTiffUtils.TRANSPARENT, 0);
          }
       
       
       
          @Override
          public double getMaximumValue() {
            return maximum;
          }
       
          @Override
          public double getMinimumValue() {
            return minimum;
          }
       
          @Override
          public double[] getNoDataValues() throws IllegalStateException {
            return new double[]{nodata};
          }
       
          @Override
          public double getOffset() throws IllegalStateException {
            return offset;
          }
       
          @Override
          public NumberRange<? extends Number> getRange() {
            return super.getRange();
          }
       
          @Override
          public SampleDimensionType getSampleDimensionType() {
            return type;
          }
       
          @Override
          public MathTransform1D getSampleToGeophysics() {
            return super.getSampleToGeophysics();
          }
       
          @Override
          public Unit<?> getUnits() {
            return unit;
          }
         
          @Override
          public double getScale() {
            return scale;
          }
         
          @Override
          public ColorInterpretation getColorInterpretation() {
            return color;
          }
       
       
          @Override
          public Category getBackground() {
            return bkg;
          }
       
          @Override
          public InternationalString[] getCategoryNames()
              throws IllegalStateException {
            return new InternationalString[]{SimpleInternationalString.wrap("Background")};
          }
        }

    /** Logger. */
    private final static Logger LOGGER = org.geotools.util.logging.Logging
            .getLogger(RasterLayerResponse.class);

    /**
     * The GridCoverage produced after a {@link #compute()} method call
     */
    private GridCoverage2D gridCoverage;

    /** The {@link RasterLayerRequest} originating this response */
    private RasterLayerRequest request;

    /** The coverage factory producing a {@link GridCoverage} from an image */
    private GridCoverageFactory coverageFactory;

    /** The base envelope related to the input coverage */
    private GeneralEnvelope coverageEnvelope;

    private RasterManager rasterManager;

    private Color transparentColor;

    private ReferencedEnvelope finalBBox;

    private Rectangle rasterBounds;

    private MathTransform2D finalGridToWorldCorner;

    private MathTransform2D finalWorldToGridCorner;

    private int overviewsLevel = 0;

    private EnhancedImageReadParam baseReadParameters = new EnhancedImageReadParam();
   
    private MathTransform baseGridToWorld;

    private double[] backgroundValues;

    private Hints hints;

    private boolean oversampledRequest = false;

    /**
     * Construct a {@code RasterLayerResponse} given a specific
     * {@link RasterLayerRequest}, a {@code GridCoverageFactory} to produce
     * {@code GridCoverage}s and an {@code ImageReaderSpi} to be used for
     * instantiating an Image Reader for a read operation,
     *
     * @param request
     *            a {@link RasterLayerRequest} originating this response.
     * @param coverageFactory
     *            a {@code GridCoverageFactory} to produce a {@code GridCoverage}
     *            when calling the {@link #compute()} method.
     * @param readerSpi
     *            the Image Reader Service provider interface.
     */
    public RasterLayerResponse(final RasterLayerRequest request, final RasterManager rasterManager) {
        this.request = request;
        hints = rasterManager.getHints();
        coverageEnvelope = rasterManager.getCoverageEnvelope();
        baseGridToWorld = rasterManager.getRaster2Model();
        coverageFactory = rasterManager.getGridCoverageFactory();
        this.rasterManager = rasterManager;
        backgroundValues = request.getBackgroundValues();
        transparentColor = request.getInputTransparentColor();       

    }

    /**
     * Compute the coverage request and produce a grid coverage which will be
     * returned by {@link #createResponse()}. The produced grid coverage may be
     * {@code null} in case of empty request.
     *
     * @return the {@link GridCoverage} produced as computation of this response
     *         using the {@link #compute()} method.
     * @throws IOException
     * @uml.property name="gridCoverage"
     */
    public GridCoverage2D createResponse() throws IOException {
        processRequest();
        return gridCoverage;
    }

    /**
     * @return the {@link RasterLayerRequest} originating this response.
     *
     * @uml.property name="request"
     */
    public RasterLayerRequest getOriginatingCoverageRequest() {
        return request;
    }
    /**
     * This method creates the GridCoverage2D from the underlying file given a
     * specified envelope, and a requested dimension.
     *
     * @param iUseJAI
     *            specify if the underlying read process should leverage on a
     *            JAI ImageRead operation or a simple direct call to the {@code
     *            read} method of a proper {@code ImageReader}.
     * @param overviewPolicy
     *            the overview policy which need to be adopted
     * @return a {@code GridCoverage}
     *
     * @throws java.io.IOException
     */
    private  void processRequest() throws IOException {

            if (request.isEmpty())
            {
                    if(LOGGER.isLoggable(Level.FINE))
                            LOGGER.log(Level.FINE,"Request is empty: "+request.toString());
                    this.gridCoverage=null;
                    return;
            }
           
            // assemble granules
            final RenderedImage mosaic = prepareResponse();
           
            //postproc
            RenderedImage finalRaster = postProcessRaster(mosaic);
            //create the coverage
            gridCoverage = prepareCoverage(finalRaster);
           
    }
    /**
     * This method loads the granules which overlap the requested {@link GeneralEnvelope} using
     * the provided values for alpha and input ROI.
     */
    private RenderedImage prepareResponse() throws DataSourceException {

        try {

            // select the relevant overview, notice that at this time we have relaxed a bit the
            // requirement to have the same exact resolution for all the levels, but still we
            // do not allow for reading the various grid to world transform directly from the
            // input files, therefore we are assuming that each rasterDescriptor has a scale
            // and translate only grid to world that can be deduced from its base level dimension
            // and envelope. The grid to world transforms for the other levels can be computed
            // accordingly knowning the scale factors.
            if (request.getRequestedBBox() != null && request.getRequestedRasterArea() != null) {
                overviewsLevel = setReadParams(request.getOverviewPolicy(), baseReadParameters, request);
            } else {
                overviewsLevel = 0;
            }
            assert overviewsLevel >= 0;
            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.fine("Loading level " + overviewsLevel + " with subsampling factors "
                        + baseReadParameters.getSourceXSubsampling() + " "
                        + baseReadParameters.getSourceYSubsampling());
            }

            final BoundingBox cropBBOX = request.getCropBBox();
            if (cropBBOX != null) {
                finalBBox = ReferencedEnvelope.reference(cropBBOX);
            } else {
                finalBBox = new ReferencedEnvelope(coverageEnvelope);
            }
            // compute final world to grid base grid to world for the center of pixels
            final AffineTransform g2w = new AffineTransform((AffineTransform) baseGridToWorld);
            // move it to the corner
            g2w.concatenate(CoverageUtilities.CENTER_TO_CORNER);

            // keep into account levels and subsampling
            final OverviewLevel level = rasterManager.overviewsController.resolutionsLevels.get(overviewsLevel);
            final OverviewLevel baseLevel = rasterManager.overviewsController.resolutionsLevels.get(0);
            final AffineTransform2D adjustments = new AffineTransform2D(
                    (level.resolutionX / baseLevel.resolutionX)
                            * baseReadParameters.getSourceXSubsampling(), 0, 0,
                    (level.resolutionY / baseLevel.resolutionY)
                            * baseReadParameters.getSourceYSubsampling(), 0, 0);
            g2w.concatenate(adjustments);
           
            // move it to the corner
            finalGridToWorldCorner = new AffineTransform2D(g2w);
            finalWorldToGridCorner = finalGridToWorldCorner.inverse();           
            final GeneralEnvelope tempRasterBounds = CRS.transform(finalWorldToGridCorner, finalBBox);
            rasterBounds=tempRasterBounds.toRectangle2D().getBounds();
            if (rasterBounds.width == 0)
                rasterBounds.width++;
            if (rasterBounds.height == 0)
                rasterBounds.height++;
           
            final double[] requestRes = request.getRequestedResolution();
            final double resX = baseLevel.resolutionX;
            final double resY = baseLevel.resolutionY;           
            if ((requestRes[0] < resX || requestRes[1] < resY) ) {
                // Using the best available resolution
                oversampledRequest = true;
            }            
            if(oversampledRequest)
                rasterBounds.grow(2, 2);           



            RenderedImage theImage=null;
            try {

                RasterLoadingResult result = rasterManager.rasterDescriptor.loadRaster(baseReadParameters, overviewsLevel, finalBBox,
                        finalWorldToGridCorner, request, request.getTileDimensions());
                theImage =result.getRaster();
                if (theImage == null) {
                    if (LOGGER.isLoggable(Level.FINE)) {
                        LOGGER.log(Level.FINE, "Unable to load the raster with request " + request.toString());
                    }

                }
               
                //
                // Set final transformation
                //
                RasterLayerResponse.this.finalGridToWorldCorner=new AffineTransform2D(result.gridToWorld);


            } catch (ImagingException e) {
                if (LOGGER.isLoggable(Level.INFO)) {
                    LOGGER.fine("Unable to load the raster with request "  + request);
                }
                theImage = null;
            } catch (Throwable e) {
                if (LOGGER.isLoggable(Level.INFO)) {
                    LOGGER.fine("Unable to load the raster with request " + request);
                }
                theImage = null;
            }

            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.fine("Processing loaded raster data ");
            }


            //
            // Did we actually load anything?? Notice that it might happen that either we have
            // wholes inside the definition area for the image or we had some problem with
            // missing tiles, therefore it might happen that for some bboxes we don't have
            // anything to load.
            //
            if (theImage != null) {

                //
                // Create the mosaic image by doing a crop if necessary and also managing the
                // transparent color if applicable. Be aware that management of the transparent
                // color involves removing transparency information from the input images.
                //
                if (LOGGER.isLoggable(Level.FINE)) {
                    LOGGER.fine("Loaded finalBBox " + finalBBox.toString()
                            + " while crop finalBBox " + request.getCropBBox());
                }

                return theImage;

            } else {
                // if we get here that means that we do not have anything to load
                // but still we are inside the definition area for the mosaic,
                // therefore we create a fake coverage using the background values,
                // if provided (defaulting to 0), as well as the compute raster
                // bounds, envelope and grid to world.

                final Number[] values = ImageUtilities.getBackgroundValues(rasterManager.baseImageType.getSampleModel(), backgroundValues);
                // create a constant image with a proper layout
                final RenderedImage finalImage = ConstantDescriptor.create(
                        Float.valueOf(rasterBounds.width),
                        Float.valueOf(rasterBounds.height),
                        values,
                        null);
                if(rasterManager.baseImageType!=null&&rasterManager.baseImageType.getColorModel()!=null){
                    final ImageLayout2 il= new ImageLayout2();
                    il.setColorModel(rasterManager.baseImageType.getColorModel());
                    Dimension tileSize= request.getTileDimensions();
                    if(tileSize==null){
                        tileSize=JAI.getDefaultTileSize();
                    }
                    il.setSampleModel(rasterManager.baseImageType.getColorModel().createCompatibleSampleModel(tileSize.width, tileSize.height));
                    il.setTileGridXOffset(0).setTileGridYOffset(0).setTileWidth((int)tileSize.getWidth()).setTileHeight((int)tileSize.getHeight());
                    return FormatDescriptor.create(
                            finalImage,
                            Integer.valueOf(il.getSampleModel(null).getDataType()),
                            new RenderingHints(JAI.KEY_IMAGE_LAYOUT,il));
                }
                return finalImage;
            }

        } catch (IOException e) {
            throw new DataSourceException("Unable to create this mosaic", e);
        } catch (TransformException e) {
            throw new DataSourceException("Unable to create this mosaic", e);
        }
    }

    /**
     * This method is responsible for creating a coverage from the supplied {@link RenderedImage}.
     *
     * @param image
     * @return
     * @throws IOException
     */
    private GridCoverage2D prepareCoverage(RenderedImage image) throws IOException {
       
        // creating bands
        final SampleModel sm=image.getSampleModel();
        final ColorModel cm=image.getColorModel();
        final int numBands = sm.getNumBands();
        final GridSampleDimension[] bands = new GridSampleDimension[numBands];
        // setting bands names.
        for (int i = 0; i < numBands; i++) {
                // color interpretation
        final ColorInterpretation colorInterpretation=TypeMap.getColorInterpretation(cm, i);
        if(colorInterpretation==null)
               throw new IOException("Unrecognized sample dimension type");
       
        // sample dimension type
        final SampleDimensionType st=TypeMap.getSampleDimensionType(sm, i);
           
        // set some no data values, as well as Min and Max values
        final double noData;
        double min=-Double.MAX_VALUE,max=Double.MAX_VALUE;
        if(backgroundValues!=null)
        {
                // sometimes background values are not specified as 1 per each band, therefore we need to be careful
                noData= backgroundValues[backgroundValues.length > i ? i:0];
        }
        else
        {
                if(st.compareTo(SampleDimensionType.REAL_32BITS)==0)
                        noData= Float.NaN;
                else
                        if(st.compareTo(SampleDimensionType.REAL_64BITS)==0)
                                noData= Double.NaN;
                        else
                                if(st.compareTo(SampleDimensionType.SIGNED_16BITS)==0)
                                {
                                        noData=Short.MIN_VALUE;
                                        min=Short.MIN_VALUE;
                                        max=Short.MAX_VALUE;
                                }
                                else
                                        if(st.compareTo(SampleDimensionType.SIGNED_32BITS)==0)
                                        {
                                                noData= Integer.MIN_VALUE;
   
                                                min=Integer.MIN_VALUE;
                                                max=Integer.MAX_VALUE;                                                 
                                        }
                                        else
                                                if(st.compareTo(SampleDimensionType.SIGNED_8BITS)==0)
                                                {
                                                        noData= -128;
                                                        min=-128;
                                                        max=127;
                                                }
                                                else
                                                {
                                                        //unsigned
                                                        noData= 0;
                                                        min=0;
                                                       
                                                       
                                                        // compute max
                                                        if(st.compareTo(SampleDimensionType.UNSIGNED_1BIT)==0)
                                                                max=1;
                                                        else
                                                                if(st.compareTo(SampleDimensionType.UNSIGNED_2BITS)==0)
                                                                        max=3;
                                                                else
                                                                        if(st.compareTo(SampleDimensionType.UNSIGNED_4BITS)==0)
                                                                                max=7;
                                                                        else
                                                                                if(st.compareTo(SampleDimensionType.UNSIGNED_8BITS)==0)
                                                                                        max=255;
                                                                                else
                                                                                        if(st.compareTo(SampleDimensionType.UNSIGNED_16BITS)==0)
                                                                                                max=65535;
                                                                                        else
                                                                                                if(st.compareTo(SampleDimensionType.UNSIGNED_32BITS)==0)
                                                                                                        max=Math.pow(2, 32)-1;
                                                                                                                       
                                                }
               
                                    
        }
        bands[i] = new SimplifiedGridSampleDimension(
                        colorInterpretation.name(),
                        st,
                        colorInterpretation,
                        noData,
                        min,
                        max,
                        1,                                                      //no scale
                        0,                                                      //no offset
                        null
                        ).geophysics(true);
        }
   
        return coverageFactory.create(
                rasterManager.getCoverageIdentifier(),
                image,
                new GridGeometry2D(
                        new GridEnvelope2D(PlanarImage.wrapRenderedImage(image).getBounds()),
                        PixelInCell.CELL_CORNER,
                        finalGridToWorldCorner,
                        this.rasterManager.getCoverageCRS(),
                        hints),
                bands,
                null,
                null);         

    }


    /**
     * This method is responsible for preparing the read param for doing an
     * {@link ImageReader#read(int, ImageReadParam)}.
     *
     *
     * <p>
     * This method is responsible for preparing the read param for doing an
     * {@link ImageReader#read(int, ImageReadParam)}. It sets the passed
     * {@link ImageReadParam} in terms of decimation on reading using the
     * provided requestedEnvelope and requestedDim to evaluate the needed
     * resolution. It also returns and {@link Integer} representing the index of
     * the raster to be read when dealing with multipage raster.
     *
     * @param overviewPolicy
     *            it can be one of {@link Hints#VALUE_OVERVIEW_POLICY_IGNORE},
     *            {@link Hints#VALUE_OVERVIEW_POLICY_NEAREST},
     *            {@link Hints#VALUE_OVERVIEW_POLICY_QUALITY} or
     *            {@link Hints#VALUE_OVERVIEW_POLICY_SPEED}. It specifies the
     *            policy to compute the levels level upon request.
     * @param readParams
     *            an instance of {@link ImageReadParam} for setting the
     *            subsampling factors.
     * @param requestedEnvelope
     *            the {@link GeneralEnvelope} we are requesting.
     * @param requestedDim
     *            the requested dimensions.
     * @return the index of the raster to read in the underlying data sourceFile.
     * @throws IOException
     * @throws TransformException
     */
    private int setReadParams(final OverviewPolicy overviewPolicy,
            final ImageReadParam readParams, final RasterLayerRequest request)
            throws IOException, TransformException {

        // Default image index 0
        int imageChoice = 0;
        // default values for subsampling
        readParams.setSourceSubsampling(1, 1, 0, 0);

        //
        // Init overview policy
        //
        // //
        // when policy is explictly provided it overrides the policy provided
        // using hints.
        final OverviewPolicy policy;
        if (overviewPolicy == null) {
            policy = rasterManager.overviewPolicy;
        } else {
            policy = overviewPolicy;
        }

        // requested to ignore levels
        if (policy.equals(OverviewPolicy.IGNORE)) {
            return imageChoice;
        }

        // levels and decimation
        imageChoice = ReadParamsController.setReadParams(
                request.getRequestedResolution(),
                request.getOverviewPolicy(),
                request.getDecimationPolicy(),
                baseReadParameters,
                request.rasterManager,
                request.rasterManager.overviewsController); // use general levels controller
        return imageChoice;
    }

    private RenderedImage postProcessRaster(RenderedImage image) {
        // alpha on the final mosaic
        if (transparentColor != null) {

            //
            // TRANSPARENT COLOR MANAGEMENT
            //
            //
            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.fine("Support for alpha on input image ");
            }
            return ImageUtilities.maskColor(transparentColor, image);

        }
//        if (!needsReprojection){
//            try {
//               
//                // creating sourceFile grid to world corrected to the pixel corner
//                final AffineTransform sourceGridToWorld = new AffineTransform((AffineTransform) finalGridToWorldCorner);
//               
//                // target world to grid at the corner
//                final AffineTransform targetGridToWorld = new AffineTransform(request.getRequestedGridToWorld());
//                targetGridToWorld.concatenate(CoverageUtilities.CENTER_TO_CORNER);
//               
//                // target world to grid at the corner
//                final AffineTransform targetWorldToGrid=targetGridToWorld.createInverse();
//                // final complete transformation
//                targetWorldToGrid.concatenate(sourceGridToWorld);
//               
//                //update final grid to world
//                finalGridToWorldCorner=new AffineTransform2D(targetGridToWorld);
//                //
//                // Check and see if the affine transform is doing a copy.
//                // If so call the copy operation.
//                //
//                // we are in raster space here, so 1E-3 is safe
//                if(XAffineTransform.isIdentity(targetWorldToGrid, GeoTiffUtils.AFFINE_IDENTITY_EPS))
//                    return image;
//               
//                // create final image
//                // TODO this one could be optimized further depending on how the affine is created
//                //
//                // In case we are asked to use certain tile dimensions we tile
//                // also at this stage in case the read type is Direct since
//                // buffered images comes up untiled and this can affect the
//                // performances of the subsequent affine operation.
//                //
//                final Hints localHints= new Hints(hints);
//                if (hints != null && !hints.containsKey(JAI.KEY_BORDER_EXTENDER)) {
//                    final Object extender = hints.get(JAI.KEY_BORDER_EXTENDER);
//                    if (!(extender != null && extender instanceof BorderExtender)) {
//                        localHints.add(ImageUtilities.EXTEND_BORDER_BY_COPYING);
//                    }
//                }
//                ImageWorker iw = new ImageWorker(image);
//                iw.setRenderingHints(localHints);
//                iw.affine(targetWorldToGrid, new InterpolationNearest(), backgroundValues);
//                image = iw.getRenderedImage();
//            } catch (NoninvertibleTransformException e) {
//                if (LOGGER.isLoggable(Level.SEVERE)){
//                    LOGGER.log(Level.SEVERE, "Unable to create the requested mosaic ", e );
//                }
//            }
//        }
        return image;
    }
}
TOP

Related Classes of org.geotools.gce.RasterLayerResponse$SimplifiedGridSampleDimension

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.