1// Copyright (C) 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
3/************************************************************************
4 * Copyright (C) 1996-2008, International Business Machines Corporation *
5 * and others. All Rights Reserved.                                     *
6 ************************************************************************
7 *  2003-nov-07   srl       Port from Java
8 */
9
10#ifndef ASTRO_H
11#define ASTRO_H
12
13#include "unicode/utypes.h"
14
15#if !UCONFIG_NO_FORMATTING
16
17#include "gregoimp.h"  // for Math
18#include "unicode/unistr.h"
19
20U_NAMESPACE_BEGIN
21
22/**
23 * <code>CalendarAstronomer</code> is a class that can perform the calculations to
24 * determine the positions of the sun and moon, the time of sunrise and
25 * sunset, and other astronomy-related data.  The calculations it performs
26 * are in some cases quite complicated, and this utility class saves you
27 * the trouble of worrying about them.
28 * <p>
29 * The measurement of time is a very important part of astronomy.  Because
30 * astronomical bodies are constantly in motion, observations are only valid
31 * at a given moment in time.  Accordingly, each <code>CalendarAstronomer</code>
32 * object has a <code>time</code> property that determines the date
33 * and time for which its calculations are performed.  You can set and
34 * retrieve this property with {@link #setDate setDate}, {@link #getDate getDate}
35 * and related methods.
36 * <p>
37 * Almost all of the calculations performed by this class, or by any
38 * astronomer, are approximations to various degrees of accuracy.  The
39 * calculations in this class are mostly modelled after those described
40 * in the book
41 * <a href="http://www.amazon.com/exec/obidos/ISBN=0521356997" target="_top">
42 * Practical Astronomy With Your Calculator</a>, by Peter J.
43 * Duffett-Smith, Cambridge University Press, 1990.  This is an excellent
44 * book, and if you want a greater understanding of how these calculations
45 * are performed it a very good, readable starting point.
46 * <p>
47 * <strong>WARNING:</strong> This class is very early in its development, and
48 * it is highly likely that its API will change to some degree in the future.
49 * At the moment, it basically does just enough to support {@link IslamicCalendar}
50 * and {@link ChineseCalendar}.
51 *
52 * @author Laura Werner
53 * @author Alan Liu
54 * @internal
55 */
56class U_I18N_API CalendarAstronomer : public UMemory {
57public:
58  // some classes
59
60public:
61  /**
62   * Represents the position of an object in the sky relative to the ecliptic,
63   * the plane of the earth's orbit around the Sun.
64   * This is a spherical coordinate system in which the latitude
65   * specifies the position north or south of the plane of the ecliptic.
66   * The longitude specifies the position along the ecliptic plane
67   * relative to the "First Point of Aries", which is the Sun's position in the sky
68   * at the Vernal Equinox.
69   * <p>
70   * Note that Ecliptic objects are immutable and cannot be modified
71   * once they are constructed.  This allows them to be passed and returned by
72   * value without worrying about whether other code will modify them.
73   *
74   * @see CalendarAstronomer.Equatorial
75   * @see CalendarAstronomer.Horizon
76   * @internal
77   */
78  class U_I18N_API Ecliptic : public UMemory {
79  public:
80    /**
81     * Constructs an Ecliptic coordinate object.
82     * <p>
83     * @param lat The ecliptic latitude, measured in radians.
84     * @param lon The ecliptic longitude, measured in radians.
85     * @internal
86     */
87    Ecliptic(double lat = 0, double lon = 0) {
88      latitude = lat;
89      longitude = lon;
90    }
91
92    /**
93     * Setter for Ecliptic Coordinate object
94     * @param lat The ecliptic latitude, measured in radians.
95     * @param lon The ecliptic longitude, measured in radians.
96     * @internal
97     */
98    void set(double lat, double lon) {
99      latitude = lat;
100      longitude = lon;
101    }
102
103    /**
104     * Return a string representation of this object
105     * @internal
106     */
107    UnicodeString toString() const;
108
109    /**
110     * The ecliptic latitude, in radians.  This specifies an object's
111     * position north or south of the plane of the ecliptic,
112     * with positive angles representing north.
113     * @internal
114     */
115    double latitude;
116
117    /**
118     * The ecliptic longitude, in radians.
119     * This specifies an object's position along the ecliptic plane
120     * relative to the "First Point of Aries", which is the Sun's position
121     * in the sky at the Vernal Equinox,
122     * with positive angles representing east.
123     * <p>
124     * A bit of trivia: the first point of Aries is currently in the
125     * constellation Pisces, due to the precession of the earth's axis.
126     * @internal
127     */
128    double longitude;
129  };
130
131  /**
132   * Represents the position of an
133   * object in the sky relative to the plane of the earth's equator.
134   * The <i>Right Ascension</i> specifies the position east or west
135   * along the equator, relative to the sun's position at the vernal
136   * equinox.  The <i>Declination</i> is the position north or south
137   * of the equatorial plane.
138   * <p>
139   * Note that Equatorial objects are immutable and cannot be modified
140   * once they are constructed.  This allows them to be passed and returned by
141   * value without worrying about whether other code will modify them.
142   *
143   * @see CalendarAstronomer.Ecliptic
144   * @see CalendarAstronomer.Horizon
145   * @internal
146   */
147  class U_I18N_API Equatorial : public UMemory {
148  public:
149    /**
150     * Constructs an Equatorial coordinate object.
151     * <p>
152     * @param asc The right ascension, measured in radians.
153     * @param dec The declination, measured in radians.
154     * @internal
155     */
156    Equatorial(double asc = 0, double dec = 0)
157      : ascension(asc), declination(dec) { }
158
159    /**
160     * Setter
161     * @param asc The right ascension, measured in radians.
162     * @param dec The declination, measured in radians.
163     * @internal
164     */
165    void set(double asc, double dec) {
166      ascension = asc;
167      declination = dec;
168    }
169
170    /**
171     * Return a string representation of this object, with the
172     * angles measured in degrees.
173     * @internal
174     */
175    UnicodeString toString() const;
176
177    /**
178     * Return a string representation of this object with the right ascension
179     * measured in hours, minutes, and seconds.
180     * @internal
181     */
182    //String toHmsString() {
183    //return radToHms(ascension) + "," + radToDms(declination);
184    //}
185
186    /**
187     * The right ascension, in radians.
188     * This is the position east or west along the equator
189     * relative to the sun's position at the vernal equinox,
190     * with positive angles representing East.
191     * @internal
192     */
193    double ascension;
194
195    /**
196     * The declination, in radians.
197     * This is the position north or south of the equatorial plane,
198     * with positive angles representing north.
199     * @internal
200     */
201    double declination;
202  };
203
204  /**
205   * Represents the position of an  object in the sky relative to
206   * the local horizon.
207   * The <i>Altitude</i> represents the object's elevation above the horizon,
208   * with objects below the horizon having a negative altitude.
209   * The <i>Azimuth</i> is the geographic direction of the object from the
210   * observer's position, with 0 representing north.  The azimuth increases
211   * clockwise from north.
212   * <p>
213   * Note that Horizon objects are immutable and cannot be modified
214   * once they are constructed.  This allows them to be passed and returned by
215   * value without worrying about whether other code will modify them.
216   *
217   * @see CalendarAstronomer.Ecliptic
218   * @see CalendarAstronomer.Equatorial
219   * @internal
220   */
221  class U_I18N_API Horizon : public UMemory {
222  public:
223    /**
224     * Constructs a Horizon coordinate object.
225     * <p>
226     * @param alt  The altitude, measured in radians above the horizon.
227     * @param azim The azimuth, measured in radians clockwise from north.
228     * @internal
229     */
230    Horizon(double alt=0, double azim=0)
231      : altitude(alt), azimuth(azim) { }
232
233    /**
234     * Setter for Ecliptic Coordinate object
235     * @param alt  The altitude, measured in radians above the horizon.
236     * @param azim The azimuth, measured in radians clockwise from north.
237     * @internal
238     */
239    void set(double alt, double azim) {
240      altitude = alt;
241      azimuth = azim;
242    }
243
244    /**
245     * Return a string representation of this object, with the
246     * angles measured in degrees.
247     * @internal
248     */
249    UnicodeString toString() const;
250
251    /**
252     * The object's altitude above the horizon, in radians.
253     * @internal
254     */
255    double altitude;
256
257    /**
258     * The object's direction, in radians clockwise from north.
259     * @internal
260     */
261    double azimuth;
262  };
263
264public:
265  //-------------------------------------------------------------------------
266  // Assorted private data used for conversions
267  //-------------------------------------------------------------------------
268
269  // My own copies of these so compilers are more likely to optimize them away
270  static const double PI;
271
272  /**
273   * The average number of solar days from one new moon to the next.  This is the time
274   * it takes for the moon to return the same ecliptic longitude as the sun.
275   * It is longer than the sidereal month because the sun's longitude increases
276   * during the year due to the revolution of the earth around the sun.
277   * Approximately 29.53.
278   *
279   * @see #SIDEREAL_MONTH
280   * @internal
281   * @deprecated ICU 2.4. This class may be removed or modified.
282   */
283  static const double SYNODIC_MONTH;
284
285  //-------------------------------------------------------------------------
286  // Constructors
287  //-------------------------------------------------------------------------
288
289  /**
290   * Construct a new <code>CalendarAstronomer</code> object that is initialized to
291   * the current date and time.
292   * @internal
293   */
294  CalendarAstronomer();
295
296  /**
297   * Construct a new <code>CalendarAstronomer</code> object that is initialized to
298   * the specified date and time.
299   * @internal
300   */
301  CalendarAstronomer(UDate d);
302
303  /**
304   * Construct a new <code>CalendarAstronomer</code> object with the given
305   * latitude and longitude.  The object's time is set to the current
306   * date and time.
307   * <p>
308   * @param longitude The desired longitude, in <em>degrees</em> east of
309   *                  the Greenwich meridian.
310   *
311   * @param latitude  The desired latitude, in <em>degrees</em>.  Positive
312   *                  values signify North, negative South.
313   *
314   * @see java.util.Date#getTime()
315   * @internal
316   */
317  CalendarAstronomer(double longitude, double latitude);
318
319  /**
320   * Destructor
321   * @internal
322   */
323  ~CalendarAstronomer();
324
325  //-------------------------------------------------------------------------
326  // Time and date getters and setters
327  //-------------------------------------------------------------------------
328
329  /**
330   * Set the current date and time of this <code>CalendarAstronomer</code> object.  All
331   * astronomical calculations are performed based on this time setting.
332   *
333   * @param aTime the date and time, expressed as the number of milliseconds since
334   *              1/1/1970 0:00 GMT (Gregorian).
335   *
336   * @see #setDate
337   * @see #getTime
338   * @internal
339   */
340  void setTime(UDate aTime);
341
342
343  /**
344   * Set the current date and time of this <code>CalendarAstronomer</code> object.  All
345   * astronomical calculations are performed based on this time setting.
346   *
347   * @param aTime the date and time, expressed as the number of milliseconds since
348   *              1/1/1970 0:00 GMT (Gregorian).
349   *
350   * @see #getTime
351   * @internal
352   */
353  void setDate(UDate aDate) { setTime(aDate); }
354
355  /**
356   * Set the current date and time of this <code>CalendarAstronomer</code> object.  All
357   * astronomical calculations are performed based on this time setting.
358   *
359   * @param jdn   the desired time, expressed as a "julian day number",
360   *              which is the number of elapsed days since
361   *              1/1/4713 BC (Julian), 12:00 GMT.  Note that julian day
362   *              numbers start at <em>noon</em>.  To get the jdn for
363   *              the corresponding midnight, subtract 0.5.
364   *
365   * @see #getJulianDay
366   * @see #JULIAN_EPOCH_MS
367   * @internal
368   */
369  void setJulianDay(double jdn);
370
371  /**
372   * Get the current time of this <code>CalendarAstronomer</code> object,
373   * represented as the number of milliseconds since
374   * 1/1/1970 AD 0:00 GMT (Gregorian).
375   *
376   * @see #setTime
377   * @see #getDate
378   * @internal
379   */
380  UDate getTime();
381
382  /**
383   * Get the current time of this <code>CalendarAstronomer</code> object,
384   * expressed as a "julian day number", which is the number of elapsed
385   * days since 1/1/4713 BC (Julian), 12:00 GMT.
386   *
387   * @see #setJulianDay
388   * @see #JULIAN_EPOCH_MS
389   * @internal
390   */
391  double getJulianDay();
392
393  /**
394   * Return this object's time expressed in julian centuries:
395   * the number of centuries after 1/1/1900 AD, 12:00 GMT
396   *
397   * @see #getJulianDay
398   * @internal
399   */
400  double getJulianCentury();
401
402  /**
403   * Returns the current Greenwich sidereal time, measured in hours
404   * @internal
405   */
406  double getGreenwichSidereal();
407
408private:
409  double getSiderealOffset();
410public:
411  /**
412   * Returns the current local sidereal time, measured in hours
413   * @internal
414   */
415  double getLocalSidereal();
416
417  /**
418   * Converts local sidereal time to Universal Time.
419   *
420   * @param lst   The Local Sidereal Time, in hours since sidereal midnight
421   *              on this object's current date.
422   *
423   * @return      The corresponding Universal Time, in milliseconds since
424   *              1 Jan 1970, GMT.
425   */
426  //private:
427  double lstToUT(double lst);
428
429  /**
430   *
431   * Convert from ecliptic to equatorial coordinates.
432   *
433   * @param ecliptic     The ecliptic
434   * @param result       Fillin result
435   * @return reference to result
436   */
437  Equatorial& eclipticToEquatorial(Equatorial& result, const Ecliptic& ecliptic);
438
439  /**
440   * Convert from ecliptic to equatorial coordinates.
441   *
442   * @param eclipLong     The ecliptic longitude
443   * @param eclipLat      The ecliptic latitude
444   *
445   * @return              The corresponding point in equatorial coordinates.
446   * @internal
447   */
448  Equatorial& eclipticToEquatorial(Equatorial& result, double eclipLong, double eclipLat);
449
450  /**
451   * Convert from ecliptic longitude to equatorial coordinates.
452   *
453   * @param eclipLong     The ecliptic longitude
454   *
455   * @return              The corresponding point in equatorial coordinates.
456   * @internal
457   */
458  Equatorial& eclipticToEquatorial(Equatorial& result, double eclipLong) ;
459
460  /**
461   * @internal
462   */
463  Horizon& eclipticToHorizon(Horizon& result, double eclipLong) ;
464
465  //-------------------------------------------------------------------------
466  // The Sun
467  //-------------------------------------------------------------------------
468
469  /**
470   * The longitude of the sun at the time specified by this object.
471   * The longitude is measured in radians along the ecliptic
472   * from the "first point of Aries," the point at which the ecliptic
473   * crosses the earth's equatorial plane at the vernal equinox.
474   * <p>
475   * Currently, this method uses an approximation of the two-body Kepler's
476   * equation for the earth and the sun.  It does not take into account the
477   * perturbations caused by the other planets, the moon, etc.
478   * @internal
479   */
480  double getSunLongitude();
481
482  /**
483   * TODO Make this public when the entire class is package-private.
484   */
485  /*public*/ void getSunLongitude(double julianDay, double &longitude, double &meanAnomaly);
486
487  /**
488   * The position of the sun at this object's current date and time,
489   * in equatorial coordinates.
490   * @param result fillin for the result
491   * @internal
492   */
493  Equatorial& getSunPosition(Equatorial& result);
494
495public:
496  /**
497   * Constant representing the vernal equinox.
498   * For use with {@link #getSunTime getSunTime}.
499   * Note: In this case, "vernal" refers to the northern hemisphere's seasons.
500   * @internal
501   */
502//  static double VERNAL_EQUINOX();
503
504  /**
505   * Constant representing the summer solstice.
506   * For use with {@link #getSunTime getSunTime}.
507   * Note: In this case, "summer" refers to the northern hemisphere's seasons.
508   * @internal
509   */
510  static double SUMMER_SOLSTICE();
511
512  /**
513   * Constant representing the autumnal equinox.
514   * For use with {@link #getSunTime getSunTime}.
515   * Note: In this case, "autumn" refers to the northern hemisphere's seasons.
516   * @internal
517   */
518//  static double AUTUMN_EQUINOX();
519
520  /**
521   * Constant representing the winter solstice.
522   * For use with {@link #getSunTime getSunTime}.
523   * Note: In this case, "winter" refers to the northern hemisphere's seasons.
524   * @internal
525   */
526  static double WINTER_SOLSTICE();
527
528  /**
529   * Find the next time at which the sun's ecliptic longitude will have
530   * the desired value.
531   * @internal
532   */
533  UDate getSunTime(double desired, UBool next);
534
535  /**
536   * Returns the time (GMT) of sunrise or sunset on the local date to which
537   * this calendar is currently set.
538   *
539   * NOTE: This method only works well if this object is set to a
540   * time near local noon.  Because of variations between the local
541   * official time zone and the geographic longitude, the
542   * computation can flop over into an adjacent day if this object
543   * is set to a time near local midnight.
544   *
545   * @internal
546   */
547  UDate getSunRiseSet(UBool rise);
548
549  //-------------------------------------------------------------------------
550  // The Moon
551  //-------------------------------------------------------------------------
552
553  /**
554   * The position of the moon at the time set on this
555   * object, in equatorial coordinates.
556   * @internal
557   * @return const reference to internal field of calendar astronomer. Do not use outside of the lifetime of this astronomer.
558   */
559  const Equatorial& getMoonPosition();
560
561  /**
562   * The "age" of the moon at the time specified in this object.
563   * This is really the angle between the
564   * current ecliptic longitudes of the sun and the moon,
565   * measured in radians.
566   *
567   * @see #getMoonPhase
568   * @internal
569   */
570  double getMoonAge();
571
572  /**
573   * Calculate the phase of the moon at the time set in this object.
574   * The returned phase is a <code>double</code> in the range
575   * <code>0 <= phase < 1</code>, interpreted as follows:
576   * <ul>
577   * <li>0.00: New moon
578   * <li>0.25: First quarter
579   * <li>0.50: Full moon
580   * <li>0.75: Last quarter
581   * </ul>
582   *
583   * @see #getMoonAge
584   * @internal
585   */
586  double getMoonPhase();
587
588  class U_I18N_API MoonAge : public UMemory {
589  public:
590    MoonAge(double l)
591      :  value(l) { }
592    void set(double l) { value = l; }
593    double value;
594  };
595
596  /**
597   * Constant representing a new moon.
598   * For use with {@link #getMoonTime getMoonTime}
599   * @internal
600   */
601  static const MoonAge NEW_MOON();
602
603  /**
604   * Constant representing the moon's first quarter.
605   * For use with {@link #getMoonTime getMoonTime}
606   * @internal
607   */
608//  static const MoonAge FIRST_QUARTER();
609
610  /**
611   * Constant representing a full moon.
612   * For use with {@link #getMoonTime getMoonTime}
613   * @internal
614   */
615  static const MoonAge FULL_MOON();
616
617  /**
618   * Constant representing the moon's last quarter.
619   * For use with {@link #getMoonTime getMoonTime}
620   * @internal
621   */
622//  static const MoonAge LAST_QUARTER();
623
624  /**
625   * Find the next or previous time at which the Moon's ecliptic
626   * longitude will have the desired value.
627   * <p>
628   * @param desired   The desired longitude.
629   * @param next      <tt>true</tt> if the next occurrance of the phase
630   *                  is desired, <tt>false</tt> for the previous occurrance.
631   * @internal
632   */
633  UDate getMoonTime(double desired, UBool next);
634  UDate getMoonTime(const MoonAge& desired, UBool next);
635
636  /**
637   * Returns the time (GMT) of sunrise or sunset on the local date to which
638   * this calendar is currently set.
639   * @internal
640   */
641  UDate getMoonRiseSet(UBool rise);
642
643  //-------------------------------------------------------------------------
644  // Interpolation methods for finding the time at which a given event occurs
645  //-------------------------------------------------------------------------
646
647  // private
648  class AngleFunc : public UMemory {
649  public:
650    virtual double eval(CalendarAstronomer&) = 0;
651    virtual ~AngleFunc();
652  };
653  friend class AngleFunc;
654
655  UDate timeOfAngle(AngleFunc& func, double desired,
656                    double periodDays, double epsilon, UBool next);
657
658  class CoordFunc : public UMemory {
659  public:
660    virtual void eval(Equatorial& result, CalendarAstronomer&) = 0;
661    virtual ~CoordFunc();
662  };
663  friend class CoordFunc;
664
665  double riseOrSet(CoordFunc& func, UBool rise,
666                   double diameter, double refraction,
667                   double epsilon);
668
669  //-------------------------------------------------------------------------
670  // Other utility methods
671  //-------------------------------------------------------------------------
672private:
673
674  /**
675   * Return the obliquity of the ecliptic (the angle between the ecliptic
676   * and the earth's equator) at the current time.  This varies due to
677   * the precession of the earth's axis.
678   *
679   * @return  the obliquity of the ecliptic relative to the equator,
680   *          measured in radians.
681   */
682  double eclipticObliquity();
683
684  //-------------------------------------------------------------------------
685  // Private data
686  //-------------------------------------------------------------------------
687private:
688  /**
689   * Current time in milliseconds since 1/1/1970 AD
690   * @see java.util.Date#getTime
691   */
692  UDate fTime;
693
694  /* These aren't used yet, but they'll be needed for sunset calculations
695   * and equatorial to horizon coordinate conversions
696   */
697  double fLongitude;
698  double fLatitude;
699  double fGmtOffset;
700
701  //
702  // The following fields are used to cache calculated results for improved
703  // performance.  These values all depend on the current time setting
704  // of this object, so the clearCache method is provided.
705  //
706
707  double    julianDay;
708  double    julianCentury;
709  double    sunLongitude;
710  double    meanAnomalySun;
711  double    moonLongitude;
712  double    moonEclipLong;
713  double    meanAnomalyMoon;
714  double    eclipObliquity;
715  double    siderealT0;
716  double    siderealTime;
717
718  void clearCache();
719
720  Equatorial  moonPosition;
721  UBool       moonPositionSet;
722
723  /**
724   * @internal
725   */
726//  UDate local(UDate localMillis);
727};
728
729U_NAMESPACE_END
730
731struct UHashtable;
732
733U_NAMESPACE_BEGIN
734
735/**
736 * Cache of month -> julian day
737 * @internal
738 */
739class CalendarCache : public UMemory {
740public:
741  static int32_t get(CalendarCache** cache, int32_t key, UErrorCode &status);
742  static void put(CalendarCache** cache, int32_t key, int32_t value, UErrorCode &status);
743  virtual ~CalendarCache();
744private:
745  CalendarCache(int32_t size, UErrorCode& status);
746  static void createCache(CalendarCache** cache, UErrorCode& status);
747  /**
748   * not implemented
749   */
750  CalendarCache();
751  UHashtable *fTable;
752};
753
754U_NAMESPACE_END
755
756#endif
757#endif
758