/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2014, 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.storage.coverage;
import org.apache.sis.geometry.GeneralDirectPosition;
import org.geotoolkit.coverage.GridCoverageStack;
import org.geotoolkit.coverage.GridSampleDimension;
import org.geotoolkit.coverage.grid.GridCoverage2D;
import org.geotoolkit.coverage.grid.GridGeometry2D;
import org.geotoolkit.coverage.io.CoverageStoreException;
import org.geotoolkit.coverage.io.GridCoverageReadParam;
import org.geotoolkit.coverage.io.GridCoverageReader;
import org.geotoolkit.lang.Static;
import org.opengis.coverage.grid.GridCoverage;
import org.opengis.geometry.DirectPosition;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import java.util.*;
/**
* A set of utility method to extract values, coverages or cube from a GridCoverage.
*
* @author Quentin Boileau (Geomatys)
*/
public class CoverageExtractor extends Static {
/**
* Simple Pojo that keep rayExtraction values.
*/
public static class Ray {
private List<GridSampleDimension> sampleDimensions = new ArrayList<GridSampleDimension>();
private Map<DirectPosition, double[]> values = new TreeMap<>(new SliceComparator());
public List<GridSampleDimension> getSampleDimensions() {
return sampleDimensions;
}
public Map<DirectPosition, double[]> getValues() {
return values;
}
}
/**
* Call {@link org.opengis.coverage.grid.GridCoverage#evaluate(org.opengis.geometry.DirectPosition, double[])} on all
* {@link org.geotoolkit.coverage.grid.GridCoverage2D} slices returned by reader.
*
* @param point position given to evaluate function.
* @param reader GridCoverageReader not disposed or released
* @param imageIndex index given to read.
* @param param GridCoverageReadParam. Deferred parameter will be forced at true.
* @return Ray bean object.
* @throws CoverageStoreException
* @throws TransformException
*/
public static Ray rayExtraction(GeneralDirectPosition point, GridCoverageReader reader, int imageIndex,
GridCoverageReadParam param) throws CoverageStoreException, TransformException {
param.setDeferred(true); //force deferred
final GridCoverage coverage = reader.read(imageIndex, param);
Ray result = new Ray();
result.getSampleDimensions().addAll(reader.getSampleDimensions(imageIndex));
evaluateAllSlices(point, coverage, result);
return result;
}
/**
* Call {@link org.opengis.coverage.grid.GridCoverage#evaluate(org.opengis.geometry.DirectPosition, double[])} on all
* {@link org.geotoolkit.coverage.grid.GridCoverage2D slices}.
*
* @param directPos position given to evaluate function.
* @param coverage GridCoverage2D or GridCoverageStack coverage.
* @param result recursively filled with extracted values
* @throws CoverageStoreException
* @throws TransformException
*/
private static void evaluateAllSlices(GeneralDirectPosition directPos, GridCoverage coverage, Ray result)
throws CoverageStoreException, TransformException {
if (coverage instanceof GridCoverage2D) {
final GridCoverage2D coverage2D = (GridCoverage2D) coverage;
double[] values = new double[coverage2D.getSampleDimensions().length];
//place directPos to a pixel center
GridGeometry2D gg2D = coverage2D.getGridGeometry();
MathTransform gridToCRS = gg2D.getGridToCRS2D();
gridToCRS.inverse().transform(directPos, directPos);
for (int i = 0; i < directPos.getDimension(); i++) {
directPos.setOrdinate(i, Math.round(directPos.getOrdinate(i)));
}
gridToCRS.transform(directPos, directPos);
coverage2D.evaluate(directPos, values);
final CoordinateReferenceSystem crs = gg2D.getCoordinateReferenceSystem();
int dimension = crs.getCoordinateSystem().getDimension();
double[] point = new double[dimension];
final MathTransform cov2DGridToCRS = gg2D.getGridToCRS();
cov2DGridToCRS.transform(point, 0, point, 0, 1);
final GeneralDirectPosition position = new GeneralDirectPosition(point);
position.setCoordinateReferenceSystem(crs);
position.setOrdinate(0, directPos.getOrdinate(0));
position.setOrdinate(1, directPos.getOrdinate(1));
result.getValues().put(position, values);
} else if (coverage instanceof GridCoverageStack) {
final GridCoverageStack coverageStack = (GridCoverageStack) coverage;
int length = coverageStack.getStackSize();
for (int i = 0; i < length; i++) {
evaluateAllSlices(directPos, (GridCoverage) coverageStack.coverageAtIndex(i), result);
}
}
}
/**
* Comparator of DirectPosition to sort slice by dimensions.
*/
private static class SliceComparator implements Comparator<DirectPosition> {
@Override
public int compare(DirectPosition o1, DirectPosition o2) {
int dimension = o1.getDimension();
if (dimension > 2) {
int currDim = 2;
int[] dimCompar = new int[dimension-2];
while (currDim <= dimension-1) {
dimCompar[currDim-2] = Double.compare(o1.getOrdinate(currDim), o2.getOrdinate(currDim));
currDim++;
}
for (int i = 0; i < dimCompar.length; i++) {
if (dimCompar[i] != 0) {
return dimCompar[i];
}
}
}
return 0;
}
}
}