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 &gt;&gt;&gt;32))</li>
338         * <li>float -- code = Float.floatToIntBits(f);</li>
339         * <li>double -- long l = Double.doubleToLongBits(f); code = (int)(l ^ (l &gt;&gt;&gt; 32))</li>
340         * <li>all Objects, (where equals(&nbsp;) calls equals(&nbsp;) for this field) -- code = f.hashCode(&nbsp;)</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    }