325 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			325 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
'use strict';
 | 
						||
 | 
						||
Object.defineProperty(exports, '__esModule', { value: true });
 | 
						||
 | 
						||
var apparent = require('./apparent.cjs');
 | 
						||
var base = require('./base.cjs');
 | 
						||
var coord = require('./coord.cjs');
 | 
						||
var kepler = require('./kepler.cjs');
 | 
						||
var nutation = require('./nutation.cjs');
 | 
						||
var planetposition = require('./planetposition.cjs');
 | 
						||
var solarxyz = require('./solarxyz.cjs');
 | 
						||
 | 
						||
/**
 | 
						||
 * @copyright 2013 Sonia Keys
 | 
						||
 * @copyright 2016 commenthol
 | 
						||
 * @license MIT
 | 
						||
 * @module elliptic
 | 
						||
 */
 | 
						||
 | 
						||
/**
 | 
						||
 * Position returns observed equatorial coordinates of a planet at a given time.
 | 
						||
 *
 | 
						||
 * Argument p must be a valid V87Planet object for the observed planet.
 | 
						||
 * Argument earth must be a valid V87Planet object for Earth.
 | 
						||
 *
 | 
						||
 * Results are right ascension and declination, α and δ in radians.
 | 
						||
 */
 | 
						||
function position (planet, earth, jde) { // (p, earth *pp.V87Planet, jde float64)  (α, δ float64)
 | 
						||
  let x = 0;
 | 
						||
  let y = 0;
 | 
						||
  let z = 0;
 | 
						||
  const posEarth = earth.position(jde);
 | 
						||
  const [L0, B0, R0] = [posEarth.lon, posEarth.lat, posEarth.range];
 | 
						||
  const [sB0, cB0] = base["default"].sincos(B0);
 | 
						||
  const [sL0, cL0] = base["default"].sincos(L0);
 | 
						||
 | 
						||
  function pos (τ = 0) {
 | 
						||
    const pos = planet.position(jde - τ);
 | 
						||
    const [L, B, R] = [pos.lon, pos.lat, pos.range];
 | 
						||
    const [sB, cB] = base["default"].sincos(B);
 | 
						||
    const [sL, cL] = base["default"].sincos(L);
 | 
						||
    x = R * cB * cL - R0 * cB0 * cL0;
 | 
						||
    y = R * cB * sL - R0 * cB0 * sL0;
 | 
						||
    z = R * sB - R0 * sB0;
 | 
						||
  }
 | 
						||
 | 
						||
  pos();
 | 
						||
  const Δ = Math.sqrt(x * x + y * y + z * z); // (33.4) p. 224
 | 
						||
  const τ = base["default"].lightTime(Δ);
 | 
						||
  // repeating with jde-τ
 | 
						||
  pos(τ);
 | 
						||
 | 
						||
  let λ = Math.atan2(y, x); // (33.1) p. 223
 | 
						||
  let β = Math.atan2(z, Math.hypot(x, y)); // (33.2) p. 223
 | 
						||
  const [Δλ, Δβ] = apparent["default"].eclipticAberration(λ, β, jde);
 | 
						||
  const fk5 = planetposition["default"].toFK5(λ + Δλ, β + Δβ, jde);
 | 
						||
  λ = fk5.lon;
 | 
						||
  β = fk5.lat;
 | 
						||
  const [Δψ, Δε] = nutation["default"].nutation(jde);
 | 
						||
  λ += Δψ;
 | 
						||
  const ε = nutation["default"].meanObliquity(jde) + Δε;
 | 
						||
  return new coord["default"].Ecliptic(λ, β).toEquatorial(ε)
 | 
						||
  // Meeus gives a formula for elongation but doesn't spell out how to
 | 
						||
  // obtaion term λ0 and doesn't give an example solution.
 | 
						||
}
 | 
						||
 | 
						||
/**
 | 
						||
 * Elements holds keplerian elements.
 | 
						||
 */
 | 
						||
