TidalDisplacement.java

  1. /* Copyright 2002-2018 CS Systèmes d'Information
  2.  * Licensed to CS Systèmes d'Information (CS) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * CS licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *   http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.orekit.models.earth.displacement;

  18. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  19. import org.hipparchus.util.FastMath;
  20. import org.orekit.data.BodiesElements;
  21. import org.orekit.data.PoissonSeries.CompiledSeries;
  22. import org.orekit.errors.OrekitException;
  23. import org.orekit.frames.Frame;
  24. import org.orekit.time.AbsoluteDate;
  25. import org.orekit.utils.IERSConventions;
  26. import org.orekit.utils.PVCoordinatesProvider;

  27. /**
  28.  * Modeling of displacement of reference points due to tidal effects.
  29.  * <p>
  30.  * This class implements displacement of reference point (i.e.
  31.  * {@link org.orekit.estimation.measurements.GroundStation ground stations})
  32.  * due to tidal effects, as per IERS conventions.
  33.  * </p>
  34.  * <p>
  35.  * Displacement can be computed with respect to either <em>conventional tide free</em>
  36.  * or <em>mean tide</em> coordinates. The difference between the two systems is
  37.  * about -12cm at poles and +6cm at equator. Selecting one system or the other
  38.  * depends on how the station coordinates have been computed (i.e. it depends
  39.  * whether the coordinates already include the permanent deformation or not).
  40.  * </p>
  41.  * <p>
  42.  * Instances of this class are guaranteed to be immutable
  43.  * </p>
  44.  * @see org.orekit.estimation.measurements.GroundStation
  45.  * @since 9.1
  46.  * @author Luc Maisonobe
  47.  */
  48. public class TidalDisplacement implements StationDisplacement {

  49.     /** Sun motion model. */
  50.     private final PVCoordinatesProvider sun;

  51.     /** Moon motion model. */
  52.     private final PVCoordinatesProvider moon;

  53.     /** Flag for permanent deformation. */
  54.     private final boolean removePermanentDeformation;

  55.     /** Ratio for degree 2 tide generated by Sun. */
  56.     private final double ratio2S;

  57.     /** Ratio for degree 3 tide generated by Sun. */
  58.     private final double ratio3S;

  59.     /** Ratio for degree 2 tide generated by Moon. */
  60.     private final double ratio2M;

  61.     /** Ratio for degree 3 tide generated by Moon. */
  62.     private final double ratio3M;

  63.     /** Displacement Shida number h⁽⁰⁾. */
  64.     private final double hSup0;

  65.     /** Displacement Shida number h⁽²⁾. */
  66.     private final double hSup2;

  67.     /** Displacement Shida number h₃. */
  68.     private final double h3;

  69.     /** Displacement Shida number hI diurnal. */
  70.     private final double hIDiurnal;

  71.     /** Displacement Shida number hI semi-diurnal. */
  72.     private final double hISemiDiurnal;

  73.     /** Displacement Love number l⁽⁰⁾. */
  74.     private final double lSup0;

  75.     /** Displacement Love number l⁽¹⁾ diurnal. */
  76.     private final double lSup1Diurnal;

  77.     /** Displacement Love number l⁽¹⁾ semi-diurnal. */
  78.     private final double lSup1SemiDiurnal;

  79.     /** Displacement Love number l⁽²⁾. */
  80.     private final double lSup2;

  81.     /** Displacement Love number l₃. */
  82.     private final double l3;

  83.     /** Displacement Love number lI diurnal. */
  84.     private final double lIDiurnal;

  85.     /** Displacement Love number lI semi-diurnal. */
  86.     private final double lISemiDiurnal;

  87.     /** Permanent deformation amplitude. */
  88.     private final double h0Permanent;

  89.     /** Function computing corrections in the frequency domain for diurnal tides.
  90.      * <ul>
  91.      *  <li>f[0]: radial correction, longitude cosine part</li>
  92.      *  <li>f[1]: radial correction, longitude sine part</li>
  93.      *  <li>f[2]: North correction, longitude cosine part</li>
  94.      *  <li>f[3]: North correction, longitude sine part</li>
  95.      *  <li>f[4]: East correction, longitude cosine part</li>
  96.      *  <li>f[5]: East correction, longitude sine part</li>
  97.      * </ul>
  98.      */
  99.     private final CompiledSeries frequencyCorrectionDiurnal;

  100.     /** Function computing corrections in the frequency domain for zonal tides.
  101.      * <ul>
  102.      *  <li>f[0]: radial correction</li>
  103.      *  <li>f[1]: North correction, longitude cosine part</li>
  104.      * </ul>
  105.      */
  106.     private final CompiledSeries frequencyCorrectionZonal;

  107.     /** Simple constructor.
  108.      * @param rEarth Earth equatorial radius (from gravity field model)
  109.      * @param sunEarthSystemMassRatio Sun/(Earth + Moon) mass ratio
  110.      * (typically {@link org.orekit.utils.Constants#JPL_SSD_SUN_EARTH_PLUS_MOON_MASS_RATIO Constants.JPL_SSD_SUN_EARTH_PLUS_MOON_MASS_RATIO})
  111.      * @param earthMoonMassRatio Earth/Moon mass ratio
  112.      * (typically {@link org.orekit.utils.Constants#JPL_SSD_EARTH_MOON_MASS_RATIO Constants.JPL_SSD_EARTH_MOON_MASS_RATIO})
  113.      * @param sun Sun model
  114.      * @param moon Moon model
  115.      * @param conventions IERS conventions to use
  116.      * @param removePermanentDeformation if true, the station coordinates are
  117.      * considered <em>mean tide</em> and already include the permanent deformation, hence
  118.      * it should be removed from the displacement to avoid considering it twice;
  119.      * if false, the station coordinates are considered <em>conventional tide free</em>
  120.      * so the permanent deformation must be included in the displacement
  121.      * @see org.orekit.frames.FramesFactory#getITRF(IERSConventions, boolean)
  122.      * @see org.orekit.frames.FramesFactory#getEOPHistory(IERSConventions, boolean)
  123.      * @see org.orekit.utils.Constants#JPL_SSD_SUN_EARTH_PLUS_MOON_MASS_RATIO
  124.      * @see org.orekit.utils.Constants#JPL_SSD_EARTH_MOON_MASS_RATIO
  125.      * @exception OrekitException if fundamental nutation arguments cannot be loaded
  126.      */
  127.     public TidalDisplacement(final double rEarth,
  128.                              final double sunEarthSystemMassRatio,
  129.                              final double earthMoonMassRatio,
  130.                              final PVCoordinatesProvider sun, final PVCoordinatesProvider moon,
  131.                              final IERSConventions conventions,
  132.                              final boolean removePermanentDeformation)
  133.         throws OrekitException {

  134.         final double sunEarthMassRatio = sunEarthSystemMassRatio * (1 + 1 / earthMoonMassRatio);
  135.         final double moonEarthMassRatio = 1.0 / earthMoonMassRatio;

  136.         this.sun                         = sun;
  137.         this.moon                        = moon;
  138.         this.removePermanentDeformation = removePermanentDeformation;

  139.         final double r2 = rEarth * rEarth;
  140.         final double r4 = r2 * r2;
  141.         this.ratio2S    = r4 * sunEarthMassRatio;
  142.         this.ratio3S    = ratio2S * rEarth;
  143.         this.ratio2M    = r4 * moonEarthMassRatio;
  144.         this.ratio3M    = ratio2M * rEarth;

  145.         // Get the nominal values for the Love and Shiva numbers
  146.         final double[] hl = conventions.getNominalTidalDisplacement();
  147.         hSup0            = hl[ 0];
  148.         hSup2            = hl[ 1];
  149.         h3               = hl[ 2];
  150.         hIDiurnal        = hl[ 3];
  151.         hISemiDiurnal    = hl[ 4];
  152.         lSup0            = hl[ 5];
  153.         lSup1Diurnal     = hl[ 6];
  154.         lSup1SemiDiurnal = hl[ 7];
  155.         lSup2            = hl[ 8];
  156.         l3               = hl[ 9];
  157.         lIDiurnal        = hl[10];
  158.         lISemiDiurnal    = hl[11];
  159.         h0Permanent      = hl[12];

  160.         this.frequencyCorrectionDiurnal = conventions.getTidalDisplacementFrequencyCorrectionDiurnal();
  161.         this.frequencyCorrectionZonal   = conventions.getTidalDisplacementFrequencyCorrectionZonal();

  162.     }

  163.     /** {@inheritDoc} */
  164.     @Override
  165.     public Vector3D displacement(final BodiesElements elements, final Frame earthFrame, final Vector3D referencePoint)
  166.         throws OrekitException {

  167.         final AbsoluteDate date = elements.getDate();

  168.         // preliminary computation (we hold everything in local variables so method is thread-safe)
  169.         final PointData      pointData    = new PointData(referencePoint);
  170.         final Vector3D       sunPosition  = sun.getPVCoordinates(date, earthFrame).getPosition();
  171.         final BodyData       sunData      = new BodyData(sunPosition, ratio2S, ratio3S, pointData);
  172.         final Vector3D       moonPosition = moon.getPVCoordinates(date, earthFrame).getPosition();
  173.         final BodyData       moonData     = new BodyData(moonPosition, ratio2M, ratio3M, pointData);

  174.         // step 1 in IERS procedure: corrections in the time domain
  175.         Vector3D displacement = timeDomainCorrection(pointData, sunData, moonData);

  176.         // step 2 in IERS procedure: corrections in the frequency domain
  177.         displacement = displacement.add(frequencyDomainCorrection(elements, pointData));

  178.         if (removePermanentDeformation) {
  179.             // the station coordinates already include permanent deformation,
  180.             // so it should not be included in the displacement that will be
  181.             // added to these coordinates to avoid considering this deformation twice
  182.             // as step 1 did include permanent deformation, we remove it here
  183.             displacement = displacement.subtract(permanentDeformation(pointData));
  184.         }

  185.         return displacement;

  186.     }

  187.     /** Compute the corrections in the time domain (step 1 in IERS procedure).
  188.      * @param pointData reference point data
  189.      * @param sunData Sun data
  190.      * @param moonData Moon data
  191.      * @return displacement of the reference point
  192.      * @exception OrekitException if Sun or Moon position cannot be retrieved in Earth frame
  193.      */
  194.     private Vector3D timeDomainCorrection(final PointData pointData,
  195.                                           final BodyData sunData, final BodyData moonData)
  196.         throws OrekitException {

  197.         final double h2  = hSup0 + hSup2 * pointData.f;
  198.         final double l2  = lSup0 + lSup2 * pointData.f;

  199.         // in-phase, degree 2 (equation 7.5 in IERS conventions 2010)
  200.         final double s2R = sunData.factor2  * 3.0 * l2 * sunData.dot;
  201.         final double s2r = sunData.factor2  * 0.5 * h2 * (3 * sunData.dot2 - 1) - s2R * sunData.dot;
  202.         final double m2R = moonData.factor2 * 3.0 * l2 * moonData.dot;
  203.         final double m2r = moonData.factor2 * 0.5 * h2 * (3 * moonData.dot2 - 1) - m2R * moonData.dot;

  204.         // in-phase, degree 3 (equation 7.6 in IERS conventions 2010)
  205.         final double s3R = sunData.factor3  * l3 * (7.5 * sunData.dot2 - 1.5);
  206.         final double s3r = sunData.factor3  * h3 * sunData.dot * (2.5 * sunData.dot2 - 1.5) - s3R * sunData.dot;
  207.         final double m3R = moonData.factor3 * l3 * (7.5 * moonData.dot2 - 1.5);
  208.         final double m3r = moonData.factor3 * h3 * moonData.dot * (2.5 * moonData.dot2 - 1.5) - m3R * moonData.dot;

  209.         // combine contributions along radial, Sun and Moon directions
  210.         final Vector3D inPhaseDisplacement = new Vector3D(s2r + m2r + s3r + m3r,    pointData.radial,
  211.                                                           (s2R + s3R) / sunData.r,  sunData.position,
  212.                                                           (m2R + m3R) / moonData.r, moonData.position);

  213.         // out-of-phase, degree 2, diurnal tides (equations 7.10a and 7.10b in IERS conventions 2010)
  214.         final double drOd = -0.75 * hIDiurnal * pointData.sin2Phi *
  215.                             (sunData.factor2  * sunData.sin2Phi  * sunData.sinDeltaLambda +
  216.                              moonData.factor2 * moonData.sin2Phi * moonData.sinDeltaLambda);
  217.         final double dnOd = -1.5 * lIDiurnal * pointData.cos2Phi *
  218.                             (sunData.factor2  * sunData.sin2Phi  * sunData.sinDeltaLambda +
  219.                              moonData.factor2 * moonData.sin2Phi * moonData.sinDeltaLambda);
  220.         final double deOd = -1.5 * lIDiurnal * pointData.sinPhi *
  221.                             (sunData.factor2  * sunData.sin2Phi  * sunData.cosDeltaLambda +
  222.                              moonData.factor2 * moonData.sin2Phi * moonData.cosDeltaLambda);

  223.         // out-of-phase, degree 2, semi-diurnal tides (equation 7.11 in IERS conventions 2010)
  224.         final double drOsd = -0.75 * hISemiDiurnal * pointData.cosPhi2 *
  225.                              (sunData.factor2  * sunData.cosPhi2  * sunData.sin2DeltaLambda +
  226.                               moonData.factor2 * moonData.cosPhi2 * moonData.sin2DeltaLambda);
  227.         final double dnOsd = 0.75 * lISemiDiurnal * pointData.sin2Phi *
  228.                              (sunData.factor2  * sunData.cosPhi2  * sunData.sin2DeltaLambda +
  229.                               moonData.factor2 * moonData.cosPhi2 * moonData.sin2DeltaLambda);
  230.         final double deOsd = -1.5 * lISemiDiurnal * pointData.cosPhi *
  231.                              (sunData.factor2  * sunData.cosPhi2  * sunData.cos2DeltaLambda +
  232.                               moonData.factor2 * moonData.cosPhi2 * moonData.cos2DeltaLambda);

  233.         // latitude dependency, diurnal tides (equation 7.8 in IERS conventions 2010)
  234.         final double dnLd = -lSup1Diurnal * pointData.sinPhi2 *
  235.                             (sunData.factor2  * sunData.p21  * sunData.cosDeltaLambda +
  236.                              moonData.factor2 * moonData.p21 * moonData.cosDeltaLambda);
  237.         final double deLd =  lSup1Diurnal * pointData.sinPhi * pointData.cos2Phi *
  238.                             (sunData.factor2  * sunData.p21  * sunData.sinDeltaLambda +
  239.                              moonData.factor2 * moonData.p21 * moonData.sinDeltaLambda);

  240.         // latitude dependency, semi-diurnal tides (equation 7.9 in IERS conventions 2010)
  241.         final double dnLsd = -0.25 * lSup1SemiDiurnal * pointData.sin2Phi *
  242.                              (sunData.factor2  * sunData.p22  * sunData.cos2DeltaLambda +
  243.                               moonData.factor2 * moonData.p22 * moonData.cos2DeltaLambda);
  244.         final double deLsd = -0.25 * lSup1SemiDiurnal * pointData.sin2Phi * pointData.sinPhi *
  245.                              (sunData.factor2  * sunData.p22  * sunData.sin2DeltaLambda +
  246.                               moonData.factor2 * moonData.p22 * moonData.sin2DeltaLambda);

  247.         // combine diurnal and semi-diurnal tides
  248.         final Vector3D outOfPhaseDisplacement = new Vector3D(drOd + drOsd,                pointData.radial,
  249.                                                              dnOd + dnOsd + dnLd + dnLsd, pointData.north,
  250.                                                              deOd + deOsd + deLd + deLsd, pointData.east);

  251.         return inPhaseDisplacement.add(outOfPhaseDisplacement);

  252.     }

  253.     /** Compute the corrections in the frequency domain (step 2 in IERS procedure).
  254.      * @param elements elements affecting Earth orientation
  255.      * @param pointData reference point data
  256.      * @return displacement of the reference point
  257.      */
  258.     private Vector3D frequencyDomainCorrection(final BodiesElements elements, final PointData pointData) {

  259.         // corrections due to diurnal tides
  260.         final double[] cD  = frequencyCorrectionDiurnal.value(elements);
  261.         final double   drD = pointData.sin2Phi * (cD[0] * pointData.cosLambda + cD[1] * pointData.sinLambda);
  262.         final double   dnD = pointData.cos2Phi * (cD[2] * pointData.cosLambda + cD[3] * pointData.sinLambda);
  263.         final double   deD = pointData.sinPhi  * (cD[4] * pointData.cosLambda + cD[5] * pointData.sinLambda);

  264.         // corrections due to zonal long period tides
  265.         final double[] cZ  = frequencyCorrectionZonal.value(elements);
  266.         final double   drZ = (1.5 * pointData.sinPhi2 - 0.5) * cZ[0];
  267.         final double   dnZ = pointData.sin2Phi               * cZ[1];

  268.         return new Vector3D(drD + drZ, pointData.radial,
  269.                             dnD + dnZ, pointData.north,
  270.                             deD,       pointData.east);

  271.     }

  272.     /** Compute the permanent part of the deformation.
  273.      * @param pointData reference point data
  274.      * @return displacement of the reference point
  275.      */
  276.     private Vector3D permanentDeformation(final PointData pointData) {

  277.         final double h2  = hSup0 + hSup2 * pointData.f;
  278.         final double l2  = lSup0 + lSup2 * pointData.f;

  279.         // permanent deformation, which depend only on latitude
  280.         final double factor = FastMath.sqrt(1.25 / FastMath.PI);
  281.         final double dr = factor *       h2 * h0Permanent * pointData.f;
  282.         final double dn = factor * 1.5 * l2 * h0Permanent * pointData.sin2Phi;

  283.         return new Vector3D(dr, pointData.radial,
  284.                             dn, pointData.north);

  285.     }

  286.     /** Holder for various intermediate data related to reference point. */
  287.     private static class PointData {

  288.         /** Reference point position in {@link #getEarthFrame() Earth frame}. */
  289.         private final Vector3D position;

  290.         /** Distance to geocenter. */
  291.         private final double   r;

  292.         /** Sine of geocentric latitude (NOT geodetic latitude). */
  293.         private final double   sinPhi;

  294.         /** Cosine of geocentric latitude (NOT geodetic latitude). */
  295.         private final double   cosPhi;

  296.         /** Square of the sine of the geocentric latitude (NOT geodetic latitude). */
  297.         private final double   sinPhi2;

  298.         /** Square of the cosine of the geocentric latitude (NOT geodetic latitude). */
  299.         private final double   cosPhi2;

  300.         /** Sine of twice the geocentric latitude (NOT geodetic latitude). */
  301.         private final double   sin2Phi;

  302.         /** Cosine of twice the geocentric latitude (NOT geodetic latitude). */
  303.         private final double   cos2Phi;

  304.         /** Sine of longitude. */
  305.         private final double   sinLambda;

  306.         /** Cosine of longitude. */
  307.         private final double   cosLambda;

  308.         /** Unit radial vector (NOT zenith as it starts from geocenter). */
  309.         private final Vector3D radial;

  310.         /** Unit vector in North direction. */
  311.         private final Vector3D north;

  312.         /** Unit vector in East direction. */
  313.         private final Vector3D east;

  314.         /** (3 sin²φ - 1) / 2 where φ is geoCENTRIC latitude of the reference point (NOT geodetic latitude). */
  315.         private final double f;

  316.         /** Simple constructor.
  317.          * @param position reference point position in {@link #getEarthFrame() Earth frame}
  318.          */
  319.         PointData(final Vector3D position) {

  320.             this.position   = position;
  321.             final double x  = position.getX();
  322.             final double y  = position.getY();
  323.             final double z  = position.getZ();
  324.             final double x2 = x * x;
  325.             final double y2 = y * y;
  326.             final double z2 = z * z;

  327.             // preliminary computation related to station position
  328.             final double rho2 = x2 + y2;
  329.             final double rho  = FastMath.sqrt(rho2);
  330.             final double r2   = rho2 + z2;
  331.             r                 = FastMath.sqrt(r2);
  332.             sinPhi            = z / r;
  333.             cosPhi            = rho / r;
  334.             sinPhi2           = sinPhi * sinPhi;
  335.             cosPhi2           = cosPhi * cosPhi;
  336.             sin2Phi           = 2 * sinPhi * cosPhi;
  337.             cos2Phi           = cosPhi2 - sinPhi2;
  338.             if (rho == 0.0) {
  339.                 // at pole
  340.                 sinLambda = 0.0;
  341.                 cosLambda = 1.0;
  342.             } else {
  343.                 // regular point
  344.                 sinLambda = y / rho;
  345.                 cosLambda = x / rho;
  346.             }
  347.             radial = new Vector3D(x / r, y / r, sinPhi);
  348.             north  = new Vector3D(-cosLambda * sinPhi, -sinLambda * sinPhi, cosPhi);
  349.             east   = new Vector3D(-sinLambda, cosLambda, 0);

  350.             // (3 sin²φ - 1) / 2 where φ is geoCENTRIC latitude of the reference point (NOT geodetic latitude)
  351.             f = (z2 - 0.5 * rho2) / r2;

  352.         }

  353.     }

  354.     /** Holder for various intermediate data related to tide generating body. */
  355.     private static class BodyData {

  356.         /** Body position in Earth frame. */
  357.         private final Vector3D position;

  358.         /** Distance to geocenter. */
  359.         private final double r;

  360.         /** Dot product with reference point direction. */
  361.         private final double dot;

  362.         /** Squared dot product with reference point direction. */
  363.         private final double dot2;

  364.         /** Factor for degree 2 tide. */
  365.         private final double factor2;

  366.         /** Factor for degree 3 tide. */
  367.         private final double factor3;

  368.         /** Square of the cosine of the geocentric latitude (NOT geodetic latitude). */
  369.         private final double   cosPhi2;

  370.         /** Sine of twice the geocentric latitude (NOT geodetic latitude). */
  371.         private final double   sin2Phi;

  372.         /** Legendre function P₂¹. */
  373.         private final double p21;

  374.         /** Legendre function P₂². */
  375.         private final double p22;

  376.         /** Sine of the longitude difference with reference point. */
  377.         private final double sinDeltaLambda;

  378.         /** Cosine of the longitude difference with reference point. */
  379.         private final double cosDeltaLambda;

  380.         /** Sine of twice the longitude difference with reference point. */
  381.         private final double sin2DeltaLambda;

  382.         /** Cosine of twice the longitude difference with reference point. */
  383.         private final double cos2DeltaLambda;

  384.         /** Simple constructor.
  385.          * @param position body position in Earth frame
  386.          * @param ratio2 ratio for the degree 2 tide generated by this body
  387.          * @param ratio3 ratio for the degree 3 tide generated by this body
  388.          * @param pointData reference point data
  389.          */
  390.         BodyData(final Vector3D position, final double ratio2, final double ratio3,
  391.                  final PointData pointData) {

  392.             final double x  = position.getX();
  393.             final double y  = position.getY();
  394.             final double z  = position.getZ();
  395.             final double x2 = x * x;
  396.             final double y2 = y * y;
  397.             final double z2 = z * z;

  398.             this.position    = position;
  399.             final double r2  = x2 + y2 + z2;
  400.             r                = FastMath.sqrt(r2);
  401.             dot              = Vector3D.dotProduct(position, pointData.position) / (r * pointData.r);
  402.             dot2             = dot * dot;

  403.             factor2          = ratio2 / (r2 * r);
  404.             factor3          = ratio3 / (r2 * r2);

  405.             final double rho       = FastMath.sqrt(x2 + y2);
  406.             final double sinPhi    = z / r;
  407.             final double cosPhi    = rho / r;
  408.             final double sinCos    = sinPhi * cosPhi;
  409.             cosPhi2                = cosPhi * cosPhi;
  410.             sin2Phi                = 2 * sinCos;
  411.             p21                    = 3 * sinCos;
  412.             p22                    = 3 * cosPhi2;

  413.             final double sinLambda = y / rho;
  414.             final double cosLambda = x / rho;
  415.             sinDeltaLambda  = pointData.sinLambda * cosLambda  - pointData.cosLambda * sinLambda;
  416.             cosDeltaLambda  = pointData.cosLambda * cosLambda  + pointData.sinLambda * sinLambda;
  417.             sin2DeltaLambda = 2 * sinDeltaLambda * cosDeltaLambda;
  418.             cos2DeltaLambda = cosDeltaLambda * cosDeltaLambda - sinDeltaLambda * sinDeltaLambda;

  419.         }

  420.     }

  421. }