| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283 | import buildModuleUrl from "./buildModuleUrl.js";import defaultValue from "./defaultValue.js";import defer from "./defer.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 = [];  const order = this._interpolationOrder;  // Compute denominators and X values for interpolation.  const denom = (this._denominators = new Array(order + 1));  const xTable = (this._xTable = new Array(order + 1));  const stepN = Math.pow(this._stepSizeDays, order);  for (let i = 0; i <= order; ++i) {    denom[i] = stepN;    xTable[i] = i * this._stepSizeDays;    for (let 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);}const julianDateScratch = new JulianDate(0, 0.0, TimeStandard.TAI);function getDaysSinceEpoch(xys, dayTT, secondTT) {  const 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) {  const startDaysSinceEpoch = getDaysSinceEpoch(    this,    startDayTT,    startSecondTT  );  const stopDaysSinceEpoch = getDaysSinceEpoch(this, stopDayTT, stopSecondTT);  let startIndex =    (startDaysSinceEpoch / this._stepSizeDays - this._interpolationOrder / 2) |    0;  if (startIndex < 0) {    startIndex = 0;  }  let stopIndex =    (stopDaysSinceEpoch / this._stepSizeDays - this._interpolationOrder / 2) |    (0 + this._interpolationOrder);  if (stopIndex >= this._totalSamples) {    stopIndex = this._totalSamples - 1;  }  const startChunk = (startIndex / this._samplesPerXysFile) | 0;  const stopChunk = (stopIndex / this._samplesPerXysFile) | 0;  const promises = [];  for (let i = startChunk; i <= stopChunk; ++i) {    promises.push(requestXysChunk(this, i));  }  return Promise.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) {  const daysSinceEpoch = getDaysSinceEpoch(this, dayTT, secondTT);  if (daysSinceEpoch < 0.0) {    // Can't evaluate prior to the epoch of the data.    return undefined;  }  const centerIndex = (daysSinceEpoch / this._stepSizeDays) | 0;  if (centerIndex >= this._totalSamples) {    // Can't evaluate after the last sample in the data.    return undefined;  }  const degree = this._interpolationOrder;  let firstIndex = centerIndex - ((degree / 2) | 0);  if (firstIndex < 0) {    firstIndex = 0;  }  let 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  let isDataMissing = false;  const 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;  }  const x = daysSinceEpoch - firstIndex * this._stepSizeDays;  const work = this._work;  const denom = this._denominators;  const coef = this._coef;  const xTable = this._xTable;  let 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];    let 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];  }  const deferred = defer();  xysData._chunkDownloadsInProgress[chunkIndex] = deferred;  let chunkUrl;  const 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`),    });  }  chunkUrl.fetchJson().then(function (chunk) {    xysData._chunkDownloadsInProgress[chunkIndex] = false;    const samples = xysData._samples;    const newSamples = chunk.samples;    const startIndex = chunkIndex * xysData._samplesPerXysFile * 3;    for (let i = 0, len = newSamples.length; i < len; ++i) {      samples[startIndex + i] = newSamples[i];    }    deferred.resolve();  });  return deferred.promise;}export default Iau2006XysData;
 |