/*
* Geotoolkit.org - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2001-2012, Open Source Geospatial Foundation (OSGeo)
* (C) 2009-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.operation.transform;
import org.apache.sis.internal.referencing.j2d.AffineTransform2D;
import java.awt.geom.Point2D;
import java.awt.image.RasterFormatException;
import javax.media.jai.Warp;
import org.opengis.referencing.operation.MathTransform2D;
import org.opengis.referencing.operation.TransformException;
import org.geotoolkit.resources.Errors;
import org.apache.sis.referencing.operation.transform.MathTransforms;
/**
* Wraps an arbitrary {@link MathTransform2D} into an image warp operation. This warp
* operation is used by {@link org.geotoolkit.coverage.processing.operation.Resample}
* when no standard warp operation has been found applicable.
*
* @author Martin Desruisseaux (IRD)
* @version 3.00
*
* @since 2.1
* @module
*/
final class WarpAdapter extends Warp {
/**
* For cross-version compatibility.
*/
private static final long serialVersionUID = -8679060848877065181L;
/**
* The transform to apply before the transform given at construction time.
*/
private static final AffineTransform2D PRE_TRANSFORM = new AffineTransform2D(1, 0, 0, 1, 0.5, 0.5);
/**
* The transform to apply after the transform given at construction time.
*/
private static final AffineTransform2D POST_TRANSFORM = new AffineTransform2D(1, 0, 0, 1, -0.5, -0.5);
/**
* The coverage name. Used for formatting error message.
*/
private final CharSequence name;
/**
* The <strong>inverse</strong> of the transform to apply for projecting an image.
* This transform maps destination pixels to source pixels.
*/
private final MathTransform2D inverse;
/**
* Constructs a new {@code WarpAdapter} using the given transform.
*
* @param name The coverage name. Used for formatting error message.
* @param inverse The <strong>inverse</strong> of the transformation to apply for projecting
* an image. This inverse transform maps destination pixels to source pixels.
*/
public WarpAdapter(final CharSequence name, final MathTransform2D inverse) {
this.name = name;
this.inverse = MathTransforms.concatenate(PRE_TRANSFORM, inverse, POST_TRANSFORM);
}
/**
* Returns the transform from image destination pixels to source pixels.
*/
public MathTransform2D getTransform() {
return inverse;
}
/**
* Computes the source pixel positions for a given rectangular
* destination region, subsampled with an integral period.
*/
@Override
public float[] warpSparseRect(final int xmin, final int ymin,
final int width, final int height,
final int periodX, final int periodY, float[] destRect)
{
if (periodX < 1) throw new IllegalArgumentException(String.valueOf(periodX));
if (periodY < 1) throw new IllegalArgumentException(String.valueOf(periodY));
final int xmax = xmin + width;
final int ymax = ymin + height;
final int count = ((width + (periodX - 1)) / periodX) *
((height + (periodY - 1)) / periodY);
if (destRect == null) {
destRect = new float[2*count];
}
int index = 0;
for (int y=ymin; y<ymax; y+=periodY) {
for (int x=xmin; x<xmax; x+=periodX) {
destRect[index++] = x;
destRect[index++] = y;
}
}
try {
inverse.transform(destRect, 0, destRect, 0, count);
} catch (TransformException exception) {
// At least one transformation failed. In Geotk MapProjection
// implementation, unprojected coordinates are set to (NaN,NaN).
RasterFormatException e = new RasterFormatException(
Errors.format(Errors.Keys.CantReprojectCoverage_1, name));
e.initCause(exception);
throw e;
}
return destRect;
}
/**
* Computes the source point corresponding to the supplied point.
*
* @param destPt The position in destination image coordinates
* to map to source image coordinates.
*/
@Override
public Point2D mapDestPoint(final Point2D destPt) {
try {
return inverse.transform(destPt, null);
} catch (TransformException exception) {
throw new IllegalArgumentException(Errors.format(
Errors.Keys.IllegalParameterValue_2, "destPt", destPt), exception);
}
}
/**
* Computes the destination point corresponding to the supplied point.
*
* @param sourcePt The position in source image coordinates
* to map to destination image coordinates.
*/
@Override
public Point2D mapSourcePoint(final Point2D sourcePt) {
try {
return inverse.inverse().transform(sourcePt, null);
} catch (TransformException exception) {
throw new IllegalArgumentException(Errors.format(
Errors.Keys.IllegalParameterValue_2, "sourcePt", sourcePt), exception);
}
}
}