Source Code Cross Referenced for MolodenskiTransform.java in  » GIS » GeoTools-2.4.1 » org » geotools » referencing » operation » transform » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » GIS » GeoTools 2.4.1 » org.geotools.referencing.operation.transform 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *    GeoTools - OpenSource mapping toolkit
003:         *    http://geotools.org
004:         *   
005:         *   (C) 2003-2006, Geotools Project Managment Committee (PMC)
006:         * 
007:         *    This library is free software; you can redistribute it and/or
008:         *    modify it under the terms of the GNU Lesser General Public
009:         *    License as published by the Free Software Foundation; either
010:         *    version 2.1 of the License, or (at your option) any later version.
011:         *
012:         *    This library is distributed in the hope that it will be useful,
013:         *    but WITHOUT ANY WARRANTY; without even the implied warranty of
014:         *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015:         *    Lesser General Public License for more details.
016:         */
017:        package org.geotools.referencing.operation.transform;
018:
019:        // J2SE dependencies and extensions
020:        import java.io.Serializable;
021:        import java.util.Collection;
022:        import java.util.Collections;
023:        import javax.units.SI;
024:
025:        // OpenGIS dependencies
026:        import org.opengis.parameter.ParameterDescriptor;
027:        import org.opengis.parameter.ParameterDescriptorGroup;
028:        import org.opengis.parameter.ParameterNotFoundException;
029:        import org.opengis.parameter.ParameterValue;
030:        import org.opengis.parameter.ParameterValueGroup;
031:        import org.opengis.referencing.operation.MathTransform;
032:        import org.opengis.referencing.operation.MathTransform2D;
033:        import org.opengis.referencing.operation.OperationMethod;
034:        import org.opengis.referencing.operation.Transformation;
035:
036:        // Geotools dependencies
037:        import org.geotools.metadata.iso.citation.Citations;
038:        import org.geotools.parameter.DefaultParameterDescriptor;
039:        import org.geotools.parameter.FloatParameter;
040:        import org.geotools.parameter.Parameter;
041:        import org.geotools.parameter.ParameterGroup;
042:        import org.geotools.referencing.NamedIdentifier;
043:        import org.geotools.referencing.operation.MathTransformProvider;
044:        import org.geotools.resources.i18n.VocabularyKeys;
045:        import org.geotools.resources.i18n.Vocabulary;
046:        import org.geotools.resources.i18n.ErrorKeys;
047:        import org.geotools.resources.i18n.Errors;
048:
049:        /**
050:         * Two- or three-dimensional datum shift using the (potentially abridged) Molodensky transformation.
051:         * The Molodensky transformation (EPSG code 9604) and the abridged Molodensky transformation (EPSG
052:         * code 9605) transform two or three dimensional geographic points from one geographic coordinate
053:         * reference system to another (a datum shift), using three shift parameters (delta X, delta Y,
054:         * delta Z) and the difference between the semi-major axis and flattenings of the two ellipsoids.
055:         * <p>
056:         *
057:         * Unlike the Bursa-Wolf 3 parameter method (which acts on geocentric coordinates),
058:         * this transformation can be performed directly on geographic coordinates.
059:         * <p>
060:         *
061:         * <strong>References:</strong><ul>
062:         *   <li> Defense Mapping Agency (DMA), Datums, Ellipsoids, Grids and Grid Reference Systems,
063:         *        Technical Manual 8358.1. 
064:         *        Available from <a href="http://earth-info.nga.mil/GandG/pubs.html">http://earth-info.nga.mil/GandG/pubs.html</a></li>
065:         *   <li> Defense Mapping Agency (DMA), The Universal Grids: Universal Transverse 
066:         *        Mercator (UTM) and Universal Polar Stereographic (UPS), Fairfax VA, Technical Manual 8358.2. 
067:         *        Available from <a href="http://earth-info.nga.mil/GandG/pubs.html">http://earth-info.nga.mil/GandG/pubs.html</a></li>
068:         *   <li> National Imagery and Mapping Agency (NIMA), Department of Defense World 
069:         *        Geodetic System 1984, Technical Report 8350.2. 
070:         *        Available from <a href="http://earth-info.nga.mil/GandG/pubs.html">http://earth-info.nga.mil/GandG/pubs.html</a></li>
071:         *   <li> "Coordinate Conversions and Transformations including Formulas",
072:         *        EPSG Guidence Note Number 7, Version 19.</li>
073:         * </ul>
074:         *
075:         * @since 2.1
076:         * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/referencing/operation/transform/MolodenskiTransform.java $
077:         * @version $Id: MolodenskiTransform.java 24384 2007-02-14 00:23:05Z desruisseaux $
078:         * @author Rueben Schulz
079:         * @author Martin Desruisseaux
080:         */
081:        public class MolodenskiTransform extends AbstractMathTransform
082:                implements  Serializable {
083:            /**
084:             * Serial number for interoperability with different versions.
085:             */
086:            private static final long serialVersionUID = 7536566033885338422L;
087:
088:            /**
089:             * The tolerance error for assertions, in decimal degrees.
090:             */
091:            private static final float EPS = 1E-5f;
092:
093:            /**
094:             * {@code true} for the abridged formula, or {@code false} for the complete version.
095:             */
096:            private final boolean abridged;
097:
098:            /**
099:             * {@code true} for a 3D transformation, or
100:             * {@code false} for a 2D transformation.
101:             */
102:            private final boolean source3D, target3D;
103:
104:            /**
105:             * X,Y,Z shift in meters.
106:             */
107:            private final double dx, dy, dz;
108:
109:            /**
110:             * Semi-major (<var>a</var>) semi-minor (<var>b/<var>) radius in meters.
111:             */
112:            private final double a, b;
113:
114:            /**
115:             * Difference in the semi-major ({@code da = target a - source a}) and semi-minor
116:             * ({@code db = target b - source b}) axes of the target and source ellipsoids.
117:             */
118:            private final double da, db;
119:
120:            /**
121:             * Difference between the flattenings ({@code df = target f - source f})
122:             * of the target and source ellipsoids.
123:             */
124:            private final double df;
125:
126:            /**
127:             * Ratio of the Semi-major (<var>a</var>) semi-minor (<var>b/<var>) axis 
128:             * values ({@code a_b = a/b} and {@code b_a = b/a}).
129:             */
130:            private final double b_a, a_b;
131:
132:            /**
133:             * Some more constants (<code>daa = da*a</code> and {@code da_a = da/a}).
134:             */
135:            private final double daa, da_a;
136:
137:            /**
138:             * The square of excentricity of the ellipsoid: eČ = (aČ-bČ)/aČ where
139:             * <var>a</var> is the semi-major axis length and
140:             * <var>b</var> is the semi-minor axis length.
141:             */
142:            private final double e2;
143:
144:            /**
145:             * Defined as <code>(a*df) + (f*da)</code>.
146:             */
147:            private final double adf;
148:
149:            /**
150:             * The inverse of this transform. Will be created only when first needed.
151:             */
152:            private transient MolodenskiTransform inverse;
153:
154:            /**
155:             * Constructs a Molodenski transform from the specified parameters.
156:             * 
157:             * @param abridged {@code true} for the abridged formula, or {@code false} for the complete one.
158:             * @param a        The source semi-major axis length in meters.
159:             * @param b        The source semi-minor axis length in meters.
160:             * @param source3D {@code true} if the source has a height.
161:             * @param ta       The target semi-major axis length in meters.
162:             * @param tb       The target semi-minor axis length in meters.
163:             * @param target3D {@code true} if the target has a height.
164:             * @param dx       The <var>x</var> translation in meters.
165:             * @param dy       The <var>y</var> translation in meters.
166:             * @param dz       The <var>z</var> translation in meters.
167:             */
168:            public MolodenskiTransform(final boolean abridged, final double a,
169:                    final double b, final boolean source3D, final double ta,
170:                    final double tb, final boolean target3D, final double dx,
171:                    final double dy, final double dz) {
172:                this .abridged = abridged;
173:                this .source3D = source3D;
174:                this .target3D = target3D;
175:                this .dx = dx;
176:                this .dy = dy;
177:                this .dz = dz;
178:                this .a = a;
179:                this .b = b;
180:
181:                da = ta - a;
182:                db = tb - b;
183:                a_b = a / b;
184:                b_a = b / a;
185:                daa = da * a;
186:                da_a = da / a;
187:                df = (ta - tb) / ta - (a - b) / a;
188:                e2 = 1 - (b * b) / (a * a);
189:                adf = (a * df) + (a - b) * da / a;
190:            }
191:
192:            /**
193:             * Returns the parameter descriptors for this math transform.
194:             */
195:            public ParameterDescriptorGroup getParameterDescriptors() {
196:                return abridged ? ProviderAbridged.PARAMETERS
197:                        : Provider.PARAMETERS;
198:            }
199:
200:            /**
201:             * Returns the parameters for this math transform.
202:             *
203:             * @return The parameters for this math transform.
204:             */
205:            public ParameterValueGroup getParameterValues() {
206:                final ParameterValue dim = new Parameter(Provider.DIM);
207:                dim.setValue(getSourceDimensions());
208:                return new ParameterGroup(getParameterDescriptors(),
209:                        new ParameterValue[] {
210:                                dim,
211:                                new FloatParameter(Provider.DX, dx),
212:                                new FloatParameter(Provider.DY, dy),
213:                                new FloatParameter(Provider.DZ, dz),
214:                                new FloatParameter(Provider.SRC_SEMI_MAJOR, a),
215:                                new FloatParameter(Provider.SRC_SEMI_MINOR, b),
216:                                new FloatParameter(Provider.TGT_SEMI_MAJOR, a
217:                                        + da),
218:                                new FloatParameter(Provider.TGT_SEMI_MINOR, b
219:                                        + db) });
220:            }
221:
222:            /**
223:             * Gets the dimension of input points.
224:             */
225:            public int getSourceDimensions() {
226:                return source3D ? 3 : 2;
227:            }
228:
229:            /**
230:             * Gets the dimension of output points.
231:             */
232:            public final int getTargetDimensions() {
233:                return target3D ? 3 : 2;
234:            }
235:
236:            /**
237:             * Transforms a list of coordinate point ordinal values.
238:             * This method is provided for efficiently transforming many points.
239:             * The supplied array of ordinal values will contain packed ordinal
240:             * values.  For example, if the source dimension is 3, then the ordinals
241:             * will be packed in this order:
242:             *
243:             * (<var>x<sub>0</sub></var>,<var>y<sub>0</sub></var>,<var>z<sub>0</sub></var>,
244:             *  <var>x<sub>1</sub></var>,<var>y<sub>1</sub></var>,<var>z<sub>1</sub></var> ...).
245:             *
246:             * @param srcPts the array containing the source point coordinates.
247:             * @param srcOff the offset to the first point to be transformed
248:             *               in the source array.
249:             * @param dstPts the array into which the transformed point
250:             *               coordinates are returned. May be the same
251:             *               than {@code srcPts}.
252:             * @param dstOff the offset to the location of the first
253:             *               transformed point that is stored in the
254:             *               destination array.
255:             * @param numPts the number of point objects to be transformed.
256:             */
257:            public void transform(double[] srcPts, int srcOff, double[] dstPts,
258:                    int dstOff, int numPts) {
259:                transform(null, srcPts, srcOff, null, dstPts, dstOff, numPts);
260:                /*
261:                 * Assertions: computes the inverse transform in the 3D-case only
262:                 *             (otherwise the transform is too approximative).
263:                 *
264:                 * NOTE: The somewhat complicated expression below executes 'maxError' *only* if
265:                 * 1) assertions are enabled and 2) the conditions before 'maxError' are meet. Do
266:                 * not factor the call to 'maxError' outside the 'assert' statement, otherwise it
267:                 * would be executed everytime and would hurt performance for normal operations
268:                 * (instead of slowing down during debugging only).
269:                 */
270:                assert !(target3D && srcPts != dstPts && (maxError(null,
271:                        srcPts, srcOff, null, dstPts, dstOff, numPts)) > EPS);
272:            }
273:
274:            /**
275:             * Transforms a list of coordinate point ordinal values.
276:             * This method is provided for efficiently transforming many points.
277:             * The supplied array of ordinal values will contain packed ordinal
278:             * values.  For example, if the source dimension is 3, then the ordinals
279:             * will be packed in this order:
280:             *
281:             * (<var>x<sub>0</sub></var>,<var>y<sub>0</sub></var>,<var>z<sub>0</sub></var>,
282:             *  <var>x<sub>1</sub></var>,<var>y<sub>1</sub></var>,<var>z<sub>1</sub></var> ...).
283:             *
284:             * @param srcPts the array containing the source point coordinates.
285:             * @param srcOff the offset to the first point to be transformed
286:             *               in the source array.
287:             * @param dstPts the array into which the transformed point
288:             *               coordinates are returned. May be the same
289:             *               than {@code srcPts}.
290:             * @param dstOff the offset to the location of the first
291:             *               transformed point that is stored in the
292:             *               destination array.
293:             * @param numPts the number of point objects to be transformed.
294:             */
295:            public void transform(final float[] srcPts, int srcOff,
296:                    final float[] dstPts, int dstOff, int numPts) {
297:                transform(srcPts, null, srcOff, dstPts, null, dstOff, numPts);
298:                /*
299:                 * Assertions: computes the inverse transform in the 3D-case only
300:                 *             (otherwise the transform is too approximative).
301:                 *
302:                 * NOTE: The somewhat complicated expression below executes 'maxError' *only* if
303:                 * 1) assertions are enabled and 2) the conditions before 'maxError' are meet. Do
304:                 * not factor the call to 'maxError' outside the 'assert' statement, otherwise it
305:                 * would be executed everytime and would hurt performance for normal operations
306:                 * (instead of slowing down during debugging only).
307:                 */
308:                assert !(target3D && srcPts != dstPts && (maxError(srcPts,
309:                        null, srcOff, dstPts, null, dstOff, numPts)) > EPS);
310:            }
311:
312:            /**
313:             * Implementation of the transformation methods for all cases.
314:             */
315:            private void transform(final float[] srcPts1,
316:                    final double[] srcPts2, int srcOff, final float[] dstPts1,
317:                    final double[] dstPts2, int dstOff, int numPts) {
318:                int step = 0;
319:                if ((srcPts2 != null ? srcPts2 == dstPts2 : srcPts1 == dstPts1)
320:                        && srcOff < dstOff
321:                        && srcOff + numPts * getSourceDimensions() > dstOff) {
322:                    if (source3D != target3D) {
323:                        // TODO: we need to figure out a general way to handle this case
324:                        //       (overwritting the source array  while source and target
325:                        //       dimensions are not the same).   This case occurs enough
326:                        //       in the CTS implementation...
327:                        throw new UnsupportedOperationException(
328:                                "Not yet implemented.");
329:                    }
330:                    step = -getSourceDimensions();
331:                    srcOff -= (numPts - 1) * step;
332:                    dstOff -= (numPts - 1) * step;
333:                }
334:                while (--numPts >= 0) {
335:                    double x, y, z;
336:                    if (srcPts2 != null) {
337:                        x = srcPts2[srcOff++];
338:                        y = srcPts2[srcOff++];
339:                        z = (source3D) ? srcPts2[srcOff++] : 0.0;
340:                    } else {
341:                        x = srcPts1[srcOff++];
342:                        y = srcPts1[srcOff++];
343:                        z = (source3D) ? srcPts1[srcOff++] : 0.0;
344:                    }
345:                    x = Math.toRadians(x);
346:                    y = Math.toRadians(y);
347:                    final double sinX = Math.sin(x);
348:                    final double cosX = Math.cos(x);
349:                    final double sinY = Math.sin(y);
350:                    final double cosY = Math.cos(y);
351:                    final double sin2Y = sinY * sinY;
352:                    final double Rn = a / Math.sqrt(1 - e2 * sin2Y);
353:                    final double Rm = Rn * (1 - e2) / (1 - e2 * sin2Y);
354:
355:                    // Note: Computation of 'x' and 'y' ommit the division by sin(1"), because
356:                    //       1/sin(1") / (60*60*180/PI) = 1.0000000000039174050898603898692...
357:                    //       (60*60 is for converting the final result from seconds to degrees,
358:                    //       and 180/PI is for converting degrees to radians). This is an error
359:                    //       of about 8E-7 arc seconds, probably close to rounding errors anyway.
360:                    if (abridged) {
361:                        y += (dz * cosY - sinY * (dy * sinX + dx * cosX) + adf
362:                                * Math.sin(2 * y))
363:                                / Rm;
364:                        x += (dy * cosX - dx * sinX) / (Rn * cosY);
365:                    } else {
366:                        y += (dz * cosY - sinY * (dy * sinX + dx * cosX) + da_a
367:                                * (Rn * e2 * sinY * cosY) + df
368:                                * (Rm * (a_b) + Rn * (b_a)) * sinY * cosY)
369:                                / (Rm + z);
370:                        x += (dy * cosX - dx * sinX) / ((Rn + z) * cosY);
371:                    }
372:                    //stay within latitude +-90 deg. and longitude +-180 deg.
373:                    if (Math.abs(y) > Math.PI / 2.0) {
374:                        if (dstPts2 != null) {
375:                            dstPts2[dstOff++] = 0.0;
376:                            dstPts2[dstOff++] = (y > 0.0) ? 90.0 : -90.0;
377:                        } else {
378:                            dstPts1[dstOff++] = 0.0f;
379:                            dstPts1[dstOff++] = (y > 0.0f) ? 90.0f : -90.0f;
380:                        }
381:                    } else {
382:                        x = Math.toDegrees(rollLongitude(x));
383:                        y = Math.toDegrees(y);
384:                        if (dstPts2 != null) {
385:                            dstPts2[dstOff++] = x;
386:                            dstPts2[dstOff++] = y;
387:                        } else {
388:                            dstPts1[dstOff++] = (float) x;
389:                            dstPts1[dstOff++] = (float) y;
390:                        }
391:                    }
392:                    if (target3D) {
393:                        if (abridged) {
394:                            z += dx * cosY * cosX + dy * cosY * sinX + dz
395:                                    * sinY + adf * sin2Y - da;
396:                        } else {
397:                            z += dx * cosY * cosX + dy * cosY * sinX + dz
398:                                    * sinY + df * (b_a) * Rn * sin2Y - daa / Rn;
399:                        }
400:                        if (dstPts2 != null) {
401:                            dstPts2[dstOff++] = z;
402:                        } else {
403:                            dstPts1[dstOff++] = (float) z;
404:                        }
405:                    }
406:                    srcOff += step;
407:                    dstOff += step;
408:                }
409:            }
410:
411:            /**
412:             * After a call to {@code transform}, applies the <em>inverse</em> transform on {@code dstPts}
413:             * and compares the result with {@code srcPts}. The maximal difference (in absolute value) is
414:             * returned. This method is used for assertions.
415:             */
416:            private float maxError(final float[] srcPts1,
417:                    final double[] srcPts2, int srcOff, final float[] dstPts1,
418:                    final double[] dstPts2, int dstOff, int numPts) {
419:                float max = 0f;
420:                if (inverse == null) {
421:                    inverse();
422:                    if (inverse == null) {
423:                        return max; // Custom user's subclass; can't do the test.
424:                    }
425:                }
426:                final int sourceDim = getSourceDimensions();
427:                final float[] tmp = new float[numPts * sourceDim];
428:                inverse.transform(dstPts1, dstPts2, dstOff, tmp, null, 0,
429:                        numPts);
430:                for (int i = 0; i < tmp.length; i++, srcOff++) {
431:                    final float expected = (srcPts2 != null) ? (float) srcPts2[srcOff]
432:                            : srcPts1[srcOff];
433:                    float error = Math.abs(tmp[i] - expected);
434:                    switch (i % sourceDim) {
435:                    case 0:
436:                        error -= 360 * Math.floor(error / 360);
437:                        break; // Rool Longitude
438:                    case 2:
439:                        continue; // Ignore height because inacurate.
440:                    }
441:                    if (error > max) {
442:                        max = error;
443:                    }
444:                }
445:                return max;
446:            }
447:
448:            /**
449:             * Creates the inverse transform of this object.
450:             */
451:            public MathTransform inverse() {
452:                if (inverse == null) {
453:                    inverse = new MolodenskiTransform(abridged, a + da, b + db,
454:                            target3D, a, b, source3D, -dx, -dy, -dz);
455:                    inverse.inverse = this ;
456:                }
457:                return inverse;
458:            }
459:
460:            /**
461:             * Returns a hash value for this transform.
462:             */
463:            public final int hashCode() {
464:                final long code = Double.doubleToLongBits(dx)
465:                        + 37
466:                        * (Double.doubleToLongBits(dy) + 37 * (Double
467:                                .doubleToLongBits(dz) + 37 * (Double
468:                                .doubleToLongBits(a) + 37 * (Double
469:                                .doubleToLongBits(b) + 37 * (Double
470:                                .doubleToLongBits(da) + 37 * (Double
471:                                .doubleToLongBits(db)))))));
472:                int c = (int) code ^ (int) (code >>> 32)
473:                        ^ (int) serialVersionUID;
474:                if (abridged)
475:                    c = ~c;
476:                return c;
477:            }
478:
479:            /**
480:             * Compares the specified object with this math transform for equality.
481:             */
482:            public final boolean equals(final Object object) {
483:                if (object == this ) {
484:                    // Slight optimization
485:                    return true;
486:                }
487:                if (super .equals(object)) {
488:                    final MolodenskiTransform that = (MolodenskiTransform) object;
489:                    return this .abridged == that.abridged
490:                            && this .source3D == that.source3D
491:                            && this .target3D == that.target3D
492:                            && Double.doubleToLongBits(this .dx) == Double
493:                                    .doubleToLongBits(that.dx)
494:                            && Double.doubleToLongBits(this .dy) == Double
495:                                    .doubleToLongBits(that.dy)
496:                            && Double.doubleToLongBits(this .dz) == Double
497:                                    .doubleToLongBits(that.dz)
498:                            && Double.doubleToLongBits(this .a) == Double
499:                                    .doubleToLongBits(that.a)
500:                            && Double.doubleToLongBits(this .b) == Double
501:                                    .doubleToLongBits(that.b)
502:                            && Double.doubleToLongBits(this .da) == Double
503:                                    .doubleToLongBits(that.da)
504:                            && Double.doubleToLongBits(this .db) == Double
505:                                    .doubleToLongBits(that.db);
506:                }
507:                return false;
508:            }
509:
510:            /**
511:             * A Molodenski transforms in 2D. This implementation is identical to
512:             * {@link MolodenksiTransform} except that it implements {@link MathTransform2D}.
513:             */
514:            private static final class As2D extends MolodenskiTransform
515:                    implements  MathTransform2D {
516:                /** Serial number for compatibility with different versions. */
517:                private static final long serialVersionUID = 8098439371246167474L;
518:
519:                /** Constructs a 2D transform using Molodenski formulas. */
520:                public As2D(final boolean abridged, final double a,
521:                        final double b, final double ta, final double tb,
522:                        final double dx, final double dy, final double dz) {
523:                    super (abridged, a, b, false, ta, tb, false, dx, dy, dz);
524:                }
525:
526:                /** Creates the inverse transform of this object. */
527:                public MathTransform inverse() {
528:                    if (super .inverse == null) {
529:                        super .inverse = new As2D(super .abridged, super .a
530:                                + super .da, super .b + super .db, super .a,
531:                                super .b, -super .dx, -super .dy, -super .dz);
532:                        super .inverse.inverse = this ;
533:                    }
534:                    return super .inverse;
535:                }
536:            }
537:
538:            /**
539:             * The provider for {@link MolodenskiTransform}. This provider will construct
540:             * transforms from {@linkplain org.geotools.referencing.crs.DefaultGeographicCRS geographic}
541:             * to {@linkplain org.geotools.referencing.crs.DefaultGeographicCRS geographic} coordinate
542:             * reference systems.
543:             * <p>
544:             * <strong>Note:</strong>
545:             * The EPSG does not use src_semi_major, etc. parameters and instead uses 
546:             * "Semi-major axis length difference" and "Flattening difference".
547:             *
548:             * @version $Id: MolodenskiTransform.java 24384 2007-02-14 00:23:05Z desruisseaux $
549:             * @author Rueben Schulz
550:             */
551:            public static class Provider extends MathTransformProvider {
552:                /**
553:                 * Serial number for interoperability with different versions.
554:                 */
555:                private static final long serialVersionUID = -5332126871499059030L;
556:
557:                /**
558:                 * The default value for source and target geographic dimensions, which is 2.
559:                 */
560:                // NOTE: If this default value is modified, then
561:                // the handling of the 3D cases must be adjusted.
562:                static final int DEFAULT_DIMENSION = GeocentricTranslation.Provider.DEFAULT_DIMENSION;
563:
564:                /**
565:                 * The number of geographic dimension (2 or 3). This argument applies on
566:                 * both the source and the target dimension. The default value is 2.
567:                 */
568:                public static final ParameterDescriptor DIM = new DefaultParameterDescriptor(
569:                        Collections.singletonMap(NAME_KEY, new NamedIdentifier(
570:                                Citations.OGC, "dim")), DEFAULT_DIMENSION, 2,
571:                        3, false);
572:
573:                /**
574:                 * The number of source geographic dimension (2 or 3).
575:                 * This is a Geotools-specific argument.
576:                 *
577:                 * @todo Not yet used by this provider. See GEOT-411.
578:                 */
579:                public static final ParameterDescriptor SRC_DIM = GeocentricTranslation.Provider.SRC_DIM;
580:
581:                /**
582:                 * The number of target geographic dimension (2 or 3).
583:                 * This is a Geotools-specific argument.
584:                 *
585:                 * @todo Not yet used by this provider. See GEOT-411.
586:                 */
587:                public static final ParameterDescriptor TGT_DIM = GeocentricTranslation.Provider.TGT_DIM;
588:
589:                /**
590:                 * The operation parameter descriptor for the <cite>X-axis translation</cite> ("dx")
591:                 * parameter value. Valid values range from -infinity to infinity. Units are meters.
592:                 */
593:                public static final ParameterDescriptor DX = GeocentricTranslation.Provider.DX;
594:
595:                /**
596:                 * The operation parameter descriptor for the <cite>Y-axis translation</cite> ("dy")
597:                 * parameter value. Valid values range from -infinity to infinity. Units are meters.
598:                 */
599:                public static final ParameterDescriptor DY = GeocentricTranslation.Provider.DY;
600:
601:                /**
602:                 * The operation parameter descriptor for the <cite>Z-axis translation</cite> ("dz")
603:                 * parameter value. Valid values range from -infinity to infinity. Units are meters.
604:                 */
605:                public static final ParameterDescriptor DZ = GeocentricTranslation.Provider.DZ;
606:
607:                /**
608:                 * The operation parameter descriptor for the "src_semi_major" parameter value.
609:                 * Valid values range from 0 to infinity.
610:                 */
611:                public static final ParameterDescriptor SRC_SEMI_MAJOR = createDescriptor(
612:                        identifiers(GeocentricTranslation.Provider.SRC_SEMI_MAJOR),
613:                        Double.NaN, 0.0, Double.POSITIVE_INFINITY, SI.METER);
614:
615:                /**
616:                 * The operation parameter descriptor for the "src_semi_minor" parameter value.
617:                 * Valid values range from 0 to infinity.
618:                 */
619:                public static final ParameterDescriptor SRC_SEMI_MINOR = createDescriptor(
620:                        identifiers(GeocentricTranslation.Provider.SRC_SEMI_MINOR),
621:                        Double.NaN, 0.0, Double.POSITIVE_INFINITY, SI.METER);
622:
623:                /**
624:                 * The operation parameter descriptor for the "tgt_semi_major" parameter value.
625:                 * Valid values range from 0 to infinity.
626:                 */
627:                public static final ParameterDescriptor TGT_SEMI_MAJOR = createDescriptor(
628:                        identifiers(GeocentricTranslation.Provider.TGT_SEMI_MAJOR),
629:                        Double.NaN, 0.0, Double.POSITIVE_INFINITY, SI.METER);
630:
631:                /**
632:                 * The operation parameter descriptor for the "tgt_semi_minor" parameter value.
633:                 * Valid values range from 0 to infinity.
634:                 */
635:                public static final ParameterDescriptor TGT_SEMI_MINOR = createDescriptor(
636:                        identifiers(GeocentricTranslation.Provider.TGT_SEMI_MINOR),
637:                        Double.NaN, 0.0, Double.POSITIVE_INFINITY, SI.METER);
638:
639:                /** Helper method for parameter descriptor creation. */
640:                private static final NamedIdentifier[] identifiers(
641:                        final ParameterDescriptor parameter) {
642:                    final Collection id = parameter.getAlias();
643:                    return (NamedIdentifier[]) id
644:                            .toArray(new NamedIdentifier[id.size()]);
645:                }
646:
647:                /**
648:                 * The parameters group.
649:                 */
650:                static final ParameterDescriptorGroup PARAMETERS = createDescriptorGroup(
651:                        new NamedIdentifier[] {
652:                                new NamedIdentifier(Citations.OGC, "Molodenski"),
653:                                new NamedIdentifier(Citations.EPSG,
654:                                        "Molodenski"),
655:                                new NamedIdentifier(Citations.EPSG, "9604"),
656:                                new NamedIdentifier(
657:                                        Citations.GEOTOOLS,
658:                                        Vocabulary
659:                                                .formatInternational(VocabularyKeys.MOLODENSKI_TRANSFORM)) },
660:                        new ParameterDescriptor[] { DIM, DX, DY, DZ,
661:                                SRC_SEMI_MAJOR, SRC_SEMI_MINOR, TGT_SEMI_MAJOR,
662:                                TGT_SEMI_MINOR });
663:
664:                /**
665:                 * The provider for the 3D case. Will be constructed
666:                 * by {@link #getMethod} when first needed.
667:                 */
668:                private transient Provider withHeight;
669:
670:                /**
671:                 * Constructs a provider.
672:                 */
673:                public Provider() {
674:                    super (DEFAULT_DIMENSION, DEFAULT_DIMENSION, PARAMETERS);
675:                }
676:
677:                /**
678:                 * Constructs a provider from a set of parameters.
679:                 *
680:                 * @param sourceDimensions Number of dimensions in the source CRS of this operation method.
681:                 * @param targetDimensions Number of dimensions in the target CRS of this operation method.
682:                 * @param parameters       The set of parameters (never {@code null}).
683:                 */
684:                Provider(final int sourceDimensions,
685:                        final int targetDimensions,
686:                        final ParameterDescriptorGroup parameters) {
687:                    super (sourceDimensions, targetDimensions, parameters);
688:                }
689:
690:                /**
691:                 * Returns the operation type.
692:                 */
693:                public Class getOperationType() {
694:                    return Transformation.class;
695:                }
696:
697:                /**
698:                 * Creates a math transform from the specified group of parameter values.
699:                 *
700:                 * @param  values The group of parameter values.
701:                 * @return The created math transform.
702:                 * @throws ParameterNotFoundException if a required parameter was not found.
703:                 */
704:                protected MathTransform createMathTransform(
705:                        final ParameterValueGroup values)
706:                        throws ParameterNotFoundException {
707:                    final boolean hasHeight;
708:                    final int dim = intValue(DIM, values);
709:                    switch (dim) {
710:                    case 0: // Default value: fall through
711:                    case DEFAULT_DIMENSION: {
712:                        hasHeight = false;
713:                        break;
714:                    }
715:                    case 3: {
716:                        hasHeight = true;
717:                        if (withHeight == null) {
718:                            withHeight = create3D();
719:                        }
720:                        break;
721:                    }
722:                    default: {
723:                        throw new IllegalArgumentException(Errors.format(
724:                                ErrorKeys.ILLEGAL_ARGUMENT_$2, "dim",
725:                                new Integer(dim)));
726:                    }
727:                    }
728:                    final double a = doubleValue(SRC_SEMI_MAJOR, values);
729:                    final double b = doubleValue(SRC_SEMI_MINOR, values);
730:                    final double ta = doubleValue(TGT_SEMI_MAJOR, values);
731:                    final double tb = doubleValue(TGT_SEMI_MINOR, values);
732:                    final double dx = doubleValue(DX, values);
733:                    final double dy = doubleValue(DY, values);
734:                    final double dz = doubleValue(DZ, values);
735:                    final boolean abridged = isAbridged();
736:                    if (!hasHeight) {
737:                        return new As2D(abridged, a, b, ta, tb, dx, dy, dz);
738:                    } else {
739:                        return new Delegate(
740:                                new MolodenskiTransform(abridged, a, b,
741:                                        hasHeight, ta, tb, hasHeight, dx, dy,
742:                                        dz), withHeight);
743:                    }
744:                }
745:
746:                /**
747:                 * Creates the 3D-version of this provider.
748:                 * This method is overridden by {@link ProviderAbridged}.
749:                 */
750:                Provider create3D() {
751:                    return new Provider(3, 3, PARAMETERS);
752:                }
753:
754:                /**
755:                 * Returns {@code true} for the abridged formulas.
756:                 * This method is overridden by {@link ProviderAbridged}.
757:                 */
758:                boolean isAbridged() {
759:                    return false;
760:                }
761:            }
762:
763:            /**
764:             * The provider for abridged {@link MolodenskiTransform}. This provider will construct
765:             * transforms from {@linkplain org.geotools.referencing.crs.DefaultGeographicCRS geographic}
766:             * to {@linkplain org.geotools.referencing.crs.DefaultGeographicCRS geographic} coordinate
767:             * reference systems. 
768:             * <p>
769:             * <strong>Note:</strong>
770:             * The EPSG does not use src_semi_major, etc. parameters and instead uses 
771:             * "Semi-major axis length difference" and "Flattening difference".
772:             *
773:             * @version $Id: MolodenskiTransform.java 24384 2007-02-14 00:23:05Z desruisseaux $
774:             * @author Martin Desruisseaux
775:             * @author Rueben Schulz
776:             */
777:            public static class ProviderAbridged extends Provider {
778:                /**
779:                 * Serial number for interoperability with different versions.
780:                 */
781:                private static final long serialVersionUID = 9148242601566635131L;
782:
783:                /**
784:                 * The parameters group.
785:                 */
786:                static final ParameterDescriptorGroup PARAMETERS = createDescriptorGroup(
787:                        new NamedIdentifier[] {
788:                                new NamedIdentifier(Citations.OGC,
789:                                        "Abridged_Molodenski"),
790:                                new NamedIdentifier(Citations.EPSG,
791:                                        "Abridged Molodenski"),
792:                                new NamedIdentifier(Citations.EPSG, "9605"),
793:                                new NamedIdentifier(
794:                                        Citations.GEOTOOLS,
795:                                        Vocabulary
796:                                                .format(VocabularyKeys.ABRIDGED_MOLODENSKI_TRANSFORM)) },
797:                        new ParameterDescriptor[] { DIM, DX, DY, DZ,
798:                                SRC_SEMI_MAJOR, SRC_SEMI_MINOR, TGT_SEMI_MAJOR,
799:                                TGT_SEMI_MINOR });
800:
801:                /**
802:                 * Constructs a provider.
803:                 */
804:                public ProviderAbridged() {
805:                    super (DEFAULT_DIMENSION, DEFAULT_DIMENSION, PARAMETERS);
806:                }
807:
808:                /**
809:                 * Constructs a provider from a set of parameters.
810:                 *
811:                 * @param sourceDimensions Number of dimensions in the source CRS of this operation method.
812:                 * @param targetDimensions Number of dimensions in the target CRS of this operation method.
813:                 * @param parameters       The set of parameters (never {@code null}).
814:                 */
815:                private ProviderAbridged(final int sourceDimensions,
816:                        final int targetDimensions,
817:                        final ParameterDescriptorGroup parameters) {
818:                    super (sourceDimensions, targetDimensions, parameters);
819:                }
820:
821:                /**
822:                 * Creates the 3D-version of this provider.
823:                 */
824:                Provider create3D() {
825:                    return new ProviderAbridged(3, 3, PARAMETERS);
826:                }
827:
828:                /**
829:                 * Returns {@code true} for the abridged formulas.
830:                 */
831:                boolean isAbridged() {
832:                    return true;
833:                }
834:            }
835:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.