UNPKG

astronomy-js

Version:

A lightweight javascript library for astronomical calculations.

299 lines (284 loc) 9.29 kB
import { RectangularCoordinates } from "./coordinates/rectangular-coordinates"; import { MathHelper } from "./math-helper"; import { SphericalCoordinates } from "./coordinates/spherical-coordinates"; import { TimeHelper } from "./time-helper"; import { Constants } from "./constants"; export class AstronomicalCalculator { constructor(sphericalCoordinates, solarSystemObject) { this.sphericalCoordinates = sphericalCoordinates || new SphericalCoordinates( Constants.GREENWICH_OBSERVATORY_COORDINATES.LATITUDE, Constants.GREENWICH_OBSERVATORY_COORDINATES.LONGITUDE, Constants.GREENWICH_OBSERVATORY_COORDINATES.RADIUS, ); this.solarSystemObject = solarSystemObject; } getRectangularObjectCentricCoordinatesForSolarSystemObject( otherSolarSystemObject, julianDate, ) { return otherSolarSystemObject .getRectangularHeliocentricCoordinates(julianDate) .minus( this.solarSystemObject.getRectangularHeliocentricCoordinates( julianDate, ), ); } getRectangularEquatorialCoordinatesForSolarSystemObject( otherSolarSystemObject, julianDate, ) { const rectangularObjectCentricCoordinatesForSolarSystemObject = this.getRectangularObjectCentricCoordinatesForSolarSystemObject( otherSolarSystemObject, julianDate, ); const axialTiltInRadians = MathHelper.degreesToRadians( this.solarSystemObject.axialTilt, ); return new RectangularCoordinates( rectangularObjectCentricCoordinatesForSolarSystemObject.x, rectangularObjectCentricCoordinatesForSolarSystemObject.y * Math.cos(axialTiltInRadians) - rectangularObjectCentricCoordinatesForSolarSystemObject.z * Math.sin(axialTiltInRadians), rectangularObjectCentricCoordinatesForSolarSystemObject.y * Math.sin(axialTiltInRadians) + rectangularObjectCentricCoordinatesForSolarSystemObject.z * Math.cos(axialTiltInRadians), ); } getDistanceToSolarSystemObject(otherSolarSystemObject, julianDate) { const objectCentricCoordinates = this.getRectangularObjectCentricCoordinatesForSolarSystemObject( otherSolarSystemObject, julianDate, ); return Math.sqrt( Math.pow(objectCentricCoordinates.x, 2) + Math.pow(objectCentricCoordinates.y, 2) + Math.pow(objectCentricCoordinates.z, 2), ); } getRADecCoordinatesForSolarSystemObject(otherSolarSystemObject, julianDate) { const equatorialCoordinates = this.getRectangularEquatorialCoordinatesForSolarSystemObject( otherSolarSystemObject, julianDate, ); const correction = equatorialCoordinates.x > 0 && equatorialCoordinates.y < 0 ? 360 : equatorialCoordinates.x < 0 ? 180 : 0; const rightAscension = MathHelper.radiansToDegrees( Math.atan(equatorialCoordinates.y / equatorialCoordinates.x), ) + correction; const declination = MathHelper.radiansToDegrees( Math.atan( equatorialCoordinates.z / Math.sqrt( Math.pow(equatorialCoordinates.x, 2) + Math.pow(equatorialCoordinates.y, 2), ), ), ); return new SphericalCoordinates( declination, rightAscension, this.getDistanceToSolarSystemObject(otherSolarSystemObject, julianDate), ); } getHADecCoordinatesForSolarSystemObject(otherSolarSystemObject, julianDate) { const equatorialCoordinates = this.getRectangularEquatorialCoordinatesForSolarSystemObject( otherSolarSystemObject, julianDate, ); const correction = equatorialCoordinates.x > 0 && equatorialCoordinates.y < 0 ? 360 : equatorialCoordinates.x < 0 ? 180 : 0; const rightAscension = MathHelper.radiansToDegrees( Math.atan(equatorialCoordinates.y / equatorialCoordinates.x), ) + correction; const localHourAngle = MathHelper.modDegrees( this.getLocalSiderealTime(julianDate) - rightAscension, ); const declination = MathHelper.radiansToDegrees( Math.atan( equatorialCoordinates.z / Math.sqrt( Math.pow(equatorialCoordinates.x, 2) + Math.pow(equatorialCoordinates.y, 2), ), ), ); return new SphericalCoordinates( declination, localHourAngle, this.getDistanceToSolarSystemObject(otherSolarSystemObject, julianDate), ); } getAltAzCoordinatesForEquatorialCoordinates( equatorialCoordinates, julianDate, ) { const hourAngle = MathHelper.degreesToRadians( MathHelper.modDegrees( equatorialCoordinates.longitude - this.getLocalSiderealTime(julianDate), ), ); const latitude = MathHelper.degreesToRadians( this.sphericalCoordinates.latitude, ); const declination = MathHelper.degreesToRadians( equatorialCoordinates.latitude, ); const altitude = MathHelper.radiansToDegrees( Math.asin( Math.sin(latitude) * Math.sin(declination) + Math.cos(latitude) * Math.cos(declination) * Math.cos(hourAngle), ), ); const azimuth = MathHelper.radiansToDegrees( Math.PI - Math.atan2( Math.sin(hourAngle), Math.cos(hourAngle) * Math.sin(latitude) - Math.tan(declination) * Math.cos(latitude), ), ); return new SphericalCoordinates(altitude, azimuth, null); } getLocalSiderealTime(julianDate) { return MathHelper.modDegrees( TimeHelper.meanSiderealTime(julianDate) + this.sphericalCoordinates.longitude, ); } getObjectTransit(otherSolarSystemObject, julianDate) { const rightAscension = this.getRADecCoordinatesForSolarSystemObject( otherSolarSystemObject, julianDate, ).longitude; return this.getLocalSiderealTime(julianDate) - rightAscension; } getObjectLocalHourAngleForAltitude( otherSolarSystemObject, julianDate, altitude, ) { const observerLatitude = MathHelper.degreesToRadians( this.sphericalCoordinates.latitude, ); const objectAltitude = MathHelper.degreesToRadians(altitude); const objectDeclination = MathHelper.degreesToRadians( this.getRADecCoordinatesForSolarSystemObject( otherSolarSystemObject, julianDate, ).latitude, ); const localHourAngle = (Math.sin(objectAltitude) - Math.sin(observerLatitude) * Math.sin(objectDeclination)) / (Math.cos(observerLatitude) * Math.cos(objectDeclination)); return MathHelper.radiansToDegrees(Math.acos(localHourAngle)); } getIterationValueForPositionalEphemerisForObject( solarSystemObject, julianDate, ephemerisType, ) { if (ephemerisType === Constants.EPHEMERIS_TYPE.TRANSIT) { return ( julianDate - this.getObjectTransit(solarSystemObject, julianDate) / 15 / 24 ); } else { const objectTransit = this.getObjectTransit( solarSystemObject, julianDate, ); const localHourAngle = this.getObjectLocalHourAngleForAltitude( solarSystemObject, julianDate, ephemerisType.ALTITUDE, ); const angleUntilRise = MathHelper.mod180Degrees( ephemerisType.IS_GOING_UP ? objectTransit + localHourAngle : objectTransit - localHourAngle, ); return julianDate - angleUntilRise / 15 / 24; } } iteratePositionalEphemerisForObject( otherSolarSystemObject, julianDate, ephemerisType, ) { let result = this.getIterationValueForPositionalEphemerisForObject( otherSolarSystemObject, julianDate, ephemerisType, ); let oldResult = +result; for (let loopCount = 0; loopCount < 1000; loopCount++) { result = this.getIterationValueForPositionalEphemerisForObject( otherSolarSystemObject, result, ephemerisType, ); if ((Math.abs(result - oldResult) < 10) ^ -5) { break; } oldResult = result; } return TimeHelper.julianDateToDate(result); } getCorrectDateForPositionalEphemeris( otherSolarSystemObject, julianDate, ephemerisType, numberOfAttemptsLeft, ) { const result = this.iteratePositionalEphemerisForObject( otherSolarSystemObject, julianDate, ephemerisType, ); if ( numberOfAttemptsLeft > 0 && result.getDate() !== TimeHelper.julianDateToDate(julianDate).getDate() ) { const resultAsJulianDate = TimeHelper.julianDate(result); const deltaDays = resultAsJulianDate > julianDate ? -1 : 1; return this.getCorrectDateForPositionalEphemeris( otherSolarSystemObject, resultAsJulianDate + deltaDays, ephemerisType, numberOfAttemptsLeft - 1, ); } else if (numberOfAttemptsLeft === 0) { return null; } else { return result; } } getDateForPositionalEphemeris(solarSystemObject, julianDate, ephemerisType) { return this.getCorrectDateForPositionalEphemeris( solarSystemObject, julianDate, ephemerisType, Constants.NUMBERS_OF_ATTEMPT_TO_GET_POSITIONAL_EPHEMERIS, ); } }