/*
* Geotoolkit.org - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2012, 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.coverage.finder;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.geotoolkit.storage.coverage.CoverageUtilities;
import org.geotoolkit.storage.coverage.GridMosaic;
import org.geotoolkit.storage.coverage.Pyramid;
import org.apache.sis.geometry.GeneralEnvelope;
import org.apache.sis.referencing.CRS;
import org.opengis.geometry.Envelope;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.util.FactoryException;
/**
* More Mathematical exhaustive CoverageFinder.
*
* @author Remi Marechal (Geomatys).
*/
public class StrictlyCoverageFinder extends CoverageFinder {
/**
* {@inheritDoc }.
* <p>Note : Can return null if no mosaic within {@link Envelope} parameter area exist.</p>
*/
@Override
public GridMosaic findMosaic(Pyramid pyramid, double resolution, double tolerance, Envelope env, Integer maxTileNumber)
throws FactoryException {
final MathTransform mt = CRS.findOperation(pyramid.getCoordinateReferenceSystem(), env.getCoordinateReferenceSystem(), null).getMathTransform();
if (!mt.isIdentity()) throw new IllegalArgumentException("findMosaic : not same CoordinateReferenceSystem");
final List<GridMosaic> mosaics = new ArrayList<>(pyramid.getMosaics());
final List<GridMosaic> goodMosaics;
final GeneralEnvelope findEnvelope = new GeneralEnvelope(env);
// if crs is compound
if (env.getDimension() > 2) {
double bestRatio = Double.NEGATIVE_INFINITY;
goodMosaics = new ArrayList<>();
// find nearest gridMosaic
for (GridMosaic gridMosaic : mosaics) {
final Envelope gridEnvelope = gridMosaic.getEnvelope();
// if intersection solution exist
if (findEnvelope.intersects(gridEnvelope, true)) {
final double ratioTemp = CoverageUtilities.getRatioND(findEnvelope, gridEnvelope);
if (ratioTemp > (bestRatio + DEFAULT_EPSILON)) { // >
goodMosaics.clear();
goodMosaics.add(gridMosaic);
bestRatio = ratioTemp;
} else if ((Math.abs(ratioTemp - bestRatio)) <= DEFAULT_EPSILON) { // =
goodMosaics.add(gridMosaic);
}
}
}
} else {
goodMosaics = mosaics;
}
// if no coverage intersect search envelope.
if (goodMosaics.isEmpty()) return null;
if (goodMosaics.size() == 1) return goodMosaics.get(0);
// find mosaic with the most appropriate scale value.
Collections.sort(goodMosaics, SCALE_COMPARATOR);
Collections.reverse(goodMosaics);
GridMosaic result = null;
for (GridMosaic candidate : goodMosaics) {// find best scale
final double scale = candidate.getScale();
if(result == null){
//set the highest mosaic as base
result = candidate;
}
//check if it will not requiere too much tiles
final Dimension tileSize = candidate.getTileSize();
double nbtileX = env.getSpan(0) / (tileSize.width*scale);
double nbtileY = env.getSpan(1) / (tileSize.height*scale);
//if the envelope has some NaN, we presume it's a square
if(Double.isNaN(nbtileX) || Double.isInfinite(nbtileX)){
nbtileX = nbtileY;
}else if(Double.isNaN(nbtileY) || Double.isInfinite(nbtileY)){
nbtileY = nbtileX;
}
if(maxTileNumber != null && maxTileNumber > 0 && nbtileX*nbtileY > maxTileNumber){
//we haven't reach the best resolution, it would requiere
//too much tiles, we use the previous scale level
break;
}
result = candidate;
if( (scale * (1-tolerance)) < resolution){
//we found the most accurate resolution
break;
}
}
return result;
}
}