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 }