001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/model/csct/ct/CoordinateTransformation.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001 by:
006     EXSE, Department of Geography, University of Bonn
007     http://www.giub.uni-bonn.de/exse/
008     lat/lon GmbH
009     http://www.lat-lon.de
010    
011     It has been implemented within SEAGIS - An OpenSource implementation of OpenGIS specification
012     (C) 2001, Institut de Recherche pour le D�veloppement (http://sourceforge.net/projects/seagis/)
013     SEAGIS Contacts:  Surveillance de l'Environnement Assist�e par Satellite
014     Institut de Recherche pour le D�veloppement / US-Espace
015     mailto:seasnet@teledetection.fr
016    
017    
018     This library is free software; you can redistribute it and/or
019     modify it under the terms of the GNU Lesser General Public
020     License as published by the Free Software Foundation; either
021     version 2.1 of the License, or (at your option) any later version.
022    
023     This library is distributed in the hope that it will be useful,
024     but WITHOUT ANY WARRANTY; without even the implied warranty of
025     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
026     Lesser General Public License for more details.
027    
028     You should have received a copy of the GNU Lesser General Public
029     License along with this library; if not, write to the Free Software
030     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
031    
032     Contact:
033    
034     Andreas Poth
035     lat/lon GmbH
036     Aennchenstr. 19
037     53115 Bonn
038     Germany
039     E-Mail: poth@lat-lon.de
040    
041     Klaus Greve
042     Department of Geography
043     University of Bonn
044     Meckenheimer Allee 166
045     53115 Bonn
046     Germany
047     E-Mail: klaus.greve@uni-bonn.de
048    
049     
050     ---------------------------------------------------------------------------*/
051    package org.deegree.model.csct.ct;
052    
053    // OpenGIS dependencies
054    import org.deegree.model.csct.cs.CoordinateSystem;
055    import org.deegree.model.csct.cs.Info;
056    import org.deegree.model.csct.resources.Utilities;
057    import org.deegree.model.csct.resources.css.ResourceKeys;
058    import org.deegree.model.csct.resources.css.Resources;
059    
060    /**
061     * Describes a coordinate transformation. A coordinate transformation class establishes an
062     * association between a source and a target coordinate reference system, and provides a
063     * {@link MathTransform} for transforming coordinates in the source coordinate reference system to
064     * coordinates in the target coordinate reference system. These coordinate systems can be ground or
065     * image coordinates. In general mathematics, "transformation" is the general term for mappings
066     * between coordinate systems (see tensor analysis). <br>
067     * <br>
068     * For a ground coordinate point, if the transformation depends only on mathematically derived
069     * parameters (as in a cartographic projection), then this is an ISO conversion. If the
070     * transformation depends on empirically derived parameters (as in datum transformations), then this
071     * is an ISO transformation.
072     * 
073     * @version 1.00
074     * @author OpenGIS (www.opengis.org)
075     * @author Martin Desruisseaux
076     * 
077     * @author last edited by: $Author: bezema $
078     * 
079     * @version $Revision: 6259 $, $Date: 2007-03-20 10:15:15 +0100 (Di, 20 Mär 2007) $
080     * 
081     * @see "org.opengis.ct.CT_CoordinateTransformation"
082     */
083    public class CoordinateTransformation extends Info {
084        /**
085         * Serial number for interoperability with different versions.
086         */
087        private static final long serialVersionUID = -1850470924499685544L;
088    
089        /**
090         * The source coordinate system.
091         */
092        private final CoordinateSystem sourceCS;
093    
094        /**
095         * The destination coordinate system.
096         */
097        private final CoordinateSystem targetCS;
098    
099        /**
100         * The transform type.
101         */
102        private final TransformType type;
103    
104        /**
105         * The underlying math transform, or <code>null</code> if it doesn't has been constructed yet.
106         * If <code>null</code>, then subclass <strong>must</strong> initialize this field the first
107         * time {@link #getMathTransform} is invoked.
108         */
109        protected MathTransform transform;
110    
111        /**
112         * The inverse transform. This field will be computed only when needed.
113         */
114        transient CoordinateTransformation inverse;
115    
116        /**
117         * Construct a coordinate transformation.
118         * 
119         * @param name
120         *            The coordinate transformation name, or <code>null</code> for an automatically
121         *            generated name.
122         * @param sourceCS
123         *            The source coordinate system.
124         * @param targetCS
125         *            The destination coordinate system.
126         * @param type
127         *            The transform type.
128         * @param transform
129         *            The math transform. This argument is allowed to be <code>null</code> only if
130         *            this constructor is invoked from within a subclass constructor. In this case, the
131         *            subclass <strong>must</strong> construct a math transform no later than the first
132         *            time {@link #getMathTransform} is invoked.
133         */
134        public CoordinateTransformation( final String name, final CoordinateSystem sourceCS,
135                                         final CoordinateSystem targetCS, final TransformType type,
136                                         final MathTransform transform ) {
137            super( ( name != null ) ? name : "" );
138            this.sourceCS = sourceCS;
139            this.targetCS = targetCS;
140            this.type = type;
141            this.transform = transform;
142            ensureNonNull( "sourceCS", sourceCS );
143            ensureNonNull( "targetCS", targetCS );
144            ensureNonNull( "type", type );
145            if ( getClass().equals( CoordinateTransformation.class ) ) {
146                ensureNonNull( "transform", transform );
147            }
148            if ( transform.getDimSource() != sourceCS.getDimension() ) {
149                throw new IllegalArgumentException( "sourceCS" );
150            }
151            if ( transform.getDimTarget() != targetCS.getDimension() ) {
152                throw new IllegalArgumentException( "targetCS" );
153            }
154        }
155    
156        /**
157         * Gets the name of this coordinate transformation.
158         * 
159         * @param locale
160         *            The desired locale, or <code>null</code> for the default locale.
161         * @return the name of this coordinate transformation.
162         */
163        public String getName() {
164            final String name = super.getName();
165            if ( name.length() != 0 )
166                return name;
167            else if ( transform instanceof AbstractMathTransform )
168                return ( (AbstractMathTransform) transform ).getName();
169            else
170                return sourceCS.getName() + "\u00A0\u21E8\u00A0" + targetCS.getName();
171        }
172    
173        /**
174         * Gets the source coordinate system.
175         * 
176         * @return the source coordinate system.
177         * 
178         * @see "org.opengis.ct.CT_CoordinateTransformation#getSourceCS()"
179         */
180        public CoordinateSystem getSourceCS() {
181            return sourceCS;
182        }
183    
184        /**
185         * Gets the target coordinate system.
186         * 
187         * @return the target coordinate system.
188         * 
189         * @see "org.opengis.ct.CT_CoordinateTransformation#getTargetCS()"
190         */
191        public CoordinateSystem getTargetCS() {
192            return targetCS;
193        }
194    
195        /**
196         * Gets the semantic type of transform. For example, a datum transformation or a coordinate
197         * conversion.
198         * 
199         * @return the semantic type of transform.
200         * 
201         * @see "org.opengis.ct.CT_CoordinateTransformation#getTransformType()"
202         */
203        public TransformType getTransformType() {
204            return type;
205        }
206    
207        /**
208         * Gets the math transform. The math transform will transform positions in the source coordinate
209         * system into positions in the target coordinate system.
210         * 
211         * @return the math transform. The math transform will transform positions in the source
212         *         coordinate system into positions in the target coordinate system.
213         * 
214         * @see "org.opengis.ct.CT_CoordinateTransformation#getMathTransform()"
215         */
216        public MathTransform getMathTransform() {
217            if ( transform != null ) {
218                return transform;
219            }
220            throw new IllegalStateException();
221        }
222    
223        /**
224         * Returns the inverse transform of this object.
225         * 
226         * @return the inverse transform of this object.
227         * @throws NoninvertibleTransformException
228         */
229        public synchronized CoordinateTransformation inverse()
230                                throws NoninvertibleTransformException {
231            if ( inverse == null ) {
232                inverse = new Inverse( this );
233            }
234            return inverse;
235        }
236    
237        /**
238         * The inverse coordinate transformation. This class override {@link #getName} in order to
239         * delegate part of the call to the underlying direct transformation.
240         * 
241         * @version 1.0
242         * @author Martin Desruisseaux
243         */
244        private static final class Inverse extends CoordinateTransformation {
245            /**
246             * Construct a coordinate transformation.
247             * 
248             * @param transform
249             * @throws NoninvertibleTransformException
250             */
251            public Inverse( final CoordinateTransformation transform )
252                                    throws NoninvertibleTransformException {
253                super( null, transform.getTargetCS(), transform.getSourceCS(),
254                       transform.getTransformType(), transform.getMathTransform().inverse() );
255                this.inverse = transform;
256            }
257    
258            /**
259             * Gets the name of this coordinate transformation.
260             * 
261             * @return the name of this coordinate transformation.
262             */
263            public String getName() {
264                return Resources.getResources( null ).getString( ResourceKeys.INVERSE_$1,
265                                                                 this.inverse.getName() );
266            }
267        }
268    
269        /**
270         * Returns a hash value for this coordinate transformation.
271         * 
272         * @return a hash value for this coordinate transformation.
273         */
274        public int hashCode() {
275            int code = 7851236;
276            CoordinateSystem cs;
277            if ( ( cs = getSourceCS() ) != null )
278                code = code * 37 + cs.hashCode();
279            if ( ( cs = getTargetCS() ) != null )
280                code = code * 37 + cs.hashCode();
281            return code;
282        }
283    
284        /**
285         * Compares the specified object with this coordinate transformation for equality. The default
286         * implementation compare name, transform type, source and target coordinate systems. It doesn't
287         * compare the math transform, since it should be equivalents if the above mentionned parameters
288         * are equal.
289         * 
290         * @param object
291         * @return
292         */
293        public boolean equals( final Object object ) {
294            if ( object == this )
295                return true;
296            if ( super.equals( object ) ) {
297                final CoordinateTransformation that = (CoordinateTransformation) object;
298                return Utilities.equals( this.getTransformType(), that.getTransformType() )
299                       && Utilities.equals( this.getSourceCS(), that.getSourceCS() )
300                       && Utilities.equals( this.getTargetCS(), that.getTargetCS() );
301            }
302            return false;
303        }
304    
305    }