/*
* SEAGIS - An OpenSource implementation of OpenGIS specification
* (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
*
*
* Contacts:
* FRANCE: Surveillance de l'Environnement Assist�e par Satellite
* Institut de Recherche pour le D�veloppement / US-Espace
* mailto:seasnet@teledetection.fr
*
* CANADA: Observatoire du Saint-Laurent
* Institut Maurice-Lamontagne
* mailto:osl@osl.gc.ca
*
* This package contains documentation from OpenGIS specifications.
* OpenGIS consortium's work is fully acknowledged here.
*/
package org.deegree.model.csct.cs;
// OpenGIS dependencies
import java.awt.geom.Point2D;
import javax.media.jai.ParameterList;
import org.deegree.model.csct.resources.WeakHashSet;
import org.deegree.model.csct.units.Unit;
/**
* Builds up complex objects from simpler objects or values.
* <code>CoordinateSystemFactory</code> allows applications to make coordinate
* systems that cannot be created by a {@link CoordinateSystemAuthorityFactory}.
* This factory is very flexible, whereas the authority factory is easier to use.
*
* So {@link CoordinateSystemAuthorityFactory} can be used to make 'standard'
* coordinate systems, and <code>CoordinateSystemFactory</code> can be used to
* make "special" coordinate systems.
*
* For example, the EPSG authority has codes for USA state plane coordinate systems
* using the NAD83 datum, but these coordinate systems always use meters. EPSG does
* not have codes for NAD83 state plane coordinate systems that use feet units. This
* factory lets an application create such a hybrid coordinate system.
*
* @version 1.00
* @author OpenGIS (www.opengis.org)
* @author Martin Desruisseaux
*
* @see org.opengis.cs.CS_CoordinateSystemFactory
*/
public class CoordinateSystemFactory {
/**
* Default coordinate system factory.
* Will be constructed only when first needed.
*/
private static CoordinateSystemFactory DEFAULT;
/**
* Set of weak references to existing coordinate systems.
* This set is used in order to return pre-existing object
* instead of creating new one.
*/
private final WeakHashSet pool;
/**
* Construct a new factory with the specified pool.
*/
private CoordinateSystemFactory( final WeakHashSet pool ) {
this.pool = pool;
}
/**
* Default constructor.
*/
protected CoordinateSystemFactory() {
this( new WeakHashSet() );
}
/**
* Returns the default coordinate system factory.
*/
public static synchronized CoordinateSystemFactory getDefault() {
if ( DEFAULT == null ) {
DEFAULT = new CoordinateSystemFactory( Info.pool );
}
return DEFAULT;
}
/**
* Creates a geographic coordinate system. This coordinate system will use
* <var>longitude</var>/<var>latitude</var> ordinates with longitude values
* increasing east and latitude values increasing north. Angular units are
* degrees and prime meridian is Greenwich.
*
* @param name Name to give new object.
* @param datum Horizontal datum for created coordinate system.
*/
public GeographicCoordinateSystem createGeographicCoordinateSystem( final String name,
final HorizontalDatum datum ) {
return createGeographicCoordinateSystem( name, Unit.DEGREE, datum, PrimeMeridian.GREENWICH,
AxisInfo.LONGITUDE, AxisInfo.LATITUDE );
}
/**
* Creates a geographic coordinate system, which could be
* <var>latitude</var>/<var>longiude</var> or
* <var>longitude</var>/<var>latitude</var>.
*
* @param name Name to give new object.
* @param unit Angular units for created coordinate system.
* @param datum Horizontal datum for created coordinate system.
* @param meridian Prime Meridian for created coordinate system.
* @param axis0 Details of 0th ordinates.
* @param axis1 Details of 1st ordinates.
*
*/
public GeographicCoordinateSystem createGeographicCoordinateSystem(
final String name,
final Unit unit,
final HorizontalDatum datum,
final PrimeMeridian meridian,
final AxisInfo axis0,
final AxisInfo axis1 ) {
return (GeographicCoordinateSystem) pool.intern( new GeographicCoordinateSystem( name,
unit,
datum,
meridian,
axis0,
axis1 ) );
}
/**
* Creates a projected coordinate system using the specified geographic
* system. Projected coordinates will be in meters, <var>x</var> values
* increasing east and <var>y</var> values increasing north.
*
* @param name Name to give new object.
* @param gcs Geographic coordinate system to base projection on.
* @param projection Projection from geographic to projected coordinate system.
*/
public ProjectedCoordinateSystem createProjectedCoordinateSystem(
final String name,
final GeographicCoordinateSystem gcs,
final Projection projection ) {
return createProjectedCoordinateSystem( name, gcs, projection, Unit.METRE, AxisInfo.X,
AxisInfo.Y );
}
/**
* Creates a projected coordinate system using a projection object.
*
* @param name Name to give new object.
* @param gcs Geographic coordinate system to base projection on.
* @param projection Projection from geographic to projected coordinate system.
* @param unit Linear units of returned PCS.
* @param axis0 Details of 0th ordinates in returned PCS coordinates.
* @param axis1 Details of 1st ordinates in returned PCS coordinates.
*
*/
public ProjectedCoordinateSystem createProjectedCoordinateSystem(
final String name,
final GeographicCoordinateSystem gcs,
final Projection projection,
final Unit unit,
final AxisInfo axis0,
final AxisInfo axis1 ) {
return (ProjectedCoordinateSystem) pool.intern( new ProjectedCoordinateSystem( name, gcs,
projection,
unit, axis0,
axis1 ) );
}
/**
* Creates a vertical coordinate system from a datum. Units
* will be metres and values will be increasing upward.
*
* @param name Name to give new object.
* @param datum Datum to use for new coordinate system.
*/
public VerticalCoordinateSystem createVerticalCoordinateSystem( final String name,
final VerticalDatum datum ) {
return createVerticalCoordinateSystem( name, datum, Unit.METRE, AxisInfo.ALTITUDE );
}
/**
* Creates a vertical coordinate system from a datum and linear units.
*
* @param name Name to give new object.
* @param datum Datum to use for new coordinate system.
* @param unit Units to use for new coordinate system.
* @param axis Axis to use for new coordinate system.
*
*/
public VerticalCoordinateSystem createVerticalCoordinateSystem( final String name,
final VerticalDatum datum,
final Unit unit,
final AxisInfo axis ) {
return (VerticalCoordinateSystem) pool.intern( new VerticalCoordinateSystem( name, datum,
unit, axis ) );
}
/**
* Creates a compound coordinate system.
*
* @param name Name to give new object.
* @param head Coordinate system to use for earlier ordinates.
* @param tail Coordinate system to use for later ordinates.
*
*/
public CompoundCoordinateSystem createCompoundCoordinateSystem( final String name,
final CoordinateSystem head,
final CoordinateSystem tail ) {
return (CompoundCoordinateSystem) pool.intern( new CompoundCoordinateSystem( name, head,
tail ) );
}
/**
* Creates a local coordinate system.
* The dimension of the local coordinate system is determined by the size
* of the axis array. All the axes will have the same units. If you want
* to make a coordinate system with mixed units, then you can make a
* compound coordinate system from different local coordinate systems.
*
* @param name Name to give new object.
* @param datum Local datum to use in created CS.
* @param unit Units to use for all axes in created CS.
* @param axes Axes to use in created CS.
*
*/
public LocalCoordinateSystem createLocalCoordinateSystem( final String name,
final LocalDatum datum,
final Unit unit, final AxisInfo[] axes ) {
return (LocalCoordinateSystem) pool.intern( new LocalCoordinateSystem( name, datum, unit,
axes ) );
}
/**
* Creates an ellipsoid from radius values.
*
* @param name Name to give new object.
* @param semiMajorAxis Equatorial radius in supplied linear units.
* @param semiMinorAxis Polar radius in supplied linear units.
* @param unit Linear units of ellipsoid axes.
*
*/
public Ellipsoid createEllipsoid( final String name, final double semiMajorAxis,
final double semiMinorAxis, final Unit unit ) {
return (Ellipsoid) pool.intern( new Ellipsoid( name, semiMajorAxis, semiMinorAxis, unit ) );
}
/**
* Creates an ellipsoid from an major radius, and inverse flattening.
*
* @param name Name to give new object.
* @param semiMajorAxis Equatorial radius in supplied linear units.
* @param inverseFlattening Eccentricity of ellipsoid.
* @param unit Linear units of major axis.
*
*/
public Ellipsoid createFlattenedSphere( final String name, final double semiMajorAxis,
final double inverseFlattening, final Unit unit ) {
return (Ellipsoid) pool.intern( Ellipsoid.createFlattenedSphere( name, semiMajorAxis,
inverseFlattening, unit ) );
}
/**
* Creates a prime meridian, relative to Greenwich.
*
* @param name Name to give new object.
* @param unit Angular units of longitude.
* @param longitude Longitude of prime meridian in supplied angular units East of Greenwich.
*
*/
public PrimeMeridian createPrimeMeridian( final String name, final Unit unit,
final double longitude ) {
return (PrimeMeridian) pool.intern( new PrimeMeridian( name, unit, longitude ) );
}
/**
* Creates a projection. The client must ensure that all the linear parameters are
* expressed in meters, and all the angular parameters are expressed in degrees.
* Also, they must supply <code>"semi_major"</code> and <code>"semi_minor"</code>
* parameters. The set of legal parameters and their default values can be queried
* using {@link #createProjectionParameterList}. Example:
*
* <blockquote><pre>
* {link ParameterList} param = {@link #createProjectionParameterList createProjectionParameterList}("Transverse_Mercator")
* .setParameter("semi_major", 6378206.4)
* .setParameter("semi_minor", 6356583.8);
* {@link Projection} proj = createProjection("My projection", "Transverse_Mercator", param);
* </pre></blockquote>
*
* @param name Name to give new object.
* @param classification Classification string for projection (e.g. "Transverse_Mercator").
* @param parameters Parameters to use for projection. A default set of parameters can
* be constructed using <code>{@link #createProjectionParameterList
* createProjectionParameterList}(classification)</code> and initialized
* using a chain of <code>setParameter(...)</code> calls.
*
*/
public Projection createProjection( final String name, final String classification,
final ParameterList parameters ) {
return (Projection) pool.intern( new Projection( name, classification, parameters ) );
}
/**
* Convenience method for constructing 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 createProjection( final String name, final String classification,
final Ellipsoid ellipsoid, final Point2D centre,
final Point2D translation, final double scaleFactor ) {
ParameterList param = createProjectionParameterList( classification );
param = Projection.init( param, ellipsoid, centre, translation, scaleFactor );
return createProjection( name, classification, param );
}
/**
* Returns a default parameter list for the specified projection.
*
* @param classification Classification string for projection (e.g. "Transverse_Mercator").
* @return A default parameter list for the supplied projection class.
*
* @see #createProjection(String, String, ParameterList)
*/
public ParameterList createProjectionParameterList( final String classification ) {
return Projection.getParameterList( classification );
}
/**
* Creates horizontal datum from ellipsoid and Bursa-Wolf parameters.
* Since this method contains a set of Bursa-Wolf parameters, the created datum will always
* have a relationship to WGS84. If you wish to create a horizontal datum that
* has no relationship with WGS84, then you can either specify
* {@link DatumType.Horizontal#OTHER} as the horizontalDatumType,
* or create it via WKT.
*
* @param name Name to give new object.
* @param type Type of horizontal datum to create.
* @param ellipsoid Ellipsoid to use in new horizontal datum.
* @param toWGS84 Suggested approximate conversion from new datum to WGS84.
*
*/
public HorizontalDatum createHorizontalDatum( final String name,
final DatumType.Horizontal type,
final Ellipsoid ellipsoid,
final WGS84ConversionInfo toWGS84 ) {
return (HorizontalDatum) pool.intern( new HorizontalDatum( name, type, ellipsoid, toWGS84 ) );
}
/**
* Creates horizontal datum from an ellipsoid.
* The datum type will be {@link DatumType.Horizontal#OTHER}.
*
* @param name Name to give new object.
* @param ellipsoid Ellipsoid to use in new horizontal datum.
*/
public HorizontalDatum createHorizontalDatum( final String name, final Ellipsoid ellipsoid ) {
return createHorizontalDatum( name, DatumType.Horizontal.OTHER, ellipsoid, null );
}
/**
* Creates a vertical datum from an enumerated type value.
*
* @param name Name to give new object.
* @param type Type of vertical datum to create.
*
*/
public VerticalDatum createVerticalDatum( final String name, final DatumType.Vertical type ) {
return (VerticalDatum) pool.intern( new VerticalDatum( name, type ) );
}
/**
* Creates a local datum.
*
* @param name Name to give new object.
* @param type Type of local datum to create.
*
*/
public LocalDatum createLocalDatum( final String name, final DatumType.Local type ) {
return (LocalDatum) pool.intern( new LocalDatum( name, type ) );
}
}