Phase 1 — Stars, comets, Keplerian propagation: - star_observe() / star_observe_safe(): fixed star alt/az via IAU 1976 precession, equatorial-to-horizontal transform - kepler_propagate(): two-body Keplerian orbit propagation for elliptic, parabolic, and hyperbolic orbits - comet_observe(): observe comets/asteroids from orbital elements - heliocentric type: ecliptic J2000 position (x, y, z in AU) Phase 2 — VSOP87 planets, ELP82B Moon, Sun: - planet_heliocentric(): VSOP87 heliocentric ecliptic J2000 positions for Mercury through Neptune (Bretagnon & Francou, MIT) - planet_observe(): full observation pipeline for any planet - sun_observe(): Sun position from negated Earth VSOP87 - moon_observe(): ELP2000-82B lunar position (Chapront-Touzé, MIT) - Clean-room precession (IAU 2006) and sidereal time (IERS 2010) - elliptic_to_rectangular utility (Stellarium, MIT) All Stellarium extractions are MIT-licensed, thread-safe (static caching removed for PARALLEL SAFE), zero external data files. All 9 regression tests pass (90ms total).
123 lines
3.6 KiB
C
123 lines
3.6 KiB
C
/*
|
|
* star_funcs.c -- Star and fixed-position object observation
|
|
*
|
|
* Takes J2000 catalog coordinates (RA in hours, Dec in degrees),
|
|
* applies IAU 1976 precession to date of observation, computes
|
|
* local hour angle, and converts to topocentric azimuth/elevation.
|
|
*
|
|
* Range and range_rate are zero -- stars are effectively at infinity.
|
|
* For objects with known proper motion, apply it to (RA, Dec) before
|
|
* calling star_observe.
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
#include "fmgr.h"
|
|
#include "utils/timestamp.h"
|
|
#include "types.h"
|
|
#include "astro_math.h"
|
|
|
|
PG_FUNCTION_INFO_V1(star_observe);
|
|
PG_FUNCTION_INFO_V1(star_observe_safe);
|
|
|
|
/*
|
|
* star_observe(ra_hours, dec_degrees, observer, timestamptz) -> topocentric
|
|
*
|
|
* Compute az/el of a fixed celestial object from an observer at a time.
|
|
* Uses IAU 1976 precession (~1 arcsecond accuracy for centuries near J2000).
|
|
*/
|
|
Datum
|
|
star_observe(PG_FUNCTION_ARGS)
|
|
{
|
|
double ra_hours = PG_GETARG_FLOAT8(0);
|
|
double dec_deg = PG_GETARG_FLOAT8(1);
|
|
pg_observer *obs = (pg_observer *) PG_GETARG_POINTER(2);
|
|
int64 ts = PG_GETARG_INT64(3);
|
|
|
|
double jd;
|
|
double ra_j2000, dec_j2000;
|
|
double ra_date, dec_date;
|
|
double gmst, lst, ha;
|
|
double az, el;
|
|
pg_topocentric *result;
|
|
|
|
if (ra_hours < 0.0 || ra_hours >= 24.0)
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
errmsg("right ascension out of range: %.6f", ra_hours),
|
|
errhint("RA must be in [0, 24) hours.")));
|
|
|
|
if (dec_deg < -90.0 || dec_deg > 90.0)
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
errmsg("declination out of range: %.6f", dec_deg),
|
|
errhint("Declination must be between -90 and +90 degrees.")));
|
|
|
|
jd = timestamptz_to_jd(ts);
|
|
|
|
ra_j2000 = ra_hours * (M_PI / 12.0);
|
|
dec_j2000 = dec_deg * DEG_TO_RAD;
|
|
|
|
precess_j2000_to_date(jd, ra_j2000, dec_j2000, &ra_date, &dec_date);
|
|
|
|
gmst = gmst_from_jd(jd);
|
|
lst = gmst + obs->lon;
|
|
ha = lst - ra_date;
|
|
|
|
equatorial_to_horizontal(ha, dec_date, obs->lat, &az, &el);
|
|
|
|
result = (pg_topocentric *) palloc(sizeof(pg_topocentric));
|
|
result->azimuth = az;
|
|
result->elevation = el;
|
|
result->range_km = 0.0;
|
|
result->range_rate = 0.0;
|
|
|
|
PG_RETURN_POINTER(result);
|
|
}
|
|
|
|
|
|
/*
|
|
* star_observe_safe -- returns NULL if inputs are out of range.
|
|
* For batch queries over star catalogs.
|
|
*/
|
|
Datum
|
|
star_observe_safe(PG_FUNCTION_ARGS)
|
|
{
|
|
double ra_hours = PG_GETARG_FLOAT8(0);
|
|
double dec_deg = PG_GETARG_FLOAT8(1);
|
|
pg_observer *obs = (pg_observer *) PG_GETARG_POINTER(2);
|
|
int64 ts = PG_GETARG_INT64(3);
|
|
|
|
double jd;
|
|
double ra_j2000, dec_j2000;
|
|
double ra_date, dec_date;
|
|
double gmst, lst, ha;
|
|
double az, el;
|
|
pg_topocentric *result;
|
|
|
|
if (ra_hours < 0.0 || ra_hours >= 24.0)
|
|
PG_RETURN_NULL();
|
|
if (dec_deg < -90.0 || dec_deg > 90.0)
|
|
PG_RETURN_NULL();
|
|
|
|
jd = timestamptz_to_jd(ts);
|
|
|
|
ra_j2000 = ra_hours * (M_PI / 12.0);
|
|
dec_j2000 = dec_deg * DEG_TO_RAD;
|
|
|
|
precess_j2000_to_date(jd, ra_j2000, dec_j2000, &ra_date, &dec_date);
|
|
|
|
gmst = gmst_from_jd(jd);
|
|
lst = gmst + obs->lon;
|
|
ha = lst - ra_date;
|
|
|
|
equatorial_to_horizontal(ha, dec_date, obs->lat, &az, &el);
|
|
|
|
result = (pg_topocentric *) palloc(sizeof(pg_topocentric));
|
|
result->azimuth = az;
|
|
result->elevation = el;
|
|
result->range_km = 0.0;
|
|
result->range_rate = 0.0;
|
|
|
|
PG_RETURN_POINTER(result);
|
|
}
|