/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2001-2008, Open Source Geospatial Foundation (OSGeo) * * 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. * * This package contains documentation from OpenGIS specifications. * OpenGIS consortium's work is fully acknowledged here. */ package org.geotools.referencing.operation.transform; import java.awt.geom.AffineTransform; import java.awt.geom.Point2D; import java.io.Serializable; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import javax.vecmath.MismatchedSizeException; import javax.vecmath.SingularMatrixException; import javax.measure.unit.NonSI; import org.opengis.parameter.ParameterDescriptor; import org.opengis.parameter.ParameterDescriptorGroup; import org.opengis.parameter.ParameterNotFoundException; import org.opengis.parameter.ParameterValueGroup; import org.opengis.referencing.operation.Conversion; import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.Matrix; import org.opengis.referencing.operation.NoninvertibleTransformException; import org.opengis.geometry.DirectPosition; import org.geotools.metadata.iso.citation.Citations; import org.geotools.parameter.MatrixParameterDescriptors; import org.geotools.parameter.MatrixParameters; import org.geotools.referencing.NamedIdentifier; import org.geotools.referencing.operation.LinearTransform; import org.geotools.referencing.operation.MathTransformProvider; import org.geotools.referencing.operation.matrix.MatrixFactory; import org.geotools.referencing.operation.matrix.GeneralMatrix; import org.geotools.referencing.operation.matrix.XMatrix; import org.geotools.resources.i18n.VocabularyKeys; import org.geotools.resources.i18n.Vocabulary; import org.geotools.resources.i18n.ErrorKeys; import org.geotools.resources.i18n.Errors; /** * A usually affine, or otherwise a projective transform. A projective transform is capable of * mapping an arbitrary quadrilateral into another arbitrary quadrilateral, while preserving the * straightness of lines. In the special case where the transform is affine, the parallelism of * lines in the source is preserved in the output. *
* Such a coordinate transformation can be represented by a square {@linkplain GeneralMatrix matrix}
* of an arbitrary size. Point coordinates must have a dimension equals to
* {@linkplain Matrix#getNumCol}-1
. For example, for square matrix of size 4×4,
* coordinate points are three-dimensional. The transformed points (x',y',z')
are
* computed as below (note that this computation is similar to
* {@link javax.media.jai.PerspectiveTransform} in Java Advanced Imaging):
*
*
* * In the special case of an affine transform, the last row contains only zero * values except in the last column, which contains 1. * * @since 2.0 * * * @source $URL$ * @version $Id$ * @author Martin Desruisseaux (IRD) * * @see javax.media.jai.PerspectiveTransform * @see java.awt.geom.AffineTransform * @see Affine transformation on MathWorld */ public class ProjectiveTransform extends AbstractMathTransform implements LinearTransform, Serializable { /** * Serial number for interoperability with different versions. */ private static final long serialVersionUID = -2104496465933824935L; /** * The number of rows. */ private final int numRow; /** * The number of columns. */ private final int numCol; /** * Elements of the matrix. Column indice vary fastest. */ private final double[] elt; /** * The inverse transform. Will be created only when first needed. */ private transient ProjectiveTransform inverse; /** * Constructs a transform from the specified matrix. * The matrix should be affine, but it will not be verified. * * @param matrix The matrix. */ protected ProjectiveTransform(final Matrix matrix) { numRow = matrix.getNumRow(); numCol = matrix.getNumCol(); elt = new double[numRow*numCol]; int index = 0; for (int j=0; j* [ u ] [ m00 m01 m02 m03 ] [ x ] * [ v ] = [ m10 m11 m12 m13 ] [ y ] * [ w ] [ m20 m21 m22 m23 ] [ z ] * [ t ] [ m30 m31 m32 m33 ] [ 1 ] * * x' = u/t * y' = v/t * y' = w/t *
[x0, y0, z0,
* x1, y1, z1...,
* xn, yn, zn]
.
*
* @param srcPts The array containing the source point coordinates.
* @param srcOff The offset to the first point to be transformed in the source array.
* @param dstPts The array into which the transformed point coordinates are returned.
* @param dstOff The offset to the location of the first transformed point that is stored
* in the destination array. The source and destination array sections can
* be overlaps.
* @param numPts The number of points to be transformed
*/
@Override
public void transform(float[] srcPts, int srcOff,
final float[] dstPts, int dstOff, int numPts)
{
final int inputDimension = numCol-1; // The last ordinate will be assumed equals to 1.
final int outputDimension = numRow-1;
final double[] buffer = new double[numRow];
if (srcPts == dstPts) {
// We are going to write in the source array. Checks if
// source and destination sections are going to clash.
final int upperSrc = srcOff + numPts*inputDimension;
if (upperSrc > dstOff) {
if (inputDimension >= outputDimension ? dstOff > srcOff :
dstOff + numPts*outputDimension > upperSrc) {
// If source overlaps destination, then the easiest workaround is
// to copy source data. This is not the most efficient however...
srcPts = new float[numPts*inputDimension];
System.arraycopy(dstPts, srcOff, srcPts, 0, srcPts.length);
srcOff = 0;
}
}
}
while (--numPts >= 0) {
int mix = 0;
for (int j=0; j[x0, y0, z0,
* x1, y1, z1...,
* xn, yn, zn]
.
*
* @param srcPts The array containing the source point coordinates.
* @param srcOff The offset to the first point to be transformed in the source array.
* @param dstPts The array into which the transformed point coordinates are returned.
* @param dstOff The offset to the location of the first transformed point that is stored
* in the destination array. The source and destination array sections can
* be overlaps.
* @param numPts The number of points to be transformed
*/
public void transform(double[] srcPts, int srcOff,
final double[] dstPts, int dstOff, int numPts)
{
final int inputDimension = numCol-1; // The last ordinate will be assumed equals to 1.
final int outputDimension = numRow-1;
final double[] buffer = new double[numRow];
if (srcPts == dstPts) {
// We are going to write in the source array. Checks if
// source and destination sections are going to clash.
final int upperSrc = srcOff + numPts*inputDimension;
if (upperSrc > dstOff) {
if (inputDimension >= outputDimension ? dstOff > srcOff :
dstOff + numPts*outputDimension > upperSrc) {
// If source overlaps destination, then the easiest workaround is
// to copy source data. This is not the most efficient however...
srcPts = new double[numPts*inputDimension];
System.arraycopy(dstPts, srcOff, srcPts, 0, srcPts.length);
srcOff = 0;
}
}
}
while (--numPts >= 0) {
int mix = 0;
for (int j=0; j
* Note that affine transform is a special case of projective transform.
*
* @version $Id$
* @author Martin Desruisseaux (IRD)
*/
public static final class ProviderAffine extends MathTransformProvider {
/**
* Serial number for interoperability with different versions.
*/
private static final long serialVersionUID = 649555815622129472L;
/**
* The set of predefined providers.
*/
private static final ProviderAffine[] methods = new ProviderAffine[8];
/**
* The parameters group.
*
* @todo We should register EPSG parameter identifiers (A0, A1, A2, B0, B1, B2) as well.
*/
static final ParameterDescriptorGroup PARAMETERS;
static {
final NamedIdentifier name = new NamedIdentifier(Citations.OGC, "Affine");
final Map