/* Copyright (c) 2014, Vladimir Agafonkin Copyright (c) 2024, cidoku All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * SunCalc (https://github.com/mourner/suncalc) is a JavaScript library for * calculating sun/moon position and light * phases. This is my port of part of SunCalc to C. */ #include #include #include "suncalc.h" // general sun calculations // sun calculations are based on http://aa.quae.nl/en/reken/zonpositie.html formulas void sun_coords(double d, double* dec, double* ra) { double M = SOLAR_MEAN_ANOMALY(d); double L = ECLIPTIC_LONGITUDE(M); *dec = DECLINATION(L, 0); *ra = RIGHT_ASCENSION(L, 0); } // calculations for sun times // sun times configuration: sunrise, sunrise_end, dawn, nautical_dawn, // night_end, golden_hour_end const double sun_times[SUN_TIMES_LEN] = {-0.833, -0.3, -6, -12, -18, 6}; // calculates sun times for a given date, latitude/longitude, and, optionally, // the observer height (in meters) relative to the horizon void get_sun_times(time_t date, double lat, double lng, int height, struct s_data* times) { double lw = RAD * -lng; double phi = RAD * lat; double dh = OBSERVER_ANGLE(height); double d = TO_DAYS(date + DAY_SEC); // I have no idea why it's off by a day double n = JULIAN_CYCLE(d, lw); double ds = APPROX_TRANSIT(0, lw, n); double M = SOLAR_MEAN_ANOMALY(ds); double L = ECLIPTIC_LONGITUDE(M); double dec = DECLINATION(L, 0); double J_noon = SOLAR_TRANSIT_J(ds, M, L); int len, set, rise; double time, h0, J_set, J_rise; times->solar_noon = FROM_JULIAN(J_noon); times->nadir = FROM_JULIAN(J_noon - 0.5); for (int i = 0; i < SUN_TIMES_LEN; i++) { time = sun_times[i]; h0 = (time + dh) * RAD; J_set = GET_SET_J(h0, lw, phi, dec, n, M, L); J_rise = J_noon - (J_set - J_noon); rise = FROM_JULIAN(J_rise); set = FROM_JULIAN(J_set); switch (i) { case 0: times->sunrise = rise; times->sunset = set; times->length = set - rise; break; case 1: times->sunrise_end = rise; times->sunset_start = set; break; case 2: times->dawn = rise; times->dusk = set; break; case 3: times->nautical_dawn = rise; times->nautical_dusk = set; break; case 4: times->night_end = rise; times->night = set; break; case 5: times->golden_hour_end = rise; times->golden_hour = set; break; } } } // moon coords calculation based on http://aa.quae.nl/en/reken/hemelpositie.html formulas void moon_coords(double d, double* dec, double* ra, double* dist) { // geocentric ecliptic coordinates of the moon double L = RAD * (218.316 + 13.176396 * d); // ecliptic longitude double M = RAD * (134.963 + 13.064993 * d); // mean anomaly double F = RAD * (93.272 + 13.229350 * d); // mean distance double l = L + RAD * 6.289 * sin(M); // longitude double b = RAD * 5.128 * sin(F); // latitude double dt = 385001 - 20905 * cos(M); // distance to the moon in km *dec = DECLINATION(l, b); *ra = RIGHT_ASCENSION(l, b); *dist = dt; } // calculations for illumination parameters of the moon, // based on http://idlastro.gsfc.nasa.gov/ftp/pro/astro/mphase.pro formulas and // Chapter 48 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. void get_moon_illumination(int date, struct m_light* m_light) { double d = TO_DAYS((double)date); double s_dec, m_dec, s_ra, m_ra, m_dist; sun_coords(d, &s_dec, &s_ra); moon_coords(d, &m_dec, &m_ra, &m_dist); const int sdist = 149598000; // distance from Earth to Sun in km double phi = acos(sin(s_dec) * sin(m_dec) + cos(s_dec) * cos(m_dec) * cos(s_ra - m_ra)); double inc = atan2(sdist * sin(phi), m_dist - sdist * cos(phi)); double ang = atan2(cos(s_dec) * sin(s_ra - m_ra), sin(s_dec) * cos(m_dec) - cos(s_dec) * sin(m_dec) * cos(s_ra - m_ra)); m_light->fraction = (1 + cos(inc)) / 2; m_light->phase = 0.5 + 0.5 * inc * (ang < 0 ? -1 : 1) / M_PI; m_light->angle = ang; }