/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2008 - 2009, Geomatys
*
* 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.geotoolkit.display2d.canvas;
import java.awt.geom.Rectangle2D;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map.Entry;
import java.util.logging.Level;
import javax.measure.IncommensurableException;
import org.apache.sis.geometry.GeneralDirectPosition;
import org.apache.sis.geometry.GeneralEnvelope;
import org.apache.sis.internal.referencing.GeodeticObjectBuilder;
import org.apache.sis.util.ArraysExt;
import org.apache.sis.util.logging.Logging;
import org.geotoolkit.storage.coverage.CoverageExtractor;
import org.geotoolkit.storage.coverage.CoverageReference;
import org.geotoolkit.coverage.GridSampleDimension;
import org.geotoolkit.coverage.grid.GridCoverage2D;
import org.geotoolkit.coverage.io.CoverageStoreException;
import org.geotoolkit.coverage.io.GridCoverageReadParam;
import org.geotoolkit.coverage.io.GridCoverageReader;
import org.geotoolkit.display.SearchArea;
import org.geotoolkit.display.canvas.RenderingContext;
import org.geotoolkit.display2d.GraphicVisitor;
import org.geotoolkit.display2d.primitive.ProjectedCoverage;
import org.geotoolkit.display2d.primitive.ProjectedFeature;
import org.geotoolkit.display2d.primitive.SearchAreaJ2D;
import org.geotoolkit.map.CoverageMapLayer;
import org.apache.sis.referencing.CRS;
import org.opengis.coverage.CannotEvaluateException;
import org.opengis.display.primitive.Graphic;
import org.opengis.geometry.Envelope;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.crs.TemporalCRS;
import org.opengis.referencing.operation.TransformException;
import org.opengis.util.FactoryException;
import org.apache.sis.geometry.Envelopes;
import org.apache.sis.measure.Units;
/**
* A visitor which can be applied to the
* {@link org.opengis.display.primitive.Graphic} objects of a scene and through
* the {@code Graphic} objects, to the underlying
* {@link org.opengis.feature.Feature} or
* {@link org.opengis.coverage.grid.GridCoverage}.
*
* @author Johann Sorel (Geomatys)
* @module
*/
public abstract class AbstractGraphicVisitor implements GraphicVisitor {
public abstract void visit(ProjectedFeature feature, RenderingContext2D context, SearchAreaJ2D area);
public abstract void visit(ProjectedCoverage coverage, RenderingContext2D context, SearchAreaJ2D area);
/**
* {@inheritDoc }
*/
@Override
public void startVisit() {
}
/**
* {@inheritDoc }
*/
@Override
public void endVisit() {
}
/**
* {@inheritDoc }
*/
@Override
public void visit(final Graphic graphic, final RenderingContext context, final SearchArea area) {
if(graphic == null ) return;
if(graphic instanceof ProjectedFeature){
visit((ProjectedFeature)graphic, (RenderingContext2D)context, (SearchAreaJ2D)area);
}else if(graphic instanceof ProjectedCoverage){
visit((ProjectedCoverage)graphic, (RenderingContext2D)context, (SearchAreaJ2D)area);
}
}
/**
* {@inheritDoc }
*/
@Override
public boolean isStopRequested() {
return false;
}
/**
* Returns the data values of the given coverage, or {@code null} if the
* values can not be obtained.
*
* @return list : each entry contain a gridsampledimension and value associated.
*/
protected static List<Entry<GridSampleDimension,Object>> getCoverageValues(final ProjectedCoverage gra, final RenderingContext2D context, final SearchAreaJ2D queryArea) {
final CoverageMapLayer layer = gra.getLayer();
Envelope objBounds = context.getCanvasObjectiveBounds();
CoordinateReferenceSystem objCRS = objBounds.getCoordinateReferenceSystem();
TemporalCRS temporalCRS = CRS.getTemporalComponent(objCRS);
if (temporalCRS == null) {
/*
* If there is no temporal range, arbitrarily select the latest date.
* This is necessary otherwise the call to reader.read(...) will scan
* every records in the GridCoverages table for the layer.
*/
Envelope timeRange = layer.getBounds();
if (timeRange != null) {
temporalCRS = CRS.getTemporalComponent(timeRange.getCoordinateReferenceSystem());
if (temporalCRS != null) {
try {
timeRange = Envelopes.transform(timeRange, temporalCRS);
} catch (TransformException e) {
// Should never happen since temporalCRS is a component of layer CRS.
Logging.unexpectedException(null, AbstractGraphicVisitor.class, "getCoverageValues", e);
return null;
}
final double lastTime = timeRange.getMaximum(0);
double day;
try {
// Arbitrarily use a time range of 1 day, to be converted in units of the temporal CRS.
day = Units.DAY.getConverterToAny(temporalCRS.getCoordinateSystem().getAxis(0).getUnit()).convert(1);
} catch (IncommensurableException e) {
// Should never happen since TemporalCRS use time units. But if it happen
// anyway, use a time range of 1 of whatever units the temporal CRS use.
Logging.unexpectedException(null, AbstractGraphicVisitor.class, "getCoverageValues", e);
day = 1;
}
try {
objCRS = new GeodeticObjectBuilder().addName(objCRS.getName().getCode() + " + time")
.createCompoundCRS(objCRS, temporalCRS);
} catch (FactoryException ex) {
throw new IllegalStateException(ex);
}
final GeneralEnvelope merged = new GeneralEnvelope(objCRS);
merged.subEnvelope(0, objBounds.getDimension()).setEnvelope(objBounds);
merged.setRange(objBounds.getDimension(), lastTime - day, lastTime);
objBounds = merged;
}
}
}
double[] resolution = context.getResolution();
resolution = ArraysExt.resize(resolution, objCRS.getCoordinateSystem().getDimension());
final GridCoverageReadParam param = new GridCoverageReadParam();
param.setEnvelope(objBounds);
param.setResolution(resolution);
final GridCoverage2D coverage;
try {
final CoverageReference ref = layer.getCoverageReference();
final GridCoverageReader reader = ref.acquireReader();
coverage = (GridCoverage2D) reader.read(ref.getImageIndex(),param);
ref.recycle(reader);
} catch (CoverageStoreException ex) {
context.getMonitor().exceptionOccured(ex, Level.INFO);
return null;
}
if (coverage == null) {
//no coverage for this BBOX
return null;
}
final GeneralDirectPosition dp = new GeneralDirectPosition(objCRS);
final Rectangle2D bounds2D = queryArea.getObjectiveShape().getBounds2D();
dp.setOrdinate(0, bounds2D.getCenterX());
dp.setOrdinate(1, bounds2D.getCenterY());
float[] values = null;
try{
values = coverage.evaluate(dp, values);
}catch(CannotEvaluateException ex){
context.getMonitor().exceptionOccured(ex, Level.INFO);
values = new float[coverage.getSampleDimensions().length];
Arrays.fill(values, Float.NaN);
}
final List<Entry<GridSampleDimension,Object>> results = new ArrayList<>();
for (int i=0; i<values.length; i++){
final GridSampleDimension sample = coverage.getSampleDimension(i);
results.add(new SimpleImmutableEntry<GridSampleDimension, Object>(sample, values[i]));
}
return results;
}
/**
*
* @param projectedCoverage
* @param context
* @param area
* @return
* @throws CoverageStoreException
* @throws TransformException
*/
protected static CoverageExtractor.Ray rayExtraction(ProjectedCoverage projectedCoverage, RenderingContext2D context, SearchAreaJ2D area)
throws CoverageStoreException, TransformException {
//point in objective CRS
final GeneralDirectPosition dp = new GeneralDirectPosition(context.getObjectiveCRS2D());
final Rectangle2D bounds2D = area.getObjectiveShape().getBounds2D();
dp.setOrdinate(0, bounds2D.getCenterX());
dp.setOrdinate(1, bounds2D.getCenterY());
final CoverageMapLayer layer = projectedCoverage.getLayer();
final CoverageReference covRef = layer.getCoverageReference();
GridCoverageReader reader = null;
try {
reader = covRef.acquireReader();
final Envelope canvasObjective = context.getCanvasObjectiveBounds();
final int canvasNbDim = canvasObjective.getDimension();
//fix resolution array
double[] resolution = new double[canvasNbDim];
resolution[0] = context.getResolution()[0];
resolution[1] = context.getResolution()[1];
for (int i = 2; i < canvasNbDim; i++) {
resolution[i] = 1.0;
}
final GridCoverageReadParam param = new GridCoverageReadParam();
param.setDeferred(true);
param.setEnvelope(canvasObjective);
param.setResolution(resolution);
return CoverageExtractor.rayExtraction(dp, reader, covRef.getImageIndex(), param);
} finally {
if (reader != null) {
covRef.recycle(reader);
}
}
}
}