acid-drop

- Hacking the planet from a LilyGo T-Deck using custom firmware
git clone git://git.acid.vegas/acid-drop.git
Log | Files | Refs | Archive | README | LICENSE

astronomy.h (44760B)

      1 /*
      2     Astronomy Engine for C/C++.
      3     https://github.com/cosinekitty/astronomy
      4 
      5     MIT License
      6 
      7     Copyright (c) 2019-2020 Don Cross <cosinekitty@gmail.com>
      8 
      9     Permission is hereby granted, free of charge, to any person obtaining a copy
     10     of this software and associated documentation files (the "Software"), to deal
     11     in the Software without restriction, including without limitation the rights
     12     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     13     copies of the Software, and to permit persons to whom the Software is
     14     furnished to do so, subject to the following conditions:
     15 
     16     The above copyright notice and this permission notice shall be included in all
     17     copies or substantial portions of the Software.
     18 
     19     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     20     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     21     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     22     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     23     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     24     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     25     SOFTWARE.
     26 */
     27 
     28 #ifndef __ASTRONOMY_H
     29 #define __ASTRONOMY_H
     30 
     31 #include <stddef.h>     /* for size_t */
     32 
     33 #ifdef __cplusplus
     34 extern "C" {
     35 #endif
     36 
     37 /*---------- types ----------*/
     38 
     39 /**
     40  * @brief Indicates success/failure of an Astronomy Engine function call.
     41  */
     42 typedef enum
     43 {
     44     ASTRO_SUCCESS,                  /**< The operation was successful. */
     45     ASTRO_NOT_INITIALIZED,          /**< A placeholder that can be used for data that is not yet initialized. */
     46     ASTRO_INVALID_BODY,             /**< The celestial body was not valid. Different sets of bodies are supported depending on the function. */
     47     ASTRO_NO_CONVERGE,              /**< A numeric solver failed to converge. This should not happen unless there is a bug in Astronomy Engine. */
     48     ASTRO_BAD_TIME,                 /**< The provided date/time is outside the range allowed by this function. */
     49     ASTRO_BAD_VECTOR,               /**< Vector magnitude is too small to be normalized into a unit vector. */
     50     ASTRO_SEARCH_FAILURE,           /**< Search was not able to find an ascending root crossing of the function in the specified time interval. */
     51     ASTRO_EARTH_NOT_ALLOWED,        /**< The Earth cannot be treated as a celestial body seen from an observer on the Earth itself. */
     52     ASTRO_NO_MOON_QUARTER,          /**< No lunar quarter occurs inside the specified time range. */
     53     ASTRO_WRONG_MOON_QUARTER,       /**< Internal error: Astronomy_NextMoonQuarter found the wrong moon quarter. */
     54     ASTRO_INTERNAL_ERROR,           /**< A self-check failed inside the code somewhere, indicating a bug needs to be fixed. */
     55     ASTRO_INVALID_PARAMETER,        /**< A parameter value passed to a function was not valid. */
     56     ASTRO_FAIL_APSIS,               /**< Special-case logic for finding Neptune/Pluto apsis failed. */
     57     ASTRO_BUFFER_TOO_SMALL,         /**< A provided buffer's size is too small to receive the requested data. */
     58     ASTRO_OUT_OF_MEMORY             /**< An attempt to allocate memory failed. */
     59 }
     60 astro_status_t;
     61 
     62 /**
     63  * @brief A date and time used for astronomical calculations.
     64  *
     65  * This type is of fundamental importance to Astronomy Engine.
     66  * It is used to represent dates and times for all astronomical calculations.
     67  * It is also included in the values returned by many Astronomy Engine functions.
     68  *
     69  * To create a valid astro_time_t value from scratch, call #Astronomy_MakeTime
     70  * (for a given calendar date and time) or #Astronomy_CurrentTime (for the system's
     71  * current date and time).
     72  *
     73  * To adjust an existing astro_time_t by a certain real number of days,
     74  * call #Astronomy_AddDays.
     75  *
     76  * The astro_time_t type contains `ut` to represent Universal Time (UT1/UTC) and
     77  * `tt` to represent Terrestrial Time (TT, also known as *ephemeris time*).
     78  * The difference `tt-ut` is known as *&Delta;T*, and is obtained from
     79  * a model provided by the
     80  * [United States Naval Observatory](http://maia.usno.navy.mil/ser7/).
     81  *
     82  * Both `tt` and `ut` are necessary for performing different astronomical calculations.
     83  * Indeed, certain calculations (such as rise/set times) require both time scales.
     84  * See the documentation for the `ut` and `tt` fields for more detailed information.
     85  *
     86  * In cases where astro_time_t is included in a structure returned by
     87  * a function that can fail, the astro_status_t field `status` will contain a value
     88  * other than `ASTRO_SUCCESS`; in that case the `ut` and `tt` will hold `NAN` (not a number).
     89  * In general, when there is an error code stored in a struct field `status`, the
     90  * caller should ignore all other values in that structure, including the `ut` and `tt`
     91  * inside astro_time_t.
     92  */
     93 typedef struct
     94 {
     95     /**
     96      * @brief   UT1/UTC number of days since noon on January 1, 2000.
     97      *
     98      * The floating point number of days of Universal Time since noon UTC January 1, 2000.
     99      * Astronomy Engine approximates UTC and UT1 as being the same thing, although they are
    100      * not exactly equivalent; UTC and UT1 can disagree by up to &plusmn;0.9 seconds.
    101      * This approximation is sufficient for the accuracy requirements of Astronomy Engine.
    102      *
    103      * Universal Time Coordinate (UTC) is the international standard for legal and civil
    104      * timekeeping and replaces the older Greenwich Mean Time (GMT) standard.
    105      * UTC is kept in sync with unpredictable observed changes in the Earth's rotation
    106      * by occasionally adding leap seconds as needed.
    107      *
    108      * UT1 is an idealized time scale based on observed rotation of the Earth, which
    109      * gradually slows down in an unpredictable way over time, due to tidal drag by the Moon and Sun,
    110      * large scale weather events like hurricanes, and internal seismic and convection effects.
    111      * Conceptually, UT1 drifts from atomic time continuously and erratically, whereas UTC
    112      * is adjusted by a scheduled whole number of leap seconds as needed.
    113      *
    114      * The value in `ut` is appropriate for any calculation involving the Earth's rotation,
    115      * such as calculating rise/set times, culumination, and anything involving apparent
    116      * sidereal time.
    117      *
    118      * Before the era of atomic timekeeping, days based on the Earth's rotation
    119      * were often known as *mean solar days*.
    120      */
    121     double ut;
    122 
    123     /**
    124      * @brief   Terrestrial Time days since noon on January 1, 2000.
    125      *
    126      * Terrestrial Time is an atomic time scale defined as a number of days since noon on January 1, 2000.
    127      * In this system, days are not based on Earth rotations, but instead by
    128      * the number of elapsed [SI seconds](https://physics.nist.gov/cuu/Units/second.html)
    129      * divided by 86400. Unlike `ut`, `tt` increases uniformly without adjustments
    130      * for changes in the Earth's rotation.
    131      *
    132      * The value in `tt` is used for calculations of movements not involving the Earth's rotation,
    133      * such as the orbits of planets around the Sun, or the Moon around the Earth.
    134      *
    135      * Historically, Terrestrial Time has also been known by the term *Ephemeris Time* (ET).
    136      */
    137     double tt;
    138 
    139     /**
    140      * @brief   For internal use only. Used to optimize Earth tilt calculations.
    141      */
    142     double psi;
    143 
    144     /**
    145      * @brief   For internal use only.  Used to optimize Earth tilt calculations.
    146      */
    147     double eps;
    148 }
    149 astro_time_t;
    150 
    151 /**
    152  * @brief A calendar date and time expressed in UTC.
    153  */
    154 typedef struct
    155 {
    156     int     year;       /**< The year value, e.g. 2019. */
    157     int     month;      /**< The month value: 1=January, 2=February, ..., 12=December. */
    158     int     day;        /**< The day of the month in the range 1..31. */
    159     int     hour;       /**< The hour of the day in the range 0..23. */
    160     int     minute;     /**< The minute of the hour in the range 0..59. */
    161     double  second;     /**< The floating point number of seconds in the range [0,60). */
    162 }
    163 astro_utc_t;
    164 
    165 /**
    166  * @brief A 3D Cartesian vector whose components are expressed in Astronomical Units (AU).
    167  */
    168 typedef struct
    169 {
    170     astro_status_t status;  /**< `ASTRO_SUCCESS` if this struct is valid; otherwise an error code. */
    171     double x;               /**< The Cartesian x-coordinate of the vector in AU. */
    172     double y;               /**< The Cartesian y-coordinate of the vector in AU. */
    173     double z;               /**< The Cartesian z-coordinate of the vector in AU. */
    174     astro_time_t t;         /**< The date and time at which this vector is valid. */
    175 }
    176 astro_vector_t;
    177 
    178 /**
    179  * @brief Spherical coordinates: latitude, longitude, distance.
    180  */
    181 typedef struct
    182 {
    183     astro_status_t status;  /**< `ASTRO_SUCCESS` if this struct is valid; otherwise an error code. */
    184     double lat;             /**< The latitude angle: -90..+90 degrees. */
    185     double lon;             /**< The longitude angle: 0..360 degrees. */
    186     double dist;            /**< Distance in AU. */
    187 }
    188 astro_spherical_t;
    189 
    190 /**
    191  * @brief An angular value expressed in degrees.
    192  */
    193 typedef struct
    194 {
    195     astro_status_t status;  /**< `ASTRO_SUCCESS` if this struct is valid; otherwise an error code. */
    196     double angle;           /**< An angle expressed in degrees. */
    197 }
    198 astro_angle_result_t;
    199 
    200 /**
    201  * @brief A celestial body.
    202  */
    203 typedef enum
    204 {
    205     BODY_INVALID = -1,      /**< An invalid or undefined celestial body. */
    206     BODY_MERCURY,           /**< Mercury */
    207     BODY_VENUS,             /**< Venus */
    208     BODY_EARTH,             /**< Earth */
    209     BODY_MARS,              /**< Mars */
    210     BODY_JUPITER,           /**< Jupiter */
    211     BODY_SATURN,            /**< Saturn */
    212     BODY_URANUS,            /**< Uranus */
    213     BODY_NEPTUNE,           /**< Neptune */
    214     BODY_PLUTO,             /**< Pluto */
    215     BODY_SUN,               /**< Sun */
    216     BODY_MOON,              /**< Moon */
    217     BODY_EMB,               /**< Earth/Moon Barycenter */
    218     BODY_SSB                /**< Solar System Barycenter */
    219 }
    220 astro_body_t;
    221 
    222 #define MIN_BODY    BODY_MERCURY    /**< Minimum valid astro_body_t value; useful for iteration. */
    223 #define MAX_BODY    BODY_SSB        /**< Maximum valid astro_body_t value; useful for iteration. */
    224 
    225 #define MIN_YEAR    1700    /**< Minimum year value supported by Astronomy Engine. */
    226 #define MAX_YEAR    2200    /**< Maximum year value supported by Astronomy Engine. */
    227 
    228 /**
    229  * @brief The location of an observer on (or near) the surface of the Earth.
    230  *
    231  * This structure is passed to functions that calculate phenomena as observed
    232  * from a particular place on the Earth.
    233  *
    234  * You can create this structure directly, or you can call the convenience function
    235  * #Astronomy_MakeObserver# to create one for you.
    236  */
    237 typedef struct
    238 {
    239     double latitude;        /**< Geographic latitude in degrees north (positive) or south (negative) of the equator. */
    240     double longitude;       /**< Geographic longitude in degrees east (positive) or west (negative) of the prime meridian at Greenwich, England. */
    241     double height;          /**< The height above (positive) or below (negative) sea level, expressed in meters. */
    242 }
    243 astro_observer_t;
    244 
    245 /**
    246  * @brief Equatorial angular coordinates.
    247  *
    248  * Coordinates of a celestial body as seen from the Earth (geocentric or topocentric, depending on context),
    249  * oriented with respect to the projection of the Earth's equator onto the sky.
    250  */
    251 typedef struct
    252 {
    253     astro_status_t status;  /**< `ASTRO_SUCCESS` if this struct is valid; otherwise an error code. */
    254     double ra;              /**< right ascension in sidereal hours. */
    255     double dec;             /**< declination in degrees */
    256     double dist;            /**< distance to the celestial body in AU. */
    257 }
    258 astro_equatorial_t;
    259 
    260 /**
    261  * @brief Ecliptic angular and Cartesian coordinates.
    262  *
    263  * Coordinates of a celestial body as seen from the center of the Sun (heliocentric),
    264  * oriented with respect to the plane of the Earth's orbit around the Sun (the ecliptic).
    265  */
    266 typedef struct
    267 {
    268     astro_status_t status;  /**< `ASTRO_SUCCESS` if this struct is valid; otherwise an error code. */
    269     double ex;              /**< Cartesian x-coordinate: in the direction of the equinox along the ecliptic plane. */
    270     double ey;              /**< Cartesian y-coordinate: in the ecliptic plane 90 degrees prograde from the equinox. */
    271     double ez;              /**< Cartesian z-coordinate: perpendicular to the ecliptic plane. Positive is north. */
    272     double elat;            /**< Latitude in degrees north (positive) or south (negative) of the ecliptic plane. */
    273     double elon;            /**< Longitude in degrees around the ecliptic plane prograde from the equinox. */
    274 }
    275 astro_ecliptic_t;
    276 
    277 /**
    278  * @brief Coordinates of a celestial body as seen by a topocentric observer.
    279  *
    280  * Contains horizontal and equatorial coordinates seen by an observer on or near
    281  * the surface of the Earth (a topocentric observer).
    282  * Optionally corrected for atmospheric refraction.
    283  */
    284 typedef struct
    285 {
    286     double azimuth;     /**< Compass direction around the horizon in degrees. 0=North, 90=East, 180=South, 270=West. */
    287     double altitude;    /**< Angle in degrees above (positive) or below (negative) the observer's horizon. */
    288     double ra;          /**< Right ascension in sidereal hours. */
    289     double dec;         /**< Declination in degrees. */
    290 }
    291 astro_horizon_t;
    292 
    293 /**
    294  * @brief Contains a rotation matrix that can be used to transform one coordinate system to another.
    295  */
    296 typedef struct
    297 {
    298     astro_status_t status;  /**< `ASTRO_SUCCESS` if this struct is valid; otherwise an error code. */
    299     double rot[3][3];       /**< A normalized 3x3 rotation matrix. */
    300 }
    301 astro_rotation_t;
    302 
    303 /**
    304  * @brief Selects whether to correct for atmospheric refraction, and if so, how.
    305  */
    306 typedef enum
    307 {
    308     REFRACTION_NONE,    /**< No atmospheric refraction correction (airless). */
    309     REFRACTION_NORMAL,  /**< Recommended correction for standard atmospheric refraction. */
    310     REFRACTION_JPLHOR   /**< Used only for compatibility testing with JPL Horizons online tool. */
    311 }
    312 astro_refraction_t;
    313 
    314 /**
    315  * @brief The result of a search for an astronomical event.
    316  */
    317 typedef struct
    318 {
    319     astro_status_t  status;     /**< `ASTRO_SUCCESS` if this struct is valid; otherwise an error code. */
    320     astro_time_t    time;       /**< The time at which a searched-for event occurs. */
    321 }
    322 astro_search_result_t;
    323 
    324 /**
    325  * @brief
    326  *      The dates and times of changes of season for a given calendar year.
    327  *      Call #Astronomy_Seasons to calculate this data structure for a given year.
    328  */
    329 typedef struct
    330 {
    331     astro_status_t  status;         /**< `ASTRO_SUCCESS` if this struct is valid; otherwise an error code. */
    332     astro_time_t    mar_equinox;    /**< The date and time of the March equinox for the specified year. */
    333     astro_time_t    jun_solstice;   /**< The date and time of the June soltice for the specified year. */
    334     astro_time_t    sep_equinox;    /**< The date and time of the September equinox for the specified year. */
    335     astro_time_t    dec_solstice;   /**< The date and time of the December solstice for the specified year. */
    336 }
    337 astro_seasons_t;
    338 
    339 /**
    340  * @brief A lunar quarter event (new moon, first quarter, full moon, or third quarter) along with its date and time.
    341  */
    342 typedef struct
    343 {
    344     astro_status_t  status;     /**< `ASTRO_SUCCESS` if this struct is valid; otherwise an error code. */
    345     int             quarter;    /**< 0=new moon, 1=first quarter, 2=full moon, 3=third quarter. */
    346     astro_time_t    time;       /**< The date and time of the lunar quarter. */
    347 }
    348 astro_moon_quarter_t;
    349 
    350 /**
    351  * @brief A real value returned by a function whose ascending root is to be found.
    352  *
    353  * When calling #Astronomy_Search, the caller must pass in a callback function
    354  * compatible with the function-pointer type #astro_search_func_t
    355  * whose ascending root is to be found. That callback function must return astro_func_result_t.
    356  * If the function call is successful, it will set `status` to `ASTRO_SUCCESS` and `value`
    357  * to the numeric value appropriate for the given date and time.
    358  * If the call fails for some reason, it should set `status` to an appropriate error value
    359  * other than `ASTRO_SUCCESS`; in the error case, to guard against any possible misuse of `value`,
    360  * it is recommended to set `value` to `NAN`, though this is not strictly necessary.
    361  */
    362 typedef struct
    363 {
    364     astro_status_t status;      /**< `ASTRO_SUCCESS` if this struct is valid; otherwise an error code. */
    365     double value;               /**< The value returned by a function whose ascending root is to be found. */
    366 }
    367 astro_func_result_t;
    368 
    369 /**
    370  * @brief A pointer to a function that is to be passed as a callback to #Astronomy_Search.
    371  *
    372  * The function #Astronomy_Search numerically solves for the time that a given event occurs.
    373  * An event is defined as the time when an arbitrary function transitions between having
    374  * a negative value and a non-negative value. This transition is called an *ascending root*.
    375  *
    376  * The type astro_search_func_t represents such a callback function that accepts a
    377  * custom `context` pointer and an astro_time_t representing the time to probe.
    378  * The function returns an astro_func_result_t that contains either a real
    379  * number in `value` or an error code in `status` that aborts the search.
    380  *
    381  * The `context` points to some data whose type varies depending on the callback function.
    382  * It can contain any auxiliary parameters (other than time) needed to evaluate the function.
    383  * For example, a function may pertain to a specific celestial body, in which case `context`
    384  * may point to a value of type astro_body_t. The `context` parameter is supplied by
    385  * the caller of #Astronomy_Search, which passes it along to every call to the callback function.
    386  * If the caller of `Astronomy_Search` knows that the callback function does not need a context,
    387  * it is safe to pass `NULL` as the context pointer.
    388  */
    389 typedef astro_func_result_t (* astro_search_func_t) (void *context, astro_time_t time);
    390 
    391 /**
    392  * @brief A pointer to a function that calculates Delta T.
    393  *
    394  * Delta T is the discrepancy between times measured using an atomic clock
    395  * and times based on observations of the Earth's rotation, which is gradually
    396  * slowing down over time. Delta T = TT - UT, where
    397  * TT = Terrestrial Time, based on atomic time, and
    398  * UT = Universal Time, civil time based on the Earth's rotation.
    399  * Astronomy Engine defaults to using a Delta T function defined by
    400  * Espenak and Meeus in their "Five Millennium Canon of Solar Eclipses".
    401  * See: https://eclipse.gsfc.nasa.gov/SEhelp/deltatpoly2004.html
    402  */
    403 typedef double (* astro_deltat_func) (double ut);
    404 
    405 double Astronomy_DeltaT_EspenakMeeus(double ut);
    406 double Astronomy_DeltaT_JplHorizons(double ut);
    407 
    408 void Astronomy_SetDeltaTFunction(astro_deltat_func func);
    409 
    410 /**
    411  * @brief Indicates whether a body (especially Mercury or Venus) is best seen in the morning or evening.
    412  */
    413 typedef enum
    414 {
    415     VISIBLE_MORNING,    /**< The body is best visible in the morning, before sunrise. */
    416     VISIBLE_EVENING     /**< The body is best visible in the evening, after sunset. */
    417 }
    418 astro_visibility_t;
    419 
    420 /**
    421  * @brief
    422  *      Contains information about the visibility of a celestial body at a given date and time.
    423  *      See #Astronomy_Elongation for more detailed information about the members of this structure.
    424  *      See also #Astronomy_SearchMaxElongation for how to search for maximum elongation events.
    425  */
    426 typedef struct
    427 {
    428     astro_status_t      status;                 /**< `ASTRO_SUCCESS` if this struct is valid; otherwise an error code. */
    429     astro_time_t        time;                   /**< The date and time of the observation. */
    430     astro_visibility_t  visibility;             /**< Whether the body is best seen in the morning or the evening. */
    431     double              elongation;             /**< The angle in degrees between the body and the Sun, as seen from the Earth. */
    432     double              ecliptic_separation;    /**< The difference between the ecliptic longitudes of the body and the Sun, as seen from the Earth. */
    433 }
    434 astro_elongation_t;
    435 
    436 /**
    437  * @brief Information about a celestial body crossing a specific hour angle.
    438  *
    439  * Returned by the function #Astronomy_SearchHourAngle to report information about
    440  * a celestial body crossing a certain hour angle as seen by a specified topocentric observer.
    441  */
    442 typedef struct
    443 {
    444     astro_status_t      status;     /**< `ASTRO_SUCCESS` if this struct is valid; otherwise an error code. */
    445     astro_time_t        time;       /**< The date and time when the body crosses the specified hour angle. */
    446     astro_horizon_t     hor;        /**< Apparent coordinates of the body at the time it crosses the specified hour angle. */
    447 }
    448 astro_hour_angle_t;
    449 
    450 /**
    451  * @brief Information about the brightness and illuminated shape of a celestial body.
    452  *
    453  * Returned by the functions #Astronomy_Illumination and #Astronomy_SearchPeakMagnitude
    454  * to report the visual magnitude and illuminated fraction of a celestial body at a given date and time.
    455  */
    456 typedef struct
    457 {
    458     astro_status_t      status;         /**< `ASTRO_SUCCESS` if this struct is valid; otherwise an error code. */
    459     astro_time_t        time;           /**< The date and time of the observation. */
    460     double              mag;            /**< The visual magnitude of the body. Smaller values are brighter. */
    461     double              phase_angle;    /**< The angle in degrees between the Sun and the Earth, as seen from the body. Indicates the body's phase as seen from the Earth. */
    462     double              helio_dist;     /**< The distance between the Sun and the body at the observation time. */
    463     double              ring_tilt;      /**< For Saturn, the tilt angle in degrees of its rings as seen from Earth. For all other bodies, 0. */
    464 }
    465 astro_illum_t;
    466 
    467 /**
    468  * @brief The type of apsis: pericenter (closest approach) or apocenter (farthest distance).
    469  */
    470 typedef enum
    471 {
    472     APSIS_PERICENTER,   /**< The body is at its closest approach to the object it orbits. */
    473     APSIS_APOCENTER,    /**< The body is at its farthest distance from the object it orbits. */
    474     APSIS_INVALID       /**< Undefined or invalid apsis. */
    475 }
    476 astro_apsis_kind_t;
    477 
    478 /**
    479  * @brief An apsis event: pericenter (closest approach) or apocenter (farthest distance).
    480  *
    481  * For the Moon orbiting the Earth, or a planet orbiting the Sun, an *apsis* is an
    482  * event where the orbiting body reaches its closest or farthest point from the primary body.
    483  * The closest approach is called *pericenter* and the farthest point is *apocenter*.
    484  *
    485  * More specific terminology is common for particular orbiting bodies.
    486  * The Moon's closest approach to the Earth is called *perigee* and its farthest
    487  * point is called *apogee*. The closest approach of a planet to the Sun is called
    488  * *perihelion* and the furthest point is called *aphelion*.
    489  *
    490  * This data structure is returned by #Astronomy_SearchLunarApsis and #Astronomy_NextLunarApsis
    491  * to iterate through consecutive alternating perigees and apogees.
    492  */
    493 typedef struct
    494 {
    495     astro_status_t      status;     /**< `ASTRO_SUCCESS` if this struct is valid; otherwise an error code. */
    496     astro_time_t        time;       /**< The date and time of the apsis. */
    497     astro_apsis_kind_t  kind;       /**< Whether this is a pericenter or apocenter event. */
    498     double              dist_au;    /**< The distance between the centers of the bodies in astronomical units. */
    499     double              dist_km;    /**< The distance between the centers of the bodies in kilometers. */
    500 }
    501 astro_apsis_t;
    502 
    503 /**
    504  * @brief The different kinds of lunar/solar eclipses.
    505  */
    506 typedef enum
    507 {
    508     ECLIPSE_NONE,       /**< No eclipse found. */
    509     ECLIPSE_PENUMBRAL,  /**< A penumbral lunar eclipse. (Never used for a solar eclipse.) */
    510     ECLIPSE_PARTIAL,    /**< A partial lunar/solar eclipse. */
    511     ECLIPSE_ANNULAR,    /**< An annular solar eclipse. (Never used for a lunar eclipse.) */
    512     ECLIPSE_TOTAL       /**< A total lunar/solar eclipse. */
    513 }
    514 astro_eclipse_kind_t;
    515 
    516 /**
    517  * @brief Information about a lunar eclipse.
    518  *
    519  * Returned by #Astronomy_SearchLunarEclipse or #Astronomy_NextLunarEclipse
    520  * to report information about a lunar eclipse event.
    521  * If a lunar eclipse is found, `status` holds `ASTRO_SUCCESS` and the other fields are set.
    522  * If `status` holds any other value, it is an error code and the other fields are undefined.
    523  *
    524  * When a lunar eclipse is found, it is classified as penumbral, partial, or total.
    525  * Penumbral eclipses are difficult to observe, because the moon is only slightly dimmed
    526  * by the Earth's penumbra; no part of the Moon touches the Earth's umbra.
    527  * Partial eclipses occur when part, but not all, of the Moon touches the Earth's umbra.
    528  * Total eclipses occur when the entire Moon passes into the Earth's umbra.
    529  *
    530  * The `kind` field thus holds `ECLIPSE_PENUMBRAL`, `ECLIPSE_PARTIAL`, or `ECLIPSE_TOTAL`,
    531  * depending on the kind of lunar eclipse found.
    532  *
    533  * Field `peak` holds the date and time of the center of the eclipse, when it is at its peak.
    534  *
    535  * Fields `sd_penum`, `sd_partial`, and `sd_total` hold the semi-duration of each phase
    536  * of the eclipse, which is half of the amount of time the eclipse spends in each
    537  * phase (expressed in minutes), or 0 if the eclipse never reaches that phase.
    538  * By converting from minutes to days, and subtracting/adding with `center`, the caller
    539  * may determine the date and time of the beginning/end of each eclipse phase.
    540  */
    541 typedef struct
    542 {
    543     astro_status_t          status;         /**< `ASTRO_SUCCESS` if this struct is valid; otherwise an error code. */
    544     astro_eclipse_kind_t    kind;           /**< The type of lunar eclipse found. */
    545     astro_time_t            peak;           /**< The time of the eclipse at its peak. */
    546     double                  sd_penum;       /**< The semi-duration of the penumbral phase in minutes. */
    547     double                  sd_partial;     /**< The semi-duration of the partial phase in minutes, or 0.0 if none. */
    548     double                  sd_total;       /**< The semi-duration of the total phase in minutes, or 0.0 if none. */
    549 }
    550 astro_lunar_eclipse_t;
    551 
    552 
    553 /**
    554  * @brief Reports the time and geographic location of the peak of a solar eclipse.
    555  *
    556  * Returned by #Astronomy_SearchGlobalSolarEclipse or #Astronomy_NextGlobalSolarEclipse
    557  * to report information about a solar eclipse event.
    558  * If a solar eclipse is found, `status` holds `ASTRO_SUCCESS` and `kind`, `peak`, and `distance`
    559  * have valid values. The `latitude` and `longitude` are set only for total and annular eclipses
    560  * (see more below).
    561  * If `status` holds any value other than `ASTRO_SUCCESS`, it is an error code;
    562  * in that case, `kind` holds `ECLIPSE_NONE` and all the other fields are undefined.
    563  *
    564  * Field `peak` holds the date and time of the peak of the eclipse, defined as
    565  * the instant when the axis of the Moon's shadow cone passes closest to the Earth's center.
    566  *
    567  * The eclipse is classified as partial, annular, or total, depending on the
    568  * maximum amount of the Sun's disc obscured, as seen at the peak location
    569  * on the surface of the Earth.
    570  *
    571  * The `kind` field thus holds `ECLIPSE_PARTIAL`, `ECLIPSE_ANNULAR`, or `ECLIPSE_TOTAL`.
    572  * A total eclipse is when the peak observer sees the Sun completely blocked by the Moon.
    573  * An annular eclipse is like a total eclipse, but the Moon is too far from the Earth's surface
    574  * to completely block the Sun; instead, the Sun takes on a ring-shaped appearance.
    575  * A partial eclipse is when the Moon blocks part of the Sun's disc, but nobody on the Earth
    576  * observes either a total or annular eclipse.
    577  *
    578  * If `kind` is `ECLIPSE_TOTAL` or `ECLIPSE_ANNULAR`, the `latitude` and `longitude`
    579  * fields give the geographic coordinates of the center of the Moon's shadow projected
    580  * onto the daytime side of the Earth at the instant of the eclipse's peak.
    581  * If `kind` has any other value, `latitude` and `longitude` are undefined and should
    582  * not be used.
    583  */
    584 typedef struct
    585 {
    586     astro_status_t          status;         /**< `ASTRO_SUCCESS` if this struct is valid; otherwise an error code. */
    587     astro_eclipse_kind_t    kind;           /**< The type of solar eclipse found. */
    588     astro_time_t            peak;           /**< The date and time of the eclipse at its peak. */
    589     double                  distance;       /**< The distance between the Sun/Moon shadow axis and the center of the Earth, in kilometers. */
    590     double                  latitude;       /**< The geographic latitude at the center of the peak eclipse shadow. */
    591     double                  longitude;      /**< The geographic longitude at the center of the peak eclipse shadow. */
    592 }
    593 astro_global_solar_eclipse_t;
    594 
    595 
    596 /**
    597  * @brief Holds a time and the observed altitude of the Sun at that time.
    598  *
    599  * When reporting a solar eclipse observed at a specific location on the Earth
    600  * (a "local" solar eclipse), a series of events occur. In addition
    601  * to the time of each event, it is important to know the altitude of the Sun,
    602  * because each event may be invisible to the observer if the Sun is below
    603  * the horizon (i.e. it at night).
    604  *
    605  * If `altitude` is negative, the event is theoretical only; it would be
    606  * visible if the Earth were transparent, but the observer cannot actually see it.
    607  * If `altitude` is positive but less than a few degrees, visibility will be impaired by
    608  * atmospheric interference (sunrise or sunset conditions).
    609  */
    610 typedef struct
    611 {
    612     astro_time_t    time;       /**< The date and time of the event. */
    613     double          altitude;   /**< The angular altitude of the center of the Sun above/below the horizon, at `time`, corrected for atmospheric refraction and expressed in degrees. */
    614 }
    615 astro_eclipse_event_t;
    616 
    617 
    618 /**
    619  * @brief Information about a solar eclipse as seen by an observer at a given time and geographic location.
    620  *
    621  * Returned by #Astronomy_SearchLocalSolarEclipse or #Astronomy_NextLocalSolarEclipse
    622  * to report information about a solar eclipse as seen at a given geographic location.
    623  * If a solar eclipse is found, `status` holds `ASTRO_SUCCESS` and the other fields are set.
    624  * If `status` holds any other value, it is an error code and the other fields are undefined.
    625  *
    626  * When a solar eclipse is found, it is classified as partial, annular, or total.
    627  * The `kind` field thus holds `ECLIPSE_PARTIAL`, `ECLIPSE_ANNULAR`, or `ECLIPSE_TOTAL`.
    628  * A partial solar eclipse is when the Moon does not line up directly enough with the Sun
    629  * to completely block the Sun's light from reaching the observer.
    630  * An annular eclipse occurs when the Moon's disc is completely visible against the Sun
    631  * but the Moon is too far away to completely block the Sun's light; this leaves the
    632  * Sun with a ring-like appearance.
    633  * A total eclipse occurs when the Moon is close enough to the Earth and aligned with the
    634  * Sun just right to completely block all sunlight from reaching the observer.
    635  *
    636  * There are 5 "event" fields, each of which contains a time and a solar altitude.
    637  * Field `peak` holds the date and time of the center of the eclipse, when it is at its peak.
    638  * The fields `partial_begin` and `partial_end` are always set, and indicate when
    639  * the eclipse begins/ends. If the eclipse reaches totality or becomes annular,
    640  * `total_begin` and `total_end` indicate when the total/annular phase begins/ends.
    641  * When an event field is valid, the caller must also check its `altitude` field to
    642  * see whether the Sun is above the horizon at that time. See #astro_eclipse_kind_t
    643  * for more information.
    644  */
    645 typedef struct
    646 {
    647     astro_status_t          status;         /**< `ASTRO_SUCCESS` if this struct is valid; otherwise an error code. */
    648     astro_eclipse_kind_t    kind;           /**< The type of solar eclipse found: `ECLIPSE_PARTIAL`, `ECLIPSE_ANNULAR`, or `ECLIPSE_TOTAL`. */
    649     astro_eclipse_event_t   partial_begin;  /**< The time and Sun altitude at the beginning of the eclipse. */
    650     astro_eclipse_event_t   total_begin;    /**< If this is an annular or a total eclipse, the time and Sun altitude when annular/total phase begins; otherwise invalid. */
    651     astro_eclipse_event_t   peak;           /**< The time and Sun altitude when the eclipse reaches its peak. */
    652     astro_eclipse_event_t   total_end;      /**< If this is an annular or a total eclipse, the time and Sun altitude when annular/total phase ends; otherwise invalid. */
    653     astro_eclipse_event_t   partial_end;    /**< The time and Sun altitude at the end of the eclipse. */
    654 }
    655 astro_local_solar_eclipse_t;
    656 
    657 
    658 /**
    659  * @brief Information about a transit of Mercury or Venus, as seen from the Earth.
    660  *
    661  * Returned by #Astronomy_SearchTransit or #Astronomy_NextTransit to report
    662  * information about a transit of Mercury or Venus.
    663  * A transit is when Mercury or Venus passes between the Sun and Earth so that
    664  * the other planet is seen in silhouette against the Sun.
    665  *
    666  * The `start` field reports the moment in time when the planet first becomes
    667  * visible against the Sun in its background.
    668  * The `peak` field reports when the planet is most aligned with the Sun,
    669  * as seen from the Earth.
    670  * The `finish` field reports the last moment when the planet is visible
    671  * against the Sun in its background.
    672  *
    673  * The calculations are performed from the point of view of a geocentric observer.
    674  */
    675 typedef struct
    676 {
    677     astro_status_t  status;         /**< `ASTRO_SUCCESS` if this struct is valid; otherwise an error code. */
    678     astro_time_t    start;          /**< Date and time at the beginning of the transit. */
    679     astro_time_t    peak;           /**< Date and time of the peak of the transit. */
    680     astro_time_t    finish;         /**< Date and time at the end of the transit. */
    681     double          separation;     /**< Angular separation in arcminutes between the centers of the Sun and the planet at time `peak`. */
    682 }
    683 astro_transit_t;
    684 
    685 
    686 /**
    687  * @brief   Aberration calculation options.
    688  *
    689  * [Aberration](https://en.wikipedia.org/wiki/Aberration_of_light) is an effect
    690  * causing the apparent direction of an observed body to be shifted due to transverse
    691  * movement of the Earth with respect to the rays of light coming from that body.
    692  * This angular correction can be anywhere from 0 to about 20 arcseconds,
    693  * depending on the position of the observed body relative to the instantaneous
    694  * velocity vector of the Earth.
    695  *
    696  * Some Astronomy Engine functions allow optional correction for aberration by
    697  * passing in a value of this enumerated type.
    698  *
    699  * Aberration correction is useful to improve accuracy of coordinates of
    700  * apparent locations of bodies seen from the Earth.
    701  * However, because aberration affects not only the observed body (such as a planet)
    702  * but the surrounding stars, aberration may be unhelpful (for example)
    703  * for determining exactly when a planet crosses from one constellation to another.
    704  */
    705 typedef enum
    706 {
    707     ABERRATION,     /**< Request correction for aberration. */
    708     NO_ABERRATION   /**< Do not correct for aberration. */
    709 }
    710 astro_aberration_t;
    711 
    712 /**
    713  * @brief   Selects the date for which the Earth's equator is to be used for representing equatorial coordinates.
    714  *
    715  * The Earth's equator is not always in the same plane due to precession and nutation.
    716  *
    717  * Sometimes it is useful to have a fixed plane of reference for equatorial coordinates
    718  * across different calendar dates.  In these cases, a fixed *epoch*, or reference time,
    719  * is helpful. Astronomy Engine provides the J2000 epoch for such cases.  This refers
    720  * to the plane of the Earth's orbit as it was on noon UTC on 1 January 2000.
    721  *
    722  * For some other purposes, it is more helpful to represent coordinates using the Earth's
    723  * equator exactly as it is on that date. For example, when calculating rise/set times
    724  * or horizontal coordinates, it is most accurate to use the orientation of the Earth's
    725  * equator at that same date and time. For these uses, Astronomy Engine allows *of-date*
    726  * calculations.
    727  */
    728 typedef enum
    729 {
    730     EQUATOR_J2000,      /**< Represent equatorial coordinates in the J2000 epoch. */
    731     EQUATOR_OF_DATE     /**< Represent equatorial coordinates using the Earth's equator at the given date and time. */
    732 }
    733 astro_equator_date_t;
    734 
    735 /**
    736  * @brief Selects whether to search for a rise time or a set time.
    737  *
    738  * The #Astronomy_SearchRiseSet function finds the rise or set time of a body
    739  * depending on the value of its `direction` parameter.
    740  */
    741 typedef enum
    742 {
    743     DIRECTION_RISE = +1,    /**< Search for the time a body begins to rise above the horizon. */
    744     DIRECTION_SET  = -1,    /**< Search for the time a body finishes sinking below the horizon. */
    745 }
    746 astro_direction_t;
    747 
    748 
    749 /**
    750  * @brief Reports the constellation that a given celestial point lies within.
    751  *
    752  * The #Astronomy_Constellation function returns this struct
    753  * to report which constellation corresponds with a given point in the sky.
    754  * Constellations are defined with respect to the B1875 equatorial system
    755  * per IAU standard. Although `Astronomy.Constellation` requires J2000 equatorial
    756  * coordinates, the struct contains converted B1875 coordinates for reference.
    757  */
    758 typedef struct
    759 {
    760     astro_status_t status;      /**< `ASTRO_SUCCESS` if this struct is valid; otherwise an error code. */
    761     const char    *symbol;      /**< 3-character mnemonic symbol for the constellation, e.g. "Ori". */
    762     const char    *name;        /**< Full name of constellation, e.g. "Orion". */
    763     double         ra_1875;     /**< Right ascension expressed in B1875 coordinates. */
    764     double         dec_1875;    /**< Declination expressed in B1875 coordinates. */
    765 }
    766 astro_constellation_t;
    767 
    768 
    769 /**
    770  * @brief Selects the output format of the function #Astronomy_FormatTime.
    771  */
    772 typedef enum
    773 {
    774     TIME_FORMAT_DAY,    /**< Truncate to UTC calendar date only, e.g. `2020-12-31`. Buffer size must be at least 11 characters. */
    775     TIME_FORMAT_MINUTE, /**< Round to nearest UTC minute, e.g. `2020-12-31T15:47Z`. Buffer size must be at least 18 characters. */
    776     TIME_FORMAT_SECOND, /**< Round to nearest UTC second, e.g. `2020-12-31T15:47:32Z`. Buffer size must be at least 21 characters. */
    777     TIME_FORMAT_MILLI   /**< Round to nearest UTC millisecond, e.g. `2020-12-31T15:47:32.397Z`. Buffer size must be at least 25 characters. */
    778 }
    779 astro_time_format_t;
    780 
    781 #define TIME_TEXT_BYTES  25   /**< The smallest number of characters that is always large enough for #Astronomy_FormatTime. */
    782 
    783 /*---------- functions ----------*/
    784 
    785 void Astronomy_Reset(void);
    786 double Astronomy_VectorLength(astro_vector_t vector);
    787 const char *Astronomy_BodyName(astro_body_t body);
    788 astro_body_t Astronomy_BodyCode(const char *name);
    789 astro_observer_t Astronomy_MakeObserver(double latitude, double longitude, double height);
    790 astro_time_t Astronomy_CurrentTime(void);
    791 astro_time_t Astronomy_MakeTime(int year, int month, int day, int hour, int minute, double second);
    792 astro_time_t Astronomy_TimeFromUtc(astro_utc_t utc);
    793 astro_utc_t  Astronomy_UtcFromTime(astro_time_t time);
    794 astro_status_t Astronomy_FormatTime(astro_time_t time, astro_time_format_t format, char *text, size_t size);
    795 astro_time_t Astronomy_TimeFromDays(double ut);
    796 astro_time_t Astronomy_AddDays(astro_time_t time, double days);
    797 astro_func_result_t Astronomy_HelioDistance(astro_body_t body, astro_time_t time);
    798 astro_vector_t Astronomy_HelioVector(astro_body_t body, astro_time_t time);
    799 astro_vector_t Astronomy_GeoVector(astro_body_t body, astro_time_t time, astro_aberration_t aberration);
    800 astro_vector_t Astronomy_GeoMoon(astro_time_t time);
    801 
    802 astro_equatorial_t Astronomy_Equator(
    803     astro_body_t body,
    804     astro_time_t *time,
    805     astro_observer_t observer,
    806     astro_equator_date_t equdate,
    807     astro_aberration_t aberration
    808 );
    809 
    810 astro_ecliptic_t Astronomy_SunPosition(astro_time_t time);
    811 astro_ecliptic_t Astronomy_Ecliptic(astro_vector_t equ);
    812 astro_angle_result_t Astronomy_EclipticLongitude(astro_body_t body, astro_time_t time);
    813 
    814 astro_horizon_t Astronomy_Horizon(
    815     astro_time_t *time,
    816     astro_observer_t observer,
    817     double ra,
    818     double dec,
    819     astro_refraction_t refraction);
    820 
    821 astro_angle_result_t Astronomy_AngleFromSun(astro_body_t body, astro_time_t time);
    822 astro_elongation_t Astronomy_Elongation(astro_body_t body, astro_time_t time);
    823 astro_elongation_t Astronomy_SearchMaxElongation(astro_body_t body, astro_time_t startTime);
    824 astro_angle_result_t Astronomy_LongitudeFromSun(astro_body_t body, astro_time_t time);
    825 astro_search_result_t Astronomy_SearchRelativeLongitude(astro_body_t body, double targetRelLon, astro_time_t startTime);
    826 astro_angle_result_t Astronomy_MoonPhase(astro_time_t time);
    827 astro_search_result_t Astronomy_SearchMoonPhase(double targetLon, astro_time_t startTime, double limitDays);
    828 astro_moon_quarter_t Astronomy_SearchMoonQuarter(astro_time_t startTime);
    829 astro_moon_quarter_t Astronomy_NextMoonQuarter(astro_moon_quarter_t mq);
    830 astro_lunar_eclipse_t Astronomy_SearchLunarEclipse(astro_time_t startTime);
    831 astro_lunar_eclipse_t Astronomy_NextLunarEclipse(astro_time_t prevEclipseTime);
    832 astro_global_solar_eclipse_t Astronomy_SearchGlobalSolarEclipse(astro_time_t startTime);
    833 astro_global_solar_eclipse_t Astronomy_NextGlobalSolarEclipse(astro_time_t prevEclipseTime);
    834 astro_local_solar_eclipse_t Astronomy_SearchLocalSolarEclipse(astro_time_t startTime, astro_observer_t observer);
    835 astro_local_solar_eclipse_t Astronomy_NextLocalSolarEclipse(astro_time_t prevEclipseTime, astro_observer_t observer);
    836 astro_transit_t Astronomy_SearchTransit(astro_body_t body, astro_time_t startTime);
    837 astro_transit_t Astronomy_NextTransit(astro_body_t body, astro_time_t prevTransitTime);
    838 
    839 astro_search_result_t Astronomy_Search(
    840     astro_search_func_t func,
    841     void *context,
    842     astro_time_t t1,
    843     astro_time_t t2,
    844     double dt_tolerance_seconds);
    845 
    846 astro_search_result_t Astronomy_SearchSunLongitude(
    847     double targetLon,
    848     astro_time_t startTime,
    849     double limitDays);
    850 
    851 astro_hour_angle_t Astronomy_SearchHourAngle(
    852     astro_body_t body,
    853     astro_observer_t observer,
    854     double hourAngle,
    855     astro_time_t startTime);
    856 
    857 astro_search_result_t Astronomy_SearchRiseSet(
    858     astro_body_t body,
    859     astro_observer_t observer,
    860     astro_direction_t direction,
    861     astro_time_t startTime,
    862     double limitDays);
    863 
    864 astro_seasons_t Astronomy_Seasons(int year);
    865 astro_illum_t Astronomy_Illumination(astro_body_t body, astro_time_t time);
    866 astro_illum_t Astronomy_SearchPeakMagnitude(astro_body_t body, astro_time_t startTime);
    867 astro_apsis_t Astronomy_SearchLunarApsis(astro_time_t startTime);
    868 astro_apsis_t Astronomy_NextLunarApsis(astro_apsis_t apsis);
    869 astro_apsis_t Astronomy_SearchPlanetApsis(astro_body_t body, astro_time_t startTime);
    870 astro_apsis_t Astronomy_NextPlanetApsis(astro_body_t body, astro_apsis_t apsis);
    871 
    872 astro_rotation_t Astronomy_InverseRotation(astro_rotation_t rotation);
    873 astro_rotation_t Astronomy_CombineRotation(astro_rotation_t a, astro_rotation_t b);
    874 astro_vector_t Astronomy_VectorFromSphere(astro_spherical_t sphere, astro_time_t time);
    875 astro_spherical_t Astronomy_SphereFromVector(astro_vector_t vector);
    876 astro_vector_t Astronomy_VectorFromEquator(astro_equatorial_t equ, astro_time_t time);
    877 astro_equatorial_t Astronomy_EquatorFromVector(astro_vector_t vector);
    878 astro_vector_t Astronomy_VectorFromHorizon(astro_spherical_t sphere, astro_time_t time, astro_refraction_t refraction);
    879 astro_spherical_t Astronomy_HorizonFromVector(astro_vector_t vector, astro_refraction_t refraction);
    880 astro_vector_t Astronomy_RotateVector(astro_rotation_t rotation, astro_vector_t vector);
    881 
    882 astro_rotation_t Astronomy_Rotation_EQD_EQJ(astro_time_t time);
    883 astro_rotation_t Astronomy_Rotation_EQD_ECL(astro_time_t time);
    884 astro_rotation_t Astronomy_Rotation_EQD_HOR(astro_time_t time, astro_observer_t observer);
    885 astro_rotation_t Astronomy_Rotation_EQJ_EQD(astro_time_t time);
    886 astro_rotation_t Astronomy_Rotation_EQJ_ECL(void);
    887 astro_rotation_t Astronomy_Rotation_EQJ_HOR(astro_time_t time, astro_observer_t observer);
    888 astro_rotation_t Astronomy_Rotation_ECL_EQD(astro_time_t time);
    889 astro_rotation_t Astronomy_Rotation_ECL_EQJ(void);
    890 astro_rotation_t Astronomy_Rotation_ECL_HOR(astro_time_t time, astro_observer_t observer);
    891 astro_rotation_t Astronomy_Rotation_HOR_EQD(astro_time_t time, astro_observer_t observer);
    892 astro_rotation_t Astronomy_Rotation_HOR_EQJ(astro_time_t time, astro_observer_t observer);
    893 astro_rotation_t Astronomy_Rotation_HOR_ECL(astro_time_t time, astro_observer_t observer);
    894 
    895 double Astronomy_Refraction(astro_refraction_t refraction, double altitude);
    896 double Astronomy_InverseRefraction(astro_refraction_t refraction, double bent_altitude);
    897 
    898 astro_constellation_t Astronomy_Constellation(double ra, double dec);
    899 
    900 #ifdef __cplusplus
    901 }
    902 #endif
    903 
    904 #endif  /* ifndef __ASTRONOMY_H */