Package org.geotools.arcsde.raster.info

Source Code of org.geotools.arcsde.raster.info.RasterDatasetInfo

/*
*    GeoTools - The Open Source Java GIS Toolkit
*    http://geotools.org
*
*    (C) 2002-2009, 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.arcsde.raster.info;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.image.IndexColorModel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.imageio.ImageTypeSpecifier;

import org.geotools.coverage.Category;
import org.geotools.coverage.GridSampleDimension;
import org.geotools.coverage.grid.GeneralGridEnvelope;
import org.geotools.coverage.grid.io.OverviewPolicy;
import org.geotools.geometry.GeneralEnvelope;
import org.geotools.referencing.CRS;
import org.geotools.referencing.operation.builder.GridToEnvelopeMapper;
import org.geotools.referencing.operation.transform.LinearTransform1D;
import org.geotools.resources.i18n.Vocabulary;
import org.geotools.resources.i18n.VocabularyKeys;
import org.geotools.util.NumberRange;
import org.opengis.coverage.grid.GridEnvelope;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.datum.PixelInCell;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.NoninvertibleTransformException;
import org.opengis.referencing.operation.TransformException;

/**
* Wraps metadata information for a raster dataset, whether it is composed of a single raster, or
* it's raster catalog, and provides some conveinent methods to get to the raster metadata of it's
* rasters and pyramid levels.
* <p>
* This is the single entry point to the metadata of a raster dataset. The associated classes
* {@link RasterInfo} and {@link PyramidLevelInfo} are to be considered private to this class.
* </p>
*
* @author Gabriel Roldan (OpenGeo)
* @since 2.5.4
* @version $Id$
*
*
* @source $URL$
*         http://svn.osgeo.org/geotools/trunk/modules/plugin/arcsde/datastore/src/main/java/org
*         /geotools/arcsde/gce/RasterDatasetInfo.java $
*/
@SuppressWarnings({ "nls" })
public final class RasterDatasetInfo {

    /** TRasterDatasetInfo the raster table we're pulling images from in this reader * */
    private String rasterTable = null;

    /**
     * raster column names on this raster. If there's more than one raster column (is this
     * possible?) then we just use the first one.
     */
    private String[] rasterColumns;

    /** Array holding information on each level of the pyramid in this raster. * */
    private List<RasterInfo> subRasterInfo;

    private GridEnvelope originalGridRange;

    private List<GridSampleDimension> gridSampleDimensions;

    private final Map<Integer, ImageTypeSpecifier> renderedImageSpec = new HashMap<Integer, ImageTypeSpecifier>();

    /**
     * @param rasterTable
     *            the rasterTable to set
     */
    void setRasterTable(String rasterTable) {
        this.rasterTable = rasterTable;
    }

    /**
     * @return the raster table name
     */
    public String getRasterTable() {
        return rasterTable;
    }

    /**
     * @param rasterColumns
     *            the rasterColumns to set
     */
    void setRasterColumns(String[] rasterColumns) {
        this.rasterColumns = rasterColumns;
    }

    /**
     * @return the raster column names
     */
    public String[] getRasterColumns() {
        return rasterColumns;
    }

    /**
     * @param pyramidInfo
     *            the pyramidInfo to set
     */
    public void setPyramidInfo(List<RasterInfo> pyramidInfo) {
        this.subRasterInfo = pyramidInfo;
    }

