001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/model/csct/ct/AbridgedMolodenskiTransform.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 (SEAGIS)
054    import java.io.Serializable;
055    
056    import javax.media.jai.ParameterList;
057    
058    import org.deegree.model.csct.cs.Ellipsoid;
059    import org.deegree.model.csct.cs.HorizontalDatum;
060    import org.deegree.model.csct.cs.WGS84ConversionInfo;
061    import org.deegree.model.csct.resources.css.ResourceKeys;
062    
063    
064    /**
065     * Transforms a three dimensional geographic points using
066     * abridged versions of formulas derived by Molodenski.
067     *
068     * @version 1.00
069     * @author OpenGIS (www.opengis.org)
070     * @author Martin Desruisseaux
071     */
072    class AbridgedMolodenskiTransform extends AbstractMathTransform implements Serializable
073    {
074        /**
075         * Serial number for interoperability with different versions.
076         */
077        //private static final long serialVersionUID = ?;
078    
079        /**
080         * X,Y,Z shift in meters
081         */
082        private final double dx, dy, dz;
083    
084        /**
085         * Source equatorial radius in meters.
086         */
087        private final double a;
088    
089        /**
090         * Source polar radius in meters
091         */
092        private final double b;
093    
094        /**
095         * Source flattening factor.
096         */
097        private final double f;
098    
099        /**
100         * Difference in the semi-major axes (a1 - a2)
101         * of the first and second ellipsoids.
102         */
103        private final double da;
104    
105        /**
106         * Difference in the flattening of the two ellipsoids.
107         */
108        private final double df;
109    
110        /**
111         * Square of the eccentricity of the ellipsoid.
112         */
113        private final double e2;
114    
115        /**
116         * Defined as <code>(a*df) + (f*da)</code>.
117         */
118        private final double adf;
119    
120        /**
121         * Construct a transform.
122         */
123        protected AbridgedMolodenskiTransform(final HorizontalDatum source, final HorizontalDatum target)
124        {
125            final WGS84ConversionInfo srcInfo = source.getWGS84Parameters();
126            final WGS84ConversionInfo tgtInfo = source.getWGS84Parameters();
127            final Ellipsoid      srcEllipsoid = source.getEllipsoid();
128            final Ellipsoid      tgtEllipsoid = target.getEllipsoid();
129            dx =     srcInfo.dx - tgtInfo.dx;
130            dy =     srcInfo.dy - tgtInfo.dy;
131            dz =     srcInfo.dz - tgtInfo.dz;
132            a  =     srcEllipsoid.getSemiMajorAxis();
133            b  =     srcEllipsoid.getSemiMinorAxis();
134            f  = 1 / srcEllipsoid.getInverseFlattening();
135            da = a - tgtEllipsoid.getSemiMajorAxis();
136            df = f - 1/tgtEllipsoid.getInverseFlattening();
137            e2  = 1 - (b*b)/(a*a);
138            adf = (a*df) + (f*da);
139        }
140    
141        /**
142         * Transforms a list of coordinate point ordinal values.
143         */
144        public void transform(final double[] srcPts, int srcOff, final double[] dstPts, int dstOff, int numPts)
145        {
146            int step = 0;
147            if (srcPts==dstPts && srcOff<dstOff && srcOff+numPts*getDimSource()>dstOff)
148            {
149                step = -getDimSource();
150                srcOff -= (numPts-1)*step;
151                dstOff -= (numPts-1)*step;
152            }
153            final double rho = Double.NaN; // TODO: Definition???
154            while (--numPts >= 0)
155            {
156                double x = Math.toRadians(srcPts[srcOff++]);
157                double y = Math.toRadians(srcPts[srcOff++]);
158                double z = srcPts[srcOff++];
159                final double sinX = Math.sin(x);
160                final double cosX = Math.cos(x);
161                final double sinY = Math.sin(y);
162                final double cosY = Math.cos(y);
163                final double sin2Y = sinY*sinY;
164                final double nu = a / Math.sqrt(1 - e2*sin2Y);
165    
166                // Note: Computation of 'x' and 'y' ommit the division by sin(1"), because
167                //       1/sin(1") / (60*60*180/PI) = 1.0000000000039174050898603898692...
168                //       (60*60 is for converting the final result from seconds to degrees,
169                //       and 180/PI is for converting degrees to radians). This is an error
170                //       of about 8E-7 arc seconds, probably close to rounding errors anyway.
171                y += (dz*cosY - sinY*(dy*sinX + dx*cosX) + adf*Math.sin(2*y)) / rho;
172                x += (dy*cosX - dx*sinX) / (nu*cosY);
173                z += dx*cosY*cosX + dy*cosY*sinX + dz*sinY + adf*sin2Y - da;
174    
175                dstPts[dstOff++] = Math.toDegrees(x);
176                dstPts[dstOff++] = Math.toDegrees(y);
177                dstPts[dstOff++] = z;
178                srcOff += step;
179                dstOff += step;
180            }
181        }
182    
183        /**
184         * Transforms a list of coordinate point ordinal values.
185         */
186        public void transform(final float[] srcPts, final int srcOff, final float[] dstPts, final int dstOff, int numPts)
187        {
188            // TODO: Copy the implementation from 'transform(double[]...)'.
189            try
190            {
191                super.transform(srcPts, srcOff, dstPts, dstOff, numPts);
192            }
193            catch (TransformException exception)
194            {
195                // Should not happen.
196            }
197        }
198    
199        /**
200         * Gets the dimension of input points, which is 3.
201         */
202        public int getDimSource()
203        {return 3;}
204    
205        /**
206         * Gets the dimension of output points, which
207         * is the same than {@link #getDimSource()}.
208         */
209        public final int getDimTarget()
210        {return getDimSource();}
211    
212        /**
213         * Tests whether this transform does not move any points.
214         * This method returns always <code>false</code>.
215         */
216        public final boolean isIdentity()
217        {return false;}
218    
219        /**
220         * Returns a hash value for this transform.
221         */
222        public final int hashCode()
223        {
224            final long code = Double.doubleToLongBits(dx) +
225                          37*(Double.doubleToLongBits(dy) +
226                          37*(Double.doubleToLongBits(dz) +
227                          37*(Double.doubleToLongBits(a ) +
228                          37*(Double.doubleToLongBits(b ) +
229                          37*(Double.doubleToLongBits(da) +
230                          37*(Double.doubleToLongBits(df)))))));
231            return (int) code ^ (int) (code >>> 32);
232        }
233    
234        /**
235         * Compares the specified object with
236         * this math transform for equality.
237         */
238        public final boolean equals(final Object object)
239        {
240            if (object==this) return true; // Slight optimization
241            if (super.equals(object))
242            {
243                final AbridgedMolodenskiTransform that = (AbridgedMolodenskiTransform) object;
244                return Double.doubleToLongBits(this.dx) == Double.doubleToLongBits(that.dx) &&
245                       Double.doubleToLongBits(this.dy) == Double.doubleToLongBits(that.dy) &&
246                       Double.doubleToLongBits(this.dz) == Double.doubleToLongBits(that.dz) &&
247                       Double.doubleToLongBits(this.a ) == Double.doubleToLongBits(that.a ) &&
248                       Double.doubleToLongBits(this.b ) == Double.doubleToLongBits(that.b ) &&
249                       Double.doubleToLongBits(this.da) == Double.doubleToLongBits(that.da) &&
250                       Double.doubleToLongBits(this.df) == Double.doubleToLongBits(that.df);
251            }
252            return false;
253        }
254    
255        /**
256         * Returns the WKT for this math transform.
257         */
258        public final String toString()
259        {
260            final StringBuffer buffer = paramMT("Abridged_Molodenski");
261            addParameter(buffer, "dim", getDimSource());
262            addParameter(buffer, "dx",              dx);
263            addParameter(buffer, "dy",              dy);
264            addParameter(buffer, "src_semi_major",   a);
265            addParameter(buffer, "src_semi_minor",   b);
266            addParameter(buffer, "tgt_semi_major",   a-da);
267    //      addParameter(buffer, "tgt_semi_minor",   b);  // TODO
268            buffer.append(']');
269            return buffer.toString();
270        }
271    
272        /**
273         * The provider for {@link AbridgedMolodenskiTransform}.
274         *
275         * @version 1.0
276         * @author Martin Desruisseaux
277         */
278        static final class Provider extends MathTransformProvider
279        {
280            /**
281             * Create a provider.
282             */
283            public Provider()
284            {
285                super("Abridged_Molodenski", ResourceKeys.ABRIDGED_MOLODENSKI_TRANSFORM, null);
286                put("dim",            Double.NaN, POSITIVE_RANGE);
287                put("dx",             Double.NaN, null);
288                put("dy",             Double.NaN, null);
289                put("src_semi_major", Double.NaN, POSITIVE_RANGE);
290                put("src_semi_minor", Double.NaN, POSITIVE_RANGE);
291                put("tgt_semi_major", Double.NaN, POSITIVE_RANGE);
292                put("tgt_semi_minor", Double.NaN, POSITIVE_RANGE);
293            }
294    
295            /**
296             * Returns a transform for the specified parameters.
297             *
298             * @param  parameters The parameter values in standard units.
299             * @return A {@link MathTransform} object of this classification.
300             */
301            public MathTransform create(final ParameterList parameters)
302            {return null;} // TODO
303        }
304    }