/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2002-2012, 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.
*/
package org.geotools.referencing.operation.transform;
import javax.measure.quantity.Dimensionless;
import javax.measure.unit.NonSI;
import javax.measure.unit.SI;
import org.geotools.metadata.iso.citation.Citations;
import org.geotools.referencing.NamedIdentifier;
import org.geotools.referencing.operation.MathTransformProvider;
import org.geotools.referencing.operation.transform.AffineTransform2D;
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.MathTransform;
/**
* The provider for the "<cite>Similarity transformation</cite>" (EPSG 9621).
* <p>
* Note that similarity transform is a special case of an Affine transform 2D.
*
* @source $URL$
* @version $Id$
* @author Oscar Fonts
*/
public class SimilarityTransformProvider extends MathTransformProvider {
private static final long serialVersionUID = -7413519919588731455L;
// TODO: TRANSLATION_1 and TRANSLATION_2 should be expressed in "target CRS units", not necessarily SI.METER.
/**
* "Ordinate 1 of evaluation point in target CRS" EPSG::8621
*/
public static final ParameterDescriptor<Double> TRANSLATION_1 = createDescriptor(
new NamedIdentifier[] {
new NamedIdentifier(Citations.EPSG, "Ordinate 1 of evaluation point in target CRS"),
new NamedIdentifier(Citations.EPSG, "8621")
},
0, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, SI.METER);
/**
* "Ordinate 2 of evaluation point in target CRS" EPSG::8622
*/
public static final ParameterDescriptor<Double> TRANSLATION_2 = createDescriptor(
new NamedIdentifier[] {
new NamedIdentifier(Citations.EPSG, "Ordinate 2 of evaluation point in target CRS"),
new NamedIdentifier(Citations.EPSG, "8622")
},
0, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, SI.METER);
/**
* "Scale difference" EPSG::8611
*/
public static final ParameterDescriptor<Double> SCALE = createDescriptor(
new NamedIdentifier[] {
new NamedIdentifier(Citations.EPSG, "Scale difference"),
new NamedIdentifier(Citations.EPSG, "8611")
},
1, Double.MIN_NORMAL, Double.POSITIVE_INFINITY, Dimensionless.UNIT);
/**
* "Rotation angle of source coordinate reference system axes" EPSG::8614
*/
public static final ParameterDescriptor<Double> ROTATION = createDescriptor(
new NamedIdentifier[] {
new NamedIdentifier(Citations.EPSG, "Rotation angle of source coordinate reference system axes"),
new NamedIdentifier(Citations.EPSG, "8614")
},
0, 0, 360 * 60 * 60, NonSI.SECOND_ANGLE);
/**
* The parameter group for "Similarity transformation" EPSG::9621.
*
* Includes {@link #TRANSLATION_1}, {@link #TRANSLATION_2}, {@link #SCALE}, {@link #ROTATION}.
*/
static final ParameterDescriptorGroup PARAMETERS = createDescriptorGroup(
new NamedIdentifier[] {
new NamedIdentifier(Citations.EPSG, "Similarity transformation"),
new NamedIdentifier(Citations.EPSG, "9621")
},
new ParameterDescriptor[] {
TRANSLATION_1,
TRANSLATION_2,
SCALE,
ROTATION
}
);
/**
* Creates a two-dimensional similarity transform.
*
* EPSG defines explicitly this transform as 2D.
*/
public SimilarityTransformProvider() {
super(2, 2, PARAMETERS);
}
/**
* Constructs an {@link AffineTransform2D} math transform from the specified group of parameter values.
*
* The similarity transform is a particular case of Affine Transform 2D where:
*
* <blockquote><pre>
* m00 = SCALE * cos(ROTATION)
* m01 = SCALE * sin(ROTATION)
* m02 = TRANSLATION_1
* m10 = -m01
* m11 = m00
* m12 = TRANSLATION_2
* </pre></blockquote>
*
* @param values The group of parameter values {@link #PARAMETERS}.
* @return an {@link AffineTransform2D}.
* @throws ParameterNotFoundException if a required parameter was not found.
*/
protected MathTransform createMathTransform(ParameterValueGroup values)
throws ParameterNotFoundException {
// The four parameters
double t1 = doubleValue(TRANSLATION_1, values);
double t2 = doubleValue(TRANSLATION_2, values);
double scale = doubleValue(SCALE, values);
double rotation = doubleValue(ROTATION, values);
// Calculate affine transform coefficients
double theta = Math.PI * rotation / 648000; // arcsec to rad
double p1 = scale * Math.cos(theta);
double p2 = scale * Math.sin(theta);
return new AffineTransform2D(p1, -p2, p2, p1, t1, t2);
}
}