/*
* Geotoolkit.org - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2010-2012, Open Source Geospatial Foundation (OSGeo)
* (C) 2010-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.referencing.adapters;
import java.util.Map;
import java.util.LinkedHashMap;
import javax.imageio.IIOException;
import ucar.nc2.Dimension;
import ucar.nc2.dataset.CoordinateAxis2D;
import org.opengis.referencing.operation.TransformException;
import org.geotoolkit.resources.Errors;
/**
* Wraps a NetCDF {@link CoordinateAxis2D} as an implementation of GeoAPI interfaces.
*
* @author Martin Desruisseaux (Geomatys)
* @version 3.20
*
* @since 3.20 (derived from 3.08)
* @module
*/
final class NetcdfAxis2D extends NetcdfAxis {
/**
* The index of the ordinate values to fetch in a source coordinate.
*/
private final int iDim, jDim;
/**
* Lengths along the two first axes.
*/
private final int iNum, jNum;
/**
* Creates a new {@code NetcdfAxis} object wrapping the given NetCDF coordinate axis.
*
* @param axis The NetCDF coordinate axis to wrap.
* @param domain Dimensions of the variable for which we are wrapping an axis, in natural order
* (reverse of NetCDF order). They are often, but not necessarily, the coordinate system
* dimensions.
* @throws IIOException If the axis domain is not contained in the given list of dimensions.
*/
NetcdfAxis2D(final CoordinateAxis2D axis, final Dimension[] domain) throws IIOException {
super(axis);
iDim = indexOfDimension(axis, 0, domain);
jDim = indexOfDimension(axis, 1, domain);
iNum = axis.getShape(0);
jNum = axis.getShape(1);
}
/**
* Creates a copy of the given axis with only different {@link #iDim} and {@link #jDim} values.
*/
private NetcdfAxis2D(final NetcdfAxis2D axis, final int iDim, final int jDim) {
super(axis);
this.iDim = iDim;
this.jDim = jDim;
this.iNum = axis.iNum;
this.jNum = axis.jNum;
}
/**
* Returns a NetCDF axis which is part of the given domain.
* This method does not modify this axis. Instead, it will create a new one if necessary.
*
* @param domain The new domain in <em>natural</em> order (<strong>not</strong> the NetCDF order).
* @throws IIOException If the given domain does not contains this axis domain.
*/
@Override
final NetcdfAxis forDomain(final Dimension[] domain) throws IIOException {
final int i0 = indexOfDimension(axis, 0, domain);
final int i1 = indexOfDimension(axis, 1, domain);
return (i0 == iDim && i1 == jDim) ? this : new NetcdfAxis2D(this, i0, i1);
}
/**
* Returns the source dimensions of this axis, associated to the indices in source coordinates.
*/
@Override
final Map<Integer,Dimension> getDomain() {
final Map<Integer,Dimension> domain = new LinkedHashMap<>(4);
domain.put(iDim, axis.getDimension(0));
domain.put(jDim, axis.getDimension(1));
return domain;
}
/**
* Returns the number of source ordinate values along the given <em>source</em> dimension,
* or -1 if this axis is not for the given dimension.
*/
@Override
final int length(final int sourceDimension) {
if (sourceDimension == iDim) return iNum;
if (sourceDimension == jDim) return jNum;
return super.length(sourceDimension);
}
/**
* Interpolates the ordinate values at cell center from the given grid coordinate.
*/
@Override
public double getOrdinateValue(final double[] gridPts, final int srcOff) throws TransformException {
final double x = gridPts[srcOff + iDim];
final double y = gridPts[srcOff + jDim];
try {
/*
* Casting to (int) round all values between -1 and 1 toward 0, which is exactly what we
* need in this particular case. We want -0.5 to be rounded toward zero because envelope
* transformations will often apply a 0.5 shift on the pixel coordinates, thus resulting
* in some -0.5 values. For such cases, a small extrapolation will be applied.
*/
final int i = (int) x;
final int j = (int) y;
final CoordinateAxis2D axis = (CoordinateAxis2D) this.axis;
double value = axis.getCoordValue(i, j);
double dx = x - i;
double dy = y - j;
if (dx != 0 || dy != 0) {
int i1 = i+1; if (i1 == iNum) {i1 -= 2; dx = -dx;}
int j1 = j+1; if (j1 == jNum) {j1 -= 2; dy = -dy;}
double v2 = axis.getCoordValue(i, j1);
v2 += dx * (axis.getCoordValue(i1, j1) - v2);
value += dx * (axis.getCoordValue(i1, j ) - value);
value += dy * (v2 - value);
}
return value;
} catch (IndexOutOfBoundsException e) {
throw new TransformException(Errors.format(Errors.Keys.IllegalCoordinate_1,
"(" + x + ", " + y + ')'), e);
}
}
}