UNPKG

@cquiroz/aladin-lite

Version:
554 lines (444 loc) 14.2 kB
//================================= // Class Coo //================================= import AstroMath from './astroMath'; /** * Constructor * @param longitude longitude (decimal degrees) * @param latitude latitude (decimal degrees) * @param prec precision * (8: 1/1000th sec, 7: 1/100th sec, 6: 1/10th sec, 5: sec, 4: 1/10th min, 3: min, 2: 1/10th deg, 1: deg */ function Coo(longitude, latitude, prec) { this.lon = longitude; this.lat = latitude; this.prec = prec; this.frame = null; this.computeDirCos(); } Coo.factor = [3600.0, 60.0, 1.0]; Coo.prototype = { setFrame: function setFrame(astroframe) { this.frame = astroframe; }, computeDirCos: function computeDirCos() { var coslat = AstroMath.cosd(this.lat); this.x = coslat * AstroMath.cosd(this.lon); this.y = coslat * AstroMath.sind(this.lon); this.z = AstroMath.sind(this.lat); }, computeLonLat: function computeLonLat() { var r2 = this.x * this.x + this.y * this.y; this.lon = 0.0; if (r2 === 0.0) { // In case of poles if (this.z === 0.0) { this.lon = 0.0 / 0.0; this.lat = 0.0 / 0.0; } else { this.lat = this.z > 0.0 ? 90.0 : -90.0; } } else { this.lon = AstroMath.atan2d(this.y, this.x); this.lat = AstroMath.atan2d(this.z, Math.sqrt(r2)); if (this.lon < 0) this.lon += 360.0; } }, /** * Squared distance between 2 points (= 4.sin<sup>2</sup>(r/2)) * @param pos another position on the sphere * @return ||pos-this||<sup>2</sup> = 4.sin<sup>2</sup>(r/2) **/ dist2: function dist2(pos) { // if ((this.x==0)&&(this.y==0)&&(this.z==0)) return(0./0.); // if ((pos.x==0)&&(pos.y==0)&&(pos.z==0)) return(0./0.); var w = pos.x - this.x; var r2 = w * w; w = pos.y - this.y; r2 += w * w; w = pos.z - this.z; r2 += w * w; return r2; }, /** * Distance between 2 points on the sphere. * @param pos another position on the sphere * @return distance in degrees in range [0, 180] **/ distance: function distance(pos) { // Take care of NaN: if (pos.x === 0 && pos.y === 0 && pos.z === 0) return 0. / 0.; if (this.x === 0 && this.y === 0 && this.z === 0) return 0. / 0.; return 2. * AstroMath.asind(0.5 * Math.sqrt(this.dist2(pos))); }, /** * Transform the position into another frame. * @param new_frame The frame of the resulting position. **/ convertTo: function convertTo(new_frame) { // Verify first if frames identical -- then nothing to do ! if (this.frame.equals(new_frame)) { return; } // Move via ICRS this.frame.toICRS(this.coo); // Position now in ICRS new_frame.fromICRS(this.coo); // Position now in new_frame this.frame = new_frame; this.lon = this.lat = 0. / 0.; // Actual angles not recomputed }, /** * Rotate a coordinate (apply a rotation to the position). * @param R [3][3] Rotation Matrix */ rotate: function rotate(R) { var X, Y, Z; // if (R == Umatrix3) return; X = R[0][0] * this.x + R[0][1] * this.y + R[0][2] * this.z; Y = R[1][0] * this.x + R[1][1] * this.y + R[1][2] * this.z; Z = R[2][0] * this.x + R[2][1] * this.y + R[2][2] * this.z; // this.set(X, Y, Z); Not necessary to compute positions each time. this.x = X; this.y = Y; this.z = Z; this.lon = this.lat = 0. / 0.; }, /** * Rotate a coordinate (apply a rotation to the position) in reverse direction. * The method is the inverse of rotate. * @param R [3][3] Rotation Matrix */ rotate_1: function rotate_1(R) { var X, Y, Z; // if (R == Umatrix3) return; X = R[0][0] * this.x + R[1][0] * this.y + R[2][0] * this.z; Y = R[0][1] * this.x + R[1][1] * this.y + R[2][1] * this.z; Z = R[0][2] * this.x + R[1][2] * this.y + R[2][2] * this.z; // this.set(X, Y, Z); Not necessary to compute positions each time. this.x = X; this.y = Y; this.z = Z; this.lon = this.lat = 0. / 0.; }, /** * Test equality of Coo. * @param coo Second coordinate to compare with * @return True if the two coordinates are equal */ equals: function equals(coo) { return this.x === coo.x && this.y === coo.y && this.z === coo.z; }, /** * parse a coordinate string. The coordinates can be in decimal or sexagesimal * @param str string to parse * @return true if the parsing succeded, false otherwise */ parse: function parse(str) { var p = str.indexOf('+'); if (p < 0) p = str.indexOf('-'); if (p < 0) p = str.indexOf(' '); if (p < 0) { this.lon = 0.0 / 0.0; this.lat = 0.0 / 0.0; this.prec = 0; return false; } var strlon = str.substring(0, p); var strlat = str.substring(p); this.lon = this.parseLon(strlon); // sets the precision parameter this.lat = this.parseLat(strlat); // sets the precision parameter return true; }, parseLon: function parseLon(string) { var str = string.trim(); str = str.replace(/:/g, ' '); if (str.indexOf(' ') < 0) { // The longitude is a integer or decimal number var p = str.indexOf('.'); this.prec = p < 0 ? 0 : str.length - p - 1; return parseFloat(str); } else { var stok = new Tokenizer(str, ' '); var i = 0; var l = 0; var pr = 0; while (stok.hasMore()) { var tok = stok.nextToken(); var dec = tok.indexOf('.'); l += parseFloat(tok) * Coo.factor[i]; // pr = dec < 0 ? 1 : 2; switch (i) { case 0: pr = dec < 0 ? 1 : 2; break; case 1: pr = dec < 0 ? 3 : 4; break; case 2: pr = dec < 0 ? 5 : 4 + tok.length - dec; break; default: break; } i++; } this.prec = pr; return l * 15 / 3600.0; } }, parseLat: function parseLat(string) { var str = string.trim(); str = str.replace(/:/g, ' '); var sign; if (str.charAt(0) === '-') { sign = -1; str = str.substring(1); } else { // No sign specified sign = 1; } if (str.indexOf(' ') < 0) { // The longitude is a integer or decimal number var p = str.indexOf('.'); this.prec = p < 0 ? 0 : str.length - p - 1; return parseFloat(str) * sign; } else { var stok = new Tokenizer(str, ' '); var i = 0; var l = 0; var pr = 0; while (stok.hasMore()) { var tok = stok.nextToken(); var dec = tok.indexOf('.'); l += parseFloat(tok) * Coo.factor[i]; switch (i) { case 0: pr = dec < 0 ? 1 : 2; break; case 1: pr = dec < 0 ? 3 : 4; break; case 2: pr = dec < 0 ? 5 : 4 + tok.length - dec; break; default: break; } i++; } this.prec = pr; return l * sign / 3600.0; } }, /** * Format coordinates according to the options * @param options 'd': decimal, 's': sexagésimal, '/': space separated, '2': return [ra,dec] in an array * @return the formatted coordinates */ format: function format(options) { if (isNaN(this.lon)) this.computeLonLat(); var strlon = "", strlat = ""; if (options.indexOf('d') >= 0) { // decimal display strlon = Numbers.format(this.lon, this.prec); strlat = Numbers.format(this.lat, this.prec); } else { // sexagesimal display var hlon = this.lon / 15.0; strlon = Numbers.toSexagesimal(hlon, this.prec + 1, false); strlat = Numbers.toSexagesimal(this.lat, this.prec, false); } if (this.lat > 0) strlat = '+' + strlat; if (options.indexOf('/') >= 0) { return strlon + ' ' + strlat; } else if (options.indexOf('2') >= 0) { return [strlon, strlat]; } return strlon + strlat; } }; /** * Distance between 2 points on the sphere. * @param coo1 firs var coslat = AstroMath.cosd(this.lat); this.x = coslat*AstroMath.cosd(this.lon); this.y = coslat*AstroMath.sind(this.lon); this.z = AstroMath.sind(this.lat); t coordinates point * @param coo2 second coordinates point * @return distance in degrees in range [0, 180] **/ /* Coo.distance = function(Coo coo1, Coo coo2) { return Coo.distance(coo1.lon, coo1.lat, coo2.lon, coo2.lat); } */ /** * Distance between 2 points on the sphere. * @param lon1 longitude of first point in degrees * @param lat1 latitude of first point in degrees * @param lon2 longitude of second point in degrees * @param lat2 latitude of second point in degrees * @return distance in degrees in range [0, 180] **/ /* Coo.distance = function(lon1, lat1, lon2, lat2) { var c1 = AstroMath.cosd(lat1); var c2 = AstroMath.cosd(lat2); var w, r2; w = c1 * AstroMath.cosd(lon1) - c2 * AstroMath.cosd(lon2); r2 = w*w; w = c1 * AstroMath.sind(lon1) - c2 * AstroMath.sind(lon2); r2 += w*w; w = AstroMath.sind(lat1) - AstroMath.sind(lat2); r2 += w*w; return 2. * AstroMath.asind(0.5 * Math.sqrt(r2)); } //=================================== // Class Tokenizer (similar to Java) //=================================== /** * Constructor * @param str String to tokenize * @param sep token separator char */ function Tokenizer(str, sep) { this.string = Strings.trim(str, sep); this.sep = sep; this.pos = 0; } Tokenizer.prototype = { /** * Check if the string has more tokens * @return true if a token remains (read with nextToken()) */ hasMore: function hasMore() { return this.pos < this.string.length; }, /** * Returns the next token (as long as hasMore() is true) * @return the token string */ nextToken: function nextToken() { // skip all the separator chars var p0 = this.pos; while (p0 < this.string.length && this.string.charAt(p0) === this.sep) { p0++; } var p1 = p0; // get the token while (p1 < this.string.length && this.string.charAt(p1) !== this.sep) { p1++; } this.pos = p1; return this.string.substring(p0, p1); } }; //================================ // Class Strings (static methods) //================================ function Strings() {} /** * Removes a given char at the beginning and the end of a string * @param str string to trim * @param c char to remove * @return the trimmed string */ Strings.trim = function (str, c) { var p0 = 0, p1 = str.length - 1; while (p0 < str.length && str.charAt(p0) === c) { p0++; } if (p0 === str.length) return ""; while (p1 > p0 && str.charAt(p1) === c) { p1--; } return str.substring(p0, p1 + 1); }; //================================ // Class Numbers (static methods) //================================ function Numbers() {} // 0 1 2 3 4 5 6 7 8 9 Numbers.pow10 = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, // 10 11 12 13 14 10000000000, 100000000000, 1000000000000, 10000000000000, 100000000000000]; // 0 1 2 3 4 5 6 7 Numbers.rndval = [0.5, 0.05, 0.005, 0.0005, 0.00005, 0.000005, 0.0000005, 0.00000005, // 8 9 10 11 12 0.000000005, 0.0000000005, 0.00000000005, 0.000000000005, 0.0000000000005, // 13 14 0.00000000000005, 0.00000000000005]; /** * Format a integer or decimal number, adjusting the value with 'prec' decimal digits * @param num number (integer or decimal) * @param prec precision (= number of decimal digit to keep or append) * @return a string with the formatted number */ Numbers.format = function (num, prec) { if (prec <= 0) { // Return an integer number return Math.round(num).toString(); } var str = num.toString(); var p = str.indexOf('.'); var nbdec = p >= 0 ? str.length - p - 1 : 0; if (prec >= nbdec) { if (p < 0) str += '.'; for (var i = 0; i < prec - nbdec; i++) { str += '0'; } return str; } // HERE: prec > 0 and prec < nbdec str = (num + Numbers.rndval[prec]).toString(); return str.substr(0, p + prec + 1); }; /** * Convert a decimal coordinate into sexagesimal string, according to the given precision<br> * 8: 1/1000th sec, 7: 1/100th sec, 6: 1/10th sec, 5: sec, 4: 1/10th min, 3: min, 2: 1/10th deg, 1: deg * @param num number (integer or decimal) * @param prec precision (= number of decimal digit to keep or append) * @param plus if true, the '+' sign is displayed * @return a string with the formatted sexagesimal number */ Numbers.toSexagesimal = function (num, prec, plus) { // var resu = ""; var sign = num < 0 ? '-' : plus ? '+' : ''; var n = Math.abs(num); switch (prec) { case 1: { // deg var n1 = Math.round(n); return sign + n1.toString(); } case 2: // deg.d return sign + Numbers.format(n, 1); case 3: { // deg min var _n = Math.floor(n); var n2 = Math.round((n - _n) * 60); return sign + _n + ' ' + n2; } case 4: { // deg min.d var _n2 = Math.floor(n); var _n3 = (n - _n2) * 60; return sign + _n2 + ' ' + Numbers.format(_n3, 1); } case 5: { // deg min sec var _n4 = Math.floor(n); // d var _n5 = (n - _n4) * 60; // M.d var n3 = Math.floor(_n5); // M var n4 = Math.round((_n5 - n3) * 60); // S return sign + _n4 + ' ' + n3 + ' ' + n4; } case 6: // deg min sec.d case 7: // deg min sec.dd case 8: { // deg min sec.ddd var _n6 = Math.floor(n); // d if (_n6 < 10) _n6 = '0' + _n6; var _n7 = (n - _n6) * 60; // M.d var _n8 = Math.floor(_n7); // M if (_n8 < 10) _n8 = '0' + _n8; var _n9 = (_n7 - _n8) * 60; // S.ddd return sign + _n6 + ' ' + _n8 + ' ' + Numbers.format(_n9, prec - 5); } default: return sign + Numbers.format(n, 1); } }; export default Coo;