@cquiroz/aladin-lite
Version:
AladinLite module
554 lines (444 loc) • 14.2 kB
JavaScript
//=================================
// 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;