/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2004-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.factory; import java.text.ParseException; import java.util.Date; import java.util.Map; import java.util.HashMap; import javax.measure.unit.Unit; import javax.measure.quantity.Angle; import javax.measure.quantity.Length; import org.opengis.referencing.*; import org.opengis.referencing.cs.*; import org.opengis.referencing.crs.*; import org.opengis.referencing.datum.*; import org.opengis.referencing.operation.*; import org.opengis.parameter.ParameterValueGroup; import org.geotools.factory.Hints; import org.geotools.factory.Factory; import org.geotools.factory.BufferedFactory; import org.geotools.referencing.ReferencingFactoryFinder; import org.geotools.referencing.wkt.Parser; import org.geotools.referencing.wkt.Symbols; import org.geotools.referencing.cs.*; import org.geotools.referencing.crs.*; import org.geotools.referencing.datum.*; import org.geotools.referencing.operation.MathTransformProvider; import org.geotools.referencing.operation.DefaultMathTransformFactory; import org.geotools.util.CanonicalSet; /** * Builds Geotools implementations of {@linkplain CoordinateReferenceSystem CRS}, * {@linkplain CoordinateSystem CS} and {@linkplain Datum datum} objects. Most factory methods * expect properties given through a {@link Map} argument. The content of this map is described * in the {@link ObjectFactory} interface. * * @since 2.4 * * @source $URL$ * @version $Id$ * @author Martin Desruisseaux (IRD) */ public class ReferencingObjectFactory extends ReferencingFactory implements CSFactory, DatumFactory, CRSFactory, BufferedFactory { /** * The math transform factory. Will be created only when first needed. */ private MathTransformFactory mtFactory; /** * The object to use for parsing <cite>Well-Known Text</cite> (WKT) strings. * Will be created only when first needed. */ private Parser parser; /** * Set of weak references to existing objects (identifiers, CRS, Datum, whatever). * This set is used in order to return a pre-existing object instead of creating a * new one. */ private final CanonicalSet<IdentifiedObject> pool; /** * Constructs a default factory. This method is public in order to allows instantiations * from a {@linkplain javax.imageio.spi.ServiceRegistry service registry}. Users should * not instantiate this factory directly, but use one of the following lines instead: * * <blockquote><pre> * {@linkplain DatumFactory} factory = FactoryFinder.{@linkplain ReferencingFactoryFinder#getDatumFactory getDatumFactory}null); * {@linkplain CSFactory} factory = FactoryFinder.{@linkplain ReferencingFactoryFinder#getCSFactory getCSFactory}(null); * {@linkplain CRSFactory} factory = FactoryFinder.{@linkplain ReferencingFactoryFinder#getCRSFactory getCRSFactory}(null); * </pre></blockquote> */ public ReferencingObjectFactory() { this(null); } /** * Constructs a factory with the specified hints. Users should not instantiate this * factory directly, but use one of the following lines instead: * * <blockquote><pre> * {@linkplain DatumFactory} factory = FactoryFinder.{@linkplain ReferencingFactoryFinder#getDatumFactory getDatumFactory}(hints); * {@linkplain CSFactory} factory = FactoryFinder.{@linkplain ReferencingFactoryFinder#getCSFactory getCSFactory}(hints); * {@linkplain CRSFactory} factory = FactoryFinder.{@linkplain ReferencingFactoryFinder#getCRSFactory getCRSFactory}(hints); * </pre></blockquote> * * @param hints An optional set of hints, or {@code null} if none. * * @since 2.5 */ public ReferencingObjectFactory(final Hints hints) { pool = CanonicalSet.newInstance(IdentifiedObject.class); if (hints != null && !hints.isEmpty()) { /* * Creates the dependencies (MathTransform factory, WKT parser...) now because * we need to process user's hints. Then, we will keep only the relevant hints. */ mtFactory = ReferencingFactoryFinder.getMathTransformFactory(hints); final DatumFactory datumFactory = ReferencingFactoryFinder.getDatumFactory(hints); createParser(datumFactory, mtFactory); addHints(datumFactory); addHints(mtFactory); } } /** * Copies the hints from the supplied factory. Note that we do not expose the factories * themself (at the contrary of what we usually do) because it is a little bit strange * to declare that this factory depends on an other {@link DatumFactory}. It is only a * trick for getting the WKT paser to work with aliases. * * @todo We should remove this trick if we can. Possible alternatives may be: make * DatumAliases to implements CRSFactory with appropriate createWKT(String) * method; move the createWKT(String) method out of CRSFactory interface. */ private void addHints(final Object factory) { if (factory instanceof Factory) { hints.putAll(((Factory) factory).getImplementationHints()); } } /** * Returns the math transform factory for internal usage only. The hints given to * {@link ReferencingFactoryFinder} must be null, since the non-null case should * have been handled by the constructor. * * @see #createParser */ private synchronized MathTransformFactory getMathTransformFactory() { if (mtFactory == null) { mtFactory = ReferencingFactoryFinder.getMathTransformFactory(null); } return mtFactory; } ///////////////////////////////////////////////////////////////////////////////////////// //////// //////// //////// D A T U M F A C T O R Y //////// //////// //////// ///////////////////////////////////////////////////////////////////////////////////////// /** * Creates an ellipsoid from radius values. * * @param properties Name and other properties to give to the 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. * @throws FactoryException if the object creation failed. */ public Ellipsoid createEllipsoid(Map<String,?> properties, double semiMajorAxis, double semiMinorAxis, Unit<Length> unit) throws FactoryException { Ellipsoid ellipsoid; try { ellipsoid = DefaultEllipsoid.createEllipsoid( properties, semiMajorAxis, semiMinorAxis, unit); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } ellipsoid = pool.unique(ellipsoid); return ellipsoid; } /** * Creates an ellipsoid from an major radius, and inverse flattening. * * @param properties Name and other properties to give to the new object. * @param semiMajorAxis Equatorial radius in supplied linear units. * @param inverseFlattening Eccentricity of ellipsoid. * @param unit Linear units of major axis. * @throws FactoryException if the object creation failed. */ public Ellipsoid createFlattenedSphere(Map<String,?> properties, double semiMajorAxis, double inverseFlattening, Unit<Length> unit) throws FactoryException { Ellipsoid ellipsoid; try { ellipsoid = DefaultEllipsoid.createFlattenedSphere( properties, semiMajorAxis, inverseFlattening, unit); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } ellipsoid = pool.unique(ellipsoid); return ellipsoid; } /** * Creates a prime meridian, relative to Greenwich. * * @param properties Name and other properties to give to the new object. * @param longitude Longitude of prime meridian in supplied angular units East of Greenwich. * @param angularUnit Angular units of longitude. * @throws FactoryException if the object creation failed. */ public PrimeMeridian createPrimeMeridian(Map<String,?> properties, double longitude, Unit<Angle> angularUnit) throws FactoryException { PrimeMeridian meridian; try { meridian = new DefaultPrimeMeridian(properties, longitude, angularUnit); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } meridian = pool.unique(meridian); return meridian; } /** * Creates geodetic datum from ellipsoid and (optionaly) Bursa-Wolf parameters. * * @param properties Name and other properties to give to the new object. * @param ellipsoid Ellipsoid to use in new geodetic datum. * @param primeMeridian Prime meridian to use in new geodetic datum. * @throws FactoryException if the object creation failed. */ public GeodeticDatum createGeodeticDatum(Map<String,?> properties, Ellipsoid ellipsoid, PrimeMeridian primeMeridian) throws FactoryException { GeodeticDatum datum; try { datum = new DefaultGeodeticDatum(properties, ellipsoid, primeMeridian); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } datum = pool.unique(datum); return datum; } /** * Creates a vertical datum from an enumerated type value. * * @param properties Name and other properties to give to the new object. * @param type The type of this vertical datum (often geoidal). * @throws FactoryException if the object creation failed. */ public VerticalDatum createVerticalDatum(Map<String,?> properties, VerticalDatumType type) throws FactoryException { VerticalDatum datum; try { datum = new DefaultVerticalDatum(properties, type); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } datum = pool.unique(datum); return datum; } /** * Creates a temporal datum from an enumerated type value. * * @param properties Name and other properties to give to the new object. * @param origin The date and time origin of this temporal datum. * @throws FactoryException if the object creation failed. */ public TemporalDatum createTemporalDatum(Map<String,?> properties, Date origin) throws FactoryException { TemporalDatum datum; try { datum = new DefaultTemporalDatum(properties, origin); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } datum = pool.unique(datum); return datum; } /** * Creates an engineering datum. * * @param properties Name and other properties to give to the new object. * @throws FactoryException if the object creation failed. */ public EngineeringDatum createEngineeringDatum(Map<String,?> properties) throws FactoryException { EngineeringDatum datum; try { datum = new DefaultEngineeringDatum(properties); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } datum = pool.unique(datum); return datum; } /** * Creates an image datum. * * @param properties Name and other properties to give to the new object. * @param pixelInCell Specification of the way the image grid is associated * with the image data attributes. * @throws FactoryException if the object creation failed. */ public ImageDatum createImageDatum(Map<String,?> properties, PixelInCell pixelInCell) throws FactoryException { ImageDatum datum; try { datum = new DefaultImageDatum(properties, pixelInCell); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } datum = pool.unique(datum); return datum; } ///////////////////////////////////////////////////////////////////////////////////////// //////// //////// //////// C O O R D I N A T E S Y S T E M F A C T O R Y //////// //////// //////// ///////////////////////////////////////////////////////////////////////////////////////// /** * Creates a coordinate system axis from an abbreviation and a unit. * * @param properties Name and other properties to give to the new object. * @param abbreviation The coordinate axis abbreviation. * @param direction The axis direction. * @param unit The coordinate axis unit. * @throws FactoryException if the object creation failed. */ public CoordinateSystemAxis createCoordinateSystemAxis(Map<String,?> properties, String abbreviation, AxisDirection direction, Unit<?> unit) throws FactoryException { CoordinateSystemAxis axis; try { axis = new DefaultCoordinateSystemAxis(properties, abbreviation, direction, unit); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } axis = pool.unique(axis); return axis; } /** * Creates a two dimensional cartesian coordinate system from the given pair of axis. * * @param properties Name and other properties to give to the new object. * @param axis0 The first axis. * @param axis1 The second axis. * @throws FactoryException if the object creation failed. */ public CartesianCS createCartesianCS(Map<String,?> properties, CoordinateSystemAxis axis0, CoordinateSystemAxis axis1) throws FactoryException { CartesianCS cs; try { cs = new DefaultCartesianCS(properties, axis0, axis1); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } cs = pool.unique(cs); return cs; } /** * Creates a three dimensional cartesian coordinate system from the given set of axis. * * @param properties Name and other properties to give to the new object. * @param axis0 The first axis. * @param axis1 The second axis. * @param axis2 The third axis. * @throws FactoryException if the object creation failed. */ public CartesianCS createCartesianCS(Map<String,?> properties, CoordinateSystemAxis axis0, CoordinateSystemAxis axis1, CoordinateSystemAxis axis2) throws FactoryException { CartesianCS cs; try { cs = new DefaultCartesianCS(properties, axis0, axis1, axis2); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } cs = pool.unique(cs); return cs; } /** * Creates a two dimensional coordinate system from the given pair of axis. * * @param properties Name and other properties to give to the new object. * @param axis0 The first axis. * @param axis1 The second axis. * @throws FactoryException if the object creation failed. */ public AffineCS createAffineCS(Map<String,?> properties, CoordinateSystemAxis axis0, CoordinateSystemAxis axis1) throws FactoryException { AffineCS cs; try { cs = new DefaultAffineCS(properties, axis0, axis1); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } cs = pool.unique(cs); return cs; } /** * Creates a three dimensional coordinate system from the given set of axis. * * @param properties Name and other properties to give to the new object. * @param axis0 The first axis. * @param axis1 The second axis. * @param axis2 The third axis. * @throws FactoryException if the object creation failed. */ public AffineCS createAffineCS(Map<String,?> properties, CoordinateSystemAxis axis0, CoordinateSystemAxis axis1, CoordinateSystemAxis axis2) throws FactoryException { AffineCS cs; try { cs = new DefaultAffineCS(properties, axis0, axis1, axis2); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } cs = pool.unique(cs); return cs; } /** * Creates a polar coordinate system from the given pair of axis. * * @param properties Name and other properties to give to the new object. * @param axis0 The first axis. * @param axis1 The second axis. * @throws FactoryException if the object creation failed. */ public PolarCS createPolarCS(Map<String,?> properties, CoordinateSystemAxis axis0, CoordinateSystemAxis axis1) throws FactoryException { PolarCS cs; try { cs = new DefaultPolarCS(properties, axis0, axis1); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } cs = pool.unique(cs); return cs; } /** * Creates a cylindrical coordinate system from the given set of axis. * * @param properties Name and other properties to give to the new object. * @param axis0 The first axis. * @param axis1 The second axis. * @param axis2 The third axis. * @throws FactoryException if the object creation failed. */ public CylindricalCS createCylindricalCS(Map<String,?> properties, CoordinateSystemAxis axis0, CoordinateSystemAxis axis1, CoordinateSystemAxis axis2) throws FactoryException { CylindricalCS cs; try { cs = new DefaultCylindricalCS(properties, axis0, axis1, axis2); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } cs = pool.unique(cs); return cs; } /** * Creates a spherical coordinate system from the given set of axis. * * @param properties Name and other properties to give to the new object. * @param axis0 The first axis. * @param axis1 The second axis. * @param axis2 The third axis. * @throws FactoryException if the object creation failed. */ public SphericalCS createSphericalCS(Map<String,?> properties, CoordinateSystemAxis axis0, CoordinateSystemAxis axis1, CoordinateSystemAxis axis2) throws FactoryException { SphericalCS cs; try { cs = new DefaultSphericalCS(properties, axis0, axis1, axis2); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } cs = pool.unique(cs); return cs; } /** * Creates an ellipsoidal coordinate system without ellipsoidal height. * * @param properties Name and other properties to give to the new object. * @param axis0 The first axis. * @param axis1 The second axis. * @throws FactoryException if the object creation failed. */ public EllipsoidalCS createEllipsoidalCS(Map<String,?> properties, CoordinateSystemAxis axis0, CoordinateSystemAxis axis1) throws FactoryException { EllipsoidalCS cs; try { cs = new DefaultEllipsoidalCS(properties, axis0, axis1); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } cs = pool.unique(cs); return cs; } /** * Creates an ellipsoidal coordinate system with ellipsoidal height. * * @param properties Name and other properties to give to the new object. * @param axis0 The first axis. * @param axis1 The second axis. * @param axis2 The third axis. * @throws FactoryException if the object creation failed. */ public EllipsoidalCS createEllipsoidalCS(Map<String,?> properties, CoordinateSystemAxis axis0, CoordinateSystemAxis axis1, CoordinateSystemAxis axis2) throws FactoryException { EllipsoidalCS cs; try { cs = new DefaultEllipsoidalCS(properties, axis0, axis1, axis2); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } cs = pool.unique(cs); return cs; } /** * Creates a vertical coordinate system. * * @param properties Name and other properties to give to the new object. * @param axis The axis. * @throws FactoryException if the object creation failed. */ public VerticalCS createVerticalCS(Map<String,?> properties, CoordinateSystemAxis axis) throws FactoryException { VerticalCS cs; try { cs = new DefaultVerticalCS(properties, axis); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } cs = pool.unique(cs); return cs; } /** * Creates a temporal coordinate system. * * @param properties Name and other properties to give to the new object. * @param axis The axis. * @throws FactoryException if the object creation failed. */ public TimeCS createTimeCS(Map<String,?> properties, CoordinateSystemAxis axis) throws FactoryException { TimeCS cs; try { cs = new DefaultTimeCS(properties, axis); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } cs = pool.unique(cs); return cs; } /** * Creates a linear coordinate system. * * @param properties Name and other properties to give to the new object. * @param axis The axis. * @throws FactoryException if the object creation failed. */ public LinearCS createLinearCS(Map<String,?> properties, CoordinateSystemAxis axis) throws FactoryException { LinearCS cs; try { cs = new DefaultLinearCS(properties, axis); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } cs = pool.unique(cs); return cs; } /** * Creates a two dimensional user defined coordinate system from the given pair of axis. * * @param properties Name and other properties to give to the new object. * @param axis0 The first axis. * @param axis1 The second axis. * @throws FactoryException if the object creation failed. */ public UserDefinedCS createUserDefinedCS(Map<String,?> properties, CoordinateSystemAxis axis0, CoordinateSystemAxis axis1) throws FactoryException { UserDefinedCS cs; try { cs = new DefaultUserDefinedCS(properties, axis0, axis1); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } cs = pool.unique(cs); return cs; } /** * Creates a three dimensional user defined coordinate system from the given set of axis. * * @param properties Name and other properties to give to the new object. * @param axis0 The first axis. * @param axis1 The second axis. * @param axis2 The third axis. * @throws FactoryException if the object creation failed. */ public UserDefinedCS createUserDefinedCS(Map<String,?> properties, CoordinateSystemAxis axis0, CoordinateSystemAxis axis1, CoordinateSystemAxis axis2) throws FactoryException { UserDefinedCS cs; try { cs = new DefaultUserDefinedCS(properties, axis0, axis1, axis2); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } cs = pool.unique(cs); return cs; } ///////////////////////////////////////////////////////////////////////////////////////// //////// //////// //////// C O O R D I N A T E R E F E R E N C E S Y S T E M F A C T O R Y //////// //////// //////// ///////////////////////////////////////////////////////////////////////////////////////// /** * Creates a compound coordinate reference system from an ordered * list of {@code CoordinateReferenceSystem} objects. * * @param properties Name and other properties to give to the new object. * @param elements ordered array of {@code CoordinateReferenceSystem} objects. * @throws FactoryException if the object creation failed. */ public CompoundCRS createCompoundCRS(Map<String,?> properties, CoordinateReferenceSystem[] elements) throws FactoryException { CompoundCRS crs; try { crs = new DefaultCompoundCRS(properties, elements); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } crs = pool.unique(crs); return crs; } /** * Creates a engineering coordinate reference system. * * @param properties Name and other properties to give to the new object. * @param datum Engineering datum to use in created CRS. * @param cs The coordinate system for the created CRS. * @throws FactoryException if the object creation failed. */ public EngineeringCRS createEngineeringCRS(Map<String,?> properties, EngineeringDatum datum, CoordinateSystem cs) throws FactoryException { EngineeringCRS crs; try { crs = new DefaultEngineeringCRS(properties, datum, cs); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } crs = pool.unique(crs); return crs; } /** * Creates an image coordinate reference system. * * @param properties Name and other properties to give to the new object. * @param datum Image datum to use in created CRS. * @param cs The Cartesian or Oblique Cartesian coordinate system for the created CRS. * @throws FactoryException if the object creation failed. */ public ImageCRS createImageCRS(Map<String,?> properties, ImageDatum datum, AffineCS cs) throws FactoryException { ImageCRS crs; try { crs = new DefaultImageCRS(properties, datum, cs); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } crs = pool.unique(crs); return crs; } /** * Creates a temporal coordinate reference system. * * @param properties Name and other properties to give to the new object. * @param datum Temporal datum to use in created CRS. * @param cs The Temporal coordinate system for the created CRS. * @throws FactoryException if the object creation failed. */ public TemporalCRS createTemporalCRS(Map<String,?> properties, TemporalDatum datum, TimeCS cs) throws FactoryException { TemporalCRS crs; try { crs = new DefaultTemporalCRS(properties, datum, cs); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } crs = pool.unique(crs); return crs; } /** * Creates a vertical coordinate reference system. * * @param properties Name and other properties to give to the new object. * @param datum Vertical datum to use in created CRS. * @param cs The Vertical coordinate system for the created CRS. * @throws FactoryException if the object creation failed. */ public VerticalCRS createVerticalCRS(Map<String,?> properties, VerticalDatum datum, VerticalCS cs) throws FactoryException { VerticalCRS crs; try { crs = new DefaultVerticalCRS(properties, datum, cs); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } crs = pool.unique(crs); return crs; } /** * Creates a geocentric coordinate reference system from a {@linkplain CartesianCS * cartesian coordinate system}. * * @param properties Name and other properties to give to the new object. * @param datum Geodetic datum to use in created CRS. * @param cs The cartesian coordinate system for the created CRS. * @throws FactoryException if the object creation failed. */ public GeocentricCRS createGeocentricCRS(Map<String,?> properties, GeodeticDatum datum, CartesianCS cs) throws FactoryException { GeocentricCRS crs; try { crs = new DefaultGeocentricCRS(properties, datum, cs); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } crs = pool.unique(crs); return crs; } /** * Creates a geocentric coordinate reference system from a {@linkplain SphericalCS * spherical coordinate system}. * * @param properties Name and other properties to give to the new object. * @param datum Geodetic datum to use in created CRS. * @param cs The spherical coordinate system for the created CRS. * @throws FactoryException if the object creation failed. */ public GeocentricCRS createGeocentricCRS(Map<String,?> properties, GeodeticDatum datum, SphericalCS cs) throws FactoryException { GeocentricCRS crs; try { crs = new DefaultGeocentricCRS(properties, datum, cs); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } crs = pool.unique(crs); return crs; } /** * Creates a geographic coordinate reference system. * It could be <var>Latitude</var>/<var>Longitude</var> or * <var>Longitude</var>/<var>Latitude</var>. * * @param properties Name and other properties to give to the new object. * @param datum Geodetic datum to use in created CRS. * @param cs The ellipsoidal coordinate system for the created CRS. * @throws FactoryException if the object creation failed. */ public GeographicCRS createGeographicCRS(Map<String,?> properties, GeodeticDatum datum, EllipsoidalCS cs) throws FactoryException { GeographicCRS crs; try { crs = new DefaultGeographicCRS(properties, datum, cs); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } crs = pool.unique(crs); return crs; } /** * Creates a derived coordinate reference system. If the transformation is an affine * map performing a rotation, then any mixed axes must have identical units. * For example, a (<var>lat_deg</var>, <var>lon_deg</var>, <var>height_feet</var>) * system can be rotated in the (<var>lat</var>, <var>lon</var>) plane, since both * affected axes are in decimal degrees. But you should not rotate this coordinate * system in any other plane. * <p> * <b>NOTE:</b> * It is the user's responsability to ensure that the {@code baseToDerived} transform performs * all required steps, including {@linkplain AbstractCS#swapAndScaleAxis unit conversions and * change of axis order}, if needed. The {@link ReferencingFactoryContainer} class provides * conveniences methods for this task. * * @param properties Name and other properties to give to the new object. * @param method A description of the {@linkplain Conversion#getMethod method for the * conversion}. * @param base Coordinate reference system to base the derived CRS on. * @param baseToDerived The transform from the base CRS to returned CRS. * @param derivedCS The coordinate system for the derived CRS. * @throws FactoryException if the object creation failed. * * @deprecated Use {@link CoordinateOperationFactory#createDefiningConversion} followed by * {@link #createDerivedCRS} instead. */ public DerivedCRS createDerivedCRS(Map<String,?> properties, OperationMethod method, CoordinateReferenceSystem base, MathTransform baseToDerived, CoordinateSystem derivedCS) throws FactoryException { DerivedCRS crs; try { crs = new DefaultDerivedCRS(properties, method, base, baseToDerived, derivedCS); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } crs = pool.unique(crs); return crs; } /** * Creates a derived coordinate reference system from a conversion. * It is the user's responsability to ensure that the conversion performs all required steps, * including {@linkplain AbstractCS#swapAndScaleAxis unit conversions and change of axis order}, * if needed. * * @param properties Name and other properties to give to the new object. * @param baseCRS Coordinate reference system to base projection on. * @param conversionFromBase The {@linkplain DefiningConversion defining conversion}. * @param derivedCS The coordinate system for the derived CRS. * @throws FactoryException if the object creation failed. * * @since 2.5 */ public DerivedCRS createDerivedCRS(Map<String,?> properties, CoordinateReferenceSystem baseCRS, Conversion conversionFromBase, CoordinateSystem derivedCS) throws FactoryException { MathTransform mt = conversionFromBase.getMathTransform(); if (mt == null) { final ParameterValueGroup parameters = conversionFromBase.getParameterValues(); final MathTransformFactory mtFactory = getMathTransformFactory(); mt = mtFactory.createParameterizedTransform(parameters); } DerivedCRS crs; try { crs = new DefaultDerivedCRS(properties, conversionFromBase, baseCRS, mt, derivedCS); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } crs = pool.unique(crs); return crs; } /** * Creates a projected coordinate reference system from a transform. * <p> * <b>NOTE:</b> * It is the user's responsability to ensure that the {@code baseToDerived} transform performs * all required steps, including {@linkplain AbstractCS#swapAndScaleAxis unit conversions and * change of axis order}, if needed. The {@link ReferencingFactoryContainer} class provides * conveniences methods for this task. * * @param properties Name and other properties to give to the new object. * @param method A description of the {@linkplain Conversion#getMethod method for the * projection}. * @param base Geographic coordinate reference system to base projection on. * @param baseToDerived The transform from the geographic to the projected CRS. * @param derivedCS The coordinate system for the projected CRS. * @throws FactoryException if the object creation failed. * * @deprecated Use {@link CoordinateOperationFactory#createDefiningConversion} followed by * {@link #createProjectedCRS} instead. */ public ProjectedCRS createProjectedCRS(Map<String,?> properties, OperationMethod method, GeographicCRS base, MathTransform baseToDerived, CartesianCS derivedCS) throws FactoryException { ProjectedCRS crs; try { crs = new DefaultProjectedCRS(properties, method, base, baseToDerived, derivedCS); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } crs = pool.unique(crs); return crs; } /** * Creates a projected coordinate reference system from a conversion. The supplied * conversion should <strong>not</strong> includes the operation steps for performing * {@linkplain AbstractCS#swapAndScaleAxis unit conversions and change of axis order} * since those operations will be inferred by this constructor * * @param properties Name and other properties to give to the new object. * @param baseCRS Geographic coordinate reference system to base projection on. * @param conversionFromBase The {@linkplain DefiningConversion defining conversion}. * @param derivedCS The coordinate system for the projected CRS. * @throws FactoryException if the object creation failed. * * @since 2.5 */ public ProjectedCRS createProjectedCRS(Map<String,?> properties, GeographicCRS baseCRS, Conversion conversionFromBase, CartesianCS derivedCS) throws FactoryException { MathTransform mt; final MathTransform existing = conversionFromBase.getMathTransform(); final MathTransformFactory mtFactory = getMathTransformFactory(); if (existing != null && mtFactory instanceof DefaultMathTransformFactory) { /* * In the particular case of GeoTools implementation, we use a shortcut which avoid * the cost of creating a new parameterized transform; we use directly the existing * transform instance instead. It also avoid slight rounding errors as a side-effect. * This is because when a MapProjection is created, the angular parameters given to * the construtor are converted from degrees to radians. When the parameters are asked * back with 'conversionFromBase.getParameterValues()', they are converted back from * radians to degrees resulting in values slightly different than the original ones. * Those slight differences are enough for getting a math transform which is different * in the sense of MapProjection.equals(Object), with the usual consequences on cached * instances. */ mt = ((DefaultMathTransformFactory) mtFactory).createBaseToDerived(baseCRS, existing, derivedCS); } else { /* * Non-GeoTools implementation, or no existing MathTransform instance. * Creates the transform from the parameters. */ final ParameterValueGroup parameters = conversionFromBase.getParameterValues(); mt = mtFactory.createBaseToDerived(baseCRS, parameters, derivedCS); OperationMethod method = conversionFromBase.getMethod(); if (!(method instanceof MathTransformProvider)) { /* * Our Geotools implementation of DefaultProjectedCRS may not be able to detect * the conversion type (PlanarProjection, CylindricalProjection, etc.) because * we rely on the Geotools-specific MathTransformProvider for that. We will try * to help it with the optional "conversionType" hint, providing that the user * do not already provides this hint. */ if (!properties.containsKey(DefaultProjectedCRS.CONVERSION_TYPE_KEY)) { method = mtFactory.getLastMethodUsed(); if (method instanceof MathTransformProvider) { final Map<String,Object> copy = new HashMap<String,Object>(properties); copy.put(DefaultProjectedCRS.CONVERSION_TYPE_KEY, ((MathTransformProvider) method).getOperationType()); properties = copy; } } } /* * If the user gave an explicit conversion, checks if it is suitable. * It may not be suitable is unit conversion, axis switch, etc. have * been inserted in the operation chain by 'createBaseToDerived'. */ if (existing != null && existing.equals(mt)) { mt = existing; } } ProjectedCRS crs; try { crs = new DefaultProjectedCRS(properties, conversionFromBase, baseCRS, mt, derivedCS); } catch (IllegalArgumentException exception) { throw new FactoryException(exception); } crs = pool.unique(crs); return crs; } /** * Creates a coordinate reference system object from a XML string. * * @param xml Coordinate reference system encoded in XML format. * @throws FactoryException if the object creation failed. * * @todo Not yet implemented. */ public CoordinateReferenceSystem createFromXML(String xml) throws FactoryException { throw new FactoryException("Not yet implemented"); } /** * Creates a coordinate reference system object from a string. * * @param wkt Coordinate system encoded in Well-Known Text format. * @throws FactoryException if the object creation failed. */ public synchronized CoordinateReferenceSystem createFromWKT(final String wkt) throws FactoryException { /* * Note: while this factory is thread safe, the WKT parser is not. * Since we share a single instance of this parser, we must synchronize. */ if (parser == null) { createParser(ReferencingFactoryFinder.getDatumFactory(null), getMathTransformFactory()); } try { return parser.parseCoordinateReferenceSystem(wkt); } catch (ParseException exception) { final Throwable cause = exception.getCause(); if (cause instanceof FactoryException) { throw (FactoryException) cause; } throw new FactoryException(exception); } } /** * Creates inconditionnaly the WKT parser. This is factored out as a single private method * for making easier to spot the places in this code that need to create the parser and the * datum-alias patch. */ private void createParser(final DatumFactory datumFactory, final MathTransformFactory mtFactory) { parser = new Parser(Symbols.DEFAULT, datumFactory, this, this, mtFactory); } }