|
| 1 | +/* |
| 2 | + equatorial.js - by Don Cross - 2021-03-27 |
| 3 | +
|
| 4 | + Example Node.js program for Astronomy Engine: |
| 5 | + https://github.com/cosinekitty/astronomy |
| 6 | +
|
| 7 | + Given an observer's location on the Earth, a |
| 8 | + date/time, and horizontal coordinates (azimuth, altitude) |
| 9 | + for that observer, this program works backwards |
| 10 | + to figure out the equatorial coordinates for that |
| 11 | + location in the sky. It provides two solutions: |
| 12 | + one that includes atmospheric refraction, another |
| 13 | + that ignores atmospheric refraction. |
| 14 | +
|
| 15 | + To execute, run the command: |
| 16 | + node equatorial latitude longitude azimuth altitude [date] |
| 17 | +*/ |
| 18 | + |
| 19 | +const Astronomy = require('./astronomy.js'); |
| 20 | + |
| 21 | +function ParseNumber(text, name) { |
| 22 | + const x = Number(text); |
| 23 | + if (!Number.isFinite(x)) { |
| 24 | + console.error(`ERROR: Not a valid numeric value for ${name}: "${text}"`); |
| 25 | + process.exit(1); |
| 26 | + } |
| 27 | + return x; |
| 28 | +} |
| 29 | + |
| 30 | +function ParseDate(text) { |
| 31 | + const d = new Date(text); |
| 32 | + if (!Number.isFinite(d.getTime())) { |
| 33 | + console.error(`ERROR: Not a valid date: "${text}"`); |
| 34 | + process.exit(1); |
| 35 | + } |
| 36 | + return d; |
| 37 | +} |
| 38 | + |
| 39 | + |
| 40 | +function Format(x, length, digits) { |
| 41 | + let s = x.toFixed(digits); |
| 42 | + while (s.length < length) |
| 43 | + s = ' ' + s; |
| 44 | + return s; |
| 45 | +} |
| 46 | + |
| 47 | + |
| 48 | +function Solve(refract, observer, time, azimuth, altitude) { |
| 49 | + // Convert the angular horizontal coordinates (azimuth, altitude) |
| 50 | + // to a horizontal vector (north, west, zenith). |
| 51 | + const hor_sphere = new Astronomy.Spherical(altitude, azimuth, 1); |
| 52 | + const refraction_option = refract ? 'normal' : null; |
| 53 | + const hor_vec = Astronomy.VectorFromHorizon(hor_sphere, time, refraction_option); |
| 54 | + |
| 55 | + // Make a rotation matrix for this observer and date/time that converts |
| 56 | + // horizontal coordinates (HOR) to equatorial coordinates in the J2000 epoch (EQJ). |
| 57 | + const rot_hor_eqj = Astronomy.Rotation_HOR_EQJ(time, observer); |
| 58 | + |
| 59 | + // Use the rotation matrix to convert the horizontal vector to an equatorial vector. |
| 60 | + const eqj_vec = Astronomy.RotateVector(rot_hor_eqj, hor_vec); |
| 61 | + |
| 62 | + // Convert the equatorial vector to equatorial angular coordinates (RA, DEC). |
| 63 | + const eqj = Astronomy.EquatorFromVector(eqj_vec); |
| 64 | + |
| 65 | + // Self-check the answers by converting back to horizontal coordinates, |
| 66 | + // using a different algorithm that has been tested to work. |
| 67 | + |
| 68 | + // First we need to convert J2000 equatorial (EQJ) to equator-of-date (EQD), |
| 69 | + // because the Horizon function expects EQD. |
| 70 | + const rot_eqj_eqd = Astronomy.Rotation_EQJ_EQD(time); |
| 71 | + const eqd_vec = Astronomy.RotateVector(rot_eqj_eqd, eqj_vec); |
| 72 | + const eqd = Astronomy.EquatorFromVector(eqd_vec); |
| 73 | + |
| 74 | + const check_hor = Astronomy.Horizon(time, observer, eqd.ra, eqd.dec, refraction_option); |
| 75 | + const alt_error = Math.abs(check_hor.altitude - altitude); |
| 76 | + const az_error = Math.abs(check_hor.azimuth - azimuth); |
| 77 | + |
| 78 | + let line = (refract ? ' yes' : ' no '); |
| 79 | + line += ' ' + Format(eqj.ra, 10, 4); |
| 80 | + line += ' ' + Format(eqj.dec, 10, 4); |
| 81 | + line += ' ' + Format(eqd.ra, 10, 4); |
| 82 | + line += ' ' + Format(eqd.dec, 10, 4); |
| 83 | + line += ' ' + Format(alt_error, 10, 6); |
| 84 | + line += ' ' + Format(az_error, 10, 6); |
| 85 | + console.log(line); |
| 86 | +} |
| 87 | + |
| 88 | + |
| 89 | +function Demo() { |
| 90 | + if (process.argv.length === 6 || process.argv.length === 7) { |
| 91 | + const latitude = ParseNumber(process.argv[2]); |
| 92 | + const longitude = ParseNumber(process.argv[3]); |
| 93 | + const observer = new Astronomy.Observer(latitude, longitude, 0); |
| 94 | + const azimuth = ParseNumber(process.argv[4]); |
| 95 | + const altitude = ParseNumber(process.argv[5]); |
| 96 | + const time = Astronomy.MakeTime((process.argv.length === 7) ? ParseDate(process.argv[6]) : new Date()); |
| 97 | + |
| 98 | + // Print a common header for both solutions. |
| 99 | + console.log('Refract? J2000_RA J2000_DEC OFDATE_RA OFDATE_DEC ALT_error AZ_error'); |
| 100 | + |
| 101 | + // Solve once ignoring atmospheric refraction. |
| 102 | + Solve(false, observer, time, azimuth, altitude); |
| 103 | + |
| 104 | + // Solve again considering atmospheric refraction. |
| 105 | + Solve(true, observer, time, azimuth, altitude); |
| 106 | + |
| 107 | + process.exit(0); |
| 108 | + } else { |
| 109 | + console.log('USAGE: node equatorial latitude longitude azimuth altitude [date]'); |
| 110 | + process.exit(1); |
| 111 | + } |
| 112 | +} |
| 113 | + |
| 114 | +Demo(); |
0 commit comments