UNPKG

slimfits

Version:

Package for loading data stored in FITS data format

793 lines 38.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var tslib_1 = require("tslib"); // TODO: we need to incorporate RADECSYS in processing var SphericalProjectionConverterBase = /** @class */ (function () { function SphericalProjectionConverterBase(obj) { this.ra2de = 180 / Math.PI; this.de2ra = Math.PI / 180; this.phi_0 = NaN; this.theta_0 = NaN; this.alpha_0 = NaN; this.delta_0 = NaN; this.theta_p = NaN; this.phi_p = NaN; this.transform_matrix = undefined; this.inverse_transform_matrix = undefined; if (Array.isArray(obj)) { this.constructFromHeader(obj); } else { this.constructFromDefinition(obj); } } SphericalProjectionConverterBase.isLongitudal = function (type) { for (var _i = 0, _a = SphericalProjectionConverterBase.longitudalTypes; _i < _a.length; _i++) { var longitudalType = _a[_i]; if (longitudalType === type) { return true; } } return false; }; SphericalProjectionConverterBase.prototype.convert = function (coords) { var relativeCoords = this.convertToRelative(coords); var intermediateCoords = this.convertToIntermediate(relativeCoords); var sphericalCoords = this.convertToSpherical(intermediateCoords); var celestialCoords = this.convertToCelestial(sphericalCoords); return celestialCoords; }; SphericalProjectionConverterBase.prototype.convertBack = function (coords) { var sphericalCoords = this.convertFromCelestial(coords); var intermediateCoords = this.convertFromSpherical(sphericalCoords); var relativeCoords = this.convertFromIntermediate(intermediateCoords); var plateCoords = this.convertFromRelative(relativeCoords); return plateCoords; }; SphericalProjectionConverterBase.prototype.multiplyMatrices = function (arr1, arr2) { var res = [[0, 0], [0, 0]]; for (var row = 0; row < 2; row++) { for (var col = 0; col < 2; col++) { for (var i = 0; i < 2; i++) { res[row][col] += arr1[row][i] * arr2[i][col]; } } } return res; }; SphericalProjectionConverterBase.prototype.convertToRelative = function (coords) { return { u: coords.x + 1 - this.crpixs[0], v: coords.y + 1 - this.crpixs[1] }; }; SphericalProjectionConverterBase.prototype.convertFromRelative = function (coords) { return { x: Math.round((coords.u + this.crpixs[0] - 1) * 1000) / 1000, y: Math.round((coords.v + this.crpixs[1] - 1) * 1000) / 1000 }; }; SphericalProjectionConverterBase.prototype.convertToIntermediate = function (coords) { var is = []; var crds = [coords.u, coords.v]; for (var i = 0; i < this.wcslen; i += 1) { is[i] = 0; for (var j = 0; j < this.wcslen; j += 1) { is[i] += this.transform_matrix[i][j] * crds[j]; } is[i] *= this.de2ra; } return { x: is[0], y: is[1] }; }; SphericalProjectionConverterBase.prototype.convertFromIntermediate = function (coords) { var is = []; var crds = [coords.x, coords.y]; for (var i = 0; i < this.wcslen; i += 1) { is[i] = 0; for (var j = 0; j < this.wcslen; j += 1) { is[i] += this.inverse_transform_matrix[i][j] * crds[j]; } is[i] *= this.ra2de; // is[i] += this.crpixs[i] - 1; } return { u: is[0], v: is[1] //Math.round(is[1] * 1000) / 1000 }; }; SphericalProjectionConverterBase.prototype.convertFromSpherical = function (coords) { return { x: coords.r * Math.sin(coords.phi), y: -coords.r * Math.cos(coords.phi) }; }; SphericalProjectionConverterBase.prototype.convertToCelestial = function (coords) { var alpha = NaN; var delta = NaN; var coords_p = this.calculate_alphap_deltap(); if (coords_p.delta_p === Math.PI / 2) { // SEE: http://www.aanda.org/articles/aa/pdf/2002/45/aah3860.pdf (eqn. 3) alpha = (coords_p.alpha_p + coords.phi - this.phi_p - Math.PI) * this.ra2de; delta = coords.theta * this.ra2de; } else if (coords_p.delta_p === -Math.PI / 2) { // SEE: http://www.aanda.org/articles/aa/pdf/2002/45/aah3860.pdf (eqn. 4) alpha = (coords_p.alpha_p - coords.phi + this.phi_p) * this.ra2de; delta = -coords.theta * this.ra2de; } else { // SEE: http://www.aanda.org/articles/aa/pdf/2002/45/aah3860.pdf (eqn. 2) var sin_theta = Math.sin(coords.theta); var cos_theta = Math.cos(coords.theta); var sin_dphi = Math.sin(coords.phi - this.phi_p); var cos_dphi = Math.cos(coords.phi - this.phi_p); var sin_de_p = Math.sin(coords_p.delta_p); var cos_de_p = Math.cos(coords_p.delta_p); var xt = sin_theta * cos_de_p - cos_theta * sin_de_p * cos_dphi; var yt = -cos_theta * sin_dphi; var zt = sin_theta * sin_de_p + cos_theta * cos_de_p * cos_dphi; alpha = (Math.atan2(yt, xt) + coords_p.alpha_p) * this.ra2de; delta = Math.asin(zt) * this.ra2de; } alpha = (alpha + 360) % 360; alpha /= 15; return { alpha: alpha, delta: delta }; }; SphericalProjectionConverterBase.prototype.convertFromCelestialToAngles = function (coords) { var phi; var theta; var alpha = coords.alpha * 15 * this.de2ra; var delta = coords.delta * this.de2ra; var coords_p = this.calculate_alphap_deltap(); if (coords_p.delta_p === Math.PI / 2) { // SEE: http://www.aanda.org/articles/aa/pdf/2002/45/aah3860.pdf (inverted eqn. 3) phi = alpha + Math.PI + this.phi_p - coords_p.alpha_p; theta = delta; } else if (coords_p.delta_p === -Math.PI / 2) { // SEE: http://www.aanda.org/articles/aa/pdf/2002/45/aah3860.pdf (inverted eqn. 4) phi = coords_p.alpha_p - alpha + this.phi_p; theta = -delta; } else { // SEE: http://www.aanda.org/articles/aa/pdf/2002/45/aah3860.pdf (eqn. 5) var sin_delta = Math.sin(delta); var cos_delta = Math.cos(delta); var sin_delta_p = Math.sin(coords_p.delta_p); var cos_delta_p = Math.cos(coords_p.delta_p); var cos_dalpha = Math.cos(alpha - coords_p.alpha_p); var sin_dalpha = Math.sin(alpha - coords_p.alpha_p); phi = this.phi_p + Math.atan2(sin_delta * cos_delta_p - cos_delta * sin_delta_p * cos_dalpha, -cos_delta * sin_dalpha); theta = Math.asin(sin_delta * sin_delta_p + cos_delta * cos_delta_p * cos_dalpha); } return { phi: phi, theta: theta }; }; SphericalProjectionConverterBase.prototype.constructFromHeader = function (header) { // TODO: as the construction of a converter relies on CTYPE // most likely obtaining/defining ctypes and axis_types // should be removed from this place to the builder. // Moreover, axes_types shall define whether we deal with // equatorial, galactic or ecliptic coordinates. this.ctypes = header.filter(function (o) { return o.key.indexOf('CTYPE') === 0; }) .sort(function (a, b) { return a.key.localeCompare(b.key); }) .map(function (val) { return val.value; }); if (this.ctypes.length <= 0) { return; } this.projection = this.ctypes[0].slice(5); this.axes_types = []; for (var _i = 0, _a = this.ctypes; _i < _a.length; _i++) { var ctype = _a[_i]; var type = ctype.substr(0, 5).replace('-', ''); this.axes_types.push({ name: type, isLongitudal: SphericalProjectionConverterBase.isLongitudal(type) }); } // TODO: WCS standard has an optional WCSAXES this.wcslen = header.filter(function (o) { return /NAXIS\d+/.test(o.key); }) .length; this.crpixs = header.filter(function (o) { return /CRPIX\d+/.test(o.key); }) .sort(function (a, b) { return a.key.localeCompare(b.key); }) .map(function (val) { return val.value; }); this.crvals = header.filter(function (o) { return /CRVAL\d+/.test(o.key); }) .sort(function (a, b) { return a.key.localeCompare(b.key); }) .map(function (val) { return val.value; }); this.cdelts = header.filter(function (o) { return /CDELT\d+/.test(o.key); }) .sort(function (a, b) { return a.key.localeCompare(b.key); }) .map(function (val) { return val.value; }); // TODO: currently with the below prescription we assume ra ~ x and dec ~ y // (not to mention all the other coordinate systems). // There must be implemented the logic describing this.alpha_0 = this.crvals[0] * this.de2ra; this.delta_0 = this.crvals[1] * this.de2ra; var latpole_found = false; var lonpole_found = false; for (var _b = 0, header_1 = header; _b < header_1.length; _b++) { var kw = header_1[_b]; if (kw.key === 'LATPOLE') { this.theta_p = parseFloat(kw.value) * this.de2ra; latpole_found = true; } if (kw.key === 'LONPOLE') { this.phi_p = parseFloat(kw.value) * this.de2ra; lonpole_found = true; } if (latpole_found && lonpole_found) { break; } } var phitheta = this.calculate_phi0_theta0(); this.phi_0 = phitheta.phi_0; this.theta_0 = phitheta.theta_0; if (isNaN(this.phi_p)) { this.phi_p = (this.delta_0 >= this.theta_0) ? 0 : Math.PI; } // INFO: currently we compile down to es5 that doesn't have Array.prototype.find method. // This should be changed to a polyfill at one point. var find_element = function (arr, key) { for (var _i = 0, arr_1 = arr; _i < arr_1.length; _i++) { var kw = arr_1[_i]; if (kw.key === key) { return kw.value; } } return undefined; }; var default_for; var rot_matrix_key_regex = /CD\d+_\d+/; var rot_matrix_kws = header.filter(function (o) { return rot_matrix_key_regex.test(o.key); }); var rot_matrix_key_prefix = 'CD'; var rot_can_create_transform_matrix = false; if (rot_matrix_kws != null && rot_matrix_kws.length > 0) { // CDs are present so we use them default_for = function (_, __) { return 0; }; // we must have at least one number given rot_can_create_transform_matrix = rot_matrix_kws.length > 0; } else { // CDs are not present. Find PC elements and CDELT elements rot_matrix_key_regex = /PC\d+_\d+/; rot_matrix_key_prefix = 'PC'; rot_matrix_kws = header.filter(function (o) { return rot_matrix_key_regex.test(o.key); }); default_for = function (i, j) { return (i === j) ? 1 : 0; }; // we're good to go as there is a non-zero value rot_can_create_transform_matrix = true; } if (rot_can_create_transform_matrix) { this.transform_matrix = []; for (var i = 0; i < this.wcslen; i++) { this.transform_matrix[i] = []; for (var j = 0; j < this.wcslen; j++) { var elem_default = default_for(i, j); var loc_prefix = rot_matrix_key_prefix + (i + 1) + '_' + (j + 1); var pc_tmp = find_element(rot_matrix_kws, loc_prefix); this.transform_matrix[i][j] = (pc_tmp !== undefined) ? parseFloat(pc_tmp) : elem_default; } } if (rot_matrix_key_prefix === 'PC' && this.cdelts.length > 0) { this.transform_matrix = this.multiplyMatrices([[this.cdelts[0], 0], [0, this.cdelts[1]]], this.transform_matrix); } } // We rely on the CD formalism, meaning our transform_matrix IS de facto CDs array. // Thus to cover for that when a FITS file uses PC formalism we reformat [CDELTs]*[PCs] // according to the equation below. // SEE: http://www.aanda.org/articles/aa/pdf/2002/45/aah3860.pdf // The translation between CD and PC formalism is: // / CD1_1 CD1_2 \ - / CDELT1 0 \ . / PC1_1 PC1_2 \ // \ CD2_1 CD2_2 / - \ 0 CDELT2 / \ PC2_1 PC2_2 / this.crotas = header.filter(function (o) { return /CROTA\d+/.test(o.key); }) .sort(function (a, b) { return a.key.localeCompare(b.key); }) .map(function (val) { return val.value; }); // SEE: http://www.aanda.org/articles/aa/pdf/2002/45/aah3860.pdf (section 6.1) // we don't want to use CROTA as it's obsolete, but just in case // the implementation is given below // SEE: http://www.aanda.org/articles/aa/pdf/2002/45/aah3860.pdf, eqn/ 186, 187, 188 & 189 if (this.transform_matrix === undefined && this.crotas !== undefined && this.crotas.length > 0) { this.transform_matrix = [ [this.cdelts[0] * Math.cos(this.crotas[0]), -this.cdelts[1] * Math.sin(this.crotas[1])], [this.cdelts[0] * Math.sin(this.crotas[0]), this.cdelts[1] * Math.cos(this.crotas[1])] ]; } this.inverse_transform_matrix = this.inverseOf(this.transform_matrix); }; SphericalProjectionConverterBase.prototype.constructFromDefinition = function (definition) { this.wcslen = 2; this.crpixs = [ definition.frame_reference_point.x + 1, definition.frame_reference_point.y + 1 ]; this.alpha_0 = definition.sky_reference_point.alpha; this.delta_0 = definition.sky_reference_point.delta; var phitheta = this.calculate_phi0_theta0(); // TODO: check whether it is ok. this.theta_p = definition.celestial_pole.latitude; this.phi_p = definition.celestial_pole.longitude; if (isNaN(this.phi_p)) { this.phi_p = (this.delta_0 >= this.theta_0) ? 0 : Math.PI; } this.phi_0 = phitheta.phi_0; this.theta_0 = phitheta.theta_0; this.transform_matrix = []; var dtm_length = definition.transform_matrix.length; for (var x = 0; x < dtm_length; x++) { this.transform_matrix[x] = []; var dtm_sub_length = definition.transform_matrix[x].length; for (var y = 0; y < dtm_sub_length; y++) { this.transform_matrix[x][y] = definition.transform_matrix[x][y]; } } this.inverse_transform_matrix = this.inverseOf(this.transform_matrix); }; SphericalProjectionConverterBase.prototype.inverseOf = function (arr) { var det = arr[0][0] * arr[1][1] - arr[0][1] * arr[1][0]; var inv = [ [arr[1][1] / det, -arr[0][1] / det], [-arr[1][0] / det, arr[0][0] / det] ]; return inv; }; // 'RA', 'DEC' - equatorial coordinates (=> meeus.EquatorialCoordinates?) // 'ELON', 'ELAT' - ecliptic coordinates (=> meeus.EclipticCoordinates?) // 'GLON', 'GLAT' - galactic coordinates (=> meeus.GalacticCoordinates?) // 'HLON', 'HLAT' - helioecliptic coordinates // 'SLON', 'SLAT' - supergalactic coordinates SphericalProjectionConverterBase.longitudalTypes = ['RA', 'ELON', 'GLON', 'HLON', 'SLON']; return SphericalProjectionConverterBase; }()); exports.SphericalProjectionConverterBase = SphericalProjectionConverterBase; // INFO: For zenithal projections, (phi_0, theta_0) = (0, PI / 2), // so the CRVAL elements specify the celestial coordinates // of the native pole, i.e. (ra_0, de_0) = (ra_p, de_p) // TODO: as written above: this only works for zenithal projections. // It must be updated to work for all the others. var ZenithalProjectionConverterBase = /** @class */ (function (_super) { tslib_1.__extends(ZenithalProjectionConverterBase, _super); function ZenithalProjectionConverterBase() { return _super !== null && _super.apply(this, arguments) || this; } ZenithalProjectionConverterBase.prototype.calculate_alphap_deltap = function () { return { alpha_p: this.alpha_0, delta_p: this.delta_0 }; }; // SEE: http://www.aanda.org/articles/aa/pdf/2002/45/aah3860.pdf, p. 1079, par 1 ZenithalProjectionConverterBase.prototype.calculate_phi0_theta0 = function () { return { phi_0: 0, theta_0: Math.PI / 2 }; }; return ZenithalProjectionConverterBase; }(SphericalProjectionConverterBase)); exports.ZenithalProjectionConverterBase = ZenithalProjectionConverterBase; // INFO: For zenithal projections, (phi_0, theta_0) = (0, PI / 2), // so the CRVAL elements specify the celestial coordinates // of the native pole, i.e. (ra_0, de_0) = (ra_p, de_p) // TODO: as written above: this only works for zenithal projections. // It must be updated to work for all the others. // See: http://www.aanda.org/articles/aa/pdf/2002/45/aah3860.pdf (eqns: 8, 9, 10) var NonPolarProjectionConverterBase = /** @class */ (function (_super) { tslib_1.__extends(NonPolarProjectionConverterBase, _super); function NonPolarProjectionConverterBase() { return _super !== null && _super.apply(this, arguments) || this; } NonPolarProjectionConverterBase.prototype.calculate_alphap_deltap = function () { throw new Error('NotImplemented'); }; return NonPolarProjectionConverterBase; }(SphericalProjectionConverterBase)); exports.NonPolarProjectionConverterBase = NonPolarProjectionConverterBase; var GnomonicProjectionConverter = /** @class */ (function (_super) { tslib_1.__extends(GnomonicProjectionConverter, _super); function GnomonicProjectionConverter() { return _super !== null && _super.apply(this, arguments) || this; } GnomonicProjectionConverter.prototype.convertToSpherical = function (coords) { var r = Math.sqrt(coords.x * coords.x + coords.y * coords.y); return { r: r, phi: Math.atan2(coords.x, -coords.y), theta: Math.atan(1 / r) }; }; GnomonicProjectionConverter.prototype.convertFromCelestial = function (coords) { var angles = _super.prototype.convertFromCelestialToAngles.call(this, coords); return { r: 1.0 / Math.tan(angles.theta), phi: angles.phi, theta: angles.theta }; }; return GnomonicProjectionConverter; }(ZenithalProjectionConverterBase)); exports.GnomonicProjectionConverter = GnomonicProjectionConverter; var TpvGnomonicProjectionConverter = /** @class */ (function (_super) { tslib_1.__extends(TpvGnomonicProjectionConverter, _super); function TpvGnomonicProjectionConverter() { return _super !== null && _super.apply(this, arguments) || this; } TpvGnomonicProjectionConverter.prototype.convert = function (coords) { var relativeCoords = this.convertToRelative(coords); var intermediateCoords = this.convertToIntermediate(relativeCoords); var distortedIntermediateCoords = this.convertToDistorted(intermediateCoords); var sphericalCoords = this.convertToSpherical(distortedIntermediateCoords); var celestialCoords = this.convertToCelestial(sphericalCoords); return celestialCoords; }; TpvGnomonicProjectionConverter.prototype.convertBack = function (coords) { var sphericalCoords = this.convertFromCelestial(coords); var distortedIntermediateCoords = this.convertFromSpherical(sphericalCoords); var intermediateCoords = this.convertFromDistorted(distortedIntermediateCoords); var relativeCoords = this.convertFromIntermediate(intermediateCoords); var plateCoords = this.convertFromRelative(relativeCoords); return plateCoords; }; TpvGnomonicProjectionConverter.prototype.constructFromHeader = function (header) { _super.prototype.constructFromHeader.call(this, header); this.pvs = undefined; // INFO: currently we compile down to es5 that doesn't have Array.prototype.find method. // This should be changed to a polyfill at one point. var find_element = function (arr, key) { for (var _i = 0, arr_2 = arr; _i < arr_2.length; _i++) { var kw = arr_2[_i]; if (kw.key === key) { return kw.value; } } return undefined; }; // TPV convention: https://fits.gsfc.nasa.gov/registry/tpvwcs/tpv.html var default_for = function (i, j) { return 0; }; var pvs_kws = header.filter(function (o) { return /PV\d+_\d+/.test(o.key); }); var pvs_prefix = 'PV'; var pvs_cnt = 0; if (pvs_kws.length > 0) { this.pvs = []; for (var i = 0; i < this.wcslen; i++) { this.pvs[i] = []; for (var j = 0; j < 40; j++) { var elem_default = default_for(i, j); var loc_prefix = pvs_prefix + (i + 1) + '_' + (j); var pv_tmp = find_element(pvs_kws, loc_prefix); this.pvs[i][j] = (pv_tmp !== undefined) ? parseFloat(pv_tmp) : elem_default; pvs_cnt += Math.abs(this.pvs[i][j]); } } } if (pvs_cnt === 0) { this.pvs = undefined; } }; TpvGnomonicProjectionConverter.prototype.constructFromDefinition = function (definition) { _super.prototype.constructFromDefinition.call(this, definition); this.pvs = undefined; if (definition.distortion_matrix === undefined) { throw new Error('distortion_matrix is undefined'); } this.pvs = []; var pvc_length = definition.distortion_matrix.length; for (var x = 0; x < pvc_length; x++) { this.pvs[x] = []; var pvc_sub_length = definition.distortion_matrix[x].length; var y = 0; for (; y < pvc_sub_length; y++) { this.pvs[x][y] = definition.distortion_matrix[x][y]; } for (; y < 40; y++) { this.pvs[x][y] = 0.0; } } }; TpvGnomonicProjectionConverter.prototype.convertToDistorted = function (coords) { if (this.pvs === undefined) { return coords; } var x = coords.x * this.ra2de; var y = coords.y * this.ra2de; var xout = this.getDistortedParam(x, y, this.pvs[0]); var yout = this.getDistortedParam(y, x, this.pvs[1]); return { x: xout * this.de2ra, y: yout * this.de2ra }; }; TpvGnomonicProjectionConverter.prototype.getDistortedParam = function (xi, eta, pv) { var r = Math.sqrt(xi * xi + eta * eta); var r2 = r * r; var r3 = r * r2; var r4 = r * r3; var r5 = r * r4; var r6 = r * r5; var r7 = r * r6; var xi2 = xi * xi; var xi3 = xi * xi2; var xi4 = xi * xi3; var xi5 = xi * xi4; var xi6 = xi * xi5; var xi7 = xi * xi6; var eta2 = eta * eta; var eta3 = eta * eta2; var eta4 = eta * eta3; var eta5 = eta * eta4; var eta6 = eta * eta5; var eta7 = eta * eta6; return pv[0] + pv[1] * xi + pv[2] * eta + pv[3] * r + pv[4] * xi * xi + pv[5] * xi * eta + pv[6] * eta * eta + pv[7] * xi * xi * xi + pv[8] * xi * xi * eta + pv[9] * xi * eta * eta + pv[10] * eta * eta * eta + pv[11] * r * r * r + pv[12] * xi * xi * xi * xi + pv[13] * xi * xi * xi * eta + pv[14] * xi * xi * eta * eta + pv[15] * xi * eta * eta * eta + pv[16] * eta * eta * eta * eta + pv[17] * xi * xi * xi * xi * xi + pv[18] * xi * xi * xi * xi * eta + pv[19] * xi * xi * xi * eta * eta + pv[20] * xi * xi * eta * eta * eta + pv[21] * xi * eta * eta * eta * eta + pv[22] * eta * eta * eta * eta * eta + pv[23] * r * r * r * r * r + pv[24] * xi * xi * xi * xi * xi * xi + pv[25] * xi * xi * xi * xi * xi * eta + pv[26] * xi * xi * xi * xi * eta * eta + pv[27] * xi * xi * xi * eta * eta * eta + pv[28] * xi * xi * eta * eta * eta * eta + pv[29] * xi * eta * eta * eta * eta * eta + pv[30] * eta * eta * eta * eta * eta * eta + pv[31] * xi * xi * xi * xi * xi * xi * xi + pv[32] * xi * xi * xi * xi * xi * xi * eta + pv[33] * xi * xi * xi * xi * xi * eta * eta + pv[34] * xi * xi * xi * xi * eta * eta * eta + pv[35] * xi * xi * xi * eta * eta * eta * eta + pv[36] * xi * xi * eta * eta * eta * eta * eta + pv[37] * xi * eta * eta * eta * eta * eta * eta + pv[38] * eta * eta * eta * eta * eta * eta * eta + pv[39] * r * r * r * r * r * r * r; }; TpvGnomonicProjectionConverter.prototype.convertFromDistorted = function (coords) { if (this.pvs === undefined) { return coords; } throw new Error('NotImplemented'); }; return TpvGnomonicProjectionConverter; }(GnomonicProjectionConverter)); exports.TpvGnomonicProjectionConverter = TpvGnomonicProjectionConverter; var SipGnomonicProjectionConverter = /** @class */ (function (_super) { tslib_1.__extends(SipGnomonicProjectionConverter, _super); function SipGnomonicProjectionConverter() { return _super !== null && _super.apply(this, arguments) || this; } SipGnomonicProjectionConverter.prototype.convert = function (coords) { var relativeCoords = this.convertToRelative(coords); var distortedCoords = this.convertToDistorted(relativeCoords); var intermediateCoords = this.convertToIntermediate(distortedCoords); var sphericalCoords = this.convertToSpherical(intermediateCoords); var celestialCoords = this.convertToCelestial(sphericalCoords); return celestialCoords; }; SipGnomonicProjectionConverter.prototype.convertBack = function (coords) { var sphericalCoords = this.convertFromCelestial(coords); var intermediateCoords = this.convertFromSpherical(sphericalCoords); var distortedCoords = this.convertFromIntermediate(intermediateCoords); var relativeCoords = this.convertFromDistorted(distortedCoords); var plateCoords = this.convertFromRelative(relativeCoords); return plateCoords; }; SipGnomonicProjectionConverter.prototype.constructFromHeader = function (header) { _super.prototype.constructFromHeader.call(this, header); this.a = undefined; this.b = undefined; this.ab_inv = undefined; // INFO: currently we compile down to es5 that doesn't have Array.prototype.find method. // This should be changed to a polyfill at one point. var find_element = function (arr, key) { for (var _i = 0, arr_3 = arr; _i < arr_3.length; _i++) { var kw = arr_3[_i]; if (kw.key === key) { return kw.value; } } return undefined; }; // SIP convention: https://fits.gsfc.nasa.gov/registry/sip.html var default_for = function (i, j) { return 0; }; var generate_distortion_array = function (kws, order, prefix) { var arr = []; for (var i = 0; i <= order; i++) { arr[i] = []; for (var j = 0; j <= order; j++) { var elem_default = default_for(i, j); var loc_prefix = prefix + '_' + (i) + '_' + (j); var tmp = find_element(kws, loc_prefix); arr[i][j] = (tmp !== undefined) ? parseFloat(tmp) : elem_default; } } return arr; }; var a_kws = header.filter(function (o) { return /A_\d+_\d+/.test(o.key); }); this.a_order = parseInt(header.find(function (o) { return /A_ORDER/.test(o.key); }).value, 10); if (this.a_order > 0) { this.a = generate_distortion_array(a_kws, this.a_order, 'A'); } var b_kws = header.filter(function (o) { return /B_\d+_\d+/.test(o.key); }); this.b_order = parseInt(header.find(function (o) { return /B_ORDER/.test(o.key); }).value, 10); if (this.b_order > 0) { this.b = generate_distortion_array(b_kws, this.b_order, 'B'); } // TODO: implement the inverse transforms. // const ap_kws: any[] = header.filter(o => /AP_\d+_\d+/.test(o.key)); // const bp_kws: any[] = header.filter(o => /BP_\d+_\d+/.test(o.key)); // const ap_order: number = header.find(o => /AP_ORDER/.test(o.key)).value; // const bp_order: number = header.find(o => /BP_ORDER/.test(o.key)).value; // this.inv_a_order = ap_order; // this.inv_b_order = bp_order; }; SipGnomonicProjectionConverter.prototype.constructFromDefinition = function (definition) { _super.prototype.constructFromDefinition.call(this, definition); this.a = undefined; this.b = undefined; throw new Error('NotImplemented'); }; SipGnomonicProjectionConverter.prototype.convertToDistorted = function (coords) { if (this.a === undefined || this.b === undefined) { coords; } return { u: coords.u + this.getDistortedParam(coords.u, coords.v, this.a, this.a_order), v: coords.v + this.getDistortedParam(coords.u, coords.v, this.b, this.b_order) }; }; SipGnomonicProjectionConverter.prototype.getDistortedParam = function (u, v, arr, order) { var par = 0; for (var i = 0; i <= order; i++) { for (var j = 0; j <= order; j++) { if (arr[i][j] !== 0) { par += arr[i][j] * Math.pow(u, i) * Math.pow(v, j); } } } return par; }; SipGnomonicProjectionConverter.prototype.convertFromDistorted = function (coords) { if (this.ab_inv === undefined) { return coords; } throw new Error('NotImplemented'); }; return SipGnomonicProjectionConverter; }(GnomonicProjectionConverter)); exports.SipGnomonicProjectionConverter = SipGnomonicProjectionConverter; var SlantOrtographicProjectionConverter = /** @class */ (function (_super) { tslib_1.__extends(SlantOrtographicProjectionConverter, _super); function SlantOrtographicProjectionConverter() { return _super !== null && _super.apply(this, arguments) || this; } SlantOrtographicProjectionConverter.prototype.convertToSpherical = function (coords) { var r = Math.sqrt(coords.x * coords.x + coords.y * coords.y); return { r: r, phi: Math.atan2(coords.x, -coords.y), theta: Math.acos(r) }; }; SlantOrtographicProjectionConverter.prototype.convertFromCelestial = function (coords) { var angles = _super.prototype.convertFromCelestialToAngles.call(this, coords); return { r: Math.cos(angles.theta), phi: angles.phi, theta: angles.theta }; }; return SlantOrtographicProjectionConverter; }(ZenithalProjectionConverterBase)); exports.SlantOrtographicProjectionConverter = SlantOrtographicProjectionConverter; var ZenithalEquidistantProjectionConverter = /** @class */ (function (_super) { tslib_1.__extends(ZenithalEquidistantProjectionConverter, _super); function ZenithalEquidistantProjectionConverter() { return _super !== null && _super.apply(this, arguments) || this; } ZenithalEquidistantProjectionConverter.prototype.convertToSpherical = function (coords) { var r = Math.sqrt(coords.x * coords.x + coords.y * coords.y); return { r: r, phi: Math.atan2(coords.x, -coords.y), theta: this.theta_0 - r }; }; ZenithalEquidistantProjectionConverter.prototype.convertFromCelestial = function (coords) { var angles = _super.prototype.convertFromCelestialToAngles.call(this, coords); return { r: this.theta_0 - angles.theta, phi: angles.phi, theta: angles.theta }; }; return ZenithalEquidistantProjectionConverter; }(ZenithalProjectionConverterBase)); exports.ZenithalEquidistantProjectionConverter = ZenithalEquidistantProjectionConverter; var StereographicProjectionConverter = /** @class */ (function (_super) { tslib_1.__extends(StereographicProjectionConverter, _super); function StereographicProjectionConverter() { return _super !== null && _super.apply(this, arguments) || this; } StereographicProjectionConverter.prototype.convertToSpherical = function (coords) { var r = Math.sqrt(coords.x * coords.x + coords.y * coords.y); return { r: r, phi: Math.atan2(coords.x, -coords.y), theta: Math.PI / 2 - 2 * Math.atan(r / 2) }; }; StereographicProjectionConverter.prototype.convertFromCelestial = function (coords) { var angles = _super.prototype.convertFromCelestialToAngles.call(this, coords); return { r: 2 * Math.tan((Math.PI / 2 - angles.theta) / 2), phi: angles.phi, theta: angles.theta }; }; return StereographicProjectionConverter; }(ZenithalProjectionConverterBase)); exports.StereographicProjectionConverter = StereographicProjectionConverter; var ZenithalEqualAreaProjectionConverter = /** @class */ (function (_super) { tslib_1.__extends(ZenithalEqualAreaProjectionConverter, _super); function ZenithalEqualAreaProjectionConverter() { return _super !== null && _super.apply(this, arguments) || this; } ZenithalEqualAreaProjectionConverter.prototype.convertToSpherical = function (coords) { var r = Math.sqrt(coords.x * coords.x + coords.y * coords.y); return { r: r, phi: Math.atan2(coords.x, -coords.y), theta: Math.PI / 2 - 2 * Math.asin(r / 2) }; }; ZenithalEqualAreaProjectionConverter.prototype.convertFromCelestial = function (coords) { var angles = _super.prototype.convertFromCelestialToAngles.call(this, coords); return { r: 2 * Math.sin((Math.PI / 2 - angles.theta) / 2), phi: angles.phi, theta: angles.theta }; }; return ZenithalEqualAreaProjectionConverter; }(ZenithalProjectionConverterBase)); exports.ZenithalEqualAreaProjectionConverter = ZenithalEqualAreaProjectionConverter; var SphericalProjectionConvertersBuilder = /** @class */ (function () { function SphericalProjectionConvertersBuilder() { this.registeredConverters = { 'TAN': function (header) { return new GnomonicProjectionConverter(header); }, 'TPV': function (header) { return new TpvGnomonicProjectionConverter(header); }, 'TAN-SIP': function (header) { return new SipGnomonicProjectionConverter(header); }, 'SIN': function (header) { return new SlantOrtographicProjectionConverter(header); }, 'ARC': function (header) { return new ZenithalEquidistantProjectionConverter(header); }, 'STG': function (header) { return new StereographicProjectionConverter(header); }, 'ZEA': function (header) { return new ZenithalEqualAreaProjectionConverter(header); } }; } SphericalProjectionConvertersBuilder.prototype.canBuild = function (obj) { var projection = null; if (Array.isArray(obj)) { projection = this.canBuildInner(obj); } else { projection = obj; } return (projection === null) ? false : this.registeredConverters.hasOwnProperty(projection); }; SphericalProjectionConvertersBuilder.prototype.build = function (obj) { var projection = null; if (Array.isArray(obj)) { projection = this.canBuildInner(obj); if (projection !== null) { return this.registeredConverters[projection](obj); } } else { if (this.registeredConverters.hasOwnProperty(obj.projection)) { return this.registeredConverters[obj.projection](obj.definition); } } throw new Error('No converter for projection "' + projection + '" registered.'); }; SphericalProjectionConvertersBuilder.prototype.registerConverter = function (projection, converter) { this.registeredConverters[projection] = converter; }; SphericalProjectionConvertersBuilder.prototype.canBuildInner = function (header) { var ctypes = header.filter(function (o) { return o.key.indexOf('CTYPE') === 0; }) .sort(function (a, b) { return a.key.localeCompare(b.key); }) .map(function (val) { return val.value; }); if (ctypes.length <= 0) { return null; } return ctypes[0].slice(5); }; return SphericalProjectionConvertersBuilder; }()); exports.SphericalProjectionConvertersBuilder = SphericalProjectionConvertersBuilder; //# sourceMappingURL=SphericalProjectionConverters.js.map