Package org.geotools.gce

Source Code of org.geotools.gce.RasterDescriptor$RasterLoadingResult

/*
*    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.gce;

import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.spi.ImageInputStreamSpi;
import javax.imageio.stream.ImageInputStream;
import javax.media.jai.ROIShape;

import org.geotools.coverage.grid.RasterLayout;
import org.geotools.coverage.grid.io.imageio.ImageReaderSource;
import org.geotools.data.DataUtilities;
import org.geotools.gce.geotiff.GeoTiffUtils;
import org.geotools.geometry.GeneralEnvelope;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.image.io.ImageIOExt;
import org.geotools.referencing.CRS;
import org.geotools.referencing.operation.matrix.XAffineTransform;
import org.geotools.referencing.operation.transform.AffineTransform2D;
import org.geotools.referencing.operation.transform.ProjectiveTransform;
import org.geotools.resources.coverage.CoverageUtilities;
import org.geotools.resources.geometry.XRectangle2D;
import org.opengis.geometry.BoundingBox;
import org.opengis.referencing.operation.MathTransform2D;
import org.opengis.referencing.operation.TransformException;

/**
* A RasterDescriptor is an elementar piece of data image, with its own
* levels and everything.
*
* <p>
* This class is responsible for caching the various size of the different
* levels of each single rasterGranuleLoader.
*
* <p>
* Right now we are making the assumption that a single rasterGranuleLoader is
* made a by a single file with embedded levels, either explicit or intrinsic
* through wavelets like MrSID, ECW or JPEG2000.
*
* @author Simone Giannecchini, GeoSolutions S.A.S.
* @since 2.5.5
*
* @source $URL$
*/
public class RasterDescriptor {

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

    /**
     * This class represent an overview level in a single rasterGranuleLoader.
     *
     * @author Simone Giannecchini, GeoSolutions S.A.S.
     *
     */
    public class RasterLevelDescriptor {
       
        final ImageReaderSource source;
       
        final double scaleX;

        final double scaleY;

        final AffineTransform2D baseToLevelTransform;

        final AffineTransform2D gridToWorldTransformCorner;

        final RasterLayout rasterDimensions;

        public ImageReaderSource getSource() {
            return source;
        }


        public AffineTransform getBaseToLevelTransform() {
            return baseToLevelTransform;
        }

        public double getScaleX() {
            return scaleX;
        }

        public double getScaleY() {
            return scaleY;
        }

        public RasterLevelDescriptor(
                final ImageReaderSource source,
                final double scaleX,
                final double scaleY,
                final RasterLayout rasterLayout) {
            this.source=source;
            this.scaleX = scaleX;
            this.scaleY = scaleY;
            this.baseToLevelTransform = new AffineTransform2D(XAffineTransform.getScaleInstance(scaleX, scaleY, 0, 0));
            final AffineTransform gridToWorldTransform_ = new AffineTransform(baseToLevelTransform);
            gridToWorldTransform_.preConcatenate(CoverageUtilities.CENTER_TO_CORNER);
            gridToWorldTransform_.preConcatenate(baseGridToWorld);
            this.gridToWorldTransformCorner = new AffineTransform2D(gridToWorldTransform_);
            this.rasterDimensions = (RasterLayout) rasterLayout.clone();
        }

        public Rectangle getBounds() {
            return (Rectangle) rasterDimensions.clone();
        }

        public AffineTransform2D getGridToWorldTransformCorner() {
            return gridToWorldTransformCorner;
        }

        @Override
        public String toString() {
            return "RasterLevelDescriptor [source=" + source + ", scaleX=" + scaleX + ", scaleY="
                    + scaleY + ", baseToLevelTransform=" + baseToLevelTransform
                    + ", gridToWorldTransformCorner=" + gridToWorldTransformCorner
                    + ", rasterDimensions=" + rasterDimensions + "]";
        }

    }

    /**
     * Simple placeholder class to store the result of a Granule Loading
     * which comprises of a raster as well as a {@link ROIShape} for its footprint.
     *
     * @author Daniele Romagnoli, GeoSolutions S.A.S.
     *
     */
    static class RasterLoadingResult {

