// © 2016 and later: Unicode, Inc. and others.1// License & terms of use: http://www.unicode.org/copyright.html2/************************************************************************3* Copyright (C) 1996-2008, International Business Machines Corporation *4* and others. All Rights Reserved. *5************************************************************************6* 2003-nov-07 srl Port from Java7*/89#ifndef ASTRO_H10#define ASTRO_H1112#include "unicode/utypes.h"1314#if !UCONFIG_NO_FORMATTING1516#include "gregoimp.h" // for Math17#include "unicode/unistr.h"1819U_NAMESPACE_BEGIN2021/**22* <code>CalendarAstronomer</code> is a class that can perform the calculations to23* determine the positions of the sun and moon, the time of sunrise and24* sunset, and other astronomy-related data. The calculations it performs25* are in some cases quite complicated, and this utility class saves you26* the trouble of worrying about them.27* <p>28* The measurement of time is a very important part of astronomy. Because29* astronomical bodies are constantly in motion, observations are only valid30* at a given moment in time. Accordingly, each <code>CalendarAstronomer</code>31* object has a <code>time</code> property that determines the date32* and time for which its calculations are performed. You can set and33* retrieve this property with {@link #setDate setDate}, {@link #getDate getDate}34* and related methods.35* <p>36* Almost all of the calculations performed by this class, or by any37* astronomer, are approximations to various degrees of accuracy. The38* calculations in this class are mostly modelled after those described39* in the book40* <a href="http://www.amazon.com/exec/obidos/ISBN=0521356997" target="_top">41* Practical Astronomy With Your Calculator</a>, by Peter J.42* Duffett-Smith, Cambridge University Press, 1990. This is an excellent43* book, and if you want a greater understanding of how these calculations44* are performed it a very good, readable starting point.45* <p>46* <strong>WARNING:</strong> This class is very early in its development, and47* it is highly likely that its API will change to some degree in the future.48* At the moment, it basically does just enough to support {@link IslamicCalendar}49* and {@link ChineseCalendar}.50*51* @author Laura Werner52* @author Alan Liu53* @internal54*/55class U_I18N_API CalendarAstronomer : public UMemory {56public:57// some classes5859public:60/**61* Represents the position of an object in the sky relative to the ecliptic,62* the plane of the earth's orbit around the Sun.63* This is a spherical coordinate system in which the latitude64* specifies the position north or south of the plane of the ecliptic.65* The longitude specifies the position along the ecliptic plane66* relative to the "First Point of Aries", which is the Sun's position in the sky67* at the Vernal Equinox.68* <p>69* Note that Ecliptic objects are immutable and cannot be modified70* once they are constructed. This allows them to be passed and returned by71* value without worrying about whether other code will modify them.72*73* @see CalendarAstronomer.Equatorial74* @see CalendarAstronomer.Horizon75* @internal76*/77class U_I18N_API Ecliptic : public UMemory {78public:79/**80* Constructs an Ecliptic coordinate object.81* <p>82* @param lat The ecliptic latitude, measured in radians.83* @param lon The ecliptic longitude, measured in radians.84* @internal85*/86Ecliptic(double lat = 0, double lon = 0) {87latitude = lat;88longitude = lon;89}9091/**92* Setter for Ecliptic Coordinate object93* @param lat The ecliptic latitude, measured in radians.94* @param lon The ecliptic longitude, measured in radians.95* @internal96*/97void set(double lat, double lon) {98latitude = lat;99longitude = lon;100}101102/**103* Return a string representation of this object104* @internal105*/106UnicodeString toString() const;107108/**109* The ecliptic latitude, in radians. This specifies an object's110* position north or south of the plane of the ecliptic,111* with positive angles representing north.112* @internal113*/114double latitude;115116/**117* The ecliptic longitude, in radians.118* This specifies an object's position along the ecliptic plane119* relative to the "First Point of Aries", which is the Sun's position120* in the sky at the Vernal Equinox,121* with positive angles representing east.122* <p>123* A bit of trivia: the first point of Aries is currently in the124* constellation Pisces, due to the precession of the earth's axis.125* @internal126*/127double longitude;128};129130/**131* Represents the position of an132* object in the sky relative to the plane of the earth's equator.133* The <i>Right Ascension</i> specifies the position east or west134* along the equator, relative to the sun's position at the vernal135* equinox. The <i>Declination</i> is the position north or south136* of the equatorial plane.137* <p>138* Note that Equatorial objects are immutable and cannot be modified139* once they are constructed. This allows them to be passed and returned by140* value without worrying about whether other code will modify them.141*142* @see CalendarAstronomer.Ecliptic143* @see CalendarAstronomer.Horizon144* @internal145*/146class U_I18N_API Equatorial : public UMemory {147public:148/**149* Constructs an Equatorial coordinate object.150* <p>151* @param asc The right ascension, measured in radians.152* @param dec The declination, measured in radians.153* @internal154*/155Equatorial(double asc = 0, double dec = 0)156: ascension(asc), declination(dec) { }157158/**159* Setter160* @param asc The right ascension, measured in radians.161* @param dec The declination, measured in radians.162* @internal163*/164void set(double asc, double dec) {165ascension = asc;166declination = dec;167}168169/**170* Return a string representation of this object, with the171* angles measured in degrees.172* @internal173*/174UnicodeString toString() const;175176/**177* Return a string representation of this object with the right ascension178* measured in hours, minutes, and seconds.179* @internal180*/181//String toHmsString() {182//return radToHms(ascension) + "," + radToDms(declination);183//}184185/**186* The right ascension, in radians.187* This is the position east or west along the equator188* relative to the sun's position at the vernal equinox,189* with positive angles representing East.190* @internal191*/192double ascension;193194/**195* The declination, in radians.196* This is the position north or south of the equatorial plane,197* with positive angles representing north.198* @internal199*/200double declination;201};202203/**204* Represents the position of an object in the sky relative to205* the local horizon.206* The <i>Altitude</i> represents the object's elevation above the horizon,207* with objects below the horizon having a negative altitude.208* The <i>Azimuth</i> is the geographic direction of the object from the209* observer's position, with 0 representing north. The azimuth increases210* clockwise from north.211* <p>212* Note that Horizon objects are immutable and cannot be modified213* once they are constructed. This allows them to be passed and returned by214* value without worrying about whether other code will modify them.215*216* @see CalendarAstronomer.Ecliptic217* @see CalendarAstronomer.Equatorial218* @internal219*/220class U_I18N_API Horizon : public UMemory {221public:222/**223* Constructs a Horizon coordinate object.224* <p>225* @param alt The altitude, measured in radians above the horizon.226* @param azim The azimuth, measured in radians clockwise from north.227* @internal228*/229Horizon(double alt=0, double azim=0)230: altitude(alt), azimuth(azim) { }231232/**233* Setter for Ecliptic Coordinate object234* @param alt The altitude, measured in radians above the horizon.235* @param azim The azimuth, measured in radians clockwise from north.236* @internal237*/238void set(double alt, double azim) {239altitude = alt;240azimuth = azim;241}242243/**244* Return a string representation of this object, with the245* angles measured in degrees.246* @internal247*/248UnicodeString toString() const;249250/**251* The object's altitude above the horizon, in radians.252* @internal253*/254double altitude;255256/**257* The object's direction, in radians clockwise from north.258* @internal259*/260double azimuth;261};262263public:264//-------------------------------------------------------------------------265// Assorted private data used for conversions266//-------------------------------------------------------------------------267268// My own copies of these so compilers are more likely to optimize them away269static const double PI;270271/**272* The average number of solar days from one new moon to the next. This is the time273* it takes for the moon to return the same ecliptic longitude as the sun.274* It is longer than the sidereal month because the sun's longitude increases275* during the year due to the revolution of the earth around the sun.276* Approximately 29.53.277*278* @see #SIDEREAL_MONTH279* @internal280* @deprecated ICU 2.4. This class may be removed or modified.281*/282static const double SYNODIC_MONTH;283284//-------------------------------------------------------------------------285// Constructors286//-------------------------------------------------------------------------287288/**289* Construct a new <code>CalendarAstronomer</code> object that is initialized to290* the current date and time.291* @internal292*/293CalendarAstronomer();294295/**296* Construct a new <code>CalendarAstronomer</code> object that is initialized to297* the specified date and time.298* @internal299*/300CalendarAstronomer(UDate d);301302/**303* Construct a new <code>CalendarAstronomer</code> object with the given304* latitude and longitude. The object's time is set to the current305* date and time.306* <p>307* @param longitude The desired longitude, in <em>degrees</em> east of308* the Greenwich meridian.309*310* @param latitude The desired latitude, in <em>degrees</em>. Positive311* values signify North, negative South.312*313* @see java.util.Date#getTime()314* @internal315*/316CalendarAstronomer(double longitude, double latitude);317318/**319* Destructor320* @internal321*/322~CalendarAstronomer();323324//-------------------------------------------------------------------------325// Time and date getters and setters326//-------------------------------------------------------------------------327328/**329* Set the current date and time of this <code>CalendarAstronomer</code> object. All330* astronomical calculations are performed based on this time setting.331*332* @param aTime the date and time, expressed as the number of milliseconds since333* 1/1/1970 0:00 GMT (Gregorian).334*335* @see #setDate336* @see #getTime337* @internal338*/339void setTime(UDate aTime);340341342/**343* Set the current date and time of this <code>CalendarAstronomer</code> object. All344* astronomical calculations are performed based on this time setting.345*346* @param aTime the date and time, expressed as the number of milliseconds since347* 1/1/1970 0:00 GMT (Gregorian).348*349* @see #getTime350* @internal351*/352void setDate(UDate aDate) { setTime(aDate); }353354/**355* Set the current date and time of this <code>CalendarAstronomer</code> object. All356* astronomical calculations are performed based on this time setting.357*358* @param jdn the desired time, expressed as a "julian day number",359* which is the number of elapsed days since360* 1/1/4713 BC (Julian), 12:00 GMT. Note that julian day361* numbers start at <em>noon</em>. To get the jdn for362* the corresponding midnight, subtract 0.5.363*364* @see #getJulianDay365* @see #JULIAN_EPOCH_MS366* @internal367*/368void setJulianDay(double jdn);369370/**371* Get the current time of this <code>CalendarAstronomer</code> object,372* represented as the number of milliseconds since373* 1/1/1970 AD 0:00 GMT (Gregorian).374*375* @see #setTime376* @see #getDate377* @internal378*/379UDate getTime();380381/**382* Get the current time of this <code>CalendarAstronomer</code> object,383* expressed as a "julian day number", which is the number of elapsed384* days since 1/1/4713 BC (Julian), 12:00 GMT.385*386* @see #setJulianDay387* @see #JULIAN_EPOCH_MS388* @internal389*/390double getJulianDay();391392/**393* Return this object's time expressed in julian centuries:394* the number of centuries after 1/1/1900 AD, 12:00 GMT395*396* @see #getJulianDay397* @internal398*/399double getJulianCentury();400401/**402* Returns the current Greenwich sidereal time, measured in hours403* @internal404*/405double getGreenwichSidereal();406407private:408double getSiderealOffset();409public:410/**411* Returns the current local sidereal time, measured in hours412* @internal413*/414double getLocalSidereal();415416/**417* Converts local sidereal time to Universal Time.418*419* @param lst The Local Sidereal Time, in hours since sidereal midnight420* on this object's current date.421*422* @return The corresponding Universal Time, in milliseconds since423* 1 Jan 1970, GMT.424*/425//private:426double lstToUT(double lst);427428/**429*430* Convert from ecliptic to equatorial coordinates.431*432* @param ecliptic The ecliptic433* @param result Fillin result434* @return reference to result435*/436Equatorial& eclipticToEquatorial(Equatorial& result, const Ecliptic& ecliptic);437438/**439* Convert from ecliptic to equatorial coordinates.440*441* @param eclipLong The ecliptic longitude442* @param eclipLat The ecliptic latitude443*444* @return The corresponding point in equatorial coordinates.445* @internal446*/447Equatorial& eclipticToEquatorial(Equatorial& result, double eclipLong, double eclipLat);448449/**450* Convert from ecliptic longitude to equatorial coordinates.451*452* @param eclipLong The ecliptic longitude453*454* @return The corresponding point in equatorial coordinates.455* @internal456*/457Equatorial& eclipticToEquatorial(Equatorial& result, double eclipLong) ;458459/**460* @internal461*/462Horizon& eclipticToHorizon(Horizon& result, double eclipLong) ;463464//-------------------------------------------------------------------------465// The Sun466//-------------------------------------------------------------------------467468/**469* The longitude of the sun at the time specified by this object.470* The longitude is measured in radians along the ecliptic471* from the "first point of Aries," the point at which the ecliptic472* crosses the earth's equatorial plane at the vernal equinox.473* <p>474* Currently, this method uses an approximation of the two-body Kepler's475* equation for the earth and the sun. It does not take into account the476* perturbations caused by the other planets, the moon, etc.477* @internal478*/479double getSunLongitude();480481/**482* TODO Make this public when the entire class is package-private.483*/484/*public*/ void getSunLongitude(double julianDay, double &longitude, double &meanAnomaly);485486/**487* The position of the sun at this object's current date and time,488* in equatorial coordinates.489* @param result fillin for the result490* @internal491*/492Equatorial& getSunPosition(Equatorial& result);493494public:495/**496* Constant representing the vernal equinox.497* For use with {@link #getSunTime getSunTime}.498* Note: In this case, "vernal" refers to the northern hemisphere's seasons.499* @internal500*/501// static double VERNAL_EQUINOX();502503/**504* Constant representing the summer solstice.505* For use with {@link #getSunTime getSunTime}.506* Note: In this case, "summer" refers to the northern hemisphere's seasons.507* @internal508*/509static double SUMMER_SOLSTICE();510511/**512* Constant representing the autumnal equinox.513* For use with {@link #getSunTime getSunTime}.514* Note: In this case, "autumn" refers to the northern hemisphere's seasons.515* @internal516*/517// static double AUTUMN_EQUINOX();518519/**520* Constant representing the winter solstice.521* For use with {@link #getSunTime getSunTime}.522* Note: In this case, "winter" refers to the northern hemisphere's seasons.523* @internal524*/525static double WINTER_SOLSTICE();526527/**528* Find the next time at which the sun's ecliptic longitude will have529* the desired value.530* @internal531*/532UDate getSunTime(double desired, UBool next);533534/**535* Returns the time (GMT) of sunrise or sunset on the local date to which536* this calendar is currently set.537*538* NOTE: This method only works well if this object is set to a539* time near local noon. Because of variations between the local540* official time zone and the geographic longitude, the541* computation can flop over into an adjacent day if this object542* is set to a time near local midnight.543*544* @internal545*/546UDate getSunRiseSet(UBool rise);547548//-------------------------------------------------------------------------549// The Moon550//-------------------------------------------------------------------------551552/**553* The position of the moon at the time set on this554* object, in equatorial coordinates.555* @internal556* @return const reference to internal field of calendar astronomer. Do not use outside of the lifetime of this astronomer.557*/558const Equatorial& getMoonPosition();559560/**561* The "age" of the moon at the time specified in this object.562* This is really the angle between the563* current ecliptic longitudes of the sun and the moon,564* measured in radians.565*566* @see #getMoonPhase567* @internal568*/569double getMoonAge();570571/**572* Calculate the phase of the moon at the time set in this object.573* The returned phase is a <code>double</code> in the range574* <code>0 <= phase < 1</code>, interpreted as follows:575* <ul>576* <li>0.00: New moon577* <li>0.25: First quarter578* <li>0.50: Full moon579* <li>0.75: Last quarter580* </ul>581*582* @see #getMoonAge583* @internal584*/585double getMoonPhase();586587class U_I18N_API MoonAge : public UMemory {588public:589MoonAge(double l)590: value(l) { }591void set(double l) { value = l; }592double value;593};594595/**596* Constant representing a new moon.597* For use with {@link #getMoonTime getMoonTime}598* @internal599*/600static const MoonAge NEW_MOON();601602/**603* Constant representing the moon's first quarter.604* For use with {@link #getMoonTime getMoonTime}605* @internal606*/607// static const MoonAge FIRST_QUARTER();608609/**610* Constant representing a full moon.611* For use with {@link #getMoonTime getMoonTime}612* @internal613*/614static const MoonAge FULL_MOON();615616/**617* Constant representing the moon's last quarter.618* For use with {@link #getMoonTime getMoonTime}619* @internal620*/621// static const MoonAge LAST_QUARTER();622623/**624* Find the next or previous time at which the Moon's ecliptic625* longitude will have the desired value.626* <p>627* @param desired The desired longitude.628* @param next <tt>true</tt> if the next occurrence of the phase629* is desired, <tt>false</tt> for the previous occurrence.630* @internal631*/632UDate getMoonTime(double desired, UBool next);633UDate getMoonTime(const MoonAge& desired, UBool next);634635/**636* Returns the time (GMT) of sunrise or sunset on the local date to which637* this calendar is currently set.638* @internal639*/640UDate getMoonRiseSet(UBool rise);641642//-------------------------------------------------------------------------643// Interpolation methods for finding the time at which a given event occurs644//-------------------------------------------------------------------------645646// private647class AngleFunc : public UMemory {648public:649virtual double eval(CalendarAstronomer&) = 0;650virtual ~AngleFunc();651};652friend class AngleFunc;653654UDate timeOfAngle(AngleFunc& func, double desired,655double periodDays, double epsilon, UBool next);656657class CoordFunc : public UMemory {658public:659virtual void eval(Equatorial& result, CalendarAstronomer&) = 0;660virtual ~CoordFunc();661};662friend class CoordFunc;663664double riseOrSet(CoordFunc& func, UBool rise,665double diameter, double refraction,666double epsilon);667668//-------------------------------------------------------------------------669// Other utility methods670//-------------------------------------------------------------------------671private:672673/**674* Return the obliquity of the ecliptic (the angle between the ecliptic675* and the earth's equator) at the current time. This varies due to676* the precession of the earth's axis.677*678* @return the obliquity of the ecliptic relative to the equator,679* measured in radians.680*/681double eclipticObliquity();682683//-------------------------------------------------------------------------684// Private data685//-------------------------------------------------------------------------686private:687/**688* Current time in milliseconds since 1/1/1970 AD689* @see java.util.Date#getTime690*/691UDate fTime;692693/* These aren't used yet, but they'll be needed for sunset calculations694* and equatorial to horizon coordinate conversions695*/696double fLongitude;697double fLatitude;698double fGmtOffset;699700//701// The following fields are used to cache calculated results for improved702// performance. These values all depend on the current time setting703// of this object, so the clearCache method is provided.704//705706double julianDay;707double julianCentury;708double sunLongitude;709double meanAnomalySun;710double moonLongitude;711double moonEclipLong;712double meanAnomalyMoon;713double eclipObliquity;714double siderealT0;715double siderealTime;716717void clearCache();718719Equatorial moonPosition;720UBool moonPositionSet;721722/**723* @internal724*/725// UDate local(UDate localMillis);726};727728U_NAMESPACE_END729730struct UHashtable;731732U_NAMESPACE_BEGIN733734/**735* Cache of month -> julian day736* @internal737*/738class CalendarCache : public UMemory {739public:740static int32_t get(CalendarCache** cache, int32_t key, UErrorCode &status);741static void put(CalendarCache** cache, int32_t key, int32_t value, UErrorCode &status);742virtual ~CalendarCache();743private:744CalendarCache(int32_t size, UErrorCode& status);745static void createCache(CalendarCache** cache, UErrorCode& status);746/**747* not implemented748*/749CalendarCache();750UHashtable *fTable;751};752753U_NAMESPACE_END754755#endif756#endif757758759