/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2009-2013, 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.primitive;
import java.util.logging.Level;
import org.apache.sis.geometry.GeneralEnvelope;
import org.apache.sis.util.collection.Cache;
import org.geotoolkit.storage.coverage.CoverageReference;
import org.geotoolkit.coverage.GridCoverageStack;
import org.geotoolkit.coverage.grid.GridCoverage2D;
import org.geotoolkit.coverage.io.CoverageStoreException;
import org.geotoolkit.coverage.io.DisjointCoverageDomainException;
import org.geotoolkit.coverage.io.GridCoverageReadParam;
import org.geotoolkit.coverage.io.GridCoverageReader;
import org.geotoolkit.display.canvas.AbstractCanvas2D;
import org.geotoolkit.display2d.GO2Hints;
import org.geotoolkit.display2d.GO2Utilities;
import org.geotoolkit.display2d.container.stateless.StatelessContextParams;
import org.geotoolkit.geometry.jts.JTS;
import org.geotoolkit.map.CoverageMapLayer;
import org.geotoolkit.map.ElevationModel;
import org.opengis.coverage.grid.GridCoverage;
import org.opengis.filter.expression.Expression;
import org.opengis.geometry.Envelope;
import org.opengis.referencing.operation.TransformException;
import org.apache.sis.geometry.Envelopes;
import org.apache.sis.util.logging.Logging;
/**
* Convenient representation of a coverage for rendering.
* Caches coverage based on given parameters.
*
* Not thread safe.
* Use it knowing you make clear cache operation in a synchronize way.
*
* @author Johann Sorel (Geomatys)
* @module
*/
public class ProjectedCoverage implements ProjectedObject<CoverageMapLayer> {
private final Cache<GridCoverageReadParam, GridCoverage2D> cache = new Cache<>(1, 0, false);
private final StatelessContextParams params;
private final CoverageMapLayer layer;
private ProjectedGeometry border;
public ProjectedCoverage(final StatelessContextParams params, final CoverageMapLayer layer) {
this.params = params;
this.layer = layer;
}
public void clearObjectiveCache(){
border = null;
}
public void clearDisplayCache(){
border = null;
}
/**
* Get the original CoverageMapLayer from where the feature is from.
*
* @return CoverageMapLayer
*/
@Override
public CoverageMapLayer getLayer() {
return layer;
}
/**
* Return internal coverage.
*
* TODO return a GridCoverage instead of GridCoverage2D ?
*
* @param param : expected coverage parameters
* @return GridCoverage2D or {@code null} if the requested parameters are out of the coverage area.
*
* @throws CoverageStoreException if problem during {@link CoverageReference#acquireReader() }
* or {@link GridCoverageReader#dispose() } call.
*/
public GridCoverage2D getCoverage(final GridCoverageReadParam param) throws CoverageStoreException{
GridCoverage2D value = cache.peek(param);
if (value == null) {
Cache.Handler<GridCoverage2D> handler = cache.lock(param);
try {
value = handler.peek();
if (value == null) {
final CoverageReference ref = layer.getCoverageReference();
final GridCoverageReader reader = ref.acquireReader();
try {
final GridCoverage result = reader.read(layer.getCoverageReference().getImageIndex(), param);
if (result instanceof GridCoverageStack) {
throw new CoverageStoreException("Coverage reader return more than one slice.");
}
value = (GridCoverage2D) result;
ref.recycle(reader);
} catch (DisjointCoverageDomainException ex) {
//-- DisjointCoverageDomainException is return when we request area out of source boundary.
//-- it's an expected comportement
//-- this method will return null in accordance with its contract.
ref.recycle(reader);
} catch (Throwable e) {
reader.dispose();
throw e;
}
}
} finally {
handler.putAndUnlock(value);
}
}
return value;
}
/**
* Get the projected geometry representation of the coverage border.
*
* @return ProjectedGeometry
*/
public ProjectedGeometry getEnvelopeGeometry() {
if(border == null){
Envelope env = layer.getBounds();
try {
env = Envelopes.transform(env, params.context.getObjectiveCRS2D());
} catch (TransformException ex) {
Logging.getLogger("org.geotoolkit.display2d.primitive").log(Level.SEVERE, null, ex);
}
env = new GeneralEnvelope(env);
GO2Utilities.removeNaN((GeneralEnvelope)env);
border = new ProjectedGeometry(params);
border.setDataGeometry(JTS.toGeometry(env),env.getCoordinateReferenceSystem());
}
return border;
}
/**
* Get a coverage reference for the elevation model.
*
* @param param : expected coverage parameters
* @return GridCoverage2D or null if the requested parameters are out of the coverage area.
*
* @throws CoverageStoreException
*/
public GridCoverage2D getElevationCoverage(final GridCoverageReadParam param) throws CoverageStoreException{
ElevationModel elevationModel = layer.getElevationModel();
if(elevationModel == null){
elevationModel = (ElevationModel) params.context.getRenderingHints().get(GO2Hints.KEY_ELEVATION_MODEL);
}
if(elevationModel != null){
return (GridCoverage2D) elevationModel.getCoverageReader().read(0,param);
}else{
return null;
}
}
/**
* {@inheritDoc }
*/
@Override
public boolean isVisible() {
return true;
}
/**
* {@inheritDoc }
*/
@Override
public void setVisible(final boolean visible) {
}
/**
* {@inheritDoc }
*/
@Override
public void dispose() {
cache.clear();
}
@Override
public AbstractCanvas2D getCanvas() {
return params.canvas;
}
@Override
public CoverageMapLayer getCandidate() {
return layer;
}
@Override
public ProjectedGeometry getGeometry(Expression name) {
throw new UnsupportedOperationException("Not supported.");
}
}