text: /*global define*/
  define([
          '../ThirdParty/when',
          './Cartesian2',
          './Cartesian3',
          './Cartesian4',
          './Cartographic',
          './Check',
          './defaultValue',
          './defined',
          './deprecationWarning',
          './DeveloperError',
          './EarthOrientationParameters',
          './EarthOrientationParametersSample',
          './Ellipsoid',
          './Iau2006XysData',
          './Iau2006XysSample',
          './JulianDate',
          './Math',
          './Matrix3',
          './Matrix4',
          './Quaternion',
          './TimeConstants'
      ], function(
          when,
          Cartesian2,
          Cartesian3,
          Cartesian4,
          Cartographic,
          Check,
          defaultValue,
          defined,
          deprecationWarning,
          DeveloperError,
          EarthOrientationParameters,
          EarthOrientationParametersSample,
          Ellipsoid,
          Iau2006XysData,
          Iau2006XysSample,
          JulianDate,
          CesiumMath,
          Matrix3,
          Matrix4,
          Quaternion,
          TimeConstants) {
      'use strict';
  
      /**
       * Contains functions for transforming positions to various reference frames.
       *
       * @exports Transforms
       */
      var Transforms = {};
  
      var vectorProductLocalFrame = {
          up : {
              south : 'east',
              north : 'west',
              west : 'south',
              east : 'north'
          },
          down : {
              south : 'west',
              north : 'east',
              west : 'north',
              east : 'south'
          },
          south : {
              up : 'west',
              down : 'east',
              west : 'down',
              east : 'up'
          },
          north : {
              up : 'east',
              down : 'west',
              west : 'up',
              east : 'down'
          },
          west : {
              up : 'north',
              down : 'south',
              north : 'down',
              south : 'up'
          },
          east : {
              up : 'south',
              down : 'north',
              north : 'up',
              south : 'down'
          }
      };
  
      var degeneratePositionLocalFrame = {
          north : [-1, 0, 0],
          east : [0, 1, 0],
          up : [0, 0, 1],
          south : [1, 0, 0],
          west : [0, -1, 0],
          down : [0, 0, -1]
      };
  
      var localFrameToFixedFrameCache = {};
  
      var scratchCalculateCartesian = {
          east : new Cartesian3(),
          north : new Cartesian3(),
          up : new Cartesian3(),
          west : new Cartesian3(),
          south : new Cartesian3(),
          down : new Cartesian3()
      };
      var scratchFirstCartesian = new Cartesian3();
      var scratchSecondCartesian = new Cartesian3();
      var scratchThirdCartesian = new Cartesian3();
      /**
      * Generates a function that computes a 4x4 transformation matrix from a reference frame
      * centered at the provided origin to the provided ellipsoid's fixed reference frame.
      * @param  {String} firstAxis  name of the first axis of the local reference frame. Must be
      *  'east', 'north', 'up', 'west', 'south' or 'down'.
      * @param  {String} secondAxis  name of the second axis of the local reference frame. Must be
      *  'east', 'north', 'up', 'west', 'south' or 'down'.
      * @return {localFrameToFixedFrameGenerator~resultat} The function that will computes a
      * 4x4 transformation matrix from a reference frame, with first axis and second axis compliant with the parameters,
      */
      Transforms.localFrameToFixedFrameGenerator = function( firstAxis, secondAxis) {
        if (!vectorProductLocalFrame.hasOwnProperty(firstAxis) || !vectorProductLocalFrame[firstAxis].hasOwnProperty(secondAxis)) {
            throw new DeveloperError('firstAxis and secondAxis must be east, north, up, west, south or down.');
        }
        var thirdAxis = vectorProductLocalFrame[firstAxis][secondAxis];
  
        /**
         * Computes a 4x4 transformation matrix from a reference frame
         * centered at the provided origin to the provided ellipsoid's fixed reference frame.
         * @callback Transforms~LocalFrameToFixedFrame
         * @param {Cartesian3} origin The center point of the local reference frame.
         * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid whose fixed frame is used in the transformation.
         * @param {Matrix4} [result] The object onto which to store the result.
         * @returns {Matrix4} The modified result parameter or a new Matrix4 instance if none was provided.
         */
        var resultat;
        var hashAxis = firstAxis + secondAxis;
        if (defined(localFrameToFixedFrameCache[hashAxis])) {
            resultat = localFrameToFixedFrameCache[hashAxis];
        } else {
            resultat = function(origin, ellipsoid, result) {
                //>>includeStart('debug', pragmas.debug);
                if (!defined(origin)) {
                    throw new DeveloperError('origin is required.');
                }
                //>>includeEnd('debug');
                if (!defined(result)) {
                    result = new Matrix4();
                }
                // If x and y are zero, assume origin is at a pole, which is a special case.
                if (CesiumMath.equalsEpsilon(origin.x, 0.0, CesiumMath.EPSILON14) && CesiumMath.equalsEpsilon(origin.y, 0.0, CesiumMath.EPSILON14)) {
                    var sign = CesiumMath.sign(origin.z);
  
                    Cartesian3.unpack(degeneratePositionLocalFrame[firstAxis], 0, scratchFirstCartesian);
                    if (firstAxis !== 'east' && firstAxis !== 'west') {
                        Cartesian3.multiplyByScalar(scratchFirstCartesian, sign, scratchFirstCartesian);
                    }
  
                    Cartesian3.unpack(degeneratePositionLocalFrame[secondAxis], 0, scratchSecondCartesian);
                    if (secondAxis !== 'east' && secondAxis !== 'west') {
                        Cartesian3.multiplyByScalar(scratchSecondCartesian, sign, scratchSecondCartesian);
                    }
  
                    Cartesian3.unpack(degeneratePositionLocalFrame[thirdAxis], 0, scratchThirdCartesian);
                    if (thirdAxis !== 'east' && thirdAxis !== 'west') {
                        Cartesian3.multiplyByScalar(scratchThirdCartesian, sign, scratchThirdCartesian);
                    }
                } else {
                    ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
                    ellipsoid.geodeticSurfaceNormal(origin, scratchCalculateCartesian.up);
  
                    var up = scratchCalculateCartesian.up;
                    var east = scratchCalculateCartesian.east;
                    east.x = -origin.y;
                    east.y = origin.x;
                    east.z = 0.0;
                    Cartesian3.normalize(east, scratchCalculateCartesian.east);
                    Cartesian3.cross(up, east, scratchCalculateCartesian.north);
  
                    Cartesian3.multiplyByScalar(scratchCalculateCartesian.up, -1, scratchCalculateCartesian.down);
                    Cartesian3.multiplyByScalar(scratchCalculateCartesian.east, -1, scratchCalculateCartesian.west);
                    Cartesian3.multiplyByScalar(scratchCalculateCartesian.north, -1, scratchCalculateCartesian.south);
  
                    scratchFirstCartesian = scratchCalculateCartesian[firstAxis];
                    scratchSecondCartesian = scratchCalculateCartesian[secondAxis];
                    scratchThirdCartesian = scratchCalculateCartesian[thirdAxis];
                }
                result[0] = scratchFirstCartesian.x;
                result[1] = scratchFirstCartesian.y;
                result[2] = scratchFirstCartesian.z;
                result[3] = 0.0;
                result[4] = scratchSecondCartesian.x;
                result[5] = scratchSecondCartesian.y;
                result[6] = scratchSecondCartesian.z;
                result[7] = 0.0;
                result[8] = scratchThirdCartesian.x;
                result[9] = scratchThirdCartesian.y;
                result[10] = scratchThirdCartesian.z;
                result[11] = 0.0;
                result[12] = origin.x;
                result[13] = origin.y;
                result[14] = origin.z;
                result[15] = 1.0;
                return result;
            };
            localFrameToFixedFrameCache[hashAxis] = resultat;
        }
        return resultat;
      };
  
      /**
       * Computes a 4x4 transformation matrix from a reference frame with an east-north-up axes
       * centered at the provided origin to the provided ellipsoid's fixed reference frame.
       * The local axes are defined as:
       * <ul>
       * <li>The <code>x</code> axis points in the local east direction.</li>
       * <li>The <code>y</code> axis points in the local north direction.</li>
       * <li>The <code>z</code> axis points in the direction of the ellipsoid surface normal which passes through the position.</li>
       * </ul>
       *
       * @param {Cartesian3} origin The center point of the local reference frame.
       * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid whose fixed frame is used in the transformation.
       * @param {Matrix4} [result] The object onto which to store the result.
       * @returns {Matrix4} The modified result parameter or a new Matrix4 instance if none was provided.
       *
       * @example
       * // Get the transform from local east-north-up at cartographic (0.0, 0.0) to Earth's fixed frame.
       * var center = Cesium.Cartesian3.fromDegrees(0.0, 0.0);
       * var transform = Cesium.Transforms.eastNorthUpToFixedFrame(center);
       */
      Transforms.eastNorthUpToFixedFrame = Transforms.localFrameToFixedFrameGenerator('east','north');
  
      /**
       * Computes a 4x4 transformation matrix from a reference frame with an north-east-down axes
       * centered at the provided origin to the provided ellipsoid's fixed reference frame.
       * The local axes are defined as:
       * <ul>
       * <li>The <code>x</code> axis points in the local north direction.</li>
       * <li>The <code>y</code> axis points in the local east direction.</li>
       * <li>The <code>z</code> axis points in the opposite direction of the ellipsoid surface normal which passes through the position.</li>
       * </ul>
       *
       * @param {Cartesian3} origin The center point of the local reference frame.
       * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid whose fixed frame is used in the transformation.
       * @param {Matrix4} [result] The object onto which to store the result.
       * @returns {Matrix4} The modified result parameter or a new Matrix4 instance if none was provided.
       *
       * @example
       * // Get the transform from local north-east-down at cartographic (0.0, 0.0) to Earth's fixed frame.
       * var center = Cesium.Cartesian3.fromDegrees(0.0, 0.0);
       * var transform = Cesium.Transforms.northEastDownToFixedFrame(center);
       */
      Transforms.northEastDownToFixedFrame = Transforms.localFrameToFixedFrameGenerator('north','east');
  
      /**
       * Computes a 4x4 transformation matrix from a reference frame with an north-up-east axes
       * centered at the provided origin to the provided ellipsoid's fixed reference frame.
       * The local axes are defined as:
       * <ul>
       * <li>The <code>x</code> axis points in the local north direction.</li>
       * <li>The <code>y</code> axis points in the direction of the ellipsoid surface normal which passes through the position.</li>
       * <li>The <code>z</code> axis points in the local east direction.</li>
       * </ul>
       *
       * @param {Cartesian3} origin The center point of the local reference frame.
       * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid whose fixed frame is used in the transformation.
       * @param {Matrix4} [result] The object onto which to store the result.
       * @returns {Matrix4} The modified result parameter or a new Matrix4 instance if none was provided.
       *
       * @example
       * // Get the transform from local north-up-east at cartographic (0.0, 0.0) to Earth's fixed frame.
       * var center = Cesium.Cartesian3.fromDegrees(0.0, 0.0);
       * var transform = Cesium.Transforms.northUpEastToFixedFrame(center);
       */
      Transforms.northUpEastToFixedFrame = Transforms.localFrameToFixedFrameGenerator('north','up');
  
      /**
      * Computes a 4x4 transformation matrix from a reference frame with an north-west-up axes
      * centered at the provided origin to the provided ellipsoid's fixed reference frame.
      * The local axes are defined as:
      * <ul>
      * <li>The <code>x</code> axis points in the local north direction.</li>
      * <li>The <code>y</code> axis points in the local west direction.</li>
      * <li>The <code>z</code> axis points in the direction of the ellipsoid surface normal which passes through the position.</li>
      * </ul>
      *
      * @param {Cartesian3} origin The center point of the local reference frame.
      * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid whose fixed frame is used in the transformation.
      * @param {Matrix4} [result] The object onto which to store the result.
      * @returns {Matrix4} The modified result parameter or a new Matrix4 instance if none was provided.
      *
      * @example
      * // Get the transform from local north-West-Up at cartographic (0.0, 0.0) to Earth's fixed frame.
      * var center = Cesium.Cartesian3.fromDegrees(0.0, 0.0);
      * var transform = Cesium.Transforms.northWestUpToFixedFrame(center);
      */
     Transforms.northWestUpToFixedFrame = Transforms.localFrameToFixedFrameGenerator('north','west');
  
      var scratchHPRQuaternion = new Quaternion();
      var scratchScale = new Cartesian3(1.0, 1.0, 1.0);
      var scratchHPRMatrix4 = new Matrix4();
  
      /**
       * Computes a 4x4 transformation matrix from a reference frame with axes computed from the heading-pitch-roll angles
       * centered at the provided origin to the provided ellipsoid's fixed reference frame. Heading is the rotation from the local north
       * direction where a positive angle is increasing eastward. Pitch is the rotation from the local east-north plane. Positive pitch angles
       * are above the plane. Negative pitch angles are below the plane. Roll is the first rotation applied about the local east axis.
       *
       * @param {Cartesian3} origin The center point of the local reference frame.
       * @param {HeadingPitchRoll} headingPitchRoll The heading, pitch, and roll.
       * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid whose fixed frame is used in the transformation.
       * @param {Transforms~LocalFrameToFixedFrame} [fixedFrameTransformOrResult=Transforms.eastNorthUpToFixedFrame] A 4x4 transformation
       *  matrix from a reference frame to the provided ellipsoid's fixed reference frame
       * @param {Matrix4} [result] The object onto which to store the result.
       * @returns {Matrix4} The modified result parameter or a new Matrix4 instance if none was provided.
       *
       * @example
       * // Get the transform from local heading-pitch-roll at cartographic (0.0, 0.0) to Earth's fixed frame.
       * var center = Cesium.Cartesian3.fromDegrees(0.0, 0.0);
       * var heading = -Cesium.Math.PI_OVER_TWO;
       * var pitch = Cesium.Math.PI_OVER_FOUR;
       * var roll = 0.0;
       * var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
       * var transform = Cesium.Transforms.headingPitchRollToFixedFrame(center, hpr);
       */
      Transforms.headingPitchRollToFixedFrame = function(origin, headingPitchRoll, ellipsoid, fixedFrameTransformOrResult, result) {
          //>>includeStart('debug', pragmas.debug);
          Check.typeOf.object( 'HeadingPitchRoll', headingPitchRoll);
          //>>includeEnd('debug');
  
          // checks for required parameters happen in the called functions
          if(fixedFrameTransformOrResult instanceof Matrix4){
              result = fixedFrameTransformOrResult;
              fixedFrameTransformOrResult = undefined;
              deprecationWarning('Transforms.headingPitchRollToFixedFrame(origin, headingPitchRoll, ellipsoid, result)', 'The method was deprecated in Cesium 1.31 and will be removed in version 1.33. Transforms.headingPitchRollToFixedFrame(origin, headingPitchRoll, ellipsoid, fixedFrameTransform, result) where fixedFrameTransform is a a 4x4 transformation matrix (see Transforms.localFrameToFixedFrameGenerator)');
          }
          fixedFrameTransformOrResult = defaultValue(fixedFrameTransformOrResult,Transforms.eastNorthUpToFixedFrame);
          var hprQuaternion = Quaternion.fromHeadingPitchRoll(headingPitchRoll, scratchHPRQuaternion);
          var hprMatrix = Matrix4.fromTranslationQuaternionRotationScale(Cartesian3.ZERO, hprQuaternion, scratchScale, scratchHPRMatrix4);
          result = fixedFrameTransformOrResult(origin, ellipsoid, result);
          return Matrix4.multiply(result, hprMatrix, result);
      };
  
      var scratchENUMatrix4 = new Matrix4();
      var scratchHPRMatrix3 = new Matrix3();
  
      /**
       * Computes a quaternion from a reference frame with axes computed from the heading-pitch-roll angles
       * centered at the provided origin. Heading is the rotation from the local north
       * direction where a positive angle is increasing eastward. Pitch is the rotation from the local east-north plane. Positive pitch angles
       * are above the plane. Negative pitch angles are below the plane. Roll is the first rotation applied about the local east axis.
       *
       * @param {Cartesian3} origin The center point of the local reference frame.
       * @param {HeadingPitchRoll} headingPitchRoll The heading, pitch, and roll.
       * @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid whose fixed frame is used in the transformation.
       * @param {Transforms~LocalFrameToFixedFrame} [fixedFrameTransformOrResult=Transforms.eastNorthUpToFixedFrame] A 4x4 transformation
       *  matrix from a reference frame to the provided ellipsoid's fixed reference frame
       * @param {Quaternion} [result] The object onto which to store the result.
       * @returns {Quaternion} The modified result parameter or a new Quaternion instance if none was provided.
       *
       * @example
       * // Get the quaternion from local heading-pitch-roll at cartographic (0.0, 0.0) to Earth's fixed frame.
       * var center = Cesium.Cartesian3.fromDegrees(0.0, 0.0);
       * var heading = -Cesium.Math.PI_OVER_TWO;
       * var pitch = Cesium.Math.PI_OVER_FOUR;
       * var roll = 0.0;
       * var hpr = new HeadingPitchRoll(heading, pitch, roll);
       * var quaternion = Cesium.Transforms.headingPitchRollQuaternion(center, hpr);
       */
      Transforms.headingPitchRollQuaternion = function(origin, headingPitchRoll, ellipsoid, fixedFrameTransformOrResult, result) {
          //>>includeStart('debug', pragmas.debug);
          Check.typeOf.object( 'HeadingPitchRoll', headingPitchRoll);
          //>>includeEnd('debug');
          if (fixedFrameTransformOrResult instanceof Quaternion) {
              result = fixedFrameTransformOrResult;
              fixedFrameTransformOrResult = undefined;
              deprecationWarning('Transforms.headingPitchRollQuaternion(origin, headingPitchRoll, ellipsoid, result)', 'The method was deprecated in Cesium 1.31 and will be removed in version 1.33. Transforms.headingPitchRollQuaternion(origin, headingPitchRoll, ellipsoid, fixedFrameTransform, result) where fixedFrameTransform is a a 4x4 transformation matrix (see Transforms.localFrameToFixedFrameGenerator)');
          }
          var transform = Transforms.headingPitchRollToFixedFrame(origin, headingPitchRoll, ellipsoid,fixedFrameTransformOrResult, scratchENUMatrix4);
          var rotation = Matrix4.getRotation(transform, scratchHPRMatrix3);
          return Quaternion.fromRotationMatrix(rotation, result);
      };
  
      var gmstConstant0 = 6 * 3600 + 41 * 60 + 50.54841;
      var gmstConstant1 = 8640184.812866;
      var gmstConstant2 = 0.093104;
      var gmstConstant3 = -6.2E-6;
      var rateCoef = 1.1772758384668e-19;
      var wgs84WRPrecessing = 7.2921158553E-5;
      var twoPiOverSecondsInDay = CesiumMath.TWO_PI / 86400.0;
      var dateInUtc = new JulianDate();
  
      /**
       * Computes a rotation matrix to transform a point or vector from True Equator Mean Equinox (TEME) axes to the
       * pseudo-fixed axes at a given time.  This method treats the UT1 time standard as equivalent to UTC.
       *
       * @param {JulianDate} date The time at which to compute the rotation matrix.
       * @param {Matrix3} [result] The object onto which to store the result.
       * @returns {Matrix3} The modified result parameter or a new Matrix3 instance if none was provided.
       *
       * @example
       * //Set the view to in the inertial frame.
       * scene.preRender.addEventListener(function(scene, time) {
       *    var now = Cesium.JulianDate.now();
       *    var offset = Cesium.Matrix4.multiplyByPoint(camera.transform, camera.position, new Cesium.Cartesian3());
       *    var transform = Cesium.Matrix4.fromRotationTranslation(Cesium.Transforms.computeTemeToPseudoFixedMatrix(now));
       *    var inverseTransform = Cesium.Matrix4.inverseTransformation(transform, new Cesium.Matrix4());
       *    Cesium.Matrix4.multiplyByPoint(inverseTransform, offset, offset);
       *    camera.lookAtTransform(transform, offset);
       * });
       */
      Transforms.computeTemeToPseudoFixedMatrix = function (date, result) {
          //>>includeStart('debug', pragmas.debug);
          if (!defined(date)) {
              throw new DeveloperError('date is required.');
          }
          //>>includeEnd('debug');
  
          // GMST is actually computed using UT1.  We're using UTC as an approximation of UT1.
          // We do not want to use the function like convertTaiToUtc in JulianDate because
          // we explicitly do not want to fail when inside the leap second.
  
          dateInUtc = JulianDate.addSeconds(date, -JulianDate.computeTaiMinusUtc(date), dateInUtc);
          var utcDayNumber = dateInUtc.dayNumber;
          var utcSecondsIntoDay = dateInUtc.secondsOfDay;
  
          var t;
          var diffDays = utcDayNumber - 2451545;
          if (utcSecondsIntoDay >= 43200.0) {
              t = (diffDays + 0.5) / TimeConstants.DAYS_PER_JULIAN_CENTURY;
          } else {
              t = (diffDays - 0.5) / TimeConstants.DAYS_PER_JULIAN_CENTURY;
          }
  
          var gmst0 = gmstConstant0 + t * (gmstConstant1 + t * (gmstConstant2 + t * gmstConstant3));
          var angle = (gmst0 * twoPiOverSecondsInDay) % CesiumMath.TWO_PI;
          var ratio = wgs84WRPrecessing + rateCoef * (utcDayNumber - 2451545.5);
          var secondsSinceMidnight = (utcSecondsIntoDay + TimeConstants.SECONDS_PER_DAY * 0.5) % TimeConstants.SECONDS_PER_DAY;
          var gha = angle + (ratio * secondsSinceMidnight);
          var cosGha = Math.cos(gha);
          var sinGha = Math.sin(gha);
  
          if (!defined(result)) {
              return new Matrix3(cosGha, sinGha, 0.0,
                                -sinGha, cosGha, 0.0,
                                    0.0,    0.0, 1.0);
          }
          result[0] = cosGha;
          result[1] = -sinGha;
          result[2] = 0.0;
          result[3] = sinGha;
          result[4] = cosGha;
          result[5] = 0.0;
          result[6] = 0.0;
          result[7] = 0.0;
          result[8] = 1.0;
          return result;
      };
  
      /**
       * The source of IAU 2006 XYS data, used for computing the transformation between the
       * Fixed and ICRF axes.
       * @type {Iau2006XysData}
       *
       * @see Transforms.computeIcrfToFixedMatrix
       * @see Transforms.computeFixedToIcrfMatrix
       *
       * @private
       */
      Transforms.iau2006XysData = new Iau2006XysData();
  
      /**
       * The source of Earth Orientation Parameters (EOP) data, used for computing the transformation
       * between the Fixed and ICRF axes.  By default, zero values are used for all EOP values,
       * yielding a reasonable but not completely accurate representation of the ICRF axes.
       * @type {EarthOrientationParameters}
       *
       * @see Transforms.computeIcrfToFixedMatrix
       * @see Transforms.computeFixedToIcrfMatrix
       *
       * @private
       */
      Transforms.earthOrientationParameters = EarthOrientationParameters.NONE;
  
      var ttMinusTai = 32.184;
      var j2000ttDays = 2451545.0;
  
      /**
       * Preloads the data necessary to transform between the ICRF and Fixed axes, in either
       * direction, over a given interval.  This function returns a promise that, when resolved,
       * indicates that the preload has completed.
       *
       * @param {TimeInterval} timeInterval The interval to preload.
       * @returns {Promise.<undefined>} A promise that, when resolved, indicates that the preload has completed
       *          and evaluation of the transformation between the fixed and ICRF axes will
       *          no longer return undefined for a time inside the interval.
       *
       *
       * @example
       * var interval = new Cesium.TimeInterval(...);
       * when(Cesium.Transforms.preloadIcrfFixed(interval), function() {
       *     // the data is now loaded
       * });
       *
       * @see Transforms.computeIcrfToFixedMatrix
       * @see Transforms.computeFixedToIcrfMatrix
       * @see when
       */
      Transforms.preloadIcrfFixed = function(timeInterval) {
          var startDayTT = timeInterval.start.dayNumber;
          var startSecondTT = timeInterval.start.secondsOfDay + ttMinusTai;
          var stopDayTT = timeInterval.stop.dayNumber;
          var stopSecondTT = timeInterval.stop.secondsOfDay + ttMinusTai;
  
          var xysPromise = Transforms.iau2006XysData.preload(startDayTT, startSecondTT, stopDayTT, stopSecondTT);
          var eopPromise = Transforms.earthOrientationParameters.getPromiseToLoad();
  
          return when.all([xysPromise, eopPromise]);
      };
  
      /**
       * Computes a rotation matrix to transform a point or vector from the International Celestial
       * Reference Frame (GCRF/ICRF) inertial frame axes to the Earth-Fixed frame axes (ITRF)
       * at a given time.  This function may return undefined if the data necessary to
       * do the transformation is not yet loaded.
       *
       * @param {JulianDate} date The time at which to compute the rotation matrix.
       * @param {Matrix3} [result] The object onto which to store the result.  If this parameter is
       *                  not specified, a new instance is created and returned.
       * @returns {Matrix3} The rotation matrix, or undefined if the data necessary to do the
       *                   transformation is not yet loaded.
       *
       *
       * @example
       * scene.preRender.addEventListener(function(scene, time) {
       *   var icrfToFixed = Cesium.Transforms.computeIcrfToFixedMatrix(time);
       *   if (Cesium.defined(icrfToFixed)) {
       *     var offset = Cesium.Matrix4.multiplyByPoint(camera.transform, camera.position, new Cesium.Cartesian3());
       *     var transform = Cesium.Matrix4.fromRotationTranslation(icrfToFixed)
       *     var inverseTransform = Cesium.Matrix4.inverseTransformation(transform, new Cesium.Matrix4());
       *     Cesium.Matrix4.multiplyByPoint(inverseTransform, offset, offset);
       *     camera.lookAtTransform(transform, offset);
       *   }
       * });
       *
       * @see Transforms.preloadIcrfFixed
       */
      Transforms.computeIcrfToFixedMatrix = function(date, result) {
          //>>includeStart('debug', pragmas.debug);
          if (!defined(date)) {
              throw new DeveloperError('date is required.');
          }
          //>>includeEnd('debug');
          if (!defined(result)) {
              result = new Matrix3();
          }
  
          var fixedToIcrfMtx = Transforms.computeFixedToIcrfMatrix(date, result);
          if (!defined(fixedToIcrfMtx)) {
              return undefined;
          }
  
          return Matrix3.transpose(fixedToIcrfMtx, result);
      };
  
      var xysScratch = new Iau2006XysSample(0.0, 0.0, 0.0);
      var eopScratch = new EarthOrientationParametersSample(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
      var rotation1Scratch = new Matrix3();
      var rotation2Scratch = new Matrix3();
  
      /**
       * Computes a rotation matrix to transform a point or vector from the Earth-Fixed frame axes (ITRF)
       * to the International Celestial Reference Frame (GCRF/ICRF) inertial frame axes
       * at a given time.  This function may return undefined if the data necessary to
       * do the transformation is not yet loaded.
       *
       * @param {JulianDate} date The time at which to compute the rotation matrix.
       * @param {Matrix3} [result] The object onto which to store the result.  If this parameter is
       *                  not specified, a new instance is created and returned.
       * @returns {Matrix3} The rotation matrix, or undefined if the data necessary to do the
       *                   transformation is not yet loaded.
       *
       *
       * @example
       * // Transform a point from the ICRF axes to the Fixed axes.
       * var now = Cesium.JulianDate.now();
       * var pointInFixed = Cesium.Cartesian3.fromDegrees(0.0, 0.0);
       * var fixedToIcrf = Cesium.Transforms.computeIcrfToFixedMatrix(now);
       * var pointInInertial = new Cesium.Cartesian3();
       * if (Cesium.defined(fixedToIcrf)) {
       *     pointInInertial = Cesium.Matrix3.multiplyByVector(fixedToIcrf, pointInFixed, pointInInertial);
       * }
       *
       * @see Transforms.preloadIcrfFixed
       */
      Transforms.computeFixedToIcrfMatrix = function(date, result) {
          //>>includeStart('debug', pragmas.debug);
          if (!defined(date)) {
              throw new DeveloperError('date is required.');
          }
          //>>includeEnd('debug');
  
          if (!defined(result)) {
              result = new Matrix3();
          }
  
          // Compute pole wander
          var eop = Transforms.earthOrientationParameters.compute(date, eopScratch);
          if (!defined(eop)) {
              return undefined;
          }
  
          // There is no external conversion to Terrestrial Time (TT).
          // So use International Atomic Time (TAI) and convert using offsets.
          // Here we are assuming that dayTT and secondTT are positive
          var dayTT = date.dayNumber;
          // It's possible here that secondTT could roll over 86400
          // This does not seem to affect the precision (unit tests check for this)
          var secondTT = date.secondsOfDay + ttMinusTai;
  
          var xys = Transforms.iau2006XysData.computeXysRadians(dayTT, secondTT, xysScratch);
          if (!defined(xys)) {
              return undefined;
          }
  
          var x = xys.x + eop.xPoleOffset;
          var y = xys.y + eop.yPoleOffset;
  
          // Compute XYS rotation
          var a = 1.0 / (1.0 + Math.sqrt(1.0 - x * x - y * y));
  
          var rotation1 = rotation1Scratch;
          rotation1[0] = 1.0 - a * x * x;
          rotation1[3] = -a * x * y;
          rotation1[6] = x;
          rotation1[1] = -a * x * y;
          rotation1[4] = 1 - a * y * y;
          rotation1[7] = y;
          rotation1[2] = -x;
          rotation1[5] = -y;
          rotation1[8] = 1 - a * (x * x + y * y);
  
          var rotation2 = Matrix3.fromRotationZ(-xys.s, rotation2Scratch);
          var matrixQ = Matrix3.multiply(rotation1, rotation2, rotation1Scratch);
  
          // Similar to TT conversions above
          // It's possible here that secondTT could roll over 86400
          // This does not seem to affect the precision (unit tests check for this)
          var dateUt1day = date.dayNumber;
          var dateUt1sec = date.secondsOfDay - JulianDate.computeTaiMinusUtc(date) + eop.ut1MinusUtc;
  
          // Compute Earth rotation angle
          // The IERS standard for era is
          //    era = 0.7790572732640 + 1.00273781191135448 * Tu
          // where
          //    Tu = JulianDateInUt1 - 2451545.0
          // However, you get much more precision if you make the following simplification
          //    era = a + (1 + b) * (JulianDayNumber + FractionOfDay - 2451545)
          //    era = a + (JulianDayNumber - 2451545) + FractionOfDay + b (JulianDayNumber - 2451545 + FractionOfDay)
          //    era = a + FractionOfDay + b (JulianDayNumber - 2451545 + FractionOfDay)
          // since (JulianDayNumber - 2451545) represents an integer number of revolutions which will be discarded anyway.
          var daysSinceJ2000 = dateUt1day - 2451545;
          var fractionOfDay = dateUt1sec / TimeConstants.SECONDS_PER_DAY;
          var era = 0.7790572732640 + fractionOfDay + 0.00273781191135448 * (daysSinceJ2000 + fractionOfDay);
          era = (era % 1.0) * CesiumMath.TWO_PI;
  
          var earthRotation = Matrix3.fromRotationZ(era, rotation2Scratch);
  
          // pseudoFixed to ICRF
          var pfToIcrf = Matrix3.multiply(matrixQ, earthRotation, rotation1Scratch);
  
          // Compute pole wander matrix
          var cosxp = Math.cos(eop.xPoleWander);
          var cosyp = Math.cos(eop.yPoleWander);
          var sinxp = Math.sin(eop.xPoleWander);
          var sinyp = Math.sin(eop.yPoleWander);
  
          var ttt = (dayTT - j2000ttDays) + secondTT / TimeConstants.SECONDS_PER_DAY;
          ttt /= 36525.0;
  
          // approximate sp value in rad
          var sp = -47.0e-6 * ttt * CesiumMath.RADIANS_PER_DEGREE / 3600.0;
          var cossp = Math.cos(sp);
          var sinsp = Math.sin(sp);
  
          var fToPfMtx = rotation2Scratch;
          fToPfMtx[0] = cosxp * cossp;
          fToPfMtx[1] = cosxp * sinsp;
          fToPfMtx[2] = sinxp;
          fToPfMtx[3] = -cosyp * sinsp + sinyp * sinxp * cossp;
          fToPfMtx[4] = cosyp * cossp + sinyp * sinxp * sinsp;
          fToPfMtx[5] = -sinyp * cosxp;
          fToPfMtx[6] = -sinyp * sinsp - cosyp * sinxp * cossp;
          fToPfMtx[7] = sinyp * cossp - cosyp * sinxp * sinsp;
          fToPfMtx[8] = cosyp * cosxp;
  
          return Matrix3.multiply(pfToIcrf, fToPfMtx, result);
      };
  
      var pointToWindowCoordinatesTemp = new Cartesian4();
  
      /**
       * Transform a point from model coordinates to window coordinates.
       *
       * @param {Matrix4} modelViewProjectionMatrix The 4x4 model-view-projection matrix.
       * @param {Matrix4} viewportTransformation The 4x4 viewport transformation.
       * @param {Cartesian3} point The point to transform.
       * @param {Cartesian2} [result] The object onto which to store the result.
       * @returns {Cartesian2} The modified result parameter or a new Cartesian2 instance if none was provided.
       */
      Transforms.pointToWindowCoordinates = function (modelViewProjectionMatrix, viewportTransformation, point, result) {
          result = Transforms.pointToGLWindowCoordinates(modelViewProjectionMatrix, viewportTransformation, point, result);
          result.y = 2.0 * viewportTransformation[5] - result.y;
          return result;
      };
  
      /**
       * @private
       */
      Transforms.pointToGLWindowCoordinates = function(modelViewProjectionMatrix, viewportTransformation, point, result) {
          //>>includeStart('debug', pragmas.debug);
          if (!defined(modelViewProjectionMatrix)) {
              throw new DeveloperError('modelViewProjectionMatrix is required.');
          }
  
          if (!defined(viewportTransformation)) {
              throw new DeveloperError('viewportTransformation is required.');
          }
  
          if (!defined(point)) {
              throw new DeveloperError('point is required.');
          }
          //>>includeEnd('debug');
  
          if (!defined(result)) {
              result = new Cartesian2();
          }
  
          var tmp = pointToWindowCoordinatesTemp;
  
          Matrix4.multiplyByVector(modelViewProjectionMatrix, Cartesian4.fromElements(point.x, point.y, point.z, 1, tmp), tmp);
          Cartesian4.multiplyByScalar(tmp, 1.0 / tmp.w, tmp);
          Matrix4.multiplyByVector(viewportTransformation, tmp, tmp);
          return Cartesian2.fromCartesian4(tmp, result);
      };
  
      var normalScratch = new Cartesian3();
      var rightScratch = new Cartesian3();
      var upScratch = new Cartesian3();
  
      /**
       * @private
       */
      Transforms.rotationMatrixFromPositionVelocity = function(position, velocity, ellipsoid, result) {
          //>>includeStart('debug', pragmas.debug);
          if (!defined(position)) {
              throw new DeveloperError('position is required.');
          }
  
          if (!defined(velocity)) {
              throw new DeveloperError('velocity is required.');
          }
          //>>includeEnd('debug');
  
          var normal = defaultValue(ellipsoid, Ellipsoid.WGS84).geodeticSurfaceNormal(position, normalScratch);
          var right = Cartesian3.cross(velocity, normal, rightScratch);
          if (Cartesian3.equalsEpsilon(right, Cartesian3.ZERO, CesiumMath.EPSILON6)) {
              right = Cartesian3.clone(Cartesian3.UNIT_X, right);
          }
  
          var up = Cartesian3.cross(right, velocity, upScratch);
          Cartesian3.cross(velocity, up, right);
          Cartesian3.negate(right, right);
  
          if (!defined(result)) {
              result = new Matrix3();
          }
  
          result[0] = velocity.x;
          result[1] = velocity.y;
          result[2] = velocity.z;
          result[3] = right.x;
          result[4] = right.y;
          result[5] = right.z;
          result[6] = up.x;
          result[7] = up.y;
          result[8] = up.z;
  
          return result;
      };
  
      var swizzleMatrix = new Matrix4(
          0.0, 0.0, 1.0, 0.0,
          1.0, 0.0, 0.0, 0.0,
          0.0, 1.0, 0.0, 0.0,
          0.0, 0.0, 0.0, 1.0
      );
  
      var scratchCartographic = new Cartographic();
      var scratchCartesian3Projection = new Cartesian3();
      var scratchCenter = new Cartesian3();
      var scratchRotation = new Matrix3();
      var scratchFromENU = new Matrix4();
      var scratchToENU = new Matrix4();
  
      /**
       * @private
       */
      Transforms.basisTo2D = function(projection, matrix, result) {
          //>>includeStart('debug', pragmas.debug);
          if (!defined(projection)) {
              throw new DeveloperError('projection is required.');
          }
          if (!defined(matrix)) {
              throw new DeveloperError('matrix is required.');
          }
          if (!defined(result)) {
              throw new DeveloperError('result is required.');
          }
          //>>includeEnd('debug');
  
          var rtcCenter = Matrix4.getTranslation(matrix, scratchCenter);
          var ellipsoid = projection.ellipsoid;
  
          // Get the 2D Center
          var cartographic = ellipsoid.cartesianToCartographic(rtcCenter, scratchCartographic);
          var projectedPosition = projection.project(cartographic, scratchCartesian3Projection);
          Cartesian3.fromElements(projectedPosition.z, projectedPosition.x, projectedPosition.y, projectedPosition);
  
          // Assuming the instance are positioned in WGS84, invert the WGS84 transform to get the local transform and then convert to 2D
          var fromENU = Transforms.eastNorthUpToFixedFrame(rtcCenter, ellipsoid, scratchFromENU);
          var toENU = Matrix4.inverseTransformation(fromENU, scratchToENU);
          var rotation = Matrix4.getRotation(matrix, scratchRotation);
          var local = Matrix4.multiplyByMatrix3(toENU, rotation, result);
          Matrix4.multiply(swizzleMatrix, local, result); // Swap x, y, z for 2D
          Matrix4.setTranslation(result, projectedPosition, result); // Use the projected center
  
          return result;
      };
  
      /**
       * @private
       */
      Transforms.wgs84To2DModelMatrix = function(projection, center, result) {
          //>>includeStart('debug', pragmas.debug);
          if (!defined(projection)) {
              throw new DeveloperError('projection is required.');
          }
          if (!defined(center)) {
              throw new DeveloperError('center is required.');
          }
          if (!defined(result)) {
              throw new DeveloperError('result is required.');
          }
          //>>includeEnd('debug');
  
          var ellipsoid = projection.ellipsoid;
  
          var fromENU = Transforms.eastNorthUpToFixedFrame(center, ellipsoid, scratchFromENU);
          var toENU = Matrix4.inverseTransformation(fromENU, scratchToENU);
  
          var cartographic = ellipsoid.cartesianToCartographic(center, scratchCartographic);
          var projectedPosition = projection.project(cartographic, scratchCartesian3Projection);
          Cartesian3.fromElements(projectedPosition.z, projectedPosition.x, projectedPosition.y, projectedPosition);
  
          var translation = Matrix4.fromTranslation(projectedPosition, scratchFromENU);
          Matrix4.multiply(swizzleMatrix, toENU, result);
          Matrix4.multiply(translation, result, result);
  
          return result;
      };
  
      return Transforms;
  });
  