mirror of
https://github.com/acamarata/pray-calc-dart.git
synced 2026-07-01 03:14:27 +00:00
98 lines
3.2 KiB
Dart
98 lines
3.2 KiB
Dart
/// High-accuracy solar ephemeris using Jean Meeus "Astronomical Algorithms"
|
||
/// (2nd ed., Ch. 25) low-precision formulas.
|
||
///
|
||
/// Accuracy: ~0.01° for solar declination, ~0.0001 AU for Earth-Sun distance
|
||
/// over years 1950–2050.
|
||
library;
|
||
|
||
import 'dart:math';
|
||
|
||
import 'types.dart';
|
||
|
||
/// Julian Date from a Dart [DateTime] (UTC).
|
||
double toJulianDate(DateTime date) {
|
||
return date.millisecondsSinceEpoch / 86400000.0 + 2440587.5;
|
||
}
|
||
|
||
/// Compute solar declination, Earth-Sun distance, and ecliptic longitude
|
||
/// from a Julian Date.
|
||
SolarEphemeris solarEphemeris(double jd) {
|
||
const deg = pi / 180;
|
||
final t = (jd - 2451545.0) / 36525.0;
|
||
|
||
// Geometric mean longitude L0 (degrees)
|
||
final l0 =
|
||
((280.46646 + 36000.76983 * t + 0.0003032 * t * t) % 360 + 360) % 360;
|
||
|
||
// Mean anomaly M (degrees)
|
||
final m =
|
||
((357.52911 + 35999.05029 * t - 0.0001537 * t * t) % 360 + 360) % 360;
|
||
final mRad = m * deg;
|
||
|
||
// Orbital eccentricity
|
||
final e = 0.016708634 - 0.000042037 * t - 0.0000001267 * t * t;
|
||
|
||
// Equation of center C (degrees)
|
||
final c =
|
||
(1.914602 - 0.004817 * t - 0.000014 * t * t) * sin(mRad) +
|
||
(0.019993 - 0.000101 * t) * sin(2 * mRad) +
|
||
0.000289 * sin(3 * mRad);
|
||
|
||
// Sun's true longitude (degrees)
|
||
final sunLon = l0 + c;
|
||
|
||
// Sun's true anomaly (degrees)
|
||
final nu = m + c;
|
||
final nuRad = nu * deg;
|
||
|
||
// Earth-Sun distance in AU
|
||
final r = (1.000001018 * (1 - e * e)) / (1 + e * cos(nuRad));
|
||
|
||
// Longitude of ascending node of Moon's orbit (for nutation)
|
||
final omega = ((125.04 - 1934.136 * t) % 360 + 360) % 360;
|
||
final omegaRad = omega * deg;
|
||
|
||
// Apparent solar longitude corrected for nutation and aberration
|
||
final lambda = sunLon - 0.00569 - 0.00478 * sin(omegaRad);
|
||
final lambdaRad = lambda * deg;
|
||
|
||
// Mean obliquity of the ecliptic (degrees)
|
||
final epsilon0 =
|
||
23.439291 - 0.013004 * t - 1.638e-7 * t * t + 5.036e-7 * t * t * t;
|
||
|
||
// True obliquity with nutation correction
|
||
final epsilon = (epsilon0 + 0.00256 * cos(omegaRad)) * deg;
|
||
|
||
// Solar declination
|
||
final sinDecl = sin(epsilon) * sin(lambdaRad);
|
||
final decl = asin(sinDecl.clamp(-1.0, 1.0)) / deg;
|
||
|
||
// Ecliptic longitude as season phase θ ∈ [0, 2π)
|
||
final eclLon = ((lambdaRad % (2 * pi)) + 2 * pi) % (2 * pi);
|
||
|
||
return SolarEphemeris(decl: decl, r: r, eclLon: eclLon);
|
||
}
|
||
|
||
/// Solar vertical angular speed near a given hour angle [hAngleRad] (radians),
|
||
/// in degrees per hour.
|
||
double solarVerticalSpeed(double latRad, double declRad, double hAngleRad) {
|
||
return 15 * (cos(latRad) * cos(declRad) * sin(hAngleRad)).abs();
|
||
}
|
||
|
||
/// Compute the atmospheric refraction correction (degrees) for a given
|
||
/// apparent solar altitude using the Bennett/Saemundsson formula.
|
||
///
|
||
/// Returns a positive correction. For altitudes below -1°, returns 0.
|
||
double atmosphericRefraction(
|
||
double altitudeDeg, {
|
||
double pressureMbar = 1013.25,
|
||
double temperatureC = 15,
|
||
}) {
|
||
if (altitudeDeg < -1) return 0;
|
||
const deg = pi / 180;
|
||
// Bennett's formula in arcminutes
|
||
final r0 = 1.02 / tan((altitudeDeg + 10.3 / (altitudeDeg + 5.11)) * deg);
|
||
// Scale for pressure and temperature
|
||
final r = r0 * (pressureMbar / 1010) * (283 / (273 + temperatureC));
|
||
return r < 0 ? 0.0 : r / 60; // convert arcminutes to degrees
|
||
}
|