Astronomia
Astronomical algorithms in Dart, ported from Jean Meeus's Astronomical Algorithms (2nd Ed.) via the Go meeus library and the JS astronomia library.
Features
56 modules covering positional astronomy, celestial mechanics, and calendar computations:
| Category | Modules |
|---|---|
| Time & Calendar | Julian Day, Delta T, sidereal time, equation of time, Easter |
| Coordinates | Ecliptic/equatorial/horizontal/galactic transforms, precession, nutation, parallax, refraction, aberration |
| Sun | Solar position (low-acc + VSOP87), solstices & equinoxes, sunrise/sunset, solar disk ephemeris |
| Moon | Lunar position, phases, illumination, nodes, apsis, max declination, moonrise/moonset, physical libration, selenographic coords |
| Planets | VSOP87 heliocentric positions (all 8 planets), geocentric positions with light-time correction, Kepler solvers, orbital elements, conjunctions, oppositions, elongations, Pluto |
| Orbits | Elliptic, parabolic, and near-parabolic motion, velocity, orbit length |
| Planet Details | Illumination & magnitudes, Jupiter physical ephemeris, Galilean moons, Saturn ring geometry, Saturn moons, Mars physical ephemeris |
| Rise/Set | Meeus ch. 15 refined algorithm with 3-day interpolation for any body |
| Geodesy | Earth ellipsoid, geodetic distance, parallax constants |
| Stellar | Magnitude arithmetic, binary star orbits, angular separation |
| Misc | Eclipse prediction, semidiameters, sundials, smallest circle, collinearity |
Getting started
dependencies:
astronomia: ^0.3.1
import 'package:astronomia/astronomia.dart';
Usage
The barrel import gives you foundations (julian, coordinates, nutation, etc.):
import 'package:astronomia/astronomia.dart';
void main() {
// Julian Day for J2000.0
final jd = calendarGregorianToJD(2000, 1, 1.5);
print('J2000.0 = JD $jd'); // 2451545.0
// Date of Easter 2025
final e = gregorian(2025);
print('Easter 2025: April ${e.day}'); // April 20
}
For specialized modules, import them directly — many share common names
like position, radius, eccentricity, so prefixed imports keep things clear:
import 'package:astronomia/astronomia.dart';
import 'package:astronomia/solar.dart' as solar;
import 'package:astronomia/moonposition.dart' as moon;
import 'package:astronomia/moonphase.dart' as phase;
import 'package:astronomia/rise.dart' as rise;
import 'package:astronomia/globe.dart' as globe;
void main() {
final jd = calendarGregorianToJD(2000, 1, 1.5);
// Solar ecliptic longitude
final sunLon = solar.apparentLongitude(j2000Century(jd));
// Moon position
final pos = moon.position(jd);
print('Moon: lon=${toDeg(pos.lon)}°, lat=${toDeg(pos.lat)}°');
// Next new moon
final newMoonJDE = phase.newMoon(2025.5);
// Earth surface distance (km)
final km = globe.distance(lat1, lon1, lat2, lon2);
}
Moonrise / Moonset
import 'package:astronomia/astronomia.dart';
import 'package:astronomia/rise.dart' as rise;
import 'package:astronomia/moonposition.dart' as moon;
import 'package:astronomia/sidereal.dart' as sid;
import 'package:astronomia/coord.dart' as coord;
import 'dart:math' as math;
void main() {
// London, 2025 March 8 at midnight UT
final jd = calendarGregorianToJD(2025, 3, 8.0);
final lat = toRad(51.5);
final lon = toRad(0.0); // Greenwich, positive west
final th0 = sid.apparent0UT(jd);
final result = rise.moonTimes(jd, lat, lon, 69, th0, (jde) {
final pos = moon.position(jde);
final eps = toRad(23.44);
final eq = coord.eclToEq(pos.lon, pos.lat, math.sin(eps), math.cos(eps));
return (ra: eq.ra, dec: eq.dec, parallax: moon.parallax(pos.delta));
});
if (result != null) {
print('Moonrise: ${(result.rise / 3600).toStringAsFixed(1)}h UT');
print('Transit: ${(result.transit / 3600).toStringAsFixed(1)}h UT');
print('Moonset: ${(result.set / 3600).toStringAsFixed(1)}h UT');
}
}
Planet positions
import 'package:astronomia/planetposition.dart';
import 'package:astronomia/elliptic.dart' as elliptic;
import 'package:astronomia/astronomia.dart';
void main() {
final earth = Planet(planetEarth);
final mars = Planet(planetMars);
final jde = 2451545.0; // J2000
// Heliocentric ecliptic (VSOP87)
final pos = mars.position2000(jde);
print('Mars: L=${toDeg(pos.lon)}°, R=${pos.range} AU');
// Geocentric equatorial (observed)
final eq = elliptic.position(mars, earth, jde);
print('Mars: RA=${toDeg(eq.ra)}°, Dec=${toDeg(eq.dec)}°');
}
Conventions
- All angles are in radians (
double). UsetoRad()/toDeg()to convert. - Time is represented as Julian Day numbers (
double). - Multi-value returns use Dart records:
({double lon, double lat, double delta}). - The J2000.0 epoch constant is
j2000 = 2451545.0.
Status
All 56 modules fully implemented (1 stub: Jewish/Moslem calendars). 216 tests passing, validated against examples from Meeus's book.
References
- Meeus, Jean. Astronomical Algorithms. 2nd ed. Richmond: Willmann-Bell, 1998.
- soniakeys/meeus (Go)
- commenthol/astronomia (JS)
License
MIT
Libraries
- angle
- apparent
- apsis
- astronomia
- Astronomical algorithms in Dart.
- base
- binary
- circle
- conjunction
- coord
- deltat
- easter
- eclipse
- elementequinox
- elliptic
- eqtime
- fit
- globe
- illum
- interpolation
- iterate
- jm
- julian
- jupiter
- jupitermoons
- kepler
- line
- mars
- moon
- moonillum
- moonmaxdec
- moonnode
- moonphase
- moonposition
- nearparabolic
- node2
- nutation
- parabolic
- parallactic
- parallax
- perihelion
- planetary
- planetelements
- planetposition
- pluto
- precess
- refraction
- rise
- saturnmoons
- saturnring
- semidiameter
- sexagesimal
- sidereal
- solar
- solardisk
- solarxyz
- solstice
- stellar
- sundial
- sunrise