    public GridSampleDimension[] getGridSampleDimensions() {
        if (gridSampleDimensions == null) {
            synchronized (this) {
                if (gridSampleDimensions == null) {
                    gridSampleDimensions = buildSampleDimensions();
                }
            }
        }
        return gridSampleDimensions.toArray(new GridSampleDimension[getNumBands()]);
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    private List<GridSampleDimension> buildSampleDimensions() {

        final int numBands = getNumBands();
        List<GridSampleDimension> dimensions = new ArrayList<GridSampleDimension>(numBands);

        final Color transparent = new Color(0, 0, 0, 0);

        List<RasterBandInfo> bands = subRasterInfo.get(0).getBands();

        for (RasterBandInfo band : bands) {
            // use native cell type, in case no-data value has been computed to account for
            // sample depth promotion, we want to category to keep being the native range for
            // the values category
            final RasterCellType targetCellType = getNativeCellType();
            String bandName = band.getBandName();

            final double statsMin = band.getStatsMin();
            final double statsMax = band.getStatsMax();

            NumberRange<?> sampleValueRange;
            if (Double.isNaN(statsMin) || Double.isNaN(statsMax)) {
                sampleValueRange = targetCellType.getSampleValueRange();
            } else {
                sampleValueRange = NumberRange.create(statsMin, statsMax);
                Class elementClass = targetCellType.getSampleValueRange().getElementClass();
                sampleValueRange = sampleValueRange.castTo(elementClass);
            }

            final Color[] colorRange = null;

            final boolean geophysics = isGeoPhysics();

            Category valuesCat = new Category("values", colorRange, sampleValueRange,
                    LinearTransform1D.IDENTITY).geophysics(geophysics);

            Category[] categories;
            if (geophysics) {
                double noDataValue = band.getNoDataValue().doubleValue();
                // same as Category.NODATA but for the actual nodata value instead of hardcoded to
                // zero
                Category nodataCat = new Category(
                        Vocabulary.formatInternational(VocabularyKeys.NODATA), transparent,
                        noDataValue);
                categories = new Category[] { valuesCat, nodataCat };
            } else {
                // do not build a nodata category. A nodata value that doesn't overlap the value
                // range couldn't be determined
                categories = new Category[] { valuesCat };
            }
            /*
             * if (band.isHasStats()) { //can't do this, get an exception telling categories
             * overlap.. so no real way to express the statistics, uh? Category catMin = new
             * Category("Min", null, band.getStatsMin()).geophysics(true); Category catMax = new
             * Category("Max", null, band.getStatsMin()).geophysics(true); Category catMean = new
             * Category("Mean", null, band.getStatsMin()).geophysics(true); Category catStdDev = new
             * Category("StdDev", null, band.getStatsMin()) .geophysics(true); categories = new
             * Category[] { valuesCat, nodataCat, catMin, catMax, catMean, catStdDev }; } else {
             * categories = new Category[] { valuesCat, nodataCat }; }
             */

            // .geophysics(false) because our sample model always corresponds to the packed view
            // (whether it matches the underlying sample depth or we're promoting in order to make
            // room for the nodata value).
            GridSampleDimension sampleDim = new GridSampleDimension(bandName, categories, null)
                    .geophysics(false);

            dimensions.add(sampleDim);
        }
        return dimensions;
    }

    private boolean isGeoPhysics() {
        if (isColorMapped()) {
            return false;
        }
        return RasterUtils.isGeoPhysics(getNumBands(), getNativeCellType());
    }

    public int getNumBands() {
        return subRasterInfo.get(0).getNumBands();
    }

    public int getImageWidth() {
        final GridEnvelope originalGridRange = getOriginalGridRange();
        final int width = originalGridRange.getSpan(0);
        return width;
    }

    public int getImageHeight() {
        final GridEnvelope originalGridRange = getOriginalGridRange();
        final int height = originalGridRange.getSpan(1);
        return height;
    }

    /**
     * @return the coverageCrs
     */
    public CoordinateReferenceSystem getCoverageCrs() {
        return subRasterInfo.get(0).getCoordinateReferenceSystem();
    }

    /**
     * @return the originalGridRange for the whole raster dataset, based on the first raster in the
     *         raster dataset
     */
    public GridEnvelope getOriginalGridRange() {
        if (originalGridRange == null) {
            final int rasterCount = getNumRasters();
            if (1 == rasterCount) {
                originalGridRange = getGridRange(0, 0);
                return originalGridRange;
            }

            final MathTransform modelToRaster;
            try {
                final MathTransform rasterToModel = getRasterToModel();
                modelToRaster = rasterToModel.inverse();
            } catch (NoninvertibleTransformException e) {
                throw new IllegalStateException("Can't create transform from model to raster");
            }

            int minx = Integer.MAX_VALUE;
            int miny = Integer.MAX_VALUE;
            int maxx = Integer.MIN_VALUE;
            int maxy = Integer.MIN_VALUE;

            for (int rasterN = 0; rasterN < rasterCount; rasterN++) {
                final GeneralEnvelope rasterEnvelope = getGridEnvelope(rasterN, 0);
                GeneralEnvelope rasterGridRangeInDataSet;
                try {
                    rasterGridRangeInDataSet = CRS.transform(modelToRaster, rasterEnvelope);
                } catch (NoninvertibleTransformException e) {
                    throw new IllegalArgumentException(e);
                } catch (TransformException e) {
                    throw new IllegalArgumentException(e);
                }

                minx = Math.min(minx, (int) Math.floor(rasterGridRangeInDataSet.getMinimum(0)));
                miny = Math.min(miny, (int) Math.floor(rasterGridRangeInDataSet.getMinimum(1)));
                maxx = Math.max(maxx, (int) Math.ceil(rasterGridRangeInDataSet.getMaximum(0)));
                maxy = Math.max(maxy, (int) Math.ceil(rasterGridRangeInDataSet.getMaximum(1)));
            }
            int width = maxx - minx;
            int height = maxy - miny;
            Rectangle range = new Rectangle(0, 0, width, height);
            originalGridRange = new GeneralGridEnvelope(range, 2);
        }
        return originalGridRange;
    }

    public MathTransform getRasterToModel() {
        return getRasterToModel(0, 0);
    }

    public MathTransform getRasterToModel(final int rasterIndex, final int pyramidLevel) {

        GeneralEnvelope levelEnvelope = getGridEnvelope(rasterIndex, pyramidLevel);
        GridEnvelope levelGridRange = getGridRange(rasterIndex, pyramidLevel);

        // create a raster to model transform, from this tile pixel space to the tile's geographic
        // extent
        GridToEnvelopeMapper geMapper = new GridToEnvelopeMapper(levelGridRange, levelEnvelope);
        geMapper.setPixelAnchor(PixelInCell.CELL_CORNER);

        MathTransform rasterToModel = geMapper.createTransform();
        return rasterToModel;
    }

    /**
     * @param pixelAnchor
     * @return the originalEnvelope
     */
    public GeneralEnvelope getOriginalEnvelope(final PixelInCell pixelAnchor) {
        GeneralEnvelope env = null;
        if (1 == getNumRasters()) {
            env = getGridEnvelope(0, 0);
        } else {
            for (RasterInfo raster : subRasterInfo) {
                int rasterIndex = getRasterIndex(raster.getRasterId());
                GeneralEnvelope rasterEnvelope = getGridEnvelope(rasterIndex, 0);
                if (env == null) {
                    env = new GeneralEnvelope(rasterEnvelope);
                } else {
                    env.add(rasterEnvelope);
                }
            }
        }

        if (PixelInCell.CELL_CENTER.equals(pixelAnchor)) {
            double[] resolution = getResolution(0, 0);
            double deltaX = resolution[0] / 2;
            double deltaY = resolution[1] / 2;
            env.setEnvelope(env.getMinimum(0) + deltaX, env.getMinimum(1) + deltaY,
                    env.getMaximum(0) - deltaX, env.getMaximum(1) - deltaY);
        }
        return env;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("ArcSDE Raster: " + getRasterTable());
        sb.append(", Raster columns: ").append(Arrays.asList(getRasterColumns()));
        sb.append(", Num bands: ").append(getNumBands());
        sb.append(", Dimension: ").append(getImageWidth()).append("x").append(getImageHeight());
        sb.append(", Pixel type: ").append(getNativeCellType());
        sb.append(", Has Color Map: ").append(isColorMapped());
        for (int rasterIndex = 0; rasterIndex < getNumRasters(); rasterIndex++) {
            RasterInfo raster = getRasterInfo(rasterIndex);
            sb.append("\n ");
            sb.append(raster.toString());
        }
        return sb.toString();
    }

    public int getNumRasters() {
        return subRasterInfo.size();
    }

    public RasterBandInfo getBand(final int rasterIndex, final int bandIndex) {
        RasterInfo rasterInfo = getRasterInfo(rasterIndex);
        return rasterInfo.getBand(bandIndex);
    }

    public int getNumPyramidLevels(final int rasterIndex) {
        RasterInfo rasterInfo = getRasterInfo(rasterIndex);
        return rasterInfo.getNumLevels();
    }

    public GeneralEnvelope getGridEnvelope(final int rasterIndex, final int pyramidLevel) {
        PyramidLevelInfo level = getLevel(rasterIndex, pyramidLevel);
        return level.getSpatialExtent();
    }

    public GridEnvelope getGridRange(final int rasterIndex, final int pyramidLevel) {
        PyramidLevelInfo level = getLevel(rasterIndex, pyramidLevel);
        GridEnvelope levelRange = level.getGridEnvelope();
        return levelRange;
    }

    public int getNumTilesWide(int rasterIndex, int pyramidLevel) {
        PyramidLevelInfo level = getLevel(rasterIndex, pyramidLevel);
        return level.getNumTilesWide();
    }

    public int getNumTilesHigh(int rasterIndex, int pyramidLevel) {
        PyramidLevelInfo level = getLevel(rasterIndex, pyramidLevel);
        return level.getNumTilesHigh();
    }

    public int getTileWidth(final long rasterId) {
        return getTileDimension(rasterId).width;
    }

    public int getTileHeight(final long rasterId) {
        return getTileDimension(rasterId).height;
    }

    public Dimension getTileDimension(final long rasterId) {
        final int rasterIndex = getRasterIndex(rasterId);
        final RasterInfo rasterInfo = getRasterInfo(rasterIndex);
        return rasterInfo.getTileDimension();
    }

    public Dimension getTileDimension(int rasterIndex) {
        RasterInfo rasterInfo = getRasterInfo(rasterIndex);
        return rasterInfo.getTileDimension();
    }

    private PyramidLevelInfo getLevel(int rasterIndex, int pyramidLevel) {
        RasterInfo rasterInfo = getRasterInfo(rasterIndex);
        PyramidLevelInfo level = rasterInfo.getPyramidLevel(pyramidLevel);
        return level;
    }

    private RasterInfo getRasterInfo(int rasterIndex) {
        RasterInfo rasterInfo = subRasterInfo.get(rasterIndex);
        return rasterInfo;
    }

    public ImageTypeSpecifier getRenderedImageSpec(final long rasterId) {
        final int rasterIndex = getRasterIndex(rasterId);
        return getRenderedImageSpec(rasterIndex);
    }

    public ImageTypeSpecifier getRenderedImageSpec(final int rasterIndex) {
        if (!this.renderedImageSpec.containsKey(Integer.valueOf(rasterIndex))) {
            synchronized (this) {
                if (!this.renderedImageSpec.containsKey(Integer.valueOf(rasterIndex))) {
                    ImageTypeSpecifier imageTypeSpecifier;
                    imageTypeSpecifier = RasterUtils
                            .createFullImageTypeSpecifier(this, rasterIndex);
                    renderedImageSpec.put(Integer.valueOf(rasterIndex), imageTypeSpecifier);
                }
            }
        }
        return this.renderedImageSpec.get(Integer.valueOf(rasterIndex));
    }

    public IndexColorModel getColorMap(final int rasterIndex) {
        final RasterBandInfo bandOne = getBand(rasterIndex, 0);
        return bandOne.getColorMap();
    }

    public boolean isColorMapped() {
        RasterInfo rasterInfo = getRasterInfo(0);
        return rasterInfo.isColorMapped();
    }

    public RasterCellType getNativeCellType() {
        RasterInfo rasterInfo = getRasterInfo(0);
        return rasterInfo.getNativeCellType();
    }

    public RasterCellType getTargetCellType(final int rasterIndex) {
        RasterInfo rasterInfo = getRasterInfo(rasterIndex);
        return rasterInfo.getTargetCellType();
    }

    public RasterCellType getTargetCellType(final long rasterId) {
        final int rasterIndex = getRasterIndex(rasterId);
        return getTargetCellType(rasterIndex);
    }

    public Long getRasterId(final int rasterIndex) {
        final RasterInfo rasterInfo = getRasterInfo(rasterIndex);
        return rasterInfo.getRasterId();
    }

    public int getOptimalPyramidLevel(final int rasterIndex, final OverviewPolicy policy,
            final GeneralEnvelope requestedEnvelope, final GridEnvelope requestedDim) {

        final RasterInfo rasterInfo = getRasterInfo(rasterIndex);

        double[] requestedRes = new double[2];
        double reqSpanX = requestedEnvelope.getSpan(0);
        double reqSpanY = requestedEnvelope.getSpan(1);
        requestedRes[0] = reqSpanX / (double) requestedDim.getSpan(0);
        requestedRes[1] = reqSpanY / (double) requestedDim.getSpan(1);

        return rasterInfo.getOptimalPyramidLevel(policy, requestedRes);
    }

    public int getRasterIndex(Long rasterId) {
        int index = -1;
        for (RasterInfo p : subRasterInfo) {
            index++;
            if (rasterId.equals(p.getRasterId())) {
                return index;
            }
        }
        throw new IllegalArgumentException("rasterId: " + rasterId);
    }

    public double[] getResolution(int rasterN, int pyramidLevel) {
        RasterInfo rasterInfo = getRasterInfo(rasterN);
        double[] resolution = rasterInfo.getResolution(pyramidLevel);
        return resolution;
    }

    public Number getNoDataValue(final long rasterId, final int bandIndex) {
        final int rasterIndex = getRasterIndex(rasterId);
        return getNoDataValue(rasterIndex, bandIndex);
    }

    public Number getNoDataValue(final int rasterIndex, final int bandIndex) {
        RasterBandInfo band = getBand(rasterIndex, bandIndex);
        Number noDataValue = band.getNoDataValue();
        return noDataValue;
    }

    /**
     * @param rasterIndex
     *            the raster for which bands to return the no data values
     * @return the list of no data values, one per band for the raster at index {@code rasterIndex}
     */
    public List<Number> getNoDataValues(final int rasterIndex) {
        return getRasterInfo(rasterIndex).getNoDataValues();
    }

    /**
     * Returns the actual ArcSDE pyramid level for the given raster and internal pyramid level, in
     * order to take into acount the fact that if the raster is registered with "skipLevelOne", we
     * don't hold any information for the arcsde pyramid level 1 of this raster.
     */
    public int getArcSDEPyramidLevel(final Long rasterId, final int pyramidLevel) {
        if (pyramidLevel == 0) {
            return 0;
        }
        RasterInfo rasterInfo = getRasterInfo(getRasterIndex(rasterId));
        boolean skipLevelOne = rasterInfo.isSkipLevelOne();
        if (skipLevelOne) {
            return pyramidLevel + 1;
        }
        return pyramidLevel;
    }
}
TOP

Related Classes of org.geotools.arcsde.raster.info.RasterDatasetInfo

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.