class Elements {
 | 
						||
  /*
 | 
						||
  Axis  float64 // Semimajor axis, a, in AU
 | 
						||
  Ecc   float64 // Eccentricity, e
 | 
						||
  Inc   float64 // Inclination, i, in radians
 | 
						||
  ArgP  float64 // Argument of perihelion, ω, in radians
 | 
						||
  Node  float64 // Longitude of ascending node, Ω, in radians
 | 
						||
  TimeP float64 // Time of perihelion, T, as jde
 | 
						||
  */
 | 
						||
  constructor (axis, ecc, inc, argP, node, timeP) {
 | 
						||
    let o = {};
 | 
						||
    if (typeof axis === 'object') {
 | 
						||
      o = axis;
 | 
						||
    }
 | 
						||
    this.axis = o.axis || axis;
 | 
						||
    this.ecc = o.ecc || ecc;
 | 
						||
    this.inc = o.inc || inc;
 | 
						||
    this.argP = o.argP || argP;
 | 
						||
    this.node = o.node || node;
 | 
						||
    this.timeP = o.timeP || timeP;
 | 
						||
  }
 | 
						||
 | 
						||
  /**
 | 
						||
   * Position returns observed equatorial coordinates of a body with Keplerian elements.
 | 
						||
   *
 | 
						||
   * Argument e must be a valid V87Planet object for Earth.
 | 
						||
   *
 | 
						||
   * Results are right ascension and declination α and δ, and elongation ψ,
 | 
						||
   * all in radians.
 | 
						||
   */
 | 
						||
  position (jde, earth) { // (α, δ, ψ float64) {
 | 
						||
    // (33.6) p. 227
 | 
						||
    const n = base["default"].K / this.axis / Math.sqrt(this.axis);
 | 
						||
    const sε = base["default"].SOblJ2000;
 | 
						||
    const cε = base["default"].COblJ2000;
 | 
						||
    const [sΩ, cΩ] = base["default"].sincos(this.node);
 | 
						||
    const [si, ci] = base["default"].sincos(this.inc);
 | 
						||
    // (33.7) p. 228
 | 
						||
    const F = cΩ;
 | 
						||
    const G = sΩ * cε;
 | 
						||
    const H = sΩ * sε;
 | 
						||
    const P = -sΩ * ci;
 | 
						||
    const Q = cΩ * ci * cε - si * sε;
 | 
						||
    const R = cΩ * ci * sε + si * cε;
 | 
						||
    // (33.8) p. 229
 | 
						||
    const A = Math.atan2(F, P);
 | 
						||
    const B = Math.atan2(G, Q);
 | 
						||
    const C = Math.atan2(H, R);
 | 
						||
    const a = Math.hypot(F, P);
 | 
						||
    const b = Math.hypot(G, Q);
 | 
						||
    const c = Math.hypot(H, R);
 | 
						||
 | 
						||
    const f = (jde) => { // (x, y, z float64) {
 | 
						||
      const M = n * (jde - this.timeP);
 | 
						||
      let E;
 | 
						||
      try {
 | 
						||
        E = kepler["default"].kepler2b(this.ecc, M, 15);
 | 
						||
      } catch (e) {
 | 
						||
        E = kepler["default"].kepler3(this.ecc, M);
 | 
						||
      }
 | 
						||
      const ν = kepler["default"].trueAnomaly(E, this.ecc);
 | 
						||
      const r = kepler["default"].radius(E, this.ecc, this.axis);
 | 
						||
      // (33.9) p. 229
 | 
						||
      const x = r * a * Math.sin(A + this.argP + ν);
 | 
						||
      const y = r * b * Math.sin(B + this.argP + ν);
 | 
						||
      const z = r * c * Math.sin(C + this.argP + ν);
 | 
						||
      return { x, y, z }
 | 
						||
    };
 | 
						||
    return astrometricJ2000(f, jde, earth)
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
/**
 | 
						||
 * AstrometricJ2000 is a utility function for computing astrometric coordinates.
 | 
						||
 *
 | 
						||
 * It is used internally and only exported so that it can be used from
 | 
						||
 * multiple packages.  It is not otherwise expected to be used.
 | 
						||
 *
 | 
						||
 * Argument f is a function that returns J2000 equatorial rectangular
 | 
						||
 * coodinates of a body.
 | 
						||
 *
 | 
						||
 * Results are J2000 right ascention, declination, and elongation.
 | 
						||
 */
 | 
						||
function astrometricJ2000 (f, jde, earth) { // (f func(float64)  (x, y, z float64), jde float64, e *pp.V87Planet) (α, δ, ψ float64)
 | 
						||
  const sol = solarxyz["default"].positionJ2000(earth, jde);
 | 
						||
  const [X, Y, Z] = [sol.x, sol.y, sol.z];
 | 
						||
  let ξ = 0;
 | 
						||
  let η = 0;
 | 
						||
  let ζ = 0;
 | 
						||
  let Δ = 0;
 | 
						||
 | 
						||
  function fn (τ = 0) {
 | 
						||
    // (33.10) p. 229
 | 
						||
    const { x, y, z } = f(jde - τ);
 | 
						||
    ξ = X + x;
 | 
						||
    η = Y + y;
 | 
						||
    ζ = Z + z;
 | 
						||
    Δ = Math.sqrt(ξ * ξ + η * η + ζ * ζ);
 | 
						||
  }
 | 
						||
 | 
						||
  fn();
 | 
						||
  const τ = base["default"].lightTime(Δ);
 | 
						||
  fn(τ);
 | 
						||
 | 
						||
  let α = Math.atan2(η, ξ);
 | 
						||
  if (α < 0) {
 | 
						||
    α += 2 * Math.PI;
 | 
						||
  }
 | 
						||
  const δ = Math.asin(ζ / Δ);
 | 
						||
  const R0 = Math.sqrt(X * X + Y * Y + Z * Z);
 | 
						||
  const ψ = Math.acos((ξ * X + η * Y + ζ * Z) / R0 / Δ);
 | 
						||
  return new base["default"].Coord(α, δ, undefined, ψ)
 | 
						||
}
 | 
						||
 | 
						||
/**
 | 
						||
 * Velocity returns instantaneous velocity of a body in elliptical orbit around the Sun.
 | 
						||
 *
 | 
						||
 * Argument a is the semimajor axis of the body, r is the instaneous distance
 | 
						||
 * to the Sun, both in AU.
 | 
						||
 *
 | 
						||
 * Result is in Km/sec.
 | 
						||
 */
 | 
						||
function velocity (a, r) { // (a, r float64)  float64
 | 
						||
  return 42.1219 * Math.sqrt(1 / r - 0.5 / a)
 | 
						||
}
 | 
						||
 | 
						||
/**
 | 
						||
 * Velocity returns the velocity of a body at aphelion.
 | 
						||
 *
 | 
						||
 * Argument a is the semimajor axis of the body in AU, e is eccentricity.
 | 
						||
 *
 | 
						||
 * Result is in Km/sec.
 | 
						||
 */
 | 
						||
function vAphelion (a, e) { // (a, e float64)  float64
 | 
						||
  return 29.7847 * Math.sqrt((1 - e) / (1 + e) / a)
 | 
						||
}
 | 
						||
 | 
						||
/**
 | 
						||
 * Velocity returns the velocity of a body at perihelion.
 | 
						||
 *
 | 
						||
 * Argument a is the semimajor axis of the body in AU, e is eccentricity.
 | 
						||
 *
 | 
						||
 * Result is in Km/sec.
 | 
						||
 */
 | 
						||
function vPerihelion (a, e) { // (a, e float64)  float64
 | 
						||
  return 29.7847 * Math.sqrt((1 + e) / (1 - e) / a)
 | 
						||
}
 | 
						||
 | 
						||
/**
 | 
						||
 * Length1 returns Ramanujan's approximation for the length of an elliptical
 | 
						||
 * orbit.
 | 
						||
 *
 | 
						||
 * Argument a is semimajor axis, e is eccentricity.
 | 
						||
 *
 | 
						||
 * Result is in units used for semimajor axis, typically AU.
 | 
						||
 */
 | 
						||
function length1 (a, e) { // (a, e float64)  float64
 | 
						||
  const b = a * Math.sqrt(1 - e * e);
 | 
						||
  return Math.PI * (3 * (a + b) - Math.sqrt((a + 3 * b) * (3 * a + b)))
 | 
						||
}
 | 
						||
 | 
						||
/**
 | 
						||
 * Length2 returns an alternate approximation for the length of an elliptical
 | 
						||
 * orbit.
 | 
						||
 *
 | 
						||
 * Argument a is semimajor axis, e is eccentricity.
 | 
						||
 *
 | 
						||
 * Result is in units used for semimajor axis, typically AU.
 | 
						||
 */
 | 
						||
function length2 (a, e) { // (a, e float64)  float64
 | 
						||
  const b = a * Math.sqrt(1 - e * e);
 | 
						||
  const s = a + b;
 | 
						||
  const p = a * b;
 | 
						||
  const A = s * 0.5;
 | 
						||
  const G = Math.sqrt(p);
 | 
						||
  const H = 2 * p / s;
 | 
						||
  return Math.PI * (21 * A - 2 * G - 3 * H) * 0.125
 | 
						||
}
 | 
						||
 | 
						||
/**
 | 
						||
 * Length3 returns the length of an elliptical orbit.
 | 
						||
 *
 | 
						||
 * Argument a is semimajor axis, e is eccentricity.
 | 
						||
 *
 | 
						||
 * Result is exact, and in units used for semimajor axis, typically AU.
 | 
						||
 */
 | 
						||
/* As Meeus notes, Length4 converges faster.  There is no reason to use
 | 
						||
this function
 | 
						||
export function length3 (a, e) { // (a, e float64)  float64
 | 
						||
  const sum0 = 1.0
 | 
						||
  const e2 = e * e
 | 
						||
  const term = e2 * 0.25
 | 
						||
  const sum1 = 1.0 - term
 | 
						||
  const nf = 1.0
 | 
						||
  const df = 2.0
 | 
						||
  while (sum1 !== sum0) {
 | 
						||
    term *= nf
 | 
						||
    nf += 2
 | 
						||
    df += 2
 | 
						||
    term *= nf * e2 / (df * df)
 | 
						||
    sum0 = sum1
 | 
						||
    sum1 -= term
 | 
						||
  }
 | 
						||
  return 2 * Math.PI * a * sum0
 | 
						||
} */
 | 
						||
 | 
						||
/**
 | 
						||
 * Length4 returns the length of an elliptical orbit.
 | 
						||
 *
 | 
						||
 * Argument a is semimajor axis, e is eccentricity.
 | 
						||
 *
 | 
						||
 * Result is exact, and in units used for semimajor axis, typically AU.
 | 
						||
 */
 | 
						||
function length4 (a, e) { // (a, e float64)  float64
 | 
						||
  const b = a * Math.sqrt(1 - e * e);
 | 
						||
  const m = (a - b) / (a + b);
 | 
						||
  const m2 = m * m;
 | 
						||
  let sum0 = 1.0;
 | 
						||
  let term = m2 * 0.25;
 | 
						||
  let sum1 = 1.0 + term;
 | 
						||
  let nf = -1.0;
 | 
						||
  let df = 2.0;
 | 
						||
  while (sum1 !== sum0) {
 | 
						||
    nf += 2;
 | 
						||
    df += 2;
 | 
						||
    term *= nf * nf * m2 / (df * df);
 | 
						||
    sum0 = sum1;
 | 
						||
    sum1 += term;
 | 
						||
  }
 | 
						||
  return 2 * Math.PI * a * sum0 / (1 + m)
 | 
						||
}
 | 
						||
 | 
						||
var elliptic = {
 | 
						||
  position,
 | 
						||
  Elements,
 | 
						||
  astrometricJ2000,
 | 
						||
  velocity,
 | 
						||
  vAphelion,
 | 
						||
  vPerihelion,
 | 
						||
  length1,
 | 
						||
  length2,
 | 
						||
  // length3,
 | 
						||
  length4
 | 
						||
};
 | 
						||
 | 
						||
exports.Elements = Elements;
 | 
						||
exports.astrometricJ2000 = astrometricJ2000;
 | 
						||
exports["default"] = elliptic;
 | 
						||
exports.length1 = length1;
 | 
						||
exports.length2 = length2;
 | 
						||
exports.length4 = length4;
 | 
						||
exports.position = position;
 | 
						||
exports.vAphelion = vAphelion;
 | 
						||
exports.vPerihelion = vPerihelion;
 | 
						||
exports.velocity = velocity;
 |