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,
109: String[] versions, String[] descriptions,
110: String[] areasOfUse) {
111: super (identifiers, names, versions, descriptions, areasOfUse);
112:
113: }
114:
115: /**
116: * @param dx
117: * Bursa Wolf shift in meters.
118: * @param dy
119: * Bursa Wolf shift in meters.
120: * @param dz
121: * Bursa Wolf shift in meters.
122: * @param ex
123: * Bursa Wolf rotation in arc seconds.
124: * @param ey
125: * Bursa Wolf rotation in arc seconds.
126: * @param ez
127: * Bursa Wolf rotation in arc seconds.
128: * @param ppm
129: * Bursa Wolf scaling in parts per million.
130: * @param identifiers
131: * @param names
132: * @param versions
133: * @param descriptions
134: * @param areaOfUses
135: */
136: public WGS84ConversionInfo(double dx, double dy, double dz,
137: double ex, double ey, double ez, double ppm,
138: String[] identifiers, String[] names, String[] versions,
139: String[] descriptions, String[] areaOfUses) {
140: super (identifiers, names, versions, descriptions, areaOfUses);
141: this .dx = dx;
142: this .dy = dy;
143: this .dz = dz;
144: this .ex = ex;
145: this .ey = ey;
146: this .ez = ez;
147: this .ppm = ppm;
148: }
149:
150: /**
151: * @param dx
152: * Bursa Wolf shift in meters.
153: * @param dy
154: * Bursa Wolf shift in meters.
155: * @param dz
156: * Bursa Wolf shift in meters.
157: * @param ex
158: * Bursa Wolf rotation in arc seconds.
159: * @param ey
160: * Bursa Wolf rotation in arc seconds.
161: * @param ez
162: * Bursa Wolf rotation in arc seconds.
163: * @param ppm
164: * Bursa Wolf scaling in parts per million.
165: * @param identifier
166: * @param name
167: * @param version
168: * @param description
169: * @param areaOfUse
170: */
171: public WGS84ConversionInfo(double dx, double dy, double dz,
172: double ex, double ey, double ez, double ppm,
173: String identifier, String name, String version,
174: String description, String areaOfUse) {
175: this (dx, dy, dz, ex, ey, ez, ppm, new String[] { identifier },
176: new String[] { name }, new String[] { version },
177: new String[] { description },
178: new String[] { areaOfUse });
179: }
180:
181: /**
182: * @param dx
183: * Bursa Wolf shift in meters.
184: * @param dy
185: * Bursa Wolf shift in meters.
186: * @param dz
187: * Bursa Wolf shift in meters.
188: * @param ex
189: * Bursa Wolf rotation in arc seconds.
190: * @param ey
191: * Bursa Wolf rotation in arc seconds.
192: * @param ez
193: * Bursa Wolf rotation in arc seconds.
194: * @param ppm
195: * Bursa Wolf scaling in parts per million.
196: * @param identifiers
197: */
198: public WGS84ConversionInfo(double dx, double dy, double dz,
199: double ex, double ey, double ez, double ppm,
200: String[] identifiers) {
201: this (dx, dy, dz, ex, ey, ez, ppm, identifiers, null, null,
202: null, null);
203: }
204:
205: /**
206: * @param dx
207: * Bursa Wolf shift in meters.
208: * @param dy
209: * Bursa Wolf shift in meters.
210: * @param dz
211: * Bursa Wolf shift in meters.
212: * @param ex
213: * Bursa Wolf rotation in arc seconds.
214: * @param ey
215: * Bursa Wolf rotation in arc seconds.
216: * @param ez
217: * Bursa Wolf rotation in arc seconds.
218: * @param ppm
219: * Bursa Wolf scaling in parts per million.
220: * @param identifier
221: */
222: public WGS84ConversionInfo(double dx, double dy, double dz,
223: double ex, double ey, double ez, double ppm,
224: String identifier) {
225: this (dx, dy, dz, ex, ey, ez, ppm, new String[] { identifier });
226: }
227:
228: /**
229: * @param dx
230: * Bursa Wolf shift in meters.
231: * @param dy
232: * Bursa Wolf shift in meters.
233: * @param dz
234: * Bursa Wolf shift in meters.
235: * @param ex
236: * Bursa Wolf rotation in arc seconds.
237: * @param ey
238: * Bursa Wolf rotation in arc seconds.
239: * @param ez
240: * Bursa Wolf rotation in arc seconds.
241: * @param ppm
242: * Bursa Wolf scaling in parts per million.
243: * @param identifiable
244: * object containing all relevant id.
245: */
246: public WGS84ConversionInfo(double dx, double dy, double dz,
247: double ex, double ey, double ez, double ppm,
248: Identifiable identifiable) {
249: super (identifiable);
250: this .dx = dx;
251: this .dy = dy;
252: this .dz = dz;
253: this .ex = ex;
254: this .ey = ey;
255: this .ez = ez;
256: this .ppm = ppm;
257: }
258:
259: /**
260: * Returns an affine transformation also known as the "Helmert" transformation. The matrix representation of this
261: * transformation (also known as "Bursa Wolf" formula) is as follows:
262: *
263: * <blockquote>
264: *
265: * <pre>
266: * S = 1 + {@link #ppm}/1000000
267: *
268: * [ X ] [ S -{@link #ez}*S +{@link #ey}*S {@link #dx} ] [ X ]
269: * [ Y ] = [ +{@link #ez}*S S -{@link #ex}*S {@link #dy} ] [ Y ]
270: * [ Z ] [ -{@link #ey}*S +{@link #ex}*S S {@link #dz} ] [ Z ]
271: * [ 1 ] [ 0 0 0 1 ] [ 1 ]
272: * </pre>
273: *
274: * </blockquote>
275: *
276: * This affine transform can be applied to transform <code>geocentric</code> coordinates from one datum into
277: * <code>geocentric</code> coordinates of an other datum. see <a
278: * href="http://www.posc.org/Epicentre.2_2/DataModel/ExamplesofUsage/eu_cs35.html#CS3523_helmert">
279: * http://www.posc.org/Epicentre.2_2/DataModel/ExamplesofUsage/eu_cs35.html</a> for more information.
280: *
281: * @return the affine "Helmert" transformation as a Matrix4d.
282: */
283: public Matrix4d getAsAffineTransform() {
284: // Note: (ex, ey, ez) is a rotation in arc seconds. We need to convert it into radians (the R factor in RS).
285: final double S = 1 + (ppm * 1E-6);
286: final double RS = (Math.PI / (180. * 3600.)) * S;
287: return new Matrix4d(S, -ez * RS, +ey * RS, dx, +ez * RS, S, -ex
288: * RS, dy, -ey * RS, +ex * RS, S, dz, 0, 0, 0, 1.);
289: }
290:
291: /**
292: * @return true if any of the helmert parameters were set.
293: */
294: public boolean hasValues() {
295: return !(ex == 0 && ey == 0 && ez == 0 && dx == 0 && dy == 0
296: && dz == 0 && ppm == 0);
297: }
298:
299: @Override
300: public boolean equals(final Object other) {
301: if (other != null && other instanceof WGS84ConversionInfo) {
302: final WGS84ConversionInfo that = (WGS84ConversionInfo) other;
303: return (Math.abs(this .dx - that.dx) < ProjectionUtils.EPS11)
304: && (Math.abs(this .dy - that.dy) < ProjectionUtils.EPS11)
305: && (Math.abs(this .dz - that.dz) < ProjectionUtils.EPS11)
306: && (Math.abs(this .ex - that.ex) < ProjectionUtils.EPS11)
307: && (Math.abs(this .ey - that.ey) < ProjectionUtils.EPS11)
308: && (Math.abs(this .ez - that.ez) < ProjectionUtils.EPS11)
309: && (Math.abs(this .ppm - that.ppm) < ProjectionUtils.EPS11)
310: && super .equals(that);
311:
312: }
313: return false;
314: }
315:
316: /**
317: * Returns the Well Know Text (WKT) for this object. The WKT is part of OpenGIS's specification and looks like
318: * <code>TOWGS84[dx, dy, dz, ex, ey, ez, ppm]</code>.
319: *
320: * @return the Well Know Text (WKT) for this object.
321: */
322: @Override
323: public String toString() {
324: final StringBuffer buffer = new StringBuffer("[\"");
325: buffer.append(dx);
326: buffer.append(", ");
327: buffer.append(dy);
328: buffer.append(", ");
329: buffer.append(dz);
330: buffer.append(", ");
331: buffer.append(ex);
332: buffer.append(", ");
333: buffer.append(ey);
334: buffer.append(", ");
335: buffer.append(ez);
336: buffer.append(", ");
337: buffer.append(ppm);
338: buffer.append(']');
339: return buffer.toString();
340: }
341:
342: /**
343: * Implementation as proposed by Joshua Block in Effective Java (Addison-Wesley 2001), which supplies an even
344: * distribution and is relatively fast. It is created from field <b>f</b> as follows:
345: * <ul>
346: * <li>boolean -- code = (f ? 0 : 1)</li>
347: * <li>byte, char, short, int -- code = (int)f </li>
348: * <li>long -- code = (int)(f ^ (f >>>32))</li>
349: * <li>float -- code = Float.floatToIntBits(f);</li>
350: * <li>double -- long l = Double.doubleToLongBits(f); code = (int)(l ^ (l >>> 32))</li>
351: * <li>all Objects, (where equals( ) calls equals( ) for this field) -- code = f.hashCode( )</li>
352: * <li>Array -- Apply above rules to each element</li>
353: * </ul>
354: * <p>
355: * Combining the hash code(s) computed above: result = 37 * result + code;
356: * </p>
357: *
358: * @return (int) ( result >>> 32 ) ^ (int) result;
359: *
360: * @see java.lang.Object#hashCode()
361: */
362: @Override
363: public int hashCode() {
364: // the 2nd millionth prime, :-)
365: long code = 32452843;
366: long tmp = Double.doubleToLongBits(dx);
367: code = code * 37 + (int) (tmp ^ (tmp >>> 32));
368:
369: tmp = Double.doubleToLongBits(dy);
370: code = code * 37 + (int) (tmp ^ (tmp >>> 32));
371:
372: tmp = Double.doubleToLongBits(dz);
373: code = code * 37 + (int) (tmp ^ (tmp >>> 32));
374:
375: tmp = Double.doubleToLongBits(ex);
376: code = code * 37 + (int) (tmp ^ (tmp >>> 32));
377:
378: tmp = Double.doubleToLongBits(ey);
379: code = code * 37 + (int) (tmp ^ (tmp >>> 32));
380:
381: tmp = Double.doubleToLongBits(ez);
382: code = code * 37 + (int) (tmp ^ (tmp >>> 32));
383:
384: tmp = Double.doubleToLongBits(ppm);
385: code = code * 37 + (int) (tmp ^ (tmp >>> 32));
386: return (int) (code >>> 32) ^ (int) code;
387: }
388: }
|