Files
astronomy/demo/nodejs/camera.js
Don Cross 0547aafc2b Made 'camera' demo checks tolerant of floating point roundoff.
The demo tests on Mac OS failed because of very tiny
floating point discrepancies that don't matter.
Changed the output of the "Moon check" so that slight
differences in vector residue no longer fail the unit tests.
2022-01-06 21:25:26 -05:00

127 lines
5.1 KiB
JavaScript

/*
camera.js - by Don Cross - 2021-03-26
Example Node.js program for Astronomy Engine:
https://github.com/cosinekitty/astronomy
Given an observer's location on the Earth and a date/time,
calculates the angle of the sunlit side of the Moon as
seen through a camera aimed at it.
To execute, run the command:
node camera latitude longitude [date]
*/
const Astronomy = require('./astronomy.js');
function ParseNumber(text, name) {
const x = Number(text);
if (!Number.isFinite(x)) {
console.error(`ERROR: Not a valid numeric value for ${name}: "${text}"`);
process.exit(1);
}
return x;
}
function ParseDate(text) {
const d = new Date(text);
if (!Number.isFinite(d.getTime())) {
console.error(`ERROR: Not a valid date: "${text}"`);
process.exit(1);
}
return d;
}
function Camera(observer, time) {
const tolerance = 1.0e-15;
const RAD2DEG = 57.295779513082321;
// Calculate the topocentric equatorial coordinates of date for the Moon.
// Assume aberration does not matter because the Moon is so close and has such a small relative velocity.
const moon_equ = Astronomy.Equator(Astronomy.Body.Moon, time, observer, true, false);
// Also calculate the Sun's topocentric position in the same coordinate system.
const sun_equ = Astronomy.Equator(Astronomy.Body.Sun, time, observer, true, false);
// Get the Moon's horizontal coordinates, so we know how much to pivot azimuth and altitude.
const moon_hor = Astronomy.Horizon(time, observer, moon_equ.ra, moon_equ.dec, false);
console.log(`Moon horizontal position: azimuth = ${moon_hor.azimuth.toFixed(3)}, altitude = ${moon_hor.altitude.toFixed(3)}`);
// Get the rotation matrix that converts equatorial to horizontal coordintes for this place and time.
let rot = Astronomy.Rotation_EQD_HOR(time, observer);
// Modify the rotation matrix in two steps:
// First, rotate the orientation so we are facing the Moon's azimuth.
// We do this by pivoting around the zenith axis.
// Horizontal axes are: 0 = north, 1 = west, 2 = zenith.
// Tricky: because the pivot angle increases counterclockwise, and azimuth
// increases clockwise, we undo the azimuth by adding the positive value.
rot = Astronomy.Pivot(rot, 2, moon_hor.azimuth);
// Second, pivot around the leftward axis to bring the Moon to the camera's altitude level.
// From the point of view of the leftward axis, looking toward the camera,
// adding the angle is the correct sense for subtracting the altitude.
rot = Astronomy.Pivot(rot, 1, moon_hor.altitude);
// As a sanity check, apply this rotation to the Moon's equatorial (EQD) coordinates and verify x=0, y=0.
let vec = Astronomy.RotateVector(rot, moon_equ.vec);
// Convert to unit vector.
const radius = vec.Length();
vec.x /= radius;
vec.y /= radius;
vec.z /= radius;
console.log(`Moon check: x = ${vec.x.toFixed(6)}, y = ${Math.abs(vec.y).toFixed(6)}, z = ${Math.abs(vec.z).toFixed(6)}`);
if (!Number.isFinite(vec.x) || Math.abs(vec.x - 1.0) > tolerance) {
console.error("Excessive error in moon check (x).");
return 1;
}
if (!Number.isFinite(vec.y) || Math.abs(vec.y) > tolerance) {
console.error("Excessive error in moon check (y).");
return 1;
}
if (!Number.isFinite(vec.z) || Math.abs(vec.z) > tolerance) {
console.error("Excessive error in moon check (z).");
return 1;
}
// Apply the same rotation to the Sun's equatorial vector.
// The x- and y-coordinates now tell us which side appears sunlit in the camera!
vec = Astronomy.RotateVector(rot, sun_equ.vec);
// Don't bother normalizing the Sun vector, because in AU it will be close to unit anyway.
console.log(`Sun vector: x = ${vec.x.toFixed(6)}, y = ${vec.y.toFixed(6)}, z = ${vec.z.toFixed(6)}`);
// Calculate the tilt angle of the sunlit side, as seen by the camera.
// The x-axis is now pointing directly at the object, z is up in the camera image, y is to the left.
const tilt = RAD2DEG * Math.atan2(vec.z, vec.y);
console.log(`Tilt angle of sunlit side of the Moon = ${tilt.toFixed(3)} degrees counterclockwise from up.`);
const illum = Astronomy.Illumination(Astronomy.Body.Moon, time);
console.log(`Moon magnitude = ${illum.mag.toFixed(2)}, phase angle = ${illum.phase_angle.toFixed(2)} degrees.`);
const angle = Astronomy.AngleFromSun(Astronomy.Body.Moon, time);
console.log(`Angle between Moon and Sun as seen from Earth = ${angle.toFixed(2)} degrees.`);
}
function Demo() {
if (process.argv.length === 4 || process.argv.length === 5) {
const latitude = ParseNumber(process.argv[2]);
const longitude = ParseNumber(process.argv[3]);
const observer = new Astronomy.Observer(latitude, longitude, 0);
const time = Astronomy.MakeTime((process.argv.length === 5) ? ParseDate(process.argv[4]) : new Date());
Camera(observer, time);
process.exit(0);
} else {
console.log('USAGE: node camera latitude longitude [date]');
process.exit(1);
}
}
Demo();