        RenderedImage raster;

        AffineTransform gridToWorld;

        public AffineTransform getGridToWorld() {
            return gridToWorld;
        }

        public RenderedImage getRaster() {
            return raster;
        }

        RasterLoadingResult(RenderedImage raster, final AffineTransform gridToWorld) {
            this.raster = raster;
            this.gridToWorld = gridToWorld;
        }
    }

    ReferencedEnvelope rasterBBOX;

    final List<RasterLevelDescriptor> levels =new ArrayList<RasterLevelDescriptor>();

    AffineTransform baseGridToWorld;
//
//    public RasterDescriptor(RasterManager rasterManager) {
//
//        // get basic info
//        this.rasterBBOX = new ReferencedEnvelope(rasterManager.spatialDomainManager.coverageBBox);
//        this.baseGridToWorld=new AffineTransform((AffineTransform) rasterManager.spatialDomainManager.coverageGridToWorld2D);
//        final File granuleFile = DataUtilities.urlToFile(rasterManager.parent.sourceURL);
//       
//        // create the base grid to world transformation
//        ImageInputStream inStream = null;
//        ImageReader reader = null;
//        try {
//            //
//            // LOAD INFO FROM MAIN FILE
//            //
//           
//            // get a stream
//            inStream = ImageIOExt.createImageInputStream(granuleFile);
//            if (inStream == null) {
//                throw new IllegalArgumentException(
//                        "Unable to get an input stream for the provided file "
//                                + granuleFile.toString());
//            }
//
//            // get a reader
//            reader = GeoTiffUtils.TIFFREADERFACTORY.createReaderInstance();
//            reader.setInput(inStream);
//           
//            // cache stream SPI
//            ImageInputStreamSpi streamSPI=ImageIOExt.getImageInputStreamSPI(granuleFile);
//
//            // load info from main sourceFile
//            int numRasters=reader.getNumImages(true);
//            int i=0;
//            int baseLevelWidth=-1, baseLevelHeight=-1;
//            for(;i<numRasters;i++){
//                final int width=reader.getWidth(i);
//                final int height=reader.getHeight(i);
//                // add the base level
//                if(i==0) {
//                    baseLevelWidth=width;
//                    baseLevelHeight=height;
//                    this.levels.add(
//                            new RasterLevelDescriptor(
//                                    ImageReaderSource.wrapFile(i,granuleFile, streamSPI, GeoTiffUtils.TIFFREADERFACTORY),
//                                    1,
//                                    1,
//                                    new RasterLayout(0, 0, width, height,reader.getTileGridXOffset(i),reader.getTileGridYOffset(i),reader.getTileWidth(i),reader.getTileHeight(i))                                   
//                                    )
//                            );
//                }
//                else {
//                    final double scaleX = baseLevelWidth / (1.0 * width);
//                    final double scaleY = baseLevelHeight / (1.0 * height);
//                    // add the base level
//                    this.levels.add(
//                            new RasterLevelDescriptor(
//                                    ImageReaderSource.wrapFile(i,granuleFile, streamSPI, GeoTiffUtils.TIFFREADERFACTORY),
//                                    scaleX,
//                                    scaleY,
//                                    new RasterLayout(0, 0, width, height,reader.getTileGridXOffset(i),reader.getTileGridYOffset(i),reader.getTileWidth(i),reader.getTileHeight(i))
//                                    )
//                            );
//                }
//                   
//            }
//           
//            //
//            // EXTERNAL Overviews management
//            //
//            if (rasterManager.parent.extOvrImgChoice >= 0 ) {
//               
//                // close current stream and reopen new one
//                try {
//                    if (inStream != null) {
//                        inStream.close();
//                    }
//                } catch (Throwable e) {
//                   
//                }
//               
//                try {
//                    if (reader != null)
//                        reader.dispose();
//                } catch (Throwable e) {
//                   
//                }
//               
//                // get a stream
//                inStream = rasterManager.parent.ovrInStreamSPI.createInputStreamInstance(rasterManager.parent.ovrSource, ImageIO.getUseCache(), ImageIO.getCacheDirectory());
//                if (inStream == null) {
//                    throw new IllegalArgumentException(
//                            "Unable to get an input stream for the provided file "
//                                    + granuleFile.toString());
//                }
//                streamSPI=ImageIOExt.getImageInputStreamSPI(rasterManager.parent.ovrSource);
//                // get a reader
//                reader = GeoTiffUtils.TIFFREADERFACTORY.createReaderInstance();
//                reader.setInput(inStream);              
//
//                // load info from main sourceFile
//                numRasters=reader.getNumImages(true);
//                for(int k=0;k<numRasters;k++,i++){
//                    final int width=reader.getWidth(k);
//                    final int height=reader.getHeight(k);
//                    final double scaleX = baseLevelWidth / (1.0 * width);
//                    final double scaleY = baseLevelHeight / (1.0 * height);
//                    // add the level
//                    this.levels.add(
//                            new RasterLevelDescriptor(
//                                    ImageReaderSource.wrapFile(k,rasterManager.parent.ovrSource, rasterManager.parent.ovrInStreamSPI, GeoTiffUtils.TIFFREADERFACTORY),
//                                    scaleX,
//                                    scaleY,
//                                    new RasterLayout(0, 0, width, height,reader.getTileGridXOffset(k),reader.getTileGridYOffset(k),reader.getTileWidth(k),reader.getTileHeight(k))
//                                    )
//                            );                   
//                }
//
//
//            }          
//           
//
//        } catch (IllegalStateException e) {
//            throw new IllegalArgumentException(e);
//
//        } catch (IOException e) {
//            throw new IllegalArgumentException(e);
//        } finally {
//            try {
//                if (inStream != null) {
//                    inStream.close();
//                }
//            } catch (Throwable e) {
//                throw new IllegalArgumentException(e);
//            } finally {
//                if (reader != null)
//                    reader.dispose();
//            }
//        }
//    }

