/*
* 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.Rectangle;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageTypeSpecifier;
import javax.media.jai.ImageLayout;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridCoverageFactory;
import org.geotools.coverage.grid.io.OverviewPolicy;
import org.geotools.data.DataSourceException;
import org.geotools.factory.Hints;
import org.geotools.gce.geotiff.GeoTiffReader;
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.util.Utilities;
import org.opengis.parameter.GeneralParameterValue;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.datum.PixelInCell;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransform2D;
import org.opengis.referencing.operation.TransformException;
/**
*
*
* @source $URL$
*/
public class RasterManager {
/**
* This class is responsible for putting together all the 2D spatial
* information needed for a certain raster.
*
* <p>
* Notice that when this structure will be extended to work in ND this will
* become much more complex or as an alternative a sibling
* TemporalDomainManager will be created.
*
* @author Simone Giannecchini, GeoSolutions SAS
*
*/
class SpatialDomainManager {
public SpatialDomainManager(
CoordinateReferenceSystem coverageCRS,
GeneralEnvelope coverageEnvelope,
MathTransform2D coverageGridToWorld2D,
Rectangle coverageRasterArea) throws TransformException, FactoryException {
this.coverageCRS = coverageCRS;
this.coverageEnvelope = coverageEnvelope;
this.coverageGridToWorld2D = coverageGridToWorld2D;
this.coverageRasterArea = coverageRasterArea;
prepareCoverageSpatialElements();
}
/** The base envelope 2D */
ReferencedEnvelope coverageBBox;
/** The CRS for the coverage */
CoordinateReferenceSystem coverageCRS;
/** The CRS related to the base envelope 2D */
CoordinateReferenceSystem coverageCRS2D;
// ////////////////////////////////////////////////////////////////////////
//
// Base coverage properties
//
// ////////////////////////////////////////////////////////////////////////
/** The base envelope read from file */
GeneralEnvelope coverageEnvelope;
/** WGS84 envelope 2D for this coverage */
ReferencedEnvelope coverageGeographicBBox;
CoordinateReferenceSystem coverageGeographicCRS2D;
MathTransform2D coverageGridToWorld2D;
/** The base grid range for the coverage */
Rectangle coverageRasterArea;
/**
* Initialize the 2D properties (CRS and Envelope) of this coverage
*
* @throws TransformException
*
* @throws FactoryException
* @throws TransformException
* @throws FactoryException
*/
private void prepareCoverageSpatialElements() throws TransformException, FactoryException {
//
// basic initialization
//
coverageGeographicBBox = new ReferencedEnvelope(CRS.transform(CRS.findMathTransform(
coverageEnvelope.getCoordinateReferenceSystem(), GeoTiffUtils.WGS84,
true), coverageEnvelope));
coverageGeographicCRS2D = coverageGeographicBBox!=null?coverageGeographicBBox.getCoordinateReferenceSystem():null;
//
// Get the original envelope 2d and its spatial reference system
//
coverageCRS2D = CRS.getHorizontalCRS(coverageCRS);
assert coverageCRS2D.getCoordinateSystem().getDimension() == 2;
if (coverageCRS.getCoordinateSystem().getDimension() != 2) {
final MathTransform transform = CRS.findMathTransform(coverageCRS,
(CoordinateReferenceSystem) coverageCRS2D);
final GeneralEnvelope bbox = CRS.transform(transform, coverageEnvelope);
bbox.setCoordinateReferenceSystem(coverageCRS2D);
coverageBBox = new ReferencedEnvelope(bbox);
} else {
// it is already a bbox
coverageBBox = new ReferencedEnvelope(coverageEnvelope);
}
}
}
/**
* The name of the input coverage TODO consider URI
*/
String coverageIdentifier;
/** The hints to be used to produce this coverage */
Hints hints;
OverviewsController overviewsController;
OverviewPolicy overviewPolicy;
GeoTiffReader parent;
SpatialDomainManager spatialDomainManager;
ImageTypeSpecifier baseImageType;
ImageLayout defaultImageLayout;
RasterDescriptor rasterDescriptor;
/** Logger. */
private final static Logger LOGGER = org.geotools.util.logging.Logging.getLogger(RasterManager.class);
public RasterManager(
String identifier,
Hints hints,
CoordinateReferenceSystem crs,
GeneralEnvelope envelope,
MathTransform2D gridToWorld,
Rectangle originalRasterRange,
double [][] resolutions,
ImageTypeSpecifier baseImageType,
GeoTiffReader reader) throws DataSourceException {
Utilities.ensureNonNull("GeoTiffReader", reader);
initialize(
identifier,
hints,
crs,
envelope,
gridToWorld,
originalRasterRange,
resolutions,
baseImageType,
reader);
}
private void initialize(
String identifier,
Hints hints,
CoordinateReferenceSystem crs,
GeneralEnvelope envelope,
MathTransform2D gridToWorld,
Rectangle originalRasterRange,
double[][] resolutions,
ImageTypeSpecifier baseImageType,
GeoTiffReader reader) throws DataSourceException {
Utilities.ensureNonNull("GeoTiffReader", reader);
this.parent = reader;
this.coverageIdentifier = identifier;
hints = reader.getHints();
// get the default levels policy from the hints
extractOverviewPolicy();
// base image type
this.baseImageType = baseImageType;
// default ImageLayout
defaultImageLayout= new ImageLayout().setColorModel( baseImageType.getColorModel()).setSampleModel(baseImageType.getSampleModel());
//instantiating controller for subsampling and levels
overviewsController=new OverviewsController(resolutions);
try {
spatialDomainManager = new SpatialDomainManager(
crs,
envelope,
gridToWorld,
originalRasterRange);
} catch (TransformException e) {
throw new DataSourceException(e);
} catch (FactoryException e) {
throw new DataSourceException(e);
}
// rasterDescriptor creation
rasterDescriptor = new RasterDescriptor(this);
}
public RasterManager(final GeoTiffReader reader) throws DataSourceException {
Utilities.ensureNonNull("GeoTiffReader", reader);
// extract levels
double [][]resolutions = new double[reader.getNumberOfOverviews()+1][2];
double[][] overviewResolutions=reader.getOverviewsResolution();
resolutions[0]=reader.getHighestRes();
for(int i=1; i<resolutions.length;i++)
resolutions[i]=overviewResolutions[i-1];
initialize(
reader.getName(),
reader.getHints(),
reader.getCrs(),
reader.getOriginalEnvelope(),
(MathTransform2D)reader.getOriginalGridToWorld(PixelInCell.CELL_CENTER),
(Rectangle) reader.getOriginalGridRange(),
resolutions,
reader.baseImageType,
reader);
}
/**
* This method is responsible for checking the overview policy as defined by
* the provided {@link Hints}.
*
* @return the overview policy which can be one of
* {@link Hints#VALUE_OVERVIEW_POLICY_IGNORE},
* {@link Hints#VALUE_OVERVIEW_POLICY_NEAREST},
* {@link Hints#VALUE_OVERVIEW_POLICY_SPEED},
* {@link Hints#VALUE_OVERVIEW_POLICY_QUALITY}. Default is
* {@link Hints#VALUE_OVERVIEW_POLICY_NEAREST}.
*/
private OverviewPolicy extractOverviewPolicy() {
// check if a policy was provided using hints (check even the
// deprecated one)
if (this.hints != null) {
if (this.hints.containsKey(Hints.OVERVIEW_POLICY)) {
overviewPolicy = (OverviewPolicy) this.hints.get(Hints.OVERVIEW_POLICY);
}
}
// use default if not provided. Default is nearest
if (overviewPolicy == null) {
overviewPolicy = OverviewPolicy.getDefaultPolicy();
}
assert overviewPolicy != null;
return overviewPolicy;
}
public Collection<GridCoverage2D> read(final GeneralParameterValue[] params) throws IOException {
// create a request
final RasterLayerRequest request = new RasterLayerRequest(params, this);
if (request.isEmpty()) {
if (LOGGER.isLoggable(Level.FINE))
LOGGER.log(Level.FINE, "Request is empty: " + request.toString());
return Collections.emptyList();
}
// create a response for the provided request
final RasterLayerResponse response = new RasterLayerResponse(request, this);
// execute the request
final GridCoverage2D elem = response.createResponse();
if (elem != null) {
return Collections.singletonList(elem);
}
return Collections.emptyList();
}
public void dispose() {
}
public String getCoverageIdentifier() {
return coverageIdentifier;
}
public Hints getHints() {
return hints;
}
public CoordinateReferenceSystem getCoverageCRS() {
return spatialDomainManager.coverageCRS;
}
public GeneralEnvelope getCoverageEnvelope() {
return spatialDomainManager.coverageEnvelope;
}
public MathTransform2D getRaster2Model() {
return spatialDomainManager.coverageGridToWorld2D;
}
public Rectangle getCoverageGridrange() {
return spatialDomainManager.coverageRasterArea;
}
public GridCoverageFactory getGridCoverageFactory() {
return null;
}
}