localSolar function

({double? localMaximum, double magnitude, double obscuration, double? sunAltitude, int type, bool visible}) localSolar(
  1. double jmax,
  2. double lat,
  3. double lon, {
  4. double height = 0,
  5. double? deltaT,
})

Local circumstances for a solar eclipse near global maximum jmax.

jmax is the Julian Ephemeris Day returned by solar. lat and lon are the observer's geodetic latitude and longitude in radians, with longitude positive west. height is metres above the reference ellipsoid.

The calculation samples the topocentric separation of the apparent Sun and Moon over the global eclipse window, then refines the closest visible approach. It determines whether any part of the solar disc is eclipsed while above the geometric horizon. It does not calculate contact times or account for the lunar limb profile or atmospheric refraction.

deltaT is TD - UT in seconds. When omitted, the package's polynomial or tabular approximation is used.

Implementation

({
  bool visible,
  int type,
  double? localMaximum,
  double magnitude,
  double obscuration,
  double? sunAltitude,
})
localSolar(
  double jmax,
  double lat,
  double lon, {
  double height = 0,
  double? deltaT,
}) {
  final dt = deltaT ?? _estimatedDeltaT(jmax);
  final observer = globe.parallaxConstants(lat, height);

  // The complete partial phase of even the longest solar eclipses fits well
  // inside this window. Two-minute samples avoid missing a short grazing
  // eclipse; the best interval is refined below.
  const halfWindow = 4 / 24;
  const step = 2 / 1440;
  _LocalSolarSample? best;

  for (
    var jde = jmax - halfWindow;
    jde <= jmax + halfWindow + step / 2;
    jde += step
  ) {
    final sample = _localSolarSample(jde, lat, lon, observer, dt);
    if (!sample.aboveHorizon) continue;
    if (best == null || sample.separation < best.separation) best = sample;
  }

  if (best == null) return _noLocalSolar;
  var resolved = best;

  // Refine the two-minute bracket around the best sampled instant.
  var lo = resolved.jde - step;
  var hi = resolved.jde + step;
  for (var i = 0; i < 32; i++) {
    final m1 = lo + (hi - lo) / 3;
    final m2 = hi - (hi - lo) / 3;
    final s1 = _localSolarSample(m1, lat, lon, observer, dt);
    final s2 = _localSolarSample(m2, lat, lon, observer, dt);
    final v1 = s1.aboveHorizon ? s1.separation : double.infinity;
    final v2 = s2.aboveHorizon ? s2.separation : double.infinity;
    if (v1 <= v2) {
      hi = m2;
      if (v1 < resolved.separation) resolved = s1;
    } else {
      lo = m1;
      if (v2 < resolved.separation) resolved = s2;
    }
  }

  final sum = resolved.sunRadius + resolved.moonRadius;
  if (resolved.separation >= sum) return _noLocalSolar;

  final difference = (resolved.sunRadius - resolved.moonRadius).abs();
  final int localType;
  final double magnitude;
  if (resolved.separation <= difference) {
    localType = resolved.moonRadius >= resolved.sunRadius ? total : annular;
    magnitude = resolved.moonRadius / resolved.sunRadius;
  } else {
    localType = partial;
    magnitude = (sum - resolved.separation) / (2 * resolved.sunRadius);
  }

  return (
    visible: true,
    type: localType,
    localMaximum: resolved.jde,
    magnitude: magnitude,
    obscuration: _discObscuration(
      resolved.sunRadius,
      resolved.moonRadius,
      resolved.separation,
    ),
    sunAltitude: resolved.sunAltitude,
  );
}