001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/model/csct/cs/CoordinateSystemFactory.java $
002    /*
003     * SEAGIS - An OpenSource implementation of OpenGIS specification
004     *          (C) 2001, Institut de Recherche pour le D�veloppement
005     *
006     *    This library is free software; you can redistribute it and/or
007     *    modify it under the terms of the GNU Lesser General Public
008     *    License as published by the Free Software Foundation; either
009     *    version 2.1 of the License, or (at your option) any later version.
010     *
011     *    This library is distributed in the hope that it will be useful,
012     *    but WITHOUT ANY WARRANTY; without even the implied warranty of
013     *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     *    Lesser General Public License for more details.
015     *
016     *    You should have received a copy of the GNU Lesser General Public
017     *    License along with this library; if not, write to the Free Software
018     *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
019     *
020     *
021     * Contacts:
022     *     FRANCE: Surveillance de l'Environnement Assist�e par Satellite
023     *             Institut de Recherche pour le D�veloppement / US-Espace
024     *             mailto:seasnet@teledetection.fr
025     *
026     *     CANADA: Observatoire du Saint-Laurent
027     *             Institut Maurice-Lamontagne
028     *             mailto:osl@osl.gc.ca
029     *
030     *    This package contains documentation from OpenGIS specifications.
031     *    OpenGIS consortium's work is fully acknowledged here.
032     */
033    package org.deegree.model.csct.cs;
034    
035    // OpenGIS dependencies
036    import java.awt.geom.Point2D;
037    
038    import javax.media.jai.ParameterList;
039    
040    import org.deegree.model.csct.resources.WeakHashSet;
041    import org.deegree.model.csct.units.Unit;
042    
043    /**
044     * Builds up complex objects from simpler objects or values. <code>CoordinateSystemFactory</code>
045     * allows applications to make coordinate systems that cannot be created by a
046     * {@link CoordinateSystemAuthorityFactory}. This factory is very flexible, whereas the authority
047     * factory is easier to use.
048     * 
049     * So {@link CoordinateSystemAuthorityFactory} can be used to make 'standard' coordinate systems,
050     * and <code>CoordinateSystemFactory</code> can be used to make "special" coordinate systems.
051     * 
052     * For example, the EPSG authority has codes for USA state plane coordinate systems using the NAD83
053     * datum, but these coordinate systems always use meters. EPSG does not have codes for NAD83 state
054     * plane coordinate systems that use feet units. This factory lets an application create such a
055     * hybrid coordinate system.
056     * 
057     * @version 1.00
058     * @author OpenGIS (www.opengis.org)
059     * @author Martin Desruisseaux
060     * 
061     * @author last edited by: $Author: bezema $
062     * 
063     * @version $Revision: 6259 $, $Date: 2007-03-20 10:15:15 +0100 (Di, 20 Mär 2007) $
064     * 
065     * @see "org.opengis.cs.CS_CoordinateSystemFactory"
066     */
067    public class CoordinateSystemFactory {
068        /**
069         * Default coordinate system factory. Will be constructed only when first needed.
070         */
071        private static CoordinateSystemFactory DEFAULT;
072    
073        /**
074         * Set of weak references to existing coordinate systems. This set is used in order to return
075         * pre-existing object instead of creating new one.
076         */
077        private final WeakHashSet pool;
078    
079        /**
080         * Construct a new factory with the specified pool.
081         */
082        private CoordinateSystemFactory( final WeakHashSet pool ) {
083            this.pool = pool;
084        }
085    
086        /**
087         * Default constructor.
088         */
089        protected CoordinateSystemFactory() {
090            this( new WeakHashSet() );
091        }
092    
093        /**
094         * Returns the default coordinate system factory.
095         * 
096         * @return the default coordinate system factory.
097         */
098        public static synchronized CoordinateSystemFactory getDefault() {
099            if ( DEFAULT == null ) {
100                DEFAULT = new CoordinateSystemFactory( Info.pool );
101            }
102            return DEFAULT;
103        }
104    
105        /**
106         * Creates a geographic coordinate system. This coordinate system will use <var>longitude</var>/<var>latitude</var>
107         * ordinates with longitude values increasing east and latitude values increasing north. Angular
108         * units are degrees and prime meridian is Greenwich.
109         * 
110         * @param name
111         *            Name to give new object.
112         * @param datum
113         *            Horizontal datum for created coordinate system.
114         */
115        public GeographicCoordinateSystem createGeographicCoordinateSystem( final String name,
116                                                                            final HorizontalDatum datum ) {
117            return createGeographicCoordinateSystem( name, Unit.DEGREE, datum, PrimeMeridian.GREENWICH,
118                                                     AxisInfo.LONGITUDE, AxisInfo.LATITUDE );
119        }
120    
121        /**
122         * Creates a geographic coordinate system, which could be <var>latitude</var>/<var>longiude</var>
123         * or <var>longitude</var>/<var>latitude</var>.
124         * 
125         * @param name
126         *            Name to give new object.
127         * @param unit
128         *            Angular units for created coordinate system.
129         * @param datum
130         *            Horizontal datum for created coordinate system.
131         * @param meridian
132         *            Prime Meridian for created coordinate system.
133         * @param axis0
134         *            Details of 0th ordinates.
135         * @param axis1
136         *            Details of 1st ordinates.
137         * 
138         */
139        public GeographicCoordinateSystem createGeographicCoordinateSystem(
140                                                                            final String name,
141                                                                            final Unit unit,
142                                                                            final HorizontalDatum datum,
143                                                                            final PrimeMeridian meridian,
144                                                                            final AxisInfo axis0,
145                                                                            final AxisInfo axis1 ) {
146            return (GeographicCoordinateSystem) pool.intern( new GeographicCoordinateSystem( name,
147                                                                                             unit,
148                                                                                             datum,
149                                                                                             meridian,
150                                                                                             axis0,
151                                                                                             axis1 ) );
152        }
153    
154        /**
155         * Creates a projected coordinate system using the specified geographic system. Projected
156         * coordinates will be in meters, <var>x</var> values increasing east and <var>y</var> values
157         * increasing north.
158         * 
159         * @param name
160         *            Name to give new object.
161         * @param gcs
162         *            Geographic coordinate system to base projection on.
163         * @param projection
164         *            Projection from geographic to projected coordinate system.
165         */
166        public ProjectedCoordinateSystem createProjectedCoordinateSystem(
167                                                                          final String name,
168                                                                          final GeographicCoordinateSystem gcs,
169                                                                          final Projection projection ) {
170            return createProjectedCoordinateSystem( name, gcs, projection, Unit.METRE, AxisInfo.X,
171                                                    AxisInfo.Y );
172        }
173    
174        /**
175         * Creates a projected coordinate system using a projection object.
176         * 
177         * @param name
178         *            Name to give new object.
179         * @param gcs
180         *            Geographic coordinate system to base projection on.
181         * @param projection
182         *            Projection from geographic to projected coordinate system.
183         * @param unit
184         *            Linear units of returned PCS.
185         * @param axis0
186         *            Details of 0th ordinates in returned PCS coordinates.
187         * @param axis1
188         *            Details of 1st ordinates in returned PCS coordinates.
189         * 
190         */
191        public ProjectedCoordinateSystem createProjectedCoordinateSystem(
192                                                                          final String name,
193                                                                          final GeographicCoordinateSystem gcs,
194                                                                          final Projection projection,
195                                                                          final Unit unit,
196                                                                          final AxisInfo axis0,
197                                                                          final AxisInfo axis1 ) {
198            return (ProjectedCoordinateSystem) pool.intern( new ProjectedCoordinateSystem( name, gcs,
199                                                                                           projection,
200                                                                                           unit, axis0,
201                                                                                           axis1 ) );
202        }
203    
204        /**
205         * Creates a vertical coordinate system from a datum. Units will be metres and values will be
206         * increasing upward.
207         * 
208         * @param name
209         *            Name to give new object.
210         * @param datum
211         *            Datum to use for new coordinate system.
212         */
213        public VerticalCoordinateSystem createVerticalCoordinateSystem( final String name,
214                                                                        final VerticalDatum datum ) {
215            return createVerticalCoordinateSystem( name, datum, Unit.METRE, AxisInfo.ALTITUDE );
216        }
217    
218        /**
219         * Creates a vertical coordinate system from a datum and linear units.
220         * 
221         * @param name
222         *            Name to give new object.
223         * @param datum
224         *            Datum to use for new coordinate system.
225         * @param unit
226         *            Units to use for new coordinate system.
227         * @param axis
228         *            Axis to use for new coordinate system.
229         * 
230         */
231        public VerticalCoordinateSystem createVerticalCoordinateSystem( final String name,
232                                                                        final VerticalDatum datum,
233                                                                        final Unit unit,
234                                                                        final AxisInfo axis ) {
235            return (VerticalCoordinateSystem) pool.intern( new VerticalCoordinateSystem( name, datum,
236                                                                                         unit, axis ) );
237        }
238    
239        /**
240         * Creates a compound coordinate system.
241         * 
242         * @param name
243         *            Name to give new object.
244         * @param head
245         *            Coordinate system to use for earlier ordinates.
246         * @param tail
247         *            Coordinate system to use for later ordinates.
248         * 
249         */
250        public CompoundCoordinateSystem createCompoundCoordinateSystem( final String name,
251                                                                        final CoordinateSystem head,
252                                                                        final CoordinateSystem tail ) {
253            return (CompoundCoordinateSystem) pool.intern( new CompoundCoordinateSystem( name, head,
254                                                                                         tail ) );
255        }
256    
257        /**
258         * Creates a local coordinate system. The dimension of the local coordinate system is determined
259         * by the size of the axis array. All the axes will have the same units. If you want to make a
260         * coordinate system with mixed units, then you can make a compound coordinate system from
261         * different local coordinate systems.
262         * 
263         * @param name
264         *            Name to give new object.
265         * @param datum
266         *            Local datum to use in created CS.
267         * @param unit
268         *            Units to use for all axes in created CS.
269         * @param axes
270         *            Axes to use in created CS.
271         * 
272         */
273        public LocalCoordinateSystem createLocalCoordinateSystem( final String name,
274                                                                  final LocalDatum datum,
275                                                                  final Unit unit, final AxisInfo[] axes ) {
276            return (LocalCoordinateSystem) pool.intern( new LocalCoordinateSystem( name, datum, unit,
277                                                                                   axes ) );
278        }
279    
280        /**
281         * Creates an ellipsoid from radius values.
282         * 
283         * @param name
284         *            Name to give new object.
285         * @param semiMajorAxis
286         *            Equatorial radius in supplied linear units.
287         * @param semiMinorAxis
288         *            Polar radius in supplied linear units.
289         * @param unit
290         *            Linear units of ellipsoid axes.
291         * 
292         */
293        public Ellipsoid createEllipsoid( final String name, final double semiMajorAxis,
294                                          final double semiMinorAxis, final Unit unit ) {
295            return (Ellipsoid) pool.intern( new Ellipsoid( name, semiMajorAxis, semiMinorAxis, unit ) );
296        }
297    
298        /**
299         * Creates an ellipsoid from an major radius, and inverse flattening.
300         * 
301         * @param name
302         *            Name to give new object.
303         * @param semiMajorAxis
304         *            Equatorial radius in supplied linear units.
305         * @param inverseFlattening
306         *            Eccentricity of ellipsoid.
307         * @param unit
308         *            Linear units of major axis.
309         * 
310         */
311        public Ellipsoid createFlattenedSphere( final String name, final double semiMajorAxis,
312                                                final double inverseFlattening, final Unit unit ) {
313            return (Ellipsoid) pool.intern( Ellipsoid.createFlattenedSphere( name, semiMajorAxis,
314                                                                             inverseFlattening, unit ) );
315        }
316    
317        /**
318         * Creates a prime meridian, relative to Greenwich.
319         * 
320         * @param name
321         *            Name to give new object.
322         * @param unit
323         *            Angular units of longitude.
324         * @param longitude
325         *            Longitude of prime meridian in supplied angular units East of Greenwich.
326         * 
327         */
328        public PrimeMeridian createPrimeMeridian( final String name, final Unit unit,
329                                                  final double longitude ) {
330            return (PrimeMeridian) pool.intern( new PrimeMeridian( name, unit, longitude ) );
331        }
332    
333        /**
334         * Creates a projection. The client must ensure that all the linear parameters are expressed in
335         * meters, and all the angular parameters are expressed in degrees. Also, they must supply
336         * <code>"semi_major"</code> and <code>"semi_minor"</code> parameters. The set of legal
337         * parameters and their default values can be queried using
338         * {@link #createProjectionParameterList}. Example:
339         * 
340         * <blockquote>
341         * 
342         * <pre>
343         *   {link ParameterList} param = {@link #createProjectionParameterList createProjectionParameterList}(&quot;Transverse_Mercator&quot;)
344         *                                       .setParameter(&quot;semi_major&quot;, 6378206.4)
345         *                                       .setParameter(&quot;semi_minor&quot;, 6356583.8);
346         *   {@link Projection} proj = createProjection(&quot;My projection&quot;, &quot;Transverse_Mercator&quot;, param);
347         * </pre>
348         * 
349         * </blockquote>
350         * 
351         * @param name
352         *            Name to give new object.
353         * @param classification
354         *            Classification string for projection (e.g. "Transverse_Mercator").
355         * @param parameters
356         *            Parameters to use for projection. A default set of parameters can be constructed
357         *            using <code>{@link #createProjectionParameterList
358         *                       createProjectionParameterList}(classification)</code>
359         *            and initialized using a chain of <code>setParameter(...)</code> calls.
360         * 
361         */
362        public Projection createProjection( final String name, final String classification,
363                                            final ParameterList parameters ) {
364            return (Projection) pool.intern( new Projection( name, classification, parameters ) );
365        }
366    
367        /**
368         * Convenience method for constructing a projection using the specified ellipsoid.
369         * 
370         * @param name
371         *            Name to give new object.
372         * @param classification
373         *            Classification string for projection (e.g. "Transverse_Mercator").
374         * @param ellipsoid
375         *            Ellipsoid parameter. If non-null, then <code>"semi_major"</code> and
376         *            <code>"semi_minor"</code> parameters will be set according.
377         * @param centre
378         *            Central meridian and latitude of origin, in degrees. If non-null, then
379         *            <code>"central_meridian"</code> and <code>"latitude_of_origin"</code> will be
380         *            set according.
381         * @param translation
382         *            False easting and northing, in metres. If non-null, then
383         *            <code>"false_easting"</code> and <code>"false_northing"</code> will be set
384         *            according.
385         */
386        public Projection createProjection( final String name, final String classification,
387                                            final Ellipsoid ellipsoid, final Point2D centre,
388                                            final Point2D translation, final double scaleFactor ) {
389            ParameterList param = createProjectionParameterList( classification );
390            param = Projection.init( param, ellipsoid, centre, translation, scaleFactor );
391            return createProjection( name, classification, param );
392        }
393    
394        /**
395         * Returns a default parameter list for the specified projection.
396         * 
397         * @param classification
398         *            Classification string for projection (e.g. "Transverse_Mercator").
399         * @return A default parameter list for the supplied projection class.
400         * 
401         * @see #createProjection(String, String, ParameterList)
402         */
403        public ParameterList createProjectionParameterList( final String classification ) {
404            return Projection.getParameterList( classification );
405        }
406    
407        /**
408         * Creates horizontal datum from ellipsoid and Bursa-Wolf parameters. Since this method contains
409         * a set of Bursa-Wolf parameters, the created datum will always have a relationship to WGS84.
410         * If you wish to create a horizontal datum that has no relationship with WGS84, then you can
411         * either specify {@link DatumType.Horizontal#OTHER} as the horizontalDatumType, or create it
412         * via WKT.
413         * 
414         * @param name
415         *            Name to give new object.
416         * @param type
417         *            Type of horizontal datum to create.
418         * @param ellipsoid
419         *            Ellipsoid to use in new horizontal datum.
420         * @param toWGS84
421         *            Suggested approximate conversion from new datum to WGS84.
422         * 
423         */
424        public HorizontalDatum createHorizontalDatum( final String name,
425                                                      final DatumType.Horizontal type,
426                                                      final Ellipsoid ellipsoid,
427                                                      final WGS84ConversionInfo toWGS84 ) {
428            return (HorizontalDatum) pool.intern( new HorizontalDatum( name, type, ellipsoid, toWGS84 ) );
429        }
430    
431        /**
432         * Creates horizontal datum from an ellipsoid. The datum type will be
433         * {@link DatumType.Horizontal#OTHER}.
434         * 
435         * @param name
436         *            Name to give new object.
437         * @param ellipsoid
438         *            Ellipsoid to use in new horizontal datum.
439         */
440        public HorizontalDatum createHorizontalDatum( final String name, final Ellipsoid ellipsoid ) {
441            return createHorizontalDatum( name, DatumType.Horizontal.OTHER, ellipsoid, null );
442        }
443    
444        /**
445         * Creates a vertical datum from an enumerated type value.
446         * 
447         * @param name
448         *            Name to give new object.
449         * @param type
450         *            Type of vertical datum to create.
451         * 
452         */
453        public VerticalDatum createVerticalDatum( final String name, final DatumType.Vertical type ) {
454            return (VerticalDatum) pool.intern( new VerticalDatum( name, type ) );
455        }
456    
457        /**
458         * Creates a local datum.
459         * 
460         * @param name
461         *            Name to give new object.
462         * @param type
463         *            Type of local datum to create.
464         * 
465         */
466        public LocalDatum createLocalDatum( final String name, final DatumType.Local type ) {
467            return (LocalDatum) pool.intern( new LocalDatum( name, type ) );
468        }
469    
470    }