/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2007-2014, 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.coverage.io.netcdf;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.SortedSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.media.jai.Interpolation;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.coverage.io.CoverageReadRequest;
import org.geotools.coverage.io.RasterLayout;
import org.geotools.coverage.io.ReadType;
import org.geotools.coverage.io.SpatialRequestHelper;
import org.geotools.coverage.io.SpatialRequestHelper.CoverageProperties;
import org.geotools.coverage.io.range.RangeType;
import org.geotools.coverage.io.util.DateRangeTreeSet;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.imageio.netcdf.VariableAdapter;
import org.geotools.resources.coverage.CoverageUtilities;
import org.geotools.util.DateRange;
import org.geotools.util.NumberRange;
import org.opengis.geometry.BoundingBox;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransform2D;
import org.opengis.referencing.operation.TransformException;
/**
* A class to handle coverage requests to a reader for a single 2D layer..
*
* @author Daniele Romagnoli, GeoSolutions
* @author Simone Giannecchini, GeoSolutions
*/
class NetCDFRequest extends CoverageReadRequest{
/** Logger. */
private final static Logger LOGGER = org.geotools.util.logging.Logging.getLogger(NetCDFRequest.class);
/** The Interpolation required to serve this request */
// TODO: CUSTOMIZE INTERPOLATION request.getInterpolation();
Interpolation interpolation = Interpolation.getInstance(Interpolation.INTERP_NEAREST);
NetCDFSource source;
// on NetCDF adopt the direct read: see the google document (Which one? it seems it has been deleted)
ReadType readType = ReadType.DIRECT_READ;
SpatialRequestHelper spatialRequestHelper;
CoverageReadRequest originalRequest = null;
String name = null;
/**
* Build a new {@code CoverageRequest} given a set of input parameters.
*
* @param params The {@code GeneralParameterValue}s to initialize this request
* @param baseGridCoverage2DReader
* @throws IOException
*/
public NetCDFRequest(NetCDFSource source, CoverageReadRequest request) throws IOException {
this.source = source;
this.originalRequest = request;
name = source.getName(null).toString();
// //
//
// Checking the request and filling the missing fields
//
// //
checkRequest(request);
this.spatialRequestHelper = new SpatialRequestHelper();
BoundingBox requestedBBox = request.getGeographicArea();
Rectangle requestedRasterArea = request.getRasterArea();
MathTransform2D requestedG2W = request.getGridToWorldTransform();
spatialRequestHelper.setRequestedBBox(requestedBBox);
spatialRequestHelper.setRequestedRasterArea(requestedRasterArea);
spatialRequestHelper.setRequestedGridToWorld((AffineTransform) requestedG2W);
// initialize
initInputCoverageProperties();
}
/**
* Initialize coverage input properties by collecting them from a {@link CoverageSourceWrapper}
*
* @param wrapper
* @throws IOException
*/
private void initInputCoverageProperties() throws IOException {
VariableAdapter.UnidataSpatialDomain spatialDomain = (org.geotools.imageio.netcdf.VariableAdapter.UnidataSpatialDomain) (source.getSpatialDomain());
// Getting spatial context
final Set<? extends RasterLayout> rasterElements = spatialDomain.getRasterElements(false, null);
final GridGeometry2D gridGeometry2D = spatialDomain.getGridGeometry();
final AffineTransform gridToCRS = (AffineTransform) gridGeometry2D.getGridToCRS();
final double[] coverageFullResolution = CoverageUtilities.getResolution(gridToCRS);
final MathTransform raster2Model = gridGeometry2D.getGridToCRS();
final ReferencedEnvelope bbox = spatialDomain.getReferencedEnvelope();
final ReferencedEnvelope referencedEnvelope = new ReferencedEnvelope(bbox);
final CoordinateReferenceSystem spatialReferenceSystem2D = spatialDomain.getCoordinateReferenceSystem2D();
rasterArea = rasterElements.iterator().next().toRectangle();
// Setting up Coverage info
final CoverageProperties properties = new CoverageProperties();
properties.setCrs2D(spatialReferenceSystem2D);
properties.setFullResolution(coverageFullResolution);
// Note that currently, we only support geographic CRS
properties.setBbox(referencedEnvelope);
properties.setGeographicBBox(referencedEnvelope);
properties.setGeographicCRS2D(spatialReferenceSystem2D);
properties.setGridToWorld2D((MathTransform2D)raster2Model);
properties.setRasterArea(rasterArea);
spatialRequestHelper.setCoverageProperties(properties);
spatialRequestHelper.prepare();
}
private void checkRequest(CoverageReadRequest request) throws IOException {
BoundingBox requestedBoundingBox = request.getGeographicArea();
// //
//
// Checking RequestedRasterArea setting
//
// //
Rectangle requestedRasterArea = request.getRasterArea();
VariableAdapter.UnidataSpatialDomain horizontalDomain = (VariableAdapter.UnidataSpatialDomain)source.getSpatialDomain();
VariableAdapter.UnidataTemporalDomain temporalDomain = (VariableAdapter.UnidataTemporalDomain) source.getTemporalDomain();
VariableAdapter.UnidataVerticalDomain verticalDomain = (VariableAdapter.UnidataVerticalDomain) source.getVerticalDomain();
if (requestedRasterArea == null || requestedBoundingBox == null) {
boolean bothNull = true;
if (requestedRasterArea == null) {
requestedRasterArea = horizontalDomain.getGridGeometry().getGridRange2D().getBounds();
}else{
bothNull = false;
}
if (requestedBoundingBox == null) {
requestedBoundingBox = horizontalDomain.getReferencedEnvelope();
}else{
bothNull = false;
}
if (bothNull) {
try {
request.setDomainSubset(requestedRasterArea,horizontalDomain.getGridGeometry().getGridToCRS2D(),horizontalDomain.getCoordinateReferenceSystem2D());
} catch (TransformException e) {
request.setDomainSubset(requestedRasterArea, ReferencedEnvelope.reference(requestedBoundingBox));
LOGGER.log(Level.SEVERE,"Transform exception while setting the domain subset to: "+requestedRasterArea,e);
}
} else {
// TODO: Check for center/corner anchor point
request.setDomainSubset(requestedRasterArea, ReferencedEnvelope.reference(requestedBoundingBox));
}
}
// //
//
// Checking TemporalSubset setting
//
// //
SortedSet<DateRange> temporalSubset = request.getTemporalSubset();
if (temporalDomain != null) {
if (temporalSubset.isEmpty()) {
Set<DateRange> temporalExtent = temporalDomain.getTemporalExtent();
if (temporalExtent != null) {
temporalSubset = new DateRangeTreeSet(temporalExtent);
}
request.setTemporalSubset(temporalSubset);
}
}
// //
//
// Checking VerticalSubset setting
//
// //
Set<NumberRange<Double>> verticalSubset = request.getVerticalSubset();
if (verticalDomain != null) {
Set<NumberRange<Double>> verticalExtent = verticalDomain.getVerticalExtent();
if (verticalSubset.isEmpty()) {
if (verticalExtent != null) {
verticalSubset = new HashSet<NumberRange<Double>>(verticalExtent);
}
request.setVerticalSubset(verticalSubset);
} else {
final NumberRange<Double> requestedVerticalEnv = verticalSubset.iterator().next();
if (verticalExtent != null && !verticalExtent.isEmpty() && !verticalExtent.iterator().next().contains(requestedVerticalEnv)) {
// Find the nearest vertical Envelope
NumberRange<Double> nearestEnvelope = verticalExtent.iterator().next();
double minimumDistance = Math.abs(nearestEnvelope.getMinimum() - requestedVerticalEnv.getMinimum());
for (NumberRange<Double> env : verticalExtent) {
double distance = Math.abs(env.getMinimum() - requestedVerticalEnv.getMinimum());
if (distance < minimumDistance) {
nearestEnvelope = env;
minimumDistance = distance;
}
}
verticalSubset = new HashSet<NumberRange<Double>>(1);
verticalSubset.add(nearestEnvelope);
request.setVerticalSubset(verticalSubset);
}
}
}
// //
//
// Checking RangeSubset setting
//
// //
RangeType range = request.getRangeSubset();
if (range == null) {
request.setRangeSubset(source.getRangeType(null));
}
}
ReadType getReadType() {
return readType;
}
Interpolation getInterpolation() {
return interpolation;
}
@Override
public String toString() {
return "NetCDFRequest [interpolation=" + interpolation + ", source=" + source
+ ", readType=" + readType + ", spatialRequestHelper=" + spatialRequestHelper
+ ", originalRequest=" + originalRequest + ", name=" + name + "]";
}
}