django-vue3-admin-web/node_modules/astronomia/lib/angle.cjs
2025-10-20 21:21:14 +08:00

238 lines
7.3 KiB
JavaScript

'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var base = require('./base.cjs');
var interpolation = require('./interpolation.cjs');
/**
* @copyright 2013 Sonia Keys
* @copyright 2016 commenthol
* @license MIT
* @module angle
*/
const { abs, acos, asin, atan2, cos, hypot, sin, sqrt, tan } = Math;
/**
* `sep` returns the angular separation between two celestial bodies.
*
* The algorithm is numerically naïve, and while patched up a bit for
* small separations, remains unstable for separations near π.
*
* @param {Coord} c1 - coordinate of celestial body 1
* @param {Coord} c2 - coordinate of celestial body 2
* @return {Number} angular separation between two celestial bodies
*/
function sep (c1, c2) {
const [sind1, cosd1] = base["default"].sincos(c1.dec);
const [sind2, cosd2] = base["default"].sincos(c2.dec);
const cd = sind1 * sind2 + cosd1 * cosd2 * cos(c1.ra - c2.ra); // (17.1) p. 109
if (cd < base["default"].CosSmallAngle) {
return acos(cd)
} else {
const cosd = cos((c2.dec + c1.dec) / 2); // average dec of two bodies
return hypot((c2.ra - c1.ra) * cosd, c2.dec - c1.dec) // (17.2) p. 109
}
}
/**
* `minSep` returns the minimum separation between two moving objects.
*
* The motion is represented as an ephemeris of three rows, equally spaced
* in time. Jd1, jd3 are julian day times of the first and last rows.
* R1, d1, r2, d2 are coordinates at the three times. They must each be
* slices of length 3.0
*
* Result is obtained by computing separation at each of the three times
* and interpolating a minimum. This may be invalid for sufficiently close
* approaches.
*
* @throws Error
* @param {Number} jd1 - Julian day - time at cs1[0], cs2[0]
* @param {Number} jd3 - Julian day - time at cs1[2], cs2[2]
* @param {Coord[]} cs1 - 3 coordinates of moving object 1
* @param {Coord[]} cs2 - 3 coordinates of moving object 2
* @param {function} [fnSep] - alternative `sep` function e.g. `angle.sepPauwels`, `angle.sepHav`
* @return {Number} angular separation between two celestial bodies
*/
function minSep (jd1, jd3, cs1, cs2, fnSep) {
if (cs1.length !== 3 || cs2.length !== 3) {
throw interpolation["default"].errorNot3
}
const y = new Array(3);
cs1.forEach((c, x) => {
y[x] = sep(cs1[x], cs2[x]);
});
const d3 = new interpolation["default"].Len3(jd1, jd3, y);
const dMin = d3.extremum()[1];
return dMin
}
/**
* `minSepRect` returns the minimum separation between two moving objects.
*
* Like `minSep`, but using a method of rectangular coordinates that gives
* accurate results even for close approaches.
*
* @throws Error
* @param {Number} jd1 - Julian day - time at cs1[0], cs2[0]
* @param {Number} jd3 - Julian day - time at cs1[2], cs2[2]
* @param {Coord[]} cs1 - 3 coordinates of moving object 1
* @param {Coord[]} cs2 - 3 coordinates of moving object 2
* @return {Number} angular separation between two celestial bodies
*/
function minSepRect (jd1, jd3, cs1, cs2) {
if (cs1.length !== 3 || cs2.length !== 3) {
throw interpolation["default"].ErrorNot3
}
const uv = function (c1, c2) {
const [sind1, cosd1] = base["default"].sincos(c1.dec);
const Δr = c2.ra - c1.ra;
const tanΔr = tan(Δr);
const tanhΔr = tan(Δr / 2);
const K = 1 / (1 + sind1 * sind1 * tanΔr * tanhΔr);
const sinΔd = sin(c2.dec - c1.dec);
const u = -K * (1 - (sind1 / cosd1) * sinΔd) * cosd1 * tanΔr;
const v = K * (sinΔd + sind1 * cosd1 * tanΔr * tanhΔr);
return [u, v]
};
const us = new Array(3).fill(0);
const vs = new Array(3).fill(0);
cs1.forEach((c, x) => {
[us[x], vs[x]] = uv(cs1[x], cs2[x]);
});
const u3 = new interpolation["default"].Len3(-1, 1, us); // if line throws then bug not caller's fault.
const v3 = new interpolation["default"].Len3(-1, 1, vs); // if line throws then bug not caller's fault.
const up0 = (us[2] - us[0]) / 2;
const vp0 = (vs[2] - vs[0]) / 2;
const up1 = us[0] + us[2] - 2 * us[1];
const vp1 = vs[0] + vs[2] - 2 * vs[1];
const up = up0;
const vp = vp0;
let dn = -(us[1] * up + vs[1] * vp) / (up * up + vp * vp);
let n = dn;
let u;
let v;
for (let limit = 0; limit < 10; limit++) {
u = u3.interpolateN(n);
v = v3.interpolateN(n);
if (abs(dn) < 1e-5) {
return hypot(u, v) // success
}
const up = up0 + n * up1;
const vp = vp0 + n * vp1;
dn = -(u * up + v * vp) / (up * up + vp * vp);
n += dn;
}
throw new Error('minSepRect: failure to converge')
}
/**
* haversine function (17.5) p. 115
*/
function hav (a) {
return 0.5 * (1 - Math.cos(a))
}
/**
* `sepHav` returns the angular separation between two celestial bodies.
*
* The algorithm uses the haversine function and is superior to the naïve
* algorithm of the Sep function.
*
* @param {Coord} c1 - coordinate of celestial body 1
* @param {Coord} c2 - coordinate of celestial body 2
* @return {Number} angular separation between two celestial bodies
*/
function sepHav (c1, c2) {
// using (17.5) p. 115
return 2 * asin(sqrt(hav(c2.dec - c1.dec) +
cos(c1.dec) * cos(c2.dec) * hav(c2.ra - c1.ra)))
}
/**
* Same as `minSep` but uses function `sepHav` to return the minimum separation
* between two moving objects.
*/
function minSepHav (jd1, jd3, cs1, cs2) {
return minSep(jd1, jd3, cs1, cs2)
}
/**
* `sepPauwels` returns the angular separation between two celestial bodies.
*
* The algorithm is a numerically stable form of that used in `sep`.
*
* @param {Coord} c1 - coordinate of celestial body 1
* @param {Coord} c2 - coordinate of celestial body 2
* @return {Number} angular separation between two celestial bodies
*/
function sepPauwels (c1, c2) {
const [sind1, cosd1] = base["default"].sincos(c1.dec);
const [sind2, cosd2] = base["default"].sincos(c2.dec);
const cosdr = cos(c2.ra - c1.ra);
const x = cosd1 * sind2 - sind1 * cosd2 * cosdr;
const y = cosd2 * sin(c2.ra - c1.ra);
const z = sind1 * sind2 + cosd1 * cosd2 * cosdr;
return atan2(hypot(x, y), z)
}
/**
* Same as `minSep` but uses function `sepPauwels` to return the minimum
* separation between two moving objects.
*/
function minSepPauwels (jd1, jd3, cs1, cs2) {
return minSep(jd1, jd3, cs1, cs2)
}
/**
* RelativePosition returns the position angle of one body with respect to
* another.
*
* The position angle result `p` is measured counter-clockwise from North.
* If negative then `p` is in the range of 90° ... 270°
*
* ````
* North
* |
* (p) ..|
* . |
* V |
* c1 x------------x c2
* |
* ````
*
* @param {Coord} c1 - coordinate of celestial body 1
* @param {Coord} c2 - coordinate of celestial body 2
* @return {Number} position angle (p)
*/
function relativePosition (c1, c2) {
const [sinΔr, cosΔr] = base["default"].sincos(c1.ra - c2.ra);
const [sind2, cosd2] = base["default"].sincos(c2.dec);
const p = atan2(sinΔr, cosd2 * tan(c1.dec) - sind2 * cosΔr);
return p
}
var angle = {
sep,
minSep,
minSepRect,
hav,
sepHav,
minSepHav,
sepPauwels,
minSepPauwels,
relativePosition
};
exports["default"] = angle;
exports.hav = hav;
exports.minSep = minSep;
exports.minSepHav = minSepHav;
exports.minSepPauwels = minSepPauwels;
exports.minSepRect = minSepRect;
exports.relativePosition = relativePosition;
exports.sep = sep;
exports.sepHav = sepHav;
exports.sepPauwels = sepPauwels;