import when from "../ThirdParty/when.js"; import buildModuleUrl from "./buildModuleUrl.js"; import defaultValue from "./defaultValue.js"; import defined from "./defined.js"; import Iau2006XysSample from "./Iau2006XysSample.js"; import JulianDate from "./JulianDate.js"; import Resource from "./Resource.js"; import TimeStandard from "./TimeStandard.js"; /** * A set of IAU2006 XYS data that is used to evaluate the transformation between the International * Celestial Reference Frame (ICRF) and the International Terrestrial Reference Frame (ITRF). * * @alias Iau2006XysData * @constructor * * @param {Object} [options] Object with the following properties: * @param {Resource|String} [options.xysFileUrlTemplate='Assets/IAU2006_XYS/IAU2006_XYS_{0}.json'] A template URL for obtaining the XYS data. In the template, * `{0}` will be replaced with the file index. * @param {Number} [options.interpolationOrder=9] The order of interpolation to perform on the XYS data. * @param {Number} [options.sampleZeroJulianEphemerisDate=2442396.5] The Julian ephemeris date (JED) of the * first XYS sample. * @param {Number} [options.stepSizeDays=1.0] The step size, in days, between successive XYS samples. * @param {Number} [options.samplesPerXysFile=1000] The number of samples in each XYS file. * @param {Number} [options.totalSamples=27426] The total number of samples in all XYS files. * * @private */ function Iau2006XysData(options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); this._xysFileUrlTemplate = Resource.createIfNeeded( options.xysFileUrlTemplate ); this._interpolationOrder = defaultValue(options.interpolationOrder, 9); this._sampleZeroJulianEphemerisDate = defaultValue( options.sampleZeroJulianEphemerisDate, 2442396.5 ); this._sampleZeroDateTT = new JulianDate( this._sampleZeroJulianEphemerisDate, 0.0, TimeStandard.TAI ); this._stepSizeDays = defaultValue(options.stepSizeDays, 1.0); this._samplesPerXysFile = defaultValue(options.samplesPerXysFile, 1000); this._totalSamples = defaultValue(options.totalSamples, 27426); this._samples = new Array(this._totalSamples * 3); this._chunkDownloadsInProgress = []; var order = this._interpolationOrder; // Compute denominators and X values for interpolation. var denom = (this._denominators = new Array(order + 1)); var xTable = (this._xTable = new Array(order + 1)); var stepN = Math.pow(this._stepSizeDays, order); for (var i = 0; i <= order; ++i) { denom[i] = stepN; xTable[i] = i * this._stepSizeDays; for (var j = 0; j <= order; ++j) { if (j !== i) { denom[i] *= i - j; } } denom[i] = 1.0 / denom[i]; } // Allocate scratch arrays for interpolation. this._work = new Array(order + 1); this._coef = new Array(order + 1); } var julianDateScratch = new JulianDate(0, 0.0, TimeStandard.TAI); function getDaysSinceEpoch(xys, dayTT, secondTT) { var dateTT = julianDateScratch; dateTT.dayNumber = dayTT; dateTT.secondsOfDay = secondTT; return JulianDate.daysDifference(dateTT, xys._sampleZeroDateTT); } /** * Preloads XYS data for a specified date range. * * @param {Number} startDayTT The Julian day number of the beginning of the interval to preload, expressed in * the Terrestrial Time (TT) time standard. * @param {Number} startSecondTT The seconds past noon of the beginning of the interval to preload, expressed in * the Terrestrial Time (TT) time standard. * @param {Number} stopDayTT The Julian day number of the end of the interval to preload, expressed in * the Terrestrial Time (TT) time standard. * @param {Number} stopSecondTT The seconds past noon of the end of the interval to preload, expressed in * the Terrestrial Time (TT) time standard. * @returns {Promise<void>} A promise that, when resolved, indicates that the requested interval has been * preloaded. */ Iau2006XysData.prototype.preload = function ( startDayTT, startSecondTT, stopDayTT, stopSecondTT ) { var startDaysSinceEpoch = getDaysSinceEpoch(this, startDayTT, startSecondTT); var stopDaysSinceEpoch = getDaysSinceEpoch(this, stopDayTT, stopSecondTT); var startIndex = (startDaysSinceEpoch / this._stepSizeDays - this._interpolationOrder / 2) | 0; if (startIndex < 0) { startIndex = 0; } var stopIndex = (stopDaysSinceEpoch / this._stepSizeDays - this._interpolationOrder / 2) | (0 + this._interpolationOrder); if (stopIndex >= this._totalSamples) { stopIndex = this._totalSamples - 1; } var startChunk = (startIndex / this._samplesPerXysFile) | 0; var stopChunk = (stopIndex / this._samplesPerXysFile) | 0; var promises = []; for (var i = startChunk; i <= stopChunk; ++i) { promises.push(requestXysChunk(this, i)); } return when.all(promises); }; /** * Computes the XYS values for a given date by interpolating. If the required data is not yet downloaded, * this method will return undefined. * * @param {Number} dayTT The Julian day number for which to compute the XYS value, expressed in * the Terrestrial Time (TT) time standard. * @param {Number} secondTT The seconds past noon of the date for which to compute the XYS value, expressed in * the Terrestrial Time (TT) time standard. * @param {Iau2006XysSample} [result] The instance to which to copy the interpolated result. If this parameter * is undefined, a new instance is allocated and returned. * @returns {Iau2006XysSample} The interpolated XYS values, or undefined if the required data for this * computation has not yet been downloaded. * * @see Iau2006XysData#preload */ Iau2006XysData.prototype.computeXysRadians = function ( dayTT, secondTT, result ) { var daysSinceEpoch = getDaysSinceEpoch(this, dayTT, secondTT); if (daysSinceEpoch < 0.0) { // Can't evaluate prior to the epoch of the data. return undefined; } var centerIndex = (daysSinceEpoch / this._stepSizeDays) | 0; if (centerIndex >= this._totalSamples) { // Can't evaluate after the last sample in the data. return undefined; } var degree = this._interpolationOrder; var firstIndex = centerIndex - ((degree / 2) | 0); if (firstIndex < 0) { firstIndex = 0; } var lastIndex = firstIndex + degree; if (lastIndex >= this._totalSamples) { lastIndex = this._totalSamples - 1; firstIndex = lastIndex - degree; if (firstIndex < 0) { firstIndex = 0; } } // Are all the samples we need present? // We can assume so if the first and last are present var isDataMissing = false; var samples = this._samples; if (!defined(samples[firstIndex * 3])) { requestXysChunk(this, (firstIndex / this._samplesPerXysFile) | 0); isDataMissing = true; } if (!defined(samples[lastIndex * 3])) { requestXysChunk(this, (lastIndex / this._samplesPerXysFile) | 0); isDataMissing = true; } if (isDataMissing) { return undefined; } if (!defined(result)) { result = new Iau2006XysSample(0.0, 0.0, 0.0); } else { result.x = 0.0; result.y = 0.0; result.s = 0.0; } var x = daysSinceEpoch - firstIndex * this._stepSizeDays; var work = this._work; var denom = this._denominators; var coef = this._coef; var xTable = this._xTable; var i, j; for (i = 0; i <= degree; ++i) { work[i] = x - xTable[i]; } for (i = 0; i <= degree; ++i) { coef[i] = 1.0; for (j = 0; j <= degree; ++j) { if (j !== i) { coef[i] *= work[j]; } } coef[i] *= denom[i]; var sampleIndex = (firstIndex + i) * 3; result.x += coef[i] * samples[sampleIndex++]; result.y += coef[i] * samples[sampleIndex++]; result.s += coef[i] * samples[sampleIndex]; } return result; }; function requestXysChunk(xysData, chunkIndex) { if (xysData._chunkDownloadsInProgress[chunkIndex]) { // Chunk has already been requested. return xysData._chunkDownloadsInProgress[chunkIndex]; } var deferred = when.defer(); xysData._chunkDownloadsInProgress[chunkIndex] = deferred; var chunkUrl; var xysFileUrlTemplate = xysData._xysFileUrlTemplate; if (defined(xysFileUrlTemplate)) { chunkUrl = xysFileUrlTemplate.getDerivedResource({ templateValues: { 0: chunkIndex, }, }); } else { chunkUrl = new Resource({ url: buildModuleUrl( "Assets/IAU2006_XYS/IAU2006_XYS_" + chunkIndex + ".json" ), }); } when(chunkUrl.fetchJson(), function (chunk) { xysData._chunkDownloadsInProgress[chunkIndex] = false; var samples = xysData._samples; var newSamples = chunk.samples; var startIndex = chunkIndex * xysData._samplesPerXysFile * 3; for (var i = 0, len = newSamples.length; i < len; ++i) { samples[startIndex + i] = newSamples[i]; } deferred.resolve(); }); return deferred.promise; } export default Iau2006XysData;