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 }