/* * Geotools 2 - OpenSource mapping toolkit * (C) 2003, Geotools Project Managment Committee (PMC) * (C) 2001, Institut de Recherche pour le Développement * * 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; either * version 2.1 of the License, or (at your option) any later version. * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * * This package contains documentation from OpenGIS specifications. * OpenGIS consortium's work is fully acknowledged here. */ package org.geotools.cs; // OpenGIS dependencies import java.awt.geom.Point2D; import java.rmi.RemoteException; import java.util.Locale; import javax.media.jai.ParameterList; import javax.media.jai.ParameterListDescriptor; import javax.media.jai.ParameterListImpl; import org.geotools.ct.MathTransformProvider; import org.geotools.ct.MissingParameterException; import org.geotools.resources.DescriptorNaming; import org.geotools.resources.Utilities; import org.geotools.units.Unit; import org.opengis.cs.CS_Projection; import org.opengis.cs.CS_ProjectionParameter; /** * A projection from geographic coordinates to projected coordinates. * * @source $URL$ * @version $Id$ * @author OpenGIS (www.opengis.org) * @author Martin Desruisseaux * * @see org.opengis.cs.CS_Projection * * @deprecated Replaced by {@link org.geotools.referencing.operation.DefaultOperationMethod}. */ public class Projection extends Info { /** * Serial number for interoperability with different versions. */ private static final long serialVersionUID = 2153398430020498215L; /** * Classification string for projection (e.g. "Transverse_Mercator"). */ private final String classification; /** * Parameters to use for projection, in metres or degrees. */ private final ParameterList parameters; /** * Convenience constructor for a projection using the specified ellipsoid. * * @param name Name to give new object. * @param classification Classification string for projection (e.g. "Transverse_Mercator"). * @param ellipsoid Ellipsoid parameter. If non-null, then "semi_major" * and "semi_minor" parameters will be set accordingly. * @param centre Central meridian and latitude of origin, in degrees. If non-null, then * "central_meridian" and "latitude_of_origin" * will be set accordingly. * @param translation False easting and northing, in metres. If non-null, then * "false_easting" and "false_northing" * will be set accordingly. */ public Projection(final CharSequence name, final String classification, final Ellipsoid ellipsoid, final Point2D centre, final Point2D translation) { super(name); ensureNonNull("classification", classification); this.classification = classification; this.parameters = init(getParameterList(classification), ellipsoid, centre, translation); } /** * Creates a projection. The set of parameters (parameters) may be queried * with the {@link CoordinateSystemFactory#createProjectionParameterList} * method. * * @param name Name to give new object. * @param classification Classification string for projection (e.g. "Transverse_Mercator"). * @param parameters Parameters to use for projection, in metres or degrees. * * @see org.opengis.cs.CS_CoordinateSystemFactory#createProjection */ public Projection(final CharSequence name, final String classification, final ParameterList parameters) { super(name); ensureNonNull("classification", classification); ensureNonNull("parameters", parameters); this.classification = classification; this.parameters = clone(parameters); } /** * Returns a parameter list for the specified classification. * If there is no special parameter descriptor for the specified * classification, then a default descriptor is used. */ static ParameterList getParameterList(final String classification) { // The binding of a default set of projections is done by DescriptorNaming. return DescriptorNaming.PROJECTIONS.getParameterList(classification, MathTransformProvider.DEFAULT_PROJECTION_DESCRIPTOR); } /** * Initializes a list of parameter from the specified ellipsoid and points. * * @param parameters The parameters to initialize. * @param ellipsoid Ellipsoid parameter. If non-null, then "semi_major" * and "semi_minor" parameters will be set accordingly. * @param centre Central meridian and latitude of origin, in degrees. * If non-null, then "central_meridian" and * "latitude_of_origin" will be set accordingly. * @param translation False easting and northing, in metres. If non-null, then * "false_easting" and "false_northing" * will be set accordingly. * @return parameters for convenience. */ static ParameterList init(final ParameterList parameters, final Ellipsoid ellipsoid, final Point2D centre, final Point2D translation) { if (ellipsoid!=null) { final Unit axisUnit = ellipsoid.getAxisUnit(); parameters.setParameter("semi_major", Unit.METRE.convert(ellipsoid.getSemiMajorAxis(), axisUnit)); parameters.setParameter("semi_minor", Unit.METRE.convert(ellipsoid.getSemiMinorAxis(), axisUnit)); } if (centre!=null) { parameters.setParameter("central_meridian", centre.getX()); parameters.setParameter("latitude_of_origin", centre.getY()); } if (translation!=null) { parameters.setParameter("false_easting", translation.getX()); parameters.setParameter("false_northing", translation.getY()); } return parameters; } /** * Returns a clone of a parameter list. * * @task HACK: The 'catch' clause make it possible to clone parameter list with undefined * parameter. However, it can't differenciate the case where the user didn't * provided a value but a default value was found. */ private static ParameterList clone(final ParameterList list) { if (list == null) { return null; } final ParameterListDescriptor descriptor = list.getParameterListDescriptor(); final ParameterList copy = new ParameterListImpl(descriptor); final String[] names = descriptor.getParamNames(); if (names!=null) for (int i=0; iname is not found. */ public double getValue(final String name) throws MissingParameterException { return getValue(parameters, name, Double.NaN, true); } /** * Convenience method for fetching a parameter value. * Search is case-insensitive and ignores leading and trailing blanks. * * @param name Parameter to look for. * @param defaultValue Default value to return if * parameter name is not found. * @return The parameter value, or defaultValue * if the parameter name is not found. */ public double getValue(final String name, final double defaultValue) { try { return getValue(parameters, name, defaultValue, false); } catch (MissingParameterException exception) { // Should not happen throw new AssertionError(exception); } } /** * Convenience method for fetching a parameter value. * Search is case-insensitive and ignores leading and * trailing blanks. * * @param parameters User-supplied parameters. * @param name Parameter to look for. * @param defaultValue Default value to return if * parameter name is not found. * @param required true if the parameter is required (in which case * defaultValue is ignored), or false otherwise. * @return The parameter value, or defaultValue if the parameter is * not found and required is false. * @throws MissingParameterException if required is true * and parameter name is not found. */ private static double getValue(final ParameterList parameters, String name, final double defaultValue, final boolean required) throws MissingParameterException { name = name.trim(); RuntimeException cause=null; if (parameters!=null) { try { final Object value = parameters.getObjectParameter(name); if (value instanceof Number) { // Do not require an instance of Double. return ((Number) value).doubleValue(); } else { // May require an instance of Double. Will // probably throw ClassCastException since // the last try didn't work. return parameters.getDoubleParameter(name); } } catch (IllegalArgumentException exception) { // There is no parameter with the specified name. cause = exception; } catch (IllegalStateException exception) { // the parameter value is still NO_PARAMETER_DEFAULT cause = exception; } } if (!required) { return defaultValue; } final MissingParameterException exception = new MissingParameterException(null, name); if (cause != null) { exception.initCause(cause); } throw exception; } /** * Compare this projection with the specified object for equality. * * @param object The object to compare to this. * @param compareNames true to comparare the {@linkplain #getName name}, * {@linkplain #getAlias alias}, {@linkplain #getAuthorityCode authority * code}, etc. as well, or false to compare only properties * relevant to transformations. * @return true if both objects are equal. */ public boolean equals(final Info object, final boolean compareNames) { if (object == this) { return true; } if (super.equals(object, compareNames)) { final Projection that = (Projection) object; return Utilities.equals(this.classification, that.classification) && DescriptorNaming.equals(this.parameters, that.parameters); } return false; } /** * Returns a hash value for this projection. {@linkplain #getName Name}, * {@linkplain #getAlias alias}, {@linkplain #getAuthorityCode authority code} * and the like are not taken in account. In other words, two projections * will return the same hash value if they are equal in the sense of * {@link #equals equals}(Info, false). * * @return The hash code value. This value doesn't need to be the same * in past or future versions of this class. */ public int hashCode() { int code = (int)serialVersionUID; if (classification!=null) code = code*37 + classification.hashCode(); // if (parameters !=null) code = code*37 + parameters.hashCode(); // ---- We can't take 'parameters' in account since ParameterList do not override hashCode() ---- return code; } /** * Fills the part inside "[...]". * Used for formatting Well Known Text (WKT). */ String addString(final StringBuffer buffer, final Unit context) { return "PROJECTION"; } /** * Add the parameters for this projection. This is used * for WKT formatting of {@link ProjectedCoordinateSystem}. */ final void addParameters(final StringBuffer buffer, final Unit context) { final String[] names = parameters.getParameterListDescriptor().getParamNames(); for (int i=0; i