    public RasterDescriptor(final List<RasterSlice> slices) {
        final RasterSlice fullRes= slices.get(0);
        // get basic info
        this.rasterBBOX = new ReferencedEnvelope(new ReferencedEnvelope(fullRes.envelope));
        this.baseGridToWorld = new AffineTransform((AffineTransform) fullRes.gridToWorld.clone());
        this.levels.add(new RasterLevelDescriptor(fullRes.source, 1.0, 1.0, fullRes.rasterDimensions));
       
        final int baseLevelWidth=fullRes.rasterDimensions.getWidth(), baseLevelHeight=fullRes.rasterDimensions.getHeight();
        final int size= slices.size();
        for(int i =1;i<size;i++){
            final RasterSlice slice= slices.get(i);
            final double scaleX = baseLevelWidth / (1.0 * slice.rasterDimensions.getWidth());
            final double scaleY = baseLevelHeight / (1.0 * slice.rasterDimensions.getHeight());
            this.levels.add(new RasterLevelDescriptor(slice.source, scaleX, scaleY, slice.rasterDimensions));
           
        }

    }
   
    public RasterLoadingResult loadRaster(
            final ImageReadParam readParameters,
            final int overviewIndex,
            final ReferencedEnvelope cropBBox,
            final MathTransform2D requestedWorldToGrid,
            final RasterLayerRequest request,
            final Dimension tileDimension) throws IOException {

        if (LOGGER.isLoggable(java.util.logging.Level.FINE)) {
            LOGGER.fine("Loading raster data for RasterDescriptor " + this.toString());
        }
        ImageInputStream inStream = null;

        final ReferencedEnvelope bbox = new ReferencedEnvelope(rasterBBOX);
        // intersection of this tile bound with the current crop bbox
        final ReferencedEnvelope intersection = new ReferencedEnvelope(bbox.intersection(cropBBox),
                cropBBox.getCoordinateReferenceSystem());

        ImageReader reader = null;
        try {
            //
            // get info about the raster we have to read
            //
            // get selected level and base level dimensions
            final RasterLevelDescriptor selectedlevel=levels.get(Integer.valueOf(overviewIndex));
            final Object input = selectedlevel.source.getSource();
            inStream = selectedlevel.source.getInputStreamSPI().createInputStreamInstance(input, ImageIO.getUseCache(), ImageIO.getCacheDirectory());
            int imageChoice= selectedlevel.source.getImageIndex();
           
            if (inStream == null) {
                return null;
            }

            // get a reader
            reader = GeoTiffUtils.TIFFREADERFACTORY.createReaderInstance();
            reader.setInput(inStream);

            // now create the crop grid to world which can be used to decide
            // which sourceFile area we need to crop in the selected level taking
            // into account the scale factors imposed by the selection of this
            // level together with the base level grid to world transformation
            final MathTransform2D cropGridToWorldCorner = (MathTransform2D) ProjectiveTransform.create(selectedlevel.gridToWorldTransformCorner);
            final MathTransform2D cropWorldToGrid = cropGridToWorldCorner.inverse();

            // computing the crop sourceFile area which leaves straight into the
            // selected level raster space, NOTICE that at the end we need to
            // take into account the fact that we might also decimate therefore
            // we cannot just use the crop grid to world but we need to correct
            // it.
            final Rectangle sourceArea = CRS.transform(cropWorldToGrid, new GeneralEnvelope(intersection)).toRectangle2D().getBounds();
            XRectangle2D.intersect(sourceArea, selectedlevel.rasterDimensions.getBounds(), sourceArea);
            // make sure roundings don't bother us

            // is it empty??
            if (sourceArea.isEmpty()) {
                if (LOGGER.isLoggable(java.util.logging.Level.WARNING)) {
                    LOGGER.warning("Got empty area for rasterGranuleLoader " + this.toString()
                            + " with request " + request.toString());
                }
                return null;

            } else if (LOGGER.isLoggable(java.util.logging.Level.FINE)) {
                LOGGER.fine("Loading level " + overviewIndex + " with sourceFile region " + sourceArea);
            }
            // set the sourceFile region
            // readParameters.setSourceRegion(sourceAreaWithCollar);
            readParameters.setSourceRegion(sourceArea);

            // read
            // TODO make this generic
            RenderedImage raster = request.getReadType().read(readParameters, imageChoice, (File) input, selectedlevel.rasterDimensions.getBounds(), tileDimension);
            if (raster == null) {
                return null;
            }
            try {
                raster.getWidth();
            } catch (Throwable e) {
                if (LOGGER.isLoggable(java.util.logging.Level.FINE)) {
                    LOGGER.log(java.util.logging.Level.FINE,
                            "Unable to load raster for rasterGranuleLoader " + this.toString()
                                    + " with request " + request.toString(), e);
                }
                return null;
            }

            // use fixed sourceFile area
            sourceArea.setRect(readParameters.getSourceRegion());

            //
            // setting new coefficients to define a new affineTransformation
            // to be applied to the grid to world transformation
            // -----------------------------------------------------------------------------------
            //
            // With respect to the original envelope, the obtained planarImage
            // needs to be rescaled. The scaling factors are computed as the
            // ratio between the cropped sourceFile region sizes and the read
            // image sizes.
            //
            // place it in the mosaic using the coords created above;
            double decimationScaleX = ((1.0 * sourceArea.width) / raster.getWidth());
            double decimationScaleY = ((1.0 * sourceArea.height) / raster.getHeight());
            final AffineTransform decimationScaleTranform = XAffineTransform.getScaleInstance(decimationScaleX, decimationScaleY);

            // keep into account translation to work into the selected level
            // raster space
            final AffineTransform afterDecimationTranslateTranform = XAffineTransform.getTranslateInstance(sourceArea.x, sourceArea.y);

            // now we need to go back to the base level raster space
            final AffineTransform backToBaseLevelScaleTransform =selectedlevel.getBaseToLevelTransform();
           
            // now create the overall transform
            final AffineTransform finalRaster2Model = new AffineTransform(baseGridToWorld);
            finalRaster2Model.concatenate(CoverageUtilities.CENTER_TO_CORNER);
           
            if(!XAffineTransform.isIdentity(backToBaseLevelScaleTransform, GeoTiffUtils.AFFINE_IDENTITY_EPS))
                    finalRaster2Model.concatenate(backToBaseLevelScaleTransform);
            if(!XAffineTransform.isIdentity(afterDecimationTranslateTranform, GeoTiffUtils.AFFINE_IDENTITY_EPS))
                    finalRaster2Model.concatenate(afterDecimationTranslateTranform);
            if(!XAffineTransform.isIdentity(decimationScaleTranform, GeoTiffUtils.AFFINE_IDENTITY_EPS))
                    finalRaster2Model.concatenate(decimationScaleTranform);
           
            // return raster + its own transformation
            return  new RasterLoadingResult(raster, finalRaster2Model);
           

        } catch (IllegalStateException e) {
            if (LOGGER.isLoggable(java.util.logging.Level.WARNING)) {
                LOGGER.log(java.util.logging.Level.WARNING,
                        "Unable to load raster for rasterGranuleLoader " + this.toString()
                                + " with request " + request.toString(), e);
            }
            return null;
        } catch (org.opengis.referencing.operation.NoninvertibleTransformException e) {
            if (LOGGER.isLoggable(java.util.logging.Level.WARNING)) {
                LOGGER.log(java.util.logging.Level.WARNING,
                        "Unable to load raster for rasterGranuleLoader " + this.toString()
                                + " with request " + request.toString(), e);
            }
            return null;
        } catch (TransformException e) {
            if (LOGGER.isLoggable(java.util.logging.Level.WARNING)) {
                LOGGER.log(java.util.logging.Level.WARNING,
                        "Unable to load raster for rasterGranuleLoader " + this.toString()
                                + " with request " + request.toString(), e);
            }
            return null;
        } finally {

            if (inStream != null) {
                try {
                    inStream.close();
                } catch (Throwable t) {

                }
            }
            if (reader != null) {
                try {
                    reader.dispose();
                } catch (Throwable t) {

                }
            }
        }

    }

//    private RasterLevelDescriptor getLevel(ImageReader reader, RasterLayerRequest request,  int imageChoice, int overviewIndex) {
//        synchronized (levels) {
//            if (levels.containsKey(Integer.valueOf(overviewIndex))) {
//                return levels.get(Integer.valueOf(overviewIndex));
//            } else {
//                // load level
//                // create the base grid to world transformation
//                try {
//                    //
//                    // get info about the raster we have to read
//                    //
//                    // get selected level and base level dimensions
//                    final Rectangle levelDimension =  new Rectangle(0, 0, reader.getWidth(imageChoice), reader.getHeight(imageChoice));
//
//                    final RasterLevelDescriptor baseLevel = levels.get(0);
//                    final double scaleX = baseLevel.width / (1.0 * levelDimension.width);
//                    final double scaleY = baseLevel.height / (1.0 * levelDimension.height);
//
//                    // add the base level
//                    final RasterLevelDescriptor newLevel = new RasterLevelDescriptor(scaleX, scaleY, levelDimension.width,levelDimension.height);
//                    this.granuleLevels.put(Integer.valueOf(overviewIndex), newLevel);
//                    return newLevel;
//
//                } catch (IllegalStateException e) {
//                    throw new IllegalArgumentException(e);
//
//                } catch (IOException e) {
//                    throw new IllegalArgumentException(e);
//                }
//            }
//
//        }
//    }

    @Override
    public String toString() {
        // build a decent representation for this level
        final StringBuilder buffer = new StringBuilder();
        buffer.append("Description of a rasterGranuleLoader ").append("\n").append("BBOX:\t\t")
                .append(rasterBBOX.toString()).append("gridToWorld:\t\t").append(baseGridToWorld);
        int i = 1;
        for (final RasterLevelDescriptor rasterLevelDescriptor : levels) {
            i++;
            buffer.append("Description of level ").append(i++).append("\n")
                    .append(rasterLevelDescriptor.toString()).append("\n");
        }
        return super.toString();
    }


    public BoundingBox getBBOX() {
      return rasterBBOX;
    }

}
TOP

Related Classes of org.geotools.gce.RasterDescriptor$RasterLoadingResult

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.