1 // © 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 
20 U_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  */
56 class U_I18N_API CalendarAstronomer : public UMemory {
57 public:
58   // some classes
59 
60 public:
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      */
set(double lat,double lon)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)
ascension(asc)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      */
set(double asc,double dec)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)
altitude(alt)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      */
set(double alt,double azim)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 
264 public:
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    */
setDate(UDate aDate)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 
408 private:
409   double getSiderealOffset();
410 public:
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 
495 public:
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:
MoonAge(double l)590     MoonAge(double l)
591       :  value(l) { }
set(double 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   //-------------------------------------------------------------------------
672 private:
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   //-------------------------------------------------------------------------
687 private:
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 
729 U_NAMESPACE_END
730 
731 struct UHashtable;
732 
733 U_NAMESPACE_BEGIN
734 
735 /**
736  * Cache of month -> julian day
737  * @internal
738  */
739 class CalendarCache : public UMemory {
740 public:
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();
744 private:
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 
754 U_NAMESPACE_END
755 
756 #endif
757 #endif
758