/*---------------- FILE HEADER ------------------------------------------
This file is part of deegree.
Copyright (C) 2001 by:
EXSE, Department of Geography, University of Bonn
http://www.giub.uni-bonn.de/exse/
lat/lon GmbH
http://www.lat-lon.de
It has been implemented within SEAGIS - An OpenSource implementation of OpenGIS specification
(C) 2001, Institut de Recherche pour le D�veloppement (http://sourceforge.net/projects/seagis/)
SEAGIS Contacts: Surveillance de l'Environnement Assist�e par Satellite
Institut de Recherche pour le D�veloppement / US-Espace
mailto:seasnet@teledetection.fr
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
Contact:
Andreas Poth
lat/lon GmbH
Aennchenstr. 19
53115 Bonn
Germany
E-Mail: poth@lat-lon.de
Klaus Greve
Department of Geography
University of Bonn
Meckenheimer Allee 166
53115 Bonn
Germany
E-Mail: klaus.greve@uni-bonn.de
---------------------------------------------------------------------------*/
package org.deegree.model.csct.cs;
// OpenGIS dependencies
import java.awt.geom.Point2D;
import java.util.Map;
import javax.media.jai.ParameterList;
import javax.media.jai.ParameterListDescriptor;
import javax.media.jai.ParameterListImpl;
import org.deegree.model.csct.ct.MathTransformProvider;
import org.deegree.model.csct.ct.MissingParameterException;
import org.deegree.model.csct.resources.Naming;
import org.deegree.model.csct.resources.Utilities;
import org.deegree.model.csct.units.Unit;
/**
* A projection from geographic coordinates to projected coordinates.
*
* @version 1.00
* @author OpenGIS (www.opengis.org)
* @author Martin Desruisseaux
*
* @see org.opengis.cs.CS_Projection
*/
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 <code>"semi_major"</code>
* and <code>"semi_minor"</code> parameters will be set according.
* @param centre Central meridian and latitude of origin, in degrees. If non-null, then
* <code>"central_meridian"</code> and <code>"latitude_of_origin"</code>
* will be set according.
* @param translation False easting and northing, in metres. If non-null, then
* <code>"false_easting"</code> and <code>"false_northing"</code>
* will be set according.
*/
public Projection( final String name, final String classification, final Ellipsoid ellipsoid,
final Point2D centre, final Point2D translation, final double scaleFactor ) {
super( name );
ensureNonNull( "classification", classification );
this.classification = classification;
this.parameters = init( getParameterList( classification ), ellipsoid, centre, translation,
scaleFactor );
}
/**
* Creates a projection. The set of parameters (<code>parameters</code>) may be queried with
* <code>{@link org.deegree.model.csct.ct.MathTransformFactory#getMathTransformProvider
* MathTransformFactory.getMathTransformProvider}(classification).{@link
* MathTransformProvider#getParameterList getParameterList()}</code>.
*
* @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.
*
*/
public Projection( final String name, final String classification,
final ParameterList parameters ) {
super( name );
ensureNonNull( "classification", classification );
ensureNonNull( "parameters", parameters );
this.classification = classification;
this.parameters = clone( parameters );
}
/**
* Creates a projection.
*
* @param properties The set of properties (see {@link Info}).
* @param classification Classification string for projection (e.g. "Transverse_Mercator").
* @param parameters Parameters to use for projection, in metres or degrees.
*/
Projection( final Map properties, final String classification, final ParameterList parameters ) {
super( properties );
this.classification = classification;
this.parameters = parameters;
// Accept null values.
}
/**
* 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 ) {
return Naming.PROJECTIONS.getParameterList(
classification,
MathTransformProvider.DEFAULT_PROJECTION_DESCRIPTOR );
}
/**
* Initialize a list of parameter from the specified ellipsoid and points.
*
* @param parameters The parameters to initialize.
* @param ellipsoid Ellipsoid parameter. If non-null, then <code>"semi_major"</code>
* and <code>"semi_minor"</code> parameters will be set according.
* @param centre Central meridian and latitude of origin, in degrees. If non-null, then
* <code>"central_meridian"</code> and <code>"latitude_of_origin"</code>
* will be set according.
* @param translation False easting and northing, in metres. If non-null, then
* <code>"false_easting"</code> and <code>"false_northing"</code>
* will be set according.
* @return <code>parameters</code> for convenience.
*/
static ParameterList init( final ParameterList parameters, final Ellipsoid ellipsoid,
final Point2D centre, final Point2D translation,
final double scaleFactor ) {
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() );
}
if ( scaleFactor < 0 || scaleFactor > 3.5 ) {
parameters.setParameter( "scale_factor", 1.0 );
} else {
parameters.setParameter( "scale_factor", scaleFactor );
}
return parameters;
}
/**
* Returns a clone of a parameter list.
*/
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; i < names.length; i++ ) {
final String name = names[i];
copy.setParameter( name, list.getObjectParameter( name ) );
}
return copy;
}
/**
* Gets the projection classification name (e.g. "Transverse_Mercator").
*
* @see org.opengis.cs.CS_Projection#getClassName()
*/
public String getClassName() {
return classification;
}
/**
* Returns all parameters.
*
* @see org.opengis.cs.CS_Projection#getNumParameters()
* @see org.opengis.cs.CS_Projection#getParameter(int)
*/
public ParameterList getParameters() {
return clone( parameters );
}
/**
* Convenience method for fetching a parameter value.
* Search is case-insensitive and ignore leading and trailing blanks.
*
* @param name Parameter to look for.
* @return The parameter value.
* @throws MissingParameterException if parameter <code>name</code> 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 ignore leading and trailing blanks.
*
* @param name Parameter to look for.
* @param defaultValue Default value to return if
* parameter <code>name</code> is not found.
* @return The parameter value, or <code>defaultValue</code>
* if the parameter <code>name</code> is not found.
*/
public double getValue( final String name, final double defaultValue ) {
return getValue( parameters, name, defaultValue, false );
}
/**
* Convenience method for fetching a parameter value.
* Search is case-insensitive and ignore leading and
* trailing blanks.
*
* @param parameters User-suplied parameters.
* @param name Parameter to look for.
* @param defaultValue Default value to return if
* parameter <code>name</code> is not found.
* @param required <code>true</code> if the parameter is required (in which case
* <code>defaultValue</code> is ignored), or <code>false</code> otherwise.
* @return The parameter value, or <code>defaultValue</code> if the parameter is
* not found and <code>required</code> is <code>false</code>.
* @throws MissingParameterException if <code>required</code> is <code>true</code>
* and parameter <code>name</code> 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();
}
// May require an instance of Double. Will
// probably throw ClassCastException since
// the last try didn't worked.
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;
}
if ( cause != null ) {
throw cause;
}
final MissingParameterException exception = new MissingParameterException( null, name );
throw exception;
}
/**
* Returns a hash value for this projection.
*/
public int hashCode() {
int code = 45896321;
if ( classification != null )
code = code * 37 + classification.hashCode();
if ( parameters != null )
code = code * 37 + parameters.hashCode();
return code;
}
/**
* Compares the specified object with
* this projection for equality.
*/
public boolean equals( final Object object ) {
if ( super.equals( object ) ) {
final Projection that = (Projection) object;
return Utilities.equals( this.classification, that.classification )
&& Utilities.equals( this.parameters, that.parameters );
}
return false;
}
/**
* Fill the part inside "[...]".
* Used for formatting Well Know Text (WKT).
*/
String addString( final StringBuffer buffer ) {
return "PROJECTION";
}
}