moon-sighting-dart/README.md

6.8 KiB

moon_sighting

pub package CI License: MIT

Lunar crescent visibility for Dart and Flutter. Computes moon phase, topocentric position, illumination, and Yallop/Odeh crescent visibility criteria using Meeus algorithms. Zero dependencies.

Installation

dependencies:
  moon_sighting: ^1.0.0

Quick Start

import 'package:moon_sighting/moon_sighting.dart';

// Current moon phase
final phase = getMoonPhase();
print('${phase.phaseName} ${phase.phaseSymbol}');
print('Illumination: ${phase.illumination.toStringAsFixed(1)}%');
print('Age: ${phase.age.toStringAsFixed(1)} hours');

// Moon position for an observer
final pos = getMoonPosition(DateTime.now(), 51.5074, -0.1278, elevation: 10);
print('Azimuth: ${pos.azimuth.toStringAsFixed(1)}');
print('Altitude: ${pos.altitude.toStringAsFixed(1)}');
print('Distance: ${pos.distance.toStringAsFixed(0)} km');

// Crescent visibility estimate (pass a post-sunset time)
final vis = getMoonVisibilityEstimate(
  DateTime.utc(2025, 3, 31, 18, 30),
  21.4225, 39.8262, // Mecca
);
print('Zone: ${vis.zone.label}'); // A through D
print('Visible naked eye: ${vis.isVisibleNakedEye}');

API

getMoonPhase([DateTime? date])

Returns MoonPhaseResult with:

Field Type Description
phase MoonPhaseName Enum: newMoon, waxingCrescent, firstQuarter, etc.
phaseName String Human-readable name
phaseSymbol String Moon emoji
illumination double Percent illuminated (0-100)
age double Hours since last new moon
elongationDeg double Moon-Sun elongation in degrees
isWaxing bool True when illumination is increasing
nextNewMoon DateTime Next new moon (UTC)
nextFullMoon DateTime Next full moon (UTC)
prevNewMoon DateTime Previous new moon (UTC)

getMoonPosition(DateTime? date, double lat, double lon, {double elevation = 0})

Returns MoonPosition with:

Field Type Description
azimuth double Degrees from North, clockwise
altitude double Degrees above horizon (refraction applied)
distance double Earth-Moon distance in km
parallacticAngle double Parallactic angle in radians

getMoonIllumination([DateTime? date])

Returns MoonIlluminationResult with:

Field Type Description
fraction double Illuminated fraction (0-1)
phase double Phase cycle (0=new, 0.25=Q1, 0.5=full, 0.75=Q3)
angle double Bright limb position angle (radians)
isWaxing bool True when waxing

getMoonVisibilityEstimate(DateTime? date, double lat, double lon, {double elevation = 0})

Returns MoonVisibilityEstimate with:

Field Type Description
v double Odeh V parameter
zone OdehZone Visibility zone (a through d)
description String Zone description
isVisibleNakedEye bool True for zone A
isVisibleWithOpticalAid bool True for zones A and B
arcl double Sun-Moon elongation (degrees)
arcv double Arc of vision (degrees)
w double Crescent width (arc minutes)
moonAboveHorizon bool Moon above horizon at given time

getMoon(DateTime? date, double lat, double lon, {double elevation = 0})

Returns MoonSnapshot combining all four results: phase, position, illumination, visibility.

Visibility Criteria

The Odeh criterion (2006) classifies crescent visibility into four zones:

Zone V threshold Meaning
A V >= 5.65 Visible with naked eye
B V >= 2.00 Visible with optical aid, may be seen naked eye
C V >= -0.96 Visible with optical aid only
D V < -0.96 Not visible even with optical aid

The Yallop q-test (1997) uses six categories A through F with different threshold semantics. Both criteria use the same underlying polynomial for the minimum arc of vision as a function of crescent width.

Accuracy

All positions use Meeus (1998) approximations:

  • Sun: < 0.01 deg ecliptic longitude error
  • Moon: < 0.3 deg longitude, < 0.2 deg latitude
  • Distance: ~300 km error (~0.08%)
  • New/full moon times: within ~2 hours

The GCRS-to-topocentric conversion uses a simplified Earth rotation (ERA only, no nutation/precession), adding ~1 deg systematic error. This is acceptable for phase displays, illumination calculations, and approximate visibility estimates.

For high-precision crescent sighting reports with DE442S ephemeris accuracy, see the TypeScript moon-sighting package.

Lite Mode vs Full Mode

This Dart package implements lite mode only. It covers moon phase, position, illumination, and quick visibility estimates using analytical Meeus algorithms with no external data files.

The full-mode features (DE442S JPL ephemeris, sub-arcsecond accuracy, rise/set event finding, best-time optimization, full sighting reports) are available in the TypeScript package.

Architecture

Two-mode design: lite mode uses Jean Meeus Chapters 47 and 48 for moon phase, position, and illumination: zero dependencies, no file I/O, works in any Dart environment. The GCRS-to-topocentric conversion applies ERA-only Earth rotation (no full nutation/precession), which introduces a ~1 degree systematic error acceptable for display and quick-estimate use cases.

Full-mode features (DE442S ephemeris, sub-arcsecond accuracy, rise/set event finding) are in the TypeScript moon-sighting package.

Compatibility

  • Dart SDK >= 3.7.0
  • Works in Flutter, Dart CLI, and server-side Dart
  • Zero runtime dependencies
  • moon-sighting (TypeScript) - Full-accuracy lunar crescent visibility with DE442S ephemeris
  • nrel-spa (TypeScript) - Pure JS NREL Solar Position Algorithm
  • pray-calc (JavaScript) - Islamic prayer time calculation
  • luxon-hijri (TypeScript) - Hijri/Gregorian calendar conversion

Acknowledgments

Crescent visibility criteria implemented from:

  • B.D. Yallop, "A Method for Predicting the First Sighting of the New Crescent Moon," NAO Technical Note No. 69, 1997.
  • M.Sh. Odeh, "New Criterion for Lunar Crescent Visibility," Experimental Astronomy 18(1), 39-64, 2006.

Meeus positions from: Jean Meeus, "Astronomical Algorithms," 2nd ed., Chapters 47 and 48.

License

MIT