001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/crs/src/org/deegree/model/csct/cs/WGS84ConversionInfo.java $ 002 /*---------------- FILE HEADER ------------------------------------------ 003 This file is part of deegree. 004 Copyright (C) 2001-2008 by: 005 Department of Geography, University of Bonn 006 http://www.giub.uni-bonn.de/deegree/ 007 lat/lon GmbH 008 http://www.lat-lon.de 009 010 This library is free software; you can redistribute it and/or 011 modify it under the terms of the GNU Lesser General Public 012 License as published by the Free Software Foundation; either 013 version 2.1 of the License, or (at your option) any later version. 014 This library is distributed in the hope that it will be useful, 015 but WITHOUT ANY WARRANTY; without even the implied warranty of 016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 017 Lesser General Public License for more details. 018 You should have received a copy of the GNU Lesser General Public 019 License along with this library; if not, write to the Free Software 020 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 021 Contact: 022 023 Andreas Poth 024 lat/lon GmbH 025 Aennchenstr. 19 026 53177 Bonn 027 Germany 028 E-Mail: poth@lat-lon.de 029 030 Prof. Dr. Klaus Greve 031 Department of Geography 032 University of Bonn 033 Meckenheimer Allee 166 034 53115 Bonn 035 Germany 036 E-Mail: greve@giub.uni-bonn.de 037 ---------------------------------------------------------------------------*/ 038 package org.deegree.crs.transformations; 039 040 import javax.vecmath.Matrix4d; 041 042 import org.deegree.crs.Identifiable; 043 import org.deegree.crs.projections.ProjectionUtils; 044 045 /** 046 * Parameters for a geographic transformation into WGS84. The Bursa Wolf parameters should be applied to geocentric 047 * coordinates, where the X axis points towards the Greenwich Prime Meridian, the Y axis points East, and the Z axis 048 * points North. 049 * 050 * 051 * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a> 052 * 053 * @author last edited by: $Author:$ 054 * 055 * @version $Revision:$, $Date:$ 056 * 057 */ 058 public class WGS84ConversionInfo extends Identifiable { 059 060 /** Bursa Wolf shift in meters. */ 061 public double dx; 062 063 /** Bursa Wolf shift in meters. */ 064 public double dy; 065 066 /** Bursa Wolf shift in meters. */ 067 public double dz; 068 069 /** Bursa Wolf rotation in arc seconds, which is 1/3600 of a degree. */ 070 public double ex; 071 072 /** Bursa Wolf rotation in arc seconds. */ 073 public double ey; 074 075 /** Bursa Wolf rotation in arc seconds. */ 076 public double ez; 077 078 /** Bursa Wolf scaling in parts per million. */ 079 public double ppm; 080 081 /** 082 * Construct a conversion info with all parameters set to 0; 083 * 084 * @param identifier 085 */ 086 public WGS84ConversionInfo( String identifier ) { 087 this( new String[]{identifier} ); 088 } 089 090 /** 091 * Construct a conversion info with all parameters set to 0; 092 * 093 * @param identifiers 094 */ 095 public WGS84ConversionInfo( String[] identifiers ) { 096 super( identifiers ); 097 } 098 099 /** 100 * Construct a conversion info with all parameters set to 0; 101 * 102 * @param identifiers 103 * @param names 104 * @param versions 105 * @param descriptions 106 * @param areasOfUse 107 */ 108 public WGS84ConversionInfo( String[] identifiers, String[] names, String[] versions, String[] descriptions, String[] areasOfUse ) { 109 super( identifiers, names, versions, descriptions, areasOfUse ); 110 111 } 112 113 /** 114 * @param dx 115 * Bursa Wolf shift in meters. 116 * @param dy 117 * Bursa Wolf shift in meters. 118 * @param dz 119 * Bursa Wolf shift in meters. 120 * @param ex 121 * Bursa Wolf rotation in arc seconds. 122 * @param ey 123 * Bursa Wolf rotation in arc seconds. 124 * @param ez 125 * Bursa Wolf rotation in arc seconds. 126 * @param ppm 127 * Bursa Wolf scaling in parts per million. 128 * @param identifiers 129 * @param names 130 * @param versions 131 * @param descriptions 132 * @param areaOfUses 133 */ 134 public WGS84ConversionInfo( double dx, double dy, double dz, double ex, double ey, double ez, double ppm, 135 String[] identifiers, String[] names, String[] versions, String[] descriptions, String[] areaOfUses ) { 136 super( identifiers, names, versions, descriptions, areaOfUses ); 137 this.dx = dx; 138 this.dy = dy; 139 this.dz = dz; 140 this.ex = ex; 141 this.ey = ey; 142 this.ez = ez; 143 this.ppm = ppm; 144 } 145 146 /** 147 * @param dx 148 * Bursa Wolf shift in meters. 149 * @param dy 150 * Bursa Wolf shift in meters. 151 * @param dz 152 * Bursa Wolf shift in meters. 153 * @param ex 154 * Bursa Wolf rotation in arc seconds. 155 * @param ey 156 * Bursa Wolf rotation in arc seconds. 157 * @param ez 158 * Bursa Wolf rotation in arc seconds. 159 * @param ppm 160 * Bursa Wolf scaling in parts per million. 161 * @param identifier 162 * @param name 163 * @param version 164 * @param description 165 * @param areaOfUse 166 */ 167 public WGS84ConversionInfo( double dx, double dy, double dz, double ex, double ey, double ez, double ppm, 168 String identifier, String name, String version, String description, String areaOfUse ) { 169 this( dx, dy, dz, ex, ey, ez, ppm, new String[]{identifier}, new String[]{name}, new String[]{version}, new String[]{description}, new String[]{areaOfUse} ); 170 } 171 172 /** 173 * @param dx 174 * Bursa Wolf shift in meters. 175 * @param dy 176 * Bursa Wolf shift in meters. 177 * @param dz 178 * Bursa Wolf shift in meters. 179 * @param ex 180 * Bursa Wolf rotation in arc seconds. 181 * @param ey 182 * Bursa Wolf rotation in arc seconds. 183 * @param ez 184 * Bursa Wolf rotation in arc seconds. 185 * @param ppm 186 * Bursa Wolf scaling in parts per million. 187 * @param identifiers 188 */ 189 public WGS84ConversionInfo( double dx, double dy, double dz, double ex, double ey, double ez, double ppm, 190 String[] identifiers ) { 191 this( dx, dy, dz, ex, ey, ez, ppm, identifiers, null, null, null, null ); 192 } 193 194 /** 195 * @param dx 196 * Bursa Wolf shift in meters. 197 * @param dy 198 * Bursa Wolf shift in meters. 199 * @param dz 200 * Bursa Wolf shift in meters. 201 * @param ex 202 * Bursa Wolf rotation in arc seconds. 203 * @param ey 204 * Bursa Wolf rotation in arc seconds. 205 * @param ez 206 * Bursa Wolf rotation in arc seconds. 207 * @param ppm 208 * Bursa Wolf scaling in parts per million. 209 * @param identifier 210 */ 211 public WGS84ConversionInfo( double dx, double dy, double dz, double ex, double ey, double ez, double ppm, 212 String identifier) { 213 this( dx, dy, dz, ex, ey, ez, ppm, new String[]{identifier}); 214 } 215 216 /** 217 * @param dx 218 * Bursa Wolf shift in meters. 219 * @param dy 220 * Bursa Wolf shift in meters. 221 * @param dz 222 * Bursa Wolf shift in meters. 223 * @param ex 224 * Bursa Wolf rotation in arc seconds. 225 * @param ey 226 * Bursa Wolf rotation in arc seconds. 227 * @param ez 228 * Bursa Wolf rotation in arc seconds. 229 * @param ppm 230 * Bursa Wolf scaling in parts per million. 231 * @param identifiable object containing all relevant id. 232 */ 233 public WGS84ConversionInfo( double dx, double dy, double dz, double ex, double ey, double ez, double ppm, Identifiable identifiable ) { 234 super( identifiable ); 235 this.dx = dx; 236 this.dy = dy; 237 this.dz = dz; 238 this.ex = ex; 239 this.ey = ey; 240 this.ez = ez; 241 this.ppm = ppm; 242 } 243 244 /** 245 * Returns an affine tranformation also known as the "Helmert" transformation. The matrix representation of this 246 * transformation (also known as "Bursa Wolf" formula) is as follows: 247 * 248 * <blockquote> 249 * 250 * <pre> 251 * S = 1 + {@link #ppm}/1000000 252 * 253 * [ X ] [ S -{@link #ez}*S +{@link #ey}*S {@link #dx} ] [ X ] 254 * [ Y ] = [ +{@link #ez}*S S -{@link #ex}*S {@link #dy} ] [ Y ] 255 * [ Z ] [ -{@link #ey}*S +{@link #ex}*S S {@link #dz} ] [ Z ] 256 * [ 1 ] [ 0 0 0 1 ] [ 1 ] 257 * </pre> 258 * 259 * </blockquote> 260 * 261 * This affine transform can be applied to transform <code>geocentric</code> coordinates from one datum into 262 * <code>geocentric</code> coordinates of an other datum. see <a 263 * href="http://www.posc.org/Epicentre.2_2/DataModel/ExamplesofUsage/eu_cs35.html#CS3523_helmert"> 264 * http://www.posc.org/Epicentre.2_2/DataModel/ExamplesofUsage/eu_cs35.html</a> for more information. 265 * 266 * @return the affine "Helmert" transformation as a Matrix4d. 267 */ 268 public Matrix4d getAsAffineTransform() { 269 // Note: (ex, ey, ez) is a rotation in arc seconds. We need to convert it into radians (the R factor in RS). 270 final double S = 1 + ( ppm * 1E-6 ); 271 final double RS = ( Math.PI / ( 180. * 3600. ) ) * S; 272 return new Matrix4d( S, 273 -ez * RS, 274 +ey * RS, 275 dx, 276 +ez * RS, 277 S, 278 -ex * RS, 279 dy, 280 -ey * RS, 281 +ex * RS, 282 S, 283 dz, 284 0, 285 0, 286 0, 287 1. ); 288 } 289 290 @Override 291 public boolean equals( final Object object ) { 292 if ( object != null && object instanceof WGS84ConversionInfo ) { 293 final WGS84ConversionInfo that = (WGS84ConversionInfo) object; 294 return Math.abs( this.dx - that.dx ) < ProjectionUtils.EPS11 && Math.abs( this.dy - that.dy ) < ProjectionUtils.EPS11 295 && Math.abs( this.dz - that.dz ) < ProjectionUtils.EPS11 296 && Math.abs( this.ex - that.ex ) < ProjectionUtils.EPS11 297 && Math.abs( this.ey - that.ey ) < ProjectionUtils.EPS11 298 && Math.abs( this.ez - that.ez ) < ProjectionUtils.EPS11 299 && Math.abs( this.ppm - that.ppm ) < ProjectionUtils.EPS11; 300 301 } 302 return false; 303 } 304 305 /** 306 * Returns the Well Know Text (WKT) for this object. The WKT is part of OpenGIS's specification and looks like 307 * <code>TOWGS84[dx, dy, dz, ex, ey, ez, ppm]</code>. 308 * 309 * @return the Well Know Text (WKT) for this object. 310 */ 311 @Override 312 public String toString() { 313 final StringBuffer buffer = new StringBuffer( "[\"" ); 314 buffer.append( dx ); 315 buffer.append( ", " ); 316 buffer.append( dy ); 317 buffer.append( ", " ); 318 buffer.append( dz ); 319 buffer.append( ", " ); 320 buffer.append( ex ); 321 buffer.append( ", " ); 322 buffer.append( ey ); 323 buffer.append( ", " ); 324 buffer.append( ez ); 325 buffer.append( ", " ); 326 buffer.append( ppm ); 327 buffer.append( ']' ); 328 return buffer.toString(); 329 } 330 331 /** 332 * Implementation as proposed by Joshua Block in Effective Java (Addison-Wesley 2001), which supplies an even 333 * distribution and is relatively fast. It is created from field <b>f</b> as follows: 334 * <ul> 335 * <li>boolean -- code = (f ? 0 : 1)</li> 336 * <li>byte, char, short, int -- code = (int)f </li> 337 * <li>long -- code = (int)(f ^ (f >>>32))</li> 338 * <li>float -- code = Float.floatToIntBits(f);</li> 339 * <li>double -- long l = Double.doubleToLongBits(f); code = (int)(l ^ (l >>> 32))</li> 340 * <li>all Objects, (where equals( ) calls equals( ) for this field) -- code = f.hashCode( )</li> 341 * <li>Array -- Apply above rules to each element</li> 342 * </ul> 343 * <p> 344 * Combining the hash code(s) computed above: result = 37 * result + code; 345 * </p> 346 * 347 * @return (int) ( result >>> 32 ) ^ (int) result; 348 * 349 * @see java.lang.Object#hashCode() 350 */ 351 @Override 352 public int hashCode() { 353 // the 2nd millionth prime, :-) 354 long code = 32452843; 355 long tmp = Double.doubleToLongBits( dx ); 356 code = code * 37 + (int)( tmp ^ (tmp >>> 32 )); 357 358 tmp = Double.doubleToLongBits( dy ); 359 code = code * 37 + (int)( tmp ^ (tmp >>> 32 )); 360 361 tmp = Double.doubleToLongBits( dz ); 362 code = code * 37 + (int)( tmp ^ (tmp >>> 32 )); 363 364 tmp = Double.doubleToLongBits( ex ); 365 code = code * 37 + (int)( tmp ^ (tmp >>> 32 )); 366 367 tmp = Double.doubleToLongBits( ey ); 368 code = code * 37 + (int)( tmp ^ (tmp >>> 32 )); 369 370 tmp = Double.doubleToLongBits( ez ); 371 code = code * 37 + (int)( tmp ^ (tmp >>> 32 )); 372 373 tmp = Double.doubleToLongBits( ppm ); 374 code = code * 37 + (int)( tmp ^ (tmp >>> 32 )); 375 return (int) ( code >>> 32 ) ^ (int) code; 376 } 377 }